| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| | | } |