diff --git a/homeassistant/components/homekit_controller/number.py b/homeassistant/components/homekit_controller/number.py index 79130bfcef7..beb0ffa7fa5 100644 --- a/homeassistant/components/homekit_controller/number.py +++ b/homeassistant/components/homekit_controller/number.py @@ -4,22 +4,26 @@ Support for Homekit number ranges. These are mostly used where a HomeKit accessory exposes additional non-standard characteristics that don't map to a Home Assistant feature. """ +from __future__ import annotations + from aiohomekit.model.characteristics import Characteristic, CharacteristicsTypes -from homeassistant.components.number import NumberEntity +from homeassistant.components.number import NumberEntity, NumberEntityDescription from homeassistant.core import callback from . import KNOWN_DEVICES, CharacteristicEntity -NUMBER_ENTITIES = { - CharacteristicsTypes.Vendor.VOCOLINC_HUMIDIFIER_SPRAY_LEVEL: { - "name": "Spray Quantity", - "icon": "mdi:water", - }, - CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION: { - "name": "Elevation", - "icon": "mdi:elevation-rise", - }, +NUMBER_ENTITIES: dict[str, NumberEntityDescription] = { + CharacteristicsTypes.Vendor.VOCOLINC_HUMIDIFIER_SPRAY_LEVEL: NumberEntityDescription( + key=CharacteristicsTypes.Vendor.VOCOLINC_HUMIDIFIER_SPRAY_LEVEL, + name="Spray Quantity", + icon="mdi:water", + ), + CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION: NumberEntityDescription( + key=CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION, + name="Elevation", + icon="mdi:elevation-rise", + ), } @@ -30,11 +34,10 @@ async def async_setup_entry(hass, config_entry, async_add_entities): @callback def async_add_characteristic(char: Characteristic): - kwargs = NUMBER_ENTITIES.get(char.type) - if not kwargs: + if not (description := NUMBER_ENTITIES.get(char.type)): return False info = {"aid": char.service.accessory.aid, "iid": char.service.iid} - async_add_entities([HomeKitNumber(conn, info, char, **kwargs)], True) + async_add_entities([HomeKitNumber(conn, info, char, description)], True) return True conn.add_char_factory(async_add_characteristic) @@ -48,32 +51,16 @@ class HomeKitNumber(CharacteristicEntity, NumberEntity): conn, info, char, - device_class=None, - icon=None, - name=None, - **kwargs, + description: NumberEntityDescription, ): """Initialise a HomeKit number control.""" - self._device_class = device_class - self._icon = icon - self._name = name - + self.entity_description = description super().__init__(conn, info, char) def get_characteristic_types(self): """Define the homekit characteristics the entity is tracking.""" return [self._char.type] - @property - def device_class(self): - """Return type of sensor.""" - return self._device_class - - @property - def icon(self): - """Return the sensor icon.""" - return self._icon - @property def min_value(self) -> float: """Return the minimum value.""" diff --git a/homeassistant/components/homekit_controller/sensor.py b/homeassistant/components/homekit_controller/sensor.py index aaddadd2c53..bc0ed0455fa 100644 --- a/homeassistant/components/homekit_controller/sensor.py +++ b/homeassistant/components/homekit_controller/sensor.py @@ -1,8 +1,17 @@ """Support for Homekit sensors.""" +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass + from aiohomekit.model.characteristics import Characteristic, CharacteristicsTypes from aiohomekit.model.services import ServicesTypes -from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity +from homeassistant.components.sensor import ( + STATE_CLASS_MEASUREMENT, + SensorEntity, + SensorEntityDescription, +) from homeassistant.const import ( CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, CONCENTRATION_PARTS_PER_MILLION, @@ -32,92 +41,112 @@ from . import KNOWN_DEVICES, CharacteristicEntity, HomeKitEntity CO2_ICON = "mdi:molecule-co2" -SIMPLE_SENSOR = { - CharacteristicsTypes.Vendor.EVE_ENERGY_WATT: { - "name": "Real Time Energy", - "device_class": DEVICE_CLASS_POWER, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": POWER_WATT, - }, - CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY: { - "name": "Real Time Energy", - "device_class": DEVICE_CLASS_POWER, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": POWER_WATT, - }, - CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY_2: { - "name": "Real Time Energy", - "device_class": DEVICE_CLASS_POWER, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": POWER_WATT, - }, - CharacteristicsTypes.Vendor.EVE_DEGREE_AIR_PRESSURE: { - "name": "Air Pressure", - "device_class": DEVICE_CLASS_PRESSURE, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": PRESSURE_HPA, - }, - CharacteristicsTypes.TEMPERATURE_CURRENT: { - "name": "Current Temperature", - "device_class": DEVICE_CLASS_TEMPERATURE, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": TEMP_CELSIUS, +@dataclass +class HomeKitSensorEntityDescription(SensorEntityDescription): + """Describes Homekit sensor.""" + + probe: Callable[[Characteristic], bool] | None = None + + +SIMPLE_SENSOR: dict[str, HomeKitSensorEntityDescription] = { + CharacteristicsTypes.Vendor.EVE_ENERGY_WATT: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.Vendor.EVE_ENERGY_WATT, + name="Real Time Energy", + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=POWER_WATT, + ), + CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY, + name="Real Time Energy", + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=POWER_WATT, + ), + CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY_2: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.Vendor.KOOGEEK_REALTIME_ENERGY_2, + name="Real Time Energy", + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=POWER_WATT, + ), + CharacteristicsTypes.Vendor.EVE_DEGREE_AIR_PRESSURE: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.Vendor.EVE_DEGREE_AIR_PRESSURE, + name="Air Pressure", + device_class=DEVICE_CLASS_PRESSURE, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=PRESSURE_HPA, + ), + CharacteristicsTypes.TEMPERATURE_CURRENT: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.TEMPERATURE_CURRENT, + name="Current Temperature", + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=TEMP_CELSIUS, # This sensor is only for temperature characteristics that are not part # of a temperature sensor service. - "probe": lambda char: char.service.type + probe=lambda char: char.service.type != ServicesTypes.get_uuid(ServicesTypes.TEMPERATURE_SENSOR), - }, - CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT: { - "name": "Current Humidity", - "device_class": DEVICE_CLASS_HUMIDITY, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": PERCENTAGE, + ), + CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT, + name="Current Humidity", + device_class=DEVICE_CLASS_HUMIDITY, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=PERCENTAGE, # This sensor is only for humidity characteristics that are not part # of a humidity sensor service. - "probe": lambda char: char.service.type + probe=lambda char: char.service.type != ServicesTypes.get_uuid(ServicesTypes.HUMIDITY_SENSOR), - }, - CharacteristicsTypes.AIR_QUALITY: { - "name": "Air Quality", - "device_class": DEVICE_CLASS_AQI, - "state_class": STATE_CLASS_MEASUREMENT, - }, - CharacteristicsTypes.DENSITY_PM25: { - "name": "PM2.5 Density", - "device_class": DEVICE_CLASS_PM25, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, - }, - CharacteristicsTypes.DENSITY_PM10: { - "name": "PM10 Density", - "device_class": DEVICE_CLASS_PM10, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, - }, - CharacteristicsTypes.DENSITY_OZONE: { - "name": "Ozone Density", - "device_class": DEVICE_CLASS_OZONE, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, - }, - CharacteristicsTypes.DENSITY_NO2: { - "name": "Nitrogen Dioxide Density", - "device_class": DEVICE_CLASS_NITROGEN_DIOXIDE, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, - }, - CharacteristicsTypes.DENSITY_SO2: { - "name": "Sulphur Dioxide Density", - "device_class": DEVICE_CLASS_SULPHUR_DIOXIDE, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, - }, - CharacteristicsTypes.DENSITY_VOC: { - "name": "Volatile Organic Compound Density", - "device_class": DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, - "state_class": STATE_CLASS_MEASUREMENT, - "unit": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, - }, + ), + CharacteristicsTypes.AIR_QUALITY: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.AIR_QUALITY, + name="Air Quality", + device_class=DEVICE_CLASS_AQI, + state_class=STATE_CLASS_MEASUREMENT, + ), + CharacteristicsTypes.DENSITY_PM25: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.DENSITY_PM25, + name="PM2.5 Density", + device_class=DEVICE_CLASS_PM25, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + CharacteristicsTypes.DENSITY_PM10: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.DENSITY_PM10, + name="PM10 Density", + device_class=DEVICE_CLASS_PM10, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + CharacteristicsTypes.DENSITY_OZONE: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.DENSITY_OZONE, + name="Ozone Density", + device_class=DEVICE_CLASS_OZONE, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + CharacteristicsTypes.DENSITY_NO2: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.DENSITY_NO2, + name="Nitrogen Dioxide Density", + device_class=DEVICE_CLASS_NITROGEN_DIOXIDE, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + CharacteristicsTypes.DENSITY_SO2: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.DENSITY_SO2, + name="Sulphur Dioxide Density", + device_class=DEVICE_CLASS_SULPHUR_DIOXIDE, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), + CharacteristicsTypes.DENSITY_VOC: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.DENSITY_VOC, + name="Volatile Organic Compound Density", + device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, + state_class=STATE_CLASS_MEASUREMENT, + native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ), } # For legacy reasons, "built-in" characteristic types are in their short form @@ -285,55 +314,27 @@ class SimpleSensor(CharacteristicEntity, SensorEntity): be multiple entities per HomeKit service (this was not previously the case). """ + entity_description: HomeKitSensorEntityDescription + def __init__( self, conn, info, char, - device_class=None, - state_class=None, - unit=None, - icon=None, - name=None, - **kwargs, + description: HomeKitSensorEntityDescription, ): """Initialise a secondary HomeKit characteristic sensor.""" - self._device_class = device_class - self._state_class = state_class - self._unit = unit - self._icon = icon - self._name = name - + self.entity_description = description super().__init__(conn, info, char) def get_characteristic_types(self): """Define the homekit characteristics the entity is tracking.""" return [self._char.type] - @property - def device_class(self): - """Return type of sensor.""" - return self._device_class - - @property - def state_class(self): - """Return type of state.""" - return self._state_class - - @property - def native_unit_of_measurement(self): - """Return units for the sensor.""" - return self._unit - - @property - def icon(self): - """Return the sensor icon.""" - return self._icon - @property def name(self) -> str: """Return the name of the device if any.""" - return f"{super().name} - {self._name}" + return f"{super().name} - {self.entity_description.name}" @property def native_value(self): @@ -368,13 +369,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities): @callback def async_add_characteristic(char: Characteristic): - kwargs = SIMPLE_SENSOR.get(char.type) - if not kwargs: + if not (description := SIMPLE_SENSOR.get(char.type)): return False - if "probe" in kwargs and not kwargs["probe"](char): + if description.probe and not description.probe(char): return False info = {"aid": char.service.accessory.aid, "iid": char.service.iid} - async_add_entities([SimpleSensor(conn, info, char, **kwargs)], True) + async_add_entities([SimpleSensor(conn, info, char, description)], True) return True