parent
575467d76a
commit
76469decc5
|
|
@ -92,7 +92,7 @@ public class DeviceAckHandler {
|
|||
String lockKey = "lock:" + deviceId + ":" + funcType;
|
||||
Boolean delete = stringRedisTemplate.delete(lockKey);
|
||||
if (propObj.size() > 1) {
|
||||
log.warn("【设备回执】prop包含多个功能码,仅处理第一个:{}", propObj.keySet());
|
||||
log.warn("【设备回执】prop包含多个功能码,仅处理第一个:{}, {}", propObj,payload);
|
||||
}
|
||||
log.info("【设备回执】设备{}的{}功能执行完成,已释放锁:{},{}", deviceId, funcType, lockKey, delete);
|
||||
int runTime = 0;
|
||||
|
|
|
|||
|
|
@ -109,17 +109,6 @@ public class DeviceStatusHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
// 转发消息
|
||||
forwardPayload(deviceId, payload,payloadObj,action);
|
||||
|
||||
// 获取第二个动态段,如"up"或"ack"
|
||||
if ("ack".equals(action)) {
|
||||
deviceAckHandler.isStartAutoOffTask(payloadObj,deviceId,payload);
|
||||
}
|
||||
}
|
||||
|
||||
private void forwardPayload(String deviceId,String payload,JSONObject payloadObj,String action) {
|
||||
try {
|
||||
boolean isAck = payloadObj.containsKey("suc") && payloadObj.containsKey("prop");
|
||||
JSONObject sendObj = payloadObj; // 默认直接用原对象
|
||||
// 如果是回执,先拿 funcType
|
||||
|
|
@ -142,6 +131,20 @@ public class DeviceStatusHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 转发消息
|
||||
forwardPayload(deviceId, payload,payloadObj,action, sendObj, isAck);
|
||||
|
||||
// 获取第二个动态段,如"up"或"ack"
|
||||
if ("ack".equals(action)) {
|
||||
deviceAckHandler.isStartAutoOffTask(payloadObj,deviceId,payload);
|
||||
}
|
||||
}
|
||||
|
||||
private void forwardPayload(String deviceId,String payload,
|
||||
JSONObject payloadObj,String action, JSONObject sendObj, boolean isAck) {
|
||||
try {
|
||||
|
||||
// 非回执消息:正常转发给订阅前端
|
||||
// 查询Redis中订阅该设备的前端列表:sub:{deviceId}
|
||||
Set<String> subscribedClients = stringRedisTemplate.opsForSet().members("sub:" + deviceId);
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ public class FrontendConfigHandler {
|
|||
log.warn("【分布式锁】前端{}操作设备{}的{}功能失败;可能其他用户正在操作此功能", clientId, deviceId, funcType);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 转发前端指令
|
||||
String deviceTopic = "dtu/" + deviceId + "/down";
|
||||
mqttMessageSender.publish(deviceTopic, payload);
|
||||
|
|
@ -133,5 +134,8 @@ public class FrontendConfigHandler {
|
|||
rollerAir.setOpTime(currentTime);
|
||||
sysRollerAirService.save(rollerAir);
|
||||
log.info("【指令转发】前端{} → 设备{}的{}功能", clientId, deviceId, funcType);
|
||||
} finally {
|
||||
stringRedisTemplate.delete(lockKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.agri.framework.interceptor;
|
||||
|
||||
import com.agri.common.core.domain.entity.SysUser;
|
||||
import com.agri.common.utils.wechat.WxUtil;
|
||||
import com.agri.framework.config.MqttConfig;
|
||||
import com.agri.framework.manager.MqttAutoOffManager;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
|
|
@ -153,6 +154,7 @@ public class FrontendControlHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 3. 记录日志
|
||||
log.info("【指令处理】前端{}于{}控制设备{}的{}功能,指令:{}",
|
||||
clientId, LocalDateTime.now(), deviceId, funcType, payload);
|
||||
|
|
@ -184,6 +186,9 @@ public class FrontendControlHandler {
|
|||
// testAutoOffTask(deviceId,funcCodeMap);
|
||||
// }
|
||||
log.info("【指令转发】前端{} → 设备{}的{}功能", clientId, deviceId, funcType);
|
||||
} finally {
|
||||
stringRedisTemplate.delete(lockKey);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAutoOffTask(String deviceId, Map<String,Integer> funcCodeMap) throws MqttException {
|
||||
|
|
|
|||
|
|
@ -276,12 +276,23 @@ public class MqttAutoOffManager {
|
|||
log.info("【自动关任务】{}功能忙(锁占用),跳过自动关闭:deviceId={}, funcType={}", funcType, deviceId, funcType);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String deviceTopic = "dtu/" + deviceId + "/down";
|
||||
JSONObject down = new JSONObject();
|
||||
down.put(funcType, 0);
|
||||
log.info("触发自动化条件");
|
||||
//todo
|
||||
mqttMessageSender.publish(deviceTopic, down.toJSONString());
|
||||
saveDevLog(deviceId, funcType, down, latest);
|
||||
log.info("【自动关任务】检测仍在运行,已下发关闭:deviceId={}, funcType={}, payload={}", deviceId, funcType, down.toJSONString());
|
||||
} catch (Exception e){
|
||||
WxUtil.pushText("自动关任务执行报错-下发关闭指令:\n deviceId: " + deviceId + "\n funcType:" + funcType+"\n Cause: "+e);
|
||||
log.warn("【自动关任务】下发关闭指令失败,跳过:deviceId={}, funcType={}", deviceId, funcType);
|
||||
} finally {
|
||||
stringRedisTemplate.delete(lockKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveDevLog(String deviceId, String funcType, JSONObject down, String latest) {
|
||||
SysAgriInfo agriInfo = sysAgriInfoService.lambdaQuery()
|
||||
.eq(SysAgriInfo::getImei, deviceId)
|
||||
.one();
|
||||
|
|
@ -300,8 +311,6 @@ public class MqttAutoOffManager {
|
|||
logDto.setCreateBy("自动关");
|
||||
logDto.setTaskStatus(getFutureStatus().toString());
|
||||
sysDevOperLogService.save(logDto);
|
||||
log.info("【自动关任务】检测仍在运行,已下发关闭:deviceId={}, funcType={}, payload={}", deviceId, funcType, down.toJSONString());
|
||||
|
||||
}
|
||||
|
||||
// 新增:收到“关”指令时,尝试取消对应自动关任务(优化:减少无意义任务执行;正确性仍以到点状态判断为准)
|
||||
|
|
|
|||
|
|
@ -7,13 +7,12 @@ import com.agri.common.utils.wechat.WxUtil;
|
|||
import com.agri.framework.config.MqttConfig;
|
||||
import com.agri.framework.manager.MqttAutoOffManager;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.SysAgriLimit;
|
||||
import com.agri.system.domain.SysDevOperLog;
|
||||
import com.agri.system.domain.vo.RollerTermVO;
|
||||
import com.agri.system.service.ISysAgriInfoService;
|
||||
import com.agri.system.service.ISysDevOperLogService;
|
||||
import com.agri.system.service.ISysDtuDataService;
|
||||
import com.agri.system.service.ISysRollerParamService;
|
||||
import com.agri.system.service.*;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -26,10 +25,9 @@ import javax.annotation.Resource;
|
|||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
|
@ -74,12 +72,30 @@ public class RollerAutoTask {
|
|||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ISysAgriLimitService agriLimitService;
|
||||
|
||||
|
||||
@Value("${spring.mqtt.dtu-ctl-lock-ttl}")
|
||||
private int dtuCtlLockTTL;
|
||||
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
|
||||
|
||||
|
||||
private static final Map<String, Function<SysAgriLimit, Integer>> LIMIT_MAP = new HashMap<>();
|
||||
private static final Set<String> VALID_FUNC_CODES = new HashSet<>();
|
||||
static {
|
||||
LIMIT_MAP.put("jm1g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm1gLimit())));
|
||||
LIMIT_MAP.put("jm2g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm2gLimit())));
|
||||
LIMIT_MAP.put("jbg1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJbgLimit())));
|
||||
LIMIT_MAP.put("jm3g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm3gLimit())));
|
||||
LIMIT_MAP.put("jm2k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm2kLimit())));
|
||||
LIMIT_MAP.put("jm3k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm3kLimit())));
|
||||
LIMIT_MAP.put("jbk1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJbkLimit())));
|
||||
LIMIT_MAP.put("jm1k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm1kLimit())));
|
||||
}
|
||||
|
||||
|
||||
// ========== 常量定义(新增) ==========
|
||||
private static final int WORK_MODE_AUTO = 1; // 自动模式
|
||||
private static final int NOT_DELETED = 0; // 未删除
|
||||
|
|
@ -88,6 +104,7 @@ public class RollerAutoTask {
|
|||
private static final String CREATE_BY = "条件控制";
|
||||
private static final int OP_SOURCE = 3; // 操作来源:条件控制
|
||||
private static final int LOCK_ACQUIRED = 1; // 是否获取锁
|
||||
private static final int DEFAULT_RUN_TIME = 300; // 默认运行时间
|
||||
|
||||
public void checkAutoTerm() {
|
||||
try {
|
||||
|
|
@ -359,22 +376,28 @@ public class RollerAutoTask {
|
|||
// ========== 2. 记录操作日志 ==========
|
||||
log.error("【指令处理】自动模式下触发{}设备{}的{}功能,指令:{}",
|
||||
isOpen ? "开启" : "关闭", imei, funcType, message);
|
||||
saveOperLog(imei, agriName, funcType, message, isOpen ? 1 : 0);
|
||||
|
||||
// ========== 3. 发布MQTT指令 ==========todo
|
||||
mqttMessageSender.publish("dtu/" + imei + "/down", message);
|
||||
if (isCancelOff) {
|
||||
log.debug("【自动关调度】设备{}卷膜{}:触发最后一条自动化条件,下发关闭指令,无需暂停!时间:{}", imei, roller, LocalDateTime.now());
|
||||
return;
|
||||
}
|
||||
|
||||
// ========== 4. 计算运行时间并调度自动关 ==========
|
||||
int runTime = RollerTimeCalculator.calculateRunTime(len);
|
||||
if (isCancelOff) {
|
||||
// 如果最后一条则遵循手动限位设置,如果没设置默认300秒
|
||||
SysAgriLimit agriLimit = agriLimitService.lambdaQuery()
|
||||
.eq(SysAgriLimit::getImei, imei)
|
||||
.one();
|
||||
if (agriLimit != null) {
|
||||
runTime = LIMIT_MAP.getOrDefault(funcType, k -> DEFAULT_RUN_TIME).apply(agriLimit);
|
||||
}
|
||||
log.debug("【自动关调度】设备{}卷膜{}:触发最后一条自动化条件,遵循手动限位设置!时间:{}", imei, roller, LocalDateTime.now());
|
||||
}
|
||||
if (runTime > 0) {
|
||||
String autoOffKey = roller + (isOpen ? "k1" : "g1");
|
||||
autoOffManager.scheduleAutoOff(imei, autoOffKey, runTime);
|
||||
log.debug("【自动关调度】设备{}卷膜「{}:{}」调度{}秒后自动关闭", imei, roller,(isOpen?"开":"关"), runTime);
|
||||
}
|
||||
|
||||
saveOperLog(imei, agriName, funcType, message, isOpen ? 1 : 0, isCancelOff, runTime);
|
||||
}
|
||||
// catch (MqttException e) {
|
||||
// // ========== 异常处理:记录详细日志,不抛运行时异常 ==========
|
||||
|
|
@ -397,7 +420,8 @@ public class RollerAutoTask {
|
|||
* @param payload 指令内容
|
||||
* @param opType 操作类型(1-开,0-关)
|
||||
*/
|
||||
private void saveOperLog(String imei, String agriName, String funcCode, String payload, int opType) {
|
||||
private void saveOperLog(String imei, String agriName,
|
||||
String funcCode, String payload, int opType, boolean isCancelOff, int runTime) {
|
||||
SysDevOperLog logDto = new SysDevOperLog();
|
||||
logDto.setAgriName(agriName);
|
||||
logDto.setImei(imei);
|
||||
|
|
@ -405,8 +429,13 @@ public class RollerAutoTask {
|
|||
logDto.setOpType(opType);
|
||||
logDto.setOpSource(OP_SOURCE);
|
||||
logDto.setPayload(payload);
|
||||
logDto.setRunTime(runTime);
|
||||
logDto.setLockAcquired(LOCK_ACQUIRED); // 已获取锁
|
||||
logDto.setLockHolder(AUTO_MODE);
|
||||
logDto.setIsTask(isCancelOff?0:1);
|
||||
if (isCancelOff) {
|
||||
logDto.setNoTaskReason("触发最后一条自动化指令,遵循手动限位设置,默认300秒");
|
||||
}
|
||||
logDto.setCreateBy(CREATE_BY);
|
||||
// 可选:增加异常捕获,避免日志保存失败影响指令执行
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in New Issue