Update version to 0.1.41 and enhance integration with voice mode fixes, gateway connection status, and updated documentation
This commit is contained in:
@@ -2,6 +2,16 @@
|
|||||||
|
|
||||||
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.41] - 2026-02-20
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed voice-mode option sync so wake-word enabled/disabled changes are reloaded before toggling voice mode.
|
||||||
|
- Removed legacy always-on voice mode behavior that could force sticky voice-mode state.
|
||||||
|
- Added live gateway connection badge to the chat card header using existing OpenClaw status entities.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Removed "Always-on voice mode" option from integration options UI and translations.
|
||||||
|
|
||||||
## [0.1.40] - 2026-02-20
|
## [0.1.40] - 2026-02-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -28,15 +28,17 @@ OpenClaw is a Home Assistant custom integration that connects your HA instance t
|
|||||||
- `openclaw_message_received`
|
- `openclaw_message_received`
|
||||||
- `openclaw_tool_invoked`
|
- `openclaw_tool_invoked`
|
||||||
- **Sensors / status entities** for model and connection state
|
- **Sensors / status entities** for model and connection state
|
||||||
|
- Includes tool telemetry sensors (`Last Tool`, `Last Tool Status`, `Last Tool Duration`, `Last Tool Invoked`)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Home Assistant with Supervisor support for addon discovery
|
- Home Assistant Core `2025.1.0+` (declared minimum)
|
||||||
|
- Supervisor is optional (used for auto-discovery)
|
||||||
- OpenClaw Assistant addon installed and running
|
- OpenClaw Assistant addon installed and running
|
||||||
|
|
||||||
The integration auto-detects the addon. You do not need to manually set an API base URL.
|
The integration can auto-detect the addon when Supervisor is available. You can always configure host/port/token manually.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -73,6 +75,8 @@ The integration auto-detects the addon. You do not need to manually set an API b
|
|||||||
|
|
||||||
The card is registered automatically by the integration.
|
The card is registered automatically by the integration.
|
||||||
|
|
||||||
|
The card header shows live gateway state (`Online` / `Offline`) using existing OpenClaw status entities.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
type: custom:openclaw-chat-card
|
type: custom:openclaw-chat-card
|
||||||
title: OpenClaw Chat
|
title: OpenClaw Chat
|
||||||
@@ -125,7 +129,6 @@ When enabled, OpenClaw tool-call responses can execute Home Assistant services.
|
|||||||
|
|
||||||
- **Wake word enabled**
|
- **Wake word enabled**
|
||||||
- **Wake word** (default: `hey openclaw`)
|
- **Wake word** (default: `hey openclaw`)
|
||||||
- **Always voice mode** (continuous listening while card is open)
|
|
||||||
- **Voice input provider** (`browser` or `assist_stt`)
|
- **Voice input provider** (`browser` or `assist_stt`)
|
||||||
|
|
||||||
### Voice provider usage
|
### Voice provider usage
|
||||||
@@ -138,7 +141,7 @@ When enabled, OpenClaw tool-call responses can execute Home Assistant services.
|
|||||||
- **`assist_stt`**
|
- **`assist_stt`**
|
||||||
- Uses Home Assistant STT provider via `/api/stt/<provider>`.
|
- Uses Home Assistant STT provider via `/api/stt/<provider>`.
|
||||||
- Intended for manual mic input (press mic, speak, auto-stop, transcribe, send).
|
- Intended for manual mic input (press mic, speak, auto-stop, transcribe, send).
|
||||||
- Continuous voice mode is not used in this provider.
|
- If continuous Voice Mode is enabled while this provider is selected, the card uses browser speech for continuous listening.
|
||||||
|
|
||||||
For `assist_stt`, make sure an STT engine is configured in **Settings → Voice assistants**.
|
For `assist_stt`, make sure an STT engine is configured in **Settings → Voice assistants**.
|
||||||
|
|
||||||
@@ -291,6 +294,11 @@ action:
|
|||||||
- For `browser`: open browser console for `OpenClaw: Speech recognition error`; repeated `network` usually means browser speech backend failure
|
- For `browser`: open browser console for `OpenClaw: Speech recognition error`; repeated `network` usually means browser speech backend failure
|
||||||
- For `assist_stt`: check network calls to `/api/stt/<provider>` and verify Home Assistant Voice/STT provider is configured
|
- For `assist_stt`: check network calls to `/api/stt/<provider>` and verify Home Assistant Voice/STT provider is configured
|
||||||
|
|
||||||
|
### Tool sensors show `Unknown`
|
||||||
|
|
||||||
|
- `Last Tool*` sensors stay `Unknown` until at least one `openclaw.invoke_tool` service call has executed.
|
||||||
|
- `Session Count` remains `0` if gateway policy blocks `sessions_list` for `/tools/invoke`.
|
||||||
|
|
||||||
### Responses do not appear after sending
|
### Responses do not appear after sending
|
||||||
|
|
||||||
- Verify `openclaw_message_received` is being fired in Developer Tools → Events
|
- Verify `openclaw_message_received` is being fired in Developer Tools → Events
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ from .const import (
|
|||||||
CONF_INCLUDE_EXPOSED_CONTEXT,
|
CONF_INCLUDE_EXPOSED_CONTEXT,
|
||||||
CONF_WAKE_WORD,
|
CONF_WAKE_WORD,
|
||||||
CONF_WAKE_WORD_ENABLED,
|
CONF_WAKE_WORD_ENABLED,
|
||||||
CONF_ALWAYS_VOICE_MODE,
|
|
||||||
CONF_ALLOW_BRAVE_WEBSPEECH,
|
CONF_ALLOW_BRAVE_WEBSPEECH,
|
||||||
CONF_VOICE_PROVIDER,
|
CONF_VOICE_PROVIDER,
|
||||||
CONTEXT_STRATEGY_TRUNCATE,
|
CONTEXT_STRATEGY_TRUNCATE,
|
||||||
@@ -67,7 +66,6 @@ from .const import (
|
|||||||
DEFAULT_INCLUDE_EXPOSED_CONTEXT,
|
DEFAULT_INCLUDE_EXPOSED_CONTEXT,
|
||||||
DEFAULT_WAKE_WORD,
|
DEFAULT_WAKE_WORD,
|
||||||
DEFAULT_WAKE_WORD_ENABLED,
|
DEFAULT_WAKE_WORD_ENABLED,
|
||||||
DEFAULT_ALWAYS_VOICE_MODE,
|
|
||||||
DEFAULT_ALLOW_BRAVE_WEBSPEECH,
|
DEFAULT_ALLOW_BRAVE_WEBSPEECH,
|
||||||
DEFAULT_VOICE_PROVIDER,
|
DEFAULT_VOICE_PROVIDER,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@@ -92,7 +90,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.40"
|
_CARD_URL = f"{_CARD_STATIC_URL}?v=0.1.41"
|
||||||
|
|
||||||
OpenClawConfigEntry = ConfigEntry
|
OpenClawConfigEntry = ConfigEntry
|
||||||
|
|
||||||
@@ -802,10 +800,6 @@ def _async_register_websocket_api(hass: HomeAssistant) -> None:
|
|||||||
DEFAULT_WAKE_WORD_ENABLED,
|
DEFAULT_WAKE_WORD_ENABLED,
|
||||||
),
|
),
|
||||||
CONF_WAKE_WORD: options.get(CONF_WAKE_WORD, DEFAULT_WAKE_WORD),
|
CONF_WAKE_WORD: options.get(CONF_WAKE_WORD, DEFAULT_WAKE_WORD),
|
||||||
CONF_ALWAYS_VOICE_MODE: options.get(
|
|
||||||
CONF_ALWAYS_VOICE_MODE,
|
|
||||||
DEFAULT_ALWAYS_VOICE_MODE,
|
|
||||||
),
|
|
||||||
CONF_ALLOW_BRAVE_WEBSPEECH: options.get(
|
CONF_ALLOW_BRAVE_WEBSPEECH: options.get(
|
||||||
CONF_ALLOW_BRAVE_WEBSPEECH,
|
CONF_ALLOW_BRAVE_WEBSPEECH,
|
||||||
DEFAULT_ALLOW_BRAVE_WEBSPEECH,
|
DEFAULT_ALLOW_BRAVE_WEBSPEECH,
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -44,7 +44,6 @@ from .const import (
|
|||||||
CONF_INCLUDE_EXPOSED_CONTEXT,
|
CONF_INCLUDE_EXPOSED_CONTEXT,
|
||||||
CONF_WAKE_WORD,
|
CONF_WAKE_WORD,
|
||||||
CONF_WAKE_WORD_ENABLED,
|
CONF_WAKE_WORD_ENABLED,
|
||||||
CONF_ALWAYS_VOICE_MODE,
|
|
||||||
CONF_ALLOW_BRAVE_WEBSPEECH,
|
CONF_ALLOW_BRAVE_WEBSPEECH,
|
||||||
CONF_VOICE_PROVIDER,
|
CONF_VOICE_PROVIDER,
|
||||||
CONTEXT_STRATEGY_CLEAR,
|
CONTEXT_STRATEGY_CLEAR,
|
||||||
@@ -57,7 +56,6 @@ from .const import (
|
|||||||
DEFAULT_INCLUDE_EXPOSED_CONTEXT,
|
DEFAULT_INCLUDE_EXPOSED_CONTEXT,
|
||||||
DEFAULT_WAKE_WORD,
|
DEFAULT_WAKE_WORD,
|
||||||
DEFAULT_WAKE_WORD_ENABLED,
|
DEFAULT_WAKE_WORD_ENABLED,
|
||||||
DEFAULT_ALWAYS_VOICE_MODE,
|
|
||||||
DEFAULT_ALLOW_BRAVE_WEBSPEECH,
|
DEFAULT_ALLOW_BRAVE_WEBSPEECH,
|
||||||
DEFAULT_VOICE_PROVIDER,
|
DEFAULT_VOICE_PROVIDER,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@@ -462,13 +460,6 @@ class OpenClawOptionsFlow(OptionsFlow):
|
|||||||
DEFAULT_WAKE_WORD,
|
DEFAULT_WAKE_WORD,
|
||||||
),
|
),
|
||||||
): str,
|
): str,
|
||||||
vol.Optional(
|
|
||||||
CONF_ALWAYS_VOICE_MODE,
|
|
||||||
default=options.get(
|
|
||||||
CONF_ALWAYS_VOICE_MODE,
|
|
||||||
DEFAULT_ALWAYS_VOICE_MODE,
|
|
||||||
),
|
|
||||||
): bool,
|
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
CONF_ALLOW_BRAVE_WEBSPEECH,
|
CONF_ALLOW_BRAVE_WEBSPEECH,
|
||||||
default=options.get(
|
default=options.get(
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ CONF_CONTEXT_STRATEGY = "context_strategy"
|
|||||||
CONF_ENABLE_TOOL_CALLS = "enable_tool_calls"
|
CONF_ENABLE_TOOL_CALLS = "enable_tool_calls"
|
||||||
CONF_WAKE_WORD_ENABLED = "wake_word_enabled"
|
CONF_WAKE_WORD_ENABLED = "wake_word_enabled"
|
||||||
CONF_WAKE_WORD = "wake_word"
|
CONF_WAKE_WORD = "wake_word"
|
||||||
CONF_ALWAYS_VOICE_MODE = "always_voice_mode"
|
|
||||||
CONF_ALLOW_BRAVE_WEBSPEECH = "allow_brave_webspeech"
|
CONF_ALLOW_BRAVE_WEBSPEECH = "allow_brave_webspeech"
|
||||||
CONF_VOICE_PROVIDER = "voice_provider"
|
CONF_VOICE_PROVIDER = "voice_provider"
|
||||||
|
|
||||||
@@ -40,7 +39,6 @@ DEFAULT_CONTEXT_STRATEGY = "truncate"
|
|||||||
DEFAULT_ENABLE_TOOL_CALLS = False
|
DEFAULT_ENABLE_TOOL_CALLS = False
|
||||||
DEFAULT_WAKE_WORD_ENABLED = False
|
DEFAULT_WAKE_WORD_ENABLED = False
|
||||||
DEFAULT_WAKE_WORD = "hey openclaw"
|
DEFAULT_WAKE_WORD = "hey openclaw"
|
||||||
DEFAULT_ALWAYS_VOICE_MODE = False
|
|
||||||
DEFAULT_ALLOW_BRAVE_WEBSPEECH = False
|
DEFAULT_ALLOW_BRAVE_WEBSPEECH = False
|
||||||
DEFAULT_VOICE_PROVIDER = "browser"
|
DEFAULT_VOICE_PROVIDER = "browser"
|
||||||
|
|
||||||
|
|||||||
@@ -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.40",
|
"version": "0.1.41",
|
||||||
"dependencies": ["conversation"],
|
"dependencies": ["conversation"],
|
||||||
"after_dependencies": ["hassio", "lovelace"]
|
"after_dependencies": ["hassio", "lovelace"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
"enable_tool_calls": "Enable tool calls (execute services)",
|
"enable_tool_calls": "Enable tool calls (execute services)",
|
||||||
"wake_word_enabled": "Require wake word",
|
"wake_word_enabled": "Require wake word",
|
||||||
"wake_word": "Wake word",
|
"wake_word": "Wake word",
|
||||||
"always_voice_mode": "Always-on voice mode",
|
|
||||||
"allow_brave_webspeech": "Allow Web Speech in Brave (experimental)",
|
"allow_brave_webspeech": "Allow Web Speech in Brave (experimental)",
|
||||||
"voice_provider": "Voice input provider (browser or HA STT)"
|
"voice_provider": "Voice input provider (browser or HA STT)"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
"enable_tool_calls": "Enable tool calls (execute services)",
|
"enable_tool_calls": "Enable tool calls (execute services)",
|
||||||
"wake_word_enabled": "Require wake word",
|
"wake_word_enabled": "Require wake word",
|
||||||
"wake_word": "Wake word",
|
"wake_word": "Wake word",
|
||||||
"always_voice_mode": "Always-on voice mode",
|
|
||||||
"allow_brave_webspeech": "Allow Web Speech in Brave (experimental)",
|
"allow_brave_webspeech": "Allow Web Speech in Brave (experimental)",
|
||||||
"voice_provider": "Voice input provider (browser or HA STT)"
|
"voice_provider": "Voice input provider (browser or HA STT)"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* + subscribes to openclaw_message_received events.
|
* + subscribes to openclaw_message_received events.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const CARD_VERSION = "0.3.4";
|
const CARD_VERSION = "0.3.5";
|
||||||
|
|
||||||
// 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;
|
||||||
@@ -62,7 +62,6 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
this._historySyncRetryTimer = null;
|
this._historySyncRetryTimer = null;
|
||||||
this._wakeWordEnabled = false;
|
this._wakeWordEnabled = false;
|
||||||
this._wakeWord = "hey openclaw";
|
this._wakeWord = "hey openclaw";
|
||||||
this._alwaysVoiceMode = false;
|
|
||||||
this._voiceStatus = "";
|
this._voiceStatus = "";
|
||||||
this._voiceRetryTimer = null;
|
this._voiceRetryTimer = null;
|
||||||
this._voiceRetryCount = 0;
|
this._voiceRetryCount = 0;
|
||||||
@@ -123,8 +122,24 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
this._subscribeToEvents();
|
this._subscribeToEvents();
|
||||||
this._syncHistoryFromBackend();
|
this._syncHistoryFromBackend();
|
||||||
this._loadIntegrationSettings();
|
this._loadIntegrationSettings();
|
||||||
this._render();
|
|
||||||
}
|
}
|
||||||
|
this._render();
|
||||||
|
}
|
||||||
|
|
||||||
|
_getGatewayConnectionState() {
|
||||||
|
const statusEntity = this._hass?.states?.["sensor.openclaw_status"];
|
||||||
|
const binaryEntity = this._hass?.states?.["binary_sensor.openclaw_connected"];
|
||||||
|
const status = String(statusEntity?.state || "").toLowerCase();
|
||||||
|
const connected = String(binaryEntity?.state || "").toLowerCase() === "on";
|
||||||
|
|
||||||
|
if (connected || status === "online") {
|
||||||
|
return { label: "Online", css: "online" };
|
||||||
|
}
|
||||||
|
if (status === "offline" || String(binaryEntity?.state || "").toLowerCase() === "off") {
|
||||||
|
return { label: "Offline", css: "offline" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { label: "Unknown", css: "unknown" };
|
||||||
}
|
}
|
||||||
|
|
||||||
getCardSize() {
|
getCardSize() {
|
||||||
@@ -321,7 +336,7 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _loadIntegrationSettings() {
|
async _loadIntegrationSettings(includePipeline = true) {
|
||||||
if (!this._hass) return;
|
if (!this._hass) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -336,7 +351,6 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
|
|
||||||
this._wakeWordEnabled = !!result?.wake_word_enabled;
|
this._wakeWordEnabled = !!result?.wake_word_enabled;
|
||||||
this._wakeWord = (result?.wake_word || "hey openclaw").toString().trim().toLowerCase();
|
this._wakeWord = (result?.wake_word || "hey openclaw").toString().trim().toLowerCase();
|
||||||
this._alwaysVoiceMode = !!result?.always_voice_mode;
|
|
||||||
this._allowBraveWebSpeechIntegration = !!result?.allow_brave_webspeech;
|
this._allowBraveWebSpeechIntegration = !!result?.allow_brave_webspeech;
|
||||||
this._voiceProviderIntegration =
|
this._voiceProviderIntegration =
|
||||||
result?.voice_provider === "assist_stt" ? "assist_stt" : "browser";
|
result?.voice_provider === "assist_stt" ? "assist_stt" : "browser";
|
||||||
@@ -344,7 +358,8 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
? this._normalizeSpeechLanguage(result.language)
|
? this._normalizeSpeechLanguage(result.language)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
try {
|
if (includePipeline) {
|
||||||
|
try {
|
||||||
let pipelineResult;
|
let pipelineResult;
|
||||||
if (typeof this._hass.callWS === "function") {
|
if (typeof this._hass.callWS === "function") {
|
||||||
pipelineResult = await this._hass.callWS({ type: "assist_pipeline/pipeline/list" });
|
pipelineResult = await this._hass.callWS({ type: "assist_pipeline/pipeline/list" });
|
||||||
@@ -372,13 +387,9 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
if (ttsLanguage) {
|
if (ttsLanguage) {
|
||||||
this._integrationTtsLanguage = this._normalizeSpeechLanguage(ttsLanguage);
|
this._integrationTtsLanguage = this._normalizeSpeechLanguage(ttsLanguage);
|
||||||
}
|
}
|
||||||
} catch (pipelineErr) {
|
} catch (pipelineErr) {
|
||||||
console.debug("OpenClaw: assist pipeline language detection skipped:", pipelineErr);
|
console.debug("OpenClaw: assist pipeline language detection skipped:", pipelineErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._alwaysVoiceMode && !this._isVoiceMode) {
|
|
||||||
this._isVoiceMode = true;
|
|
||||||
this._startVoiceRecognition();
|
|
||||||
}
|
}
|
||||||
this._render();
|
this._render();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -1162,7 +1173,8 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
}, delayMs);
|
}, delayMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
_toggleVoiceMode() {
|
async _toggleVoiceMode() {
|
||||||
|
await this._loadIntegrationSettings(false);
|
||||||
this._isVoiceMode = !this._isVoiceMode;
|
this._isVoiceMode = !this._isVoiceMode;
|
||||||
if (this._isVoiceMode) {
|
if (this._isVoiceMode) {
|
||||||
this._startVoiceRecognition();
|
this._startVoiceRecognition();
|
||||||
@@ -1303,6 +1315,7 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
const voiceActive = this._recognition !== null;
|
const voiceActive = this._recognition !== null;
|
||||||
|
const gatewayState = this._getGatewayConnectionState();
|
||||||
|
|
||||||
this.shadowRoot.innerHTML = `
|
this.shadowRoot.innerHTML = `
|
||||||
<style>
|
<style>
|
||||||
@@ -1332,6 +1345,24 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--oc-text);
|
color: var(--oc-text);
|
||||||
}
|
}
|
||||||
|
.header-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.gateway-status {
|
||||||
|
font-size: 11px;
|
||||||
|
border: 1px solid var(--oc-border);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
color: var(--oc-text-secondary);
|
||||||
|
}
|
||||||
|
.gateway-status.online {
|
||||||
|
color: #10b981;
|
||||||
|
}
|
||||||
|
.gateway-status.offline {
|
||||||
|
color: #ef4444;
|
||||||
|
}
|
||||||
.header-actions {
|
.header-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@@ -1503,7 +1534,10 @@ class OpenClawChatCard extends HTMLElement {
|
|||||||
|
|
||||||
<ha-card>
|
<ha-card>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h3>${this._escapeHtml(config.title)}</h3>
|
<div class="header-title">
|
||||||
|
<h3>${this._escapeHtml(config.title)}</h3>
|
||||||
|
<span class="gateway-status ${gatewayState.css}">Gateway: ${gatewayState.label}</span>
|
||||||
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
${
|
${
|
||||||
config.show_voice_button
|
config.show_voice_button
|
||||||
|
|||||||
@@ -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.40";
|
const src = "/openclaw/openclaw-chat-card.js?v=0.1.41";
|
||||||
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