海燕边缘网关 haiyan-io
haiyan-io 是一套面向智能硬件与工业现场的边缘网关。它接住 Modbus、OPC UA、私有 TCP/串口和 MQTT 直连设备,把不同的地址、帧格式与采集方式翻译成统一物模型,再通过 MQTT、REST、WebSocket 和 gRPC 向上层系统提供一致的数据与指令接口。
我不想把它做成一个只完成“协议 A 转协议 B”的转发程序。真实网关还要面对断网、设备掉线、慢消费者、配置变更、告警联动、远程升级和多台网关运维。这个项目交付的是一套可以独立运行在现场的边缘执行环境。
先统一设备,再讨论协议
核心模型只有三层:设备、采集组和点位。采集组拥有独立周期,点位描述数据类型、比例变换、质量戳、单位与是否可写。驱动只负责把现场协议转换成这套模型,不需要知道数据最终会走 MQTT、REST 还是其他北向通道。
南向驱动使用静态 trait 插件:每类协议实现工厂与连接器,hyd 再通过 Cargo feature 决定编入哪些驱动。当前已实现模拟器、Modbus TCP/RTU、OPC UA、MQTT 设备直连,以及可复用的私有 TCP/串口协议框架。
这里刻意没有采用 Rust 动态库插件。边缘设备更看重可预测部署和故障边界;编译期注册能换来单二进制交付、类型安全和按 feature 裁剪体积。私有请求应答协议也不必从头写完整驱动:实现 FrameCodec 的请求编码、帧定界、响应解码与写入编码即可,传输、缓冲、超时、重连和调度由公共框架接管。
一条数据如何穿过网关
轮询型设备由独立 Tokio 任务持有连接,并按采集组最近到期时间调度;MQTT 直连等主动上报设备则切换到事件推送模式。两种形态最后都会进入同一个 Core::ingest:
现场设备
-> 南向驱动(轮询或事件推送)
-> Core::ingest
-> 设备影子:REST / WebSocket 实时查询
-> 有界消息总线
-> 规则引擎:告警、恢复与联动控制
-> 持久队列:MQTT 可靠上云
-> gRPC / WebSocket 实时流
每台设备由自己的监督器管理。连接失败按 1 秒到 60 秒指数退避,连续采集失败触发重连,任务 panic 只重建当前设备。Modbus RTU 多从站可以共享 RS485 总线,但访问仍保持串行,避免请求应答协议被并发写乱。
下行指令走相反方向:北向请求进入统一 CommandRouter,路由到目标设备任务,由驱动执行写点位或协议动作,再沿原通道返回带 request_id 的结果。超时会得到明确错误应答,业务系统不需要猜测指令是否仍在执行。
断网时,数据先留在现场
MQTT 上云采用 QoS 1,但 QoS 本身不足以解决进程重启和长时间离线。遥测进入北向桥接前先写入 redb 持久队列,发布后直到收到对应 PubAck 才删除;Broker 恢复后,积压数据按序继续发送。每条消息携带单调递增的 seq,云端可以按 (gateway_id, seq) 做幂等去重。
这套语义是“至少一次”,不是“绝不重复”。磁盘队列有容量上限,空间耗尽时优先保留新数据并丢弃最旧项。进程内的广播与命令通道同样有界:慢 WebSocket 客户端只影响自己的订阅,不会让内存无限增长。
云断了,本地规则仍然工作
规则引擎支持上下限、回差、连续采样确认和滑动窗口 avg/min/max 聚合,也可以用通配设备匹配同类点位。告警触发与恢复事件会进入 MQTT、WebSocket、gRPC 和 REST;活动告警与历史台账写入 redb,重启后仍可恢复,并能记录确认人。
规则触发或恢复时还能调用统一指令路由写回设备。温度越界后关闭加热器、液位恢复后重新启泵,不必等待云端往返;即使外网中断,网关仍能在本地完成采集、判断和控制闭环。
把管理能力装进同一个二进制
网关内置 Vue 3 管理界面,release 构建时通过 rust-embed 打进 Rust 二进制。部署现场只需要 hyd、一份 TOML 配置和数据目录,不必额外安装 Node 或单独维护 Web 服务。
界面覆盖设备状态、实时点位、写指令、告警台账、规则与设备配置、配置备份、口令修改和 OTA。服务端逐请求强制权限,管理员可以变更配置,viewer 只能查询与订阅。登录使用 JWT,口令以 argon2id 哈希保存;脚本集成可以使用独立机器令牌,敏感字段支持 ${VAR} 展开,REST 与 MQTT 管理通道记录结构化审计日志。
配置更新也不等同于整机重启。管理面写回 TOML 时会尽量保留手写注释,先完整校验再替换文件;热重载按设备做增量 diff,未变化的采集任务保持运行,错误配置不会落盘。
从单台网关走向一组网关
现场设备常在 NAT 后,中心侧无法直接访问每台网关。hy-console 和 gw-admin 复用 MQTT 管理通道完成网关发现、分组、规则下发、远程重启和 OTA 推送。升级包按块传输,网关组装后校验 SHA-256 与 ed25519 签名,再进入候选槽位。
网关本地采用 A/B 槽位和独立启动器。新版本只有稳定运行达到确认时间才会晋升;此前反复崩溃,启动器回到上一版本。控制台还能按波次灰度升级,等待前一批网关重新上线并通过恢复门控后再继续,失败超过阈值则终止后续批次。
自动化验证
整理这篇项目时,我执行了完整 workspace 测试:
cargo test --workspace --locked
共 115 项测试通过。除了模型、配置和协议序列化等单元测试,还包含真实 TCP 私有协议往返、Modbus 位读改写、MQTT 设备全链路、OPC UA 读写与加密会话、gRPC 查询/指令/流、REST 与 WebSocket 鉴权、MQTT 管理通道、持久队列、告警恢复以及 OTA 包和槽位状态机。
这个项目解决了什么
haiyan-io 最有价值的地方不是支持了多少协议,而是把协议接入之后的工程问题放在同一套边界里处理:数据怎样统一、断网怎样保存、故障怎样隔离、规则怎样在本地闭环、配置怎样不停机生效、升级失败怎样回来,以及几十台网关怎样被同一处管理。
它既是一台边缘设备的完整运行时,也是承载现场协议、硬件与云平台连接的统一基础。比起再写一个能读到寄存器的 Demo,我更在意它在网络不可靠、设备会掉线、配置会出错的现实条件下,仍然知道自己该做什么。