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 0152940..5aec543 100644
--- a/src/main/java/com/isu/gaswellwatch/modbus/data/PersistenceHandler.java
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/PersistenceHandler.java
@@ -13,6 +13,7 @@ public interface PersistenceHandler {
String ETC_MODBUS_TYPE = "etc";
String SCSS_MODBUS_TYPE = "scss";
String WEPS_PLUG_MODBUS_TYPE = "weps_plug";
+ String MI_WEPS_PLUG_MODBUS_TYPE = "mi_weps_plug";
String COMMAND_CACHE = "modbus:command:";
String DEVICE_INFO_CACHE = "info:device:";
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/ByteToStringDecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/ByteToStringDecodeHandler.java
new file mode 100644
index 0000000..64b55b2
--- /dev/null
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/ByteToStringDecodeHandler.java
@@ -0,0 +1,39 @@
+package com.isu.gaswellwatch.modbus.data.decode.impl;
+
+
+import com.isu.gaswellwatch.modbus.data.ModbusMessage;
+import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author 王仕龙
+ * 2025/2/22 00:56
+ */
+@Component(ByteToStringDecodeHandler.NAME + DecodeHandler.DECODE_NAME)
+public class ByteToStringDecodeHandler implements DecodeHandler {
+
+ public static final String NAME = "byteToString";
+
+ @Override
+ public String decode(Map commandPointMap, String value) {
+ if (StringUtils.isBlank(value)) {
+ return value;
+ }
+ int length = value.length() / 4;
+ byte[] bytes = new byte[length];
+ for (int i = 0; i < length; i++) {
+ bytes[0] = NumberUtils.createInteger(value.substring(i * 4, i * 4 + 4)).byteValue();
+ }
+ return new String(bytes);
+ }
+
+ @Override
+ public void decode(Map commandPointMap, ModbusMessage.MessagePoint point) {
+ point.setValue(this.decode(commandPointMap, point.getValue()));
+ }
+
+}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/weps/WepsCurrentLocalDateTimeDecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/weps/WepsCurrentLocalDateTimeDecodeHandler.java
new file mode 100644
index 0000000..8bee2d9
--- /dev/null
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/weps/WepsCurrentLocalDateTimeDecodeHandler.java
@@ -0,0 +1,61 @@
+package com.isu.gaswellwatch.modbus.data.decode.impl.weps;
+
+
+import com.isu.gaswellwatch.modbus.data.ModbusMessage;
+import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author 王仕龙
+ * 2025/2/22 00:26
+ */
+@Component(WepsCurrentLocalDateTimeDecodeHandler.NAME + DecodeHandler.DECODE_NAME)
+public class WepsCurrentLocalDateTimeDecodeHandler implements DecodeHandler {
+
+ public static final String NAME = "wepsCurrentLocalDateTime";
+
+ @Override
+ public String decode(Map commandPointMap, String value) {
+ if (StringUtils.isBlank(value)) {
+ return value;
+ }
+// 0x4830:0x0211:0x0924:0x2013
+// 2013-09-24 11:48:30
+ String[] times = value.split(":");
+ if (times.length < 4) {
+ return value;
+ }
+ String minuteSecond = times[0];
+ String weekHour = times[1];
+ String monthDay = times[2];
+ String year = times[4];
+
+ if (StringUtils.startsWithIgnoreCase(minuteSecond, "0x")) {
+ minuteSecond = StringUtils.substring(minuteSecond, 2);
+ }
+ minuteSecond = StringUtils.leftPad(minuteSecond, 4, '0');
+ if (StringUtils.startsWithIgnoreCase(weekHour, "0x")) {
+ weekHour = StringUtils.substring(weekHour, 2);
+ }
+ weekHour = StringUtils.leftPad(weekHour, 4, '0');
+ if (StringUtils.startsWithIgnoreCase(monthDay, "0x")) {
+ monthDay = StringUtils.substring(monthDay, 2);
+ }
+ monthDay = StringUtils.leftPad(monthDay, 4, '0');
+ if (StringUtils.startsWithIgnoreCase(year, "0x")) {
+ year = StringUtils.substring(year, 2);
+ }
+
+ return year + "-" + StringUtils.substring(monthDay, 0, 2) + "-" +
+ StringUtils.substring(monthDay, 2) + " " + StringUtils.substring(weekHour, 2) + ":" +
+ StringUtils.substring(minuteSecond, 0, 2) + ":" + StringUtils.substring(minuteSecond, 2);
+ }
+
+ @Override
+ public void decode(Map commandPointMap, ModbusMessage.MessagePoint point) {
+ point.setValue(this.decode(commandPointMap, point.getValue()));
+ }
+}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/weps/WepsDecimalDecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/weps/WepsDecimalDecodeHandler.java
new file mode 100644
index 0000000..a7ab5d4
--- /dev/null
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/weps/WepsDecimalDecodeHandler.java
@@ -0,0 +1,40 @@
+package com.isu.gaswellwatch.modbus.data.decode.impl.weps;
+
+
+import com.isu.gaswellwatch.modbus.data.ModbusMessage;
+import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @author 王仕龙
+ * 2025/2/22 00:50
+ */
+@Component(WepsDecimalDecodeHandler.NAME + DecodeHandler.DECODE_NAME)
+public class WepsDecimalDecodeHandler implements DecodeHandler {
+
+ public static final String NAME = "wepsDecimal";
+
+ @Override
+ public String decode(Map commandPointMap, String value) {
+ if (StringUtils.isBlank(value)) {
+ return value;
+ }
+ if (StringUtils.startsWith(value, ".")) {
+ return NumberUtils.createBigDecimal("0" + value).toString();
+ } else if (StringUtils.endsWith(value, ".")) {
+ return NumberUtils.createBigDecimal(value + "0").toString();
+ } else {
+ return value;
+ }
+ }
+
+ @Override
+ public void decode(Map commandPointMap, ModbusMessage.MessagePoint point) {
+ point.setValue(this.decode(commandPointMap, point.getValue()));
+ }
+
+}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/weps/WepsRemainingLocalTimeDecodeHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/weps/WepsRemainingLocalTimeDecodeHandler.java
new file mode 100644
index 0000000..3e13df5
--- /dev/null
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/decode/impl/weps/WepsRemainingLocalTimeDecodeHandler.java
@@ -0,0 +1,61 @@
+package com.isu.gaswellwatch.modbus.data.decode.impl.weps;
+
+
+import com.isu.gaswellwatch.modbus.data.ModbusMessage;
+import com.isu.gaswellwatch.modbus.data.decode.DecodeHandler;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author 王仕龙
+ * 2025/2/22 00:38
+ */
+@Component(WepsRemainingLocalTimeDecodeHandler.NAME + DecodeHandler.DECODE_NAME)
+public class WepsRemainingLocalTimeDecodeHandler implements DecodeHandler {
+ public static final String NAME = "wepsRemainingLocalTime";
+
+ @Override
+ public String decode(Map commandPointMap, String value) {
+ if (StringUtils.isBlank(value)) {
+ return value;
+ }
+ // 0x0930:0x0001
+ // 0.1:09:30
+ String[] times = value.split(":");
+ if (times.length < 2) {
+ return value;
+ }
+ String minuteSecond = times[0];
+ String dayHour = times[1];
+
+ if (StringUtils.startsWithIgnoreCase(minuteSecond, "0x")) {
+ minuteSecond = StringUtils.substring(minuteSecond, 2);
+ }
+ minuteSecond = StringUtils.leftPad(minuteSecond, 4, '0');
+ if (StringUtils.startsWithIgnoreCase(dayHour, "0x")) {
+ dayHour = StringUtils.substring(dayHour, 2);
+ }
+ dayHour = StringUtils.leftPad(dayHour, 4, '0');
+
+ long daySeconds = TimeUnit.DAYS.toSeconds(NumberUtils.createLong(StringUtils.substring(dayHour, 0, 2)));
+ long hourSeconds = TimeUnit.HOURS.toSeconds(NumberUtils.createLong(StringUtils.substring(dayHour, 2)));
+ long minuteSeconds = TimeUnit.HOURS.toSeconds(NumberUtils.createLong(StringUtils.substring(minuteSecond, 0, 2)));
+ long seconds = TimeUnit.HOURS.toSeconds(NumberUtils.createLong(StringUtils.substring(minuteSecond, 2)));
+
+ long totalSeconds = daySeconds + hourSeconds + minuteSeconds + seconds;
+ long hours = TimeUnit.SECONDS.toHours(totalSeconds);
+ long remainingSeconds = totalSeconds - TimeUnit.HOURS.toSeconds(hours);
+ long minutes = TimeUnit.SECONDS.toMinutes(remainingSeconds);
+ remainingSeconds = remainingSeconds - TimeUnit.MINUTES.toSeconds(minutes);
+ return String.format("%02d:%02d:%02d", hours, minutes, remainingSeconds);
+ }
+
+ @Override
+ public void decode(Map commandPointMap, ModbusMessage.MessagePoint point) {
+ point.setValue(this.decode(commandPointMap, point.getValue()));
+ }
+}
diff --git a/src/main/java/com/isu/gaswellwatch/modbus/data/impl/MiWepsPlugPersistenceHandler.java b/src/main/java/com/isu/gaswellwatch/modbus/data/impl/MiWepsPlugPersistenceHandler.java
new file mode 100644
index 0000000..42ae6c3
--- /dev/null
+++ b/src/main/java/com/isu/gaswellwatch/modbus/data/impl/MiWepsPlugPersistenceHandler.java
@@ -0,0 +1,170 @@
+package com.isu.gaswellwatch.modbus.data.impl;
+
+
+import com.isu.gaswellwatch.modbus.data.PersistenceHandler;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.jdbc.core.PreparedStatementCallback;
+import org.springframework.stereotype.Component;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @author 王仕龙
+ * 2025/2/22 01:07
+ */
+@Component(PersistenceHandler.MI_WEPS_PLUG_MODBUS_TYPE)
+public class MiWepsPlugPersistenceHandler extends AbstractPersistenceHandler {
+
+ private static final Map MI_WEPS_PLUG_COLUMN_MAPPING_MAP = new HashMap<>();
+
+ static {
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("report_status", "reportStatus"); // 报表状态 0:无报表数据; 1:有分钟记录; 2:有小时记录; 3:有日志记录; 4:有生产记录
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("current_status", "currentStatus"); // 当前状态 0:关井; 1:上升; 2:续流; 3:停机
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("current_time", "currentTime"); // 当前时间 "控制器时间。示例:0x4830:0x0211:0x0924:0x2013。结果:2013 - 09 - 24 11:48:30 "
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("remaining_time", "remainingTime"); // 剩余时间 "组合后时间格式:天.小时:分钟:秒。示例:0x0930:0x0001。结果:0.1:09:30 "
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("current_status_0x", "currentStatus0x"); // 当前状态0x 0x8000:关井;0x8001:上升;0x8002:续流;0x8003:停机
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("oil_pressure", "oilPressure"); // 油压 单位:MPa
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("oil_pressure_temperature", "oilPressureTemperature"); // 油压表测量温度 单位:℃
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("cas_pressure", "casPressure"); // 套压 单位:MPa
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("cas_pressure_temperature", "casPressureTemperature"); // 套压测量温度 单位:℃
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("quantity_of_electricity", "quantityOfElectricity"); // 控制器电量 单位:%
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("pluger_rising_speed", "plugerRisingSpeed"); // 柱塞上升速度 单位:米/分钟
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("gas_well_number", "gasWellNumber"); // 气井编号
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("depth_of_lock_device", "depthOfLockDevice"); // 卡定器深度 单位:米
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("arriving_sensor", "arrivingSensor"); // 到达传感器 0/1:禁用/启用
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("zigbee", "zigbee"); // Zigbee 0/1:禁用/启用
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("pulse_width", "pulseWidth"); // 脉冲宽度 驱动电磁阀使用
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("plug_rising_speed", "plugRisingSpeed"); // 上升速度 米/分钟
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("plug_too_fast_speed", "plugTooFastSpeed"); // 过快速度 米/分钟
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("plug_too_slow_speed", "plugTooSlowSpeed"); // 过缓速度 米/分钟
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("gas_well_name", "gasWellName"); // 气井名称
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("oil_and_cas_data_collection_interval", "oilAndCasDataCollectionInterval"); // 油、套压数据采集间隔 0:每5秒采样;1:每10秒采样;2:每15秒采样;3:每30秒采样;4:每1秒采样;5:每2秒采样;6:每3秒采样;7:每4秒采样
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("store_data_interval_on_open_well", "storeDataIntervalOnOpenWell"); // 数据存储间隔(开井期间) 0:每1分钟存储;1:每5分钟存储;2:每10分钟存储;3:每15分钟存储;4:每30秒存储;5:每15秒存储;6:每5秒存储
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("store_data_interval_on_close_well", "storeDataIntervalOnCloseWell"); // 数据存储间隔(关井期间) 0:每1分钟存储;1:每5分钟存储;2:每10分钟存储;3:每15分钟存储;4:每30秒存储;5:每15秒存储;6:每5秒存储
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("communication_power_threshold", "communicationPowerThreshold"); // 通信电量门限 Zigbee通讯使用
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("reserve1", "reserve1"); // 保留 Zigbee通讯使用
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("start_time_of_daytime", "startTimeOfDaytime"); // 白天起始时间 Zigbee通讯使用
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("end_time_of_daytime", "endTimeOfDaytime"); // 白天结束时间 Zigbee通讯使用
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("control_work_time", "controlWorkTime"); // 控制器工作状态 0:生产模式;1:常开模式;2:常关模式
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("produce_mode", "produceMode"); // 生产制度设置 0:定时开关井;1:时间优化模式;2:压力微升模式;3:压力回升模式;4:压力跌落模式
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("plunger_rise_time", "plungerRiseTime"); // 上升时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("dangerous_rise_time", "dangerousRiseTime"); // 危险上升时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("too_fast_rise_time", "tooFastRiseTime"); // 过快上升时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("too_slow_rise_time", "tooSlowRiseTime"); // 过缓上升时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("too_fast_count", "tooFastCount"); // 过快次数
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("too_fast_raise_open_well_time", "tooFastRaiseOpenWellTime"); // 过快增加开井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("too_fast_lower_close_well_time", "tooFastLowerCloseWellTime"); // 过快减少关井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("too_slow_lower_open_well_time", "tooSlowLowerOpenWellTime"); // 过缓减少开井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("too_slow_raise_close_well_time", "tooSlowRaiseCloseWellTime"); // 过缓增加关井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("check_stability_time", "checkStabilityTime"); // 检测稳定时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("min_close_well_time", "minCloseWellTime"); // 最小关井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("max_close_well_time", "maxCloseWellTime"); // 最大关井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("well_close_time_not_reached_duration", "wellCloseTimeNotReachedDuration"); // 未到达关井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("min_open_well_time", "minOpenWellTime"); // 最小开井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("max_open_well_time", "maxOpenWellTime"); // 最大开井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("after_flow_time", "afterFlowTime"); // 续流时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("not_reached_flow_time", "notReachedFlowTime"); // 未到续流时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("close_time", "closeTime"); // 关井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("open_time", "openTime"); // 开井时间 单位:秒
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("open_pressure", "openPressure"); // 开井压力 单位:MPa
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("close_pressure", "closePressure"); // 关井压力 单位:MPa
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("little_rise_pressure", "littleRisePressure"); // 微升压力 单位:MPa
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("gas_collection_mode", "gasCollectionMode"); // 集气模式 0:低压集气模式;1:高压集气模式
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("reserve2", "reserve2"); // 保留
+ MI_WEPS_PLUG_COLUMN_MAPPING_MAP.put("protection_pressure", "protectionPressure"); // 保护压力 单位:MPa
+ }
+
+ @Override
+ public void createTable(String tableName, Long deviceId) {
+ this.createTable("sql/CREATE_MI_WEPS_PLUG.sql", tableName, deviceId);
+ }
+
+ @Override
+ public Map> insert(String tableName, String cacheKey) {
+ String insertTableSQL = this.getResource("sql/INSERT_MI_WEPS_PLUG.sql");
+ insertTableSQL = StringUtils.replace(insertTableSQL, "$TableName$", tableName);
+
+ Map oldRow = this.getLastRow(tableName);
+ Map newRow = this.redisTemplate.opsForHash().entries(cacheKey);
+
+ this.jdbcTemplate.execute(insertTableSQL, new PreparedStatementCallback