Skip to content

Commit ce5538e

Browse files
authored
Refactor dynamic entity setup of Xbox integration (home-assistant#155176)
1 parent 6819b0c commit ce5538e

File tree

4 files changed

+54
-81
lines changed

4 files changed

+54
-81
lines changed

homeassistant/components/xbox/binary_sensor.py

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from collections.abc import Callable
66
from dataclasses import dataclass
77
from enum import StrEnum
8-
from functools import partial
98

109
from xbox.webapi.api.provider.people.models import Person
1110
from yarl import URL
@@ -18,7 +17,7 @@
1817
from homeassistant.core import HomeAssistant, callback
1918
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
2019

21-
from .coordinator import XboxConfigEntry, XboxUpdateCoordinator
20+
from .coordinator import XboxConfigEntry
2221
from .entity import XboxBaseEntity, check_deprecated_entity
2322

2423

@@ -111,15 +110,30 @@ async def async_setup_entry(
111110
async_add_entities: AddConfigEntryEntitiesCallback,
112111
) -> None:
113112
"""Set up Xbox Live friends."""
113+
xuids_added: set[str] = set()
114114
coordinator = entry.runtime_data
115115

116-
update_friends = partial(
117-
async_update_friends, hass, coordinator, {}, async_add_entities
118-
)
119-
120-
entry.async_on_unload(coordinator.async_add_listener(update_friends))
121-
122-
update_friends()
116+
@callback
117+
def add_entities() -> None:
118+
nonlocal xuids_added
119+
120+
current_xuids = set(coordinator.data.presence)
121+
if new_xuids := current_xuids - xuids_added:
122+
for xuid in new_xuids:
123+
async_add_entities(
124+
[
125+
XboxBinarySensorEntity(coordinator, xuid, description)
126+
for description in SENSOR_DESCRIPTIONS
127+
if check_deprecated_entity(
128+
hass, xuid, description, BINARY_SENSOR_DOMAIN
129+
)
130+
]
131+
)
132+
xuids_added |= new_xuids
133+
xuids_added &= current_xuids
134+
135+
coordinator.async_add_listener(add_entities)
136+
add_entities()
123137

124138

125139
class XboxBinarySensorEntity(XboxBaseEntity, BinarySensorEntity):
@@ -142,31 +156,3 @@ def entity_picture(self) -> str | None:
142156
if (fn := self.entity_description.entity_picture_fn) is not None
143157
else super().entity_picture
144158
)
145-
146-
147-
@callback
148-
def async_update_friends(
149-
hass: HomeAssistant,
150-
coordinator: XboxUpdateCoordinator,
151-
current: dict[str, list[XboxBinarySensorEntity]],
152-
async_add_entities,
153-
) -> None:
154-
"""Update friends."""
155-
new_ids = set(coordinator.data.presence)
156-
current_ids = set(current)
157-
158-
# Process new favorites, add them to Home Assistant
159-
new_entities: list[XboxBinarySensorEntity] = []
160-
for xuid in new_ids - current_ids:
161-
current[xuid] = []
162-
for description in SENSOR_DESCRIPTIONS:
163-
entity = XboxBinarySensorEntity(coordinator, xuid, description)
164-
if check_deprecated_entity(hass, entity, BINARY_SENSOR_DOMAIN):
165-
current[xuid].append(entity)
166-
new_entities = new_entities + current[xuid]
167-
if new_entities:
168-
async_add_entities(new_entities)
169-
170-
# Process deleted favorites, remove them from Home Assistant
171-
for xuid in current_ids - new_ids:
172-
del current[xuid]

homeassistant/components/xbox/coordinator.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,20 +200,19 @@ async def _async_update_data(self) -> XboxData:
200200
)
201201

202202
if (
203-
self.current_friends
204-
- (new_friends := {x.xuid for x in presence_data.values()})
203+
self.current_friends - (new_friends := set(presence_data))
205204
or not self.current_friends
206205
):
207-
self.remove_stale_devices(presence_data)
206+
self.remove_stale_devices(new_friends)
208207
self.current_friends = new_friends
209208

210209
return XboxData(new_console_data, presence_data)
211210

212-
def remove_stale_devices(self, presence_data: dict[str, Person]) -> None:
211+
def remove_stale_devices(self, xuids: set[str]) -> None:
213212
"""Remove stale devices from registry."""
214213

