作者 钟来

plc终端控制功能完成

@@ -42,6 +42,12 @@ public class PutTopic extends TopicFactoryAdapter { @@ -42,6 +42,12 @@ public class PutTopic extends TopicFactoryAdapter {
42 ModbusMasterMessage.closeMaster(id); // 销毁旧连接 42 ModbusMasterMessage.closeMaster(id); // 销毁旧连接
43 } 43 }
44 logger.error("写plc异常",e); 44 logger.error("写plc异常",e);
  45 + try {
  46 + mqttService.publish("PUT_REQ/"+topicDto.getTime(),JSONObject.toJSONString(new Message(0,"写plc异常",jsonObject)));
  47 + } catch (MqttException ex) {
  48 + logger.error("饭hi结果异常",e);
  49 + }
  50 + return;
45 } 51 }
46 } 52 }
47 try { 53 try {
@@ -14,6 +14,7 @@ import org.slf4j.Logger; @@ -14,6 +14,7 @@ import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory; 14 import org.slf4j.LoggerFactory;
15 15
16 import java.io.File; 16 import java.io.File;
  17 +import java.io.IOException;
17 import java.util.HashMap; 18 import java.util.HashMap;
18 import java.util.List; 19 import java.util.List;
19 import java.util.Map; 20 import java.util.Map;
@@ -70,10 +71,22 @@ public class Modbus4jRead { @@ -70,10 +71,22 @@ public class Modbus4jRead {
70 try { 71 try {
71 results = ModbusMasterMessage.getMaster( id).send(batch); 72 results = ModbusMasterMessage.getMaster( id).send(batch);
72 } catch (Exception e) { 73 } catch (Exception e) {
73 - logger.error("批量读取点位异常", e); 74 + logger.error("第一次批量读取异常,尝试一次", e);
  75 + if (e instanceof ModbusInitException || e instanceof ModbusTransportException || e.getCause() instanceof IOException) {
  76 + ModbusMasterMessage.closeMaster(id);
  77 + try {
  78 + results = ModbusMasterMessage.getMaster( id).send(batch);
  79 + } catch (Exception ex) {
  80 + logger.error("第二次批量读取异常,不处理", ex);
  81 + return null;
  82 + }
  83 + } else {
  84 + logger.info("第一次批量读不是联系异常,不尝试了");
74 return null; 85 return null;
75 } 86 }
76 87
  88 + }
  89 +
77 // 转换成 JSON 对象 90 // 转换成 JSON 对象
78 Map<String, Object> jsonMap = new HashMap<>(); 91 Map<String, Object> jsonMap = new HashMap<>();
79 for (PlcPoint plcPoint : plcPoints) { 92 for (PlcPoint plcPoint : plcPoints) {
1 package com.zhonglai.luhui.device.modbus.terminal.modbus; 1 package com.zhonglai.luhui.device.modbus.terminal.modbus;
2 2
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.serotonin.modbus4j.msg.*;
  5 +import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.PlcDataType;
3 import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.PlcPoint; 6 import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.PlcPoint;
4 import org.apache.commons.logging.Log; 7 import org.apache.commons.logging.Log;
5 import org.apache.commons.logging.LogFactory; 8 import org.apache.commons.logging.LogFactory;
@@ -12,16 +15,11 @@ import com.serotonin.modbus4j.exception.ModbusInitException; @@ -12,16 +15,11 @@ import com.serotonin.modbus4j.exception.ModbusInitException;
12 import com.serotonin.modbus4j.exception.ModbusTransportException; 15 import com.serotonin.modbus4j.exception.ModbusTransportException;
13 import com.serotonin.modbus4j.ip.IpParameters; 16 import com.serotonin.modbus4j.ip.IpParameters;
14 import com.serotonin.modbus4j.locator.BaseLocator; 17 import com.serotonin.modbus4j.locator.BaseLocator;
15 -import com.serotonin.modbus4j.msg.ModbusResponse;  
16 -import com.serotonin.modbus4j.msg.WriteCoilRequest;  
17 -import com.serotonin.modbus4j.msg.WriteCoilResponse;  
18 -import com.serotonin.modbus4j.msg.WriteCoilsRequest;  
19 -import com.serotonin.modbus4j.msg.WriteCoilsResponse;  
20 -import com.serotonin.modbus4j.msg.WriteRegisterRequest;  
21 -import com.serotonin.modbus4j.msg.WriteRegisterResponse;  
22 -import com.serotonin.modbus4j.msg.WriteRegistersRequest; 18 +import org.slf4j.Logger;
  19 +import org.slf4j.LoggerFactory;
23 20
24 -import java.util.List; 21 +import java.io.IOException;
  22 +import java.util.*;
25 23
26 /** 24 /**
27 * modbus4j写入数据 25 * modbus4j写入数据
@@ -30,18 +28,39 @@ import java.util.List; @@ -30,18 +28,39 @@ import java.util.List;
30 * 28 *
31 */ 29 */
32 public class Modbus4jWrite { 30 public class Modbus4jWrite {
33 - private static Log log = LogFactory.getLog(Modbus4jWrite.class); 31 + private static final Logger log = LoggerFactory.getLogger(Modbus4jWrite.class);
34 private String id; 32 private String id;
35 33
36 public Modbus4jWrite(String id) throws Exception { 34 public Modbus4jWrite(String id) throws Exception {
37 this.id = id; 35 this.id = id;
38 } 36 }
  37 + private final Object writeLock = new Object(); // 全局串行化写锁
39 38
  39 + public void batchWrite(List<PlcPoint> points, boolean zeroBasedAddress) throws Exception {
  40 + if (points == null || points.isEmpty()) return;
40 41
41 - /**  
42 - * 单点写  
43 - */  
44 - public void writePoint(PlcPoint point, boolean zeroBasedAddress) throws ModbusTransportException, ErrorResponseException { 42 + synchronized (writeLock) {
  43 + ModbusMaster master = ModbusMasterMessage.getMaster(id);
  44 +
  45 + try {
  46 + sendBatch(master, points, zeroBasedAddress);
  47 + } catch (Exception e) {
  48 + log.info("第一次批量写入异常,尝试重连后再写入", e);
  49 +
  50 + if (e instanceof ModbusInitException || e instanceof ModbusTransportException || e.getCause() instanceof IOException) {
  51 + ModbusMasterMessage.closeMaster(id);
  52 + master = ModbusMasterMessage.getMaster(id);
  53 + sendBatch(master, points, zeroBasedAddress);
  54 + } else {
  55 + log.info("第二次批量写入异常,不处理", e);
  56 + }
  57 + }
  58 + }
  59 + }
  60 + // 批量写入封装
  61 + private void sendBatch(ModbusMaster master, List<PlcPoint> points, boolean zeroBasedAddress) throws Exception {
  62 +
  63 + for (PlcPoint point : points) {
45 BaseLocator<?> locator = ModbusAddressParser.parseLocator( 64 BaseLocator<?> locator = ModbusAddressParser.parseLocator(
46 point.getAddress(), 65 point.getAddress(),
47 point.getDataType(), 66 point.getDataType(),
@@ -49,89 +68,86 @@ public class Modbus4jWrite { @@ -49,89 +68,86 @@ public class Modbus4jWrite {
49 zeroBasedAddress, 68 zeroBasedAddress,
50 point.getOrder() 69 point.getOrder()
51 ); 70 );
52 - Object value = point.getValue();  
53 71
54 - // 如果 value 是 String,则根据 dataType 转换 72 + Object value = convertValue(point);
  73 +
  74 + if (point.getDataType() == PlcDataType.BIT && point.getAddress().contains(".")) {
  75 + // ⚡ 先读寄存器,再修改 bit 位,再写回
  76 + int offset = ModbusAddressParser.parseOffset(point.getAddress(), zeroBasedAddress);
  77 + int bitIndex = ModbusAddressParser.parseBitIndex(point.getAddress());
  78 + if (bitIndex < 0) {
  79 + throw new IllegalArgumentException("无效的 bit 地址: " + point.getAddress());
  80 + }
  81 +
  82 + // 读 holding register
  83 + int rawValue = master.getValue(
  84 + BaseLocator.holdingRegister(point.getSlaveId(), offset, DataType.TWO_BYTE_INT_UNSIGNED)
  85 + ).intValue();
  86 +
  87 + // 修改 bit
  88 + boolean bitVal = (Boolean) value;
  89 + if (bitVal) {
  90 + rawValue = rawValue | (1 << bitIndex); // 置位
  91 + } else {
  92 + rawValue = rawValue & ~(1 << bitIndex); // 清位
  93 + }
  94 +
  95 + // 写回
  96 + master.setValue(
  97 + ModbusAddressParser.parseLocator(
  98 + point.getAddress().split("\\.")[0],
  99 + PlcDataType.INT16,
  100 + point.getSlaveId(),
  101 + zeroBasedAddress,
  102 + point.getOrder()
  103 + ),
  104 + rawValue
  105 + );
  106 +
  107 + log.info("写入成功(Bit): {}[{}] = {}", point.getName(), point.getAddress(), value);
  108 +
  109 + } else {
  110 + // ⚡ 其它类型照旧
  111 + master.setValue(locator, value);
  112 + log.info("写入成功: {}[{}] = {}", point.getName(), point.getAddress(), value);
  113 + }
  114 + }
  115 + }
  116 +
  117 +
  118 + // 值转换逻辑沿用你的 writePoint
  119 + private Object convertValue(PlcPoint point) {
  120 + Object value = point.getValue();
55 if (value instanceof String) { 121 if (value instanceof String) {
56 String strVal = (String) value; 122 String strVal = (String) value;
57 switch (point.getDataType()) { 123 switch (point.getDataType()) {
58 - case BIT:  
59 - value = Boolean.parseBoolean(strVal);  
60 - break;  
61 - case INT16:  
62 - value = Short.parseShort(strVal);  
63 - break;  
64 - case UINT16:  
65 - value = Integer.parseInt(strVal); // Modbus4j 内部支持 unsigned  
66 - break; 124 + case BIT: return Boolean.parseBoolean(strVal);
  125 + case INT16: return Short.parseShort(strVal);
  126 + case UINT16: return Integer.parseInt(strVal);
67 case INT32: 127 case INT32:
68 int raw = Integer.parseInt(strVal); 128 int raw = Integer.parseInt(strVal);
69 switch (point.getOrder()) { 129 switch (point.getOrder()) {
70 - case "ABCD":  
71 - value = ModbusAddressParser.int32ToABCD(raw);  
72 - break;  
73 - case "BADC":  
74 - value = ModbusAddressParser.int32ToBADC(raw);  
75 - break;  
76 - case "CDAB":  
77 - value = ModbusAddressParser.int32ToCDAB(raw);  
78 - break;  
79 - case "DCBA":  
80 - value = ModbusAddressParser.int32ToDCBA(raw);  
81 - break;  
82 - default:  
83 - value = raw;  
84 - break; 130 + case "ABCD": return ModbusAddressParser.int32ToABCD(raw);
  131 + case "BADC": return ModbusAddressParser.int32ToBADC(raw);
  132 + case "CDAB": return ModbusAddressParser.int32ToCDAB(raw);
  133 + case "DCBA": return ModbusAddressParser.int32ToDCBA(raw);
  134 + default: return raw;
85 } 135 }
86 - break;  
87 - case INT64:  
88 - value = Long.parseLong(strVal);  
89 - break; 136 + case INT64: return Long.parseLong(strVal);
90 case FLOAT32: 137 case FLOAT32:
91 float fvalue = Float.parseFloat(strVal); 138 float fvalue = Float.parseFloat(strVal);
92 switch (point.getOrder()) { 139 switch (point.getOrder()) {
93 - case "ABCD":  
94 - value = ModbusAddressParser.floatToIntABCD(fvalue);  
95 - break;  
96 - case "BADC":  
97 - value = ModbusAddressParser.floatToIntBADC(fvalue);  
98 - break;  
99 - case "CDAB":  
100 - value = ModbusAddressParser.floatToIntCDAB(fvalue);  
101 - break;  
102 - case "DCBA":  
103 - value = ModbusAddressParser.floatToIntDCBA(fvalue);  
104 - break;  
105 - default:  
106 - value = fvalue;  
107 - break;  
108 - }  
109 - break;  
110 - case DOUBLE64:  
111 - value = Double.parseDouble(strVal);  
112 - break;  
113 - default:  
114 - throw new IllegalArgumentException("不支持的数据类型: " + point.getDataType()); 140 + case "ABCD": return ModbusAddressParser.floatToIntABCD(fvalue);
  141 + case "BADC": return ModbusAddressParser.floatToIntBADC(fvalue);
  142 + case "CDAB": return ModbusAddressParser.floatToIntCDAB(fvalue);
  143 + case "DCBA": return ModbusAddressParser.floatToIntDCBA(fvalue);
  144 + default: return fvalue;
115 } 145 }
  146 + case DOUBLE64: return Double.parseDouble(strVal);
  147 + default: throw new IllegalArgumentException("不支持的数据类型: " + point.getDataType());
116 } 148 }
117 -  
118 - // 设置值  
119 - try {  
120 - ModbusMasterMessage.getMaster(id).setValue(locator, value);  
121 - } catch (Exception e) {  
122 - log.error("写入失败",e);  
123 - return;  
124 } 149 }
125 - log.info("写入成功: " + point.getName() + " = " + point.getValue()); 150 + return value;
126 } 151 }
127 152
128 - /**  
129 - * 批量写(兼容 3.1.0,没有 BatchWrite)  
130 - */  
131 - public void batchWrite(List<PlcPoint> points, boolean zeroBasedAddress) throws ModbusTransportException, ErrorResponseException {  
132 -  
133 - for (PlcPoint plcPoint:points) {  
134 - writePoint(plcPoint, zeroBasedAddress);  
135 - }  
136 - }  
137 } 153 }
@@ -112,6 +112,32 @@ public class ModbusAddressParser { @@ -112,6 +112,32 @@ public class ModbusAddressParser {
112 throw new IllegalArgumentException("地址和数据类型不匹配: " + rawAddress + " -> " + type); 112 throw new IllegalArgumentException("地址和数据类型不匹配: " + rawAddress + " -> " + type);
113 } 113 }
114 114
  115 + /**
  116 + * 解析寄存器地址(不包含小数点后的 bit 部分)
  117 + * @param addressStr e.g. "40050.06" 或 "40050"
  118 + * @param zeroBasedAddress 是否零基地址
  119 + * @return int registerAddress
  120 + */
  121 + public static int parseRegisterAddress(String addressStr, boolean zeroBasedAddress) {
  122 + String[] parts = addressStr.split("\\.");
  123 + int baseAddr = Integer.parseInt(parts[0]);
  124 +
  125 + // 去掉40001/30001等逻辑前缀,Modbus4j用的是零基
  126 + if (baseAddr >= 40001 && baseAddr <= 49999) {
  127 + baseAddr = baseAddr - 40001;
  128 + } else if (baseAddr >= 30001 && baseAddr <= 39999) {
  129 + baseAddr = baseAddr - 30001;
  130 + } else if (baseAddr >= 1 && baseAddr <= 9999) {
  131 + baseAddr = baseAddr - 1;
  132 + }
  133 +
  134 + if (!zeroBasedAddress) {
  135 + baseAddr = baseAddr + 1; // 用户配置非零基,则+1
  136 + }
  137 +
  138 + return baseAddr;
  139 + }
  140 +
115 /** 解析寄存器偏移量 */ 141 /** 解析寄存器偏移量 */
116 public static int parseOffset(String rawAddress, boolean zeroBasedAddress) { 142 public static int parseOffset(String rawAddress, boolean zeroBasedAddress) {
117 if (rawAddress == null || rawAddress.isEmpty()) { 143 if (rawAddress == null || rawAddress.isEmpty()) {
@@ -299,4 +325,62 @@ public class ModbusAddressParser { @@ -299,4 +325,62 @@ public class ModbusAddressParser {
299 return ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getInt(); 325 return ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getInt();
300 } 326 }
301 327
  328 + private short[] toRegisters(Object value, PlcDataType dataType, String order) {
  329 + switch (dataType) {
  330 + case INT16:
  331 + return new short[]{(Short) value};
  332 + case UINT16:
  333 + return new short[]{((Integer) value).shortValue()};
  334 + case INT32:
  335 + int intVal = (Integer) value;
  336 + return int32ToShorts(intVal, order);
  337 + case FLOAT32:
  338 + float fVal = (Float) value;
  339 + return floatToShorts(fVal, order);
  340 + case DOUBLE64:
  341 + double dVal = (Double) value;
  342 + return doubleToShorts(dVal, order);
  343 + default:
  344 + throw new IllegalArgumentException("不支持的数据类型: " + dataType);
  345 + }
  346 + }
  347 +
  348 + // INT32 转 short[2]
  349 + private short[] int32ToShorts(int value, String order) {
  350 + short high = (short) ((value >> 16) & 0xFFFF);
  351 + short low = (short) (value & 0xFFFF);
  352 + if ("ABCD".equals(order)) return new short[]{high, low};
  353 + if ("BADC".equals(order)) return new short[]{(short)((high & 0xFF) << 8 | (high >> 8 & 0xFF)),
  354 + (short)((low & 0xFF) << 8 | (low >> 8 & 0xFF))};
  355 + if ("CDAB".equals(order)) return new short[]{low, high};
  356 + if ("DCBA".equals(order)) return new short[]{(short)((low & 0xFF) << 8 | (low >> 8 & 0xFF)),
  357 + (short)((high & 0xFF) << 8 | (high >> 8 & 0xFF))};
  358 + return new short[]{high, low};
  359 + }
  360 +
  361 + // FLOAT32 转 short[2]
  362 + private short[] floatToShorts(float f, String order) {
  363 + int bits = Float.floatToIntBits(f);
  364 + return int32ToShorts(bits, order);
  365 + }
  366 +
  367 + // DOUBLE64 转 short[4]
  368 + private short[] doubleToShorts(double d, String order) {
  369 + long bits = Double.doubleToLongBits(d);
  370 + short[] regs = new short[4];
  371 + regs[0] = (short)((bits >> 48) & 0xFFFF);
  372 + regs[1] = (short)((bits >> 32) & 0xFFFF);
  373 + regs[2] = (short)((bits >> 16) & 0xFFFF);
  374 + regs[3] = (short)(bits & 0xFFFF);
  375 +
  376 + switch (order) {
  377 + case "ABCD": return regs;
  378 + case "BADC": return new short[]{regs[1], regs[0], regs[3], regs[2]};
  379 + case "CDAB": return new short[]{regs[2], regs[3], regs[0], regs[1]};
  380 + case "DCBA": return new short[]{regs[3], regs[2], regs[1], regs[0]};
  381 + default: return regs;
  382 + }
  383 + }
  384 +
  385 +
302 } 386 }
1 package com.zhonglai.luhui.device.modbus.terminal.modbus; 1 package com.zhonglai.luhui.device.modbus.terminal.modbus;
2 2
3 -import com.alibaba.fastjson.JSONObject;  
4 import com.serotonin.modbus4j.ModbusFactory; 3 import com.serotonin.modbus4j.ModbusFactory;
5 import com.serotonin.modbus4j.ModbusMaster; 4 import com.serotonin.modbus4j.ModbusMaster;
6 -import com.serotonin.modbus4j.exception.ModbusInitException;  
7 -import com.serotonin.modbus4j.exception.ModbusTransportException; 5 +import com.alibaba.fastjson.JSONObject;
8 import com.serotonin.modbus4j.ip.IpParameters; 6 import com.serotonin.modbus4j.ip.IpParameters;
9 -import com.serotonin.modbus4j.msg.*; 7 +import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest;
  8 +import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
10 import com.zhonglai.luhui.device.modbus.terminal.config.InitPlcConfig; 9 import com.zhonglai.luhui.device.modbus.terminal.config.InitPlcConfig;
11 import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.CachPlcConfig; 10 import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.CachPlcConfig;
12 import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.JSerialCommWrapper; 11 import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.JSerialCommWrapper;
  12 +import org.slf4j.Logger;
  13 +import org.slf4j.LoggerFactory;
13 14
14 import java.io.File; 15 import java.io.File;
15 import java.util.concurrent.ConcurrentHashMap; 16 import java.util.concurrent.ConcurrentHashMap;
16 17
17 public class ModbusMasterMessage { 18 public class ModbusMasterMessage {
18 - /**  
19 - * 工厂  
20 - */  
21 - static ModbusFactory modbusFactory;  
22 - static {  
23 - if (modbusFactory == null) {  
24 - modbusFactory = new ModbusFactory();  
25 - }  
26 - }  
27 -  
28 - // 存储每个系统的 ModbusMaster 19 + private static final Logger log = LoggerFactory.getLogger(ModbusMasterMessage.class);
29 private static final ConcurrentHashMap<String, ModbusMaster> masterCache = new ConcurrentHashMap<>(); 20 private static final ConcurrentHashMap<String, ModbusMaster> masterCache = new ConcurrentHashMap<>();
30 - // 每个系统 ID 对应的锁对象  
31 private static final ConcurrentHashMap<String, Object> lockMap = new ConcurrentHashMap<>(); 21 private static final ConcurrentHashMap<String, Object> lockMap = new ConcurrentHashMap<>();
  22 + private static final ModbusFactory factory = new ModbusFactory();
32 23
33 -  
34 -  
35 - /**  
36 - * 创建或获取 ModbusMaster (线程安全)  
37 - */ 24 + /** 获取或创建 ModbusMaster,不做连接性检测 */
38 public static ModbusMaster getMaster(String id) throws Exception { 25 public static ModbusMaster getMaster(String id) throws Exception {
39 ModbusMaster master = masterCache.get(id); 26 ModbusMaster master = masterCache.get(id);
40 - if (master != null && master.isConnected()) { 27 + if (master != null) {
41 return master; 28 return master;
42 } 29 }
43 30
44 - // 获取该 ID 的专用锁 31 + // double-check locking 保证只创建一次
45 Object lock = lockMap.computeIfAbsent(id, k -> new Object()); 32 Object lock = lockMap.computeIfAbsent(id, k -> new Object());
46 -  
47 synchronized (lock) { 33 synchronized (lock) {
48 - // 双重检查,避免重复创建  
49 master = masterCache.get(id); 34 master = masterCache.get(id);
50 - if (master != null && master.isConnected()) {  
51 - return master;  
52 - }  
53 -  
54 - // 如果旧的存在但断开了,销毁  
55 - if (master != null) {  
56 - master.destroy(); 35 + if (master == null) {
  36 + CachPlcConfig config = InitPlcConfig.getPlcSystems(id);
  37 + if (config == null) {
  38 + throw new IllegalArgumentException("未找到PLC配置: " + id);
57 } 39 }
58 -  
59 - // 创建新 master  
60 - ModbusMaster newMaster = selectMaster(id);  
61 - newMaster.setIoLog(new MyIOLog(new File("/app/logs/modbus-" + id + ".log")));  
62 - newMaster.init();  
63 -  
64 - masterCache.put(id, newMaster);  
65 - return newMaster; 40 + master = createMaster(config);
  41 + master.setIoLog(new MyIOLog(new File("logs/modbus.log")));
  42 + master.init();
  43 + masterCache.put(id, master);
  44 + log.info("ModbusMaster[{}] 已创建", id);
66 } 45 }
67 } 46 }
68 -  
69 -  
70 - private static ModbusMaster selectMaster(String id) throws Exception {  
71 -  
72 - CachPlcConfig cachPlcConfig = InitPlcConfig.getPlcSystems(id);  
73 - if (null == cachPlcConfig)  
74 - {  
75 - throw new Exception("系统: " + id+" 未配置"); 47 + return master;
76 } 48 }
77 - JSONObject connectConfig = cachPlcConfig.getConnectConfig();  
78 49
79 - switch (cachPlcConfig.getProtocolType())  
80 - {  
81 - case RTU:  
82 - return modbusFactory.createRtuMaster(JSONObject.parseObject(connectConfig.toJSONString(),JSerialCommWrapper.class)); 50 + /**
  51 + * 创建 Master
  52 + */
  53 + private static ModbusMaster createMaster(CachPlcConfig config) throws Exception {
  54 + System.out.println("config:"+JSONObject.toJSONString(config));
  55 + JSONObject connectConfig = config.getConnectConfig();
  56 + switch (config.getProtocolType()) {
83 case TCP: 57 case TCP:
84 - return modbusFactory.createTcpMaster(JSONObject.parseObject(connectConfig.toJSONString(),IpParameters.class), true); //这里传的是 false → 表示短连接模式,每次用完连接就会关闭。 58 + IpParameters parameters = JSONObject.parseObject(connectConfig.toJSONString(), IpParameters.class);
  59 +// parameters.setEncapsulated(false);
  60 + return factory.createTcpMaster(parameters
  61 + , true);
  62 + case RTU:
  63 + return factory.createRtuMaster(
  64 + JSONObject.parseObject(connectConfig.toJSONString(), JSerialCommWrapper.class));
85 case ASCII: 65 case ASCII:
86 - return modbusFactory.createAsciiMaster(JSONObject.parseObject(connectConfig.toJSONString(),JSerialCommWrapper.class)); 66 + return factory.createAsciiMaster(
  67 + JSONObject.parseObject(connectConfig.toJSONString(), JSerialCommWrapper.class));
87 case UDP: 68 case UDP:
88 - return modbusFactory.createUdpMaster(JSONObject.parseObject(connectConfig.toJSONString(),IpParameters.class)); 69 + return factory.createUdpMaster(
  70 + JSONObject.parseObject(connectConfig.toJSONString(), IpParameters.class));
89 default: 71 default:
90 - throw new Exception("系统: " + id+" 不支持的协议"); 72 + throw new Exception("不支持协议");
91 } 73 }
92 } 74 }
93 75
94 /** 76 /**
95 - * 关闭指定系统的 Master 77 + * 关闭 Master
96 */ 78 */
97 public static void closeMaster(String id) { 79 public static void closeMaster(String id) {
98 Object lock = lockMap.computeIfAbsent(id, k -> new Object()); 80 Object lock = lockMap.computeIfAbsent(id, k -> new Object());
99 synchronized (lock) { 81 synchronized (lock) {
100 ModbusMaster master = masterCache.remove(id); 82 ModbusMaster master = masterCache.remove(id);
101 - if (master != null) {  
102 - master.destroy();  
103 - } 83 + if (master != null) master.destroy();
104 lockMap.remove(id); 84 lockMap.remove(id);
105 } 85 }
106 } 86 }
@@ -114,3 +94,4 @@ public class ModbusMasterMessage { @@ -114,3 +94,4 @@ public class ModbusMasterMessage {
114 lockMap.clear(); 94 lockMap.clear();
115 } 95 }
116 } 96 }
  97 +
1 { 1 {
2 "cameras": [ 2 "cameras": [
3 { 3 {
4 - "id": "G28890297",  
5 - "connectConfig": {"pass": "WQMJWP"} 4 + "id": "FW8199460",
  5 + "connectConfig": {"pass": "Luhui586"}
6 } 6 }
7 ], 7 ],
8 "plcs": [ 8 "plcs": [
9 { 9 {
10 - "id": "2_6",  
11 - "systemName": "测试",  
12 - "protocolType": "TCP",  
13 - "connectConfig": { "host": "192.168.1.82", "port": 2000},  
14 - "points": [  
15 - {"name": "水泵1故障", "system": "sb1gz", "address": "40001.01", "dataType": "bit","access":"r"},  
16 - {"name": "水泵2故障", "system": "sb2gz", "address": "40001.02", "dataType": "bit","access":"r"},  
17 - {"name": "氧锥泵1故障", "system": "yzb1gz", "address": "40001.03", "dataType": "bit","access":"r"},  
18 - {"name": "氧锥泵2故障", "system": "yzb2gz", "address": "40001.04", "dataType": "bit","access":"r"},  
19 - {"name": "氧锥泵3故障", "system": "yzb3gz", "address": "40001.05", "dataType": "bit","access":"r"},  
20 - {"name": "氧锥泵4故障", "system": "yzb4gz", "address": "40001.06", "dataType": "bit","access":"r"},  
21 - {"name": "排污泵故障", "system": "pwb_gz", "address": "40001.07", "dataType": "bit","access":"r"},  
22 - {"name": "排污阀1开不到位", "system": "pwf1kbdw", "address": "40001.09", "dataType": "bit","access":"r"},  
23 - {"name": "溶氧上限报警设定值", "system": "ry_sxsz", "address": "40053-40054", "dataType": "float32","order": "ABCD","access":"rw"},  
24 - {"name": "溶氧下限报警设定值", "system": "ry_xxsz", "address": "40055-40056", "dataType": "float32","order": "ABCD","access":"rw"}  
25 - ]  
26 - },  
27 - {  
28 "id": "2_1", 10 "id": "2_1",
29 "systemName": "成鱼系统1", 11 "systemName": "成鱼系统1",
30 "protocolType": "TCP", 12 "protocolType": "TCP",
31 - "connectConfig": { "host": "192.168.2.11", "port": 2000}, 13 + "connectConfig": { "host": "192.168.2.11", "port": 2010},
32 "points": [ 14 "points": [
33 {"name": "自动", "system": "zd", "address": "10001", "dataType": "bit"}, 15 {"name": "自动", "system": "zd", "address": "10001", "dataType": "bit"},
34 {"name": "远程", "system": "yc", "address": "10002", "dataType": "bit"}, 16 {"name": "远程", "system": "yc", "address": "10002", "dataType": "bit"},
@@ -94,7 +76,7 @@ @@ -94,7 +76,7 @@
94 {"name": "溶氧值", "system": "ryz", "address": "40003-40004","order": "ABCD", "dataType": "float32"}, 76 {"name": "溶氧值", "system": "ryz", "address": "40003-40004","order": "ABCD", "dataType": "float32"},
95 {"name": "温度值", "system": "wdz", "address": "40005-40006","order": "ABCD", "dataType": "float32"}, 77 {"name": "温度值", "system": "wdz", "address": "40005-40006","order": "ABCD", "dataType": "float32"},
96 {"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float32"}, 78 {"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float32"},
97 - {"name": "当前氧锥泵运行台数", "system": "dqyzb", "address": "40009", "dataType": "int16"}, 79 + {"name": "当前氧锥泵运行台数", "system": "dqyzb", "address": "40009", "dataType": "int"},
98 {"name": "氧锥泵1运行时间", "system": "yzb1_sj", "address": "40011-40012","order": "ABCD", "dataType": "int32"}, 80 {"name": "氧锥泵1运行时间", "system": "yzb1_sj", "address": "40011-40012","order": "ABCD", "dataType": "int32"},
99 {"name": "氧锥泵2运行时间", "system": "yzb2_sj", "address": "40013-40014","order": "ABCD", "dataType": "int32"}, 81 {"name": "氧锥泵2运行时间", "system": "yzb2_sj", "address": "40013-40014","order": "ABCD", "dataType": "int32"},
100 {"name": "氧锥泵3运行时间", "system": "yzb3_sj", "address": "40015-40016","order": "ABCD", "dataType": "int32"}, 82 {"name": "氧锥泵3运行时间", "system": "yzb3_sj", "address": "40015-40016","order": "ABCD", "dataType": "int32"},
@@ -103,30 +85,33 @@ @@ -103,30 +85,33 @@
103 {"name": "循环水泵故障", "system": "xhsb_gz", "address": "40021.01", "dataType": "bit"}, 85 {"name": "循环水泵故障", "system": "xhsb_gz", "address": "40021.01", "dataType": "bit"},
104 {"name": "生化池水温低限报警", "system": "shcsw_dx_bj", "address": "40021.02", "dataType": "bit"}, 86 {"name": "生化池水温低限报警", "system": "shcsw_dx_bj", "address": "40021.02", "dataType": "bit"},
105 {"name": "生化池水温高限报警", "system": "shcsw_gx_bj", "address": "40021.03", "dataType": "bit"}, 87 {"name": "生化池水温高限报警", "system": "shcsw_gx_bj", "address": "40021.03", "dataType": "bit"},
106 - {"name": "排污阀1开OR关", "system": "pwf1_or", "address": "40051.01", "dataType": "bit"},  
107 - {"name": "排污阀2开OR关", "system": "pwf2_or", "address": "40051.02", "dataType": "bit"},  
108 - {"name": "排污阀3开OR关", "system": "pwf3_or", "address": "40051.03", "dataType": "bit"},  
109 - {"name": "排污阀4开OR关", "system": "pwf4_or", "address": "40051.04", "dataType": "bit"},  
110 - {"name": "排污阀5开OR关", "system": "pwf5_or", "address": "40051.05", "dataType": "bit"},  
111 - {"name": "排污阀6开OR关", "system": "pwf6_or", "address": "40051.06", "dataType": "bit"},  
112 - {"name": "排污阀7开OR关", "system": "pwf7_or", "address": "40051.07", "dataType": "bit"},  
113 - {"name": "排污阀8开OR关", "system": "pwf8_or", "address": "40051.08", "dataType": "bit"},  
114 - {"name": "水泵1启动", "system": "sb1start", "address": "40051.09", "dataType": "bit"},  
115 - {"name": "水泵2启动", "system": "sb2start", "address": "40051.10", "dataType": "bit"},  
116 - {"name": "氧锥泵1启动", "system": "yzb1_qd", "address": "40051.11", "dataType": "bit"},  
117 - {"name": "氧锥泵2启动", "system": "yzb2_qd", "address": "40051.12", "dataType": "bit"},  
118 - {"name": "氧锥泵3启动", "system": "yzb3_qd", "address": "40051.13", "dataType": "bit"},  
119 - {"name": "氧锥泵4启动", "system": "yzb4_qd", "address": "40051.14", "dataType": "bit"},  
120 - {"name": "排污泵启动", "system": "pwb_qd", "address": "40051.15", "dataType": "bit"},  
121 - {"name": "水泵1停止", "system": "sb1stop", "address": "40052.01", "dataType": "bit"},  
122 - {"name": "水泵2停止", "system": "sb2stop", "address": "40052.02", "dataType": "bit"},  
123 - {"name": "氧锥泵1停止", "system": "yzb1_tz", "address": "40052.03", "dataType": "bit"},  
124 - {"name": "氧锥泵2停止", "system": "yzb2_tz", "address": "40052.04", "dataType": "bit"},  
125 - {"name": "氧锥泵3停止", "system": "yzb3_tz", "address": "40052.05", "dataType": "bit"},  
126 - {"name": "氧锥泵4停止", "system": "yzb4_tz", "address": "40052.06", "dataType": "bit"},  
127 - {"name": "排污泵停止", "system": "pwb_tz", "address": "40052.07", "dataType": "bit"},  
128 - {"name": "清报警", "system": "qbj", "address": "40052.09", "dataType": "bit"},  
129 - {"name": "累计时间清零", "system": "ljtq", "address": "40052.10", "dataType": "bit"}, 88 + {"name": "排污阀1开OR关", "system": "pwf1_or", "address": "40051.09", "dataType": "bit"},
  89 + {"name": "排污阀2开OR关", "system": "pwf2_or", "address": "40051.10", "dataType": "bit"},
  90 + {"name": "排污阀3开OR关", "system": "pwf3_or", "address": "40051.11", "dataType": "bit"},
  91 + {"name": "排污阀4开OR关", "system": "pwf4_or", "address": "40051.12", "dataType": "bit"},
  92 + {"name": "排污阀5开OR关", "system": "pwf5_or", "address": "40051.13", "dataType": "bit"},
  93 + {"name": "排污阀6开OR关", "system": "pwf6_or", "address": "40051.14", "dataType": "bit"},
  94 + {"name": "排污阀7开OR关", "system": "pwf7_or", "address": "40051.15", "dataType": "bit"},
  95 + {"name": "排污阀8开OR关", "system": "pwf8_or", "address": "40051.16", "dataType": "bit"},
  96 +
  97 + {"name": "水泵1启动", "system": "sb1start", "address": "40051.01", "dataType": "bit"},
  98 + {"name": "水泵2启动", "system": "sb2start", "address": "40051.02", "dataType": "bit"},
  99 + {"name": "氧锥泵1启动", "system": "yzb1_qd", "address": "40051.03", "dataType": "bit"},
  100 + {"name": "氧锥泵2启动", "system": "yzb2_qd", "address": "40051.04", "dataType": "bit"},
  101 + {"name": "氧锥泵3启动", "system": "yzb3_qd", "address": "40051.05", "dataType": "bit"},
  102 + {"name": "氧锥泵4启动", "system": "yzb4_qd", "address": "40051.06", "dataType": "bit"},
  103 + {"name": "排污泵启动", "system": "pwb_qd", "address": "40051.07", "dataType": "bit"},
  104 +
  105 + {"name": "水泵1停止", "system": "sb1stop", "address": "40052.09", "dataType": "bit"},
  106 + {"name": "水泵2停止", "system": "sb2stop", "address": "40052.10", "dataType": "bit"},
  107 + {"name": "氧锥泵1停止", "system": "yzb1_tz", "address": "40052.11", "dataType": "bit"},
  108 + {"name": "氧锥泵2停止", "system": "yzb2_tz", "address": "40052.12", "dataType": "bit"},
  109 + {"name": "氧锥泵3停止", "system": "yzb3_tz", "address": "40052.13", "dataType": "bit"},
  110 + {"name": "氧锥泵4停止", "system": "yzb4_tz", "address": "40052.14", "dataType": "bit"},
  111 + {"name": "排污泵停止", "system": "pwb_tz", "address": "40052.15", "dataType": "bit"},
  112 +
  113 + {"name": "清报警", "system": "qbj", "address": "40052.01", "dataType": "bit"},
  114 + {"name": "累计时间清零", "system": "ljtq", "address": "40052.02", "dataType": "bit"},
130 {"name": "溶氧上限报警设定值", "system": "rysjup", "address": "40053-40054","order": "ABCD", "dataType": "float32"}, 115 {"name": "溶氧上限报警设定值", "system": "rysjup", "address": "40053-40054","order": "ABCD", "dataType": "float32"},
131 {"name": "溶氧下限报警设定值", "system": "rysjdown", "address": "40055-40056","order": "ABCD", "dataType": "float32"} 116 {"name": "溶氧下限报警设定值", "system": "rysjdown", "address": "40055-40056","order": "ABCD", "dataType": "float32"}
132 ] 117 ]
@@ -201,7 +186,7 @@ @@ -201,7 +186,7 @@
201 {"name": "溶氧值", "system": "ryz", "address": "40003-40004","order": "ABCD", "dataType": "float32"}, 186 {"name": "溶氧值", "system": "ryz", "address": "40003-40004","order": "ABCD", "dataType": "float32"},
202 {"name": "温度值", "system": "wdz", "address": "40005-40006","order": "ABCD", "dataType": "float32"}, 187 {"name": "温度值", "system": "wdz", "address": "40005-40006","order": "ABCD", "dataType": "float32"},
203 {"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float32"}, 188 {"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float32"},
204 - {"name": "当前氧锥泵运行台数", "system": "dqyzb", "address": "40009", "dataType": "int16"}, 189 + {"name": "当前氧锥泵运行台数", "system": "dqyzb", "address": "40009", "dataType": "int"},
205 {"name": "氧锥泵1运行时间", "system": "yzb1_sj", "address": "40011-40012","order": "ABCD", "dataType": "int32"}, 190 {"name": "氧锥泵1运行时间", "system": "yzb1_sj", "address": "40011-40012","order": "ABCD", "dataType": "int32"},
206 {"name": "氧锥泵2运行时间", "system": "yzb2_sj", "address": "40013-40014","order": "ABCD", "dataType": "int32"}, 191 {"name": "氧锥泵2运行时间", "system": "yzb2_sj", "address": "40013-40014","order": "ABCD", "dataType": "int32"},
207 {"name": "氧锥泵3运行时间", "system": "yzb3_sj", "address": "40015-40016","order": "ABCD", "dataType": "int32"}, 192 {"name": "氧锥泵3运行时间", "system": "yzb3_sj", "address": "40015-40016","order": "ABCD", "dataType": "int32"},
@@ -210,30 +195,33 @@ @@ -210,30 +195,33 @@
210 {"name": "循环水泵故障", "system": "xhsb_gz", "address": "40021.01", "dataType": "bit"}, 195 {"name": "循环水泵故障", "system": "xhsb_gz", "address": "40021.01", "dataType": "bit"},
211 {"name": "生化池水温低限报警", "system": "shcsw_dx_bj", "address": "40021.02", "dataType": "bit"}, 196 {"name": "生化池水温低限报警", "system": "shcsw_dx_bj", "address": "40021.02", "dataType": "bit"},
212 {"name": "生化池水温高限报警", "system": "shcsw_gx_bj", "address": "40021.03", "dataType": "bit"}, 197 {"name": "生化池水温高限报警", "system": "shcsw_gx_bj", "address": "40021.03", "dataType": "bit"},
213 - {"name": "排污阀1开OR关", "system": "pwf1_or", "address": "40051.01", "dataType": "bit"},  
214 - {"name": "排污阀2开OR关", "system": "pwf2_or", "address": "40051.02", "dataType": "bit"},  
215 - {"name": "排污阀3开OR关", "system": "pwf3_or", "address": "40051.03", "dataType": "bit"},  
216 - {"name": "排污阀4开OR关", "system": "pwf4_or", "address": "40051.04", "dataType": "bit"},  
217 - {"name": "排污阀5开OR关", "system": "pwf5_or", "address": "40051.05", "dataType": "bit"},  
218 - {"name": "排污阀6开OR关", "system": "pwf6_or", "address": "40051.06", "dataType": "bit"},  
219 - {"name": "排污阀7开OR关", "system": "pwf7_or", "address": "40051.07", "dataType": "bit"},  
220 - {"name": "排污阀8开OR关", "system": "pwf8_or", "address": "40051.08", "dataType": "bit"},  
221 - {"name": "水泵1启动", "system": "sb1start", "address": "40051.09", "dataType": "bit"},  
222 - {"name": "水泵2启动", "system": "sb2start", "address": "40051.10", "dataType": "bit"},  
223 - {"name": "氧锥泵1启动", "system": "yzb1_qd", "address": "40051.11", "dataType": "bit"},  
224 - {"name": "氧锥泵2启动", "system": "yzb2_qd", "address": "40051.12", "dataType": "bit"},  
225 - {"name": "氧锥泵3启动", "system": "yzb3_qd", "address": "40051.13", "dataType": "bit"},  
226 - {"name": "氧锥泵4启动", "system": "yzb4_qd", "address": "40051.14", "dataType": "bit"},  
227 - {"name": "排污泵启动", "system": "pwb_qd", "address": "40051.15", "dataType": "bit"},  
228 - {"name": "水泵1停止", "system": "sb1stop", "address": "40052.01", "dataType": "bit"},  
229 - {"name": "水泵2停止", "system": "sb2stop", "address": "40052.02", "dataType": "bit"},  
230 - {"name": "氧锥泵1停止", "system": "yzb1_tz", "address": "40052.03", "dataType": "bit"},  
231 - {"name": "氧锥泵2停止", "system": "yzb2_tz", "address": "40052.04", "dataType": "bit"},  
232 - {"name": "氧锥泵3停止", "system": "yzb3_tz", "address": "40052.05", "dataType": "bit"},  
233 - {"name": "氧锥泵4停止", "system": "yzb4_tz", "address": "40052.06", "dataType": "bit"},  
234 - {"name": "排污泵停止", "system": "pwb_tz", "address": "40052.07", "dataType": "bit"},  
235 - {"name": "清报警", "system": "qbj", "address": "40052.09", "dataType": "bit"},  
236 - {"name": "累计时间清零", "system": "ljtq", "address": "40052.10", "dataType": "bit"}, 198 + {"name": "排污阀1开OR关", "system": "pwf1_or", "address": "40051.09", "dataType": "bit"},
  199 + {"name": "排污阀2开OR关", "system": "pwf2_or", "address": "40051.10", "dataType": "bit"},
  200 + {"name": "排污阀3开OR关", "system": "pwf3_or", "address": "40051.11", "dataType": "bit"},
  201 + {"name": "排污阀4开OR关", "system": "pwf4_or", "address": "40051.12", "dataType": "bit"},
  202 + {"name": "排污阀5开OR关", "system": "pwf5_or", "address": "40051.13", "dataType": "bit"},
  203 + {"name": "排污阀6开OR关", "system": "pwf6_or", "address": "40051.14", "dataType": "bit"},
  204 + {"name": "排污阀7开OR关", "system": "pwf7_or", "address": "40051.15", "dataType": "bit"},
  205 + {"name": "排污阀8开OR关", "system": "pwf8_or", "address": "40051.16", "dataType": "bit"},
  206 +
  207 + {"name": "水泵1启动", "system": "sb1start", "address": "40051.01", "dataType": "bit"},
  208 + {"name": "水泵2启动", "system": "sb2start", "address": "40051.02", "dataType": "bit"},
  209 + {"name": "氧锥泵1启动", "system": "yzb1_qd", "address": "40051.03", "dataType": "bit"},
  210 + {"name": "氧锥泵2启动", "system": "yzb2_qd", "address": "40051.04", "dataType": "bit"},
  211 + {"name": "氧锥泵3启动", "system": "yzb3_qd", "address": "40051.05", "dataType": "bit"},
  212 + {"name": "氧锥泵4启动", "system": "yzb4_qd", "address": "40051.06", "dataType": "bit"},
  213 + {"name": "排污泵启动", "system": "pwb_qd", "address": "40051.07", "dataType": "bit"},
  214 +
  215 + {"name": "水泵1停止", "system": "sb1stop", "address": "40052.09", "dataType": "bit"},
  216 + {"name": "水泵2停止", "system": "sb2stop", "address": "40052.10", "dataType": "bit"},
  217 + {"name": "氧锥泵1停止", "system": "yzb1_tz", "address": "40052.11", "dataType": "bit"},
  218 + {"name": "氧锥泵2停止", "system": "yzb2_tz", "address": "40052.12", "dataType": "bit"},
  219 + {"name": "氧锥泵3停止", "system": "yzb3_tz", "address": "40052.13", "dataType": "bit"},
  220 + {"name": "氧锥泵4停止", "system": "yzb4_tz", "address": "40052.14", "dataType": "bit"},
  221 + {"name": "排污泵停止", "system": "pwb_tz", "address": "40052.15", "dataType": "bit"},
  222 +
  223 + {"name": "清报警", "system": "qbj", "address": "40052.01", "dataType": "bit"},
  224 + {"name": "累计时间清零", "system": "ljtq", "address": "40052.02", "dataType": "bit"},
237 {"name": "溶氧上限报警设定值", "system": "rysjup", "address": "40053-40054","order": "ABCD", "dataType": "float32"}, 225 {"name": "溶氧上限报警设定值", "system": "rysjup", "address": "40053-40054","order": "ABCD", "dataType": "float32"},
238 {"name": "溶氧下限报警设定值", "system": "rysjdown", "address": "40055-40056","order": "ABCD", "dataType": "float32"} 226 {"name": "溶氧下限报警设定值", "system": "rysjdown", "address": "40055-40056","order": "ABCD", "dataType": "float32"}
239 ] 227 ]
@@ -272,18 +260,18 @@ @@ -272,18 +260,18 @@
272 {"name": "风机1运行时间", "system": "fj1t", "address": "40017-40018","order": "ABCD", "dataType": "long"}, 260 {"name": "风机1运行时间", "system": "fj1t", "address": "40017-40018","order": "ABCD", "dataType": "long"},
273 {"name": "风机2运行时间", "system": "fj2t", "address": "40019-40020","order": "ABCD", "dataType": "long"}, 261 {"name": "风机2运行时间", "system": "fj2t", "address": "40019-40020","order": "ABCD", "dataType": "long"},
274 262
275 - {"name": "水源泵1启动", "system": "syp1s", "address": "40051.01", "dataType": "bit"},  
276 - {"name": "水源泵2启动", "system": "syp2s", "address": "40051.02", "dataType": "bit"},  
277 - {"name": "水源泵3启动", "system": "syp3s", "address": "40051.03", "dataType": "bit"},  
278 - {"name": "风机1启动", "system": "fj1s", "address": "40051.04", "dataType": "bit"},  
279 - {"name": "风机2启动", "system": "fj2s", "address": "40051.05", "dataType": "bit"},  
280 - {"name": "水源泵1停止", "system": "syp1t", "address": "40051.09", "dataType": "bit"},  
281 - {"name": "水源泵2停止", "system": "syp2t", "address": "40051.10", "dataType": "bit"},  
282 - {"name": "水源泵3停止", "system": "syp3t", "address": "40051.11", "dataType": "bit"},  
283 - {"name": "风机1停止", "system": "fj1p", "address": "40051.12", "dataType": "bit"},  
284 - {"name": "风机2停止", "system": "fj2p", "address": "40051.13", "dataType": "bit"},  
285 - {"name": "清报警", "system": "qbj", "address": "40052.01", "dataType": "bit"},  
286 - {"name": "累计时间清零", "system": "ljtq", "address": "40052.02", "dataType": "bit"} 263 + {"name": "水源泵1启动", "system": "syp1s", "address": "40051.09", "dataType": "bit"},
  264 + {"name": "水源泵2启动", "system": "syp2s", "address": "40051.10", "dataType": "bit"},
  265 + {"name": "水源泵3启动", "system": "syp3s", "address": "40051.11", "dataType": "bit"},
  266 + {"name": "风机1启动", "system": "fj1s", "address": "40051.12", "dataType": "bit"},
  267 + {"name": "风机2启动", "system": "fj2s", "address": "40051.13", "dataType": "bit"},
  268 + {"name": "水源泵1停止", "system": "syp1t", "address": "40051.01", "dataType": "bit"},
  269 + {"name": "水源泵2停止", "system": "syp2t", "address": "40051.02", "dataType": "bit"},
  270 + {"name": "水源泵3停止", "system": "syp3t", "address": "40051.03", "dataType": "bit"},
  271 + {"name": "风机1停止", "system": "fj1p", "address": "40051.04", "dataType": "bit"},
  272 + {"name": "风机2停止", "system": "fj2p", "address": "40051.05", "dataType": "bit"},
  273 + {"name": "清报警", "system": "qbj", "address": "40052.09", "dataType": "bit"},
  274 + {"name": "累计时间清零", "system": "ljtq", "address": "40052.10", "dataType": "bit"}
287 ] 275 ]
288 }, 276 },
289 { 277 {
@@ -325,23 +313,23 @@ @@ -325,23 +313,23 @@
325 {"name": "溶氧值", "system": "ryz", "address": "40003-40004","order": "ABCD", "dataType": "float32"}, 313 {"name": "溶氧值", "system": "ryz", "address": "40003-40004","order": "ABCD", "dataType": "float32"},
326 {"name": "温度值", "system": "wdz", "address": "40005-40006","order": "ABCD", "dataType": "float32"}, 314 {"name": "温度值", "system": "wdz", "address": "40005-40006","order": "ABCD", "dataType": "float32"},
327 {"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float32"}, 315 {"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float32"},
328 - {"name": "当前风机运行台数", "system": "dqfj", "address": "40009", "dataType": "int32"}, 316 + {"name": "当前风机运行台数", "system": "dqfj", "address": "40009", "dataType": "int"},
329 {"name": "风机1运行时间", "system": "fj1t", "address": "40011-40012","order": "ABCD", "dataType": "long"}, 317 {"name": "风机1运行时间", "system": "fj1t", "address": "40011-40012","order": "ABCD", "dataType": "long"},
330 {"name": "风机2运行时间", "system": "fj2t", "address": "40013-40014","order": "ABCD", "dataType": "long"}, 318 {"name": "风机2运行时间", "system": "fj2t", "address": "40013-40014","order": "ABCD", "dataType": "long"},
331 319
332 - {"name": "水泵1启动", "system": "sb1start", "address": "40051.01", "dataType": "bit"},  
333 - {"name": "水泵2启动", "system": "sb2start", "address": "40051.02", "dataType": "bit"},  
334 - {"name": "风机1启动", "system": "fj1s", "address": "40051.03", "dataType": "bit"},  
335 - {"name": "风机2启动", "system": "fj2s", "address": "40051.04", "dataType": "bit"},  
336 - {"name": "补水泵3启动", "system": "bsb3s", "address": "40051.05", "dataType": "bit"},  
337 - {"name": "水泵1停止", "system": "sb1stop", "address": "40051.09", "dataType": "bit"},  
338 - {"name": "水泵2停止", "system": "sb2stop", "address": "40051.10", "dataType": "bit"},  
339 - {"name": "风机1停止", "system": "fj1p", "address": "40051.11", "dataType": "bit"},  
340 - {"name": "风机2停止", "system": "fj2p", "address": "40051.12", "dataType": "bit"},  
341 - {"name": "补水泵3停止", "system": "bsb3p", "address": "40051.13", "dataType": "bit"}, 320 + {"name": "水泵1启动", "system": "sb1start", "address": "40051.09", "dataType": "bit"},
  321 + {"name": "水泵2启动", "system": "sb2start", "address": "40051.10", "dataType": "bit"},
  322 + {"name": "风机1启动", "system": "fj1s", "address": "40051.11", "dataType": "bit"},
  323 + {"name": "风机2启动", "system": "fj2s", "address": "40051.12", "dataType": "bit"},
  324 + {"name": "补水泵3启动", "system": "bsb3s", "address": "40051.13", "dataType": "bit"},
  325 + {"name": "水泵1停止", "system": "sb1stop", "address": "40051.01", "dataType": "bit"},
  326 + {"name": "水泵2停止", "system": "sb2stop", "address": "40051.02", "dataType": "bit"},
  327 + {"name": "风机1停止", "system": "fj1p", "address": "40051.03", "dataType": "bit"},
  328 + {"name": "风机2停止", "system": "fj2p", "address": "40051.04", "dataType": "bit"},
  329 + {"name": "补水泵3停止", "system": "bsb3p", "address": "40051.05", "dataType": "bit"},
342 330
343 - {"name": "清报警", "system": "qbj", "address": "40052.01", "dataType": "bit"},  
344 - {"name": "累计时间清零", "system": "ljtq", "address": "40052.02", "dataType": "bit"}, 331 + {"name": "清报警", "system": "qbj", "address": "40052.09", "dataType": "bit"},
  332 + {"name": "累计时间清零", "system": "ljtq", "address": "40052.10", "dataType": "bit"},
345 333
346 {"name": "溶氧上限报警设定值", "system": "rysjup", "address": "40053-40054","order": "ABCD", "dataType": "float32"}, 334 {"name": "溶氧上限报警设定值", "system": "rysjup", "address": "40053-40054","order": "ABCD", "dataType": "float32"},
347 {"name": "溶氧下限报警设定值", "system": "rysjdown", "address": "40055-40056","order": "ABCD", "dataType": "float32"} 335 {"name": "溶氧下限报警设定值", "system": "rysjdown", "address": "40055-40056","order": "ABCD", "dataType": "float32"}
@@ -351,7 +339,7 @@ @@ -351,7 +339,7 @@
351 "id": "2_5", 339 "id": "2_5",
352 "systemName": "设备房系统", 340 "systemName": "设备房系统",
353 "protocolType": "TCP", 341 "protocolType": "TCP",
354 - "connectConfig": { "host": "192.168.2.3", "port": 2003}, 342 + "connectConfig": { "host": "127.0.0.1", "port": 2003},
355 "points": [ 343 "points": [
356 {"name": "自动", "system": "zd", "address": "10001", "dataType": "bit"}, 344 {"name": "自动", "system": "zd", "address": "10001", "dataType": "bit"},
357 {"name": "远程", "system": "yc", "address": "10002", "dataType": "bit"}, 345 {"name": "远程", "system": "yc", "address": "10002", "dataType": "bit"},
@@ -393,22 +381,22 @@ @@ -393,22 +381,22 @@
393 {"name": "风机3运行时间", "system": "fj3t", "address": "40015-40016","order": "ABCD", "dataType": "long"}, 381 {"name": "风机3运行时间", "system": "fj3t", "address": "40015-40016","order": "ABCD", "dataType": "long"},
394 {"name": "风机4运行时间", "system": "fj4t", "address": "40017-40018","order": "ABCD", "dataType": "long"}, 382 {"name": "风机4运行时间", "system": "fj4t", "address": "40017-40018","order": "ABCD", "dataType": "long"},
395 383
396 - {"name": "补水阀1开OR关", "system": "bsf1c", "address": "40051.01", "dataType": "bit"},  
397 - {"name": "补水阀2开OR关", "system": "bsf2c", "address": "40051.02", "dataType": "bit"},  
398 - {"name": "风机1启动", "system": "fj1s", "address": "40051.09", "dataType": "bit"},  
399 - {"name": "风机2启动", "system": "fj2s", "address": "40051.10", "dataType": "bit"},  
400 - {"name": "风机3启动", "system": "fj3s", "address": "40051.11", "dataType": "bit"},  
401 - {"name": "风机4启动", "system": "fj4s", "address": "40051.12", "dataType": "bit"},  
402 - {"name": "补水泵1启动", "system": "bsb1s", "address": "40051.13", "dataType": "bit"},  
403 - {"name": "补水泵2启动", "system": "bsb2s", "address": "40051.14", "dataType": "bit"},  
404 - {"name": "风机1停止", "system": "fj1p", "address": "40052.01", "dataType": "bit"},  
405 - {"name": "风机2停止", "system": "fj2p", "address": "40052.02", "dataType": "bit"},  
406 - {"name": "风机3停止", "system": "fj3p", "address": "40052.03", "dataType": "bit"},  
407 - {"name": "风机4停止", "system": "fj4p", "address": "40052.04", "dataType": "bit"},  
408 - {"name": "补水泵1停止", "system": "bsb1p", "address": "40052.05", "dataType": "bit"},  
409 - {"name": "补水泵2停止", "system": "bsb2p", "address": "40052.06", "dataType": "bit"},  
410 - {"name": "清报警", "system": "qbj", "address": "40052.09", "dataType": "bit"},  
411 - {"name": "累计时间清零", "system": "ljtq", "address": "40052.10", "dataType": "bit"} 384 + {"name": "补水阀1开OR关", "system": "bsf1c", "address": "40051.09", "dataType": "bit"},
  385 + {"name": "补水阀2开OR关", "system": "bsf2c", "address": "40051.10", "dataType": "bit"},
  386 + {"name": "风机1启动", "system": "fj1s", "address": "40051.01", "dataType": "bit"},
  387 + {"name": "风机2启动", "system": "fj2s", "address": "40051.02", "dataType": "bit"},
  388 + {"name": "风机3启动", "system": "fj3s", "address": "40051.03", "dataType": "bit"},
  389 + {"name": "风机4启动", "system": "fj4s", "address": "40051.04", "dataType": "bit"},
  390 + {"name": "补水泵1启动", "system": "bsb1s", "address": "40051.05", "dataType": "bit"},
  391 + {"name": "补水泵2启动", "system": "bsb2s", "address": "40051.06", "dataType": "bit"},
  392 + {"name": "风机1停止", "system": "fj1p", "address": "40052.09", "dataType": "bit"},
  393 + {"name": "风机2停止", "system": "fj2p", "address": "40052.10", "dataType": "bit"},
  394 + {"name": "风机3停止", "system": "fj3p", "address": "40052.11", "dataType": "bit"},
  395 + {"name": "风机4停止", "system": "fj4p", "address": "40052.12", "dataType": "bit"},
  396 + {"name": "补水泵1停止", "system": "bsb1p", "address": "40052.13", "dataType": "bit"},
  397 + {"name": "补水泵2停止", "system": "bsb2p", "address": "40052.14", "dataType": "bit"},
  398 + {"name": "清报警", "system": "qbj", "address": "40052.01", "dataType": "bit"},
  399 + {"name": "累计时间清零", "system": "ljtq", "address": "40052.02", "dataType": "bit"}
412 ] 400 ]
413 } 401 }
414 ] 402 ]
1 import com.alibaba.fastjson.JSONObject; 1 import com.alibaba.fastjson.JSONObject;
  2 +import com.serotonin.modbus4j.ModbusFactory;
  3 +import com.serotonin.modbus4j.ModbusMaster;
  4 +import com.serotonin.modbus4j.code.DataType;
  5 +import com.serotonin.modbus4j.ip.IpParameters;
  6 +import com.serotonin.modbus4j.locator.BaseLocator;
2 import com.zhonglai.luhui.device.modbus.terminal.config.InitPlcConfig; 7 import com.zhonglai.luhui.device.modbus.terminal.config.InitPlcConfig;
3 import com.zhonglai.luhui.device.modbus.terminal.modbus.Modbus4jRead; 8 import com.zhonglai.luhui.device.modbus.terminal.modbus.Modbus4jRead;
4 import com.zhonglai.luhui.device.modbus.terminal.modbus.Modbus4jWrite; 9 import com.zhonglai.luhui.device.modbus.terminal.modbus.Modbus4jWrite;
@@ -11,7 +16,7 @@ import java.util.Map; @@ -11,7 +16,7 @@ import java.util.Map;
11 16
12 public class TestModbus { 17 public class TestModbus {
13 public static void main(String[] args) throws Exception { 18 public static void main(String[] args) throws Exception {
14 - args = new String[]{"E:\\work\\idea\\Luhui\\lh-modules\\lh-device-modbus-terminal\\src\\main\\resources\\configs\\plcs.json","false","测试", "ry_sxsz=3.16","ry_xxsz=2.1"}; 19 + args = new String[]{"E:\\work\\idea\\Luhui\\lh-modules\\lh-device-modbus-terminal\\src\\main\\resources\\configs\\plcs.json","false","2_5", "fj1","fj4p=false"};
15 if (args.length < 2) { 20 if (args.length < 2) {
16 System.out.println("用法: java -jar modbus-app.jar <plcs.json路径> <点位名1> <点位名2> ..."); 21 System.out.println("用法: java -jar modbus-app.jar <plcs.json路径> <点位名1> <点位名2> ...");
17 return; 22 return;
@@ -42,27 +47,38 @@ public class TestModbus { @@ -42,27 +47,38 @@ public class TestModbus {
42 Map<String, Object> map = new Modbus4jRead(id).batchRead(plcPoints,zeroBasedAddress); 47 Map<String, Object> map = new Modbus4jRead(id).batchRead(plcPoints,zeroBasedAddress);
43 System.out.println(JSONObject.toJSONString(map)); 48 System.out.println(JSONObject.toJSONString(map));
44 } 49 }
45 - private static void testWrite(String[] args) throws Exception  
46 - { 50 + private static void testWrite(String[] args) throws Exception {
47 String jsonPath = args[0]; 51 String jsonPath = args[0];
48 - boolean zeroBasedAddress = new Boolean(args[1]); 52 + boolean zeroBasedAddress = Boolean.parseBoolean(args[1]);
49 String id = args[2]; 53 String id = args[2];
50 List<String> pointNames = Arrays.asList(Arrays.copyOfRange(args, 3, args.length)); 54 List<String> pointNames = Arrays.asList(Arrays.copyOfRange(args, 3, args.length));
51 55
  56 + // 初始化 PLC 配置
52 InitPlcConfig.initPlcConfigFromFile(jsonPath); 57 InitPlcConfig.initPlcConfigFromFile(jsonPath);
53 58
  59 + // 构建写入点列表
54 List<PlcPoint> plcPoints = new ArrayList<>(); 60 List<PlcPoint> plcPoints = new ArrayList<>();
55 - for (String pointName :pointNames)  
56 - { 61 + for (String pointName : pointNames) {
57 String[] pointNameArr = pointName.split("="); 62 String[] pointNameArr = pointName.split("=");
58 PlcPoint plcPoint = InitPlcConfig.getPlcSystem(id, pointNameArr[0]); 63 PlcPoint plcPoint = InitPlcConfig.getPlcSystem(id, pointNameArr[0]);
59 - if ( null != plcPoint)  
60 - { 64 + if (plcPoint != null) {
61 plcPoint.setValue(pointNameArr[1]); 65 plcPoint.setValue(pointNameArr[1]);
62 plcPoints.add(plcPoint); 66 plcPoints.add(plcPoint);
63 } 67 }
64 -  
65 } 68 }
66 - new Modbus4jWrite(id).batchWrite(plcPoints,zeroBasedAddress); 69 +
  70 + // 写入
  71 + Modbus4jWrite writer = new Modbus4jWrite(id);
  72 + writer.batchWrite(plcPoints, zeroBasedAddress);
  73 + System.out.println("写入完成");
  74 +
  75 + // 写入完成后稍微等待
  76 + Thread.sleep(100);
  77 +
  78 + // 读取刚才写入的点并打印
  79 + Modbus4jRead reader = new Modbus4jRead(id); // 假设有类似的读类
  80 + Map<String, Object> objectMap = reader.batchRead(plcPoints, zeroBasedAddress);
  81 + System.out.println("读取结果:"+JSONObject.toJSONString(objectMap));
67 } 82 }
  83 +
68 } 84 }