Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 194 additions & 12 deletions homeassistant/components/qnap_qsw/sensor.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
"""Support for the QNAP QSW sensors."""
from __future__ import annotations

from dataclasses import dataclass
from dataclasses import dataclass, replace
from typing import Final

from aioqsw.const import (
QSD_FAN1_SPEED,
QSD_FAN2_SPEED,
QSD_LACP_PORTS,
QSD_LINK,
QSD_PORT_NUM,
QSD_PORTS,
QSD_PORTS_STATISTICS,
QSD_PORTS_STATUS,
QSD_RX_ERRORS,
QSD_RX_OCTETS,
QSD_RX_SPEED,
QSD_SPEED,
QSD_SYSTEM_BOARD,
QSD_SYSTEM_SENSOR,
QSD_SYSTEM_TIME,
Expand Down Expand Up @@ -43,14 +46,16 @@

from .const import ATTR_MAX, DOMAIN, QSW_COORD_DATA, RPM
from .coordinator import QswDataCoordinator
from .entity import QswEntityDescription, QswSensorEntity
from .entity import QswEntityDescription, QswEntityType, QswSensorEntity


@dataclass
class QswSensorEntityDescription(SensorEntityDescription, QswEntityDescription):
"""A class that describes QNAP QSW sensor entities."""

attributes: dict[str, list[str]] | None = None
qsw_type: QswEntityType | None = None
sep_key: str = "_"


SENSOR_TYPES: Final[tuple[QswSensorEntityDescription, ...]] = (
Expand Down Expand Up @@ -152,20 +157,195 @@ class QswSensorEntityDescription(SensorEntityDescription, QswEntityDescription):
),
)

LACP_PORT_SENSOR_TYPES: Final[tuple[QswSensorEntityDescription, ...]] = (
QswSensorEntityDescription(
device_class=SensorDeviceClass.DATA_RATE,
entity_registry_enabled_default=False,
icon="mdi:speedometer",
key=QSD_PORTS_STATUS,
name="Link Speed",
native_unit_of_measurement=UnitOfDataRate.MEGABITS_PER_SECOND,
qsw_type=QswEntityType.LACP_PORT,
state_class=SensorStateClass.MEASUREMENT,
subkey=QSD_SPEED,
),
QswSensorEntityDescription(
entity_registry_enabled_default=False,
icon="mdi:download-network",
key=QSD_PORTS_STATISTICS,
name="RX",
native_unit_of_measurement=UnitOfInformation.BYTES,
qsw_type=QswEntityType.LACP_PORT,
state_class=SensorStateClass.TOTAL_INCREASING,
subkey=QSD_RX_OCTETS,
),
QswSensorEntityDescription(
entity_registry_enabled_default=False,
icon="mdi:close-network",
key=QSD_PORTS_STATISTICS,
entity_category=EntityCategory.DIAGNOSTIC,
name="RX Errors",
qsw_type=QswEntityType.LACP_PORT,
state_class=SensorStateClass.TOTAL_INCREASING,
subkey=QSD_RX_ERRORS,
),
QswSensorEntityDescription(
device_class=SensorDeviceClass.DATA_RATE,
entity_registry_enabled_default=False,
icon="mdi:download-network",
key=QSD_PORTS_STATISTICS,
name="RX Speed",
native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
qsw_type=QswEntityType.LACP_PORT,
state_class=SensorStateClass.MEASUREMENT,
subkey=QSD_RX_SPEED,
),
QswSensorEntityDescription(
entity_registry_enabled_default=False,
icon="mdi:upload-network",
key=QSD_PORTS_STATISTICS,
name="TX",
native_unit_of_measurement=UnitOfInformation.BYTES,
qsw_type=QswEntityType.LACP_PORT,
state_class=SensorStateClass.TOTAL_INCREASING,
subkey=QSD_TX_OCTETS,
),
QswSensorEntityDescription(
device_class=SensorDeviceClass.DATA_RATE,
entity_registry_enabled_default=False,
icon="mdi:upload-network",
key=QSD_PORTS_STATISTICS,
name="TX Speed",
native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
qsw_type=QswEntityType.LACP_PORT,
state_class=SensorStateClass.MEASUREMENT,
subkey=QSD_TX_SPEED,
),
)

