系统端设备与摄像头对接配置说明.md 18 KB

系统端设备与摄像头对接配置说明

本文是当前项目的部署配置手册,面向管理系统部署人员和边缘端联调人员。内容覆盖:

  • 自动 UDP 发现和手工 IP 接入;
  • MQTT 道闸控制、状态上报和图片 HTTP 上传;
  • 系统端将 RTSP/HTTP 摄像头流转换为浏览器可播放的 MJPEG;
  • 数据库、Windows 防火墙、启动、验证和故障排查。

边缘端协议字段和 Topic 的完整定义见 doc/边缘端自动与手工接入对接指南.md。本文只说明管理系统需要改哪些文件、填什么值。

1. 配置文件位置

1.1 开发运行

开发运行使用项目根目录的 config.yaml

D:\lq\Smart Parking\lc_garage\config.yaml

执行 wails devgo run 时,程序优先从当前工作目录读取该文件。

1.2 生产运行

生产程序使用启动参数 -c 指定配置;未指定时,程序从 Gin 运行模式对应的配置文件读取,并在当前目录找不到时尝试可执行文件目录。因此生产部署必须把配置文件放在 exe 同目录:

build\bin\smart-parking.exe
build\bin\config.yaml

也可以明确指定:

.\build\bin\smart-parking.exe -c .\build\bin\config.yaml

internal/config.yaml 是旧模板/服务端兼容配置,不是 Wails 桌面程序默认编辑的文件。除非启动参数明确指定它,否则不要在两个文件之间来回修改。

1.3 代码配置结构

internal/config/mqtt.gointernal/config/camera.go 只是 YAML 映射结构,通常不需要填写。只有新增配置字段或协议变化时才修改 Go 代码;日常部署只改 config.yaml

2. 可直接复制的基础配置

下面配置适用于“管理系统和内嵌 MQTT Broker 在同一台 Windows 主机、边缘设备通过局域网连接、摄像头由系统端转换”的场景。把 192.168.110.164 换成边缘设备实际能访问的管理主机 IPv4 地址。

system:
    db-type: sqlite
    oss-type: local
    router-prefix: ""
    addr: 8888
    gate-simulator: false
    debug-routes: false

sqlite:
    db-name: lc_garage
    path: ""

mqtt:
    enabled: true
    embed-broker: true
    broker-listen: ":1883"
    broker: tcp://127.0.0.1:1883
    advertised-host: "192.168.110.164"
    advertised-port: 1883
    tls-enabled: false
    client-id: smart-parking
    username: ""
    password: ""

camera:
    conversion-mode: system
    ffmpeg-path: ffmpeg
    mjpeg-fps: 8
    jpeg-quality: 5

local:
    path: uploads/file
    store-path: uploads/file

说明:

配置 当前实现中的含义
system.addr 管理系统 HTTP 端口;图片上传地址会使用该端口。
mqtt.broker-listen 内嵌 Broker 监听地址。:1883 表示监听本机所有 IPv4 接口。
mqtt.broker 管理系统自身连接 Broker 的地址;内嵌 Broker 时保留 127.0.0.1
mqtt.advertised-host 下发给边缘端的 Broker 主机地址。内嵌 Broker 时必须是管理主机局域网 IP,不能是 127.0.0.1localhost0.0.0.0
mqtt.advertised-port 边缘端连接 Broker 的端口;必须与 broker-listen 的端口一致。
mqtt.tls-enabled 下发给设备的 MQTT TLS 标志。当前内嵌 Broker 没有 TLS listener,因此内嵌模式必须填 false
mqtt.username/password 当前内嵌 Broker 允许匿名连接,可留空。若改用带认证的外部 Broker,系统连接和边缘端凭据必须由两端按同一版本协议配置。
camera.conversion-mode system 表示管理端调用 FFmpeg;edge 表示使用数据库中的边缘播放地址。

3. MQTT Broker 配置

3.1 内嵌 Broker(当前默认方案)

只需要在 config.yaml 填:

mqtt:
    enabled: true
    embed-broker: true
    broker-listen: ":1883"
    broker: tcp://127.0.0.1:1883
    advertised-host: "192.168.110.164"
    advertised-port: 1883
    tls-enabled: false

设备收到配置后连接:

tcp://192.168.110.164:1883

advertised-host 的填写规则:

  1. 在管理主机执行 ipconfig,选择与边缘设备同一网络、且边缘设备可路由到的 IPv4 地址;
  2. 不要填写浏览器地址栏中的 localhost
  3. 不要填写设备自身 IP;
  4. 设备跨 VLAN 时填写管理网段的可达地址,并在三层防火墙放行 TCP 1883;
  5. 管理主机 IP 变化时必须同步修改该值并重启/重新下发设备配置。

