# Camera API

> 摄像头设备与云事件 API 技能。用于查询设备列表、根据设备名解析 device_id、查询设备最新封面图、查询设备在线状态、按天查询或汇总云事件、查询单个事件详情，以及在需要最新画面时向设备发送截图指令并轮询结果。当用户要求查看某个摄像头当前画面、最新封面、在线状态、今天/昨天/某天/最近几天发生了什么、某个事件详情，或只知道设备名称不知道 device_id 时使用。

- Skill: `leoyeai-openclaw-master-skills/camera-api` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add leoyeai-openclaw-master-skills/camera-api`
- Raw SKILL.md: https://api.skillmd.com/api/skills/leoyeai-openclaw-master-skills/camera-api/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: LeoYeAI (https://skillmd.com/u/leoyeai-openclaw-master-skills)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/leoyeai-openclaw-master-skills/camera-api

---


# Camera API

通过探鸽云端 API 完成设备解析、接口选路、云事件归纳和截图轮询，并将结果整理成面向用户的答案。优先返回设备状态、事件摘要和图片内容，不直接回传原始签名图片 URL 或未整理的接口响应。

## 硬性约束

### 认证与地址

- 所有请求都使用 `https://openapi-cn01.tange365.com/`。
- 所有请求都带上以下请求头：

```http
Authorization: Bearer $TIVS_API_KEY
X-Tg-App-Id: $TIVS_APP_ID
Accept-Language: zh-CN
X-Tg-Platform: pc
Content-Type: application/json
X-Tg-SDK-VERSION: 216
```

- 只使用环境变量 `TIVS_API_KEY` 和 `TIVS_APP_ID`。不要在技能内容、代码或回复里硬编码任何凭据或用户私密信息。
- 默认按上面的 `X-Tg-Platform: pc` 发请求；如果当前运行环境已经通过 SDK 自动注入 `web`，沿用运行时默认值，不要同时发送两个不同的 `X-Tg-Platform`。
- 这些都是云端 API。通过局域网模式添加、直连的设备，不适用本技能里的云端查询接口。
- `https://openapi-cn01.tange365.com/` 只是 API 服务地址，不是创建 `AppID` 或 `api_key` 的入口页面。

### 凭据缺失处理

- `AppID` / `api_key` 的获取页面可能因客户 APP 名称、APP 账号体系不同而不同，不要假设所有用户共用同一个入口页面。
- 只能按用户当前使用的 APP 名称来识别对应页面，不要尝试按品牌名推断，因为同一个 APP 里可能包含多个品牌。
- 已知映射：
  - `icam365` APP 账号：`https://skill.webcamapp.cc/icam365/api-key`
  - `wosee` APP 账号：`https://skill.webcamapp.cc/wosee/api-key`
- 如果首次聊天里已经提到当前 APP 对应的获取页面，把这个页面记为固定上下文，后续缺少 `TIVS_API_KEY` 或 `TIVS_APP_ID` 时优先复用。
- 缺少凭据时，不要让用户直接把他人的密钥贴给你，也不要猜测或替换成 API Base URL、demo 地址、文档地址，更不要臆造一个 APP 页面 URL。
- 标准提示动作：
  1. 明确指出缺少的是 `TIVS_API_KEY`、`TIVS_APP_ID`，还是两者都缺失。
  2. 先确认用户当前使用的 APP 名称；如果上下文里已经明确，就不要重复追问。
  3. 若 APP 命中已知映射，直接给出对应的 API Key 获取页面。
  4. 若 APP 未命中已知映射，但首次聊天里给过该 APP 页面，就复用首次聊天里的页面。
  5. 若 APP 未知或当前上下文里没有该 APP 页面，就明确让用户补充“当前使用的 APP 名称”或提供该 APP 的官方 API Key 获取页面。
  6. 提醒用户在对应页面创建应用并获取 `AppID` 和 `api_key`，再配置到当前运行环境。
- 当用户只说“没有 API Key”但没说自己用的是哪个 APP 时，先追问 APP 名称，例如 `icam365`、`wosee`，再给页面。

### 响应判断

