β³ This skill is pending AI review.
Scores will appear once the review pipeline completes.
openclaw-xiaomi-home
Your OpenClaw can now control your smart home. It connects to your Xiaomi/Mijia devices through Home Assistant and lets you control lights, AC, locks, sensors and more with plain text or voice commands. Ask things like "turn on the living room light", "set AC to 26 degrees", "is the front door locked?", or "what's the bedroom temperature?" and your AI assistant handles it instantly. Triggers: "turn on the light", "set AC temperature", "is the door locked?", "check the temperature", "lock the doo
Choose how to use this skill
You do not need every option. Choose the path your AI client supports. The stable page stays the same; versioned files are immutable.
1. Native installer
This listing has no registered native installer command. Use the complete package or source fallback below, depending on what your client supports.
Do not guess an installer command or replace an existing version without reviewing the diff.
2. Complete package recommended
Download the ZIP when available. It includes SKILL.md plus the references, security notes and version metadata.
No complete ProSkills package is published for this listing yet.3. Prompt-only
Copy the prompt above when the agent can read the stable page or when you want to adopt the workflow without installing a skill.
Need only the instruction file?
Download SKILL.md only if your client requires a single file. The complete ZIP is safer for a full installation because it preserves the references and release context.
No path installs or executes anything by itself. Your agent still needs access to the project files. Before updating, compare the installed version and review the diff.
// RATINGS
Not yet listed on ClawHub or SkillsMP
// README
openclaw-xiaomi-home
Your OpenClaw can now control your smart home. Connect to Xiaomi/Mijia devices through Home Assistant and control everything with plain text or voice.
The Problem It Solves
Smart home devices are scattered across apps:
- Open Mi Home app β find device β tap button
This skill fixes that. Just tell your AI what you want:
"Turn on the living room light"
"Set bedroom AC to 26 degrees"
"Is the front door locked?"
Done.
What You Can Control
| Category | Examples |
|---|---|
| π‘ Lights | On/off, brightness |
| βοΈ Air Conditioning | Temperature, mode, fan speed |
| π Door Locks | Lock/unlock from anywhere |
| π‘οΈ Sensors | Temperature, humidity, motion |
| π¨ Fans & Humidifiers | On/off, speed |
| πͺ Blinds & Curtains | Open/close |
| π€ Robot Vacuums | Start, stop, return to base |
| π XiaoAI Speakers | Voice announcements (TTS) |
Works with 1837+ Xiaomi/Mijia devices.
How It Works
You β "Turn on the light"
β
OpenClaw AI
β
Home Assistant (local)
β
Xiaomi Device
All stays on your local network β no cloud, no subscription.
Installation
# ClawHub
clawhub install openclaw-xiaomi-home
# Manual
git clone https://github.com/canmaxice-maker/openclaw-xiaomi-home.git
mv openclaw-xiaomi-home ~/.openclaw/skills/
Setup (One Time)
1. Start Home Assistant
cd ~/.openclaw/skills/openclaw-xiaomi-home
docker compose up -d
Open http://localhost:8123 and create your account.
2. Add Xiaomi Devices
- Settings β Devices & Services β Add Integration
- Search Xiaomi Home β login with Xiaomi account
- Wait for devices to import
3. Create Access Token
- HA profile β Long-Lived Access Tokens β Create Token
- Copy and save it
4. Install Control Server
cd ~/.openclaw/skills/openclaw-xiaomi-home/scripts/ha-mcp-server
npm install && cp .env.example .env
# Edit .env with your HA_URL and HA_TOKEN
5. Start
launchctl load ~/.openclaw/skills/openclaw-xiaomi-home/scripts/ha-mcp-server/ai.openclaw.ha-mcp.plist
6. Test
node src/call-tool.mjs ping_ha
node src/call-tool.mjs list_all_devices '{"domain":"light"}'
Usage
Just talk to your AI assistant:
"Turn on the living room light"
"Set bedroom AC to 26 degrees"
"Is the front door locked?"
"What's the temperature?"
"Lock all doors"
"Turn off all lights"
"Open the blinds"
"Start the vacuum"
XiaoAI TTS Voice Announcement
Use XiaoAI speakers as a voice announcement system β your AI can "speak" reminders and alerts through the speaker.
β οΈ Note: Entity IDs are device-specific. You must find your own XiaoAI speaker's notify entity in Home Assistant (see Finding Your Entity IDs below).
Python script: ~/.openclaw/workspace/scripts/xiaoai_announce.py
# Find your notify entity ID first (see below), then:
python3 ~/.openclaw/workspace/scripts/xiaoai_announce.py "06:30 θ―₯θ΅·εΊδΊ" "notify.YOUR_ENTITY_ID"
MCP tool: xiaoai_announce(message, entity_id?)
Use cases: Health reminders, smart home alerts, agent notifications.
Finding Your Entity IDs
XiaoAI speaker entity IDs are unique to your account. To find them:
- Open Home Assistant β Developer Tools β States
- Filter by
notifyand look for entities containingxiaoai,play_text, orspeaker - Copy the entity ID (format:
notify.xiaomi_cn_XXXXXXXXXX_xxxx)
Security & Privacy
Required Credentials
| Credential | Purpose | Storage |
|---|---|---|
HA_TOKEN | Home Assistant Long-Lived Access Token | .env file (gitignored) |
Security Model
| Concern | Mitigation |
|---|---|
| Unauthenticated access | MCP server requires Authorization: Bearer <HA_TOKEN> on every request |
| Cross-origin abuse | CORS restricted to http://localhost only |
| LAN access | Server binds to localhost, not all interfaces |
| Token exfiltration | HA_TOKEN is only sent to localhost:8123 β never to external services |
| Credential leakage | .env is in .gitignore β never committed to git |
What This Skill Does NOT Do
- β Does NOT transmit your HA token to any external service
- β Does NOT accept requests from non-localhost origins
- β Does NOT collect, log, or transmit usage data
- β Does NOT use any LLM or AI processing
- β Does NOT expose unauthenticated endpoints
Troubleshooting
HA won't start
docker logs homeassistant
Devices not showing
- Use China mainland Xiaomi server in Mi Home
- Restart the homeassistant container
Token not working
- Re-create the Long-Lived Access Token in HA
- Update
HA_TOKENin.env
Credits
Changelog
| Version | Date | Changes |
|---|---|---|
| v1.2.0 | 2026-04-24 | Added XiaoAI TTS voice announcement via xiaoai_announce tool |
| v1.1.0 | 2026-04-21 | Plain language rewrite β user benefit focus |
| v1.0.0 | 2026-04-21 | Initial release |
License
MIT
// HOW IT'S BUILT
// FILES
21 files shipped with this skill. Inline text is the catalog copy. The upstream link is the source repository.
SKILL.md3.2 KB9f9dd4b1040fupstream β
--- name: openclaw-xiaomi-home description: Your OpenClaw can now control your smart home. It connects to your Xiaomi/Mijia devices through Home Assistant and lets you control lights, AC, locks, sensors and more with plain text or voice commands. Ask things like "turn on the living room light", "set AC to 26 degrees", "is the front door locked?", or "what's the bedroom temperature?" and your AI assistant handles it instantly. Triggers: "turn on the light", "set AC temperature", "is the door locked?", "check the temperature", "lock the door", "turn everything off". NOTE: Requires Home Assistant (Docker, localhost:8123) and Xiaomi devices paired with Mi Home. Required credentials: - `HA_TOKEN`: Long-Lived Access Token from Home Assistant, stored in `.env` (gitignored). Used as Bearer token to authenticate MCP server requests. Never sent to any external service. Security: - MCP server only accepts requests from localhost - All MCP calls require "Authorization: Bearer <HA_TOKEN>" header - HA_TOKEN is never transmitted to any service other than your local Home Assistant - No data collection or exfiltration β purely local device control --- # Xiaomi Home Control **Your OpenClaw can now control your smart home.** Connect to Xiaomi/Mijia devices through Home Assistant and control everything with plain text or voice. ## What It Does Just tell your AI what you want: ``` "Turn on the living room light" "Set bedroom AC to 26 degrees" "Is the front door locked?" "What's the temperature?" "Lock all doors" "Turn off all lights" ``` Done. No apps. No switching. No pointing and clicking. ## What You Can Control | Category | Examples | |----------|---------| | π‘ Lights | Turn on/off, adjust brightness | | βοΈ Air Conditioning | Set temperature, mode, fan speed | | π Door Locks | Lock/unlock from anywhere | | π‘οΈ Sensors | Temperature, humidity, motion | | π¨ Fans & Humidifiers | On/off, speed control | | πͺ Blinds & Curtains | Open/close | | π€ Robot Vacuums | Start, stop, return to charger | Works with **1837+ Xiaomi/Mijia devices** via the official Xiaomi Home integration. ## Setup (One Time) ```bash # 1. Start Home Assistant docker compose up -d # 2. Connect your Xiaomi devices # (open localhost:8123 β add Xiaomi Home integration) # 3. Install the control server cd scripts/ha-mcp-server && npm install # 4. Done ``` Full guide in README.md. ## How It Works ``` You β "Turn on the light" β OpenClaw AI β Home Assistant (your local server) β Xiaomi Device ``` All on **your local network** β no cloud, no subscription. ## Why It's Better | Before | After | |--------|-------| | Open app β find device β tap | Just say what you want | | One device at a time | Control everything at once | | Can't do it remotely | Through AI assistant from anywhere | | Remember which app for which device | Describe it in plain English | ## Privacy - Everything stays on your home network - No cloud dependency after setup - No data collection or tracking - Runs on your own hardware ## Example Commands ``` "Turn on the living room light" "Dim the bedroom to 30%" "Set AC to cool mode at 24 degrees" "Is the door locked?" "Lock the front door" "What's the living room temperature?" "Turn off all lights" "Open the blinds" "Start the vacuum" ```README.md5.6 KBfc336c6ac863upstream β
# openclaw-xiaomi-home [](https://github.com/canmaxfire/openclaw-xiaomi-home) [](https://clawhub.com/openclaw-xiaomi-home) **Your OpenClaw can now control your smart home.** Connect to Xiaomi/Mijia devices through Home Assistant and control everything with plain text or voice. ## The Problem It Solves Smart home devices are scattered across apps: - Open Mi Home app β find device β tap button **This skill fixes that.** Just tell your AI what you want: ``` "Turn on the living room light" "Set bedroom AC to 26 degrees" "Is the front door locked?" ``` Done. ## What You Can Control | Category | Examples | |----------|----------| | π‘ Lights | On/off, brightness | | βοΈ Air Conditioning | Temperature, mode, fan speed | | π Door Locks | Lock/unlock from anywhere | | π‘οΈ Sensors | Temperature, humidity, motion | | π¨ Fans & Humidifiers | On/off, speed | | πͺ Blinds & Curtains | Open/close | | π€ Robot Vacuums | Start, stop, return to base | | π **XiaoAI Speakers** | **Voice announcements (TTS)** | Works with **1837+ Xiaomi/Mijia devices**. ## How It Works ``` You β "Turn on the light" β OpenClaw AI β Home Assistant (local) β Xiaomi Device ``` All stays **on your local network** β no cloud, no subscription. ## Installation ```bash # ClawHub clawhub install openclaw-xiaomi-home # Manual git clone https://github.com/canmaxice-maker/openclaw-xiaomi-home.git mv openclaw-xiaomi-home ~/.openclaw/skills/ ``` ## Setup (One Time) ### 1. Start Home Assistant ```bash cd ~/.openclaw/skills/openclaw-xiaomi-home docker compose up -d ``` Open http://localhost:8123 and create your account. ### 2. Add Xiaomi Devices 1. **Settings β Devices & Services β Add Integration** 2. Search **Xiaomi Home** β login with Xiaomi account 3. Wait for devices to import ### 3. Create Access Token 1. HA profile β **Long-Lived Access Tokens** β Create Token 2. Copy and save it ### 4. Install Control Server ```bash cd ~/.openclaw/skills/openclaw-xiaomi-home/scripts/ha-mcp-server npm install && cp .env.example .env # Edit .env with your HA_URL and HA_TOKEN ``` ### 5. Start ```bash launchctl load ~/.openclaw/skills/openclaw-xiaomi-home/scripts/ha-mcp-server/ai.openclaw.ha-mcp.plist ``` ### 6. Test ```bash node src/call-tool.mjs ping_ha node src/call-tool.mjs list_all_devices '{"domain":"light"}' ``` ## Usage Just talk to your AI assistant: ``` "Turn on the living room light" "Set bedroom AC to 26 degrees" "Is the front door locked?" "What's the temperature?" "Lock all doors" "Turn off all lights" "Open the blinds" "Start the vacuum" ``` ## XiaoAI TTS Voice Announcement Use XiaoAI speakers as a voice announcement system β your AI can "speak" reminders and alerts through the speaker. **β οΈ Note:** Entity IDs are device-specific. You must find your own XiaoAI speaker's `notify` entity in Home Assistant (see [Finding Your Entity IDs](#finding-your-entity-ids) below). **Python script:** `~/.openclaw/workspace/scripts/xiaoai_announce.py` ```bash # Find your notify entity ID first (see below), then: python3 ~/.openclaw/workspace/scripts/xiaoai_announce.py "06:30 θ―₯θ΅·εΊδΊ" "notify.YOUR_ENTITY_ID" ``` **MCP tool:** `xiaoai_announce(message, entity_id?)` **Use cases:** Health reminders, smart home alerts, agent notifications. ### Finding Your Entity IDs XiaoAI speaker entity IDs are unique to your account. To find them: 1. Open Home Assistant β **Developer Tools β States** 2. Filter by `notify` and look for entities containing `xiaoai`, `play_text`, or `speaker` 3. Copy the entity ID (format: `notify.xiaomi_cn_XXXXXXXXXX_xxxx`) --- ## Security & Privacy ### Required Credentials | Credential | Purpose | Storage | |------------|---------|---------| | `HA_TOKEN` | Home Assistant Long-Lived Access Token | `.env` file (gitignored) | ### Security Model | Concern | Mitigation | |---------|------------| | Unauthenticated access | MCP server requires `Authorization: Bearer <HA_TOKEN>` on every request | | Cross-origin abuse | CORS restricted to `http://localhost` only | | LAN access | Server binds to localhost, not all interfaces | | Token exfiltration | HA_TOKEN is only sent to `localhost:8123` β never to external services | | Credential leakage | `.env` is in `.gitignore` β never committed to git | ### What This Skill Does NOT Do - β Does NOT transmit your HA token to any external service - β Does NOT accept requests from non-localhost origins - β Does NOT collect, log, or transmit usage data - β Does NOT use any LLM or AI processing - β Does NOT expose unauthenticated endpoints ## Troubleshooting ### HA won't start ```bash docker logs homeassistant ``` ### Devices not showing - Use **China mainland** Xiaomi server in Mi Home - Restart the homeassistant container ### Token not working - Re-create the Long-Lived Access Token in HA - Update `HA_TOKEN` in `.env` ## Credits - [Home Assistant](https://www.home-assistant.io/) - [ha_xiaomi_home](https://github.com/nickoowen/ha-xiaomi-home) - [OpenClaw](https://openclaw.ai/) ## Changelog | Version | Date | Changes | |---------|------|---------| | [v1.2.0](https://github.com/canmaxice-maker/openclaw-xiaomi-home/releases/tag/v1.2.0) | 2026-04-24 | Added XiaoAI TTS voice announcement via `xiaoai_announce` tool | | [v1.1.0](https://github.com/canmaxice-maker/openclaw-xiaomi-home/releases/tag/v1.1.0) | 2026-04-21 | Plain language rewrite β user benefit focus | | [v1.0.0](https://github.com/canmaxice-maker/openclaw-xiaomi-home/releases/tag/v1.0.0) | 2026-04-21 | Initial release | ## License MITscripts/ha-mcp-server/.env.example137 B77c671b22c29upstream β
# Home Assistant Configuration HA_URL=http://localhost:8123 HA_TOKEN=your_long_lived_access_token_here # Server Configuration PORT=3002scripts/ha-mcp-server/ai.openclaw.ha-mcp.plist986 B67ac4f04ecd8upstream β
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>ai.openclaw.ha-mcp</string> <key>ProgramArguments</key> <array> <string>/opt/homebrew/bin/node</string> <string>/Users/nanali/.openclaw/skills/openclaw-xiaomi-home/scripts/ha-mcp-server/src/http-server.mjs</string> </array> <key>EnvironmentVariables</key> <dict> <key>HOME</key> <string>/Users/nanali</string> </dict> <key>WorkingDirectory</key> <string>/Users/nanali/.openclaw/skills/openclaw-xiaomi-home/scripts/ha-mcp-server</string> <key>StandardOutPath</key> <string>/Users/nanali/.openclaw/logs/ha-mcp.log</string> <key>StandardErrorPath</key> <string>/Users/nanali/.openclaw/logs/ha-mcp.err.log</string> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> </dict> </plist>scripts/ha-mcp-server/package-lock.json57 KB1c2827c3c162upstream β
Contents are not inlined in the catalog. Open the upstream file.
scripts/ha-mcp-server/package.json550 B38e5be15861cupstream β
{ "name": "ha-mcp-server", "version": "1.0.0", "description": "MCP server for Home Assistant - controls Xiaomi devices via natural language", "type": "module", "main": "src/http-server.mjs", "scripts": { "start": "node src/http-server.mjs", "start:stdio": "node src/index.mjs", "test": "node src/call-tool.mjs ping_ha" }, "keywords": [ "home-assistant", "xiaomi", "mcp", "smart-home", "openclaw" ], "author": "Nana / OpenClaw", "license": "MIT", "dependencies": { "dotenv": "^16.4.5" } }scripts/ha-mcp-server/src/call-tool.mjs2.0 KB41c41bdbf16fupstream β
/** * HA MCP Client - Call tools via HTTP JSON-RPC * Usage: node call-tool.mjs <tool_name> [args_json] */ import http from "http"; import { readFileSync } from "fs"; import path from "path"; import { fileURLToPath } from "url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const envPath = path.resolve(__dirname, "../.env"); const env = {}; try { const lines = readFileSync(envPath, "utf8").split("\n"); for (const line of lines) { const [key, ...vals] = line.split("="); if (key && vals.length) env[key.trim()] = vals.join("=").trim(); } } catch (e) { /* no .env */ } const HOST = process.env.HA_MCP_HOST || "localhost"; const PORT = process.env.HA_MCP_PORT || "3002"; const HA_TOKEN = env.HA_TOKEN || ""; function rpc(method, params = {}) { return new Promise((resolve, reject) => { const body = JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }); const headers = { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(body), "Authorization": `Bearer ${HA_TOKEN}`, }; const options = { hostname: HOST, port: PORT, path: "/", method: "POST", headers }; const req = http.request(options, res => { let data = ""; res.on("data", chunk => data += chunk); res.on("end", () => { try { const json = JSON.parse(data); if (json.error) reject(new Error(json.error.message)); else resolve(json.result); } catch (e) { reject(e); } }); }); req.on("error", reject); req.write(body); req.end(); }); } const tool = process.argv[2]; const args = process.argv[3] ? JSON.parse(process.argv[3]) : {}; if (!tool) { console.error("Usage: node call-tool.mjs <tool_name> [args_json]"); process.exit(1); } rpc("tools/call", { name: tool, arguments: args }) .then(result => { const text = result.content?.[0]?.text || JSON.stringify(result); console.log(text); }) .catch(err => { console.error("Error:", err.message); process.exit(1); });scripts/ha-mcp-server/src/http-server.mjs12 KBcaaa58b5c872upstream β
/** * Home Assistant MCP Server - Simple HTTP JSON-RPC * Compatible with any MCP client via HTTP POST */ import http from "http"; import { readFileSync } from "fs"; import path from "path"; import { fileURLToPath } from "url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const envPath = path.resolve(__dirname, "../.env"); const env = {}; try { const lines = readFileSync(envPath, "utf8").split("\n"); for (const line of lines) { const [key, ...vals] = line.split("="); if (key && vals.length) env[key.trim()] = vals.join("=").trim(); } } catch (e) { /* no .env */ } const HA_URL = env.HA_URL || "http://localhost:8123"; const HA_TOKEN = env.HA_TOKEN || ""; const PORT = parseInt(env.PORT || "3002", 10); const ALLOWED_ORIGIN = "http://localhost"; // Only allow localhost for CORS // Simple bearer token auth: must send "Authorization: Bearer <HA_TOKEN>" header function checkAuth(req) { const auth = req.headers["authorization"] || req.headers["Authorization"]; if (!auth || !auth.startsWith("Bearer ")) return false; const token = auth.slice("Bearer ".length); return token === HA_TOKEN; } // ============================================================================ // HA API // ============================================================================ async function haFetch(endpoint, options = {}) { const url = `${HA_URL}/api${endpoint}`; const response = await fetch(url, { ...options, headers: { "Authorization": `Bearer ${HA_TOKEN}`, "Content-Type": "application/json", ...options.headers, }, }); if (!response.ok) throw new Error(`HA API error: ${response.status}`); return response.json(); } const getEntity = (id) => haFetch(`/states/${id}`); const callService = (d, s, data) => haFetch(`/services/${d}/${s}`, { method: "POST", body: JSON.stringify(data) }); const getAllEntities = () => haFetch("/states"); // ============================================================================ // Tool Implementations // ============================================================================ const tools = { // Lights light_turn_on: async ({ entity_id, brightness }) => { const data = { entity_id }; if (brightness !== undefined) data.brightness = brightness; await callService("light", "turn_on", data); return textResult(`Light ${entity_id} turned on${brightness ? ` (brightness: ${brightness})` : ""}`); }, light_turn_off: async ({ entity_id }) => { await callService("light", "turn_off", { entity_id }); return textResult(`Light ${entity_id} turned off`); }, get_light_state: async ({ entity_id }) => { const e = await getEntity(entity_id); return textResult(`${e.entity_id}: ${e.state} (brightness: ${e.attributes.brightness ?? "N/A"})`); }, // Climate / AC climate_set_temperature: async ({ entity_id, temperature }) => { await callService("climate", "set_temperature", { entity_id, temperature }); return textResult(`${entity_id} set to ${temperature}Β°C`); }, climate_set_mode: async ({ entity_id, mode }) => { await callService("climate", "set_hvac_mode", { entity_id, hvac_mode: mode }); return textResult(`${entity_id} mode set to ${mode}`); }, get_climate_state: async ({ entity_id }) => { const e = await getEntity(entity_id); const a = e.attributes; return textResult(`${e.entity_id}: ${e.state}, temp: ${a.current_temperature}Β°C, target: ${a.temperature}Β°C`); }, // Fans fan_turn_on: async ({ entity_id }) => { await callService("fan", "turn_on", { entity_id }); return textResult(`${entity_id} turned on`); }, fan_turn_off: async ({ entity_id }) => { await callService("fan", "turn_off", { entity_id }); return textResult(`${entity_id} turned off`); }, fan_set_speed: async ({ entity_id, speed }) => { await callService("fan", "set_percentage", { entity_id, percentage: speed }); return textResult(`${entity_id} speed set to ${speed}%`); }, get_fan_state: async ({ entity_id }) => { const e = await getEntity(entity_id); return textResult(`${e.entity_id}: ${e.state} (speed: ${e.attributes.percentage ?? "N/A"}%)`); }, // Switches switch_turn_on: async ({ entity_id }) => { await callService("switch", "turn_on", { entity_id }); return textResult(`${entity_id} turned on`); }, switch_turn_off: async ({ entity_id }) => { await callService("switch", "turn_off", { entity_id }); return textResult(`${entity_id} turned off`); }, get_switch_state: async ({ entity_id }) => { const e = await getEntity(entity_id); return textResult(`${e.entity_id}: ${e.state}`); }, // Locks lock_lock: async ({ entity_id }) => { await callService("lock", "lock", { entity_id }); return textResult(`${entity_id} locked`); }, lock_unlock: async ({ entity_id }) => { await callService("lock", "unlock", { entity_id }); return textResult(`${entity_id} unlocked`); }, get_lock_state: async ({ entity_id }) => { const e = await getEntity(entity_id); return textResult(`${e.entity_id}: ${e.state}`); }, // Sensors get_sensor_reading: async ({ entity_id }) => { const e = await getEntity(entity_id); return textResult(`${e.entity_id}: ${e.state} ${e.attributes.unit_of_measurement ?? ""}`); }, list_sensors: async () => { const entities = await getAllEntities(); const sensors = entities.filter(e => e.entity_id.startsWith("sensor.") || e.entity_id.startsWith("binary_sensor.")); const list = sensors.slice(0, 30).map(e => ` - ${e.entity_id}: ${e.state} ${e.attributes.unit_of_measurement ?? ""}`).join("\n"); return textResult(`Sensors (${sensors.length} total):\n${list}`); }, // Humidifier humidifier_turn_on: async ({ entity_id }) => { await callService("humidifier", "turn_on", { entity_id }); return textResult(`${entity_id} turned on`); }, humidifier_turn_off: async ({ entity_id }) => { await callService("humidifier", "turn_off", { entity_id }); return textResult(`${entity_id} turned off`); }, get_humidifier_state: async ({ entity_id }) => { const e = await getEntity(entity_id); return textResult(`${e.entity_id}: ${e.state}, humidity: ${e.attributes.current_humidity ?? "N/A"}%`); }, // Cover / Blinds cover_open: async ({ entity_id }) => { await callService("cover", "open_cover", { entity_id }); return textResult(`${entity_id} opened`); }, cover_close: async ({ entity_id }) => { await callService("cover", "close_cover", { entity_id }); return textResult(`${entity_id} closed`); }, get_cover_state: async ({ entity_id }) => { const e = await getEntity(entity_id); return textResult(`${e.entity_id}: ${e.state}`); }, // Vacuum vacuum_start: async ({ entity_id }) => { await callService("vacuum", "start", { entity_id }); return textResult(`${entity_id} started`); }, vacuum_stop: async ({ entity_id }) => { await callService("vacuum", "stop", { entity_id }); return textResult(`${entity_id} stopped`); }, vacuum_return_to_base: async ({ entity_id }) => { await callService("vacuum", "return_to_base", { entity_id }); return textResult(`${entity_id} returning to base`); }, // Devices list_all_devices: async (args = {}) => { const entities = await getAllEntities(); const filtered = args.domain ? entities.filter(e => e.entity_id.startsWith(args.domain + ".")) : entities; const list = filtered.slice(0, 50).map(e => ` - ${e.entity_id}: ${e.state}`).join("\n"); return textResult(`${filtered.length} entities (showing 50):\n${list}`); }, get_device_state: async ({ entity_id }) => { const e = await getEntity(entity_id); return textResult(`${e.entity_id}\nState: ${e.state}\nAttributes: ${JSON.stringify(e.attributes, null, 2)}`); }, // Scene trigger_scene: async ({ entity_id }) => { await callService("scene", "turn_on", { entity_id }); return textResult(`Scene ${entity_id} triggered`); }, // XiaoAI TTS Announce xiaoai_announce: async ({ message, entity_id }) => { const target = entity_id || "notify.xiaomi_cn_501481700_l16a_play_text_a_7_3"; await haFetch("/services/notify/send_message", { method: "POST", body: JSON.stringify({ message, entity_id: target }), }); return textResult(`XiaoAI announced: ${message}`); }, // HA status ping_ha: async () => { await haFetch("/config"); return textResult("Home Assistant is reachable and running"); }, get_ha_config: async () => { const c = await haFetch("/config"); return textResult(`Home Assistant version: ${c.version}`); }, }; function textResult(text) { return { content: [{ type: "text", text }] }; } // ============================================================================ // HTTP Server // ============================================================================ const server = http.createServer(async (req, res) => { if (req.method === "OPTIONS") { res.writeHead(200, { "Access-Control-Allow-Origin": ALLOWED_ORIGIN, "Access-Control-Allow-Methods": "POST, GET, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization" }); res.end(); return; } // Reject requests from non-localhost origins const origin = req.headers["origin"] || req.headers["Origin"]; if (origin && !origin.startsWith(ALLOWED_ORIGIN)) { res.writeHead(403, { "Content-Type": "application/json" }); res.end(JSON.stringify({ error: "Forbidden: cross-origin request denied" })); return; } // Require authentication for all tool calls if (req.method === "POST" && !checkAuth(req)) { res.writeHead(401, { "Content-Type": "application/json", "WWW-Authenticate": "Bearer" }); res.end(JSON.stringify({ error: "Unauthorized: valid Bearer token required" })); return; } if (req.method === "GET" && req.url === "/health") { res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ status: "ok" })); return; } if (req.method !== "POST") { res.writeHead(404); res.end(); return; } let body = ""; req.on("data", chunk => body += chunk); req.on("end", async () => { try { const json = JSON.parse(body); const jsonrpc = json.jsonrpc || "2.0"; const method = json.method; const params = json.params || {}; const responseId = json.id; if (method === "tools/list") { const toolList = Object.keys(tools).map(name => ({ name, description: "", inputSchema: { type: "object" } })); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ jsonrpc, id: responseId, result: { tools: toolList } })); return; } if (method === "tools/call") { const toolName = params.name; const args = params.arguments || {}; if (!tools[toolName]) { res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ jsonrpc, id: responseId, error: { code: -32601, message: `Tool ${toolName} not found` } })); return; } try { const result = await tools[toolName](args); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ jsonrpc, id: responseId, result })); } catch (err) { res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ jsonrpc, id: responseId, error: { code: -32603, message: err.message } })); } return; } res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ jsonrpc, id: responseId, error: { code: -32601, message: "Method not found" } })); } catch (e) { res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } })); } }); }); server.listen(PORT, () => { console.error(`HA MCP Server running on http://localhost:${PORT}`); });scripts/ha-mcp-server/tsconfig.json336 B2b380862c53cupstream β
{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "resolveJsonModule": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] }scripts/setup.sh3.1 KB7c350679d661upstream β
#!/bin/bash # Setup script for openclaw-xiaomi-home skill # This script helps users install Home Assistant and configure the MCP server set -e SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)" SCRIPT_DIR="$SKILL_DIR/scripts/ha-mcp-server" PLIST_SRC="$SCRIPT_DIR/ai.openclaw.ha-mcp.plist" echo "==========================================" echo "Xiaomi Home Skill Setup" echo "==========================================" # Check Docker if ! command -v docker &> /dev/null; then echo "Error: Docker is not installed." echo "Please install Docker Desktop from: https://docs.docker.com/desktop/setup/install/mac-install/" exit 1 fi if ! docker info &> /dev/null; then echo "Error: Docker is not running." echo "Please start Docker Desktop." exit 1 fi echo "β Docker is installed and running" # Start Home Assistant echo "" echo "Starting Home Assistant..." cd "$SKILL_DIR" docker compose up -d 2>/dev/null || docker run -d \ --name homeassistant \ --privileged \ -p 8123:8123 \ -v ~/homeassistant/config:/config \ -v /etc/localtime:/etc/localtime:ro \ -e TZ=Asia/Shanghai \ --dns=8.8.8.8 \ --dns=223.5.5.5 \ --restart=unless-stopped \ ghcr.io/home-assistant/home-assistant:stable echo "β Home Assistant started" echo " Access at: http://localhost:8123" echo "" echo " First-time setup:" echo " 1. Open http://localhost:8123 and create your account" echo " 2. Add 'external_url: http://localhost:8123' to ~/homeassistant/config/configuration.yaml" echo " 3. Go to Settings β Devices & Services β Add Integration" echo " 4. Search 'Xiaomi Home' and login with your Xiaomi account" echo " 5. Profile β Security β Create Long-Lived Access Token" echo "" # Setup HA token if [ ! -f "$SCRIPT_DIR/.env" ]; then echo "==========================================" echo "MCP Server Configuration" echo "==========================================" echo "Enter your Home Assistant Long-Lived Access Token:" read -r HA_TOKEN echo "HA_URL=http://localhost:8123" > "$SCRIPT_DIR/.env" echo "HA_TOKEN=$HA_TOKEN" >> "$SCRIPT_DIR/.env" echo "PORT=3002" >> "$SCRIPT_DIR/.env" echo "β Created .env file" else echo "β .env file already exists" fi # Install MCP Server dependencies echo "" echo "Installing MCP Server..." cd "$SCRIPT_DIR" npm install --silent 2>/dev/null # Setup LaunchAgent echo "" echo "Installing HA MCP Server as LaunchAgent..." mkdir -p "$HOME/Library/LaunchAgents" mkdir -p "$(dirname "$PLIST_SRC")" # Create user-specific plist PLIST_DST="$HOME/Library/LaunchAgents/ai.openclaw.ha-mcp.plist" sed "s|/Users/nanali|$HOME|g" "$PLIST_SRC" > "$PLIST_DST" launchctl load "$PLIST_DST" 2>/dev/null || true echo "β HA MCP Server installed as LaunchAgent" echo "" echo "==========================================" echo "Setup Complete!" echo "==========================================" echo "" echo "HA MCP Server: http://localhost:3002" echo "Home Assistant: http://localhost:8123" echo "" echo "Test the MCP server:" echo " node $SCRIPT_DIR/src/call-tool.mjs ping_ha" echo "" echo "For OpenClaw integration, add this skill to your OpenClaw" echo "and the MCP server will automatically handle device control."references/api-notes.md2.0 KBade0f653cd84upstream β
# Home Assistant API Notes ## Authentication All API requests require a Long-Lived Access Token in the Authorization header: ``` Authorization: Bearer YOUR_TOKEN_HERE ``` ## Base URL ``` http://localhost:8123/api ``` ## Key Endpoints ### States ```bash # Get all states GET /api/states # Get single entity state GET /api/states/{entity_id} # Example curl -H "Authorization: Bearer $HA_TOKEN" \ http://localhost:8123/api/states/light.living_room ``` ### Services ```bash # Call a service POST /api/services/{domain}/{service} # Light examples POST /api/services/light/turn_on {"entity_id": "light.living_room", "brightness": 255} POST /api/services/light/turn_off {"entity_id": "light.living_room"} # Climate examples POST /api/services/climate/set_temperature {"entity_id": "climate.living_room_ac", "temperature": 26} POST /api/services/climate/set_hvac_mode {"entity_id": "climate.living_room_ac", "hvac_mode": "cool"} # Lock examples POST /api/services/lock/lock {"entity_id": "lock.front_door"} POST /api/services/lock/unlock {"entity_id": "lock.front_door"} ``` ### Config ```bash GET /api/config ``` ### Events ```bash # Listen to events (Server-Sent Events) GET /api/events ``` ## Entity ID Format ``` {domain}.{device_name}_{identifier} ``` Examples: - `light.living_room_ceiling` - `climate.bedroom_ac` - `sensor.kitchen_temperature` - `binary_sensor.front_door` - `lock.front_door` - `switch.tv_plug` ## Common Domains | Domain | Type | |--------|------| | `light` | Lights | | `switch` | Plugs, Switches | | `climate` | AC, Heaters | | `sensor` | Sensors (readings) | | `binary_sensor` | Binary sensors (on/off) | | `lock` | Smart locks | | `cover` | Curtains, Blinds | | `fan` | Fans | | `scene` | Scenes | | `automation` | Automations | ## Error Responses ```json { "code": "not_found", "message": "Entity not found" } ``` ## Rate Limits - No strict rate limit for local API - Recommended: max 10 calls/second - Cloud API (Xiaomi) may have stricter limitsreferences/automations.md3.4 KBd5188bcb0a34upstream β
# Automation Templates ## Home Assistant Automation Examples These automations can be configured in Home Assistant's UI or via YAML. ### Temperature-Based Climate Control ```yaml automation: - alias: "Auto AC when hot" trigger: - platform: numeric_state entity_id: sensor.living_room_temperature above: 28 condition: - condition: time after: "08:00:00" before: "22:00:00" action: - service: climate.set_temperature target: entity_id: climate.living_room_ac data: temperature: 26 - service: notify.openclaw data: message: "π‘οΈ Living room temp above 28Β°C, AC turned on to 26Β°C" ``` ### Motion-Activated Light ```yaml automation: - alias: "Hallway light on motion" trigger: - platform: state entity_id: binary_sensor.hallway_motion to: "on" condition: - condition: sun after: sunset before: sunrise action: - service: light.turn_on target: entity_id: light.hallway data: brightness: 128 ``` ### Door Lock Reminder ```yaml automation: - alias: "Front door auto-lock" trigger: - platform: state entity_id: binary_sensor.front_door to: "closed" for: minutes: 2 condition: - condition: state entity_id: lock.front_door state: "unlocked" action: - service: lock.lock target: entity_id: lock.front_door ``` ### Goodnight Routine ```yaml automation: - alias: "Goodnight scene" trigger: - platform: time at: "22:30:00" action: - service: light.turn_off target: entity_id: group.all_lights - service: climate.set_temperature target: entity_id: climate.bedroom_ac data: temperature: 25 - service: lock.lock target: entity_id: lock.front_door ``` ### Leave Home ```yaml automation: - alias: "Turn off when leaving" trigger: - platform: state entity_id: binary_sensor.front_door to: "closed" for: minutes: 5 condition: - condition: state entity_id: person.jun state: "not_home" action: - service: switch.turn_off target: entity_id: group.all_switches - service: notify.openclaw data: message: "π Home secured. All devices off." ``` ## OpenClaw Webhook Integration To receive alerts in OpenClaw, set up a webhook in Home Assistant. ### Configuration Add to `configuration.yaml`: ```yaml rest_command: notify_openclaw: url: "http://localhost:8123/api/webhook/openclaw_notify" method: POST content_type: "application/json" payload: '{"message": "{{ message }}"}' ``` ### Enable Webhook in UI Settings β Devices & Services β Helpers β Add Helper β Webhook ### Notify OpenClaw from Automation ```yaml action: - service: rest_command.notify_openclaw data: message: "β οΈ Smoke detected in living room!" ``` ## Natural Language Commands from OpenClaw OpenClaw can execute these automations via the MCP tools: ``` User: "Turn on the fan when temperature exceeds 30Β°C" β OpenClaw: Creates automation in HA or triggers manual command User: "Lock all doors at 10 PM" β OpenClaw: Creates time-based automation User: "Turn off everything when I leave" β OpenClaw: Creates device-based automation ```references/device-support.md2.9 KB9401dd5eb9daupstream β
# Device Support Reference ## Supported Devices ### Lighting β | Category | Examples | Notes | |----------|----------|-------| | Ceiling Lights | Mi LED Ceiling Light, Philips Ceiling Light | Full on/off/brightness/color control | | Table Lamps | Mi Bedside Lamp, Mi Desk Lamp | Full control | | Floor Lamps | Mi Floor Lamp | Full control | | Bulbs | Mi LED Bulb, Philips Hue (via ecosystem) | Full on/off/brightness | ### Climate β | Category | Examples | Notes | |----------|----------|-------| | Air Conditioners | Mi Air Conditioner, various IR-based ACs | Temperature, mode, fan speed | | Heaters | Mi Smart Heater, Mi Oil Heater | Temperature control | | Fans | Mi Smart Fan, Mi Standing Fan | On/off, speed | ### Sensors β | Category | Examples | Notes | |----------|----------|-------| | Temperature/Humidity | Mi Temperature and Humidity Sensor | Readings | | Door/Window | Mi Door/Window Sensor | Open/close status | | Motion | Mi Motion Sensor | Detected/idle | | Water Leak | Mi Water Leak Sensor | Detected/safe | ### Smart Locks β | Category | Examples | Notes | |----------|----------|-------| | Door Locks | Xiaomi Smart Door Lock, Aqara Smart Lock | Lock/unlock, auto-lock settings | ### Plugs & Switches β | Category | Examples | Notes | |----------|----------|-------| | Smart Plugs | Mi Smart Plug, Aqara Plug | On/off, power monitoring | | Wall Switches | Mi Wall Switch, Aqara Wall Switch | On/off | ### Appliances β οΈ | Category | Examples | Notes | |----------|----------|-------| | Refrigerators | Mi Refrigerator | Basic on/off, temperature | | Washers | Mi Washing Machine | Start/stop, basic modes | | Projectors | Mi Laser Projector | On/off, input selection | ## NOT Supported β - **Bluetooth devices** (direct BLE connection) - **Infrared (IR) devices** (TVs, AC remotes via IR blaster) - **Virtual devices** (scenes, automations created in Mi Home) - **Wearable devices** (Mi Band, etc.) - **Air Purifiers** (some models may work) - **Robot Vacuums** (different integration path) ## Local vs Cloud Control ### With Central Hub Gateway β - Commands go through the local hub - Faster response (< 1 second) - Works without internet - Requires: Hub firmware 3.3.0_0023+ ### Without Central Hub - Commands go through Xiaomi Cloud - Slower response (1-3 seconds) - Requires internet connection - May have latency during cloud outages ### LAN Control (Partial Alternative) Enable in Xiaomi Home integration settings: Settings β Devices & Services β Xiaomi Home β Configure β LAN Control β οΈ Note: LAN control only works for IP devices (WiFi), not BLE Mesh/ZigBee devices. ## Entity Naming Convention In Home Assistant, Xiaomi devices appear as: - `light.xiaomi_xxx` - Lights - `climate.xiaomi_xxx` - AC/Heaters - `sensor.xiaomi_temperature` - Sensors - `binary_sensor.xiaomi_door` - Door/Window sensors - `lock.xiaomi_lock` - Smart locks - `switch.xiaomi_plug` - Plugs/Switchesreferences/installation.md2.3 KBa78382a729b1upstream β
# Detailed Installation Guide ## Prerequisites - Docker Desktop 4.x+ - Xiaomi account with Mi Home app and linked devices - (Optional) Xiaomi Central Hub Gateway for local control ## Step 1: Install Docker Desktop Download from: https://docs.docker.com/desktop/setup/install/mac-install/ After installation, ensure Docker is running (whale icon in menu bar). ## Step 2: Clone and Setup the Skill ```bash git clone https://github.com/YOUR_USERNAME/openclaw-xiaomi-home.git cd openclaw-xiaomi-home ``` ## Step 3: Configure mcporter Add the MCP server to your mcporter config: ```bash mcporter config add ha-mcp \ --stdio "cd /path/to/openclaw-xiaomi-home/scripts/ha-mcp-server && npm start" ``` Or add it manually to `~/.openclaw/config/mcporter.json`: ```json { "servers": { "ha-mcp": { "command": "node", "args": ["/path/to/openclaw-xiaomi-home/scripts/ha-mcp-server/dist/index.js"], "env": { "HA_URL": "http://localhost:8123", "HA_TOKEN": "your_long_lived_token" } } } } ``` ## Step 4: Get Home Assistant Token 1. Open Home Assistant: http://localhost:8123 2. Create account / Login 3. Profile (your username) β Security 4. Create Long-Lived Access Token 5. Copy the token ## Step 5: Update .env Edit `scripts/ha-mcp-server/.env`: ``` HA_URL=http://localhost:8123 HA_TOKEN=your_copied_token_here PORT=3002 ``` ## Step 6: Install ha_xiaomi_home Integration 1. Home Assistant β Settings β Devices & Services 2. Add Integration β Search "Xiaomi Home" 3. Click "Xiaomi Home" β Continue 4. Login with Xiaomi account 5. Select your home and devices to import ## Step 7: Test After HA restarts and devices are imported, test: ```bash mcporter call ha-mcp.list_all_devices mcporter call ha-mcp.ping_ha ``` ## Troubleshooting ### HA Container Won't Start Check logs: ```bash docker logs homeassistant ``` ### Can't Login to Xiaomi The Xiaomi Cloud API may be blocked in your region. Use a VPN or enable LAN control in the integration settings. ### Devices Not Showing - Ensure devices are added to Mi Home app first - Check if device type is supported (no BLE/IR devices) - Try re-authorizing the Xiaomi account in integration settings ## Updating ```bash cd openclaw-xiaomi-home git pull cd scripts/ha-mcp-server npm install && npm run build docker compose restart homeassistant ```.github/ISSUE_TEMPLATE/bug_report.md628 B003460b4115fupstream β
--- name: "\U0001F41B Bug Report" about: Report something that isn't working correctly title: "[Bug] " labels: bug assignees: '' --- ## π Description [Describe the bug clearly and concisely] ## π Steps to Reproduce 1. 2. 3. ## β Expected Behavior [What should happen] ## β Actual Behavior [What actually happens] ## π Environment - **Home Assistant version**: - **openclaw-xiaomi-home version**: - **Device type**: - **macOS / Linux version**: ## πΈ Screenshots / Logs [If applicable, add screenshots or relevant log output] ## π Additional Context [Add any other context about the problem here].github/ISSUE_TEMPLATE/config.yml405 B6732e04732f6upstream β
blank_issues_enabled: false contact_links: - name: "\U0001F4AC General Question / Usage Help" url: https://github.com/canmaxfire/openclaw-xiaomi-home/discussions" about: Please ask and answer general questions here. - name: "\U0001F310 Installation Help" url: https://github.com/canmaxfire/openclaw-xiaomi-home#quick-start" about: Check the README for installation instructions first..github/ISSUE_TEMPLATE/feature_request.md737 B72711c6456d8upstream β
--- name: "\U0001F31F Feature Request" about: Suggest a new feature or improvement title: "[Feature] " labels: enhancement assignees: '' --- ## β¨ Problem / Use Case [Describe the problem you want to solve, or the use case this feature would enable] ## π‘ Proposed Solution [Describe what you'd like to happen] ## π Current Workaround [If applicable, describe any workaround you're currently using] ## π Alternative Solutions [Describe any alternative solutions or features you've considered] ## π§ Device / Integration [Is this related to a specific device type or Home Assistant integration?] - Device type: - Home Assistant version: ## πΈ Mockup / Examples [If applicable, add screenshots, diagrams, or examples].github/PULL_REQUEST_TEMPLATE.md789 Bb05275f73e2fupstream β
## π¦ Pull Request ### Description [Describe what changes this PR makes and why] ### Related Issue [Link to the issue this PR addresses, e.g. "Fixes #12"] ### Type of Change - [ ] Bug fix - [ ] New feature - [ ] Documentation update - [ ] Code refactoring - [ ] Other: ### Testing [Describe what testing you've done] - [ ] Tested locally with Home Assistant - [ ] Tested with specific device(s): - [ ] No testing done (please explain why) ### Checklist - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings ### Screenshots / Logs [If applicable].gitignore41 B4274b5191944upstream β
node_modules/ dist/ .env *.log .DS_Storedocker-compose.yml463 B545018b39c2bupstream β
# Home Assistant + Xiaomi Home Integration # Usage: docker compose up -d services: homeassistant: container_name: homeassistant image: ghcr.io/home-assistant/home-assistant:stable privileged: true network_mode: host volumes: - ./config:/config - /etc/localtime:/etc/localtime:ro environment: - TZ=Asia/Shanghai restart: unless-stopped # For Apple Silicon Macs, you may need to add: # platform: linux/arm64LICENSE1.0 KB1809662b5abbupstream β
MIT License Copyright (c) 2026 Nana / OpenClaw Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Plain-text copy, no login: /skill-bundles/canmaxfire-openclaw-xiaomi-home.md