Update version to 0.1.50 and enhance voice behavior, chat consistency, and auto-scroll functionality
This commit is contained in:
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
All notable changes to the OpenClaw Home Assistant Integration will be documented in this file.
|
All notable changes to the OpenClaw Home Assistant Integration will be documented in this file.
|
||||||
|
|
||||||
|
## [0.1.50] - 2026-02-21
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Improved Android Home Assistant app voice behavior by preferring Home Assistant TTS first and handling browser-TTS-unavailable cases correctly.
|
||||||
|
|
||||||
## [0.1.49] - 2026-02-21
|
## [0.1.49] - 2026-02-21
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -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)
|
# URL at which the card JS is served (registered via register_static_path)
|
||||||
_CARD_STATIC_URL = f"/openclaw/{_CARD_FILENAME}"
|
_CARD_STATIC_URL = f"/openclaw/{_CARD_FILENAME}"
|
||||||
# Versioned URL used for Lovelace resource registration to avoid stale browser cache
|
# Versioned URL used for Lovelace resource registration to avoid stale browser cache
|
||||||
_CARD_URL = f"{_CARD_STATIC_URL}?v=0.1.49"
|
_CARD_URL = f"{_CARD_STATIC_URL}?v=0.1.50"
|
||||||
|
|
||||||
OpenClawConfigEntry = ConfigEntry
|
OpenClawConfigEntry = ConfigEntry
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"issue_tracker": "https://github.com/techartdev/OpenClawHomeAssistant/issues",
|
"issue_tracker": "https://github.com/techartdev/OpenClawHomeAssistant/issues",
|
||||||
"requirements": [],
|
"requirements": [],
|
||||||
"version": "0.1.49",
|
"version": "0.1.50",
|
||||||
"dependencies": ["conversation"],
|
"dependencies": ["conversation"],
|
||||||
"after_dependencies": ["hassio", "lovelace"]
|
"after_dependencies": ["hassio", "lovelace"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* + subscribes to openclaw_message_received events.
|
* + subscribes to openclaw_message_received events.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const CARD_VERSION = "0.3.8";
|
const CARD_VERSION = "0.3.9";
|
||||||
|
|
||||||
// Max time (ms) to show the thinking indicator before falling back to an error
|
// Max time (ms) to show the thinking indicator before falling back to an error
|
||||||
const THINKING_TIMEOUT_MS = 120_000;
|
const THINKING_TIMEOUT_MS = 120_000;
|
||||||
@@ -641,6 +641,11 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
return brandMatch || ua.includes("brave") || !!navigator.brave;
|
return brandMatch || ua.includes("brave") || !!navigator.brave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isHomeAssistantAndroidApp() {
|
||||||
|
const ua = (navigator.userAgent || "").toLowerCase();
|
||||||
|
return ua.includes("home assistant") && ua.includes("android");
|
||||||
|
}
|
||||||
|
|
||||||
_getVoiceProvider() {
|
_getVoiceProvider() {
|
||||||
const configured = this._config.voice_provider;
|
const configured = this._config.voice_provider;
|
||||||
if (configured === "assist_stt" || configured === "browser") {
|
if (configured === "assist_stt" || configured === "browser") {
|
||||||
@@ -1218,6 +1223,7 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
if (this._voiceIdleRestartTimer) {
|
if (this._voiceIdleRestartTimer) {
|
||||||
clearTimeout(this._voiceIdleRestartTimer);
|
clearTimeout(this._voiceIdleRestartTimer);
|
||||||
}
|
}
|
||||||
|
const idleRestartDelayMs = this._isHomeAssistantAndroidApp() ? 3500 : 1500;
|
||||||
this._voiceIdleRestartTimer = setTimeout(() => {
|
this._voiceIdleRestartTimer = setTimeout(() => {
|
||||||
this._voiceIdleRestartTimer = null;
|
this._voiceIdleRestartTimer = null;
|
||||||
if (!this._isVoiceMode || !this._recognition) {
|
if (!this._isVoiceMode || !this._recognition) {
|
||||||
@@ -1228,7 +1234,7 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Ignore — may already be started
|
// Ignore — may already be started
|
||||||
}
|
}
|
||||||
}, 1500);
|
}, idleRestartDelayMs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1348,8 +1354,10 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_speak(text) {
|
_speak(text) {
|
||||||
if (!("speechSynthesis" in window)) return;
|
const hasBrowserTts = "speechSynthesis" in window;
|
||||||
this._pauseVoiceInputForTts();
|
this._pauseVoiceInputForTts();
|
||||||
|
this._voiceStatus = "Speaking…";
|
||||||
|
this._render();
|
||||||
// Strip markdown for TTS
|
// Strip markdown for TTS
|
||||||
const plain = text.replace(/[*_`#\[\]()]/g, "");
|
const plain = text.replace(/[*_`#\[\]()]/g, "");
|
||||||
const preferredLanguage = this._getSpeechSynthesisLanguage();
|
const preferredLanguage = this._getSpeechSynthesisLanguage();
|
||||||
@@ -1357,6 +1365,25 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
this._hass?.locale?.language || this._hass?.selectedLanguage || this._hass?.language || navigator.language || "en-US"
|
this._hass?.locale?.language || this._hass?.selectedLanguage || this._hass?.language || navigator.language || "en-US"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!hasBrowserTts) {
|
||||||
|
this._voiceStatus = "Browser TTS unavailable, trying Home Assistant TTS…";
|
||||||
|
this._render();
|
||||||
|
this._speakViaHomeAssistantTts(plain, preferredLanguage).then((ok) => {
|
||||||
|
if (ok) {
|
||||||
|
this._voiceStatus = "";
|
||||||
|
this._render();
|
||||||
|
this._resumeVoiceInputAfterTts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reason = this._lastHaTtsAttempt ? ` (${this._lastHaTtsAttempt})` : "";
|
||||||
|
this._voiceStatus = `TTS unavailable${reason}`;
|
||||||
|
this._render();
|
||||||
|
this._resumeVoiceInputAfterTts();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const pickVoice = (targetLanguage, voices) => {
|
const pickVoice = (targetLanguage, voices) => {
|
||||||
const normalizedTarget = String(targetLanguage || "").toLowerCase();
|
const normalizedTarget = String(targetLanguage || "").toLowerCase();
|
||||||
const targetBase = normalizedTarget.split("-")[0];
|
const targetBase = normalizedTarget.split("-")[0];
|
||||||
@@ -1468,6 +1495,8 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
utterance.onend = () => {
|
utterance.onend = () => {
|
||||||
|
this._voiceStatus = "";
|
||||||
|
this._render();
|
||||||
this._resumeVoiceInputAfterTts();
|
this._resumeVoiceInputAfterTts();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1479,6 +1508,25 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
speechSynthesis.speak(utterance);
|
speechSynthesis.speak(utterance);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this._isHomeAssistantAndroidApp()) {
|
||||||
|
this._voiceStatus = "Speaking with Home Assistant TTS…";
|
||||||
|
this._render();
|
||||||
|
this._speakViaHomeAssistantTts(plain, preferredLanguage).then((ok) => {
|
||||||
|
if (ok) {
|
||||||
|
this._voiceStatus = "";
|
||||||
|
this._render();
|
||||||
|
this._resumeVoiceInputAfterTts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reason = this._lastHaTtsAttempt ? ` (${this._lastHaTtsAttempt})` : "";
|
||||||
|
this._voiceStatus = `Home Assistant TTS unavailable${reason}; trying browser TTS…`;
|
||||||
|
this._render();
|
||||||
|
speakNow(preferredLanguage);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const loadedVoices = speechSynthesis.getVoices() || [];
|
const loadedVoices = speechSynthesis.getVoices() || [];
|
||||||
if (loadedVoices.length) {
|
if (loadedVoices.length) {
|
||||||
speakNow(preferredLanguage);
|
speakNow(preferredLanguage);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
if (!customElements.get("openclaw-chat-card")) {
|
if (!customElements.get("openclaw-chat-card")) {
|
||||||
const src = "/openclaw/openclaw-chat-card.js?v=0.1.49";
|
const src = "/openclaw/openclaw-chat-card.js?v=0.1.50";
|
||||||
console.info("OpenClaw loader importing", src);
|
console.info("OpenClaw loader importing", src);
|
||||||
await import(src);
|
await import(src);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user