Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The Dormakaba dKey integration."""
2 
3 from __future__ import annotations
4 
5 from datetime import timedelta
6 import logging
7 
8 from py_dormakaba_dkey import DKEYLock
9 from py_dormakaba_dkey.errors import DKEY_EXCEPTIONS, NotAssociated
10 from py_dormakaba_dkey.models import AssociationData
11 
12 from homeassistant.components import bluetooth
13 from homeassistant.components.bluetooth.match import ADDRESS, BluetoothCallbackMatcher
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.const import CONF_ADDRESS, EVENT_HOMEASSISTANT_STOP, Platform
16 from homeassistant.core import Event, HomeAssistant, callback
17 from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
18 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
19 
20 from .const import CONF_ASSOCIATION_DATA, DOMAIN, UPDATE_SECONDS
21 from .models import DormakabaDkeyData
22 
23 PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.LOCK, Platform.SENSOR]
24 
25 _LOGGER = logging.getLogger(__name__)
26 
27 
28 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
29  """Set up Dormakaba dKey from a config entry."""
30  address: str = entry.data[CONF_ADDRESS]
31  ble_device = bluetooth.async_ble_device_from_address(hass, address.upper(), True)
32  if not ble_device:
33  raise ConfigEntryNotReady(f"Could not find dKey device with address {address}")
34 
35  lock = DKEYLock(ble_device)
36  lock.set_association_data(
37  AssociationData.from_json(entry.data[CONF_ASSOCIATION_DATA])
38  )
39 
40  @callback
41  def _async_update_ble(
42  service_info: bluetooth.BluetoothServiceInfoBleak,
43  change: bluetooth.BluetoothChange,
44  ) -> None:
45  """Update from a ble callback."""
46  lock.set_ble_device_and_advertisement_data(
47  service_info.device, service_info.advertisement
48  )
49 
50  entry.async_on_unload(
51  bluetooth.async_register_callback(
52  hass,
53  _async_update_ble,
54  BluetoothCallbackMatcher({ADDRESS: address}),
55  bluetooth.BluetoothScanningMode.PASSIVE,
56  )
57  )
58 
59  async def _async_update() -> None:
60  """Update the device state."""
61  try:
62  await lock.update()
63  await lock.disconnect()
64  except NotAssociated as ex:
65  raise ConfigEntryAuthFailed("Not associated") from ex
66  except DKEY_EXCEPTIONS as ex:
67  raise UpdateFailed(str(ex)) from ex
68 
69  coordinator = DataUpdateCoordinator(
70  hass,
71  _LOGGER,
72  config_entry=entry,
73  name=lock.name,
74  update_method=_async_update,
75  update_interval=timedelta(seconds=UPDATE_SECONDS),
76  )
77  await coordinator.async_config_entry_first_refresh()
78 
79  hass.data.setdefault(DOMAIN, {})[entry.entry_id] = DormakabaDkeyData(
80  lock, coordinator
81  )
82 
83  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
84 
85  async def _async_stop(event: Event) -> None:
86  """Close the connection."""
87  await lock.disconnect()
88 
89  entry.async_on_unload(
90  hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_stop)
91  )
92  return True
93 
94 
95 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
96  """Unload a config entry."""
97  if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
98  data: DormakabaDkeyData = hass.data[DOMAIN].pop(entry.entry_id)
99  await data.lock.disconnect()
100 
101  return unload_ok
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:28
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:95
None _async_stop(HomeAssistant hass, bool restart)
Definition: __init__.py:392