docs(iot): 基于真实代码重置IoT文档,引入Codec协议、物模型元素、场景规则引擎等底层逻辑
This commit is contained in:
@@ -1,59 +1,58 @@
|
||||
# 01-设备接入与控制主链路
|
||||
|
||||
IoT 系统的命脉在于可靠的通信机制。本链路基于 MQTT 协议,设计了设备从上线建连到数据双向交互的完整闭环。
|
||||
在 AIOT 平台中,IoT 设备接入由 `viewsh-module-iot-gateway` 统一处理,支持多种协议栈。这是物理世界数据流向业务系统的第一道关口。
|
||||
|
||||
## 一、设备接入完整交互时序图
|
||||
## 一、支持的接入协议栈
|
||||
|
||||
根据底层网关编解码器(Codec)的实现,平台当前支持以下协议的设备接入:
|
||||
- **MQTT**:主流通讯协议,配合 EMQX 等 Broker 进行上下行流转。
|
||||
- **JT808**:部标车载终端通信协议。
|
||||
- **Alink**:阿里标准物联网协议。
|
||||
- **TCP**:支持自定义的 TCP Binary(透传)与 TCP JSON 格式。
|
||||
|
||||
设备的网络通信类型 (`IotNetTypeEnum`) 抽象为:`WIFI`, `CELLULAR` (蜂窝), `ETHERNET` (以太网), `OTHER`。
|
||||
|
||||
## 二、MQTT 接入与状态流转
|
||||
|
||||
以最典型的 MQTT 接入为例,设备的状态流转受严格的网关路由管理:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Device as IoT设备
|
||||
participant Gateway as MQTT Broker(网关)
|
||||
participant IoTModule as module-iot(业务后服务)
|
||||
participant EMQX as EMQX (Broker)
|
||||
participant Gateway as module-iot-gateway
|
||||
|
||||
== 第一阶段:设备注册与认证 ==
|
||||
Device->>Gateway: CONNECT (Client ID, User, Password)
|
||||
activate Gateway
|
||||
Gateway->>IoTModule: 鉴权 Hook (校验 Token/秘钥)
|
||||
IoTModule-->>Gateway: 鉴权通过
|
||||
Gateway-->>Device: CONNACK (连接接受)
|
||||
deactivate Gateway
|
||||
== 1. 设备鉴权与上线 ==
|
||||
Device->>EMQX: CONNECT
|
||||
EMQX->>Gateway: 触发 AuthEventProtocol
|
||||
Gateway->>Gateway: IotEmqxAuthEventHandler 校验 Token/秘钥
|
||||
Gateway-->>EMQX: 鉴权结果
|
||||
EMQX-->>Device: CONNACK
|
||||
|
||||
Device->>Gateway: SUBSCRIBE (Topic: /down/device/{id})
|
||||
Gateway-->>Device: SUBACK
|
||||
Note over Gateway: 鉴权通过后,状态变更为 ONLINE(1)
|
||||
|
||||
== 第二阶段:保活与状态同步 ==
|
||||
loop 心跳周期 (如 30s)
|
||||
Device->>Gateway: PINGREQ
|
||||
Gateway-->>Device: PINGRESP
|
||||
end
|
||||
== 2. 上行数据 (Upstream) ==
|
||||
Device->>EMQX: PUBLISH (/up/telemetry)
|
||||
EMQX->>Gateway: 推送数据
|
||||
Gateway->>Gateway: IotMqttUpstreamHandler 根据 Codec 解码
|
||||
Gateway->>Gateway: IotEmqxUpstreamProtocol 解析数据抛出事件
|
||||
|
||||
== 第三阶段:数据上报 (Telemetry) ==
|
||||
Device->>Gateway: PUBLISH (Topic: /up/telemetry/{id}, Payload: JSON)
|
||||
Gateway->>IoTModule: 消息路由/桥接
|
||||
IoTModule->>IoTModule: 根据设备品类物模型进行解析
|
||||
IoTModule->>IoTModule: 属性落库 / 存入时序数据库
|
||||
== 3. 下行指令 (Downstream) ==
|
||||
Gateway->>EMQX: PUBLISH (/down/command) via IotMqttDownstreamHandler
|
||||
EMQX->>Device: 投递指令
|
||||
Device-->>EMQX: ACK / 结果返回
|
||||
|
||||
== 第四阶段:指令下发 (Command) ==
|
||||
IoTModule->>Gateway: PUBLISH (Topic: /down/device/{id}, Payload: 控制指令)
|
||||
Gateway->>Device: 推送下行消息
|
||||
activate Device
|
||||
Device->>Device: 执行硬件动作 (如关阀门)
|
||||
Device->>Gateway: PUBLISH (Topic: /up/reply/{id}, Payload: 执行结果)
|
||||
deactivate Device
|
||||
Gateway->>IoTModule: 结果回调
|
||||
IoTModule->>IoTModule: 更新指令状态及设备影子
|
||||
== 4. 断开与离线 ==
|
||||
Device->>EMQX: DISCONNECT 或 心跳超时
|
||||
EMQX->>Gateway: 触发离线事件
|
||||
Note over Gateway: 状态变更为 OFFLINE(2)
|
||||
```
|
||||
|
||||
## 二、通信链路设计红线与规范
|
||||
## 三、设备生命周期 (IotDeviceStateEnum)
|
||||
|
||||
### 1. QoS (服务质量) 策略
|
||||
- **数据上报 (Telemetry)**:推荐使用 **QoS 0**。传感器高频数据允许丢失单点,追求高吞吐量;若属于关键状态跳变(如火警触发),必须使用 **QoS 1**。
|
||||
- **指令下发 (Command)**:强制使用 **QoS 1**。云端下发的开关门、断电指令必须确保到达,依靠 MQTT 协议级 ACK 进行重传保证。
|
||||
系统对设备的在线状态维护极其严格,分为三种终态:
|
||||
1. **`INACTIVE(0)` (未激活)**:设备在平台已建档,但从未与云端建立过通信。
|
||||
2. **`ONLINE(1)` (在线)**:TCP 连接保持中,或心跳周期内正常。
|
||||
3. **`OFFLINE(2)` (离线)**:网关层面检测到连接断开或心跳超时抛出的事件。
|
||||
|
||||
### 2. 异常断连与重连退避
|
||||
- 硬件网络天然不可靠。设备端在断连后,重连机制必须包含**指数退避(Exponential Backoff)加随机抖动(Jitter)算法**。
|
||||
- **严禁**:断网后设备以固定的 1 秒频率死循环重连。这将在基站恢复或 Broker 重启时引发“重连风暴”,直接导致网关雪崩。
|
||||
|
||||
### 3. 上下线状态管理
|
||||
- 严禁通过轮询设备或单纯依赖心跳报文在业务代码里算超时。
|
||||
- 必须依赖 MQTT Broker 的 **连接/断开 Webhook (或遗嘱消息 Will Message)** 机制,由 Broker 主动回调 `module-iot` 通知设备上下线,业务侧被动更新 DB 状态。
|
||||
严禁在业务层写死轮询来判断设备在线,必须监听 `IotDeviceStateEnum` 的状态翻转事件。
|
||||
@@ -1,52 +1,31 @@
|
||||
# 02-物模型标准设计
|
||||
|
||||
如果你让一个做业务的程序员去处理设备发来的 `01 03 00 00 00 01 84 0A` (Modbus RTU),他会崩溃。
|
||||
**物模型(Thing Specification)**的作用就是把物理世界的设备抽象成程序员能看懂的“对象”。
|
||||
底层网关屏蔽了 JT808、MQTT、TCP Binary 等各种异构协议后,所有推入平台核心业务流的数据必须服从统一的「物模型(Thing Model)」规范。
|
||||
|
||||
## 一、物模型三要素 (Property, Event, Service)
|
||||
## 一、物模型三要素 (IotThingModelTypeEnum)
|
||||
|
||||
所有接入 AIOT 平台的设备,无论是摄像头、烟感还是水表,都必须在这三层结构下被抽象。
|
||||
根据系统的定义,任何设备的物模型结构被强制约束为三大类型:
|
||||
|
||||
### 1. 属性 (Property)
|
||||
描述设备的运行状态(通常是只读或可读写的连续数据)。
|
||||
- **示例**:当前温度 (25.5℃)、工作模式 (Auto)、电池电量 (80%)。
|
||||
- **特点**:业务系统随时可以查询,云端需维护一份最新的副本(设备影子)。
|
||||
### 1. `PROPERTY(1)` (属性)
|
||||
- 描述:反映设备连续的运行状态数据(如温度、电量、当前档位)。
|
||||
- 上报:对应网关的方法 `DEVICE_PROPERTY_POST`。
|
||||
- 业务处理:存入实时库或影子库。属性的设定可通过场景规则触发(`DEVICE_PROPERTY_SET`)。
|
||||
|
||||
### 2. 事件 (Event)
|
||||
设备在运行期间主动向云端发出的瞬时通知。
|
||||
事件分为三个等级:
|
||||
- **INFO (信息)**:如“设备重启完成”。
|
||||
- **WARN (告警)**:如“网络延迟过高”。
|
||||
- **ERROR (故障)**:如“传感器短路”,此类事件通常直接触发规则引擎派生 Ops 工单。
|
||||
### 2. `SERVICE(2)` (服务)
|
||||
- 描述:平台主动下发给设备的指令,设备执行后需要响应结果(如开阀、设置重启参数)。
|
||||
- 调用:对应 `DEVICE_SERVICE_INVOKE`。这更像一种双向 RPC 调用,通常会携带参数 (`IotThingModelParamDirectionEnum`)。
|
||||
|
||||
### 3. 服务 (Service) / 指令
|
||||
云端向设备下发的要求设备执行某个动作的操作,且该操作通常需要硬件执行完毕后返回结果。
|
||||
- **示例**:开门 (openDoor)、设置重启定时 (setRebootTimer)。
|
||||
- **与属性的区别**:设置温度阈值是“写属性”,要求设备清空历史记录是“调服务”。服务更像是一个 RPC 调用。
|
||||
### 3. `EVENT(3)` (事件)
|
||||
- 描述:设备主动上报的瞬时、非连续通知(如硬件故障、越界告警)。
|
||||
- 上报:对应 `DEVICE_EVENT_POST`。
|
||||
- 业务处理:通常直接送入规则引擎(`IotSceneRuleTriggerTypeEnum`)作为触发源。
|
||||
|
||||
## 二、标准 JSON Payload 规范
|
||||
## 二、数据消费去向 (IotDataSinkTypeEnum)
|
||||
|
||||
网关接收到底层报文后,无论是何种私有协议,经过“协议解析脚本”后,推送到业务主逻辑的 JSON 必须符合以下规范:
|
||||
物模型解析后的数据并非只是存在 MySQL 中,系统支持将数据分发到各种目标(Sink)供不同业务消费:
|
||||
- **消息队列**:`ROCKETMQ(30)`, `RABBITMQ(31)`, `KAFKA(32)` —— 适合大数据量的数仓抽取。
|
||||
- **高速缓存**:`REDIS(21)` —— 适合大屏实时展示和设备影子。
|
||||
- **协议转发**:`HTTP(1)`, `TCP(2)`, `WEBSOCKET(3)`, `MQTT(10)` —— 适合外部系统对接。
|
||||
- **持久化**:`DATABASE(20)` —— 适合历史轨迹和报表查询。
|
||||
|
||||
```json
|
||||
{
|
||||
"device_id": "SN_12345678",
|
||||
"timestamp": 1712419200000,
|
||||
"type": "property_report",
|
||||
"data": {
|
||||
"temperature": 26.5,
|
||||
"humidity": 45,
|
||||
"battery_level": 88
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 三、设备影子 (Device Shadow) 机制
|
||||
|
||||
**痛点**:由于设备可能休眠(如 NB-IoT 水表一天只醒一次),App 用户如果在这个时候去点“开阀”或者查询状态,是无法立刻得到设备回应的。
|
||||
|
||||
**解法:设备影子**
|
||||
- 云端在 Redis/MySQL 中永久维护一份该设备最后一次上报的属性镜像。
|
||||
- 用户查询时:直接返回“影子”中的数据。
|
||||
- 用户下发控制时:指令先更新到“影子”的期望值(Expected Value)中,并缓存指令。
|
||||
- 当休眠设备下一次唤醒并上报心跳时,云端比对影子的“实际值”和“期望值”,发现不一致,立刻将缓存的控制指令下发给设备。
|
||||
开发新业务时,请通过配置 Sink 来订阅数据,**不要在核心解析链路里直接写死 DB 插入代码**。
|
||||
@@ -1,37 +1,42 @@
|
||||
# 03-规则引擎与联动策略
|
||||
# 03-规则引擎与告警联动
|
||||
|
||||
有了设备接入和物模型后,IoT 系统算跑通了单机,但 AIOT 的威力在于**联动**。
|
||||
本章节描述大量无序的设备数据如何安全、有效地转化为 Ops 系统的工单任务。
|
||||
规则引擎(Scene Rule)是打通设备感知(IoT)与人工干预(Ops)的桥梁。系统通过灵活的触发器和执行器组合,实现自动化的业务闭环。
|
||||
|
||||
## 一、数据洪流与防抖过滤
|
||||
## 一、规则触发与执行架构
|
||||
|
||||
在将设备异常转化为实际告警或工单之前,**防抖(Debounce)与收敛**是第一道防线。
|
||||
在 `IotSceneRule` 体系下,一个完整的规则包含**触发器 (Trigger)** 和 **执行器 (Action)**。
|
||||
|
||||
### 1. 为什么要做防抖?
|
||||
如果一个温湿度传感器发生故障,它可能会以 1 秒 1 次的频率疯狂上报 `[ERROR] 探头短路`。如果不做拦截直接联动 Ops,安保大叔的手机一分钟内会被弹 60 个“派单通知”,系统也会因为瞬间的数据库写入被压死。
|
||||
### 1. 触发类型 (`IotSceneRuleTriggerTypeEnum`)
|
||||
系统支持 5 种维度的触发方式:
|
||||
- **`DEVICE_STATE_UPDATE(1)`**:设备上下线翻转触发。
|
||||
- **`DEVICE_PROPERTY_POST(2)`**:属性上报触发(如温湿度数值变化)。由于属性可能批量上报,引擎会做拆解匹配。
|
||||
- **`DEVICE_EVENT_POST(3)`**:事件上报触发(如故障事件)。
|
||||
- **`DEVICE_SERVICE_INVOKE(4)`**:服务调用触发。
|
||||
- **`TIMER(100)`**:定时触发(如每天早上 8 点自动执行)。
|
||||
|
||||
### 2. 规则引擎防抖策略
|
||||
- **时间窗口去重**:同一台设备的同一种事件(如烟感报警),在 5 分钟内无论上报多少次,规则引擎只向后置业务流抛出**一次**告警事件。
|
||||
- **状态跳变判断**:只有当属性值从“正常阈值”跨越到“告警阈值”的那个瞬间(Edge Trigger),才触发规则。一直在告警线以上的数据点不重复触发。
|
||||
### 2. 动作类型 (`IotSceneRuleActionTypeEnum`)
|
||||
触发条件满足后,系统可执行如下动作组合:
|
||||
- **联动反控**:
|
||||
- `DEVICE_PROPERTY_SET(1)`:修改另一台设备的属性。
|
||||
- `DEVICE_SERVICE_INVOKE(2)`:调用另一台设备的服务(如温度高触发开风扇)。
|
||||
- **告警流转**:
|
||||
- `ALERT_TRIGGER(100)`:触发告警(生成 `IotAlertRecordDO`)。
|
||||
- `ALERT_RECOVER(101)`:解除告警。
|
||||
|
||||
## 二、IoT 到 Ops 的正向联动链路
|
||||
## 二、告警系统与 Ops 的联动
|
||||
|
||||
从设备端发现问题,到现场人员赶到处理。
|
||||
告警 (`ALERT`) 是连接 Ops 派单引擎的关键介质。
|
||||
|
||||
1. **规则命中**:设备上报数据解析出 `water_leak = true`,触发 `规则ID=102: 水管漏水告警`。
|
||||
2. **事件转换**:规则引擎组装一个标准的「内部系统事件(Internal Event)」,包含 `设备ID`、`发生时间`、`发生物理位置(查设备表获得)`、`告警级别`。
|
||||
3. **跨域调用**:`module-iot` 通过内部 API(禁止通过外网网关)调用 `module-ops` 的 `生成紧急工单` 接口。
|
||||
4. **接力执行**:Ops 系统接管,按照其内部的抢单、强推播逻辑(参见 [[../02-Ops领域/03-安保业务核心链路.md]]),将任务压给最近的安保或维修工。
|
||||
### 1. 告警产生
|
||||
当规则引擎执行了 `ALERT_TRIGGER` 动作,系统会在 `IotAlertRecord` 表中写入一条告警记录。该记录包含触发的规则 ID、设备 ID 和严重等级。
|
||||
|
||||
## 三、Ops 到 IoT 的逆向状态闭环(反写)
|
||||
### 2. 联动派单 (`EventDomainEnum.RULE`)
|
||||
告警生成后,将向外抛出事件(领域标识为 `RULE`)。
|
||||
此时,`module-ops` 监听到告警事件,并根据内部逻辑:
|
||||
- 如果属于紧急安保事件 -> 派发 `SECURITY` 类型的抢单任务给就近保安。
|
||||
- 如果属于设备故障 -> 派发 `REPAIR` 类型的工单给工程组。
|
||||
|
||||
仅仅把单派出去是不够的,还需要实现信息闭环,防止 IoT 控制台和 Ops 控制台两张皮。
|
||||
|
||||
### 1. 告警状态解绑
|
||||
- IoT 侧的告警大屏上,该设备的告警状态会亮起红灯。
|
||||
- 这盏红灯何时熄灭?不能仅仅依赖传感器下一次上报“正常”(因为传感器可能坏死)。
|
||||
- **必须由 Ops 侧驱动**:当维修工人在手机 App 上提交了现场修复照片,并将维修工单流转为 `COMPLETED` 状态时,Ops 系统回调 IoT 的接口,将对应的那条告警记录状态变更为【人工已解除】。
|
||||
|
||||
### 2. 现场反控配合
|
||||
- 维修工到达现场处理故障时,由于控制箱被锁,他可以在 App 的工单详情页,点击「临时断电调试」。
|
||||
- 这个点击动作,穿透 Ops 域,直接调用 IoT 领域的“服务下发(Service Call)”接口,实现对现场断路器的远程切断。这证明了我们在架构中采用统一后端底座的优越性。
|
||||
### 3. 告警处理闭环 (`IotAlertRecordProcessReqVO`)
|
||||
当维修工或保安在现场处理完毕,通过移动端(App / 智能工牌)提交完工(状态变为 `COMPLETED`)后,Ops 系统必须调用 IoT 领域的处理接口。
|
||||
- 调用 `IotAlertRecordController.processAlert()` 进行状态核销。
|
||||
- 或者由设备恢复正常状态后,触发规则引擎的 `ALERT_RECOVER(101)` 动作实现自动核销。
|
||||
Reference in New Issue
Block a user