Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Motionblinds Bluetooth integration."""
2 
3 from __future__ import annotations
4 
5 from functools import partial
6 import logging
7 
8 from motionblindsble.const import MotionBlindType
9 from motionblindsble.crypt import MotionCrypt
10 from motionblindsble.device import MotionDevice
11 
13  BluetoothCallbackMatcher,
14  BluetoothChange,
15  BluetoothScanningMode,
16  BluetoothServiceInfoBleak,
17  async_ble_device_from_address,
18  async_register_callback,
19 )
20 from homeassistant.config_entries import ConfigEntry
21 from homeassistant.const import CONF_ADDRESS, Platform
22 from homeassistant.core import HomeAssistant, callback
23 from homeassistant.helpers import config_validation as cv
24 from homeassistant.helpers.event import async_call_later
25 from homeassistant.helpers.typing import ConfigType
26 
27 from .const import (
28  CONF_BLIND_TYPE,
29  CONF_MAC_CODE,
30  DOMAIN,
31  OPTION_DISCONNECT_TIME,
32  OPTION_PERMANENT_CONNECTION,
33 )
34 
35 _LOGGER = logging.getLogger(__name__)
36 
37 PLATFORMS: list[Platform] = [
38  Platform.BUTTON,
39  Platform.COVER,
40  Platform.SELECT,
41  Platform.SENSOR,
42 ]
43 
44 CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
45 
46 
47 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
48  """Set up Motionblinds Bluetooth integration."""
49 
50  _LOGGER.debug("Setting up Motionblinds Bluetooth integration")
51 
52  # The correct time is needed for encryption
53  _LOGGER.debug("Setting timezone for encryption: %s", hass.config.time_zone)
54  MotionCrypt.set_timezone(hass.config.time_zone)
55 
56  return True
57 
58 
59 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
60  """Set up Motionblinds Bluetooth device from a config entry."""
61 
62  _LOGGER.debug("(%s) Setting up device", entry.data[CONF_MAC_CODE])
63 
64  ble_device = async_ble_device_from_address(hass, entry.data[CONF_ADDRESS])
65  device = MotionDevice(
66  ble_device if ble_device is not None else entry.data[CONF_ADDRESS],
67  blind_type=MotionBlindType[entry.data[CONF_BLIND_TYPE].upper()],
68  )
69 
70  # Register Home Assistant functions to use in the library
71  device.set_create_task_factory(
72  partial(
73  entry.async_create_background_task,
74  hass=hass,
75  name=device.ble_device.address,
76  )
77  )
78  device.set_call_later_factory(partial(async_call_later, hass=hass))
79 
80  # Register a callback that updates the BLEDevice in the library
81  @callback
82  def async_update_ble_device(
83  service_info: BluetoothServiceInfoBleak, change: BluetoothChange
84  ) -> None:
85  """Update the BLEDevice."""
86  _LOGGER.debug("(%s) New BLE device found", service_info.address)
87  device.set_ble_device(service_info.device, rssi=service_info.advertisement.rssi)
88 
89  entry.async_on_unload(
91  hass,
92  async_update_ble_device,
93  BluetoothCallbackMatcher(address=entry.data[CONF_ADDRESS]),
94  BluetoothScanningMode.ACTIVE,
95  )
96  )
97 
98  hass.data.setdefault(DOMAIN, {})[entry.entry_id] = device
99 
100  # Register OptionsFlow update listener
101  entry.async_on_unload(entry.add_update_listener(options_update_listener))
102 
103  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
104 
105  # Apply options
106  entry.async_create_background_task(
107  hass, apply_options(hass, entry), device.ble_device.address
108  )
109 
110  _LOGGER.debug("(%s) Finished setting up device", entry.data[CONF_MAC_CODE])
111 
112  return True
113 
114 
115 async def options_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
116  """Handle options update."""
117  _LOGGER.debug(
118  "(%s) Updated device options: %s", entry.data[CONF_MAC_CODE], entry.options
119  )
120  await apply_options(hass, entry)
121 
122 
123 async def apply_options(hass: HomeAssistant, entry: ConfigEntry) -> None:
124  """Apply the options from the OptionsFlow."""
125 
126  device: MotionDevice = hass.data[DOMAIN][entry.entry_id]
127  disconnect_time: float | None = entry.options.get(OPTION_DISCONNECT_TIME, None)
128  permanent_connection: bool = entry.options.get(OPTION_PERMANENT_CONNECTION, False)
129 
130  device.set_custom_disconnect_time(disconnect_time)
131  await device.set_permanent_connection(permanent_connection)
132 
133 
134 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
135  """Unload Motionblinds Bluetooth device from a config entry."""
136 
137  if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
138  hass.data[DOMAIN].pop(entry.entry_id)
139 
140  return unload_ok
BLEDevice|None async_ble_device_from_address(HomeAssistant hass, str address, bool connectable=True)
Definition: api.py:88
None options_update_listener(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:115
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:134
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:47
None apply_options(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:123
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:59
Callable[[], None] async_register_callback(HomeAssistant hass, Callable[[SsdpServiceInfo, SsdpChange], Coroutine[Any, Any, None]|None] callback, dict[str, str]|None match_dict=None)
Definition: __init__.py:153