1 """The Xiaomi Bluetooth integration."""
3 from __future__
import annotations
5 from functools
import partial
7 from typing
import cast
9 from xiaomi_ble
import EncryptionScheme, SensorUpdate, XiaomiBluetoothDeviceData
12 DOMAIN
as BLUETOOTH_DOMAIN,
13 BluetoothScanningMode,
14 BluetoothServiceInfoBleak,
15 async_ble_device_from_address,
25 CONF_DISCOVERED_EVENT_CLASSES,
31 from .coordinator
import XiaomiActiveBluetoothProcessorCoordinator
32 from .types
import XiaomiBLEConfigEntry
34 PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.EVENT, Platform.SENSOR]
36 _LOGGER = logging.getLogger(__name__)
41 entry: XiaomiBLEConfigEntry,
42 device_registry: DeviceRegistry,
43 service_info: BluetoothServiceInfoBleak,
45 """Process a BluetoothServiceInfoBleak, running side effects and returning sensor data."""
46 coordinator = entry.runtime_data
47 data = coordinator.device_data
48 update = data.update(service_info)
49 discovered_event_classes = coordinator.discovered_event_classes
50 if entry.data.get(CONF_SLEEPY_DEVICE,
False) != data.sleepy_device:
51 hass.config_entries.async_update_entry(
53 data=entry.data | {CONF_SLEEPY_DEVICE: data.sleepy_device},
56 address = service_info.device.address
57 for device_key, event
in update.events.items():
58 sensor_device_info = update.devices[device_key.device_id]
59 device = device_registry.async_get_or_create(
60 config_entry_id=entry.entry_id,
61 connections={(CONNECTION_BLUETOOTH, address)},
62 identifiers={(BLUETOOTH_DOMAIN, address)},
63 manufacturer=sensor_device_info.manufacturer,
64 model=sensor_device_info.model,
65 name=sensor_device_info.name,
66 sw_version=sensor_device_info.sw_version,
67 hw_version=sensor_device_info.hw_version,
71 event_class = event.device_key.key
72 event_type = event.event_type
77 event_class=event_class,
78 event_type=event_type,
79 event_properties=event.event_properties,
82 if event_class
not in discovered_event_classes:
83 discovered_event_classes.add(event_class)
84 hass.config_entries.async_update_entry(
87 | {CONF_DISCOVERED_EVENT_CLASSES:
list(discovered_event_classes)},
93 hass.bus.async_fire(XIAOMI_BLE_EVENT, cast(dict, ble_event))
104 and data.encryption_scheme != EncryptionScheme.NONE
105 and not data.bindkey_verified
107 entry.async_start_reauth(hass, data={
"device": data})
113 """Format an event dispatcher name."""
114 return f
"{DOMAIN}_event_{address}_{event_class}"
118 """Format a discovered event class."""
119 return f
"{DOMAIN}_discovered_event_class_{address}"
123 """Set up Xiaomi BLE device from a config entry."""
124 address = entry.unique_id
125 assert address
is not None
128 if bindkey := entry.data.get(
"bindkey"):
129 kwargs[
"bindkey"] = bytes.fromhex(bindkey)
130 data = XiaomiBluetoothDeviceData(**kwargs)
133 service_info: BluetoothServiceInfoBleak, last_poll: float |
None
138 hass.state
is CoreState.running
139 and data.poll_needed(service_info, last_poll)
142 hass, service_info.device.address, connectable=
True
147 async
def _async_poll(service_info: BluetoothServiceInfoBleak) -> SensorUpdate:
152 if service_info.connectable:
153 connectable_device = service_info.device
155 hass, service_info.device.address,
True
157 connectable_device = device
162 f
"No connectable device found for {service_info.device.address}"
164 return await data.async_poll(connectable_device)
166 device_registry = dr.async_get(hass)
171 mode=BluetoothScanningMode.PASSIVE,
172 update_method=partial(process_service_info, hass, entry, device_registry),
173 needs_poll_method=_needs_poll,
175 discovered_event_classes=set(entry.data.get(CONF_DISCOVERED_EVENT_CLASSES, [])),
176 poll_method=_async_poll,
183 entry.runtime_data = coordinator
184 await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
186 entry.async_on_unload(coordinator.async_start())
191 """Unload a config entry."""
192 return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
BLEDevice|None async_ble_device_from_address(HomeAssistant hass, str address, bool connectable=True)
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
str format_discovered_event_class(str address)
SensorUpdate process_service_info(HomeAssistant hass, XiaomiBLEConfigEntry entry, DeviceRegistry device_registry, BluetoothServiceInfoBleak service_info)
bool async_unload_entry(HomeAssistant hass, XiaomiBLEConfigEntry entry)
str format_event_dispatcher_name(str address, str event_class)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)