diff --git a/pom.xml b/pom.xml
index d8ccf78..efa8dd6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -166,6 +166,11 @@
sa-token-spring-boot3-starter
1.38.0
+
+ org.bouncycastle
+ bcprov-jdk15on
+ 1.70
+
com.infiniteautomation
modbus4j
diff --git a/src/main/java/com/isu/gaswellwatch/GasWellWatchApplication.java b/src/main/java/com/isu/gaswellwatch/GasWellWatchApplication.java
index 46c402e..b80fcc9 100644
--- a/src/main/java/com/isu/gaswellwatch/GasWellWatchApplication.java
+++ b/src/main/java/com/isu/gaswellwatch/GasWellWatchApplication.java
@@ -2,7 +2,9 @@ package com.isu.gaswellwatch;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+@EnableScheduling
@SpringBootApplication
public class GasWellWatchApplication {
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/PersistenceHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/PersistenceHandler.java
index 3b176ea..1c5efd0 100644
--- a/src/main/java/com/isu/gaswellwatch/modbus/data/PersistenceHandler.java
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/PersistenceHandler.java
@@ -10,7 +10,7 @@ public interface PersistenceHandler {
public static final String MODBUS_DEVICE_TYPE = "KNPCV1";
String DEVICE_DATA_CACHE = "data:device:";
- void createTable(String tableName);
+ void createTable(String tableName, Long deviceId);
void insert(String tableName, String cacheKey);
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/DecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/DecodeHandler.java
index 4d65ef9..070d73c 100644
--- a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/DecodeHandler.java
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/DecodeHandler.java
@@ -4,6 +4,8 @@ import com.isu.gaswellwatch.modbus.data.ModbusMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Map;
+
/**
* Modbus 数据解析器
*
@@ -14,6 +16,8 @@ public interface DecodeHandler {
Logger logger = LoggerFactory.getLogger("com.isu.gaswellwatch.decode");
- void decode(ModbusMessage.MessagePoint point);
+ String decode(Map commandPointMap, String value);
+
+ void decode(Map commandPointMap, ModbusMessage.MessagePoint point);
}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/FactorDecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/FactorDecodeHandler.java
new file mode 100644
index 0000000..7400676
--- /dev/null
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/FactorDecodeHandler.java
@@ -0,0 +1,51 @@
+package com.isu.gaswellwatch.modbus.data.decode.impl;
+
+import cn.hutool.core.map.MapUtil;
+import com.isu.gaswellwatch.modbus.data.ModbusMessage;
+import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Map;
+
+/**
+ * 乘除系数解析器
+ *
+ * 系数为正数时,采用除法
+ * - 例如:输入值:2580,系数(factor):100,精度(precision):2,输出值:2580 / 100 = 25.8
+ * 系数为负数时,采用乘法
+ * - 例如:输入值:2580,系数(factor):100,精度(precision):2,输出值:2580 * 100 = 258000
+ *
+ *
+ * @author 王仕龙
+ * 2024/11/24 21:23
+ */
+@Slf4j
+@SuppressWarnings("all")
+@Component("factorDecodeHandler")
+public class FactorDecodeHandler implements DecodeHandler {
+
+ @Override
+ public String decode(Map commandPointMap, String value) {
+ return value;
+ }
+
+ @Override
+ public void decode(Map commandPointMap, ModbusMessage.MessagePoint point) {
+ point.setValue(decode(commandPointMap, point.getParseValue()));
+ String factorStr = MapUtil.getStr(commandPointMap, "factor");
+ if (StringUtils.isNotBlank(factorStr) && StringUtils.isNotBlank(point.getParseValue())) {
+ BigDecimal factor = new BigDecimal(factorStr);
+ BigDecimal value = new BigDecimal(point.getParseValue());
+ int precision = MapUtil.getInt(commandPointMap, "precision", 0);
+ switch (factor.compareTo(BigDecimal.ZERO)) {
+ case -1 -> point.setValue(value.multiply(factor.abs()).toString());
+ case 1 -> point.setValue(value.divide(factor, precision, RoundingMode.HALF_UP).toString());
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/Knpcv1DecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/Knpcv1DecodeHandler.java
deleted file mode 100644
index 8c2394b..0000000
--- a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/Knpcv1DecodeHandler.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.isu.gaswellwatch.modbus.data.decode.impl;
-
-import com.isu.gaswellwatch.modbus.data.ModbusMessage;
-import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.stereotype.Component;
-
-/**
- * KNPCV1 柱塞器解析
- *
- * @author 王仕龙
- * 2024/11/23 11:23
- */
-@Slf4j
-@SuppressWarnings("all")
-@Component(Knpcv1DecodeHandler.MODBUS_DEVICE_TYPE + "_1")
-public class Knpcv1DecodeHandler implements DecodeHandler {
-
- public static final String MODBUS_DEVICE_TYPE = "KNPCV1";
- private static final String COMMAND_POINT_SQL = "select * from command_points where command_id = ?";
-
- @Resource
- private JdbcTemplate jdbcTemplate;
-
- @Resource(name = "redisTemplate")
- private RedisTemplate redisTemplate;
-
- @Override
- public void decode(ModbusMessage.MessagePoint point) {
-
- }
-
-}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/LocalDateDecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/LocalDateDecodeHandler.java
new file mode 100644
index 0000000..4b78c13
--- /dev/null
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/LocalDateDecodeHandler.java
@@ -0,0 +1,36 @@
+package com.isu.gaswellwatch.modbus.data.decode.impl;
+
+import com.isu.gaswellwatch.modbus.data.ModbusMessage;
+import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Map;
+
+/**
+ * 本地日期类型解析器
+ *
+ * @author 王仕龙
+ * 2024/11/25 11:51
+ */
+@Slf4j
+@SuppressWarnings("all")
+@Component("localDateDecodeHandler")
+public class LocalDateDecodeHandler implements DecodeHandler {
+ public static final DateTimeFormatter IN_FORMATTER = DateTimeFormatter.ofPattern("yyyy-M-d");
+ public static final DateTimeFormatter OUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+
+ @Override
+ public String decode(Map commandPointMap, String value) {
+ return LocalDate.parse(value, IN_FORMATTER).format(OUT_FORMATTER);
+ }
+
+ @Override
+ public void decode(Map commandPointMap, ModbusMessage.MessagePoint point) {
+ point.setValue(decode(commandPointMap, point.getParseValue()));
+ }
+
+}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/LocalDateTimeDecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/LocalDateTimeDecodeHandler.java
new file mode 100644
index 0000000..8c86993
--- /dev/null
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/LocalDateTimeDecodeHandler.java
@@ -0,0 +1,36 @@
+package com.isu.gaswellwatch.modbus.data.decode.impl;
+
+import com.isu.gaswellwatch.modbus.data.ModbusMessage;
+import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Map;
+
+/**
+ * 本地日期时间类型解析器
+ *
+ * @author 王仕龙
+ * 2024/11/24 21:34
+ */
+@Slf4j
+@SuppressWarnings("all")
+@Component("localDateTimeDecodeHandler")
+public class LocalDateTimeDecodeHandler implements DecodeHandler {
+ public static final DateTimeFormatter IN_FORMATTER = DateTimeFormatter.ofPattern("yyyy-M-d H:m:s");
+ public static final DateTimeFormatter OUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+
+ @Override
+ public String decode(Map commandPointMap, String value) {
+ return LocalDateTime.parse(value, IN_FORMATTER).format(OUT_FORMATTER);
+ }
+
+ @Override
+ public void decode(Map commandPointMap, ModbusMessage.MessagePoint point) {
+ point.setValue(decode(commandPointMap, point.getParseValue()));
+ }
+
+}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/LocalTimeDecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/LocalTimeDecodeHandler.java
new file mode 100644
index 0000000..37ed01a
--- /dev/null
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/LocalTimeDecodeHandler.java
@@ -0,0 +1,36 @@
+package com.isu.gaswellwatch.modbus.data.decode.impl;
+
+import com.isu.gaswellwatch.modbus.data.ModbusMessage;
+import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Map;
+
+/**
+ * 本地时间类型解析器
+ *
+ * @author 王仕龙
+ * 2024/11/25 11:58
+ */
+@Slf4j
+@SuppressWarnings("all")
+@Component("localTimeDecodeHandler")
+public class LocalTimeDecodeHandler implements DecodeHandler {
+ public static final DateTimeFormatter IN_FORMATTER = DateTimeFormatter.ofPattern("H:m:s");
+ public static final DateTimeFormatter OUT_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
+
+
+ @Override
+ public String decode(Map commandPointMap, String value) {
+ return LocalTime.parse(value, IN_FORMATTER).format(OUT_FORMATTER);
+ }
+
+ @Override
+ public void decode(Map commandPointMap, ModbusMessage.MessagePoint point) {
+ point.setValue(decode(commandPointMap, point.getParseValue()));
+ }
+
+}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/StringTimeDecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/StringTimeDecodeHandler.java
new file mode 100644
index 0000000..3458295
--- /dev/null
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/StringTimeDecodeHandler.java
@@ -0,0 +1,40 @@
+package com.isu.gaswellwatch.modbus.data.decode.impl;
+
+import com.isu.gaswellwatch.modbus.data.ModbusMessage;
+import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 时间类型解析器
+ * 支持解析:999:59:59, 实际使用中请不要转为LocalTime
+ *
+ * @author 王仕龙
+ * 2024/11/24 21:38
+ */
+@Slf4j
+@SuppressWarnings("all")
+@Component("stringTimeDecodeHandler")
+public class StringTimeDecodeHandler implements DecodeHandler {
+
+ @Override
+ public String decode(Map commandPointMap, String value) {
+ if (StringUtils.isBlank(value)) {
+ return value;
+ }
+ return Arrays.stream(StringUtils.split(value, ":"))
+ .map(item -> StringUtils.leftPad(item, 2, '0'))
+ .collect(Collectors.joining(":"));
+ }
+
+ @Override
+ public void decode(Map commandPointMap, ModbusMessage.MessagePoint point) {
+ point.setValue(decode(commandPointMap, point.getParseValue()));
+ }
+
+}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/listener/ModbusMessagePersistListener.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/listener/ModbusMessagePersistListener.java
index a821e5a..5ee9e8a 100644
--- a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/listener/ModbusMessagePersistListener.java
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/listener/ModbusMessagePersistListener.java
@@ -5,7 +5,9 @@ import cn.hutool.json.JSONUtil;
import com.isu.gaswellwatch.modbus.data.ModbusMessage;
import com.isu.gaswellwatch.modbus.data.PersistenceHandler;
import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
-import com.serotonin.modbus4j.msg.ReadInputRegistersResponse;
+import com.isu.gaswellwatch.modbus.data.decode.impl.LocalDateTimeDecodeHandler;
+import com.serotonin.modbus4j.code.FunctionCode;
+import com.serotonin.modbus4j.msg.*;
import com.serotonin.modbus4j.serial.rtu.RtuMessageParser;
import com.serotonin.modbus4j.serial.rtu.RtuMessageResponse;
import com.serotonin.modbus4j.sero.util.queue.ByteQueue;
@@ -22,7 +24,13 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import java.time.Duration;
-import java.util.*;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
/**
* @author 王仕龙
@@ -39,7 +47,7 @@ public class ModbusMessagePersistListener implements BatchMessageListener {
@Resource
private JdbcTemplate jdbcTemplate;
- @Resource(name = "redisTemplate")
+ @Resource(name = "stringRedisTemplate")
private RedisTemplate redisTemplate;
@Resource
private Map decodeHandlerMap;
@@ -66,35 +74,50 @@ public class ModbusMessagePersistListener implements BatchMessageListener {
continue;
}
+ messagePointMap = new HashMap<>();
collectionMessage = messageSplit[5];
commandId = NumberUtils.createLong(messageSplit[2]);
commandString = Objects.toString(this.redisTemplate.opsForValue().get(COMMAND_CACHE + commandId), "");
commandMap = StringUtils.isNotEmpty(commandString) ? JSONUtil.parseObj(commandString) : null;
if (ObjectUtils.isEmpty(commandMap)) {
commandMap = this.jdbcTemplate.queryForMap(COMMAND_SQL, commandId);
- if (ObjectUtils.isNotEmpty(commandMap)) {
+ if (ObjectUtils.isEmpty(commandMap)) {
log.error("指令[{}]不存在,数据: {}", commandId, messageString);
continue;
}
this.redisTemplate.opsForValue()
.setIfAbsent(COMMAND_CACHE + commandId, JSONUtil.toJsonStr(commandMap), Duration.ofDays(1));
}
- DecodeHandler decodeHandler = Optional.ofNullable(MapUtil.getStr(commandMap, "decode_handler_name"))
- .map(this.decodeHandlerMap::get)
- .orElse(null);
- if (Objects.isNull(decodeHandler)) {
- log.error("指令[{}]未配置解析器,数据: {}", commandId, messageString);
- continue;
- }
- messagePointMap = new HashMap<>();
try {
String address;
int index = MapUtil.getInt(commandMap, "start_address"), stepSize = 0;
ByteQueue byteQueue = new ByteQueue(collectionMessage);
RtuMessageParser masterParser = new RtuMessageParser(true);
RtuMessageResponse response = (RtuMessageResponse) masterParser.parseMessage(byteQueue);
- ReadInputRegistersResponse readInputRegistersResponse = (ReadInputRegistersResponse) response.getModbusResponse();
- for (short value : readInputRegistersResponse.getShortData()) {
+ ModbusResponse modbusResponse = response.getModbusResponse();
+
+ short[] values = null;
+ switch (modbusResponse.getFunctionCode()) {
+ case FunctionCode.READ_COILS -> {
+ values = ((ReadCoilsResponse) modbusResponse).getShortData();
+ }
+ case FunctionCode.READ_DISCRETE_INPUTS -> {
+ values = ((ReadDiscreteInputsResponse) modbusResponse).getShortData();
+ }
+ case FunctionCode.READ_INPUT_REGISTERS -> {
+ values = ((ReadInputRegistersResponse) modbusResponse).getShortData();
+ }
+ case FunctionCode.READ_HOLDING_REGISTERS -> {
+ values = ((ReadHoldingRegistersResponse) modbusResponse).getShortData();
+ }
+// case FunctionCode.READ_EXCEPTION_STATUS -> {
+// values = new short[]{((ReadExceptionStatusResponse) modbusResponse).getExceptionStatus()};
+// }
+ default -> {
+ throw new RuntimeException("Funcetion code not supported: " + modbusResponse.getFunctionCode());
+ }
+ }
+ for (short value : values) {
stepSize = index * 4;
messagePointMap.put(StringUtils.leftPad(String.valueOf(index), 4, '0'),
ModbusMessage.MessagePoint.builder()
@@ -131,7 +154,7 @@ public class ModbusMessagePersistListener implements BatchMessageListener {
List