3.2 外部 Broker

外部 Broker 场景下,broker 是管理系统连接地址,advertised-host/port 是边缘端连接地址,两者可以相同,也可以不同:

mqtt:
    enabled: true
    embed-broker: false
    broker-listen: ":1883"       # 不启动内嵌 Broker 时该项不生效
    broker: tcp://192.168.110.20:1883
    advertised-host: "192.168.110.20"
    advertised-port: 1883
    tls-enabled: false
    client-id: smart-parking
    username: parking-system
    password: "替换为外部 Broker 密码"

外部 Broker 管理员还必须配置:

  • 允许管理主机和边缘设备访问对应 TCP 端口;
  • 为系统客户端和每台设备配置唯一 Client ID;
  • 授权系统订阅 parking/lot/+/booth/+/channel/+/gate/stategate/lwtgate/cmd/ackcamera/event
  • 授权每台设备只发布自己的 gate/stategate/lwtgate/cmd/ackcamera/event,只订阅自己的 gate/cmd
  • 若 Broker 使用 TLS,应使用外部 Broker 的 TLS 地址和证书策略。当前项目的内嵌 Broker 未配置证书,不能仅把 tls-enabled 改成 true 就获得 TLS。

3.3 防火墙

在管理主机以管理员 PowerShell 执行(仅在确认端口未被其他服务占用时):

New-NetFirewallRule -DisplayName "Smart Parking HTTP 8888" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 8888
New-NetFirewallRule -DisplayName "Smart Parking MQTT 1883" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 1883

自动发现不需要管理系统固定 UDP 监听端口。系统从临时 UDP 端口向边缘端 UDP/31001 发送广播,边缘端响应到请求源 IP/源端口。跨 VLAN 或无线隔离时不要依赖该流程,改用手工 IP。

验证监听:

Get-NetTCPConnection -LocalPort 8888,1883 -State Listen
Test-NetConnection 192.168.110.164 -Port 1883

4. 自动和手工接入时系统端需要做什么

4.1 自动 UDP 发现

系统端没有额外的 YAML 开关。管理员在“设备接入”页面点击自动发现,系统会:

  1. 向每个启用网卡的 IPv4 定向广播地址发送 discovery.request.v1,目标端口固定 31001,发送 3 次;
  2. 接收并校验 request_idnonce、设备永久 ID、设备签名、公钥指纹、响应来源 IP 和 HTTPS 配置地址;
  3. 通过 HTTPS GET /api/v1/identity 再次读取设备身份和服务器证书指纹;
  4. 管理员确认指纹/配对码后,选择停车场、岗亭、通道和方向;
  5. 通过 HTTPS POST /api/v1/provision 下发 MQTT、业务路由和图片上传地址;
  6. 等待设备发布 retained gate.state.v1,收到后才显示“在线”。

自动发现响应被丢弃时,重点看后端日志中的 收到 UDP 发现响应丢弃 UDP 发现响应,常见原因是公钥指纹不匹配、报文来源 IP 与响应 ip 不一致、签名错误或 config_url 不是 HTTPS。

4.2 手工 IP 接入

管理员在页面输入边缘设备 IP 和 HTTPS 端口(端口为空时后端使用 8443)。系统端请求:

GET https://<设备IP>:<端口>/api/v1/identity
POST https://<设备IP>:<端口>/api/v1/pair       # pairing_required=true 时
POST https://<设备IP>:<端口>/api/v1/provision

手工 IP 是正式接入路径,适用于跨 VLAN、UDP 广播被禁、无线隔离、VPN 和不支持发现协议的设备。系统拒绝 127.0.0.1localhost0.0.0.0、IPv4 广播、IPv4/IPv6 组播、主机名和非法端口。

4.3 管理 API(用于联调)

以下 API 均在 JWT、Casbin 和操作审计保护下,只有管理员权限(authority 888)可调用。前端开发服务器地址为 http://localhost:5173 时,前缀仍是 /api

方法 URL 用途
POST /api/device-provisioning/discover 发起自动发现,可选 {"broadcast_address":"192.168.110.255"}
GET /api/device-provisioning/discoveries 查询 10 分钟内的发现结果
POST /api/device-provisioning/manual/identity 手工 IP 读取身份,Body {"ip":"192.168.110.218","port":8443}
POST /api/device-provisioning/{device_id}/identity 读取自动发现候选的 HTTPS 身份
POST /api/device-provisioning/{device_id}/verify Body {"fingerprint":"SHA256:...","pairing_code":"..."}
POST /api/device-provisioning/{device_id}/provision 绑定并下发配置
GET /api/device-provisioning/{device_id}/status 查询 provisioned/online/failed 等状态

