纳入范围: - 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
207 lines
14 KiB
Markdown
207 lines
14 KiB
Markdown
# 产品管理模块(Product & TSL & OTA)分析设计
|
||
|
||
> 状态:分析设计(待评审,先不开发)
|
||
> 日期:2026-09-19
|
||
> 目标:论证并设计中控屏/IoT 平台所需的"产品管理"能力(产品参数、物模型 TSL、固件 OTA)
|
||
|
||
---
|
||
|
||
## 1. 结论先行(建议)
|
||
|
||
**非常需要,且应尽快立项。** 当前系统是"设备直管"模式,缺少产品(Product)这一层抽象,导致物模型零散、固件无管理、新增设备类型成本高。引入 **产品 → 设备 两级模型**(对标涂鸦/阿里云 IoT 的 Product 概念)是平台标准化的必经之路,并能直接支撑中控屏标准控制 UI、场景、AI 控制、固件升级。
|
||
|
||
---
|
||
|
||
## 2. 现状与痛点
|
||
|
||
### 2.1 现状(代码事实)
|
||
|
||
- `Device` 实体(`device` 表)字段:`deviceId, deviceName, platform, deviceType, manufacturer, model, firmwareVersion, status, capabilities(JSON), ..., homeId, roomId` —— **无 `productId`**。
|
||
- `Device.capabilities`:设备级 JSON,存"设备能力描述",**每个设备重复存静态能力**,无产品级统一定义。
|
||
- `AiDeviceProfile`(`ai_device_profile` 表,iot-device 与 iot-rule 两侧都有):**设备级**"指令码档案"(`powerCode/brightnessCode/colorTempCode/temperatureCode/modeCode`…),本质是物模型 DP 雏形,但按 `deviceId` 维度重复存储。
|
||
- `Device.firmwareVersion`:仅版本字符串,**无固件库、无升级包、无 OTA 任务、无灰度/回滚**。
|
||
- 涂鸦侧 `TuyaDeviceDTO` 有 `productId/productName/category`,但平台未把它沉淀为自有 Product 实体,仅在对接时透传。
|
||
|
||
### 2.2 痛点
|
||
|
||
1. **重复定义、难维护**:同类设备(同型号)每个都重复存 `capabilities` / `AiDeviceProfile` 指令码,产品能力变更需逐设备改。
|
||
2. **无标准物模型**:控制逻辑(DP 点、属性/事件/服务)散落在设备 JSON 与 `AiDeviceProfile`,AI 控制、场景、中控屏各自解析,易错且无法复用。
|
||
3. **固件无管理**:只有版本号,无法上传/发布/下发/灰度/回滚固件,中控屏等设备的固件升级无法支撑。
|
||
4. **产品参数无沉淀**:厂商/型号/品类/联网方式/配网/图标等散落,无法以"产品"维度统一管理和展示标准控制 UI。
|
||
5. **接入新设备类型成本高**:每接一类设备都要改代码/前端,无法配置化。
|
||
|
||
---
|
||
|
||
## 3. 产品管理模块范围
|
||
|
||
| 能力 | 说明 |
|
||
|------|------|
|
||
| 产品基础信息 | 名称、品类(category)、厂商(manufacturer)、型号(model)、联网方式(wifi/ble/zigbee/matter)、配网方式、图标、说明、发布状态 |
|
||
| 物模型(TSL) | 属性(Property)、事件(Event)、服务(Action) 三类功能点,含 DP 点定义与涂鸦/平台映射 |
|
||
| 固件管理(OTA) | 固件版本库、升级包存储(md5)、发布、升级任务、灰度、回滚、设备当前版本追踪 |
|
||
| 平台映射 | 本平台 Product ↔ 涂鸦 `productId` 等(`platform` + `platformProductId`) |
|
||
| 设备归属 | Device 增加 `productId`,继承产品物模型与固件基线 |
|
||
| 接入/配网模板(二期) | 标准化配网流程、设备自动归属产品 |
|
||
|
||
---
|
||
|
||
## 4. 与现有概念的关系(迁移策略)
|
||
|
||
| 现有 | 去向 |
|
||
|------|------|
|
||
| `Device.manufacturer` / `model` | 提升到 `Product`;Device 改为引用 `productId`(建议移除冗余,或保留只读快照防不一致) |
|
||
| `Device.capabilities`(JSON) | 由 Product 物模型(TSL)生成,设备运行时状态另存(`device_data`/status),不再每设备存静态能力 |
|
||
| `AiDeviceProfile`(设备级指令码) | **下沉为 Product 物模型的 DP 定义**(powerCode 等即产品的"开关属性");AI 控制/场景直接读产品物模型,设备不再单独存 |
|
||
| 涂鸦 `productId` | `Product.platform` + `platformProductId` 字段建立映射(一个平台产品 → 本平台一个 Product) |
|
||
| `Device.firmwareVersion` | 保留为设备"当前版本"(运行时上报);新增 `firmware` 表管理"可用版本库",`ota_task` 记录目标版本 |
|
||
|
||
---
|
||
|
||
## 5. 数据模型设计
|
||
|
||
### 5.1 product(产品表)
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| id | PK |
|
||
| product_key | 业务编码(如 P_LIGHT_001) |
|
||
| name | 产品名称 |
|
||
| category | 品类(light/switch/ac/security…) |
|
||
| manufacturer | 厂商 |
|
||
| model | 型号 |
|
||
| platform | 接入平台(tuya/local/matter…) |
|
||
| platform_product_id | 涂鸦 productId 等映射 |
|
||
| connect_type | wifi/ble/zigbee/matter |
|
||
| net_config_type | 配网方式 |
|
||
| icon | 图标 |
|
||
| description | 说明 |
|
||
| status | 草稿/已发布 |
|
||
| spec_version | 当前物模型版本号 |
|
||
| create_time / update_time | — |
|
||
|
||
### 5.2 物模型(TSL)
|
||
推荐**拆表**(便于校验、UI 渲染、DP 映射),顶层用 `spec_version` 关联快照:
|
||
|
||
- `product_property`(属性):id, product_id, code(如 switch_1), name, access(读/写/上报), type(bool/int/enum/float/string/json), min, max, step, unit, enum_list, dp_id(涂鸦DP映射), default_value, sort
|
||
- `product_event`(事件):id, product_id, code, name, type(info/alert/fault), params(JSON)
|
||
- `product_action`(服务):id, product_id, code, name, input(JSON), output(JSON)
|
||
|
||
> 可选:同时存一份 `product.spec_json`(完整 TSL 快照)便于缓存下发。
|
||
|
||
### 5.3 firmware(固件表)
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| id | PK |
|
||
| product_id | 所属产品 |
|
||
| version | 固件版本 |
|
||
| file_url | 升级包地址 |
|
||
| file_md5 | 校验 |
|
||
| size | 大小 |
|
||
| release_note | 更新说明 |
|
||
| is_latest | 是否最新 |
|
||
| status | 草稿/已发布 |
|
||
| create_time | — |
|
||
|
||
### 5.4 ota_task(升级任务)
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| id | PK |
|
||
| product_id | 产品 |
|
||
| firmware_id | 目标固件 |
|
||
| target_version | 目标版本 |
|
||
| scope | 全部 / 指定设备 / 灰度% |
|
||
| device_ids | 指定设备 |
|
||
| status | 进行中/完成/暂停/失败 |
|
||
| success_count / fail_count | 统计 |
|
||
| create_time | — |
|
||
|
||
### 5.5 Device 改造
|
||
- 新增 `product_id`(FK,关联 product.id)。
|
||
- 视情况移除 `model`/`manufacturer` 冗余(或保留只读快照)。
|
||
- `firmwareVersion` 保留为设备当前运行版本(上报)。
|
||
|
||
---
|
||
|
||
## 6. 接口设计(建议)
|
||
|
||
### 6.1 管理端(后台/管理员)
|
||
- `POST/GET/PUT/DELETE /api/v1/products` —— 产品 CRUD
|
||
- `GET /api/v1/products/{id}/spec` —— 物模型查询
|
||
- `POST /api/v1/products/{id}/spec/properties` 等 —— DP/事件/服务增删改
|
||
- `POST /api/v1/products/{id}/firmware` —— 上传固件
|
||
- `GET /api/v1/products/{id}/firmwares` —— 固件列表
|
||
- `POST /api/v1/products/{id}/ota` —— 创建升级任务
|
||
- `GET /api/v1/ota-tasks/{id}` —— 任务进度
|
||
|
||
### 6.2 设备/中控屏侧(复用)
|
||
- 设备详情返回 `productId` + 物模型(用于渲染**标准控制 UI**,不再依赖零散 capabilities)。
|
||
- 控制接口基于物模型 DP(统一语义)。
|
||
- 固件查询:设备上报/拉取最新固件版本,触发 OTA。
|
||
|
||
---
|
||
|
||
## 7. 固件 OTA 流程
|
||
|
||
1. 管理员上传固件到 Product → 生成 `firmware` 记录(version, url, md5)。
|
||
2. 创建 `ota_task`(目标版本 + 设备范围 / 灰度比例)。
|
||
3. 设备定期上报/查询最新固件(或平台主动推送升级指令)→ 下载升级 → 上报新 `firmwareVersion` → 任务统计。
|
||
4. 支持回滚(将上一版本 `is_latest=false`,重新下发任务)。
|
||
- **中控屏本身也是一类 Product**,可纳入同一套 OTA 管理。
|
||
|
||
---
|
||
|
||
## 8. 分阶段实施
|
||
|
||
- **P0 产品基础**:`product` 表 + `Device.productId` 改造 + 产品 CRUD;按 `model+manufacturer` 自动归并或手动建产品,给存量设备回填 `productId`。
|
||
- **P1 物模型**:TSL(property/event/action)建模 + 管理接口;将 `AiDeviceProfile` / `capabilities` **迁移沉淀为产品物模型**,AI 控制/场景改读产品物模型。
|
||
- **P2 固件 OTA**:✅ 已实现(2026-09-19)。后端 `FirmwareService/Controller`:固件注册(草稿)/发布(置最新)/最新版查询、升级任务创建(all/designated/gray 物化目标设备)/任务分页/详情/设备上报回调(回写 device.firmware_version、统计完成)/暂停。管理后台「设备管理→产品管理」含固件OTA面板(注册/发布/建任务/进度/暂停)。V13/V14 迁移已在开发库(iot-mysql 3386)执行,8 台涂鸦设备已 reconcile 归类为 8 个产品。
|
||
- **P3 标准化控制**:✅ 已实现(2026-09-20)。核心是「标准控制模型」`ControlSchemaService`:`GET /api/v1/products/{id}/control-schema`(产品级)与 `GET /api/v1/devices/{deviceId}/control-schema`(设备级,含 DP 当前值填充)。物模型→控件映射:bool→switch、int/float 有范围→slider、enum→segmented、其余→number/text;主开关自动识别(开关/电源/switch/power 优先,否则唯一可写 bool)。设备无产品时 `available=false`,客户端回退原有渲染。消费端:管理后台「物模型→控制预览」按模型渲染只读控件;Android `DeviceControlActivity` 优先拉后端模型渲染(`ApiService.getDeviceControlSchema`),失败/无模型回退涂鸦 schema(需 Android Studio 编译确认)。
|
||
- **P4 高级**:✅ 大部分已实现(2026-09-20)。版本回滚 `POST /products/{id}/ota/rollback`(不指定版本则回退上一个已发布版本);灰度改为**设备ID稳定哈希分组**(同一设备恒在同一组,可配合不同版本做 A/B 对比);统计看板 `GET /ota-tasks/stats?productId=`(任务数/进行中/完成/暂停、成功失败数、成功率、设备固件版本分布),管理后台 OTA 面板顶部为统计卡片 + 版本分布。未做:配网模板。
|
||
|
||
---
|
||
|
||
## 9. 风险与注意
|
||
|
||
- **存量迁移**:设备需回填 `productId`(按 model+manufacturer 归并或人工关联)。
|
||
- **兼容性**:保留 `capabilities` 读兼容,逐步切到产品物模型,避免一次性大改。
|
||
- **物模型版本**:用 `spec_version` 管理,产品变更不影响已部署设备(设备绑定创建时的 spec 快照)。
|
||
- **涂鸦映射一致性**:`platformProductId` 与涂鸦 productId 对齐,DP 映射字段 `dp_id` 准确。
|
||
|
||
---
|
||
|
||
## 10. 价值总结
|
||
|
||
引入产品层可一次性解决当前三大痛点:**① 物模型统一(消除 `capabilities`/`AiDeviceProfile` 设备级重复)② 固件可管理(OTA)③ 设备类型配置化接入**。同时为已规划的中控屏标准控制 UI、场景、AI 语音控制提供统一数据底座,是平台从"能连设备"走向"可运营 IoT 平台"的关键一步。
|
||
|
||
---
|
||
|
||
## 11. 已确认决策(2026-09-19 评审)
|
||
|
||
| 项 | 决策 |
|
||
|----|------|
|
||
| 存量设备回填 | **两者结合**:系统按 `model+platform` 自动预归类生成建议产品与归属,管理员在后台确认/调整 |
|
||
| Device 冗余字段 | **移除** `Device.model` / `manufacturer`,统一从 `product` 取(需同步改所有读写该字段的逻辑:DeviceController.createDevice、DeviceInfo DTO、AiDeviceProfile、前端设备卡片等) |
|
||
| 物模型存储 | **拆表**:`product_property` / `product_event` / `product_action`,每行一个 DP 点,含 `dp_id` 涂鸦映射与 `spec_version` |
|
||
| 首期范围 | **P0 + P1 全做**:产品基础 + `Device.product_id` + 存量回填 + 物模型(属性/事件/服务)建模与接口,并将 `AiDeviceProfile` / `capabilities` **下沉为产品物模型** |
|
||
|
||
### 11.1 开发前影响面排查(移除冗余字段必做)
|
||
- `Device.model` / `manufacturer` 读写点:`DeviceController`(create/update/query)、`DeviceInfo`/`DeviceData` 等 DTO、SQL 映射、前端设备详情/卡片展示。
|
||
- `AiDeviceProfile` 下沉:iot-device 写入、iot-rule 读取(AI 控制翻译)需改为读产品物模型;迁移脚本把存量 deviceId 级指令码归并到所属产品的 property。
|
||
- `capabilities` 兼容:保留读兼容,新设备改由产品物模型生成;提供回填/转换脚本。
|
||
|
||
## 12. 实现进度(2026-09-19,P0+P1 基础)
|
||
|
||
### 12.1 已完成(可编译,已通过 LSP)
|
||
- **SQL** `backend/sql/V13__add_product_module.sql`:新建 `product` / `product_property` / `product_event` / `product_action` / `firmware` / `ota_task` 六表;`device` 表新增 `product_id` 列(保留原 `model/manufacturer` 兼容快照,未物理删除)。
|
||
- **实体 + Mapper**:6 个实体与 6 个 `BaseMapper`(纯新增)。
|
||
- **ProductService / Impl**:产品 CRUD、物模型查询与增删改、`resolveProductId`(按平台信息解析/自动建产品)、`reconcileDevices`(存量设备按 `model+platform` 自动归类回填 `product_id`)。
|
||
- **ProductController** `POST/GET/PUT/DELETE /api/v1/products`、`/products/{id}/spec`、`/properties|events|actions`、`/reconcile`、`/resolve`。
|
||
- **Device / DeviceInfo** 增加 `productId`;`TuyaDeviceAdapter.getDeviceInfo` 回填 `productId`(设备详情可返回所属产品)。
|
||
|
||
### 12.2 未做(高风险,单列计划,未破坏现有功能)
|
||
1. **✅ 移除 `Device.model/manufacturer` 冗余(D)**:`V14` 给 `device` 加 `platform_product_id`(承接塞进 `model` 列的涂鸦 productId)、迁移存量、再 `DROP COLUMN model/manufacturer`。`Device` 实体删两字段加 `platformProductId`;`TuyaController` 改设 `platformProductId`;`reconcileDevices` 改按 `platform+platformProductId` 归类;`DeviceInfo` 的 `model/manufacturer` 改为**从 `product` 取**(`TuyaDeviceAdapter` 注入 `ProductMapper`)→ 前端零改动。
|
||
2. **✅ `AiDeviceProfile` 下沉产品级(C,向后兼容)**:`ai_device_profile` 加 `product_id`。`iot-device` 探测与 `iot-rule` 解析/保存全部改为**优先读产品级、推断落产品级**;旧设备级作 fallback。`AiDeviceView` 加 `productId`。
|
||
3. **✅ 设备同步自动关联(B)**:`TuyaController` 创建/更新涂鸦设备时自动 `resolveProductId` 设 `device.product_id`。
|
||
4. **✅ `capabilities` 由物模型生成**:`DeviceServiceImpl.getDeviceInfo` 改为依据设备所属 `product` + `product_property` 动态推导能力描述(`product` 元数据 + 每个功能点 `code/name/type/access/writable/min/max/step/unit/enum/default`),取代各 adapter 硬编码能力(如 `LocalDeviceAdapter` 的 `switch/brightness/color`);`device.capabilities` 列仅保留 `dps` 运行时态;无产品时回退 adapter 自带能力。前端无引用,零改动。
|
||
|
||
> 验证:后端 `mvn -pl iot-device,iot-rule -am compile` 通过(exitCode 0)。存量设备 productId 回填与产品创建由部署后执行 `POST /api/v1/products/reconcile` 完成(已基于 `platformProductId`)。
|