iotsaas/docs/10寸中控屏/05-评审回复与落地方案.md
2995840376 0ce191c448 chore: 初始化 iotsaas 版本库基线
纳入范围:
- backend/  Spring Boot 多模块后端(iot-common/device/rule/data/alarm/auth)
- frontend/admin/  Vue3 + Element Plus 管理后台
- Android/   涂鸦原生 APP (com.xhai.iot)
- backend/sql/  Flyway 风格迁移脚本(V2~V21)
- docs/       对接文档与设计文档

排除范围:
- 构建产物: node_modules/ target/ build/ dist/ .gradle/
- 签名密钥: *.jks *.keystore (严禁入库)
- 本机配置: Android/local.properties
- 运行日志: logs/ *.log
- AI 协作本地数据 .codebuddy/ 与第三方 demo tuya-demo/

.gitattributes 统一以 LF 存储, Windows 批处理保留 CRLF
2026-10-27 12:00:41 +08:00

17 KiB
Raw Permalink Blame History

中控屏直连 MumIot 协议 · 平台方评审回复与落地方案

项目 内容
对应文档 04-中控屏直连MumIot对接协议-评审稿.html(v0.1,2026-10-16)
本稿版本 v1.0(平台方评审回复)
日期 2026-10-22
评审范围 协议 13 章 / 24 个接口(21 个新增建议 + 3 个扩展建议)
评审方 MumIot 平台

一、总体结论

采纳本协议作为中控屏接入的主体框架。

协议提出的"屏 = 本地执行网关 + 命令单据化 + 三重版本号(归属/物模型/状态)"设计,与平台演进方向一致。落地后不只中控屏受益,平台现有手机端 / 网页端也会同步补上四项长期欠账:

现状欠账 落地后改善
设备命令纯同步、无记录、不可追溯 命令单据化 + 状态机,全程可查
设备状态无版本号、/latest 是空壳 属性级状态 + 序号,最新值可用
无面向客户端的事件通道 家庭增量事件 + 长轮询,多端一致
OTA 只有任务级聚合、无单设备追踪 单设备升级尝试(attempt),进度可追踪

但需分期落地,不建议一次全量实施。 协议中有三块属全新子系统建设(命令状态机、事件通道、状态版本号),另有 OTA 模型需重构,一次性上线的风险与回归成本过高。


二、P0 前置事项结论

2.1 DDL 缺列排查 —— ✅ 已澄清,非阻塞

协议要求"本地设备挂载到屏(父网关)",依赖 Device.parentDeviceId 与 Device.isGateway。此前发现 backend/sql/ 全部迁移脚本中均无这两列,疑为阻塞项。已核查生产库,结论如下:

parent_device_id  varchar(64)  YES          NULL
is_gateway        tinyint      YES          0

生产库 device 表实际已存在这两列,非生产阻塞项。

遗留事项(降为 P1):sql/ 目录缺少对应迁移脚本,导致「从脚本重建的新环境」会缺列。需补一个迁移脚本登记这两列,保证环境可重建。详见第五章 P1。

2.2 三项契约冲突 —— 我方裁决

协议第 2 章通用约定与平台现行约定存在三处冲突,我方裁决如下:

冲突 1:HTTP 状态码

  • 平台现状:全局约定「业务异常 HTTP 200 + JSON 业务码」。例:/api/v1/auth/token 凭证无效返回 200 + {"code":401}。
  • 协议要求:错误使用对应非 2xx(含 202/409/410/429/503),且明确「屏不能仅凭 HTTP 200 判定设备控制成功」。

