mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Fix zwave_js unique ID migration logic (#47031)
This commit is contained in:
parent
7dc9071776
commit
a43f3c1a0c
@ -85,6 +85,21 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
dev_reg = await device_registry.async_get_registry(hass)
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
|
||||
@callback
|
||||
def migrate_entity(platform: str, old_unique_id: str, new_unique_id: str) -> None:
|
||||
"""Check if entity with old unique ID exists, and if so migrate it to new ID."""
|
||||
if entity_id := ent_reg.async_get_entity_id(platform, DOMAIN, old_unique_id):
|
||||
LOGGER.debug(
|
||||
"Migrating entity %s from old unique ID '%s' to new unique ID '%s'",
|
||||
entity_id,
|
||||
old_unique_id,
|
||||
new_unique_id,
|
||||
)
|
||||
ent_reg.async_update_entity(
|
||||
entity_id,
|
||||
new_unique_id=new_unique_id,
|
||||
)
|
||||
|
||||
@callback
|
||||
def async_on_node_ready(node: ZwaveNode) -> None:
|
||||
"""Handle node ready event."""
|
||||
@ -97,26 +112,49 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
for disc_info in async_discover_values(node):
|
||||
LOGGER.debug("Discovered entity: %s", disc_info)
|
||||
|
||||
# This migration logic was added in 2021.3 to handle breaking change to
|
||||
# value_id format. Some time in the future, this code block
|
||||
# (and get_old_value_id helper) can be removed.
|
||||
old_value_id = get_old_value_id(disc_info.primary_value)
|
||||
old_unique_id = get_unique_id(
|
||||
client.driver.controller.home_id, old_value_id
|
||||
# This migration logic was added in 2021.3 to handle a breaking change to
|
||||
# the value_id format. Some time in the future, this code block
|
||||
# (as well as get_old_value_id helper and migrate_entity closure) can be
|
||||
# removed.
|
||||
value_ids = [
|
||||
# 2021.2.* format
|
||||
get_old_value_id(disc_info.primary_value),
|
||||
# 2021.3.0b0 format
|
||||
disc_info.primary_value.value_id,
|
||||
]
|
||||
|
||||
new_unique_id = get_unique_id(
|
||||
client.driver.controller.home_id,
|
||||
disc_info.primary_value.value_id,
|
||||
)
|
||||
if entity_id := ent_reg.async_get_entity_id(
|
||||
disc_info.platform, DOMAIN, old_unique_id
|
||||
):
|
||||
LOGGER.debug(
|
||||
"Entity %s is using old unique ID, migrating to new one", entity_id
|
||||
)
|
||||
ent_reg.async_update_entity(
|
||||
entity_id,
|
||||
new_unique_id=get_unique_id(
|
||||
client.driver.controller.home_id,
|
||||
disc_info.primary_value.value_id,
|
||||
),
|
||||
|
||||
for value_id in value_ids:
|
||||
old_unique_id = get_unique_id(
|
||||
client.driver.controller.home_id,
|
||||
f"{disc_info.primary_value.node.node_id}.{value_id}",
|
||||
)
|
||||
# Most entities have the same ID format, but notification binary sensors
|
||||
# have a state key in their ID so we need to handle them differently
|
||||
if (
|
||||
disc_info.platform == "binary_sensor"
|
||||
and disc_info.platform_hint == "notification"
|
||||
):
|
||||
for state_key in disc_info.primary_value.metadata.states:
|
||||
# ignore idle key (0)
|
||||
if state_key == "0":
|
||||
continue
|
||||
|
||||
migrate_entity(
|
||||
disc_info.platform,
|
||||
f"{old_unique_id}.{state_key}",
|
||||
f"{new_unique_id}.{state_key}",
|
||||
)
|
||||
|
||||
# Once we've iterated through all state keys, we can move on to the
|
||||
# next item
|
||||
continue
|
||||
|
||||
migrate_entity(disc_info.platform, old_unique_id, new_unique_id)
|
||||
|
||||
async_dispatcher_send(
|
||||
hass, f"{DOMAIN}_{entry.entry_id}_add_{disc_info.platform}", disc_info
|
||||
|
@ -24,11 +24,6 @@ class ZwaveDiscoveryInfo:
|
||||
# hint for the platform about this discovered entity
|
||||
platform_hint: Optional[str] = ""
|
||||
|
||||
@property
|
||||
def value_id(self) -> str:
|
||||
"""Return the unique value_id belonging to primary value."""
|
||||
return f"{self.node.node_id}.{self.primary_value.value_id}"
|
||||
|
||||
|
||||
@dataclass
|
||||
class ZWaveValueDiscoverySchema:
|
||||
|
@ -32,7 +32,7 @@ class ZWaveBaseEntity(Entity):
|
||||
self.info = info
|
||||
self._name = self.generate_name()
|
||||
self._unique_id = get_unique_id(
|
||||
self.client.driver.controller.home_id, self.info.value_id
|
||||
self.client.driver.controller.home_id, self.info.primary_value.value_id
|
||||
)
|
||||
# entities requiring additional values, can add extra ids to this list
|
||||
self.watched_value_ids = {self.info.primary_value.value_id}
|
||||
|
@ -18,7 +18,7 @@ from homeassistant.config_entries import (
|
||||
from homeassistant.const import STATE_UNAVAILABLE
|
||||
from homeassistant.helpers import device_registry, entity_registry
|
||||
|
||||
from .common import AIR_TEMPERATURE_SENSOR
|
||||
from .common import AIR_TEMPERATURE_SENSOR, NOTIFICATION_MOTION_BINARY_SENSOR
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
@ -124,13 +124,15 @@ async def test_on_node_added_ready(
|
||||
)
|
||||
|
||||
|
||||
async def test_unique_id_migration(hass, multisensor_6_state, client, integration):
|
||||
"""Test unique ID is migrated from old format to new."""
|
||||
async def test_unique_id_migration_v1(hass, multisensor_6_state, client, integration):
|
||||
"""Test unique ID is migrated from old format to new (version 1)."""
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
|
||||
# Migrate version 1
|
||||
entity_name = AIR_TEMPERATURE_SENSOR.split(".")[1]
|
||||
|
||||
# Create entity RegistryEntry using old unique ID format
|
||||
old_unique_id = f"{client.driver.controller.home_id}.52-49-00-Air temperature-00"
|
||||
old_unique_id = f"{client.driver.controller.home_id}.52.52-49-00-Air temperature-00"
|
||||
entity_entry = ent_reg.async_get_or_create(
|
||||
"sensor",
|
||||
DOMAIN,
|
||||
@ -155,6 +157,73 @@ async def test_unique_id_migration(hass, multisensor_6_state, client, integratio
|
||||
assert entity_entry.unique_id == new_unique_id
|
||||
|
||||
|
||||
async def test_unique_id_migration_v2(hass, multisensor_6_state, client, integration):
|
||||
"""Test unique ID is migrated from old format to new (version 2)."""
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
# Migrate version 2
|
||||
ILLUMINANCE_SENSOR = "sensor.multisensor_6_illuminance"
|
||||
entity_name = ILLUMINANCE_SENSOR.split(".")[1]
|
||||
|
||||
# Create entity RegistryEntry using old unique ID format
|
||||
old_unique_id = f"{client.driver.controller.home_id}.52.52-49-0-Illuminance-00-00"
|
||||
entity_entry = ent_reg.async_get_or_create(
|
||||
"sensor",
|
||||
DOMAIN,
|
||||
old_unique_id,
|
||||
suggested_object_id=entity_name,
|
||||
config_entry=integration,
|
||||
original_name=entity_name,
|
||||
)
|
||||
assert entity_entry.entity_id == ILLUMINANCE_SENSOR
|
||||
assert entity_entry.unique_id == old_unique_id
|
||||
|
||||
# Add a ready node, unique ID should be migrated
|
||||
node = Node(client, multisensor_6_state)
|
||||
event = {"node": node}
|
||||
|
||||
client.driver.controller.emit("node added", event)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Check that new RegistryEntry is using new unique ID format
|
||||
entity_entry = ent_reg.async_get(ILLUMINANCE_SENSOR)
|
||||
new_unique_id = f"{client.driver.controller.home_id}.52-49-0-Illuminance-00-00"
|
||||
assert entity_entry.unique_id == new_unique_id
|
||||
|
||||
|
||||
async def test_unique_id_migration_notification_binary_sensor(
|
||||
hass, multisensor_6_state, client, integration
|
||||
):
|
||||
"""Test unique ID is migrated from old format to new for a notification binary sensor."""
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
|
||||
entity_name = NOTIFICATION_MOTION_BINARY_SENSOR.split(".")[1]
|
||||
|
||||
# Create entity RegistryEntry using old unique ID format
|
||||
old_unique_id = f"{client.driver.controller.home_id}.52.52-113-00-Home Security-Motion sensor status.8"
|
||||
entity_entry = ent_reg.async_get_or_create(
|
||||
"binary_sensor",
|
||||
DOMAIN,
|
||||
old_unique_id,
|
||||
suggested_object_id=entity_name,
|
||||
config_entry=integration,
|
||||
original_name=entity_name,
|
||||
)
|
||||
assert entity_entry.entity_id == NOTIFICATION_MOTION_BINARY_SENSOR
|
||||
assert entity_entry.unique_id == old_unique_id
|
||||
|
||||
# Add a ready node, unique ID should be migrated
|
||||
node = Node(client, multisensor_6_state)
|
||||
event = {"node": node}
|
||||
|
||||
client.driver.controller.emit("node added", event)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Check that new RegistryEntry is using new unique ID format
|
||||
entity_entry = ent_reg.async_get(NOTIFICATION_MOTION_BINARY_SENSOR)
|
||||
new_unique_id = f"{client.driver.controller.home_id}.52-113-0-Home Security-Motion sensor status-Motion sensor status.8"
|
||||
assert entity_entry.unique_id == new_unique_id
|
||||
|
||||
|
||||
async def test_on_node_added_not_ready(
|
||||
hass, multisensor_6_state, client, integration, device_registry
|
||||
):
|
||||
|
Loading…
x
Reference in New Issue
Block a user