城市感知设备怎么统一接入?从多协议网关到设备模型的中间件架构设计

做城市级AI视觉或物联网平台,经常会遇到一个问题:

设备接得越多,平台反而越难维护。

摄像头可能走ONVIF、GB/T 28181或者厂商SDK;环境传感器可能走MQTT、Modbus;还有门禁、道闸、边缘终端以及各种私有协议。

如果每增加一种设备,上层业务就增加一套适配代码,最终很容易变成:

设备品牌 × 协议 × 业务系统 = 大量重复开发。

所以设备接入中间件真正要解决的,不是"支持多少协议",而是:

怎么把不同设备转换成统一、稳定、可扩展的能力模型。


一、先把整个设备接入链路拆开

一个比较清晰的架构可以分成5层:

text 复制代码
┌────────────────────────────────────┐
│ 业务应用层:AI分析 / 告警 / GIS / 业务系统 │
├────────────────────────────────────┤
│ 设备抽象层:属性 / 事件 / 服务 / 能力模型   │
├────────────────────────────────────┤
│ 协议适配层:ONVIF / GB28181 / MQTT / SDK │
├────────────────────────────────────┤
│ 接入网关层:TCP / UDP / HTTP / SIP等      │
├────────────────────────────────────┤
│ 网络与设备层:以太网 / 4G / 5G / LoRaWAN等 │
└────────────────────────────────────┘

核心原则只有一句:

上层业务不直接依赖具体厂商协议。

比如业务系统想做"摄像机预置位控制",调用的应该是统一设备服务,而不是:

text 复制代码
if 海康:
    调海康SDK
elif 大华:
    调大华SDK
elif 宇视:
    调宇视SDK

否则设备越多,技术债越重。


二、协议适配层:不要把"协议"和"设备能力"混在一起

不同协议解决的问题并不完全相同。

例如:

GB/T 28181主要用于视频监控联网场景中的注册、目录、点播和媒体传输等能力。

ONVIF更偏向IP安防设备互操作。Profile T支持高级视频流、H.264/H.265、事件和元数据等能力;Profile M进一步标准化分析元数据和事件。

MQTT则是典型的轻量级发布/订阅消息协议,很适合IoT设备和边缘节点消息通信。

所以工程上不要做成一个巨大的:

text 复制代码
DeviceManager

更合理的是把协议实现做成插件。

例如:

text 复制代码
drivers/
├── gb28181/
├── onvif/
├── mqtt/
├── modbus/
├── vendor_sdk/
└── custom/

每个Driver负责:

text 复制代码
设备发现
→ 认证/注册
→ 建立连接
→ 数据解析
→ 状态上报
→ 指令转换
→ 心跳
→ 重连
→ 释放资源

这样新增设备时,改的是协议插件,而不是整个业务平台。


三、真正重要的是"统一设备模型"

协议适配完成以后,还需要再做一次抽象。

一个设备可以统一描述为:

json 复制代码
{
  "deviceId": "camera_001",
  "deviceType": "camera",
  "properties": {},
  "events": [],
  "services": [],
  "capabilities": []
}

其中:

Properties表示设备当前状态,比如在线状态、码率、水位、温度。

Events表示设备产生的事件,例如离线、告警、目标出现。

Services表示设备可以执行的动作,比如抓图、PTZ控制、重启。

Capabilities表示设备具备哪些能力。

这样上层系统只需要面向统一模型开发。

底层到底是哪个品牌,业务层不需要知道。


四、视频设备要特别处理"能力差异"

这里很容易踩坑。

即使两台摄像机都支持ONVIF,也不意味着它们支持完全一样的功能。

有的支持PTZ;

有的不支持。

有的能够输出分析Metadata;

有的只能提供视频流。

ONVIF本身也是通过不同Profile定义互操作能力,而不是"支持ONVIF就什么都支持"。

所以设备模型里最好不要只有:

json 复制代码
"online": true

而应该有Capability:

json 复制代码
{
  "capabilities": [
    "LIVE_VIDEO",
    "PTZ",
    "SNAPSHOT",
    "ANALYTICS_METADATA"
  ]
}

上层业务先判断能力,再决定功能是否可用。

这比大量厂商判断逻辑干净得多。


五、设备影子解决的不是"在线",而是"状态同步"

