Restore HomeKit Controller BLE GSN at startup (#83206)
This commit is contained in:
parent
de77132a5a
commit
1577f6ea50
8 changed files with 50 additions and 37 deletions
|
@ -84,7 +84,7 @@ async def async_setup_entry(
|
|||
entity.old_unique_id, entity.unique_id, Platform.BUTTON
|
||||
)
|
||||
|
||||
async_add_entities(entities, True)
|
||||
async_add_entities(entities)
|
||||
return True
|
||||
|
||||
conn.add_char_factory(async_add_characteristic)
|
||||
|
|
|
@ -583,6 +583,7 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
accessories_state.config_num,
|
||||
accessories_state.accessories.serialize(),
|
||||
serialize_broadcast_key(accessories_state.broadcast_key),
|
||||
accessories_state.state_num,
|
||||
)
|
||||
|
||||
return self.async_create_entry(title=name, data=pairing_data)
|
||||
|
|
|
@ -20,7 +20,7 @@ from aiohomekit.model.services import Service
|
|||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_VIA_DEVICE, EVENT_HOMEASSISTANT_STARTED
|
||||
from homeassistant.core import CALLBACK_TYPE, CoreState, Event, HomeAssistant, callback
|
||||
from homeassistant.core import CoreState, Event, HomeAssistant, callback
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
|
@ -116,11 +116,6 @@ class HKDevice:
|
|||
|
||||
self.pollable_characteristics: list[tuple[int, int]] = []
|
||||
|
||||
# If this is set polling is active and can be disabled by calling
|
||||
# this method.
|
||||
self._polling_interval_remover: CALLBACK_TYPE | None = None
|
||||
self._ble_available_interval_remover: CALLBACK_TYPE | None = None
|
||||
|
||||
# Never allow concurrent polling of the same accessory or bridge
|
||||
self._polling_lock = asyncio.Lock()
|
||||
self._polling_lock_warned = False
|
||||
|
@ -185,8 +180,8 @@ class HKDevice:
|
|||
self.available = available
|
||||
async_dispatcher_send(self.hass, self.signal_state_updated)
|
||||
|
||||
async def _async_retry_populate_ble_accessory_state(self, event: Event) -> None:
|
||||
"""Try again to populate the BLE accessory state.
|
||||
async def _async_populate_ble_accessory_state(self, event: Event) -> None:
|
||||
"""Populate the BLE accessory state without blocking startup.
|
||||
|
||||
If the accessory was asleep at startup we need to retry
|
||||
since we continued on to allow startup to proceed.
|
||||
|
@ -194,6 +189,7 @@ class HKDevice:
|
|||
If this fails the state may be inconsistent, but will
|
||||
get corrected as soon as the accessory advertises again.
|
||||
"""
|
||||
self._async_start_polling()
|
||||
try:
|
||||
await self.pairing.async_populate_accessories_state(force_update=True)
|
||||
except STARTUP_EXCEPTIONS as ex:
|
||||
|
@ -221,20 +217,28 @@ class HKDevice:
|
|||
# so we only poll those chars but that is not possible
|
||||
# yet.
|
||||
attempts = None if self.hass.state == CoreState.running else 1
|
||||
try:
|
||||
await self.pairing.async_populate_accessories_state(
|
||||
force_update=True, attempts=attempts
|
||||
)
|
||||
except AccessoryNotFoundError:
|
||||
if transport != Transport.BLE or not pairing.accessories:
|
||||
# BLE devices may sleep and we can't force a connection
|
||||
raise
|
||||
if (
|
||||
transport == Transport.BLE
|
||||
and pairing.accessories
|
||||
and pairing.accessories.has_aid(1)
|
||||
):
|
||||
# The GSN gets restored and a catch up poll will be
|
||||
# triggered via disconnected events automatically
|
||||
# if we are out of sync. To be sure we are in sync;
|
||||
# If for some reason the BLE connection failed
|
||||
# previously we force an update after startup
|
||||
# is complete.
|
||||
entry.async_on_unload(
|
||||
self.hass.bus.async_listen(
|
||||
EVENT_HOMEASSISTANT_STARTED,
|
||||
self._async_retry_populate_ble_accessory_state,
|
||||
self._async_populate_ble_accessory_state,
|
||||
)
|
||||
)
|
||||
else:
|
||||
await self.pairing.async_populate_accessories_state(
|
||||
force_update=True, attempts=attempts
|
||||
)
|
||||
self._async_start_polling()
|
||||
|
||||
entry.async_on_unload(pairing.dispatcher_connect(self.process_new_events))
|
||||
entry.async_on_unload(
|
||||
|
@ -252,27 +256,34 @@ class HKDevice:
|
|||
|
||||
self.async_set_available_state(self.pairing.is_available)
|
||||
|
||||
# We use async_request_update to avoid multiple updates
|
||||
# at the same time which would generate a spurious warning
|
||||
# in the log about concurrent polling.
|
||||
self._polling_interval_remover = async_track_time_interval(
|
||||
self.hass, self.async_request_update, self.pairing.poll_interval
|
||||
)
|
||||
|
||||
if transport == Transport.BLE:
|
||||
# If we are using BLE, we need to periodically check of the
|
||||
# BLE device is available since we won't get callbacks
|
||||
# when it goes away since we HomeKit supports disconnected
|
||||
# notifications and we cannot treat a disconnect as unavailability.
|
||||
self._ble_available_interval_remover = async_track_time_interval(
|
||||
self.hass,
|
||||
self.async_update_available_state,
|
||||
timedelta(seconds=BLE_AVAILABILITY_CHECK_INTERVAL),
|
||||
entry.async_on_unload(
|
||||
async_track_time_interval(
|
||||
self.hass,
|
||||
self.async_update_available_state,
|
||||
timedelta(seconds=BLE_AVAILABILITY_CHECK_INTERVAL),
|
||||
)
|
||||
)
|
||||
# BLE devices always get an RSSI sensor as well
|
||||
if "sensor" not in self.platforms:
|
||||
await self.async_load_platform("sensor")
|
||||
|
||||
@callback
|
||||
def _async_start_polling(self) -> None:
|
||||
"""Start polling for updates."""
|
||||
# We use async_request_update to avoid multiple updates
|
||||
# at the same time which would generate a spurious warning
|
||||
# in the log about concurrent polling.
|
||||
self.config_entry.async_on_unload(
|
||||
async_track_time_interval(
|
||||
self.hass, self.async_request_update, self.pairing.poll_interval
|
||||
)
|
||||
)
|
||||
|
||||
async def async_add_new_entities(self) -> None:
|
||||
"""Add new entities to Home Assistant."""
|
||||
await self.async_load_platforms()
|
||||
|
@ -529,9 +540,6 @@ class HKDevice:
|
|||
|
||||
async def async_unload(self) -> None:
|
||||
"""Stop interacting with device and prepare for removal from hass."""
|
||||
if self._polling_interval_remover:
|
||||
self._polling_interval_remover()
|
||||
|
||||
await self.pairing.shutdown()
|
||||
|
||||
await self.hass.config_entries.async_unload_platforms(
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "HomeKit Controller",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
|
||||
"requirements": ["aiohomekit==2.3.6"],
|
||||
"requirements": ["aiohomekit==2.4.0"],
|
||||
"zeroconf": ["_hap._tcp.local.", "_hap._udp.local."],
|
||||
"bluetooth": [{ "manufacturer_id": 76, "manufacturer_data_start": [6] }],
|
||||
"dependencies": ["bluetooth", "zeroconf"],
|
||||
|
|
|
@ -78,7 +78,7 @@ async def async_setup_entry(
|
|||
entity.old_unique_id, entity.unique_id, Platform.NUMBER
|
||||
)
|
||||
|
||||
async_add_entities(entities, True)
|
||||
async_add_entities(entities)
|
||||
return True
|
||||
|
||||
conn.add_char_factory(async_add_characteristic)
|
||||
|
|
|
@ -61,11 +61,15 @@ class EntityMapStorage:
|
|||
config_num: int,
|
||||
accessories: list[Any],
|
||||
broadcast_key: str | None = None,
|
||||
state_num: int | None = None,
|
||||
) -> Pairing:
|
||||
"""Create a new pairing cache."""
|
||||
_LOGGER.debug("Creating or updating entity map for %s", homekit_id)
|
||||
data = Pairing(
|
||||
config_num=config_num, accessories=accessories, broadcast_key=broadcast_key
|
||||
config_num=config_num,
|
||||
accessories=accessories,
|
||||
broadcast_key=broadcast_key,
|
||||
state_num=state_num,
|
||||
)
|
||||
self.storage_data[homekit_id] = data
|
||||
self._async_schedule_save()
|
||||
|
|
|
@ -174,7 +174,7 @@ aioguardian==2022.07.0
|
|||
aioharmony==0.2.9
|
||||
|
||||
# homeassistant.components.homekit_controller
|
||||
aiohomekit==2.3.6
|
||||
aiohomekit==2.4.0
|
||||
|
||||
# homeassistant.components.emulated_hue
|
||||
# homeassistant.components.http
|
||||
|
|
|
@ -158,7 +158,7 @@ aioguardian==2022.07.0
|
|||
aioharmony==0.2.9
|
||||
|
||||
# homeassistant.components.homekit_controller
|
||||
aiohomekit==2.3.6
|
||||
aiohomekit==2.4.0
|
||||
|
||||
# homeassistant.components.emulated_hue
|
||||
# homeassistant.components.http
|
||||
|
|
Loading…
Add table
Reference in a new issue