Update changelog for version 0.1.7, resolve chat card startup race, enhance frontend registration with retries, and add MIT license file

This commit is contained in:
techartdev
2026-02-20 15:44:50 +02:00
parent c3311a6376
commit b89ad7528a
5 changed files with 86 additions and 38 deletions
+10
View File
@@ -2,6 +2,16 @@
All notable changes to the OpenClaw Home Assistant Integration will be documented in this file.
## [0.1.7] - 2026-02-20
### Fixed
- Resolved chat card startup race where Lovelace resources were attempted before HTTP/Lovelace were ready, causing `Custom element not found: openclaw-chat-card`.
- Frontend registration now retries and waits for Home Assistant startup readiness before giving up.
- Static JS path registration is now idempotent and only marked successful after the path is actually registered.
### Added
- Added MIT license file at repository root (`LICENSE`).
## [0.1.6] - 2025-01-01
### Fixed
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 techartdev, Tech Art Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+1 -1
View File
@@ -81,4 +81,4 @@ action:
## License
See [LICENSE](../LICENSE).
See [LICENSE](LICENSE).
+53 -36
View File
@@ -5,6 +5,7 @@ Sets up the OpenClaw integration: API client, coordinator, platforms, and servic
from __future__ import annotations
import asyncio
from datetime import datetime, timezone
import logging
from pathlib import Path
@@ -13,6 +14,7 @@ from typing import Any
import voluptuous as vol
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
@@ -173,42 +175,60 @@ async def _async_register_frontend(hass: HomeAssistant) -> None:
Called as a fire-and-forget task from async_setup_entry.
Wrapped entirely in try/except so it can NEVER crash the integration.
"""
frontend_key = f"{DOMAIN}_frontend_registered"
frontend_key = f"{DOMAIN}_frontend_registration_started"
if hass.data.get(frontend_key):
return
hass.data[frontend_key] = True
url = _CARD_URL
async def _register_with_retries() -> None:
for _ in range(12):
url = await _async_register_static_path(hass)
if url and await _async_add_lovelace_resource(hass, url):
return
await asyncio.sleep(5)
# ── Step 1: Serve the JS via a static HTTP path ───────────────────
if _CARD_PATH.exists() and hass.http is not None:
try:
# HA 2024.11+ — async_register_static_paths w/ StaticPathConfig
from homeassistant.components.http import StaticPathConfig # noqa: PLC0415
await hass.http.async_register_static_paths(
[StaticPathConfig(url, str(_CARD_PATH), cache_headers=True)]
)
_LOGGER.debug("Registered static path (new API): %s", url)
except (ImportError, AttributeError):
try:
# HA <2024.11 — synchronous register_static_path
hass.http.register_static_path(url, str(_CARD_PATH), True)
_LOGGER.debug("Registered static path (legacy API): %s", url)
except Exception as err: # noqa: BLE001
_LOGGER.debug("Could not register static path '%s': %s", url, err)
url = f"/local/{_CARD_FILENAME}" # fall back to /local/ URL
except Exception as err: # noqa: BLE001
_LOGGER.debug("Could not register static path '%s': %s", url, err)
url = f"/local/{_CARD_FILENAME}"
else:
# JS not in package (shouldn't happen) or HTTP not ready — try /local/
url = f"/local/{_CARD_FILENAME}"
_LOGGER.warning(
"Could not auto-register OpenClaw chat card resource after retries. "
"Add it manually in Dashboard resources: %s",
_CARD_URL,
)
# ── Step 2: Add to Lovelace resource store ───────────────────────
await _async_add_lovelace_resource(hass, url)
hass.async_create_task(_register_with_retries())
async def _on_ha_started(_event) -> None:
await _register_with_retries()
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, _on_ha_started)
async def _async_add_lovelace_resource(hass: HomeAssistant, url: str) -> None:
async def _async_register_static_path(hass: HomeAssistant) -> str | None:
"""Register the packaged chat-card JS as a static path when HTTP is ready."""
static_key = f"{DOMAIN}_static_registered"
if hass.data.get(static_key):
return _CARD_URL
if not _CARD_PATH.exists():
_LOGGER.warning("Chat card JS not found at %s", _CARD_PATH)
return None
if hass.http is None:
return None
try:
from homeassistant.components.http import StaticPathConfig # noqa: PLC0415
await hass.http.async_register_static_paths(
[StaticPathConfig(_CARD_URL, str(_CARD_PATH), cache_headers=True)]
)
except (ImportError, AttributeError):
hass.http.register_static_path(_CARD_URL, str(_CARD_PATH), True)
hass.data[static_key] = True
_LOGGER.debug("Registered static path: %s", _CARD_URL)
return _CARD_URL
async def _async_add_lovelace_resource(hass: HomeAssistant, url: str) -> bool:
"""Add the card URL to Lovelace's resource store if not already present."""
# Lovelace stores resources in hass.data["lovelace"]["resources"].
# It is a ResourceStorageCollection with:
@@ -216,22 +236,17 @@ async def _async_add_lovelace_resource(hass: HomeAssistant, url: str) -> None:
# .async_create_item(data) → persists a new resource
lovelace_data = hass.data.get("lovelace")
if not lovelace_data:
_LOGGER.debug(
"Lovelace not loaded; resource '%s' must be added manually if needed",
url,
)
return
return False
resource_collection = lovelace_data.get("resources")
if resource_collection is None:
_LOGGER.debug("Lovelace resource store not available")
return
return False
try:
existing_urls = {item["url"] for item in resource_collection.async_items()}
if url in existing_urls:
_LOGGER.debug("Lovelace resource already registered: %s", url)
return
return True
await resource_collection.async_create_item(
{"res_type": "module", "url": url}
@@ -240,6 +255,7 @@ async def _async_add_lovelace_resource(hass: HomeAssistant, url: str) -> None:
"Auto-registered Lovelace resource: %s — the chat card is ready to use.",
url,
)
return True
except Exception as err: # noqa: BLE001
_LOGGER.warning(
"Could not auto-register Lovelace resource '%s': %s. "
@@ -247,6 +263,7 @@ async def _async_add_lovelace_resource(hass: HomeAssistant, url: str) -> None:
url,
err,
)
return False
# ── Service registration ──────────────────────────────────────────────────────
+1 -1
View File
@@ -8,7 +8,7 @@
"iot_class": "local_polling",
"issue_tracker": "https://github.com/techartdev/OpenClawHomeAssistant/issues",
"requirements": [],
"version": "0.1.6",
"version": "0.1.7",
"dependencies": ["conversation"],
"after_dependencies": ["hassio", "lovelace"]
}