package com.zy.task;
|
|
import HslCommunication.Core.Types.OperateResult;
|
import HslCommunication.Core.Types.OperateResultExOne;
|
import HslCommunication.Profinet.Siemens.SiemensPLCS;
|
import HslCommunication.Profinet.Siemens.SiemensS7Net;
|
import com.baomidou.mybatisplus.mapper.EntityWrapper;
|
import com.zy.core.model.CrnSlave;
|
import com.zy.core.properties.SlaveProperties;
|
import com.zy.entity.CrnTiltRecord;
|
import com.zy.service.CrnTiltRecordService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.event.ContextRefreshedEvent;
|
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.stereotype.Component;
|
|
import java.util.Calendar;
|
import java.util.Date;
|
import java.util.List;
|
|
/**
|
* 堆垛机倾斜度记录定时任务
|
* 每周记录一次堆垛机的倾斜度数据
|
*
|
* 说明:
|
* 1. 根据"货架倾斜度.txt"和"堆垛机_DB101发送wcs信息.pdf"文档
|
* 2. 倾斜度数据从 PLC 的 DB101 数据块读取(具体偏移量需要根据实际传感器配置确定)
|
* 3. 每周执行一次(默认每周一凌晨2点执行)
|
*/
|
@Slf4j
|
@Component
|
public class CrnTiltRecordTask implements ApplicationListener<ContextRefreshedEvent> {
|
|
@Autowired
|
private SlaveProperties slaveProperties;
|
|
@Autowired
|
private CrnTiltRecordService crnTiltRecordService;
|
|
private boolean startupRecordExecuted = false;
|
|
/**
|
* 系统启动后自动记录一次倾斜度数据
|
* 使用 ApplicationListener 监听 ContextRefreshedEvent,确保在 Spring 上下文完全初始化后执行
|
*/
|
@Override
|
public void onApplicationEvent(ContextRefreshedEvent event) {
|
// 避免重复执行(Spring 可能会触发多次事件)
|
if (startupRecordExecuted) {
|
return;
|
}
|
startupRecordExecuted = true;
|
|
log.info("========== 系统启动,开始执行堆垛机倾斜度启动记录 ==========");
|
|
// 延迟10秒执行,确保系统完全启动,数据库连接等都已就绪
|
new Thread(() -> {
|
try {
|
log.info("倾斜度启动记录任务将在10秒后执行...");
|
Thread.sleep(10000);
|
log.info("开始执行倾斜度启动记录任务...");
|
recordTiltDataOnStartup();
|
} catch (InterruptedException e) {
|
log.error("启动记录任务被中断", e);
|
} catch (Exception e) {
|
log.error("启动记录任务执行异常", e);
|
}
|
}, "CrnTiltRecord-Startup").start();
|
}
|
|
/**
|
* 启动时记录倾斜度数据(不检查当天是否已记录)
|
*/
|
private void recordTiltDataOnStartup() {
|
log.info("========== 开始执行倾斜度启动记录 ==========");
|
try {
|
if (slaveProperties == null) {
|
log.error("SlaveProperties 未注入,跳过启动倾斜度记录");
|
return;
|
}
|
|
if (crnTiltRecordService == null) {
|
log.error("CrnTiltRecordService 未注入,跳过启动倾斜度记录");
|
return;
|
}
|
|
List<CrnSlave> crnSlaves = slaveProperties.getCrn();
|
if (crnSlaves == null || crnSlaves.isEmpty()) {
|
log.warn("没有配置堆垛机,跳过启动倾斜度记录");
|
return;
|
}
|
|
log.info("找到 {} 台堆垛机,开始记录倾斜度数据", crnSlaves.size());
|
|
Date recordDate = new Date();
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(recordDate);
|
cal.set(Calendar.HOUR_OF_DAY, 0);
|
cal.set(Calendar.MINUTE, 0);
|
cal.set(Calendar.SECOND, 0);
|
cal.set(Calendar.MILLISECOND, 0);
|
Date recordDateOnly = cal.getTime();
|
|
int successCount = 0;
|
int failCount = 0;
|
|
for (CrnSlave crnSlave : crnSlaves) {
|
try {
|
// 读取倾斜度数据
|
CrnTiltRecord record = readTiltDataFromPLC(crnSlave);
|
if (record != null) {
|
record.setCrnNo(crnSlave.getId());
|
record.setRecordDate(recordDateOnly);
|
record.setRecordTime(recordDate);
|
record.setRecordType("STARTUP"); // 启动时记录
|
|
// 获取上次记录用于对比
|
EntityWrapper<CrnTiltRecord> lastWrapper = new EntityWrapper<>();
|
lastWrapper.eq("crn_no", crnSlave.getId());
|
lastWrapper.orderBy("record_date", false);
|
lastWrapper.orderBy("record_time", false);
|
lastWrapper.last("OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY");
|
CrnTiltRecord lastRecord = crnTiltRecordService.selectOne(lastWrapper);
|
|
if (lastRecord != null && lastRecord.getTiltValue() != null) {
|
// 对比倾斜度
|
record.setPrevTiltValue(lastRecord.getTiltValue());
|
if (record.getTiltValue() != null) {
|
float change = record.getTiltValue() - lastRecord.getTiltValue();
|
record.setTiltChange(change);
|
log.info("堆垛机{}启动倾斜度对比:当前值={}, 上次值={}, 变化量={}",
|
crnSlave.getId(), record.getTiltValue(),
|
lastRecord.getTiltValue(), change);
|
}
|
}
|
|
// 保存到数据库
|
if (crnTiltRecordService.insert(record)) {
|
successCount++;
|
log.info("堆垛机{}启动倾斜度记录成功:倾斜度={}, X={}, Y={}, Z={}, 变化量={}",
|
crnSlave.getId(), record.getTiltValue(),
|
record.getTiltX(), record.getTiltY(), record.getTiltZ(),
|
record.getTiltChange() != null ? record.getTiltChange() : 0);
|
} else {
|
failCount++;
|
log.error("堆垛机{}启动倾斜度记录保存失败", crnSlave.getId());
|
}
|
} else {
|
failCount++;
|
log.error("堆垛机{}启动倾斜度数据读取失败", crnSlave.getId());
|
}
|
} catch (Exception e) {
|
failCount++;
|
log.error("堆垛机{}启动倾斜度记录异常", crnSlave.getId(), e);
|
}
|
}
|
|
log.info("堆垛机倾斜度启动记录完成:成功{}条,失败{}条", successCount, failCount);
|
} catch (Exception e) {
|
log.error("堆垛机倾斜度启动记录任务执行异常", e);
|
}
|
}
|
|
/**
|
* 每周记录一次堆垛机倾斜度数据
|
* cron表达式:0 0 2 ? * MON 表示每周一凌晨2点执行
|
* 如果需要修改执行时间,可以调整cron表达式
|
*/
|
@Scheduled(cron = "0 0 2 ? * MON")
|
public void recordCrnTiltData() {
|
log.info("开始执行堆垛机倾斜度记录任务...");
|
|
try {
|
List<CrnSlave> crnSlaves = slaveProperties.getCrn();
|
if (crnSlaves == null || crnSlaves.isEmpty()) {
|
log.warn("没有配置堆垛机,跳过倾斜度记录");
|
return;
|
}
|
|
Date recordDate = new Date();
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(recordDate);
|
// 设置为当天的开始时间(00:00:00)
|
cal.set(Calendar.HOUR_OF_DAY, 0);
|
cal.set(Calendar.MINUTE, 0);
|
cal.set(Calendar.SECOND, 0);
|
cal.set(Calendar.MILLISECOND, 0);
|
Date recordDateOnly = cal.getTime();
|
|
int successCount = 0;
|
int failCount = 0;
|
|
for (CrnSlave crnSlave : crnSlaves) {
|
try {
|
// 检查本周是否已经记录过
|
EntityWrapper<CrnTiltRecord> wrapper = new EntityWrapper<>();
|
wrapper.eq("crn_no", crnSlave.getId());
|
wrapper.ge("record_date", recordDateOnly);
|
wrapper.le("record_date", new Date(recordDateOnly.getTime() + 24 * 60 * 60 * 1000 - 1));
|
|
int count = crnTiltRecordService.selectCount(wrapper);
|
if (count > 0) {
|
log.info("堆垛机{}本周已记录过倾斜度数据,跳过", crnSlave.getId());
|
continue;
|
}
|
|
// 读取倾斜度数据
|
CrnTiltRecord record = readTiltDataFromPLC(crnSlave);
|
if (record != null) {
|
record.setCrnNo(crnSlave.getId());
|
record.setRecordDate(recordDateOnly);
|
record.setRecordTime(recordDate);
|
record.setRecordType("AUTO"); // 自动记录
|
|
// 获取上次记录用于对比
|
EntityWrapper<CrnTiltRecord> lastWrapper = new EntityWrapper<>();
|
lastWrapper.eq("crn_no", crnSlave.getId());
|
lastWrapper.orderBy("record_date", false);
|
lastWrapper.orderBy("record_time", false);
|
lastWrapper.last("OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY");
|
CrnTiltRecord lastRecord = crnTiltRecordService.selectOne(lastWrapper);
|
|
if (lastRecord != null && lastRecord.getTiltValue() != null) {
|
// 对比倾斜度
|
record.setPrevTiltValue(lastRecord.getTiltValue());
|
if (record.getTiltValue() != null) {
|
float change = record.getTiltValue() - lastRecord.getTiltValue();
|
record.setTiltChange(change);
|
log.info("堆垛机{}倾斜度对比:当前值={}, 上次值={}, 变化量={}",
|
crnSlave.getId(), record.getTiltValue(),
|
lastRecord.getTiltValue(), change);
|
}
|
}
|
|
// 保存到数据库
|
if (crnTiltRecordService.insert(record)) {
|
successCount++;
|
log.info("堆垛机{}倾斜度记录成功:倾斜度={}, X={}, Y={}, Z={}, 变化量={}",
|
crnSlave.getId(), record.getTiltValue(),
|
record.getTiltX(), record.getTiltY(), record.getTiltZ(),
|
record.getTiltChange() != null ? record.getTiltChange() : 0);
|
} else {
|
failCount++;
|
log.error("堆垛机{}倾斜度记录保存失败", crnSlave.getId());
|
}
|
} else {
|
failCount++;
|
log.error("堆垛机{}倾斜度数据读取失败", crnSlave.getId());
|
}
|
} catch (Exception e) {
|
failCount++;
|
log.error("堆垛机{}倾斜度记录异常", crnSlave.getId(), e);
|
}
|
}
|
|
log.info("堆垛机倾斜度记录任务完成:成功{}条,失败{}条", successCount, failCount);
|
} catch (Exception e) {
|
log.error("堆垛机倾斜度记录任务执行异常", e);
|
}
|
}
|
|
/**
|
* 从 PLC 读取倾斜度数据
|
*
|
* 注意:根据实际传感器配置,倾斜度数据可能存储在:
|
* 1. DB101 的某个偏移量位置(需要根据"货架倾斜度.txt"文档确定具体位置)
|
* 2. 或者其他数据块
|
*
|
* 当前实现假设倾斜度数据存储在 DB101 的偏移量位置(需要根据实际配置调整)
|
*
|
* @param crnSlave 堆垛机配置
|
* @return 倾斜度记录对象,如果读取失败返回null
|
*/
|
private CrnTiltRecord readTiltDataFromPLC(CrnSlave crnSlave) {
|
SiemensS7Net siemensNet = null;
|
try {
|
// 创建 PLC 连接
|
siemensNet = new SiemensS7Net(SiemensPLCS.S1200, crnSlave.getIp());
|
siemensNet.setRack(crnSlave.getRack().byteValue());
|
siemensNet.setSlot(crnSlave.getSlot().byteValue());
|
|
OperateResult connect = siemensNet.ConnectServer();
|
if (!connect.IsSuccess) {
|
log.error("堆垛机{} PLC连接失败:{}", crnSlave.getId(), connect.Message);
|
return null;
|
}
|
|
// 读取倾斜度数据
|
// 注意:根据"货架倾斜度.txt"文档,需要确定倾斜度数据在 DB101 中的具体偏移量
|
// 假设倾斜度数据存储在 DB101.56 开始的位置(需要根据实际配置调整)
|
// 读取4个Real类型数据(X、Y、Z倾斜度和总倾斜度),每个Real占4字节,共16字节
|
OperateResultExOne<byte[]> result = siemensNet.Read("DB101.56", (short) 16);
|
|
if (!result.IsSuccess) {
|
log.error("堆垛机{}读取倾斜度数据失败:{}", crnSlave.getId(), result.Message);
|
return null;
|
}
|
|
CrnTiltRecord record = new CrnTiltRecord();
|
|
// 解析倾斜度数据(根据实际传感器数据格式调整)
|
// 假设:偏移量0-3: X方向倾斜度(Real),偏移量4-7: Y方向倾斜度(Real),偏移量8-11: Z方向倾斜度(Real),偏移量12-15: 总倾斜度(Real)
|
record.setTiltX(siemensNet.getByteTransform().TransSingle(result.Content, 0));
|
record.setTiltY(siemensNet.getByteTransform().TransSingle(result.Content, 4));
|
record.setTiltZ(siemensNet.getByteTransform().TransSingle(result.Content, 8));
|
record.setTiltValue(siemensNet.getByteTransform().TransSingle(result.Content, 12));
|
|
log.debug("堆垛机{}倾斜度数据读取成功:X={}, Y={}, Z={}, 总倾斜度={}",
|
crnSlave.getId(), record.getTiltX(), record.getTiltY(),
|
record.getTiltZ(), record.getTiltValue());
|
|
return record;
|
} catch (Exception e) {
|
log.error("堆垛机{}读取倾斜度数据异常", crnSlave.getId(), e);
|
return null;
|
} finally {
|
if (siemensNet != null) {
|
try {
|
siemensNet.ConnectClose();
|
} catch (Exception e) {
|
log.warn("关闭PLC连接异常", e);
|
}
|
}
|
}
|
}
|
|
/**
|
* 手动触发记录(用于测试或手动记录)
|
* @param crnNo 堆垛机编号,如果为null则记录所有堆垛机
|
*/
|
public void manualRecord(Integer crnNo) {
|
log.info("手动触发堆垛机倾斜度记录任务,堆垛机编号:{}", crnNo);
|
|
try {
|
List<CrnSlave> crnSlaves = slaveProperties.getCrn();
|
if (crnSlaves == null || crnSlaves.isEmpty()) {
|
log.warn("没有配置堆垛机,跳过倾斜度记录");
|
return;
|
}
|
|
Date recordDate = new Date();
|
Calendar cal = Calendar.getInstance();
|
cal.setTime(recordDate);
|
cal.set(Calendar.HOUR_OF_DAY, 0);
|
cal.set(Calendar.MINUTE, 0);
|
cal.set(Calendar.SECOND, 0);
|
cal.set(Calendar.MILLISECOND, 0);
|
Date recordDateOnly = cal.getTime();
|
|
int successCount = 0;
|
int failCount = 0;
|
|
for (CrnSlave crnSlave : crnSlaves) {
|
// 如果指定了堆垛机编号,只记录指定的堆垛机
|
if (crnNo != null && !crnNo.equals(crnSlave.getId())) {
|
continue;
|
}
|
|
try {
|
// 读取倾斜度数据
|
CrnTiltRecord record = readTiltDataFromPLC(crnSlave);
|
if (record != null) {
|
record.setCrnNo(crnSlave.getId());
|
record.setRecordDate(recordDateOnly);
|
record.setRecordTime(recordDate);
|
record.setRecordType("MANUAL"); // 手动触发
|
|
// 获取上次记录用于对比
|
EntityWrapper<CrnTiltRecord> lastWrapper = new EntityWrapper<>();
|
lastWrapper.eq("crn_no", crnSlave.getId());
|
lastWrapper.orderBy("record_date", false);
|
lastWrapper.orderBy("record_time", false);
|
lastWrapper.last("OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY");
|
CrnTiltRecord lastRecord = crnTiltRecordService.selectOne(lastWrapper);
|
|
if (lastRecord != null && lastRecord.getTiltValue() != null) {
|
// 对比倾斜度
|
record.setPrevTiltValue(lastRecord.getTiltValue());
|
if (record.getTiltValue() != null) {
|
float change = record.getTiltValue() - lastRecord.getTiltValue();
|
record.setTiltChange(change);
|
log.info("堆垛机{}倾斜度对比:当前值={}, 上次值={}, 变化量={}",
|
crnSlave.getId(), record.getTiltValue(),
|
lastRecord.getTiltValue(), change);
|
}
|
}
|
|
// 保存到数据库
|
if (crnTiltRecordService.insert(record)) {
|
successCount++;
|
log.info("堆垛机{}手动倾斜度记录成功:倾斜度={}, X={}, Y={}, Z={}, 变化量={}",
|
crnSlave.getId(), record.getTiltValue(),
|
record.getTiltX(), record.getTiltY(), record.getTiltZ(),
|
record.getTiltChange() != null ? record.getTiltChange() : 0);
|
} else {
|
failCount++;
|
log.error("堆垛机{}倾斜度记录保存失败", crnSlave.getId());
|
}
|
} else {
|
failCount++;
|
log.error("堆垛机{}倾斜度数据读取失败", crnSlave.getId());
|
}
|
} catch (Exception e) {
|
failCount++;
|
log.error("堆垛机{}倾斜度记录异常", crnSlave.getId(), e);
|
}
|
}
|
|
log.info("手动堆垛机倾斜度记录任务完成:成功{}条,失败{}条", successCount, failCount);
|
} catch (Exception e) {
|
log.error("手动堆垛机倾斜度记录任务执行异常", e);
|
}
|
}
|
}
|