audio fix, js duplication removal

This commit is contained in:
techartdev
2026-02-20 18:31:04 +02:00
parent e2fbd7ac74
commit ad97326509
5 changed files with 68 additions and 1010 deletions
+7
View File
@@ -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.19] - 2026-02-20
### Changed
- Made `custom_components/openclaw/www/openclaw-chat-card.js` the single source of truth for card implementation.
- Replaced root `www/openclaw-chat-card.js` with a tiny loader shim that imports `/openclaw/openclaw-chat-card.js`.
- Removed manual-maintenance duplication between two full card script files.
## [0.1.18] - 2026-02-20 ## [0.1.18] - 2026-02-20
### Fixed ### Fixed
+2 -3
View File
@@ -24,9 +24,8 @@ A native Home Assistant integration for communicating with the
### Manual ### Manual
1. Copy `custom_components/openclaw/` into your HA `config/custom_components/` directory 1. Copy `custom_components/openclaw/` into your HA `config/custom_components/` directory
2. Copy `www/openclaw-chat-card.js` into `config/www/` 2. Restart Home Assistant
3. Restart Home Assistant 3. Add the integration via Settings → Devices & Services
4. Add the integration via Settings → Devices & Services
## Prerequisites ## Prerequisites
+1 -1
View File
@@ -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.18", "version": "0.1.19",
"dependencies": ["conversation"], "dependencies": ["conversation"],
"after_dependencies": ["hassio", "lovelace"] "after_dependencies": ["hassio", "lovelace"]
} }
@@ -64,6 +64,8 @@ class OpenClawChatCard extends HTMLElement {
this._wakeWord = "hey openclaw"; this._wakeWord = "hey openclaw";
this._alwaysVoiceMode = false; this._alwaysVoiceMode = false;
this._voiceStatus = ""; this._voiceStatus = "";
this._voiceRetryTimer = null;
this._voiceRetryCount = 0;
} }
// ── HA card interface ─────────────────────────────────────────────── // ── HA card interface ───────────────────────────────────────────────
@@ -120,6 +122,10 @@ class OpenClawChatCard extends HTMLElement {
clearTimeout(this._historySyncRetryTimer); clearTimeout(this._historySyncRetryTimer);
this._historySyncRetryTimer = null; this._historySyncRetryTimer = null;
} }
if (this._voiceRetryTimer) {
clearTimeout(this._voiceRetryTimer);
this._voiceRetryTimer = null;
}
} }
// ── Event subscription ────────────────────────────────────────────── // ── Event subscription ──────────────────────────────────────────────
@@ -445,7 +451,21 @@ class OpenClawChatCard extends HTMLElement {
this._recognition.onerror = (event) => { this._recognition.onerror = (event) => {
console.error("OpenClaw: Speech recognition error:", event.error); console.error("OpenClaw: Speech recognition error:", event.error);
this._voiceStatus = `Voice error: ${event.error}`; const err = event?.error || "unknown";
if (err === "network") {
this._voiceStatus =
"Voice network error: browser speech service unavailable. Check internet and retry.";
} else if (err === "not-allowed") {
this._voiceStatus = "Microphone access denied. Allow mic permission for this site.";
} else if (err === "audio-capture") {
this._voiceStatus = "No microphone available.";
} else {
this._voiceStatus = `Voice error: ${err}`;
}
if (this._isVoiceMode && ["network", "audio-capture", "no-speech"].includes(err)) {
this._scheduleVoiceRetry();
}
this._render(); this._render();
}; };
@@ -472,10 +492,40 @@ class OpenClawChatCard extends HTMLElement {
this._recognition.abort(); this._recognition.abort();
this._recognition = null; this._recognition = null;
} }
if (this._voiceRetryTimer) {
clearTimeout(this._voiceRetryTimer);
this._voiceRetryTimer = null;
}
this._voiceRetryCount = 0;
this._isVoiceMode = false; this._isVoiceMode = false;
this._voiceStatus = ""; this._voiceStatus = "";
} }
_scheduleVoiceRetry() {
if (!this._isVoiceMode) return;
if (this._voiceRetryCount >= 6) {
this._voiceStatus =
"Voice retry stopped after repeated errors. Toggle voice mode to try again.";
this._render();
return;
}
if (this._voiceRetryTimer) {
clearTimeout(this._voiceRetryTimer);
}
const delayMs = Math.min(1000 * (this._voiceRetryCount + 1), 6000);
this._voiceRetryCount += 1;
this._voiceStatus = `Voice reconnecting in ${Math.ceil(delayMs / 1000)}s…`;
this._render();
this._voiceRetryTimer = setTimeout(() => {
this._voiceRetryTimer = null;
if (!this._isVoiceMode) return;
this._startVoiceRecognition();
}, delayMs);
}
_toggleVoiceMode() { _toggleVoiceMode() {
this._isVoiceMode = !this._isVoiceMode; this._isVoiceMode = !this._isVoiceMode;
if (this._isVoiceMode) { if (this._isVoiceMode) {
+5 -1003
View File
File diff suppressed because it is too large Load Diff