215214
device_reg = dr.async_get(self.hass)
216-
identifiers = {(DOMAIN, xuid) for xuid in set(presence_data)} | {
215+
identifiers = {(DOMAIN, xuid) for xuid in xuids} | {
217216
(DOMAIN, console.id) for console in self.consoles.result
218217
}
219218

homeassistant/components/xbox/entity.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,18 @@ def entity_used_in(hass: HomeAssistant, entity_id: str) -> list[str]:
9898

9999
def check_deprecated_entity(
100100
hass: HomeAssistant,
101-
entity: XboxBaseEntity,
101+
xuid: str,
102+
entity_description: EntityDescription,
102103
entity_domain: str,
103104
) -> bool:
104105
"""Check for deprecated entity and remove it."""
105-
if not getattr(entity.entity_description, "deprecated", False):
106+
if not getattr(entity_description, "deprecated", False):
106107
return True
107108
ent_reg = er.async_get(hass)
108109
if entity_id := ent_reg.async_get_entity_id(
109110
entity_domain,
110111
DOMAIN,
111-
f"{entity.xuid}_{entity.entity_description.key}",
112+
f"{xuid}_{entity_description.key}",
112113
):
113114
ent_reg.async_remove(entity_id)
114115

homeassistant/components/xbox/sensor.py

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from dataclasses import dataclass
77
from datetime import UTC, datetime
88
from enum import StrEnum
9-
from functools import partial
109

1110
from xbox.webapi.api.provider.people.models import Person
1211

@@ -20,7 +19,7 @@
2019
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
2120
from homeassistant.helpers.typing import StateType
2221

23-
from .coordinator import XboxConfigEntry, XboxUpdateCoordinator
22+
from .coordinator import XboxConfigEntry
2423
from .entity import XboxBaseEntity, check_deprecated_entity
2524

2625

@@ -94,14 +93,30 @@ async def async_setup_entry(
9493
async_add_entities: AddConfigEntryEntitiesCallback,
9594
) -> None:
9695
"""Set up Xbox Live friends."""
96+
xuids_added: set[str] = set()
9797
coordinator = config_entry.runtime_data
9898

99-
update_friends = partial(
100-
async_update_friends, hass, coordinator, {}, async_add_entities
101-
)
102-
103-
config_entry.async_on_unload(coordinator.async_add_listener(update_friends))
104-
update_friends()
99+
@callback
100+
def add_entities() -> None:
101+
nonlocal xuids_added
102+
103+
current_xuids = set(coordinator.data.presence)
104+
if new_xuids := current_xuids - xuids_added:
105+
for xuid in new_xuids:
106+
async_add_entities(
107+
[
108+
XboxSensorEntity(coordinator, xuid, description)
109+
for description in SENSOR_DESCRIPTIONS
110+
if check_deprecated_entity(
111+
hass, xuid, description, SENSOR_DOMAIN
112+
)
113+
]
114+
)
115+
xuids_added |= new_xuids
116+
xuids_added &= current_xuids
117+
118+
coordinator.async_add_listener(add_entities)
119+
add_entities()
105120

106121

107122
class XboxSensorEntity(XboxBaseEntity, SensorEntity):
@@ -113,31 +128,3 @@ class XboxSensorEntity(XboxBaseEntity, SensorEntity):
113128
def native_value(self) -> StateType | datetime:
114129
"""Return the state of the requested attribute."""
115130
return self.entity_description.value_fn(self.data)
116-
117-
118-
@callback
119-
def async_update_friends(
120-
hass: HomeAssistant,
121-
coordinator: XboxUpdateCoordinator,
122-
current: dict[str, list[XboxSensorEntity]],
123-
async_add_entities,
124-
) -> None:
125-
"""Update friends."""
126-
new_ids = set(coordinator.data.presence)
127-
current_ids = set(current)
128-
129-
# Process new favorites, add them to Home Assistant
130-
new_entities: list[XboxSensorEntity] = []
131-
for xuid in new_ids - current_ids:
132-
current[xuid] = []
133-
for description in SENSOR_DESCRIPTIONS:
134-
entity = XboxSensorEntity(coordinator, xuid, description)
135-
if check_deprecated_entity(hass, entity, SENSOR_DOMAIN):
136-
current[xuid].append(entity)
137-
new_entities = new_entities + current[xuid]
138-
if new_entities:
139-
async_add_entities(new_entities)
140-
141-
# Process deleted favorites, remove them from Home Assistant
142-
for xuid in current_ids - new_ids:
143-
del current[xuid]

0 commit comments

Comments
 (0)