注意:/api/device-provisioning/discoveries 返回 404 时,通常是后端未重启、请求打到了错误端口,或请求 URL 少了 /api 代理前缀;先访问 http://127.0.0.1:8888/health 验证后端。

5. 图片 HTTP 上传配置

设备绑定成功后,系统下发的图片地址由 mqtt.advertised-hostsystem.addr 生成:

http://<advertised-host>:<system.addr>/device-images/upload

当前版本按用户要求不使用上传令牌,依赖内网隔离和设备绑定校验。边缘端必须使用 multipart/form-data,字段为 device_codeimage_id、可选 event_id/direction 和文件字段 image。单张图片限制 8 MB;图片上传成功后再发布 MQTT camera.event.v1,事件只引用 image_id

因此必须放行管理主机 TCP 8888,且 mqtt.advertised-host 不能填 127.0.0.1。图片上传路由是 /device-images/upload,不是 /api/device-images/upload

6. 摄像头配置(系统端转换)

6.1 config.yaml

camera:
    conversion-mode: system
    ffmpeg-path: C:\\ffmpeg\\bin\\ffmpeg.exe
    mjpeg-fps: 8
    jpeg-quality: 5

ffmpeg-path 可以填 ffmpeg(要求已加入 PATH),也可以填绝对路径。mjpeg-fps 建议 5-10;jpeg-quality 是 FFmpeg 的质量值,数值越小画质越好、带宽和 CPU 占用越高。

6.2 安装和验证 FFmpeg

ffmpeg -version
Test-Path 'C:\ffmpeg\bin\ffmpeg.exe'

如果系统找不到 FFmpeg,把绝对路径写入 ffmpeg-path,修改后重启后端。摄像头原始地址必须能从管理主机访问,例如:

rtsp://用户名:密码@192.168.1.50:554/live

6.3 camera 表字段

摄像头表由启动时 AutoMigrate 自动创建,不需要手工建表。当前没有独立摄像头配置页面,使用 SQLite 客户端写入/更新记录:

字段 填写要求
device_code 摄像头唯一编码,例如 CAM-IN-01
device_name 页面显示名称。
channel_id 与摄像头对应的道闸通道 ID;摄像头、道闸必须是同一通道。
ip_address/port 摄像头管理地址和 RTSP/HTTP 端口。
username/password 原始流凭据,仅后端使用,不返回前端。
stream_protocol 系统转换填 system-mjpeg;边缘转换填 webrtchls
source_url 系统转换时填 RTSP/HTTP 原始地址。
stream_url 系统转换留空;边缘转换填 WHEP/HLS 播放地址。
is_active 1 启用,0 停用。
status online/offline,仅用于页面状态显示。

查询停车场、岗亭、通道 ID:

SELECT id, lot_code, lot_name FROM parking_lot WHERE deleted_at IS NULL;
SELECT id, booth_code, booth_name, parking_lot_id FROM booth WHERE deleted_at IS NULL;
SELECT id, channel_code, channel_name, parking_lot_id, booth_id, direction FROM channel WHERE deleted_at IS NULL;

插入一台系统转换摄像头(把 8 换成实际 channel_id):

INSERT INTO camera
    (created_at, updated_at, device_code, device_name, channel_id, ip_address, port,
     username, password, channel, status, is_active, stream_protocol, source_url,
     stream_url, snapshot_url, description)
VALUES
    (datetime('now'), datetime('now'), 'CAM-IN-01', '入口摄像头', 8, '192.168.1.50', 554,
     'admin', '替换为摄像头密码', 1, 'offline', 1, 'system-mjpeg',
     'rtsp://admin:替换为摄像头密码@192.168.1.50:554/live', '', '', '系统端转换');

更新已有记录:

UPDATE camera
SET channel_id = 8,
    stream_protocol = 'system-mjpeg',
    source_url = 'rtsp://admin:替换为摄像头密码@192.168.1.50:554/live',
    stream_url = '',
    is_active = 1,
    updated_at = datetime('now')
WHERE device_code = 'CAM-IN-01';

系统转换时,接口 GET /api/parking/camera/streams 返回短期播放地址:

/api/parking/camera/stream/CAM-IN-01/<token>

浏览器以 <img> 显示 MJPEG;每次页面重新加载会获得新的短期令牌。后端断开浏览器连接后自动结束 FFmpeg 进程。

6.4 切换边缘端转换

camera:
    conversion-mode: edge

然后更新数据库:

