# Ecovacs Pet Control API Reference

**Entry point**: see the parent [SKILL.md](../SKILL.md) for the quick start. **`cmd` must be in the allowlist** (you can temporarily widen it via the env var **`PET_CMD_ALLOWLIST`**). Per-cmd `data` field details follow the gateway / cloud responses.

## Authentication (AK)

The **Access Key (AK)** must be obtained from the Ecovacs Open Platform “Service Overview” (CN `https://open.ecovacs.cn/`, INTL `https://open.ecovacs.com/`).

The AK is parsed by the gateway to perform authentication; the caller only needs to send the request body fields described below.

---

## Gateway interface (recommended)

The gateway address is fixed to the Open Platform domain: CN `https://open.ecovacs.cn/`, INTL `https://open.ecovacs.com/`.

### Device list (GET / POST)

```bash
curl -sS "${BASE_URL}/robot/skill/deviceList?ak=YOUR_AK"
```

On success, `data[]` contains the list of device objects; the `product_category` field can be used to identify **FAMIBOT**.

`POST ${BASE_URL}/robot/skill/deviceList`, `Content-Type: application/json`, body: `{"ak":"<AK>"}`.

### Pet control (recommended): `POST /robot/skill/pet/cmd`

- **Content-Type**: `application/json`
- **Body**:

```json
{
  "ak": "<AK>",
  "nickName": "<fragment fuzzy-matched against nick or name from deviceList>",
  "cmd": "<business command, e.g. getPetState, display>",
  "data": {}
}
```

- **`data`**: can be omitted or `{}` for no-arg commands; otherwise fill in fields incrementally guided by the error messages.
- **`display`**: `data` is the full display payload, e.g.
  `{"msgId":"…","cmd":"action_sequence","data":{"variables":{},"conditions":{},"actions":[…]}}`.
- **Wake guard for display actions**: `scripts/ecovacs.py display ...` checks `getCamera` before sending motion/persona display actions. If the pet is asleep / eyes closed (`enable != 1`), the script first sends `setCamera {"enable":1}` through the same gateway, waits for `getCamera.enable=1`, then sends `setWorkMode {"mode":"standard"}` before the display action.
- **Play sound (high-level wrapper)**: `cmd="playSound"` and `data` carries only the high-level intent (raw `file` is not exposed); the server translates it into a `display` + `play_sound` protocol call.

The request only succeeds when the device is **FAMIBOT**; the URL and field names stay the same regardless.

**Enabling more `cmd`s**: write the allowed `cmd` list (comma-separated) into **`PET_CMD_ALLOWLIST`**, or ask a maintainer to adjust the default allowlist.

### Examples (curl)

```bash
export BASE_URL="https://open.ecovacs.cn"   # CN; for INTL use https://open.ecovacs.com
export AK="YOUR_AK"
```

Query pet state:

```bash
curl -sS -X POST "${BASE_URL}/robot/skill/pet/cmd" -H 'Content-Type: application/json' \
  -d "{\"ak\":\"${AK}\",\"nickName\":\"nickname-fragment\",\"cmd\":\"getPetState\",\"data\":{}}"
```

`display` + `action_sequence` (nod example):

```bash
curl -sS -X POST "${BASE_URL}/robot/skill/pet/cmd" -H 'Content-Type: application/json' \
  -d "{\"ak\":\"${AK}\",\"nickName\":\"nickname-fragment\",\"cmd\":\"display\",\"data\":{\"msgId\":\"1730000000000\",\"cmd\":\"action_sequence\",\"data\":{\"variables\":{},\"conditions\":{},\"actions\":[{\"type\":\"nod_head\",\"angle\":\"20\",\"moveTimeMs\":\"800\",\"count\":\"1\",\"delay\":\"0\",\"ctrlpoint\":\"\"}]}}}"
```

`playSound` (server randomly picks the audio file):

```bash
curl -sS -X POST "${BASE_URL}/robot/skill/pet/cmd" -H 'Content-Type: application/json' \
  -d "{\"ak\":\"${AK}\",\"nickName\":\"nickname-fragment\",\"cmd\":\"playSound\",\"data\":{\"category\":\"happy\",\"count\":10}}"
```

### Compatibility: `POST /robot/skill/ctl`

`ak` + `nickName` + `ctl: { cmd, data }` is still accepted; new integrations should prefer **`/skill/pet/cmd`**.

---

## Interface boundaries

- Device discovery: `/robot/skill/deviceList`
- Pet control: **`/robot/skill/pet/cmd`** (business `cmd` + `data`)
- The `scripts/ecovacs.py` script only calls the gateway paths above.

### Reading responses

Outer payload mainly has `msg` / `code`; the business result shape follows the cloud response.

| Scenario | Direction |
|----------|-----------|
| Outer `code != 0` | Read `msg`; common causes are invalid AK, device not matched, not FAMIBOT, or `cmd` **not in the allowlist** |
| Token errors like **4504** | Check / rotate the **AK** on the Open Platform |
| Permission errors like **3003** | Confirm whether `nickName` matched the target device |
| Device offline / timeout | Check device connectivity and network |

---

## About `data`

Build the request based on the **capability names and `cmd`** described in [SKILL.md](../SKILL.md); the shape of `data` follows the actual error messages returned by the cloud. We recommend starting with the smallest field set and adding fields incrementally.