- 将 `code = 0` 或 `code = 200` 视为成功。
- 失败时优先向用户解释失败原因或缺失条件，不要伪造结果。
- 对于没有完整字段文档支撑、或运行时字段结构不稳定的接口，只提取响应里实际存在的字段，不要臆造字段名。
- 云事件相关接口的常见字段并不完全一致，读取时优先兼容这些实际字段：`id`、`time`、`thumbnail`、`image`、`image_path`、`tag.tag`、`tag.name`、`tag.msg`、`can_play`、`summary`。

### 图片与隐私

- 图片 URL 往往带签名参数，必须使用完整 URL 才能访问。
- 不要把原始签名图片 URL 直接发给用户。优先下载图片内容后再展示。
- 如果当前执行环境不能直接下载图片，就明确说明无法直接展示图片，不要把签名 URL 当作最终答案返回。

### 参数处理

- 当用户只提供设备名称、备注名或模糊描述时，先调用设备列表接口定位 `device_id`。
- 只有明确支持多设备的接口才传入逗号分隔的 `device_id` 字符串；按天事件接口和事件详情接口按单设备、单事件处理。
- 用户说“今天”“昨天”“某天”时，先换算成明确日期，再调用按天事件接口。日期格式一律使用 `YYYY-MM-DD`。
- 用户未给日期，但问题是“发生了什么”“帮我总结事件”等日级查询时，默认按今天处理，并在回复里带上解析后的日期。
- 用户要求“最近几天”“一段时间内”的事件时，按天拆分成多次单日查询后再汇总，不要臆造不存在的范围 REST 接口。
- 用户要“实时画面”时，将其理解为“触发一次截图并等待设备上报结果”，不是实时视频流。

### 路径与方法严格匹配

- 只能使用本技能已明确列出的 HTTP 方法和接口路径；不要根据命名习惯自行臆造相似路径。
- 截图工作流里，发送截图指令的唯一路径是 `POST /v2/msg/directive/device/{device_id}`；查询抓拍结果的唯一路径是 `GET /v2/cloud/screenshot/{device_id}`。
- `POST /v2/device/thumbnail` 只是查询封面图，不是抓拍结果接口；不要把它和 `GET /v2/cloud/screenshot/{device_id}` 混用。
- 明确禁止写成 `GET /v2/device/screenshot/{device_id}`、`POST /v2/device/screenshot/{device_id}`，或任何未在本文档出现的 screenshot 变体路径。
- 如果请求返回 `404`、`405` 或 `501`，先逐字检查方法和路径是否与本文档一致，再决定是否回退到备用接口；不要在错误路径上重复重试。

## 任务路由

- 查询设备列表、根据名称找设备 ID：`POST /v2/device/list`
- 查询设备最新封面图，不唤醒设备：`POST /v2/device/thumbnail`
- 查询设备在线状态：`POST /v3/device/online`
- 查询某个设备某一天的云事件：`GET /v2/cloud/events/{device_id}/{date}`
- 分页查询某天云事件、按标签过滤、为截图轮询找新增事件：`POST /v2/cloud/event`
- 查询单个云事件详情：`GET /v2/cloud/event/{event_id}`
- 查询设备当前最新画面：先 `POST /v2/msg/directive/device/{device_id}` 发送截图指令，再优先 `GET /v2/cloud/screenshot/{device_id}` 或回退到当天云事件查询获取最新截图

## 执行顺序

### 1. 解析设备

当请求里没有可靠的 `device_id` 时：

1. 调用设备列表接口。
2. 优先按 `device_name` 精确匹配，再做保守的包含匹配。
3. 如果第一页不足以唯一定位，而响应里显示还有更多设备，继续翻页，直到唯一命中或穷尽列表。
4. 如果匹配到多个候选，先向用户澄清，不要随意选择。
5. 如果用户一次指定多个设备，为支持批量的接口整理成逗号分隔的 `device_id` 字符串；不支持批量的接口逐个调用。

### 2. 选择接口

