From 6474b923d8f6d8ea5e5b63277f18335136c7e33c Mon Sep 17 00:00:00 2001
From: ‘liusuyi’ <1951119284@qq.com>
Date: Mon, 04 Dec 2023 11:24:16 +0800
Subject: [PATCH] 增加动态客户端备用代码 优化雷达追踪引导 优化打印日志

---
 src/main/java/com/ard/utils/tcp/ClientHandler.java            |   25 +
 src/main/java/com/ard/alarm/radar/domain/RadarAlarmData.java  |    2 
 src/main/java/com/ard/utils/tcp/DynamicClient.java            |  150 +++++++++++++
 src/main/java/com/ard/utils/other/ByteUtils.java              |    7 
 src/main/java/com/ard/utils/tcp/DynamicClientHandler.java     |  437 +++++++++++++++++++++++++++++++++++++++
 src/main/java/com/ard/utils/tcp/DynamicClientInitializer.java |   25 ++
 src/main/java/com/ard/utils/tcp/ClientInitialize.java         |    2 
 7 files changed, 635 insertions(+), 13 deletions(-)

diff --git a/src/main/java/com/ard/alarm/radar/domain/RadarAlarmData.java b/src/main/java/com/ard/alarm/radar/domain/RadarAlarmData.java
index e6269d5..8cf17ec 100644
--- a/src/main/java/com/ard/alarm/radar/domain/RadarAlarmData.java
+++ b/src/main/java/com/ard/alarm/radar/domain/RadarAlarmData.java
@@ -17,5 +17,5 @@
     String radarName;
     String alarmTime;
     List<ArdAlarmRadar> ardAlarmRadars;
-    ArdAlarmRadar ardFollowRadar;
+    List<ArdAlarmRadar> ardFollowRadars;
 }
diff --git a/src/main/java/com/ard/utils/other/ByteUtils.java b/src/main/java/com/ard/utils/other/ByteUtils.java
index 0c11f68..fe2ab19 100644
--- a/src/main/java/com/ard/utils/other/ByteUtils.java
+++ b/src/main/java/com/ard/utils/other/ByteUtils.java
@@ -189,7 +189,12 @@
         // System.out.print("校验:"+DatatypeConverter.printHexBinary(bytes));//打印crc32的校验值
         return bytes;
     }
