1 """Config flow for Airthings BlE integration."""
3 from __future__
import annotations
9 from airthings_ble
import AirthingsBluetoothDeviceData, AirthingsDevice
10 from bleak
import BleakError
11 import voluptuous
as vol
16 async_discovered_service_info,
21 from .const
import DOMAIN, MFCT_ID
23 _LOGGER = logging.getLogger(__name__)
26 "b42e1f6e-ade7-11e4-89d3-123b93f75cba",
27 "b42e4a8e-ade7-11e4-89d3-123b93f75cba",
28 "b42e1c08-ade7-11e4-89d3-123b93f75cba",
29 "b42e3882-ade7-11e4-89d3-123b93f75cba",
33 @dataclasses.dataclass
35 """A discovered bluetooth device."""
38 discovery_info: BluetoothServiceInfo
39 device: AirthingsDevice
43 """Generate name with model and identifier for device."""
45 name = device.friendly_name()
46 if identifier := device.identifier:
47 name += f
" ({identifier})"
52 """Custom error class for device updates."""
55 class AirthingsConfigFlow(ConfigFlow, domain=DOMAIN):
56 """Handle a config flow for Airthings BLE."""
61 """Initialize the config flow."""
63 self._discovered_devices: dict[str, Discovery] = {}
66 self, discovery_info: BluetoothServiceInfo
68 ble_device = bluetooth.async_ble_device_from_address(
69 self.hass, discovery_info.address
71 if ble_device
is None:
72 _LOGGER.debug(
"no ble_device in _get_device_data")
75 airthings = AirthingsBluetoothDeviceData(_LOGGER)
78 data = await airthings.update_device(ble_device)
79 except BleakError
as err:
81 "Error connecting to and getting data from %s: %s",
82 discovery_info.address,
86 except Exception
as err:
88 "Unknown error occurred from %s: %s", discovery_info.address, err
94 self, discovery_info: BluetoothServiceInfo
95 ) -> ConfigFlowResult:
96 """Handle the bluetooth discovery step."""
97 _LOGGER.debug(
"Discovered BT device: %s", discovery_info)
103 except AirthingsDeviceUpdateError:
109 self.context[
"title_placeholders"] = {
"name": name}
115 self, user_input: dict[str, Any] |
None =
None
116 ) -> ConfigFlowResult:
117 """Confirm discovery."""
118 if user_input
is not None:
120 title=self.context[
"title_placeholders"][
"name"], data={}
125 step_id=
"bluetooth_confirm",
126 description_placeholders=self.context[
"title_placeholders"],
130 self, user_input: dict[str, Any] |
None =
None
131 ) -> ConfigFlowResult:
132 """Handle the user step to pick discovered device."""
133 if user_input
is not None:
134 address = user_input[CONF_ADDRESS]
137 discovery = self._discovered_devices[address]
139 self.context[
"title_placeholders"] = {
140 "name": discovery.name,
149 address = discovery_info.address
150 if address
in current_addresses
or address
in self._discovered_devices:
153 if MFCT_ID
not in discovery_info.manufacturer_data:
156 if not any(uuid
in SERVICE_UUIDS
for uuid
in discovery_info.service_uuids):
161 except AirthingsDeviceUpdateError:
166 self._discovered_devices[address] =
Discovery(name, discovery_info, device)
168 if not self._discovered_devices:
172 address: discovery.device.name
173 for (address, discovery)
in self._discovered_devices.items()
177 data_schema=vol.Schema(
179 vol.Required(CONF_ADDRESS): vol.In(titles),
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_bluetooth_confirm(self, dict[str, Any]|None user_input=None)
AirthingsDevice _get_device_data(self, BluetoothServiceInfo discovery_info)
ConfigFlowResult async_step_bluetooth(self, BluetoothServiceInfo discovery_info)
None _abort_if_unique_id_configured(self, dict[str, Any]|None updates=None, bool reload_on_update=True, *str error="already_configured")
None _set_confirm_only(self)
set[str|None] _async_current_ids(self, bool include_ignore=True)
ConfigEntry|None async_set_unique_id(self, str|None unique_id=None, *bool raise_on_progress=True)
ConfigFlowResult async_create_entry(self, *str title, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None, Mapping[str, Any]|None options=None)
ConfigFlowResult async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
ConfigFlowResult async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_create_entry(self, *str|None title=None, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None)
_FlowResultT async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
str get_name(AirthingsDevice device)
Iterable[BluetoothServiceInfoBleak] async_discovered_service_info(HomeAssistant hass, bool connectable=True)