- 要“最新封面”“最近一张图”“不打扰设备看下最新画面”，优先用封面图接口。
- 要“当前是否在线”“能不能连上”“设备是否在休眠”，用在线状态接口。
- 要“今天发生了什么”“某天事件列表”“帮我总结当天事件”，用按天事件接口。
- 要“分页看事件”“只看某类 tag”“抓拍后找刚刚新增的事件”，用 `POST /v2/cloud/event`。
- 要“这个事件详情”“这个 event_id 是什么”，用事件详情接口。
- 要“现在拍一张”“看实时画面”“立即截图”，先发截图指令，再优先查 `GET /v2/cloud/screenshot/{device_id}`，必要时才回退到当天事件。

### 3. 处理截图轮询

触发截图后按下面流程执行：

1. 记录发起截图时的当前时间，作为本次操作的时间基线。
2. 向 `/v2/msg/directive/device/{device_id}` 发送 `save_video` 指令。
3. 指令成功后必须先等待 3 秒，再查询抓拍结果；否则设备可能还没有完成上报。
4. 优先用 `GET /v2/cloud/screenshot/{device_id}` 获取最新抓拍结果；方法和路径都要逐字匹配，不要改写成 `/v2/device/screenshot/{device_id}` 或其他变体。
5. 只有当该接口返回的图片时间晚于时间基线，或能明确判断为本次新上报结果时，才把它当作本次截图结果。
6. 如果该接口只返回旧截图、没有可用时间字段、或无法确认新鲜度，则回退到 `POST /v2/cloud/event` 查询当天事件。
7. 在事件列表里优先选择时间晚于时间基线，且满足 `tag.tag == "screenshot"` 的最新事件；如果没有 `tag.tag`，再看 `tag.name` 或 `tag.msg` 是否表示截图。
8. 如果接口没有明确的截图标签，则选择时间晚于时间基线、且最可能由本次操作产生的新增事件。
9. 如果第一次还没有新截图，再等 2 秒重试，最多额外重试 2 次。
10. 超过重试次数仍没有结果时，明确告诉用户设备还没有上报新的截图结果。

不要无限轮询。

## 输出规范

- 列设备时，优先给出 `device_name`、`device_id`、是否主人、绑定时间、联网方式等关键信息。
- 查封面图或截图结果时，优先直接展示图片内容；若无法展示，说明原因并保留事件摘要。
- 查在线状态时，先以顶层 `is_online` 作为设备整体是否在线的最终结论，再分别解释 `register_status.is_online`、`dormant_status.is_alive`、`rtc_status.is_online` 等子系统状态；子系统状态只能补充说明连接形态，不能单独推翻顶层在线结论。如果顶层 `is_online` 缺失，再明确说明整体结论未知，并列出已返回的各子系统状态。
- 查事件列表时，先自行按 `time` 倒序整理，再将 Unix 秒级时间戳转为可读时间，必要时结合 `tag`、`summary`、图片信息做简短总结。
- 查事件详情时，提取事件时间、类型、图片、摘要等关键信息。
- 对“今天”“昨天”等相对时间，向用户回复时优先带上解析后的明确日期，避免歧义。
- 用户要求总结某天事件时，基于该天全部事件做总结，不要只返回原始 JSON。
- 用户要求总结最近几天事件时，先按日期分组，再在每个日期内按设备归纳，最后给出跨天总结。

## 接口说明

### 查询设备列表

当需要列出设备或根据设备名解析 `device_id` 时，调用：

```http
POST /v2/device/list
```

请求体示例：

```json
{
  "offset": 0,
  "limit": 10,
  "name": "我的门铃",
  "device_id": ""
}
```

请求参数说明：

- `name`：按设备名称过滤，适合用户只提供设备名称、备注名或模糊名称时使用。
- `device_id`：按设备 ID 过滤，适合已经知道精确设备 ID 时使用。
- `offset` / `limit`：分页参数。

优先从响应中读取：

- `device_id`
- `device_name`
- `is_owner`
- `connect_way`
- `extend.bind_time`
- `total`
- 当用户给的是设备名称时，可优先用 `name` 做初筛，再对返回项做精确匹配。
- 若 `total` 大于当前已取回的数量，而设备仍未唯一匹配，继续翻页。

### 查询设备封面图

当用户想看设备最近一张画面，但不要求立刻唤醒设备时，调用：

```http
POST /v2/device/thumbnail
```

请求体示例：

