diff --git a/CHANGELOG.md b/CHANGELOG.md index 57303a6..a4b7f89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to the OpenClaw Home Assistant Integration will be documented in this file. +## [0.1.55] - 2026-02-23 + +### Fixed +- Fixed chat always scrolling to the TOP instead of bottom on every message (both user and bot). +- Restored `requestAnimationFrame` in `_scrollToBottom()` — synchronous scrollTop assignment after innerHTML replacement does not persist in shadow DOM before the browser finalizes layout. +- Changed `_render()` to only upgrade `_autoScrollPinned` to `true` (never downgrade), preventing a race condition where rapid re-renders set it to `false` permanently. +- Fixed "Gateway: Unknown" badge — entity ID lookup now matches `sensor.openclaw*status` and `binary_sensor.openclaw*connected` patterns, covering `has_entity_name` variants like `sensor.openclaw_assistant_status`. + ## [0.1.53] - 2026-02-23 ### Fixed diff --git a/custom_components/openclaw/__init__.py b/custom_components/openclaw/__init__.py index 00a89ae..a83c72f 100644 --- a/custom_components/openclaw/__init__.py +++ b/custom_components/openclaw/__init__.py @@ -93,7 +93,7 @@ _CARD_PATH = Path(__file__).parent / "www" / _CARD_FILENAME # URL at which the card JS is served (registered via register_static_path) _CARD_STATIC_URL = f"/openclaw/{_CARD_FILENAME}" # Versioned URL used for Lovelace resource registration to avoid stale browser cache -_CARD_URL = f"{_CARD_STATIC_URL}?v=0.1.53" +_CARD_URL = f"{_CARD_STATIC_URL}?v=0.1.55" OpenClawConfigEntry = ConfigEntry diff --git a/custom_components/openclaw/manifest.json b/custom_components/openclaw/manifest.json index f863128..cbdff64 100644 --- a/custom_components/openclaw/manifest.json +++ b/custom_components/openclaw/manifest.json @@ -8,7 +8,7 @@ "iot_class": "local_polling", "issue_tracker": "https://github.com/techartdev/OpenClawHomeAssistant/issues", "requirements": [], - "version": "0.1.54", + "version": "0.1.55", "dependencies": ["conversation"], "after_dependencies": ["hassio", "lovelace"] } diff --git a/custom_components/openclaw/www/openclaw-chat-card.js b/custom_components/openclaw/www/openclaw-chat-card.js index be42504..457096e 100644 --- a/custom_components/openclaw/www/openclaw-chat-card.js +++ b/custom_components/openclaw/www/openclaw-chat-card.js @@ -13,7 +13,7 @@ * + subscribes to openclaw_message_received events. */ -const CARD_VERSION = "0.3.11"; +const CARD_VERSION = "0.3.12"; // Max time (ms) to show the thinking indicator before falling back to an error const THINKING_TIMEOUT_MS = 120_000; @@ -145,12 +145,16 @@ class OpenClawChatCard extends HTMLElement { const statusEntity = states["sensor.openclaw_status"] || - stateEntries.find(([entityId]) => entityId.startsWith("sensor.openclaw_status"))?.[1] || + stateEntries.find(([entityId]) => + entityId.startsWith("sensor.openclaw") && entityId.includes("status") + )?.[1] || null; const binaryEntity = states["binary_sensor.openclaw_connected"] || - stateEntries.find(([entityId]) => entityId.startsWith("binary_sensor.openclaw_connected"))?.[1] || + stateEntries.find(([entityId]) => + entityId.startsWith("binary_sensor.openclaw") && entityId.includes("connected") + )?.[1] || null; const status = String(statusEntity?.state || "").toLowerCase(); @@ -163,17 +167,18 @@ class OpenClawChatCard extends HTMLElement { const states = this._hass?.states || {}; const stateEntries = Object.entries(states); - const exactStatus = states["sensor.openclaw_status"]; - const exactConnected = states["binary_sensor.openclaw_connected"]; - const statusEntity = - exactStatus || - stateEntries.find(([entityId]) => entityId.startsWith("sensor.openclaw_status"))?.[1] || + states["sensor.openclaw_status"] || + stateEntries.find(([entityId]) => + entityId.startsWith("sensor.openclaw") && entityId.includes("status") + )?.[1] || null; const binaryEntity = - exactConnected || - stateEntries.find(([entityId]) => entityId.startsWith("binary_sensor.openclaw_connected"))?.[1] || + states["binary_sensor.openclaw_connected"] || + stateEntries.find(([entityId]) => + entityId.startsWith("binary_sensor.openclaw") && entityId.includes("connected") + )?.[1] || null; const status = String(statusEntity?.state || "").toLowerCase(); @@ -1782,10 +1787,12 @@ class OpenClawChatCard extends HTMLElement { } _scrollToBottom(force = false) { - const container = this.shadowRoot?.querySelector(".messages"); - if (container && (force || this._autoScrollPinned)) { - container.scrollTop = container.scrollHeight; - } + requestAnimationFrame(() => { + const container = this.shadowRoot?.querySelector(".messages"); + if (container && (force || this._autoScrollPinned)) { + container.scrollTop = container.scrollHeight; + } + }); } _formatTime(isoString) { @@ -1802,8 +1809,8 @@ class OpenClawChatCard extends HTMLElement { _render() { const previousContainer = this.shadowRoot?.querySelector(".messages"); - if (previousContainer) { - this._autoScrollPinned = this._isNearBottom(previousContainer); + if (previousContainer && this._isNearBottom(previousContainer)) { + this._autoScrollPinned = true; } const config = this._config; diff --git a/www/openclaw-chat-card.js b/www/openclaw-chat-card.js index 4adac28..4b5630a 100644 --- a/www/openclaw-chat-card.js +++ b/www/openclaw-chat-card.js @@ -1,7 +1,7 @@ (async () => { try { if (!customElements.get("openclaw-chat-card")) { - const src = "/openclaw/openclaw-chat-card.js?v=0.1.54"; + const src = "/openclaw/openclaw-chat-card.js?v=0.1.55"; console.info("OpenClaw loader importing", src); await import(src); }