"""SFR Box sensor platform.""" from collections.abc import Callable from dataclasses import dataclass from sfrbox_api.models import DslInfo, SystemInfo from homeassistant.components.sensor import ( SensorDeviceClass, SensorEntity, SensorEntityDescription, SensorStateClass, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import SIGNAL_STRENGTH_DECIBELS, UnitOfDataRate from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import StateType from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN from .coordinator import SFRDataUpdateCoordinator from .models import DomainData @dataclass class SFRBoxSensorMixin: """Mixin for SFR Box sensors.""" value_fn: Callable[[DslInfo], StateType] @dataclass class SFRBoxSensorEntityDescription(SensorEntityDescription, SFRBoxSensorMixin): """Description for SFR Box sensors.""" SENSOR_TYPES: tuple[SFRBoxSensorEntityDescription, ...] = ( SFRBoxSensorEntityDescription( key="linemode", name="Line mode", entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, value_fn=lambda x: x.linemode, ), SFRBoxSensorEntityDescription( key="counter", name="Counter", entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, value_fn=lambda x: x.counter, ), SFRBoxSensorEntityDescription( key="crc", name="CRC", entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, value_fn=lambda x: x.crc, ), SFRBoxSensorEntityDescription( key="noise_down", name="Noise down", device_class=SensorDeviceClass.SIGNAL_STRENGTH, entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, state_class=SensorStateClass.MEASUREMENT, value_fn=lambda x: x.noise_down, ), SFRBoxSensorEntityDescription( key="noise_up", name="Noise up", device_class=SensorDeviceClass.SIGNAL_STRENGTH, entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, state_class=SensorStateClass.MEASUREMENT, value_fn=lambda x: x.noise_up, ), SFRBoxSensorEntityDescription( key="attenuation_down", name="Attenuation down", device_class=SensorDeviceClass.SIGNAL_STRENGTH, entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, state_class=SensorStateClass.MEASUREMENT, value_fn=lambda x: x.attenuation_down, ), SFRBoxSensorEntityDescription( key="attenuation_up", name="Attenuation up", device_class=SensorDeviceClass.SIGNAL_STRENGTH, entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, state_class=SensorStateClass.MEASUREMENT, value_fn=lambda x: x.attenuation_up, ), SFRBoxSensorEntityDescription( key="rate_down", name="Rate down", device_class=SensorDeviceClass.DATA_RATE, native_unit_of_measurement=UnitOfDataRate.KILOBITS_PER_SECOND, state_class=SensorStateClass.MEASUREMENT, value_fn=lambda x: x.rate_down, ), SFRBoxSensorEntityDescription( key="rate_up", name="Rate up", device_class=SensorDeviceClass.DATA_RATE, native_unit_of_measurement=UnitOfDataRate.KILOBITS_PER_SECOND, state_class=SensorStateClass.MEASUREMENT, value_fn=lambda x: x.rate_up, ), SFRBoxSensorEntityDescription( key="line_status", name="Line status", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, options=[ "no_defect", "of_frame", "loss_of_signal", "loss_of_power", "loss_of_signal_quality", "unknown", ], translation_key="line_status", value_fn=lambda x: x.line_status.lower().replace(" ", "_"), ), SFRBoxSensorEntityDescription( key="training", name="Training", device_class=SensorDeviceClass.ENUM, entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, options=[ "idle", "g_994_training", "g_992_started", "g_922_channel_analysis", "g_992_message_exchange", "g_993_started", "g_993_channel_analysis", "g_993_message_exchange", "showtime", "unknown", ], translation_key="training", value_fn=lambda x: x.training.lower().replace(" ", "_").replace(".", "_"), ), ) async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: """Set up the sensors.""" data: DomainData = hass.data[DOMAIN][entry.entry_id] entities = [ SFRBoxSensor(data.dsl, description, data.system.data) for description in SENSOR_TYPES ] async_add_entities(entities) class SFRBoxSensor(CoordinatorEntity[SFRDataUpdateCoordinator[DslInfo]], SensorEntity): """SFR Box sensor.""" entity_description: SFRBoxSensorEntityDescription _attr_has_entity_name = True def __init__( self, coordinator: SFRDataUpdateCoordinator[DslInfo], description: SFRBoxSensorEntityDescription, system_info: SystemInfo, ) -> None: """Initialize the sensor.""" super().__init__(coordinator) self.entity_description = description self._attr_unique_id = f"{system_info.mac_addr}_dsl_{description.key}" self._attr_device_info = {"identifiers": {(DOMAIN, system_info.mac_addr)}} @property def native_value(self) -> StateType: """Return the native value of the device.""" return self.entity_description.value_fn(self.coordinator.data)