66from typing import TYPE_CHECKING , Any
77
88import voluptuous as vol
9- from homeassistant .components .bluetooth import async_discovered_service_info
9+ from bleak .exc import BleakError
10+ from homeassistant .components .bluetooth import (
11+ async_ble_device_from_address ,
12+ async_discovered_service_info ,
13+ )
1014from homeassistant .config_entries import ConfigFlow , ConfigFlowResult
1115from homeassistant .const import CONF_ADDRESS
1216
1317from .const import DOMAIN , MANUFACTURER_ID
18+ from .run_chicken_ble import RunChickenDevice
1419
1520if TYPE_CHECKING :
1621 from homeassistant .components .bluetooth import BluetoothServiceInfoBleak
@@ -45,23 +50,32 @@ async def async_step_bluetooth(self, discovery_info: BluetoothServiceInfoBleak)
4550 return await self .async_step_bluetooth_confirm ()
4651
4752 async def async_step_bluetooth_confirm (self , user_input : dict [str , Any ] | None = None ) -> ConfigFlowResult :
48- """Confirm adding a device discovered over bluetooth."""
53+ """Confirm adding a device discovered over bluetooth, verifying it is reachable."""
54+ errors : dict [str , str ] = {}
4955 if user_input is not None :
50- return self .async_create_entry (title = self ._discovery_info .name , data = {})
56+ error = await self ._async_try_connect (self ._discovery_info .address )
57+ if error is None :
58+ return self .async_create_entry (title = self ._discovery_info .name , data = {})
59+ errors ["base" ] = error
5160
5261 self ._set_confirm_only ()
5362 return self .async_show_form (
5463 step_id = "bluetooth_confirm" ,
5564 description_placeholders = {"name" : self ._discovery_info .name },
65+ errors = errors ,
5666 )
5767
5868 async def async_step_user (self , user_input : dict [str , Any ] | None = None ) -> ConfigFlowResult :
5969 """Show a list of discovered devices and let the user pick one."""
70+ errors : dict [str , str ] = {}
6071 if user_input is not None :
6172 address = user_input [CONF_ADDRESS ]
6273 await self .async_set_unique_id (address , raise_on_progress = False )
6374 self ._abort_if_unique_id_configured ()
64- return self .async_create_entry (title = self ._discovered_devices [address ], data = {})
75+ error = await self ._async_try_connect (address )
76+ if error is None :
77+ return self .async_create_entry (title = self ._discovered_devices .get (address , address ), data = {})
78+ errors ["base" ] = error
6579
6680 # Skip devices already set up or being set up in another in-progress flow.
6781 addresses_in_use = self ._async_current_ids () | {
@@ -80,4 +94,31 @@ async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Con
8094 return self .async_abort (reason = "no_devices_found" )
8195
8296 schema = vol .Schema ({vol .Required (CONF_ADDRESS ): vol .In (self ._discovered_devices )})
83- return self .async_show_form (step_id = "user" , data_schema = schema )
97+ return self .async_show_form (step_id = "user" , data_schema = schema , errors = errors )
98+
99+ async def _async_try_connect (self , address : str ) -> str | None :
100+ """
101+ Probe connectivity to the device at ``address``.
102+
103+ Establishes a single BLE connection and immediately disconnects, leaving
104+ the device free for the entry setup to reconnect. Returns an error key
105+ (``cannot_connect``/``unknown``) on failure, or ``None`` on success.
106+ """
107+ ble_device = async_ble_device_from_address (self .hass , address , connectable = True )
108+ if ble_device is None :
109+ _LOGGER .debug ("No connectable BLE device found for %s" , address )
110+ return "cannot_connect"
111+
112+ device = RunChickenDevice (ble_device )
113+ try :
114+ await device .ensure_client_connected ()
115+ except (BleakError , TimeoutError ):
116+ _LOGGER .debug ("Could not connect to Run-Chicken device %s" , address , exc_info = True )
117+ return "cannot_connect"
118+ except Exception :
119+ _LOGGER .exception ("Unexpected error connecting to Run-Chicken device %s" , address )
120+ return "unknown"
121+ finally :
122+ if device .client is not None :
123+ await device .client .disconnect ()
124+ return None
0 commit comments