新增云协议设备实时数据功能

This commit is contained in:
xy
2025-09-04 14:00:15 +08:00
parent f88baa52be
commit 1a3e443be1
15 changed files with 398 additions and 150 deletions

View File

@@ -1,15 +1,8 @@
package com.njcn.access.api;
import com.njcn.access.api.fallback.AskDeviceDataClientFallbackFactory;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.constant.ServerInfo;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.HttpResultUtil;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@@ -41,4 +34,7 @@ public interface AskDeviceDataFeignClient {
@PostMapping("/askRealData")
HttpResult<String> askRealData(@RequestParam("nDid") String nDid, @RequestParam("idx") Integer idx, @RequestParam("clDId") Integer clDId);
@PostMapping("/askCldRealData")
HttpResult<String> askCldRealData(@RequestParam("devId") String devId, @RequestParam("lineId") String lineId);
}

View File

@@ -73,6 +73,12 @@ public class AskDeviceDataClientFallbackFactory implements FallbackFactory<AskDe
log.error("{}异常,降级处理,异常为:{}","询问装置实时数据",cause.toString());
throw new BusinessException(finalExceptionEnum);
}
@Override
public HttpResult<String> askCldRealData(String devId, String lineId) {
log.error("{}异常,降级处理,异常为:{}","询问云前置实时数据",cause.toString());
throw new BusinessException(finalExceptionEnum);
}
};
}
}

View File

@@ -0,0 +1,68 @@
package com.njcn.access.utils;
import com.njcn.redis.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* @author 徐扬
*/
@Component
@Slf4j
public class RedisSetUtil {
@Autowired
private RedisUtil redisUtil;
/**
* 向Redis Set中添加元素
*/
public void addToSet(String key, String value, long expireSeconds) {
try {
Object existing = redisUtil.getObjectByKey(key);
Set<String> set = convertToSet(existing);
set.add(value);
redisUtil.saveByKeyWithExpire(key, set, expireSeconds);
} catch (Exception e) {
log.error("向Redis Set添加元素失败key: {}", key, e);
}
}
/**
* 从Redis Set中移除元素
*/
public void removeFromSet(String key, String value) {
try {
Object existing = redisUtil.getObjectByKey(key);
if (existing != null) {
Set<String> set = convertToSet(existing);
set.remove(value);
redisUtil.saveByKey(key, set);
}
} catch (Exception e) {
log.error("从Redis Set移除元素失败key: {}", key, e);
}
}
/**
* 安全的对象到Set转换
*/
public Set<String> convertToSet(Object obj) {
if (obj == null) {
return new HashSet<>();
}
if (obj instanceof Set) {
return new HashSet<>((Set<String>) obj);
}
if (obj instanceof Collection) {
return new HashSet<>((Collection<String>) obj);
}
log.warn("无法转换的对象类型: {}", obj.getClass().getName());
return new HashSet<>();
}
}

View File

@@ -123,5 +123,17 @@ public class AskDeviceDataController extends BaseController {
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
}
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@PostMapping("/askCldRealData")
@ApiOperation("询问云前置实时数据")
@ApiImplicitParams({
@ApiImplicitParam(name = "devId", value = "装置id"),
@ApiImplicitParam(name = "lineId", value = "监测点id")
})
public HttpResult<String> askCldRealData(@RequestParam("devId") String devId, @RequestParam("lineId") String lineId){
String methodDescribe = getMethodDescribe("askCldRealData");
askDeviceDataService.askCldRealData(devId,lineId);
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
}
}

View File

