From 43bc31c8b4aadb4d2664c164d127469753895b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Bachmann?= Date: Mon, 19 Jan 2026 16:52:59 +0000 Subject: [PATCH] 0.6.9 --- custom_components/bahmcloud_store/__init__.py | 70 +++++++++++++++---- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/custom_components/bahmcloud_store/__init__.py b/custom_components/bahmcloud_store/__init__.py index b6c7665..110ebf7 100644 --- a/custom_components/bahmcloud_store/__init__.py +++ b/custom_components/bahmcloud_store/__init__.py @@ -3,35 +3,51 @@ from __future__ import annotations import logging from datetime import timedelta +from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.components.panel_custom import async_register_panel from homeassistant.helpers.event import async_track_time_interval, async_call_later from homeassistant.const import EVENT_HOMEASSISTANT_STARTED -from homeassistant.helpers.discovery import async_load_platform from .core import BCSCore, BCSConfig, BCSError +from .config_flow import CONF_GITHUB_TOKEN _LOGGER = logging.getLogger(__name__) DOMAIN = "bahmcloud_store" +# Fixed store index URL (not configurable by users) DEFAULT_STORE_URL = "https://git.bahmcloud.de/bahmcloud/ha_store/raw/branch/main/store.yaml" -CONF_STORE_URL = "store_url" + +PLATFORMS: list[str] = ["update"] + +DATA_ENTRY = f"{DOMAIN}_entry_runtime" async def async_setup(hass: HomeAssistant, config: dict) -> bool: - cfg = config.get(DOMAIN, {}) or {} - store_url = cfg.get(CONF_STORE_URL, DEFAULT_STORE_URL) + """Set up Bahmcloud Store. - core = BCSCore(hass, BCSConfig(store_url=store_url)) + YAML configuration is intentionally not supported. + Setup must happen via the UI (Config Flow). + """ + if DOMAIN in (config or {}): + _LOGGER.warning( + "BCS does not support configuration.yaml setup. " + "Please remove 'bahmcloud_store:' from configuration.yaml and set up the integration via Settings -> Devices & Services." + ) + return True + + +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: + """Set up Bahmcloud Store from a config entry.""" + token = (entry.options.get(CONF_GITHUB_TOKEN) or "").strip() or None + + core = BCSCore(hass, BCSConfig(store_url=DEFAULT_STORE_URL, github_token=token)) hass.data[DOMAIN] = core await core.async_initialize() - # Provide native Update entities in Settings -> System -> Updates. - # This integration is YAML-based (async_setup), therefore we load the platform manually. - await async_load_platform(hass, "update", DOMAIN, {}, config) - + # Register HTTP views + static assets from .views import ( StaticAssetsView, BCSApiView, @@ -62,25 +78,29 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool: hass.http.register_view(BCSRestoreView(core)) hass.http.register_view(BCSRestartView(core)) + # Sidebar panel await async_register_panel( hass, frontend_url_path="bahmcloud-store", webcomponent_name="bahmcloud-store-panel", # IMPORTANT: bump v to avoid caching old JS - module_url="/api/bahmcloud_store_static/panel.js?v=108", + module_url="/api/bahmcloud_store_static/panel.js?v=109", sidebar_title="Bahmcloud Store", sidebar_icon="mdi:store", require_admin=True, config={}, ) + # Forward platform setup (Update entities) + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + async def _do_startup_refresh(_now=None) -> None: try: await core.full_refresh(source="startup") except BCSError as e: _LOGGER.error("Initial refresh failed: %s", e) - # Do not block Home Assistant startup. Schedule the initial refresh after HA started. + # Do not block HA startup: schedule refresh after HA started. def _on_ha_started(_event) -> None: async_call_later(hass, 30, _do_startup_refresh) @@ -95,6 +115,30 @@ async def async_setup(hass: HomeAssistant, config: dict) -> bool: _LOGGER.exception("Unexpected error during periodic refresh: %s", e) interval_seconds = int(getattr(core, "refresh_seconds", 300) or 300) - async_track_time_interval(hass, periodic, timedelta(seconds=interval_seconds)) + unsub = async_track_time_interval(hass, periodic, timedelta(seconds=interval_seconds)) - return True \ No newline at end of file + # Store unload callbacks safely + runtimes = hass.data.setdefault(DATA_ENTRY, {}) + runtimes[entry.entry_id] = {"unsub_interval": unsub} + return True + + +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: + """Unload a config entry.""" + try: + runtimes = hass.data.get(DATA_ENTRY, {}) or {} + rt = runtimes.pop(entry.entry_id, {}) if isinstance(runtimes, dict) else {} + unsub = rt.get("unsub_interval") + if callable(unsub): + unsub() + except Exception: + pass + + unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) + if unload_ok: + hass.data.pop(DOMAIN, None) + return unload_ok + + +async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: + await hass.config_entries.async_reload(entry.entry_id)