Skip to content

Commit

Permalink
Handle missing or incorrect device name and unique id for ESPHome dur…
Browse files Browse the repository at this point in the history
…ing manual add (#95678)

* Handle incorrect or missing device name for ESPHome noise encryption

If we did not have the device name during setup we could never
get the key from the dashboard. The device will send us
its name if we try encryption which allows us to find the
right key from the dashboard.

This should help get users unstuck when they change the key
and cannot get the device back online after deleting and
trying to set it up again manually

* bump lib to get name

* tweak

* reduce number of connections

* less connections when we know we will fail

* coverage shows it works but it does not

* add more coverage

* fix test

* bump again
  • Loading branch information
bdraco authored and balloob committed Jul 3, 2023
1 parent 327a54e commit ca20663
Show file tree
Hide file tree
Showing 5 changed files with 342 additions and 21 deletions.
42 changes: 28 additions & 14 deletions homeassistant/components/esphome/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
ESPHOME_URL = "https://esphome.io/"
_LOGGER = logging.getLogger(__name__)

ZERO_NOISE_PSK = "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA="


class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle a esphome config flow."""
Expand Down Expand Up @@ -149,11 +151,22 @@ def _name(self, value: str) -> None:
async def _async_try_fetch_device_info(self) -> FlowResult:
error = await self.fetch_device_info()

if (
error == ERROR_REQUIRES_ENCRYPTION_KEY
and await self._retrieve_encryption_key_from_dashboard()
):
error = await self.fetch_device_info()
if error == 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()
self._noise_psk = None

if (
self._device_name
and await self._retrieve_encryption_key_from_dashboard()
):
error = await self.fetch_device_info()

# If the fetched key is invalid, unset it again.
if error == ERROR_INVALID_ENCRYPTION_KEY:
self._noise_psk = None
Expand Down Expand Up @@ -323,7 +336,10 @@ async def fetch_device_info(self) -> str | None:
self._device_info = await cli.device_info()
except RequiresEncryptionAPIError:
return ERROR_REQUIRES_ENCRYPTION_KEY
except InvalidEncryptionKeyAPIError:
except InvalidEncryptionKeyAPIError as ex:
if ex.received_name:
self._device_name = ex.received_name
self._name = ex.received_name
return ERROR_INVALID_ENCRYPTION_KEY
except ResolveAPIError:
return "resolve_error"
Expand All @@ -334,9 +350,8 @@ async def fetch_device_info(self) -> str | None:

self._name = self._device_info.friendly_name or self._device_info.name
self._device_name = self._device_info.name
await self.async_set_unique_id(
self._device_info.mac_address, raise_on_progress=False
)
mac_address = format_mac(self._device_info.mac_address)
await self.async_set_unique_id(mac_address, raise_on_progress=False)
if not self._reauth_entry:
self._abort_if_unique_id_configured(
updates={CONF_HOST: self._host, CONF_PORT: self._port}
Expand Down Expand Up @@ -373,14 +388,13 @@ async def _retrieve_encryption_key_from_dashboard(self) -> bool:
Return boolean if a key was retrieved.
"""
if self._device_name is None:
return False

if (dashboard := async_get_dashboard(self.hass)) is None:
if (
self._device_name is None
or (dashboard := async_get_dashboard(self.hass)) is None
):
return False

await dashboard.async_request_refresh()

if not dashboard.last_update_success:
return False

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/esphome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"iot_class": "local_push",
"loggers": ["aioesphomeapi", "noiseprotocol"],
"requirements": [
"aioesphomeapi==15.0.1",
"aioesphomeapi==15.1.1",
"bluetooth-data-tools==1.3.0",
"esphome-dashboard-api==1.2.3"
],
Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ aioecowitt==2023.5.0
aioemonitor==1.0.5

# homeassistant.components.esphome
aioesphomeapi==15.0.1
aioesphomeapi==15.1.1

# homeassistant.components.flo
aioflo==2021.11.0
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ aioecowitt==2023.5.0
aioemonitor==1.0.5

# homeassistant.components.esphome
aioesphomeapi==15.0.1
aioesphomeapi==15.1.1

# homeassistant.components.flo
aioflo==2021.11.0
Expand Down
Loading

0 comments on commit ca20663

Please sign in to comment.