@@ -1,14 +1,17 @@
package com.njcn.access.listener;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.github.tocrhz.mqtt.publisher.MqttPublisher;
import com.njcn.access.enums.AccessEnum;
import com.njcn.access.pojo.dto.NoticeUserDto;
import com.njcn.access.pojo.po.CsDeviceOnlineLogs;
import com.njcn.access.service.ICsDeviceOnlineLogsService;
import com.njcn.access.service.ICsEquipmentDeliveryService;
import com.njcn.access.service.ICsTopicService;
import com.njcn.access.service.impl.CsDeviceServiceImpl;
import com.njcn.access.utils.MqttUtil;
import com.njcn.access.utils.RedisSetUtil;
import com.njcn.access.utils.SendMessageUtil;
import com.njcn.common.pojo.dto.DeviceLogDTO;
import com.njcn.csdevice.api.*;
@@ -17,6 +20,7 @@ import com.njcn.csdevice.pojo.dto.PqsCommunicateDto;
import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.rt.pojo.dto.BaseRealDataSet;
import com.njcn.user.api.AppUserFeignClient;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.pojo.po.User;
@@ -32,6 +36,7 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -46,8 +51,6 @@ import java.util.stream.Collectors;
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
@Resource
private ICsTopicService csTopicService;
@Resource
private ICsEquipmentDeliveryService csEquipmentDeliveryService;
@Resource
@@ -73,9 +76,11 @@ public class RedisKeyExpirationListener extends KeyExpirationEventMessageListene
@Resource
private SendMessageUtil sendMessageUtil;
@Resource
private CsDeviceServiceImpl csDeviceServiceImpl;
@Resource
private CsCommunicateFeignClient csCommunicateFeignClient;
@Resource
private MqttPublisher publisher;
@Resource
private RedisSetUtil redisSetUtil;
private final Object lock = new Object();
@@ -101,6 +106,20 @@ public class RedisKeyExpirationListener extends KeyExpirationEventMessageListene
String nDid = expiredKey.split(":")[1];
executeMainTask(nDid);
}
if(expiredKey.startsWith("cldRtDataOverTime:")){
String lineId = expiredKey.split(":")[1];
Object redisObject = redisUtil.getObjectByKey("rtDataUserId:"+lineId);
if (ObjectUtil.isNotNull(redisObject)) {
Set<String> userSet = redisSetUtil.convertToSet(redisObject);
userSet.forEach(userId->{
BaseRealDataSet baseRealDataSet = new BaseRealDataSet();
baseRealDataSet.setUserId(userId);
baseRealDataSet.setResult(false);
baseRealDataSet.setContent("设备未响应,超时中断");
publisher.send("/Web/RealData/" + lineId, new Gson().toJson(baseRealDataSet), 1, false);
});
}
}
}
//主任务
@@ -118,10 +137,6 @@ public class RedisKeyExpirationListener extends KeyExpirationEventMessageListene
logDto.setOperate(nDid +"装置离线");
sendMessage(nDid);
//记录装置掉线时间
// CsDeviceOnlineLogs record = onlineLogsService.findLastData(nDid);
// record.setOfflineTime(LocalDateTime.now());
// onlineLogsService.updateById(record);
//记录装置掉线时间
PqsCommunicateDto dto = new PqsCommunicateDto();
dto.setTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
dto.setDevId(nDid);
@@ -131,68 +146,6 @@ public class RedisKeyExpirationListener extends KeyExpirationEventMessageListene
csLogsFeignClient.addUserLog(logDto);
}
//主任务
//1.装置心跳断连
//2.MQTT客户端不在线
// private void executeMainTask(String nDid, String version) {
// ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
// log.info("{}->装置离线", nDid);
// DeviceLogDTO logDto = new DeviceLogDTO();
// logDto.setUserName("运维管理员");
// logDto.setLoginName("njcnyw");
// //判断mqtt
// String clientName = "NJCN-" + nDid.substring(nDid.length() - 6);
// boolean mqttClient = mqttUtil.judgeClientOnline(clientName);
// //心跳异常,但是客户端在线,则发送接入请求
// if (mqttClient) {
// csDeviceService.devAccessAskTemplate(nDid,version,1);
// redisUtil.saveByKey(AppRedisKey.DEVICE_MID + nDid,1);
// try {
// Thread.sleep(5000);
// Object object = redisUtil.getObjectByKey("online" + nDid);
// if (Objects.nonNull(object)) {
// scheduler.shutdown();
// logDto.setOperate(nDid + "客户端在线重连成功");
// } else {
// //装置下线
// csEquipmentDeliveryService.updateRunStatusBynDid(nDid, AccessEnum.OFFLINE.getCode());
// //装置调整为注册状态
// csEquipmentDeliveryService.updateStatusBynDid(nDid,AccessEnum.REGISTERED.getCode());
// logDto.setOperate(nDid +"装置离线");
// sendMessage(nDid);
//
// //记录装置掉线时间
// CsDeviceOnlineLogs record = onlineLogsService.findLastData(nDid);
// record.setOfflineTime(LocalDateTime.now());
// onlineLogsService.updateById(record);
//
// scheduler.shutdown();
// }
// } catch (InterruptedException e) {
// scheduler.shutdown();
// throw new RuntimeException(e);
// }
// csLogsFeignClient.addUserLog(logDto);
// }
// //客户端不在线则修改装置状态,进入定时任务
// else {
// //装置下线
// csEquipmentDeliveryService.updateRunStatusBynDid(nDid, AccessEnum.OFFLINE.getCode());
// //装置调整为注册状态
// csEquipmentDeliveryService.updateStatusBynDid(nDid,AccessEnum.REGISTERED.getCode());
// logDto.setOperate(nDid +"主任务执行失败,装置下线");
// csLogsFeignClient.addUserLog(logDto);
// sendMessage(nDid);
//
// //记录装置掉线时间
// CsDeviceOnlineLogs record = onlineLogsService.findLastData(nDid);
// record.setOfflineTime(LocalDateTime.now());
// onlineLogsService.updateById(record);
//
// scheduler.shutdown();
// }
// }
private void startScheduledTask(ScheduledExecutorService scheduler, String nDid, String version) {
synchronized (lock) {
//判断是否推送消息

View File

@@ -203,8 +203,7 @@ public class AutoAccessTimer implements ApplicationRunner {
// }
// };
// //第一次执行的时间为120s然后在前一个任务执行完毕后等待120s再执行下一个任务
//// scheduler.scheduleWithFixedDelay(task, AUTO_TIME, AUTO_TIME, TimeUnit.SECONDS);
// scheduler.scheduleWithFixedDelay(task, 10, 10, TimeUnit.SECONDS);
// scheduler.scheduleWithFixedDelay(task, AUTO_TIME, AUTO_TIME, TimeUnit.SECONDS);
// }
//
// public void accessDev(List<CsEquipmentDeliveryPO> list) {

View File

@@ -21,4 +21,6 @@ public interface AskDeviceDataService {
* 实时数据请求报文
*/
void askRealData(String nDid, Integer idx, Integer size);
void askCldRealData(String devId, String lineId);
}

View File

@@ -11,6 +11,8 @@ import com.njcn.access.pojo.dto.ReqAndResDto;
import com.njcn.access.service.AskDeviceDataService;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.enums.AlgorithmResponseEnum;
import com.njcn.mq.message.RealDataMessage;
import com.njcn.mq.template.RealDataMessageTemplate;
import com.njcn.redis.pojo.enums.AppRedisKey;
import com.njcn.redis.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
@@ -32,6 +34,7 @@ public class AskDeviceDataServiceImpl implements AskDeviceDataService {
private final MqttPublisher publisher;
private final CsTopicFeignClient csTopicFeignClient;
private final RedisUtil redisUtil;
private final RealDataMessageTemplate realDataMessageTemplate;
private static Integer mid = 1;
private static Integer range = 51200;
@@ -209,6 +212,16 @@ public class AskDeviceDataServiceImpl implements AskDeviceDataService {
redisUtil.saveByKey(AppRedisKey.DEVICE_MID + nDid,mid);
}
@Override
public void askCldRealData(String devId, String lineId) {
RealDataMessage realDataMessage = new RealDataMessage();
realDataMessage.setDevSeries(devId);
realDataMessage.setLine(lineId);
realDataMessage.setRealData(true);
realDataMessage.setSoeData(true);
realDataMessage.setLimit(20);
realDataMessageTemplate.sendMember(realDataMessage);
}
public Object getDeviceMid(String nDid) {
return redisUtil.getObjectByKey(AppRedisKey.DEVICE_MID + nDid);

View File

@@ -726,7 +726,7 @@ public class CsDeviceServiceImpl implements ICsDeviceService {
}
}
publisher.send("/Pfm/DevCmd/"+version+"/"+nDid, new Gson().toJson(getJson(mid,TypeEnum.TYPE_5.getCode())), 1, false);
redisUtil.saveByKeyWithExpire("startFile:" + nDid, null, 60L);
// redisUtil.saveByKeyWithExpire("startFile:" + nDid, null, 60L);
result = true;
} catch (Exception e) {
DeviceLogDTO logDto = new DeviceLogDTO();