Skip to content

Commit c32f331

Browse files
Merge pull request #11 from andrew-codechimp/device-association
Device association
2 parents ebc7c4b + b58b8da commit c32f331

File tree

2 files changed

+89
-10
lines changed

2 files changed

+89
-10
lines changed

custom_components/periodic_min_max/sensor.py

Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from datetime import datetime
66
from typing import Any
77

8+
import voluptuous as vol
89
from homeassistant.components.sensor import (
910
SensorDeviceClass,
1011
SensorEntity,
@@ -20,14 +21,18 @@
2021
STATE_UNKNOWN,
2122
)
2223
from homeassistant.core import Event, EventStateChangedData, HomeAssistant, callback
24+
from homeassistant.helpers import device_registry as dr
2325
from homeassistant.helpers import entity_platform
2426
from homeassistant.helpers import entity_registry as er
2527
from homeassistant.helpers.device import async_device_info_to_link_from_entity
2628
from homeassistant.helpers.entity_platform import (
2729
AddConfigEntryEntitiesCallback,
2830
AddEntitiesCallback,
2931
)
30-
from homeassistant.helpers.event import async_track_state_change_event
32+
from homeassistant.helpers.event import (
33+
async_track_entity_registry_updated_event,
34+
async_track_state_change_event,
35+
)
3136
from homeassistant.helpers.reload import async_setup_reload_service
3237
from homeassistant.helpers.restore_state import RestoreEntity
3338
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType
@@ -49,18 +54,95 @@
4954
SENSOR_TYPE_TO_ATTR = {v: k for k, v in SENSOR_TYPES.items()}
5055

5156

57+
@callback
58+
def async_add_to_device(
59+
hass: HomeAssistant, entry: ConfigEntry, entity_id: str
60+
) -> str | None:
61+
"""Add our config entry to the tracked entity's device."""
62+
registry = er.async_get(hass)
63+
device_registry = dr.async_get(hass)
64+
device_id = None
65+
66+
if (
67+
not (source_device := registry.async_get(entity_id))
68+
or not (device_id := source_device.device_id)
69+
or not (device_registry.async_get(device_id))
70+
):
71+
return device_id
72+
73+
device_registry.async_update_device(device_id, add_config_entry_id=entry.entry_id)
74+
75+
return device_id
76+
77+
78+
async def config_entry_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
79+
"""Update listener, called when the config entry options are changed."""
80+
await hass.config_entries.async_reload(entry.entry_id)
81+
82+
5283
async def async_setup_entry(
5384
hass: HomeAssistant,
5485
config_entry: ConfigEntry,
5586
async_add_entities: AddConfigEntryEntitiesCallback,
5687
) -> None:
5788
"""Initialize min/max/mean config entry."""
58-
registry = er.async_get(hass)
59-
entity_id = er.async_validate_entity_id(
60-
registry, config_entry.options[CONF_ENTITY_ID]
61-
)
89+
entity_registry = er.async_get(hass)
90+
device_registry = dr.async_get(hass)
91+
try:
92+
entity_id = er.async_validate_entity_id(
93+
entity_registry, config_entry.options[CONF_ENTITY_ID]
94+
)
95+
except vol.Invalid:
96+
# The entity is identified by an unknown entity registry ID
97+
LOGGER.error(
98+
"Failed to setup periodic_min_max for unknown entity %s",
99+
config_entry.options[CONF_ENTITY_ID],
100+
)
101+
return False
102+
62103
sensor_type = config_entry.options[CONF_TYPE]
63104

105+
async def async_registry_updated(
106+
event: Event[er.EventEntityRegistryUpdatedData],
107+
) -> None:
108+
"""Handle entity registry update."""
109+
data = event.data
110+
if data["action"] == "remove":
111+
await hass.config_entries.async_remove(config_entry.entry_id)
112+
113+
if data["action"] != "update":
114+
return
115+
116+
if "entity_id" in data["changes"]:
117+
# Entity_id changed, reload the config entry
118+
await hass.config_entries.async_reload(config_entry.entry_id)
119+
120+
if device_id and "device_id" in data["changes"]:
121+
# If the tracked entity is no longer in the device, remove our config entry
122+
# from the device
123+
if (
124+
not (entity_entry := entity_registry.async_get(data[CONF_ENTITY_ID]))
125+
or not device_registry.async_get(device_id)
126+
or entity_entry.device_id == device_id
127+
):
128+
# No need to do any cleanup
129+
return
130+
131+
device_registry.async_update_device(
132+
device_id, remove_config_entry_id=config_entry.entry_id
133+
)
134+
135+
config_entry.async_on_unload(
136+
async_track_entity_registry_updated_event(
137+
hass, entity_id, async_registry_updated
138+
)
139+
)
140+
config_entry.async_on_unload(
141+
config_entry.add_update_listener(config_entry_update_listener)
142+
)
143+
144+
device_id = async_add_to_device(hass, config_entry, entity_id)
145+
64146
async_add_entities(
65147
[
66148
PeriodicMinMaxSensor(

scripts/develop

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,10 @@ if [[ ! -d "${PWD}/config" ]]; then
1111
fi
1212

1313
# Set the path to custom_components
14-
## This let's us have the structure we want <root>/custom_components/periodic_min_max
14+
## This let's us have the structure we want <root>/custom_components/integration_battery_types
1515
## while at the same time have Home Assistant configuration inside <root>/config
1616
## without resulting to symlinks.
1717
export PYTHONPATH="${PYTHONPATH}:${PWD}/custom_components"
1818

1919
# Start Home Assistant
20-
# debugpy logging, if required: --log-to debugpy
21-
python3 -Xfrozen_modules=off \
22-
-m debugpy --listen localhost:5678 \
23-
-m homeassistant --config "${PWD}/config"
20+
hass --config "${PWD}/config" --debug

0 commit comments

Comments
 (0)