-
+    /**
+     * byte转二进制字符串
+     */
+    public static String byteToBitString(byte b) {
+        return String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0');
+    }
     /**
      * 去除包头包尾
      * 刘苏义
diff --git a/src/main/java/com/ard/utils/tcp/ClientHandler.java b/src/main/java/com/ard/utils/tcp/ClientHandler.java
index 2f62a5f..a032d57 100644
--- a/src/main/java/com/ard/utils/tcp/ClientHandler.java
+++ b/src/main/java/com/ard/utils/tcp/ClientHandler.java
@@ -188,7 +188,8 @@
             byte[] type = Arrays.copyOfRange(data, 0, 1);//命令类型
             //  log.info("命令类型:" + DatatypeConverter.printHexBinary(type));
             byte[] cmdId = Arrays.copyOfRange(data, 1, 2);//命令ID
-            //  log.info("命令ID:" + DatatypeConverter.printHexBinary(cmdId));
+            String cmdIdStr=DatatypeConverter.printHexBinary(cmdId);
+            //log.info("命令ID:" + DatatypeConverter.printHexBinary(cmdId));
             byte[] payloadSize = Arrays.copyOfRange(data, 2, 4);//有效负载大小
             payloadSize = toLittleEndian(payloadSize);
             //log.info("payloadSize:" + DatatypeConverter.printHexBinary(payloadSize));
@@ -196,11 +197,12 @@
             // log.info("有效负载大小(转整型):" + payloadSizeToDecimal);
             //endregion
             List<ArdAlarmRadar> radarAlarmInfos = new ArrayList<>();
-            ArdAlarmRadar radarFollowInfo = null;
+            List<ArdAlarmRadar> radarFollowInfos = new ArrayList<>();
             //抽油机状态雷达推送集合
             List<ArdAlarmRadar> well = new ArrayList<>();
             String alarmTime = "";
             Integer targetNum = 0;
+            log.debug("处理雷达"+radarName+"数据-->命令ID:"+cmdIdStr);
             //雷达移动防火报警
             if (Arrays.equals(cmdId, new byte[]{0x01})) {
                 //region 告警信息反馈
@@ -309,11 +311,15 @@
                     double thetaRadians = Math.toRadians(fTy + 90);
                     // 使用正弦函数计算对边长度
                     Distance = Math.sin(thetaRadians) * Distance;
+                    if(Distance<0)
+                    {
+                        continue;//过滤距离小于0的脏数据
+                    }
                     //log.debug("目标投影距离(m):" + Distance);
 
                     Double[] radarXY = {radarLongitude, radarLagitude};
                     Double[] alarmXY = GisUtils.CalculateCoordinates(radarXY, Distance, (double) fTx);
-                    log.debug("报警信息:" + "【radarId】" + radarId+ "【targetId】" + targetId + "【name】" + alarmPointName + "【alarmType】" + alarmType + "【alarmTime】" + alarmTime + "【distance】" + Distance + "【P】" + fTx + "【T】" + fTy + "【X】" + alarmXY[0] + "【Y】" + alarmXY[1]);
+                    log.debug("报警信息:" + "【radarName】" + radarName + "【targetId】"+ targetId  + "【alarmType】" + alarmType + "【alarmTime】" + alarmTime + "【name】" + alarmPointName+"【Distance】"+Distance);
                     ArdAlarmRadar ardAlarmRadar = new ArdAlarmRadar();
                     ardAlarmRadar.setTargetId(targetId);
                     ardAlarmRadar.setName(alarmPointName);
@@ -324,9 +330,7 @@
                     int bit1 = (cStat[0] >> 1) & 0x1;
                     //目标的B1=1 锁定
                     if (bit1 == 1) {
-                        radarFollowInfo = ardAlarmRadar;
-                        //将追踪锁定的报警对象属性复制给radarFollowInfo对象
-                        //BeanUtils.copyProperties(ardAlarmRadar, radarFollowInfo);
+                        radarFollowInfos.add(ardAlarmRadar);
                     }
                 }
                 //endregion
@@ -342,9 +346,10 @@
                 radarAlarmData.setAlarmTime(alarmTime);
                 radarAlarmData.setArdAlarmRadars(radarAlarmInfos);
                 MqttProducer.publish(2, false, "radar", JSON.toJSONString(radarAlarmData));
-                if (radarFollowInfo != null) {
+                if (radarFollowInfos.size() >0) {
+                    radarAlarmData.setArdFollowRadars(radarFollowInfos);
                     //当前雷达扫描存在引导跟踪数据,只保留最后一次锁定的数据
-                    MqttProducer.publish(2, false, "radarFollowGuide", JSON.toJSONString(radarFollowInfo));
+                    MqttProducer.publish(2, false, "radarFollowGuide", JSON.toJSONString(radarAlarmData));
                 }
                 //抽油机状态MQTT队列
                 radarAlarmData.setArdAlarmRadars(well);
@@ -428,7 +433,7 @@
                         //log.info("所属告警区域名称:" + DatatypeConverter.printHexBinary(szName));
                         String alarmPointName = ByteUtils.bytesToStringZh(szName);
                         // log.info("所属告警区域名称:" + alarmPointName);
-                        log.debug("报警信息:"+ "【radarId】" + radarId + "【targetId】" + targetId + "【name】" + alarmPointName + "【alarmType】" + alarmType + "【alarmTime】" + alarmTime);
+                        log.debug("报警信息:"+ "【radarName】" + radarName + "【targetId】" + targetId + "【name】" + alarmPointName + "【alarmType】" + alarmType + "【alarmTime】" + alarmTime);
                         ArdAlarmRadar ardAlarmRadar = new ArdAlarmRadar();
                         ardAlarmRadar.setTargetId(targetId);
                         ardAlarmRadar.setName(alarmPointName);
@@ -441,7 +446,7 @@
                     //抽油机状态集合中装入数据
                     byte[] szName = Arrays.copyOfRange(data, index + 32, index + 64);
                     String alarmPointName = ByteUtils.bytesToStringZh(szName);
-                    log.debug("报警信息:" + "【radarId】" + radarId + "【targetId】" + targetId + "【name】" + alarmPointName + "【alarmType】抽油机状态报警【alarmState】" + wellType + "【alarmTime】" + alarmTime);
+                    //log.debug("状态信息:" + "【radarName】" + radarName + "【targetId】" + targetId  + "【alarmTime】" + alarmTime + "【name】" + alarmPointName + "【alarmState】" + wellType);
                     ArdAlarmRadar wellAlarm = new ArdAlarmRadar();
                     wellAlarm.setTargetId(targetId);
                     wellAlarm.setName(alarmPointName);
diff --git a/src/main/java/com/ard/utils/tcp/ClientInitialize.java b/src/main/java/com/ard/utils/tcp/ClientInitialize.java
index dfc0ca8..89a5cf7 100644
--- a/src/main/java/com/ard/utils/tcp/ClientInitialize.java
+++ b/src/main/java/com/ard/utils/tcp/ClientInitialize.java
@@ -135,7 +135,7 @@
         for (ArdEquipRadar ardEquipRadar : ardEquipRadars) {
             String host = ardEquipRadar.getIp();
             Integer port = Integer.valueOf(ardEquipRadar.getPort());
-            log.debug("TCP客户端尝试连接:" + host + ":" + port);
+            log.debug("TCP client try to connect radar【:" + host + ":" + port+"】");
             connectServer(ardEquipRadar);//连接每一个雷达服务
         }
     }
diff --git a/src/main/java/com/ard/utils/tcp/DynamicClient.java b/src/main/java/com/ard/utils/tcp/DynamicClient.java
new file mode 100644
index 0000000..e22cb3f
--- /dev/null
+++ b/src/main/java/com/ard/utils/tcp/DynamicClient.java
@@ -0,0 +1,150 @@
+package com.ard.utils.tcp;
+
+import com.ard.alarm.radar.domain.ArdEquipRadar;
+import com.ard.alarm.radar.service.IArdEquipRadarService;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.stereotype.Component;
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * @Description: 雷达动态tcp客户端(备用)
+ * @ClassName: DynamicClient
+ * @Author: 刘苏义
+ * @Date: 2023年11月30日9:25:48
+ **/
+@Slf4j(topic = "netty")
+@Component
+public class DynamicClient {
+    @Resource
+    IArdEquipRadarService ardEquipRadarService;
+
+    @Value("${spring.netty.tcp.enabled}")
+    private Boolean tcpClientEnable;
+
+    private static List<Channel> serverChannels = new ArrayList<>();
+    public static ConcurrentHashMap<Channel, ArdEquipRadar> ConnectMap = new ConcurrentHashMap();
+
+    public static void main(String[] args) throws InterruptedException {
+        EventLoopGroup group = new NioEventLoopGroup();
+        Bootstrap bootstrap = new Bootstrap();
+        bootstrap.group(group)
+                .channel(NioSocketChannel.class)
+                .option(ChannelOption.TCP_NODELAY, true)
+                .option(ChannelOption.SO_KEEPALIVE, true)
+                .handler(new DynamicClientInitializer());
+
+        DynamicClient dynamicClient = new DynamicClient();
+        ArdEquipRadar radar1 = new ArdEquipRadar();
+        radar1.setName("511");
+        radar1.setIp("112.98.126.2");
+        radar1.setPort(1200);
+        dynamicClient.connect(bootstrap, radar1);
+
+        Thread.sleep(2000); // 等待连接建立
+
+        // 模拟动态增加一个服务端
+        ArdEquipRadar radar2 = new ArdEquipRadar();
+        radar2.setName("140");
+        radar2.setIp("112.98.126.2");
+        radar2.setPort(1201);
+        dynamicClient.connect(bootstrap, radar2);
+
+    }
+
+    public void connectToServer(ArdEquipRadar radar) {
+        EventLoopGroup group = new NioEventLoopGroup();
+        try {
+            Bootstrap bootstrap = new Bootstrap();
+            bootstrap.group(group)
+                    .channel(NioSocketChannel.class)
+                    .option(ChannelOption.TCP_NODELAY, true)
+                    .option(ChannelOption.SO_KEEPALIVE, true)
+                    .handler(new DynamicClientInitializer());
+            // 连接服务端
+            ChannelFuture channelFuture = bootstrap.connect(radar.getIp(), radar.getPort()).sync();
+            Channel serverChannel = channelFuture.channel();
+            // 将连接的服务端 Channel 添加到管理列表
+            serverChannels.add(serverChannel);
+            ConnectMap.put(serverChannel, radar);
+            log.debug("雷达【" + radar.getIp() + ":" + radar.getPort() + "】连接成功");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public Channel connect(Bootstrap bootstrap, ArdEquipRadar radar) {
+        ChannelFuture future = bootstrap.connect(radar.getIp(), radar.getPort());
+        future.addListener((ChannelFutureListener) futureListener -> {
+            if (futureListener.isSuccess()) {
+                log.info("Connected to radar device: " + radar.getName() + "【" + radar.getIp() + ":" + radar.getPort() + "】" + " successful");
+                // 在连接建立后,你可以在这里添加业务逻辑或其他处理
+                serverChannels.add(future.channel());
+                ConnectMap.put(future.channel(), radar);
+            } else {
+                log.error("Connection to radar device " + radar.getName() + "【" + radar.getIp() + ":" + radar.getPort() + "】" + " failed. Retrying...");
+                // 连接失败时,定时进行重连
+                futureListener.channel().eventLoop().schedule(
+                        () -> connect(bootstrap, radar),
+                        1L, TimeUnit.SECONDS
+                );
+            }
+        });
+
+        return future.channel();
+    }
+
+    // 在连接建立后可以通过调用这个方法向指定的服务端发送数据
+    public void sendDataToServer(Channel serverChannel, Object data) {
+        serverChannel.writeAndFlush(data);
+    }
+
+    // 关闭指定的服务端连接
+    public void closeServerConnection(Channel serverChannel) {
+        serverChannel.close();
+        serverChannels.remove(serverChannel);
+    }
+
+    // 关闭所有服务端连接
+    public void closeAllServerConnections() {
+        for (Channel serverChannel : serverChannels) {
+            serverChannel.close();
+        }
+        serverChannels.clear();
+    }
+
+    /**
+     * 初始化方法
+     */
+    //@Override
+    public void run(ApplicationArguments args) {
+        if (!tcpClientEnable) {
+            return;
+        }
+        EventLoopGroup group = new NioEventLoopGroup();
+        Bootstrap bootstrap = new Bootstrap();
+        bootstrap.group(group)
+                .channel(NioSocketChannel.class)
+                .option(ChannelOption.TCP_NODELAY, true)
+                .option(ChannelOption.SO_KEEPALIVE, true)
+                .handler(new DynamicClientInitializer());
+        List<ArdEquipRadar> ardEquipRadars = ardEquipRadarService.selectArdEquipRadarList(new ArdEquipRadar());
+        for (ArdEquipRadar ardEquipRadar : ardEquipRadars) {
+            String host = ardEquipRadar.getIp();
+            Integer port = Integer.valueOf(ardEquipRadar.getPort());
+            log.debug("TCP client try to connect radar【:" + host + ":" + port+"】");
+            // connectServer(ardEquipRadar);//连接每一个雷达服务
+            connect(bootstrap, ardEquipRadar);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ard/utils/tcp/DynamicClientHandler.java b/src/main/java/com/ard/utils/tcp/DynamicClientHandler.java
new file mode 100644
index 0000000..ac8483d
--- /dev/null
+++ b/src/main/java/com/ard/utils/tcp/DynamicClientHandler.java
@@ -0,0 +1,437 @@
+package com.ard.utils.tcp;
+
+import com.alibaba.fastjson2.JSON;
+import com.ard.alarm.radar.domain.ArdAlarmRadar;
+import com.ard.alarm.radar.domain.ArdEquipRadar;
+import com.ard.alarm.radar.domain.RadarAlarmData;
+import com.ard.utils.mqtt.MqttProducer;
+import com.ard.utils.other.ByteUtils;
+import com.ard.utils.other.GisUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import javax.xml.bind.DatatypeConverter;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import static com.ard.utils.other.ByteUtils.byteToBitString;
+import static com.ard.utils.other.ByteUtils.toLittleEndian;
+
+/**
+ * @Description: 客户端数据处理器(备用)
+ * @ClassName: DynamicClientHandler
+ * @Author: 刘苏义
+ * @Date: 2023年11月30日9:27:55
+ **/
+@Slf4j(topic = "netty")
+class DynamicClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
+    /**
+     * 连接建立
+     *
+     * @param ctx
+     * @throws Exception
+     */
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) {
+        context = ctx;
+        startHeartbeatTask();//开始发送心跳
+    }
+
+    @Override
+    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
+        // 处理接收到的数据
+        // ...
+        Channel channel = ctx.channel();
+        ArdEquipRadar ardEquipRadar = DynamicClient.ConnectMap.get(channel);
+        // 处理接收到的消息
+        byte[] byteArray = new byte[msg.readableBytes()];
+        msg.getBytes(msg.readerIndex(), byteArray);
+        byte[] bytes = MessageParsing.receiveCompletePacket(byteArray);
+        if (bytes != null) {
+            processData(ardEquipRadar, bytes);
+        }
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        // 处理异常
+        // ...
+        log.error("处理异常");
+    }
+
+    private ScheduledFuture<?> heartbeatTask;
+    private ChannelHandlerContext context;
+
+    /**
+     * 开始心跳任务
+     */
+    private void startHeartbeatTask() {
+        heartbeatTask = context.executor().scheduleAtFixedRate(() -> {
+            // 发送心跳消息
+            ByteBuf message = context.alloc().buffer();
+            byte[] header = {0x01, 0x02, 0x01};
+            byte[] payload = {0x10, 0x00, 0x00, 0x00};
+            byte[] payloadCrc32 = ByteUtils.parseCrc32(payload);
+            byte[] footer = {0x01, 0x02, 0x00};
+            byte[] heart = ByteUtils.appendArrays(header, payload, payloadCrc32, footer);
+//            byte[] heart = {0x01, 0x02, 0x01, 0x10, 0x00, 0x00, 0x00, (byte) 0x83, (byte) 0x88, 0x5d, 0x71, 0x01, 0x02, 0x00};
+            String hexString = DatatypeConverter.printHexBinary(heart);
+            // log.debug("发送心跳:" + hexString);
+            message.writeBytes(heart);
+            context.writeAndFlush(message);
+
+        }, 0, 5, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 停止心跳任务
+     */
+    private void stopHeartbeatTask() {
+        if (heartbeatTask != null) {
+            heartbeatTask.cancel(false);
+            heartbeatTask = null;
+        }
+    }
+
+    /**
+     * 解析报警数据
+     */
+    public void processData(ArdEquipRadar ardEquipRadarbyte, byte[] data) {
+        try {
+            String radarId = ardEquipRadarbyte.getId();
+            String radarName = ardEquipRadarbyte.getName();
+            Double radarLongitude = ardEquipRadarbyte.getLongitude();
+            Double radarLagitude = ardEquipRadarbyte.getLatitude();
+            Double radarAltitude = ardEquipRadarbyte.getAltitude();
+            //region crc校验-目前仅用于显示校验结果
+            Boolean crc32Check = MessageParsing.CRC32Check(data);
+            if (!crc32Check) {
+                log.debug("CRC32校验不通过");
+            } else {
+                //log.debug("CRC32校验通过");
+            }
+            //endregion
+            //log.info("原始数据:" + DatatypeConverter.printHexBinary(data));
+            //log.info("雷达信息:" + host + "【port】" + port + "【X】" + longitude + "【Y】" + lagitude + "【Z】" + altitude);
+            data = MessageParsing.transferData(data);//去掉包头和包尾、校验及转义
+            //region 负载头解析
+            byte[] type = Arrays.copyOfRange(data, 0, 1);//命令类型
+            //  log.info("命令类型:" + DatatypeConverter.printHexBinary(type));
+            byte[] cmdId = Arrays.copyOfRange(data, 1, 2);//命令ID
+            String cmdIdStr = DatatypeConverter.printHexBinary(cmdId);
+            //log.info("命令ID:" + DatatypeConverter.printHexBinary(cmdId));
+            byte[] payloadSize = Arrays.copyOfRange(data, 2, 4);//有效负载大小
+            payloadSize = toLittleEndian(payloadSize);
+            //log.info("payloadSize:" + DatatypeConverter.printHexBinary(payloadSize));
+            int payloadSizeToDecimal = ByteUtils.bytesToDecimal(payloadSize);
+            // log.info("有效负载大小(转整型):" + payloadSizeToDecimal);
+            //endregion
+            List<ArdAlarmRadar> radarAlarmInfos = new ArrayList<>();
+            ArdAlarmRadar radarFollowInfo = null;
+            //抽油机状态雷达推送集合
+            List<ArdAlarmRadar> well = new ArrayList<>();
+            String alarmTime = "";
+            Integer targetNum = 0;
+            log.debug("Processing radar data 【" + radarName + "】数据-->命令ID:"  + cmdIdStr + "二进制:" + byteToBitString(cmdId[0]));
+            //雷达移动防火报警
+            if (Arrays.equals(cmdId, new byte[]{0x01})) {
+                //region 告警信息反馈
+                byte[] dwTim = Arrays.copyOfRange(data, 4, 8);
+                dwTim = toLittleEndian(dwTim);
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                long l = ByteUtils.bytesToDecimal(dwTim);
+                alarmTime = sdf.format(l * 1000);
+                // log.info("周视图像的出现时间(转date):" + alarmTime);
+
+                byte[] wTargetNum = Arrays.copyOfRange(data, 8, 10);
+                wTargetNum = toLittleEndian(wTargetNum);
+                targetNum = ByteUtils.bytesToDecimal(wTargetNum);
+                if (targetNum == 0) {
+                    return;
+                }
+                //log.debug("目标总点数(转整型):" + targetNum);
+
+                //解析NET_TARGET_UNIT(64是NET_TARGET_HEAD的字节数)
+                int uintSize = (payloadSizeToDecimal - 64) / targetNum;
+                // log.info("单条报警大小:" + uintSize);
+
+                for (int i = 0; i < targetNum; i++) {
+
+                    Integer index = 68 + uintSize * i;
+                    byte[] dwID = Arrays.copyOfRange(data, index, index + 4);
+                    // log.info("目标ID:" + DatatypeConverter.printHexBinary(cmdId));
+                    dwID = toLittleEndian(dwID);
+                    int targetId = ByteUtils.bytesToDecimal(dwID);
+                    // log.info("目标ID号:" + targetId);
+
+                    byte[] iDistance = Arrays.copyOfRange(data, index + 8, index + 12);
+                    iDistance = toLittleEndian(iDistance);
+                    double Distance = ByteUtils.bytesToDecimal(iDistance);
+                    //log.debug("目标当前直线距离(m):" + Distance);
+
+                    //region 不需要的字段
+//                    byte[] dwGSum = Arrays.copyOfRange(data, index + 4, index + 8);
+//                    dwGSum = toLittleEndian(dwGSum);
+//                    int GSum = byteArrayToDecimal(dwGSum);
+//                    log.info("目标当前像素灰度和:" + GSum);
+//                    byte[] iTw = Arrays.copyOfRange(data, index + 12, index + 16);
+//                    iTw = toLittleEndian(iTw);
+//                    int Tw = byteArrayToDecimal(iTw);
+//                    log.info("目标当前的像素宽度:" + Tw);
+//
+//                    byte[] iTh = Arrays.copyOfRange(data, index + 16, index + 20);
+//                    iTh = toLittleEndian(iTh);
+//                    int Th = byteArrayToDecimal(iTh);
+//                    log.info("目标当前的像素高度:" + Th);
+//
+//                    byte[] wPxlArea = Arrays.copyOfRange(data, index + 20, index + 22);
+//                    wPxlArea = toLittleEndian(wPxlArea);
+//                    int PxlArea = byteArrayToDecimal(wPxlArea);
+//                    log.info("目标当前像素面积:" + PxlArea);
+//
+//                    byte[] cTrkNum = Arrays.copyOfRange(data, index + 22, index + 23);
+//                    cTrkNum = toLittleEndian(cTrkNum);
+//                    int TrkNum = byteArrayToDecimal(cTrkNum);
+//                    log.info("轨迹点数:" + TrkNum);
+
+//                    byte[] sVx = Arrays.copyOfRange(data, index + 24, index + 26);
+//                    sVx = toLittleEndian(sVx);
+//                    int Vx = byteArrayToDecimal(sVx);
+//                    log.info("目标当前速度矢量(像素距离)X:" + Vx);
+//
+//                    byte[] sVy = Arrays.copyOfRange(data, index + 26, index + 28);
+//                    sVy = toLittleEndian(sVy);
+//                    int Vy = byteArrayToDecimal(sVy);
+//                    log.info("目标当前速度矢量(像素距离)Y:" + Vy);
+//
+//                    byte[] sAreaNo = Arrays.copyOfRange(data, index + 28, index + 30);
+//                    sAreaNo = toLittleEndian(sAreaNo);
+//                    int AreaNo = byteArrayToDecimal(sAreaNo);
+//                    log.info("目标归属的告警区域号:" + AreaNo);
+//
+//                    byte[] cGrp = Arrays.copyOfRange(data, index + 30, index + 31);
+//                    cGrp = toLittleEndian(cGrp);
+//                    int Grp = byteArrayToDecimal(cGrp);
+//                    log.info("所属组:" + Grp);
+                    //endregion
+                    String alarmType = "";
+                    byte[] cStat = Arrays.copyOfRange(data, index + 23, index + 24);
+                    log.info("原始状态:" + byteToBitString(cStat[0]));
+                    // cStat = toLittleEndian(cStat);
+                    // 提取第4位至第6位的值
+                    int extractedValue = (cStat[0] >> 4) & 0b00001111;
+                    // 判断提取的值
+                    if (extractedValue == 0b0000) {
+                        alarmType = "运动目标检测";
+                    } else if (extractedValue == 0b0001) {
+                        alarmType = "热源检测";
+                    }
+                    // log.info("报警类型:" + alarmType);
+                    byte[] szName = Arrays.copyOfRange(data, index + 64, index + 96);
+                    String alarmPointName = ByteUtils.bytesToStringZh(szName);
+                    // log.info("所属告警区域名称:" + alarmPointName);
+                    byte[] afTx = Arrays.copyOfRange(data, index + 96, index + 100);
+                    afTx = toLittleEndian(afTx);
+                    float fTx = ByteUtils.bytesToFloat(afTx);
+                    //  log.info("水平角度:" + fTx);
+                    byte[] afTy = Arrays.copyOfRange(data, index + 112, index + 116);
+                    afTy = toLittleEndian(afTy);
+                    float fTy = ByteUtils.bytesToFloat(afTy);
+                    //log.debug("垂直角度:" + fTy);
+                    // 将角度转换为弧度
+                    double thetaRadians = Math.toRadians(fTy + 90);
+                    // 使用正弦函数计算对边长度
+                    Distance = Math.sin(thetaRadians) * Distance;
+                    //log.debug("目标投影距离(m):" + Distance);
+
+                    Double[] radarXY = {radarLongitude, radarLagitude};
+                    Double[] alarmXY = GisUtils.CalculateCoordinates(radarXY, Distance, (double) fTx);
+                    log.debug("报警信息:" + "【radarName】" + radarName + "【targetId】" + targetId + "【alarmType】" + alarmType + "【alarmTime】" + alarmTime + "【name】" + alarmPointName);
+                    ArdAlarmRadar ardAlarmRadar = new ArdAlarmRadar();
+                    ardAlarmRadar.setTargetId(targetId);
+                    ardAlarmRadar.setName(alarmPointName);
+                    ardAlarmRadar.setLongitude(alarmXY[0]);
+                    ardAlarmRadar.setLatitude(alarmXY[1]);
+                    ardAlarmRadar.setAlarmType(alarmType);
+                    radarAlarmInfos.add(ardAlarmRadar);
+
+                    int bit1 = (cStat[0] >> 1) & 0x1;
+                    //目标的B1=1 锁定
+                    if (bit1 == 1) {
+                        radarFollowInfo = ardAlarmRadar;
+                        //将追踪锁定的报警对象属性复制给radarFollowInfo对象
+                        //BeanUtils.copyProperties(ardAlarmRadar, radarFollowInfo);
+                    }
+                }
+                //endregion
+                if (StringUtils.isEmpty(alarmTime)) {
+                    return;
+                }
+                if (targetNum == 0) {
+                    return;
+                }
+                RadarAlarmData radarAlarmData = new RadarAlarmData();
+                radarAlarmData.setRadarId(radarId);
+                radarAlarmData.setRadarName(radarName);
+                radarAlarmData.setAlarmTime(alarmTime);
+                radarAlarmData.setArdAlarmRadars(radarAlarmInfos);
+                MqttProducer.publish(2, false, "radar", JSON.toJSONString(radarAlarmData));
+                if (radarFollowInfo != null) {
+                    //当前雷达扫描存在引导跟踪数据,只保留最后一次锁定的数据
+                    MqttProducer.publish(2, false, "radarFollowGuide", JSON.toJSONString(radarFollowInfo));
+                }
+                //抽油机状态MQTT队列
+                radarAlarmData.setArdAlarmRadars(well);
+                MqttProducer.publish(2, false, "radarWellData", JSON.toJSONString(radarAlarmData));
+
+            }
+            //抽油机AI状态反馈
+            if (Arrays.equals(cmdId, new byte[]{0x04})) {
+                //region抽油机AI状态反馈
+                String hexString = DatatypeConverter.printHexBinary(data);
+                //log.info(hexString);
+
+                byte[] dwTim = Arrays.copyOfRange(data, 4, 8);
+                dwTim = toLittleEndian(dwTim);
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                long l = ByteUtils.bytesToDecimal(dwTim);
+                alarmTime = sdf.format(l * 1000);
+                //log.info("周视图像的出现时间(转date):" + alarmTime);
+
+                byte[] wTargetNum = Arrays.copyOfRange(data, 8, 10);
+                wTargetNum = toLittleEndian(wTargetNum);
+                targetNum = ByteUtils.bytesToDecimal(wTargetNum);
+                //log.debug("目标总点数(转整型):" + targetNum);
+                if (targetNum == 0) {
+                    return;
+                }
+                //解析NET_TARGET_UNIT(64是NET_TARGET_HEAD的字节数)
+                int uintSize = (payloadSizeToDecimal - 64) / targetNum;
+                //log.info("单条报警大小:" + uintSize);
+                for (int i = 0; i < targetNum; i++) {
+                    Integer index = 68 + uintSize * i;
+                    byte[] dwID = Arrays.copyOfRange(data, index, index + 4);
+                    //log.info("目标ID:" + DatatypeConverter.printHexBinary(dwID));
+                    dwID = toLittleEndian(dwID);
+                    int targetId = ByteUtils.bytesToDecimal(dwID);
+                    //log.info("目标ID号:" + targetId);
+                    //region 不需要的字段
+                    byte[] iTw = Arrays.copyOfRange(data, index + 4, index + 8);
+                    iTw = toLittleEndian(iTw);
+                    int Tw = ByteUtils.bytesToDecimal(iTw);
+                    // log.info("目标当前的像素宽度:" + Tw);
+
+                    byte[] iTh = Arrays.copyOfRange(data, index + 8, index + 12);
+                    iTh = toLittleEndian(iTh);
+                    int Th = ByteUtils.bytesToDecimal(iTh);
+                    //log.info("目标当前的像素高度:" + Th);
+
+                    byte[] fTx = Arrays.copyOfRange(data, index + 12, index + 16);
+                    fTx = toLittleEndian(fTx);
+                    float fTxAngle = ByteUtils.bytesToFloat(fTx);
+                    //log.debug("p角度:" + fTxAngle);
+                    byte[] fTy = Arrays.copyOfRange(data, index + 16, index + 20);
+                    fTy = toLittleEndian(fTy);
+                    float fTyAngle = ByteUtils.bytesToFloat(fTy);
+                    //log.debug("t角度:" + fTyAngle);
+
+                    byte[] sAreaNo = Arrays.copyOfRange(data, index + 20, index + 22);
+                    sAreaNo = toLittleEndian(sAreaNo);
+                    int AreaNo = ByteUtils.bytesToDecimal(sAreaNo);
+                    //log.debug("目标归属的告警区域号:" + AreaNo);
+
+                    byte[] cGrp = Arrays.copyOfRange(data, index + 22, index + 23);
+                    cGrp = toLittleEndian(cGrp);
+                    int Grp = ByteUtils.bytesToDecimal(cGrp);
+                    //log.info("所属组:" + Grp);
+                    //endregion
+                    String alarmType;
+                    //抽油机状态变量
+                    String wellType;
+                    byte[] cStat = Arrays.copyOfRange(data, index + 23, index + 24);
+                    cStat = toLittleEndian(cStat);
+                    //String binaryString = String.format("%8s", Integer.toBinaryString(cStat[0] & 0xFF)).replace(' ', '0');
+                    //log.info("目标当前状态:" + binaryString);
+                    // 提取第0位值
+                    // 使用位运算操作判断第0位是否为1
+                    boolean isB0 = (cStat[0] & 0x01) == 0x00;
+                    // 判断提取的值
+                    if (isB0) {
+                        alarmType = "雷达抽油机停机";
+                        byte[] szName = Arrays.copyOfRange(data, index + 32, index + 64);
+                        //log.info("所属告警区域名称:" + DatatypeConverter.printHexBinary(szName));
+                        String alarmPointName = ByteUtils.bytesToStringZh(szName);
+                        // log.info("所属告警区域名称:" + alarmPointName);
+                        //log.debug("报警信息:"+ "【radarName】" + radarName + "【targetId】" + targetId + "【name】" + alarmPointName + "【alarmType】" + alarmType + "【alarmTime】" + alarmTime);
+                        ArdAlarmRadar ardAlarmRadar = new ArdAlarmRadar();
+                        ardAlarmRadar.setTargetId(targetId);
+                        ardAlarmRadar.setName(alarmPointName);
+                        ardAlarmRadar.setAlarmType(alarmType);
+                        radarAlarmInfos.add(ardAlarmRadar);
+                        wellType = "停机";
+                    } else {
+                        wellType = "运行";
+                    }
+                    //抽油机状态集合中装入数据
+                    byte[] szName = Arrays.copyOfRange(data, index + 32, index + 64);
+                    String alarmPointName = ByteUtils.bytesToStringZh(szName);
+                    log.debug("报警信息:" + "【radarName】" + radarName + "【targetId】" + targetId + "【alarmType】抽油机状态报警" + "【alarmTime】" + alarmTime + "【name】" + alarmPointName + "【alarmState】" + wellType);
+                    ArdAlarmRadar wellAlarm = new ArdAlarmRadar();
+                    wellAlarm.setTargetId(targetId);
+                    wellAlarm.setName(alarmPointName);
+                    wellAlarm.setAlarmType(wellType);
+                    well.add(wellAlarm);
+                }
+                //endregion
+                if (StringUtils.isEmpty(alarmTime)) {
+                    return;
+                }
+                if (targetNum == 0) {
+                    return;
+                }
+                RadarAlarmData radarAlarmData = new RadarAlarmData();
+                radarAlarmData.setRadarId(radarId);
+                radarAlarmData.setRadarName(radarName);
+                radarAlarmData.setAlarmTime(alarmTime);
+                radarAlarmData.setArdAlarmRadars(radarAlarmInfos);
+                MqttProducer.publish(2, false, "radar", JSON.toJSONString(radarAlarmData));
+                //抽油机状态MQTT队列
+                radarAlarmData.setArdAlarmRadars(well);
+                MqttProducer.publish(2, false, "radarWellData", JSON.toJSONString(radarAlarmData));
+            }
+            //强制引导
+            if (Arrays.equals(cmdId, new byte[]{0x02})) {
+                //region 告警前端发送的强制引导信息
+                byte[] iDistance = Arrays.copyOfRange(data, 4, 8);
+                iDistance = toLittleEndian(iDistance);
+                long distance = ByteUtils.bytesToDecimal(iDistance);
+                log.info("目标当前距离(m):" + distance);
+                byte[] fTx = Arrays.copyOfRange(data, 8, 12);
+                fTx = toLittleEndian(fTx);
+                float tx = ByteUtils.bytesToFloat(fTx);
+                log.debug("方位:" + tx);
+                byte[] fTy = Arrays.copyOfRange(data, 12, 16);
+                fTy = toLittleEndian(fTy);
+                float ty = ByteUtils.bytesToFloat(fTy);
+                if (ty < 0) {
+                    ty += 360;
+                }
+                log.debug("俯仰:" + ty);
+                Map<String, Object> forceGuideMap = new HashMap<>();
+                forceGuideMap.put("distance", distance);
+                forceGuideMap.put("p", tx);
+                forceGuideMap.put("t", ty);
+                forceGuideMap.put("radarId", radarId);
+                log.debug("强制引导信息" + forceGuideMap);
+                //endregion
+                MqttProducer.publish(2, false, "radarForceGuide", JSON.toJSONString(forceGuideMap));
+            }
+        } catch (Exception ex) {
+            log.error("雷达报文解析异常:" + ex.getMessage());
+        }
+    }
+}
diff --git a/src/main/java/com/ard/utils/tcp/DynamicClientInitializer.java b/src/main/java/com/ard/utils/tcp/DynamicClientInitializer.java
new file mode 100644
index 0000000..0a84573
--- /dev/null
+++ b/src/main/java/com/ard/utils/tcp/DynamicClientInitializer.java
@@ -0,0 +1,25 @@
+package com.ard.utils.tcp;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+
+/**
+ * @Description: 初始化客户端的通道(备用)
+ * @ClassName: DynamicClientInitializer
+ * @Author: 刘苏义
+ * @Date: 2023年11月30日9:27:03
+ **/
+public class DynamicClientInitializer extends ChannelInitializer<SocketChannel> {
+    @Override
+    protected void initChannel(SocketChannel ch){
+        try {
+            ChannelPipeline pipeline = ch.pipeline();
+            // 添加你需要的处理器
+            pipeline.addLast(new DynamicClientHandler());
+        }catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+}

--
Gitblit v1.9.3