版本:v1.0 适用对象:硬件端(车牌识别相机 / LPR 相机、UHF 读写器、道闸控制器)工程师 配套文档:
doc/设备接入层设计.md、doc/多岗亭改造方案.md
系统与硬件设备之间采用 MQTT 消息总线 + HTTP 图片传输 两种通道:
┌─────────────┐ MQTT 发布(识别事件/状态/回执) ┌──────────────────┐
│ 硬件设备 │ ─────────────────────────────▶ │ 智慧停车系统 │
│ (相机/道闸) │ │ (内嵌 MQTT Broker)│
│ │ ◀───────────────────────────── │ │
└─────────────┘ MQTT 订阅(道闸指令) └──────────────────┘
│
│ HTTP(抓拍图片,图片不进 MQTT)
▼
图片存储/URL 引用
核心原则:
mochi-mqtt),设备主动连接它,而不是系统连接设备。| 参数 | 值 | 说明 |
|---|---|---|
| 协议 | MQTT 3.1.1 | 标准 MQTT |
| Broker 地址 | tcp://<系统主机IP>:1883 |
系统内嵌 broker,默认端口 1883 |
| ClientID | 设备编码(device_code) | 必须全局唯一,建议用系统里配置的设备编码 |
| 用户名 / 密码 | 留空 | 当前版本匿名接入(allow-all-auth) |
| QoS | 1(至少一次) | 所有消息统一 QoS 1 |
| Keep Alive | 30 秒 | 建议 30s,超时 broker 会判定离线 |
| 遗嘱(LWT) | 必须配置 | 见 §2.1,用于系统感知设备离线 |
设备连接时必须设置 LWT 遗嘱消息,否则设备断电/断网后系统无法感知离线。
| 遗嘱参数 | 值 |
|---|---|
| Topic | parking/lot/{lot}/booth/{booth}/channel/{ch}/gate/lwt |
| Payload | {"schema":"gate.lwt.v1","device_code":"<设备编码>"} |
| QoS | 1 |
| Retained | true |
设备连接成功后,立即发布一条 retained 的状态消息,让系统知道设备上线:
parking/lot/{lot}/booth/{booth}/channel/{ch}/gate/statetruegate.state.v1统一前缀 parking/,中间为「停车场 → 岗亭 → 通道」三级坐标,末尾为消息类型:
parking/lot/{lot_id}/booth/{booth_id}/channel/{channel_id}/{类型}
{lot_id}、{booth_id}、{channel_id}是系统分配的数字 ID,不是编码(code)。设备端需从系统获取这三元组并配置到设备(见 §7)。
| 方向 | Topic | QoS | Retained | 说明 |
|---|---|---|---|---|
| 设备 → 系统 | .../channel/{ch}/camera/event |
1 | 否 | 车牌/RFID 识别事件 |
| 设备 → 系统 | .../channel/{ch}/gate/state |
1 | 是 | 道闸状态/在线心跳 |
| 系统 → 设备 | .../channel/{ch}/gate/cmd |
1 | 否 | 开/关闸指令 |
| 设备 → 系统 | .../channel/{ch}/gate/cmd/ack |
1 | 否 | 指令执行回执 |
| 设备 → 系统 | .../channel/{ch}/gate/lwt |
1 | 是 | 遗嘱消息(离线通知) |
设备只需订阅自己坐标下的指令:
parking/lot/{lot}/booth/{booth}/channel/{ch}/gate/cmd
所有消息为 JSON 文本,UTF-8 编码。每个消息都含 schema 字段用于区分类型。
camera.event.v1(设备 → 系统)车牌识别(或 RFID 读取)成功后上报,触发系统执行进场/出场流程。
{
"schema": "camera.event.v1",
"device_code": "CAM-A01",
"plate_number": "粤A12345",
"rfid_tag": "E28068940000500ABCDEF",
"direction": "in",
"ts": 1730000000,
"image_path": "http://192.168.1.50/capture/20240814_001.jpg",
"confidence": 0.98
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| schema | string | 是 | 固定 camera.event.v1 |
| device_code | string | 是 | 设备编码,必须与系统设备管理中配置的一致 |
| plate_number | string | 否* | 车牌号(无牌车可空) |
| rfid_tag | string | 否* | RFID 标签 EPC(无 RFID 可空) |
| direction | string | 是 | 通行方向 in(进场)/ out(出场) |
| ts | int64 | 是 | 事件时间戳,Unix 秒 |
| image_path | string | 否 | 抓拍图 URL 或路径(图片不走 MQTT) |
| confidence | float | 否 | 识别置信度,0~1 |
*plate_number与rfid_tag至少一个非空。
gate.state.v1(设备 → 系统,retained)道闸状态变化或上线时上报,系统据此维护设备在线状态。
{
"schema": "gate.state.v1",
"device_code": "GATE-A01",
"state": "closed",
"ts": 1730000000
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| schema | string | 是 | 固定 gate.state.v1 |
| device_code | string | 是 | 设备编码 |
| state | string | 是 | open / closed / moving |
| ts | int64 | 是 | Unix 秒时间戳 |
gate.cmd.v1(系统 → 设备)系统在进出场放行时下发开/关闸指令,设备收到后执行并回执。
{
"schema": "gate.cmd.v1",
"cmd_id": "3f2a1b9c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"device_code": "GATE-A01",
"action": "open",
"valid_time": 2
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| schema | string | 是 | 固定 gate.cmd.v1 |
| cmd_id | string | 是 | 指令唯一编号(UUID),回执需原样带回 |
| device_code | string | 是 | 目标设备编码 |
| action | string | 是 | open(开闸)/ close(关闸) |
| valid_time | int | 是 | 道闸动作保持时长(秒),默认 2,范围 1~255 |
gate.ack.v1(设备 → 系统)设备执行完指令后立即回执。必须在 5 秒内回执,否则系统判定超时。
{
"schema": "gate.ack.v1",
"cmd_id": "3f2a1b9c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"device_code": "GATE-A01",
"result": "success",
"error": ""
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| schema | string | 是 | 固定 gate.ack.v1 |
| cmd_id | string | 是 | 对应指令的 cmd_id,原样带回 |
| device_code | string | 是 | 设备编码 |
| result | string | 是 | success(成功)/ failed(失败) |
| error | string | 否 | 失败原因(result=failed 时填写) |
gate.lwt.v1(设备 → 系统,retained)设备异常断开时,由 broker 自动发布遗嘱消息。设备无需主动发布,只需在连接时配置好 LWT(见 §2.1)。
{
"schema": "gate.lwt.v1",
"device_code": "GATE-A01"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| schema | string | 是 | gate.lwt.v1(系统兼容 gate.lwt) |
| device_code | string | 是 | 设备编码 |
设备 Broker(系统)
│ 1. CONNECT(ClientID=device_code, LWT配置) │
│────────────────────────────────────────────▶│
│ 2. CONNACK │
│◀────────────────────────────────────────────│
│ 3. SUBSCRIBE .../gate/cmd │
│────────────────────────────────────────────▶│
│ 4. PUBLISH .../gate/state (retained, closed)│
│────────────────────────────────────────────▶│ ← 系统回写设备 online
相机 系统 道闸
│ PUBLISH camera/event(in) │ │
│────────────────────────────▶│ 黑名单/满位/临时车校验 │
│ │ PUBLISH gate/cmd(open) │
│ │────────────────────────────▶│
│ │ PUBLISH gate/cmd/ack │
│ │◀────────────────────────────│
│ │ (5秒内未回执则超时) │
同 §5.2,区别是 camera/event 的 direction 为 out。系统会先做计费结算,再下发开闸指令。
道闸异常断开
│
▼
Broker 自动发布 retained 的 gate/lwt 遗嘱
│
▼
系统收到 → 回写设备 offline + 记录「设备离线」异常
| 字段 | 取值 | 说明 |
|---|---|---|
| direction | in / out |
进场 / 出场 |
| state | open / closed / moving |
道闸开启 / 关闭 / 动作中 |
| action | open / close |
开闸 / 关闸 |
| result | success / failed |
指令成功 / 失败 |
| schema | 见 §4 | 消息类型标识 |
设备端部署时,需要从系统获取并配置以下参数:
| 参数 | 来源 | 说明 |
|---|---|---|
device_code |
系统「设备管理」 | 设备编码,全局唯一 |
lot_id |
系统「停车场管理」 | 所属停车场数字 ID |
booth_id |
系统「岗亭管理」 | 所属岗亭数字 ID |
channel_id |
系统「通道管理」 | 绑定通道数字 ID |
停车场 ParkingLot (lot_id)
└── 岗亭 Booth (booth_id)
└── 通道 Channel (channel_id)
└── 设备 UHFReader (device_code)
设备必须「绑定通道」后,坐标三元组 (lot_id, booth_id, channel_id) 才完整。MQTT 设备必须绑定通道(系统已强制校验)。
在系统界面「停车管理 → 停车场信息」中,依次查看停车场、岗亭、通道、设备的 ID;或通过后端接口查询(/parking/lot/list、/parking/booth/list、/parking/channel/list、/parking/device/list)。
注意:topic 中使用的是数字 ID(数据库主键),不是 lot_code/booth_code/channel_code 编码字符串。
抓拍图片不通过 MQTT 传输。识别事件中通过 image_path 字段引用图片,系统前端直接加载该 URL 显示。
设备端在识别时抓拍图片,并由设备自身提供 HTTP 访问(或存到约定的图片服务器),然后在 camera.event.v1 的 image_path 里带上该图片的完整 URL:
"image_path": "http://192.168.1.50/capture/20240814_001.jpg"
系统会把该 URL 存到车辆记录的入场/出场图片字段,工作台直接显示。
若后续需要「设备主动上传图片到系统」,可协商增加系统侧 HTTP 上传端点(POST multipart),当前版本未实现。
| 场景 | 约定 |
|---|---|
| 指令下发失败(Publish 失败) | 系统记录异常,本次放行标记失败 |
| 指令超时(5 秒未收到 ack) | 系统判定「开闸失败」,记录道闸异常 |
| ack result=failed | 系统记录「道闸执行失败」,保留 error 信息 |
| 设备断连 | 靠 LWT 遗嘱触发,系统自动标记离线 |
| 设备重连 | 重新 CONNECT 后,先向 gate/lwt 发布 retained 空载荷清除旧遗嘱,再立即重发 retained 的 gate.state.v1 |
| 识别事件重复 | 系统有 3 秒防抖,同一标识 3 秒内重复事件会被丢弃 |
tcp://<系统IP>:1883(匿名)device_codegate/lwt 的 retained 遗嘱,再发布 retained 的 gate.state.v1gate/cmd 指令 Topiccamera.event.v1(direction 正确)gate.cmd.v1 后 5 秒内能回 gate.ack.v1A1 识别事件(进场)
{"schema":"camera.event.v1","device_code":"CAM-A01","plate_number":"粤A12345","rfid_tag":"","direction":"in","ts":1730000000,"image_path":"http://192.168.1.50/cap/001.jpg","confidence":0.97}
A2 识别事件(出场,仅 RFID)
{"schema":"camera.event.v1","device_code":"CAM-B02","plate_number":"","rfid_tag":"E28068940000500ABCDEF","direction":"out","ts":1730000010,"image_path":"","confidence":0}
A3 道闸状态(上线)
{"schema":"gate.state.v1","device_code":"GATE-A01","state":"closed","ts":1730000000}
A4 开闸指令(系统下发)
{"schema":"gate.cmd.v1","cmd_id":"3f2a1b9c-4d5e-4f6a-8b9c-0d1e2f3a4b5c","device_code":"GATE-A01","action":"open","valid_time":2}
A5 开闸回执(成功)
{"schema":"gate.ack.v1","cmd_id":"3f2a1b9c-4d5e-4f6a-8b9c-0d1e2f3a4b5c","device_code":"GATE-A01","result":"success","error":""}
A6 开闸回执(失败)
{"schema":"gate.ack.v1","cmd_id":"3f2a1b9c-4d5e-4f6a-8b9c-0d1e2f3a4b5c","device_code":"GATE-A01","result":"failed","error":"motor timeout"}
A7 遗嘱(离线)
{"schema":"gate.lwt.v1","device_code":"GATE-A01"}