Commit 1c3cf716 authored by wanghao's avatar wanghao

1 使用 modbus4j + juc 实现 读取老化柜和老化层状态--测试中

parent 5179d8fe
...@@ -13,13 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -13,13 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.*;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/** /**
* 生产设备数据采集 * 生产设备数据采集
...@@ -37,19 +31,18 @@ public class EquipmentDataCollection { ...@@ -37,19 +31,18 @@ public class EquipmentDataCollection {
private ITStoreyInfoService tStoreyInfoService; private ITStoreyInfoService tStoreyInfoService;
@Autowired @Autowired
private ITEquipmentAlarmDataService tEquipmentAlarmDataService; private ITEquipmentAlarmDataService tEquipmentAlarmDataService;
/** /**
* 1.老化柜、标定柜巡查 * 1.老化柜、标定柜巡查
* 2.老化层断电 * 2.老化层断电
*/ */
@GetMapping("/equipmentPatrol") @GetMapping("/equipmentPatrol")
public void equipmentPatrol(){ public void equipmentPatrol() {
List<String> type = new ArrayList<>(); List<String> type = new ArrayList<>();
type.add("1"); type.add("1");
type.add("2"); type.add("2");
List<TEquipmentInfo> equipmentInfos = tEquipmentInfoService.selectTEquipmentList(type); List<TEquipmentInfo> equipmentInfos = tEquipmentInfoService.selectTEquipmentList(type);
try{ try {
if(equipmentInfos.size() == 0){ if (equipmentInfos.size() == 0) {
log.error("设备列表查询结果为空"); log.error("设备列表查询结果为空");
throw new Exception("无设备信息!"); throw new Exception("无设备信息!");
} }
...@@ -58,9 +51,9 @@ public class EquipmentDataCollection { ...@@ -58,9 +51,9 @@ public class EquipmentDataCollection {
String sendMsg1 = "00010000000601040000000A"; String sendMsg1 = "00010000000601040000000A";
String receiveMsg1 = null; String receiveMsg1 = null;
TEquipmentAlarmData alarmData = new TEquipmentAlarmData(); TEquipmentAlarmData alarmData = new TEquipmentAlarmData();
for(TEquipmentInfo info : equipmentInfos){ for (TEquipmentInfo info : equipmentInfos) {
receiveMsg1 = agingCabinetCommunication(info, sendMsg1); receiveMsg1 = agingCabinetCommunication(info, sendMsg1);
if(receiveMsg1 == null || receiveMsg1.length() != 58){ if (receiveMsg1 == null || receiveMsg1.length() != 58) {
// 记录异常数据 // 记录异常数据
alarmData.setfAlarmType("01"); // 01.老化柜 02.标定柜 03.机械臂 04.老化层 05.点位 alarmData.setfAlarmType("01"); // 01.老化柜 02.标定柜 03.机械臂 04.老化层 05.点位
alarmData.setfEquipmentCode(info.getfEquipmentCode()); alarmData.setfEquipmentCode(info.getfEquipmentCode());
...@@ -73,7 +66,7 @@ public class EquipmentDataCollection { ...@@ -73,7 +66,7 @@ public class EquipmentDataCollection {
// 解析服务器返回信息 // 解析服务器返回信息
// 示例:00 01 00 00 00 17 01 04 14 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // 示例:00 01 00 00 00 17 01 04 14 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
String flag = receiveMsg1.substring(18, 58); String flag = receiveMsg1.substring(18, 58);
if("0000000000000000000000000000000000000000".equals(flag) && !"0".equals(info.getfStatus())){ if ("0000000000000000000000000000000000000000".equals(flag) && !"0".equals(info.getfStatus())) {
// 更新老化柜状态(“0”空闲,“1”运行,“2”故障) // 更新老化柜状态(“0”空闲,“1”运行,“2”故障)
info.setfStatus("0"); info.setfStatus("0");
info.setfUpdateTime(new Date()); info.setfUpdateTime(new Date());
...@@ -82,7 +75,7 @@ public class EquipmentDataCollection { ...@@ -82,7 +75,7 @@ public class EquipmentDataCollection {
info.setfStatus("1"); info.setfStatus("1");
info.setfUpdateTime(new Date()); info.setfUpdateTime(new Date());
tEquipmentInfoService.updateTEquipmentInfo(info); tEquipmentInfoService.updateTEquipmentInfo(info);
} else if ("0000000000000000000000000000000000000000".equals(flag)){ } else if ("0000000000000000000000000000000000000000".equals(flag)) {
// 解析层状态,根据层编号修改状态 // 解析层状态,根据层编号修改状态
int startIndex; int startIndex;
int endIndex; int endIndex;
...@@ -90,11 +83,11 @@ public class EquipmentDataCollection { ...@@ -90,11 +83,11 @@ public class EquipmentDataCollection {
String status; String status;
TStoreyInfo storeyInfo = new TStoreyInfo(); TStoreyInfo storeyInfo = new TStoreyInfo();
String storeyCode; String storeyCode;
for(startIndex = 18,endIndex = 22,code = 1; endIndex <= receiveMsg1.length(); startIndex += 4,endIndex += 4,code++){ for (startIndex = 18, endIndex = 22, code = 1; endIndex <= receiveMsg1.length(); startIndex += 4, endIndex += 4, code++) {
status = receiveMsg1.substring(startIndex, endIndex); status = receiveMsg1.substring(startIndex, endIndex);
storeyCode = info.getfEquipmentCode() + "-" + code; storeyCode = info.getfEquipmentCode() + "-" + code;
storeyInfo = tStoreyInfoService.selectTStoreyInfoByCode(storeyCode); storeyInfo = tStoreyInfoService.selectTStoreyInfoByCode(storeyCode);
if(storeyInfo == null){ if (storeyInfo == null) {
// 记录异常数据 // 记录异常数据
alarmData.setfAlarmType("01"); // 01.老化柜 02.标定柜 03.机械臂 04.老化层 05.点位 alarmData.setfAlarmType("01"); // 01.老化柜 02.标定柜 03.机械臂 04.老化层 05.点位
alarmData.setfEquipmentCode(info.getfEquipmentCode()); alarmData.setfEquipmentCode(info.getfEquipmentCode());
...@@ -102,13 +95,13 @@ public class EquipmentDataCollection { ...@@ -102,13 +95,13 @@ public class EquipmentDataCollection {
tEquipmentAlarmDataService.insertTEquipmentAlarmData(alarmData); tEquipmentAlarmDataService.insertTEquipmentAlarmData(alarmData);
continue; continue;
} }
if("0000".equals(status)){ if ("0000".equals(status)) {
/* 2.老化层断电 */ /* 2.老化层断电 */
// 示例:000100000006 01 功能码05 寄存器地址0000 断电0000 // 示例:000100000006 01 功能码05 寄存器地址0000 断电0000
String addr = Integer.toHexString(code-1).length()<2?"0"+Integer.toHexString(code-1):Integer.toHexString(code-1); String addr = Integer.toHexString(code - 1).length() < 2 ? "0" + Integer.toHexString(code - 1) : Integer.toHexString(code - 1);
String sendMsg2 = "000100000006010500" + addr + "0000"; String sendMsg2 = "000100000006010500" + addr + "0000";
String receiveMsg2 = storeyCommunication(storeyInfo, sendMsg2); String receiveMsg2 = storeyCommunication(storeyInfo, sendMsg2);
if(sendMsg2.equals(receiveMsg2)){ if (sendMsg2.equals(receiveMsg2)) {
// 更新老化层状态 // 更新老化层状态
storeyInfo.setfStatus("3"); //断电 storeyInfo.setfStatus("3"); //断电
tStoreyInfoService.updateTStoreyInfo(storeyInfo); tStoreyInfoService.updateTStoreyInfo(storeyInfo);
...@@ -171,20 +164,20 @@ public class EquipmentDataCollection { ...@@ -171,20 +164,20 @@ public class EquipmentDataCollection {
// 解析服务器返回信息 // 解析服务器返回信息
// 示例:00 01 00 00 00 17 01 04 14 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // 示例:00 01 00 00 00 17 01 04 14 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
String storeyCode = storeyInfo.getfStoreyCode(); String storeyCode = storeyInfo.getfStoreyCode();
int code = Integer.parseInt(storeyCode.substring(storeyCode.indexOf("-")+1)); int code = Integer.parseInt(storeyCode.substring(storeyCode.indexOf("-") + 1));
int startIndex; int startIndex;
int endIndex; int endIndex;
String status; String status;
int flag = 1; int flag = 1;
for(startIndex = 18,endIndex = 22,code = 1; endIndex <= receiveMsg1.length(); startIndex += 4,endIndex += 4,flag++){ for (startIndex = 18, endIndex = 22, code = 1; endIndex <= receiveMsg1.length(); startIndex += 4, endIndex += 4, flag++) {
status = receiveMsg1.substring(startIndex, endIndex); status = receiveMsg1.substring(startIndex, endIndex);
if(flag == code && "0001".equals(status)){ if (flag == code && "0001".equals(status)) {
/* 3.老化层上电 */ /* 3.老化层上电 */
// 示例:000100000006 01 功能码05 寄存器地址0000 上电FF00 // 示例:000100000006 01 功能码05 寄存器地址0000 上电FF00
String addr = Integer.toHexString(flag-1).length()<2?"0"+Integer.toHexString(flag-1):Integer.toHexString(flag-1); String addr = Integer.toHexString(flag - 1).length() < 2 ? "0" + Integer.toHexString(flag - 1) : Integer.toHexString(flag - 1);
String sendMsg2 = "000100000006010500" + addr + "FF00"; String sendMsg2 = "000100000006010500" + addr + "FF00";
String receiveMsg2 = storeyCommunication(storeyInfo, sendMsg2); String receiveMsg2 = storeyCommunication(storeyInfo, sendMsg2);
if(!sendMsg2.equals(receiveMsg2) || receiveMsg2 == null){ if (!sendMsg2.equals(receiveMsg2) || receiveMsg2 == null) {
// 记录异常数据 // 记录异常数据
alarmData.setfAlarmType("04"); //01.老化柜 02.标定柜 03.机械臂 04.老化层 05.点位 alarmData.setfAlarmType("04"); //01.老化柜 02.标定柜 03.机械臂 04.老化层 05.点位
alarmData.setfEquipmentCode(storeyInfo.getfStoreyCode()); alarmData.setfEquipmentCode(storeyInfo.getfStoreyCode());
...@@ -200,7 +193,7 @@ public class EquipmentDataCollection { ...@@ -200,7 +193,7 @@ public class EquipmentDataCollection {
// 示例:000100000006 点位地址01 功能码03 起始位置0000 终止位置000A // 示例:000100000006 点位地址01 功能码03 起始位置0000 终止位置000A
String sendMsg3 = "00010000000601030000000A"; String sendMsg3 = "00010000000601030000000A";
String receiveMsg3 = storeyCommunication(storeyInfo, sendMsg3); String receiveMsg3 = storeyCommunication(storeyInfo, sendMsg3);
if(receiveMsg3 == null){ if (receiveMsg3 == null) {
// 记录异常数据 // 记录异常数据
alarmData.setfAlarmType("04"); //01.老化柜 02.标定柜 03.机械臂 04.老化层 05.点位 alarmData.setfAlarmType("04"); //01.老化柜 02.标定柜 03.机械臂 04.老化层 05.点位
alarmData.setfEquipmentCode(storeyInfo.getfStoreyCode()); alarmData.setfEquipmentCode(storeyInfo.getfStoreyCode());
...@@ -210,11 +203,11 @@ public class EquipmentDataCollection { ...@@ -210,11 +203,11 @@ public class EquipmentDataCollection {
// 解析服务器返回信息 // 解析服务器返回信息
// 示例:000100000017010314 浓度0000 状态0001 AD值01F7 标定AD值01F7 年07E9 月0005 日0004 时000E 分000F 秒0015 // 示例:000100000017010314 浓度0000 状态0001 AD值01F7 标定AD值01F7 年07E9 月0005 日0004 时000E 分000F 秒0015
String value = receiveMsg3.substring(22, 26); //板子状态 String value = receiveMsg3.substring(22, 26); //板子状态
if("0001".equals(value)){ if ("0001".equals(value)) {
/* 5.写入时间,年、月、日、时、分 */ /* 5.写入时间,年、月、日、时、分 */
// 示例:000100000006 设备地址01写时间06 寄存器地址0004(年04月05日06时07分08) 年/月/日/时/分数值07E9(2025) // 示例:000100000006 设备地址01写时间06 寄存器地址0004(年04月05日06时07分08) 年/月/日/时/分数值07E9(2025)
Calendar cal=Calendar.getInstance(); Calendar cal = Calendar.getInstance();
// 当前年 // 当前年
int y = cal.get(Calendar.YEAR); int y = cal.get(Calendar.YEAR);
// 当前月 // 当前月
...@@ -225,15 +218,15 @@ public class EquipmentDataCollection { ...@@ -225,15 +218,15 @@ public class EquipmentDataCollection {
int h = cal.get(Calendar.HOUR_OF_DAY); int h = cal.get(Calendar.HOUR_OF_DAY);
// 当前分钟 // 当前分钟
int mm = cal.get(Calendar.MINUTE); int mm = cal.get(Calendar.MINUTE);
String minutes = Integer.toHexString(mm).length()<2?"000"+Integer.toHexString(mm):"00"+Integer.toHexString(mm); String minutes = Integer.toHexString(mm).length() < 2 ? "000" + Integer.toHexString(mm) : "00" + Integer.toHexString(mm);
String hours = Integer.toHexString(h).length()<2?"000"+Integer.toHexString(h):"00"+Integer.toHexString(h); String hours = Integer.toHexString(h).length() < 2 ? "000" + Integer.toHexString(h) : "00" + Integer.toHexString(h);
String date = Integer.toHexString(d).length()<2?"000"+Integer.toHexString(d):"00"+Integer.toHexString(d); String date = Integer.toHexString(d).length() < 2 ? "000" + Integer.toHexString(d) : "00" + Integer.toHexString(d);
String month = Integer.toHexString(m).length()<2?"000"+Integer.toHexString(m):"00"+Integer.toHexString(m); String month = Integer.toHexString(m).length() < 2 ? "000" + Integer.toHexString(m) : "00" + Integer.toHexString(m);
String year = Integer.toHexString(y).length()<4?"0"+Integer.toHexString(y):Integer.toHexString(y); String year = Integer.toHexString(y).length() < 4 ? "0" + Integer.toHexString(y) : Integer.toHexString(y);
String sendMsgYear = "0001000000060" + code + "060004" + year; String sendMsgYear = "0001000000060" + code + "060004" + year;
String receiveMsgYear = storeyCommunication(storeyInfo, sendMsgYear); String receiveMsgYear = storeyCommunication(storeyInfo, sendMsgYear);
if(!sendMsgYear.equals(receiveMsgYear) || receiveMsgYear == null){ if (!sendMsgYear.equals(receiveMsgYear) || receiveMsgYear == null) {
// 记录异常数据 // 记录异常数据
alarmData.setfAlarmType("05"); //01.老化柜 02.标定柜 03.机械臂 04.老化层 05.点位 alarmData.setfAlarmType("05"); //01.老化柜 02.标定柜 03.机械臂 04.老化层 05.点位
alarmData.setfEquipmentCode(storeyInfo.getfStoreyCode()); alarmData.setfEquipmentCode(storeyInfo.getfStoreyCode());
...@@ -251,45 +244,45 @@ public class EquipmentDataCollection { ...@@ -251,45 +244,45 @@ public class EquipmentDataCollection {
String ip = null; String ip = null;
Integer port = null; Integer port = null;
int num = 1; int num = 1;
try{ try {
ip = equipment.getfIp(); ip = equipment.getfIp();
port = equipment.getfPort(); port = equipment.getfPort();
if(ip == null || port == null){ if (ip == null || port == null) {
receiveMsg = equipment.getfEquipmentCode(); receiveMsg = equipment.getfEquipmentCode();
} else { } else {
// 若通讯失败将再次通讯,最多通讯3次 // 若通讯失败将再次通讯,最多通讯3次
while((receiveMsg == null || receiveMsg.length() != 58) && num <= 3){ while ((receiveMsg == null || receiveMsg.length() != 58) && num <= 3) {
// 发送并接收数据 // 发送并接收数据
receiveMsg = TCPClient.PLCConnect(ip, port, sendMsg); receiveMsg = TCPClient.PLCConnect(ip, port, sendMsg);
num++; num++;
} }
} }
} catch(Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return receiveMsg; return receiveMsg;
} }
//老化层通讯 //老化层通讯
private String storeyCommunication(TStoreyInfo storey, String sendMsg){ private String storeyCommunication(TStoreyInfo storey, String sendMsg) {
String ip = null; String ip = null;
Integer port = null; Integer port = null;
String receiveMsg = null; String receiveMsg = null;
int num = 1; int num = 1;
try{ try {
ip = storey.getfIp(); ip = storey.getfIp();
port = storey.getfPort(); port = storey.getfPort();
if(ip == null || port == null){ if (ip == null || port == null) {
receiveMsg = storey.getfStoreyCode(); receiveMsg = storey.getfStoreyCode();
} }
// 若通讯失败将再次通讯,最多通讯3次 // 若通讯失败将再次通讯,最多通讯3次
while((!sendMsg.equals(receiveMsg) || receiveMsg == null) && num <= 3){ while ((!sendMsg.equals(receiveMsg) || receiveMsg == null) && num <= 3) {
// 发送并接收数据 // 发送并接收数据
receiveMsg = TCPClient.PLCConnect(ip, port, sendMsg); receiveMsg = TCPClient.PLCConnect(ip, port, sendMsg);
num++; num++;
} }
}catch(Exception e){ } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return receiveMsg; return receiveMsg;
......
package com.zehong.web.task;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.zehong.framework.modbus4j.Modbus4jUtils;
import com.zehong.system.domain.TEquipmentInfo;
import com.zehong.system.domain.modbus.ModbusDeviceData;
import com.zehong.system.service.ITEquipmentInfoService;
import com.zehong.web.controller.equipment.EquipmentDataCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/**
* @author lenovo
* @date 2025/6/9
* @description 老化柜巡查 + 老化层断电检测
*/
@Component("agingCabinetInspectionAndPowerCheckTask")
public class AgingCabinetInspectionAndPowerCheckTask {
private static final Logger log = LoggerFactory.getLogger(AgingCabinetInspectionAndPowerCheckTask.class);
private final ExecutorService executor = Executors.newFixedThreadPool(10);
@Resource
private ITEquipmentInfoService tEquipmentInfoService;
/**
* 五分钟一次
* 1.老化柜、标定柜巡查
* 2.老化层断电
* 这种方式先注释掉
// for (TEquipmentInfo equipmentInfo : equipmentInfos) {
// Future<Map<Integer, Object>> future = executor.submit(new ModbusTcpTask(equipmentInfo, registerOffset));
// futures.add(future);
// }
// List<ModbusDeviceData> results = new ArrayList<>();
//
// for (int i = 0; i < futures.size(); i++) {
// Map<Integer, Object> data = futures.get(i).get();
// ModbusDeviceData deviceData = new ModbusDeviceData();
// deviceData.setDeviceId(equipmentInfos.get(i).getfEquipmentId().toString());
// deviceData.setRegisterValues(data.entrySet().stream()
// .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString())));
// results.add(deviceData);
// }
*/
public void ryCheck() {
List<String> type = new ArrayList<>();
type.add("1");
type.add("2");
List<TEquipmentInfo> equipmentInfos = tEquipmentInfoService.selectTEquipmentList(type);
try {
if (equipmentInfos.size() == 0) {
log.error("设备列表查询结果为空");
throw new Exception("无设备信息!");
}
// 10 层
// List<Integer> registerOffset = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
//
// List<CompletableFuture<ModbusDeviceData>> futures = equipmentInfos.stream().map(equipmentInfo -> CompletableFuture.supplyAsync(() -> {
// ModbusMaster master = null;
// try {
// master = Modbus4jUtils.getMaster(equipmentInfo.getfIp(), equipmentInfo.getfPort());
// Map<Integer, Object> integerObjectMap = Modbus4jUtils.batchReadAgingCabinet(master, registerOffset);
// // 构造结果对象
// ModbusDeviceData deviceData = new ModbusDeviceData();
// deviceData.setDeviceId(equipmentInfo.getfEquipmentId().toString());
// deviceData.setRegisterValues(integerObjectMap.entrySet().stream()
// .collect(Collectors.toMap(
// Map.Entry::getKey,
// e -> e.getValue() != null ? e.getValue().toString() : "NULL"
// )));
//
// return deviceData;
//
// } catch (ModbusInitException e) {
//
// // 初始化失败
// Map<Integer, String> errorMap = new HashMap<>();
//
// ModbusDeviceData deviceData = new ModbusDeviceData();
// deviceData.setDeviceId("");
// deviceData.setRegisterValues(errorMap);
//
// return deviceData;
// } catch (ModbusTransportException | ErrorResponseException e) {
// // 返回错误信息
// Map<Integer, String> errorMap = new HashMap<>();
// registerOffset.forEach(offset -> errorMap.put(offset, "ERROR: " + e.getMessage()));
//
// ModbusDeviceData deviceData = new ModbusDeviceData();
// deviceData.setDeviceId(equipmentInfo.getfEquipmentId().toString());
// deviceData.setRegisterValues(errorMap);
//
// return deviceData;
// } finally {
// if (master != null) {
// master.destroy();
// }
// }
// }, executor)).collect(Collectors.toList());
//
// // 等待所有任务完成并收集结果
// CompletableFuture<List<ModbusDeviceData>> listCompletableFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
// .thenApply(v -> futures.stream()
// .map(CompletableFuture::join)
// .collect(Collectors.toList()));
//
// DeferredResult<List<ModbusDeviceData>> deferredResult = new DeferredResult<>();
//
// listCompletableFuture.whenComplete((result, ex) -> {
// if (ex != null) {
// deferredResult.setErrorResult(Collections.singletonList(createErrorData(ex)));
// } else {
// deferredResult.setResult(result);
// }
// });
} catch (Exception e) {
e.printStackTrace();
}
}
private ModbusDeviceData createErrorData(Throwable ex) {
ModbusDeviceData errorData = new ModbusDeviceData();
errorData.setDeviceId("error");
errorData.setRegisterValues(Collections.singletonMap(0, "系统错误:" + ex.getMessage()));
return errorData;
}
}
...@@ -118,6 +118,12 @@ ...@@ -118,6 +118,12 @@
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
</dependency> </dependency>
<!-- modbus4j-->
<dependency>
<groupId>com.infiniteautomation</groupId>
<artifactId>modbus4j</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies> </dependencies>
......
package com.zehong.framework.modbus4j;
import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* modbus通讯工具类,采用modbus4j实现
*
*/
public class Modbus4jUtils {
private static final Logger log = LoggerFactory.getLogger(Modbus4jUtils.class);
/**
* 工厂。
*/
static ModbusFactory modbusFactory;
static {
if (modbusFactory == null) {
modbusFactory = new ModbusFactory();
}
}
/**
* 获取master
*
* @return master
* @throws ModbusInitException m
*/
public static ModbusMaster getMaster() throws ModbusInitException {
IpParameters params = new IpParameters();
params.setHost("localhost");
params.setPort(502);
//
// modbusFactory.createRtuMaster(wapper); //RTU 协议
// modbusFactory.createUdpMaster(params);//UDP 协议
// modbusFactory.createAsciiMaster(wrapper);//ASCII 协议
ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
master.init();
return master;
}
/**
* 动态获取 modubus master
* @param ip ip
* @param port port
* @return r
* @throws ModbusInitException m
*/
public static ModbusMaster getMaster(String ip, int port) throws ModbusInitException {
IpParameters params = new IpParameters();
params.setHost(ip);
params.setPort(port);
ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
master.init();
return master;
}
/**
* 读取[01 Coil Status 0x]类型 开关数据
*
* @param slaveId
* slaveId
* @param offset
* 位置
* @return 读取值
* @throws ModbusTransportException
* 异常
* @throws ErrorResponseException
* 异常
* @throws ModbusInitException
* 异常
*/
public static Boolean readCoilStatus(int slaveId, int offset)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 01 Coil Status
BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
Boolean value = getMaster().getValue(loc);
return value;
}
/**
* 读取[02 Input Status 1x]类型 开关数据
*
* @param slaveId
* @param offset
* @return
* @throws ModbusTransportException
* @throws ErrorResponseException
* @throws ModbusInitException
*/
public static Boolean readInputStatus(int slaveId, int offset)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 02 Input Status
BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
Boolean value = getMaster().getValue(loc);
return value;
}
/**
* 读取[03 Holding Register类型 2x]模拟量数据
*
* @param slaveId
* slave Id
* @param offset
* 位置
* @param dataType
* 数据类型,来自com.serotonin.modbus4j.code.DataType
* @return
* @throws ModbusTransportException
* 异常
* @throws ErrorResponseException
* 异常
* @throws ModbusInitException
* 异常
*/
public static Number readHoldingRegister(int slaveId, int offset, int dataType)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 03 Holding Register类型数据读取
BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
Number value = getMaster().getValue(loc);
return value;
}
/**
* 读取[04 Input Registers 3x]类型 模拟量数据
*
* @param slaveId
* slaveId
* @param offset
* 位置
* @param dataType
* 数据类型,来自com.serotonin.modbus4j.code.DataType
* @return 返回结果
* @throws ModbusTransportException
* 异常
* @throws ErrorResponseException
* 异常
* @throws ModbusInitException
* 异常
*/
public static Number readInputRegisters(int slaveId, int offset, int dataType)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 04 Input Registers类型数据读取
BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
Number value = getMaster().getValue(loc);
return value;
}
/**
*
* @param master
* @param slaveId
* @param offset
* @param length
* @return
* @throws ModbusTransportException
* @throws ErrorResponseException
* @throws ModbusInitException
*/
/**
* 读取[04 Input Registers 3x]类型 模拟量数据
*
* @param master
* master
* @param slaveId
* slaveId
* @param offset
* 位置
* @param dataType
* 数据类型,来自com.serotonin.modbus4j.code.DataType
* @return 返回结果
* @throws ModbusTransportException
* 异常
* @throws ErrorResponseException
* 异常
* @throws ModbusInitException
* 异常
*/
public static Number readInputRegisters(ModbusMaster master,int slaveId, int offset, int dataType)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 04 Input Registers类型数据读取
BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
Number value = getMaster().getValue(loc);
return value;
}
/**
* 批量读取使用方法
*
* @throws ModbusTransportException m
* @throws ErrorResponseException e
* @throws ModbusInitException m
*/
public static void batchRead() throws ModbusTransportException, ErrorResponseException, ModbusInitException {
BatchRead<Integer> batch = new BatchRead<Integer>();
batch.addLocator(0, BaseLocator.holdingRegister(1, 1, DataType.FOUR_BYTE_FLOAT));
batch.addLocator(1, BaseLocator.inputStatus(1, 0));
ModbusMaster master = getMaster();
batch.setContiguousRequests(false);
BatchResults<Integer> results = master.send(batch);
System.out.println(results.getValue(0));
System.out.println(results.getValue(1));
}
/**
* 批量读取使用方法
*
* @throws ModbusTransportException m
* @throws ErrorResponseException e
* @throws ModbusInitException m
*/
public static Map<Integer, Object> batchReadAgingCabinet(ModbusMaster master, List<Integer> registerOffsets) throws ModbusTransportException, ErrorResponseException {
BatchRead<Integer> batch = new BatchRead<Integer>();
for (Integer registerOffset : registerOffsets) {
batch.addLocator(registerOffset, BaseLocator.holdingRegister(1, registerOffset, DataType.FOUR_BYTE_FLOAT));
}
// 非连续地址也支持
batch.setContiguousRequests(false);
BatchResults<Integer> send = master.send(batch);
Map<Integer, Object> result = new HashMap<>();
for (Integer registerOffset : registerOffsets) {
result.put(registerOffset, send.getValue(registerOffset));
}
return result;
}
/**
* 写 [01 Coil Status(0x)]写一个 function ID = 5
*
* @param slaveId
* slave的ID
* @param writeOffset
* 位置
* @param writeValue
* 值
* @return 是否写入成功
* @throws ModbusTransportException m
* @throws ModbusInitException m
*/
public static boolean writeCoil(int slaveId, int writeOffset, boolean writeValue)
throws ModbusTransportException, ModbusInitException {
// 获取master
ModbusMaster tcpMaster = getMaster();
// 创建请求
WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
// 发送请求并获取响应对象
WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request);
if (response.isException()) {
return false;
} else {
return true;
}
}
/**
* 写[01 Coil Status(0x)] 写多个 function ID = 15
*
* @param slaveId
* slaveId
* @param startOffset
* 开始位置
* @param bdata
* 写入的数据
* @return 是否写入成功
* @throws ModbusTransportException m
* @throws ModbusInitException m
*/
public static boolean writeCoils(int slaveId, int startOffset, boolean[] bdata)
throws ModbusTransportException, ModbusInitException {
// 获取master
ModbusMaster tcpMaster = getMaster();
// 创建请求
WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata);
// 发送请求并获取响应对象
WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request);
if (response.isException()) {
return false;
} else {
return true;
}
}
/***
* 写[03 Holding Register(4x)] 写一个 function ID = 6
*
* @param slaveId s
* @param writeOffset w
* @param writeValue w
* @return
* @throws ModbusTransportException m
* @throws ModbusInitException m
*/
public static boolean writeRegister(int slaveId, int writeOffset, short writeValue)
throws ModbusTransportException, ModbusInitException {
// 获取master
ModbusMaster tcpMaster = getMaster();
// 创建请求对象
WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);
WriteRegisterResponse response = (WriteRegisterResponse) tcpMaster.send(request);
if (response.isException()) {
log.error(response.getExceptionMessage());
return false;
} else {
return true;
}
}
/**
*
* 写入[03 Holding Register(4x)]写多个 function ID=16
*
* @param slaveId
* modbus的slaveID
* @param startOffset
* 起始位置偏移量值
* @param sdata
* 写入的数据
* @return 返回是否写入成功
* @throws ModbusTransportException m
* @throws ModbusInitException m
*/
public static boolean writeRegisters(int slaveId, int startOffset, short[] sdata)
throws ModbusTransportException, ModbusInitException {
// 获取master
ModbusMaster tcpMaster = getMaster();
// 创建请求对象
WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, sdata);
// 发送请求并获取响应对象
ModbusResponse response = tcpMaster.send(request);
if (response.isException()) {
log.error(response.getExceptionMessage());
return false;
} else {
return true;
}
}
/**
* 写入数字类型的模拟量(如:写入Float类型的模拟量、Double类型模拟量、整数类型Short、Integer、Long)
*
* @param slaveId s
* @param offset o
* @param value
* 写入值,Number的子类,例如写入Float浮点类型,Double双精度类型,以及整型short,int,long
* @param dataType r
* ,com.serotonin.modbus4j.code.DataType
* @throws ModbusTransportException m
* @throws ErrorResponseException e
* @throws ModbusInitException m
*/
public static void writeHoldingRegister(int slaveId, int offset, Number value, int dataType)
throws ModbusTransportException, ErrorResponseException, ModbusInitException {
// 获取master
ModbusMaster tcpMaster = getMaster();
// 类型
BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, dataType);
tcpMaster.setValue(locator, value);
}
/**
* 测试
*
* @param args a
*/
public static void main(String[] args) {
try {
// 01测试
Boolean v011 = readCoilStatus(1, 0);
Boolean v012 = readCoilStatus(1, 1);
Boolean v013 = readCoilStatus(1, 6);
System.out.println("v011:" + v011);
System.out.println("v012:" + v012);
System.out.println("v013:" + v013);
// 02测试
Boolean v021 = readInputStatus(1, 0);
Boolean v022 = readInputStatus(1, 1);
Boolean v023 = readInputStatus(1, 2);
System.out.println("v021:" + v021);
System.out.println("v022:" + v022);
System.out.println("v023:" + v023);
// 03测试
Number v031 = readHoldingRegister(1, 1, DataType.FOUR_BYTE_FLOAT);// 注意,float
Number v032 = readHoldingRegister(1, 3, DataType.FOUR_BYTE_FLOAT);// 同上
System.out.println("v031:" + v031);
System.out.println("v032:" + v032);
// 04测试
Number v041 = readInputRegisters(1, 0, DataType.FOUR_BYTE_FLOAT);//
Number v042 = readInputRegisters(1, 2, DataType.FOUR_BYTE_FLOAT);//
System.out.println("v041:" + v041);
System.out.println("v042:" + v042);
// 批量读取
batchRead();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.zehong.framework.modbus4j;
import java.util.Map;
/**
* @author lenovo
* @date 2025/6/9
* @description TODO
*/
public class ModbusDeviceData {
private String deviceId;
private Map<Integer, String> registerValues; // key: 寄存器地址, value: 读取结果
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public Map<Integer, String> getRegisterValues() {
return registerValues;
}
public void setRegisterValues(Map<Integer, String> registerValues) {
this.registerValues = registerValues;
}
}
package com.zehong.framework.modbus4j;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.zehong.system.domain.TEquipmentInfo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* @author lenovo
* @date 2025/6/9
* @description 读取数据多线程封装
*/
public class ModbusTcpTask implements Callable<Map<Integer, Object>> {
private final TEquipmentInfo equipmentInfo;
private final List<Integer> registerOffsets;
public ModbusTcpTask(TEquipmentInfo equipmentInfo, List<Integer> registerOffset) {
this.equipmentInfo = equipmentInfo;
this.registerOffsets = registerOffset;
}
@Override
public Map<Integer, Object> call(){
ModbusMaster master = null;
try {
master = Modbus4jUtils.getMaster(equipmentInfo.getfIp(), equipmentInfo.getfPort());
return Modbus4jUtils.batchReadAgingCabinet(master,registerOffsets);
} catch (ModbusInitException e) {
Map<Integer, Object> errorMap = new HashMap<>();
errorMap.put(1,-1);
return errorMap;
} catch (Exception e) {
Map<Integer, Object> errorMap = new HashMap<>();
registerOffsets.forEach(offset -> errorMap.put(offset, "ERROR: " + e.getMessage()));
return errorMap;
} finally {
if (master != null) {
master.destroy();
}
}
}
}
package com.zehong.system.domain.modbus;
import java.util.Map;
/**
* @author lenovo
* @date 2025/6/9
* @description TODO
*/
public class ModbusDeviceData {
private String deviceId;
private Map<Integer, String> registerValues; // key: 寄存器地址, value: 读取结果
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public Map<Integer, String> getRegisterValues() {
return registerValues;
}
public void setRegisterValues(Map<Integer, String> registerValues) {
this.registerValues = registerValues;
}
}
package com.zehong.system.service; package com.zehong.system.service;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
import com.zehong.system.domain.TEquipmentInfo; import com.zehong.system.domain.TEquipmentInfo;
import com.zehong.system.domain.modbus.ModbusDeviceData;
/** /**
* 生产设备信息Service接口 * 生产设备信息Service接口
...@@ -35,6 +38,8 @@ public interface ITEquipmentInfoService ...@@ -35,6 +38,8 @@ public interface ITEquipmentInfoService
*/ */
public List<TEquipmentInfo> selectTEquipmentList(List<String> types); public List<TEquipmentInfo> selectTEquipmentList(List<String> types);
CompletableFuture<List<ModbusDeviceData>> readAllDevicesRegistersAsync(List<Integer> registerOffsets);
/** /**
* 新增生产设备信息 * 新增生产设备信息
* *
......
package com.zehong.system.service.impl; package com.zehong.system.service.impl;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
import com.zehong.system.domain.modbus.ModbusDeviceData;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.zehong.system.mapper.TEquipmentInfoMapper; import com.zehong.system.mapper.TEquipmentInfoMapper;
...@@ -102,4 +106,23 @@ public class TEquipmentInfoServiceImpl implements ITEquipmentInfoService ...@@ -102,4 +106,23 @@ public class TEquipmentInfoServiceImpl implements ITEquipmentInfoService
{ {
return tEquipmentInfoMapper.deleteTEquipmentInfoById(fEquipmentId); return tEquipmentInfoMapper.deleteTEquipmentInfoById(fEquipmentId);
} }
/**
* 批量查询设备寄存器数据
*
* @param registerOffsets 设备寄存器地址
* @return 设备寄存器数据
*/
@Override
public CompletableFuture<List<ModbusDeviceData>> readAllDevicesRegistersAsync(List<Integer> registerOffsets) {
List<String> type = new ArrayList<>();
type.add("1");
type.add("2");
List<TEquipmentInfo> tEquipmentInfos = tEquipmentInfoMapper.selectTEquipmentList(type);
return null;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment