集成modbus连接本地设备读取数据代码-配置文件方式读取;
PCS开关机功能通过modbus连接设备发送控制命令;
This commit is contained in:
@ -119,6 +119,12 @@
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- modbus -->
|
||||
<dependency>
|
||||
<groupId>com.infiniteautomation</groupId>
|
||||
<artifactId>modbus4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,61 @@
|
||||
package com.xzzn.common.core.modbus;
|
||||
|
||||
import com.serotonin.modbus4j.ModbusMaster;
|
||||
import com.xzzn.common.core.modbus.domain.DeviceConfig;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class Modbus4jConnectionManager {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Modbus4jConnectionManager.class);
|
||||
|
||||
private final Map<String, GenericObjectPool<ModbusMaster>> connectionPools = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public ModbusMaster borrowMaster(DeviceConfig config) throws Exception {
|
||||
String poolKey = getPoolKey(config);
|
||||
GenericObjectPool<ModbusMaster> pool = connectionPools.computeIfAbsent(poolKey, key -> {
|
||||
PooledModbusMasterFactory factory = new PooledModbusMasterFactory(config.getHost(), config.getPort());
|
||||
GenericObjectPoolConfig<ModbusMaster> poolConfig = new GenericObjectPoolConfig<>();
|
||||
poolConfig.setMaxTotal(5); // 池中最大连接数
|
||||
poolConfig.setMinIdle(1); // 最小空闲连接数
|
||||
poolConfig.setTestOnBorrow(true); // 借用时测试连接有效性
|
||||
|
||||
return new GenericObjectPool<>(factory, poolConfig);
|
||||
});
|
||||
return pool.borrowObject();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void returnMaster(DeviceConfig config, ModbusMaster master) {
|
||||
if (master == null) {
|
||||
return;
|
||||
}
|
||||
String poolKey = getPoolKey(config);
|
||||
GenericObjectPool<ModbusMaster> pool = connectionPools.get(poolKey);
|
||||
if (pool != null) {
|
||||
pool.returnObject(master);
|
||||
}
|
||||
}
|
||||
|
||||
private String getPoolKey(DeviceConfig config) {
|
||||
return config.getHost() + ":" + config.getPort();
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
connectionPools.values().forEach(GenericObjectPool::close);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,384 @@
|
||||
package com.xzzn.common.core.modbus;
|
||||
|
||||
import com.serotonin.modbus4j.BatchRead;
|
||||
import com.serotonin.modbus4j.BatchResults;
|
||||
import com.serotonin.modbus4j.ModbusMaster;
|
||||
import com.serotonin.modbus4j.code.DataType;
|
||||
import com.serotonin.modbus4j.exception.ErrorResponseException;
|
||||
import com.serotonin.modbus4j.exception.ModbusTransportException;
|
||||
import com.serotonin.modbus4j.locator.BaseLocator;
|
||||
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 com.xzzn.common.core.modbus.domain.DeviceConfig;
|
||||
import com.xzzn.common.core.modbus.domain.TagConfig;
|
||||
import com.xzzn.common.core.modbus.domain.WriteTagConfig;
|
||||
import com.xzzn.common.core.redis.RedisCache;
|
||||
import com.xzzn.common.enums.ModBusType;
|
||||
import com.xzzn.common.enums.RegisterType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import static com.xzzn.common.enums.RegisterType.COIL;
|
||||
import static com.xzzn.common.enums.RegisterType.DISCRETE_INPUT;
|
||||
|
||||
@Service
|
||||
public class ModbusProcessor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ModbusProcessor.class);
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
@Autowired
|
||||
private Modbus4jConnectionManager connectionManager;
|
||||
|
||||
public boolean writeDataToDevice(DeviceConfig config) {
|
||||
ModbusMaster master = null;
|
||||
boolean result = true;
|
||||
try {
|
||||
master = connectionManager.borrowMaster(config);
|
||||
// 设置了Modbus通信的超时时间为3000毫秒(3秒)。当主设备与从设备通信时,若在3秒内未收到响应,则认为通信超时并抛出异常。这有助于避免长时间等待无响应的设备。
|
||||
master.setTimeout(5000);
|
||||
writeTagValue(master, config, config.getWriteTags());
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to borrow connection or write to devices '{}'", config.getDeviceName(), e);
|
||||
result = false;
|
||||
}
|
||||
finally {
|
||||
// 关键:无论成功与否,都必须将连接归还到池中
|
||||
if (master != null) {
|
||||
connectionManager.returnMaster(config, master);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void writeTagValue(ModbusMaster master, DeviceConfig config, List<WriteTagConfig> tags) {
|
||||
tags.forEach(tag -> {
|
||||
Map<Integer, RegisterType> type = ModBusType.REGISTER_TYPE;
|
||||
int firstDigit = Integer.parseInt(tag.getAddress().substring(0, 1));
|
||||
int address = 0;
|
||||
int addressLength = tag.getAddress().length();
|
||||
int exp = (int) Math.pow(10, addressLength-1);
|
||||
if (firstDigit != 0){
|
||||
int digit = Integer.parseInt(tag.getAddress());
|
||||
address = digit % (exp);
|
||||
}else {
|
||||
address = Integer.parseInt(tag.getAddress());
|
||||
}
|
||||
RegisterType registerType = type.get(firstDigit);
|
||||
logger.info("Register type: {}, address: {}, firstDigit: {}", registerType, tag.getAddress(), firstDigit);
|
||||
switch (registerType) {
|
||||
case COIL: {
|
||||
writeCoilRequest(master, config.getSlaveId(), address, Boolean.parseBoolean(String.valueOf(tag.getValue())));
|
||||
break;
|
||||
}
|
||||
case HOLDING_REGISTER: {
|
||||
writeRegisterRequest(master, config.getSlaveId(), address, Integer.parseInt(String.valueOf(tag.getValue())));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
logger.error("Unsupported register type: {}", registerType);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void writeCoilRequest(ModbusMaster master, int slaveId, int address, boolean value) {
|
||||
try {
|
||||
WriteCoilRequest request = new WriteCoilRequest(slaveId, address, value);
|
||||
WriteCoilResponse response = (WriteCoilResponse)master.send(request);
|
||||
if (response.isException()) {
|
||||
logger.info("Write coil failed: " + response.getExceptionMessage());
|
||||
} else {
|
||||
logger.info("Write coil successful");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to write coil value '{}' to address '{}'", value, address, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeCoilsRequest(ModbusMaster master, int slaveId, int address, boolean[] values) {
|
||||
try {
|
||||
WriteCoilsRequest request = new WriteCoilsRequest(slaveId, address, values);
|
||||
WriteCoilsResponse response = (WriteCoilsResponse)master.send(request);
|
||||
if (response.isException()) {
|
||||
logger.info("Write coils failed: " + response.getExceptionMessage());
|
||||
} else {
|
||||
logger.info("Write coils successful");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to write coils value '{}' to address '{}'", values, address, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeRegisterRequest(ModbusMaster master, int slaveId, int address, int value) {
|
||||
try {
|
||||
WriteRegisterRequest request = new WriteRegisterRequest(slaveId, address, value);
|
||||
WriteRegisterResponse response = (WriteRegisterResponse)master.send(request);
|
||||
if (response.isException()) {
|
||||
logger.info("Write register failed: " + response.getExceptionMessage());
|
||||
} else {
|
||||
logger.info("Write register successful");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to write register value '{}' to address '{}'", value, address, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeRegistersRequest(ModbusMaster master, int slaveId, int address, short[] values) {
|
||||
try {
|
||||
WriteRegistersRequest request = new WriteRegistersRequest(slaveId, address, values);
|
||||
WriteRegistersResponse response = (WriteRegistersResponse)master.send(request);
|
||||
if (response.isException()) {
|
||||
logger.info("Write registers failed: " + response.getExceptionMessage());
|
||||
} else {
|
||||
logger.info("Write registers successful");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to write registers value '{}' to address '{}'", values, address, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setCoilValue(ModbusMaster master, int slaveId, int address, int value) {
|
||||
// 写入单个线圈(从站ID, 地址, 布尔值)
|
||||
BaseLocator<Boolean> coilLocator = BaseLocator.coilStatus(slaveId, address);
|
||||
try {
|
||||
// 写入布尔值到线圈
|
||||
master.setValue(coilLocator, value);
|
||||
logger.info("set coil successful");
|
||||
} catch (ModbusTransportException | ErrorResponseException e) {
|
||||
logger.error("Failed to set coil value '{}' to address '{}'", value, address, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setRegisterValue(ModbusMaster master, int slaveId, int address, int value) {
|
||||
// 写入单个保持寄存器(从站, 地址, 16位整数)
|
||||
BaseLocator<Number> holdingLocator = BaseLocator.holdingRegister(slaveId, address, DataType.TWO_BYTE_INT_UNSIGNED);
|
||||
try {
|
||||
// 写入整数值到保持寄存器
|
||||
master.setValue(holdingLocator, value);
|
||||
logger.info("set register successful");
|
||||
} catch (ModbusTransportException | ErrorResponseException e) {
|
||||
logger.error("Failed to set register value '{}' to address '{}'", value, address, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Map<String, Object> readDataFromDevice(DeviceConfig config, ModbusMaster master) {
|
||||
Map<String, Object> deviceData = new HashMap<>();
|
||||
// ModbusMaster master = null; // 将master的声明提前
|
||||
try {
|
||||
master = connectionManager.borrowMaster(config);
|
||||
// 设置了Modbus通信的超时时间为3000毫秒(3秒)。当主设备与从设备通信时,若在3秒内未收到响应,则认为通信超时并抛出异常。这有助于避免长时间等待无响应的设备。
|
||||
master.setTimeout(5000);
|
||||
BatchResults<String> results = readTagValues(master, config.getSlaveId(), config.getTags());
|
||||
for (TagConfig tag : config.getTags()) {
|
||||
if (Objects.equals(tag.getDataType(), "FOUR_BYTE_FLOAT_DBCA")){
|
||||
Object value = results.getValue(tag.getKey());
|
||||
value = convertValueToFloat(value);
|
||||
deviceData.put(tag.getKey(), value);
|
||||
}else {
|
||||
deviceData.put(tag.getKey(), results.getValue(tag.getKey()));
|
||||
}
|
||||
|
||||
|
||||
// try {
|
||||
// Object value = readTagValue(master, config.getSlaveId(), tag);
|
||||
// if (value != null) {
|
||||
// deviceData.put(tag.getKey(), value);
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// logger.error("Failed to read tag '{}' from devices '{}'", tag.getKey(), config.getDeviceName(), e);
|
||||
// }
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to borrow connection or read from devices '{}'", config.getDeviceName(), e);
|
||||
}
|
||||
finally {
|
||||
// 关键:无论成功与否,都必须将连接归还到池中
|
||||
if (master != null) {
|
||||
connectionManager.returnMaster(config, master);
|
||||
}
|
||||
}
|
||||
String deviceNumber = config.getDeviceNumber();
|
||||
redisCache.setCacheObject(deviceNumber, deviceData);
|
||||
return deviceData;
|
||||
}
|
||||
|
||||
private Object readTagValue(ModbusMaster master, int slaveId, TagConfig tag) throws Exception {
|
||||
Object value;
|
||||
Map<Integer, RegisterType> type = ModBusType.REGISTER_TYPE;
|
||||
Map<String, Integer> DATA_LENGTH = ModBusType.LENGTH;
|
||||
int firstDigit = Integer.parseInt(tag.getAddress().substring(0, 1));
|
||||
int address = 0;
|
||||
int addressLength = tag.getAddress().length();
|
||||
int exp = (int) Math.pow(10, addressLength-1);
|
||||
if (firstDigit != 0){
|
||||
int digit = Integer.parseInt(tag.getAddress());
|
||||
address = digit % (exp);
|
||||
}else {
|
||||
address = Integer.parseInt(tag.getAddress());
|
||||
}
|
||||
RegisterType registerType = type.get(firstDigit);
|
||||
int dataLength = DATA_LENGTH.get(tag.getDataType());
|
||||
// 增加配置校验和警告
|
||||
if ((Objects.equals(registerType, COIL) || Objects.equals(registerType, DISCRETE_INPUT))) {
|
||||
logger.warn("Configuration warning for tag '{}': ModBusType is {} but DataType is {}. DataType should be BOOLEAN. Proceeding with BOOLEAN read.",
|
||||
tag.getKey(), registerType, tag.getDataType());
|
||||
}
|
||||
try {
|
||||
switch (registerType) {
|
||||
case COIL: {
|
||||
|
||||
BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, address);
|
||||
value = master.getValue(loc);
|
||||
logger.info("读取线圈{}成功: {}",tag.getAddress(), value);
|
||||
break;
|
||||
}
|
||||
case DISCRETE_INPUT: {
|
||||
BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, address);
|
||||
value = master.getValue(loc);
|
||||
logger.info("读取输入{}成功: {}",tag.getAddress(), value);
|
||||
break;
|
||||
}
|
||||
case HOLDING_REGISTER: {
|
||||
if (dataLength == 28){
|
||||
BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, address, 4);
|
||||
value = master.getValue(locator);
|
||||
//将 value 转换为二进制数据
|
||||
value = convertValueToFloat(value);
|
||||
}else{
|
||||
BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, address, dataLength);
|
||||
value = master.getValue(locator);
|
||||
}
|
||||
logger.info("读取保持寄存器{}成功: {}",tag.getAddress(), value);
|
||||
break;
|
||||
}
|
||||
case INPUT_REGISTER: {
|
||||
BaseLocator<Number> locator = BaseLocator.inputRegister(slaveId, address, dataLength);
|
||||
value= master.getValue(locator);
|
||||
logger.info("读取输入寄存器{}成功: {}",tag.getAddress(), value);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
logger.error("Unsupported register type: {}", registerType);
|
||||
value = null;
|
||||
break;
|
||||
}
|
||||
}catch (Exception e){
|
||||
logger.error("Failed to read tag '{}'", tag.getKey(), e);
|
||||
value = null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
private BatchResults<String> readTagValues(ModbusMaster master, int slaveId, List<TagConfig> tags) throws Exception {
|
||||
try {
|
||||
BatchRead<String> batch = new BatchRead<>();
|
||||
tags.forEach(tag -> {
|
||||
Map<Integer, RegisterType> type = ModBusType.REGISTER_TYPE;
|
||||
Map<String, Integer> DATA_LENGTH = ModBusType.LENGTH;
|
||||
int firstDigit = Integer.parseInt(tag.getAddress().substring(0, 1));
|
||||
int address = 0;
|
||||
int addressLength = tag.getAddress().length();
|
||||
int exp = (int) Math.pow(10, addressLength-1);
|
||||
if (firstDigit != 0){
|
||||
int digit = Integer.parseInt(tag.getAddress());
|
||||
address = digit % (exp);
|
||||
}else {
|
||||
address = Integer.parseInt(tag.getAddress());
|
||||
}
|
||||
RegisterType registerType = type.get(firstDigit);
|
||||
int dataLength = DATA_LENGTH.get(tag.getDataType());
|
||||
switch (registerType) {
|
||||
case COIL: {
|
||||
BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, address);
|
||||
batch.addLocator(tag.getKey(), loc);
|
||||
break;
|
||||
}
|
||||
case DISCRETE_INPUT: {
|
||||
BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, address);
|
||||
batch.addLocator(tag.getKey(), loc);
|
||||
break;
|
||||
}
|
||||
case HOLDING_REGISTER: {
|
||||
logger.info("HOLDING_REGISTER: {}",tag.getAddress());
|
||||
if (dataLength == 28){
|
||||
BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, address, 4);
|
||||
batch.addLocator(tag.getKey(), locator);
|
||||
}else {
|
||||
BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, address, dataLength);
|
||||
batch.addLocator(tag.getKey(), loc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INPUT_REGISTER: {
|
||||
logger.info("INPUT_REGISTER: {}",tag.getAddress());
|
||||
BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, address, dataLength);
|
||||
batch.addLocator(tag.getKey(), loc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BatchResults<String> results = master.send(batch);
|
||||
for (TagConfig tag : tags){
|
||||
if (tag.getBit()!=null){
|
||||
logger.info("批处理读取寄存器成功: {}",tag.getAddress() +"(" + tag.getBit() + "):" + results.getValue(tag.getKey()));
|
||||
|
||||
}else {
|
||||
logger.info("批处理读取寄存器成功: {}",tag.getAddress() + ":" + results.getValue(tag.getKey()));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}catch (Exception e){
|
||||
logger.error("Failed to read master '{}'", slaveId, e);
|
||||
throw new Exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static float convertValueToFloat(Object value) {
|
||||
if (!(value instanceof Number)) {
|
||||
throw new IllegalArgumentException("Input must be a Number");
|
||||
}
|
||||
|
||||
int intValue = ((Number) value).intValue();
|
||||
String binaryData = Integer.toBinaryString(intValue);
|
||||
|
||||
// 补足32位二进制字符串
|
||||
if (binaryData.length() < 32) {
|
||||
binaryData = String.format("%32s", binaryData).replace(' ', '0');
|
||||
}
|
||||
|
||||
// 分割为4个字节并重组为 dcba 格式
|
||||
byte[] reorderedBytes = new byte[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int start = i * 8;
|
||||
String byteStr = binaryData.substring(start, start + 8);
|
||||
reorderedBytes[3 - i] = (byte) Integer.parseInt(byteStr, 2);
|
||||
}
|
||||
|
||||
// 使用 ByteBuffer 提高可读性和安全性
|
||||
return Float.intBitsToFloat(
|
||||
java.nio.ByteBuffer.wrap(reorderedBytes).getInt()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package com.xzzn.common.core.modbus;
|
||||
|
||||
|
||||
import com.serotonin.modbus4j.ModbusFactory;
|
||||
import com.serotonin.modbus4j.ModbusMaster;
|
||||
import com.serotonin.modbus4j.ip.IpParameters;
|
||||
|
||||
import org.apache.commons.pool2.BasePooledObjectFactory;
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
|
||||
public class PooledModbusMasterFactory extends BasePooledObjectFactory<ModbusMaster> {
|
||||
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
public PooledModbusMasterFactory(String host, int port) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModbusMaster create() throws Exception {
|
||||
IpParameters params = new IpParameters();
|
||||
params.setHost(this.host);
|
||||
params.setPort(this.port);
|
||||
params.setEncapsulated(false);
|
||||
|
||||
ModbusMaster master = new ModbusFactory().createTcpMaster(params, true);
|
||||
master.init();
|
||||
return master;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PooledObject<ModbusMaster> wrap(ModbusMaster master) {
|
||||
return new DefaultPooledObject<>(master);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyObject(PooledObject<ModbusMaster> p) throws Exception {
|
||||
if (p.getObject() != null) {
|
||||
p.getObject().destroy();
|
||||
}
|
||||
super.destroyObject(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateObject(PooledObject<ModbusMaster> p) {
|
||||
// testConnectivity() 方法在 modbus4j 中不存在。
|
||||
// 一个真正的验证需要执行一次读操作,但这需要 slaveId,而工厂是通用的,不知道 slaveId。
|
||||
// 因此,我们使用一个较弱的验证,只检查 master 对象是否已初始化。
|
||||
// 这无法检测到被远程设备断开的连接,错误将在实际读取操作中被捕获。
|
||||
if (p.getObject() == null) {
|
||||
return false;
|
||||
}
|
||||
return p.getObject().isInitialized();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.xzzn.common.core.modbus.domain;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class DeviceConfig {
|
||||
|
||||
|
||||
private String deviceNumber;
|
||||
private String deviceName;
|
||||
private String host;
|
||||
private int port;
|
||||
private long time;
|
||||
private int slaveId;
|
||||
private boolean enabled;
|
||||
private List<TagConfig> tags;
|
||||
private List<WriteTagConfig> writeTags;
|
||||
|
||||
public String getDeviceNumber() {
|
||||
return deviceNumber;
|
||||
}
|
||||
|
||||
public void setDeviceNumber(String deviceNumber) {
|
||||
this.deviceNumber = deviceNumber;
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
public void setDeviceName(String deviceName) {
|
||||
this.deviceName = deviceName;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public int getSlaveId() {
|
||||
return slaveId;
|
||||
}
|
||||
|
||||
public void setSlaveId(int slaveId) {
|
||||
this.slaveId = slaveId;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public List<TagConfig> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setTags(List<TagConfig> tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public List<WriteTagConfig> getWriteTags() {
|
||||
return writeTags;
|
||||
}
|
||||
|
||||
public void setWriteTags(List<WriteTagConfig> writeTags) {
|
||||
this.writeTags = writeTags;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package com.xzzn.common.core.modbus.domain;
|
||||
|
||||
|
||||
|
||||
public class TagConfig {
|
||||
private String key;
|
||||
private String des;
|
||||
private String address;
|
||||
private String dataType;
|
||||
private float a;
|
||||
private float k;
|
||||
private float b;
|
||||
private Integer bit;
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getDes() {
|
||||
return des;
|
||||
}
|
||||
|
||||
public void setDes(String des) {
|
||||
this.des = des;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public void setDataType(String dataType) {
|
||||
this.dataType = dataType;
|
||||
}
|
||||
|
||||
public float getA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
public void setA(float a) {
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
public float getK() {
|
||||
return k;
|
||||
}
|
||||
|
||||
public void setK(float k) {
|
||||
this.k = k;
|
||||
}
|
||||
|
||||
public float getB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
public void setB(float b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public Integer getBit() {
|
||||
return bit;
|
||||
}
|
||||
|
||||
public void setBit(Integer bit) {
|
||||
this.bit = bit;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.xzzn.common.core.modbus.domain;
|
||||
|
||||
public class WriteTagConfig {
|
||||
private Object value;
|
||||
private String address;
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package com.xzzn.common.enums;
|
||||
|
||||
import com.serotonin.modbus4j.code.DataType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class ModBusType {
|
||||
|
||||
|
||||
public static final Map<Integer, RegisterType> REGISTER_TYPE = new HashMap<Integer, RegisterType>();
|
||||
public static final Map<String, Integer> LENGTH = new HashMap<String, Integer>();
|
||||
|
||||
|
||||
|
||||
static {
|
||||
REGISTER_TYPE.put(0, RegisterType.COIL);
|
||||
REGISTER_TYPE.put(1, RegisterType.DISCRETE_INPUT);
|
||||
REGISTER_TYPE.put(4, RegisterType.HOLDING_REGISTER);
|
||||
REGISTER_TYPE.put(3, RegisterType.INPUT_REGISTER);
|
||||
|
||||
|
||||
LENGTH.put("BINARY",DataType.BINARY);
|
||||
LENGTH.put("TWO_BYTE_INT_UNSIGNED",DataType.TWO_BYTE_INT_UNSIGNED);
|
||||
LENGTH.put("TWO_BYTE_INT_SIGNED",DataType.TWO_BYTE_INT_SIGNED);
|
||||
LENGTH.put("TWO_BYTE_INT_UNSIGNED_SWAPPED",DataType.TWO_BYTE_INT_UNSIGNED_SWAPPED);
|
||||
LENGTH.put("TWO_BYTE_INT_SIGNED_SWAPPED",DataType.TWO_BYTE_INT_SIGNED_SWAPPED);
|
||||
LENGTH.put("FOUR_BYTE_INT_UNSIGNED",DataType.FOUR_BYTE_INT_UNSIGNED);
|
||||
LENGTH.put("FOUR_BYTE_INT_SIGNED",DataType.FOUR_BYTE_INT_SIGNED);
|
||||
LENGTH.put("FOUR_BYTE_INT_UNSIGNED_SWAPPED",DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED);
|
||||
LENGTH.put("FOUR_BYTE_INT_SIGNED_SWAPPED",DataType.FOUR_BYTE_INT_SIGNED_SWAPPED);
|
||||
LENGTH.put("FOUR_BYTE_INT_UNSIGNED_SWAPPED_SWAPPED",DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED_SWAPPED);
|
||||
LENGTH.put("FOUR_BYTE_INT_SIGNED_SWAPPED_SWAPPED",DataType.FOUR_BYTE_INT_SIGNED_SWAPPED_SWAPPED);
|
||||
LENGTH.put("FOUR_BYTE_FLOAT",DataType.FOUR_BYTE_FLOAT);
|
||||
LENGTH.put("FOUR_BYTE_FLOAT_SWAPPED",DataType.FOUR_BYTE_FLOAT_SWAPPED);
|
||||
LENGTH.put("FOUR_BYTE_FLOAT_SWAPPED_INVERTED",DataType.FOUR_BYTE_FLOAT_SWAPPED_INVERTED);
|
||||
LENGTH.put("FOUR_BYTE_FLOAT_INVERTED",DataType.FOUR_BYTE_FLOAT_INVERTED);
|
||||
LENGTH.put("FOUR_BYTE_FLOAT_SWAPPED_SWAPPED",DataType.FOUR_BYTE_FLOAT_SWAPPED_SWAPPED);
|
||||
LENGTH.put("EIGHT_BYTE_INT_UNSIGNED",DataType.EIGHT_BYTE_INT_UNSIGNED);
|
||||
LENGTH.put("EIGHT_BYTE_INT_SIGNED",DataType.EIGHT_BYTE_INT_SIGNED);
|
||||
LENGTH.put("EIGHT_BYTE_INT_UNSIGNED_SWAPPED",DataType.EIGHT_BYTE_INT_UNSIGNED_SWAPPED);
|
||||
LENGTH.put("EIGHT_BYTE_INT_SIGNED_SWAPPED",DataType.EIGHT_BYTE_INT_SIGNED_SWAPPED);
|
||||
LENGTH.put("EIGHT_BYTE_FLOAT",DataType.EIGHT_BYTE_FLOAT);
|
||||
LENGTH.put("EIGHT_BYTE_FLOAT_SWAPPED",DataType.EIGHT_BYTE_FLOAT_SWAPPED);
|
||||
LENGTH.put("TWO_BYTE_BCD",DataType.TWO_BYTE_BCD);
|
||||
LENGTH.put("FOUR_BYTE_BCD",DataType.FOUR_BYTE_BCD);
|
||||
LENGTH.put("FOUR_BYTE_BCD_SWAPPED",DataType.FOUR_BYTE_BCD_SWAPPED);
|
||||
LENGTH.put("CHAR",DataType.CHAR);
|
||||
LENGTH.put("VARCHAR",DataType.VARCHAR);
|
||||
|
||||
LENGTH.put("FOUR_BYTE_FLOAT_DBCA",28);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.xzzn.common.enums;
|
||||
|
||||
public enum PcsControlCommand {
|
||||
TOTAL_START(0x0004, "总运行"),
|
||||
TOTAL_STOP(0x0010, "总停机"),
|
||||
TOTAL_RESET(0x0080, "总复位"),
|
||||
// CLUSTER1_START(0x1004, "电池簇1运行"),
|
||||
// CLUSTER1_STOP(0x1010, "电池簇1停机"),
|
||||
// CLUSTER1_RESET(0x1080, "电池簇1复位"),
|
||||
// CLUSTER2_START(0x2004, "电池簇2运行"),
|
||||
// CLUSTER2_STOP(0x2010, "电池簇2停机"),
|
||||
// CLUSTER2_RESET(0x2080, "电池簇2复位"),
|
||||
// CLUSTER3_START(0x3004, "电池簇3运行"),
|
||||
// CLUSTER3_STOP(0x3010, "电池簇3停机"),
|
||||
// CLUSTER3_RESET(0x3080, "电池簇3复位"),
|
||||
// CLUSTER4_START(0x4004, "电池簇4运行"),
|
||||
// CLUSTER4_STOP(0x4010, "电池簇4停机"),
|
||||
// CLUSTER4_RESET(0x4080, "电池簇4复位"),
|
||||
;
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
|
||||
PcsControlCommand(int code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public static PcsControlCommand fromDeviceStatus(String deviceStatus) {
|
||||
if (DeviceRunningStatus.RUNNING.getCode().equals(deviceStatus)) {
|
||||
return PcsControlCommand.TOTAL_START;
|
||||
} else if (DeviceRunningStatus.SHUTDOWN.getCode().equals(deviceStatus) ) {
|
||||
return PcsControlCommand.TOTAL_STOP;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.xzzn.common.enums;
|
||||
|
||||
public enum RegisterType {
|
||||
COIL,
|
||||
DISCRETE_INPUT,
|
||||
HOLDING_REGISTER,
|
||||
INPUT_REGISTER
|
||||
}
|
||||
Reference in New Issue
Block a user