Avoid probing ESPHome devices when we do not have the encryption key (#95820)
parent
e8397063d3
commit
995fb993e6
|
@ -55,6 +55,7 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||
self._host: str | None = None
|
||||
self._port: int | None = None
|
||||
self._password: str | None = None
|
||||
self._noise_required: bool | None = None
|
||||
self._noise_psk: str | None = None
|
||||
self._device_info: DeviceInfo | None = None
|
||||
self._reauth_entry: ConfigEntry | None = None
|
||||
|
@ -151,33 +152,45 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||
self.context["title_placeholders"] = {"name": self._name}
|
||||
|
||||
async def _async_try_fetch_device_info(self) -> FlowResult:
|
||||
error = await self.fetch_device_info()
|
||||
"""Try to fetch device info and return any errors."""
|
||||
response: str | None
|
||||
if self._noise_required:
|
||||
# If we already know we need encryption, don't try to fetch device info
|
||||
# without encryption.
|
||||
response = ERROR_REQUIRES_ENCRYPTION_KEY
|
||||
else:
|
||||
# After 2024.08, stop trying to fetch device info without encryption
|
||||
# so we can avoid probe requests to check for password. At this point
|
||||
# most devices should announce encryption support and password is
|
||||
# deprecated and can be discovered by trying to connect only after they
|
||||
# interact with the flow since it is expected to be a rare case.
|
||||
response = await self.fetch_device_info()
|
||||
|
||||
if error == ERROR_REQUIRES_ENCRYPTION_KEY:
|
||||
if response == ERROR_REQUIRES_ENCRYPTION_KEY:
|
||||
if not self._device_name and not self._noise_psk:
|
||||
# If device name is not set we can send a zero noise psk
|
||||
# to get the device name which will allow us to populate
|
||||
# the device name and hopefully get the encryption key
|
||||
# from the dashboard.
|
||||
self._noise_psk = ZERO_NOISE_PSK
|
||||
error = await self.fetch_device_info()
|
||||
response = await self.fetch_device_info()
|
||||
self._noise_psk = None
|
||||
|
||||
if (
|
||||
self._device_name
|
||||
and await self._retrieve_encryption_key_from_dashboard()
|
||||
):
|
||||
error = await self.fetch_device_info()
|
||||
response = await self.fetch_device_info()
|
||||
|
||||
# If the fetched key is invalid, unset it again.
|
||||
if error == ERROR_INVALID_ENCRYPTION_KEY:
|
||||
if response == ERROR_INVALID_ENCRYPTION_KEY:
|
||||
self._noise_psk = None
|
||||
error = ERROR_REQUIRES_ENCRYPTION_KEY
|
||||
response = ERROR_REQUIRES_ENCRYPTION_KEY
|
||||
|
||||
if error == ERROR_REQUIRES_ENCRYPTION_KEY:
|
||||
if response == ERROR_REQUIRES_ENCRYPTION_KEY:
|
||||
return await self.async_step_encryption_key()
|
||||
if error is not None:
|
||||
return await self._async_step_user_base(error=error)
|
||||
if response is not None:
|
||||
return await self._async_step_user_base(error=response)
|
||||
return await self._async_authenticate_or_add()
|
||||
|
||||
async def _async_authenticate_or_add(self) -> FlowResult:
|
||||
|
@ -220,6 +233,7 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||
self._device_name = device_name
|
||||
self._host = discovery_info.host
|
||||
self._port = discovery_info.port
|
||||
self._noise_required = bool(discovery_info.properties.get("api_encryption"))
|
||||
|
||||
# Check if already configured
|
||||
await self.async_set_unique_id(mac_address)
|
||||
|
|
|
@ -1233,6 +1233,72 @@ async def test_zeroconf_encryption_key_via_dashboard(
|
|||
assert mock_client.noise_psk == VALID_NOISE_PSK
|
||||
|
||||
|
||||
async def test_zeroconf_encryption_key_via_dashboard_with_api_encryption_prop(
|
||||
hass: HomeAssistant,
|
||||
mock_client,
|
||||
mock_zeroconf: None,
|
||||
mock_dashboard,
|
||||
mock_setup_entry: None,
|
||||
) -> None:
|
||||
"""Test encryption key retrieved from dashboard with api_encryption property set."""
|
||||
service_info = zeroconf.ZeroconfServiceInfo(
|
||||
host="192.168.43.183",
|
||||
addresses=["192.168.43.183"],
|
||||
hostname="test8266.local.",
|
||||
name="mock_name",
|
||||
port=6053,
|
||||
properties={
|
||||
"mac": "1122334455aa",
|
||||
"api_encryption": "any",
|
||||
},
|
||||
type="mock_type",
|
||||
)
|
||||
flow = await hass.config_entries.flow.async_init(
|
||||
"esphome", context={"source": config_entries.SOURCE_ZEROCONF}, data=service_info
|
||||
)
|
||||
|
||||
assert flow["type"] == FlowResultType.FORM
|
||||
assert flow["step_id"] == "discovery_confirm"
|
||||
|
||||
mock_dashboard["configured"].append(
|
||||
{
|
||||
"name": "test8266",
|
||||
"configuration": "test8266.yaml",
|
||||
}
|
||||
)
|
||||
|
||||
await dashboard.async_get_dashboard(hass).async_refresh()
|
||||
|
||||
mock_client.device_info.side_effect = [
|
||||
DeviceInfo(
|
||||
uses_password=False,
|
||||
name="test8266",
|
||||
mac_address="11:22:33:44:55:AA",
|
||||
),
|
||||
]
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.esphome.dashboard.ESPHomeDashboardAPI.get_encryption_key",
|
||||
return_value=VALID_NOISE_PSK,
|
||||
) as mock_get_encryption_key:
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
flow["flow_id"], user_input={}
|
||||
)
|
||||
|
||||
assert len(mock_get_encryption_key.mock_calls) == 1
|
||||
|
||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == "test8266"
|
||||
assert result["data"][CONF_HOST] == "192.168.43.183"
|
||||
assert result["data"][CONF_PORT] == 6053
|
||||
assert result["data"][CONF_NOISE_PSK] == VALID_NOISE_PSK
|
||||
|
||||
assert result["result"]
|
||||
assert result["result"].unique_id == "11:22:33:44:55:aa"
|
||||
|
||||
assert mock_client.noise_psk == VALID_NOISE_PSK
|
||||
|
||||
|
||||
async def test_zeroconf_no_encryption_key_via_dashboard(
|
||||
hass: HomeAssistant,
|
||||
mock_client,
|
||||
|
|
Loading…
Reference in New Issue