engZafer35/IEC62056-MeterSim

GitHub: engZafer35/IEC62056-MeterSim

一个轻量级的 IEC 62056 智能电能表 TCP 模拟器,用于在没有真实硬件的环境下生成一致的能源消耗数据并支持协议读取和负荷曲线查询。

Stars: 0 | Forks: 0

# ⚡ IEC 62056 TCP 电能表模拟器 这是一个基于 Python、受 **IEC 62056-21**(原 IEC 1107)启发、**支持 TCP** 的电能表模拟器。 它不执行真实的测量;相反,它会以固定的时间间隔(默认 **15 分钟**)生成随机但**正向且一致的**能源消耗,并更新: - **总输入电能 (OBIS 1.8.0)** - **瞬时功率 (1.7.0)** - **电压 (32.7.0)** - **负荷曲线 (P.01 记录)** 这些数值可以通过 **TCP 读取**以及通过**本地数据文件**展示。 ## 🛠 功能特性 - **分层架构**: - **传输层**:TCP 服务器 (`tcp_server.py`) - **协议/消息解析**:类似 IEC 62056 的状态机 (`iec62056_protocol.py`) - **电表核心与负荷曲线**:仿真与数据文件管理 (`meter_model.py`) - **短/默认读取**支持: - `/?!` 握手 → 电表标识 - `ACK050` → 完整的 OBIS 读取 - **负荷曲线 (P.01)** 查询: - `P.01(YYMMDDhhmm)(YYMMDDhhmm)` → 返回给定范围内的所有记录 - **负荷曲线数据文件**: - 默认文件:`meter_data.txt` — 每个间隔占一行,采用 6 字段格式(日期、时间、总电能、电压、电流、功率因数)。 - 快照文件:`meter_data_total_endex.txt` — 包含上次的时间戳和总输入;**内容派生自**最后一条记录的**总电能字段**(或在关闭时写入)。 - 在启动时,应用程序会从 `meter_data.txt` 的**最后一行**(或快照文件)加载状态,因此 OBIS 1.8.0 与负荷曲线保持一致。 - **更快的测试周期**: - 实际应用的间隔为 15 分钟,但为了测试,您可以将其设置为例如 10 秒。 - **🖥 TCP 客户端应用程序** (`Meter_Client_Test.py`): - 通过 TCP 连接并执行协议请求 - 主机和端口可通过 CLI 配置 - 包含超时和基本错误处理的安全连接 - OBIS 读取: - `/?!` → 获取电表 ID - `ACK050` → 接收短/完整读取结果 - 负荷曲线 (P.01) 查询: - 获取给定开始/结束时间范围内的数据 - 支持较大的响应(缓冲区 ≥ 4 KB) - **参数** --host, --port → 目标服务器 --interval → 查询间隔(以秒为单位) --start, --end → 负荷曲线时间窗口 - **持续监控** - 按照指定的间隔自动重新查询 - 可以通过按 Ctrl+C 安全停止 ## ⚙ 安装说明 ### 📦 环境要求 - Python **3.9+**(推荐 3.10 或更高版本) - Windows、Linux 或 macOS(以下示例使用 Windows/PowerShell) ### 🚀 运行 克隆项目后,进入该文件夹: ``` cd ElectricityMeter ``` 使用默认设置启动模拟器: ``` python run_simulator.py ``` 默认配置: - 主机:`0.0.0.0` - 端口:`5000` - 负荷曲线文件:`meter_data.txt` - 间隔:`900` 秒(**15 分钟**) 为了进行测试,您可以加快间隔速度(例如,每 10 秒创建一条新记录): ``` python run_simulator.py --interval-seconds 10 ``` 自定义主机/端口和 meterID 的示例: ``` python run_simulator.py --host 127.0.0.1 --port 5000 --meter-id ZD5ME666-667 ``` 连接 TCP 客户端并获取数据: ``` python Meter_Client_Test.py --host 127.0.0.1 --port 5000 --interval 10 ``` ## 🧱 针对 Windows 编译 新增了 `build_windows_exe.ps1` 脚本,用于将 Python 代码转换为单个可执行文件。 ``` cd c:\Users\zafer\OneDrive\Desktop\ElectricityMeter\IEC62056-MeterSim .\build_windows_exe.ps1 -Mode nuitka ``` 如果您想使用 `pyinstaller` 作为替代方案: ``` .\build_windows_exe.ps1 -Mode pyinstaller ``` ## 🧱 针对 Linux 编译 新增了 `build_linux_exe.sh` 脚本,用于在 Linux 上创建可执行包。 ``` cd /path/to/ElectricityMeter/IEC62056-MeterSim chmod +x ./build_linux_exe.sh ./build_linux_exe.sh nuitka ``` 使用 PyInstaller: ``` ./build_linux_exe.sh pyinstaller ```

