第五部分:详细设计文档
本章节在概要设计基础上,对软件各模块、硬件各部件、数据库、接口等进行细化设计,明确具体实现逻辑、数据结构、流程细节、硬件电路与固件设计,为编码与硬件集成提供直接依据。
5.1 软件详细设计(独立模块)
5.1.1 设备接入模块详细设计
5.1.1.1 模块类设计(以Java/Spring为例)
| 类名 | 职责 | 关键方法 |
|---|---|---|
KafkaInboundListener | 消费 EMQX Bridge 写入的上行 Kafka Topic | telemetry(payload), event(payload), commandAck(payload) |
KafkaCommandPublisher | 向 Kafka 下行 Topic 发布指令 | publish(CommandDown) |
DeviceService | 设备、绑定、遥测、指令和告警领域用例 | ingestTelemetry, sendCommand, handleCommandAck |
TokenAuthenticationFilter | 从 Redis Token 恢复登录身份 | doFilterInternal |
RedisSessionStore | 登录会话 TTL 管理 | save, find, delete |
5.1.1.2 设备接入流程
- MQTT 接入:设备连接 EMQX → EMQX 校验设备凭据和 Topic ACL → 设备属性/事件触发 Rule/Bridge → 写入 Kafka 上行 Topic → Spring Boot Consumer 处理。
- 指令下行:Spring Boot 写
device_command→ 发布 Kafkacommand.down→ EMQX Bridge 发布设备 MQTT Topic → 设备执行并回 ACK → ACK 经 Kafka 回写指令状态。 - TCP/HTTP 扩展:后续独立适配器负责连接和鉴权,标准化后写入同一 Kafka Topic;业务单体不维护 TCP/MQTT 长连接。
5.1.1.3 状态管理机制
- 使用Redis存储设备在线状态,key:
device:status:{deviceId},value:online/offline,TTL:90秒(心跳超时)。 - EMQX 将连接/断开事件经 Kafka 转发,后端结合事件和 Redis TTL 更新在线态。
- MySQL 保存最终设备状态与最后活跃时间,Redis 只保存可重建的短时在线缓存。
5.1.2 数据采集与存储模块详细设计
5.1.2.1 数据采集流程
-
设备上报 → EMQX → Kafka
iot.device.telemetry.up→KafkaInboundListener→ 格式校验 → 解析为标准 JSON:json
{ "deviceId": "xxx", "timestamp": 1700000000000, "data": {"temperature": 25.6, "humidity": 60} } -
异常检测:根据预设阈值(如温度>50℃)触发告警,写入告警表。
-
存储策略:一期遥测、设备配置和业务元数据写入 MySQL;达到容量阈值后遥测迁移专用时序存储,业务表继续使用 MySQL。
5.1.2.2 数据清理与备份
- 原始数据保存30天,自动转存到冷存储(对象存储)或删除。
- 每日凌晨2点执行数据备份(全量+增量),备份保留7天。
5.1.3 远程控制模块详细设计
5.1.3.1 控制指令下发流程
- 用户在 Vue 管理后台或小程序发起控制 → 调用
POST /api/admin/commands或用户设备指令接口。 - 后端生成 commandId → 写
device_command,状态为PENDING。 KafkaCommandPublisher发布iot.device.command.down,成功后状态为SENT。- EMQX Bridge 将 Kafka 消息发布到设备 MQTT Topic。
- 设备 ACK 经
iot.device.command.ack返回,后端更新为SUCCEEDED/FAILED。 - 一期增强加入 Outbox、10 秒超时、最多 3 次重试、失败告警和迟到 ACK 保护。
5.1.3.2 批量控制设计
- 支持选择多个设备 → 后台并发调用单设备控制逻辑,使用线程池(最大10线程)。
- 记录批量任务ID,可查询每个设备的执行结果。
5.1.4 用户管理与权限模块详细设计
5.1.4.1 权限模型(RBAC)
- 表结构:
user、role、permission、user_role、role_permission - 预置角色:
- 管理员:所有权限
- 普通用户:仅查看自己设备的实时数据及历史数据
- 运维人员:设备调试、固件升级、故障日志查看
5.1.4.2 认证与授权
- 登录生成不透明 Token,存入 Redis
iot:session:{token},默认 TTL 24 小时。 - 接口权限使用 Spring Security
@PreAuthorize,当前角色为 ADMIN、OPERATOR、USER。 - 设备级权限:用户与设备通过
iot_device.owner_id关联,查询和控制时强制过滤。
5.1.5 接口详细设计(RESTful API示例)
5.1.5.1 设备注册接口
text
POST /api/admin/devices
Request Body: { "deviceName": "sensor_01", "serialNumber": "SN001", "productId": "p_xxx" }
Response: { "code": 0, "data": { "id": "d_xxx", "deviceSecret": "仅创建时返回", "bindCode": "IOT-SN001" } }
5.1.5.2 数据查询接口
text
GET /api/mini/devices/{deviceId}
Response: { "code": 0, "data": { "id": "d_xxx", "properties": {...}, "telemetry": [...] } }
5.1.5.3 控制指令接口
text
POST /api/admin/commands
Request: { "deviceId": "d_xxx", "name": "setPower", "params": { "power": false } }
Response: { "code": 0, "data": { "id": "cmd_xxx", "status": "SENT" } }
5.2 硬件详细设计(独立模块)
5.2.1 感知设备详细设计(以温湿度传感器为例)
5.2.1.1 硬件选型(示例)
| 组件 | 型号/规格 | 说明 |
|---|---|---|
| 传感器芯片 | SHT30 | 精度:±0.3℃ / ±2%RH |
| 主控MCU | ESP32-C3 | 支持Wi-Fi/BLE,低功耗 |
| 通信模块 | 内置Wi-Fi | 支持MQTT/TCP |
| 电源 | 3.7V锂电池 + 充电管理TP4056 | 续航约6个月(每小时上报一次) |
5.2.1.2 电路连接
- SHT30的SCL→ESP32的IO22,SDA→IO21,VCC→3.3V,GND→GND
- 电池正极→TP4056的BAT+,TP4056的OUT+→ESP32的VIN
- 预留UART0作为调试口
5.2.1.3 固件设计
- 采用Arduino/ESP-IDF开发
- 主循环:读取传感器(每10秒一次)→ 平均值计算(每分钟)→ 通过MQTT上报 → 进入深度睡眠(剩余时间)
- 上报频率可远程配置(默认60秒)
- 支持OTA升级
5.2.2 控制终端详细设计
5.2.2.1 硬件组成
- 主控:STM32F103C8T6
- 继电器模块(控制220V设备)
- 通信接口:SPI接ESP8266(透传MQTT)
- 本地存储:AT24C02(保存设备配置)
5.2.2.2 控制逻辑
- 监听通信模块转发的控制指令 → 解析指令类型(开关、PWM调光等)→ 驱动GPIO/继电器 → 读取传感器反馈(可选)→ 返回执行结果。
5.2.3 硬件协同时序
text
[传感器] --> UART --> [控制终端] --> SPI --> [通信模组] --> MQTT --> [平台]
[平台] --> MQTT --> [通信模组] --> SPI --> [控制终端] --> GPIO --> [执行器]
5.3 数据库详细设计
5.3.1 关系型数据库表设计(MySQL)
5.3.1.1 设备表 device
| 字段 | 类型 | 说明 |
|---|---|---|
| device_id | VARCHAR(32) PK | 设备唯一标识 |
| device_name | VARCHAR(64) | 设备名称 |
| protocol | ENUM('MQTT','TCP','HTTP') | 接入协议 |
| product_key | VARCHAR(32) | 产品型号 |
| secret | VARCHAR(64) | 设备密钥(加密存储) |
| status | TINYINT | 0-离线,1-在线 |
| last_active_time | DATETIME | 最后心跳时间 |
| created_time | DATETIME | 注册时间 |
5.3.1.2 用户表 user
| 字段 | 类型 | 说明 |
|---|---|---|
| user_id | INT AUTO PK | |
| username | VARCHAR(32) UNIQUE | |
| password | VARCHAR(128) | bcrypt加密 |
| role_id | INT | 关联角色表 |
| ... | ... |
5.3.1.3 指令日志表 control_log
| 字段 | 类型 | 说明 |
|---|---|---|
| command_id | VARCHAR(36) PK | |
| device_id | VARCHAR(32) | |
| command | TEXT | 指令内容 |
| status | VARCHAR(16) | pending/succeeded/failed |
| retry_count | INT | 重试次数 |
| create_time | DATETIME | |
| finish_time | DATETIME |
5.3.2 设备遥测表设计(MySQL)
当前单体阶段将遥测数据统一写入 MySQL 的 device_telemetry 表,避免在中间件地址和实际容量尚未确认前引入额外数据库。Kafka 上行消费者按 (device_id, message_id) 幂等落库。
| 字段 | 类型 | 说明 |
|---|---|---|
| id | VARCHAR(64) PK | 遥测记录 ID |
| message_id | VARCHAR(80) | 消息唯一标识;与 device_id 组成唯一键 |
| device_id | VARCHAR(64) | 设备 ID |
| event_time | TIMESTAMP(6) | 设备事件时间 |
| data_json | LONGTEXT | 遥测属性 JSON |
索引 idx_telemetry_device_time(device_id, event_time) 支持按设备和时间范围查询。数据量增长后,可保持 Kafka 消息契约和应用服务接口不变,将遥测存储模块独立拆分到专用时序存储。