update all

This commit is contained in:
xiaochao
2025-06-30 15:31:15 +08:00
commit 8c3008722a
15 changed files with 2674 additions and 0 deletions

View File

@@ -0,0 +1,497 @@
import logging
from homeassistant.components.sensor import SensorEntity, SensorDeviceClass, SensorStateClass
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.const import UnitOfTemperature
from .const import (
DOMAIN, HDD_TEMP, HDD_HEALTH, HDD_STATUS, SYSTEM_INFO, ICON_DISK,
ICON_TEMPERATURE, ICON_HEALTH, ATTR_DISK_MODEL, ATTR_SERIAL_NO,
ATTR_POWER_ON_HOURS, ATTR_TOTAL_CAPACITY, ATTR_HEALTH_STATUS,
DEVICE_ID_NAS, DATA_UPDATE_COORDINATOR
)
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities):
domain_data = hass.data[DOMAIN][config_entry.entry_id]
coordinator = domain_data[DATA_UPDATE_COORDINATOR]
ups_coordinator = domain_data["ups_coordinator"]
entities = []
existing_ids = set()
# 添加硬盘传感器
for disk in coordinator.data.get("disks", []):
# 温度传感器
temp_uid = f"{config_entry.entry_id}_{disk['device']}_temperature"
if temp_uid not in existing_ids:
entities.append(
DiskSensor(
coordinator,
disk["device"],
HDD_TEMP,
f"硬盘 {disk.get('model', '未知')} 温度",
temp_uid,
UnitOfTemperature.CELSIUS,
ICON_TEMPERATURE,
disk
)
)
existing_ids.add(temp_uid)
# 健康状态传感器
health_uid = f"{config_entry.entry_id}_{disk['device']}_health"
if health_uid not in existing_ids:
entities.append(
DiskSensor(
coordinator,
disk["device"],
HDD_HEALTH,
f"硬盘 {disk.get('model', '未知')} 健康状态",
health_uid,
None,
ICON_HEALTH,
disk
)
)
existing_ids.add(health_uid)
# 硬盘状态传感器
status_uid = f"{config_entry.entry_id}_{disk['device']}_status"
if status_uid not in existing_ids:
entities.append(
DiskSensor(
coordinator,
disk["device"],
HDD_STATUS,
f"硬盘 {disk.get('model', '未知')} 状态",
status_uid,
None,
ICON_DISK,
disk
)
)
existing_ids.add(status_uid)
# 添加系统信息传感器
system_uid = f"{config_entry.entry_id}_system_status"
if system_uid not in existing_ids:
entities.append(
SystemSensor(
coordinator,
"系统状态",
system_uid,
None,
"mdi:server",
)
)
existing_ids.add(system_uid)
# 添加CPU温度传感器
cpu_temp_uid = f"{config_entry.entry_id}_cpu_temperature"
if cpu_temp_uid not in existing_ids:
entities.append(
CPUTempSensor(
coordinator,
"CPU温度",
cpu_temp_uid,
UnitOfTemperature.CELSIUS,
"mdi:thermometer",
)
)
existing_ids.add(cpu_temp_uid)
# 添加主板温度传感器
mobo_temp_uid = f"{config_entry.entry_id}_motherboard_temperature"
if mobo_temp_uid not in existing_ids:
entities.append(
MoboTempSensor(
coordinator,
"主板温度",
mobo_temp_uid,
UnitOfTemperature.CELSIUS,
"mdi:thermometer",
)
)
existing_ids.add(mobo_temp_uid)
# 添加虚拟机状态传感器
if "vms" in coordinator.data:
for vm in coordinator.data["vms"]:
vm_uid = f"{config_entry.entry_id}_flynas_vm_{vm['name']}_status"
if vm_uid not in existing_ids:
entities.append(
VMStatusSensor(
coordinator,
vm["name"],
vm.get("title", vm["name"]),
config_entry.entry_id
)
)
existing_ids.add(vm_uid)
# 添加UPS传感器使用UPS协调器
if ups_coordinator.data: # 检查是否有UPS数据
ups_data = ups_coordinator.data
# UPS电池电量传感器
ups_battery_uid = f"{config_entry.entry_id}_ups_battery"
if ups_battery_uid not in existing_ids:
entities.append(
UPSSensor(
ups_coordinator, # 使用UPS协调器
"UPS电池电量",
ups_battery_uid,
"%",
"mdi:battery",
"battery_level",
device_class=SensorDeviceClass.BATTERY,
state_class=SensorStateClass.MEASUREMENT
)
)
existing_ids.add(ups_battery_uid)
# UPS剩余时间传感器
ups_runtime_uid = f"{config_entry.entry_id}_ups_runtime"
if ups_runtime_uid not in existing_ids:
entities.append(
UPSSensor(
ups_coordinator, # 使用UPS协调器
"UPS剩余时间",
ups_runtime_uid,
"分钟",
"mdi:clock",
"runtime_remaining",
state_class=SensorStateClass.MEASUREMENT
)
)
existing_ids.add(ups_runtime_uid)
# UPS输出电压传感器
ups_output_voltage_uid = f"{config_entry.entry_id}_ups_output_voltage"
if ups_output_voltage_uid not in existing_ids:
entities.append(
UPSSensor(
ups_coordinator, # 使用UPS协调器
"UPS输出电压",
ups_output_voltage_uid,
"V",
"mdi:lightning-bolt-outline",
"output_voltage",
device_class=SensorDeviceClass.VOLTAGE,
state_class=SensorStateClass.MEASUREMENT
)
)
existing_ids.add(ups_output_voltage_uid)
# UPS负载传感器
ups_load_uid = f"{config_entry.entry_id}_ups_load"
if ups_load_uid not in existing_ids:
entities.append(
UPSSensor(
ups_coordinator, # 使用UPS协调器
"UPS负载",
ups_load_uid,
"%",
"mdi:gauge",
"load_percent",
state_class=SensorStateClass.MEASUREMENT
)
)
existing_ids.add(ups_load_uid)
# UPS型号传感器
ups_model_uid = f"{config_entry.entry_id}_ups_model"
if ups_model_uid not in existing_ids:
entities.append(
UPSSensor(
ups_coordinator, # 使用UPS协调器
"UPS型号",
ups_model_uid,
None,
"mdi:information",
"model"
)
)
existing_ids.add(ups_model_uid)
# UPS状态传感器
ups_status_uid = f"{config_entry.entry_id}_ups_status"
if ups_status_uid not in existing_ids:
entities.append(
UPSSensor(
ups_coordinator, # 使用UPS协调器
"UPS状态",
ups_status_uid,
None,
"mdi:power-plug",
"status"
)
)
existing_ids.add(ups_status_uid)
async_add_entities(entities)
class DiskSensor(CoordinatorEntity, SensorEntity):
def __init__(self, coordinator, device_id, sensor_type, name, unique_id, unit, icon, disk_info):
super().__init__(coordinator)
self.device_id = device_id
self.sensor_type = sensor_type
self._attr_name = name
self._attr_unique_id = unique_id
self._attr_native_unit_of_measurement = unit
self._attr_icon = icon
self.disk_info = disk_info
self._attr_device_info = {
"identifiers": {(DOMAIN, f"disk_{device_id}")},
"name": disk_info.get("model", "未知硬盘"),
"manufacturer": "硬盘设备",
"via_device": (DOMAIN, DEVICE_ID_NAS)
}
@property
def native_value(self):
for disk in self.coordinator.data.get("disks", []):
if disk["device"] == self.device_id:
if self.sensor_type == HDD_TEMP:
temp = disk.get("temperature")
if temp is None or temp == "未知" or temp == "未检测":
return None
if isinstance(temp, str):
try:
if "°C" in temp:
return float(temp.replace("°C", "").strip())
return float(temp)
except ValueError:
return None
elif isinstance(temp, (int, float)):
return temp
return None
elif self.sensor_type == HDD_HEALTH:
health = disk.get("health", "未知")
if health == "未检测":
return "未检测"
return health if health != "未知" else "未知状态"
elif self.sensor_type == HDD_STATUS:
return disk.get("status", "未知")
return None
@property
def device_class(self):
if self.sensor_type == HDD_TEMP:
return SensorDeviceClass.TEMPERATURE
return None
@property
def extra_state_attributes(self):
return {
ATTR_DISK_MODEL: self.disk_info.get("model", "未知"),
ATTR_SERIAL_NO: self.disk_info.get("serial", "未知"),
ATTR_POWER_ON_HOURS: self.disk_info.get("power_on_hours", "未知"),
ATTR_TOTAL_CAPACITY: self.disk_info.get("capacity", "未知"),
ATTR_HEALTH_STATUS: self.disk_info.get("health", "未知"),
"设备ID": self.device_id,
"状态": self.disk_info.get("status", "未知")
}
class SystemSensor(CoordinatorEntity, SensorEntity):
def __init__(self, coordinator, name, unique_id, unit, icon):
super().__init__(coordinator)
self._attr_name = name
self._attr_unique_id = unique_id
self._attr_native_unit_of_measurement = unit
self._attr_icon = icon
self._attr_device_info = {
"identifiers": {(DOMAIN, DEVICE_ID_NAS)},
"name": "飞牛NAS系统监控",
"manufacturer": "飞牛"
}
self._last_uptime = None
@property
def native_value(self):
system_data = self.coordinator.data.get("system", {})
status = system_data.get("status", "unknown")
if status == "off":
return "离线"
if status == "rebooting":
return "重启中"
if status == "unknown":
return "状态未知"
try:
uptime_seconds = system_data.get("uptime_seconds", 0)
if self._last_uptime == uptime_seconds:
return self._last_value
hours = float(uptime_seconds) / 3600
value = f"已运行 {hours:.1f}小时"
self._last_value = value
self._last_uptime = uptime_seconds
return value
except (ValueError, TypeError):
return "运行中"
@property
def extra_state_attributes(self):
system_data = self.coordinator.data.get("system", {})
return {
"运行时间": system_data.get("uptime", "未知"),
"系统状态": system_data.get("status", "unknown"),
"主机地址": self.coordinator.host,
"CPU温度": system_data.get("cpu_temperature", "未知"),
"主板温度": system_data.get("motherboard_temperature", "未知")
}
class CPUTempSensor(CoordinatorEntity, SensorEntity):
def __init__(self, coordinator, name, unique_id, unit, icon):
super().__init__(coordinator)
self._attr_name = name
self._attr_unique_id = unique_id
self._attr_native_unit_of_measurement = unit
self._attr_icon = icon
self._attr_device_info = {
"identifiers": {(DOMAIN, DEVICE_ID_NAS)},
"name": "飞牛NAS系统监控",
"manufacturer": "飞牛"
}
self._attr_device_class = SensorDeviceClass.TEMPERATURE
@property
def native_value(self):
system_data = self.coordinator.data.get("system", {})
temp_str = system_data.get("cpu_temperature", "未知")
if system_data.get("status") == "off":
return None
if temp_str is None or temp_str == "未知":
return None
if isinstance(temp_str, (int, float)):
return temp_str
if "°C" in temp_str:
try:
return float(temp_str.replace("°C", "").strip())
except:
return None
return None
class MoboTempSensor(CoordinatorEntity, SensorEntity):
def __init__(self, coordinator, name, unique_id, unit, icon):
super().__init__(coordinator)
self._attr_name = name
self._attr_unique_id = unique_id
self._attr_native_unit_of_measurement = unit
self._attr_icon = icon
self._attr_device_info = {
"identifiers": {(DOMAIN, DEVICE_ID_NAS)},
"name": "飞牛NAS系统监控",
"manufacturer": "飞牛"
}
self._attr_device_class = SensorDeviceClass.TEMPERATURE
@property
def native_value(self):
system_data = self.coordinator.data.get("system", {})
temp_str = system_data.get("motherboard_temperature", "未知")
if system_data.get("status") == "off":
return None
if temp_str is None or temp_str == "未知":
return None
if isinstance(temp_str, (int, float)):
return temp_str
try:
cleaned = temp_str.lower().replace('°c', '').replace('c', '').strip()
return float(cleaned)
except (ValueError, TypeError) as e:
_LOGGER.warning("主板温度解析失败: 原始值='%s', 错误: %s", temp_str, str(e))
return None
class UPSSensor(CoordinatorEntity, SensorEntity):
def __init__(self, coordinator, name, unique_id, unit, icon, data_key, device_class=None, state_class=None):
super().__init__(coordinator)
self._attr_name = name
self._attr_unique_id = unique_id
self._attr_native_unit_of_measurement = unit
self._attr_icon = icon
self.data_key = data_key
self._attr_device_info = {
"identifiers": {(DOMAIN, "flynas_ups")},
"name": "飞牛NAS UPS",
"manufacturer": "UPS设备",
"via_device": (DOMAIN, DEVICE_ID_NAS)
}
# 设置设备类和状态类(如果提供)
if device_class:
self._attr_device_class = device_class
if state_class:
self._attr_state_class = state_class
@property
def native_value(self):
return self.coordinator.data.get(self.data_key) # 直接使用协调器的数据
@property
def extra_state_attributes(self):
attributes = {
"最后更新时间": self.coordinator.data.get("last_update", "未知"),
"UPS类型": self.coordinator.data.get("ups_type", "未知")
}
# 添加原始字符串值(如果存在)
if f"{self.data_key}_str" in self.coordinator.data:
attributes["原始值"] = self.coordinator.data[f"{self.data_key}_str"]
return attributes
class VMStatusSensor(CoordinatorEntity, SensorEntity):
"""虚拟机状态传感器"""
def __init__(self, coordinator, vm_name, vm_title, entry_id):
super().__init__(coordinator)
self.vm_name = vm_name
self.vm_title = vm_title
self._attr_name = f"{vm_title} 状态"
self._attr_unique_id = f"{entry_id}_flynas_vm_{vm_name}_status" # 使用entry_id确保唯一性
self._attr_device_info = {
"identifiers": {(DOMAIN, f"vm_{vm_name}")},
"name": vm_title,
"via_device": (DOMAIN, DEVICE_ID_NAS)
}
@property
def native_value(self):
"""返回虚拟机状态"""
for vm in self.coordinator.data.get("vms", []):
if vm["name"] == self.vm_name:
# 将状态转换为中文
state_map = {
"running": "运行中",
"shut off": "已关闭",
"paused": "已暂停",
"rebooting": "重启中",
"crashed": "崩溃"
}
return state_map.get(vm["state"], vm["state"])
return "未知"
@property
def icon(self):
"""根据状态返回图标"""
for vm in self.coordinator.data.get("vms", []):
if vm["name"] == self.vm_name:
if vm["state"] == "running":
return "mdi:server"
elif vm["state"] == "shut off":
return "mdi:server-off"
elif vm["state"] == "rebooting":
return "mdi:server-security"
return "mdi:server"