From 2613bb16b55b087c7c774fdfce2e93aceb1a57bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LAPTOP-S9HJSOEB=5C=E6=98=8A=E5=A4=A9?= Date: Wed, 26 Aug 2026 16:54:30 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E4=BD=93=E4=BF=AE=E6=94=B9iot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- copy_subdirs_out.cmd | 25 ++ default.txt | 152 ++++++++++ network.txt | 7 + test_ksec.cmd | 17 ++ .../web/config/ConfigProperties.java | 4 +- .../web/config/FusionDesignApplication.java | 72 ++++- .../controller/CameraControlController.java | 2 - .../web/controller/CheckLogController.java | 39 ++- .../IndustrialCameraController.java | 2 +- .../web/controller/IotController.java | 154 ++++++++++ .../web/lib/CameraControlLoginModule.java | 2 +- .../lib/hik/HikCameraControlModuleImpl.java | 122 +++++--- .../web/lib/hik/HikExceptionCallBack.java | 3 + .../web/lib/hik/HikLoginModuleImpl.java | 15 +- .../lib/joyware/JoywareLoginModuleImpl.java | 2 +- .../callBackTest/JoywarePlaybackTest.java | 2 +- .../web/pojo/IndustrialCameraVO.java | 2 +- .../web/pojo/stock/CheckLogSearch.java | 1 + .../zhehekeji/web/service/CameraService.java | 2 +- .../IndustrialCamera/HikSaveImage.java | 209 ++++++++++---- .../LxPointCloudSaveImage.java | 19 ++ .../zhehekeji/web/service/InitService.java | 9 +- .../com/zhehekeji/web/service/PlcService.java | 19 +- .../web/service/com/SerialPortManager.java | 18 ++ .../service/iotService/IotServiceImpl.java | 264 ++++++++++++++++++ .../service/iotService/ScheduleConfig.java | 38 +++ .../web/service/ksec/CommandQueue.java | 2 +- .../web/service/ksec/KescFilter.java | 8 +- .../web/service/ksec/KsecDecoder.java | 82 ++++-- .../web/service/ksec/KsecNettyClient.java | 6 +- .../web/service/sick/CognexSocket.java | 10 +- .../web/service/sick/SickSocket.java | 6 +- web/src/main/resources/application-prod.yml | 7 +- web/src/main/resources/logback-spring.xml | 24 ++ 说明 | 10 + 35 files changed, 1181 insertions(+), 175 deletions(-) create mode 100644 copy_subdirs_out.cmd create mode 100644 default.txt create mode 100644 network.txt create mode 100644 test_ksec.cmd create mode 100644 web/src/main/java/com/zhehekeji/web/controller/IotController.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/iotService/IotServiceImpl.java create mode 100644 web/src/main/java/com/zhehekeji/web/service/iotService/ScheduleConfig.java create mode 100644 说明 diff --git a/copy_subdirs_out.cmd b/copy_subdirs_out.cmd new file mode 100644 index 0000000..ac302f4 --- /dev/null +++ b/copy_subdirs_out.cmd @@ -0,0 +1,25 @@ +@echo off +chcp 65001 >nul +setlocal enabledelayedexpansion + +echo ============================================ +echo 将当前目录下所有文件夹的子文件夹提取到外层 +echo ============================================ +echo. + +set "ROOT=%cd%" + +for /d %%P in ("%ROOT%\*") do ( + echo [处理] %%P + for /d %%S in ("%%P\*") do ( + set "SUBNAME=%%~nxS" + echo 提取子文件夹: !SUBNAME! + robocopy "%%S" "%ROOT%\!SUBNAME!" /E /IS /IT >nul + ) +) + +echo. +echo ============================================ +echo 完成! +echo ============================================ +pause diff --git a/default.txt b/default.txt new file mode 100644 index 0000000..bf124c4 --- /dev/null +++ b/default.txt @@ -0,0 +1,152 @@ +{"001": + { + "deviceName": "非动碰盘点1号巷道盘点系统", + "time": "2026-06-26 09:30:00", + "warehouseRunStatus": 1, + "warehouseNetworkStatus": 1, + "leftScannerNetworkStatus": 1, + "leftScannerScanResult": 1, + "rightScannerNetworkStatus": 1, + "rightScannerScanResult": 1, + "cameraNetworkStatus": 1, + "cameraErrorCode": 0, + "apNetworkStatus": 1, + "cpeNetworkStatus": 1, + "visionControllerNetworkStatus": 1, + "communicationData": { + } + }, + "002": { + "deviceName": "一号仓库动碰盘点系统", + "time": "2026-06-26 09:30:00", + "warehouseRunStatus": 1, + "warehouseNetworkStatus": 1, + "leftScannerNetworkStatus": 1, + "leftScannerScanResult": 1, + "rightScannerNetworkStatus": 1, + "rightScannerScanResult": 1, + "leftDepthScannerNetworkStatus": 1, + "leftDepthScannerScanResult": 1, + "rightDepthScannerNetworkStatus": 1, + "rightDepthScannerScanResult": 1, + "cameraNetworkStatus": 1, + "cameraErrorCode": 0, + "apNetworkStatus": 1, + "cpeNetworkStatus": 1, + "visionControllerNetworkStatus": 1, + "communicationData": { + } + }, + "003": { + "deviceName": "一号仓库动碰盘点系统", + "time": "2026-06-26 09:30:00", + "warehouseRunStatus": 1, + "warehouseNetworkStatus": 1, + "leftScannerNetworkStatus": 1, + "leftScannerScanResult": 1, + "rightScannerNetworkStatus": 1, + "rightScannerScanResult": 1, + "leftDepthScannerNetworkStatus": 1, + "leftDepthScannerScanResult": 1, + "rightDepthScannerNetworkStatus": 1, + "rightDepthScannerScanResult": 1, + "cameraNetworkStatus": 1, + "cameraErrorCode": 0, + "apNetworkStatus": 1, + "cpeNetworkStatus": 1, + "visionControllerNetworkStatus": 1, + "communicationData": { + } + }, + "004": { + "deviceName": "一号仓库动碰盘点系统", + "time": "2026-06-26 09:30:00", + "warehouseRunStatus": 1, + "warehouseNetworkStatus": 1, + "leftScannerNetworkStatus": 1, + "leftScannerScanResult": 1, + "rightScannerNetworkStatus": 1, + "rightScannerScanResult": 1, + "cameraNetworkStatus": 1, + "cameraErrorCode": 1, + "apNetworkStatus": 1, + "cpeNetworkStatus": 1, + "visionControllerNetworkStatus": 1, + "communicationData": { + } + }, + "005": { + "deviceName": "一号仓库动碰盘点系统", + "time": "2026-06-26 09:30:00", + "warehouseRunStatus": 1, + "warehouseNetworkStatus": 1, + "leftScannerNetworkStatus": 1, + "leftScannerScanResult": 1, + "rightScannerNetworkStatus": 1, + "rightScannerScanResult": 1, + "cameraNetworkStatus": 1, + "cameraErrorCode": 0, + "apNetworkStatus": 1, + "cpeNetworkStatus": 1, + "visionControllerNetworkStatus": 1, + "communicationData": { + } + }, + "006": { + "deviceName": "一号仓库动碰盘点系统", + "time": "2026-06-26 09:30:00", + "warehouseRunStatus": 1, + "warehouseNetworkStatus": 1, + "leftScannerNetworkStatus": 1, + "leftScannerScanResult": 1, + "rightScannerNetworkStatus": 1, + "rightScannerScanResult": 1, + "rightDepthScannerNetworkStatus": 1, + "rightDepthScannerScanResult": 1, + "cameraNetworkStatus": 1, + "cameraErrorCode": 0, + "apNetworkStatus": 1, + "cpeNetworkStatus": 1, + "visionControllerNetworkStatus": 1, + "communicationData": { + } + }, + "007": { + "deviceName": "一号仓库动碰盘点系统", + "time": "2026-06-26 09:30:00", + "warehouseRunStatus": 1, + "warehouseNetworkStatus": 1, + "leftScannerNetworkStatus": 1, + "leftScannerScanResult": 1, + "rightScannerNetworkStatus": 1, + "rightScannerScanResult": 1, + "leftDepthScannerNetworkStatus": 1, + "leftDepthScannerScanResult": 1, + "rightDepthScannerNetworkStatus": 1, + "rightDepthScannerScanResult": 1, + "cameraNetworkStatus": 1, + "cameraErrorCode": 0, + "apNetworkStatus": 1, + "cpeNetworkStatus": 1, + "visionControllerNetworkStatus": 1, + "communicationData": { + } + }, + "008": { + "deviceName": "一号仓库动碰盘点系统", + "time": "2026-06-26 09:30:00", + "warehouseRunStatus": 1, + "warehouseNetworkStatus": 1, + "leftScannerNetworkStatus": 1, + "leftScannerScanResult": 1, + "rightScannerNetworkStatus": 1, + "rightScannerScanResult": 1, + "cameraNetworkStatus": 1, + "cameraErrorCode": 0, + "apNetworkStatus": 1, + "cpeNetworkStatus": 1, + "visionControllerNetworkStatus": 1, + "communicationData": { + } + } +} \ No newline at end of file diff --git a/network.txt b/network.txt new file mode 100644 index 0000000..e4d68a8 --- /dev/null +++ b/network.txt @@ -0,0 +1,7 @@ +"192.168.42.11"=zt:industrialCamera1NetworkStatus +"192.168.43.11"=zt:industrialCamera2NetworkStatus +"192.168.44.11"=zt:industrialCamera3NetworkStatus +"192.168.45.11"=zt:industrialCamera4NetworkStatus +"192.168.46.11"=zt:industrialCamera5NetworkStatus +"192.168.47.11"=zt:industrialCamera6NetworkStatus +"192.168.48.11"=zt:camera3dNetworkStatus \ No newline at end of file diff --git a/test_ksec.cmd b/test_ksec.cmd new file mode 100644 index 0000000..a82758b --- /dev/null +++ b/test_ksec.cmd @@ -0,0 +1,17 @@ +@echo off +chcp 65001 >nul +echo ===== 测试 KSEC 接口 ===== +echo 目标: http://10.100.81.10:8000/ksecwcs/tinventoryinfo +echo. + +curl -v -X POST "http://10.100.81.10:8000/ksecwcs/tinventoryinfo" ^ + -H "Content-Type: application/json" ^ + -H "User-Agent: Mozilla/5.0" ^ + --connect-timeout 5 ^ + --max-time 10 ^ + -d "{\"code\":200,\"msg\":\"图像识别完成\",\"data\":{\"trayCode\":\"75759\",\"wmsTrayCode\":\"75759\",\"flag\":1,\"count\":null}}" + +echo. +echo. +echo ===== 测试完成 ===== +pause diff --git a/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java b/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java index 5e078aa..72876f0 100644 --- a/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java +++ b/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java @@ -5,6 +5,7 @@ import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; +import java.util.ArrayList; import java.util.List; @Component @@ -23,6 +24,7 @@ public class ConfigProperties { public static Integer JOYWARE_CAMERA = 0; private String ComConfig; + private List comTofConfig = new ArrayList<>(); private CameraConfig cameraConfig; @@ -111,7 +113,7 @@ public class ConfigProperties { public Integer verticalAdjustmentTime = 2; - private List industrialCamera; + private List industrialCamera = new ArrayList<>(); private String camera3D; private String sickIp; diff --git a/web/src/main/java/com/zhehekeji/web/config/FusionDesignApplication.java b/web/src/main/java/com/zhehekeji/web/config/FusionDesignApplication.java index 7aadb8e..59ca7b4 100644 --- a/web/src/main/java/com/zhehekeji/web/config/FusionDesignApplication.java +++ b/web/src/main/java/com/zhehekeji/web/config/FusionDesignApplication.java @@ -1,27 +1,81 @@ package com.zhehekeji.web.config; -import org.springframework.boot.web.client.RestTemplateBuilder; +import org.apache.http.HeaderElement; +import org.apache.http.HeaderElementIterator; +import org.apache.http.NoHttpResponseException; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeaderElementIterator; +import org.apache.http.protocol.HTTP; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.client.RestTemplate; -import javax.annotation.Resource; -import java.time.Duration; +import java.io.IOException; +import java.util.concurrent.TimeUnit; @EnableAsync @EnableScheduling @Configuration public class FusionDesignApplication { - @Resource - //RestTemplateBuilder - private RestTemplateBuilder builder; - // 使用RestTemplateBuilder来实例化RestTemplate对象,spring默认已经注入了RestTemplateBuilder实例 + @Bean public RestTemplate restTemplate() { - return builder.setConnectTimeout(Duration.ofMinutes(10)) // 设置连接超时时间,单位分钟 - .setReadTimeout(Duration.ofMinutes(20)) // 设置读取超时时间,单位分钟 + // 连接池:空闲 15 秒回收,防止复用被服务端关闭的死连接(NoHttpResponseException) + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(15, TimeUnit.SECONDS); + connManager.setMaxTotal(100); // 最大连接数 + connManager.setDefaultMaxPerRoute(20); // 每路由最大连接数 + // 每 5 秒清理一次过期/空闲连接 + connManager.setValidateAfterInactivity(3000); // 3秒未活动的连接,使用前先验证有效性 + + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(5000) // 连接超时 5 秒 + .setSocketTimeout(30000) // 读取超时 30 秒 + .setConnectionRequestTimeout(3000) // 从池里取连接超时 3 秒 .build(); + + // Keep-Alive 策略:默认存活 5 秒,避免使用已被服务端关闭的死连接 + ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> { + HeaderElementIterator it = new BasicHeaderElementIterator( + response.headerIterator(HTTP.CONN_KEEP_ALIVE)); + while (it.hasNext()) { + HeaderElement he = it.nextElement(); + String param = he.getName(); + String value = he.getValue(); + if (value != null && "timeout".equalsIgnoreCase(param)) { + return Long.parseLong(value) * 1000; + } + } + return 5000; // 默认 5 秒 + }; + + CloseableHttpClient httpClient = HttpClientBuilder.create() + .setConnectionManager(connManager) + .setDefaultRequestConfig(requestConfig) + .setKeepAliveStrategy(keepAliveStrategy) + .evictIdleConnections(15, TimeUnit.SECONDS) // 15 秒回收空闲连接 + .setRetryHandler((exception, executionCount, context) -> { + // 对 NoHttpResponseException 进行重试(服务端关闭连接未响应, + // 此时请求未送达,重试是安全的) + if (executionCount > 2) { + return false; + } + if (exception instanceof NoHttpResponseException) { + return true; + } + // 其他 IOException 也重试一次 + return executionCount <= 1 && exception instanceof IOException; + }) + .build(); + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); + + return new RestTemplate(factory); } } diff --git a/web/src/main/java/com/zhehekeji/web/controller/CameraControlController.java b/web/src/main/java/com/zhehekeji/web/controller/CameraControlController.java index a510a0e..4d09fef 100644 --- a/web/src/main/java/com/zhehekeji/web/controller/CameraControlController.java +++ b/web/src/main/java/com/zhehekeji/web/controller/CameraControlController.java @@ -32,8 +32,6 @@ public class CameraControlController { @Resource private CameraControlModule cameraControlModule; - @Resource - private CameraControlLoginModule loginControlModule; @PostMapping("/{id}") @ApiOperation(value = "球机登录") diff --git a/web/src/main/java/com/zhehekeji/web/controller/CheckLogController.java b/web/src/main/java/com/zhehekeji/web/controller/CheckLogController.java index d18eec2..6a61d5b 100644 --- a/web/src/main/java/com/zhehekeji/web/controller/CheckLogController.java +++ b/web/src/main/java/com/zhehekeji/web/controller/CheckLogController.java @@ -1,20 +1,21 @@ package com.zhehekeji.web.controller; +import com.baomidou.mybatisplus.extension.api.R; import com.github.pagehelper.PageInfo; import com.zhehekeji.common.util.ValidatorUtil; import com.zhehekeji.core.pojo.Result; -import com.zhehekeji.web.entity.CheckLog; -import com.zhehekeji.web.entity.ReadOCR; -import com.zhehekeji.web.entity.SensorGun; -import com.zhehekeji.web.entity.StockLog; +import com.zhehekeji.web.entity.*; import com.zhehekeji.web.pojo.stock.CheckLogSearch; import com.zhehekeji.web.pojo.stock.StockLogSearch; import com.zhehekeji.web.service.CheckLogService; import com.zhehekeji.web.service.SensorService; import com.zhehekeji.web.service.StockLogService; +import com.zhehekeji.web.service.StreetService; import com.zhehekeji.web.service.sick.CognexSocket; +import com.zhehekeji.web.service.sick.SickSocket; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -25,6 +26,7 @@ import javax.annotation.Resource; @Api(tags = "盘点历史") @RequestMapping("/checkLog") @RestController +@Slf4j public class CheckLogController { @Resource @@ -34,6 +36,9 @@ public class CheckLogController { @Resource private SensorService sensorService; + @Resource + private StreetService streetService; + @ApiOperation("盘点历史") @PostMapping("") public Result> list(@RequestBody CheckLogSearch checkLogSearch){ @@ -41,21 +46,35 @@ public class CheckLogController { } - @ApiOperation("深货位扫码") - @PostMapping("CognexSocket") - public Result CognexSocket(@RequestBody CheckLogSearch checkLogSearch){ + @ApiOperation("扫码抢") + @PostMapping("scanSocket") + public Result scanSocket(@RequestBody CheckLogSearch checkLogSearch){ + String pointIdentification = "ScannerScanResult"; + + //使用sick扫码枪 int leftRight = checkLogSearch.getLeftRight(); if(checkLogSearch.getSide()==2) { + pointIdentification = "Depth"+ pointIdentification; leftRight=leftRight+2; } + if(checkLogSearch.getLeftRight()==1) { + pointIdentification = "left"+ pointIdentification; + }else { + pointIdentification = "right"+ pointIdentification; + } + Street street = streetService.getStreetByPlcId(checkLogSearch.getStreetPlc()); + + //托盘使用sick扫码枪 + SensorGun sensorGun = sensorService.getSensorByPlc(street.getId(), leftRight); ReadOCR trayCode = new ReadOCR(); - SensorGun sensorGun = sensorService.getSensorByPlc(checkLogSearch.getStreetId(),leftRight); if (sensorGun == null) { - trayCode.setCode("扫码枪未配置"); + log.error("no sensor gun config in database ,street id:{},direction:{}", street.getId(), checkLogSearch.getLeftRight()); } else { if (leftRight > 2) { - trayCode = CognexSocket.readOCR(sensorGun.getIp(), sensorGun.getPort()); + trayCode = CognexSocket.readOCR(sensorGun.getIp(), sensorGun.getPort(), pointIdentification, street.getPlcId()); + } else { + trayCode = SickSocket.readOCR(sensorGun.getIp(), sensorGun.getPort(), pointIdentification, street.getPlcId()); } } return Result.success(trayCode.getCode()); diff --git a/web/src/main/java/com/zhehekeji/web/controller/IndustrialCameraController.java b/web/src/main/java/com/zhehekeji/web/controller/IndustrialCameraController.java index 840f509..897a38f 100644 --- a/web/src/main/java/com/zhehekeji/web/controller/IndustrialCameraController.java +++ b/web/src/main/java/com/zhehekeji/web/controller/IndustrialCameraController.java @@ -180,7 +180,7 @@ public class IndustrialCameraController { try { Thread.sleep(400); - readOCR = SickSocket.readOCR(configProperties.getCameraConfig().getSickIp(), configProperties.getCameraConfig().getSickPort()); + readOCR = SickSocket.readOCR(configProperties.getCameraConfig().getSickIp(), configProperties.getCameraConfig().getSickPort(),"scannerScanResult","zt"); log.info("sick识别结果:"+readOCR); if(readOCR.getStatus()!=1){ code = "0"; diff --git a/web/src/main/java/com/zhehekeji/web/controller/IotController.java b/web/src/main/java/com/zhehekeji/web/controller/IotController.java new file mode 100644 index 0000000..7c42595 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/controller/IotController.java @@ -0,0 +1,154 @@ +package com.zhehekeji.web.controller; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.pagehelper.PageInfo; +import com.zhehekeji.core.pojo.Result; +import com.zhehekeji.web.entity.KuKou; +import com.zhehekeji.web.pojo.OrderSearch; +import com.zhehekeji.web.service.iotService.IotServiceImpl; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Api(tags = "iot查询管理") +@RequestMapping("/IotController") +@RestController +@Slf4j +public class IotController { + @Resource + private IotServiceImpl iotService; + + + @PostMapping("/list") + @ApiOperation(value = "查询") + //@SessionHandler + public Result> list() { + + //validatorUtil.validate(orderSearch); + return Result.success(iotService.get()); + } + + @PostMapping("/listOne") + @ApiOperation(value = "查询") + //@SessionHandler + public Result> listOne(@RequestParam("type") String type) { + + //validatorUtil.validate(orderSearch); + return Result.success(iotService.get(type)); + } + + @PostMapping("/listZT") + @ApiOperation(value = "查询") + //@SessionHandler + public Result> listZT() { + Map map = iotService.get("zt"); + + //validatorUtil.validate(orderSearch); + return Result.success(map); + } + + private final ObjectMapper objectMapper = new ObjectMapper(); + + /** + * 接收报警服务器推送的 Webhook 报警 + */ + @PostMapping("/receive") + public Map receiveAlarm( + @RequestBody String rawJson) { + + log.info("====== 收到报警服务器推送 ======"); + // log.debug("原始 JSON: {}", rawJson); // 调试时打开,正式环境建议关闭以防日志爆满 + + Map response = new HashMap<>(); + + try { + // 1. 【安全校验】(如果平台配置了 Token 或签名,在这里校验) + // String token = headers.getFirst("Authorization"); + // if (!"your_secret_token".equals(token)) { + // response.put("code", 401); response.put("msg", "Unauthorized"); + // return response; + // } + + // 2. 解析原始 JSON (这里以海康/大华常见的通用结构为例,具体需看平台文档) + JsonNode rootNode = objectMapper.readTree(rawJson); + + // 3. 转换为内部标准 DTO (防腐层核心逻辑) + StandardAlarmDTO standardAlarm = convertToStandardDTO(rootNode); + System.out.println(standardAlarm); + + // 4. 【核心】异步处理报警 (发 MQTT、存数据库、推 WebSocket 等) + // 注意:千万不要在这里同步执行耗时操作,必须异步! +// alarmProcessService.processAsync(standardAlarm); + + // 5. 返回成功响应 (必须返回平台要求的成功格式,否则平台会认为推送失败并疯狂重试) + response.put("code", 0); // 或 "code": "200",具体看平台文档要求 + response.put("msg", "success"); + + } catch (Exception e) { + log.error("处理报警服务器推送数据异常", e); + response.put("code", 500); + response.put("msg", "Internal Server Error"); + } + + return response; + } + + /** + * 将平台原始 JSON 转换为内部标准 DTO + * (注:以下字段映射为模拟,请根据实际报警服务器的 JSON 结构进行修改) + */ + private StandardAlarmDTO convertToStandardDTO(JsonNode rootNode) { + StandardAlarmDTO dto = new StandardAlarmDTO(); + + // 提取唯一ID (防重放攻击/重复消费的关键) + dto.setAlarmId(rootNode.path("eventId").asText(rootNode.path("alarmId").asText(""))); + + // 提取设备信息 + JsonNode deviceNode = rootNode.path("deviceInfo"); + dto.setDeviceName(deviceNode.path("deviceName").asText("未知设备")); + dto.setDeviceIp(deviceNode.path("ip").asText("")); + + // 提取报警业务信息 + dto.setAlarmType(rootNode.path("eventType").asText("未知报警")); + dto.setAlarmLevel(rootNode.path("level").asText("一般")); + dto.setDescription(rootNode.path("description").asText("")); + + // 提取时间 (注意时区和格式转换) + String timeStr = rootNode.path("happenTime").asText(); + if (!timeStr.isEmpty()) { + dto.setOccurTime(LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + } else { + dto.setOccurTime(LocalDateTime.now()); + } + + // 提取图片 URL (如果有) + JsonNode picNode = rootNode.path("pictureUrl"); + if (!picNode.isMissingNode()) { + dto.setImageUrl(picNode.asText()); + } + + return dto; + } +} + +@Data +class StandardAlarmDTO { + private String alarmId; // 平台报警唯一ID (用于防重) + private String deviceName; // 设备名称 (如:1号门摄像机) + private String deviceIp; // 设备IP + private String alarmType; // 报警类型 (如:区域入侵、未戴安全帽) + private String alarmLevel; // 报警等级 (如:紧急、一般) + private LocalDateTime occurTime;// 发生时间 + private String imageUrl; // 抓拍图片URL (注意:只传URL,不传Base64) + private String description; // 报警描述 +} \ No newline at end of file diff --git a/web/src/main/java/com/zhehekeji/web/lib/CameraControlLoginModule.java b/web/src/main/java/com/zhehekeji/web/lib/CameraControlLoginModule.java index 49d198e..c8ef3c3 100644 --- a/web/src/main/java/com/zhehekeji/web/lib/CameraControlLoginModule.java +++ b/web/src/main/java/com/zhehekeji/web/lib/CameraControlLoginModule.java @@ -4,6 +4,6 @@ import com.zhehekeji.web.lib.joyware.NetSDKLib; public interface CameraControlLoginModule { - NetSDKLib.LLong login(String ip, int port, String user, String password); + NetSDKLib.LLong login(Integer id,String ip, int port, String user, String password); } diff --git a/web/src/main/java/com/zhehekeji/web/lib/hik/HikCameraControlModuleImpl.java b/web/src/main/java/com/zhehekeji/web/lib/hik/HikCameraControlModuleImpl.java index b8de780..cfbd16d 100644 --- a/web/src/main/java/com/zhehekeji/web/lib/hik/HikCameraControlModuleImpl.java +++ b/web/src/main/java/com/zhehekeji/web/lib/hik/HikCameraControlModuleImpl.java @@ -10,6 +10,7 @@ import com.zhehekeji.web.lib.CameraConnMap; import com.zhehekeji.web.lib.CameraControlModule; import com.zhehekeji.web.lib.joyware.NetSDKLib; import com.zhehekeji.web.pojo.camera.CameraPtzPojo; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import lombok.extern.slf4j.Slf4j; import java.io.*; @@ -17,9 +18,7 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.Timer; +import java.util.*; import static com.zhehekeji.web.lib.hik.HCNetSDK.NET_DVR_GET_PTZPOS; import static com.zhehekeji.web.lib.hik.HCNetSDK.NET_DVR_SET_TIMECFG; @@ -31,10 +30,26 @@ import static com.zhehekeji.web.lib.hik.HCNetSDK.NET_DVR_SET_TIMECFG; @Slf4j public class HikCameraControlModuleImpl implements CameraControlModule { + + /** + * 云台控制结果写入IOT状态:成功写0,失败写错误码 + */ + private boolean writeCameraStatus(Integer cameraId, boolean ok) { + if (ok) { + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId), "cameraErrorCode", 0); + } else { + int errorCode = HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(); + log.error("ptz error:{},cameraId:{}", errorCode, cameraId); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId), "cameraErrorCode", errorCode); + } + return ok; + } + public boolean connectStatus(Integer cameraId){ NetSDKLib.LLong userId = CameraConnMap.getConnId(cameraId); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_RemoteControl(userId.intValue(),20005,null,0); + boolean ok = HikLoginModuleImpl.hcNetsdk.NET_DVR_RemoteControl(userId.intValue(),20005,null,0); + return writeCameraStatus(cameraId, ok); } @@ -44,13 +59,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlUpStart(Integer cameraId, int nChannelID, int dwPTZCommand,int dwStop) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.TILT_UP, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.TILT_UP, 0)); } public boolean ptzControlUpEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.TILT_UP, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.TILT_UP, 1)); } /** @@ -59,13 +74,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlDownStart(Integer cameraId, int nChannelID, int dwPTZCommand, int dwStop) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.TILT_DOWN, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.TILT_DOWN, 0)); } public boolean ptzControlDownEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.TILT_DOWN, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.TILT_DOWN, 1)); } /** @@ -74,13 +89,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlLeftStart(Integer cameraId, int nChannelID, int dwPTZCommand, int dwStop) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.PAN_LEFT, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.PAN_LEFT, 0)); } public boolean ptzControlLeftEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.PAN_LEFT, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.PAN_LEFT, 1)); } @Override @@ -93,11 +108,14 @@ public class HikCameraControlModuleImpl implements CameraControlModule { IntByReference intByReference = new IntByReference(1); boolean b_GetPTZ = HikLoginModuleImpl.hcNetsdk.NET_DVR_GetDVRConfig(lUserId, NET_DVR_GET_PTZPOS,1,pointer,netDvrPtzpos.size(),intByReference); if (b_GetPTZ == false) { - System.out.println("获取PTZ坐标信息失败,错误码:" +HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError()); + int errorCode = HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(); + System.out.println("获取PTZ坐标信息失败,错误码:" + errorCode); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(lUserID),"cameraErrorCode",errorCode); cameraPtzPojo.setGetSuccess(false); }else { cameraPtzPojo.setGetSuccess(true); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(lUserID),"cameraErrorCode",0); netDvrPtzpos.read(); cameraPtzPojo.setWPanPos(hexToDegree(netDvrPtzpos.wPanPos)); cameraPtzPojo.setWTiltPos(hexToDegree(netDvrPtzpos.wTiltPos)); @@ -122,13 +140,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlRightStart(Integer cameraId, int nChannelID, int dwPTZCommand, int dwStop) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.PAN_RIGHT, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.PAN_RIGHT, 0)); } public boolean ptzControlRightEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.PAN_RIGHT, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.PAN_RIGHT, 1)); } /** * 向左上 @@ -136,13 +154,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlLeftUpStart(Integer cameraId, int nChannelID, int dwPTZCommand, int dwStop) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.UP_LEFT, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.UP_LEFT, 0)); } public boolean ptzControlLeftUpEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.UP_LEFT, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.UP_LEFT, 1)); } /** @@ -151,14 +169,14 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlRightUpStart(Integer cameraId, int nChannelID, int dwPTZCommand, int dwStop) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.UP_RIGHT, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.UP_RIGHT, 0)); } public boolean ptzControlRightUpEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.UP_RIGHT, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.UP_RIGHT, 1)); } /** * 向左下 @@ -167,15 +185,12 @@ public class HikCameraControlModuleImpl implements CameraControlModule { { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); Boolean ok = HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.DOWN_LEFT, 0); - if(!ok){ - log.error("error:{},cameraId:{}", HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(),cameraId); - } - return ok; + return writeCameraStatus(cameraId, ok); } public boolean ptzControlLeftDownEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.DOWN_LEFT, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.DOWN_LEFT, 1)); } /** * 向右下 @@ -183,13 +198,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlRightDownStart(Integer cameraId, int nChannelID, int dwPTZCommand, int dwStop) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.DOWN_RIGHT, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.DOWN_RIGHT, 0)); } public boolean ptzControlRightDownEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.DOWN_RIGHT, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.DOWN_RIGHT, 1)); } /** @@ -198,13 +213,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlZoomAddStart(Integer cameraId, int nChannelID, int dwPTZCommand) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.ZOOM_IN, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.ZOOM_IN, 0)); } public boolean ptzControlZoomAddEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.ZOOM_IN, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.ZOOM_IN, 1)); } /** @@ -213,13 +228,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlZoomDecStart(Integer cameraId, int nChannelID, int dwPTZCommand) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.ZOOM_OUT, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.ZOOM_OUT, 0)); } public boolean ptzControlZoomDecEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.ZOOM_OUT, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.ZOOM_OUT, 1)); } /** * 变焦+ @@ -227,13 +242,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlFocusAddStart(Integer cameraId, int nChannelID, int dwPTZCommand) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.FOCUS_NEAR, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.FOCUS_NEAR, 0)); } public boolean ptzControlFocusAddEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.FOCUS_NEAR, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.FOCUS_NEAR, 1)); } /** * 变焦- @@ -241,13 +256,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlFocusDecStart(Integer cameraId, int nChannelID, int dwPTZCommand) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.FOCUS_FAR, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.FOCUS_FAR, 0)); } public boolean ptzControlFocusDecEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.FOCUS_FAR, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.FOCUS_FAR, 1)); } /** @@ -256,13 +271,13 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlIrisAddStart(Integer cameraId, int nChannelID, int dwPTZCommand) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.IRIS_OPEN, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.IRIS_OPEN, 0)); } public boolean ptzControlIrisAddEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.IRIS_OPEN, 1); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.IRIS_OPEN, 1)); } /** @@ -271,14 +286,14 @@ public class HikCameraControlModuleImpl implements CameraControlModule { public boolean ptzControlIrisDecStart(Integer cameraId, int nChannelID, int dwPTZCommand) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.IRIS_CLOSE, 0); + return writeCameraStatus(cameraId, HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.IRIS_CLOSE, 0)); } public boolean ptzControlIrisDecEnd(Integer cameraId, int nChannelID) { int lUserId = CameraConnMap.getConnId(cameraId).intValue(); Boolean ok = HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZControl_Other(lUserId, 1, HCNetSDK.IRIS_CLOSE, 1); - return ok; + return writeCameraStatus(cameraId, ok); } public boolean pic(Integer cameraId, int nChannelID, String path) @@ -290,7 +305,12 @@ public class HikCameraControlModuleImpl implements CameraControlModule { HCNetSDK.NET_DVR_JPEGPARA jpegpara = new HCNetSDK.NET_DVR_JPEGPARA(wPicSize, wPicQuality); boolean picResult = HikLoginModuleImpl.hcNetsdk.NET_DVR_CaptureJPEGPicture(lUserId, 1, jpegpara, path); if (!picResult) { - log.error("pic error:{},cameraId:{},lUserId{}", HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(),cameraId,lUserId); + int errorCode = HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(); + log.error("pic error:{},cameraId:{},lUserId{}",errorCode ,cameraId,lUserId); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",errorCode); + }else{ + + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",0); } return picResult; @@ -309,12 +329,16 @@ public class HikCameraControlModuleImpl implements CameraControlModule { int result = HikLoginModuleImpl.hcNetsdk.NET_DVR_GetFileByTime(lUserID, 1, startTime, endTime, path); if (result == -1) { - log.error("downloadMp4 error code:{},cameraId:{},path:{}", HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(),cameraId,path); + int errorCode = HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(); + log.error("downloadMp4 error code:{},cameraId:{},path:{}", errorCode,cameraId,path); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",errorCode); } else { HikLoginModuleImpl.hcNetsdk.NET_DVR_PlayBackControl(result, HikLoginModuleImpl.hcNetsdk.NET_DVR_PLAYSTART,0,null); Timer downloadtimer = new Timer(); downloadtimer.schedule(new DownloadTask(result,downloadtimer,path,cameraId), 0, 5000); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",0); } + } class DownloadTask extends java.util.TimerTask { @@ -421,7 +445,11 @@ public class HikCameraControlModuleImpl implements CameraControlModule { int dwzCommand = HCNetSDK.SET_PRESET; Boolean ok = HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZPreset_Other(CameraConnMap.getConnId(cameraId).intValue(), 1, dwzCommand, ptzId.intValue()); if(!ok){ - log.error("ptz error:{},cameraId:{}", HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(),cameraId); + int errorCode = HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(); + log.error("ptz error:{},cameraId:{}", errorCode,cameraId); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",errorCode); + }else { + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",0); } Assert.isTrue(ok, "设置失败"); } @@ -436,7 +464,11 @@ public class HikCameraControlModuleImpl implements CameraControlModule { int dwPTZCommand = HCNetSDK.GOTO_PRESET; Boolean ok = HikLoginModuleImpl.hcNetsdk.NET_DVR_PTZPreset_Other(CameraConnMap.getConnId(cameraId).intValue(), 1, dwPTZCommand, ptzId); if(!ok){ - log.error("toPtz error:{},cameraId:{}", HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(),cameraId); + int errorCode = HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(); + log.error("ptz error:{},cameraId:{}", errorCode,cameraId); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",errorCode); + }else { + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",0); } } @@ -459,7 +491,11 @@ public class HikCameraControlModuleImpl implements CameraControlModule { Boolean ok = HikLoginModuleImpl.netsdk.CLIENT_DHPTZControlEx2(CameraConnMap.getConnId(cameraId), 0, dwPTZCommand, 0, 0, 0, 0, absolutely.getPointer()); if(!ok){ - log.error("toPtzSlow error:{},cameraId:{}", HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(),cameraId); + int errorCode = HikLoginModuleImpl.hcNetsdk.NET_DVR_GetLastError(); + log.error("ptz error:{},cameraId:{}", errorCode,cameraId); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",errorCode); + }else { + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",0); } } @@ -470,8 +506,8 @@ public class HikCameraControlModuleImpl implements CameraControlModule { LocalDateTime localDateTime = LocalDateTime.now(); time.setTime(localDateTime.getYear(),localDateTime.getMonthValue(),localDateTime.getDayOfMonth(),localDateTime.getHour(),localDateTime.getMinute(),localDateTime.getSecond()); time.write(); - return HikLoginModuleImpl.hcNetsdk.NET_DVR_SetDVRConfig(lUserId, NET_DVR_SET_TIMECFG, 0,time.getPointer(), time.size()); - + boolean ok = HikLoginModuleImpl.hcNetsdk.NET_DVR_SetDVRConfig(lUserId, NET_DVR_SET_TIMECFG, 0,time.getPointer(), time.size()); + return writeCameraStatus(cameraId, ok); } } diff --git a/web/src/main/java/com/zhehekeji/web/lib/hik/HikExceptionCallBack.java b/web/src/main/java/com/zhehekeji/web/lib/hik/HikExceptionCallBack.java index 097bf53..e5a4b8c 100644 --- a/web/src/main/java/com/zhehekeji/web/lib/hik/HikExceptionCallBack.java +++ b/web/src/main/java/com/zhehekeji/web/lib/hik/HikExceptionCallBack.java @@ -3,6 +3,7 @@ package com.zhehekeji.web.lib.hik; import com.sun.jna.Pointer; import com.zhehekeji.web.lib.CameraConnMap; import com.zhehekeji.web.lib.joyware.NetSDKLib; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -16,9 +17,11 @@ public class HikExceptionCallBack implements HCNetSDK.FExceptionCallBack { if(dwType == 32768){ log.error("hik disconnect,cameraId:{}", cameraId); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",dwType); }else if(dwType == 32791){ log.info("hik reconnect,cameraId:{}", cameraId); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(cameraId),"cameraErrorCode",0); if(!lLong.equals(CameraConnMap.getConnId(cameraId))) { log.error("hik reconnect,cameraId:{},lUserId:{}", cameraId,lLong); diff --git a/web/src/main/java/com/zhehekeji/web/lib/hik/HikLoginModuleImpl.java b/web/src/main/java/com/zhehekeji/web/lib/hik/HikLoginModuleImpl.java index 8e56835..fcdc385 100644 --- a/web/src/main/java/com/zhehekeji/web/lib/hik/HikLoginModuleImpl.java +++ b/web/src/main/java/com/zhehekeji/web/lib/hik/HikLoginModuleImpl.java @@ -1,16 +1,24 @@ package com.zhehekeji.web.lib.hik; import com.sun.jna.Pointer; +import com.zhehekeji.web.config.ConfigProperties; import com.zhehekeji.web.lib.CameraControlLoginModule; import com.zhehekeji.web.lib.joyware.NetSDKLib; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; /** * 海康 登陆接口实现 * 主要有 :初始化、登陆、登出功能 */ @Slf4j +@Component public class HikLoginModuleImpl implements CameraControlLoginModule { + @Resource + private IotServiceImpl iotService; @@ -69,7 +77,7 @@ public class HikLoginModuleImpl implements CameraControlLoginModule { * 登录设备 * \endif */ - public NetSDKLib.LLong login(String m_strIp, int m_nPort, String m_strUser, String m_strPassword) { + public NetSDKLib.LLong login(Integer id,String m_strIp, int m_nPort, String m_strUser, String m_strPassword) { init(); HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//设备登录信息 @@ -97,7 +105,9 @@ public class HikLoginModuleImpl implements CameraControlLoginModule { int tryTimes = 0; while(m_lUserID < 0 && tryTimes < MAX_RECONNET_TIME){ - log.error("hik login error,ip:{},port:{},errorCode:{}",m_strIp,m_nPort,hcNetsdk.NET_DVR_GetLastError()); + int errorCode = hcNetsdk.NET_DVR_GetLastError(); + log.error("hik login error,ip:{},port:{},errorCode:{}",m_strIp,m_nPort,errorCode); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(id),"cameraErrorCode",errorCode); try { Thread.sleep(500); } catch (InterruptedException e) { @@ -108,6 +118,7 @@ public class HikLoginModuleImpl implements CameraControlLoginModule { } if(m_lUserID >= 0){ log.info("hik login success"); + IotServiceImpl.set(IotServiceImpl.cameraToStreetMap.get(id),"cameraErrorCode",0); //此id是用来保存视频的 且id不是固定的 int lDChannel = (int)m_strDeviceInfo.struDeviceV30.byStartDChan + lChannel -1; diff --git a/web/src/main/java/com/zhehekeji/web/lib/joyware/JoywareLoginModuleImpl.java b/web/src/main/java/com/zhehekeji/web/lib/joyware/JoywareLoginModuleImpl.java index 3261ed1..05c10d8 100644 --- a/web/src/main/java/com/zhehekeji/web/lib/joyware/JoywareLoginModuleImpl.java +++ b/web/src/main/java/com/zhehekeji/web/lib/joyware/JoywareLoginModuleImpl.java @@ -121,7 +121,7 @@ public class JoywareLoginModuleImpl implements CameraControlLoginModule { * 登录设备 * \endif */ - public LLong login(String m_strIp, int m_nPort, String m_strUser, String m_strPassword) { + public LLong login(Integer id,String m_strIp, int m_nPort, String m_strUser, String m_strPassword) { //IntByReference nError = new IntByReference(0); //入参 init(disConnectCallBack, haveReConnect); diff --git a/web/src/main/java/com/zhehekeji/web/lib/joyware/callBackTest/JoywarePlaybackTest.java b/web/src/main/java/com/zhehekeji/web/lib/joyware/callBackTest/JoywarePlaybackTest.java index d81be02..c2ca12a 100644 --- a/web/src/main/java/com/zhehekeji/web/lib/joyware/callBackTest/JoywarePlaybackTest.java +++ b/web/src/main/java/com/zhehekeji/web/lib/joyware/callBackTest/JoywarePlaybackTest.java @@ -136,7 +136,7 @@ public class JoywarePlaybackTest { if (password.isEmpty()) password = "admin123"; try { - LLong loginId = joywareLogin.login(ip, port, username, password); + LLong loginId = joywareLogin.login(1,ip, port, username, password); if (loginId != null && loginId.longValue() != 0) { loginIdMap.put(ip, loginId); diff --git a/web/src/main/java/com/zhehekeji/web/pojo/IndustrialCameraVO.java b/web/src/main/java/com/zhehekeji/web/pojo/IndustrialCameraVO.java index 9958476..8f55c83 100644 --- a/web/src/main/java/com/zhehekeji/web/pojo/IndustrialCameraVO.java +++ b/web/src/main/java/com/zhehekeji/web/pojo/IndustrialCameraVO.java @@ -19,7 +19,7 @@ public class IndustrialCameraVO implements Delayed { private String trayCode; private String wmsTrayCode; - private int flag; + private int flag = 12; private String streetId; private int sentCount; diff --git a/web/src/main/java/com/zhehekeji/web/pojo/stock/CheckLogSearch.java b/web/src/main/java/com/zhehekeji/web/pojo/stock/CheckLogSearch.java index 7a6a62f..f2ee0ce 100644 --- a/web/src/main/java/com/zhehekeji/web/pojo/stock/CheckLogSearch.java +++ b/web/src/main/java/com/zhehekeji/web/pojo/stock/CheckLogSearch.java @@ -19,6 +19,7 @@ public class CheckLogSearch { private LocalDateTime endTimestamp; private Integer streetId; + private String streetPlc; @ApiModelProperty("左右 1:左 2:右") private Integer leftRight; diff --git a/web/src/main/java/com/zhehekeji/web/service/CameraService.java b/web/src/main/java/com/zhehekeji/web/service/CameraService.java index 019a458..d3a6208 100644 --- a/web/src/main/java/com/zhehekeji/web/service/CameraService.java +++ b/web/src/main/java/com/zhehekeji/web/service/CameraService.java @@ -322,7 +322,7 @@ public class CameraService { } public void cameraLogin(Camera camera){ - NetSDKLib.LLong lLong = cameraControlLoginModule.login(camera.getIp(),camera.getPort(),camera.getUser(),camera.getPassword()); + NetSDKLib.LLong lLong = cameraControlLoginModule.login(camera.getId(),camera.getIp(),camera.getPort(),camera.getUser(),camera.getPassword()); if(lLong != null){ log.info("camera login success,cameraId:{},ip:{}",camera.getId(),camera.getIp()); CameraConnMap.conn(camera.getId(),lLong); diff --git a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/HikSaveImage.java b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/HikSaveImage.java index e2c51bd..6566715 100644 --- a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/HikSaveImage.java +++ b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/HikSaveImage.java @@ -10,9 +10,12 @@ package com.zhehekeji.web.service.IndustrialCamera; /*************************** **************************************************************************************************/ import MvCameraControlWrapper.*; +import com.zhehekeji.web.config.ConfigProperties; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import org.springframework.stereotype.Service; import javax.annotation.PreDestroy; +import javax.annotation.Resource; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -30,6 +33,17 @@ import static MvCameraControlWrapper.MvCameraControlDefines.*; @Service public class HikSaveImage implements CameraSaveUtil{ + @Resource + ConfigProperties configProperties; + + void setCameraErrorStatus(String sn,int status){ + for (int i = 1; i <= configProperties.getCameraConfig().getIndustrialCamera().size(); i++){ + if (configProperties.getCameraConfig().getIndustrialCamera().get(i-1).equals(sn)){ + IotServiceImpl.set("zt","industrialCamera"+i+"ErrorCode",status); + break; + } + } + } // 设备句柄保存 static Map handleMap = new ConcurrentHashMap<>(); private static void printDeviceInfo(MV_CC_DEVICE_INFO stDeviceInfo) @@ -167,80 +181,144 @@ public class HikSaveImage implements CameraSaveUtil{ @Override public boolean saveImage(String sn, String path,String type) { int nRet = MV_OK; + int maxRetry = 3; - System.out.println("SDK Version " + MvCameraControl.MV_CC_GetSDKVersion()); - - // Enuerate GigE and USB devices + System.out.println("SDK Version " + MvCameraControl.MV_CC_GetSDKVersion()); - // choose camera + // 重试循环:任何一步失败都会清理旧句柄、重新连接后重试 + for (int attempt = 1; attempt <= maxRetry; attempt++) { + try { + Handle hCamera = null; + if (handleMap.containsKey(sn) && handleMap.get(sn) != null) { + //已经获得句柄 + hCamera = handleMap.get(sn); + }else { + // 没有连接,重新连接设备 + System.out.println("未找到句柄,尝试重新连接设备: " + sn); + hCamera = reconnect(sn, type); + if (hCamera == null) { + System.out.println("重新连接设备失败: " + sn); + continue; + } + System.out.println("重新连接设备成功: " + sn); + } + // Get payload size + MVCC_INTVALUE stParam = new MVCC_INTVALUE(); + nRet = MvCameraControl.MV_CC_GetIntValue(hCamera, "PayloadSize", stParam); + if (MV_OK != nRet) + { + System.err.printf("Get PayloadSize fail, errcode: [%#x]\n", nRet); + setCameraErrorStatus(sn, nRet); + // 句柄可能已失效,重新连接后重试 + reconnect(sn, type); + continue; + } - Handle hCamera = null; - if (handleMap.containsKey(sn) && handleMap.get(sn) != null) { - //已经获得句柄 - hCamera = handleMap.get(sn); - }else { - System.out.println("未找到句柄"); - } - // Create handle + // Get one frame + MV_FRAME_OUT_INFO stImageInfo = new MV_FRAME_OUT_INFO(); + byte[] pData = new byte[(int)stParam.curValue]; + nRet = MvCameraControl.MV_CC_GetOneFrameTimeout(hCamera, pData, stImageInfo, 1000); + if (MV_OK != nRet) + { + System.err.printf("GetOneFrameTimeout fail, errcode:[%#x]\n", nRet); + setCameraErrorStatus(sn, nRet); + reconnect(sn, type); + continue; + } + while(stImageInfo.height <= 0 || stImageInfo.width <= 0){ + nRet = MvCameraControl.MV_CC_GetOneFrameTimeout(hCamera, pData, stImageInfo, 1000); + if (MV_OK != nRet) + { + System.err.printf("GetOneFrameTimeout fail, errcode:[%#x]\n", nRet); + setCameraErrorStatus(sn, nRet); + break; + } + } + if (MV_OK != nRet) + { + reconnect(sn, type); + continue; + } + System.out.println("GetOneFrame: "); + printFrameInfo(stImageInfo); + int imageLen = stImageInfo.width * stImageInfo.height * 3; // Every RGB pixel takes 3 bytes + byte[] imageBuffer = new byte[imageLen]; + + // Call MV_CC_SaveImage to save image as JPEG + MV_SAVE_IMAGE_PARAM stSaveParam = new MV_SAVE_IMAGE_PARAM(); + stSaveParam.width = stImageInfo.width; // image width + stSaveParam.height = stImageInfo.height; // image height + stSaveParam.data = pData; // image data + stSaveParam.dataLen = stImageInfo.frameLen; // image data length + stSaveParam.pixelType = stImageInfo.pixelType; // image pixel format + stSaveParam.imageBuffer = imageBuffer; // output image buffer + stSaveParam.imageType = MV_SAVE_IAMGE_TYPE.MV_Image_Jpeg; // output image pixel format + stSaveParam.methodValue = 0; // Interpolation method that converts Bayer format to RGB24. 0-Neareast 1-double linear 2-Hamilton + stSaveParam.jpgQuality = 99; // JPG endoding quality(50-99] + + nRet = MvCameraControl.MV_CC_SaveImage(hCamera, stSaveParam); + setCameraErrorStatus(sn, nRet); + if (MV_OK != nRet) + { + System.err.printf("SaveImage fail, errcode: [%#x]\n", nRet); + reconnect(sn, type); + continue; + } + // Save buffer content to file + saveDataToFile(imageBuffer, imageLen, path); - // Get payload size - MVCC_INTVALUE stParam = new MVCC_INTVALUE(); - nRet = MvCameraControl.MV_CC_GetIntValue(hCamera, "PayloadSize", stParam); - if (MV_OK != nRet) - { - System.err.printf("Get PayloadSize fail, errcode: [%#x]\n", nRet); - return false; + setCameraErrorStatus(sn, MV_OK); + return true; + } catch (Exception e) { + System.err.println("第 " + attempt + " 次拍照异常: " + e.getMessage()); + e.printStackTrace(); + setCameraErrorStatus(sn, -1); + reconnect(sn, type); } + } + System.out.println("重试 " + maxRetry + " 次后拍照失败: " + sn); + setCameraErrorStatus(sn, nRet); + return false; + } - - // Get one frame - MV_FRAME_OUT_INFO stImageInfo = new MV_FRAME_OUT_INFO(); - byte[] pData = new byte[(int)stParam.curValue]; - nRet = MvCameraControl.MV_CC_GetOneFrameTimeout(hCamera, pData, stImageInfo, 1000); - while(true){ - if(stImageInfo.height >0 && stImageInfo.width >0){ - break; - } + /** + * 重新连接设备:清理旧句柄后,重新枚举并初始化 + * @param sn 设备序列号 + * @param type 匹配方式(sn/ip) + * @return 新句柄,失败返回null + */ + private Handle reconnect(String sn, String type) { + System.out.println("尝试重新连接设备: " + sn); + // 清理旧句柄 + Handle oldHandle = handleMap.remove(sn); + if (oldHandle != null) { + try { + MvCameraControl.MV_CC_StopGrabbing(oldHandle); + } catch (Exception ignore) { } - if (MV_OK != nRet) - { - System.err.printf("GetOneFrameTimeout fail, errcode:[%#x]\n", nRet); - return false; + try { + MvCameraControl.MV_CC_DestroyHandle(oldHandle); + } catch (Exception ignore) { } - - System.out.println("GetOneFrame: "); - printFrameInfo(stImageInfo); - int imageLen = stImageInfo.width * stImageInfo.height * 3; // Every RGB pixel takes 3 bytes - byte[] imageBuffer = new byte[imageLen]; - - // Call MV_CC_SaveImage to save image as JPEG - MV_SAVE_IMAGE_PARAM stSaveParam = new MV_SAVE_IMAGE_PARAM(); - stSaveParam.width = stImageInfo.width; // image width - stSaveParam.height = stImageInfo.height; // image height - stSaveParam.data = pData; // image data - stSaveParam.dataLen = stImageInfo.frameLen; // image data length - stSaveParam.pixelType = stImageInfo.pixelType; // image pixel format - stSaveParam.imageBuffer = imageBuffer; // output image buffer - stSaveParam.imageType = MV_SAVE_IAMGE_TYPE.MV_Image_Jpeg; // output image pixel format - stSaveParam.methodValue = 0; // Interpolation method that converts Bayer format to RGB24. 0-Neareast 1-double linear 2-Hamilton - stSaveParam.jpgQuality = 99; // JPG endoding quality(50-99] - - nRet = MvCameraControl.MV_CC_SaveImage(hCamera, stSaveParam); - if (MV_OK != nRet) - { - System.err.printf("SaveImage fail, errcode: [%#x]\n", nRet); - return false; + } + try { + ArrayList stDeviceList = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE); + if (stDeviceList == null || stDeviceList.size() <= 0) { + System.out.println("未枚举到任何设备"); + setCameraErrorStatus(sn, -1); + return null; } - - // Save buffer content to file - saveDataToFile(imageBuffer, imageLen, path); - - - return true; + return init(sn, stDeviceList, type); + } catch (CameraControlException e) { + System.err.println("枚举设备失败!" + e.toString()); + e.printStackTrace(); + setCameraErrorStatus(sn, -1); + return null; + } } public void init(List sns,String type){ ArrayList stDeviceList = new ArrayList<>(); @@ -281,6 +359,7 @@ public class HikSaveImage implements CameraSaveUtil{ nRet = MvCameraControl.MV_CC_OpenDevice(hCamera); if (MV_OK != nRet) { System.err.printf("Connect to camera failed, errcode: [%#x]\n", nRet); + setCameraErrorStatus(sn, nRet); } @@ -288,6 +367,7 @@ public class HikSaveImage implements CameraSaveUtil{ nRet = MvCameraControl.MV_CC_SetEnumValueByString(hCamera, "TriggerMode", "Off"); if (MV_OK != nRet) { System.err.printf("SetTriggerMode failed, errcode: [%#x]\n", nRet); + setCameraErrorStatus(sn, nRet); } // Get payload size @@ -295,6 +375,8 @@ public class HikSaveImage implements CameraSaveUtil{ // Start grabbing nRet = MvCameraControl.MV_CC_StartGrabbing(hCamera); + + setCameraErrorStatus(sn, nRet); if (MV_OK != nRet) { System.err.printf("Start Grabbing fail, errcode: [%#x]\n", nRet); @@ -324,6 +406,7 @@ public class HikSaveImage implements CameraSaveUtil{ if (camIndex == -1) { System.out.println("未找到摄像头"); + setCameraErrorStatus(sn, -1); return null; } //未获得句柄并初始化 @@ -335,6 +418,7 @@ public class HikSaveImage implements CameraSaveUtil{ if (MV_OK != nRet) { System.err.printf("Connect to camera failed, errcode: [%#x]\n", nRet); + setCameraErrorStatus(sn, nRet); return null; } @@ -344,6 +428,7 @@ public class HikSaveImage implements CameraSaveUtil{ if (MV_OK != nRet) { System.err.printf("SetTriggerMode failed, errcode: [%#x]\n", nRet); + setCameraErrorStatus(sn, nRet); return null; } @@ -355,6 +440,7 @@ public class HikSaveImage implements CameraSaveUtil{ if (MV_OK != nRet) { System.err.printf("Start Grabbing fail, errcode: [%#x]\n", nRet); + setCameraErrorStatus(sn, nRet); return null; } @@ -364,6 +450,7 @@ public class HikSaveImage implements CameraSaveUtil{ { System.err.println("Create handle failed!" + e.toString()); e.printStackTrace(); + setCameraErrorStatus(sn, -1); return null; diff --git a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/LxPointCloudSaveImage.java b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/LxPointCloudSaveImage.java index f9d7737..696b541 100644 --- a/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/LxPointCloudSaveImage.java +++ b/web/src/main/java/com/zhehekeji/web/service/IndustrialCamera/LxPointCloudSaveImage.java @@ -3,6 +3,7 @@ package com.zhehekeji.web.service.IndustrialCamera; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.ptr.PointerByReference; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import io.swagger.models.auth.In; import lombok.extern.slf4j.Slf4j; @@ -146,6 +147,7 @@ public class LxPointCloudSaveImage { return handleRef; } else { log.error("设备 {} 初始化失败,错误码: {}", sn, result); + IotServiceImpl.set("zt","camera3dErrorCode",result); return null; } } @@ -163,6 +165,7 @@ public class LxPointCloudSaveImage { PointerByReference handleRef, DcLibrary.LxDeviceInfo info, int maxRetries) { int result = INSTANCE.DcOpenDevice(1, sn, handleRef, info); log.debug("设备 {} 首次打开结果: {}", sn, result); + IotServiceImpl.set("zt","camera3dErrorCode",result); if (result == 0) { return result; @@ -175,6 +178,7 @@ public class LxPointCloudSaveImage { log.info("设备 {} 打开失败,第 {} 次重试,错误码: {}", sn, retryCount.get(), result); Thread.sleep(RETRY_INTERVAL_MS); result = INSTANCE.DcOpenDevice(1, sn, handleRef, info); + IotServiceImpl.set("zt","camera3dErrorCode",result); if (result == 0) { log.info("设备 {} 第 {} 次重试成功", sn, retryCount.get()); return result; @@ -183,11 +187,13 @@ public class LxPointCloudSaveImage { } catch (InterruptedException e) { log.error("设备 {} 重试被中断", sn, e); Thread.currentThread().interrupt(); + IotServiceImpl.set("zt","camera3dErrorCode",result); return result; } } log.error("设备 {} 重试 {} 次后仍然失败", sn, maxRetries); + IotServiceImpl.set("zt","camera3dErrorCode",result); return result; } @@ -226,6 +232,7 @@ public class LxPointCloudSaveImage { // 尝试重新打开设备,设置新的句柄 int result = openDeviceWithRetry(INSTANCER, sn, handleRef, info, MAX_RETRY_COUNT); + IotServiceImpl.set("zt","camera3dErrorCode",result); if (result == 0) { // 更新设备信息 DeviceInfo deviceInfo = new DeviceInfo(handleRef, info, type); @@ -370,6 +377,7 @@ public class LxPointCloudSaveImage { PointerByReference handleRef = getHandle(sn, type, INSTANCE); if (handleRef == null) { log.error("设备 {} 获取句柄失败", sn); + IotServiceImpl.set("zt","camera3dErrorCode",-3); return -3; } @@ -384,12 +392,15 @@ public class LxPointCloudSaveImage { // 设置命令码 result = INSTANCE.DcSetCmd(handleRef.getValue(), 5001); + + IotServiceImpl.set("zt","camera3dErrorCode",result); if (result != 0 && result != 25) { log.error("设备 {} 设置命令失败,错误码: {}", sn, result); return -3; } } else { log.error("设备 {} 流启动失败,错误码: {}", sn, result); + IotServiceImpl.set("zt","camera3dErrorCode",result); return -3; } } @@ -409,11 +420,13 @@ public class LxPointCloudSaveImage { if (saveResult != 0 && saveResult != 25) { log.error("设备 {} 保存点云失败,错误码: {}", sn, saveResult); + IotServiceImpl.set("zt","camera3dErrorCode",saveResult); return -1; } // 不再每次都停止流,流保持运行状态 log.info("设备 {} 保存成功", sn); + IotServiceImpl.set("zt","camera3dErrorCode",0); return 0; } @@ -445,6 +458,7 @@ public class LxPointCloudSaveImage { if (handleRef == null) { log.warn("设备 {} 第 {} 次拍照获取句柄失败,尝试重新设置句柄", sn, retryCount); lastError = -3; + IotServiceImpl.set("zt","camera3dErrorCode",lastError); // 尝试重新设置句柄 boolean reconnectSuccess = reDevice(sn); @@ -485,6 +499,9 @@ public class LxPointCloudSaveImage { int result = INSTANCER.DcSetCmd(handleRef.getValue(), 5001); log.info("设备 {} 3dCamera set cmd: {}, result: {}", sn, 5001, result); + if (result != 0 && result != 25) { + IotServiceImpl.set("zt","camera3dErrorCode",result); + } // 保存点云数据 int saveResult = INSTANCER.DcSaveXYZ(handleRef.getValue(), path); log.info("设备 {} 3dCamera save pcd: {}, result: {}", sn, path, saveResult); @@ -492,6 +509,7 @@ public class LxPointCloudSaveImage { if (saveResult != 0 && saveResult != 25) { log.warn("设备 {} 第 {} 次拍照保存点云失败,错误码: {},尝试重新设置句柄", sn, retryCount, saveResult); lastError = -1; + IotServiceImpl.set("zt","camera3dErrorCode",saveResult); // 尝试重新设置句柄 boolean reconnectSuccess = reconnect(sn, type); @@ -509,6 +527,7 @@ public class LxPointCloudSaveImage { // 拍照成功 log.info("设备 {} 第 {} 次拍照成功", sn, retryCount); + IotServiceImpl.set("zt","camera3dErrorCode",0); return 0; } catch (InterruptedException e) { diff --git a/web/src/main/java/com/zhehekeji/web/service/InitService.java b/web/src/main/java/com/zhehekeji/web/service/InitService.java index e5d0866..2bc3077 100644 --- a/web/src/main/java/com/zhehekeji/web/service/InitService.java +++ b/web/src/main/java/com/zhehekeji/web/service/InitService.java @@ -10,6 +10,7 @@ import com.zhehekeji.web.lib.joyware.JoywareCameraControlModuleImpl; import com.zhehekeji.web.lib.joyware.JoywareLoginModuleImpl; import com.zhehekeji.web.mapper.CameraMapper; import com.zhehekeji.web.mapper.StreetMapper; +import com.zhehekeji.web.pojo.street.StreetVO; import com.zhehekeji.web.service.IndustrialCamera.HikSaveImage; import com.zhehekeji.web.service.algorithm.InventoryService; import com.zhehekeji.web.service.client.ClientChanel; @@ -29,6 +30,8 @@ import javax.annotation.Resource; import java.util.HashMap; import java.util.List; +import static com.zhehekeji.web.service.iotService.IotServiceImpl.cameraToStreetMap; + /** * 服务初始化 * 上位机、 plc、球机 连接 @@ -100,10 +103,14 @@ public class InitService implements ApplicationRunner { CommandQueue.sentHttp(restTemplate, configProperties); if (configProperties.getCameraConfig()!=null && configProperties.getCameraConfig().getIndustrialCamera()!=null + && !configProperties.getCameraConfig().getIndustrialCamera().isEmpty() && !configProperties.getCameraConfig().getIndustrialCamera().equals("")) hikSaveImage.init(configProperties.getCameraConfig().getIndustrialCamera(),"sn"); if(ksec != null&& ksec.getIp()!=null&& !ksec.getIp().equals("")){ - + List streetList = streetMapper.list(); + for (StreetVO street : streetList) { + cameraToStreetMap.put(street.getCamera1Id(), street.getPlcId()); + } TaskDelayExecutor.runMp4DownloadExecutor(); // nettyServer.CreateNettyServer(configProperties.getServerPort()); diff --git a/web/src/main/java/com/zhehekeji/web/service/PlcService.java b/web/src/main/java/com/zhehekeji/web/service/PlcService.java index cc1c621..74187db 100644 --- a/web/src/main/java/com/zhehekeji/web/service/PlcService.java +++ b/web/src/main/java/com/zhehekeji/web/service/PlcService.java @@ -17,6 +17,7 @@ import com.zhehekeji.web.entity.EmptyCheckPic; import com.zhehekeji.web.service.algorithm.InventoryService; import com.zhehekeji.web.service.client.ClientChanel; import com.zhehekeji.web.service.client.TransmissionPojo; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import com.zhehekeji.web.service.ksec.KsecDataInfo; import com.zhehekeji.web.service.ksec.KsecInfo; import com.zhehekeji.web.service.lbScanCode.ReentrantLockExample; @@ -98,6 +99,9 @@ public class PlcService { @Resource private CheckStreetSummaryMapper checkStreetSummaryMapper; + @Resource + private IotServiceImpl iotService; + @Resource private InventoryService inventoryService; @@ -375,12 +379,20 @@ public class PlcService { ReadOCR scan(PlcCmdInfo plcCmdInfo,Street street,String wmsTrayCode){ Boolean trayCheck = Boolean.FALSE; ReadOCR trayCode = new ReadOCR(); + String pointIdentification = "ScannerScanResult"; log.info("扫码类型:" + configProperties.getScanCodeMode().getTray()); //使用sick扫码枪 int leftRight = plcCmdInfo.getLeftRight1(); if(plcCmdInfo.getSeparation1()==2) { + pointIdentification = "Depth"+ pointIdentification; leftRight=leftRight+2; } + if(plcCmdInfo.getLeftRight1()==1) { + pointIdentification = "left"+ pointIdentification; + }else { + pointIdentification = "right"+ pointIdentification; + } + //托盘使用sick扫码枪 SensorGun sensorGun = sensorService.getSensorByPlc(street.getId(), leftRight); if (sensorGun == null) { @@ -391,9 +403,9 @@ public class PlcService { } else { if (leftRight > 2) { - trayCode = CognexSocket.readOCR(sensorGun.getIp(), sensorGun.getPort()); + trayCode = CognexSocket.readOCR(sensorGun.getIp(), sensorGun.getPort(),pointIdentification,street.getPlcId()); } else { - trayCode = SickSocket.readOCR(sensorGun.getIp(), sensorGun.getPort()); + trayCode = SickSocket.readOCR(sensorGun.getIp(), sensorGun.getPort(),pointIdentification,street.getPlcId()); } log.info("sensor tray code:{}", trayCode); @@ -1246,4 +1258,7 @@ public class PlcService { return ksecInfo; } + public void setPlcData(KsecInfo dataInfo, String srmNumber) { + iotService.set(srmNumber,"communicationData", dataInfo); + } } diff --git a/web/src/main/java/com/zhehekeji/web/service/com/SerialPortManager.java b/web/src/main/java/com/zhehekeji/web/service/com/SerialPortManager.java index ae53d8e..101b4d0 100644 --- a/web/src/main/java/com/zhehekeji/web/service/com/SerialPortManager.java +++ b/web/src/main/java/com/zhehekeji/web/service/com/SerialPortManager.java @@ -32,6 +32,24 @@ public class SerialPortManager { return portNameList; } + /** + * 判断 COM 端口是否被占用(有其他进程在使用) + * @param portName 端口名,如 "COM1", "COM3" + * @return true=被占用,false=空闲可用 + */ + public static boolean isComPortInUse(String portName) { + SerialPort port = SerialPort.getCommPort(portName); + if (port == null) { + return false; // 端口不存在,当作未占用 + } + if (port.openPort(500)) { + // 能打开说明空闲,立即关闭释放 + port.closePort(); + return false; + } + return true; // 打不开说明被占用 + } + // 连接串口 public static void connectSerialPort(String portName){ try { diff --git a/web/src/main/java/com/zhehekeji/web/service/iotService/IotServiceImpl.java b/web/src/main/java/com/zhehekeji/web/service/iotService/IotServiceImpl.java new file mode 100644 index 0000000..27f0990 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/iotService/IotServiceImpl.java @@ -0,0 +1,264 @@ +package com.zhehekeji.web.service.iotService; + +import com.alibaba.fastjson.JSON; +import com.zhehekeji.core.pojo.Result; +import com.zhehekeji.web.config.ConfigProperties; +import com.zhehekeji.web.entity.KuKou; +import com.zhehekeji.web.entity.Street; +import com.zhehekeji.web.pojo.IndustrialCameraVO; +import com.zhehekeji.web.pojo.street.StreetVO; +import com.zhehekeji.web.service.StreetService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.annotation.Resource; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +@Service +public class IotServiceImpl { + + private static final Logger iotLog = LoggerFactory.getLogger("iot"); + + private static final ConcurrentHashMap> map = new ConcurrentHashMap<>(); + + private static final ConcurrentHashMap ztMap = new ConcurrentHashMap<>(); + // 并行 ping 的线程池(核心线程数 20,最大 50,闲置 60s 回收) + private static final ExecutorService pingPool = Executors.newFixedThreadPool(20); + + public static Map cameraToStreetMap = new HashMap<>(); + // ping 超时时间(毫秒),局域网 1 秒足够 + private static final int PING_TIMEOUT = 1000; + + @Resource + StreetService streetService; + + @Resource + ConfigProperties configProperties; + + + @Resource + RestTemplate restTemplate; + + + /** + * 初始化:读取 default.txt + */ + @PostConstruct + public void init() { + + try { + String jsonStr = new String(Files.readAllBytes(Paths.get("default.txt")), StandardCharsets.UTF_8); + Map data = JSON.parseObject(jsonStr); + for (Map.Entry entry : data.entrySet()) { + for (Map.Entry entry1 : ((Map) entry.getValue()).entrySet()) { + set(entry.getKey(), entry1.getKey(), entry1.getValue()); + } + } + System.out.println("初始化完成,数据: " + map.size()); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + @Scheduled(cron = "0/5 * * * * ?") + /** 定时任务:每5秒拉取网络状态并更新(并行 ping) */ + private void refreshNetwork() { + try { + List lines = Files.readAllLines(Paths.get("network.txt"), StandardCharsets.UTF_8); + // 收集所有异步任务 + List> futures = new ArrayList<>(); + for (String line : lines) { + line = line.trim(); + if (line.isEmpty()) continue; + + String[] parts = line.split("="); + if (parts.length != 2) continue; + + String ip = parts[0].trim().replace("\"", ""); + String[] keyField = parts[1].split(":"); + if (keyField.length != 2) continue; + String deviceKey = keyField[0].trim(); + String fieldName = keyField[1].trim(); + + // 异步提交 ping 任务 + int status = ping(ip) ? 1 : 2; + set(deviceKey, fieldName,status ); + } + + String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + for (String entry : map.keySet()) { + set(entry, "time", timestamp); + } + + set("zt", "time", timestamp); + + } catch (Exception e) { + iotLog.error("网络状态刷新异常", e); + } + getZT(); + } + + + /** + * 将当前数据状态数据推送给远端 IoT 控制器 + */ + +// @Scheduled(cron = "0/5 * * * * ?") + public void getZT() { + if (!configProperties.getComTofConfig().isEmpty()) { +// 判断TOF设备连接状态:访问 10.0.0.1 的 502 端口(Modbus TCP) + + boolean isComPortInUse = isTcpPortInUse("10.0.0.1", 502); + for (int i = 0; i < configProperties.getComTofConfig().size(); i++) { + set("zt", "tofDevice0" + (i+1) + "RunStatus", isComPortInUse ? 1 : 2); +// System.out.println("1111"); + } + + + }else { + + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/json"); + headers.set("User-Agent", "Mozilla/5.0"); + + // 从 map 构建传输对象 + IndustrialCameraVO scTransmission = new IndustrialCameraVO(); + // TODO: 根据实际需要填充 scTransmission 的字段 + // 例如:scTransmission.setDeviceList(new ArrayList<>(map.values())); + String URL = "http://" + configProperties.getSiteInventoryIp() + ":8099" + "/api/IotController/listZT"; + iotLog.info("获取站台数据: {} 路径: {}", scTransmission.toString(), URL); + // 创建 HttpEntity 对象 + HttpEntity entity = new HttpEntity<>(scTransmission, headers); + + try { + + // 发送 POST 请求 + ResponseEntity> response = restTemplate.exchange( + URL, + HttpMethod.POST, + entity, + new ParameterizedTypeReference>() { + } + ); + iotLog.info("请求成功,响应:{}", response.getBody()); + set("zt", "inventoryServerOnlineStatus", 1); + if (response.getBody() != null && response.getBody().get("data") != null) { + Map data = (Map) response.getBody().get("data"); + for (Map.Entry entry : data.entrySet()) { +// iotLog.info("数据键: {}, 值: {}", entry.getKey(), entry.getValue()); + set("zt", entry.getKey(), entry.getValue()); + } + } + }catch (Exception e) + { + set("zt", "inventoryServerOnlineStatus", 2); + iotLog.error("请求失败", e); + } + } + } + + + /** + * 获取:返回 map 的 values 列表 + */ + public List get() { + return new ArrayList<>(map.values()); + } + + public Map get(String deviceKey) { + if(deviceKey.equals("zt")){ + return ztMap; + } + return map.get(deviceKey); + } + + public static void set(String deviceKey, String key, Object value) { + if (deviceKey == null){ + iotLog.error("数据不存在{} 数据key: {} 数据value: {}新增数据类型", deviceKey, key, value.toString()); + return; + } + if (deviceKey.equals("zt")) { + Object oldValue = ztMap.get(key); + if (oldValue != null && oldValue.equals(value)) { + // 数据无变化,不记录日志 + return; + } + iotLog.info("更新站台数据key: {} 数据value: {}", key, value.toString()); + + ztMap.put(key, value); + } else { + Map deviceMap = map.get(deviceKey); + if (deviceMap == null) { + iotLog.warn("数据不存在{} 数据key: {} 数据value: {}新增数据类型", deviceKey, key, value.toString()); + deviceMap = new HashMap<>(); + deviceMap.put(key, value); + map.put(deviceKey, deviceMap); + return; + } + Object oldValue = deviceMap.get(key); + if (oldValue != null && oldValue.equals(value)) { + // 数据无变化,不记录日志 + return; + } + iotLog.info("更新巷道号{} 数据key: {} 数据value: {}", deviceKey, key, value.toString()); + + deviceMap.put(key, value); + } + } + + private boolean ping(String ip) { + try { + return InetAddress.getByName(ip).isReachable(PING_TIMEOUT); + } catch (IOException e) { + return false; + } + } + + /** + * 检测TCP端口是否可连接 + */ + private boolean isTcpPortInUse(String ip, int port) { + try (Socket socket = new Socket()) { + socket.connect(new InetSocketAddress(ip, port), 1000); + return true; + } catch (IOException e) { + return false; + } + } + + /** + * 应用关闭时释放线程池(可选,建议配合 @PreDestroy) + */ + @PreDestroy + public void destroy() { + pingPool.shutdown(); + } +} diff --git a/web/src/main/java/com/zhehekeji/web/service/iotService/ScheduleConfig.java b/web/src/main/java/com/zhehekeji/web/service/iotService/ScheduleConfig.java new file mode 100644 index 0000000..1c9127f --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/iotService/ScheduleConfig.java @@ -0,0 +1,38 @@ +package com.zhehekeji.web.service.iotService; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; +import org.springframework.scheduling.support.CronTrigger; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + +//@Configuration +//public class ScheduleConfig implements SchedulingConfigurer { +// +// @Override +// public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { +// taskRegistrar.addTriggerTask( +// // 要定时执行的任务 +// () -> refreshNetwork(), +// // 每次执行前动态读取 cron +// triggerContext -> { +// String cron = null; +// try { +// cron = new String( +// Files.readAllBytes(Paths.get("cron.txt")), StandardCharsets.UTF_8).trim(); +// } catch (IOException e) { +// throw new RuntimeException(e); +// } +// return new CronTrigger(cron).nextExecutionTime(triggerContext); +// } +// ); +// } +// +// private void refreshNetwork() { +// +// } +//} diff --git a/web/src/main/java/com/zhehekeji/web/service/ksec/CommandQueue.java b/web/src/main/java/com/zhehekeji/web/service/ksec/CommandQueue.java index 2975c27..2243ea9 100644 --- a/web/src/main/java/com/zhehekeji/web/service/ksec/CommandQueue.java +++ b/web/src/main/java/com/zhehekeji/web/service/ksec/CommandQueue.java @@ -103,7 +103,7 @@ public class CommandQueue { if (response.getStatusCode().is2xxSuccessful()) { log.info("请求成功,响应:{}", response.getBody()); } else { - log.warn("请求未成功,状态码:{}", response.getStatusCode()); + log.error("请求未成功,返回:{}状态码:{}", response, response.getStatusCode()); addCommand(scTransmission); } diff --git a/web/src/main/java/com/zhehekeji/web/service/ksec/KescFilter.java b/web/src/main/java/com/zhehekeji/web/service/ksec/KescFilter.java index 57a8aca..57b3c19 100644 --- a/web/src/main/java/com/zhehekeji/web/service/ksec/KescFilter.java +++ b/web/src/main/java/com/zhehekeji/web/service/ksec/KescFilter.java @@ -1,6 +1,7 @@ package com.zhehekeji.web.service.ksec; import com.zhehekeji.web.service.*; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelInitializer; @@ -23,12 +24,13 @@ public class KescFilter extends ChannelInitializer { private PlcService plcService; private KsecNettyClient nettyClient; + private IotServiceImpl iotService; - public KescFilter(KsecInfo ksecInfo, PlcService plcService, KsecNettyClient nettyClient){ + public KescFilter(KsecInfo ksecInfo, PlcService plcService, KsecNettyClient nettyClient,IotServiceImpl iotService){ this.ksecInfo = ksecInfo; this.plcService = plcService; this.nettyClient = nettyClient; - + this.iotService = iotService; } @Override @@ -37,7 +39,7 @@ public class KescFilter extends ChannelInitializer { //4秒发一次心跳 ph.addLast(new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS)); ByteBuf byteBuf = Unpooled.copiedBuffer(">".getBytes()); - ph.addLast(new KsecDecoder(10000,byteBuf,plcService)); + ph.addLast(new KsecDecoder(10000,byteBuf,plcService,iotService)); ph.addLast(new KescEncoder()); ph.addLast(new KescNettyHandler(ksecInfo,nettyClient)); } diff --git a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java index 6dbef00..7f6fa9f 100644 --- a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java +++ b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecDecoder.java @@ -6,6 +6,7 @@ import com.zhehekeji.web.pojo.Cmd; import com.zhehekeji.web.service.GoodsActionTimes; import com.zhehekeji.web.service.PlcCmdInfo; import com.zhehekeji.web.service.PlcService; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.DelimiterBasedFrameDecoder; @@ -38,10 +39,12 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(7,21,30, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(20000)); private PlcService plcService; + private IotServiceImpl iotService; - public KsecDecoder(int maxFrameLength, ByteBuf delimiter, PlcService plcService) { + public KsecDecoder(int maxFrameLength, ByteBuf delimiter, PlcService plcService,IotServiceImpl iotService) { super(maxFrameLength, delimiter); this.plcService = plcService; + this.iotService = iotService; } @Override @@ -51,7 +54,7 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { log.debug("no data"); return null; } - KescRunnable kescRunnable = new KescRunnable(in,ctx,plcService); + KescRunnable kescRunnable = new KescRunnable(in,ctx,plcService,iotService); threadPoolExecutor.execute(kescRunnable); return null; } @@ -63,11 +66,13 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { private ChannelHandlerContext ctx; private PlcService plcService; + private IotServiceImpl iotService; - public KescRunnable(ByteBuf body,ChannelHandlerContext ctx,PlcService plcService){ + public KescRunnable(ByteBuf body,ChannelHandlerContext ctx,PlcService plcService,IotServiceImpl iotService){ this.in = body; this.ctx = ctx; this.plcService = plcService; + this.iotService = iotService; } @Override @@ -82,8 +87,16 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { in.release(); return ; } + ksecInfo.setHeader("LP"); KsecDataInfo dataInfo = ksecInfo.getData(); - String lotnum = dataInfo.getLotnum(); + String lotnum = null; + if (dataInfo != null){ + + lotnum = dataInfo.getLotnum(); + }else { + log.error("dataInfo is null{}",body); + return; + } PlcCmdInfo plcCmdInfo = null; String srmNumber = null; String cmdName = null; @@ -104,46 +117,49 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { srmNumber = dataInfo.getSRMNumber(); cmdName = dataInfo.getCmdName(); } + //数据上传 + plcService.setPlcData(ksecInfo, srmNumber); if (Cmd.A.name().equals(ksecInfo.getType())) { //心跳 log.debug("receieve heart "); } else if (Cmd.B.name().equals(ksecInfo.getType())) { + IotServiceImpl.set(srmNumber,"communicationData",ksecInfo); //任务 if (Cmd.B1.name().equals(cmdName)) { + IotServiceImpl.set(srmNumber,"warehouseRunStatus",1); //昆船盘点模式下也会发B1 ,但是不会发送B2 //这里判断下,是否存在盘点批次号 若存在,既是盘点的B1,无需处理;若不存在lotnum,则是随行的B1 if(StringUtils.isEmpty(dataInfo.getLotnum())){ //任务开始 旋转到原点位 plcService.gyrateCamera(plcCmdInfo,Cmd.C5.name()); plcService.orderStart(plcCmdInfo); - }else { - log.info("check move"); - } - } else if (Cmd.B2.name().equals(cmdName)) { - //B2 C4 一起发的,需要停止等B2 - - //这里判断是不是双伸 - if(plcCmdInfo.getSeparation2() == 2){ - //深测货架延迟 - try { - Thread.sleep(plcService.getConfigProperties().getCameraConfig().getB2OutDelayTime()); - } catch (InterruptedException e) { - e.printStackTrace(); - } + //没有B2了,收到B1后一分钟后自动执行B2的停止逻辑 + //线程中引用的局部变量需为final + final PlcCmdInfo finalPlcCmdInfo = plcCmdInfo; + final String finalSrmNumber = srmNumber; + threadPoolExecutor.execute(() -> { + try { + //延迟一分钟 + Thread.sleep(60 * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + Thread.currentThread().interrupt(); + } + //赋值cmdName为B2 + ksecInfo.getData().setCmdName(Cmd.B2.name()); + plcService.gyrateCamera(finalPlcCmdInfo,Cmd.C5.name()); + plcService.orderStop(finalPlcCmdInfo); + + IotServiceImpl.set(finalSrmNumber,"warehouseRunStatus",3); + }); }else { - //浅侧延迟 - try { - Thread.sleep(plcService.getConfigProperties().getCameraConfig().getB2DelayTime()); - } catch (InterruptedException e) { - e.printStackTrace(); - } + log.info("check move"); } - plcService.gyrateCamera(plcCmdInfo,Cmd.C5.name()); - plcService.orderStop(plcCmdInfo); } } else if (Cmd.C.name().equals(ksecInfo.getType())) { + IotServiceImpl.set(srmNumber,"communicationData",ksecInfo); //动作 String code = dataInfo.getCmdName(); @@ -182,7 +198,9 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { // log.info("other D code :{}",code); // } } else if (Cmd.E.name().equals(ksecInfo.getType())) { + IotServiceImpl.set(srmNumber,"communicationData",ksecInfo); + IotServiceImpl.set(srmNumber,"warehouseRunStatus",2); //盘点 //转球机到盘点位 然后拍照 @@ -219,9 +237,18 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { log.error("sleep error",e); } ctx.channel().writeAndFlush(ksecInfo); + + plcService.setPlcData(ksecInfo, srmNumber); log.info("盘点结束:"+ksecInfo.getData().toString()); + + IotServiceImpl.set(srmNumber,"warehouseRunStatus",3); + + IotServiceImpl.set(srmNumber,"communicationData",ksecInfo); }else if (Cmd.SC.name().equals(ksecInfo.getType())) { + IotServiceImpl.set("zt","warehouseRunStatus",2); + + IotServiceImpl.set("zt","communicationData",ksecInfo); int flag = plcService.checkVision(dataInfo,true); ksecInfo.getData().setCmdName("SC02"); @@ -232,6 +259,9 @@ public class KsecDecoder extends DelimiterBasedFrameDecoder { log.error("sleep error",e); } ctx.channel().writeAndFlush(ksecInfo); + + IotServiceImpl.set("zt","communicationData",ksecInfo); + IotServiceImpl.set("zt","warehouseRunStatus",3); } //找到该货位的最后一张照片与现在的照片比照 //plcService.recordStock(plcCmdInfo, dataInfo.getCode(), 0, 0); diff --git a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecNettyClient.java b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecNettyClient.java index 5ca6eb3..cf5aed7 100644 --- a/web/src/main/java/com/zhehekeji/web/service/ksec/KsecNettyClient.java +++ b/web/src/main/java/com/zhehekeji/web/service/ksec/KsecNettyClient.java @@ -3,6 +3,7 @@ package com.zhehekeji.web.service.ksec; import com.zhehekeji.common.util.FileUtil; import com.zhehekeji.web.config.ConfigProperties; import com.zhehekeji.web.service.PlcService; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; @@ -25,6 +26,9 @@ public class KsecNettyClient { @Resource private ConfigProperties configProperties; + @Resource + private IotServiceImpl iotService; + /** * 重连最大次数 */ @@ -54,7 +58,7 @@ public class KsecNettyClient { c.group(group); c.channel(NioSocketChannel.class); KsecInfo heart = KsecInfo.heart(); - c.handler(new KescFilter(heart, plcService, this)); + c.handler(new KescFilter(heart, plcService, this,iotService)); client = c; } diff --git a/web/src/main/java/com/zhehekeji/web/service/sick/CognexSocket.java b/web/src/main/java/com/zhehekeji/web/service/sick/CognexSocket.java index 14f2ee2..02de062 100644 --- a/web/src/main/java/com/zhehekeji/web/service/sick/CognexSocket.java +++ b/web/src/main/java/com/zhehekeji/web/service/sick/CognexSocket.java @@ -1,6 +1,7 @@ package com.zhehekeji.web.service.sick; import com.zhehekeji.web.entity.ReadOCR; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,11 +16,8 @@ public class CognexSocket { private static final Logger tcpLogger = LoggerFactory.getLogger("sick"); - public static void main(String[] args) { - ReadOCR readOCR = readOCR("127.0.0.1", 2001); - System.out.println(readOCR); - } - public static ReadOCR readOCR(String ip, int port){ + + public static ReadOCR readOCR(String ip, int port,String key,String cmd ){ ReadOCR readOCR = new ReadOCR(); Socket socket = new Socket(); String code = "NOREAD"; @@ -45,10 +43,12 @@ public class CognexSocket { }else { readOCR.setStatus(1); } + IotServiceImpl.set(cmd,key,1); } catch (IOException e) { tcpLogger.error("sick time out,ip:{},info:{}",ip,e); log.error("sick time out,ip:{},info:{}",ip,e); readOCR.setStatus(0); + IotServiceImpl.set(cmd,key,2); }finally { if(os != null){ try { diff --git a/web/src/main/java/com/zhehekeji/web/service/sick/SickSocket.java b/web/src/main/java/com/zhehekeji/web/service/sick/SickSocket.java index 464e220..73e449b 100644 --- a/web/src/main/java/com/zhehekeji/web/service/sick/SickSocket.java +++ b/web/src/main/java/com/zhehekeji/web/service/sick/SickSocket.java @@ -1,6 +1,7 @@ package com.zhehekeji.web.service.sick; import com.zhehekeji.web.entity.ReadOCR; +import com.zhehekeji.web.service.iotService.IotServiceImpl; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,7 +20,7 @@ public class SickSocket { private static final Logger tcpLogger = LoggerFactory.getLogger("sick"); - public static ReadOCR readOCR(String ip, int port){ + public static ReadOCR readOCR(String ip, int port, String key,String cmd ){ ReadOCR readOCR = new ReadOCR(); Socket socket = new Socket(); String code = "NoRead"; @@ -45,10 +46,13 @@ public class SickSocket { }else { readOCR.setStatus(1); } + IotServiceImpl.set(cmd,key,1); } catch (Exception e) { tcpLogger.error("sick time out,ip:{},info:{}",ip,e); log.error("sick time out,ip:{},info:{}",ip,e); readOCR.setStatus(0); + + IotServiceImpl.set(cmd,key,2); }finally { if(os != null){ try { diff --git a/web/src/main/resources/application-prod.yml b/web/src/main/resources/application-prod.yml index bf48e37..08ea37d 100644 --- a/web/src/main/resources/application-prod.yml +++ b/web/src/main/resources/application-prod.yml @@ -130,4 +130,9 @@ template: code: "a1123" # 光源串口 -comConfig: "COM2" \ No newline at end of file +comConfig: "COM2" +siteInventoryIp: "127.0.0.1" +# +#comTofConfig: +# - "COM1" +# - "COM2" \ No newline at end of file diff --git a/web/src/main/resources/logback-spring.xml b/web/src/main/resources/logback-spring.xml index ba1ca23..96f8a57 100644 --- a/web/src/main/resources/logback-spring.xml +++ b/web/src/main/resources/logback-spring.xml @@ -125,6 +125,25 @@ + + + ${LOG_HOME}/${logName}-iot.log + + ${LOG_HOME}/${logName}-iot-%d{yyyy-MM-dd}.%i.log + 30 + + 10MB + + + + %d %p (%file:%line\)- %m%n + UTF-8 + + + INFO + + + @@ -135,6 +154,11 @@ + + + + + diff --git a/说明 b/说明 new file mode 100644 index 0000000..bb2c6b5 --- /dev/null +++ b/说明 @@ -0,0 +1,10 @@ +顺序 +1.先从default.txt中获取默认值 +2.每5s根据network拿数据更新网络值 +"192.168.1.2"=002:warehouseNetworkStatus +前面是ip,后面是default.txt的对应 + + +站台 +1.zt作为站台default.txt的key,只有zt!network也是只有zt! +2.定时给主服务器发送