PORT_SENSOR_TYPES: Final[tuple[QswSensorEntityDescription, ...]] = (
QswSensorEntityDescription(
device_class=SensorDeviceClass.DATA_RATE,
entity_registry_enabled_default=False,
icon="mdi:speedometer",
key=QSD_PORTS_STATUS,
name="Link Speed",
native_unit_of_measurement=UnitOfDataRate.MEGABITS_PER_SECOND,
qsw_type=QswEntityType.PORT,
state_class=SensorStateClass.MEASUREMENT,
subkey=QSD_SPEED,
),
QswSensorEntityDescription(
entity_registry_enabled_default=False,
icon="mdi:download-network",
key=QSD_PORTS_STATISTICS,
name="RX",
native_unit_of_measurement=UnitOfInformation.BYTES,
qsw_type=QswEntityType.PORT,
state_class=SensorStateClass.TOTAL_INCREASING,
subkey=QSD_RX_OCTETS,
),
QswSensorEntityDescription(
entity_registry_enabled_default=False,
icon="mdi:close-network",
key=QSD_PORTS_STATISTICS,
entity_category=EntityCategory.DIAGNOSTIC,
name="RX Errors",
qsw_type=QswEntityType.PORT,
state_class=SensorStateClass.TOTAL_INCREASING,
subkey=QSD_RX_ERRORS,
),
QswSensorEntityDescription(
device_class=SensorDeviceClass.DATA_RATE,
entity_registry_enabled_default=False,
icon="mdi:download-network",
key=QSD_PORTS_STATISTICS,
name="RX Speed",
native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
qsw_type=QswEntityType.PORT,
state_class=SensorStateClass.MEASUREMENT,
subkey=QSD_RX_SPEED,
),
QswSensorEntityDescription(
entity_registry_enabled_default=False,
icon="mdi:upload-network",
key=QSD_PORTS_STATISTICS,
name="TX",
native_unit_of_measurement=UnitOfInformation.BYTES,
qsw_type=QswEntityType.PORT,
state_class=SensorStateClass.TOTAL_INCREASING,
subkey=QSD_TX_OCTETS,
),
QswSensorEntityDescription(
device_class=SensorDeviceClass.DATA_RATE,
entity_registry_enabled_default=False,
icon="mdi:upload-network",
key=QSD_PORTS_STATISTICS,
name="TX Speed",
native_unit_of_measurement=UnitOfDataRate.BYTES_PER_SECOND,
qsw_type=QswEntityType.PORT,
state_class=SensorStateClass.MEASUREMENT,
subkey=QSD_TX_SPEED,
),
)


async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Add QNAP QSW sensors from a config_entry."""
coordinator: QswDataCoordinator = hass.data[DOMAIN][entry.entry_id][QSW_COORD_DATA]
async_add_entities(
QswSensor(coordinator, description, entry)
for description in SENSOR_TYPES

entities: list[QswSensor] = []

for description in SENSOR_TYPES:
if (
description.key in coordinator.data
and description.subkey in coordinator.data[description.key]
)
)
):
entities.append(QswSensor(coordinator, description, entry))

for description in LACP_PORT_SENSOR_TYPES:
if (
description.key not in coordinator.data
or QSD_LACP_PORTS not in coordinator.data[description.key]
):
continue

for port_id, port_values in coordinator.data[description.key][
QSD_LACP_PORTS
].items():
if description.subkey not in port_values:
continue

_desc = replace(
description,
sep_key=f"_lacp_port_{port_id}_",
name=f"LACP Port {port_id} {description.name}",
)
entities.append(QswSensor(coordinator, _desc, entry, port_id))

for description in PORT_SENSOR_TYPES:
if (
description.key not in coordinator.data
or QSD_PORTS not in coordinator.data[description.key]
):
continue

for port_id, port_values in coordinator.data[description.key][
QSD_PORTS
].items():
if description.subkey not in port_values:
continue

_desc = replace(
description,
sep_key=f"_port_{port_id}_",
name=f"Port {port_id} {description.name}",
)
entities.append(QswSensor(coordinator, _desc, entry, port_id))

async_add_entities(entities)


class QswSensor(QswSensorEntity, SensorEntity):
Expand All @@ -178,21 +358,23 @@ def __init__(
coordinator: QswDataCoordinator,
description: QswSensorEntityDescription,
entry: ConfigEntry,
type_id: int | None = None,
) -> None:
"""Initialize."""
super().__init__(coordinator, entry)
super().__init__(coordinator, entry, type_id)

self._attr_name = f"{self.product} {description.name}"
self._attr_unique_id = (
f"{entry.unique_id}_{description.key}_{description.subkey}"
)
self._attr_unique_id = f"{entry.unique_id}_{description.key}{description.sep_key}{description.subkey}"
Comment thread
Noltari marked this conversation as resolved.
self.entity_description = description
self._async_update_attrs()

@callback
def _async_update_attrs(self) -> None:
"""Update sensor attributes."""
value = self.get_device_value(
self.entity_description.key, self.entity_description.subkey
self.entity_description.key,
self.entity_description.subkey,
self.entity_description.qsw_type,
)
self._attr_native_value = value
super()._async_update_attrs()
Loading