diff --git a/homeassistant/components/fibaro/sensor.py b/homeassistant/components/fibaro/sensor.py index acaa97ee2a25..88d6113ebb92 100644 --- a/homeassistant/components/fibaro/sensor.py +++ b/homeassistant/components/fibaro/sensor.py @@ -2,11 +2,13 @@ from __future__ import annotations from contextlib import suppress +from typing import Any from homeassistant.components.sensor import ( ENTITY_ID_FORMAT, SensorDeviceClass, SensorEntity, + SensorEntityDescription, SensorStateClass, ) from homeassistant.config_entries import ConfigEntry @@ -27,49 +29,73 @@ from homeassistant.util import convert from . import FIBARO_DEVICES, FibaroDevice from .const import DOMAIN -SENSOR_TYPES = { - "com.fibaro.temperatureSensor": [ - "Temperature", - None, - None, - SensorDeviceClass.TEMPERATURE, - SensorStateClass.MEASUREMENT, - ], - "com.fibaro.smokeSensor": [ - "Smoke", - CONCENTRATION_PARTS_PER_MILLION, - "mdi:fire", - None, - None, - ], - "CO2": [ - "CO2", - CONCENTRATION_PARTS_PER_MILLION, - None, - SensorDeviceClass.CO2, - SensorStateClass.MEASUREMENT, - ], - "com.fibaro.humiditySensor": [ - "Humidity", - PERCENTAGE, - None, - SensorDeviceClass.HUMIDITY, - SensorStateClass.MEASUREMENT, - ], - "com.fibaro.lightSensor": [ - "Light", - LIGHT_LUX, - None, - SensorDeviceClass.ILLUMINANCE, - SensorStateClass.MEASUREMENT, - ], - "com.fibaro.energyMeter": [ - "Energy", - ENERGY_KILO_WATT_HOUR, - None, - SensorDeviceClass.ENERGY, - SensorStateClass.TOTAL_INCREASING, - ], +# List of known sensors which represents a fibaro device +MAIN_SENSOR_TYPES: dict[str, SensorEntityDescription] = { + "com.fibaro.temperatureSensor": SensorEntityDescription( + key="com.fibaro.temperatureSensor", + name="Temperature", + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + ), + "com.fibaro.smokeSensor": SensorEntityDescription( + key="com.fibaro.smokeSensor", + name="Smoke", + native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + icon="mdi:fire", + ), + "CO2": SensorEntityDescription( + key="CO2", + name="CO2", + native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, + device_class=SensorDeviceClass.CO2, + state_class=SensorStateClass.MEASUREMENT, + ), + "com.fibaro.humiditySensor": SensorEntityDescription( + key="com.fibaro.humiditySensor", + name="Humidity", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.HUMIDITY, + state_class=SensorStateClass.MEASUREMENT, + ), + "com.fibaro.lightSensor": SensorEntityDescription( + key="com.fibaro.lightSensor", + name="Light", + native_unit_of_measurement=LIGHT_LUX, + device_class=SensorDeviceClass.ILLUMINANCE, + state_class=SensorStateClass.MEASUREMENT, + ), + "com.fibaro.energyMeter": SensorEntityDescription( + key="com.fibaro.energyMeter", + name="Energy", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), +} + +# List of additional sensors which are created based on a property +# The key is the property name +ADDITIONAL_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( + SensorEntityDescription( + key="energy", + name="Energy", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="power", + name="Power", + native_unit_of_measurement=POWER_WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), +) + +FIBARO_TO_HASS_UNIT: dict[str, str] = { + "lux": LIGHT_LUX, + "C": TEMP_CELSIUS, + "F": TEMP_FAHRENHEIT, } @@ -80,14 +106,18 @@ async def async_setup_entry( ) -> None: """Set up the Fibaro controller devices.""" entities: list[SensorEntity] = [] + for device in hass.data[DOMAIN][entry.entry_id][FIBARO_DEVICES][Platform.SENSOR]: - entities.append(FibaroSensor(device)) + entity_description = MAIN_SENSOR_TYPES.get(device.type) + + # main sensors are created even if the entity type is not known + entities.append(FibaroSensor(device, entity_description)) + for platform in (Platform.COVER, Platform.LIGHT, Platform.SENSOR, Platform.SWITCH): for device in hass.data[DOMAIN][entry.entry_id][FIBARO_DEVICES][platform]: - if "energy" in device.interfaces: - entities.append(FibaroEnergySensor(device)) - if "power" in device.interfaces: - entities.append(FibaroPowerSensor(device)) + for entity_description in ADDITIONAL_SENSOR_TYPES: + if entity_description.key in device.properties: + entities.append(FibaroAdditionalSensor(device, entity_description)) async_add_entities(entities, True) @@ -95,97 +125,51 @@ async def async_setup_entry( class FibaroSensor(FibaroDevice, SensorEntity): """Representation of a Fibaro Sensor.""" - def __init__(self, fibaro_device): + def __init__( + self, fibaro_device: Any, entity_description: SensorEntityDescription | None + ) -> None: """Initialize the sensor.""" - self.current_value = None - self.last_changed_time = None super().__init__(fibaro_device) + if entity_description is not None: + self.entity_description = entity_description self.entity_id = ENTITY_ID_FORMAT.format(self.ha_id) - if fibaro_device.type in SENSOR_TYPES: - self._unit = SENSOR_TYPES[fibaro_device.type][1] - self._icon = SENSOR_TYPES[fibaro_device.type][2] - self._device_class = SENSOR_TYPES[fibaro_device.type][3] - self._attr_state_class = SENSOR_TYPES[fibaro_device.type][4] - else: - self._unit = None - self._icon = None - self._device_class = None + + # Map unit if it was not defined in the entity description + # or there is no entity description at all with suppress(KeyError, ValueError): - if not self._unit: - if self.fibaro_device.properties.unit == "lux": - self._unit = LIGHT_LUX - elif self.fibaro_device.properties.unit == "C": - self._unit = TEMP_CELSIUS - elif self.fibaro_device.properties.unit == "F": - self._unit = TEMP_FAHRENHEIT - else: - self._unit = self.fibaro_device.properties.unit - - @property - def native_value(self): - """Return the state of the sensor.""" - return self.current_value - - @property - def native_unit_of_measurement(self): - """Return the unit of measurement of this entity, if any.""" - return self._unit - - @property - def icon(self): - """Icon to use in the frontend, if any.""" - return self._icon - - @property - def device_class(self): - """Return the device class of the sensor.""" - return self._device_class + if not self.native_unit_of_measurement: + self._attr_native_unit_of_measurement = FIBARO_TO_HASS_UNIT.get( + fibaro_device.properties.unit, fibaro_device.properties.unit + ) def update(self): """Update the state.""" with suppress(KeyError, ValueError): - self.current_value = float(self.fibaro_device.properties.value) + self._attr_native_value = float(self.fibaro_device.properties.value) -class FibaroEnergySensor(FibaroDevice, SensorEntity): - """Representation of a Fibaro Energy Sensor.""" +class FibaroAdditionalSensor(FibaroDevice, SensorEntity): + """Representation of a Fibaro Additional Sensor.""" - _attr_device_class = SensorDeviceClass.ENERGY - _attr_state_class = SensorStateClass.TOTAL_INCREASING - _attr_native_unit_of_measurement = ENERGY_KILO_WATT_HOUR - - def __init__(self, fibaro_device): + def __init__( + self, fibaro_device: Any, entity_description: SensorEntityDescription + ) -> None: """Initialize the sensor.""" super().__init__(fibaro_device) - self.entity_id = ENTITY_ID_FORMAT.format(f"{self.ha_id}_energy") - self._attr_name = f"{fibaro_device.friendly_name} Energy" - self._attr_unique_id = f"{fibaro_device.unique_id_str}_energy" + self.entity_description = entity_description - def update(self): + # To differentiate additional sensors from main sensors they need + # to get different names and ids + self.entity_id = ENTITY_ID_FORMAT.format( + f"{self.ha_id}_{entity_description.key}" + ) + self._attr_name = f"{fibaro_device.friendly_name} {entity_description.name}" + self._attr_unique_id = f"{fibaro_device.unique_id_str}_{entity_description.key}" + + def update(self) -> None: """Update the state.""" with suppress(KeyError, ValueError): self._attr_native_value = convert( - self.fibaro_device.properties.energy, float - ) - - -class FibaroPowerSensor(FibaroDevice, SensorEntity): - """Representation of a Fibaro Power Sensor.""" - - _attr_device_class = SensorDeviceClass.POWER - _attr_state_class = SensorStateClass.MEASUREMENT - _attr_native_unit_of_measurement = POWER_WATT - - def __init__(self, fibaro_device): - """Initialize the sensor.""" - super().__init__(fibaro_device) - self.entity_id = ENTITY_ID_FORMAT.format(f"{self.ha_id}_power") - self._attr_name = f"{fibaro_device.friendly_name} Power" - self._attr_unique_id = f"{fibaro_device.unique_id_str}_power" - - def update(self): - """Update the state.""" - with suppress(KeyError, ValueError): - self._attr_native_value = convert( - self.fibaro_device.properties.power, float + self.fibaro_device.properties[self.entity_description.key], + float, )