Skip to content
Snippets Groups Projects
Unverified Commit e7c25d1c authored by J. Nick Koston's avatar J. Nick Koston Committed by GitHub
Browse files

Migrate powerwall unique ids to use the gateway din (#107509)

parent e4a15354
No related branches found
No related tags found
No related merge requests found
......@@ -21,6 +21,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD, Platform
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.aiohttp_client import async_create_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
......@@ -151,7 +152,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
raise ConfigEntryNotReady from err
gateway_din = base_info.gateway_din
if gateway_din and entry.unique_id is not None and is_ip_address(entry.unique_id):
if entry.unique_id is not None and is_ip_address(entry.unique_id):
hass.config_entries.async_update_entry(entry, unique_id=gateway_din)
runtime_data = PowerwallRuntimeData(
......@@ -178,11 +179,36 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = runtime_data
await async_migrate_entity_unique_ids(hass, entry, base_info)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_migrate_entity_unique_ids(
hass: HomeAssistant, entry: ConfigEntry, base_info: PowerwallBaseInfo
) -> None:
"""Migrate old entity unique ids to use gateway_din."""
old_base_unique_id = "_".join(base_info.serial_numbers)
new_base_unique_id = base_info.gateway_din
dev_reg = dr.async_get(hass)
if device := dev_reg.async_get_device(identifiers={(DOMAIN, old_base_unique_id)}):
dev_reg.async_update_device(
device.id, new_identifiers={(DOMAIN, new_base_unique_id)}
)
ent_reg = er.async_get(hass)
for ent_entry in er.async_entries_for_config_entry(ent_reg, entry.entry_id):
current_unique_id = ent_entry.unique_id
if current_unique_id.startswith(old_base_unique_id):
new_unique_id = f"{new_base_unique_id}{current_unique_id.removeprefix(old_base_unique_id)}"
ent_reg.async_update_entity(
ent_entry.entity_id, new_unique_id=new_unique_id
)
async def _login_and_fetch_base_info(
power_wall: Powerwall, host: str, password: str | None
) -> PowerwallBaseInfo:
......
......@@ -29,8 +29,7 @@ class PowerWallEntity(CoordinatorEntity[DataUpdateCoordinator[PowerwallData]]):
assert coordinator is not None
super().__init__(coordinator)
self.power_wall = powerwall_data[POWERWALL_API]
# The serial numbers of the powerwalls are unique to every site
self.base_unique_id = "_".join(base_info.serial_numbers)
self.base_unique_id = base_info.gateway_din
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self.base_unique_id)},
manufacturer=MANUFACTURER,
......
......@@ -21,7 +21,7 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
class PowerwallBaseInfo:
"""Base information for the powerwall integration."""
gateway_din: None | str
gateway_din: str
site_info: SiteInfoResponse
status: PowerwallStatusResponse
device_type: DeviceType
......
......@@ -16,10 +16,10 @@ from homeassistant.const import (
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers import device_registry as dr, entity_registry as er
import homeassistant.util.dt as dt_util
from .mocks import _mock_powerwall_with_fixtures
from .mocks import MOCK_GATEWAY_DIN, _mock_powerwall_with_fixtures
from tests.common import MockConfigEntry, async_fire_time_changed
......@@ -44,7 +44,7 @@ async def test_sensors(
device_registry = dr.async_get(hass)
reg_device = device_registry.async_get_device(
identifiers={("powerwall", "TG0123456789AB_TG9876543210BA")},
identifiers={("powerwall", MOCK_GATEWAY_DIN)},
)
assert reg_device.model == "PowerWall 2 (GW1)"
assert reg_device.sw_version == "1.50.1 c58c2df3"
......@@ -173,3 +173,64 @@ async def test_sensors_with_empty_meters(hass: HomeAssistant) -> None:
await hass.async_block_till_done()
assert hass.states.get("sensor.mysite_solar_power") is None
async def test_unique_id_migrate(
hass: HomeAssistant, entity_registry_enabled_by_default: None
) -> None:
"""Test we can migrate unique ids of the sensors."""
device_registry = dr.async_get(hass)
ent_reg = er.async_get(hass)
config_entry = MockConfigEntry(domain=DOMAIN, data={CONF_IP_ADDRESS: "1.2.3.4"})
config_entry.add_to_hass(hass)
mock_powerwall = await _mock_powerwall_with_fixtures(hass)
old_unique_id = "_".join(sorted(["TG0123456789AB", "TG9876543210BA"]))
new_unique_id = MOCK_GATEWAY_DIN
device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
identifiers={("powerwall", old_unique_id)},
manufacturer="Tesla",
)
old_mysite_load_power_entity = ent_reg.async_get_or_create(
"sensor",
DOMAIN,
unique_id=f"{old_unique_id}_load_instant_power",
suggested_object_id="mysite_load_power",
config_entry=config_entry,
)
assert old_mysite_load_power_entity.entity_id == "sensor.mysite_load_power"
with patch(
"homeassistant.components.powerwall.config_flow.Powerwall",
return_value=mock_powerwall,
), patch(
"homeassistant.components.powerwall.Powerwall", return_value=mock_powerwall
):
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
reg_device = device_registry.async_get_device(
identifiers={("powerwall", MOCK_GATEWAY_DIN)},
)
old_reg_device = device_registry.async_get_device(
identifiers={("powerwall", old_unique_id)},
)
assert old_reg_device is None
assert reg_device is not None
assert (
ent_reg.async_get_entity_id(
"sensor", DOMAIN, f"{old_unique_id}_load_instant_power"
)
is None
)
assert (
ent_reg.async_get_entity_id(
"sensor", DOMAIN, f"{new_unique_id}_load_instant_power"
)
is not None
)
state = hass.states.get("sensor.mysite_load_power")
assert state.state == "1.971"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment