Skip to content

Commit

Permalink
Fix DSMR migration (#135068)
Browse files Browse the repository at this point in the history
  • Loading branch information
emontnemery authored Jan 8, 2025
1 parent 43ec63e commit e052ab2
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 14 deletions.
33 changes: 20 additions & 13 deletions homeassistant/components/dsmr/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import serial

from homeassistant.components.sensor import (
DOMAIN as SENSOR_DOMAIN,
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
Expand Down Expand Up @@ -456,23 +457,29 @@ def rename_old_gas_to_mbus(
if entity.unique_id.endswith(
"belgium_5min_gas_meter_reading"
) or entity.unique_id.endswith("hourly_gas_meter_reading"):
try:
ent_reg.async_update_entity(
entity.entity_id,
new_unique_id=mbus_device_id,
)
except ValueError:
if ent_reg.async_get_entity_id(
SENSOR_DOMAIN, DOMAIN, mbus_device_id
):
LOGGER.debug(
"Skip migration of %s because it already exists",
entity.entity_id,
)
else:
LOGGER.debug(
"Migrated entity %s from unique id %s to %s",
entity.entity_id,
entity.unique_id,
mbus_device_id,
)
continue
new_device = dev_reg.async_get_or_create(
config_entry_id=entry.entry_id,
identifiers={(DOMAIN, mbus_device_id)},
)
ent_reg.async_update_entity(
entity.entity_id,
new_unique_id=mbus_device_id,
device_id=new_device.id,
)
LOGGER.debug(
"Migrated entity %s from unique id %s to %s",
entity.entity_id,
entity.unique_id,
mbus_device_id,
)
# Cleanup old device
dev_entities = er.async_entries_for_device(
ent_reg, device_id, include_disabled_entities=True
Expand Down
63 changes: 62 additions & 1 deletion tests/components/dsmr/test_mbus_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
MBUS_METER_READING,
)
from dsmr_parser.objects import CosemObject, MBusObject, Telegram
import pytest

from homeassistant.components.dsmr.const import DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
Expand Down Expand Up @@ -102,6 +103,17 @@ async def test_migrate_gas_to_mbus(
# after receiving telegram entities need to have the chance to be created
await hass.async_block_till_done()

# Check a new device is created and the old device has been removed
assert len(device_registry.devices) == 1
assert not device_registry.async_get(device.id)
new_entity = entity_registry.async_get("sensor.gas_meter_reading")
new_device = device_registry.async_get(new_entity.device_id)
new_dev_entities = er.async_entries_for_device(
entity_registry, new_device.id, include_disabled_entities=True
)
assert new_dev_entities == [new_entity]

# Check no entities are connected to the old device
dev_entities = er.async_entries_for_device(
entity_registry, device.id, include_disabled_entities=True
)
Expand Down Expand Up @@ -202,6 +214,17 @@ async def test_migrate_hourly_gas_to_mbus(
# after receiving telegram entities need to have the chance to be created
await hass.async_block_till_done()

# Check a new device is created and the old device has been removed
assert len(device_registry.devices) == 1
assert not device_registry.async_get(device.id)
new_entity = entity_registry.async_get("sensor.gas_meter_reading")
new_device = device_registry.async_get(new_entity.device_id)
new_dev_entities = er.async_entries_for_device(
entity_registry, new_device.id, include_disabled_entities=True
)
assert new_dev_entities == [new_entity]

# Check no entities are connected to the old device
dev_entities = er.async_entries_for_device(
entity_registry, device.id, include_disabled_entities=True
)
Expand Down Expand Up @@ -302,6 +325,18 @@ async def test_migrate_gas_with_devid_to_mbus(
# after receiving telegram entities need to have the chance to be created
await hass.async_block_till_done()

# Check a new device is not created and the old device has not been removed
assert len(device_registry.devices) == 1
assert device_registry.async_get(device.id)
new_entity = entity_registry.async_get("sensor.gas_meter_reading")
new_device = device_registry.async_get(new_entity.device_id)
assert new_device.id == device.id
# Check entities are still connected to the old device
dev_entities = er.async_entries_for_device(
entity_registry, device.id, include_disabled_entities=True
)
assert dev_entities == [new_entity]

assert (
entity_registry.async_get_entity_id(SENSOR_DOMAIN, DOMAIN, old_unique_id)
is None
Expand All @@ -319,6 +354,7 @@ async def test_migrate_gas_to_mbus_exists(
entity_registry: er.EntityRegistry,
device_registry: dr.DeviceRegistry,
dsmr_connection_fixture: tuple[MagicMock, MagicMock, MagicMock],
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test migration of unique_id."""
(connection_factory, transport, protocol) = dsmr_connection_fixture
Expand Down Expand Up @@ -380,7 +416,7 @@ async def test_migrate_gas_to_mbus_exists(
telegram = Telegram()
telegram.add(
MBUS_DEVICE_TYPE,
CosemObject((0, 0), [{"value": "003", "unit": ""}]),
CosemObject((0, 1), [{"value": "003", "unit": ""}]),
"MBUS_DEVICE_TYPE",
)
telegram.add(
Expand Down Expand Up @@ -414,7 +450,32 @@ async def test_migrate_gas_to_mbus_exists(
# after receiving telegram entities need to have the chance to be created
await hass.async_block_till_done()

# Check a new device is not created and the old device has not been removed
assert len(device_registry.devices) == 2
assert device_registry.async_get(device.id)
assert device_registry.async_get(device2.id)
entity = entity_registry.async_get("sensor.gas_meter_reading")
dev_entities = er.async_entries_for_device(
entity_registry, device.id, include_disabled_entities=True
)
assert dev_entities == [entity]
entity2 = entity_registry.async_get("sensor.gas_meter_reading_alt")
dev2_entities = er.async_entries_for_device(
entity_registry, device2.id, include_disabled_entities=True
)
assert dev2_entities == [entity2]

assert (
entity_registry.async_get_entity_id(SENSOR_DOMAIN, DOMAIN, old_unique_id)
== "sensor.gas_meter_reading"
)
assert (
entity_registry.async_get_entity_id(
SENSOR_DOMAIN, DOMAIN, "37464C4F32313139303333373331"
)
== "sensor.gas_meter_reading_alt"
)
assert (
"Skip migration of sensor.gas_meter_reading because it already exists"
in caplog.text
)

0 comments on commit e052ab2

Please sign in to comment.