1 """Support for the QNAP QSW sensors."""
3 from __future__
import annotations
5 from collections.abc
import Callable
6 from dataclasses
import dataclass, replace
7 from datetime
import datetime
8 from typing
import Final
10 from aioqsw.const
import (
39 SensorEntityDescription,
56 from .const
import ATTR_MAX, DOMAIN, QSW_COORD_DATA, RPM
57 from .coordinator
import QswDataCoordinator
58 from .entity
import QswEntityDescription, QswEntityType, QswSensorEntity
61 @dataclass(frozen=True)
63 """A class that describes QNAP QSW sensor entities."""
65 attributes: dict[str, list[str]] |
None =
None
66 qsw_type: QswEntityType |
None =
None
68 value_fn: Callable[[str], datetime | StateType] =
lambda value: value
72 translation_key=
"uptime",
74 entity_category=EntityCategory.DIAGNOSTIC,
75 native_unit_of_measurement=UnitOfTime.SECONDS,
76 state_class=SensorStateClass.TOTAL_INCREASING,
77 subkey=QSD_UPTIME_SECONDS,
81 SENSOR_TYPES: Final[tuple[QswSensorEntityDescription, ...]] = (
83 translation_key=
"fan_1_speed",
84 key=QSD_SYSTEM_SENSOR,
85 native_unit_of_measurement=RPM,
86 state_class=SensorStateClass.MEASUREMENT,
87 subkey=QSD_FAN1_SPEED,
90 translation_key=
"fan_2_speed",
91 key=QSD_SYSTEM_SENSOR,
92 native_unit_of_measurement=RPM,
93 state_class=SensorStateClass.MEASUREMENT,
94 subkey=QSD_FAN2_SPEED,
97 translation_key=
"ports",
99 ATTR_MAX: [QSD_SYSTEM_BOARD, QSD_PORT_NUM],
101 entity_registry_enabled_default=
False,
102 key=QSD_PORTS_STATUS,
103 state_class=SensorStateClass.MEASUREMENT,
107 entity_registry_enabled_default=
False,
108 translation_key=
"rx",
109 device_class=SensorDeviceClass.DATA_SIZE,
110 key=QSD_PORTS_STATISTICS,
111 native_unit_of_measurement=UnitOfInformation.BYTES,
112 state_class=SensorStateClass.TOTAL_INCREASING,
113 subkey=QSD_RX_OCTETS,
116 entity_registry_enabled_default=
False,
117 translation_key=
"rx_errors",
118 key=QSD_PORTS_STATISTICS,
119 entity_category=EntityCategory.DIAGNOSTIC,
120 state_class=SensorStateClass.TOTAL_INCREASING,
121 subkey=QSD_RX_ERRORS,
124 entity_registry_enabled_default=
False,
125 translation_key=
"rx_speed",
126 device_class=SensorDeviceClass.DATA_RATE,
127 key=QSD_PORTS_STATISTICS,
128 native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
129 state_class=SensorStateClass.MEASUREMENT,
134 ATTR_MAX: [QSD_SYSTEM_SENSOR, QSD_TEMP_MAX],
136 device_class=SensorDeviceClass.TEMPERATURE,
137 key=QSD_SYSTEM_SENSOR,
138 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
139 state_class=SensorStateClass.MEASUREMENT,
143 entity_registry_enabled_default=
False,
144 translation_key=
"tx",
145 device_class=SensorDeviceClass.DATA_SIZE,
146 key=QSD_PORTS_STATISTICS,
147 native_unit_of_measurement=UnitOfInformation.BYTES,
148 state_class=SensorStateClass.TOTAL_INCREASING,
149 subkey=QSD_TX_OCTETS,
152 entity_registry_enabled_default=
False,
153 translation_key=
"tx_speed",
154 device_class=SensorDeviceClass.DATA_RATE,
155 key=QSD_PORTS_STATISTICS,
156 native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
157 state_class=SensorStateClass.MEASUREMENT,
161 translation_key=
"uptime_timestamp",
163 device_class=SensorDeviceClass.TIMESTAMP,
164 entity_category=EntityCategory.DIAGNOSTIC,
165 subkey=QSD_UPTIME_TIMESTAMP,
166 value_fn=dt_util.parse_datetime,
170 LACP_PORT_SENSOR_TYPES: Final[tuple[QswSensorEntityDescription, ...]] = (
172 device_class=SensorDeviceClass.DATA_RATE,
173 entity_registry_enabled_default=
False,
174 icon=
"mdi:speedometer",
175 key=QSD_PORTS_STATUS,
177 native_unit_of_measurement=UnitOfDataRate.MEGABITS_PER_SECOND,
178 qsw_type=QswEntityType.LACP_PORT,
179 state_class=SensorStateClass.MEASUREMENT,
183 entity_registry_enabled_default=
False,
184 icon=
"mdi:download-network",
185 key=QSD_PORTS_STATISTICS,
187 native_unit_of_measurement=UnitOfInformation.BYTES,
188 qsw_type=QswEntityType.LACP_PORT,
189 state_class=SensorStateClass.TOTAL_INCREASING,
190 subkey=QSD_RX_OCTETS,
193 entity_registry_enabled_default=
False,
194 icon=
"mdi:close-network",
195 key=QSD_PORTS_STATISTICS,
196 entity_category=EntityCategory.DIAGNOSTIC,
198 qsw_type=QswEntityType.LACP_PORT,
199 state_class=SensorStateClass.TOTAL_INCREASING,
200 subkey=QSD_RX_ERRORS,
203 device_class=SensorDeviceClass.DATA_RATE,
204 entity_registry_enabled_default=
False,
205 icon=
"mdi:download-network",
206 key=QSD_PORTS_STATISTICS,
208 native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
209 qsw_type=QswEntityType.LACP_PORT,
210 state_class=SensorStateClass.MEASUREMENT,
214 entity_registry_enabled_default=
False,
215 icon=
"mdi:upload-network",
216 key=QSD_PORTS_STATISTICS,
218 native_unit_of_measurement=UnitOfInformation.BYTES,
219 qsw_type=QswEntityType.LACP_PORT,
220 state_class=SensorStateClass.TOTAL_INCREASING,
221 subkey=QSD_TX_OCTETS,
224 device_class=SensorDeviceClass.DATA_RATE,
225 entity_registry_enabled_default=
False,
226 icon=
"mdi:upload-network",
227 key=QSD_PORTS_STATISTICS,
229 native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
230 qsw_type=QswEntityType.LACP_PORT,
231 state_class=SensorStateClass.MEASUREMENT,
236 PORT_SENSOR_TYPES: Final[tuple[QswSensorEntityDescription, ...]] = (
238 device_class=SensorDeviceClass.DATA_RATE,
239 entity_registry_enabled_default=
False,
240 icon=
"mdi:speedometer",
241 key=QSD_PORTS_STATUS,
243 native_unit_of_measurement=UnitOfDataRate.MEGABITS_PER_SECOND,
244 qsw_type=QswEntityType.PORT,
245 state_class=SensorStateClass.MEASUREMENT,
249 entity_registry_enabled_default=
False,
250 icon=
"mdi:download-network",
251 key=QSD_PORTS_STATISTICS,
253 native_unit_of_measurement=UnitOfInformation.BYTES,
254 qsw_type=QswEntityType.PORT,
255 state_class=SensorStateClass.TOTAL_INCREASING,
256 subkey=QSD_RX_OCTETS,
259 entity_registry_enabled_default=
False,
260 icon=
"mdi:close-network",
261 key=QSD_PORTS_STATISTICS,
262 entity_category=EntityCategory.DIAGNOSTIC,
264 qsw_type=QswEntityType.PORT,
265 state_class=SensorStateClass.TOTAL_INCREASING,
266 subkey=QSD_RX_ERRORS,
269 device_class=SensorDeviceClass.DATA_RATE,
270 entity_registry_enabled_default=
False,
271 icon=
"mdi:download-network",
272 key=QSD_PORTS_STATISTICS,
274 native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
275 qsw_type=QswEntityType.PORT,
276 state_class=SensorStateClass.MEASUREMENT,
280 entity_registry_enabled_default=
False,
281 icon=
"mdi:upload-network",
282 key=QSD_PORTS_STATISTICS,
284 native_unit_of_measurement=UnitOfInformation.BYTES,
285 qsw_type=QswEntityType.PORT,
286 state_class=SensorStateClass.TOTAL_INCREASING,
287 subkey=QSD_TX_OCTETS,
290 device_class=SensorDeviceClass.DATA_RATE,
291 entity_registry_enabled_default=
False,
292 icon=
"mdi:upload-network",
293 key=QSD_PORTS_STATISTICS,
295 native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
296 qsw_type=QswEntityType.PORT,
297 state_class=SensorStateClass.MEASUREMENT,
304 hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
306 """Add QNAP QSW sensors from a config_entry."""
307 coordinator: QswDataCoordinator = hass.data[DOMAIN][entry.entry_id][QSW_COORD_DATA]
309 entities: list[QswSensor] = [
310 QswSensor(coordinator, description, entry)
311 for description
in SENSOR_TYPES
313 description.key
in coordinator.data
314 and description.subkey
in coordinator.data[description.key]
318 for description
in LACP_PORT_SENSOR_TYPES:
320 description.key
not in coordinator.data
321 or QSD_LACP_PORTS
not in coordinator.data[description.key]
325 for port_id, port_values
in coordinator.data[description.key][
328 if description.subkey
not in port_values:
333 sep_key=f
"_lacp_port_{port_id}_",
334 name=f
"LACP Port {port_id} {description.name}",
336 entities.append(
QswSensor(coordinator, _desc, entry, port_id))
338 for description
in PORT_SENSOR_TYPES:
340 description.key
not in coordinator.data
341 or QSD_PORTS
not in coordinator.data[description.key]
345 for port_id, port_values
in coordinator.data[description.key][
348 if description.subkey
not in port_values:
353 sep_key=f
"_port_{port_id}_",
354 name=f
"Port {port_id} {description.name}",
356 entities.append(
QswSensor(coordinator, _desc, entry, port_id))
359 entity_reg = er.async_get(hass)
360 reg_entities = er.async_entries_for_config_entry(entity_reg, entry.entry_id)
361 for entity
in reg_entities:
362 if entity.domain ==
"sensor" and entity.unique_id.endswith(
363 (
"_uptime",
"_uptime_seconds")
365 entity_id = entity.entity_id
368 entity_reg.async_remove(entity_id)
372 DEPRECATED_UPTIME_SECONDS.key
in coordinator.data
373 and DEPRECATED_UPTIME_SECONDS.subkey
374 in coordinator.data[DEPRECATED_UPTIME_SECONDS.key]
377 QswSensor(coordinator, DEPRECATED_UPTIME_SECONDS, entry)
383 for item
in entity_automations + entity_scripts:
384 ir.async_create_issue(
387 f
"uptime_seconds_deprecated_{entity_id}_{item}",
388 breaks_in_ha_version=
"2025.5.0",
390 severity=ir.IssueSeverity.WARNING,
391 translation_key=
"uptime_seconds_deprecated",
392 translation_placeholders={
402 """Define a QNAP QSW sensor."""
404 entity_description: QswSensorEntityDescription
408 coordinator: QswDataCoordinator,
409 description: QswSensorEntityDescription,
411 type_id: int |
None =
None,
414 super().
__init__(coordinator, entry, type_id)
416 if description.name == UNDEFINED:
419 self.
_attr_name_attr_name = f
"{self.product} {description.name}"
421 f
"{entry.unique_id}_{description.key}"
422 f
"{description.sep_key}{description.subkey}"
429 """Update sensor attributes."""
Any get_device_value(self, str key, str subkey, QswEntityType|None qsw_type=None)
None _async_update_attrs(self)
None _async_update_attrs(self)
None __init__(self, QswDataCoordinator coordinator, QswSensorEntityDescription description, ConfigEntry entry, int|None type_id=None)
list[str] automations_with_entity(HomeAssistant hass, str entity_id)
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
list[str] scripts_with_entity(HomeAssistant hass, str entity_id)