Update ESPHome devices from HA (#86249)

* Update ESPHome devices from HA

* esphome-dashboard-api==1.2.2

* Limit to 1 parallel ESPHome update
This commit is contained in:
Paulus Schoutsen 2023-01-19 16:28:46 -05:00 committed by GitHub
parent 8aeb20db00
commit 8f10c22a23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 62 additions and 7 deletions

View File

@ -3,7 +3,7 @@
"name": "ESPHome",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/esphome",
"requirements": ["aioesphomeapi==13.1.0", "esphome-dashboard-api==1.1"],
"requirements": ["aioesphomeapi==13.1.0", "esphome-dashboard-api==1.2.1"],
"zeroconf": ["_esphomelib._tcp.local."],
"dhcp": [{ "registered_devices": true }],
"codeowners": ["@OttoWinter", "@jesserockz"],

View File

@ -1,7 +1,9 @@
"""Update platform for ESPHome."""
from __future__ import annotations
from typing import cast
import asyncio
import logging
from typing import Any, cast
from aioesphomeapi import DeviceInfo as ESPHomeDeviceInfo
@ -22,6 +24,8 @@ from .dashboard import ESPHomeDashboard, async_get_dashboard
from .domain_data import DomainData
from .entry_data import RuntimeEntryData
KEY_UPDATE_LOCK = "esphome_update_lock"
async def async_setup_entry(
hass: HomeAssistant,
@ -64,7 +68,7 @@ class ESPHomeUpdateEntity(CoordinatorEntity[ESPHomeDashboard], UpdateEntity):
_attr_has_entity_name = True
_attr_device_class = UpdateDeviceClass.FIRMWARE
_attr_supported_features = UpdateEntityFeature.SPECIFIC_VERSION
_attr_supported_features = UpdateEntityFeature.INSTALL
_attr_title = "ESPHome"
_attr_name = "Firmware"
@ -106,3 +110,22 @@ class ESPHomeUpdateEntity(CoordinatorEntity[ESPHomeDashboard], UpdateEntity):
def release_url(self) -> str | None:
"""URL to the full release notes of the latest version available."""
return "https://esphome.io/changelog/"
async def async_install(
self, version: str | None, backup: bool, **kwargs: Any
) -> None:
"""Install an update."""
async with self.hass.data.setdefault(KEY_UPDATE_LOCK, asyncio.Lock()):
device = self.coordinator.data.get(self._device_info.name)
assert device is not None
if not await self.coordinator.api.compile(device["configuration"]):
logging.getLogger(__name__).error(
"Error compiling %s. Try again in ESPHome dashboard for error",
device["configuration"],
)
if not await self.coordinator.api.upload(device["configuration"], "OTA"):
logging.getLogger(__name__).error(
"Error OTA updating %s. Try again in ESPHome dashboard for error",
device["configuration"],
)
await self.coordinator.async_request_refresh()

View File

@ -676,7 +676,7 @@ epson-projector==0.5.0
epsonprinter==0.0.9
# homeassistant.components.esphome
esphome-dashboard-api==1.1
esphome-dashboard-api==1.2.1
# homeassistant.components.netgear_lte
eternalegypt==0.0.12

View File

@ -526,7 +526,7 @@ ephem==4.1.2
epson-projector==0.5.0
# homeassistant.components.esphome
esphome-dashboard-api==1.1
esphome-dashboard-api==1.2.1
# homeassistant.components.eufylife_ble
eufylife_ble_client==0.1.7

View File

@ -17,12 +17,23 @@ def stub_reconnect():
"devices_payload,expected_state,expected_attributes",
[
(
[{"name": "test", "current_version": "1.2.3"}],
[
{
"name": "test",
"current_version": "1.2.3",
"configuration": "test.yaml",
}
],
"on",
{"latest_version": "1.2.3", "installed_version": "1.0.0"},
),
(
[{"name": "test", "current_version": "1.0.0"}],
[
{
"name": "test",
"current_version": "1.0.0",
},
],
"off",
{"latest_version": "1.0.0", "installed_version": "1.0.0"},
),
@ -61,3 +72,24 @@ async def test_update_entity(
assert state.state == expected_state
for key, expected_value in expected_attributes.items():
assert state.attributes.get(key) == expected_value
if expected_state != "on":
return
with patch(
"esphome_dashboard_api.ESPHomeDashboardAPI.compile", return_value=True
) as mock_compile, patch(
"esphome_dashboard_api.ESPHomeDashboardAPI.upload", return_value=True
) as mock_upload:
await hass.services.async_call(
"update",
"install",
{"entity_id": "update.none_firmware"},
blocking=True,
)
assert len(mock_compile.mock_calls) == 1
assert mock_compile.mock_calls[0][1][0] == "test.yaml"
assert len(mock_upload.mock_calls) == 1
assert mock_upload.mock_calls[0][1][0] == "test.yaml"