本手册覆盖从安装到实际使用的完整流程。如果你还没有部署 ProtoForge,请先看 README 中的安装部分。
- 1. 快速入门(5 分钟)
- 2. 连接你的程序
- 3. 设备管理详解
- 4. 协议服务管理
- 5. 场景编排与规则引擎
- 6. 故障注入
- 7. 数据转发
- 8. 调试日志
- 9. EdgeLite 网关对接
- 10. 仿真测试
- 11. 系统设置
- 12. 常见问题
以下假设你已完成部署,浏览器能打开
http://localhost:8000。 没有部署?试用在线演示站(用户名admin,密码Protoforge123)。
打开 http://localhost:8000,输入 admin / admin(或你设置的密码)。
- 点击左侧菜单 「协议服务」
- 点击页面右上角 「一键启动」 按钮
- 等待所有协议状态变为绿色 运行中
💡 你也可以单独启动某个协议:点击对应协议行的「启动」按钮。
- 点击左侧菜单 「模板市场」
- 浏览或搜索设备模板(如搜索 "Modbus" 或 "PLC")
- 选择一个模板(如
Modbus PLC 控制器) - 输入设备名称(如
测试PLC) - 点击 「创建并启动」
设备创建后会自动启动,状态显示为绿色 在线。
- 点击左侧菜单 「设备管理」
- 找到刚创建的设备,点击 「测点」 按钮
- 可以看到所有测点的实时值,数据每隔 1 秒自动刷新
这是最关键的一步——ProtoForge 启动的是协议服务端,你的程序作为客户端连接它。
以 Modbus TCP 为例,ProtoForge 默认监听 5020 端口:
# Python — 用 pymodbus 连接 ProtoForge
from pymodbus.client import ModbusTcpClient
client = ModbusTcpClient("127.0.0.1", port=5020)
client.connect()
result = client.read_holding_registers(address=0, count=2, device_id=1)
print(f"读取到的寄存器值: {result.registers}")💡 不知道用什么地址连? 在设备管理页面,点击设备的 「指南」 按钮,系统会根据设备协议自动生成连接参数和代码示例。
ProtoForge 是「被采集的对象」,不是「采集者」。
- ProtoForge 启动协议服务端(Server),模拟 PLC / 传感器 / 摄像头
- 你的程序 / 网关 / SCADA 作为客户端(Client)连接 ProtoForge
- 对你的程序来说,ProtoForge 和真实设备没有任何区别
| 协议 | 默认端口 | 连接方式 | 你的程序角色 |
|---|---|---|---|
| Modbus TCP | 5020 | TCP | 主站(Master) |
| OPC-UA | 4840 | TCP | 客户端(Client) |
| MQTT | 1883 | TCP | 发布者/订阅者 |
| HTTP | 8080 | TCP | HTTP 客户端 |
| GB28181 | 5060 | TCP+UDP | 上级 SIP 平台 |
| Siemens S7 | 102 | TCP | 客户端(Client) |
| Mitsubishi MC | 5000 | TCP | 客户端(Client) |
| Omron FINS | 9600 | TCP+UDP | 客户端(Client) |
| Rockwell AB | 44818 | TCP | 客户端(Client) |
在「设备管理」页面,每台设备都有一个 「指南」 按钮。点击后系统会自动生成:
- 连接参数:IP、端口、slave_id、设备地址等
- 代码示例:Python / Node.js 等语言的连接代码
- 协议状态:当前协议服务是否运行
💡 如果看不到设备地址或端口,先确认对应协议服务已启动。
ProtoForge 的 Modbus 地址遵循标准 PLC 地址格式:
| 你在 ProtoForge 填的地址 | 实际 Modbus 寄存器地址 | 区域 |
|---|---|---|
0 |
地址 0 | Holding Register(自动判断) |
100 |
地址 100 | Holding Register(自动判断) |
40001 |
地址 0 | Holding Register(5 位 PLC 地址) |
400100 |
地址 99 | Holding Register(6 位 PLC 地址) |
30001 |
地址 0 | Input Register |
00001 |
地址 0 | Coil |
10001 |
地址 0 | Discrete Input |
HR100 |
地址 100 | Holding Register(显式前缀) |
IR100 |
地址 100 | Input Register |
C100 |
地址 100 | Coil |
你的 Modbus 客户端读取时,直接使用 Modbus 协议地址(从 0 开始的偏移地址)。
from pymodbus.client import ModbusTcpClient
client = ModbusTcpClient("127.0.0.1", port=5020)
client.connect()
# 读取 Holding Register,地址 0,数量 2,slave_id=1
result = client.read_holding_registers(address=0, count=2, device_id=1)
print(f"值: {result.registers}")
# 写入单个寄存器
client.write_register(address=0, value=1234, device_id=1)import paho.mqtt.client as mqtt
client = mqtt.Client()
client.connect("127.0.0.1", 1883)
# 订阅主题
client.subscribe("sensor/temperature")
client.on_message = lambda c, u, m: print(f"收到: {m.topic} = {m.payload.decode()}")
client.loop_start()from asyncua.sync import Client
with Client("opc.tcp://127.0.0.1:4840/freeopcua/server/") as client:
# 浏览节点
root = client.nodes.root
children = root.get_children()
print(f"节点: {[c.get_browse_name() for c in children]}")import snap7
client = snap7.client.Client()
client.connect("127.0.0.1", 0, 1)
# 读取 DB1 的前 4 个字节
data = client.db_read(1, 0, 4)
print(f"DB1.DBW0 = {int.from_bytes(data[0:2], 'big')}")- 进入 「模板市场」
- 搜索或浏览模板
- 选择模板 → 输入名称 → 点击「创建并启动」
模板已预配置好协议类型、测点地址、数据生成器,开箱即用。
- 进入 「设备管理」 → 点击「高级创建」
- 填写设备 ID(英文,如
pump-01)、设备名称 - 选择协议类型(Modbus TCP / S7 / MQTT...)
- 可选:选择一个模板导入测点配置
- 填写协议配置(如 Modbus 的
slave_id) - 点击「创建」
- 进入 「设备管理」 → 点击「批量创建」
- 选择模板
- 填写数量(最多 50 台)、名称前缀、ID 前缀
- 点击「批量创建」
批量创建适合压力测试场景,一次生成多台相同类型的设备。
- 在设备列表中点击 「编辑」 按钮
- 可以修改:
- 设备名称
- 协议配置(如 slave_id、端口号等)
- 测点配置(核心功能):
- 名称:测点标识(如
temperature) - 地址:协议地址(如 Modbus 地址
0、100、40001) - 数据类型:
uint16/int16/float32/int32/bool/string - 访问权限:
rw(读写)/r(只读)/w(只写) - 数据生成器:控制测点值的变化方式(见下表)
- 最小值/最大值:随机数生成范围
- 固定值:当生成器为
fixed时使用 - 单位:如
°C、MPa、rpm
- 名称:测点标识(如
- 点击「保存」
| 生成器 | 说明 | 适用场景 |
|---|---|---|
random |
在 min~max 范围内随机变化 | 温度、压力、流量 |
sine |
正弦波变化 | 周期性数据模拟 |
square |
方波变化 | 开关量模拟 |
sawtooth |
锯齿波变化 | 计数器、累计量 |
triangle |
三角波变化 | 周期性变化 |
increment |
递增(到 max 回绕到 min) | 计数器、产量 |
fixed / constant |
固定值不变 | 设定值、常量 |
script |
自定义脚本 | 复杂逻辑 |
- 在设备列表中点击 「测点」 按钮
- 查看实时测点值(每秒自动刷新)
- 写入测点:
- 选择要写入的测点名称
- 输入值
- 点击「写入」
- 重置测点:
- 点击「重置」恢复单个测点到生成器计算的值
- 点击「全部重置」恢复所有测点
💡 写入测点后,外部 Modbus/S7 客户端会读到新写入的值。这是测试写控制功能的常用方法。
点击设备的 「详情」 按钮,可以看到设备状态机:
- 当前状态:
online/stopped/error/starting/maintenance/program - 状态转换:选择事件(如
stop、fault、reset),点击「状态转换」 - 状态历史:记录所有状态变更事件
不同状态下,外部 Modbus 客户端会收到不同的异常码:
| 设备状态 | Modbus 异常码 | 含义 |
|---|---|---|
| online | 无(正常响应) | 正常 |
| error | 0x04 | Slave Device Failure |
| starting / stopping | 0x05 | Acknowledge(请稍后重试) |
| maintenance | 0x06 | Slave Device Busy |
| program | 0x0A | Gateway Path Unavailable |
- 单台启停:点击设备行的「启动」/「停止」按钮
- 批量启停:勾选多台设备 → 点击「批量启动」/「批量停止」
- 进入 「协议服务」 页面
- 可以看到 17 种协议及其状态和端口
- 操作:
- 一键启动:启动所有已安装的协议
- 单独启动/停止:操作单个协议
- 一键停止:停止所有协议
- 进入 「系统设置」 页面
- 找到「协议端口配置」区域
- 修改对应协议的端口号
- 点击保存
- 重启对应协议服务(在协议服务页面停止再启动)
⚠️ 修改端口后必须重启协议服务才能生效。
部分协议需要额外安装依赖才能使用:
| 协议 | 安装命令 | 说明 |
|---|---|---|
| OPC-UA | pip install -e ".[opcua]" |
需要 asyncua 库 |
| MQTT | pip install -e ".[mqtt]" |
需要 amqtt 库 |
| BACnet | pip install -e ".[bacnet]" |
需要 bacpypes 库 |
| Siemens S7 | pip install -e ".[s7]" |
需要 python-snap7 库 |
| 全部协议 | pip install -e ".[all]" |
一次安装所有依赖 |
Docker 部署的镜像已包含全部协议依赖,无需额外安装。
- 进入 「仿真场景」 页面
- 点击「创建场景」
- 输入场景名称和描述
- 添加设备到场景
- 配置联动规则(可选)
进入 「场景编排器」 页面,可以用可视化拖拽方式编排设备拓扑:
- 选择一个场景
- 点击「添加设备」→ 选择设备或从模板创建
- 设备节点会出现在画布上,可以自由拖拽布局
- 创建联动规则:
- 从源设备的连接点拖拽到目标设备
- 弹出规则配置弹窗
- 配置规则名称、类型、条件、动作
- 双击设备节点可以编辑测点配置
- 双击连线可以编辑规则
- 点击「保存布局」保存
| 类型 | 说明 | 配置示例 |
|---|---|---|
| 阈值触发 | 测点值满足条件时触发 | 温度 > 80°C 时启动风扇 |
| 值变化 | 测点值发生变化时触发 | 状态从 0 变为 1 时告警 |
| 定时触发 | 按固定时间间隔触发 | 每 60 秒采样一次 |
| 脚本触发 | 自定义脚本判断 | value > 80 and value < 120 |
| 动作 | 说明 |
|---|---|
| set | 将目标测点设为指定值 |
| toggle | 切换布尔测点的值 |
| increment | 目标测点值递增 |
| decrement | 目标测点值递减 |
场景:温度传感器超过 80°C → 启动风扇 → 注入传感器噪声
在场景编排器中:
- 添加「温度传感器」和「风扇」两个设备节点
- 从温度传感器拖拽连线到风扇
- 配置规则:
- 规则名称:
高温联动 - 规则类型:
阈值触发 - 源测点:
temperature - 条件:
> 80 - 目标测点:
speed - 动作类型:
set - 目标值:
100 - 冷却时间:
5(秒)
- 规则名称:
- 保存并启动场景
每条规则可以设置 冷却时间(秒)。规则触发后,在冷却时间内不会重复触发,防止规则频繁执行。
- 在「设备管理」页面,点击设备的 「详情」 按钮
- 找到「故障注入」区域
- 选择故障类型 → 填写参数 → 点击「注入故障」
| 故障类型 | 说明 | 效果 |
|---|---|---|
sensor_stuck |
传感器卡死 | 测点值冻结在当前值不再变化 |
sensor_drift |
传感器漂移 | 测点值逐渐偏移,偏离真实值 |
sensor_noise |
传感器噪声 | 测点值叠加随机噪声 |
sensor_failure |
传感器失效 | 测点值变为 0 或异常值 |
comm_loss |
通信中断 | 设备模拟离线,不响应请求 |
comm_delay |
通信延迟 | 响应延迟指定时间 |
comm_intermittent |
通信间歇中断 | 随机丢失部分请求 |
device_failure |
设备故障 | 设备进入 error 状态 |
actuator_stuck |
执行器卡死 | 写入操作不生效 |
| 参数 | 说明 |
|---|---|
| 目标测点 | 要注入故障的测点名称(* 表示所有测点) |
| 持续时间 | 故障持续时间(秒),-1 为永久 |
| 严重程度 | low / medium / high / critical |
| 触发方式 | manual(手动)/ random(随机)/ scheduled(定时)/ conditional(条件) |
- 在故障列表中,点击单条故障的「移除」按钮
- 点击「清除所有故障」一次性清除全部故障
ProtoForge 可以将仿真数据实时转发到外部系统。
| 类型 | 说明 | 适用场景 |
|---|---|---|
| InfluxDB | 时序数据库 | 长期存储、Grafana 可视化 |
| HTTP Webhook | HTTP POST 推送 | 自定义接收端、第三方系统对接 |
| 文件 | JSONL/CSV 文件 | 本地存储、离线分析 |
- 进入 「数据转发」 页面
- 点击「添加目标」
- 填写:
- 目标名称:
influxdb-prod - 目标类型:
InfluxDB - 主机地址:
localhost - 端口:
8086 - 数据库:
protoforge
- 目标名称:
- 点击「添加」
- 点击「添加目标」
- 填写:
- 目标名称:
my-webhook - 目标类型:
HTTP - 目标 URL:
https://your-server.com/api/data - 请求头(可选):
{"Authorization": "Bearer xxx"}
- 目标名称:
- 点击「添加」
- 点击页面顶部的 「启动转发」 按钮开始转发
- 点击 「停止转发」 按钮停止
转发启动后,ProtoForge 会将所有设备的测点数据实时推送到配置的目标。
页面顶部显示实时统计:
- 已发送:成功转发的数据条数
- 已丢弃:因队列满等原因丢弃的条数
- 错误数:发送失败次数
- 速率:每秒转发条数
调试日志是排查通信问题的关键工具。
- 进入 「调试日志」 页面
- 实时查看所有协议的收发报文(WebSocket 推送,零延迟)
| 筛选方式 | 说明 |
|---|---|
| 按协议 | 只看 Modbus / MQTT / S7 等特定协议 |
| 按方向 | ← 收(接收)/ → 发(发送)/ 系统 |
| 关键词搜索 | 搜索报文内容,如 error、register、invite |
- 点击日志条目:查看完整报文详情(十六进制 / JSON 格式)
- 暂停日志流:暂停后可以仔细分析某条消息
- 导出 JSON:将当前日志导出为文件,离线分析或分享
问题:外部客户端读不到数据
- 打开调试日志,筛选对应协议
- 用外部客户端发起读取请求
- 查看是否收到请求报文(←收 方向)
- 查看返回的响应报文(→发 方向)
- 检查响应中的数据是否为 0 或异常值
问题:写入不生效
- 筛选对应协议
- 在 ProtoForge 或外部客户端写入测点
- 查看写入请求报文
- 再次读取,查看响应是否反映了写入的值
ProtoForge 支持将设备配置自动推送到 EdgeLite 物联网网关,免去手动在网关中添加设备。
在创建或编辑设备时,在协议配置中填写 EdgeLite 信息:
| 字段 | 说明 | 示例 |
|---|---|---|
edgelite_url |
EdgeLite 网关地址 | http://192.168.1.200:8100 |
edgelite_username |
用户名 | admin |
edgelite_password |
密码 | admin123 |
不填就不推送,不影响 ProtoForge 正常使用。
- 在设备管理页面,点击设备的 「验证链路」 按钮
- 系统自动执行四步验证:
- ① 认证 EdgeLite
- ② 注册设备
- ③ 连接设备
- ④ 采集数据
- 全部通过显示绿色 ✅
使用 docker-compose.joint.yml 一条命令同时启动 ProtoForge + EdgeLite + MQTT + InfluxDB:
cp .env.joint.example .env.joint
# 编辑 .env.joint,修改所有 change_me_* 密码
docker compose -f docker-compose.joint.yml --env-file .env.joint up -d启动后:
- ProtoForge 界面:http://localhost:8000
- EdgeLite 界面:http://localhost:8081
- 进入 「仿真测试」 页面
- 点击「一键测试全部」
- 系统自动生成测试用例并运行
- 查看测试报告
系统自动生成以下测试:
- 协议连通性测试:验证协议服务是否正常响应
- 设备读写测试:验证测点数据是否可读可写
- 场景规则测试:验证联动规则是否正确触发
- 状态转换测试:验证设备状态机是否正常
- 支持 HTML 格式报告(含步骤详情、断言结果、耗时统计)
- 支持历史趋势数据查看
进入 「系统设置」 页面,可以在线修改:
| 配置项 | 说明 |
|---|---|
| 服务器端口 | Web 服务端口(默认 8000) |
| 数据库路径 | SQLite 文件路径或 PostgreSQL 连接串 |
| 日志级别 | debug / info / warning / error |
| CORS 源 | 允许跨域访问的地址 |
| InfluxDB 转发 | InfluxDB 连接配置 |
| 协议端口 | 各协议服务的监听端口 |
| gRPC 端口 | gRPC 远程管理端口(0=禁用) |
- 导出备份:点击「导出备份」按钮,下载全库 JSON 文件
- 恢复备份:上传 JSON 文件,一键恢复
备份内容包括:设备配置、场景配置、模板、测试用例、审计日志。
排查步骤:
- 确认协议服务已启动(「协议服务」页面,状态为绿色运行中)
- 确认端口号正确(查看协议服务页面或系统设置)
- 确认防火墙没有拦截端口
- 打开「调试日志」页面,看是否有连接请求到达
排查步骤:
- 在「设备管理」页面点击「测点」,确认 ProtoForge 内部测点有值
- 确认 Modbus 的
slave_id匹配(ProtoForge 设备的 slave_id 与客户端请求的一致) - 确认地址映射正确(在设备的「指南」按钮中查看地址说明)
- 打开调试日志,检查响应报文中的实际值
设备创建后需要启动才能上线。在设备管理页面,确认设备状态是「在线」(绿色)。如果是「已停止」(灰色),点击「启动」按钮。
在设备管理页面点击「编辑」→ 找到对应测点 → 修改「数据生成器」类型:
random:随机变化(默认)sine:正弦波fixed:固定值increment:递增- 等等
保存后立即生效。
在设备管理页面点击「详情」→ 故障注入区域 → 选择故障类型 → 点击「注入故障」。详见 故障注入章节。
可以。进入「数据转发」页面,添加 InfluxDB 目标并启动转发。详见 数据转发章节。
- 在「设备管理」页面点击「批量创建」
- 选择模板,填写数量(最多 50 台/次)
- 执行两次即可创建 100 台
- 全选后点击「批量启动」
- Docker 部署:删除数据卷重新创建,或设置
PROTOFORGE_ADMIN_PASSWORD环境变量重置 - 源码部署:删除
data/protoforge.db文件后重启(⚠️ 会清空所有数据)
📖 更多技术文档:README.md | DEPLOYMENT.md | SECURITY.md