能源管理系统(EMS)怎么开发?从 0 到 1 讲透架构、技术栈与核心模块 一、先搞清楚EMS 到底在做什么能源管理系统Energy Management SystemEMS不是单纯“画几个能耗曲线”它的本质是把电、水、气、热、光伏、储能等能源数据采上来 → 存好 → 算指标 → 看板展示 → 异常告警 → 指导节能决策。一个能用的 EMS 至少覆盖这条链路智能电表/水表/气表/PLC/光伏逆变器 ↓ Modbus / MQTT / OPC UA 边缘采集网关协议转换预处理 ↓ Kafka / MQTT Broker 后端微服务采集/清洗/计算/告警 ↓ MySQL(业务) InfluxDB(时序) ↓ Vue3 ECharts 大屏 / 报表 / 接口二、总体架构设计分层解耦推荐“云—边—端”五层架构层级职责典型技术感知层电表、水表、气表、PLC、传感器Modbus RTU/TCP、DL/T 645、BACnet边缘层协议解析、数据清洗、断网续传工业网关、Python/Go 采集程序平台服务层接收、计算、告警、报表Spring Boot / Flask Kafka数据存储层时序数据 关系数据InfluxDB/TimescaleDB MySQL应用展示层大屏、Web、移动端、APIVue3 ECharts Grafana中小项目可先单机 Docker 部署测点过万再拆微服务 K8s。三、技术栈选型Java 体系为例后端Spring Boot 2.7 / Spring Cloud Alibaba网关Spring Gateway注册配置Nacos消息队列Kafka 或 RabbitMQ高频数据异步削峰时序库InfluxDB / TimescaleDB / TDengine关系库MySQL 8.x设备档案、用户、报表模板缓存Redis实时值、Token、限流实时推送WebSocket前端Vue3 Element Plus PiniaECharts折线/柱/饼/热力/仪表盘大屏自适应方案scale 或 vw/vh边缘采集Pythonpymodbuspaho-mqtt或 Go高性能网关采集支持断网本地缓存、网络恢复续传四、核心功能模块怎么拆设备管理能源类型电/水/气/热、计量点、所属车间、采集频率、寄存器地址数据采集Modbus 轮询 / MQTT 订阅 / OPC UA 客户端数据清洗去抖、量程校验、空值补差、重复值去重指标计算总能耗、分项能耗单位产值能耗 kWh/万元峰谷平电量、需量同比/环比、COP、碳排放IPCC 因子实时监控WebSocket 推实时功率ECharts 画曲线告警中心阈值/突变/离线钉钉/短信/邮件报表引擎日报/月报/碳报告EasyExcel 导出权限与租户RBAC园区多租户分账五、关键代码思路伪代码级1Modbus TCP 采集Python 边缘端from pymodbus.client import ModbusTcpClient import paho.mqtt.client as mqtt import json, time client ModbusTcpClient(192.168.1.50, port502) mqtt_cli mqtt.Client() mqtt_cli.connect(broker.emqx.io, 1883) while True: # 读保持寄存器电压/电流/有功功率 res client.read_holding_registers(address0, count10, slave1) if res.isError(): time.sleep(5); continue payload { meter_id: M-001, power_kw: res.registers[0] / 10.0, ts: int(time.time() * 1000) } mqtt_cli.publish(ems/meters/M-001, json.dumps(payload)) time.sleep(1)2后端 Kafka 消费写时序库JavaKafkaListener(topics energy-topic, groupId ems-core) public void onMessage(String msg) { EnergyPoint p JSON.parseObject(msg, EnergyPoint.class); // 1. 写 InfluxDB高频时序 influxWriter.write(p.getMeterId(), p.getTs(), p.getPowerKw()); // 2. 实时值刷 Redis前端轮询/WS 用 redis.set(rt: p.getMeterId(), p.getPowerKw()); }3前端 WebSocket 实时功率const ws new WebSocket(ws://localhost:8080/ws/realtime) ws.onmessage (e) { const d JSON.parse(e.data) powerChart.appendPoint(d.ts, d.powerKw) }六、数据库建模要点最容易踩坑不要把所有秒级数据塞 MySQLMySQL存meter_meta设备元信息、alarm_rule、report_task、userInfluxDB measurementenergy_powertagmeter_id,energy_typefieldvalue聚合表分钟/小时/天级统计单独落 MySQL 或 InfluxDB CQ连续查询生命周期原始 3~6 个月聚合数据留 3~5 年七、开发落地步骤建议节奏需求边界电水气要不要光伏储能是否对接 MES/ERP点位表梳理哪块表、什么协议、寄存器地址、采集周期先通采集边缘程序跑通 Modbus→MQTT再通存储Kafka→InfluxDB确认写入延迟 2s做最小前端总能耗 实时功率 日报表加告警和分析阈值告警、同比环比、单位产品能耗接业务系统OA 推送、碳核算、租户分账上线运维Docker Compose 起步后期 K8s八、工程避坑指南时钟不同步所有边缘机装 NTP否则时序乱序聚合错Modbus 轮询阻塞单线程轮询 200 块表会卡按网关分片并发浮点量程很多表是“寄存器值×变比”不处理会差 10 倍断网丢数边缘必须本地 SQLite/文件缓冲恢复后续传等保合规TLS 传输、JWT 鉴权、操作审计别等验收再补九、想快一点参考开源底座云捷EMSPython React InfluxDBModbus/MQTT/BACnet 全支持适合二开云捷EMS仓库地址https://gitee.com/guangdong122/energy-management自研建议边缘采集自写平台层参考 MyEMS 结构如果需要云捷EMS源码合作服务可联系作者