Skip to content
19 changes: 14 additions & 5 deletions homeassistant/components/esphome/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ async def async_setup_entry(
if (dashboard := async_get_dashboard(hass)) is None:
return
entry_data = DomainData.get(hass).get_entry_data(entry)
assert entry_data.device_info is not None
device_name = entry_data.device_info.name
unsubs: list[CALLBACK_TYPE] = []

@callback
Expand All @@ -72,13 +74,22 @@ def _async_setup_update_entity() -> None:
if not entry_data.available or not dashboard.last_update_success:
return

# Do not add Dashboard Entity if this device is not known to the ESPHome dashboard.
if dashboard.data is None or dashboard.data.get(device_name) is None:
return

for unsub in unsubs:
unsub()
unsubs.clear()

async_add_entities([ESPHomeDashboardUpdateEntity(entry_data, dashboard)])

if entry_data.available and dashboard.last_update_success:
if (
entry_data.available
and dashboard.last_update_success
and dashboard.data is not None
and dashboard.data.get(device_name)
):
_async_setup_update_entity()
return

Expand Down Expand Up @@ -133,10 +144,8 @@ def _update_attrs(self) -> None:
self._attr_supported_features = NO_FEATURES
self._attr_installed_version = device_info.esphome_version
device = coordinator.data.get(device_info.name)
if device is None:
self._attr_latest_version = None
else:
self._attr_latest_version = device["current_version"]
assert device is not None
self._attr_latest_version = device["current_version"]

@callback
def _handle_coordinator_update(self) -> None:
Expand Down
47 changes: 36 additions & 11 deletions tests/components/esphome/test_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
Expand Down Expand Up @@ -83,11 +82,6 @@ def stub_reconnect():
"supported_features": 0,
},
),
(
[],
STATE_UNKNOWN, # dashboard is available but device is unknown
{"supported_features": 0},
),
],
)
async def test_update_entity(
Expand Down Expand Up @@ -408,11 +402,7 @@ async def test_update_becomes_available_at_runtime(
)
await hass.async_block_till_done()
state = hass.states.get("update.test_firmware")
assert state is not None
features = state.attributes[ATTR_SUPPORTED_FEATURES]
# There are no devices on the dashboard so no
# way to tell the version so install is disabled
assert features is UpdateEntityFeature(0)
assert state is None

# A device gets added to the dashboard
mock_dashboard["configured"] = [
Expand All @@ -433,6 +423,41 @@ async def test_update_becomes_available_at_runtime(
assert features is UpdateEntityFeature.INSTALL


async def test_update_entity_not_present_with_dashboard_but_unknown_device(
hass: HomeAssistant,
mock_client: APIClient,
mock_esphome_device: Callable[
[APIClient, list[EntityInfo], list[UserService], list[EntityState]],
Awaitable[MockESPHomeDevice],
],
mock_dashboard: dict[str, Any],
) -> None:
"""Test ESPHome update entity does not get created if the device is unknown to the dashboard."""
await mock_esphome_device(
mock_client=mock_client,
entity_info=[],
user_service=[],
states=[],
)

mock_dashboard["configured"] = [
{
"name": "other-test",
"current_version": "2023.2.0-dev",
"configuration": "other-test.yaml",
}
]

state = hass.states.get("update.test_firmware")
assert state is None

await async_get_dashboard(hass).async_refresh()
await hass.async_block_till_done()

state = hass.states.get("update.none_firmware")
assert state is None


async def test_generic_device_update_entity(
hass: HomeAssistant,
mock_client: APIClient,
Expand Down