# Aqara Agent

> aqara-agent is an official Aqara Home AI Agent skill. It supports natural-language home and space management, device inquiry, device control, ambience_create (氛围创建: apply or compose a named mood in a room or whole home via scene match then lights + optional music), ambience / mood orchestration reference, lighting effect inquiry and control (named lighting presets), device configuration (firmware/OTA upgrade only - not supported: rename devices, move devices between rooms or positions, or other device record edits outside firmware), device logs, scene management (query, execute, create, snapshot, and logs), automation management (create, query, detail, toggle, and logs), and energy / electricity-cost statistics (by device, room, or home). Examples: "How many lights are at home?", "Switch to my other home.", "Turn off the living room AC.", "What are the temperature and humidity in the bedroom?", "氛围创建", "卧室营造温馨居家氛围.", "Whole home sunset vibe.", "What lighting effects or scene modes are available at home?", "Se

- Skill: `aqara/aqara-agent` (Agent Skill, multi-file: 37 files)
- Install (CLI): `npx skillmds@latest add aqara/aqara-agent`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aqara/aqara-agent/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: aqara (https://skillmd.com/u/aqara)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/aqara/aqara-agent

---


# Aqara Smart Home AI Agent Skill

## Basics

### `aqara_open_api.py` CLI

- **Invocation:** `python3 scripts/aqara_open_api.py <method_name> [json_body]`.
- **Must:** first argument equals the **exact** public method name on `AqaraOpenAPI` (see bash examples in `references/*.md`). **Forbidden:** aliases or shortened names unless a reference documents an equivalent.
- **Dispatch:** `get_*` -> no JSON body; `post_*` -> JSON object (optional, default `{}`).
- **Energy:** `post_energy_consumption_statistic` - route from **`device_ids` only** (non-empty -> device API; else position). Fields and NL mapping: `references/energy-statistic.md`.
- **Methods (ground list):** `get_homes`, `get_rooms`, `get_home_devices`, `get_home_scenes`, `get_home_automations`, `get_home_lighting_effects_query`, `post_current_outdoor_weather`, `post_device_base_info`, `post_device_status`, `post_device_control`, `post_device_lighting_effect_query`, `post_lighting_effect_control`, `post_device_firmware_query`, `post_device_firmware_upgrade`, `post_device_log`, `post_execute_scene`, `post_scene_detail_query`, `post_create_scene`, `post_scene_snapshot`, `post_scene_execution_log`, `post_device_related_automation_query`, `post_automation_execution_log`, `post_automation_switch`, `post_create_automation`, `post_energy_consumption_statistic`. **Forbidden** call names not present on `AqaraOpenAPI` unless a reference adds them.
- **`post_create_automation` and `raw_config` (non-negotiable):** **Every** call **Must** send **non-empty** `raw_config` in the HTTP body ([automation-create.md](references/automation-create.md#post-create-raw-config-always)). **Forbidden** to send only `auxiliary_config` or only root-level supplemental `conditions` / `actions` without **non-empty** `raw_config`.
- **`post_create_automation` first round vs follow-up:** **First** call: **non-empty** `raw_config` only; **`auxiliary_config` Must be empty** (omit the argument or pass `{}`). If the response needs config-list matching, use **`LLMConfigReference`** as the **only** source for Step 03 -> **`auxiliary_config`** ([step-03-parse-config-prompt.md](references/automation-create-workflow/step-03-parse-config-prompt.md)). **Second and later** calls: **Must** resend the same **non-empty** `raw_config` **and** attach **`auxiliary_config`** ([Step 3 supplement](references/automation-create.md#step-3b-auxiliary-config)). `scripts/aqara_open_api.py` **shallow-merges** `raw_config` and `auxiliary_config` into one JSON when both are passed.
- **Optional env:** `AQARA_OPEN_HTTP_TIMEOUT` (default 60), `AQARA_OPEN_API_URL` (overrides disk). **Optional disk:** `assets/user_account.json` keys `aqara_open_api_url` or `open_api_url` (full base, no trailing slash required) when env is unset — requests use `{base}/{path}` (e.g. `homes/query`).

## Skill Package Layout

Relative to the **skill root** directory (Cursor project: **`.cursor/skills/aqara-agent/`**; other layouts: **`skills/aqara-agent/`**). **Normative:** this file + `references/*.md` (including **`references/ambience.md`** for **`ambience_create`（氛围创建）**, mood orchestration, and lighting-preset paths) + `references/scene-workflow/*.md` where scene applies + `references/automation-workflow/*.md` where automation applies (**includes** `recommend.md` for **recommend-style automation -> example NL -> create**) + `references/automation-create-workflow/*` for **`post_create_automation`** (see `references/automation-create.md`). Optional **`README.md`** (human index only) when present in a pack; **Forbidden** treat it as overriding `SKILL.md`.

| Path | Purpose |
|------|---------|
| `SKILL.md` | This document. |
| `README.md` | Optional human index in some packs; **Forbidden** treat as overriding `SKILL.md`. |
| `assets/login_reply_prompt.json` | Locales, `official_open_login_url`, `login_url_policy`. |
| `assets/user_account.example.json` | Template shape. |
| `assets/user_account.json` | Live session (sensitive). |
| `assets/device_control_action_table.csv` | Normative `attribute` / `action` / `value` mapping for control and scene slots (`devices-control.md`, scene workflows). |
| `references/*.md` | Per-domain procedures (account, home-space, devices inquiry/control/config, **[ambience.md](references/ambience.md)** — **`ambience_create`（氛围创建）** + inquiry / thin preset, scenes index, automations, energy, weather). |
| `references/scene-workflow/*.md` | Scene sub-workflows; enter via `references/scene-manage.md`. **Files (scan):** `list.md` (catalog `#catalog-list` + `#scenes-by-device`), `execute.md`, `recommend.md`, `create.md`, `snapshot.md`, `execution-log.md`, `failure-response.md`, `appendices.md`. |
| `references/automation-workflow/*.md` | Automation sub-workflows; enter via `references/automation-manage.md`. **Files (scan):** `list.md` (catalog `#catalog-list` + by-device `#by-device`), `toggle.md`, `execution-log.md`, `failure-response.md`, **`recommend.md`** (recommend-style automation -> example NL -> create; **Forbidden** `post_automation_recommend_query`). |
| `references/automation-create-workflow/` | NL -> `raw_config` -> create; **Files (scan):** `manifest.json`, `step-01-conditions-actions-extract.md`, `step-02-cell-info-fill.md`, `step-03-parse-config-prompt.md`. |
| `scripts/aqara_open_api.py` | CLI + HTTP client. |
| `scripts/save_user_account.py` | Writes `aqara_api_key`. |
| `scripts/runtime_utils.py` | Shared helpers. |
| `scripts/requirements.txt` | Dependencies. |

## Core Workflow

**deps -> sign-in -> pick home -> intent -> `references/*.md` -> summarize**

## Ground Truth (Binding)

**Forbidden** stating or implying as factual: homes, rooms, devices, capabilities, attributes, counts, logs, or control outcomes, except from **executed** skill scripts + real API responses or skill-accepted user input (e.g. pasted `aqara_api_key`). If that flow **has not** succeeded, **Forbidden** any factual claim about those entities.

**Forbidden** demo-style lists, guessed layouts, synthetic values, fake success after errors/timeouts/missing auth, or prose/JSON mimicking API output without a real response.

**Must** state missing data and cause (e.g. not signed in, API error), then auth/retry/`references/`. **Forbidden** imagined padding.

---

Execute in order:

### 1. Environment
```bash
export AQARA_OPEN_HOST=agent.aqara.com
```

```bash
cd .cursor/skills/aqara-agent   # Cursor project layout (repo root)
# cd skills/aqara-agent         # upstream pack layout
pip install -r scripts/requirements.txt
```

### 2. Auth

- **Must** confirm `user_account.json` readable/writable before features; host/project rules may require reading it first.
- **Must** follow `references/aqara-account-manage.md` (switch-home vs re-login, token save, Step 1 login copy).
- **Must** read `assets/login_reply_prompt.json` on every login guidance turn. **Must** set the user-facing login link to the **exact** `official_open_login_url` string (`login_url_policy`). **Forbidden** invent Open Platform / `sns-auth` / `client_id` / `redirect_uri` URLs from memory.
- Locale from JSON for the user's language; unknown -> `en` (`fallback_locale` / `default_locale`). **Must** deliver the **single-line** login URL per `references/aqara-account-manage.md`.

`user_account.json`:

```json
{
  "aqara_api_key": "",
  "updated_at": "",
  "home_id": "",
  "home_name": ""
}
```

### 3. Home Management

- **Must** after saving `aqara_api_key` run `references/home-space-manage.md` step **0** immediately (fetch homes; one home -> write; many -> **show the complete home list** + remind user to **choose one**, then user picks). **Forbidden** reply only "send home name" without running fetch or without listing all homes when many.
- **Must** run `save_user_account.py` and `aqara_open_api.py get_homes` as **two separate** invocations. **Forbidden** `&&` on one shell line (`aqara-account-manage.md` step 2, `home-space-manage.md` step 0).
- **Switch home:** **Must** re-fetch homes, show the **complete** list, remind user to **pick one**, then persist (`home-space-manage.md`). **Forbidden** default to re-login. **Must** use `aqara-account-manage.md` login only if the user demands re-login/token rotation or the API signals expired/unauthorized.

### 4. Intent

Categories: space, device query, device control, **`ambience_create`（氛围创建）**, ambience inquiry / thin lighting preset, device configuration, scene, automation, energy. **Multiple intents:** **Must** query before control or configuration, in utterance order.

| Intent | `AqaraOpenAPI` methods (details in reference) | Reference |
|--------|-----------------------------------------------|-----------|
| Space | `get_homes`, `get_rooms` | `references/home-space-manage.md` |
| Device query | `get_home_devices`, `post_device_status`; optional `post_device_base_info`, `post_device_log`, `post_device_firmware_query` (firmware version read) | `references/devices-inquiry.md` (incl. **User-facing wording**: say **device**, not **endpoint**; **`endpoint_id` / `device_ids`** vs. multi-channel hardware) |
| Device control | `post_device_control` - **immediate only** (generic attributes; **not** named lighting presets) | `references/devices-control.md` + `assets/device_control_action_table.csv` — **`ambience_create` / 氛围创建** → **Ambience create** row + [ambience.md](references/ambience.md); thin lamp preset only → **Fast path** in [ambience.md](references/ambience.md#fast-path-lighting-preset-inquiry-only). If NL is **scheduled / delayed device control** (not immediate), use **create automation** - see **Automation** row. |
| **Ambience create** (`ambience_create` / **氛围创建**) | User **applies or creates** a named mood for a room or whole home (**Must** [Workflow](references/ambience.md#ambience-workflow) + [LightingEffectAgent](references/ambience.md#lighting-effect-agent) in [ambience.md](references/ambience.md)): **`get_home_scenes`** (+ **`post_scene_detail_query`**) → scene match (default **≥0.85**) → **`post_execute_scene`** **or** composite **`MOOD_PRESETS`** → **`fuzzy_device_batch_control`** (Sec. **4b** only: lights **off** in Sec. 1 **`position_id`(s)**) → **`mood_device_batch_control`** ∥ **`music_on_demand`** (Sec. **4c**–**4d**) → **`get_home_lighting_effects_query`** → **`post_lighting_effect_control`** (Sec. **4e**). **Logical:** `scene_base_inquiry`, `music_on_demand`. **Persist save:** [ambience.md — Save scene payload](references/ambience.md#save-scene-payload) → **`post_create_scene`** only; **Forbidden** route through [scene-workflow/create.md](references/scene-workflow/create.md) (保存见 ambience.md，勿路由到 create.md). NL e.g. 氛围创建、营造/来个××氛围、全屋落日感. | [ambience.md](references/ambience.md) |
| **Ambience inquiry & lighting presets** | **Not** `ambience_create`: list lamp presets (`get_home_lighting_effects_query`, `post_device_lighting_effect_query`); **Fast path** thin **`post_lighting_effect_control`** only — [ambience.md#fast-path-lighting-preset-inquiry-only](references/ambience.md#fast-path-lighting-preset-inquiry-only). | [ambience.md](references/ambience.md) |
| Device configuration | `post_device_firmware_upgrade` - **Firmware/OTA only** - [Firmware-only scope](references/devices-config.md#firmware-only-scope) | `references/devices-config.md` |
| Scene | `get_home_scenes`, `post_execute_scene`, `post_create_scene`, `post_scene_snapshot`, `post_scene_detail_query`, `post_scene_execution_log`; **`post_current_outdoor_weather`** - **only** [Scene recommend workflow](references/scene-workflow/recommend.md) step 7 **Leaving home** before control (`references/weather-forecast.md`); **Forbidden** elsewhere. Recommend path uses `post_device_control` unless **Create scene** applies. Catalog list + `post_scene_detail_query`: [list.md](references/scene-workflow/list.md) (`#catalog-list`, `#scenes-by-device`) | `references/scene-manage.md` (index); `references/weather-forecast.md`; other steps in `references/scene-workflow/*.md`. If NL is **scheduled / delayed catalog scene control** (not immediate catalog scene run), use **create automation** - see **Automation** row. |
| Automation | `get_home_automations`, `post_device_related_automation_query`, `post_automation_switch`, `post_automation_execution_log`, **`post_create_automation`** | [automation-manage.md](references/automation-manage.md) (list / toggle / logs / **direct** create when the user already has an executable rule). **Recommend automation** (situational help, example sentences, then create): [automation-workflow/recommend.md](references/automation-workflow/recommend.md) only; **Forbidden** `post_automation_recommend_query`. **Create automation** (including NL classified as scheduled / delayed **device** control or scheduled / delayed **catalog scene** control, not immediate `post_device_control` / `post_execute_scene`): [automation-create.md](references/automation-create.md) + [automation-create-workflow/](references/automation-create-workflow/). Catalog and by-device: [list.md](references/automation-workflow/list.md); toggle and logs: same as first column. |
| Energy | `post_energy_consumption_statistic` | `references/energy-statistic.md` |

- **Composite `device_type`:** `get_home_devices` rows (and `device_types` filters on batch calls such as `post_device_status`) may use **comma-separated** `device_type` strings (e.g. `Switch,Button,Light`). **Must** classify and count by **token presence**: **`Light`** in the composite string means the **listed device** is still a **light-class** device for listings and counts (wall switches that control lighting included). **Must** apply the **same rule** to **air conditioners**, **curtains** (`WindowCovering`), **fans** (e.g. `IRDevice,Fan`), and other families — if the category token appears in the composite type, treat the **listed device** under that category for inquiry, filters, and summaries. User-facing list/count nouns: [devices-inquiry.md](references/devices-inquiry.md#user-facing-device-wording).

**Recommend automation (automation path):** If the user wants **situational ideas** and has **not** given one create-ready rule sentence, **Must** run [automation-workflow/recommend.md](references/automation-workflow/recommend.md) steps **0-5** (scope gate in **§0**: if neither position nor device, **`get_rooms`** + position list only — **no** examples same turn; else **`get_rooms`**, scoped **`get_home_devices`**, **`get_home_scenes`**, mandatory **`post_device_status`**, optional **`post_device_base_info`**, optional **`get_home_automations`**). **Forbidden** `post_automation_recommend_query` and platform "template name" strings as data. **User-facing reply:** success vs error format and id redaction -> that doc **§5** (§5.2: localized lead-in line matching the user's input language + numbered lines `1.` through `10.` (digit + ASCII period only) on success; on error, detail only, **no** home/device/position/scene/automation **ids**). After the user **selects or rewrites** one example line, **Must** continue with [automation-create.md](references/automation-create.md) and **`post_create_automation`** (non-empty `raw_config` on every call; `LLMConfigReference` handling per that doc and step-03).

### 5. Route and Summarize

**Must** open the matching `references/` doc, run scripts, summarize from **actual** output only. **Forbidden** fabricate success or any home/room/device/state not in script/API output (**Ground truth**).

### Illustrative CLI JSON (Agents Only)

**Forbidden** paste these raw blocks to end users.

REST shape (skeleton):

```json
{
  "code": 0,
  "message": "",
  "data": {}
}
```

### Error Handling

| Situation | Action |
|-----------|--------|
| Device not found | **Must** state no match; **allowed:** short candidate list. |
| Capability unsupported | **Must** state unsupported; **Forbidden** imply success. |
| Home/room not found | **Must** state no hit; **Must** direct next step via `references/` (re-fetch or verify home). |
| Multiple device matches | **Must** list matches; **Must** one disambiguation question (room or full name). |
| Not signed in / empty `aqara_api_key` | **Must** login + save per `references/aqara-account-manage.md`, then homes. `MissingAqaraApiKeyError` -> same. |
| No home selected | **Must** `references/home-space-manage.md`. No `home_id` -> `homes/query`; one home -> auto-write; many -> show **full** home list + **choose one** prompt, then `home_selection_required`. |
| Bad token / auth | **Must** re-login / refresh (no secret leak). **Forbidden** treat **home switch** as auth failure unless home-list returns auth error. `unauthorized or insufficient permissions` (or equivalent) -> **Must** re-login per `references/aqara-account-manage.md`; **Forbidden** fake success. |
| Control path blocked | **Must** say device found, command not sent. |
| Firmware / configuration path blocked | **Must** say device found, upgrade or config action not sent; **Must** `references/devices-config.md`. |
| Other | **Must** short summary + retry/`references/`; **Forbidden** internal URLs or full headers. |
| Indeterminate | **Must** use `references/` + script output; confirmed bug -> **Must** file skill issue. |
| Empty API data | **Forbidden** invent entities/readings; **Must** re-run or report failure (**Ground truth**). |
| HTTP / network | **Forbidden** treat as success; **Must** retry or brief explanation; **Forbidden** raw stacks. |

## Notes

1. **Forbidden** raw IDs in user text (device, position, `home_id`, ...). **Exception:** `automation_id` **allowed** if server desensitized virtual ID.
2. After layout changes, if match fails: **Must** re-fetch space + devices (`references/home-space-manage.md`, `references/devices-inquiry.md`), retry.
3. User replies: **Must** conclusion first, then detail; **Must** <= one clarification question.
4. **Session gate:** unsigned -> **Must** end on setup; **Forbidden** imply control ran.
5. **Must** run `scripts/*.py` automatically when required (stricter host policy wins).
6. Account/home change: **Must** update `user_account.json` and re-run [`references/aqara-account-manage.md`](references/aqara-account-manage.md).
7. **Forbidden** echo tokens/headers; **Must** treat `user_account.json` and caches as sensitive.
8. Multiple fuzzy name hits: **Must** user confirm.
9. User-visible: **Forbidden** shell, paths, raw stdout, debug JSON, `references/` filenames; **Must** plain summary.
10. Control OK: **Must** brief close; **Forbidden** preemptive hedging; fix only after user reports failure.

## Out of Scope

**Fully unsupported** (no API in this skill; point users to **Aqara Home app** when relevant):

- **Cameras** - live view / playback.
- **Locks** - unlock / lock-unlock.
- **Shortcuts** (e.g. Siri lists) - **Must** point to **Aqara Home app**.
- **Weather** - general forecasts and Q&A; **exception:** `post_current_outdoor_weather` **only** in [recommend.md](references/scene-workflow/recommend.md) step 7 **Leaving home** before control - see [weather-forecast.md](references/weather-forecast.md); **Forbidden** for Create scene, snapshot, run catalog scene, logs, or any other flow.
- **Entertainment** - beyond [devices-control.md](references/devices-control.md); **exception:** mood **music** only as **`music_on_demand`** inside [ambience.md](references/ambience.md) composite **Sec. 4** when the product implements it.

**Limited to documented workflows** (no app-only or undocumented features):

- **`ambience_create`（氛围创建）** - **only** [ambience.md](references/ambience.md) full workflow (ordered Sec. 1–4 + Result); **Ambience inquiry & thin preset** - **only** [ambience.md](references/ambience.md) fast path + listed APIs.
- **Scenes** - **only** procedures in [scene-manage.md](references/scene-manage.md) and `references/scene-workflow/*.md` (e.g. `list.md`, `execute.md`, `recommend.md`, `create.md`, `snapshot.md`, `execution-log.md`, `failure-response.md`, `appendices.md`).
- **Automations** - **only** procedures in [automation-manage.md](references/automation-manage.md) and `references/automation-workflow/*.md` (`list.md`, `toggle.md`, `execution-log.md`, `failure-response.md`, `recommend.md` for recommend-then-create, plus [automation-create.md](references/automation-create.md) and `references/automation-create-workflow/*` for **`post_create_automation`**).

**When** the user asks outside the above: **Must** say unsupported (or not yet); **Must** direct to **Aqara Home app** if the app covers it.