```json
{
  "device_id": "678A7QP6Q5WD"
}
```

说明：

- 支持传单个或多个 `device_id`，多个设备用逗号分隔。
- 为稳妥起见，单次批量最多处理 10 个设备；超过 10 个时分批查询。
- 封面图来自设备最新上报事件截图，适合“快速看一眼”。
- 只从响应中提取实际存在的图片和设备标识字段。

### 查询设备在线状态

当用户想知道设备是否在线、是否在工作、是否休眠、是否可用 RTC 连接时，调用：

```http
POST /v3/device/online
```

请求体示例：

```json
{
  "device_id": "678A7QP6Q5WD"
}
```

说明：

- 支持传单个或多个 `device_id`，多个设备用逗号分隔。
- 关注四类状态：整体在线、register 在线、休眠在线、RTC 在线。
- 返回结构是分层的：顶层 `is_online` 是设备整体在线状态的最终判断。用户问“设备在线吗”时，先回答这个结论。
- `register_status.is_online`、`dormant_status.is_alive`、`rtc_status.is_online` 分别表示长连接、休眠子系统、RTC 子系统的状态，用于解释整体状态来源和可用链路。
- 即使 `register_status.is_online` 为 `false`，只要顶层 `is_online` 为 `true`，仍应回答“设备整体在线”，再补充说明当前是哪个子系统在线、哪个子系统不在线。
- 只有当顶层 `is_online` 缺失时，才退化为分别报告各子系统状态，并明确说明“整体在线状态未知”。
- 如果接口返回更细字段，以实际字段为准进行解释；但不要让任何单个子系统状态覆盖顶层 `is_online` 的整体结论。

### 查询某天云事件

当用户要查询今天或某一天的事件列表时，调用：

```http
GET /v2/cloud/events/{device_id}/{date}
```

路径参数：

- `device_id`：单个设备 ID
- `date`：`YYYY-MM-DD`

说明：

- 事件通常包含时间、图片、标签，以及可能存在的 AI 总结摘要。
- 当用户要求“总结今天发生了什么”，先拉取该日事件，再基于 `tag` 和 `summary` 归纳。
- 如果用户要求汇总多个设备的同一天事件，对每个设备分别调用该接口，再合并结果。
- 如果用户要求最近几天的事件，对每一天分别调用该接口，再按日期汇总。
- 当天没有事件时，明确告诉用户“这一天没有查询到云事件”。
- 常见字段包括 `id`、`time`、`thumbnail`、`image`、`tag.tag`、`tag.name`、`tag.msg`、`can_play`。

### 分页或按标签查询某天云事件

当你需要分页、按标签过滤事件，或为截图轮询查找新增事件时，调用：

```http
POST /v2/cloud/event
```

请求体示例：

```json
{
  "device_id": "678A7QP6Q5WD",
  "tag": ["screenshot"],
  "date": "2026-03-21",
  "offset": 0,
  "limit": 10
}
```

说明：

- `tag` 可以留空数组，表示不过滤事件类型。
- 当需要更快定位截图结果时，优先把 `tag` 收窄到截图相关值。
- 该接口在现有 demo 中用于分页和标签过滤，比按天 GET 接口更适合轮询。
- 若非首页查询时 `offset > 0` 且返回空列表，视为没有更多数据。
- 成功响应中常见 `response.data.items` 数组，可继续读取 `time`、`thumbnail`、`image`、`tag`、`can_play` 等字段。

### 查询事件详情

当用户提供 `event_id` 或要求查看某条事件详情时，调用：

```http
GET /v2/cloud/event/{event_id}
```

说明：

- 提取事件时间、图片、标签、摘要等关键信息。
- 若接口返回 `detail.msg`、`detail.categoryName`、`containsVideo`、`storageId` 等详情字段，优先利用这些字段补充说明。
- 如果包含图片，遵守图片 URL 处理规则，不要直接回传签名 URL。

### 查询最新抓拍结果

当截图指令已经发送，且当前环境提供专门的抓拍结果查询接口时，调用：

```http
GET /v2/cloud/screenshot/{device_id}
```

说明：

