diff --git a/modules/common/target/common-1.0.0.jar b/modules/common/target/common-1.0.0.jar index fa6a975..6636e1c 100644 Binary files a/modules/common/target/common-1.0.0.jar and b/modules/common/target/common-1.0.0.jar differ diff --git a/modules/common/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/modules/common/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst index 9260f65..ea0e383 100644 --- a/modules/common/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +++ b/modules/common/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -1,13 +1,13 @@ -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\util\PathUtil.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\util\Tools.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\util\ValidatorUtil.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\util\SpringContextUtil.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\util\QrUtil.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\constant\CommonConstant.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\util\HttpUtil.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\properities\Md5Properity.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\properities\RedisProperity.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\CommonConfigure.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\properities\Properity.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\util\MD5Util.java -D:\git\hzleaper\lia-monitor-backend\modules\common\src\main\java\com\zhehekeji\common\util\FileUtil.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\util\MD5Util.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\util\ValidatorUtil.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\util\Tools.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\properities\RedisProperity.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\CommonConfigure.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\util\PathUtil.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\util\SpringContextUtil.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\util\FileUtil.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\util\HttpUtil.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\properities\Md5Properity.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\properities\Properity.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\constant\CommonConstant.java +D:\git\duoji_old\modules\common\src\main\java\com\zhehekeji\common\util\QrUtil.java diff --git a/modules/filter/target/filter-1.0.0.jar b/modules/filter/target/filter-1.0.0.jar index dda8a56..34cf155 100644 Binary files a/modules/filter/target/filter-1.0.0.jar and b/modules/filter/target/filter-1.0.0.jar differ diff --git a/modules/filter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/modules/filter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst index 6ce6d56..800bac0 100644 --- a/modules/filter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +++ b/modules/filter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -1,7 +1,7 @@ -D:\git\hzleaper\lia-monitor-backend\modules\filter\src\main\java\com\zhehekeji\filter\pojo\CurrentUser.java -D:\git\hzleaper\lia-monitor-backend\modules\filter\src\main\java\com\zhehekeji\filter\util\JwtUtil.java -D:\git\hzleaper\lia-monitor-backend\modules\filter\src\main\java\com\zhehekeji\filter\pojo\SessionHandler.java -D:\git\hzleaper\lia-monitor-backend\modules\filter\src\main\java\com\zhehekeji\filter\FilterConstance.java -D:\git\hzleaper\lia-monitor-backend\modules\filter\src\main\java\com\zhehekeji\filter\util\CurrentUserUtil.java -D:\git\hzleaper\lia-monitor-backend\modules\filter\src\main\java\com\zhehekeji\filter\pojo\UserType.java -D:\git\hzleaper\lia-monitor-backend\modules\filter\src\main\java\com\zhehekeji\filter\aspect\SessionAspect.java +D:\git\duoji_old\modules\filter\src\main\java\com\zhehekeji\filter\pojo\SessionHandler.java +D:\git\duoji_old\modules\filter\src\main\java\com\zhehekeji\filter\util\CurrentUserUtil.java +D:\git\duoji_old\modules\filter\src\main\java\com\zhehekeji\filter\FilterConstance.java +D:\git\duoji_old\modules\filter\src\main\java\com\zhehekeji\filter\pojo\CurrentUser.java +D:\git\duoji_old\modules\filter\src\main\java\com\zhehekeji\filter\pojo\UserType.java +D:\git\duoji_old\modules\filter\src\main\java\com\zhehekeji\filter\util\JwtUtil.java +D:\git\duoji_old\modules\filter\src\main\java\com\zhehekeji\filter\aspect\SessionAspect.java diff --git a/s7DB.txt b/s7DB.txt new file mode 100644 index 0000000..e4290de --- /dev/null +++ b/s7DB.txt @@ -0,0 +1,38 @@ +#C1推烟录像触发任务号,C2底部拍照触发任务号(同时停止录像),C3顶部拍照触发任务号。并在完成后通过out的写入指定数据块,在视觉判断没有问题后,通过ET(顶部拍照报错)和ED(底部拍照报错) +#其中,C1、C2、C3是int类型,ET、ED是布尔类型,C1直接是赋值初始位置,ED底部默认.0,ET顶部默认.1 +#格式是{货架号}-{触发任务}[-输出]:{初始值} +001-C1:0 +001-C2:4 +001-C3:8 +001-C1-out:48 +001-C2-out:52 +001-C3-out:56 +001-ET-out:60 +001-ED-out:60 + +002-C1:12 +002-C2:16 +002-C3:20 +002-C1-out:62 +002-C2-out:66 +002-C3-out:70 +002-ET-out:74 +002-ED-out:74 + +003-C1:24 +003-C2:28 +003-C3:32 +003-C1-out:76 +003-C2-out:80 +003-C3-out:84 +003-ET-out:88 +003-ED-out:88 + +004-C1:36 +004-C2:40 +004-C3:44 +004-C1-out:90 +004-C2-out:94 +004-C3-out:98 +004-ET-out:102 +004-ED-out:102 \ No newline at end of file diff --git a/web/pom.xml b/web/pom.xml index 90169b6..028b2e2 100644 --- a/web/pom.xml +++ b/web/pom.xml @@ -18,6 +18,33 @@ + + si.trina + moka7-live + 0.0.13 + + + + cn.hutool + hutool-all + 5.8.25 + + + + com.alibaba + fastjson + 1.2.47 + + + org.apache.plc4x + plc4j-api + 0.12.0 + + + org.apache.plc4x + plc4j-driver-s7 + 0.12.0 + com.zhehekeji @@ -96,6 +123,14 @@ true + + org.apache.maven.plugins + maven-compiler-plugin + + 9 + 9 + + diff --git a/web/src/main/java/com/zhehekeji/web/config/CacheConfig.java b/web/src/main/java/com/zhehekeji/web/config/CacheConfig.java index 53c130a..01f5f5d 100644 --- a/web/src/main/java/com/zhehekeji/web/config/CacheConfig.java +++ b/web/src/main/java/com/zhehekeji/web/config/CacheConfig.java @@ -11,6 +11,7 @@ import org.springframework.cache.jcache.JCacheCache; import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; import java.util.ArrayList; import java.util.Arrays; @@ -21,6 +22,11 @@ import java.util.concurrent.TimeUnit; @EnableCaching public class CacheConfig { + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + @Bean public CacheManager localCacheManager() { SimpleCacheManager simpleCacheManager = new SimpleCacheManager(); 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 c21731a..0e31d47 100644 --- a/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java +++ b/web/src/main/java/com/zhehekeji/web/config/ConfigProperties.java @@ -42,8 +42,16 @@ public class ConfigProperties { * TCP服务端端口 */ private Integer serverPort; + private Zlm zlm = new Zlm(); + @Data + public static class Zlm { + private String ip="127.0.0.1"; + private Integer apiPort=8096; + private String secret= "w3qQt6NyUzSZ1STH9riCVhLbdIosuwf1"; + } + @Data public static class CameraConfig{ diff --git a/web/src/main/java/com/zhehekeji/web/config/JsonUtils.java b/web/src/main/java/com/zhehekeji/web/config/JsonUtils.java new file mode 100644 index 0000000..3312d02 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/config/JsonUtils.java @@ -0,0 +1,202 @@ +package com.zhehekeji.web.config; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +/** + * JSON 工具类 + * + * @author 芋道源码 + */ +@Slf4j +public class JsonUtils { + + private static ObjectMapper objectMapper = new ObjectMapper(); + + static { + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null 值 + objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化 + } + + /** + * 初始化 objectMapper 属性 + *

