From 054a8590eae38713c0cdb044d03ae17aaa70dbdf Mon Sep 17 00:00:00 2001 From: zcxlsm Date: Sat, 9 Aug 2025 23:22:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(sis):=20-=20=E4=BC=98=E5=8C=96=E7=94=B5?= =?UTF-8?q?=E6=A2=AF=E6=8E=A7=E5=88=B6=E9=80=BB=E8=BE=91=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=A4=96=E9=83=A8=E6=8C=89=E9=94=AE=E8=A7=A6=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumer/CleanLiftAuthRocketConsumer.java | 54 +++-- .../dromara/sis/domain/SisDeviceManage.java | 5 + .../sis/domain/bo/SisDeviceManageBo.java | 5 + .../sis/domain/vo/SisDeviceManageVo.java | 5 + .../sis/dubbo/RemoteSisAuthServiceImpl.java | 3 + .../dromara/sis/runner/ElevatorTcpRunner.java | 35 ++- .../sis/sdk/hik/calback/HikAlarmCallBack.java | 61 ++++- ...lUtil.java => ElevatorControlTcpUtil.java} | 222 ++++++++++-------- .../sis/service/ISisDeviceManageService.java | 9 +- .../service/IZeroSensationPassageService.java | 7 + .../impl/SisDeviceManageServiceImpl.java | 15 +- .../impl/SisElevatorFloorRefServiceImpl.java | 3 + .../impl/SisElevatorInfoServiceImpl.java | 2 +- .../impl/ZeroSensationPassageServiceImpl.java | 49 +++- 14 files changed, 312 insertions(+), 163 deletions(-) rename ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/smartDevices/utils/{ElevatorControlUtil.java => ElevatorControlTcpUtil.java} (56%) diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/consumer/CleanLiftAuthRocketConsumer.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/consumer/CleanLiftAuthRocketConsumer.java index 914636a0..d07ae729 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/consumer/CleanLiftAuthRocketConsumer.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/consumer/CleanLiftAuthRocketConsumer.java @@ -33,31 +33,35 @@ public class CleanLiftAuthRocketConsumer implements RocketMQListener public void onMessage(MessageExt ext) { log.info("【消费者】接收消息:消息体 => {}", new String(ext.getBody())); - Long deviceId = Long.parseLong(ext.getUserProperty("deviceId")); - Long groupId = Long.parseLong(ext.getUserProperty("groupId")); - Long deviceFloorId = Long.parseLong(ext.getUserProperty("deviceFloorId")); - - // 获取当前电梯信息 - SisElevatorInfoVo ele = sisElevatorInfoService.queryById(deviceId); - - // 获取权限组下电梯⇄楼层关联信息 - List groupRef = sisElevatorFloorRefService.queryByAuthGroupId(groupId); - - // 取出当前电梯的楼层授权信息 - List eleRef = groupRef.stream().filter(o -> Objects.equals(o.getElevatorId(), deviceId)).toList(); - - for (SisElevatorFloorRefVo ref : eleRef){ - if (ref.getUpChannel() != null && Objects.equals(ref.getFloorId(), deviceFloorId)){ - HikApiService.getInstance().controlGateway(ele.getControlIp(), ref.getUpChannel().intValue(), 3); - } - - if (ref.getDownChannel() != null && Objects.equals(ref.getFloorId(), deviceFloorId)){ - HikApiService.getInstance().controlGateway(ele.getControlIp(), ref.getDownChannel().intValue(), 3); - } - - if (ref.getInChannel() != null && Objects.equals(ref.getFloorId(), deviceFloorId)){ - HikApiService.getInstance().controlGateway(ele.getControlIp(), ref.getInChannel().intValue(), 3); - } +// Long deviceId = Long.parseLong(ext.getUserProperty("deviceId")); +// Long groupId = Long.parseLong(ext.getUserProperty("groupId")); +// Long deviceFloorId = Long.parseLong(ext.getUserProperty("deviceFloorId")); +// +// // 获取当前电梯信息 +// SisElevatorInfoVo ele = sisElevatorInfoService.queryById(deviceId); +// +// // 获取权限组下电梯⇄楼层关联信息 +// List groupRef = sisElevatorFloorRefService.queryByAuthGroupId(groupId); +// +// // 取出当前电梯的楼层授权信息 +// List eleRef = groupRef.stream().filter(o -> Objects.equals(o.getElevatorId(), deviceId)).toList(); +// +// for (SisElevatorFloorRefVo ref : eleRef){ +// if (ref.getUpChannel() != null && Objects.equals(ref.getFloorId(), deviceFloorId)){ +// HikApiService.getInstance().controlGateway(ele.getControlIp(), ref.getUpChannel().intValue(), 3); +// } +// +// if (ref.getDownChannel() != null && Objects.equals(ref.getFloorId(), deviceFloorId)){ +// HikApiService.getInstance().controlGateway(ele.getControlIp(), ref.getDownChannel().intValue(), 3); +// } +// +// if (ref.getInChannel() != null && Objects.equals(ref.getFloorId(), deviceFloorId)){ +// HikApiService.getInstance().controlGateway(ele.getControlIp(), ref.getInChannel().intValue(), 3); +// } +// } + // todo 暂时应急处理,后续调整业务逻辑 + for (int i = 1; i < 20; i++) { + HikApiService.getInstance().controlGateway("192.168.24.150", i, 3); } log.info("梯控清除权限完成"); } diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/SisDeviceManage.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/SisDeviceManage.java index 38fd0d3c..4ad5765b 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/SisDeviceManage.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/SisDeviceManage.java @@ -85,4 +85,9 @@ public class SisDeviceManage extends BaseEntity { */ private Long floorId; + /** + * 是否支持人脸比对 + */ + private Boolean isComparison; + } diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/bo/SisDeviceManageBo.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/bo/SisDeviceManageBo.java index 81662907..aa10a140 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/bo/SisDeviceManageBo.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/bo/SisDeviceManageBo.java @@ -83,6 +83,11 @@ public class SisDeviceManageBo extends BaseEntity { */ private Long groupId; + /** + * 是否支持人脸比对 + */ + private Boolean isComparison; + private String tenantId; } diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/vo/SisDeviceManageVo.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/vo/SisDeviceManageVo.java index 0c56837a..17429d5f 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/vo/SisDeviceManageVo.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/domain/vo/SisDeviceManageVo.java @@ -95,4 +95,9 @@ public class SisDeviceManageVo implements Serializable { private Long groupId; private String groupName; + + /** + * 是否支持人脸比对 + */ + private Boolean isComparison; } diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/dubbo/RemoteSisAuthServiceImpl.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/dubbo/RemoteSisAuthServiceImpl.java index 10dbe3a0..03fa14e8 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/dubbo/RemoteSisAuthServiceImpl.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/dubbo/RemoteSisAuthServiceImpl.java @@ -107,9 +107,12 @@ public class RemoteSisAuthServiceImpl implements RemoteSisAuthService { public Long syncHuaweiBox(RemotePersonAuth person, byte[] imgByte) { Long pId; try { + SisPersonLibImgVo vo = sisPersonLibImgService.queryByPersonId(person.getId()); AddHWPersonReq req = new AddHWPersonReq(); req.setIndex(CodePrefixConstants.PERSON_LIB_IMAGE_CODE_PREFIX + IdUtil.getSnowflakeNextIdStr()); req.setName(person.getName()); + req.setCredentialType("5"); + req.setCredentialNumber(vo.getId().toString()); req.setGender(person.getSex() == 1 ? "0" : person.getSex() == 2 ? "1" : "-1"); ArrayList pictures = new ArrayList<>(); diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/runner/ElevatorTcpRunner.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/runner/ElevatorTcpRunner.java index 0fdbc566..832cba7a 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/runner/ElevatorTcpRunner.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/runner/ElevatorTcpRunner.java @@ -1,7 +1,7 @@ package org.dromara.sis.runner; import lombok.extern.slf4j.Slf4j; -import org.dromara.sis.sdk.smartDevices.utils.ElevatorControlUtil; +import org.dromara.sis.sdk.smartDevices.utils.ElevatorControlTcpUtil; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; @@ -19,22 +19,35 @@ public class ElevatorTcpRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) { - // 获取单例实例并启动服务 - ElevatorControlUtil instance = ElevatorControlUtil.getInstance(); + // 获取单例实例 + ElevatorControlTcpUtil elevatorHelper = ElevatorControlTcpUtil.getInstance(); - try{ + // 设置连接监听器 + elevatorHelper.setConnectionListener(new ElevatorControlTcpUtil.ConnectionListener() { + @Override + public void onConnected() { + log.info("梯控设备已连接"); + } + + @Override + public void onDisconnected() { + log.info("梯控设备已断开"); + } + }); + + try { // 启动服务 - instance.start(23); - log.info("启动电梯控制服务成功"); + elevatorHelper.start(23); + log.info("电梯控制TCP服务启动成功"); + // 添加关闭钩子 Runtime.getRuntime().addShutdownHook(new Thread(() -> { - // 停止服务 - log.info("应用关闭中,停止电梯服务..."); - instance.stop(); - + log.info("应用关闭中,停止电梯控制TCP服务..."); + elevatorHelper.stop(); })); + } catch (IOException e) { - log.info("启动电梯控制服务失败"); + System.err.println("无法启动电梯控制TCP服务: " + e.getMessage()); } } } diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/hik/calback/HikAlarmCallBack.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/hik/calback/HikAlarmCallBack.java index 13f27e41..695ab46e 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/hik/calback/HikAlarmCallBack.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/hik/calback/HikAlarmCallBack.java @@ -1,9 +1,14 @@ package org.dromara.sis.sdk.hik.calback; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; import com.sun.jna.Pointer; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.dromara.sis.domain.SisDeviceManage; import org.dromara.sis.sdk.hik.HCNetSDK; +import org.dromara.sis.sdk.hik.HikApiService; +import org.dromara.sis.service.ISisDeviceManageService; import org.dromara.sis.service.IZeroSensationPassageService; import org.springframework.stereotype.Component; @@ -11,6 +16,7 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.text.SimpleDateFormat; import java.util.Date; @@ -21,6 +27,7 @@ import static org.dromara.sis.sdk.hik.HCNetSDK.*; @RequiredArgsConstructor public class HikAlarmCallBack implements HCNetSDK.FMSGCallBack_V31 { + private final ISisDeviceManageService sisDeviceManageService; private final IZeroSensationPassageService zeroSensationPassageService; @Override @@ -243,12 +250,9 @@ public class HikAlarmCallBack implements HCNetSDK.FMSGCallBack_V31 { Pointer pFaceSnapMatch = strFaceSnapMatch.getPointer(); pFaceSnapMatch.write(0, pAlarmInfo.getByteArray(0, strFaceSnapMatch.size()), 0, strFaceSnapMatch.size()); strFaceSnapMatch.read(); - //比对结果,0-保留,1-比对成功,2-比对失败 - String sFaceSnapMatchInfo = "比对结果:" + strFaceSnapMatch.byContrastStatus + ",相似度:" + strFaceSnapMatch.fSimilarity; - - + handleFaceComparison(strFaceSnapMatch, pAlarmer); + break; } - default: { } @@ -262,9 +266,8 @@ public class HikAlarmCallBack implements HCNetSDK.FMSGCallBack_V31 { * * @param result 人脸数据 * @param pAlarmer 设备数据 - * @return 返回是否处理成功 */ - private boolean handleFaceSnap(HCNetSDK.NET_VCA_FACESNAP_RESULT result, HCNetSDK.NET_DVR_ALARMER pAlarmer) { + private void handleFaceSnap(HCNetSDK.NET_VCA_FACESNAP_RESULT result, HCNetSDK.NET_DVR_ALARMER pAlarmer) { // 读取人脸小图 ByteBuffer buffers = result.pBuffer1.getByteBuffer(0, result.dwFacePicLen); byte[] smallImg = new byte[result.dwFacePicLen]; @@ -279,8 +282,48 @@ public class HikAlarmCallBack implements HCNetSDK.FMSGCallBack_V31 { //设备ip String sAlarmInfo = new String(pAlarmer.sDeviceIP).trim(); log.info("海康设备告警信息上传,设备={}, 人脸图片大小={}, 背景图片大小={}", sAlarmInfo, smallImg.length, bigImg.length); - zeroSensationPassageService.pass(sAlarmInfo, smallImg, bigImg); - return false; + + SisDeviceManage device = sisDeviceManageService.queryByDeviceIp(sAlarmInfo); + + if (!device.getIsComparison()) { + log.info("设备不支持人脸比对"); + zeroSensationPassageService.pass(sAlarmInfo, smallImg, bigImg); + } + } + + /** + * 处理人脸比对上报 + */ + private void handleFaceComparison(HCNetSDK.NET_VCA_FACESNAP_MATCH_ALARM result, HCNetSDK.NET_DVR_ALARMER pAlarmer) { + // 读取比对结果比对结果,0-保留,1-比对成功,2-比对失败 + int compareResults = result.byContrastStatus; + // 比对不成功,不处理 + if (compareResults != 1) { + log.info("前置人脸比对失败,设备:{}", new String(pAlarmer.sDeviceIP).trim()); + return; + } + + // 获取相似度 + float similarity = result.fSimilarity; + // 相似度小于70,不处理 + if (similarity < 0.7) { + log.info("前置人脸比对相似度小于70,设备:{}", new String(pAlarmer.sDeviceIP).trim()); + return; + } + + // 读取名字 + String name = new String(result.struBlockListInfo.struBlockListInfo.struAttribute.byName, Charset.forName("GBK")).trim(); + // 人员id为空,不处理 + if (result.struBlockListInfo.pPID == null) return; + // 读取人员id + ByteBuffer buffers = result.struBlockListInfo.pPID.getByteBuffer(0, result.struBlockListInfo.dwPIDLen); + byte[] pidByte = new byte[result.struBlockListInfo.dwPIDLen]; + buffers.rewind(); + buffers.get(pidByte); + int pid = Integer.parseInt(new String(pidByte)); + + log.info("比对结果:{},相似度:{},人员:{},id:{}", compareResults, similarity, name, pid); + zeroSensationPassageService.handleEleOut(new String(pAlarmer.sDeviceIP).trim()); } diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/smartDevices/utils/ElevatorControlUtil.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/smartDevices/utils/ElevatorControlTcpUtil.java similarity index 56% rename from ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/smartDevices/utils/ElevatorControlUtil.java rename to ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/smartDevices/utils/ElevatorControlTcpUtil.java index 1fe653e5..aa6d4669 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/smartDevices/utils/ElevatorControlUtil.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/smartDevices/utils/ElevatorControlTcpUtil.java @@ -1,7 +1,7 @@ package org.dromara.sis.sdk.smartDevices.utils; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.io.InputStream; @@ -9,53 +9,63 @@ import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.List; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; /** * @author lsm - * @apiNote ElevatorControlUtil + * @apiNote ElevatorControlTcpUtil * @since 2025/8/8 */ -@Service -public class ElevatorControlUtil { +@Slf4j +public class ElevatorControlTcpUtil { private static final int FRAME_LENGTH = 10; private static final byte FIXED_ADDRESS = 0x00; private static final byte MANUAL_COMMAND = (byte) 0xD1; private static final byte AUTO_COMMAND = (byte) 0xD2; private static final byte MANUAL_RESPONSE = (byte) 0xC1; private static final byte AUTO_RESPONSE = (byte) 0xC2; - private static final byte HEARTBEAT_COMMAND = (byte) 0xD0; - private static ElevatorControlUtil instance; + private static ElevatorControlTcpUtil instance; private ServerSocket serverSocket; private Socket clientSocket; private InputStream inputStream; private OutputStream outputStream; private final Object lock = new Object(); - private ScheduledExecutorService heartbeatScheduler; private volatile boolean isRunning = false; + /** + * -- SETTER -- + * 设置连接状态监听器 + */ + // 连接状态监听器 + @Setter + private ConnectionListener connectionListener; + + // 线程池处理连接 + private final ExecutorService executor = Executors.newCachedThreadPool(); + // 私有构造函数 - private ElevatorControlUtil() {} + private ElevatorControlTcpUtil() { + } /** * 获取单例实例 */ - public static synchronized ElevatorControlUtil getInstance() { + public static synchronized ElevatorControlTcpUtil getInstance() { if (instance == null) { - instance = new ElevatorControlUtil(); + instance = new ElevatorControlTcpUtil(); } return instance; } /** * 启动TCP服务 + * * @param port 监听端口 */ - public void start(Integer port) throws IOException { + public void start(int port) throws IOException { if (isRunning) { throw new IllegalStateException("服务已在运行中"); } @@ -64,8 +74,8 @@ public class ElevatorControlUtil { isRunning = true; // 启动连接监听线程 - new Thread(this::acceptConnections, "TCP-Acceptor").start(); - System.out.println("电梯控制服务已启动,监听端口: " + port); + executor.execute(this::acceptConnections); + log.info("电梯控制TCP服务已启动,监听端口: {}", port); } /** @@ -74,98 +84,71 @@ public class ElevatorControlUtil { public void stop() { isRunning = false; - // 停止心跳 - if (heartbeatScheduler != null) { - heartbeatScheduler.shutdown(); - } - - // 关闭连接 + // 关闭客户端连接 closeClientResources(); // 关闭服务器 if (serverSocket != null && !serverSocket.isClosed()) { try { serverSocket.close(); - System.out.println("服务已停止"); + log.info("电梯控制TCP服务已停止"); } catch (IOException e) { - System.err.println("停止服务时出错: " + e.getMessage()); + log.error("停止电梯控制TCP服务时出错: {}", e.getMessage()); } } + + // 关闭线程池 + executor.shutdown(); } /** * 接受客户端连接 */ private void acceptConnections() { - while (isRunning) { + while (isRunning && !serverSocket.isClosed()) { try { - clientSocket = serverSocket.accept(); - clientSocket.setKeepAlive(true); - inputStream = clientSocket.getInputStream(); - outputStream = clientSocket.getOutputStream(); + log.info("等待梯控设备连接..."); + Socket newClient = serverSocket.accept(); - System.out.println("梯控设备已连接: " + clientSocket.getRemoteSocketAddress()); + synchronized (lock) { + // 关闭现有连接(如果有) + closeClientResources(); - // 启动心跳机制 - startHeartbeat(); + // 接受新连接 + clientSocket = newClient; + inputStream = clientSocket.getInputStream(); + outputStream = clientSocket.getOutputStream(); + + log.info("梯控设备已连接: {}", clientSocket.getRemoteSocketAddress()); + + // 通知连接状态变化 + if (connectionListener != null) { + connectionListener.onConnected(); + } + } } catch (IOException e) { if (isRunning) { - System.err.println("接受连接时出错: " + e.getMessage()); - try { - Thread.sleep(5000); // 5秒后重试 - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - } + log.error("接受连接时出错: {}", e.getMessage()); } } } } - /** - * 启动心跳机制 - */ - private void startHeartbeat() { - if (heartbeatScheduler != null && !heartbeatScheduler.isShutdown()) { - heartbeatScheduler.shutdown(); - } - - heartbeatScheduler = Executors.newSingleThreadScheduledExecutor(); - heartbeatScheduler.scheduleAtFixedRate(() -> { - if (isClientConnected()) { - try { - sendHeartbeat(); - } catch (IOException e) { - System.err.println("心跳包发送失败: " + e.getMessage()); - closeClientResources(); - } - } - }, 30, 30, TimeUnit.SECONDS); - } - - /** - * 发送心跳包 - */ - private void sendHeartbeat() throws IOException { - synchronized (lock) { - if (!isClientConnected()) return; - - byte[] heartbeatData = new byte[7]; - byte[] frame = buildFrame(HEARTBEAT_COMMAND, heartbeatData); - outputStream.write(frame); - outputStream.flush(); - } - } - /** * 检查客户端是否连接 */ public boolean isClientConnected() { - return clientSocket != null && clientSocket.isConnected() && !clientSocket.isClosed(); + synchronized (lock) { + return clientSocket != null && + clientSocket.isConnected() && + !clientSocket.isClosed(); + } } /** * 发送手动选层命令 + * * @param floors 要开放的楼层列表 * @return 是否成功 */ @@ -175,6 +158,7 @@ public class ElevatorControlUtil { /** * 发送自动选层命令 + * * @param floors 要开放的楼层列表 * @return 是否成功 */ @@ -195,18 +179,24 @@ public class ElevatorControlUtil { private boolean sendCommand(byte command, byte expectedResponse, byte[] floorData) { if (!isClientConnected()) { - System.err.println("发送命令失败:未连接梯控设备"); + log.info("发送命令失败:未连接梯控设备"); return false; } if (floorData == null || floorData.length != 7) { - System.err.println("发送命令失败:无效的楼层数据"); + log.info("发送命令失败:无效的楼层数据"); return false; } synchronized (lock) { for (int attempt = 0; attempt < 2; attempt++) { try { + // 检查连接是否仍然有效 + if (!isClientConnected()) { + log.info("连接在发送前已断开"); + return false; + } + byte[] frame = buildFrame(command, floorData); outputStream.write(frame); outputStream.flush(); @@ -219,19 +209,23 @@ public class ElevatorControlUtil { while (bytesRead < FRAME_LENGTH) { int read = inputStream.read(response, bytesRead, FRAME_LENGTH - bytesRead); if (read == -1) { - throw new IOException("连接已关闭"); + // 连接关闭 + handleConnectionClosed(); + return false; } bytesRead += read; } if (validateResponse(response, expectedResponse)) { return true; + } else { + log.info("响应验证失败,尝试重试"); } } catch (java.net.SocketTimeoutException e) { - System.err.println("命令响应超时,尝试重试"); + log.info("命令响应超时,尝试重试"); } catch (IOException e) { - System.err.println("发送命令时出错: " + e.getMessage()); - closeClientResources(); + log.error("发送命令时出错: {}", e.getMessage()); + handleConnectionClosed(); return false; } } @@ -239,6 +233,17 @@ public class ElevatorControlUtil { } } + /** + * 处理连接关闭 + */ + private void handleConnectionClosed() { + log.info("检测到连接已关闭"); + closeClientResources(); + if (connectionListener != null) { + connectionListener.onDisconnected(); + } + } + /** * 生成楼层数据 */ @@ -276,34 +281,61 @@ public class ElevatorControlUtil { } private boolean validateResponse(byte[] response, byte expectedHeader) { - if (response[0] != expectedHeader) return false; - if (response[1] != FIXED_ADDRESS) return false; + if (response[0] != expectedHeader) { + log.info("响应帧头错误,期望: {},实际:{}", expectedHeader, response[0]); + return false; + } + if (response[1] != FIXED_ADDRESS) { + log.info("响应地址错误"); + return false; + } byte checksum = 0; for (int i = 0; i < 9; i++) { checksum = (byte) (checksum + response[i]); } - return response[9] == checksum; + if (response[9] != checksum) { + log.info("校验和错误,期望: {},实际: {}", checksum, response[9]); + return false; + } + + return true; } /** * 关闭客户端资源 */ private void closeClientResources() { - try { - if (inputStream != null) inputStream.close(); - if (outputStream != null) outputStream.close(); - if (clientSocket != null && !clientSocket.isClosed()) { - clientSocket.close(); + synchronized (lock) { + try { + if (inputStream != null) inputStream.close(); + if (outputStream != null) outputStream.close(); + if (clientSocket != null && !clientSocket.isClosed()) { + clientSocket.close(); + } + log.info("客户端连接已关闭"); + } catch (IOException e) { + log.error("关闭连接时出错: {}", e.getMessage()); + } finally { + clientSocket = null; + inputStream = null; + outputStream = null; + + // 通知连接断开 + if (connectionListener != null) { + connectionListener.onDisconnected(); + } } - System.out.println("客户端连接已关闭"); - } catch (IOException e) { - System.err.println("关闭连接时出错: " + e.getMessage()); - } finally { - clientSocket = null; - inputStream = null; - outputStream = null; } } + + /** + * 连接状态监听接口 + */ + public interface ConnectionListener { + void onConnected(); + + void onDisconnected(); + } } diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/ISisDeviceManageService.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/ISisDeviceManageService.java index 4cdb47a7..06f89f2d 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/ISisDeviceManageService.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/ISisDeviceManageService.java @@ -70,21 +70,18 @@ public interface ISisDeviceManageService { /** * 通过设备ip查询设备信息 - * - * @param deviceIp 设备编码 + * @param deviceIp 设备ip * @return 设备信息 */ - SisDeviceManageVo queryVoByDeviceIp(String deviceIp); + SisDeviceManage queryByDeviceIp(String deviceIp); - SisDeviceManage queryByDeviceIp(String deviceId); /** * 查询设备数 * - * @return + * @return tree */ List> tree(); - /** * 通过设备id列表查询设备信息 * @param deviceIds 设备id列表 diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/IZeroSensationPassageService.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/IZeroSensationPassageService.java index 09de1825..6d8788a8 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/IZeroSensationPassageService.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/IZeroSensationPassageService.java @@ -11,4 +11,11 @@ public interface IZeroSensationPassageService { */ void pass(String deviceIp, byte[] smallImp, byte[] bigImg); + /** + * 电梯外部按键触发 + * + * @param deviceIp 设备ip + */ + void handleEleOut(String deviceIp); + } diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisDeviceManageServiceImpl.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisDeviceManageServiceImpl.java index 2562c7fe..5a82f2bd 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisDeviceManageServiceImpl.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisDeviceManageServiceImpl.java @@ -177,18 +177,15 @@ public class SisDeviceManageServiceImpl implements ISisDeviceManageService { log.info("删除设备通道完成,num={}", num); } - + /** + * 通过设备ip查询设备信息 + * @param deviceIp 设备ip + * @return 设备信息 + */ @Override - public SisDeviceManageVo queryVoByDeviceIp(String deviceIp) { + public SisDeviceManage queryByDeviceIp(String deviceIp) { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); lqw.eq(SisDeviceManage::getDeviceIp, deviceIp); - return baseMapper.selectVoOne(lqw); - } - - @Override - public SisDeviceManage queryByDeviceIp(String deviceId) { - LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.eq(SisDeviceManage::getDeviceIp, deviceId); return baseMapper.selectOne(lqw); } diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisElevatorFloorRefServiceImpl.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisElevatorFloorRefServiceImpl.java index d5706d28..a1253e12 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisElevatorFloorRefServiceImpl.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisElevatorFloorRefServiceImpl.java @@ -202,6 +202,9 @@ public class SisElevatorFloorRefServiceImpl implements ISisElevatorFloorRefServi lqw.in(SisElevatorFloorRef::getFloorId, info.stream().map(SisElevatorFloorChannelRef::getFloorId).toList()); List list = baseMapper.selectList(lqw); + // list为空不需要冗余数据,返回true + if(list.isEmpty()) return true; + // 创建Map提高查找效率,避免在循环中重复流操作 Map floorInfoMap = info.stream() .collect(Collectors.toMap(SisElevatorFloorChannelRef::getFloorId, Function.identity())); diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisElevatorInfoServiceImpl.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisElevatorInfoServiceImpl.java index 40e58eb1..449cca79 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisElevatorInfoServiceImpl.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/SisElevatorInfoServiceImpl.java @@ -252,7 +252,7 @@ public class SisElevatorInfoServiceImpl implements ISisElevatorInfoService { // 冗余数据到电梯⇄楼层关联表 Boolean update = elevatorFloorRefService.batchUpdateChannel(channelRefs); - + Assert.isTrue(update, "冗余数据到电梯⇄楼层关联表失败!"); } /** diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/ZeroSensationPassageServiceImpl.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/ZeroSensationPassageServiceImpl.java index b9cc8a98..49d09ca8 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/ZeroSensationPassageServiceImpl.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/service/impl/ZeroSensationPassageServiceImpl.java @@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboReference; import org.dromara.property.api.RemoteFloorService; import org.dromara.property.api.domain.vo.RemoteFloorVo; +import org.dromara.sis.domain.SisElevatorFloorChannelRef; import org.dromara.sis.domain.enums.ControlTypeEnum; import org.dromara.sis.domain.enums.RosterTypeEnum; import org.dromara.sis.domain.vo.*; @@ -19,7 +20,7 @@ import org.dromara.sis.sdk.e8.domain.accessControl.req.RemoteOpenDoorReq; import org.dromara.sis.sdk.hik.HikApiService; import org.dromara.sis.sdk.huawei.HuaWeiBoxApi; import org.dromara.sis.sdk.huawei.domain.HWResult; -import org.dromara.sis.sdk.smartDevices.utils.ElevatorControlUtil; +import org.dromara.sis.sdk.smartDevices.utils.ElevatorControlTcpUtil; import org.dromara.sis.service.*; import org.springframework.stereotype.Service; @@ -46,6 +47,7 @@ public class ZeroSensationPassageServiceImpl implements IZeroSensationPassageSer private final ISisDeviceBindRefService deviceBindRefService; private final ISisAccessControlService accessControlService; private final ISisElevatorFloorRefService elevatorFloorRefService; + private final ISisElevatorFloorChannelRefService elevatorFloorChannelRefService; private final E8PlatformApi e8PlatformApi; private final ISisAlarmEventsService alarmEventsService; @@ -115,11 +117,11 @@ public class ZeroSensationPassageServiceImpl implements IZeroSensationPassageSer } // 判断绑定设备类型,走不同的处理方法 if (Objects.equals(item.getControlType(), ControlTypeEnum.ACCESS_CONTROL.getCode())) { // 门禁 - handleAc(item.getDeviceId()); + handleAc(item.getBindId()); } else if (item.getControlType().equals(ControlTypeEnum.ELEVATOR_OUT_CONTROL.getCode())) { // 电梯外面面板权限 - handleEle(item.getDeviceId(), r.getAuthGroupId(), ControlTypeEnum.ELEVATOR_OUT_CONTROL.getCode(), item.getDeviceFloorId()); + handleEle(item.getBindId(), r.getAuthGroupId(), ControlTypeEnum.ELEVATOR_OUT_CONTROL.getCode(), item.getDeviceFloorId()); } else if (item.getControlType().equals(ControlTypeEnum.ELEVATOR_IN_CONTROL.getCode())) { // 电梯里面的面板 - handleEle(item.getDeviceId(), r.getAuthGroupId(), ControlTypeEnum.ELEVATOR_IN_CONTROL.getCode(), item.getDeviceFloorId()); + handleEle(item.getBindId(), r.getAuthGroupId(), ControlTypeEnum.ELEVATOR_IN_CONTROL.getCode(), item.getDeviceFloorId()); } else { log.info("设备绑定了未知的控制类型[{}],不处理", item.getControlType()); } @@ -127,6 +129,39 @@ public class ZeroSensationPassageServiceImpl implements IZeroSensationPassageSer log.info("权限下发执行完成,耗时:{}ms", interval.intervalMs()); } + /** + * 电梯外部按键触发 + * + * @param deviceIp 设备ip + */ + @Override + public void handleEleOut(String deviceIp) { + // 获取当前设备的绑定设备信息 + List bindRefList = deviceBindRefService.queryByDeviceIp(deviceIp); + bindRefList.forEach(item -> { + // 只处理外部按键 + if (Objects.equals(item.getControlType(), ControlTypeEnum.ELEVATOR_OUT_CONTROL.getCode())) { + // 获取当前电梯信息 + SisElevatorInfoVo ele = elevatorInfoService.queryById(item.getBindId()); + + List channelRef = elevatorFloorChannelRefService.queryByFloorIds(List.of(item.getDeviceFloorId())); + SisElevatorFloorChannelRefVo channelRefVo = channelRef.stream().filter(o -> Objects.equals(o.getElevatorId(), item.getBindId())).findFirst().orElse(null); + + if (channelRefVo != null) { + if (channelRefVo.getDownChannel() != null) { + HikApiService.getInstance().controlGateway(ele.getControlIp(), channelRefVo.getDownChannel().intValue(), 2); + } + + if (channelRefVo.getUpChannel() != null) { + HikApiService.getInstance().controlGateway(ele.getControlIp(), channelRefVo.getUpChannel().intValue(), 2); + } + } + } + + cleanLiftAuthRocketProducer.sendMessage(item.getBindId(), 0L, item.getDeviceFloorId(), "清除电梯" + item.getBindId() + "梯控权限", 3); + }); + } + /** * 生成告警事件 */ @@ -192,7 +227,7 @@ public class ZeroSensationPassageServiceImpl implements IZeroSensationPassageSer for (int i = 1; i < floorList.size(); i++) { int finalI = i; // 取出权限楼层id与实际楼层id相等的数据 - vo = eleRef.stream().filter(o -> Objects.equals(o.getFloorId(), floorList.get(finalI-1).getId())).findFirst().orElse(null); + vo = eleRef.stream().filter(o -> Objects.equals(o.getFloorId(), floorList.get(finalI - 1).getId())).findFirst().orElse(null); // 存在权限楼层,添加到num中,梯控模块从1开始 if (vo != null) { num.add(i); @@ -200,11 +235,11 @@ public class ZeroSensationPassageServiceImpl implements IZeroSensationPassageSer } if (CollUtil.isEmpty(num)) return; - if (!ElevatorControlUtil.getInstance().isClientConnected()){ + if (!ElevatorControlTcpUtil.getInstance().isClientConnected()) { log.info("梯控模块未连接,请检查梯控模块是否启动"); return; } - ElevatorControlUtil.getInstance().sendManualCommand(num); + ElevatorControlTcpUtil.getInstance().sendManualCommand(num); } log.info("梯控下发权限完成");