- 这是截图工作流里的优先查询接口，现有 demo 已使用它读取抓拍结果。
- 这是查询抓拍结果时唯一允许直查的接口，方法固定为 `GET`，不要改写成 `/v2/device/screenshot/{device_id}` 或其他 `/v2/device/*` 路径。
- 常见结果结构为 `response.data.items`，图片字段常见为 `image_path`。
- 返回 `200` 不代表一定拿到了本次新截图；要优先结合 `time`、`created_at`、`create_time` 等时间字段，确认图片晚于截图指令的时间基线。
- 如果该接口只返回旧图片、没有时间字段，或无法确认是不是本次新结果，就按“没有返回可用图片”处理。
- 如果该接口返回 `404`、`405` 或 `501`，先检查自己是否把方法或路径写错了；确认无误后，再判断当前环境是否不支持该接口。
- 如果该接口不可用或没有返回可用图片，再回退到 `POST /v2/cloud/event`。

### 发送截图指令

当用户明确要求“现在拍一张”“看当前画面”时，调用：

```http
POST /v2/msg/directive/device/{device_id}
```

请求体示例：

```json
{
  "directive": "save_video",
  "reactive": false,
  "data": ""
}
```

说明：

- 该接口只负责触发抓拍，不直接返回图片。
- 该接口按单个 `device_id` 调用；如果用户要多个设备的当前画面，逐个设备执行。
- 发送截图指令后必须先等待 3 秒，再去查询抓拍结果或当天事件；否则设备可能还没有完成上报。
- 如果用户没有特别要求，默认使用普通截图参数。
- 除非当前执行环境已经确认过高清截图参数的准确格式，否则不要自行扩展 `data` 字段结构。

## 常见任务模板

### 查看某个设备今天发生了什么

1. 如无 `device_id`，先查设备列表。
2. 将“今天”换算为明确日期。
3. 调用按天事件接口。
4. 提取关键事件并总结。

### 查看多个设备某一天发生了什么

1. 将目标设备解析为多个 `device_id`。
2. 对每个设备分别调用按天事件接口。
3. 按设备汇总结果，再给出跨设备总结。

### 查看某个设备最近几天发生了什么

1. 如无 `device_id`，先查设备列表。
2. 将时间范围拆成多个单日日期。
3. 对每一天分别调用按天事件接口。
4. 先按日期总结，再给出跨天结论。

### 查看某个设备现在的画面

1. 如无 `device_id`，先查设备列表。
2. 发送截图指令。
3. 优先查 `GET /v2/cloud/screenshot/{device_id}`，失败再按轮询流程查当天事件。
4. 返回最新截图结果，不直接返回签名 URL。

### 批量查看多个设备在线状态

1. 将多个 `device_id` 组装为逗号分隔字符串。
2. 调用在线状态接口。
3. 按设备逐个汇总状态，先给整体在线结论，再补充 register、休眠、RTC 等子系统状态。

### 批量查看多个设备最新封面

1. 将多个 `device_id` 组装为逗号分隔字符串。
2. 调用封面图接口。
3. 按设备提取最新封面结果。

## 失败场景处理

- 没有 `TIVS_API_KEY` 或 `TIVS_APP_ID`：明确提示缺少环境变量；先识别用户当前 APP 名称，再引导他去对应 APP 的 API Key 页面创建应用并获取 `AppID` 与 `api_key`。
- 设备属于局域网模式或直连设备：说明这些云端 API 不适用，不能用本技能直接查询。
- 设备名无法唯一匹配：先向用户确认设备。
- 查询某天事件为空：直接说明该天没有事件，不要当成系统错误。
- 截图指令成功但迟迟没有新事件：说明设备还未上报结果或当前不在线。
- 抓拍结果查询返回 `404`、`405` 或 `501`：先检查是否误写成 `/v2/device/screenshot/{device_id}`、是否把 `GET` 写成了其他方法；只有确认路径和方法都正确后，才判断接口本身不可用并回退到 `POST /v2/cloud/event`。
- 在线状态字段看起来互相矛盾：以顶层 `is_online` 作为整体结论，再说明各子系统状态可能处于切换瞬间；不要因为某一个子系统离线就误判整体离线。
- 接口返回未知字段结构：只总结已确认字段，不要杜撰字段含义。

