feat(wm-iot): #30 设备影子服务+OTA固件升级完整实现

- entity: DeviceShadow, OtaFirmware, OtaTask, OtaUpgradeRecord
- service: DeviceShadowService (Redis Hash + TTL 24h, 上报/期望/delta/离线检测/批量查询)
- service: OtaService (固件管理/升级任务创建按批次/进度追踪/结果统计)
- controller: DeviceShadowController /api/iot/shadow/*
- controller: OtaController /api/iot/ota/*
- config: RedisConfig (RedisTemplate JSON序列化)
- SQL DDL: iot_ota_firmware, iot_ota_task, iot_ota_upgrade_record
- test: DeviceShadowServiceTest + OtaServiceTest (mock Redis + mock DB)
This commit is contained in:
2026-06-14 18:22:28 +08:00
parent 69fd9d7c41
commit 9763a5700d
13 changed files with 1858 additions and 29 deletions
@@ -0,0 +1,84 @@
-- =============================================
-- 智慧水务管理系统 - 设备影子 + OTA固件升级 DDL
-- 版本: V_shadow_ota
-- =============================================
-- OTA固件版本表
CREATE TABLE IF NOT EXISTS iot_ota_firmware (
id BIGSERIAL PRIMARY KEY,
model_id BIGINT NOT NULL REFERENCES iot_device_model(id),
firmware_version VARCHAR(20) NOT NULL,
file_url VARCHAR(500) NOT NULL,
description TEXT,
status VARCHAR(20) NOT NULL DEFAULT 'draft', -- draft/published/deprecated
md5 VARCHAR(64),
file_size BIGINT DEFAULT 0,
published_by VARCHAR(50),
published_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
UNIQUE(model_id, firmware_version)
);
COMMENT ON TABLE iot_ota_firmware IS 'OTA固件版本表';
COMMENT ON COLUMN iot_ota_firmware.model_id IS '关联设备模型ID';
COMMENT ON COLUMN iot_ota_firmware.firmware_version IS '固件版本号';
COMMENT ON COLUMN iot_ota_firmware.file_url IS '固件文件下载地址';
COMMENT ON COLUMN iot_ota_firmware.status IS '状态: draft-草稿/published-已发布/deprecated-已废弃';
COMMENT ON COLUMN iot_ota_firmware.md5 IS 'MD5校验值';
CREATE INDEX IF NOT EXISTS idx_ota_firmware_model ON iot_ota_firmware(model_id);
CREATE INDEX IF NOT EXISTS idx_ota_firmware_status ON iot_ota_firmware(status);
-- OTA升级任务表
CREATE TABLE IF NOT EXISTS iot_ota_task (
id BIGSERIAL PRIMARY KEY,
firmware_id BIGINT NOT NULL REFERENCES iot_ota_firmware(id),
firmware_version VARCHAR(20) NOT NULL,
target_type VARCHAR(30), -- 目标设备类型
target_area VARCHAR(50), -- 目标区域
target_device_ids JSONB, -- 目标设备ID列表
task_status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending/executing/completed/failed/cancelled
batch_size INT DEFAULT 10, -- 每批升级数量
total_devices INT DEFAULT 0, -- 总设备数
success_count INT DEFAULT 0,
failed_count INT DEFAULT 0,
executing_count INT DEFAULT 0,
created_by VARCHAR(50),
executed_at TIMESTAMP,
completed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
COMMENT ON TABLE iot_ota_task IS 'OTA升级任务表';
COMMENT ON COLUMN iot_ota_task.task_status IS '任务状态: pending-待执行/executing-执行中/completed-已完成/failed-失败/cancelled-已取消';
COMMENT ON COLUMN iot_ota_task.batch_size IS '每批升级设备数量';
CREATE INDEX IF NOT EXISTS idx_ota_task_firmware ON iot_ota_task(firmware_id);
CREATE INDEX IF NOT EXISTS idx_ota_task_status ON iot_ota_task(task_status);
CREATE INDEX IF NOT EXISTS idx_ota_task_created ON iot_ota_task(created_at DESC);
-- OTA升级记录表(每台设备一条记录)
CREATE TABLE IF NOT EXISTS iot_ota_upgrade_record (
id BIGSERIAL PRIMARY KEY,
task_id BIGINT NOT NULL REFERENCES iot_ota_task(id),
device_id BIGINT NOT NULL REFERENCES iot_device(id),
device_sn VARCHAR(100) NOT NULL,
from_version VARCHAR(20), -- 升级前版本
to_version VARCHAR(20), -- 目标版本
status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending/executing/success/failed/timeout
fail_reason VARCHAR(500),
progress INT DEFAULT 0, -- 进度百分比 0-100
started_at TIMESTAMP,
completed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW()
);
COMMENT ON TABLE iot_ota_upgrade_record IS 'OTA升级记录表(单台设备)';
COMMENT ON COLUMN iot_ota_upgrade_record.status IS '升级状态: pending-待升级/executing-升级中/success-成功/failed-失败/timeout-超时';
CREATE INDEX IF NOT EXISTS idx_ota_record_task ON iot_ota_upgrade_record(task_id);
CREATE INDEX IF NOT EXISTS idx_ota_record_device ON iot_ota_upgrade_record(device_id);
CREATE INDEX IF NOT EXISTS idx_ota_record_sn ON iot_ota_upgrade_record(device_sn);
CREATE INDEX IF NOT EXISTS idx_ota_record_status ON iot_ota_upgrade_record(status);