readme update, brave browser workaround for voice
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.24] - 2026-02-20
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Added proactive Brave browser guard for card voice input to avoid recurring `SpeechRecognition` `network` failures.
|
||||||
|
- Voice is now disabled by default on Brave with a clear status message and opt-in override (`allow_brave_webspeech: true`).
|
||||||
|
- Reduced noisy console output for `network` speech errors.
|
||||||
|
|
||||||
## [0.1.23] - 2026-02-20
|
## [0.1.23] - 2026-02-20
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -1,106 +1,234 @@
|
|||||||
# OpenClaw Integration for Home Assistant
|
# OpenClaw Integration for Home Assistant
|
||||||
|
|
||||||
A native Home Assistant integration for communicating with the
|
OpenClaw is a Home Assistant custom integration that connects your HA instance to the OpenClaw assistant backend and provides:
|
||||||
[OpenClaw Assistant](https://github.com/techartdev/OpenClawHomeAssistant) addon.
|
|
||||||
|
|
||||||
## Features
|
- A native conversation agent for Assist
|
||||||
|
- A Lovelace chat card with session history
|
||||||
|
- Service and event APIs for automations
|
||||||
|
- Optional voice mode in the card
|
||||||
|
|
||||||
- **Chat card** — Lovelace card with streaming AI responses, file attachments, and voice mode
|
---
|
||||||
- **Sensors** — `openclaw_status`, `openclaw_model`, `openclaw_session_count`, `openclaw_last_activity`, `openclaw_connected`
|
|
||||||
- **Conversation agent** — appears in Assist & Voice PE as a native agent
|
## What it includes
|
||||||
- **Service calls** — `openclaw.send_message` for automations
|
|
||||||
- **Events** — `openclaw_message_received` for triggering automations from AI responses
|
- **Conversation agent** (`openclaw`) in Assist / Voice Assistants
|
||||||
- **Zero-config** — auto-discovers the addon via Supervisor API, no tokens or URLs to enter
|
- **Lovelace chat card** (`custom:openclaw-chat-card`) with:
|
||||||
|
- message history restore,
|
||||||
|
- typing indicator,
|
||||||
|
- optional voice input,
|
||||||
|
- wake-word handling for continuous mode
|
||||||
|
- **Services**
|
||||||
|
- `openclaw.send_message`
|
||||||
|
- `openclaw.clear_history`
|
||||||
|
- **Event**
|
||||||
|
- `openclaw_message_received`
|
||||||
|
- **Sensors / status entities** for model and connection state
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Home Assistant with Supervisor support for addon discovery
|
||||||
|
- OpenClaw Assistant addon installed and running
|
||||||
|
|
||||||
|
The integration auto-detects the addon. You do not need to manually set an API base URL.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### HACS (recommended)
|
### Option A: HACS (recommended)
|
||||||
|
|
||||||
1. Open HACS → Integrations → **+ Explore & Download Repositories**
|
1. Open **HACS → Integrations**
|
||||||
2. Search for **OpenClaw** and install
|
2. Select **Explore & Download Repositories**
|
||||||
3. Restart Home Assistant
|
3. Search for **OpenClaw** and install
|
||||||
4. Go to Settings → Devices & Services → **Add Integration → OpenClaw**
|
4. Restart Home Assistant
|
||||||
|
5. Open **Settings → Devices & Services → Add Integration**
|
||||||
|
6. Add **OpenClaw**
|
||||||
|
|
||||||
### Manual
|
### Option B: Manual
|
||||||
|
|
||||||
|
1. Copy `custom_components/openclaw` into your HA config directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
config/custom_components/openclaw
|
||||||
|
```
|
||||||
|
|
||||||
1. Copy `custom_components/openclaw/` into your HA `config/custom_components/` directory
|
|
||||||
2. Restart Home Assistant
|
2. Restart Home Assistant
|
||||||
3. Add the integration via Settings → Devices & Services
|
3. Add **OpenClaw** from **Settings → Devices & Services**
|
||||||
|
|
||||||
## Prerequisites
|
---
|
||||||
|
|
||||||
The **OpenClaw Assistant** addon must be installed and running.
|
## Dashboard card
|
||||||
The integration will auto-detect it — no manual configuration needed.
|
|
||||||
|
|
||||||
## Exposed entities (important)
|
The card is registered automatically by the integration.
|
||||||
|
|
||||||
OpenClaw uses Home Assistant's native **Assist entity exposure** controls.
|
```yaml
|
||||||
Only entities exposed to Assist are included in the context sent to OpenClaw.
|
type: custom:openclaw-chat-card
|
||||||
|
title: OpenClaw Chat
|
||||||
|
height: 500px
|
||||||
|
show_timestamps: true
|
||||||
|
show_voice_button: true
|
||||||
|
show_clear_button: true
|
||||||
|
session_id: default
|
||||||
|
```
|
||||||
|
|
||||||
Configure this in Home Assistant:
|
Minimal config:
|
||||||
|
|
||||||
1. Go to **Settings → Voice assistants**
|
|
||||||
2. Open the **Expose** tab
|
|
||||||
3. Select which entities are exposed to **Assist**
|
|
||||||
|
|
||||||
## Advanced options
|
|
||||||
|
|
||||||
Open **Settings → Devices & Services → OpenClaw → Configure** to tune:
|
|
||||||
|
|
||||||
- Include exposed entities context
|
|
||||||
- Max context characters
|
|
||||||
- Context overflow strategy (`truncate` or `clear`)
|
|
||||||
- Enable tool calls (execute HA services from model tool-call responses)
|
|
||||||
- Require wake word
|
|
||||||
- Wake word text (for example: `hey openclaw`)
|
|
||||||
- Always-on voice mode (continuous listening while the card is open)
|
|
||||||
|
|
||||||
## Chat Card
|
|
||||||
|
|
||||||
The chat card is registered automatically when the integration loads — no
|
|
||||||
manual resource configuration needed. Just add it to any dashboard:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
type: custom:openclaw-chat-card
|
type: custom:openclaw-chat-card
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Assist entity exposure context
|
||||||
|
|
||||||
|
OpenClaw can include Home Assistant entity context based on Assist exposure.
|
||||||
|
|
||||||
|
Configure exposure in:
|
||||||
|
|
||||||
|
**Settings → Voice assistants → Expose**
|
||||||
|
|
||||||
|
Only entities exposed there are included when this feature is enabled.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Integration options
|
||||||
|
|
||||||
|
Open **Settings → Devices & Services → OpenClaw → Configure**.
|
||||||
|
|
||||||
|
### Context options
|
||||||
|
|
||||||
|
- **Include exposed entities context**
|
||||||
|
- **Max context characters**
|
||||||
|
- **Context strategy**
|
||||||
|
- `truncate`: keep the first part up to max length
|
||||||
|
- `clear`: remove context when it exceeds max length
|
||||||
|
|
||||||
|
### Tool call option
|
||||||
|
|
||||||
|
- **Enable tool calls**
|
||||||
|
|
||||||
|
When enabled, OpenClaw tool-call responses can execute Home Assistant services.
|
||||||
|
|
||||||
|
### Voice options
|
||||||
|
|
||||||
|
- **Wake word enabled**
|
||||||
|
- **Wake word** (default: `hey openclaw`)
|
||||||
|
- **Always voice mode** (continuous listening while card is open)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Browser voice note (important)
|
||||||
|
|
||||||
|
Card voice input uses browser speech recognition APIs (`SpeechRecognition` / `webkitSpeechRecognition`).
|
||||||
|
|
||||||
|
- Behavior depends on browser support and provider availability
|
||||||
|
- In Brave, repeated `network` errors can occur even with mic permission
|
||||||
|
- The card now detects repeated backend failures and stops endless retries with a clear status message
|
||||||
|
|
||||||
|
If voice is unreliable in Brave, use Chrome/Edge for card voice input or continue with typed chat.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Services
|
## Services
|
||||||
|
|
||||||
### `openclaw.send_message`
|
### `openclaw.send_message`
|
||||||
|
|
||||||
Send a message to OpenClaw from an automation or script.
|
Send a message to OpenClaw.
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
|
||||||
|
- `message` (required)
|
||||||
|
- `session_id` (optional)
|
||||||
|
- `attachments` (optional)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
service: openclaw.send_message
|
service: openclaw.send_message
|
||||||
data:
|
data:
|
||||||
message: "What's the weather like today?"
|
message: "Turn on the living room lights"
|
||||||
session_id: "optional-session-id"
|
session_id: "living-room-session"
|
||||||
```
|
```
|
||||||
|
|
||||||
### `openclaw.clear_history`
|
### `openclaw.clear_history`
|
||||||
|
|
||||||
|
Clear stored conversation history for a session.
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
|
||||||
|
- `session_id` (optional; defaults to `default` session)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
service: openclaw.clear_history
|
service: openclaw.clear_history
|
||||||
data:
|
data:
|
||||||
session_id: "optional-session-id"
|
session_id: "living-room-session"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Events
|
---
|
||||||
|
|
||||||
|
## Event
|
||||||
|
|
||||||
### `openclaw_message_received`
|
### `openclaw_message_received`
|
||||||
|
|
||||||
Fired whenever OpenClaw sends a response. Use in automations:
|
Fired when OpenClaw returns a response.
|
||||||
|
|
||||||
|
Event data includes:
|
||||||
|
|
||||||
|
- `message`
|
||||||
|
- `session_id`
|
||||||
|
- `timestamp`
|
||||||
|
|
||||||
|
Automation example:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
trigger:
|
trigger:
|
||||||
- platform: event
|
- platform: event
|
||||||
event_type: openclaw_message_received
|
event_type: openclaw_message_received
|
||||||
action:
|
action:
|
||||||
- service: notify.mobile_app
|
- service: notify.mobile_app_phone
|
||||||
data:
|
data:
|
||||||
message: "{{ trigger.event.data.message }}"
|
message: "{{ trigger.event.data.message }}"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Card does not appear
|
||||||
|
|
||||||
|
- Restart Home Assistant after updating
|
||||||
|
- Hard refresh browser cache
|
||||||
|
- Confirm Integration is loaded in **Settings → Devices & Services**
|
||||||
|
|
||||||
|
### Voice button is active but no transcript is sent
|
||||||
|
|
||||||
|
- Check browser mic permission for your HA URL
|
||||||
|
- Open browser console for `OpenClaw: Speech recognition error`
|
||||||
|
- If you see repeated `network`, this is usually browser speech backend failure
|
||||||
|
|
||||||
|
### Responses do not appear after sending
|
||||||
|
|
||||||
|
- Verify `openclaw_message_received` is being fired in Developer Tools → Events
|
||||||
|
- Confirm session IDs match between card and service calls
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development notes
|
||||||
|
|
||||||
|
- Main card source is:
|
||||||
|
|
||||||
|
```
|
||||||
|
custom_components/openclaw/www/openclaw-chat-card.js
|
||||||
|
```
|
||||||
|
|
||||||
|
- Root `www/openclaw-chat-card.js` is a loader shim that imports the packaged card script.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
See [LICENSE](LICENSE).
|
MIT. See [LICENSE](LICENSE).
|
||||||
|
|||||||
@@ -74,7 +74,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.23"
|
_CARD_URL = f"{_CARD_STATIC_URL}?v=0.1.24"
|
||||||
|
|
||||||
type OpenClawConfigEntry = ConfigEntry
|
type 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.23",
|
"version": "0.1.24",
|
||||||
"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.2.3";
|
const CARD_VERSION = "0.2.4";
|
||||||
|
|
||||||
// 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;
|
||||||
@@ -88,6 +88,7 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
show_timestamps: config.show_timestamps !== false,
|
show_timestamps: config.show_timestamps !== false,
|
||||||
show_voice_button: config.show_voice_button !== false,
|
show_voice_button: config.show_voice_button !== false,
|
||||||
show_clear_button: config.show_clear_button !== false,
|
show_clear_button: config.show_clear_button !== false,
|
||||||
|
allow_brave_webspeech: config.allow_brave_webspeech === true,
|
||||||
session_id: config.session_id || null,
|
session_id: config.session_id || null,
|
||||||
...config,
|
...config,
|
||||||
};
|
};
|
||||||
@@ -458,6 +459,13 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
_startVoiceRecognition() {
|
_startVoiceRecognition() {
|
||||||
this._voiceBackendBlocked = false;
|
this._voiceBackendBlocked = false;
|
||||||
|
|
||||||
|
if (this._isLikelyBraveBrowser() && !this._config.allow_brave_webspeech) {
|
||||||
|
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.";
|
||||||
|
this._render();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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 = "Speech recognition not supported by this browser.";
|
this._voiceStatus = "Speech recognition not supported by this browser.";
|
||||||
@@ -512,8 +520,12 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this._recognition.onerror = (event) => {
|
this._recognition.onerror = (event) => {
|
||||||
console.error("OpenClaw: Speech recognition error:", event.error);
|
|
||||||
const err = event?.error || "unknown";
|
const err = event?.error || "unknown";
|
||||||
|
if (err === "network") {
|
||||||
|
console.warn("OpenClaw: Speech recognition network error");
|
||||||
|
} else {
|
||||||
|
console.error("OpenClaw: Speech recognition error:", err);
|
||||||
|
}
|
||||||
if (err === "network") {
|
if (err === "network") {
|
||||||
this._voiceNetworkErrorCount += 1;
|
this._voiceNetworkErrorCount += 1;
|
||||||
const browserLocale = this._normalizeSpeechLanguage(navigator.language || "en-US");
|
const browserLocale = this._normalizeSpeechLanguage(navigator.language || "en-US");
|
||||||
|
|||||||
@@ -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.23";
|
const src = "/openclaw/openclaw-chat-card.js?v=0.1.24";
|
||||||
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