Skip to content

Commit 28bee6d

Browse files
authored
Fix unique IDs and migrate v1 entries (home-assistant#155319)
1 parent c9d68dd commit 28bee6d

File tree

8 files changed

+193
-37
lines changed

8 files changed

+193
-37
lines changed

homeassistant/components/libre_hardware_monitor/__init__.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,75 @@
22

33
from __future__ import annotations
44

5+
import logging
6+
57
from homeassistant.const import Platform
68
from homeassistant.core import HomeAssistant
9+
from homeassistant.helpers import device_registry as dr, entity_registry as er
710

11+
from .const import DOMAIN
812
from .coordinator import (
913
LibreHardwareMonitorConfigEntry,
1014
LibreHardwareMonitorCoordinator,
1115
)
1216

1317
PLATFORMS = [Platform.SENSOR]
1418

19+
_LOGGER = logging.getLogger(__name__)
20+
21+
22+
async def async_migrate_entry(
23+
hass: HomeAssistant, config_entry: LibreHardwareMonitorConfigEntry
24+
) -> bool:
25+
"""Migrate non-unique entity and device ids."""
26+
_LOGGER.debug("Migrating from version %s", config_entry.version)
27+
28+
if config_entry.version == 1:
29+
# Migrate entity identifiers
30+
entity_registry = er.async_get(hass)
31+
registry_entries = er.async_entries_for_config_entry(
32+
entity_registry, config_entry.entry_id
33+
)
34+
for reg_entry in registry_entries:
35+
new_entity_id = f"{config_entry.entry_id}_{reg_entry.unique_id[4:]}"
36+
_LOGGER.debug(
37+
"Migrating entity %s unique id from %s to %s",
38+
reg_entry.entity_id,
39+
reg_entry.unique_id,
40+
new_entity_id,
41+
)
42+
entity_registry.async_update_entity(
43+
reg_entry.entity_id, new_unique_id=new_entity_id
44+
)
45+
46+
# Migrate device identifiers
47+
device_registry = dr.async_get(hass)
48+
device_entries = dr.async_entries_for_config_entry(
49+
registry=device_registry, config_entry_id=config_entry.entry_id
50+
)
51+
for device in device_entries:
52+
old_device_id = next(iter(device.identifiers))[1]
53+
new_device_id = f"{config_entry.entry_id}_{old_device_id}"
54+
_LOGGER.debug(
55+
"Migrating device %s unique id from %s to %s",
56+
device.name,
57+
old_device_id,
58+
new_device_id,
59+
)
60+
device_registry.async_update_device(
61+
device_id=device.id,
62+
new_identifiers={(DOMAIN, new_device_id)},
63+
)
64+
65+
hass.config_entries.async_update_entry(
66+
config_entry, data=config_entry.data, version=2
67+
)
68+
69+
_LOGGER.debug("Migration to version 2 successful")
70+
return True
71+
72+
return True
73+
1574

1675
async def async_setup_entry(
1776
hass: HomeAssistant, config_entry: LibreHardwareMonitorConfigEntry

homeassistant/components/libre_hardware_monitor/config_flow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
class LibreHardwareMonitorConfigFlow(ConfigFlow, domain=DOMAIN):
3131
"""Handle a config flow for LibreHardwareMonitor."""
3232

33-
VERSION = 1
33+
VERSION = 2
3434

3535
async def async_step_user(
3636
self, user_input: dict[str, Any] | None = None

homeassistant/components/libre_hardware_monitor/coordinator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ async def _async_handle_changes_in_devices(
114114
device_registry = dr.async_get(self.hass)
115115
for device_id in orphaned_devices:
116116
if device := device_registry.async_get_device(
117-
identifiers={(DOMAIN, device_id)}
117+
identifiers={(DOMAIN, f"{self.config_entry.entry_id}_{device_id}")}
118118
):
119119
device_registry.async_update_device(
120120
device_id=device.id,

homeassistant/components/libre_hardware_monitor/sensor.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@
1010
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
1111
from homeassistant.helpers.update_coordinator import CoordinatorEntity
1212

13-
from . import LibreHardwareMonitorCoordinator
13+
from . import LibreHardwareMonitorConfigEntry, LibreHardwareMonitorCoordinator
1414
from .const import DOMAIN
15-
from .coordinator import LibreHardwareMonitorConfigEntry
1615

17-
# Coordinator is used to centralize the data updates
1816
PARALLEL_UPDATES = 0
1917

2018
STATE_MIN_VALUE = "min_value"
@@ -30,7 +28,7 @@ async def async_setup_entry(
3028
lhm_coordinator = config_entry.runtime_data
3129

3230
async_add_entities(
33-
LibreHardwareMonitorSensor(lhm_coordinator, sensor_data)
31+
LibreHardwareMonitorSensor(lhm_coordinator, config_entry.entry_id, sensor_data)
3432
for sensor_data in lhm_coordinator.data.sensor_data.values()
3533
)
3634

@@ -46,6 +44,7 @@ class LibreHardwareMonitorSensor(
4644
def __init__(
4745
self,
4846
coordinator: LibreHardwareMonitorCoordinator,
47+
entry_id: str,
4948
sensor_data: LibreHardwareMonitorSensorData,
5049
) -> None:
5150
"""Initialize an LibreHardwareMonitor sensor."""
@@ -58,13 +57,13 @@ def __init__(
5857
STATE_MAX_VALUE: self._format_number_value(sensor_data.max),
5958
}
6059
self._attr_native_unit_of_measurement = sensor_data.unit
61-
self._attr_unique_id: str = f"lhm-{sensor_data.sensor_id}"
60+
self._attr_unique_id: str = f"{entry_id}_{sensor_data.sensor_id}"
6261

6362
self._sensor_id: str = sensor_data.sensor_id
6463

6564
# Hardware device
6665
self._attr_device_info = DeviceInfo(
67-
identifiers={(DOMAIN, sensor_data.device_id)},
66+
identifiers={(DOMAIN, f"{entry_id}_{sensor_data.device_id}")},
6867
name=sensor_data.device_name,
6968
model=sensor_data.device_type,
7069
)

tests/components/libre_hardware_monitor/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ def mock_config_entry() -> MockConfigEntry:
3131
domain=DOMAIN,
3232
title="192.168.0.20:8085",
3333
data=VALID_CONFIG,
34+
entry_id="test_entry_id",
35+
version=2,
3436
)
3537

3638

tests/components/libre_hardware_monitor/snapshots/test_sensor.ambr

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
'suggested_object_id': None,
3333
'supported_features': 0,
3434
'translation_key': None,
35-
'unique_id': 'lhm-amdcpu-0-temperature-2',
35+
'unique_id': 'test_entry_id_amdcpu-0-temperature-2',
3636
'unit_of_measurement': '°C',
3737
})
3838
# ---
@@ -86,7 +86,7 @@
8686
'suggested_object_id': None,
8787
'supported_features': 0,
8888
'translation_key': None,
89-
'unique_id': 'lhm-amdcpu-0-load-0',
89+
'unique_id': 'test_entry_id_amdcpu-0-load-0',
9090
'unit_of_measurement': '%',
9191
})
9292
# ---
@@ -140,7 +140,7 @@
140140
'suggested_object_id': None,
141141
'supported_features': 0,
142142
'translation_key': None,
143-
'unique_id': 'lhm-amdcpu-0-power-0',
143+
'unique_id': 'test_entry_id_amdcpu-0-power-0',
144144
'unit_of_measurement': 'W',
145145
})
146146
# ---
@@ -194,7 +194,7 @@
194194
'suggested_object_id': None,
195195
'supported_features': 0,
196196
'translation_key': None,
197-
'unique_id': 'lhm-amdcpu-0-temperature-3',
197+
'unique_id': 'test_entry_id_amdcpu-0-temperature-3',
198198
'unit_of_measurement': '°C',
199199
})
200200
# ---
@@ -248,7 +248,7 @@
248248
'suggested_object_id': None,
249249
'supported_features': 0,
250250
'translation_key': None,
251-
'unique_id': 'lhm-amdcpu-0-voltage-3',
251+
'unique_id': 'test_entry_id_amdcpu-0-voltage-3',
252252
'unit_of_measurement': 'V',
253253
})
254254
# ---
@@ -302,7 +302,7 @@
302302
'suggested_object_id': None,
303303
'supported_features': 0,
304304
'translation_key': None,
305-
'unique_id': 'lhm-amdcpu-0-voltage-2',
305+
'unique_id': 'test_entry_id_amdcpu-0-voltage-2',
306306
'unit_of_measurement': 'V',
307307
})
308308
# ---
@@ -356,7 +356,7 @@
356356
'suggested_object_id': None,
357357
'supported_features': 0,
358358
'translation_key': None,
359-
'unique_id': 'lhm-lpc-nct6687d-0-voltage-0',
359+
'unique_id': 'test_entry_id_lpc-nct6687d-0-voltage-0',
360360
'unit_of_measurement': 'V',
361361
})
362362
# ---
@@ -410,7 +410,7 @@
410410
'suggested_object_id': None,
411411
'supported_features': 0,
412412
'translation_key': None,
413-
'unique_id': 'lhm-lpc-nct6687d-0-voltage-1',
413+
'unique_id': 'test_entry_id_lpc-nct6687d-0-voltage-1',
414414
'unit_of_measurement': 'V',
415415
})
416416
# ---
@@ -464,7 +464,7 @@
464464
'suggested_object_id': None,
465465
'supported_features': 0,
466466
'translation_key': None,
467-
'unique_id': 'lhm-lpc-nct6687d-0-fan-0',
467+
'unique_id': 'test_entry_id_lpc-nct6687d-0-fan-0',
468468
'unit_of_measurement': 'RPM',
469469
})
470470
# ---
@@ -518,7 +518,7 @@
518518
'suggested_object_id': None,
519519
'supported_features': 0,
520520
'translation_key': None,
521-
'unique_id': 'lhm-lpc-nct6687d-0-temperature-0',
521+
'unique_id': 'test_entry_id_lpc-nct6687d-0-temperature-0',
522522
'unit_of_measurement': '°C',
523523
})
524524
# ---
@@ -572,7 +572,7 @@
572572
'suggested_object_id': None,
573573
'supported_features': 0,
574574
'translation_key': None,
575-
'unique_id': 'lhm-lpc-nct6687d-0-fan-1',
575+
'unique_id': 'test_entry_id_lpc-nct6687d-0-fan-1',
576576
'unit_of_measurement': 'RPM',
577577
})
578578
# ---
@@ -626,7 +626,7 @@
626626
'suggested_object_id': None,
627627
'supported_features': 0,
628628
'translation_key': None,
629-
'unique_id': 'lhm-lpc-nct6687d-0-fan-2',
629+
'unique_id': 'test_entry_id_lpc-nct6687d-0-fan-2',
630630
'unit_of_measurement': None,
631631
})
632632
# ---
@@ -679,7 +679,7 @@
679679
'suggested_object_id': None,
680680
'supported_features': 0,
681681
'translation_key': None,
682-
'unique_id': 'lhm-lpc-nct6687d-0-temperature-1',
682+
'unique_id': 'test_entry_id_lpc-nct6687d-0-temperature-1',
683683
'unit_of_measurement': '°C',
684684
})
685685
# ---
@@ -733,7 +733,7 @@
733733
'suggested_object_id': None,
734734
'supported_features': 0,
735735
'translation_key': None,
736-
'unique_id': 'lhm-lpc-nct6687d-0-voltage-2',
736+
'unique_id': 'test_entry_id_lpc-nct6687d-0-voltage-2',
737737
'unit_of_measurement': 'V',
738738
})
739739
# ---
@@ -787,7 +787,7 @@
787787
'suggested_object_id': None,
788788
'supported_features': 0,
789789
'translation_key': None,
790-
'unique_id': 'lhm-gpu-nvidia-0-clock-0',
790+
'unique_id': 'test_entry_id_gpu-nvidia-0-clock-0',
791791
'unit_of_measurement': 'MHz',
792792
})
793793
# ---
@@ -841,7 +841,7 @@
841841
'suggested_object_id': None,
842842
'supported_features': 0,
843843
'translation_key': None,
844-
'unique_id': 'lhm-gpu-nvidia-0-load-0',
844+
'unique_id': 'test_entry_id_gpu-nvidia-0-load-0',
845845
'unit_of_measurement': '%',
846846
})
847847
# ---
@@ -895,7 +895,7 @@
895895
'suggested_object_id': None,
896896
'supported_features': 0,
897897
'translation_key': None,
898-
'unique_id': 'lhm-gpu-nvidia-0-temperature-0',
898+
'unique_id': 'test_entry_id_gpu-nvidia-0-temperature-0',
899899
'unit_of_measurement': '°C',
900900
})
901901
# ---
@@ -949,7 +949,7 @@
949949
'suggested_object_id': None,
950950
'supported_features': 0,
951951
'translation_key': None,
952-
'unique_id': 'lhm-gpu-nvidia-0-fan-1',
952+
'unique_id': 'test_entry_id_gpu-nvidia-0-fan-1',
953953
'unit_of_measurement': 'RPM',
954954
})
955955
# ---
@@ -1003,7 +1003,7 @@
10031003
'suggested_object_id': None,
10041004
'supported_features': 0,
10051005
'translation_key': None,
1006-
'unique_id': 'lhm-gpu-nvidia-0-fan-2',
1006+
'unique_id': 'test_entry_id_gpu-nvidia-0-fan-2',
10071007
'unit_of_measurement': 'RPM',
10081008
})
10091009
# ---
@@ -1057,7 +1057,7 @@
10571057
'suggested_object_id': None,
10581058
'supported_features': 0,
10591059
'translation_key': None,
1060-
'unique_id': 'lhm-gpu-nvidia-0-temperature-2',
1060+
'unique_id': 'test_entry_id_gpu-nvidia-0-temperature-2',
10611061
'unit_of_measurement': '°C',
10621062
})
10631063
# ---
@@ -1111,7 +1111,7 @@
11111111
'suggested_object_id': None,
11121112
'supported_features': 0,
11131113
'translation_key': None,
1114-
'unique_id': 'lhm-gpu-nvidia-0-clock-4',
1114+
'unique_id': 'test_entry_id_gpu-nvidia-0-clock-4',
11151115
'unit_of_measurement': 'MHz',
11161116
})
11171117
# ---
@@ -1165,7 +1165,7 @@
11651165
'suggested_object_id': None,
11661166
'supported_features': 0,
11671167
'translation_key': None,
1168-
'unique_id': 'lhm-gpu-nvidia-0-load-1',
1168+
'unique_id': 'test_entry_id_gpu-nvidia-0-load-1',
11691169
'unit_of_measurement': '%',
11701170
})
11711171
# ---
@@ -1219,7 +1219,7 @@
12191219
'suggested_object_id': None,
12201220
'supported_features': 0,
12211221
'translation_key': None,
1222-
'unique_id': 'lhm-gpu-nvidia-0-power-0',
1222+
'unique_id': 'test_entry_id_gpu-nvidia-0-power-0',
12231223
'unit_of_measurement': 'W',
12241224
})
12251225
# ---
@@ -1273,7 +1273,7 @@
12731273
'suggested_object_id': None,
12741274
'supported_features': 0,
12751275
'translation_key': None,
1276-
'unique_id': 'lhm-gpu-nvidia-0-throughput-1',
1276+
'unique_id': 'test_entry_id_gpu-nvidia-0-throughput-1',
12771277
'unit_of_measurement': 'MB/s',
12781278
})
12791279
# ---
@@ -1327,7 +1327,7 @@
13271327
'suggested_object_id': None,
13281328
'supported_features': 0,
13291329
'translation_key': None,
1330-
'unique_id': 'lhm-gpu-nvidia-0-load-2',
1330+
'unique_id': 'test_entry_id_gpu-nvidia-0-load-2',
13311331
'unit_of_measurement': '%',
13321332
})
13331333
# ---

0 commit comments

Comments
 (0)