技术背景
在能源管理、建筑分项计量等工程应用场景中,对于电表数据的采集是经常使用的技术之一。电表数据采集的实现方法有很多,如利用组态软件采集、利用采集器硬件终端采集等,本文将利用开源框架编写电表数据采集程序,该程序可以运行在任何智能硬件上,更加符合软件定义硬件的理念。
技术基础
- 基础框架:springboot 2.4.2
- modbus模块
<dependency>
<groupId>com.ghgande</groupId>
<artifactId>j2mod</artifactId>
<version>LATEST</version>
</dependency>
- 数据库:mongodb 4.4.4
采用docker部署,简单快捷。
技术原理
电表采集的常用通讯方式是modbus-rtu协议,需要敷设RS485通讯线,但是工程现场往往不具备线缆敷设条件,因此需要外加一个透传网关,利用以太网下发modbus-tcp协议指令,再转换成modbus-rtu协议,而以太网则可以通过现场安装无线路由器将4G信号转换成wifi信号,实现远程电表采集应用。
主要代码
采集总线-电表关系模型
- Meter.java
电表类模型,描述电表的相关属性。
public class Meter {
private int meterAddr;//表地址
private String meterAsset;//表编号
private Map<MetricName,PointSamplingMethod> metric;//电气量的采集方法
//方法略
}
- PoingSamplingMethod.java
采集方法模型,描述电表的电气量所采用的采集方法,电气量包括功率、电能等。
public class PointSamplingMethod {
private int addr;//电表地址
private int registerAddr;//寄存器地址
private int registerCount;//寄存器长度
private float ratio;//变比
private Integer point;//测点序号
//方法略
}
- ModbusConfig.java
modbus协议的基本配置,描述总线与电表之间的逻辑关系。
public class ModbusConfig {
private String dnID;//采集设备编号
private String busAddr;//总线地址
private List<Meter> meters;//该总线上的电表列表
//方法略
}
modbus协议实现类
- ModbusController.java
实现类代码如下。
public class ModbusController {
private ModbusTCPMaster master;
private boolean isConnect;
private Integer delay;
private ModbusConfig config;
public ModbusController(ModbusConfig config) {
this.config = config;
this.master = new ModbusTCPMaster(config.getBusIp(),config.getBusPort(),false);
this.master.setRetries(2);
this.isConnect = false;
}
public void connect() throws Exception {
this.master.connect();
this.isConnect = true;
}
public void disconnect() {
this.master.disconnect();
this.isConnect = false;
}
public List<DnPointData> read(MetricName metric, String period) throws Exception{
List<DnPointData> data = new ArrayList<>();
List<Meter> meters = config.getMeters();
if (meters==null || meters.isEmpty()) {
return data;
}
for (Meter meter:meters) {
PointSamplingMethod method = meter.getMethod(metric);
data.add(readValue(config.getDnID(),method.getAddr(),method.getRegisterAddr(),method.getRegisterCount(),method.getRatio(),method.getPoint(), Duration.parse(period)));
}
return data;
}
private DnPointData readValue(String dnID, int addr, int ref, int count, float ratio, Integer point, Duration period) {
DnPointData pointData = new DnPointData();
pointData.setDnID(dnID);
pointData.setPoint(point);
pointData.setPeriod(period);
LocalDateTime timestamp = LocalDateTime.now();
pointData.setTimestamp(timestamp);
try {
if (!isConnect) {
connect();
}
InputRegister[] registers = this.master.readMultipleRegisters(addr,ref,count);
if (registers.length==0 || registers.length>2) {
pointData.setValue((float) 0);
pointData.setQuality(DataQuality.failure);
return pointData;
}
int value = registers[0].getValue();
if (count==2) {
value = value<<16 | registers[1].getValue();
}
pointData.setValue(value*ratio);
pointData.setQuality(DataQuality.good);
}catch (Exception e) {
pointData.setValue((float) 0);
pointData.setQuality(DataQuality.failure);
}
return pointData;
}
public Integer getDelay() {
return delay;
}
public void setDelay(Integer delay) {
this.delay = delay;
}
}
- 代码说明
- 首先,modbus-tcp协议需要建立tcp连接,因此可以通过构造方法导入总线-电表的关联关系,再使用connect()方法开启连接。
- 其次,如果成功建立连接后,即可利用read()方法读取电表中寄存器的值。该方法有两个形参,第一个是描述所采集的电气量,第二个是描述采集的频率,该频率的描述需要符合ISO 8601。
- 其中,read()方法调用了该类的私有方法readValue(),其核心的采集寄存器数据使用的是readMultipleRegisters(),并对读取出来的值进行处理,如果寄存器长度是2,则需要拼接,还要乘上变比,而对于读取失败的数据,还要置0并标记失败(failure)。
- 最后,将采集结果存入数据库。
采集数据类
DnPointData.java
采集数据类,描述电表数据。
public class DnPointData {
private String dnID;//采集设备编号
private Integer point;//测点编号
private Duration period;//采集频率
private Float value;//采集的数据值
private LocalDateTime timestamp;//采集的时间戳
private DataQuality quality;//采集的数据质量
//方法略
}
结语
本文简要描述了如何利用开源框架实现利用modbus协议的电表数据采集技术,在实际的远程抄表工程应用中,往往需要同时对现场多条总线的多块电表进行采集,在下一篇文章中,我将继续讲述如何利用xxl-job开源框架实现远程电表并发采集,敬请期待。