# SecMPS 整合方案 — 最终评估报告 > **评估日期**: 2026-05-16 > **评估对象**: SecMPS_最终整合方案_v2.0.md > **参考依据**: Owl API 文档 / Owl GitHub / ZLMediaKit 官方文档 / ZLMediaKit GitHub / 数据字典设计 --- ## 一、评估方法 以资深架构师经验,对整合方案进行三个维度的交叉验证: 1. **方案自洽性**:章节间逻辑是否一致,API 定义 ↔ 数据模型 ↔ 同步策略是否闭环 2. **对 Owl+ZLMediaKit 的准确性**:方案定义的接口和流程是否与 Owl v1.3.0 / ZLMediaKit master 实际行为匹配 3. **工程可落地性**:是否所有细节都有明确定义,是否存在"开发时再说"的模糊地带 共发现 **14 个问题**,按严重程度分为 P0(阻塞实施)、P1(影响质量)、P2(优化项)。 --- ## 二、P0 — 必须修复(4 项) ### P0-1:第四章示例代码与 A3 接口规范矛盾 **问题描述**: §四示例代码(第 263-265 行)在每次同步时写入 `DeviceName = d.Name` 和 `DeviceCategory = d.Category`。但 A3 接口规范明确说"网关不碰管理员字段,首次入库写全量,后续仅更新网关负责的列"。这导致管理员手动改过的设备名称每次同步后被网关覆盖。 **影响**:管理员的设备重命名操作会被同步覆盖,用户投诉 **解决方案**: ```csharp // 区分首次入库与增量更新 if (entity.DeviceId == 0) // 首次入库 { entity.DeviceName = d.Name; entity.DeviceCategory = d.Category; entity.DeviceGroup = d.Group; } // 增量更新:只写网关负责的字段 entity.IsOnline = d.IsOnline ? "在线" : "离线"; entity.IsParent = d.IsParent ? "是" : "否"; entity.ExtraData = d.ExtraDataJson; entity.LastSyncTime = DateTime.UtcNow; ``` --- ### P0-2:A3 设备同步中 `parentSourceId` → `ParentDeviceId` 解析链路缺失 **问题描述**: A3 请求中设备携带 `parentSourceId: "1001"`(第三方 ID),但 Vol.Pro 需要 `ParentDeviceId`(本地主键)。从第三方 ID 到本地主键的映射逻辑完全未定义。 **影响**:子设备无法挂到父设备下,设备树断裂 **解决方案**: 同步前先做映射表查询: ```csharp // 批量取出当前网关所有设备 var allIds = await _db.base_device .Where(x => x.GatewayNodeId == nodeId) .ToDictionaryAsync(x => (x.AdapterCode, x.SourceId), x => x.DeviceId); // 解析 parentSourceId int? parentDeviceId = null; if (!string.IsNullOrEmpty(d.ParentSourceId)) allIds.TryGetValue((d.AdapterCode, d.ParentSourceId), out var pid); parentDeviceId = pid > 0 ? pid : null; entity.ParentDeviceId = parentDeviceId; ``` 补充到 §四 代码示例中。 --- ### P0-3:网关重启注册时 NodeId 分配逻辑未定义 **问题描述**: 网关重启再次调用 A1 `/register`,`gateway_nodes` 表中 `NodeCode` 已存在。当前文档只说注册流程,没有说明是覆盖还是报错。如果新建 NodeId,则 `base_device.GatewayNodeId` 指向旧 ID 断裂。 **影响**:网关重启后设备归属丢失 **解决方案**: A1 接口改为 Upsert 逻辑: ``` POST /register → NodeCode 匹配 → 更新 AdapterTypes/BaseUrl/IsOnline=在线 → 返回已有 NodeId NodeCode 不匹配 → 插入新记录 → 返回新 NodeId → 401(防止未授权节点) ``` 补充到 §2.1 流程描述和 A1 API 规范中。 --- ### P0-4:Owl 管理端口错误 **问题描述**: Owl README 和 Docker Compose 明确 Owl Web 管理端口 = `15123`。方案 `appsettings.json` 和 §七部署拓扑均写 `owl_host:80`。 **影响**:网关无法连接 Owl,所有视频功能不可用 **解决方案**: - `appsettings.json` 中 Owl BaseUrl → `http://owl_host:15123` - §七部署拓扑中 Owl 端口标记为 `:15123` - 注意:ZLM 自身 HTTP 端口是 `8000`,但由 Owl 内部调用,网关不接触 --- ## 三、P1 — 影响实施质量(6 项) ### P1-1:PTZ 接口仅实现 continuous + stop **问题描述**: owl_api_research.md §6.1 和 Owl GitHub 确认:Owl 代码中仅实现了 `continuous`(持续移动)和 `stop`(停止),`preset`(预置位)、`absolute`(绝对定位)、`relative`(相对定位)均返回错误。ONVIF PTZ 标记为 TODO。 方案 §2.3 适配器矩阵和 B7 API 没有注明此限制。 **影响**:开发前端云台面板时做了预置位下拉等功能,部署后不可用 **解决方案**: - B7 接口标注:"仅支持 continuous (方向移动) + stop (停止)" - 前端云台面板:仅显示方向键(↑↓←→)+ 停止按钮,不显示预置位 - OwlAdapter.PtzControlAsync 实现:ONVIF 设备直接返回错误 --- ### P1-2:视频通道在 base_device 和 video_channel 中的双重身份不清 **问题描述**: §6 Owl 同步说 "Upsert base_device(ParentDeviceId=NVR) + video_channel",但 §3.6 层级示例中摄像机是叶子节点没有子设备。一个 Owl 通道到底是 base_device 的子记录还是 video_channel 的独立记录?还是两者都是? **影响**:开发者不清楚通道数据写入哪张表的哪个字段 **解决方案**: 明确:一个 Owl 通道 = 2 条记录: 1. `base_device` 子记录(DeviceName="通道01", DeviceCategory=摄像机, ParentDeviceId=NVR的DeviceId, ExtraData=null) 2. `video_channel` 扩展记录(DeviceId=通道的DeviceId, OwlStreamApp, OwlStreamName, HasPtz, SnapshotUrl) 在 §3.6 层级示例中增加通道示例: ``` NVR (IsParent=是) ├── 通道01 (base_device子记录, video_channel.OwlStreamApp="rtp") ├── 通道02 (base_device子记录, video_channel.OwlStreamApp="rtp") ``` --- ### P1-3:回放取流与实时取流走不同的 Owl 端点 **问题描述**: - 实时播放:`POST /channels/:id/play` - 回放播放:`GET /recordings/channels/:cid/index.m3u8?start_ms=&end_ms=&token=` 两者是 Owl 的不同端点,方案 B6 只有一个 `/live` 路径。 **影响**:回放功能无法对接 Owl **解决方案**: B6 拆分为两个端点: ``` GET /streams/{adapter}/{channelId}/live → Owl POST /channels/:id/play GET /streams/{adapter}/{channelId}/playback?start=&end= → Owl GET /recordings/channels/:cid/index.m3u8 ``` IHasStreams 接口不变(已有 GetLiveUrlAsync 和 GetPlaybackUrlAsync),只修正 B 组 API 路径。 --- ### P1-4:告警确认后 Vol.Pro 本地状态更新不闭环 **问题描述**: B9 调网关确认告警写回第三方成功,但 `iot_alarm.State` 谁来更新?当前文档没有说明这个回写链路。 **影响**:管理端显示告警仍为"未确认",需等下次 A4 同步才刷新 **解决方案**: B9 确认成功后,Vol.Pro 侧同步更新本地: ``` POST /alarms/{adapter}/{alarmId}/confirm 成功 → Vol.Pro 更新 iot_alarm SET State='已确认', ConfirmTime=NOW() ``` 不需要网关二次推送。在 B9 接口规范中补充此说明。 --- ### P1-5:video_record 同步策略缺失 **问题描述**: §六同步策略有设备同步、告警同步、反向控制,但没有录像记录的同步时机和频率。 **影响**:录像数据永远不会写入 video_record 表 **解决方案**: 补充 §六:Owl 录像数据同步策略 —— - **方式一**(推荐):管理端点击"查看回放"时,网关实时调 Owl `GET /recordings` → 返回给管理端 → 同时写入 video_record 表 - **方式二**(备选):网关定时(每 10 分钟)调 Owl `GET /recordings` → 走 A3 扩展同步 → 写入 video_record 建议先用方式一,方式二在 Phase 3 优化时引入。 --- ### P1-6:AdapterCode 双段格式无约束 **问题描述**: `"mc4:31号库房"` 中分隔符 `:` 和实例名字符集没有规范。如果实例名包含 `:` 会导致解析歧义。 **影响**:网关配置或同步时数据损坏 **解决方案**: 定义格式规范(补充到 §2.2): ``` AdapterCode = "{AdapterType}:{InstanceName}" AdapterType: 字母数字,对应网关注册的 Adapter 类名(如 MC4、Owl) InstanceName: 字母数字下划线,对应具体网关实例(如 31ku) 分隔符: ':' 示例: "MC4:31ku"、"Owl:main"、"HikvisionISC:center" ``` --- ## 四、P2 — 优化项(4 项) ### P2-1:子设备离线状态级联规则(明确即可) **问题描述**: §2.1 说网关离线 → 设备离线,但网关在线时父设备(采集器)离线,子设备是否级联标记离线? **解决方案**: 网关在 A3 同步时如实上报每个子设备的 isOnline(MC4.0 树中已有此信息),Vol.Pro 不做推断,信任网关数据。在 §六同步策略中补充此行说明即可。 --- ### P2-2:数据字典初始化运维指引(补充附录) **问题描述**: 方案依赖 7 个数据字典(DeviceCategory 18 值、DeviceGroup 5 值、IsParent/IsOnline/Enable/IsControlPoint/AlarmLevel/State),但没有初始化指引。 **解决方案**: 在文档末尾增加「附录 A:字典初始化清单」,列出每个字典的 Code/Name/Value 对照表,运维人员在 Vol.Pro 管理端按表创建。 --- ### P2-3:video_channel 流地址字段用途说明(补充注释) **问题描述**: video_channel 有 `OwlStreamApp/OwlStreamName/SnapshotUrl`,B6 取流实时调网关获取。这些字段的实际用途没说。 **解决方案**: 注明为缓存——首次取流后写入 video_channel,下次先查缓存,缓存过期(或 Owl 重启后)再调 B6 实时获取。在 video_channel 表注释中补充说明。 --- ### P2-4:Owl AI 事件可接入告警(建议纳入 Phase 1 可选范围) **问题描述**: Owl 有 YOLO 本地检测 + `GET /events` 接口,AI 事件可走 A4 告警同步。 **解决方案**: 在 OwlAdapter 中可选实现 IHasAlarms,将 `GET /events` 的 AI 检测事件映射为 StandardAlarm(AlarmLevel=提示或普通)。在 §六同步策略中补充可选说明,建议 Phase 1 范围中列入。 --- ## 五、架构正确性确认 以下方面经过 Owl+ZLMediaKit 双文档验证,确认正确: | 验证项 | 状态 | |--------|:--:| | 三层架构(前端→网关→Owl)不直接接触 ZLM | ✅ | | Owl 代理播放地址 `/proxy/sms/...` | ✅ | | Owl RTP 收流→ZLM 转协议→多格式输出的链路 | ✅ | | Owl Webhook 自动配置 ZLM(启动时 SetServerConfig) | ✅ | | JWT Token 管理 + RSA 加密登录 | ✅ | | 设备/通道 CRUD 对应 Owl API | ✅ | | 取流端点返回 WS-FLV/HTTP-FLV/HLS/WebRTC/RTMP/RTSP | ✅ | | Owl↔ZLM 联动(OpenRtpServer/CloseRtpServer/AddStreamProxy 等) | ✅ | | 按需拉流 + 30s 无人观看自动关闭(ZLM on_stream_none_reader → Owl 通知 ZLM 关流) | ✅ | | 云录像由 Owl 管理(ZLM MP4 录制→Owl on_record_mp4 hook→入库) | ✅ | | GB28181 设备注册与心跳是 SIP 层自动完成(Vol.Pro 只查 HTTP API) | ✅ | | 播放地址通过 Owl `/proxy/sms/` 反向代理到 ZLM(前端不直接访问 ZLM) | ✅ | --- ## 六、总结 | 优先级 | 数量 | 类型 | |:---:|:--:|------| | P0 | 4 | 阻塞性缺陷(代码矛盾、链路缺失、端口错误、注册逻辑缺失) | | P1 | 6 | 实施质量影响(PTZ限制、通道身份、回放端点、告警闭环、录像缺失、格式规范) | | P2 | 4 | 优化项(级联规则、字典指引、缓存说明、AI事件) | | ✅ | 12 | 已验证正确 | **总体评价**:方案架构方向完全正确,Owl+ZLMediaKit 对接路径准确。14 个问题中 P0/P1 共 10 项,全部为配置级或接口路径级微调,不涉及架构推翻。修复后可直接作为实施基准。 --- > 本报告应作为 SecMPS_最终整合方案_v2.0.md 的修正依据。建议将 P0/P1 问题修复合入方案文档后再开始 Phase 1。