裁决:分区处理,双方约定不冲突。

  • 协议新增的 /api/v1/panels/** 及声明 X-MUM-Protocol: panel-v1 的请求 → 采用标准 HTTP 语义(202 已接受 / 4xx / 5xx)。
  • 存量接口(手机 App、网页、涂鸦回调)→ 保持 200 + 业务码不动,避免打断现有客户端。
  • 我方提供《ResultCode ↔ HTTP 状态 + errorCode》映射表(见 2.3),屏端按映射表处理。

协议第 2 章已预留此口子:「平台既有错误码可映射保留,但同一含义应稳定一致」。

冲突 2:成功响应的 code 值

  • 平台现状:成功 code = 200(非 0)。
  • 协议示例:{"code": 0, "message": "success"}。

裁决:沿用平台 code = 200,并明确判定方式。

屏端请不要硬编码 code === 0。建议统一按下述优先级判定:

  1. HTTP 状态码(panel 接口);
  2. 响应体 success 布尔字段(平台 Result 已带);
  3. 业务 code(成功为 200,非 0/200 即异常)。

冲突 3:幂等键与新增必填字段的强制范围

  • 协议要求:所有 POST 必带 Idempotency-Key;控制命令必带 schemaRevision。
  • 平台现状:现有 App / 网页 / 涂鸦回调均无这些字段。

裁决:仅对声明 X-MUM-Protocol: panel-v1 的请求强制。 存量客户端保持原契约,内部归入同一设备路由与命令记录,由平台补齐默认版本。

协议第 2 章已认可:「不能直接把新必填字段施加到所有旧客户端」。

2.3 错误码映射表(我方提供,供屏端实现)

HTTP 业务 code errorCode 屏端处理
400 400 INVALID_ARGUMENT 修正参数,不自动重试
400 400 UNSUPPORTED_CAPABILITY 刷新能力,关闭无效操作
401 401 TOKEN_EXPIRED 刷新后重试同一逻辑请求
401 401 INVALID_CREDENTIAL 停止循环,上报身份错误
403 403 HOME_ACCESS_REVOKED 停止该家庭云操作,清缓存
403 403 DEVICE_OUT_OF_SCOPE 不执行跨家庭/非本屏任务
409 409 IDEMPOTENCY_CONFLICT 不生成新键掩盖冲突
409 409 SCHEMA_CHANGED 重读物模型,重新确认目标
409 409 ROUTE_CHANGED 刷新归属,旧屏不执行
409 409 DELIVERY_EXPIRED 本次投递无效,不执行
409 409 EXECUTION_ALREADY_STARTED 查原命令,不重复操作
409 409 DEVICE_OFFLINE 显示设备/执行屏离线
409 409 STALE_SESSION 停止领取
410 410 CURSOR_EXPIRED 重拉完整快照
410 410 SNAPSHOT_EXPIRED 放弃分页,重新开始
410 410 COMMAND_EXPIRED 不执行
429 429 RATE_LIMITED 按 Retry-After 退避
503 503 SERVICE_UNAVAILABLE 读请求退避;控制先查原结果

errorCode 为语义稳定字符串,屏端按 errorCode 分支;code 数值仅供日志。

2.4 时间参数默认值(我方确认按协议实现)

心跳 30s / 在线租期 90s / 长轮询 20s / 命令总超时 30s(允许 1–120s)/ 投递租期 10s / 快照缓存 120s / 事件游标保留 24h / 幂等记录保留 7 天。

全部由会话响应下发,屏端以响应值为准,不硬编码。


三、逐条评审回执

图例:接受 = 按协议实现;修改后接受 = 采纳思路但有调整;暂缓 = 延后到后续期;需澄清 = 待屏方确认后定。

第 3 章 · 中控身份与会话

# 接口 标记 结论 说明
1 POST /api/v1/panels/session 新增 接受 新增 panel_terminal 表(serialNumber 唯一 + BCrypt 凭证 + homeId/memberId/role/enabled);JwtAuthenticationFilter 增加 panel → ROLE_PANEL 分支;复用现有 JwtUtil 签发
2 POST /api/v1/panels/session/refresh 新增 接受 协议要求「轮换 + 120s 重放窗口 + 可撤销」。平台现有 refresh 为无状态 JWT、无法撤销,故新增刷新令牌表实现轮换与撤销(同时修复会员侧同一隐患)
3 GET /api/v1/panels/{panelId} 新增 接受 按协议返回,panelId 强制为自身
4 POST /api/v1/panels/{panelId}/heartbeat 新增 接受 按协议;租期自收到有效心跳起算,其它调用不隐式替代心跳

第 4 章 · 家庭快照与事件同步

# 接口 标记 结论 说明
5 GET /api/v1/homes
GET /api/v1/homes/{homeId}/rooms
扩展 接受(关键安全项) 平台现有接口以 memberId 入参过滤。屏调用时必须忽略入参、以会话绑定家庭为准。我方新增 PanelContextResolver 强制覆盖,杜绝越权选择器
6 GET /api/v1/panels/{panelId}/snapshot 新增 修改后接受 一期单页返回不分页(家庭设备量级有限),二期再上 pageToken 分页与快照一致性游标。字段按协议(含 executionSource/executorPanelId/routeRevision/schemaRevision/stateVersion)
7 GET /api/v1/panels/{panelId}/events 新增 修改后接受(P2) 采用协议的 DB 事件表 + 长轮询方案(平台无 SSE/WebSocket 端点基础设施,不另起炉灶)。新增 panel_event 表 + 不透明游标。一期先以快照 + 状态上报保证可用

第 5 章 · 设备登记与标准控制模型

# 接口 标记 结论 说明
8 POST /api/v1/panels/{panelId}/devices/register 新增 接受 映射良好:屏 = 网关设备(isGateway),本地设备挂 parentDeviceId;platform 已支持 local/matter。(panelId, localDeviceId) 唯一,重复登记返回同一映射
9 PUT /api/v1/panels/{panelId}/devices/{deviceId}/schema 新增 接受 物模型现状与协议 PropertySpec 高度吻合(code/type/access/min/max/step/unit/enumList/dpId 均已具备)。需新增 semantic、channel、completionMode 三字段,并引入设备级 schemaRevision
10 GET /api/v1/devices/{deviceId}/control-schema
GET /api/v1/products/{id}/spec
扩展 修改后接受 现 control-schema 只返回 properties,未用 ProductAction/ProductEvent。按协议补齐 actions(如 stop)。版本号平台内部称 specVersion(产品级),对外统一暴露为 schemaRevision(设备级)

第 6 章 · 控制命令与执行回执(核心)

# 接口 标记 结论 说明
11 POST /api/v1/devices/{deviceId}/commands 扩展 修改后接受(核心改造) 现为同步阻塞、无命令记录(CommandStatus 常量有定义但零引用)。按协议改造为「先落库生成 commandId → 202 → 异步执行」。
双轨兼容:云设备(涂鸦等)同步执行后直落终态,旧客户端仍返回 200 + 原结构;仅 executionSource=LOCAL_PANEL 且声明 panel-v1 的请求走 202 异步
12 GET /api/v1/device-commands/{commandId} 新增 接受 新增 device_command 表承载 10 态状态机;仅本命令关联家庭的合法调用者可查
13 POST /api/v1/panels/{panelId}/commands/pull 新增 接受 按协议:bootId 必填、投递租期 10s、deliveryToken 一次性
14 POST /api/v1/panels/{panelId}/commands/{commandId}/start 新增 接受 原子校验状态/有效期/归属/token,成功转 EXECUTING 并返回 executionToken
15 POST /api/v1/panels/{panelId}/commands/{commandId}/report 新增 接受 reportId + 递增 reportSequence 去重排序;平台按证据判定 CONFIRMED,不凭旧缓存值

第 7 章 · 状态与活动上报

# 接口 标记 结论 说明
16 POST /api/v1/panels/{panelId}/reports 新增 修改后接受 现设备实时状态唯一来源是 device.capabilities.dps(JSON 列),/data/latest 为 TODO 空壳,全项目无 stateVersion/sequence。按协议新增 device_state(deviceId + 属性码 + sequence + stateEpoch + quality),按 (epoch, seq) 比较决定 appliedToCurrentState。顺带补上 /latest 空壳,手机端同样受益

第 8 章 · 多屏、场景与 AI

# 接口 标记 结论 说明
17 GET /api/v1/scene-runs/{sceneRunId} 新增 暂缓(P3) 一期云端场景经「场景 → 设备命令 → 执行屏」即可跑通;场景执行单据化延后,避免与命令状态机同期上线放大回归面
18 POST /api/v1/panels/{panelId}/scene-runs/report 新增 暂缓(P3) 同上。离线场景历史记录二期补
19 POST /api/v1/ai/command 扩展 暂缓(P3) 平台现有二次确认字段(targetType/targetId)可覆盖基本需求;confirmationId + expiresAt + status 随屏端语音排期再上

第 9 章 · 配置、内容、日志和 OTA

# 接口 标记 结论 说明
20 GET /api/v1/panels/{panelId}/configuration 新增 暂缓(P2) 一期屏用本地默认配置即可启动;配置下发二期随运营需求上
21 POST /api/v1/panels/{panelId}/diagnostics 新增 暂缓(P3) 诊断事件延后;期间用服务端日志定位
22 GET /api/v1/panels/{panelId}/ota-tasks/next 新增 修改后接受(P2) 平台 OTA 现为「产品固件 + 任务级聚合计数」,缺 packageType/targetModel/minVersion、无单设备升级记录、重复上报会重复计数、非 running 或不在目标集合时静默丢弃上报(屏会误判成功)。按协议改造:新增 ota_attempt 单设备升级尝试,聚合计数改为由 attempt 统计
23 POST /api/v1/ota-tasks/{id}/report 扩展 修改后接受(P2) 现请求体仅 deviceId/success/version 三字段。按协议增加 attemptId/reportId/reportSequence/stage/progress/errorCode/message,并做幂等

第 2 章 · 通用约定

# 约定 结论 说明
24 幂等键 / X-MUM-Protocol / 错误响应 / 标识与时间 修改后接受 见 2.2 三项裁决。权限清单(panel.read、gateway.execute 等 7 项)我方接受,签发时写入 JWT scopes,用 hasAuthority 做细粒度校验(平台已有 scopes 机制)

四、数据模型改造清单

新增表

表 用途 期次
panel_terminal 屏终端身份(序列号、凭证哈希、家庭绑定、角色) P1
panel_refresh_token 刷新令牌轮换与撤销(兼修会员侧隐患) P1
device_command 命令单据 + 10 态状态机(核心) P1
device_state 设备属性级状态 + 序号(补 /latest 空壳) P1
idempotency_record 幂等记录(保留 7 天) P1
panel_event 家庭增量事件 + 游标 P2
ota_attempt 单设备升级尝试(attempt/stage/progress) P2
panel_configuration 屏配置下发 P2
scene_run 场景执行单据 P3

字段扩展

  • device 表新增:executor_panel_id、route_revision、schema_revision、local_device_id、protocol、execution_source
  • product_property 新增:semantic、channel、completionMode
  • firmware 新增:package_type、target_model、min_version

迁移脚本补齐(P1)

parent_device_id / is_gateway 两列生产库已存在但 sql/ 无迁移脚本,需补脚本登记,保证新环境可重建。


五、分期落地计划

P0 · 前置(已完成 / 进行中)

  • 排查 parent_device_id / is_gateway 生产库列 → 已确认存在,阻塞解除
  • 三项契约冲突裁决 → 见 2.2,待屏方确认映射表

P1 · 一期:打通主链路

目标:屏能注册、能看家、能执行云下发的命令。完成即可覆盖约 90% 屏控场景。

  1. 屏终端身份 + ROLE_PANEL + session / refresh(含刷新令牌表)
  2. PanelContextResolver:家庭范围强制覆盖(安全关键)
  3. device 执行归属字段 + devices/register + schema 更新
  4. device_command 状态机 + pull / start / report + 命令查询(双轨兼容云同步)
  5. device_state + reports 批量上报
  6. snapshot(一期单页)
  7. 补 parent_device_id / is_gateway 迁移脚本

P2 · 二期:实时性与完整性

  1. panel_event + events 长轮询
  2. control-schema 补 actions / events + 设备级 schemaRevision
  3. OTA 改造:ota_attempt + Firmware 扩展 + ota-tasks/next
  4. snapshot 分页与一致性游标
  5. configuration 下发

P3 · 三期:体验与运营

  1. scene_run / scene-runs/report
  2. AI confirmationId + status
  3. diagnostics 诊断事件
  4. 多屏归属交接流程(routeRevision 迁移)

六、需屏方确认的问题清单

对应贵方第 12 章提出的 5 点,我方反馈如下并补充需确认项:

  1. 推送方式:我方一期采用协议建议的 DB 事件表 + 长轮询(平台无 SSE/WebSocket 端点基础设施)。请确认屏端「长轮询 20s / 心跳 30s / 租期 90s」三路并发调度互不阻塞。
  2. 一期范围:scene-runs、AI confirmationId、diagnostics 我方建议延后。请确认屏端一期是否强依赖其中任何一项。
  3. CONFIRMED 的证据来源:屏端能否提供「写后读回」校验?若否,命令只能到达 ACCEPTED / UNKNOWN,界面须如实显示「已接受 / 结果未知」,不得显示为已确认(此点协议亦强调)。
  4. 多屏归属交接:一期是否仅单屏?多屏场景下 routeRevision 交接由谁触发(管理员后台操作 / 平台自动)?
  5. 配网:确认屏端 Matter/Zigbee/BLE 配网完成后走设备登记,平台不下发任何协议密钥(与协议一致)。
  6. OTA 下载:我方提供平台自有下载域名,无需屏端 Bearer Token 转发第三方(与协议一致)。
  7. 错误码映射表(见 2.3):请确认按 errorCode 字符串分支、code 数值仅用于日志,且不硬编码 code === 0。

七、下一步

  1. 双方就本回复的「修改后接受 / 暂缓」项达成一致,输出定稿版协议(路径与字段维护在同一份文档中)。
  2. 我方按第五章 P1 启动一期开发;屏端同步适配。
  3. 定稿前请勿按评审稿开发——评审稿中标注「新增建议」的路径与字段,以定稿为准。