From b9ac7949dbde5c32bb45d2311785ca60c10c7948 Mon Sep 17 00:00:00 2001 From: mampfes Date: Wed, 27 Sep 2023 16:43:41 +0200 Subject: [PATCH] add firmware update entity --- custom_components/bayernluefter/__init__.py | 17 ++++- custom_components/bayernluefter/manifest.json | 4 +- custom_components/bayernluefter/update.py | 73 +++++++++++++++++++ 3 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 custom_components/bayernluefter/update.py diff --git a/custom_components/bayernluefter/__init__.py b/custom_components/bayernluefter/__init__.py index 18274fe..3db7f26 100644 --- a/custom_components/bayernluefter/__init__.py +++ b/custom_components/bayernluefter/__init__.py @@ -3,15 +3,16 @@ """ import logging -from datetime import timedelta +from datetime import timedelta, datetime from typing import Any from homeassistant.core import HomeAssistant from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, CONF_SCAN_INTERVAL +from homeassistant.const import CONF_HOST, CONF_SCAN_INTERVAL, Platform from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.device_registry import DeviceInfo, format_mac from homeassistant.helpers.entity import Entity, EntityDescription +from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -23,8 +24,9 @@ SCAN_INTERVAL = timedelta(seconds=20) +UPDATE_SCAN_INTERVAL = timedelta(days=1) # check once per day for firmware updates -PLATFORMS = ["sensor", "binary_sensor", "fan"] +PLATFORMS = [Platform.SENSOR, Platform.BINARY_SENSOR, Platform.FAN, Platform.UPDATE] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: @@ -33,6 +35,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: session = async_get_clientsession(hass) device = Bayernluefter(entry.data[CONF_HOST], session) + await device.poll_latest_versions() + update_interval = timedelta( seconds=entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL) ) @@ -47,6 +51,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: entry.async_on_unload(entry.add_update_listener(on_update_options_listener)) + async def poll_latest_versions(now: datetime) -> None: + await device.poll_latest_versions() + + entry.async_on_unload( + async_track_time_interval(hass, poll_latest_versions, UPDATE_SCAN_INTERVAL) + ) + return True diff --git a/custom_components/bayernluefter/manifest.json b/custom_components/bayernluefter/manifest.json index c368b85..8922c92 100644 --- a/custom_components/bayernluefter/manifest.json +++ b/custom_components/bayernluefter/manifest.json @@ -8,6 +8,6 @@ "integration_type": "device", "iot_class": "local_polling", "issue_tracker": "https://github.com/mampfes/ha_bayernluefter/issues", - "requirements": ["pyernluefter==0.1.1"], - "version": "1.1.0" + "requirements": ["pyernluefter==0.2.0"], + "version": "1.2.0" } diff --git a/custom_components/bayernluefter/update.py b/custom_components/bayernluefter/update.py new file mode 100644 index 0000000..6c531df --- /dev/null +++ b/custom_components/bayernluefter/update.py @@ -0,0 +1,73 @@ +""" +Support for Bayernluefter update. +""" + +import logging +from typing import Any + +from homeassistant.components.update import ( + UpdateEntity, + UpdateEntityDescription, + UpdateEntityFeature, + UpdateDeviceClass, +) + +from pyernluefter import UpdateTarget + +from . import ( + BayernluefterEntity, + BayernluefterDataUpdateCoordinator as DataUpdateCoordinator, +) + +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up update entries.""" + coordinator: DataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] + entities = [BayernluefterUpdate(coordinator)] + async_add_entities(entities) + + +class BayernluefterUpdate(BayernluefterEntity, UpdateEntity): + """An update implementation for Bayernluefter devices.""" + + entity_description = UpdateEntityDescription( + key="FW_WiFi", device_class=UpdateDeviceClass.FIRMWARE + ) + + target = UpdateTarget.WLAN32 + + # These update specific attributes are not (yet) part of UpdateEntityDescription + _attr_supported_features = UpdateEntityFeature.INSTALL + + def __init__( + self, + coordinator: DataUpdateCoordinator, + ) -> None: + """Initialize an update entity for a Bayernluefter device.""" + super().__init__(coordinator, self.entity_description) + self._attr_release_url = self._device.release_url(self.target) + + @property + def available(self) -> bool: + return ( + self._coordinator.last_update_success + and self._device.installed_version(self.target) is not None + ) + + @property + def latest_version(self) -> str: + return self._device.latest_version(self.target) + + @property + def installed_version(self) -> str: + return self._device.installed_version(self.target) + + async def async_install( + self, version: str | None, backup: bool, **kwargs: Any + ) -> None: + """Install the latest firmware version.""" + await self._device.update_check(self.target)