+ * 通过这样的方式,使用 Spring 创建的 ObjectMapper Bean + * + * @param objectMapper ObjectMapper 对象 + */ + public static void init(ObjectMapper objectMapper) { + JsonUtils.objectMapper = objectMapper; + } + + @SneakyThrows + public static String toJsonString(Object object) { + return objectMapper.writeValueAsString(object); + } + + @SneakyThrows + public static byte[] toJsonByte(Object object) { + return objectMapper.writeValueAsBytes(object); + } + + @SneakyThrows + public static String toJsonPrettyString(Object object) { + return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object); + } + + public static T parseObject(String text, Class clazz) { + if (StrUtil.isEmpty(text)) { + return null; + } + try { + return objectMapper.readValue(text, clazz); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, String path, Class clazz) { + if (StrUtil.isEmpty(text)) { + return null; + } + try { + JsonNode treeNode = objectMapper.readTree(text); + JsonNode pathNode = treeNode.path(path); + return objectMapper.readValue(pathNode.toString(), clazz); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, Type type) { + if (StrUtil.isEmpty(text)) { + return null; + } + try { + return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type)); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + /** + * 将字符串解析成指定类型的对象 + * 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下, + * 如果 text 没有 class 属性,则会报错。此时,使用这个方法,可以解决。 + * + * @param text 字符串 + * @param clazz 类型 + * @return 对象 + */ + public static T parseObject2(String text, Class clazz) { + if (StrUtil.isEmpty(text)) { + return null; + } + return JSONUtil.toBean(text, clazz); + } + + public static T parseObject(byte[] bytes, Class clazz) { + if (ArrayUtil.isEmpty(bytes)) { + return null; + } + try { + return objectMapper.readValue(bytes, clazz); + } catch (IOException e) { + log.error("json parse err,json:{}", bytes, e); + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, TypeReference typeReference) { + try { + return objectMapper.readValue(text, typeReference); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + /** + * 解析 JSON 字符串成指定类型的对象,如果解析失败,则返回 null + * + * @param text 字符串 + * @param typeReference 类型引用 + * @return 指定类型的对象 + */ + public static T parseObjectQuietly(String text, TypeReference typeReference) { + try { + return objectMapper.readValue(text, typeReference); + } catch (IOException e) { + return null; + } + } + + public static List parseArray(String text, Class clazz) { + if (StrUtil.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static List parseArray(String text, String path, Class clazz) { + if (StrUtil.isEmpty(text)) { + return null; + } + try { + JsonNode treeNode = objectMapper.readTree(text); + JsonNode pathNode = treeNode.path(path); + return objectMapper.readValue(pathNode.toString(), objectMapper.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static JsonNode parseTree(String text) { + try { + return objectMapper.readTree(text); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static JsonNode parseTree(byte[] text) { + try { + return objectMapper.readTree(text); + } catch (IOException e) { + log.error("json parse err,json:{}", text, e); + throw new RuntimeException(e); + } + } + + public static boolean isJson(String text) { + return JSONUtil.isTypeJSON(text); + } + +} diff --git a/web/src/main/java/com/zhehekeji/web/pojo/OrderSearch.java b/web/src/main/java/com/zhehekeji/web/pojo/OrderSearch.java index c70d7e3..41f7dc8 100644 --- a/web/src/main/java/com/zhehekeji/web/pojo/OrderSearch.java +++ b/web/src/main/java/com/zhehekeji/web/pojo/OrderSearch.java @@ -18,6 +18,10 @@ public class OrderSearch { @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") private LocalDateTime endTimestamp; + private Integer status; + + private Integer streetId; + private Integer pageSize; private Integer pageNum; 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 982e811..237f293 100644 --- a/web/src/main/java/com/zhehekeji/web/service/CameraService.java +++ b/web/src/main/java/com/zhehekeji/web/service/CameraService.java @@ -60,6 +60,9 @@ public class CameraService { this.cameraControlModule = cameraControlModule; } + public Camera getById(Integer id){ + return cameraMapper.selectById(id); + } public void setCameraLoginModule(CameraControlLoginModule cameraControlLoginModule){ this.cameraControlLoginModule = cameraControlLoginModule; } diff --git a/web/src/main/java/com/zhehekeji/web/service/CronTab.java b/web/src/main/java/com/zhehekeji/web/service/CronTab.java index fefad30..ca91012 100644 --- a/web/src/main/java/com/zhehekeji/web/service/CronTab.java +++ b/web/src/main/java/com/zhehekeji/web/service/CronTab.java @@ -3,10 +3,12 @@ package com.zhehekeji.web.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.zhehekeji.web.config.ConfigProperties; +import com.zhehekeji.web.entity.Camera; import com.zhehekeji.web.entity.LightSource; import com.zhehekeji.web.mapper.CheckLogMapper; import com.zhehekeji.web.mapper.LightSourceMapper; import com.zhehekeji.web.mapper.StockLogMapper; +import com.zhehekeji.web.service.cron.ZlmService; import com.zhehekeji.web.service.damLightSource.JYDAMEquip; import com.zhehekeji.web.service.damLightSource.JYDamHelper; import com.zhehekeji.web.service.hikLightSource.HikControlSocket; @@ -30,6 +32,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -54,8 +57,23 @@ public class CronTab { @Resource private StockLogMapper stockLogMapper; + @Resource + ZlmService zlmService; + @Resource + CameraService cameraService; + + private static int gByte = 1024* 1024 * 1024; + @Scheduled(fixedDelay = 5*60*1000) + public void zlm() { + try { + List cameras = cameraService.allCameras(); + zlmService.zlmConf(cameras); + }catch (Exception e){ + log.error("zlm conf error",e); + } + } @Scheduled(cron = "0 0 0 * * ?") public void file() { diff --git a/web/src/main/java/com/zhehekeji/web/service/EmptyCheckService.java b/web/src/main/java/com/zhehekeji/web/service/EmptyCheckService.java index 2e70ea3..c536920 100644 --- a/web/src/main/java/com/zhehekeji/web/service/EmptyCheckService.java +++ b/web/src/main/java/com/zhehekeji/web/service/EmptyCheckService.java @@ -13,6 +13,7 @@ import com.zhehekeji.web.mapper.StockMapper; import com.zhehekeji.web.pojo.stock.CheckStatus; import com.zhehekeji.web.pojo.stock.RowColumnStatus; import com.zhehekeji.web.service.client.Transmission; +import com.zhehekeji.web.service.cron.PLCConnectionExample; import com.zhehekeji.web.service.ksec.KsecDataInfo; import com.zhehekeji.web.service.ksec.KsecInfo; import lombok.extern.slf4j.Slf4j; @@ -25,6 +26,7 @@ import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; + @Service @Slf4j public class EmptyCheckService { @@ -40,31 +42,49 @@ public class EmptyCheckService { @Resource private ConfigProperties configProperties; + @Resource + PLCConnectionExample plcConnectionExample; /** * * @param transmission * @return */ - public Order visualJudgment(Transmission transmission,String code,Street street){ - ConcurrentHashMap synchronizedMap = new ConcurrentHashMap(); + public Order visualJudgment(Transmission transmission,String code){ + String key = transmission.getSRMNumber() + "-"; + if("TP".equals(code)){ + key+="C3"; + }else if("BP".equals(code)){ + key+="C2"; + } + Street street = getStreet(transmission); + plcConnectionExample.writePlcDataTaskId(key + "-out", PLCConnectionExample.taskMap.get(key)); if(street!= null){ Order order = orderMapper.getOneByStreetId(street.getId()); transmission.setUrl(transmission.getUrl().replace("E:","").replace("D:","")); - order.setStatus(transmission.getSuccess()? 1 : 0); + transmission.setUrl("http://"+street.getPlcIp()+":9007/api/pic"+transmission.getUrl()); order.setPicPaths(order.getPicPaths()!=null ? order.getPicPaths() + "," +transmission.getUrl(): transmission.getUrl()); if(transmission.getNumber() != null ){ order.setNumber(transmission.getNumber()); } orderMapper.updateById(order); - if("TP".equals(code)){ - - } return order; } return null; } + @Resource + PLCConnectionExample plcConnectionService; + public Order visualJudgmentStatus(Transmission transmission,int i){ + Street street = streetService.getStreetByPlcId(transmission.getSRMNumber()); + if(street!= null){ + Order order = orderMapper.getOneByStreetId(street.getId()); + order.setStatus(1); + orderMapper.updateById(order); + plcConnectionService.writePlcDataStatusErr(street.getPlcId(),i); + } + return null; + } public KsecInfo getKSECWriteByOrder(Order order,Street street){ KsecDataInfo ksecDataInfo = new KsecDataInfo(); 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 9d18e50..32979ea 100644 --- a/web/src/main/java/com/zhehekeji/web/service/InitService.java +++ b/web/src/main/java/com/zhehekeji/web/service/InitService.java @@ -13,6 +13,7 @@ import com.zhehekeji.web.mapper.CameraMapper; import com.zhehekeji.web.mapper.SensorGunMapper; import com.zhehekeji.web.mapper.StreetMapper; import com.zhehekeji.web.service.client.NettyServer; +import com.zhehekeji.web.service.cron.ZlmService; import com.zhehekeji.web.service.ksec.KsecNettyClient; import com.zhehekeji.web.service.robotic.NettyClient; import com.zhehekeji.web.service.sick.SickNettyClient; @@ -21,6 +22,7 @@ import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; +import org.springframework.web.client.ResourceAccessException; import javax.annotation.Resource; import java.util.HashMap; @@ -79,47 +81,47 @@ public class InitService implements ApplicationRunner { cameraService.setCameraControlModule(cameraControlModule); return cameraControlModule; } - @Override public void run(ApplicationArguments args) throws Exception { nettyServer.CreateNettyServer(configProperties.getServerPort()); //球机登录 - List cameras = cameraMapper.selectByMap(new HashMap<>(0)); - cameras.forEach(camera -> { - LoginThread loginThread = new LoginThread(camera); - loginThread.start(); - }); +// List cameras = cameraMapper.selectByMap(new HashMap<>(0)); +// cameras.forEach(camera -> { +// LoginThread loginThread = new LoginThread(camera); +// loginThread.start(); +// }); + //plc连接 - if(configProperties.getServerMode() == 0){ - log.info("PLC TCP MODE"); - //plc 连接状态初始化 - List streets = streetMapper.selectByMap(new HashMap<>(0)); - - streets.forEach(street -> { - StreetConn.init(street.getId(),street.getPlcId()); - try { - nettyClient.createClient(street); - }catch (Exception e){ - log.error("streetId:{}:初始plc连接失败,url:{},port:{}",street.getId(),street.getPlcIp(),street.getPlcPort()); - } - }); - }else if(configProperties.getServerMode() == 1){ - log.info("KESC JSON MODE"); - // 昆船协议 - ConfigProperties.KSEC ksec = configProperties.getKsec(); - if(ksec != null){ - StreetConn.init(1,"ksec"); - try { - ksecNettyClient.createClient(ksec); - }catch (Exception e){ - ksecNettyClient.reconnect(1); - log.error("kesc connect error,url:{},port:{}",ksec.getIp(),ksec.getPort()); - } - }else { - log.error("ksec no config"); - } - } +// if(configProperties.getServerMode() == 0){ +// log.info("PLC TCP MODE"); +// //plc 连接状态初始化 +// List streets = streetMapper.selectByMap(new HashMap<>(0)); +// +// streets.forEach(street -> { +// StreetConn.init(street.getId(),street.getPlcId()); +// try { +// nettyClient.createClient(street); +// }catch (Exception e){ +// log.error("streetId:{}:初始plc连接失败,url:{},port:{}",street.getId(),street.getPlcIp(),street.getPlcPort()); +// } +// }); +// }else if(configProperties.getServerMode() == 1){ +// log.info("KESC JSON MODE"); +// // 昆船协议 +// ConfigProperties.KSEC ksec = configProperties.getKsec(); +// if(ksec != null){ +// StreetConn.init(1,"ksec"); +// try { +// ksecNettyClient.createClient(ksec); +// }catch (Exception e){ +// ksecNettyClient.reconnect(1); +// log.error("kesc connect error,url:{},port:{}",ksec.getIp(),ksec.getPort()); +// } +// }else { +// log.error("ksec no config"); +// } +// } TaskDelayExecutor.runMp4DownloadExecutor(); } 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 493872f..2330392 100644 --- a/web/src/main/java/com/zhehekeji/web/service/PlcService.java +++ b/web/src/main/java/com/zhehekeji/web/service/PlcService.java @@ -10,10 +10,12 @@ import com.zhehekeji.web.mapper.*; import com.zhehekeji.web.pojo.OrderVO; import com.zhehekeji.web.service.RFID.RFIDSocket; import com.zhehekeji.web.service.client.ClientChanel; +import com.zhehekeji.web.service.cron.ZlmService; import com.zhehekeji.web.service.hikLightSource.HikControlSocket; import com.zhehekeji.web.service.ksec.KsecDataInfo; import com.zhehekeji.web.service.ksec.KsecNettyClient; import com.zhehekeji.web.service.sick.SickSocket; +import io.swagger.models.auth.In; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; @@ -28,6 +30,7 @@ import java.util.concurrent.BlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; + /** * @Description plc信号指令处理类 * 对plcId做同步处理,防止内存中保存的正在运行的订单信息错乱 @@ -148,6 +151,46 @@ public class PlcService { } } + public void orderStart(String taskId,String streetPlcId,String code) { + Street street = streetService.getStreetByPlcId(streetPlcId); + + if (street != null) { + + Order order = new Order(); + order.setOrderNum(streetPlcId+"_"+taskId); + order.setStatus(0); + order.setCode(code); + order.setStartTime(LocalDateTime.now()); + order.setStreetId(street.getId()); + //todo 昆船的项目 ,取货 放货是独立的 + //取货是是不知道放货的位置的,所以订单开始的时候只写1位置 + //订单结束写2位置 + orderMapper.insert(order); + OrderRealtime.startOrder(street.getId(), order.getOrderNum()); + } + } + @Resource + ZlmService zlmService; + public void orderStart(Integer taskId, String streetPlcId) { + Street street = streetService.getStreetByPlcId(streetPlcId); + + if (street != null) { + + Order order = new Order(); + order.setOrderNum(streetPlcId+"_"+taskId); + order.setStatus(0); + order.setStartTime(LocalDateTime.now()); + order.setStreetId(street.getId()); + //todo 昆船的项目 ,取货 放货是独立的 + //取货是是不知道放货的位置的,所以订单开始的时候只写1位置 + //订单结束写2位置 + orderMapper.insert(order); + OrderRealtime.startOrder(street.getId(), order.getOrderNum()); + + zlmService.startRecord(cameraService.getById(street.getCamera1Id())); + } + } + /** * 工单结束信息 * 判断有没有告警,有告警的不做处理 @@ -192,6 +235,36 @@ public class PlcService { } + public void orderStop(String plcId,Integer taskId) { + LocalDateTime endTime = LocalDateTime.now(); + Street street = streetMapper.getStreetByPlcId(plcId); + if (street == null) { + return; + } + Order order = orderMapper.getOneByOrderNum(plcId+"_"+taskId); + if (order == null) { + log.error("订单结束信号,订单不存在,orderNum:{}", plcId); + return; + } + OrderRealtime.stopOrder(street.getId()); + Order update = new Order(); + update.setId(order.getId()); + update.setEndTime(endTime); + LocalDateTime endDownLoadTime = endTime.plusSeconds(5); + Duration duration = Duration.between(order.getStartTime(),endDownLoadTime); + + if (street.getCamera1Id() != null) { + String path = cameraVideo(street.getCamera1Id(),order.getStartTime(),endDownLoadTime); + update.setVideoPath1(path); + } + if (street.getCamera2Id() != null) { + String path = cameraVideo(street.getCamera2Id(),order.getStartTime(),endDownLoadTime); + update.setVideoPath2(path); + } + orderMapper.updateById(update); + + } + public void orderStop(KsecDataInfo plcCmdInfo) { LocalDateTime endTime = LocalDateTime.now(); Street street = streetMapper.getStreetByPlcId(plcCmdInfo.getSRMNumber()); @@ -824,6 +897,41 @@ public class PlcService { } } + + public void action(String plcId, Integer times,int taskId) { + LocalDateTime endTime = LocalDateTime.now(); + + + try { + //执行动作 +// if(times==1) { +// Thread.sleep(configProperties.getCameraConfig().getC1DelayCaptureTime()); +// +// ClientChanel.sendMessage(plcId, "C1:1"); +// } else + if (times==2) { + Thread.sleep(configProperties.getCameraConfig().getC2DelayCaptureTime()); +//C1底部拍照 + ClientChanel.sendMessage(plcId, "C1:1"); + + Thread.sleep(configProperties.getCameraConfig().getC3DelayCaptureTime()); + + Order order = orderMapper.getOneByOrderNum(plcId+"_"+taskId); + ClientChanel.sendMessage(plcId, "C3:1"); + Street street = streetService.getStreetByPlcId(plcId); + String path = zlmService.stopRecord(cameraService.getById(street.getCamera1Id())); + order.setVideoPath1(path); + + orderMapper.updateById(order); + }else if(times == 4){ + Thread.sleep(configProperties.getCameraConfig().getC4DelayCaptureTime()); + + ClientChanel.sendMessage(plcId, "C4:1"); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } public void upStreet(KsecDataInfo dataInfo) { Street street = streetMapper.list().get(0); dataInfo.setSRMNumber(street.getPlcId()); diff --git a/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java index 4c4566e..dd9e15c 100644 --- a/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java +++ b/web/src/main/java/com/zhehekeji/web/service/client/Decoder.java @@ -84,8 +84,8 @@ public class Decoder extends DelimiterBasedFrameDecoder { Transmission transmission = new Transmission(body); if("BP".equals(transmission.getHeader())){ //底部拍照 - Street street = emptyCheckService.getStreet(transmission); - Order order = emptyCheckService.visualJudgment(transmission,"BP",street); + Order order = emptyCheckService.visualJudgment(transmission,"BP"); + //KsecInfo ksecInfo = emptyCheckService.getKSECWriteByOrder(order,street); //KsecNettyClient.write(ksecInfo); @@ -94,11 +94,10 @@ public class Decoder extends DelimiterBasedFrameDecoder { ClientChanel.connect(transmission.getSRMNumber(),ctx.channel()); }else if("TP".equals(transmission.getHeader())){ - //底部拍照 - Street street = emptyCheckService.getStreet(transmission); - Order order = emptyCheckService.visualJudgment(transmission,"TP",street); - KsecInfo ksecInfo = emptyCheckService.getKSECWriteByOrder(order,street); - KsecNettyClient.write(ksecInfo); + //顶部拍照 + Order order = emptyCheckService.visualJudgment(transmission,"TP"); +// KsecInfo ksecInfo = emptyCheckService.getKSECWriteByOrder(order,street); +// KsecNettyClient.write(ksecInfo); }else if("LC".equals(transmission.getHeader())){ //光源控制 @@ -108,6 +107,16 @@ public class Decoder extends DelimiterBasedFrameDecoder { //断连 ClientChanel.disConnect(transmission.getSRMNumber()); //ClientChanel.sendMessage(transmission.getSRMNumber(),transmission.getBody()); + }else if("ED".equals(transmission.getHeader())){ + //底部报警 + + emptyCheckService.visualJudgmentStatus(transmission,0); + //ClientChanel.sendMessage(transmission.getSRMNumber(),transmission.getBody()); + }else if("ET".equals(transmission.getHeader())){ + //顶部报警 + + emptyCheckService.visualJudgmentStatus(transmission,1); + //ClientChanel.sendMessage(transmission.getSRMNumber(),transmission.getBody()); } } } diff --git a/web/src/main/java/com/zhehekeji/web/service/cron/PLCConnectionExample.java b/web/src/main/java/com/zhehekeji/web/service/cron/PLCConnectionExample.java new file mode 100644 index 0000000..b73a241 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/cron/PLCConnectionExample.java @@ -0,0 +1,375 @@ +package com.zhehekeji.web.service.cron; + +import com.sourceforge.snap7.moka7.S7; +import com.sourceforge.snap7.moka7.S7Client; +import com.zhehekeji.web.service.PlcService; +import io.swagger.models.auth.In; +import lombok.extern.slf4j.Slf4j; +import org.apache.plc4x.java.api.PlcConnection; +import org.apache.plc4x.java.api.PlcDriverManager; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcReadResponse; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.*; + +@Configuration +@Component +@EnableScheduling +@Slf4j +public class PLCConnectionExample { + + // 定义数据块和偏移量 + int dbNumber = 121; // DB121 + String plcIp = "10.69.105.122"; + int plcRack = 0; + int plcSlot = 1; + int sizeToRead = 4; // 读取4个字节 + //s7地址,在spring 开始的时候赋值 + public static final Map addressMap = new ConcurrentHashMap<>(); + // 当前命令的上一个任务号 + public static final Map taskMap = new ConcurrentHashMap<>(); +// @Resource +// S7Client s7Client; + +// 采用池化 + + private final int POOL_SIZE = 5; // 池大小 + private BlockingQueue connectionPool; + + @PostConstruct + public void PlcConnectionPool() { + // 初始化连接池 + connectionPool = new ArrayBlockingQueue<>(POOL_SIZE); + log.info("建立通信池"); + + readDbConf(); + // 创建连接池中的连接 + for (int i = 0; i < POOL_SIZE; i++) { + S7Client client = new S7Client(); + client.ConnectTo(plcIp,plcRack,plcSlot); // IP, Rack, Slot + connectionPool.offer(client); + } + } + + /** + * 获取一个连接 + */ + public S7Client getConnection() { + try { + return connectionPool.take(); // 阻塞直到获取到一个连接 + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("获取 PLC 连接失败", e); + } + } + + /** + * 替换连接到池中 + */ + public void updateConnection(S7Client client) { + try { + // 如果连接不可用,则重新创建 + connectionPool.remove(client); + S7Client newClient = new S7Client(); + newClient.ConnectTo(plcIp, plcRack, plcSlot); + connectionPool.offer(newClient); + } catch (Exception e) { + throw new RuntimeException("归还 PLC 连接失败", e); + } + } + /** + * 归还连接到池中 + */ + public void returnConnection(S7Client client) { + try { + connectionPool.offer(client); // 将连接归还到连接池 + } catch (Exception e) { + throw new RuntimeException("归还 PLC 连接失败", e); + } + } + + /** + * 定期清理无效连接 + */ + @Scheduled(fixedRate = 60000) + public void cleanUpConnections() { + for (S7Client client : connectionPool) { + if (!client.Connected) { + // 如果连接不可用,则重新创建 + connectionPool.remove(client); + S7Client newClient = new S7Client(); + newClient.ConnectTo(plcIp, plcRack, plcSlot); + connectionPool.offer(newClient); + } + } + } +// @Bean +// public S7Client s7Client(){ +// // 创建S7Client实例 +// S7Client client = new S7Client(); +// // 连接PLC +// client.ConnectTo("10.69.105.122", 0, 1); // IP, Rack, Slot +// +// if (client.Connected) { +// log.info("创建S7Client实例success"); +// return client; +// }else { +// log.error("创建S7Client实例error"); +// return null; +// } +// } + + /** + * 读取s7配置 + */ + void readDbConf(){ + try (BufferedReader reader = new BufferedReader(new FileReader("./s7DB.txt"))) { + String line; + while ((line = reader.readLine()) != null) { + if(line.startsWith("#")) continue; + String[] parts = line.split(":", 2); + if (parts.length == 2) { + addressMap.put(parts[0].trim(), Integer.valueOf(parts[1].trim())); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Resource + PlcService plcService; + + int corePoolSize = 15; // 标准线程个数 + int maximumPoolSize = 40; // 最大线程个数 + long keepAliveTime = 60; // 空闲线程存活时间 + TimeUnit unit = TimeUnit.SECONDS; // 时间单位 + BlockingQueue workQueue = new LinkedBlockingQueue<>(); // 任务队列 + + ExecutorService executorService = new ThreadPoolExecutor( + corePoolSize, + maximumPoolSize, + keepAliveTime, + unit, + workQueue + ); + + // 将原来的循环体逻辑提取到单独的方法中 + private void processKey(Integer i, String plcId,String key) { + + if (key.contains("C1")) { + // 推烟录像触发任务号 + plcService.orderStart(i, plcId); + } else if (key.contains("C2")) { + // 底部拍照触发任务号(同时停止录像) + plcService.action(plcId, 2, i); + } else if (key.contains("C3")) { + // 顶部拍照触发任务号 + plcService.action(plcId, 4, i); + } + + } + + private static final int POLL_INTERVAL = 300; // 查询间隔,单位:毫秒 + // 读数据 + @Scheduled(fixedDelay = POLL_INTERVAL) + void server(){ + + for (String key : addressMap.keySet()){ + if (key.contains("out") || !key.contains("C")) { + continue; + } + int i = readPlcDataTaskId(addressMap.get(key)); + if (i == 0) continue; + if (taskMap.get(key) == null || taskMap.get(key) != i) { + log.info("任务号变化" + key + ":" + i); + log.info("任务号变化" + key + ":" + i); + taskMap.put(key, i); + String plcId = key.split("-")[0]; + executorService.submit(() -> processKey(i, plcId, key)); + + if(key.contains("C1")){ + + writePlcDataTaskId(key+"-out", i); + + } + } + } + } + + /** + * 根据初始值,拿到任务号 + * @param startOffset + * @return + */ + public int readPlcDataTaskId(int startOffset){ + + S7Client client = getConnection(); + try { + + + byte[] buffer = new byte[sizeToRead]; + + // 读取DB121的数据 + int result = client.ReadArea(S7.S7AreaDB, dbNumber, startOffset, sizeToRead, buffer); + int i = 0; + if (result == 0) { + // 获取指定 bit 的值 +// boolean bitValue = S7.GetBitAt(buffer, 0, 1); +// + i = ((buffer[0] & 0xFF) << 24) | + ((buffer[1] & 0xFF) << 16) | + ((buffer[2] & 0xFF) << 8) | + (buffer[3] & 0xFF); + + } else { + updateConnection(client); + log.info("读取失败,错误码: " + result + " 位置: " + startOffset); + } + return i; + }catch (Exception e){ + log.error("连接池报错",e); + }finally { + returnConnection(client); + } + return 0; + } + + public boolean writePlcDataTaskId(String key,int value){ + + S7Client client = getConnection(); + try { + + byte[] buffer = new byte[sizeToRead]; + + S7.SetDIntAt(buffer,0,value); + + // 写回DB121 + int result = client.WriteArea(S7.S7AreaDB, dbNumber, PLCConnectionExample.addressMap.get(key), sizeToRead, buffer); + if (result == 0) { + log.info("写入成功"+key+":"+value); + return true; + } else { + updateConnection(client); + log.info("写入失败,错误码: " + result); + return false; + } + + }catch (Exception e){ + log.error("连接池报错",e); + }finally { + returnConnection(client); + } + return false; + } + public boolean writePlcDataStatusErr(String plcId,int digit){ + + if (digit==1){ + return writePlcDataStatus(addressMap.get(plcId+"-ET-out:"),digit,false); + }else { + return writePlcDataStatus(addressMap.get(plcId+"-ED-out"),digit,false); + } + + } + + public boolean writePlcDataStatus(int startOffset,int digit,boolean value){ + + S7Client client = getConnection(); + try { + int sizeToRead = 1; // 读取4个字节 + + byte[] buffer = new byte[sizeToRead]; + S7.SetBitAt(buffer, 0, digit, value); + + // 写回DB121 + int result = client.WriteArea(S7.S7AreaDB, dbNumber, startOffset, sizeToRead, buffer); + if (result == 0) { + log.info("写入成功"); + return true; + } else { + updateConnection(client); + log.info("写入失败,错误码: " + result); + return false; + } + + }catch (Exception e){ + log.error("连接池报错",e); + }finally { + returnConnection(client); + } + return false; + } + +// 分拣线PLC型号是西门子1518,机架号0,插槽1,IP是10.69.105.122。 +//交互数据块地址是DB121 +/* +public static void main(String[] args) { + // 创建S7Client实例 + S7Client client = new S7Client(); + + // 连接PLC + client.ConnectTo("10.69.105.122", 0, 1); // IP, Rack, Slot + + if (client.Connected) { + log.info("连接成功"); + + // 定义数据块和偏移量 + int dbNumber = 121; // DB121 + int startOffset = 48; // 起始地址 + int sizeToRead = 4; // 读取4个字节 +// + byte[] buffer = new byte[sizeToRead]; + boolean bitValue = true; +// // 读取DB121的数据 + int result = client.ReadArea(S7.S7AreaDB, dbNumber, startOffset, sizeToRead, buffer); + if (result == 0) { + log.info("读取成功"); + // 获取指定 bit 的值 +// bitValue= S7.GetBitAt(buffer, 0, 1); +// log.info(bitValue); + + int i = ((buffer[0] & 0xFF) << 24) | + ((buffer[1] & 0xFF) << 16) | + ((buffer[2] & 0xFF) << 8) | + (buffer[3] & 0xFF); + log.info(i); + } else { + log.info("读取失败,错误码: " + result); + } + + // 修改第一个字节的第一个位为true(即设置bit 0) +// + + S7.SetDIntAt(buffer,0,3001); + + // 写回DB121 + result = client.WriteArea(S7.S7AreaDB, dbNumber, startOffset, sizeToRead, buffer); + if (result == 0) { + log.info("写入成功"); + } else { + log.info("写入失败,错误码: " + result); + } + + // 断开连接 + client.Disconnect(); + } else { + log.info("连接失败"); + } +} +*/ + + +} diff --git a/web/src/main/java/com/zhehekeji/web/service/cron/RtspSessionResponse.java b/web/src/main/java/com/zhehekeji/web/service/cron/RtspSessionResponse.java new file mode 100644 index 0000000..4301892 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/cron/RtspSessionResponse.java @@ -0,0 +1,77 @@ +package com.zhehekeji.web.service.cron; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class RtspSessionResponse { + + private int code; + private List data; + + @Data + public static class RtspSession { + private int aliveSecond; + private String app; + private Integer loss; // 映射 JSON 中的 "loss" 字段 + private long bytesSpeed; + private long createStamp; + @JsonProperty("isRecordingHLS") + private boolean recordingHLS; + @JsonProperty("isRecordingMP4") + private boolean recordingMP4; + private OriginSock originSock; + private int originType; + private String originTypeStr; + private String originUrl; + private String params; + private int readerCount; + private String schema; + private String stream; + private int totalReaderCount; + private List tracks; + private String vhost; + + @Data + public static class OriginSock { + private String identifier; + @JsonProperty("local_ip") + private String localIp; + @JsonProperty("local_port") + private int localPort; + @JsonProperty("peer_ip") + private String peerIp; + @JsonProperty("peer_port") + private int peerPort; + } + + @Data + public static class Track { + @JsonProperty("codec_id") + private int codecId; + @JsonProperty("codec_id_name") + private String codecIdName; + @JsonProperty("codec_type") + private int codecType; + private long duration; + private int fps; + private int frames; + @JsonProperty("gop_interval_ms") + private int gopIntervalMs; + @JsonProperty("gop_size") + private int gopSize; + private int height; + @JsonProperty("key_frames") + private int keyFrames; + private boolean ready; + private int width; + private int channels; + @JsonProperty("sample_bit") + private int sampleBit; + @JsonProperty("sample_rate") + private int sampleRate; + } + } +} \ No newline at end of file diff --git a/web/src/main/java/com/zhehekeji/web/service/cron/ZlmService.java b/web/src/main/java/com/zhehekeji/web/service/cron/ZlmService.java new file mode 100644 index 0000000..aeb2d04 --- /dev/null +++ b/web/src/main/java/com/zhehekeji/web/service/cron/ZlmService.java @@ -0,0 +1,205 @@ +package com.zhehekeji.web.service.cron; + +import com.zhehekeji.web.config.ConfigProperties; +import com.zhehekeji.web.config.JsonUtils; +import com.zhehekeji.web.entity.Camera; +import com.zhehekeji.web.service.CronTab; +import io.swagger.models.auth.In; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.annotation.Resource; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDate; +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.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Service +@Slf4j +public class ZlmService { + @Resource + ConfigProperties configProperties; + + private String buildUrl(String baseUrl, Map params) { + UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(baseUrl); + + for (Map.Entry entry : params.entrySet()) { + urlBuilder.queryParam(entry.getKey(), entry.getValue().toString()); + } + return urlBuilder.toUriString(); + } + + @Resource + RestTemplate restTemplate; + private String get(String url) { + return restTemplate.getForObject(url, String.class); + } + + private void addRtspProxy(Camera camera, String zlmApiUrl, String zlmApiSecret) throws IOException { + try { + + Map addParams = new HashMap<>(); + addParams.put("secret", zlmApiSecret); + addParams.put("vhost", "__defaultVhost__"); + addParams.put("app", "live"); + addParams.put("stream","camera"+ camera.getId()); + addParams.put("url", camera.getRtsp()); + String addUrl = buildUrl(zlmApiUrl+"addStreamProxy" , addParams); + String response = get(addUrl); + System.out.println("Add RTSP Proxy Response: " + response); + if (response.contains("\"code\":0")) { + zlmStatus.put(camera.getId(),true); + }else zlmStatus.put(camera.getId(),false); + }catch (Exception e){ + log.error("zlm conf error",e); + + zlmStatus.put(camera.getId(),false); + } + } + + public static Map zlmStatus = new ConcurrentHashMap<>(); + + public void zlmConf(List list) { + + String zlmApiUrl = "http://"+configProperties.getZlm().getIp()+":"+configProperties.getZlm().getApiPort()+"/index/api/"; + String zlmApiSecret = configProperties.getZlm().getSecret(); + try { + // 查询当前的RTSP拉流代理 + Map queryParams = new HashMap<>(); + queryParams.put("secret", zlmApiSecret); + String queryUrl = buildUrl(zlmApiUrl +"getMediaList" , queryParams); + String response = get(queryUrl); + RtspSessionResponse rtspSessionResponse = JsonUtils.parseObject(response, RtspSessionResponse.class); + // 检查并添加缺失的RTSP代理 + for (Camera entry : list) { + boolean isRtspProxyExists = false; + if (rtspSessionResponse != null && rtspSessionResponse.getData()!=null && rtspSessionResponse.getData().size()>0) { + for (RtspSessionResponse.RtspSession rtspSession : rtspSessionResponse.getData()){ + if (rtspSession.getApp().equals("live")&&rtspSession.getStream().equals("camera"+entry.getId())){ + isRtspProxyExists = true; + break; + } + } + } + //不存在则重新注入 + if (!isRtspProxyExists){ + try { + + addRtspProxy(entry, zlmApiUrl, zlmApiSecret); + }catch (Exception e){ + e.printStackTrace(); + } + } + + } + } catch (Exception e) { + + e.printStackTrace(); + } + } + + + public String stopRecord(Camera camera) { + + + String path = checkHiddenFilesInDirectory(camera); + String zlmApiUrl = "http://"+configProperties.getZlm().getIp()+":"+configProperties.getZlm().getApiPort()+"/index/api/"; + String zlmApiSecret = configProperties.getZlm().getSecret(); + Map addParams = new HashMap<>(); + addParams.put("secret", zlmApiSecret); + addParams.put("vhost", "__defaultVhost__"); + addParams.put("app", "live"); + addParams.put("type", "1"); + addParams.put("stream","camera"+ camera.getId()); + + String addUrl = buildUrl(zlmApiUrl+"stopRecord", addParams); + String response = get(addUrl); + log.info("stopRecord camera:"+camera.getId()+" response:"+response); + return path; + + } + + public void startRecord(Camera camera){ + + String zlmApiUrl = "http://"+configProperties.getZlm().getIp()+":"+configProperties.getZlm().getApiPort()+"/index/api/"; + String zlmApiSecret = configProperties.getZlm().getSecret(); + Map addParams = new HashMap<>(); + addParams.put("secret", zlmApiSecret); + addParams.put("vhost", "__defaultVhost__"); + addParams.put("app", "live"); + addParams.put("type", "1"); + addParams.put("stream","camera"+ camera.getId()); + + String addUrl = buildUrl(zlmApiUrl+"startRecord", addParams); + String response = get(addUrl); + log.info("startRecord camera:"+camera.getId()+" response:"+response); + ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + Runnable task = () -> { + stopRecord(camera); + + }; + + // 延迟5分钟后执行停止任务,不会将录像文件录5分钟 + long delay =100; + scheduler.schedule(task, delay, TimeUnit.SECONDS); + return; + } + // 新增方法:检查指定文件夹下是否有以.为开头的文件 + public String checkHiddenFilesInDirectory(Camera camera) { + + // 获取当前日期 + LocalDate currentDate = LocalDate.now(); + + // 定义日期格式 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + // 格式化日期 + String formattedDate = currentDate.format(formatter); + + String directoryPath = configProperties.getSavePath().getMp4Path()+"record/live/camera"+camera.getId()+"/"+formattedDate; + + + Path directory = Paths.get(directoryPath); + List hiddenFiles = new ArrayList<>(); + + try (Stream paths = Files.walk(directory, 1)) { + hiddenFiles= paths + .filter(Files::isRegularFile) + .map(Path::getFileName) + .map(Path::toString) + .filter(name -> name.startsWith(".")) + .collect(Collectors.toList()); + return hiddenFiles.isEmpty() ? "" : "record/live/camera"+camera.getId()+"/"+formattedDate+"/"+removeLeadingDot(hiddenFiles.get(0)); + } catch (IOException e) { + e.printStackTrace(); + hiddenFiles= List.of(); // 返回空列表 + } + return ""; + } + + public static String removeLeadingDot(String input) { + if (input == null || input.isEmpty()) { + return input; + } + if (input.startsWith(".")) { + return input.substring(1); + } + return input; + } + +} diff --git a/web/src/main/resources/mapper/OrderMapper.xml b/web/src/main/resources/mapper/OrderMapper.xml index bd556c7..c6fbee4 100644 --- a/web/src/main/resources/mapper/OrderMapper.xml +++ b/web/src/main/resources/mapper/OrderMapper.xml @@ -9,6 +9,14 @@ and t.order_num = #{req.orderNum} + + + and t.status = #{req.status} + + + + and t.street_Id = #{req.streetId} + and t.start_time >= #{req.startTimestamp} and t.start_time <= #{req.endTimestamp}