Add edl21 sensor state class and device class (#56968)
This commit is contained in:
parent
29ec65f924
commit
dafc071214
1 changed files with 213 additions and 98 deletions
|
@ -8,7 +8,13 @@ from sml import SmlGetListResponse
|
||||||
from sml.asyncio import SmlProtocol
|
from sml.asyncio import SmlProtocol
|
||||||
import voluptuous as vol
|
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.const import CONF_NAME
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
@ -25,7 +31,6 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DOMAIN = "edl21"
|
DOMAIN = "edl21"
|
||||||
CONF_SERIAL_PORT = "serial_port"
|
CONF_SERIAL_PORT = "serial_port"
|
||||||
ICON_POWER = "mdi:flash"
|
|
||||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60)
|
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60)
|
||||||
SIGNAL_EDL21_TELEGRAM = "edl21_telegram"
|
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(
|
async def async_setup_platform(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
@ -51,94 +253,6 @@ async def async_setup_platform(
|
||||||
class EDL21:
|
class EDL21:
|
||||||
"""EDL21 handles telegrams sent by a compatible smart meter."""
|
"""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 = {
|
_OBIS_BLACKLIST = {
|
||||||
# C=96: Electricity-related service entries
|
# C=96: Electricity-related service entries
|
||||||
"1-0:96.50.1*1", # Manufacturer specific
|
"1-0:96.50.1*1", # Manufacturer specific
|
||||||
|
@ -186,11 +300,16 @@ class EDL21:
|
||||||
self._hass, SIGNAL_EDL21_TELEGRAM, electricity_id, telegram
|
self._hass, SIGNAL_EDL21_TELEGRAM, electricity_id, telegram
|
||||||
)
|
)
|
||||||
else:
|
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:
|
if self._name:
|
||||||
name = f"{self._name}: {name}"
|
name = f"{self._name}: {name}"
|
||||||
|
|
||||||
new_entities.append(
|
new_entities.append(
|
||||||
EDL21Entity(electricity_id, obis, name, telegram)
|
EDL21Entity(
|
||||||
|
electricity_id, obis, name, entity_description, telegram
|
||||||
|
)
|
||||||
)
|
)
|
||||||
self._registered_obis.add((electricity_id, obis))
|
self._registered_obis.add((electricity_id, obis))
|
||||||
elif obis not in self._OBIS_BLACKLIST:
|
elif obis not in self._OBIS_BLACKLIST:
|
||||||
|
@ -231,7 +350,7 @@ class EDL21:
|
||||||
class EDL21Entity(SensorEntity):
|
class EDL21Entity(SensorEntity):
|
||||||
"""Entity reading values from EDL21 telegram."""
|
"""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."""
|
"""Initialize an EDL21Entity."""
|
||||||
self._electricity_id = electricity_id
|
self._electricity_id = electricity_id
|
||||||
self._obis = obis
|
self._obis = obis
|
||||||
|
@ -247,6 +366,7 @@ class EDL21Entity(SensorEntity):
|
||||||
"valueSignature": "value_signature",
|
"valueSignature": "value_signature",
|
||||||
}
|
}
|
||||||
self._async_remove_dispatcher = None
|
self._async_remove_dispatcher = None
|
||||||
|
self.entity_description = entity_description
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Run when entity about to be added to hass."""
|
"""Run when entity about to be added to hass."""
|
||||||
|
@ -316,8 +436,3 @@ class EDL21Entity(SensorEntity):
|
||||||
def native_unit_of_measurement(self):
|
def native_unit_of_measurement(self):
|
||||||
"""Return the unit of measurement."""
|
"""Return the unit of measurement."""
|
||||||
return self._telegram.get("unit")
|
return self._telegram.get("unit")
|
||||||
|
|
||||||
@property
|
|
||||||
def icon(self):
|
|
||||||
"""Return an icon."""
|
|
||||||
return ICON_POWER
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue