mirror of
https://github.com/home-assistant/core.git
synced 2025-07-08 13:57:10 +00:00
Migrate unique ID in vesync switches (#137099)
This commit is contained in:
parent
b5662ded2c
commit
37461d727a
@ -7,6 +7,7 @@ from pyvesync import VeSync
|
|||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
|
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall
|
from homeassistant.core import HomeAssistant, ServiceCall
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
from .common import async_generate_device_list
|
from .common import async_generate_device_list
|
||||||
@ -91,3 +92,37 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
hass.data.pop(DOMAIN)
|
hass.data.pop(DOMAIN)
|
||||||
|
|
||||||
return unload_ok
|
return unload_ok
|
||||||
|
|
||||||
|
|
||||||
|
async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||||
|
"""Migrate old entry."""
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Migrating VeSync config entry: %s minor version: %s",
|
||||||
|
config_entry.version,
|
||||||
|
config_entry.minor_version,
|
||||||
|
)
|
||||||
|
if config_entry.minor_version == 1:
|
||||||
|
# Migrate switch/outlets entity to a new unique ID
|
||||||
|
_LOGGER.debug("Migrating VeSync config entry from version 1 to version 2")
|
||||||
|
entity_registry = er.async_get(hass)
|
||||||
|
registry_entries = er.async_entries_for_config_entry(
|
||||||
|
entity_registry, config_entry.entry_id
|
||||||
|
)
|
||||||
|
for reg_entry in registry_entries:
|
||||||
|
if "-" not in reg_entry.unique_id and reg_entry.entity_id.startswith(
|
||||||
|
Platform.SWITCH
|
||||||
|
):
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Migrating switch/outlet entity from unique_id: %s to unique_id: %s",
|
||||||
|
reg_entry.unique_id,
|
||||||
|
reg_entry.unique_id + "-device_status",
|
||||||
|
)
|
||||||
|
entity_registry.async_update_entity(
|
||||||
|
reg_entry.entity_id,
|
||||||
|
new_unique_id=reg_entry.unique_id + "-device_status",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
_LOGGER.debug("Skipping entity with unique_id: %s", reg_entry.unique_id)
|
||||||
|
hass.config_entries.async_update_entry(config_entry, minor_version=2)
|
||||||
|
|
||||||
|
return True
|
||||||
|
@ -24,6 +24,7 @@ class VeSyncFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||||||
"""Handle a config flow."""
|
"""Handle a config flow."""
|
||||||
|
|
||||||
VERSION = 1
|
VERSION = 1
|
||||||
|
MINOR_VERSION = 2
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _show_form(self, errors: dict[str, str] | None = None) -> ConfigFlowResult:
|
def _show_form(self, errors: dict[str, str] | None = None) -> ConfigFlowResult:
|
||||||
|
@ -83,6 +83,7 @@ class VeSyncSwitchHA(VeSyncBaseSwitch, SwitchEntity):
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the VeSync switch device."""
|
"""Initialize the VeSync switch device."""
|
||||||
super().__init__(plug, coordinator)
|
super().__init__(plug, coordinator)
|
||||||
|
self._attr_unique_id = f"{super().unique_id}-device_status"
|
||||||
self.smartplug = plug
|
self.smartplug = plug
|
||||||
|
|
||||||
|
|
||||||
@ -94,4 +95,5 @@ class VeSyncLightSwitch(VeSyncBaseSwitch, SwitchEntity):
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize Light Switch device class."""
|
"""Initialize Light Switch device class."""
|
||||||
super().__init__(switch, coordinator)
|
super().__init__(switch, coordinator)
|
||||||
|
self._attr_unique_id = f"{super().unique_id}-device_status"
|
||||||
self.switch = switch
|
self.switch = switch
|
||||||
|
@ -153,3 +153,25 @@ async def humidifier_config_entry(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
return entry
|
return entry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="switch_old_id_config_entry")
|
||||||
|
async def switch_old_id_config_entry(
|
||||||
|
hass: HomeAssistant, requests_mock: requests_mock.Mocker, config
|
||||||
|
) -> MockConfigEntry:
|
||||||
|
"""Create a mock VeSync config entry for `switch` with the old unique ID approach."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
title="VeSync",
|
||||||
|
domain=DOMAIN,
|
||||||
|
data=config[DOMAIN],
|
||||||
|
version=1,
|
||||||
|
minor_version=1,
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
wall_switch = "Wall Switch"
|
||||||
|
humidifer = "Humidifier 200s"
|
||||||
|
|
||||||
|
mock_multiple_device_responses(requests_mock, [wall_switch, humidifer])
|
||||||
|
|
||||||
|
return entry
|
||||||
|
@ -367,7 +367,7 @@
|
|||||||
'previous_unique_id': None,
|
'previous_unique_id': None,
|
||||||
'supported_features': 0,
|
'supported_features': 0,
|
||||||
'translation_key': None,
|
'translation_key': None,
|
||||||
'unique_id': 'outlet',
|
'unique_id': 'outlet-device_status',
|
||||||
'unit_of_measurement': None,
|
'unit_of_measurement': None,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
@ -525,7 +525,7 @@
|
|||||||
'previous_unique_id': None,
|
'previous_unique_id': None,
|
||||||
'supported_features': 0,
|
'supported_features': 0,
|
||||||
'translation_key': None,
|
'translation_key': None,
|
||||||
'unique_id': 'switch',
|
'unique_id': 'switch-device_status',
|
||||||
'unit_of_measurement': None,
|
'unit_of_measurement': None,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
@ -10,6 +10,9 @@ from homeassistant.components.vesync.const import DOMAIN, VS_DEVICES, VS_MANAGER
|
|||||||
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
|
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def test_async_setup_entry__not_login(
|
async def test_async_setup_entry__not_login(
|
||||||
@ -125,3 +128,55 @@ async def test_async_new_device_discovery(
|
|||||||
assert manager.login.call_count == 1
|
assert manager.login.call_count == 1
|
||||||
assert hass.data[DOMAIN][VS_MANAGER] == manager
|
assert hass.data[DOMAIN][VS_MANAGER] == manager
|
||||||
assert hass.data[DOMAIN][VS_DEVICES] == [fan, humidifier]
|
assert hass.data[DOMAIN][VS_DEVICES] == [fan, humidifier]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_migrate_config_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
switch_old_id_config_entry: MockConfigEntry,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test migration of config entry. Only migrates switches to a new unique_id."""
|
||||||
|
switch: er.RegistryEntry = entity_registry.async_get_or_create(
|
||||||
|
domain="switch",
|
||||||
|
platform="vesync",
|
||||||
|
unique_id="switch",
|
||||||
|
config_entry=switch_old_id_config_entry,
|
||||||
|
suggested_object_id="switch",
|
||||||
|
)
|
||||||
|
|
||||||
|
humidifer: er.RegistryEntry = entity_registry.async_get_or_create(
|
||||||
|
domain="humidifer",
|
||||||
|
platform="vesync",
|
||||||
|
unique_id="humidifer",
|
||||||
|
config_entry=switch_old_id_config_entry,
|
||||||
|
suggested_object_id="humidifer",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert switch.unique_id == "switch"
|
||||||
|
assert switch_old_id_config_entry.minor_version == 1
|
||||||
|
assert humidifer.unique_id == "humidifer"
|
||||||
|
|
||||||
|
await hass.config_entries.async_setup(switch_old_id_config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert switch_old_id_config_entry.minor_version == 2
|
||||||
|
|
||||||
|
migrated_switch = entity_registry.async_get(switch.entity_id)
|
||||||
|
assert migrated_switch is not None
|
||||||
|
assert migrated_switch.entity_id.startswith("switch")
|
||||||
|
assert migrated_switch.unique_id == "switch-device_status"
|
||||||
|
# Confirm humidifer was not impacted
|
||||||
|
migrated_humidifer = entity_registry.async_get(humidifer.entity_id)
|
||||||
|
assert migrated_humidifer is not None
|
||||||
|
assert migrated_humidifer.unique_id == "humidifer"
|
||||||
|
|
||||||
|
# Assert that only one entity exists in the switch domain
|
||||||
|
switch_entities = [
|
||||||
|
e for e in entity_registry.entities.values() if e.domain == "switch"
|
||||||
|
]
|
||||||
|
assert len(switch_entities) == 1
|
||||||
|
|
||||||
|
humidifer_entities = [
|
||||||
|
e for e in entity_registry.entities.values() if e.domain == "humidifer"
|
||||||
|
]
|
||||||
|
assert len(humidifer_entities) == 1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user