feat(update): Firmware-Update aus dem Ordner mit Einmal-URLs und WLAN-Sicherung

This commit is contained in:
Michael Sauer
2026-09-16 16:45:24 +02:00
parent cc318c9d25
commit ccc31d3286
9 changed files with 878 additions and 10 deletions
+75
View File
@@ -0,0 +1,75 @@
"""State shared by all ninlight entries: the firmware catalog and one-time download keys."""
from __future__ import annotations
import asyncio
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.util.hass_dict import HassKey
from .const import CATALOG_SCAN_INTERVAL, DOMAIN, FIRMWARE_DIR_NAME, SIGNAL_CATALOG_UPDATED
from .firmware import FirmwareCatalog
from .http import NinlightFirmwareView, OtaRegistry
def firmware_directory(hass: HomeAssistant) -> Path:
return Path(hass.config.path(FIRMWARE_DIR_NAME))
@dataclass
class NinlightShared:
"""One instance per Home Assistant."""
catalog: FirmwareCatalog
registry: OtaRegistry
scan_lock: asyncio.Lock = field(default_factory=asyncio.Lock)
unsub_scan: CALLBACK_TYPE | None = None
DATA_SHARED: HassKey[NinlightShared] = HassKey(DOMAIN)
@callback
def async_get_shared(hass: HomeAssistant) -> NinlightShared:
"""Create on first use and register the download view exactly once."""
shared = hass.data.get(DATA_SHARED)
if shared is None:
shared = NinlightShared(FirmwareCatalog(firmware_directory(hass)), OtaRegistry())
hass.data[DATA_SHARED] = shared
hass.http.register_view(NinlightFirmwareView(hass, shared.registry))
return shared
async def async_scan_catalog(hass: HomeAssistant, shared: NinlightShared) -> None:
async with shared.scan_lock:
await hass.async_add_executor_job(shared.catalog.scan)
async_dispatcher_send(hass, SIGNAL_CATALOG_UPDATED)
async def async_start_catalog(hass: HomeAssistant, shared: NinlightShared) -> None:
if shared.unsub_scan is not None:
return
async def _scheduled_scan(_now: datetime) -> None:
await async_scan_catalog(hass, shared)
shared.unsub_scan = async_track_time_interval(
hass,
_scheduled_scan,
CATALOG_SCAN_INTERVAL,
name="ninlight firmware catalog",
cancel_on_shutdown=True,
)
await async_scan_catalog(hass, shared)
@callback
def async_stop_catalog(shared: NinlightShared) -> None:
if shared.unsub_scan is not None:
shared.unsub_scan()
shared.unsub_scan = None