一个用于模拟能源管理系统(EMS)中关键设备行为的软件系统,主要用于测试和开发场景。系统支持多种工业通信协议(Modbus TCP/RTU、IEC 60870-5-101/104、DL/T 645-2007、IEC 61850、DNP3),可模拟真实工业设备(如PCS储能变流器、BMS电池管理系统、电表、断路器等)的数据交互。
EMS Simulate 已上架微软应用商店,可直接在 Windows 10/11 上安装使用。
点击上方图片,或 直接访问 Microsoft Store 下载页面。
| 功能 | 说明 |
|---|---|
| 多协议联调 | Modbus TCP/RTU、IEC 60870-5-101/104、DL/T 645-2007、IEC 61850、DNP3,支持设备模拟与客户端采集 |
| 设备管理 | 设备分组与子分组、通道与从站管理、启停、连接监视;支持批量复制及名称、IP、端口偏移配置 |
| 测点管理 | YC/YX/YK/YT 分类管理、测点编辑、Excel 点表导入与导出、协议属性配置和运行时更新 |
| 数据模拟 | 固定值、随机、递增、递减、正弦波、斜坡、脉冲;支持单点配置、批量配置和模拟数据监视 |
| 读取与控制 | 单点读取、批量读取、后台自动读取,以及各协议支持的遥控、遥调操作 |
| 测点联动 | 乘法/加法系数、自定义公式、跨设备测点映射,构建设备间的数据关联 |
| 变化追踪 | 查看测点变化时间、前后值和来源,区分手动修改、模拟、映射、协议写入和客户端读取 |
| 报文分析 | 在各协议设备下查看收发报文、原始字节与字段解析,辅助定位通信问题 |
| IEC 61850 工具 | 数据模型与 DataSet、MMS、GOOSE、Reports、Files、定值组、日志,以及 SCL 文件管理和图形化建模 |
| 界面与运行环境 | Vue 3 Web 界面、Tauri 桌面客户端、中英文切换、界面缩放、存储目录配置及应用日志查看 |
| 层次 | 技术 |
|---|---|
| 前端 | Vue 3, TypeScript, Vite, Element Plus |
| 后端 | Python 3.11+, FastAPI, SQLAlchemy |
| 协议 | pymodbus 3.12, c104, dlt645, pyiec61850-ng, pydnp3-pure,以及 IEC101 FT1.2 实现 |
| 数据库 | SQLite (默认) / MySQL |
| 桌面壳 | Tauri v2 + Rust |
已有截图直接展示;待补截图以“截图待补”标记,并附建议文件名和图片语法。将截图放入 resources/img/ 后,取消对应图片语法的 HTML 注释,即可替换占位说明。
-
主界面 — 设备分组树 + 设备详情面板
-
添加设备分组
-
添加子设备组
-
新增设备 — 选择设备类型与协议
-
展开列表行编辑测点值
-
设置数据模拟方式 — 随机 / 步进 / 固定值
-
编辑测点信息 — 地址、系数、解析码等
支持复制单个或多个设备,配置名称前后缀、IP 和端口偏移;通过从站管理和连接监视查看设备通信状态。
通过 Excel 模板批量配置测点,支持导出点表。仓库提供 Modbus、IEC104、DL/T 645 和 DNP3 示例点表。
支持固定值、随机、递增、递减、正弦波、斜坡、脉冲等模拟方式,可按测点设置参数,并批量选择参与模拟的测点。
客户端支持单点、批量和后台自动读取。自动读取在切换页面后继续运行,回到设备页面可恢复查看任务状态;停止设备时结束对应任务。
支持以多个源测点构建公式,并将结果映射到目标测点,实现跨设备、跨协议的数据联动。变化历史记录时间、前后值及变化来源,便于追查模拟和通信写入的结果。
提供中英文切换、界面缩放、存储目录配置和应用运行日志查看。
应用设置 — 展示界面、语言和存储配置。
以下按协议介绍配置、数据操作与报文查看。各协议支持服务端/从站(模拟设备)和客户端/主站(采集或控制设备)角色,具体功能见对应模块。
工业自动化领域应用最广泛的通信协议,支持 TCP 网络连接和 RTU 串口连接两种模式。
| 属性 | TCP | RTU |
|---|---|---|
| 默认端口 | 502 | —(串口) |
| 数据操作 | 线圈、离散输入、保持寄存器、输入寄存器的读取及可写区写入 | 同 TCP |
| 解析码 | 8/16/32/64 位、大小端、字交换 | 同 TCP |
支持线圈、离散输入、保持寄存器、输入寄存器四类数据区,内置完整解析码系统适配不同厂商设备。
电力系统远动通信标准协议,广泛用于变电站与调度中心之间的数据传输。
| 属性 | 说明 |
|---|---|
| 默认端口 | 2404 |
| 帧类型 | YC(遥测)、YX(遥信)、YK(遥控)、YT(遥调) |
| 品质描述 | IV/NT/SB/BL/OV 等标准品质位 |
| 传输原因 | 周期、自发、总召等 |
支持四遥(YC/YX/YK/YT)、ASDU 类型配置与筛选、总召、时钟同步及品质描述符。
IEC104 的串行远动协议版本,与 IEC104 共用 ASDU、四遥点表、品质描述符、传送原因和数值换算。
| 属性 | 说明 |
|---|---|
| 传输介质 | 串口(主站 / 从站) |
| 链路层 | FT1.2 定长帧、变长帧、单字符确认、校验和、FCB/FCV |
| 地址长度 | 链路地址 1/2 字节、COT 1/2 字节、公共地址 1/2 字节、IOA 1~3 字节 |
| 应用功能 | 一级/二级数据轮询、总召唤、读命令、遥控/遥调、时钟同步、自发上送 |
默认采用非平衡传输模式;协议运行参数中可以配置地址宽度、响应超时与轮询间隔。
中国电力行业多功能电能表通信协议标准,用于电表数据采集。
| 属性 | 说明 |
|---|---|
| 默认端口 | 8899 |
| 数据标识 | 按 DI 配置电能、功率、电压、电流等数据项 |
| 系数转换 | 乘法系数 + 加法系数 → 真实值 |
DL/T645 协议测试 — 验证读取值与系数转换的正确性
支持电表数据项标识解析,自动应用乘法/加法系数转换真实值,提供客户端读取验证。
面向智能变电站的设备模拟与联调,提供 MMS 数据访问、GOOSE 发布/订阅、报告控制、文件浏览、定值组和日志功能,并配套 SCL 管理与图形化建模工具。
| 子模块 | 功能 |
|---|---|
| MMS / Data Models | 服务端建模、客户端模型发现、树形浏览、数据读写与模型导出 |
| Data Sets | 数据集成员浏览与批量读取 |
| GOOSE | 发布、订阅、接收历史与报文抓包解析 |
| Reports | BRCB/URCB 控制块配置、启停、GI 与报告接收 |
| Files | 客户端远程目录浏览和文件下载 |
| Setting Groups | 定值组发现、读取、选择编辑组、写入、确认和激活 |
| Logs | 日志控制块发现与启停、按时间范围查询日志 |
| SCL 文件管理 | ICD/CID/SCD 文件上传、预览、校验、导入与差异对比 |
| 图形化建模 | 模型工程、LD/LN/DO/DA 编辑、CDC 模板、DataSet 与控制块配置、模型校验、版本管理及发布 |
支持客户端模型发现和模型导出;DataSet 可用于组织测点并进行批量读取。
📷 DataSet 与模型导出 — 展示模型导出格式。
查看定值组控制块,选择编辑组、修改定值并确认,再激活目标定值组。
📷 IEC61850 定值组 — 展示当前激活组、编辑组、定值列表及操作结果。
管理日志控制块
支持 SCL 文件预览、导入和差异对比;图形化建模工作区可创建或导入模型工程,编辑逻辑设备、逻辑节点和数据对象,配置数据集与控制块,执行校验、保存版本并发布模型。
MMS 报文
GOOSE 报文
Reports 报文
支持 Master(主站/客户端) 与 Outstation(从站/服务端),用于 DNP3 设备的数据采集、事件上送与控制联调。
| 属性 | 说明 |
|---|---|
| 传输与端口 | TCP,默认端口 20000;支持 TLS 配置 |
| 站点配置 | 本端与对端站点地址、请求超时、重试与重连参数 |
| 点表配置 | 点索引、静态/事件 Variation、事件 Class、死区、品质位及时间戳 |
| 数据采集 | Class 0 完整性轮询、Class 1/2/3 事件读取、单点与批量读取 |
| 事件上送 | 可配置 Unsolicited 未请求上报,接收后同步测点值与运行元数据 |
| 控制操作 | CROB 二进制控制、模拟量输出,支持 Select/Operate 和 Direct Operate |
| 其他操作 | 时间同步、计数器冻结;支持 Excel 点表导入 |
📷 DNP3 报文查看 — 展示收发方向、链路地址、应用功能码、对象组/变体及原始字节。
- Python >= 3.11
- Node.js >= 18
- uv、npm、Git(部分 Python 协议依赖从 Git 仓库安装)
在项目根目录安装 Python 依赖并启动后端:
# 如未安装 uv,先执行:pip install uv
uv sync --extra dev
uv run python start_back_end.py另开一个终端,从项目根目录启动前端:
cd front
npm install
npm run dev在浏览器中打开 Vite 输出的本地地址。后端配置见 配置说明。
Windows 构建需安装 Rust、MSVC 构建工具及 Tauri CLI。使用仓库打包脚本构建前端、Python 后端及桌面客户端:
# 在项目根目录执行
uv sync --extra dev --extra build
npm install -g @tauri-apps/cli
# 构建 Windows 安装包
.\scripts\build_tauri_windows.ps1脚本默认生成 MSI 安装包;MSIX 打包入口及额外工具要求见 Windows 打包脚本。Linux 部署见 Debian 打包与部署指南。
- 📚 项目文档: 完整的项目使用说明和 API 参考
- 设备批量复制、测点映射、公式使用、变化追踪
- 模拟配置、数据监视与自动读取
- 📦 Debian 打包与部署指南: 详细介绍了如何在 Linux 环境下构建 deb 安装包
系统支持四种测点类型:
| 类型 | 代码 | 说明 | 典型用途 |
|---|---|---|---|
| 遥测 (YC) | frame_type=0 | 模拟量测量 | 电压、电流、功率、温度 |
| 遥信 (YX) | frame_type=1 | 开关量状态 | 运行状态、故障标志 |
| 遥控 (YK) | frame_type=2 | 开关量命令 | 启停命令、合分闸 |
| 遥调 (YT) | frame_type=3 | 模拟量命令 | 功率设定、温度设定 |
| 协议 | 服务端 | 客户端 | 默认端口 |
|---|---|---|---|
| Modbus TCP | ✅ | ✅ | 502 |
| Modbus RTU | ✅ | ✅ | 串口 |
| IEC 60870-5-104 | ✅ | ✅ | 2404 |
| IEC 60870-5-101 | ✅ | ✅ | 串口 |
| DL/T 645-2007 | ✅ | ✅ | 8899 |
| DNP3 | ✅(Outstation) | ✅(Master) | 20000 |
| IEC 61850 MMS | ✅ | ✅ | 102 |
| IEC 61850 GOOSE | ✅(发布) | ✅(订阅) | —(以太网二层) |
| IEC 61850 Reports | ✅ | ✅ | 复用 MMS 连接 |
| IEC 61850 Files | ✅ | ✅ | — |
| IEC 61850 Setting Groups | ✅ | ✅ | 复用 MMS 连接 |
| IEC 61850 Logs | ✅ | ✅ | 复用 MMS 连接 |
解析码定义了 Modbus 寄存器数据的解析方式,包括数据类型、字节序和位数。
| 解析码 | 名称 | 说明 | 字节序 |
|---|---|---|---|
0x20 |
UINT16_BE | 16位无符号整数 | 大端 (AB) |
0x21 |
INT16_BE | 16位有符号整数 | 大端 (AB) |
0xC0 |
UINT16_LE | 16位无符号整数 | 小端 (BA) |
0xC1 |
INT16_LE | 16位有符号整数 | 小端 (BA) |
0xB0 |
UINT16_BE_SWAP | 16位无符号整数 | 大端字交换 |
0xB1 |
INT16_BE_SWAP | 16位有符号整数 | 大端字交换 |
| 解析码 | 名称 | 说明 | 字节序 |
|---|---|---|---|
0x40 |
UINT32_BE | 32位无符号整数 | 大端 (ABCD) |
0x41 |
INT32_BE | 32位有符号整数 | 大端 (ABCD) |
0x42 |
FLOAT_BE | 32位浮点数 | 大端 (ABCD) |
0xD0 |
UINT32_LE | 32位无符号整数 | 小端 (DCBA) |
0xD1 |
INT32_LE | 32位有符号整数 | 小端 (DCBA) |
0xD2 |
FLOAT_LE | 32位浮点数 | 小端 (DCBA) |
0x43 |
UINT32_BE_SWAP | 32位无符号整数 | 大端字交换 (CDAB) |
0x44 |
INT32_BE_SWAP | 32位有符号整数 | 大端字交换 (CDAB) |
0x45 |
FLOAT_BE_SWAP | 32位浮点数 | 大端字交换 (CDAB) |
0xD4 |
UINT32_LE_SWAP | 32位无符号整数 | 小端字交换 (BADC) |
0xD5 |
INT32_LE_SWAP | 32位有符号整数 | 小端字交换 (BADC) |
0xD3 |
FLOAT_LE_SWAP | 32位浮点数 | 小端字交换 (BADC) |
| 解析码 | 名称 | 说明 | 字节序 |
|---|---|---|---|
0x60 |
UINT64_BE | 64位无符号整数 | 大端 |
0x61 |
INT64_BE | 64位有符号整数 | 大端 |
0x62 |
DOUBLE_BE | 64位双精度浮点 | 大端 |
0xE0 |
UINT64_LE | 64位无符号整数 | 小端 |
0xE1 |
INT64_LE | 64位有符号整数 | 小端 |
0xE2 |
DOUBLE_LE | 64位双精度浮点 | 小端 |
| 解析码 | 名称 | 说明 |
|---|---|---|
0x10 |
CHAR_8_BE | 8位无符号字符 |
0x11 |
CHAR_8_BE_SIGNED | 8位有符号字符 |
以32位浮点数 1234.5 为例,其十六进制表示为 449A5000:
| 字节序类型 | 存储顺序 | 说明 |
|---|---|---|
| 大端 (BE) | 44 9A 50 00 |
高字节在前,标准网络字节序 |
| 小端 (LE) | 00 50 9A 44 |
低字节在前,x86架构常用 |
| 大端字交换 (BE_SWAP) | 50 00 44 9A |
寄存器内大端,寄存器间交换 |
| 小端字交换 (LE_SWAP) | 9A 44 00 50 |
寄存器内小端,寄存器间交换 |
from src.enums.modbus_register import Decode, DecodeCode
# 方式一:使用解析码字符串
info = Decode.get_info("0x41")
print(f"寄存器数量: {info.register_cnt}") # 2
print(f"是否有符号: {info.is_signed}") # True
print(f"字节序: {info.endian}") # >
# 方式二:使用枚举(推荐)
info = DecodeCode.FLOAT_BE.value
print(f"解析码: {info.code}") # 0x42
print(f"描述: {info.description}") # 32位浮点数(大端)
# 数据打包/解包
packed = Decode.pack_value(info.pack_format, 1234.5)
value = Decode.unpack_value(info.pack_format, packed)
# 获取所有解析码(供前端下拉菜单使用)
all_codes = Decode.get_all_codes()遥测和遥调类型支持系数转换:
真实值 = 寄存器值 × 乘法系数 + 加法系数
寄存器值 = (真实值 - 加法系数) ÷ 乘法系数
| 属性 | 说明 | 默认值 |
|---|---|---|
mul_coe |
乘法系数 | 1.0 |
add_coe |
加法系数 | 0.0 |
ems_simulate/
├── src/ # 后端源码
│ ├── config/ # 配置管理
│ │ ├── config.py # 全局配置
│ │ └── log/ # 日志配置
│ ├── data/ # 数据层
│ │ ├── dao/ # 数据访问对象
│ │ └── service/ # 业务服务
│ ├── device/ # 设备模拟器 ⭐
│ │ ├── core/ # 核心类
│ │ │ ├── device.py # Device 主类
│ │ │ ├── point/ # 测点管理与计算
│ │ │ └── data/ # 数据读取与导出
│ │ ├── protocol/ # 协议处理器
│ │ │ ├── base_handler.py # 基类
│ │ │ ├── modbus_handler.py # Modbus
│ │ │ ├── iec104_handler.py # IEC104
│ │ │ ├── iec101_handler.py # IEC101
│ │ │ ├── dlt645_handler.py # DLT645
│ │ │ ├── dnp3_handler.py # DNP3 Master/Outstation
│ │ │ └── iec61850_handler.py # IEC61850
│ │ ├── simulator/ # 模拟控制
│ │ ├── factory/ # 设备工厂
│ │ └── types/ # 设备类型
│ ├── enums/ # 枚举和数据结构
│ │ ├── modbus_register.py # 解析码定义 ⭐
│ │ └── points/ # 测点类型
│ ├── proto/ # 底层协议实现
│ │ ├── pyModbus/ # Modbus 服务端/客户端
│ │ ├── iec104/ # IEC104 服务端/客户端
│ │ ├── iec101/ # IEC101 FT1.2 主站/从站
│ │ ├── iec60870/ # IEC101/IEC104 公共 ASDU 层
│ │ ├── dlt645/ # DLT645 协议库
│ │ ├── dnp3/ # DNP3 主站/从站、事件、控制与 TLS
│ │ └── iec61850/ # IEC61850 MMS/GOOSE/Reports/Files/SV
│ ├── modeling/ # IEC61850 模型工程、校验与版本管理
│ └── web/ # Web API
│ └── api/
│ ├── device/ # 设备控制接口
│ ├── channel/ # 通道与协议管理
│ ├── point/ # 测点与映射接口
│ ├── modeling/ # IEC61850 图形化建模接口
│ └── scl/ # SCL/ICD 文件管理
├── front/ # 前端源码 (Vue3)
│ ├── src/
│ │ ├── components/ # 组件
│ │ ├── views/ # 页面
│ │ └── api/ # API封装
│ └── package.json
├── src-tauri/ # Tauri 桌面壳 (Rust)
│ ├── src/
│ │ ├── lib.rs # Tauri Builder
│ │ └── backend.rs # 后端进程管理
│ └── tauri.conf.json
├── data/ # SQLite 数据库
├── start_back_end.py # 后端入口
├── pyproject.toml # Python 依赖与配置
└── uv.lock # Python 依赖锁定文件
- 在
src/device/types/下创建新设备类 - 继承
Device基类 - 实现
setSpecialDataPointValues()方法(可选)
from src.device.core.device import Device, DeviceType
class MyDevice(Device):
def __init__(self):
super().__init__()
self.device_type = DeviceType.Other
def setSpecialDataPointValues(self):
# 设置特殊测点关联逻辑
pass- 在
src/device/protocol/下创建处理器 - 继承
ServerHandler或ClientHandler - 实现抽象方法
from src.device.protocol.base_handler import ServerHandler
class MyProtocolHandler(ServerHandler):
def initialize(self, config):
pass
async def start(self) -> bool:
self._is_running = True
return True
async def stop(self) -> bool:
self._is_running = False
return True
def read_value(self, point):
pass
def write_value(self, point, value):
pass
def add_points(self, points):
pass本项目采用 GNU General Public License v3.0(GPL-3.0),详见 LICENSE。
欢迎提交 Issue 和 Pull Request!















