## 🧩 工作原理(逐步说明) ### 1️⃣ 电表核心 (`MeterSimulator`) `meter_model.py` 中的 `MeterSimulator` 类: - 启动一个后台**线程**。 - 在每个间隔(例如测试中的 15 分钟 / 10 秒): - 在 0.1–0.6 kWh 范围内生成**随机正向消耗**。 - 根据此间隔电能,计算平均功率并将**瞬时功率 (1.7.0)** 设定在该值附近。 - 在 230 V 附近生成带有微小随机变化的**电压 (32.7.0)**。 - 对于每个间隔: - 计算**电压**(≈210–240 V)、**功率因数**(≈0.85–1.0)以及根据功率得出的**电流**(I = P/(V×PF))。 - 追加一条带有累积总电能、电压、电流和功率因数的**负荷曲线记录**。 - 将间隔消耗加到**总输入 1.8.0** 中。 - 以 **6 字段格式**写入每条记录: ``` (YYYY-MM-DD)(HH:MM)(000000.000*kWh)(229*V)(000.0*A)(1.00) ``` | 字段 | 含义 | |-------|--------| | 1 | 日期 (YYYY-MM-DD) | | 2 | 时间 (HH:MM) | | 3 | 总能耗 (kWh,累积值) | | 4 | 单相电压 (V) | | 5 | 单相电流 (A) | | 6 | 功率因数 | - 在启动时: - 读取 `meter_data.txt` 的**最后一行**(如果缺少数据文件,则读取 `meter_data_total_endex.txt`)以设置 **OBIS 1.8.0 总输入**和上次的时间戳。 ### 2️⃣ 协议流程(类似 IEC 62056) `iec62056_protocol.py` 中的 `ConnectionState` 类处理基本的 IEC 62056-21 风格的流程: 1. **握手**: - 客户端发送: - `/?!` + CRLF - 电表响应: - `/ZD5ME666-1003` + CRLF 2. **波特率选择 (ACK050)**: - 客户端发送: - `ACK050` + CRLF - 由于这是 TCP,物理波特率并未改变,但该命令被**接受以保证协议兼容性**。 - 电表立即发送**短/默认读取结果**: ``` 0.0.0(12345678) 1.8.0(0012345.67*kWh) 2.8.0(0000123.45*kWh) 1.7.0(0001.42*kW) 32.7.0(230.4*V) 0.9.1(HH:MM:SS) 0.9.2(YY-MM-DD) ! ``` 3. **负荷曲线查询 (P.01)**: - 客户端发送开始和结束时间戳: ``` P.01(YYMMDDhhmm)(YYMMDDhhmm) Example: `P.01(2401010000)(2401012359)` ``` - 电表返回给定范围内的所有记录(与数据文件相同的 6 字段格式),或者在范围为空或无效时(例如 start > end)返回 **No-Data** + `!`: ``` (2026-03-17)(14:10)(000030.960*kWh)(230*V)(008.5*A)(0.92) (2026-03-17)(14:25)(000031.520*kWh)(228*V)(007.2*A)(0.89) ... ! ``` 这种设计确保了: - 随着时间的推移,**总输入 (1.8.0)** ≈ **日/周负荷曲线的总和**,从而提供一致的仿真。 ### 3️⃣ TCP 服务器 `tcp_server.py` 中的 `MeterTCPServer` 类: - 充当电表设备并**自行打开 TCP 监听套接字**: - `bind(host, port)` + `listen()` - 为每个新客户端生成一个专用线程。 - 将传入的字节转换为 ASCII,并将其**逐行**发送到 `ConnectionState`: - 使用 **CRLF**(或 LF)作为行终止符。 - 如果 `ConnectionState.handle_line()` 返回响应字符串,则会将其发送回客户端。 ## 终端会话示例 假设模拟器正在后台运行: ``` python run_simulator.py --host 127.0.0.1 --port 5000 --interval-seconds 10 ``` 您可以在另一个终端中使用简单的 TCP 客户端(例如 `telnet`)进行连接: ``` telnet 127.0.0.1 5000 ``` 1. **握手**: ``` Client: /?! Meter : /ISK5ME382-1003 ``` 2. **ACK + 短读取**: ``` Client: ACK050 Meter : 0.0.0(12345678) 1.8.0(0000005.23*kWh) 2.8.0(0000000.00*kWh) 1.7.0(0001.42*kW) 32.7.0(230.4*V) 0.9.1(14:22:31) 0.9.2(24-01-01) ! ``` 3. **负荷曲线查询**(示例日期范围): ``` Client: P.01(2401010000)(2401012359) Meter : (2026-01-01)(00:00)(000012.340*kWh)(229*V)(005.2*A)(0.91) (2026-01-01)(00:15)(000012.720*kWh)(231*V)(004.8*A)(0.93) ... ! ``` 如果请求的范围没有数据(例如,未来日期)或者 start > end,电表将响应: ``` No-Data ! ``` ## 🔗 客户端-服务器交互 image image ## 简单的基于文本的每日消耗图表 以下是基于文本的图表示例,展示了约一天的总电能为 **~12.34 kWh**(15 分钟间隔)的情况: ``` Saat Tüketim (kWh) Grafik ----- -------------- ---------------------------- 00:00 0.42 ################ 00:15 0.38 ############### 00:30 0.35 ############# 00:45 0.40 ############### 01:00 0.50 #################### ... 23:45 0.41 ############### Total ≈ 12.34 kWh (OBIS 1.8.0 ≈ 12.34 kWh) ``` 这个想法以后可以在 **GUI 或 Web 仪表板**中转化为真实的日/周图表。 ## 💡 扩展建议 - **新的 OBIS 代码**(例如:电流、功率因数、单相测量) - **可选的配置集**: - 居民用电户 - 工业电价 - PV / 太阳能发电场景(使用 2.8.0 表示输出) - **真实的 TCP/串口桥接**: - TCP → 串口 → 真实的物理电表 (代理) - **UI 集成**: - Tkinter / PyQt / 基于 Web 的仪表板: - 瞬时功率、电压、总电能 - 负荷曲线图表 - 简单的报警/限值通知 ## 贡献与许可 本存储库是一个用于测试和教学目的的模拟器。 非常欢迎提交 Pull Request、新增 OBIS 支持以及改进建议。

标签:DLMS/COSEM, IEC 1107, IEC 62056, IEC 62056-21, IoT仿真, OBIS码, PE 加载器, Python, TCP/IP, TCP客户端, TCP服务器, 协议模拟, 嵌入式测试, 并发处理, 开发辅助, 插件系统, 数据生成器, 无后门, 智能仪表, 智能家居, 智能电网, 智能电表, 测试工具, 状态机, 用电量模拟, 电力模拟器, 电力系统测试, 电能数据, 网络编程, 能源应用, 表计读取, 负荷曲线, 负载曲线, 逆向工具