暂时提交

master
lld 2026-03-06 22:08:26 +08:00
parent 6d62735dc4
commit 88b2ba4619
1 changed files with 114 additions and 53 deletions

View File

@ -18,6 +18,7 @@ import com.agri.system.service.ISysDtuDataService;
import com.agri.system.service.ISysRollerParamService; import com.agri.system.service.ISysRollerParamService;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.checkerframework.checker.units.qual.A;
import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -76,13 +77,14 @@ public class RollerAutoTask {
*/ */
private static final Logger log = LoggerFactory.getLogger(RollerAutoTask.class); private static final Logger log = LoggerFactory.getLogger(RollerAutoTask.class);
@Value("${spring.mqtt.dtu-ctl-lock-ttl}") @Value("${spring.mqtt.dtu-ctl-lock-ttl}")
private int dtuCtlLockTTL; private int dtuCtlLockTTL;
public void checkAutoTerm() { public void checkAutoTerm() {
// 查询自动模式的大棚 // 查询自动模式的大棚
List<SysAgriInfo> agriInfos = agriInfoService.lambdaQuery() List<SysAgriInfo> agriInfos = agriInfoService.lambdaQuery()
.select(SysAgriInfo::getImei) .select(SysAgriInfo::getImei, SysAgriInfo::getAgriName)
.eq(SysAgriInfo::getWorkMode, 1) .eq(SysAgriInfo::getWorkMode, 1)
.eq(SysAgriInfo::getIsDeleted, 0) .eq(SysAgriInfo::getIsDeleted, 0)
.list(); .list();
@ -114,68 +116,91 @@ public class RollerAutoTask {
// 查询每个IMEI今天的第一条日志 // 查询每个IMEI今天的第一条日志
Map<String, Map<String, Integer>> todayLogCountByImeiMap = devOperLogService.getTodayLogCountByImeiMap(imeiList); Map<String, Map<String, Integer>> todayLogCountByImeiMap = devOperLogService.getTodayLogCountByImeiMap(imeiList);
// 循环所有开启自动化的大棚 // 循环所有开启自动化的大棚
for (String imei : imeiList) { for (SysAgriInfo agriInfo : agriInfos) {
String imei = agriInfo.getImei();
String agriName = agriInfo.getAgriName();
// 获取温湿度指定imei的数据 // 获取温湿度指定imei的数据
List<Map<String, Object>> dtuDataInfo = dtuDataByImeiMap.get(imei); List<Map<String, Object>> dtuDataInfo = dtuDataByImeiMap.get(imei);
// 该大棚温湿度不存在 // 该大棚温湿度不存在
if (CollectionUtils.isEmpty(dtuDataInfo)) { if (CollectionUtils.isEmpty(dtuDataInfo)) {
// todo 该大棚下1分钟内无最新温湿度怀疑离线 // todo 该大棚下1分钟内无最新温湿度怀疑离线
break; continue;
} }
// 获取今天对应imei的日志
Map<String, Integer> todayLogByRoller = todayLogCountByImeiMap.get(imei); // 最后一条对应imei对应温度 及时间
// 最后一条对应imei对应温度
Map<String, Object> dtuData = dtuDataInfo.get(0); Map<String, Object> dtuData = dtuDataInfo.get(0);
// 求温度上报时间
LocalDateTime dtuTime = TimeConvertUtil.strToLocalDateTimeSafe((String) dtuData.get("time"));
if (dtuTime == null) {
// todo 当前大棚温湿度时间为空 跳过
continue;
}
// 获取当前imei下的所有参数设置以及卷膜自动化条件设置 // 获取当前imei下的所有参数设置以及卷膜自动化条件设置
Map<String, List<RollerTermVO>> configTermByRollerMap = rollerTermMap.get(imei); Map<String, List<RollerTermVO>> configTermByRollerMap = rollerTermMap.get(imei);
if (configTermByRollerMap.isEmpty()) { if (configTermByRollerMap.isEmpty()) {
// todo 当前大棚下没有设置条件或者参数 // todo 当前大棚下没有设置条件或者参数
break; continue;
} }
configTermByRollerMap.forEach((config, terms) ->{
// 获取今天对应imei的日志
Map<String, Integer> todayLogByRoller = todayLogCountByImeiMap.get(imei);
for (Map.Entry<String, List<RollerTermVO>> configEntry : configTermByRollerMap.entrySet()) {
String roller = configEntry.getKey(); // 当前卷膜
List<RollerTermVO> terms = configEntry.getValue(); // 当前卷膜条件
// 每个卷膜分组只会有一个卷膜参数设置,所有取第一个即可 // 每个卷膜分组只会有一个卷膜参数设置,所有取第一个即可
if (terms == null || terms.isEmpty()) {
// todo 当前卷膜 无参数设置跳过当前roller
continue;
}
// 获取卷膜参数
RollerTermVO rollerConfig = terms.get(0); RollerTermVO rollerConfig = terms.get(0);
// 整体参数 String refTempCode = rollerConfig.getRefTempCode(); // 参考温度
String refTempCode = rollerConfig.getRefTempCode();
String roller = rollerConfig.getRoller(); // 卷膜
BigDecimal ventTotalLen = rollerConfig.getVentTotalLen(); // 风口总长 BigDecimal ventTotalLen = rollerConfig.getVentTotalLen(); // 风口总长
BigDecimal reservedLen = rollerConfig.getReservedLen(); // 预留风口 BigDecimal reservedLen = rollerConfig.getReservedLen(); // 预留风口
// 判断对应卷膜是否是今天第一次操作 // 防御性判断避免dtuData.get(refTempCode)为null
Object tempObj = dtuData.get(refTempCode);
if (tempObj == null) {
// todo 当前卷膜参考温度设置为空
continue;
}
BigDecimal currentTemp = new BigDecimal(tempObj.toString());
// 每个roller单独定义isFirstRun作用域当前roller
boolean isFirstRun = true; boolean isFirstRun = true;
// 判断对应卷膜是否是今天第一次操作
// todayLogByRoller为空铁定第一次操作否则就是todayLogByRoller.getRoller为空是第一次操作 // todayLogByRoller为空铁定第一次操作否则就是todayLogByRoller.getRoller为空是第一次操作
if (!todayLogByRoller.isEmpty()) { if (todayLogByRoller != null && !todayLogByRoller.isEmpty()) {
Integer logOfRoller = todayLogByRoller.getOrDefault(roller, 0); Integer logOfRoller = todayLogByRoller.getOrDefault(roller, 0);
if (logOfRoller>0) { // 只要当前Roller今日有操作记录就不是首次 仅影响当前roller的isFirstRun
if (logOfRoller > 0) {
isFirstRun = false; isFirstRun = false;
} }
} }
terms.forEach(term -> {
// 求温度上报时间 // 遍历当前roller的所有term改用普通for循环可读性更高
LocalDateTime dtuTime = TimeConvertUtil.strToLocalDateTimeSafe((String) dtuData.get("time")); for (RollerTermVO term : terms) {
if (dtuTime == null) {
return; // 跳过该设备
}
// 判断该温度上报时间是否在该条件设置的时间范围内 // 判断该温度上报时间是否在该条件设置的时间范围内
boolean inRange = TimeRangeUtil.isTimeInRange(dtuTime, term.getStartTime(), term.getEndTime()); boolean inRange = TimeRangeUtil.isTimeInRange(dtuTime, term.getStartTime(), term.getEndTime());
// 在范围内 // 在范围内
if (inRange) { if (inRange) {
//判断温度是否在适宜温度内 //判断温度是否在适宜温度内
String redTempCode = dtuData.get(refTempCode).toString();
BigDecimal currentTemp = new BigDecimal(dtuData.get(redTempCode).toString());
TempCommandStatus tempCommandStatus = TempJudgeUtil.judgeTempCommand(currentTemp, term.getTemp()); TempCommandStatus tempCommandStatus = TempJudgeUtil.judgeTempCommand(currentTemp, term.getTemp());
if (tempCommandStatus==TempCommandStatus.OPEN) { if (tempCommandStatus == TempCommandStatus.OPEN) {
// 开指令 // 开指令
sendOpenCommand(imei, roller, isFirstRun, term.getVent(),reservedLen); sendOpenCommand(imei,agriName, roller, isFirstRun, term.getVent(), reservedLen);
isFirstRun = false; isFirstRun = false;
} else if (tempCommandStatus==TempCommandStatus.CLOSE) { } else if (tempCommandStatus == TempCommandStatus.CLOSE) {
// 关指令 // 关指令
sendCloseCommand(imei, roller, isFirstRun, term.getVent()); sendCloseCommand(imei, agriName, roller, isFirstRun, term.getVent());
isFirstRun = false;
} }
} }
// 不在掠过 }
}); }
});
} }
@ -185,7 +210,7 @@ public class RollerAutoTask {
* @param isFirstRun * @param isFirstRun
* @param vent * @param vent
*/ */
private void sendOpenCommand(String imei, String roller, boolean isFirstRun, private void sendOpenCommand(String imei, String agriName, String roller, boolean isFirstRun,
BigDecimal vent, BigDecimal reservedLen) { BigDecimal vent, BigDecimal reservedLen) {
try { try {
// 默认 // 默认
@ -197,7 +222,7 @@ public class RollerAutoTask {
} }
String funcType = roller + "k1"; String funcType = roller + "k1";
String message = "{\"" + funcType + "\":1}";
String lockKey = "lock:" + imei + ":" + funcType; String lockKey = "lock:" + imei + ":" + funcType;
Boolean lockSuccess = stringRedisTemplate.opsForValue().setIfAbsent( Boolean lockSuccess = stringRedisTemplate.opsForValue().setIfAbsent(
lockKey, "auto_mode", dtuCtlLockTTL, TimeUnit.SECONDS // 延长至15秒适配设备回执场景 lockKey, "auto_mode", dtuCtlLockTTL, TimeUnit.SECONDS // 延长至15秒适配设备回执场景
@ -208,33 +233,33 @@ public class RollerAutoTask {
} }
// 3. 记录日志 // 3. 记录日志
log.info("【指令处理】前端{}于{}控制设备{}的{}功能,指令:{}", log.info("【指令处理】前端【自动模式】下触发【{}】操作设备【{}】的【{}】功能, 指令:{}"
clientId, LocalDateTime.now(), deviceId, funcType, payload); , roller, imei, funcType, message);
SysUser sysUser = sysUserService.lambdaQuery()
.eq(SysUser::getClientId, clientId)
.one();
String operator = "手动控制";
if (sysUser!=null) {
operator = sysUser.getUserName();
}
SysAgriInfo agriInfo = sysAgriInfoService.lambdaQuery()
.eq(SysAgriInfo::getImei, deviceId)
.one();
String agriName = (agriInfo!=null && org.apache.commons.lang3.ObjectUtils.isNotEmpty(agriInfo.getAgriName()))?agriInfo.getAgriName():null;
SysDevOperLog logDto = new SysDevOperLog(); SysDevOperLog logDto = new SysDevOperLog();
// 大棚名称
logDto.setAgriName(agriName); logDto.setAgriName(agriName);
logDto.setImei(deviceId); // imei
logDto.setImei(imei);
// 卷膜n
logDto.setFuncCode(funcType); logDto.setFuncCode(funcType);
logDto.setOpType(funcCodeMap.get(funcType)); // 运行1 暂停0
logDto.setOpSource(1); logDto.setOpType(1);
logDto.setPayload(payload); // 来源 条件控制
logDto.setOpSource(3);
// 指令
logDto.setPayload(message);
// 是否成功获取锁
logDto.setLockAcquired(1); logDto.setLockAcquired(1);
logDto.setLockHolder(clientId); // 锁持有者
logDto.setCreateBy(operator); logDto.setLockHolder("auto_mode");
sysDevOperLogService.save(logDto); // 操作人
logDto.setCreateBy("条件控制");
devOperLogService.save(logDto);
mqttMessageSender.publish("dtu/"+imei+"/down", "{\""+funcType+"\":1}"); mqttMessageSender.publish("dtu/"+imei+"/down", message);
// 获取运行时间 // 获取运行时间
int runTime = RollerTimeCalculator.calculateRunTime(openLen); int runTime = RollerTimeCalculator.calculateRunTime(openLen);
if (runTime>0) { if (runTime>0) {
@ -249,11 +274,47 @@ public class RollerAutoTask {
* @param isFirstRun * @param isFirstRun
* @param vent * @param vent
*/ */
private void sendCloseCommand(String imei, String roller, boolean isFirstRun, BigDecimal vent) { private void sendCloseCommand(String imei, String agriName, String roller, boolean isFirstRun, BigDecimal vent) {
try { try {
// 如果是第一次直接返回 // 如果是第一次直接返回
if (isFirstRun) return; if (isFirstRun) return;
String funcType = roller + "g1"; String funcType = roller + "g1";
String message = "{\"" + funcType + "\":1}";
String lockKey = "lock:" + imei + ":" + funcType;
Boolean lockSuccess = stringRedisTemplate.opsForValue().setIfAbsent(
lockKey, "auto_mode", dtuCtlLockTTL, TimeUnit.SECONDS // 延长至15秒适配设备回执场景
);
if (lockSuccess == null || !lockSuccess) {
log.warn("【分布式锁】前端【自动模式】下触发【{}】操作设备【{}】的【{}】功能失败;可能其他用户正在操作此功能", roller, imei, funcType);
return;
}
// 3. 记录日志
log.info("【指令处理】前端【自动模式】下触发【{}】操作设备【{}】的【{}】功能, 指令:{}"
, roller, imei, funcType, message);
SysDevOperLog logDto = new SysDevOperLog();
// 大棚名称
logDto.setAgriName(agriName);
// imei
logDto.setImei(imei);
// 卷膜n
logDto.setFuncCode(funcType);
// 运行1 暂停0
logDto.setOpType(1);
// 来源 条件控制
logDto.setOpSource(3);
// 指令
logDto.setPayload(message);
// 是否成功获取锁
logDto.setLockAcquired(1);
// 锁持有者
logDto.setLockHolder("auto_mode");
// 操作人
logDto.setCreateBy("条件控制");
devOperLogService.save(logDto);
mqttMessageSender.publish("dtu/"+imei+"/down", "{\""+funcType+"\":1}"); mqttMessageSender.publish("dtu/"+imei+"/down", "{\""+funcType+"\":1}");
// 获取运行时间 // 获取运行时间
int runTime = RollerTimeCalculator.calculateRunTime(vent); int runTime = RollerTimeCalculator.calculateRunTime(vent);