Switch homekit_controller to use subscriber lookups (#96739)
This commit is contained in:
parent
a4d4eb3871
commit
aa87f0ad54
2 changed files with 33 additions and 22 deletions
|
@ -22,11 +22,10 @@ from aiohomekit.model.services import Service, ServicesTypes
|
||||||
from homeassistant.components.thread.dataset_store import async_get_preferred_dataset
|
from homeassistant.components.thread.dataset_store import async_get_preferred_dataset
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ATTR_VIA_DEVICE, EVENT_HOMEASSISTANT_STARTED
|
from homeassistant.const import ATTR_VIA_DEVICE, EVENT_HOMEASSISTANT_STARTED
|
||||||
from homeassistant.core import CoreState, Event, HomeAssistant, callback
|
from homeassistant.core import CALLBACK_TYPE, CoreState, Event, HomeAssistant, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
from homeassistant.helpers.debounce import Debouncer
|
from homeassistant.helpers.debounce import Debouncer
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.event import async_track_time_interval
|
from homeassistant.helpers.event import async_track_time_interval
|
||||||
|
|
||||||
|
@ -116,8 +115,6 @@ class HKDevice:
|
||||||
|
|
||||||
self.available = False
|
self.available = False
|
||||||
|
|
||||||
self.signal_state_updated = "_".join((DOMAIN, self.unique_id, "state_updated"))
|
|
||||||
|
|
||||||
self.pollable_characteristics: list[tuple[int, int]] = []
|
self.pollable_characteristics: list[tuple[int, int]] = []
|
||||||
|
|
||||||
# Never allow concurrent polling of the same accessory or bridge
|
# Never allow concurrent polling of the same accessory or bridge
|
||||||
|
@ -138,6 +135,9 @@ class HKDevice:
|
||||||
function=self.async_update,
|
function=self.async_update,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._all_subscribers: set[CALLBACK_TYPE] = set()
|
||||||
|
self._subscriptions: dict[tuple[int, int], set[CALLBACK_TYPE]] = {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def entity_map(self) -> Accessories:
|
def entity_map(self) -> Accessories:
|
||||||
"""Return the accessories from the pairing."""
|
"""Return the accessories from the pairing."""
|
||||||
|
@ -182,7 +182,8 @@ class HKDevice:
|
||||||
if self.available == available:
|
if self.available == available:
|
||||||
return
|
return
|
||||||
self.available = available
|
self.available = available
|
||||||
async_dispatcher_send(self.hass, self.signal_state_updated)
|
for callback_ in self._all_subscribers:
|
||||||
|
callback_()
|
||||||
|
|
||||||
async def _async_populate_ble_accessory_state(self, event: Event) -> None:
|
async def _async_populate_ble_accessory_state(self, event: Event) -> None:
|
||||||
"""Populate the BLE accessory state without blocking startup.
|
"""Populate the BLE accessory state without blocking startup.
|
||||||
|
@ -768,7 +769,31 @@ class HKDevice:
|
||||||
|
|
||||||
self.entity_map.process_changes(new_values_dict)
|
self.entity_map.process_changes(new_values_dict)
|
||||||
|
|
||||||
async_dispatcher_send(self.hass, self.signal_state_updated, new_values_dict)
|
to_callback: set[CALLBACK_TYPE] = set()
|
||||||
|
for aid_iid in new_values_dict:
|
||||||
|
if callbacks := self._subscriptions.get(aid_iid):
|
||||||
|
to_callback.update(callbacks)
|
||||||
|
|
||||||
|
for callback_ in to_callback:
|
||||||
|
callback_()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_subscribe(
|
||||||
|
self, characteristics: Iterable[tuple[int, int]], callback_: CALLBACK_TYPE
|
||||||
|
) -> CALLBACK_TYPE:
|
||||||
|
"""Add characteristics to the watch list."""
|
||||||
|
self._all_subscribers.add(callback_)
|
||||||
|
for aid_iid in characteristics:
|
||||||
|
self._subscriptions.setdefault(aid_iid, set()).add(callback_)
|
||||||
|
|
||||||
|
def _unsub():
|
||||||
|
self._all_subscribers.remove(callback_)
|
||||||
|
for aid_iid in characteristics:
|
||||||
|
self._subscriptions[aid_iid].remove(callback_)
|
||||||
|
if not self._subscriptions[aid_iid]:
|
||||||
|
del self._subscriptions[aid_iid]
|
||||||
|
|
||||||
|
return _unsub
|
||||||
|
|
||||||
async def get_characteristics(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
|
async def get_characteristics(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
|
||||||
"""Read latest state from homekit accessory."""
|
"""Read latest state from homekit accessory."""
|
||||||
|
|
|
@ -11,8 +11,6 @@ from aiohomekit.model.characteristics import (
|
||||||
)
|
)
|
||||||
from aiohomekit.model.services import Service, ServicesTypes
|
from aiohomekit.model.services import Service, ServicesTypes
|
||||||
|
|
||||||
from homeassistant.core import callback
|
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|
||||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
|
@ -53,23 +51,11 @@ class HomeKitEntity(Entity):
|
||||||
"""Return a Service model that this entity is attached to."""
|
"""Return a Service model that this entity is attached to."""
|
||||||
return self.accessory.services.iid(self._iid)
|
return self.accessory.services.iid(self._iid)
|
||||||
|
|
||||||
@callback
|
|
||||||
def _async_state_changed(
|
|
||||||
self, new_values_dict: dict[tuple[int, int], dict[str, Any]] | None = None
|
|
||||||
) -> None:
|
|
||||||
"""Handle when characteristics change value."""
|
|
||||||
if new_values_dict is None or self.all_characteristics.intersection(
|
|
||||||
new_values_dict
|
|
||||||
):
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Entity added to hass."""
|
"""Entity added to hass."""
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
async_dispatcher_connect(
|
self._accessory.async_subscribe(
|
||||||
self.hass,
|
self.all_characteristics, self._async_write_ha_state
|
||||||
self._accessory.signal_state_updated,
|
|
||||||
self._async_state_changed,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue