1 """Support for Dutch Smart Meter (also known as Smartmeter or P1 port)."""
3 from __future__
import annotations
6 from asyncio
import CancelledError
7 from collections.abc
import Callable, Generator
8 from contextlib
import suppress
9 from dataclasses
import dataclass
10 from datetime
import timedelta
11 from enum
import IntEnum
12 from functools
import partial
14 from dsmr_parser.clients.protocol
import create_dsmr_reader, create_tcp_dsmr_reader
15 from dsmr_parser.clients.rfxtrx_protocol
import (
16 create_rfxtrx_dsmr_reader,
17 create_rfxtrx_tcp_dsmr_reader,
19 from dsmr_parser.objects
import DSMRObject, MbusDevice, Telegram
25 SensorEntityDescription,
33 EVENT_HOMEASSISTANT_STOP,
42 async_dispatcher_connect,
43 async_dispatcher_send,
49 from .
import DsmrConfigEntry
54 CONF_TIME_BETWEEN_UPDATE,
56 DEFAULT_RECONNECT_INTERVAL,
57 DEFAULT_TIME_BETWEEN_UPDATE,
58 DEVICE_NAME_ELECTRICITY,
67 EVENT_FIRST_TELEGRAM =
"dsmr_first_telegram_{}"
69 UNIT_CONVERSION = {
"m3": UnitOfVolume.CUBIC_METERS}
72 @dataclass(frozen=True, kw_only=True)
74 """Represents an DSMR Sensor."""
76 dsmr_versions: set[str] |
None =
None
78 is_water: bool =
False
84 """Types of mbus devices (13757-3:2013)."""
91 SENSORS: tuple[DSMRSensorEntityDescription, ...] = (
94 obis_reference=
"P1_MESSAGE_TIMESTAMP",
95 device_class=SensorDeviceClass.TIMESTAMP,
96 entity_category=EntityCategory.DIAGNOSTIC,
97 entity_registry_enabled_default=
False,
100 key=
"current_electricity_usage",
101 translation_key=
"current_electricity_usage",
102 obis_reference=
"CURRENT_ELECTRICITY_USAGE",
103 device_class=SensorDeviceClass.POWER,
104 state_class=SensorStateClass.MEASUREMENT,
107 key=
"current_electricity_delivery",
108 translation_key=
"current_electricity_delivery",
109 obis_reference=
"CURRENT_ELECTRICITY_DELIVERY",
110 device_class=SensorDeviceClass.POWER,
111 state_class=SensorStateClass.MEASUREMENT,
114 key=
"electricity_active_tariff",
115 translation_key=
"electricity_active_tariff",
116 obis_reference=
"ELECTRICITY_ACTIVE_TARIFF",
117 dsmr_versions={
"2.2",
"4",
"5",
"5B",
"5L"},
118 device_class=SensorDeviceClass.ENUM,
119 options=[
"low",
"normal"],
122 key=
"electricity_used_tariff_1",
123 translation_key=
"electricity_used_tariff_1",
124 obis_reference=
"ELECTRICITY_USED_TARIFF_1",
125 dsmr_versions={
"2.2",
"4",
"5",
"5B",
"5L"},
126 device_class=SensorDeviceClass.ENERGY,
127 state_class=SensorStateClass.TOTAL_INCREASING,
130 key=
"electricity_used_tariff_2",
131 translation_key=
"electricity_used_tariff_2",
132 obis_reference=
"ELECTRICITY_USED_TARIFF_2",
133 dsmr_versions={
"2.2",
"4",
"5",
"5B",
"5L"},
134 device_class=SensorDeviceClass.ENERGY,
135 state_class=SensorStateClass.TOTAL_INCREASING,
138 key=
"electricity_delivered_tariff_1",
139 translation_key=
"electricity_delivered_tariff_1",
140 obis_reference=
"ELECTRICITY_DELIVERED_TARIFF_1",
141 dsmr_versions={
"2.2",
"4",
"5",
"5B",
"5L"},
142 device_class=SensorDeviceClass.ENERGY,
143 state_class=SensorStateClass.TOTAL_INCREASING,
146 key=
"electricity_delivered_tariff_2",
147 translation_key=
"electricity_delivered_tariff_2",
148 obis_reference=
"ELECTRICITY_DELIVERED_TARIFF_2",
149 dsmr_versions={
"2.2",
"4",
"5",
"5B",
"5L"},
150 device_class=SensorDeviceClass.ENERGY,
151 state_class=SensorStateClass.TOTAL_INCREASING,
154 key=
"instantaneous_active_power_l1_positive",
155 translation_key=
"instantaneous_active_power_l1_positive",
156 obis_reference=
"INSTANTANEOUS_ACTIVE_POWER_L1_POSITIVE",
157 device_class=SensorDeviceClass.POWER,
158 entity_registry_enabled_default=
False,
159 state_class=SensorStateClass.MEASUREMENT,
162 key=
"instantaneous_active_power_l2_positive",
163 translation_key=
"instantaneous_active_power_l2_positive",
164 obis_reference=
"INSTANTANEOUS_ACTIVE_POWER_L2_POSITIVE",
165 device_class=SensorDeviceClass.POWER,
166 entity_registry_enabled_default=
False,
167 state_class=SensorStateClass.MEASUREMENT,
170 key=
"instantaneous_active_power_l3_positive",
171 translation_key=
"instantaneous_active_power_l3_positive",
172 obis_reference=
"INSTANTANEOUS_ACTIVE_POWER_L3_POSITIVE",
173 device_class=SensorDeviceClass.POWER,
174 entity_registry_enabled_default=
False,
175 state_class=SensorStateClass.MEASUREMENT,
178 key=
"instantaneous_active_power_l1_negative",
179 translation_key=
"instantaneous_active_power_l1_negative",
180 obis_reference=
"INSTANTANEOUS_ACTIVE_POWER_L1_NEGATIVE",
181 device_class=SensorDeviceClass.POWER,
182 entity_registry_enabled_default=
False,
183 state_class=SensorStateClass.MEASUREMENT,
186 key=
"instantaneous_active_power_l2_negative",
187 translation_key=
"instantaneous_active_power_l2_negative",
188 obis_reference=
"INSTANTANEOUS_ACTIVE_POWER_L2_NEGATIVE",
189 device_class=SensorDeviceClass.POWER,
190 entity_registry_enabled_default=
False,
191 state_class=SensorStateClass.MEASUREMENT,
194 key=
"instantaneous_active_power_l3_negative",
195 translation_key=
"instantaneous_active_power_l3_negative",
196 obis_reference=
"INSTANTANEOUS_ACTIVE_POWER_L3_NEGATIVE",
197 device_class=SensorDeviceClass.POWER,
198 entity_registry_enabled_default=
False,
199 state_class=SensorStateClass.MEASUREMENT,
202 key=
"short_power_failure_count",
203 translation_key=
"short_power_failure_count",
204 obis_reference=
"SHORT_POWER_FAILURE_COUNT",
205 dsmr_versions={
"2.2",
"4",
"5",
"5L"},
206 entity_registry_enabled_default=
False,
207 entity_category=EntityCategory.DIAGNOSTIC,
210 key=
"long_power_failure_count",
211 translation_key=
"long_power_failure_count",
212 obis_reference=
"LONG_POWER_FAILURE_COUNT",
213 dsmr_versions={
"2.2",
"4",
"5",
"5L"},
214 entity_registry_enabled_default=
False,
215 entity_category=EntityCategory.DIAGNOSTIC,
218 key=
"voltage_sag_l1_count",
219 translation_key=
"voltage_sag_l1_count",
220 obis_reference=
"VOLTAGE_SAG_L1_COUNT",
221 dsmr_versions={
"2.2",
"4",
"5",
"5L"},
222 entity_registry_enabled_default=
False,
223 entity_category=EntityCategory.DIAGNOSTIC,
226 key=
"voltage_sag_l2_count",
227 translation_key=
"voltage_sag_l2_count",
228 obis_reference=
"VOLTAGE_SAG_L2_COUNT",
229 dsmr_versions={
"2.2",
"4",
"5",
"5L"},
230 entity_registry_enabled_default=
False,
231 entity_category=EntityCategory.DIAGNOSTIC,
234 key=
"voltage_sag_l3_count",
235 translation_key=
"voltage_sag_l3_count",
236 obis_reference=
"VOLTAGE_SAG_L3_COUNT",
237 dsmr_versions={
"2.2",
"4",
"5",
"5L"},
238 entity_registry_enabled_default=
False,
239 entity_category=EntityCategory.DIAGNOSTIC,
242 key=
"voltage_swell_l1_count",
243 translation_key=
"voltage_swell_l1_count",
244 obis_reference=
"VOLTAGE_SWELL_L1_COUNT",
245 dsmr_versions={
"2.2",
"4",
"5",
"5L"},
246 entity_registry_enabled_default=
False,
247 entity_category=EntityCategory.DIAGNOSTIC,
250 key=
"voltage_swell_l2_count",
251 translation_key=
"voltage_swell_l2_count",
252 obis_reference=
"VOLTAGE_SWELL_L2_COUNT",
253 dsmr_versions={
"2.2",
"4",
"5",
"5L"},
254 entity_registry_enabled_default=
False,
255 entity_category=EntityCategory.DIAGNOSTIC,
258 key=
"voltage_swell_l3_count",
259 translation_key=
"voltage_swell_l3_count",
260 obis_reference=
"VOLTAGE_SWELL_L3_COUNT",
261 dsmr_versions={
"2.2",
"4",
"5",
"5L"},
262 entity_registry_enabled_default=
False,
263 entity_category=EntityCategory.DIAGNOSTIC,
266 key=
"instantaneous_voltage_l1",
267 translation_key=
"instantaneous_voltage_l1",
268 obis_reference=
"INSTANTANEOUS_VOLTAGE_L1",
269 device_class=SensorDeviceClass.VOLTAGE,
270 entity_registry_enabled_default=
False,
271 state_class=SensorStateClass.MEASUREMENT,
272 entity_category=EntityCategory.DIAGNOSTIC,
275 key=
"instantaneous_voltage_l2",
276 translation_key=
"instantaneous_voltage_l2",
277 obis_reference=
"INSTANTANEOUS_VOLTAGE_L2",
278 device_class=SensorDeviceClass.VOLTAGE,
279 entity_registry_enabled_default=
False,
280 state_class=SensorStateClass.MEASUREMENT,
281 entity_category=EntityCategory.DIAGNOSTIC,
284 key=
"instantaneous_voltage_l3",
285 translation_key=
"instantaneous_voltage_l3",
286 obis_reference=
"INSTANTANEOUS_VOLTAGE_L3",
287 device_class=SensorDeviceClass.VOLTAGE,
288 entity_registry_enabled_default=
False,
289 state_class=SensorStateClass.MEASUREMENT,
290 entity_category=EntityCategory.DIAGNOSTIC,
293 key=
"instantaneous_current_l1",
294 translation_key=
"instantaneous_current_l1",
295 obis_reference=
"INSTANTANEOUS_CURRENT_L1",
296 device_class=SensorDeviceClass.CURRENT,
297 entity_registry_enabled_default=
False,
298 state_class=SensorStateClass.MEASUREMENT,
299 entity_category=EntityCategory.DIAGNOSTIC,
302 key=
"instantaneous_current_l2",
303 translation_key=
"instantaneous_current_l2",
304 obis_reference=
"INSTANTANEOUS_CURRENT_L2",
305 device_class=SensorDeviceClass.CURRENT,
306 entity_registry_enabled_default=
False,
307 state_class=SensorStateClass.MEASUREMENT,
308 entity_category=EntityCategory.DIAGNOSTIC,
311 key=
"instantaneous_current_l3",
312 translation_key=
"instantaneous_current_l3",
313 obis_reference=
"INSTANTANEOUS_CURRENT_L3",
314 device_class=SensorDeviceClass.CURRENT,
315 entity_registry_enabled_default=
False,
316 state_class=SensorStateClass.MEASUREMENT,
317 entity_category=EntityCategory.DIAGNOSTIC,
320 key=
"belgium_max_power_per_phase",
321 translation_key=
"max_power_per_phase",
322 obis_reference=
"ACTUAL_TRESHOLD_ELECTRICITY",
323 dsmr_versions={
"5B"},
324 device_class=SensorDeviceClass.POWER,
325 entity_registry_enabled_default=
False,
326 state_class=SensorStateClass.MEASUREMENT,
327 entity_category=EntityCategory.DIAGNOSTIC,
330 key=
"belgium_max_current_per_phase",
331 translation_key=
"max_current_per_phase",
332 obis_reference=
"FUSE_THRESHOLD_L1",
333 dsmr_versions={
"5B"},
334 device_class=SensorDeviceClass.CURRENT,
335 entity_registry_enabled_default=
False,
336 state_class=SensorStateClass.MEASUREMENT,
337 entity_category=EntityCategory.DIAGNOSTIC,
340 key=
"electricity_imported_total",
341 translation_key=
"electricity_imported_total",
342 obis_reference=
"ELECTRICITY_IMPORTED_TOTAL",
343 dsmr_versions={
"5L",
"5S",
"Q3D"},
344 device_class=SensorDeviceClass.ENERGY,
345 state_class=SensorStateClass.TOTAL_INCREASING,
348 key=
"electricity_exported_total",
349 translation_key=
"electricity_exported_total",
350 obis_reference=
"ELECTRICITY_EXPORTED_TOTAL",
351 dsmr_versions={
"5L",
"5S",
"Q3D"},
352 device_class=SensorDeviceClass.ENERGY,
353 state_class=SensorStateClass.TOTAL_INCREASING,
356 key=
"belgium_current_average_demand",
357 translation_key=
"current_average_demand",
358 obis_reference=
"BELGIUM_CURRENT_AVERAGE_DEMAND",
359 dsmr_versions={
"5B"},
360 device_class=SensorDeviceClass.POWER,
361 state_class=SensorStateClass.MEASUREMENT,
364 key=
"belgium_maximum_demand_current_month",
365 translation_key=
"maximum_demand_current_month",
366 obis_reference=
"BELGIUM_MAXIMUM_DEMAND_MONTH",
367 dsmr_versions={
"5B"},
368 device_class=SensorDeviceClass.POWER,
369 state_class=SensorStateClass.MEASUREMENT,
372 key=
"hourly_gas_meter_reading",
373 translation_key=
"gas_meter_reading",
374 obis_reference=
"HOURLY_GAS_METER_READING",
375 dsmr_versions={
"4",
"5",
"5L"},
377 device_class=SensorDeviceClass.GAS,
378 state_class=SensorStateClass.TOTAL_INCREASING,
381 key=
"gas_meter_reading",
382 translation_key=
"gas_meter_reading",
383 obis_reference=
"GAS_METER_READING",
384 dsmr_versions={
"2.2"},
386 device_class=SensorDeviceClass.GAS,
387 state_class=SensorStateClass.TOTAL_INCREASING,
391 SENSORS_MBUS_DEVICE_TYPE: dict[int, tuple[DSMRSensorEntityDescription, ...]] = {
392 MbusDeviceType.GAS: (
395 translation_key=
"gas_meter_reading",
396 obis_reference=
"MBUS_METER_READING",
398 device_class=SensorDeviceClass.GAS,
399 state_class=SensorStateClass.TOTAL_INCREASING,
402 MbusDeviceType.HEAT: (
405 translation_key=
"heat_meter_reading",
406 obis_reference=
"MBUS_METER_READING",
408 device_class=SensorDeviceClass.ENERGY,
409 state_class=SensorStateClass.TOTAL_INCREASING,
412 MbusDeviceType.WATER: (
415 translation_key=
"water_meter_reading",
416 obis_reference=
"MBUS_METER_READING",
418 device_class=SensorDeviceClass.WATER,
419 state_class=SensorStateClass.TOTAL_INCREASING,
426 data: Telegram | MbusDevice,
427 entity_description: DSMRSensorEntityDescription,
428 ) -> tuple[SensorDeviceClass |
None, str |
None]:
429 """Get native unit of measurement from telegram,."""
430 dsmr_object = getattr(data, entity_description.obis_reference)
431 uom: str |
None = getattr(dsmr_object,
"unit")
or None
432 with suppress(ValueError):
433 if entity_description.device_class == SensorDeviceClass.GAS
and (
436 return (SensorDeviceClass.ENERGY, enery_uom)
437 if uom
in UNIT_CONVERSION:
438 return (entity_description.device_class, UNIT_CONVERSION[uom])
439 return (entity_description.device_class, uom)
443 hass: HomeAssistant, entry: ConfigEntry, mbus_device_id: str
445 """Rename old gas sensor to mbus variant."""
446 dev_reg = dr.async_get(hass)
447 for dev_id
in (mbus_device_id, entry.entry_id):
448 device_entry_v1 = dev_reg.async_get_device(identifiers={(DOMAIN, dev_id)})
449 if device_entry_v1
is not None:
450 device_id = device_entry_v1.id
452 ent_reg = er.async_get(hass)
453 entries = er.async_entries_for_device(ent_reg, device_id)
455 for entity
in entries:
456 if entity.unique_id.endswith(
457 "belgium_5min_gas_meter_reading"
458 )
or entity.unique_id.endswith(
"hourly_gas_meter_reading"):
460 ent_reg.async_update_entity(
462 new_unique_id=mbus_device_id,
463 device_id=mbus_device_id,
467 "Skip migration of %s because it already exists",
472 "Migrated entity %s from unique id %s to %s",
478 dev_entities = er.async_entries_for_device(
479 ent_reg, device_id, include_disabled_entities=
True
482 dev_reg.async_remove_device(device_id)
486 data: Telegram | MbusDevice,
487 description: DSMRSensorEntityDescription,
490 """Check if this is a supported description for this telegram."""
491 return hasattr(data, description.obis_reference)
and (
492 description.dsmr_versions
is None or dsmr_version
in description.dsmr_versions
497 hass: HomeAssistant, telegram: Telegram, entry: ConfigEntry, dsmr_version: str
498 ) -> Generator[DSMREntity]:
499 """Create MBUS Entities."""
500 mbus_devices: list[MbusDevice] = getattr(telegram,
"MBUS_DEVICES", [])
501 for device
in mbus_devices:
502 if (device_type := getattr(device,
"MBUS_DEVICE_TYPE",
None))
is None:
504 type_ =
int(device_type.value)
506 if type_
not in SENSORS_MBUS_DEVICE_TYPE:
507 LOGGER.warning(
"Unsupported MBUS_DEVICE_TYPE (%d)", type_)
510 if identifier := getattr(device,
"MBUS_EQUIPMENT_IDENTIFIER",
None):
511 serial_ = identifier.value
516 for description
in SENSORS_MBUS_DEVICE_TYPE.get(type_, ()):
530 telegram: Telegram |
None, mbus_id: int, obis_reference: str
531 ) -> DSMRObject |
None:
532 """Extract DSMR object from telegram."""
536 telegram_or_device: Telegram | MbusDevice |
None = telegram
538 telegram_or_device = telegram.get_mbus_device_by_channel(mbus_id)
539 if telegram_or_device
is None:
542 return getattr(telegram_or_device, obis_reference,
None)
546 hass: HomeAssistant, entry: DsmrConfigEntry, async_add_entities: AddEntitiesCallback
548 """Set up the DSMR sensor."""
549 dsmr_version = entry.data[CONF_DSMR_VERSION]
550 entities: list[DSMREntity] = []
551 initialized: bool =
False
552 add_entities_handler: Callable[...,
None] |
None
555 def init_async_add_entities(telegram: Telegram) ->
None:
556 """Add the sensor entities after the first telegram was received."""
557 nonlocal add_entities_handler
558 assert add_entities_handler
is not None
559 add_entities_handler()
560 add_entities_handler =
None
572 for description
in SENSORS
575 (
not description.is_gas
and not description.is_heat)
576 or CONF_SERIAL_ID_GAS
in entry.data
583 hass, EVENT_FIRST_TELEGRAM.format(entry.entry_id), init_async_add_entities
586 seconds=entry.options.get(CONF_TIME_BETWEEN_UPDATE, DEFAULT_TIME_BETWEEN_UPDATE)
589 @Throttle(min_time_between_updates)
590 def update_entities_telegram(telegram: Telegram |
None) ->
None:
591 """Update entities with latest telegram and trigger state update."""
594 for entity
in entities:
595 entity.update_data(telegram)
597 entry.runtime_data.telegram = telegram
599 if not initialized
and telegram:
602 hass, EVENT_FIRST_TELEGRAM.format(entry.entry_id), telegram
607 protocol = entry.data.get(CONF_PROTOCOL, DSMR_PROTOCOL)
608 if CONF_HOST
in entry.data:
609 if protocol == DSMR_PROTOCOL:
610 create_reader = create_tcp_dsmr_reader
612 create_reader = create_rfxtrx_tcp_dsmr_reader
613 reader_factory = partial(
615 entry.data[CONF_HOST],
616 entry.data[CONF_PORT],
618 update_entities_telegram,
620 keep_alive_interval=60,
623 if protocol == DSMR_PROTOCOL:
624 create_reader = create_dsmr_reader
626 create_reader = create_rfxtrx_dsmr_reader
627 reader_factory = partial(
629 entry.data[CONF_PORT],
631 update_entities_telegram,
635 async
def connect_and_reconnect() -> None:
636 """Connect to DSMR and keep reconnecting until Home Assistant stops."""
641 while hass.state
is CoreState.not_running
or hass.is_running:
646 update_entities_telegram({})
649 transport, protocol = await hass.loop.create_task(reader_factory())
654 def close_transport(_event: Event) ->
None:
655 """Close the transport on HA shutdown."""
660 stop_listener = hass.bus.async_listen_once(
661 EVENT_HOMEASSISTANT_STOP, close_transport
665 await protocol.wait_closed()
668 if hass.state
is CoreState.not_running
or hass.is_running:
676 update_entities_telegram(
None)
679 await asyncio.sleep(DEFAULT_RECONNECT_INTERVAL)
681 except (serial.SerialException, OSError):
684 LOGGER.exception(
"Error connecting to DSMR")
690 update_entities_telegram(
None)
693 await asyncio.sleep(DEFAULT_RECONNECT_INTERVAL)
694 except CancelledError:
697 update_entities_telegram(
None)
699 if stop_listener
and (
700 hass.state
is CoreState.not_running
or hass.is_running
708 await protocol.wait_closed()
713 task = asyncio.create_task(connect_and_reconnect())
717 if add_entities_handler
is not None:
718 add_entities_handler()
722 entry.async_on_unload(
723 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_stop)
727 entry.runtime_data.task = task
731 """Entity reading values from DSMR telegram."""
733 entity_description: DSMRSensorEntityDescription
734 _attr_has_entity_name =
True
735 _attr_should_poll =
False
739 entity_description: DSMRSensorEntityDescription,
742 device_class: SensorDeviceClass,
743 native_unit_of_measurement: str |
None,
747 """Initialize entity."""
752 self.
telegramtelegram: Telegram |
None = telegram
754 device_serial = entry.data[CONF_SERIAL_ID]
755 device_name = DEVICE_NAME_ELECTRICITY
756 if entity_description.is_gas:
758 device_serial = serial_id
760 device_serial = entry.data[CONF_SERIAL_ID_GAS]
761 device_name = DEVICE_NAME_GAS
762 if entity_description.is_water:
764 device_serial = serial_id
765 device_name = DEVICE_NAME_WATER
766 if entity_description.is_heat:
768 device_serial = serial_id
769 device_name = DEVICE_NAME_HEAT
770 if device_serial
is None:
771 device_serial = entry.entry_id
774 identifiers={(DOMAIN, device_serial)},
784 self.
_attr_unique_id_attr_unique_id = f
"{device_serial}_{entity_description.key}"
790 if self.
hasshass
and (
799 """Read attribute from last received telegram for this DSMR object."""
804 if dsmr_object
is None:
808 attr: str |
None = getattr(dsmr_object, attribute)
813 """Entity is only available if there is a telegram."""
814 return self.
telegramtelegram
is not None
818 """Return the state of sensor, if available, translate if needed."""
823 if self.
entity_descriptionentity_description.obis_reference ==
"ELECTRICITY_ACTIVE_TARIFF":
826 with suppress(TypeError):
827 value = round(
float(value), DEFAULT_PRECISION)
837 """Convert 2/1 to normal/low depending on DSMR version."""
840 if dsmr_version ==
"5B":
843 elif value ==
"0002":
None update_data(self, Telegram|None telegram)
StateType native_value(self)
str|None translate_tariff(str value, str dsmr_version)
str|None get_dsmr_object_attr(self, str attribute)
_attr_native_unit_of_measurement
None __init__(self, DSMRSensorEntityDescription entity_description, ConfigEntry entry, Telegram telegram, SensorDeviceClass device_class, str|None native_unit_of_measurement, str serial_id="", int mbus_id=0)
SensorStateClass|str|None state_class(self)
None async_write_ha_state(self)
Generator[DSMREntity] create_mbus_entities(HomeAssistant hass, Telegram telegram, ConfigEntry entry, str dsmr_version)
tuple[SensorDeviceClass|None, str|None] device_class_and_uom(Telegram|MbusDevice data, DSMRSensorEntityDescription entity_description)
None rename_old_gas_to_mbus(HomeAssistant hass, ConfigEntry entry, str mbus_device_id)
None async_setup_entry(HomeAssistant hass, DsmrConfigEntry entry, AddEntitiesCallback async_add_entities)
DSMRObject|None get_dsmr_object(Telegram|None telegram, int mbus_id, str obis_reference)
bool is_supported_description(Telegram|MbusDevice data, DSMRSensorEntityDescription description, str dsmr_version)
None _async_stop(HomeAssistant hass, bool restart)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)