IoT场景中还有一个典型问题:

设备随时可能离线。

因此平台可以维护设备的逻辑状态,例如:

json 复制代码
{
  "deviceId": "sensor_001",
  "reported": {
    "samplingInterval": 30
  },
  "desired": {
    "samplingInterval": 60
  }
}

其中:

reported代表设备最后实际报告的状态。

desired代表平台希望设备达到的状态。

设备重新上线以后,再根据差异进行同步。

但这里需要特别注意:

设备影子不能等同于无限期指令队列。

例如:

"5分钟后开启闸门"

如果设备离线一天以后重新上线,再执行这条旧指令显然有风险。

所以异步指令至少还应该包含:

TTL、版本号、幂等ID和执行条件。

设备影子的核心是:

状态最终一致。

不是"离线期间所有命令都永久保存"。


六、消息总线:设备接入以后不要直接打业务接口

设备数量增加以后,另一个常见问题是:

设备事件直接调用业务服务。

结果任何一个业务服务变慢,都可能把接入链路拖死。

更合理的方式是:

text 复制代码
设备
 ↓
接入网关
 ↓
协议标准化
 ↓
消息总线
 ↓
规则引擎 / AI / 告警 / 存储

例如:

text 复制代码
camera.motion.detected
sensor.waterlevel.changed
device.offline
ai.object.detected

统一进入Kafka等消息系统。

这样接入层和业务层就能解耦。


七、规则引擎不要写死在业务代码里

城市感知系统往往需要大量规则。

例如:

text 复制代码
水位 > 阈值
AND
持续时间 > 5min
AND
设备状态正常
THEN
产生异常事件

或者:

text 复制代码
视频发现人员
AND
区域 = 禁入区域
AND
时间 = 非作业时段
THEN
触发复核

这类规则如果全部写进Java业务代码,每次改阈值都要发布版本。

更合理的是把:

事件 → 条件 → 动作

做成独立规则层。

复杂时序事件还可以交给Flink等流处理框架进行窗口计算和状态处理。

Flink的Checkpoint可以保存流处理状态,并在故障后恢复计算状态和流位置。

但要注意:

Checkpoint ≠ 整条系统天然Exactly Once。

端到端语义仍取决于Source、消息系统和Sink是否支持重放、事务或者幂等。


八、"接入网关无状态"这个说法其实不够准确

设备网关经常维护:

TCP连接;

SIP注册;

心跳;

Session;

设备在线状态。

因此它不可能完全无状态。

更准确的设计应该是:

连接状态本地化,业务状态外置化。

也就是:

text 复制代码
本地维护:
Connection / Session

外部存储:
Device Metadata
Device Shadow
Business State
Event State

这样某个Gateway实例宕机以后,设备重新连接到其他节点时,业务状态仍然能够恢复。

目标不是:

让网关完全没有状态。

而是:

让节点故障不会造成不可恢复的业务状态丢失。


九、Redis Cluster和Sentinel不要混着写

这也是很多架构图里的常见错误。

Redis Sentinel主要解决非Redis Cluster部署下的监控和自动故障转移问题;Redis官方文档明确把它描述为"High availability for non-clustered Redis"。

所以架构设计时通常应该根据规模和业务需求选择:

text 复制代码
Redis主从 + Sentinel

或者:

text 复制代码
Redis Cluster

而不是简单写成:

text 复制代码
Redis Cluster + Sentinel

十、城市级设备接入真正应该测什么?

不要只报一个:

"支持百万设备。"

设备接入平台至少应该拆开测:

连接能力

在线连接数、连接建立速度、重连风暴。

消息能力

消息TPS、消息大小、峰值突发。

视频能力

并发取流数、总入口带宽、转发带宽。

可靠性

单节点宕机恢复、消息积压恢复、设备重新注册。

稳定性

24小时、72小时甚至更长时间压测。

延迟

P50、P95、P99,而不是只报一个平均延迟。

例如"10万连接"这个数字本身没有意义。

你还必须说明:

text 复制代码
什么CPU?
多少内存?
什么网卡?
连接是否空闲?
心跳周期多少?
单设备消息频率多少?
TLS是否开启?

没有测试环境的性能数字,基本无法横向比较。


