voice mode fixes
This commit is contained in:
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
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.45] - 2026-02-21
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Hardened voice startup/toggle flow in the chat card to prevent voice mode from getting stuck when browser speech startup fails.
|
||||||
|
- Added guarded async click handlers for voice buttons to avoid uncaught promise failures during voice mode enable/disable.
|
||||||
|
- Browser speech startup failures now set a clear in-card voice status and automatically revert continuous voice mode.
|
||||||
|
|
||||||
## [0.1.44] - 2026-02-21
|
## [0.1.44] - 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.44"
|
_CARD_URL = f"{_CARD_STATIC_URL}?v=0.1.45"
|
||||||
|
|
||||||
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.44",
|
"version": "0.1.45",
|
||||||
"dependencies": ["conversation"],
|
"dependencies": ["conversation"],
|
||||||
"after_dependencies": ["hassio", "lovelace"]
|
"after_dependencies": ["hassio", "lovelace"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -615,19 +615,25 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
return this._voiceProviderIntegration || "browser";
|
return this._voiceProviderIntegration || "browser";
|
||||||
}
|
}
|
||||||
|
|
||||||
_startVoiceRecognition() {
|
async _startVoiceRecognition() {
|
||||||
const provider = this._getVoiceProvider();
|
const provider = this._getVoiceProvider();
|
||||||
if (this._isVoiceMode && provider === "assist_stt") {
|
try {
|
||||||
this._voiceStatus =
|
if (this._isVoiceMode && provider === "assist_stt") {
|
||||||
"Voice mode uses browser speech for continuous listening (Assist STT remains available for manual mic).";
|
this._voiceStatus =
|
||||||
this._startBrowserVoiceRecognition();
|
"Voice mode uses browser speech for continuous listening (Assist STT remains available for manual mic).";
|
||||||
return;
|
return this._startBrowserVoiceRecognition();
|
||||||
|
}
|
||||||
|
if (provider === "assist_stt") {
|
||||||
|
return await this._startAssistSttRecognition();
|
||||||
|
}
|
||||||
|
return this._startBrowserVoiceRecognition();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("OpenClaw: voice startup failed", err);
|
||||||
|
this._voiceStatus = "Voice startup failed. Try again or use text input.";
|
||||||
|
this._recognition = null;
|
||||||
|
this._render();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (provider === "assist_stt") {
|
|
||||||
this._startAssistSttRecognition();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._startBrowserVoiceRecognition();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _startAssistSttRecognition() {
|
async _startAssistSttRecognition() {
|
||||||
@@ -637,20 +643,20 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
this._voiceStatus =
|
this._voiceStatus =
|
||||||
"Continuous voice mode currently requires browser speech. Switch voice provider to browser or disable continuous mode.";
|
"Continuous voice mode currently requires browser speech. Switch voice provider to browser or disable continuous mode.";
|
||||||
this._render();
|
this._render();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!navigator.mediaDevices?.getUserMedia) {
|
if (!navigator.mediaDevices?.getUserMedia) {
|
||||||
this._voiceStatus = "Microphone capture not supported by this browser.";
|
this._voiceStatus = "Microphone capture not supported by this browser.";
|
||||||
this._render();
|
this._render();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._preferredAssistSttEngine) {
|
if (!this._preferredAssistSttEngine) {
|
||||||
this._voiceStatus =
|
this._voiceStatus =
|
||||||
"No Assist STT engine found in preferred voice pipeline. Configure Voice settings first.";
|
"No Assist STT engine found in preferred voice pipeline. Configure Voice settings first.";
|
||||||
this._render();
|
this._render();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -737,12 +743,14 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
this._assistAutoStopTimer = setTimeout(() => {
|
this._assistAutoStopTimer = setTimeout(() => {
|
||||||
this._stopAssistSttRecognition(true);
|
this._stopAssistSttRecognition(true);
|
||||||
}, 4500);
|
}, 4500);
|
||||||
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("OpenClaw: failed to start Assist STT recording", err);
|
console.error("OpenClaw: failed to start Assist STT recording", err);
|
||||||
this._voiceStatus = "Could not start microphone recording for Assist STT.";
|
this._voiceStatus = "Could not start microphone recording for Assist STT.";
|
||||||
this._assistRecordingActive = false;
|
this._assistRecordingActive = false;
|
||||||
this._recognition = null;
|
this._recognition = null;
|
||||||
this._render();
|
this._render();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1021,13 +1029,14 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
this._voiceStatus =
|
this._voiceStatus =
|
||||||
"Voice input disabled on Brave by default due browser SpeechRecognition network failures. Use Chrome/Edge, or set allow_brave_webspeech: true in card config to force-enable experimental mode.";
|
"Voice input disabled on Brave by default due browser SpeechRecognition network failures. Use Chrome/Edge, or set allow_brave_webspeech: true in card config to force-enable experimental mode.";
|
||||||
this._render();
|
this._render();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!("webkitSpeechRecognition" in window) && !("SpeechRecognition" in window)) {
|
if (!("webkitSpeechRecognition" in window) && !("SpeechRecognition" in window)) {
|
||||||
console.warn("OpenClaw: Speech recognition not supported in this browser");
|
console.warn("OpenClaw: Speech recognition not supported in this browser");
|
||||||
|
this._voiceStatus = "Browser speech recognition is not supported here.";
|
||||||
this._render();
|
this._render();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
||||||
@@ -1153,8 +1162,17 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this._recognition.start();
|
try {
|
||||||
this._render();
|
this._recognition.start();
|
||||||
|
this._render();
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
console.error("OpenClaw: failed to start SpeechRecognition", err);
|
||||||
|
this._voiceStatus = "Failed to start browser speech recognition.";
|
||||||
|
this._recognition = null;
|
||||||
|
this._render();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_stopVoiceRecognition() {
|
_stopVoiceRecognition() {
|
||||||
@@ -1209,7 +1227,10 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
await this._loadIntegrationSettings(false);
|
await this._loadIntegrationSettings(false);
|
||||||
this._isVoiceMode = !this._isVoiceMode;
|
this._isVoiceMode = !this._isVoiceMode;
|
||||||
if (this._isVoiceMode) {
|
if (this._isVoiceMode) {
|
||||||
this._startVoiceRecognition();
|
const started = await this._startVoiceRecognition();
|
||||||
|
if (!started) {
|
||||||
|
this._isVoiceMode = false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this._stopVoiceRecognition();
|
this._stopVoiceRecognition();
|
||||||
}
|
}
|
||||||
@@ -1654,13 +1675,24 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
this._stopVoiceRecognition();
|
this._stopVoiceRecognition();
|
||||||
this._render();
|
this._render();
|
||||||
} else {
|
} else {
|
||||||
this._startVoiceRecognition();
|
this._startVoiceRecognition().catch((err) => {
|
||||||
|
console.error("OpenClaw: voice start failed", err);
|
||||||
|
this._voiceStatus = "Voice startup failed.";
|
||||||
|
this._render();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (voiceModeBtn) {
|
if (voiceModeBtn) {
|
||||||
voiceModeBtn.addEventListener("click", () => this._toggleVoiceMode());
|
voiceModeBtn.addEventListener("click", () => {
|
||||||
|
this._toggleVoiceMode().catch((err) => {
|
||||||
|
console.error("OpenClaw: voice mode toggle failed", err);
|
||||||
|
this._isVoiceMode = false;
|
||||||
|
this._voiceStatus = "Voice mode failed to start.";
|
||||||
|
this._render();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearBtn = this.shadowRoot.getElementById("clear-btn");
|
const clearBtn = this.shadowRoot.getElementById("clear-btn");
|
||||||
|
|||||||
@@ -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.44";
|
const src = "/openclaw/openclaw-chat-card.js?v=0.1.45";
|
||||||
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