pom.xml配置:
<!-- 辅助modbus4j:repository id:ias-snapshots id:ias-releases 两个 -->
<repositories>
<repository>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
<id>ias-snapshots</id>
<name>Infinite Automation Snapshot Repository</name>
<url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
</repository>
<repository>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>ias-releases</id>
<name>Infinite Automation Release Repository</name>
<url>https://maven.mangoautomation.net/repository/ias-release/</url>
</repository>
</repositories>
<!-- modbus -->
<dependency>
<groupId>com.infiniteautomation</groupId>
<artifactId>modbus4j</artifactId>
<version>3.0.3</version>
</dependency>
modbus配置类:
package org.wingtech.modules.modbus.config;
/**
* @program: wingtech-boot-parent
* @description: modbus读写工具类
* @author: Ricardo.Liu
* @create: 2020-05-08
* @since: JDK 1.8
**/
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.ip.IpParameters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.wingtech.modules.modbus.mapper.IpControlMapper;
import java.util.HashMap;
@Configuration
/*
* 使用@Bean,就不用使用@Import来导入相应的类了,@Bean生成的bean的名字默认为方法名,由于hashMap使用很广泛,
* 所以使用@Bean的方式引入依赖,这样在注入的时候可以指定名称,以免注入错误的对象
* @Import({java.util.HashMap.class,com.serotonin.modbus4j.ModbusFactory.class})
*/
@Import(com.serotonin.modbus4j.ModbusFactory.class)
public class ModbusConfig {
@Bean
public HashMap<String, ModbusMaster> modbusMasterHashMap() {
return new HashMap<>();
}
@Autowired
IpControlMapper ipControlMapper;
@Autowired
private ModbusFactory modbusFactory;
@Autowired
@Qualifier("modbusMasterHashMap")
private HashMap<String,ModbusMaster> masterMap;
/**
* @Description: 通过ip获取对应的modbus连接器
* @Param: [ip]
* @return: com.serotonin.modbus4j.ModbusMaster
* @throws:
* @Author: Ricardo.Liu
* @Date: 2020/5/8
*/
public ModbusMaster getMaster(String ip) {
ModbusMaster modbusMaster = masterMap.get(ip);
if(modbusMaster == null) {
setMaster(ip, ipControlMapper.queryControlByIp(ip).getPort());
modbusMaster = masterMap.get(ip);
}
return modbusMaster;
}
/**
* @Description: 设置ip对应的modbus连接器
* @Param: [ip, port]
* @return: void
* @throws:
* @Author: Ricardo.Liu
* @Date: 2020/5/8
*/
private void setMaster(String ip, Integer port) {
ModbusMaster master;
IpParameters params = new IpParameters();
params.setHost(ip);
params.setPort(port);
//设置为true,会导致TimeoutException: request=com.serotonin.modbus4j.ip.encap.EncapMessageRequest@774dfba5",
//params.setEncapsulated(true);
master = modbusFactory.createTcpMaster(params, false);// TCP 协议
try {
//设置超时时间
master.setTimeout(3*1000);
//设置重连次数
master.setRetries(3);
//初始化
master.init();
} catch (ModbusInitException e) {
e.printStackTrace();
}
masterMap.put(ip, master);
}
}
modbus工具类:
package org.wingtech.modules.modbus.util;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.msg.ReadCoilsRequest;
import com.serotonin.modbus4j.msg.ReadCoilsResponse;
import com.serotonin.modbus4j.msg.ReadDiscreteInputsRequest;
import com.serotonin.modbus4j.msg.ReadDiscreteInputsResponse;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
import com.serotonin.modbus4j.msg.ReadInputRegistersRequest;
import com.serotonin.modbus4j.msg.ReadInputRegistersResponse;
import com.serotonin.modbus4j.msg.WriteCoilRequest;
import com.serotonin.modbus4j.msg.WriteCoilResponse;
import com.serotonin.modbus4j.msg.WriteCoilsRequest;
import com.serotonin.modbus4j.msg.WriteCoilsResponse;
import com.serotonin.modbus4j.msg.WriteRegisterRequest;
import com.serotonin.modbus4j.msg.WriteRegisterResponse;
import com.serotonin.modbus4j.msg.WriteRegistersRequest;
import com.serotonin.modbus4j.msg.WriteRegistersResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.wingtech.modules.modbus.config.ModbusConfig;
/**
* @program: wingtech-boot-parent
* @description: modbus读写工具类
* @author: Ricardo.Liu
* @create: 2020-05-08
* @since: JDK 1.8
**/
@Component
public class ModbusUtil {
//从机默认值
private Integer slaveId = 1;
@Autowired
private ModbusConfig modbusConfig;
public boolean[] readCoilStatus(String ip, int offset, int numberOfRegister) throws ModbusTransportException {
ModbusMaster master = modbusConfig.getMaster(ip);
ReadCoilsRequest request = new ReadCoilsRequest(slaveId, offset, numberOfRegister);
ReadCoilsResponse response = (ReadCoilsResponse) master.send(request);
boolean[] booleans = response.getBooleanData();
return valueRegroup(numberOfRegister, booleans);
}
/**
* @Description: 读取外围设备输入的开关量,相当于功能码:02H-读离散输入状态
* @Param: [ip, offset, numberOfRegister]
* @return: boolean[]
* @throws:
* @Author: Ricardo.Liu
* @Date: 2020/5/8
*/
public boolean[] readInputStatus(String ip, int offset, int numberOfRegister) throws ModbusTransportException {
ModbusMaster master = modbusConfig.getMaster(ip);
ReadDiscreteInputsRequest request = new ReadDiscreteInputsRequest(slaveId,offset, numberOfRegister);
ReadDiscreteInputsResponse response = (ReadDiscreteInputsResponse) master.send(request);
boolean[] booleans = response.getBooleanData();
return valueRegroup(numberOfRegister, booleans);
}
/**
* @Description: 读取保持寄存器数据,相当于功能码:03H-读保持寄存器
* @Param: [ip, offset, numberOfRegister]
* @return: short[]
* @throws:
* @Author: Ricardo.Liu
* @Date: 2020/5/8
*/
public short[] readHoldingRegister(String ip, int offset, int numberOfRegister) throws ModbusTransportException {
ModbusMaster master = modbusConfig.getMaster(ip);
ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, offset, numberOfRegister);
ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.send(request);
return response.getShortData();
}
/**
* @Description: 读取外围设备输入的数据,相当于功能码:04H-读输入寄存器
* @Param: [ip, offset, numberOfRegister]
* @return: short[]
* @throws:
* @Author: Ricardo.Liu
* @Date: 2020/5/8
*/
public short[] readInputRegisters(String ip, int offset, int numberOfRegister) throws ModbusTransportException {
ModbusMaster master = modbusConfig.getMaster(ip);
ReadInputRegistersRequest request = new ReadInputRegistersRequest(slaveId, offset, numberOfRegister);
ReadInputRegistersResponse response = (ReadInputRegistersResponse) master.send(request);
return response.getShortData();
}
/**
* @Description: 写单个(线圈)开关量数据,相当于功能码:05H-写单个线圈
* @Param: [ip, writeOffset, writeValue]
* @return: boolean
* @throws:
* @Author: Ricardo.Liu
* @Date: 2020/5/8
*/
public boolean writeCoil(String ip, int writeOffset, boolean writeValue) throws ModbusTransportException {
ModbusMaster tcpMaster = modbusConfig.getMaster(ip);
WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request);
return !response.isException();
}
/**
* @Description: 写多个开关量数据(线圈),相当于功能码:0FH-写多个线圈
* @Param: [ip, startOffset, data]
* @return: boolean
* @throws:
* @Author: Ricardo.Liu
* @Date: 2020/5/8
*/
public boolean writeCoils(String ip, int startOffset, boolean[] data) throws ModbusTransportException {
ModbusMaster tcpMaster = modbusConfig.getMaster(ip);
WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, data);
WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request);
return !response.isException();
}
/**
* @Description: 写单个保持寄存器,相当于功能码:06H-写单个保持寄存器
* @Param: [ip, writeOffset, writeValue]
* @return: boolean
* @throws:
* @Author: Ricardo.Liu
* @Date: 2020/5/8
*/
public boolean writeHoldingRegister(String ip, int writeOffset, short writeValue) throws ModbusTransportException, ModbusInitException {
ModbusMaster tcpMaster = modbusConfig.getMaster(ip);
WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);
WriteRegisterResponse response = (WriteRegisterResponse) tcpMaster.send(request);
return !response.isException();
}
/**
* @Description: 写多个保持寄存器,相当于功能码:10H-写多个保持寄存器
* @Param: [ip, startOffset, data]
* @return: boolean
* @throws:
* @Author: Ricardo.Liu
* @Date: 2020/5/8
*/
public boolean writeHoldingRegisters(String ip, int startOffset, short[] data) throws ModbusTransportException, ModbusInitException {
ModbusMaster tcpMaster = modbusConfig.getMaster(ip);
WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, data);
WriteRegistersResponse response = (WriteRegistersResponse) tcpMaster.send(request);
return !response.isException();
}
/**
* @Description: 转换工具,将Boolean转换成0,1
* @Param: [numberOfBits, values]
* @return: boolean[]
* @throws:
* @Author: Ricardo.Liu
* @Date: 2020/5/8
*/
private boolean[] valueRegroup(int numberOfBits, boolean[] values) {
boolean[] bs = new boolean[numberOfBits];
int temp = 1;
for (boolean b : values) {
bs[temp - 1] = b;
temp++;
if (temp > numberOfBits) {
break;
}
}
return bs;
}
}
ipControlMapper:
package org.wingtech.modules.modbus.mapper;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
import org.wingtech.modules.modbus.entity.IpControl;
import java.util.List;
/**
* @program: wingtech-boot-parent
* @description: modbus读写工具类
* @author: Ricardo.Liu
* @create: 2020-05-08
* @since: JDK 1.8
**/
@Mapper
@Repository
public interface IpControlMapper {
@Results(id = "ipControlMap", value = {
@Result(column = "ip", property = "ip", javaType = String.class),
@Result(column = "port", property = "port", javaType = Integer.class),
@Result(column = "ip_type", property = "ipType", javaType = Integer.class),
@Result(column = "device_data_gather_cycle", property = "deviceDataGatherCycle", javaType = Integer.class),
@Result(column = "device_data_gather_interval", property = "deviceDataGatherInterval", javaType = Integer.class),
@Result(column = "note_alarm_data_gather_cycle", property = "noteAlarmDataGatherCycle", javaType = Integer.class),
@Result(column = "environment_data_gather_cycle", property = "environmentDataRecordCycle", javaType = Integer.class)
})
//通过ip查询控制器
@Select("select ip, port, ip_type, device_data_gather_cycle, device_data_gather_interval, note_alarm_data_gather_cycle, environment_data_gather_cycle " +
"from control " +
"where ip = #{ip}")
IpControl queryControlByIp(String ip);
//通过ip类型(0:区域控制器, 1:八防控制器)查询控制器
@Select("select ip " +
"from control " +
"where ip_type = #{ipType}")
List<String> queryAllIpControlIp(String ipType);
//插入控制器
@Insert("insert into control(ip, port, ip_type, device_data_gather_cycle, device_data_gather_interval, note_alarm_data_gather_cycle, environment_data_gather_cycle) " +
"values (#{ip}, #{port}, #{ipType}, #{deviceDataGatherCycle}, #{deviceDataGatherInterval}, #{noteAlarmDataGatherCycle}, #{environmentDataRecordCycle})")
void addIpControl(IpControl ipControl);
//更新区域控制器
@Update("<script>" +
"update control " +
"<set>" +
"<if test='port !=null'>port = #{port},</if>" +
"<if test='ipType !=null'>ip_type = #{ipType},</if>" +
"<if test='pollInterval !=null'>device_data_gather_cycle = #{deviceDataGatherCycle}, </if>" +
"<if test='deviceInterval !=null'>device_data_gather_interval = #{deviceDataGatherInterval}, </if>" +
"<if test='deviceInterval !=null'>note_alarm_data_gather_cycle = #{noteAlarmDataGatherCycle}, </if>" +
"<if test='enviInterval !=null'>environment_data_gather_cycle = #{environmentDataRecordCycle}, </if>" +
"</set> " +
"where ip = #{ip}" +
"</script>")
void updateIpControl(IpControl ipControl);
//通过ip删除相应的控制器
@Delete("delete " +
"from control " +
"where ip = #{ip}")
void deleteIpControl(String ip);
}
ipControlMapper:
package org.wingtech.modules.modbus.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author liuyuancheng@wingtech.com
* @version 1.0
* @ClassName IpControl
* @description
* @date 2020/5/8 14:18
* @since JDK 1.8
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class IpControl implements Serializable {
private static final long serialVersionUID = 7456080427901548044L;
private String ip;
private Integer port;
private Integer ipType;
private Integer deviceDataGatherCycle;
private Integer deviceDataGatherInterval;
private Integer noteAlarmDataGatherCycle;
private Integer environmentDataRecordCycle;
}
原文地址:https://blog.youkuaiyun.com/weixin_43069081/article/details/90048760