温度上下限告警处理
parent
780a4456e5
commit
c2d651d38d
|
|
@ -4,8 +4,15 @@ import com.agri.common.utils.wechat.WxUtil;
|
||||||
import com.agri.framework.config.MqttConfig;
|
import com.agri.framework.config.MqttConfig;
|
||||||
import com.agri.framework.manager.MqttAutoOffManager;
|
import com.agri.framework.manager.MqttAutoOffManager;
|
||||||
import com.agri.framework.manager.MqttSubscriptionManager;
|
import com.agri.framework.manager.MqttSubscriptionManager;
|
||||||
|
import com.agri.system.domain.SysAgriInfo;
|
||||||
|
import com.agri.system.domain.SysMessage;
|
||||||
|
import com.agri.system.domain.SysUserAgri;
|
||||||
|
import com.agri.system.service.AgriService;
|
||||||
|
import com.agri.system.service.ISysAgriInfoService;
|
||||||
|
import com.agri.system.util.UrlEncodeUtil;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
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;
|
||||||
|
|
@ -15,6 +22,7 @@ import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -58,11 +66,15 @@ public class DeviceStatusHandler {
|
||||||
@Autowired
|
@Autowired
|
||||||
private DeviceAckHandler deviceAckHandler;
|
private DeviceAckHandler deviceAckHandler;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysAgriInfoService agriInfoService;
|
||||||
// 新增:最新状态缓存TTL(设备每10秒上报一次,缓存一小段时间即可)
|
// 新增:最新状态缓存TTL(设备每10秒上报一次,缓存一小段时间即可)
|
||||||
@Value("${spring.mqtt.latest-ttl-seconds:120}")
|
@Value("${spring.mqtt.latest-ttl-seconds:120}")
|
||||||
private int latestTtlSeconds;
|
private int latestTtlSeconds;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AgriService agriService;
|
||||||
|
|
||||||
private static final String AUTO_MODE = "auto_mode";
|
private static final String AUTO_MODE = "auto_mode";
|
||||||
private static final String AUTO_OFF = "autooff";
|
private static final String AUTO_OFF = "autooff";
|
||||||
/**
|
/**
|
||||||
|
|
@ -134,10 +146,60 @@ public class DeviceStatusHandler {
|
||||||
|
|
||||||
// 转发消息
|
// 转发消息
|
||||||
forwardPayload(deviceId, payload,payloadObj,action, sendObj, isAck);
|
forwardPayload(deviceId, payload,payloadObj,action, sendObj, isAck);
|
||||||
|
|
||||||
// 获取第二个动态段,如"up"或"ack"
|
// 获取第二个动态段,如"up"或"ack"
|
||||||
if ("ack".equals(action)) {
|
if ("ack".equals(action)) {
|
||||||
deviceAckHandler.isStartAutoOffTask(payloadObj,deviceId,payload);
|
deviceAckHandler.isStartAutoOffTask(payloadObj,deviceId,payload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// payload全部为数字
|
||||||
|
if ("up".equals(action) && isAllKeysDigit(payloadObj)) {
|
||||||
|
SysAgriInfo agriInfo = agriInfoService.lambdaQuery()
|
||||||
|
.eq(SysAgriInfo::getImei, deviceId)
|
||||||
|
.one();
|
||||||
|
if (agriInfo == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 温度上下限
|
||||||
|
BigDecimal tempUp = agriInfo.getTempUp();
|
||||||
|
BigDecimal tempLow = agriInfo.getTempLow();
|
||||||
|
// 湿度上下限
|
||||||
|
BigDecimal humiUp = agriInfo.getHumiUp();
|
||||||
|
BigDecimal humiLow = agriInfo.getHumiLow();
|
||||||
|
List<SysAgriInfo> msgList = new ArrayList<>();
|
||||||
|
// 仅当up且所有key为数字时,才更新最新状态缓存
|
||||||
|
for (String key : payloadObj.keySet()) {
|
||||||
|
BigDecimal value = payloadObj.getBigDecimal(key);
|
||||||
|
// 温度
|
||||||
|
if (key.startsWith("20")) {
|
||||||
|
// 温度大于温度上限
|
||||||
|
if (value.compareTo(tempUp) > 0 ) {
|
||||||
|
agriInfo.setTitle("温度异常");
|
||||||
|
agriInfo.setMsg("温度"+key.substring(2)+ "异常!高于上限"+tempUp+"℃!");
|
||||||
|
}
|
||||||
|
// 温度小于温度下限
|
||||||
|
if (value.compareTo(tempLow) < 0) {
|
||||||
|
agriInfo.setTitle("温度异常");
|
||||||
|
agriInfo.setMsg("温度"+key.substring(2)+ "异常!低于下限"+tempLow+"℃!");
|
||||||
|
}
|
||||||
|
msgList.add(agriInfo);
|
||||||
|
}
|
||||||
|
// 湿度
|
||||||
|
if (key.startsWith("10")) {
|
||||||
|
// 湿度大于湿度上限
|
||||||
|
if (value.compareTo(humiUp) > 0 ) {
|
||||||
|
agriInfo.setTitle("湿度异常");
|
||||||
|
agriInfo.setMsg("湿度"+key.substring(2)+ "异常!高于上限"+humiUp+"RH%!");
|
||||||
|
}
|
||||||
|
// 湿度小于湿度下限
|
||||||
|
if (value.compareTo(humiLow) < 0) {
|
||||||
|
agriInfo.setTitle("湿度异常");
|
||||||
|
agriInfo.setMsg("湿度"+key.substring(2)+ "异常!低于下限"+humiLow+"RH%!");
|
||||||
|
}
|
||||||
|
msgList.add(agriInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
agriService.saveMessage(msgList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,4 +298,10 @@ public class DeviceStatusHandler {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isAllKeysDigit(JSONObject obj) {
|
||||||
|
return obj != null && !obj.isEmpty()
|
||||||
|
&& obj.keySet().stream().allMatch(k -> k.matches("\\d+"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import com.agri.system.service.ISysUserService;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.alibaba.fastjson2.TypeReference;
|
import com.alibaba.fastjson2.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
@ -73,7 +74,7 @@ public class FrontendControlHandler {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysUserService sysUserService;
|
private ISysUserService sysUserService;
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
@Value("${spring.mqtt.dtu-ctl-lock-ttl}")
|
@Value("${spring.mqtt.dtu-ctl-lock-ttl}")
|
||||||
private int dtuCtlLockTTL;
|
private int dtuCtlLockTTL;
|
||||||
private static final Map<String, Function<SysAgriLimit, Integer>> LIMIT_MAP = new HashMap<>();
|
private static final Map<String, Function<SysAgriLimit, Integer>> LIMIT_MAP = new HashMap<>();
|
||||||
|
|
@ -256,4 +257,15 @@ public class FrontendControlHandler {
|
||||||
// 普通用户权限:校验Redis中是否绑定该设备
|
// 普通用户权限:校验Redis中是否绑定该设备
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendAlarmMessage(String msg, String imei, String timeStr) throws Exception {
|
||||||
|
|
||||||
|
Map<String, Object> alarmMsg = new HashMap<>();
|
||||||
|
alarmMsg.put("online", msg);
|
||||||
|
alarmMsg.put("time", timeStr);
|
||||||
|
alarmMsg.put("imei", imei);
|
||||||
|
String alarmMessage = objectMapper.writeValueAsString(alarmMsg);
|
||||||
|
mqttMessageSender.publish("frontend/" + imei + "/alarm", alarmMessage);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.agri.framework.manager;
|
package com.agri.framework.manager;
|
||||||
|
|
||||||
import com.agri.framework.config.MqttConfig;
|
import com.agri.framework.config.MqttConfig;
|
||||||
|
import com.agri.framework.interceptor.FrontendControlHandler;
|
||||||
import com.agri.system.domain.SysAgriInfo;
|
import com.agri.system.domain.SysAgriInfo;
|
||||||
import com.agri.system.service.AgriService;
|
import com.agri.system.service.AgriService;
|
||||||
import com.agri.system.service.ISysAgriInfoService;
|
import com.agri.system.service.ISysAgriInfoService;
|
||||||
|
|
@ -44,6 +45,8 @@ public class AgriStatusManager {
|
||||||
|
|
||||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FrontendControlHandler frontendControlHandler;
|
||||||
@Autowired
|
@Autowired
|
||||||
private AgriService agriService;
|
private AgriService agriService;
|
||||||
|
|
||||||
|
|
@ -131,7 +134,7 @@ public class AgriStatusManager {
|
||||||
}
|
}
|
||||||
// 无论设备是否在线 只要离线就推送设备状态
|
// 无论设备是否在线 只要离线就推送设备状态
|
||||||
if (!imeiMap.get("imeiOnline")) {
|
if (!imeiMap.get("imeiOnline")) {
|
||||||
agriService.sendAlarmMessage("设备离线", imei, dateNow);
|
frontendControlHandler.sendAlarmMessage("设备离线", imei, dateNow);
|
||||||
}
|
}
|
||||||
successCount++;
|
successCount++;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ public class AgriStatusTask {
|
||||||
// 4. 保存离线设备
|
// 4. 保存离线设备
|
||||||
List<SysAgriInfo> offlineDevices = findOfflineDevices(agriInfos, statusMap);
|
List<SysAgriInfo> offlineDevices = findOfflineDevices(agriInfos, statusMap);
|
||||||
// 5. 保存消息中心
|
// 5. 保存消息中心
|
||||||
agriService.saveMessage(offlineDevices,"怀疑设备离线");
|
agriService.saveMessage(offlineDevices);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("设备在线状态推送任务异常", e);
|
log.error("设备在线状态推送任务异常", e);
|
||||||
|
|
@ -110,6 +110,8 @@ public class AgriStatusTask {
|
||||||
List<SysAgriInfo> offlineDevices = new ArrayList<>();
|
List<SysAgriInfo> offlineDevices = new ArrayList<>();
|
||||||
for (SysAgriInfo agriInfo : agriInfos) {
|
for (SysAgriInfo agriInfo : agriInfos) {
|
||||||
if (!statusMap.containsKey(agriInfo.getImei())) {
|
if (!statusMap.containsKey(agriInfo.getImei())) {
|
||||||
|
agriInfo.setTitle("设备离线告警");
|
||||||
|
agriInfo.setMsg("怀疑设备离线!请及时检查");
|
||||||
offlineDevices.add(agriInfo);
|
offlineDevices.add(agriInfo);
|
||||||
log.info("设备{} 不存在设备状态", agriInfo.getImei());
|
log.info("设备{} 不存在设备状态", agriInfo.getImei());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.agri.quartz.task;
|
package com.agri.quartz.task;
|
||||||
|
|
||||||
|
import com.agri.framework.interceptor.FrontendControlHandler;
|
||||||
import com.agri.system.service.AgriService;
|
import com.agri.system.service.AgriService;
|
||||||
import com.agri.system.domain.SysAgriInfo;
|
import com.agri.system.domain.SysAgriInfo;
|
||||||
import com.agri.system.service.ISysAgriInfoService;
|
import com.agri.system.service.ISysAgriInfoService;
|
||||||
|
|
@ -40,6 +41,9 @@ public class AgriTempTask {
|
||||||
@Autowired
|
@Autowired
|
||||||
private AgriService agriService;
|
private AgriService agriService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FrontendControlHandler frontendControlHandler;
|
||||||
|
|
||||||
public void checkTempStatus() {
|
public void checkTempStatus() {
|
||||||
if (!acquireLock()) {
|
if (!acquireLock()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -54,7 +58,7 @@ public class AgriTempTask {
|
||||||
Map<String, Object> latestDataMap = queryLatestDtuData(imeiList);
|
Map<String, Object> latestDataMap = queryLatestDtuData(imeiList);
|
||||||
List<SysAgriInfo> offlineDevices = findOfflineDevices(agriInfos, latestDataMap);
|
List<SysAgriInfo> offlineDevices = findOfflineDevices(agriInfos, latestDataMap);
|
||||||
pushOfflineAlarm(offlineDevices);
|
pushOfflineAlarm(offlineDevices);
|
||||||
agriService.saveMessage(offlineDevices,"怀疑温度离线");
|
agriService.saveMessage(offlineDevices);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("设备在线状态推送任务异常", e);
|
log.error("设备在线状态推送任务异常", e);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -104,6 +108,8 @@ public class AgriTempTask {
|
||||||
List<SysAgriInfo> offlineList = new ArrayList<>();
|
List<SysAgriInfo> offlineList = new ArrayList<>();
|
||||||
for (SysAgriInfo agriInfo : agriInfos) {
|
for (SysAgriInfo agriInfo : agriInfos) {
|
||||||
if (!latestDataMap.containsKey(agriInfo.getImei())) {
|
if (!latestDataMap.containsKey(agriInfo.getImei())) {
|
||||||
|
agriInfo.setTitle("温度离线");
|
||||||
|
agriInfo.setMsg("怀疑温度离线!请检查");
|
||||||
offlineList.add(agriInfo);
|
offlineList.add(agriInfo);
|
||||||
log.info("设备{} 不存在温湿度数据", agriInfo.getImei());
|
log.info("设备{} 不存在温湿度数据", agriInfo.getImei());
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +125,7 @@ public class AgriTempTask {
|
||||||
String timeStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
String timeStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
for (SysAgriInfo agriInfo : offlineList) {
|
for (SysAgriInfo agriInfo : offlineList) {
|
||||||
try {
|
try {
|
||||||
agriService.sendAlarmMessage("温度离线",agriInfo.getImei(), timeStr);
|
frontendControlHandler.sendAlarmMessage("温度离线",agriInfo.getImei(), timeStr);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("发送设备离线告警失败, imei={}", agriInfo.getImei(), e);
|
log.error("发送设备离线告警失败, imei={}", agriInfo.getImei(), e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,4 +112,10 @@ public class SysAgriInfo extends BaseEntity
|
||||||
/** 湿度下限(%RH) */
|
/** 湿度下限(%RH) */
|
||||||
@Excel(name = "湿度下限(%RH)")
|
@Excel(name = "湿度下限(%RH)")
|
||||||
private BigDecimal humiLow;
|
private BigDecimal humiLow;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
private String msg;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,4 +90,7 @@ public class SysUserAgri extends BaseEntity
|
||||||
public SysUserAgri(List<Long> idList) {
|
public SysUserAgri(List<Long> idList) {
|
||||||
this.idList = idList;
|
this.idList = idList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SysUserAgri() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,7 @@ import java.util.Map;
|
||||||
|
|
||||||
public interface AgriService {
|
public interface AgriService {
|
||||||
|
|
||||||
void sendAlarmMessage(String msg, String imei, String timeStr) throws Exception;
|
void saveMessage(List<SysAgriInfo> offlineList);
|
||||||
|
|
||||||
void saveMessage(List<SysAgriInfo> offlineList,String msg);
|
|
||||||
|
|
||||||
List<String> queryAllGreenhouseImei(List<SysAgriInfo> agriInfos);
|
List<String> queryAllGreenhouseImei(List<SysAgriInfo> agriInfos);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.agri.system.service.impl;
|
package com.agri.system.service.impl;
|
||||||
|
|
||||||
import com.agri.framework.config.MqttConfig;
|
|
||||||
import com.agri.system.service.AgriService;
|
import com.agri.system.service.AgriService;
|
||||||
import com.agri.system.domain.SysAgriInfo;
|
import com.agri.system.domain.SysAgriInfo;
|
||||||
import com.agri.system.domain.SysMessage;
|
import com.agri.system.domain.SysMessage;
|
||||||
|
|
@ -19,8 +18,6 @@ import java.util.stream.Collectors;
|
||||||
@Service
|
@Service
|
||||||
public class AgriServiceImpl implements AgriService {
|
public class AgriServiceImpl implements AgriService {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private MqttConfig.MqttMessageSender mqttMessageSender;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ISysUserAgriService userAgriService;
|
private ISysUserAgriService userAgriService;
|
||||||
|
|
@ -28,24 +25,9 @@ public class AgriServiceImpl implements AgriService {
|
||||||
@Resource
|
@Resource
|
||||||
private ISysMessageService messageService;
|
private ISysMessageService messageService;
|
||||||
|
|
||||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
|
|
||||||
// 发送离线告警消息
|
|
||||||
@Override
|
|
||||||
public void sendAlarmMessage(String msg, String imei, String timeStr) throws Exception {
|
|
||||||
|
|
||||||
Map<String, Object> alarmMsg = new HashMap<>();
|
|
||||||
alarmMsg.put("online", msg);
|
|
||||||
alarmMsg.put("time", timeStr);
|
|
||||||
alarmMsg.put("imei", imei);
|
|
||||||
String alarmMessage = objectMapper.writeValueAsString(alarmMsg);
|
|
||||||
mqttMessageSender.publish("frontend/" + imei + "/alarm", alarmMessage);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存离线设备消息
|
// 保存离线设备消息
|
||||||
@Override
|
@Override
|
||||||
public void saveMessage(List<SysAgriInfo> offlineList,String msg) {
|
public void saveMessage(List<SysAgriInfo> offlineList) {
|
||||||
// 离线是否为空
|
// 离线是否为空
|
||||||
if (CollectionUtils.isEmpty(offlineList)) {
|
if (CollectionUtils.isEmpty(offlineList)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -59,10 +41,10 @@ public class AgriServiceImpl implements AgriService {
|
||||||
List<SysMessage> msgList = new ArrayList<>();
|
List<SysMessage> msgList = new ArrayList<>();
|
||||||
for (SysAgriInfo agriInfo : offlineList) {
|
for (SysAgriInfo agriInfo : offlineList) {
|
||||||
SysMessage message = new SysMessage();
|
SysMessage message = new SysMessage();
|
||||||
message.setTitle(msg);
|
message.setTitle(agriInfo.getTitle());
|
||||||
message.setMsgType("status");
|
message.setMsgType("status");
|
||||||
message.setReadStatus(0L);
|
message.setReadStatus(0L);
|
||||||
message.setContent("大棚【" + agriInfo.getAgriName() + "】" + msg + "!请检查设备状态。");
|
message.setContent("大棚【" + agriInfo.getAgriName() + "】" + agriInfo.getMsg());
|
||||||
message.setImgUrl("");
|
message.setImgUrl("");
|
||||||
message.setLinkUrl(UrlEncodeUtil.buildControlPageUrl(agriInfo, "/pages/home/control/index?agriInfo="));
|
message.setLinkUrl(UrlEncodeUtil.buildControlPageUrl(agriInfo, "/pages/home/control/index?agriInfo="));
|
||||||
for (SysUserAgri userAgri : agriUser){
|
for (SysUserAgri userAgri : agriUser){
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue