From 55deaa37b89464bab662fbb834619639000b5259 Mon Sep 17 00:00:00 2001
From: fyj <913944315@qq.com>
Date: Mon, 8 Apr 2024 17:13:32 +0800
Subject: [PATCH] =?UTF-8?q?=E4=B8=AD=E5=B1=B1=E7=AB=99=E4=B8=8A=E6=8A=A5?=
=?UTF-8?q?=E6=99=BA=E5=B7=A1=E6=9C=80=E6=96=B0=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
device_cars/pom.xml | 8 +
.../xr/device_car/config/udp/UdbConfig.java | 17 +-
.../xr/device_car/config/utils/EnumUtil.java | 10 ++
.../controller/MeterConfigController.java | 74 +++++++-
.../mapper/MeterReadingRecordMapper.java | 5 +
.../modules/analysis/scheduled/Task.java | 20 +++
.../service/MeterReadingRecordService.java | 3 +
.../analysis/service/UdpClientService.java | 4 +-
.../impl/MeterReadingRecordServiceImpl.java | 9 +
.../service/impl/UdpClientServiceImpl.java | 9 +-
.../src/main/resources/application-dev.yml | 2 +-
.../src/main/resources/application-prod.yml | 44 ++---
.../src/main/resources/application.yml | 2 +-
.../analysis/MeterReadingRecordMapper.xml | 8 +
device_iec104/pom.xml | 8 +
device_iec61850clent/pom.xml | 10 +-
.../Iec61850ClentApplication.java | 2 +-
.../common/util/IEC61850Config.java | 7 +-
.../iec61850clent/common/util/ModeUtil.java | 2 +-
.../controller/AiInterfaceController.java | 2 +-
.../models/entity/MeterConfig.java | 162 ++++++++++++++----
.../models/iec61850run/Iec61850clent.java | 88 ++++++++--
.../src/main/resources/IEC61850.xlsx | Bin 14095 -> 14258 bytes
.../src/main/resources/application-prod.yml | 26 +--
device_iec61850server/pom.xml | 8 +
device_udpclent/pom.xml | 10 +-
.../common/UdpClientConfig.java | 57 ------
.../common/utils/EnumUtil.java | 52 ++++++
.../models/controller/UdpClentController.java | 21 ---
.../models/scheduled/UdpClentScheduled.java | 78 ++++++++-
.../models/service/UdpClientService.java | 4 +-
.../service/impl/UdpClientServiceImpl.java | 9 +-
.../src/main/resources/application-dev.yml | 2 +-
.../src/main/resources/application-prod.yml | 50 ++++--
.../src/main/resources/application.yml | 2 +-
.../src/main/resources/logback.xml | 51 ++++++
.../mapper/MeterReadingRecordMapper.xml | 6 +-
37 files changed, 647 insertions(+), 225 deletions(-)
create mode 100644 device_cars/src/main/java/com/xr/device_car/modules/analysis/scheduled/Task.java
delete mode 100644 device_udpclent/src/main/java/com/xr/device_udpclent/common/UdpClientConfig.java
create mode 100644 device_udpclent/src/main/java/com/xr/device_udpclent/common/utils/EnumUtil.java
delete mode 100644 device_udpclent/src/main/java/com/xr/device_udpclent/models/controller/UdpClentController.java
create mode 100644 device_udpclent/src/main/resources/logback.xml
diff --git a/device_cars/pom.xml b/device_cars/pom.xml
index 530a228..ac4909f 100644
--- a/device_cars/pom.xml
+++ b/device_cars/pom.xml
@@ -413,6 +413,14 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 8
+ 8
+
+
diff --git a/device_cars/src/main/java/com/xr/device_car/config/udp/UdbConfig.java b/device_cars/src/main/java/com/xr/device_car/config/udp/UdbConfig.java
index 9efbac5..7f368bf 100644
--- a/device_cars/src/main/java/com/xr/device_car/config/udp/UdbConfig.java
+++ b/device_cars/src/main/java/com/xr/device_car/config/udp/UdbConfig.java
@@ -16,17 +16,24 @@ public class UdbConfig {
public static String getUdbConfig(List list){
StringBuffer buffer=new StringBuffer();
SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- buffer.append(new Date().getTime()+ new Random().nextInt(9000)+1000).append("\t");
- buffer.append("");
+ //buffer.append(new Date().getTime()+ new Random().nextInt(9000)+1000).append("\t");
+ buffer.append("");
buffer.append("");
+ int i=1;
+ buffer.append("@序号").append("\t").append("站序号").append("\t").append("监控索引号").append("\t").append("设备名称").append("\t").append("设备类型")
+ .append("\t").append("实物ID").append("\t").append("是否联动信号").append("\n");
for(MeterConfig config:list){
- buffer.append("站序号").append("\t");//站序号
+ buffer.append("#"+i).append("\t"); //序号
+ buffer.append("1").append("\t");//站序号
buffer.append(config.getId()).append("\t");//监控索引号
buffer.append("中山站").append("/").append(config.getOwningInterval()).append("/").append(config.getDeviceName()).append("/").append(config.getMeterName()).append("\t");//设备名称=站名称+间隔名称+设备名称+开关名称
- buffer.append(config.getMeterCode()).append("\t");//实物ID目前取表计ID
- buffer.append("否").append(";");//是否联动信号目前取否,目前结尾符号位;
+ buffer.append("遥测").append("\t");
+ buffer.append(config.getId()).append("\t");//实物ID目前取表计ID
+ buffer.append("否").append("\n");//是否联动信号目前取否,目前结尾符号位;
+ i++;
}
buffer.append("");
+ System.out.println(buffer.toString());
return buffer.toString();
}
diff --git a/device_cars/src/main/java/com/xr/device_car/config/utils/EnumUtil.java b/device_cars/src/main/java/com/xr/device_car/config/utils/EnumUtil.java
index 568b5ea..e831f80 100644
--- a/device_cars/src/main/java/com/xr/device_car/config/utils/EnumUtil.java
+++ b/device_cars/src/main/java/com/xr/device_car/config/utils/EnumUtil.java
@@ -1,5 +1,7 @@
package com.xr.device_car.config.utils;
+import io.netty.buffer.ByteBuf;
+
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
@@ -39,4 +41,12 @@ public class EnumUtil {
}
return Arrays.stream(ts).filter(predicate).findAny();
}
+
+ public static String byteBufTo16Str(ByteBuf byteBuf){
+ StringBuilder sb = new StringBuilder();
+ for (int i = byteBuf.readerIndex(); i < byteBuf.writerIndex(); i++) {
+ sb.append(String.format("%02X", byteBuf.getByte(i))+" ");
+ }
+ return sb.toString();
+ }
}
diff --git a/device_cars/src/main/java/com/xr/device_car/modules/analysis/controller/MeterConfigController.java b/device_cars/src/main/java/com/xr/device_car/modules/analysis/controller/MeterConfigController.java
index a370df7..181ddd0 100644
--- a/device_cars/src/main/java/com/xr/device_car/modules/analysis/controller/MeterConfigController.java
+++ b/device_cars/src/main/java/com/xr/device_car/modules/analysis/controller/MeterConfigController.java
@@ -13,6 +13,8 @@ import com.xr.device_car.modules.analysis.scheduled.TaskScheduler;
import com.xr.device_car.modules.analysis.service.*;
import com.xr.device_car.modules.analysis.vo.MeterMaxMinSaveVo;
import com.xr.device_car.modules.system.entity.UserInfo;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
@@ -28,9 +30,12 @@ import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.zip.CRC32;
+import java.util.zip.Checksum;
@RestController
@RequestMapping("analysis/meterConfig")
@@ -257,11 +262,57 @@ public class MeterConfigController {
@RequestMapping("/sendSynchronizationUdp")
public Result> sendSynchronizationUdp(){
try{
+ // 每次发送的最大长度
+ final int MAX_LENGTH = 200;
QueryWrapper query=new QueryWrapper<>();
query.eq("status",1);
List list = meterConfigService.list(query);
String sendMsg = UdbConfig.getUdbConfig(list);
- udpClientService.sendData(sendMsg);
+ byte[]b = sendMsg.getBytes("GB2312");
+
+ // 计算需要分成多少段发送
+ int parts = b.length / MAX_LENGTH + (b.length % MAX_LENGTH == 0 ? 0 : 1);
+ int s = 1;
+ for (int i = 0; i < parts; i++) {
+ if(i==parts-1){
+ s=0;
+ }else{
+ s=1;
+ }
+ // 计算每一段的起始索引和结束索引
+ int start = i * MAX_LENGTH;
+ System.out.println(start);
+ int end = Math.min((i + 1) * MAX_LENGTH, b.length);
+
+ // 根据起始索引和结束索引截取字节数组的一部分
+ byte[] segment = java.util.Arrays.copyOfRange(b, start, end);
+ ByteBuf buf = Unpooled.buffer();
+ buf.writeBytes(new byte[]{(byte) 0xEB, (byte) 0x90,(byte) 0xEB, (byte) 0x90,(byte)0x43});
+ buf.writeShortLE(0x03);
+ buf.writeByte(s);
+ buf.writeShort(i);
+ buf.writeInt(start);
+ buf.writeByte(segment.length);
+ buf.writeBytes(segment);
+ //Checksum checksum = new CRC32();
+ byte c = 0;
+ int startIndex = 5; // 从第6位开始,索引是5(因为索引从0开始)
+ int endIndex = buf.readableBytes() - 1; // 到倒数第二位结束
+ // 截取并处理指定范围内的字节
+ if (startIndex <= endIndex) {
+ // 临时存放截取的字节
+ byte[] slice = new byte[endIndex - startIndex + 1];
+ // 从ByteBuf中获取数据
+ buf.getBytes(startIndex, slice);
+ c=checksum8(slice);
+ // 更新Checksum对象
+ //checksum.update(slice, 0, slice.length);
+ }
+ buf.writeByte(c);
+ System.out.println(EnumUtil.byteBufTo16Str(buf));
+ udpClientService.sendData(buf);
+ Thread.sleep(100);
+ }
}catch (Exception e){
e.printStackTrace();
return Result.OK("同步失败!");
@@ -269,4 +320,25 @@ public class MeterConfigController {
return Result.OK("同步成功!");
}
+
+
+ public List getConfigList(List list,int min,int max){
+ List list1=new ArrayList<>();
+ for(MeterConfig config:list){
+ if(config.getId()>min && config.getId()<=max){
+ list1.add(config);
+ }
+ }
+ return list1;
+ }
+
+ // 8位和校验实现
+ private byte checksum8(byte[] data) {
+ byte sum = 0;
+ for (byte b : data) {
+ sum += b&0xff;
+ }
+ return sum;
+ }
+
}
diff --git a/device_cars/src/main/java/com/xr/device_car/modules/analysis/mapper/MeterReadingRecordMapper.java b/device_cars/src/main/java/com/xr/device_car/modules/analysis/mapper/MeterReadingRecordMapper.java
index c226bf0..fe27af7 100644
--- a/device_cars/src/main/java/com/xr/device_car/modules/analysis/mapper/MeterReadingRecordMapper.java
+++ b/device_cars/src/main/java/com/xr/device_car/modules/analysis/mapper/MeterReadingRecordMapper.java
@@ -11,6 +11,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface MeterReadingRecordMapper extends BaseMapper {
+ void deleteToZt();
+
+ void deleteToLog();
+
+
}
diff --git a/device_cars/src/main/java/com/xr/device_car/modules/analysis/scheduled/Task.java b/device_cars/src/main/java/com/xr/device_car/modules/analysis/scheduled/Task.java
new file mode 100644
index 0000000..91e0692
--- /dev/null
+++ b/device_cars/src/main/java/com/xr/device_car/modules/analysis/scheduled/Task.java
@@ -0,0 +1,20 @@
+package com.xr.device_car.modules.analysis.scheduled;
+
+import com.xr.device_car.modules.analysis.service.MeterReadingRecordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Component
+public class Task {
+
+ @Autowired
+ private MeterReadingRecordService meterReadingRecordService;
+
+ @Scheduled(cron = "0 0 18 * * ?")
+ public void runTask(){
+ meterReadingRecordService.deleteToZt();
+ meterReadingRecordService.deleteToLog();
+ }
+
+}
diff --git a/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/MeterReadingRecordService.java b/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/MeterReadingRecordService.java
index 17892c0..19a5cba 100644
--- a/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/MeterReadingRecordService.java
+++ b/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/MeterReadingRecordService.java
@@ -10,4 +10,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface MeterReadingRecordService extends IService {
+ void deleteToZt();
+ void deleteToLog();
+
}
diff --git a/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/UdpClientService.java b/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/UdpClientService.java
index 2019a7b..aac09a5 100644
--- a/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/UdpClientService.java
+++ b/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/UdpClientService.java
@@ -1,7 +1,9 @@
package com.xr.device_car.modules.analysis.service;
+import io.netty.buffer.ByteBuf;
+
public interface UdpClientService {
- void sendData(String data);
+ void sendData(ByteBuf data);
}
diff --git a/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/impl/MeterReadingRecordServiceImpl.java b/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/impl/MeterReadingRecordServiceImpl.java
index a4be538..bbd3a09 100644
--- a/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/impl/MeterReadingRecordServiceImpl.java
+++ b/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/impl/MeterReadingRecordServiceImpl.java
@@ -17,6 +17,15 @@ import org.springframework.stereotype.Service;
public class MeterReadingRecordServiceImpl extends ServiceImpl
implements MeterReadingRecordService{
+ @Override
+ public void deleteToZt() {
+ ((MeterReadingRecordMapper)this.baseMapper).deleteToZt();
+ }
+
+ @Override
+ public void deleteToLog() {
+ ((MeterReadingRecordMapper)this.baseMapper).deleteToLog();
+ }
}
diff --git a/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/impl/UdpClientServiceImpl.java b/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/impl/UdpClientServiceImpl.java
index 3a99836..ddaabed 100644
--- a/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/impl/UdpClientServiceImpl.java
+++ b/device_cars/src/main/java/com/xr/device_car/modules/analysis/service/impl/UdpClientServiceImpl.java
@@ -3,6 +3,7 @@ package com.xr.device_car.modules.analysis.service.impl;
import com.xr.device_car.modules.analysis.entity.SendUdpLog;
import com.xr.device_car.modules.analysis.service.SendUdpLogService;
import com.xr.device_car.modules.analysis.service.UdpClientService;
+import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.DatagramPacket;
@@ -28,14 +29,14 @@ public class UdpClientServiceImpl implements UdpClientService {
@Override
- public void sendData(String data) {
+ public void sendData(ByteBuf byteBuf) {
SendUdpLog sendUdpLog =new SendUdpLog();
- sendUdpLog.setRequestMsg(data);
+ sendUdpLog.setRequestMsg(byteBuf.toString());
sendUdpLog.setRequestTime(new Date());
- sendUdpLog.setMessageId(data.split("\t")[0]);
+ sendUdpLog.setMessageId(new Date().getTime()+"");
try {
udpChannel.writeAndFlush(new DatagramPacket(
- Unpooled.copiedBuffer(data, CharsetUtil.UTF_8), udpServerAddress)).sync();
+ Unpooled.copiedBuffer(byteBuf), udpServerAddress)).sync();
sendUdpLog.setRequestStatus("0");
} catch (Exception e) {
sendUdpLog.setRequestStatus("1");
diff --git a/device_cars/src/main/resources/application-dev.yml b/device_cars/src/main/resources/application-dev.yml
index 6788324..3aa2509 100644
--- a/device_cars/src/main/resources/application-dev.yml
+++ b/device_cars/src/main/resources/application-dev.yml
@@ -90,5 +90,5 @@ minio:
secretKey: minioadmin
udp:
server:
- host: localhost
+ host: 192.168.1.100
port: 9300
\ No newline at end of file
diff --git a/device_cars/src/main/resources/application-prod.yml b/device_cars/src/main/resources/application-prod.yml
index c805c60..9ba8158 100644
--- a/device_cars/src/main/resources/application-prod.yml
+++ b/device_cars/src/main/resources/application-prod.yml
@@ -13,13 +13,13 @@ spring:
db1:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
- url: jdbc:mysql://192.168.1.252:3306/device_system?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false
+ url: jdbc:mysql://192.168.1.94:3306/device_system?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false
username: root
password: 123456
db2:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
- url: jdbc:mysql://192.168.1.252:3306/image_analysis_zs?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false
+ url: jdbc:mysql://192.168.1.94:3306/image_analysis?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false
username: root
password: 123456
#Hikari连接池配置
@@ -31,13 +31,13 @@ spring:
#自动提交从池中返回的连接
auto-commit: true
#连接允许在池中闲置的最长时间
- idle-timeout: 300000
+ idle-timeout: 30000
#连接池的用户定义名称,主要出现在日志记录和JMX管理控制台中以识别池和池配置
pool-name: DatebookHikariCP
#池中连接最长生命周期
max-lifetime: 18000000
#等待来自池的连接的最大毫秒数
- connection-timeout: 300000
+ connection-timeout: 30000
#验证该连接是否是有效的查询语句
connection-test-query: select 1 from dual
cloud:
@@ -47,9 +47,9 @@ spring:
enabled: false
# redis 相关
redis:
- host: ${REDIS_URL:192.168.1.252}
+ host: ${REDIS_URL:localhost}
port: ${REDIS_PORT:6379}
- password: ${REDIS_PWD:}
+ password: ${REDIS_PWD:111111}
timeout: 10000
jedis:
pool:
@@ -60,27 +60,21 @@ spring:
swagger:
show: true
analysis:
- url: http://192.168.1.252:9000/vi/syncrec
+ url: http://192.168.1.123:9000/vi/syncrec
upLoad:
- path: /home/project/upload
- url: http://192.168.1.252:85/upload/
+ path: D:\\images\\images\\
+ url: http://localhost:85/upload/
+ file: D:\\images\\images\\
python:
path: C:\\Users\\admin\\Anaconda3\\envs\\myconda310\\python.exe
modelPath: D:\\smartGrid\\smartGrid\\models
netty:
- address: 192.168.1.252
- port: 2405
+ address: 192.168.3.20
+ port: 2404
data:
- pathUrl: http://192.168.1.252:8081/api/dataAnalysisCamera/getComer
-udp:
- server:
- host: localhost
- port: 9300
-minio:
- url: http://192.168.1.210:9000
- accessKey: minioadmin
- secretKey: minioadmin
+ pathUrl: http://192.168.1.82:8081/api/dataAnalysisCamera/getComer
+ #pathUrl: http://192.168.1.44:8081/api/dataAnalysisCamera/getComer
eureka:
instance:
instance-id: ${spring.cloud.client.ip-address}:${server.port}
@@ -89,4 +83,12 @@ eureka:
healthcheck:
enabled: true
service-url:
- defaultZone: http://localhost:8084/eureka
\ No newline at end of file
+ defaultZone: http://localhost:8084/eureka
+minio:
+ url: http://192.168.1.210:9000
+ accessKey: minioadmin
+ secretKey: minioadmin
+udp:
+ server:
+ host: 192.168.1.100
+ port: 9300
\ No newline at end of file
diff --git a/device_cars/src/main/resources/application.yml b/device_cars/src/main/resources/application.yml
index 8d7945b..c854e41 100644
--- a/device_cars/src/main/resources/application.yml
+++ b/device_cars/src/main/resources/application.yml
@@ -2,7 +2,7 @@ spring:
profiles:
#active: dev #开发环境
# active: test #测试环境5
- active: dev #生产环境
+ active: prod #生产环境
# active: prod #生产环境
application:
name: deviceCars
diff --git a/device_cars/src/main/resources/modules/analysis/MeterReadingRecordMapper.xml b/device_cars/src/main/resources/modules/analysis/MeterReadingRecordMapper.xml
index d3d7e83..98d50db 100644
--- a/device_cars/src/main/resources/modules/analysis/MeterReadingRecordMapper.xml
+++ b/device_cars/src/main/resources/modules/analysis/MeterReadingRecordMapper.xml
@@ -25,4 +25,12 @@
reading_time,reading_value,create_user,
create_time,update_user,update_time
+
+
+ delete from meter_reading_record WHERE DATE(create_time) = DATE(NOW() - INTERVAL 1 DAY);
+
+
+
+ delete from send_udp_log WHERE DATE(request_time) = DATE(NOW() - INTERVAL 1 DAY);
+
diff --git a/device_iec104/pom.xml b/device_iec104/pom.xml
index f092840..886e829 100644
--- a/device_iec104/pom.xml
+++ b/device_iec104/pom.xml
@@ -97,6 +97,14 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 6
+ 6
+
+
diff --git a/device_iec61850clent/pom.xml b/device_iec61850clent/pom.xml
index 26d7703..479c8d6 100644
--- a/device_iec61850clent/pom.xml
+++ b/device_iec61850clent/pom.xml
@@ -13,7 +13,7 @@
device_iec61850clent
Demo project for Spring Boot
- 8
+ 1.8
@@ -123,6 +123,14 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 8
+ 8
+
+
diff --git a/device_iec61850clent/src/main/java/com/xr/iec61850clent/Iec61850ClentApplication.java b/device_iec61850clent/src/main/java/com/xr/iec61850clent/Iec61850ClentApplication.java
index 242f3a8..9b0ff9b 100644
--- a/device_iec61850clent/src/main/java/com/xr/iec61850clent/Iec61850ClentApplication.java
+++ b/device_iec61850clent/src/main/java/com/xr/iec61850clent/Iec61850ClentApplication.java
@@ -30,7 +30,7 @@ public class Iec61850ClentApplication implements CommandLineRunner {
@Override
@Async
public void run(String[] args){
- Iec61850clent iec61850clent=new Iec61850clent(args,"192.168.1.83",102);
+ Iec61850clent iec61850clent=new Iec61850clent(args,"192.168.1.93",102);
executor.execute(iec61850clent);
// Iec61850clent iec61850clent1=new Iec61850clent(args,"192.168.1.138",102);
// executor.submit(iec61850clent1);
diff --git a/device_iec61850clent/src/main/java/com/xr/iec61850clent/common/util/IEC61850Config.java b/device_iec61850clent/src/main/java/com/xr/iec61850clent/common/util/IEC61850Config.java
index 0a6b804..925d529 100644
--- a/device_iec61850clent/src/main/java/com/xr/iec61850clent/common/util/IEC61850Config.java
+++ b/device_iec61850clent/src/main/java/com/xr/iec61850clent/common/util/IEC61850Config.java
@@ -21,7 +21,7 @@ import java.util.List;
@Component
public class IEC61850Config {
- private static final ThreadLocal> CURRENT_CONFIG = new ThreadLocal<>();
+ private static final ThreadLocal> CURRENT_CONFIG = new ThreadLocal>();
@PostConstruct
public void setExcelConfig(){
@@ -33,7 +33,7 @@ public class IEC61850Config {
InputStream inputStream = IEC61850Config.class.getClassLoader().getResourceAsStream("IEC61850.xlsx");
XSSFWorkbook wb = null;
XSSFSheet sheet = null; // 创建工作sheet
- List dataList = new ArrayList<>();
+ List dataList = new ArrayList();
try {
wb = ExcelUtil.getWorkbook(inputStream);
sheet = ExcelUtil.getFirstSheet(wb);
@@ -140,7 +140,8 @@ public class IEC61850Config {
CURRENT_CONFIG.set(list);
}
for(ExcelConfig config:list){
- String node1 = config.getName()+config.getConnectId()+config.getAddress()+config.getGgio()+"."+config.getAng();
+ float address = Float.valueOf(config.getAddress());
+ String node1 = config.getName()+config.getConnectId()+(int)address+config.getGgio()+"."+config.getAng();
if(ip.equals(config.getDeviceIp()) && node.equals(node1)){
return config;
}
diff --git a/device_iec61850clent/src/main/java/com/xr/iec61850clent/common/util/ModeUtil.java b/device_iec61850clent/src/main/java/com/xr/iec61850clent/common/util/ModeUtil.java
index dffddc3..e1d309b 100644
--- a/device_iec61850clent/src/main/java/com/xr/iec61850clent/common/util/ModeUtil.java
+++ b/device_iec61850clent/src/main/java/com/xr/iec61850clent/common/util/ModeUtil.java
@@ -32,7 +32,7 @@ public class ModeUtil {
lds5000.setClentIp(eunm.getDeviceIp());
lds5000.setNode(node.getReference().toString());
lds5000.setFc(node.getFc().toString());
- List modelNodes=new ArrayList<>(node.getChildren());
+ List modelNodes=new ArrayList(node.getChildren());
for (ModelNode modelNode:modelNodes){
FcModelNode fcModelNode=(FcModelNode) modelNode;
if(fcModelNode.toString().contains("f:")){
diff --git a/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/controller/AiInterfaceController.java b/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/controller/AiInterfaceController.java
index 053715d..ddf20ed 100644
--- a/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/controller/AiInterfaceController.java
+++ b/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/controller/AiInterfaceController.java
@@ -62,7 +62,7 @@ public class AiInterfaceController {
meterReadingRecord.setMeterTypeId(meterConfig.getTypeId());
meterReadingRecord.setOwningInterval(meterConfig.getOwningInterval());
String meterType = MapUtil.getStr(map,"meter_type");
- QueryWrapper queryWrapper=new QueryWrapper<>();
+ QueryWrapper queryWrapper=new QueryWrapper();
queryWrapper.eq("meter_id",meterId);
Integer meterT = null;
if(meterType.equals("floatocr")){//数值型
diff --git a/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/entity/MeterConfig.java b/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/entity/MeterConfig.java
index 3126703..739a454 100644
--- a/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/entity/MeterConfig.java
+++ b/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/entity/MeterConfig.java
@@ -19,19 +19,9 @@ public class MeterConfig implements Serializable {
/**
* 主键
*/
- @TableId(type = IdType.AUTO)
+ @TableId(value = "id", type = IdType.AUTO)
private Integer id;
- /**
- * ids5000表id
- */
- private Integer ids5000Id;
-
- /**
- * 间隔类型 1 分钟 2 小时 3 天
- */
- private Integer intervalType;
-
/**
* 电压等级(1安全电压2低压3高压4超高压5特高压)
*/
@@ -52,16 +42,6 @@ public class MeterConfig implements Serializable {
*/
private String deviceName;
- /**
- * y坐标
- */
- private Double locationY;
-
- /**
- * x坐标
- */
- private Double locationX;
-
/**
* 设备类型
*/
@@ -82,15 +62,11 @@ public class MeterConfig implements Serializable {
*/
private Integer cameraId;
- /**
- * 告警最小值
- */
- private Double warningMax;
+ @TableField(exist = false)
+ private String cameraType;
- /**
- * 告警最大值
- */
- private Double warningMin;
+ @TableField(exist = false)
+ private String cameraName;
/**
* 表计类型配置编号
@@ -108,15 +84,30 @@ public class MeterConfig implements Serializable {
private Date firstTime;
/**
- * 焦距类型 1定焦2变焦
+ * 算法类型 1usb2mipi 3内部算法
*/
- private String focalLength;
+ private String algorithmType;
/**
* 执行间隔时间
*/
private Integer intervalTime;
+ /**
+ * 执行间隔类型 1分钟 2 小时 3 天
+ */
+ private Integer intervalType;
+
+ /**
+ * 告警最大值
+ */
+ private Double warningMax;
+
+ /**
+ * 告警最小值
+ */
+ private Double warningMin;
+
/**
* 焦距数量
*/
@@ -133,9 +124,9 @@ public class MeterConfig implements Serializable {
private String remarks;
/**
- * 61850读数模型
+ * 初始化状态
*/
- private String iec61850mx;
+ private String initStatus;
/**
* 创建人
@@ -152,11 +143,116 @@ public class MeterConfig implements Serializable {
*/
private String updateUser;
+ private int isJz;
+
+ private String jzVal;
+
/**
* 修改时间
*/
private Date updateTime;
+ @TableField(exist = false)
+ private String ip;
+
+ @TableField(exist = false)
+ private String typeAlias;
+
@TableField(exist = false)
private static final long serialVersionUID = 1L;
+
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (that == null) {
+ return false;
+ }
+ if (getClass() != that.getClass()) {
+ return false;
+ }
+ MeterConfig other = (MeterConfig) that;
+ return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
+ && (this.getVoltageClass() == null ? other.getVoltageClass() == null : this.getVoltageClass().equals(other.getVoltageClass()))
+ && (this.getOwningInterval() == null ? other.getOwningInterval() == null : this.getOwningInterval().equals(other.getOwningInterval()))
+ && (this.getIdentificationInterval() == null ? other.getIdentificationInterval() == null : this.getIdentificationInterval().equals(other.getIdentificationInterval()))
+ && (this.getDeviceName() == null ? other.getDeviceName() == null : this.getDeviceName().equals(other.getDeviceName()))
+ && (this.getDeviceType() == null ? other.getDeviceType() == null : this.getDeviceType().equals(other.getDeviceType()))
+ && (this.getMeterCode() == null ? other.getMeterCode() == null : this.getMeterCode().equals(other.getMeterCode()))
+ && (this.getMeterName() == null ? other.getMeterName() == null : this.getMeterName().equals(other.getMeterName()))
+ && (this.getCameraId() == null ? other.getCameraId() == null : this.getCameraId().equals(other.getCameraId()))
+ && (this.getTypeId() == null ? other.getTypeId() == null : this.getTypeId().equals(other.getTypeId()))
+ && (this.getStatus() == null ? other.getStatus() == null : this.getStatus().equals(other.getStatus()))
+ && (this.getFirstTime() == null ? other.getFirstTime() == null : this.getFirstTime().equals(other.getFirstTime()))
+ && (this.getAlgorithmType() == null ? other.getAlgorithmType() == null : this.getAlgorithmType().equals(other.getAlgorithmType()))
+ && (this.getIntervalTime() == null ? other.getIntervalTime() == null : this.getIntervalTime().equals(other.getIntervalTime()))
+ && (this.getFocalNumber() == null ? other.getFocalNumber() == null : this.getFocalNumber().equals(other.getFocalNumber()))
+ && (this.getParameterConfig() == null ? other.getParameterConfig() == null : this.getParameterConfig().equals(other.getParameterConfig()))
+ && (this.getRemarks() == null ? other.getRemarks() == null : this.getRemarks().equals(other.getRemarks()))
+ && (this.getCreateUser() == null ? other.getCreateUser() == null : this.getCreateUser().equals(other.getCreateUser()))
+ && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime()))
+ && (this.getUpdateUser() == null ? other.getUpdateUser() == null : this.getUpdateUser().equals(other.getUpdateUser()))
+ && (this.getUpdateTime() == null ? other.getUpdateTime() == null : this.getUpdateTime().equals(other.getUpdateTime()));
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
+ result = prime * result + ((getVoltageClass() == null) ? 0 : getVoltageClass().hashCode());
+ result = prime * result + ((getOwningInterval() == null) ? 0 : getOwningInterval().hashCode());
+ result = prime * result + ((getIdentificationInterval() == null) ? 0 : getIdentificationInterval().hashCode());
+ result = prime * result + ((getDeviceName() == null) ? 0 : getDeviceName().hashCode());
+ result = prime * result + ((getDeviceType() == null) ? 0 : getDeviceType().hashCode());
+ result = prime * result + ((getMeterCode() == null) ? 0 : getMeterCode().hashCode());
+ result = prime * result + ((getMeterName() == null) ? 0 : getMeterName().hashCode());
+ result = prime * result + ((getCameraId() == null) ? 0 : getCameraId().hashCode());
+ result = prime * result + ((getTypeId() == null) ? 0 : getTypeId().hashCode());
+ result = prime * result + ((getStatus() == null) ? 0 : getStatus().hashCode());
+ result = prime * result + ((getFirstTime() == null) ? 0 : getFirstTime().hashCode());
+ result = prime * result + ((getAlgorithmType() == null) ? 0 : getAlgorithmType().hashCode());
+ result = prime * result + ((getIntervalTime() == null) ? 0 : getIntervalTime().hashCode());
+ result = prime * result + ((getFocalNumber() == null) ? 0 : getFocalNumber().hashCode());
+ result = prime * result + ((getParameterConfig() == null) ? 0 : getParameterConfig().hashCode());
+ result = prime * result + ((getRemarks() == null) ? 0 : getRemarks().hashCode());
+ result = prime * result + ((getCreateUser() == null) ? 0 : getCreateUser().hashCode());
+ result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode());
+ result = prime * result + ((getUpdateUser() == null) ? 0 : getUpdateUser().hashCode());
+ result = prime * result + ((getUpdateTime() == null) ? 0 : getUpdateTime().hashCode());
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName());
+ sb.append(" [");
+ sb.append("Hash = ").append(hashCode());
+ sb.append(", id=").append(id);
+ sb.append(", voltageClass=").append(voltageClass);
+ sb.append(", owningInterval=").append(owningInterval);
+ sb.append(", identificationInterval=").append(identificationInterval);
+ sb.append(", deviceName=").append(deviceName);
+ sb.append(", deviceType=").append(deviceType);
+ sb.append(", meterCode=").append(meterCode);
+ sb.append(", meterName=").append(meterName);
+ sb.append(", cameraId=").append(cameraId);
+ sb.append(", typeId=").append(typeId);
+ sb.append(", status=").append(status);
+ sb.append(", firstTime=").append(firstTime);
+ sb.append(", algorithmType=").append(algorithmType);
+ sb.append(", intervalTime=").append(intervalTime);
+ sb.append(", focalNumber=").append(focalNumber);
+ sb.append(", parameterConfig=").append(parameterConfig);
+ sb.append(", remarks=").append(remarks);
+ sb.append(", createUser=").append(createUser);
+ sb.append(", createTime=").append(createTime);
+ sb.append(", updateUser=").append(updateUser);
+ sb.append(", updateTime=").append(updateTime);
+ sb.append(", serialVersionUID=").append(serialVersionUID);
+ sb.append("]");
+ return sb.toString();
+ }
}
\ No newline at end of file
diff --git a/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/iec61850run/Iec61850clent.java b/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/iec61850run/Iec61850clent.java
index 0b8496d..5e0ad9c 100644
--- a/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/iec61850run/Iec61850clent.java
+++ b/device_iec61850clent/src/main/java/com/xr/iec61850clent/models/iec61850run/Iec61850clent.java
@@ -130,17 +130,12 @@ public class Iec61850clent extends Thread{
MeterConfigService meterConfigService=SpringUtils.getBean(MeterConfigService.class);
MeterReadingRecordService meterReadingRecordService=SpringUtils.getBean(MeterReadingRecordService.class);
MeterTypeService meterTypeService=SpringUtils.getBean(MeterTypeService.class);
- int i=0;
while (true){
try {
- if(i>0){
- sleep(2*60*1000);
- association.getAllDataValues();
- System.out.println("更新模型成功!");
- System.out.println(Arrays.toString(new Collection[]{serverModel.getDataSets()}));
- }else{
- i++;
- }
+ DataSet dSet = serverModel.getDataSet("TEMPLATELD0/LLN0.dsMeasureInfo1");
+ association.getDataSetValues(dSet);
+ System.out.println("更新模型成功!");
+ System.out.println(Arrays.toString(new Collection[]{serverModel.getDataSets()}));
List dataSets=new ArrayList<>(serverModel.getDataSets());
for (DataSet dataSet:dataSets){
List fas=dataSet.getMembers();
@@ -154,12 +149,6 @@ public class Iec61850clent extends Thread{
queryWrapper.eq("clent_ip",host);
Lds5000 lds=lds5000Service.getOne(queryWrapper);
if (lds != null) {
- QueryWrapper q=new QueryWrapper<>();
- q.eq("f",lds5000.getF());
- q.eq("node",lds5000.getNode());
- q.eq("clent_ip",host);
- Lds5000 l=lds5000Service.getOne(q);
- if(l==null){//值发生改变
lds.setUpdateTime(new Date());
lds.setF(lds5000.getF());
lds5000Service.updateById(lds);
@@ -172,7 +161,47 @@ public class Iec61850clent extends Thread{
meterReadingRecord.setMeterId(config.getId());
meterReadingRecord.setReadingType(lds5000.getType());
if(node.getFc().name().equals("MX")){
- meterReadingRecord.setReadingValue(lds5000.getF());
+ String value = "0";
+ float f = Float.valueOf(lds5000.getF());
+ if(config.getTypeId() == 3 || config.getTypeId() == 5 || config.getTypeId() == 7){//油位计,保留2位小数
+ value = String.format("%.2f", f);
+ }
+ if(config.getTypeId() == 4 || config.getTypeId() == 11){//开关计数器
+ //处理为整数
+ int s = (int) f;
+ value = s+"";
+ }
+ if(config.getTypeId() == 8){//档位数据处理
+ //处理为整数
+ int s = (int) f;
+ if(s>7){
+ int t = s-7;
+ if(t == 9){
+ value = "9A";
+ }
+ if(t == 10){
+ value = "9B";
+ }
+ if(t == 11){
+ value = "9C";
+ }
+ if(t>11){
+ value = t-2+"";
+ }
+ }else {
+ value=s+"";
+ }
+ }
+ if(config.getTypeId() == 10){//放电计数器
+ int s = Math.round(f);
+ if(s>=10){
+ value = 0+"";
+ }
+ }
+ if(config.getIsJz() == 1){
+ value = config.getJzVal();
+ }
+ meterReadingRecord.setReadingValue(value);
}else{
meterReadingRecord.setReadingValue(lds5000.getStVal());
}
@@ -183,9 +212,10 @@ public class Iec61850clent extends Thread{
meterReadingRecord.setCreateTime(new Date());
meterReadingRecord.setMeterTypeId(config.getTypeId());
meterReadingRecord.setOwningInterval(config.getOwningInterval());
- meterReadingRecordService.save(meterReadingRecord);
- abnormalReadingJudgment(meterReadingRecord);
- }
+ if(config.getIsJz()!=1){
+ meterReadingRecordService.save(meterReadingRecord);
+ }
+ //abnormalReadingJudgment(meterReadingRecord);
}
}else{
lds5000.setCreateTime(new Date());
@@ -193,6 +223,26 @@ public class Iec61850clent extends Thread{
}
}
}
+ QueryWrapper queryWrapper=new QueryWrapper<>();
+ queryWrapper.eq("is_jz",1);
+ List meterConfigs=meterConfigService.list(queryWrapper);
+ for (MeterConfig config:meterConfigs){
+ MeterReadingRecord meterReadingRecord=new MeterReadingRecord();
+ meterReadingRecord.setMeterId(config.getId());
+ meterReadingRecord.setReadingType(config.getTypeId());
+ meterReadingRecord.setReadingTime(new Date());
+ meterReadingRecord.setReadingType(2);
+ meterReadingRecord.setReadingValue(config.getJzVal());
+ meterReadingRecord.setMeterTypeName("");
+ meterReadingRecord.setMeterCode(config.getMeterCode());
+ meterReadingRecord.setReadingTime(new Date());
+ meterReadingRecord.setCreateUser("SYSTEM");
+ meterReadingRecord.setCreateTime(new Date());
+ meterReadingRecord.setMeterTypeId(config.getTypeId());
+ meterReadingRecord.setOwningInterval(config.getOwningInterval());
+ meterReadingRecordService.save(meterReadingRecord);
+ }
+ sleep(10*60*1000);
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/device_iec61850clent/src/main/resources/IEC61850.xlsx b/device_iec61850clent/src/main/resources/IEC61850.xlsx
index 90e4037881098db094f9e01f543c631934108577..df2be4b816931c8722ad2be7dda7fe603b6cdf0f 100644
GIT binary patch
delta 8969
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
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 7
+ 7
+
+
diff --git a/device_udpclent/pom.xml b/device_udpclent/pom.xml
index 73f3db6..f9ce4bf 100644
--- a/device_udpclent/pom.xml
+++ b/device_udpclent/pom.xml
@@ -162,7 +162,15 @@
-
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 8
+ 8
+
+
+
diff --git a/device_udpclent/src/main/java/com/xr/device_udpclent/common/UdpClientConfig.java b/device_udpclent/src/main/java/com/xr/device_udpclent/common/UdpClientConfig.java
deleted file mode 100644
index 1890b46..0000000
--- a/device_udpclent/src/main/java/com/xr/device_udpclent/common/UdpClientConfig.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.xr.device_udpclent.common;
-
-import io.netty.bootstrap.Bootstrap;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelOption;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.SimpleChannelInboundHandler;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.DatagramChannel;
-import io.netty.channel.socket.DatagramPacket;
-import io.netty.channel.socket.nio.NioDatagramChannel;
-import io.netty.util.CharsetUtil;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import java.net.InetSocketAddress;
-
-@Configuration
-public class UdpClientConfig {
-
- @Value("${udp.server.host}")
- private String serverHost;
-
- @Value("${udp.server.port}")
- private int serverPort;
-
- @Bean
- public DatagramChannel udpChannel() {
- EventLoopGroup group = new NioEventLoopGroup();
- try {
- Bootstrap bootstrap = new Bootstrap();
- bootstrap.group(group)
- .channel(NioDatagramChannel.class)
- .option(ChannelOption.SO_BROADCAST, true)
- .handler(new SimpleChannelInboundHandler() {
- @Override
- protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
- // 处理接收到的数据
- String data = msg.content().toString(CharsetUtil.UTF_8);
- System.out.println("Received data: " + data);
- }
- });
-
- return (DatagramChannel) bootstrap.bind(0).sync().channel();
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- @Bean
- public InetSocketAddress udpServerAddress() {
- return new InetSocketAddress(serverHost, serverPort);
- }
-
-}
diff --git a/device_udpclent/src/main/java/com/xr/device_udpclent/common/utils/EnumUtil.java b/device_udpclent/src/main/java/com/xr/device_udpclent/common/utils/EnumUtil.java
new file mode 100644
index 0000000..08b2716
--- /dev/null
+++ b/device_udpclent/src/main/java/com/xr/device_udpclent/common/utils/EnumUtil.java
@@ -0,0 +1,52 @@
+package com.xr.device_udpclent.common.utils;
+
+import io.netty.buffer.ByteBuf;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+
+/**
+ * @Classname EnumUtil
+ * @Description TODO
+ * @Author Created by gaoby
+ * @Date 2023/3/8 16:28 下午
+ * @Version 1.0
+ */
+public class EnumUtil {
+
+ private static Map map = new ConcurrentHashMap<>();
+
+ /**
+ * 根据条件获取枚举对象
+ *
+ * @param className 枚举类
+ * @param predicate 筛选条件
+ * @param
+ * @return
+ */
+ public static Optional getEnumObject(Class className, Predicate predicate) {
+ if (!className.isEnum()) {
+ return null;
+ }
+ Object obj = map.get(className);
+ T[] ts = null;
+ if (obj == null) {
+ ts = className.getEnumConstants();
+ map.put(className, ts);
+ } else {
+ ts = (T[]) obj;
+ }
+ return Arrays.stream(ts).filter(predicate).findAny();
+ }
+
+ public static String byteBufTo16Str(ByteBuf byteBuf){
+ StringBuilder sb = new StringBuilder();
+ for (int i = byteBuf.readerIndex(); i < byteBuf.writerIndex(); i++) {
+ sb.append(String.format("%02X", byteBuf.getByte(i))+" ");
+ }
+ return sb.toString();
+ }
+}
diff --git a/device_udpclent/src/main/java/com/xr/device_udpclent/models/controller/UdpClentController.java b/device_udpclent/src/main/java/com/xr/device_udpclent/models/controller/UdpClentController.java
deleted file mode 100644
index 7bf3db0..0000000
--- a/device_udpclent/src/main/java/com/xr/device_udpclent/models/controller/UdpClentController.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.xr.device_udpclent.models.controller;
-
-import com.xr.device_udpclent.models.service.UdpClientService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@RequestMapping("udp")
-public class UdpClentController {
-
- @Autowired
- private UdpClientService udpClientService;
-
- @GetMapping("/sendData")
- public void sendData(String data) {
- udpClientService.sendData(data);
- }
-
-}
diff --git a/device_udpclent/src/main/java/com/xr/device_udpclent/models/scheduled/UdpClentScheduled.java b/device_udpclent/src/main/java/com/xr/device_udpclent/models/scheduled/UdpClentScheduled.java
index a13934b..98424e7 100644
--- a/device_udpclent/src/main/java/com/xr/device_udpclent/models/scheduled/UdpClentScheduled.java
+++ b/device_udpclent/src/main/java/com/xr/device_udpclent/models/scheduled/UdpClentScheduled.java
@@ -2,14 +2,21 @@ package com.xr.device_udpclent.models.scheduled;
import cn.hutool.extra.spring.SpringUtil;
import com.xr.device_udpclent.common.config.udp.UdbConfig;
+import com.xr.device_udpclent.common.utils.EnumUtil;
import com.xr.device_udpclent.models.entity.MeterReadingRecord;
import com.xr.device_udpclent.models.service.MeterReadingRecordService;
import com.xr.device_udpclent.models.service.UdpClientService;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
+import java.io.UnsupportedEncodingException;
+import java.util.Calendar;
import java.util.List;
+import java.util.zip.CRC32;
+import java.util.zip.Checksum;
@Component
@@ -24,15 +31,80 @@ public class UdpClentScheduled {
@Scheduled(cron = "0 0/3 * * * ?")
//定时发送监测数据
- public void udpTask(){
+ public void udpTask() throws UnsupportedEncodingException, InterruptedException {
if(meterReadingRecordService == null){
meterReadingRecordService = SpringUtil.getBean(MeterReadingRecordService.class);
}
List list = meterReadingRecordService.selectMaxReading();
for (MeterReadingRecord record:list){
- String writeValue = UdbConfig.getTestMsg(record);
- udpClientService.sendData(writeValue);
+ ByteBuf buf = Unpooled.buffer();
+ ByteBuf checksumBuffer = Unpooled.buffer(Long.BYTES);
+ buf.writeBytes(new byte[]{(byte) 0xEB, (byte) 0x90,(byte) 0xEB, (byte) 0x90,(byte)0x55});
+ buf.writeShortLE(3);
+ buf.writeShort(record.getMeterId());
+ buf.writeByte(2);
+ String s="在线监测";
+ byte [] sx=s.getBytes("GB2312");
+ buf.writeByte(sx.length);
+ buf.writeBytes(sx);
+ byte [] sz = record.getReadingValue().getBytes("GB2312");
+ buf.writeByte(sz.length);
+ buf.writeBytes(sz);
+ buf.writeBytes(generateCP56Time2a());
+
+ // 计算要校验的部分的开始索引和结束索引
+ byte c = 0;
+ int startIndex = 5; // 从第6位开始,索引是5(因为索引从0开始)
+ int endIndex = buf.readableBytes() - 1; // 到倒数第二位结束
+ // 截取并处理指定范围内的字节
+ if (startIndex <= endIndex) {
+ // 临时存放截取的字节
+ byte[] slice = new byte[endIndex - startIndex + 1];
+ // 从ByteBuf中获取数据
+ buf.getBytes(startIndex, slice);
+ c=checksum8(slice);
+ // 更新Checksum对象
+ //checksum.update(slice, 0, slice.length);
+ }
+ buf.writeByte(c);
+ // 将checksumBuffer追加到buffer末尾
+ buf.writeBytes(checksumBuffer);
+ System.out.println(EnumUtil.byteBufTo16Str(buf));
+ udpClientService.sendData(buf);
+ Thread.sleep(100);
+ }
+ }
+
+
+ private byte[] generateCP56Time2a() {
+ Calendar calendar = Calendar.getInstance();
+
+ int milliseconds = calendar.get(Calendar.MILLISECOND);
+ int minute = calendar.get(Calendar.MINUTE);
+ int hour = calendar.get(Calendar.HOUR_OF_DAY);
+ int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
+ int month = calendar.get(Calendar.MONTH) + 1; // Calendar.MONTH is zero based
+ int year = calendar.get(Calendar.YEAR) % 100; // Last two digits of the year
+
+ byte[] cp56Time2a = new byte[7];
+ cp56Time2a[0] = (byte)(milliseconds & 0xFF);
+ cp56Time2a[1] = (byte)((milliseconds >> 8) & 0xFF);
+ cp56Time2a[2] = (byte)(minute & 0xFF);
+ cp56Time2a[3] = (byte)(hour & 0xFF);
+ cp56Time2a[4] = (byte)(dayOfMonth & 0xFF);
+ cp56Time2a[5] = (byte)(month & 0xFF);
+ cp56Time2a[6] = (byte)(year & 0xFF);
+
+ return cp56Time2a;
+ }
+
+ // 8位和校验实现
+ private byte checksum8(byte[] data) {
+ byte sum = 0;
+ for (byte b : data) {
+ sum += b&0xff;
}
+ return sum;
}
}
diff --git a/device_udpclent/src/main/java/com/xr/device_udpclent/models/service/UdpClientService.java b/device_udpclent/src/main/java/com/xr/device_udpclent/models/service/UdpClientService.java
index b6ceb15..c62e78c 100644
--- a/device_udpclent/src/main/java/com/xr/device_udpclent/models/service/UdpClientService.java
+++ b/device_udpclent/src/main/java/com/xr/device_udpclent/models/service/UdpClientService.java
@@ -1,7 +1,9 @@
package com.xr.device_udpclent.models.service;
+import io.netty.buffer.ByteBuf;
+
public interface UdpClientService {
- void sendData(String data);
+ void sendData(ByteBuf byteBuf);
}
diff --git a/device_udpclent/src/main/java/com/xr/device_udpclent/models/service/impl/UdpClientServiceImpl.java b/device_udpclent/src/main/java/com/xr/device_udpclent/models/service/impl/UdpClientServiceImpl.java
index 9b4ac2e..d360045 100644
--- a/device_udpclent/src/main/java/com/xr/device_udpclent/models/service/impl/UdpClientServiceImpl.java
+++ b/device_udpclent/src/main/java/com/xr/device_udpclent/models/service/impl/UdpClientServiceImpl.java
@@ -3,6 +3,7 @@ package com.xr.device_udpclent.models.service.impl;
import com.xr.device_udpclent.models.entity.SendUdpLog;
import com.xr.device_udpclent.models.service.SendUdpLogService;
import com.xr.device_udpclent.models.service.UdpClientService;
+import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.DatagramPacket;
@@ -26,14 +27,14 @@ public class UdpClientServiceImpl implements UdpClientService {
private SendUdpLogService sendUdpLogService;
@Override
- public void sendData(String data) {
+ public void sendData(ByteBuf byteBuf) {
SendUdpLog sendUdbLog=new SendUdpLog();
- sendUdbLog.setRequestMsg(data);
+ sendUdbLog.setRequestMsg(byteBuf.toString());
sendUdbLog.setRequestTime(new Date());
- sendUdbLog.setMessageId(data.split("\t")[0]);
+ sendUdbLog.setMessageId(new Date().getTime()+"");
try {
udpChannel.writeAndFlush(new DatagramPacket(
- Unpooled.copiedBuffer(data, CharsetUtil.UTF_8), udpServerAddress)).sync();
+ Unpooled.copiedBuffer(byteBuf), udpServerAddress)).sync();
sendUdbLog.setRequestStatus("0");
} catch (Exception e) {
sendUdbLog.setRequestStatus("1");
diff --git a/device_udpclent/src/main/resources/application-dev.yml b/device_udpclent/src/main/resources/application-dev.yml
index 0e4a957..95a2024 100644
--- a/device_udpclent/src/main/resources/application-dev.yml
+++ b/device_udpclent/src/main/resources/application-dev.yml
@@ -88,7 +88,7 @@ logging:
logging: debug
udp:
server:
- host: localhost
+ host: 192.168.1.100
port: 9300
upLoad:
path: D:\\images\\images\\
diff --git a/device_udpclent/src/main/resources/application-prod.yml b/device_udpclent/src/main/resources/application-prod.yml
index bfe21b6..63591d8 100644
--- a/device_udpclent/src/main/resources/application-prod.yml
+++ b/device_udpclent/src/main/resources/application-prod.yml
@@ -1,5 +1,5 @@
server:
- port: 8081
+ port: 8091
servlet:
context-path: /api
spring:
@@ -11,13 +11,13 @@ spring:
db1:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
- url: jdbc:mysql://192.168.1.252:3306/device_system?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false
+ url: jdbc:mysql://192.168.1.94:3306/device_system?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false
username: root
password: 123456
db2:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
- url: jdbc:mysql://192.168.1.252:3306/image_analysis_zs?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false
+ url: jdbc:mysql://192.168.1.94:3306/image_analysis?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false
username: root
password: 123456
#Hikari连接池配置
@@ -43,18 +43,30 @@ spring:
timeout-seconds: 1000
config:
enabled: false
- # redis 相关
- redis:
- host: ${REDIS_URL:localhost}
- port: ${REDIS_PORT:6379}
- password: ${REDIS_PWD:111111}
- timeout: 10000
- jedis:
- pool:
- max-active: 1000
- max-wait: -1ms
- max-idle: 10
- min-idle: 5
+ stream:
+ kafka:
+ binder:
+ brokers: localhost:9092 #Kafka的消息中间件服务器
+ zk-nodes: localhost:2181 #Zookeeper的节点,如果集群,后面加,号分隔
+ auto-create-topics: false #如果设置为false,就不会自动创建Topic 有可能你Topic还没创建就直接调用了。
+# kafka:
+# bootstrap-servers: localhost:9092
+# consumer:
+# group-id: ai-consumer-group
+#kafka:
+# topic: ai-topic
+# # redis 相关
+# redis:
+# host: ${REDIS_URL:localhost}
+# port: ${REDIS_PORT:6379}
+# password: ${REDIS_PWD:111111}
+# timeout: 10000
+# jedis:
+# pool:
+# max-active: 1000
+# max-wait: -1ms
+# max-idle: 10
+# min-idle: 5
mybatis-plus:
mapper-locations: classpath:mapper/*Mapper.xml
type-aliases-package: com.xr.device_udpclent
@@ -76,14 +88,14 @@ logging:
logging: debug
udp:
server:
- host: localhost
+ host: 192.168.1.100
port: 9300
-python:
- path: C:\\Users\\admin\\Anaconda3\\envs\\myconda310\\python.exe
- modelPath: D:\\smartGrid\\smartGrid\\models
upLoad:
path: D:\\images\\images\\
url: http://localhost:85/upload/
+python:
+ path: C:\\Users\\admin\\Anaconda3\\envs\\myconda310\\python.exe
+ modelPath: D:\\smartGrid\\smartGrid\\models
eureka:
instance:
instance-id: ${spring.cloud.client.ip-address}:${server.port}
diff --git a/device_udpclent/src/main/resources/application.yml b/device_udpclent/src/main/resources/application.yml
index 9297701..0be90c8 100644
--- a/device_udpclent/src/main/resources/application.yml
+++ b/device_udpclent/src/main/resources/application.yml
@@ -1,6 +1,6 @@
spring:
profiles:
- active: dev #开发环境
+ active: prod #开发环境
# active: test #测试环境5
#active: prod #生产环境
application:
diff --git a/device_udpclent/src/main/resources/logback.xml b/device_udpclent/src/main/resources/logback.xml
new file mode 100644
index 0000000..8c2587c
--- /dev/null
+++ b/device_udpclent/src/main/resources/logback.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
+
+
+
+
+
+
+
+ ${LOG_HOME}/udpClient.log.%d{yyyy-MM-dd}.log
+
+ 30
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
+
+
+
+ 10MB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/device_udpclent/src/main/resources/mapper/MeterReadingRecordMapper.xml b/device_udpclent/src/main/resources/mapper/MeterReadingRecordMapper.xml
index 3ecbaf2..de8091f 100644
--- a/device_udpclent/src/main/resources/mapper/MeterReadingRecordMapper.xml
+++ b/device_udpclent/src/main/resources/mapper/MeterReadingRecordMapper.xml
@@ -30,8 +30,10 @@