1 """The Yale Access Bluetooth integration."""
3 from __future__
import annotations
5 from yalexs_ble
import (
12 close_stale_connections_by_address,
19 from homeassistant.core import CALLBACK_TYPE, CoreState, Event, HomeAssistant, callback
23 CONF_ALWAYS_CONNECTED,
29 from .models
import YaleXSBLEData
30 from .util
import async_find_existing_service_info, bluetooth_callback_matcher
32 type YALEXSBLEConfigEntry = ConfigEntry[YaleXSBLEData]
35 PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.LOCK, Platform.SENSOR]
39 """Set up Yale Access Bluetooth from a config entry."""
40 local_name = entry.data[CONF_LOCAL_NAME]
41 address = entry.data[CONF_ADDRESS]
42 key = entry.data[CONF_KEY]
43 slot = entry.data[CONF_SLOT]
44 has_unique_local_name = local_name_is_unique(local_name)
45 always_connected = entry.options.get(CONF_ALWAYS_CONNECTED,
False)
47 local_name, address,
None, key, slot, always_connected=always_connected
49 id_ = local_name
if has_unique_local_name
else address
50 push_lock.set_name(f
"{entry.title} ({id_})")
55 await close_stale_connections_by_address(address)
58 def _async_update_ble(
59 service_info: bluetooth.BluetoothServiceInfoBleak,
60 change: bluetooth.BluetoothChange,
62 """Update from a ble callback."""
63 push_lock.update_advertisement(service_info.device, service_info.advertisement)
65 shutdown_callback: CALLBACK_TYPE |
None = await push_lock.start()
68 def _async_shutdown(event: Event |
None =
None) ->
None:
69 nonlocal shutdown_callback
72 shutdown_callback =
None
74 entry.async_on_unload(_async_shutdown)
78 push_lock.update_advertisement(service_info.device, service_info.advertisement)
79 elif hass.state
is CoreState.starting:
85 entry.async_on_unload(
86 bluetooth.async_register_callback(
90 bluetooth.BluetoothScanningMode.PASSIVE,
95 await push_lock.wait_for_first_update(DEVICE_TIMEOUT)
96 except AuthError
as ex:
98 except (YaleXSBLEError, TimeoutError)
as ex:
100 f
"{ex}; Try moving the Bluetooth adapter closer to {local_name}"
103 entry.runtime_data =
YaleXSBLEData(entry.title, push_lock, always_connected)
106 def _async_device_unavailable(
107 _service_info: bluetooth.BluetoothServiceInfoBleak,
109 """Handle device not longer being seen by the bluetooth stack."""
110 push_lock.reset_advertisement_state()
112 entry.async_on_unload(
113 bluetooth.async_track_unavailable(
114 hass, _async_device_unavailable, push_lock.address
119 def _async_state_changed(
120 new_state: LockState, lock_info: LockInfo, connection_info: ConnectionInfo
122 """Handle state changed."""
123 if new_state.auth
and not new_state.auth.successful:
124 entry.async_start_reauth(hass)
126 entry.async_on_unload(push_lock.register_callback(_async_state_changed))
127 await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
128 entry.async_on_unload(entry.add_update_listener(_async_update_listener))
129 entry.async_on_unload(
130 hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_shutdown)
136 hass: HomeAssistant, entry: YALEXSBLEConfigEntry
138 """Handle options update."""
139 data = entry.runtime_data
140 if entry.title != data.title
or data.always_connected != entry.options.get(
141 CONF_ALWAYS_CONNECTED
143 await hass.config_entries.async_reload(entry.entry_id)
147 """Unload a config entry."""
148 return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
BluetoothServiceInfoBleak|None async_find_existing_service_info(HomeAssistant hass, str local_name, str address)
BluetoothCallbackMatcher bluetooth_callback_matcher(str local_name, str address)
bool async_unload_entry(HomeAssistant hass, YALEXSBLEConfigEntry entry)
None _async_update_listener(HomeAssistant hass, YALEXSBLEConfigEntry entry)
bool async_setup_entry(HomeAssistant hass, YALEXSBLEConfigEntry entry)