1 """Various helpers to handle config entry and api schema migrations."""
5 from aiohue
import HueBridgeV2
6 from aiohue.discovery
import is_v2_bridge
7 from aiohue.v2.models.device
import DeviceArchetypes
8 from aiohue.v2.models.resource
import ResourceTypes
10 from homeassistant
import core
17 device_registry
as dr,
18 entity_registry
as er,
21 from .const
import DOMAIN
23 LOGGER = logging.getLogger(__name__)
27 """Check if config entry needs any migration actions."""
28 host = entry.data[CONF_HOST]
31 if CONF_USERNAME
in entry.data:
32 LOGGER.info(
"Migrate %s to %s in schema", CONF_USERNAME, CONF_API_KEY)
33 data =
dict(entry.data)
34 data[CONF_API_KEY] = data.pop(CONF_USERNAME)
35 hass.config_entries.async_update_entry(entry, data=data)
37 if (conf_api_version := entry.data.get(CONF_API_VERSION, 1)) == 1:
40 websession = aiohttp_client.async_get_clientsession(hass)
41 if await is_v2_bridge(host, websession):
42 supported_api_version = 2
44 supported_api_version = 1
46 "Configured api version is %s and supported api version %s for bridge %s",
48 supported_api_version,
55 if conf_api_version == 1
and supported_api_version == 2:
61 CONF_API_VERSION
not in entry.data
62 or conf_api_version != supported_api_version
64 data =
dict(entry.data)
65 data[CONF_API_VERSION] = supported_api_version
66 hass.config_entries.async_update_entry(entry, data=data)
70 """Perform migration of devices and entities to V2 Id's."""
71 host = entry.data[CONF_HOST]
72 api_key = entry.data[CONF_API_KEY]
73 dev_reg = dr.async_get(hass)
74 ent_reg = er.async_get(hass)
75 LOGGER.info(
"Start of migration of devices and entities to support API schema 2")
81 for hass_dev
in dr.async_entries_for_config_entry(dev_reg, entry.entry_id):
82 for domain, mac
in hass_dev.identifiers:
85 normalized_mac = mac.split(
"-")[0]
86 dev_ids[normalized_mac] = hass_dev.id
89 async
with HueBridgeV2(host, api_key)
as api:
90 sensor_class_mapping = {
91 SensorDeviceClass.BATTERY.value: ResourceTypes.DEVICE_POWER,
92 BinarySensorDeviceClass.MOTION.value: ResourceTypes.MOTION,
93 SensorDeviceClass.ILLUMINANCE.value: ResourceTypes.LIGHT_LEVEL,
94 SensorDeviceClass.TEMPERATURE.value: ResourceTypes.TEMPERATURE,
98 for hue_dev
in api.devices:
99 zigbee = api.devices.get_zigbee_connectivity(hue_dev.id)
100 if not zigbee
or not zigbee.mac_address:
105 if hue_dev.product_data.product_archetype == DeviceArchetypes.BRIDGE_V2:
106 hass_dev_id = dev_ids.get(api.config.bridge_id.upper())
108 hass_dev_id = dev_ids.get(zigbee.mac_address)
109 if hass_dev_id
is None:
113 "Ignoring device %s (%s) as it does not (yet) exist in the"
116 hue_dev.metadata.name,
120 dev_reg.async_update_device(
121 hass_dev_id, new_identifiers={(DOMAIN, hue_dev.id)}
123 LOGGER.info(
"Migrated device %s (%s)", hue_dev.metadata.name, hass_dev_id)
126 for ent
in er.async_entries_for_device(ent_reg, hass_dev_id,
True):
127 if ent.entity_id.startswith(
"light"):
130 new_unique_id = next(iter(hue_dev.lights),
None)
133 matched_dev_class = sensor_class_mapping.get(
134 ent.original_device_class
or "unknown"
136 new_unique_id = next(
139 for sensor
in api.devices.get_sensors(hue_dev.id)
140 if sensor.type == matched_dev_class
145 if new_unique_id
is None:
149 "Skip migration of %s because it no longer exists on the"
157 ent_reg.async_update_entity(
158 ent.entity_id, new_unique_id=new_unique_id
165 "Skip migration of %s because it already exists",
170 "Migrated entity %s from unique id %s to %s",
177 for ent
in er.async_entries_for_config_entry(ent_reg, entry.entry_id):
178 if ent.device_id
is not None:
180 if "-" in ent.unique_id:
182 hue_group = api.groups.get(ent.unique_id)
185 v1_id = f
"/groups/{ent.unique_id}"
186 hue_group = api.groups.room.get_by_v1_id(
188 )
or api.groups.zone.get_by_v1_id(v1_id)
189 if hue_group
is None or hue_group.grouped_light
is None:
192 "Skip migration of %s because it no longer exist on the bridge",
196 new_unique_id = hue_group.grouped_light
198 "Migrating %s from unique id %s to %s ",
204 ent_reg.async_update_entity(ent.entity_id, new_unique_id=new_unique_id)
210 "Skip migration of %s because it already exists",
213 LOGGER.info(
"Migration of devices and entities to support API schema 2 finished")
None check_migration(core.HomeAssistant hass, ConfigEntry entry)
None handle_v2_migration(core.HomeAssistant hass, ConfigEntry entry)