diff --git a/homeassistant/components/edl21/sensor.py b/homeassistant/components/edl21/sensor.py index d9997a9c1e3..f52cc0c17d4 100644 --- a/homeassistant/components/edl21/sensor.py +++ b/homeassistant/components/edl21/sensor.py @@ -8,7 +8,13 @@ from sml import SmlGetListResponse from sml.asyncio import SmlProtocol import voluptuous as vol -from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity +from homeassistant.components.sensor import ( + PLATFORM_SCHEMA, + SensorDeviceClass, + SensorEntity, + SensorEntityDescription, + SensorStateClass, +) from homeassistant.const import CONF_NAME from homeassistant.core import HomeAssistant, callback import homeassistant.helpers.config_validation as cv @@ -25,7 +31,6 @@ _LOGGER = logging.getLogger(__name__) DOMAIN = "edl21" CONF_SERIAL_PORT = "serial_port" -ICON_POWER = "mdi:flash" MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) SIGNAL_EDL21_TELEGRAM = "edl21_telegram" @@ -36,6 +41,203 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( }, ) +# OBIS format: A-B:C.D.E*F +SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( + # A=1: Electricity + # C=0: General purpose objects + # D=0: Free ID-numbers for utilities + SensorEntityDescription( + key="1-0:0.0.9*255", name="Electricity ID", icon="mdi:flash" + ), + # D=2: Program entries + SensorEntityDescription( + key="1-0:0.2.0*0", name="Configuration program version number", icon="mdi:flash" + ), + SensorEntityDescription( + key="1-0:0.2.0*1", name="Firmware version number", icon="mdi:flash" + ), + # C=1: Active power + + # D=8: Time integral 1 + # E=0: Total + SensorEntityDescription( + key="1-0:1.8.0*255", + name="Positive active energy total", + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + ), + # E=1: Rate 1 + SensorEntityDescription( + key="1-0:1.8.1*255", + name="Positive active energy in tariff T1", + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + ), + # E=2: Rate 2 + SensorEntityDescription( + key="1-0:1.8.2*255", + name="Positive active energy in tariff T2", + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + ), + # D=17: Time integral 7 + # E=0: Total + SensorEntityDescription( + key="1-0:1.17.0*255", + name="Last signed positive active energy total", + ), + # C=2: Active power - + # D=8: Time integral 1 + # E=0: Total + SensorEntityDescription( + key="1-0:2.8.0*255", + name="Negative active energy total", + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + ), + # E=1: Rate 1 + SensorEntityDescription( + key="1-0:2.8.1*255", + name="Negative active energy in tariff T1", + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + ), + # E=2: Rate 2 + SensorEntityDescription( + key="1-0:2.8.2*255", + name="Negative active energy in tariff T2", + state_class=SensorStateClass.TOTAL_INCREASING, + device_class=SensorDeviceClass.ENERGY, + ), + # C=14: Supply frequency + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:14.7.0*255", name="Supply frequency", icon="mdi:sine-wave" + ), + # C=15: Active power absolute + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:15.7.0*255", + name="Absolute active instantaneous power", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.POWER, + ), + # C=16: Active power sum + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:16.7.0*255", + name="Sum active instantaneous power", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.POWER, + ), + # C=31: Active amperage L1 + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:31.7.0*255", + name="L1 active instantaneous amperage", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.CURRENT, + ), + # C=32: Active voltage L1 + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:32.7.0*255", + name="L1 active instantaneous voltage", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.VOLTAGE, + ), + # C=36: Active power L1 + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:36.7.0*255", + name="L1 active instantaneous power", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.POWER, + ), + # C=51: Active amperage L2 + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:51.7.0*255", + name="L2 active instantaneous amperage", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.CURRENT, + ), + # C=52: Active voltage L2 + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:52.7.0*255", + name="L2 active instantaneous voltage", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.VOLTAGE, + ), + # C=56: Active power L2 + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:56.7.0*255", + name="L2 active instantaneous power", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.POWER, + ), + # C=71: Active amperage L3 + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:71.7.0*255", + name="L3 active instantaneous amperage", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.CURRENT, + ), + # C=72: Active voltage L3 + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:72.7.0*255", + name="L3 active instantaneous voltage", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.VOLTAGE, + ), + # C=76: Active power L3 + # D=7: Instantaneous value + # E=0: Total + SensorEntityDescription( + key="1-0:76.7.0*255", + name="L3 active instantaneous power", + state_class=SensorStateClass.MEASUREMENT, + device_class=SensorDeviceClass.POWER, + ), + # C=81: Angles + # D=7: Instantaneous value + # E=4: U(L1) x I(L1) + # E=15: U(L2) x I(L2) + # E=26: U(L3) x I(L3) + SensorEntityDescription( + key="1-0:81.7.4*255", name="U(L1)/I(L1) phase angle", icon="mdi:sine-wave" + ), + SensorEntityDescription( + key="1-0:81.7.15*255", name="U(L2)/I(L2) phase angle", icon="mdi:sine-wave" + ), + SensorEntityDescription( + key="1-0:81.7.26*255", name="U(L3)/I(L3) phase angle", icon="mdi:sine-wave" + ), + # C=96: Electricity-related service entries + SensorEntityDescription( + key="1-0:96.1.0*255", name="Metering point ID 1", icon="mdi:flash" + ), + SensorEntityDescription( + key="1-0:96.5.0*255", name="Internal operating status", icon="mdi:flash" + ), +) + +SENSORS = {desc.key: desc for desc in SENSOR_TYPES} + async def async_setup_platform( hass: HomeAssistant, @@ -51,94 +253,6 @@ async def async_setup_platform( class EDL21: """EDL21 handles telegrams sent by a compatible smart meter.""" - # OBIS format: A-B:C.D.E*F - _OBIS_NAMES = { - # A=1: Electricity - # C=0: General purpose objects - # D=0: Free ID-numbers for utilities - "1-0:0.0.9*255": "Electricity ID", - # D=2: Program entries - "1-0:0.2.0*0": "Configuration program version number", - "1-0:0.2.0*1": "Firmware version number", - # C=1: Active power + - # D=8: Time integral 1 - # E=0: Total - "1-0:1.8.0*255": "Positive active energy total", - # E=1: Rate 1 - "1-0:1.8.1*255": "Positive active energy in tariff T1", - # E=2: Rate 2 - "1-0:1.8.2*255": "Positive active energy in tariff T2", - # D=17: Time integral 7 - # E=0: Total - "1-0:1.17.0*255": "Last signed positive active energy total", - # C=2: Active power - - # D=8: Time integral 1 - # E=0: Total - "1-0:2.8.0*255": "Negative active energy total", - # E=1: Rate 1 - "1-0:2.8.1*255": "Negative active energy in tariff T1", - # E=2: Rate 2 - "1-0:2.8.2*255": "Negative active energy in tariff T2", - # C=14: Supply frequency - # D=7: Instantaneous value - # E=0: Total - "1-0:14.7.0*255": "Supply frequency", - # C=15: Active power absolute - # D=7: Instantaneous value - # E=0: Total - "1-0:15.7.0*255": "Absolute active instantaneous power", - # C=16: Active power sum - # D=7: Instantaneous value - # E=0: Total - "1-0:16.7.0*255": "Sum active instantaneous power", - # C=31: Active amperage L1 - # D=7: Instantaneous value - # E=0: Total - "1-0:31.7.0*255": "L1 active instantaneous amperage", - # C=32: Active voltage L1 - # D=7: Instantaneous value - # E=0: Total - "1-0:32.7.0*255": "L1 active instantaneous voltage", - # C=36: Active power L1 - # D=7: Instantaneous value - # E=0: Total - "1-0:36.7.0*255": "L1 active instantaneous power", - # C=51: Active amperage L2 - # D=7: Instantaneous value - # E=0: Total - "1-0:51.7.0*255": "L2 active instantaneous amperage", - # C=52: Active voltage L2 - # D=7: Instantaneous value - # E=0: Total - "1-0:52.7.0*255": "L2 active instantaneous voltage", - # C=56: Active power L2 - # D=7: Instantaneous value - # E=0: Total - "1-0:56.7.0*255": "L2 active instantaneous power", - # C=71: Active amperage L3 - # D=7: Instantaneous value - # E=0: Total - "1-0:71.7.0*255": "L3 active instantaneous amperage", - # C=72: Active voltage L3 - # D=7: Instantaneous value - # E=0: Total - "1-0:72.7.0*255": "L3 active instantaneous voltage", - # C=76: Active power L3 - # D=7: Instantaneous value - # E=0: Total - "1-0:76.7.0*255": "L3 active instantaneous power", - # C=81: Angles - # D=7: Instantaneous value - # E=4: U(L1) x I(L1) - # E=15: U(L2) x I(L2) - # E=26: U(L3) x I(L3) - "1-0:81.7.4*255": "U(L1)/I(L1) phase angle", - "1-0:81.7.15*255": "U(L2)/I(L2) phase angle", - "1-0:81.7.26*255": "U(L3)/I(L3) phase angle", - # C=96: Electricity-related service entries - "1-0:96.1.0*255": "Metering point ID 1", - "1-0:96.5.0*255": "Internal operating status", - } _OBIS_BLACKLIST = { # C=96: Electricity-related service entries "1-0:96.50.1*1", # Manufacturer specific @@ -186,11 +300,16 @@ class EDL21: self._hass, SIGNAL_EDL21_TELEGRAM, electricity_id, telegram ) else: - if name := self._OBIS_NAMES.get(obis): + entity_description = SENSORS.get(obis) + if entity_description and entity_description.name: + name = entity_description.name if self._name: name = f"{self._name}: {name}" + new_entities.append( - EDL21Entity(electricity_id, obis, name, telegram) + EDL21Entity( + electricity_id, obis, name, entity_description, telegram + ) ) self._registered_obis.add((electricity_id, obis)) elif obis not in self._OBIS_BLACKLIST: @@ -231,7 +350,7 @@ class EDL21: class EDL21Entity(SensorEntity): """Entity reading values from EDL21 telegram.""" - def __init__(self, electricity_id, obis, name, telegram): + def __init__(self, electricity_id, obis, name, entity_description, telegram): """Initialize an EDL21Entity.""" self._electricity_id = electricity_id self._obis = obis @@ -247,6 +366,7 @@ class EDL21Entity(SensorEntity): "valueSignature": "value_signature", } self._async_remove_dispatcher = None + self.entity_description = entity_description async def async_added_to_hass(self): """Run when entity about to be added to hass.""" @@ -316,8 +436,3 @@ class EDL21Entity(SensorEntity): def native_unit_of_measurement(self): """Return the unit of measurement.""" return self._telegram.get("unit") - - @property - def icon(self): - """Return an icon.""" - return ICON_POWER