1 """The BTHome Bluetooth integration."""
3 from __future__
import annotations
5 from functools
import partial
8 from bthome_ble
import BTHomeBluetoothDeviceData, SensorUpdate
9 from bthome_ble.parser
import EncryptionScheme
12 DOMAIN
as BLUETOOTH_DOMAIN,
13 BluetoothScanningMode,
14 BluetoothServiceInfoBleak,
26 CONF_DISCOVERED_EVENT_CLASSES,
31 from .coordinator
import BTHomePassiveBluetoothProcessorCoordinator
32 from .types
import BTHomeConfigEntry
34 PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.EVENT, Platform.SENSOR]
36 _LOGGER = logging.getLogger(__name__)
41 entry: BTHomeConfigEntry,
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(BTHOME_BLE_EVENT, ble_event)
101 if data.encryption_scheme != EncryptionScheme.NONE
and not data.bindkey_verified:
102 entry.async_start_reauth(hass, data={
"device": data})
108 address: str, event_class: str
109 ) -> SignalType[BTHomeBleEvent]:
110 """Format an event dispatcher name."""
111 return SignalType(f
"{DOMAIN}_event_{address}_{event_class}")
115 """Format a discovered event class."""
116 return SignalType(f
"{DOMAIN}_discovered_event_class_{address}")
120 """Set up BTHome Bluetooth from a config entry."""
121 address = entry.unique_id
122 assert address
is not None
125 if bindkey := entry.data.get(CONF_BINDKEY):
126 kwargs[CONF_BINDKEY] = bytes.fromhex(bindkey)
127 data = BTHomeBluetoothDeviceData(**kwargs)
129 device_registry = dr.async_get(hass)
130 event_classes = set(entry.data.get(CONF_DISCOVERED_EVENT_CLASSES, ()))
135 mode=BluetoothScanningMode.PASSIVE,
136 update_method=partial(process_service_info, hass, entry, device_registry),
138 discovered_event_classes=event_classes,
142 entry.runtime_data = coordinator
143 await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
146 entry.async_on_unload(coordinator.async_start())
151 """Unload a config entry."""
152 return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
SensorUpdate process_service_info(HomeAssistant hass, BTHomeConfigEntry entry, DeviceRegistry device_registry, BluetoothServiceInfoBleak service_info)
SignalType[BTHomeBleEvent] format_event_dispatcher_name(str address, str event_class)
SignalType[str, BTHomeBleEvent] format_discovered_event_class(str address)
bool async_unload_entry(HomeAssistant hass, BTHomeConfigEntry entry)
bool async_setup_entry(HomeAssistant hass, BTHomeConfigEntry entry)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)