mirror of
https://github.com/anxms/fn_nas.git
synced 2025-10-15 17:48:29 +00:00
update all
This commit is contained in:
497
custom_components/fn_nas/sensor.py
Normal file
497
custom_components/fn_nas/sensor.py
Normal 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"
|
Reference in New Issue
Block a user