From 6bd3047c718896af514e3de13381c0e37ab801b2 Mon Sep 17 00:00:00 2001 From: techartdev Date: Sat, 21 Feb 2026 01:34:43 +0200 Subject: [PATCH] Update version to 0.1.47 and improve TTS fallback handling and voice-mode responsiveness --- CHANGELOG.md | 6 ++ custom_components/openclaw/__init__.py | 2 +- custom_components/openclaw/manifest.json | 2 +- .../openclaw/www/openclaw-chat-card.js | 65 +++++++++++++++---- www/openclaw-chat-card.js | 2 +- 5 files changed, 60 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 583b5a2..75ed57c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to the OpenClaw Home Assistant Integration will be documented in this file. +## [0.1.47] - 2026-02-21 + +### Fixed +- Improved continuous voice-mode responsiveness by finalizing recognition on speech end, reducing delay before sending spoken messages. +- Improved TTS fallback order: when no matching browser language voice is available, the card now tries Home Assistant TTS first before browser default-language fallback. + ## [0.1.46] - 2026-02-21 ### Fixed diff --git a/custom_components/openclaw/__init__.py b/custom_components/openclaw/__init__.py index 87c9061..438884e 100644 --- a/custom_components/openclaw/__init__.py +++ b/custom_components/openclaw/__init__.py @@ -92,7 +92,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.46" +_CARD_URL = f"{_CARD_STATIC_URL}?v=0.1.47" OpenClawConfigEntry = ConfigEntry diff --git a/custom_components/openclaw/manifest.json b/custom_components/openclaw/manifest.json index d162c17..e3c5b7c 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.46", + "version": "0.1.47", "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 cfcfc69..6daac19 100644 --- a/custom_components/openclaw/www/openclaw-chat-card.js +++ b/custom_components/openclaw/www/openclaw-chat-card.js @@ -1260,7 +1260,6 @@ class OpenClawChatCard extends HTMLElement { const fallbackLanguage = this._normalizeSpeechLanguage( this._hass?.locale?.language || this._hass?.selectedLanguage || this._hass?.language || navigator.language || "en-US" ); - let attemptedFallback = false; const pickVoice = (targetLanguage, voices) => { const normalizedTarget = String(targetLanguage || "").toLowerCase(); @@ -1297,6 +1296,7 @@ class OpenClawChatCard extends HTMLElement { const speakNow = (targetLanguage, allowFallback = true) => { const utterance = new SpeechSynthesisUtterance(plain); utterance.lang = targetLanguage; + let preSpeakHaFallbackAttempted = false; const voices = speechSynthesis.getVoices() || []; if (voices.length) { @@ -1307,26 +1307,63 @@ class OpenClawChatCard extends HTMLElement { if (selection.lang) { utterance.lang = selection.lang; } + + if (!selection.matched && allowFallback) { + preSpeakHaFallbackAttempted = true; + this._voiceStatus = "No matching browser TTS voice, trying Home Assistant TTS…"; + this._render(); + this._speakViaHomeAssistantTts(plain, targetLanguage).then((ok) => { + if (ok) { + this._voiceStatus = ""; + this._render(); + return; + } + + this._voiceStatus = + "Home Assistant TTS unavailable; using browser default voice as fallback."; + this._render(); + try { + speechSynthesis.cancel(); + } catch (e) { + // ignore + } + speechSynthesis.speak(utterance); + }); + return; + } } utterance.onerror = (event) => { - if (allowFallback && !attemptedFallback && targetLanguage !== fallbackLanguage) { - attemptedFallback = true; + if (!preSpeakHaFallbackAttempted) { + this._voiceStatus = "Browser TTS failed, trying Home Assistant TTS…"; + this._render(); + this._speakViaHomeAssistantTts(plain, targetLanguage).then((ok) => { + if (ok) { + this._voiceStatus = ""; + this._render(); + return; + } + + if (allowFallback && targetLanguage !== fallbackLanguage) { + speakNow(fallbackLanguage, false); + return; + } + + const reason = event?.error ? ` (${event.error})` : ""; + this._voiceStatus = `TTS error for language ${targetLanguage}${reason}`; + this._render(); + }); + return; + } + + if (allowFallback && targetLanguage !== fallbackLanguage) { speakNow(fallbackLanguage, false); return; } - this._voiceStatus = "Browser TTS failed, trying Home Assistant TTS…"; + + const reason = event?.error ? ` (${event.error})` : ""; + this._voiceStatus = `TTS error for language ${targetLanguage}${reason}`; this._render(); - this._speakViaHomeAssistantTts(plain, targetLanguage).then((ok) => { - if (ok) { - this._voiceStatus = ""; - this._render(); - return; - } - const reason = event?.error ? ` (${event.error})` : ""; - this._voiceStatus = `TTS error for language ${targetLanguage}${reason}`; - this._render(); - }); }; try { diff --git a/www/openclaw-chat-card.js b/www/openclaw-chat-card.js index 7d9937f..80cc8f8 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.46"; + const src = "/openclaw/openclaw-chat-card.js?v=0.1.47"; console.info("OpenClaw loader importing", src); await import(src); }