十一、荆棘鸟智能为什么要做这一层?

对于AI视觉平台来说,多协议设备接入并不是最终目的。

真正的问题是:

怎么把不同品牌、不同协议的视频和感知设备,统一变成AI算法可以消费的数据。

在荆棘鸟智能的智慧云视ACV平台架构中,设备接入层更适合作为算法与真实设备之间的"翻译层"。

底层负责:

接设备。

中间层负责:

统一数据和能力。

上层再负责:

AI分析、事件处理和行业业务。

这样新增一个设备品牌时,不需要重写500+AI视觉算法;

增加一个新算法时,也不应该重新适配每一种摄像机。

这才是设备接入中间件真正需要解决的解耦问题。


总结

城市感知设备统一接入,真正难的不是:

"再支持一个协议。"

而是建立一套稳定的抽象:

text 复制代码
设备
↓
协议
↓
统一模型
↓
事件总线
↓
规则与AI
↓
业务系统

一个可长期维护的物联网中间件,至少应该解决四件事:

协议插件化、设备模型统一、状态可恢复、业务与设备解耦。

设备规模越大,这几个基础设计越重要。


FAQ|物联网中间件常见问题

Q1:ONVIF和GB/T 28181有什么区别?

两者解决的问题存在重叠但定位不同。ONVIF主要解决IP安防产品之间的互操作,GB/T 28181主要服务于视频监控联网场景。工程中经常同时支持。

Q2:为什么需要设备抽象层?

因为同一种业务能力可能由不同厂商、不同协议实现。设备抽象层可以把底层差异转换成统一属性、事件、服务和能力模型。

Q3:设备影子有什么作用?

主要用于保存设备已上报状态和平台期望状态,支持设备离线后的状态同步。但异步控制还需要TTL、幂等和安全校验。

Q4:Kafka和MQTT是什么关系?

MQTT更偏设备侧轻量消息通信,Kafka更适合平台内部高吞吐事件流。两者可以存在于同一架构的不同位置。

Q5:设备网关应该设计成无状态吗?

不能完全无状态。长连接和协议Session通常必须保留本地状态,更合理的是尽量将业务状态外置,让节点具备故障恢复能力。

不能简单这么理解。Checkpoint可以恢复Flink状态,但端到端消息语义还与Source、Sink、事务和幂等设计有关。

Q7:城市级设备平台怎么验证能不能支撑百万设备?

必须通过分层压测验证连接、消息、视频、故障恢复和长期稳定性,并公布硬件、消息频率、网络和测试模型。单独报"百万设备"没有太大意义。

Q8:荆棘鸟智能的设备接入能力主要解决什么问题?

核心是将不同厂商、不同协议的视频和物联网设备统一接入,并通过标准设备模型向上层AI算法和业务系统提供一致的数据与能力接口。

相关推荐
火山引擎开发者社区1 小时前
当 AI 内容真假难辨,谁来为真实签名 —— 证书中心 C2PA 内容可信溯源服务正式发布
人工智能
百万蹄蹄向前冲1 小时前
风扇转了一晚上MVP专家团翻车事故
前端·人工智能
米小虾1 小时前
你的 harness 技巧有保质期:176 组对照实验显示,上下文管理的收益从 35.7 分跌到 2.7 分
人工智能·agent
飞哥数智坊1 小时前
一个周末,6个项目,我第一次感觉 AI 编程真的进入了新阶段
人工智能·ai编程
AOI小白新手上路1 小时前
秦方方 2025《基于深度学习的单幅图像去雨算法研究与应用》( 河南理工硕士论文)蒸馏文档
人工智能
米小虾1 小时前
一周 AI 观察(9.15–9.21):同一个星期里,token 有了官方标准,Gemini 进了三家真实公司,TPU 变成了抵押品
人工智能
冬奇Lab1 小时前
LLM 自动化测试系列(01):为什么测试是 LLM 落地的新战场
人工智能
冬奇Lab1 小时前
一天一个开源项目(第224篇):ARTEMIS —— 谷歌开源的移动端 AI 自动化框架,让 AI 助手像人一样操作手机
人工智能·开源·测试
蓝速科技2 小时前
会议室门牌公告通知发布选型与落地指南丨蓝速科技
大数据·运维·数据库·人工智能·科技