1 """Support for QNAP NAS Sensors."""
3 from __future__
import annotations
5 from datetime
import timedelta
8 from homeassistant
import config_entries
12 SensorEntityDescription,
29 from .const
import DOMAIN
30 from .coordinator
import QnapCoordinator
33 ATTR_IP =
"IP Address"
34 ATTR_MAC =
"MAC Address"
36 ATTR_MAX_SPEED =
"Max Speed"
37 ATTR_MEMORY_SIZE =
"Memory Size"
39 ATTR_PACKETS_ERR =
"Packets (Err)"
40 ATTR_SERIAL =
"Serial #"
42 ATTR_UPTIME =
"Uptime"
43 ATTR_VOLUME_SIZE =
"Volume Size"
45 _SYSTEM_MON_COND: tuple[SensorEntityDescription, ...] = (
48 translation_key=
"status",
49 entity_category=EntityCategory.DIAGNOSTIC,
53 translation_key=
"system_temp",
54 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
55 device_class=SensorDeviceClass.TEMPERATURE,
56 entity_category=EntityCategory.DIAGNOSTIC,
57 state_class=SensorStateClass.MEASUREMENT,
61 translation_key=
"uptime",
62 device_class=SensorDeviceClass.TIMESTAMP,
63 entity_category=EntityCategory.DIAGNOSTIC,
64 entity_registry_enabled_default=
False,
67 _CPU_MON_COND: tuple[SensorEntityDescription, ...] = (
70 translation_key=
"cpu_temp",
71 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
72 device_class=SensorDeviceClass.TEMPERATURE,
73 entity_category=EntityCategory.DIAGNOSTIC,
74 entity_registry_enabled_default=
False,
75 state_class=SensorStateClass.MEASUREMENT,
79 translation_key=
"cpu_usage",
80 native_unit_of_measurement=PERCENTAGE,
81 entity_category=EntityCategory.DIAGNOSTIC,
82 state_class=SensorStateClass.MEASUREMENT,
83 suggested_display_precision=0,
86 _MEMORY_MON_COND: tuple[SensorEntityDescription, ...] = (
89 translation_key=
"memory_size",
90 native_unit_of_measurement=UnitOfInformation.MEBIBYTES,
91 device_class=SensorDeviceClass.DATA_SIZE,
92 entity_category=EntityCategory.DIAGNOSTIC,
93 entity_registry_enabled_default=
False,
94 state_class=SensorStateClass.MEASUREMENT,
95 suggested_display_precision=1,
96 suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
100 translation_key=
"memory_free",
101 native_unit_of_measurement=UnitOfInformation.MEBIBYTES,
102 device_class=SensorDeviceClass.DATA_SIZE,
103 entity_category=EntityCategory.DIAGNOSTIC,
104 entity_registry_enabled_default=
False,
105 state_class=SensorStateClass.MEASUREMENT,
106 suggested_display_precision=1,
107 suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
111 translation_key=
"memory_used",
112 native_unit_of_measurement=UnitOfInformation.MEBIBYTES,
113 device_class=SensorDeviceClass.DATA_SIZE,
114 entity_category=EntityCategory.DIAGNOSTIC,
115 entity_registry_enabled_default=
False,
116 state_class=SensorStateClass.MEASUREMENT,
117 suggested_display_precision=1,
118 suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
121 key=
"memory_percent_used",
122 translation_key=
"memory_percent_used",
123 native_unit_of_measurement=PERCENTAGE,
124 entity_category=EntityCategory.DIAGNOSTIC,
125 state_class=SensorStateClass.MEASUREMENT,
126 suggested_display_precision=0,
129 _NETWORK_MON_COND: tuple[SensorEntityDescription, ...] = (
131 key=
"network_link_status",
132 translation_key=
"network_link_status",
133 entity_category=EntityCategory.DIAGNOSTIC,
137 translation_key=
"network_tx",
138 native_unit_of_measurement=UnitOfDataRate.BITS_PER_SECOND,
139 device_class=SensorDeviceClass.DATA_RATE,
140 entity_category=EntityCategory.DIAGNOSTIC,
141 entity_registry_enabled_default=
False,
142 state_class=SensorStateClass.MEASUREMENT,
143 suggested_display_precision=1,
144 suggested_unit_of_measurement=UnitOfDataRate.MEGABITS_PER_SECOND,
148 translation_key=
"network_rx",
149 native_unit_of_measurement=UnitOfDataRate.BITS_PER_SECOND,
150 device_class=SensorDeviceClass.DATA_RATE,
151 entity_category=EntityCategory.DIAGNOSTIC,
152 entity_registry_enabled_default=
False,
153 state_class=SensorStateClass.MEASUREMENT,
154 suggested_display_precision=1,
155 suggested_unit_of_measurement=UnitOfDataRate.MEGABITS_PER_SECOND,
159 translation_key=
"network_err",
160 entity_category=EntityCategory.DIAGNOSTIC,
161 entity_registry_enabled_default=
False,
162 state_class=SensorStateClass.MEASUREMENT,
165 key=
"network_max_speed",
166 translation_key=
"network_max_speed",
167 native_unit_of_measurement=UnitOfDataRate.MEGABITS_PER_SECOND,
168 device_class=SensorDeviceClass.DATA_RATE,
169 entity_category=EntityCategory.DIAGNOSTIC,
170 entity_registry_enabled_default=
False,
171 state_class=SensorStateClass.MEASUREMENT,
174 _DRIVE_MON_COND: tuple[SensorEntityDescription, ...] = (
176 key=
"drive_smart_status",
177 translation_key=
"drive_smart_status",
178 entity_category=EntityCategory.DIAGNOSTIC,
179 entity_registry_enabled_default=
False,
183 translation_key=
"drive_temp",
184 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
185 device_class=SensorDeviceClass.TEMPERATURE,
186 entity_category=EntityCategory.DIAGNOSTIC,
187 entity_registry_enabled_default=
False,
188 state_class=SensorStateClass.MEASUREMENT,
191 _VOLUME_MON_COND: tuple[SensorEntityDescription, ...] = (
193 key=
"volume_size_total",
194 translation_key=
"volume_size_total",
195 native_unit_of_measurement=UnitOfInformation.BYTES,
196 device_class=SensorDeviceClass.DATA_SIZE,
197 entity_category=EntityCategory.DIAGNOSTIC,
198 entity_registry_enabled_default=
False,
199 state_class=SensorStateClass.MEASUREMENT,
200 suggested_display_precision=1,
201 suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
204 key=
"volume_size_used",
205 translation_key=
"volume_size_used",
206 native_unit_of_measurement=UnitOfInformation.BYTES,
207 device_class=SensorDeviceClass.DATA_SIZE,
208 entity_category=EntityCategory.DIAGNOSTIC,
209 entity_registry_enabled_default=
False,
210 state_class=SensorStateClass.MEASUREMENT,
211 suggested_display_precision=1,
212 suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
215 key=
"volume_size_free",
216 translation_key=
"volume_size_free",
217 native_unit_of_measurement=UnitOfInformation.BYTES,
218 device_class=SensorDeviceClass.DATA_SIZE,
219 entity_category=EntityCategory.DIAGNOSTIC,
220 entity_registry_enabled_default=
False,
221 state_class=SensorStateClass.MEASUREMENT,
222 suggested_display_precision=1,
223 suggested_unit_of_measurement=UnitOfInformation.GIBIBYTES,
226 key=
"volume_percentage_used",
227 translation_key=
"volume_percentage_used",
228 native_unit_of_measurement=PERCENTAGE,
229 entity_category=EntityCategory.DIAGNOSTIC,
230 state_class=SensorStateClass.MEASUREMENT,
231 suggested_display_precision=0,
235 SENSOR_KEYS: list[str] = [
251 async_add_entities: AddEntitiesCallback,
255 await coordinator.async_refresh()
256 if not coordinator.last_update_success:
257 raise PlatformNotReady
258 uid = config_entry.unique_id
259 assert uid
is not None
260 sensors: list[QNAPSensor] = []
265 for description
in _SYSTEM_MON_COND
270 [
QNAPCPUSensor(coordinator, description, uid)
for description
in _CPU_MON_COND]
276 for description
in _MEMORY_MON_COND
284 for nic
in coordinator.data[
"system_stats"][
"nics"]
285 for description
in _NETWORK_MON_COND
293 for drive
in coordinator.data[
"smart_drive_health"]
294 for description
in _DRIVE_MON_COND
302 for volume
in coordinator.data[
"volumes"]
303 for description
in _VOLUME_MON_COND
310 """Base class for a QNAP sensor."""
312 _attr_has_entity_name =
True
316 coordinator: QnapCoordinator,
317 description: SensorEntityDescription,
319 monitor_device: str |
None =
None,
321 """Initialize the sensor."""
324 self.
device_namedevice_name = self.coordinator.data[
"system_stats"][
"system"][
"name"]
328 self.
_attr_unique_id_attr_unique_id = f
"{self._attr_unique_id}_{monitor_device}"
331 identifiers={(DOMAIN, unique_id)},
332 serial_number=unique_id,
334 model=self.coordinator.data[
"system_stats"][
"system"][
"model"],
335 sw_version=self.coordinator.data[
"system_stats"][
"firmware"][
"version"],
341 """A QNAP sensor that monitors CPU stats."""
345 """Return the state of the sensor."""
347 return self.coordinator.data[
"system_stats"][
"cpu"][
"temp_c"]
349 return self.coordinator.data[
"system_stats"][
"cpu"][
"usage_percent"]
355 """A QNAP sensor that monitors memory stats."""
359 """Return the state of the sensor."""
360 free =
float(self.coordinator.data[
"system_stats"][
"memory"][
"free"])
364 total =
float(self.coordinator.data[
"system_stats"][
"memory"][
"total"])
373 return used / total * 100
379 """A QNAP sensor that monitors network stats."""
385 """Return the state of the sensor."""
386 nic = self.coordinator.data[
"system_stats"][
"nics"][self.
monitor_devicemonitor_device]
388 return nic[
"link_status"]
391 return nic[
"max_speed"]
394 return nic[
"err_packets"]
396 data = self.coordinator.data[
"bandwidth"][self.
monitor_devicemonitor_device]
407 """A QNAP sensor that monitors overall system health."""
411 """Return the state of the sensor."""
413 return self.coordinator.data[
"system_health"]
416 return int(self.coordinator.data[
"system_stats"][
"system"][
"temp_c"])
419 uptime = self.coordinator.data[
"system_stats"][
"uptime"]
422 hours=uptime[
"hours"],
423 minutes=uptime[
"minutes"],
424 seconds=uptime[
"seconds"],
426 return dt_util.now() - uptime_duration
432 """A QNAP sensor that monitors HDD/SSD drive stats."""
438 """Return the state of the sensor."""
439 data = self.coordinator.data[
"smart_drive_health"][self.
monitor_devicemonitor_device]
442 return data[
"health"]
445 return int(data[
"temp_c"])
if data[
"temp_c"]
is not None else 0
451 """Return the state attributes."""
452 if self.coordinator.data:
453 data = self.coordinator.data[
"smart_drive_health"][self.
monitor_devicemonitor_device]
455 ATTR_DRIVE: data[
"drive_number"],
456 ATTR_MODEL: data[
"model"],
457 ATTR_SERIAL: data[
"serial"],
458 ATTR_TYPE: data[
"type"],
464 """A QNAP sensor that monitors storage volume stats."""
470 """Return the state of the sensor."""
471 data = self.coordinator.data[
"volumes"][self.
monitor_devicemonitor_device]
473 free_gb =
int(data[
"free_size"])
477 total_gb =
int(data[
"total_size"])
481 used_gb = total_gb - free_gb
486 return used_gb / total_gb * 100
dict[str, Any]|None extra_state_attributes(self)
_attr_translation_placeholders
None __init__(self, QnapCoordinator coordinator, SensorEntityDescription description, str unique_id, str|None monitor_device=None)
None async_setup_entry(HomeAssistant hass, config_entries.ConfigEntry config_entry, AddEntitiesCallback async_add_entities)