"""Was sich alle ninstrip-Eintraege teilen: der Abbild-Katalog und die einmaligen Schluessel.""" 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 NinstripFirmwareView, OtaRegistry def firmware_directory(hass: HomeAssistant) -> Path: return Path(hass.config.path(FIRMWARE_DIR_NAME)) @dataclass class NinstripShared: """Einmal je Home Assistant.""" catalog: FirmwareCatalog registry: OtaRegistry scan_lock: asyncio.Lock = field(default_factory=asyncio.Lock) unsub_scan: CALLBACK_TYPE | None = None DATA_SHARED: HassKey[NinstripShared] = HassKey(DOMAIN) @callback def async_get_shared(hass: HomeAssistant) -> NinstripShared: """Beim ersten Zugriff anlegen und die Ausgabe genau einmal anmelden.""" shared = hass.data.get(DATA_SHARED) if shared is None: shared = NinstripShared(FirmwareCatalog(firmware_directory(hass)), OtaRegistry()) hass.data[DATA_SHARED] = shared hass.http.register_view(NinstripFirmwareView(hass, shared.registry)) return shared async def async_scan_catalog(hass: HomeAssistant, shared: NinstripShared) -> 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: NinstripShared) -> None: if shared.unsub_scan is not None: return async def _turnus(_now: datetime) -> None: await async_scan_catalog(hass, shared) shared.unsub_scan = async_track_time_interval( hass, _turnus, CATALOG_SCAN_INTERVAL, name="ninstrip firmware catalog", cancel_on_shutdown=True, ) await async_scan_catalog(hass, shared) @callback def async_stop_catalog(shared: NinstripShared) -> None: if shared.unsub_scan is not None: shared.unsub_scan() shared.unsub_scan = None