diff --git a/device_gather/src/main/java/com/xr/device/common/utils/ModbusUtils.java b/device_gather/src/main/java/com/xr/device/common/utils/ModbusUtils.java new file mode 100644 index 0000000..7bd0a16 --- /dev/null +++ b/device_gather/src/main/java/com/xr/device/common/utils/ModbusUtils.java @@ -0,0 +1,167 @@ +package com.xr.device.common.utils; + +import com.serotonin.modbus4j.BatchRead; +import com.serotonin.modbus4j.BatchResults; +import com.serotonin.modbus4j.ModbusFactory; +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.serotonin.modbus4j.ip.IpParameters; +import com.serotonin.modbus4j.locator.BaseLocator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +import static java.lang.Thread.sleep; + +public class ModbusUtils { + private static Logger log = LoggerFactory.getLogger(ModbusUtils.class); + private static Map map=new HashMap<>(); + /** + * 工厂。 + */ + static ModbusFactory modbusFactory; + + static { + if (modbusFactory == null) { + modbusFactory = new ModbusFactory(); + } + } + + /** + * 获取master + * + * @return + * @throws ModbusInitException + */ + public static ModbusMaster getMaster(String host, int port) throws ModbusInitException { + IpParameters params = new IpParameters(); + params.setHost(host); + params.setPort(port); + // + // modbusFactory.createRtuMaster(wapper); //RTU 协议 + // modbusFactory.createUdpMaster(params);//UDP 协议 + // modbusFactory.createAsciiMaster(wrapper);//ASCII 协议 + ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议 + master.init(); + + return master; + } + + public static ModbusMaster getRtuIpMaster(String host, int port) throws ModbusInitException { + IpParameters params = new IpParameters(); + params.setHost(host); + params.setPort(port); + params.setEncapsulated(true); + ModbusMaster master = modbusFactory.createTcpMaster(params, false); + try { + //设置超时时间 + master.setTimeout(2000); + //设置重连次数 + master.setRetries(2); + //初始化 + master.init(); + } catch (ModbusInitException e) { + e.printStackTrace(); + } + return master; + } + + /** + * 读取[01 Coil Status 0x]类型 开关数据 + * + * @param slaveId 主机地址 + * @param offset 寄存器地址 + * @return 读取值 + * @throws ModbusTransportException 异常 + * @throws ErrorResponseException 异常 + * @throws ModbusInitException 异常 + */ + public static Boolean readCoilStatus(ModbusMaster master, int slaveId, int offset) + throws ModbusTransportException, ErrorResponseException, ModbusInitException { + // 01 Coil Status + BaseLocator loc = BaseLocator.coilStatus(slaveId, offset); + Boolean value = master.getValue(loc); + return value; + } + /** + * 读取[03 Holding Register类型 2x]模拟量数据 + * + * @param slaveId 主机地址 + * @param offset 寄存器地址 + * @param dataType 数据类型,来自com.serotonin.modbus4j.code.DataType + * @return + * @throws ModbusTransportException 异常 + * @throws ErrorResponseException 异常 + * @throws ModbusInitException 异常 + */ + public static Number readHoldingRegister(ModbusMaster master, int slaveId, int offset, int dataType) + throws ModbusTransportException, ErrorResponseException, ModbusInitException { + // 03 Holding Register类型数据读取 + BaseLocator loc = BaseLocator.holdingRegister(slaveId, offset, dataType); + Number value = master.getValue(loc); + return value; + } + + /** + * 读取[04 Input Registers 3x]类型 模拟量数据 + * + * @param 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 loc = BaseLocator.inputRegister(slaveId, offset, dataType); + Number value = master.getValue(loc); + return value; + } + + /** + * 批量读取使用寄存器数据 + * @param master ModbusMaster对象 + * @param batchRead 批量读取集合 + * @throws ModbusTransportException + * @throws ErrorResponseException + * @throws ModbusInitException + */ + public static BatchResults batchRead(ModbusMaster master, BatchRead batchRead)throws Exception { + try { + batchRead.setContiguousRequests(false); + BatchResults results = master.send(batchRead); + return results; + } catch (Exception e) { + log.error("批量读取使用寄存器数据出现异常"+e); + e.printStackTrace(); + } + return null; + } + + public static ModbusMaster getModbusMaster(String portName){ + return map.get(portName); + } + + + public static void main(String[] args) { + try{ + ModbusMaster modbusMaster= ModbusUtils.getMaster("192.168.1.105",1502); + while (true){ + Number n = ModbusUtils.readHoldingRegister(modbusMaster, 1, 0, 4); + System.out.println(n); + sleep(1000); + } + + }catch (Exception e){ + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/device_gather/src/main/java/com/xr/device/common/utils/StringUtils.java b/device_gather/src/main/java/com/xr/device/common/utils/StringUtils.java new file mode 100644 index 0000000..d8f34ac --- /dev/null +++ b/device_gather/src/main/java/com/xr/device/common/utils/StringUtils.java @@ -0,0 +1,607 @@ +package com.xr.device.common.utils; + + +import org.springframework.util.AntPathMatcher; + +import java.util.*; + +/** + * 字符串工具类 + * + * @author ruoyi + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils +{ + /** 空字符串 */ + private static final String NULLSTR = ""; + + /** 下划线 */ + private static final char SEPARATOR = '_'; + + /** + * 获取参数不为空值 + * + * @param value defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) + { + return value != null ? value : defaultValue; + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) + { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) + { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects 要判断的对象数组 + ** @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) + { + return isNull(objects) || (objects.length == 0); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) + { + return !isEmpty(objects); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) + { + return isNull(map) || map.isEmpty(); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) + { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) + { + return isNull(str) || NULLSTR.equals(str.trim()); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) + { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) + { + return object == null; + } + + /** + * * 判断一个对象是否非空 + * + * @param object Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) + { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) + { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * 去空格 + */ + public static String trim(String str) + { + return (str == null ? "" : str.trim()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) + { + if (str == null) + { + return NULLSTR; + } + + if (start < 0) + { + start = str.length() + start; + } + + if (start < 0) + { + start = 0; + } + if (start > str.length()) + { + return NULLSTR; + } + + return str.substring(start); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) + { + if (str == null) + { + return NULLSTR; + } + + if (end < 0) + { + end = str.length() + end; + } + if (start < 0) + { + start = str.length() + start; + } + + if (end > str.length()) + { + end = str.length(); + } + + if (start > end) + { + return NULLSTR; + } + + if (start < 0) + { + start = 0; + } + if (end < 0) + { + end = 0; + } + + return str.substring(start, end); + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) + { + if (isEmpty(params) || isEmpty(template)) + { + return template; + } + return StrFormatter.format(template, params); + } + + /** + * 是否为http(s)://开头 + * + * @param link 链接 + * @return 结果 + */ + public static boolean ishttp(String link) + { + return StringUtils.startsWithAny(link,"http://", "https://"); + } + + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static final Set str2Set(String str, String sep) + { + return new HashSet(str2List(str, sep, true, false)); + } + + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @param filterBlank 过滤纯空白 + * @param trim 去掉首尾空白 + * @return list集合 + */ + public static final List str2List(String str, String sep, boolean filterBlank, boolean trim) + { + List list = new ArrayList(); + if (StringUtils.isEmpty(str)) + { + return list; + } + + // 过滤空白字符串 + if (filterBlank && StringUtils.isBlank(str)) + { + return list; + } + String[] split = str.split(sep); + for (String string : split) + { + if (filterBlank && StringUtils.isBlank(string)) + { + continue; + } + if (trim) + { + string = string.trim(); + } + list.add(string); + } + + return list; + } + + /** + * 判断给定的set列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value + * @param array 给定的数组 + * @return boolean 结果 + */ + public static boolean containsAny(Collection collection, String... array) + { + if (isEmpty(collection) || isEmpty(array)) + { + return false; + } + else + { + for (String str : array) + { + if (collection.contains(str)) + { + return true; + } + } + return false; + } + } + + /** + * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + * + * @param cs 指定字符串 + * @param searchCharSequences 需要检查的字符串数组 + * @return 是否包含任意一个字符串 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) + { + if (isEmpty(cs) || isEmpty(searchCharSequences)) + { + return false; + } + for (CharSequence testStr : searchCharSequences) + { + if (containsIgnoreCase(cs, testStr)) + { + return true; + } + } + return false; + } + + /** + * 驼峰转下划线命名 + */ + public static String toUnderScoreCase(String str) + { + if (str == null) + { + return null; + } + StringBuilder sb = new StringBuilder(); + // 前置字符是否大写 + boolean preCharIsUpperCase = true; + // 当前字符是否大写 + boolean curreCharIsUpperCase = true; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) + { + char c = str.charAt(i); + if (i > 0) + { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } + else + { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) + { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) + { + sb.append(SEPARATOR); + } + else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) + { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) + { + if (str != null && strs != null) + { + for (String s : strs) + { + if (str.equalsIgnoreCase(trim(s))) + { + return true; + } + } + } + return false; + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) + { + StringBuilder result = new StringBuilder(); + // 快速检查 + if (name == null || name.isEmpty()) + { + // 没必要转换 + return ""; + } + else if (!name.contains("_")) + { + // 不含下划线,仅将首字母大写 + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + // 用下划线将原始字符串分割 + String[] camels = name.split("_"); + for (String camel : camels) + { + // 跳过原始字符串中开头、结尾的下换线或双重下划线 + if (camel.isEmpty()) + { + continue; + } + // 首字母大写 + result.append(camel.substring(0, 1).toUpperCase()); + result.append(camel.substring(1).toLowerCase()); + } + return result.toString(); + } + + /** + * 驼峰式命名法 + * 例如:user_name->userName + */ + public static String toCamelCase(String s) + { + if (s == null) + { + return null; + } + if (s.indexOf(SEPARATOR) == -1) + { + return s; + } + s = s.toLowerCase(); + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) + { + char c = s.charAt(i); + + if (c == SEPARATOR) + { + upperCase = true; + } + else if (upperCase) + { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } + else + { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) + { + if (isEmpty(str) || isEmpty(strs)) + { + return false; + } + for (String pattern : strs) + { + if (isMatch(pattern, str)) + { + return true; + } + } + return false; + } + + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + * @return + */ + public static boolean isMatch(String pattern, String url) + { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) + { + return (T) obj; + } + + /** + * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 + * + * @param num 数字对象 + * @param size 字符串指定长度 + * @return 返回数字的字符串格式,该字符串为指定长度。 + */ + public static final String padl(final Number num, final int size) + { + return padl(num.toString(), size, '0'); + } + + /** + * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。 + * + * @param s 原始字符串 + * @param size 字符串指定长度 + * @param c 用于补齐的字符 + * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 + */ + public static final String padl(final String s, final int size, final char c) + { + final StringBuilder sb = new StringBuilder(size); + if (s != null) + { + final int len = s.length(); + if (s.length() <= size) + { + for (int i = size - len; i > 0; i--) + { + sb.append(c); + } + sb.append(s); + } + else + { + return s.substring(len - size, len); + } + } + else + { + for (int i = size; i > 0; i--) + { + sb.append(c); + } + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/device_gather/src/main/java/com/xr/device/common/utils/ValueFormatUtil.java b/device_gather/src/main/java/com/xr/device/common/utils/ValueFormatUtil.java new file mode 100644 index 0000000..9bce9ca --- /dev/null +++ b/device_gather/src/main/java/com/xr/device/common/utils/ValueFormatUtil.java @@ -0,0 +1,80 @@ +package com.xr.device.common.utils; + + +import com.xr.device.model.entity.MeterConfig; +import com.xr.device.model.service.MeterConfigService; + +public class ValueFormatUtil { + + /* + * 处理AI分析的计数器数值,针对可以识别到,但偶尔有错误结果出现的情况 + * 1.抄写基准值 + * 2.与基准值比较,如果比基准值大于1,可能计数器跳1,更新基准值,并返回结果 + * 反之返回基准值结果为识别结果 + * 3.如果未设基准值,去0后保存结果 + * */ + public static String getNumBerJx(float getVal, MeterConfig config, MeterConfigService meterConfigService){ + int s = (int) getVal; + Integer jz = Integer.valueOf(config.getJzVal())+1; + if(StringUtils.isNotEmpty(config.getJzVal())){ + if(s==jz){ + config.setJzVal(jz+""); + meterConfigService.updateById(config); + return jz+""; + }else{ + return config.getJzVal(); + } + }else{ + return s+""; + } + } + + public static String getYwj(float f,MeterConfig config){//处理液位计识别结果 + if((f == 0 || f>1)&& StringUtils.isNotEmpty(config.getJzVal())){ + return config.getJzVal(); + }else{ + return String.format("%.2f", f*100)+"%"; + } + } + + public static String getZZl(float f,MeterConfig config){//处理指针类识别结果 + if(f ==0 && StringUtils.isNotEmpty(config.getJzVal())){ + return config.getJzVal(); + }else{ + return String.format("%.2f", f); + } + } + + public static String getDw(float f){ + int s = Math.round(f); + if(s>8){ + int t = s-8; + if(t<9){ + return t+""; + } + if(t == 9){ + return "9A"; + } + if(t == 10){ + return "9B"; + } + if(t == 11){ + return "9C"; + } + if(t>11){ + return t-2+""; + } + } + return s+""; + } + + public static String getfdjsq(float f){ + int s = Math.round(f); + if(s>=10){ + return 0+""; + }else { + return s+""; + } + } + +} diff --git a/device_gather/src/main/java/com/xr/device/model/entity/MeterConfig.java b/device_gather/src/main/java/com/xr/device/model/entity/MeterConfig.java index 0e71519..d3137f1 100644 --- a/device_gather/src/main/java/com/xr/device/model/entity/MeterConfig.java +++ b/device_gather/src/main/java/com/xr/device/model/entity/MeterConfig.java @@ -175,6 +175,9 @@ public class MeterConfig implements Serializable { @TableField(exist = false) private String deviceIp; + @TableField(exist = false) + private String meterType; + @TableField(exist = false) private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/device_gather/src/main/java/com/xr/device/model/entity/MeterReadingRecord.java b/device_gather/src/main/java/com/xr/device/model/entity/MeterReadingRecord.java index b18c701..756860b 100644 --- a/device_gather/src/main/java/com/xr/device/model/entity/MeterReadingRecord.java +++ b/device_gather/src/main/java/com/xr/device/model/entity/MeterReadingRecord.java @@ -5,7 +5,8 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; -import java.time.LocalDateTime; +import java.util.Date; + import lombok.Data; /** @@ -49,7 +50,7 @@ public class MeterReadingRecord implements Serializable { /** * 读数时间 */ - private LocalDateTime readingTime; + private Date readingTime; /** * 读数类型(1 一体化电源 2 AI摄像头 3 串口) @@ -79,7 +80,7 @@ public class MeterReadingRecord implements Serializable { /** * 创建时间 */ - private LocalDateTime createTime; + private Date createTime; /** * 修改人 @@ -89,7 +90,7 @@ public class MeterReadingRecord implements Serializable { /** * 修改时间 */ - private LocalDateTime updateTime; + private Date updateTime; @TableField(exist = false) private static final long serialVersionUID = 1L; diff --git a/device_gather/src/main/java/com/xr/device/schedule/GetMeterSchedule.java b/device_gather/src/main/java/com/xr/device/schedule/GetMeterSchedule.java index b540ff2..eb33cf4 100644 --- a/device_gather/src/main/java/com/xr/device/schedule/GetMeterSchedule.java +++ b/device_gather/src/main/java/com/xr/device/schedule/GetMeterSchedule.java @@ -1,13 +1,33 @@ package com.xr.device.schedule; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +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.xr.device.common.utils.ModbusUtils; +import com.xr.device.common.utils.StringUtils; +import com.xr.device.common.utils.UploadUtil; +import com.xr.device.common.utils.ValueFormatUtil; +import com.xr.device.model.entity.FocalLengthConfig; import com.xr.device.model.entity.MeterConfig; +import com.xr.device.model.entity.MeterReadingRecord; import com.xr.device.model.service.FocalLengthConfigService; import com.xr.device.model.service.MeterConfigService; +import com.xr.device.model.service.MeterReadingRecordService; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Date; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; @Component @RequiredArgsConstructor @@ -17,10 +37,103 @@ public class GetMeterSchedule { private final FocalLengthConfigService focalLengthConfigService; + private final MeterReadingRecordService meterReadingRecordService; + @Scheduled(cron = "0 0 0/3 * * ?") public void getMeterSchedule(){ List configs = meterConfigService.getMeterList(); + int pageSize = 10; // 每页的设备数量 + int totalDevices = configs.size(); // 总设备数量 + int totalPages = (int) Math.ceil((double) totalDevices / pageSize); // 总页数 + for (int pageNumber = 0; pageNumber < totalPages; pageNumber++) { + List devices = new ArrayList<>(); + for (int i = pageNumber * pageSize; i < (pageNumber + 1) * pageSize && i < totalDevices; i++) { + devices.add(configs.get(i)); + } + + ExecutorService executorService = Executors.newFixedThreadPool(pageSize); + + for (MeterConfig device : devices) { + executorService.submit(() -> collectDataFromDevice(device)); + } + + // 关闭线程池,等待所有任务完成 + executorService.shutdown(); + try { + if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) { + executorService.shutdownNow(); + } + } catch (InterruptedException e) { + executorService.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } + + //采集方法 + private void collectDataFromDevice(MeterConfig config) { + // 实现采集逻辑 + try { + ModbusMaster master= ModbusUtils.getMaster(config.getDeviceIp(),1502); + master.init(); + MeterReadingRecord meterReadingRecord=new MeterReadingRecord(); + meterReadingRecord.setMeterId(config.getId()); + meterReadingRecord.setReadingType(2); + String value = ""; + if(config.getTypeId() == 5 || config.getTypeId() == 7){ + Number number = ModbusUtils.readHoldingRegister(master,1,0, DataType.FOUR_BYTE_INT_SIGNED); + float f = number.floatValue()*0.0001f; + value = ValueFormatUtil.getZZl(f,config); + } + if(config.getTypeId() == 3 ){ + Number number = ModbusUtils.readHoldingRegister(master,1,0, DataType.FOUR_BYTE_INT_SIGNED); + float f = number.floatValue()*0.0001f; + value = ValueFormatUtil.getYwj(f,config); + } + if(config.getTypeId() == 4 || config.getTypeId() == 11){//开关计数器 + Number number = ModbusUtils.readHoldingRegister(master,1,0, DataType.TWO_BYTE_INT_SIGNED); + float f = number.floatValue(); + value= ValueFormatUtil.getNumBerJx(f,config,meterConfigService); + } + if(config.getTypeId() == 8){//档位数据处理 + //处理为整数 + Number number = ModbusUtils.readHoldingRegister(master,1,0, DataType.FOUR_BYTE_INT_SIGNED); + float f = number.floatValue()*0.0001f; + value = ValueFormatUtil.getDw(f); + } + if(config.getTypeId() == 10){//放电计数器 + Number number = ModbusUtils.readHoldingRegister(master,1,0, DataType.FOUR_BYTE_INT_SIGNED); + float f = number.floatValue()*0.0001f; + ValueFormatUtil.getfdjsq(f); + } + if(config.getIsJz() == 1){ + value = config.getJzVal(); + } + meterReadingRecord.setReadingValue(value); + QueryWrapper query=new QueryWrapper<>(); + query.eq("config_id",config.getId()); + FocalLengthConfig fa= focalLengthConfigService.getOne(query); + String fileName = config.getId()+new Date().getTime()+".jpg"; + String url = "http://"+config.getDeviceIp()+":8080/tao/snapshot"; + BufferedImage bufferedImage = UploadUtil.urlByImage(url); + BufferedImage buffer = UploadUtil.drawRectangleAndText(bufferedImage, + fa.getCopperX(),fa.getCopperY(),fa.getCopperX2(),fa.getCopperWid(),fa.getCopperHei(),meterReadingRecord.getReadingValue(),config.getMeterName()); + String url1 = UploadUtil.uploadImage(buffer,config.getId(),fileName); + meterReadingRecord.setMeterTypeName(config.getMeterType()); + meterReadingRecord.setMeterCode(config.getMeterCode()); + meterReadingRecord.setReadingTime(new Date()); + meterReadingRecord.setCreateUser("SYSTEM"); + meterReadingRecord.setCreateTime(new Date()); + meterReadingRecord.setReadingUrl(url1); + meterReadingRecord.setMeterTypeId(config.getTypeId()); + meterReadingRecord.setOwningInterval(config.getOwningInterval()); + meterReadingRecordService.save(meterReadingRecord); + master.destroy(); + } catch (Exception e) { + // 处理设备不在线或通信错误的情况 + System.err.println("Error communicating with " + config.getDeviceIp() + ": " + e.getMessage()); + } } }