使用读取plc来拿到信号

hubei-jinshennong
LAPTOP-S9HJSOEB\昊天 11 months ago
parent 55aeffaa4c
commit 3c2c206c9d

@ -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

@ -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

@ -0,0 +1,38 @@
#C1推烟录像触发任务号,C2底部拍照触发任务号同时停止录像,C3顶部拍照触发任务号。并在完成后通过out的写入指定数据块在视觉判断没有问题后通过ET(顶部拍照报错)和ED底部拍照报错
#其中C1、C2、C3是int类型ET、ED是布尔类型C1直接是赋值初始位置ED底部默认.0ET顶部默认.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

@ -18,6 +18,33 @@
</properties>
<dependencies>
<dependency>
<groupId>si.trina</groupId>
<artifactId>moka7-live</artifactId>
<version>0.0.13</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.25</version>
</dependency>
<!--json工具 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-api</artifactId>
<version>0.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-driver-s7</artifactId>
<version>0.12.0</version>
</dependency>
<dependency>
<groupId>com.zhehekeji</groupId>
@ -96,6 +123,14 @@
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -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();

@ -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{

@ -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
* <p>
* 使 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> T parseObject(String text, Class<T> 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> T parseObject(String text, String path, Class<T> 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> 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> T parseObject2(String text, Class<T> clazz) {
if (StrUtil.isEmpty(text)) {
return null;
}
return JSONUtil.toBean(text, clazz);
}
public static <T> T parseObject(byte[] bytes, Class<T> 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> T parseObject(String text, TypeReference<T> 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> T parseObjectQuietly(String text, TypeReference<T> typeReference) {
try {
return objectMapper.readValue(text, typeReference);
} catch (IOException e) {
return null;
}
}
public static <T> List<T> parseArray(String text, Class<T> 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 <T> List<T> parseArray(String text, String path, Class<T> 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);
}
}

@ -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;

@ -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;
}

@ -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<Camera> cameras = cameraService.allCameras();
zlmService.zlmConf(cameras);
}catch (Exception e){
log.error("zlm conf error",e);
}
}
@Scheduled(cron = "0 0 0 * * ?")
public void file() {

@ -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();

@ -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<Camera> cameras = cameraMapper.selectByMap(new HashMap<>(0));
cameras.forEach(camera -> {
LoginThread loginThread = new LoginThread(camera);
loginThread.start();
});
// List<Camera> 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<Street> 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<Street> 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();
}

@ -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());

@ -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());
}
}
}

@ -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<String, Integer> addressMap = new ConcurrentHashMap<>();
// 当前命令的上一个任务号
public static final Map<String, Integer> taskMap = new ConcurrentHashMap<>();
// @Resource
// S7Client s7Client;
// 采用池化
private final int POOL_SIZE = 5; // 池大小
private BlockingQueue<S7Client> 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<Runnable> 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插槽1IP是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("连接失败");
}
}
*/
}

@ -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<RtspSession> 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<Track> 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;
}
}
}

@ -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<String, Object> params) {
UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(baseUrl);
for (Map.Entry<String, Object> 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<String, Object> 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<Integer,Boolean> zlmStatus = new ConcurrentHashMap<>();
public void zlmConf(List<Camera> list) {
String zlmApiUrl = "http://"+configProperties.getZlm().getIp()+":"+configProperties.getZlm().getApiPort()+"/index/api/";
String zlmApiSecret = configProperties.getZlm().getSecret();
try {
// 查询当前的RTSP拉流代理
Map<String, Object> 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<String, Object> 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<String, Object> 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<String> hiddenFiles = new ArrayList<>();
try (Stream<Path> 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;
}
}

@ -9,6 +9,14 @@
<if test="req.orderNum != null and req.orderNum != ''">
and t.order_num = #{req.orderNum}
</if>
<if test="req.status != null and req.status != ''">
and t.status = #{req.status}
</if>
<if test="req.streetId != null and req.streetId != ''">
and t.street_Id = #{req.streetId}
</if>
<if test="req.startTimestamp != null and req.endTimestamp != null">
and t.start_time >= #{req.startTimestamp} and t.start_time &lt;= #{req.endTimestamp}
</if>

Loading…
Cancel
Save