zhitan-ems 二次开发实战:3 个定制场景,解锁开源能源系统的灵活价值
本文分享了基于zhitan-ems开源能源管理系统进行二次开发的实际案例。通过化工园区特种设备能耗采集适配、食品厂能耗成本核算功能新增、集团企业多厂区数据汇总看板三个场景,展示了该系统的可扩展性。开发时可通过继承接口实现硬件协议适配、扩展数据模型满足业务需求、复用现有组件保持风格统一。文章建议先熟悉项目分层架构,优先复用内置工具类,优化时序数据库查询性能。该框架特别适合需要对接特殊设备、定制报表或
作为长期做工业软件开发的程序员,接触过不少能源管理系统,但大多要么闭源无法修改,要么开源项目架构混乱难以扩展。直到尝试基于 zhitan-ems 做二次开发 —— 为某化工园区定制能耗预警模块、给食品厂新增能耗成本核算功能后,才真正感受到这款开源项目的 “友好度”。今天就结合 3 个实际开发场景,分享如何基于 zhitan-ems 实现定制化需求。

一、场景 1:化工园区特种设备能耗采集适配(硬件对接)
需求背景
某化工园区有 12 台反应釜,需采集其加热功率、冷却水电耗数据,但设备采用的是 Modbus RTU 协议的特种电表,与 zhitan-ems 默认适配的标准网关接口不兼容,需定制采集逻辑。
开发过程(关键步骤)
- 定位核心改造模块
查看项目结构发现,数据采集相关代码集中在com.zhitan.ems.collect包下,现有StandardGatewayCollector类适配通用电表,只需新建ModbusRtuCollector类继承BaseCollector接口,无需改动原有代码,符合开闭原则。
- 协议适配实现
引入net.wimpi.modbus依赖(项目已兼容 Maven,直接在 pom.xml 添加即可),核心代码如下:
// 初始化Modbus RTU连接
SerialParameters params = new SerialParameters();
params.setPortName("/dev/ttyUSB0"); // 园区设备串口
params.setBaudRate(9600);
ModbusSerialMaster master = new ModbusSerialMaster(params);
// 读取反应釜加热功率(寄存器地址0x0001)
ReadInputRegistersRequest request = new ReadInputRegistersRequest(1, 2);
ReadInputRegistersResponse response = (ReadInputRegistersResponse) master.send(request);
float power = response.getRegisterValue(0) / 10.0f; // 数据校准(设备精度0.1kW)
- 数据接入现有系统
将采集到的特种设备数据,通过DataStorageService接口存入 InfluxDB,复用项目原有时序数据存储逻辑,无需重新设计表结构,仅需在point中新增device_type:reaction_kettle标签,方便后续筛选查询。
开发亮点
原有代码预留了清晰的采集扩展接口,新增设备类型无需重构架构,3 天就完成 12 台设备的对接调试,采集成功率达 99.2%。
二、场景 2:食品厂能耗成本自动核算(功能新增)
需求背景
某食品厂需按 “车间 - 生产线 - 设备” 三级维度,自动核算每日能耗成本(电费按峰谷价、水费按阶梯价),并生成成本对比报表。
开发过程(核心改造)
- 数据模型扩展
在com.zhitan.ems.entity包下新增EnergyCost实体类,添加workshop_id(车间 ID)、peak_cost(峰时成本)、valley_cost(谷时成本)等字段,通过 JPA 自动生成数据库表,与原有EnergyData表通过device_id关联。
- 成本计算逻辑开发
在EnergyAnalysisService中新增calculateDailyCost方法,核心逻辑:
- 从EnergyData中筛选当日各设备能耗数据,按峰谷时段(复用系统原有PeakValleyConfig配置)拆分电量;
- 调用CostConfigService获取实时电价、水价(新增配置页面,在 Vue3 前端cost-config.vue中添加表单,与后端接口联动);
- 按三级维度汇总成本,示例代码:
// 按车间汇总成本
Map<Long, BigDecimal> workshopCostMap = energyDataList.stream()
.collect(Collectors.groupingBy(EnergyData::getWorkshopId,
Collectors.reducing(BigDecimal.ZERO,
data -> calculateDeviceCost(data, costConfig),
BigDecimal::add)));
- 前端报表展示
复用项目现有报表组件(src/components/ReportTable.vue),新增 “成本对比” 标签页,通过 Axios 调用/api/energy/cost/daily接口获取数据,使用 ECharts 绘制三级维度成本堆叠图,样式与原有系统保持一致。
实际效果
上线后,财务部门无需手动核算,系统每日自动生成成本报表,数据误差控制在 0.5% 以内,每月节省 8 小时统计时间。
三、场景 3:多厂区数据汇总看板(跨系统对接)
需求背景
某集团企业有 3 个异地厂区,需在总部搭建统一数据看板,汇总各厂区 zhitan-ems 系统的能耗数据,实现跨厂区对比分析。
开发关键
- 接口标准化
在各厂区 zhitan-ems 系统中,基于com.zhitan.ems.api包新增CrossPlantApi接口,返回标准化 JSON 数据(包含plant_id、total_energy、carbon_emission等字段),并配置 API 密钥鉴权。
- 总部数据拉取
在总部系统中,开发PlantDataSyncService,通过定时任务(复用项目 XXL-Job 集成能力)调用各厂区 API,将数据存入总部 PostgreSQL 数据库,核心代码:
@Scheduled(cron = "0 0/30 * * * ?") // 每30分钟同步一次
public void syncPlantData() {
for (String plantUrl : plantUrls) { // 各厂区API地址
HttpHeaders headers = new HttpHeaders();
headers.set("Api-Key", apiKey);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
plantUrl + "/api/cross-plant/data",
HttpMethod.GET,
entity,
String.class);
// 数据解析与存储
parseAndSavePlantData(response.getBody());
}
}
- 汇总看板开发
前端使用 Vue3+Element Plus 开发汇总看板,左侧展示厂区列表,右侧实时显示各厂区能耗、成本、碳排放量对比,支持按时间维度钻取数据,与原有系统交互逻辑保持一致。
四、二次开发的 3 个关键建议
- 先熟悉项目架构再动手
zhitan-ems 采用分层架构(Controller-Service-Dao),核心业务逻辑集中在 Service 层,数据访问通过 MyBatis-Plus 实现,建议先梳理README中的模块说明,避免修改核心基础类。
- 优先复用现有组件
项目内置了大量实用工具类(如DateUtils、NumberUtils)和前端组件(如数据看板、表单模板),二次开发时优先复用,既能保证风格统一,又能减少开发量。
- 注意时序数据性能
若涉及大量历史数据查询(如年维度报表),建议优化 InfluxDB 查询语句(如添加时间范围过滤、使用标签索引),避免全表扫描,我们在处理 3 年能耗数据时,通过索引优化将查询时间从 5 秒降至 0.8 秒。
五、适合二次开发的场景总结
- 需对接特种能耗设备(如工业锅炉、光伏逆变器)的企业;
- 有个性化报表、成本核算、多厂区汇总需求的集团用户;
- 想基于能源管理系统拓展新业务(如节能方案推荐)的开发者。
结语
zhitan-ems 的二次开发价值,在于它提供了 “能用、可改、易扩展” 的基础框架 —— 不需要从零搭建能源管理系统的核心逻辑,只需聚焦业务定制需求。目前我们已基于该项目完成 5 个企业的定制开发,平均开发周期比从零开发缩短 60%。
如果你也有能源系统定制需求,不妨从 Gitee 仓库克隆代码,从简单的功能改造入手(比如新增一个自定义报表),逐步解锁其灵活价值。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)