UPDATE camera
SET stream_protocol = 'webrtc',
    source_url = '',
    stream_url = 'https://边缘端或媒体网关地址/实时播放接口',
    updated_at = datetime('now')
WHERE device_code = 'CAM-IN-01';

系统端当前不负责把 RTSP 转成 WHEP;在 system 模式下统一输出 MJPEG,未来切换到 edge 模式时由边缘端/媒体网关提供 WHEP 或 HLS 地址。

7. SQLite 数据库位置和设备绑定

默认 sqlite.path 为空,数据库实际位置为:

C:\Users\<当前 Windows 用户>\AppData\Roaming\smart-parking\lc_garage.db

启动时会自动执行 AutoMigrate,包括 uhf_readerdevice_discoveriesdevice_imagescamera 表。

检查已绑定设备:

sqlite3 "$env:APPDATA\smart-parking\lc_garage.db" `
  "SELECT id, device_code, device_id, connect_type, channel_id, provision_status, status, deleted_at FROM uhf_reader ORDER BY id;"

MQTT 设备必须满足:connect_type='mqtt'is_active=1channel_id 指向正确通道。device_code 为数据库全局唯一字段;软删除记录仍占用唯一索引,重新绑定同一设备时系统会恢复原记录,不要直接重复 INSERT

8. 启动、重启和验证

项目已提供统一管理脚本:

cd 'D:\lq\Smart Parking\lc_garage'
.\scripts\manage-project.ps1 start -Mode split
.\scripts\manage-project.ps1 status
.\scripts\manage-project.ps1 restart -Mode split
.\scripts\manage-project.ps1 stop

split 模式后端是 8888、前端是 5173;Wails 桌面开发模式使用:

.\scripts\manage-project.ps1 start -Mode wails

基础验证:

Invoke-WebRequest http://127.0.0.1:8888/health
Test-NetConnection <advertised-host> -Port 1883

管理员登录后验证自动/手工接入 API,再查询状态接口。日志重点关注:

  • 内嵌 MQTT broker 已启动MQTT 连接已恢复
  • 收到 UDP 发现响应丢弃 UDP 发现响应
  • HTTPS 身份读取失败证书指纹不匹配
  • 设备配置下发失败
  • 边缘设备图片上传结果边缘设备图片上传失败
  • 收到车辆识别 MQTT 事件车辆识别事件图片引用校验成功

9. 常见问题

现象 检查项
advertised-host 配置错误 必须是边缘端可达的单播 IP;修改后重启并重新下发。
设备收到配置但 MQTT 不上线 检查 TCP 1883、防火墙、Broker 地址,以及 tls-enabled 是否与实际 listener 一致。内嵌 Broker 当前填 false
自动发现无结果 检查边缘端 UDP 31001、Windows 网络类型/防火墙;跨 VLAN、无线隔离时使用手工 IP。
日志提示公钥指纹不匹配 public_key_fingerprint 必须是 signing_public_key 原始 32 字节 Ed25519 公钥的 SHA-256。
日志提示 IP 与报文来源不一致 UDP 响应 JSON 的 ip 必须等于实际发送报文的源 IP。
HTTPS 身份读取失败 检查设备 HTTPS 端口(默认 8443)、TLS 1.2+、设备路由和证书指纹。
绑定时报 UNIQUE constraint failed 用上面的 Unscoped 查询检查同 device_code 的软删除行;当前代码会恢复同一永久 device_id 的历史行,其他设备不能复用编码。
图片上传 404 使用 /device-images/upload,不是 /api/device-images/upload;确认后端端口为 8888local.store-path/对象存储可写。
摄像头没有画面 检查 is_active=1channel_id、FFmpeg 路径和 source_url;RTSP 地址必须能从管理主机访问。

10. 部署前检查清单

  • 根目录或 exe 同目录的 config.yaml 已填写 MQTT、系统端口和摄像头模式。
  • mqtt.advertised-host 是边缘设备可达的管理主机或外部 Broker IP。
  • 内嵌 Broker 使用 tls-enabled: false;外部 TLS Broker 已由运维完成证书和监听配置。
  • TCP 8888、内嵌 MQTT TCP 1883 和设备 HTTPS 8443 路由/防火墙已放行。
  • 自动发现设备监听 UDP 31001;不满足网络条件时已准备手工 IP 接入。
  • 每个设备有稳定的永久 device_id、证书指纹和配对码。
  • 设备、道闸和摄像头绑定同一 channel_id
  • 边缘端先上传图片,再发布带 image_id 的 MQTT 事件。
  • 设备收到 provision 后能连接 MQTT,并发布 retained gate.state.v1
  • 已用日志和状态 API 验证“配置已保存”和“设备在线”两个阶段。