182 files

This commit is contained in:
Home Assistant Version Control
2026-08-17 12:11:35 +00:00
parent 7dddf6bb13
commit ece15a1c1b
183 changed files with 11457 additions and 3092 deletions
+90 -14
View File
@@ -80,6 +80,25 @@ PLATFORMS = COORDINATOR_AWARE_PLATFORMS + [
Platform.SWITCH,
]
# Suffixes used when building gateway-attached entity unique_ids in sensor.py
# (e.g. f"{device.identifier.lower()}-{suffix}"). Used to migrate those
# unique_ids when the gateway's identifier changes from DSN-based to MAC-based.
GATEWAY_ENTITY_SUFFIXES = [
"defi_hilo",
"recompenses_hilo",
"notifications_hilo",
"outdoor_weather_hilo",
"hilo_gateway",
"hilo_rate_current",
"hilo_rate_low",
"hilo_rate_medium",
"hilo_rate_high",
"hilo_rate_access",
"hilo_rate_low_threshold",
"hilo_rate_reward_rate",
"hilo_cost_total",
]
@callback
def _async_standardize_config_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
@@ -124,9 +143,39 @@ def _async_register_custom_device(
)
async def async_setup_entry( # noqa: C901
hass: HomeAssistant, entry: ConfigEntry
) -> bool:
@callback
def _async_migrate_gateway_device_identifier(
hass: HomeAssistant, entry: ConfigEntry, old_dsn: str | None, new_mac: str
) -> None:
"""Migrate the gateway device registry entry from DSN-based to MAC-based identity.
Preserves the device's registry entry (and thus its device_id, so entities,
dashboards, and automations referencing it stay attached) by renaming its
identifier in place instead of letting a new device get created.
"""
if not old_dsn or old_dsn == new_mac:
return
device_registry = dr.async_get(hass)
old_device = device_registry.async_get_device(identifiers={(DOMAIN, old_dsn)})
if old_device is None:
return # fresh install, or already migrated
new_device = device_registry.async_get_device(identifiers={(DOMAIN, new_mac)})
if new_device is not None and new_device.id != old_device.id:
LOG.warning(
"Gateway device already registered under new identifier %s, skipping device migration",
new_mac,
)
return
device_registry.async_update_device(
old_device.id, new_identifiers={(DOMAIN, new_mac)}
)
LOG.info("Migrated gateway device identifier %s -> %s", old_dsn, new_mac)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Hilo as config entry."""
HiloFlowHandler.async_register_implementation(
hass, AuthCodeWithPKCEImplementation(hass)
@@ -160,9 +209,7 @@ async def async_setup_entry( # noqa: C901
_async_standardize_config_entry(hass, entry)
scan_interval = current_options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
scan_interval = (
scan_interval if scan_interval >= MIN_SCAN_INTERVAL else MIN_SCAN_INTERVAL
)
scan_interval = max(scan_interval, MIN_SCAN_INTERVAL)
hilo = Hilo(hass, entry, api)
try:
@@ -176,9 +223,7 @@ async def async_setup_entry( # noqa: C901
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = hilo
hass.async_create_task(
hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
# Note (ic-dev21): This is a bit of a hack to rename some entities that were created with non-standard names in early versions
# HA has changed the way they name entities linked to a device by default and this breaks the naming scheme of the gateway entities.
@@ -731,6 +776,29 @@ class Hilo:
)
return self._events[event_id]
async def _fetch_legacy_gateway_dsn(self, new_mac: str) -> str | None:
"""This function looks up the Hilo gateway device in the device registry and
returns its old DSN-based identifier if it exists. If it doesn't,
it returns Noneto use the MAC address instead."""
device_registry = dr.async_get(self._hass)
for device in device_registry.devices.values():
if device.manufacturer != "Hilo" or device.model != "EQ000017":
continue
for domain, identifier in device.identifiers:
if domain == DOMAIN and identifier != new_mac:
return identifier
return None
@callback
def async_migrate_gateway_entities(self, old_dsn: str | None, new_mac: str) -> None:
"""Migrate gateway-attached entity unique_ids from DSN-based to MAC-based."""
if not old_dsn or old_dsn == new_mac:
return
for suffix in GATEWAY_ENTITY_SUFFIXES:
old_unique_id = f"{old_dsn.lower()}-{suffix}"
new_unique_id = f"{new_mac.lower()}-{suffix}"
self.async_migrate_unique_id(old_unique_id, new_unique_id, Platform.SENSOR)
async def async_init(self, scan_interval: int) -> None:
"""Initialize the Hilo "manager" class.
@@ -772,10 +840,18 @@ class Hilo:
)
)
# Step 6: Register custom devices in HA
_async_register_custom_device(
self._hass, self.entry, self.devices.find_device(1)
)
# Step 6: Migrate gateway identity (DSN -> MAC) if needed, then register
# custom devices in HA.
gateway = self.devices.find_device(1)
if gateway:
old_dsn = await self._fetch_legacy_gateway_dsn(gateway.identifier)
if old_dsn:
_async_migrate_gateway_device_identifier(
self._hass, self.entry, old_dsn, gateway.identifier
)
self.async_migrate_gateway_entities(old_dsn, gateway.identifier)
_async_register_custom_device(self._hass, self.entry, gateway)
if self.track_unknown_sources:
if not self.unknown_tracker_device:
self.unknown_tracker_device = self.devices.generate_device(
@@ -1122,7 +1198,7 @@ class Hilo:
ATTR_UNIT_OF_MEASUREMENT: parent_unit, # note ic-dev21: now uses parent_unit directly
ATTR_DEVICE_CLASS: SensorDeviceClass.ENERGY,
}
if not all(a in attrs.keys() for a in new_attrs.keys()):
if not all(a in attrs.keys() for a in new_attrs):
LOG.warning(
f"Fixing utility sensor: {entity} {current_state} new_attrs: {new_attrs}"
)