第一次提交
This commit is contained in:
@ -0,0 +1,27 @@
|
||||
package com.fastbee.data.service;
|
||||
|
||||
import com.fastbee.common.core.mq.message.DeviceMessage;
|
||||
import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem;
|
||||
import com.fastbee.iot.model.VariableReadVO;
|
||||
import com.fastbee.modbus.model.ModbusRtu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备消息Service接口
|
||||
*/
|
||||
public interface IDeviceMessageService {
|
||||
|
||||
void messagePost(DeviceMessage deviceMessage);
|
||||
|
||||
String messageEncode(ModbusRtu modbusRtu);
|
||||
|
||||
List<ThingsModelSimpleItem> messageDecode(DeviceMessage deviceMessage);
|
||||
|
||||
|
||||
/**
|
||||
* 变量读取
|
||||
* @param readVO
|
||||
*/
|
||||
public void readVariableValue(VariableReadVO readVO);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.fastbee.data.service;
|
||||
|
||||
import com.fastbee.common.core.mq.ota.OtaUpgradeDelayTask;
|
||||
|
||||
/**
|
||||
* OTA升级
|
||||
* @author bill
|
||||
*/
|
||||
public interface IOtaUpgradeService {
|
||||
|
||||
/**
|
||||
* OTA延迟升级任务发送
|
||||
* @param task
|
||||
*/
|
||||
public void upgrade(OtaUpgradeDelayTask task);
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.fastbee.data.service;
|
||||
|
||||
import com.fastbee.base.session.Session;
|
||||
import com.fastbee.common.enums.DeviceStatus;
|
||||
import com.fastbee.iot.domain.Device;
|
||||
import com.fastbee.iot.model.DeviceStatusVO;
|
||||
import com.fastbee.iot.service.IDeviceService;
|
||||
import com.fastbee.iot.service.IProductService;
|
||||
import com.fastbee.mqtt.manager.MqttRemoteManager;
|
||||
import com.fastbee.mqtt.manager.SessionManger;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 定时同步设备状态 -- netty版本mqtt使用
|
||||
* @author gsb
|
||||
* @date 2024/4/11 10:33
|
||||
*/
|
||||
@Component
|
||||
public class SyncDeviceStatusJob {
|
||||
|
||||
@Resource
|
||||
private IDeviceService deviceService;
|
||||
@Resource
|
||||
private MqttRemoteManager mqttRemoteManager;
|
||||
@Value("${server.broker.enabled}")
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 定期同步设备状态
|
||||
* 1.将异常在线设备变更为离线状态
|
||||
* 2.将离线设备但实际在线设备变更为在线
|
||||
*/
|
||||
public void syncDeviceStatus() {
|
||||
if (enabled) {
|
||||
//获取所有已激活并不是禁用的设备
|
||||
List<DeviceStatusVO> deviceStatusVOList = deviceService.selectDeviceActive();
|
||||
if (!CollectionUtils.isEmpty(deviceStatusVOList)) {
|
||||
for (DeviceStatusVO statusVO : deviceStatusVOList) {
|
||||
Session session = SessionManger.getSession(statusVO.getSerialNumber());
|
||||
//以session为准
|
||||
// 如果session中设备在线,数据库状态离线 ,则更新设备的状态为在线
|
||||
if (!Objects.isNull(session) && statusVO.getStatus() == DeviceStatus.OFFLINE.getType()) {
|
||||
Device device = new Device();
|
||||
device.setStatus(DeviceStatus.ONLINE.getType());
|
||||
device.setSerialNumber(statusVO.getSerialNumber());
|
||||
deviceService.updateDeviceStatus(device);
|
||||
mqttRemoteManager.pushDeviceStatus(-1L, statusVO.getSerialNumber(), DeviceStatus.ONLINE);
|
||||
}
|
||||
if (Objects.isNull(session) && statusVO.getStatus() == DeviceStatus.ONLINE.getType()) {
|
||||
Device device = new Device();
|
||||
device.setStatus(DeviceStatus.OFFLINE.getType());
|
||||
device.setSerialNumber(statusVO.getSerialNumber());
|
||||
deviceService.updateDeviceStatus(device);
|
||||
mqttRemoteManager.pushDeviceStatus(-1L, statusVO.getSerialNumber(), DeviceStatus.OFFLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
package com.fastbee.data.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fastbee.common.core.mq.DeviceStatusBo;
|
||||
import com.fastbee.common.core.notify.AlertPushParams;
|
||||
import com.fastbee.common.enums.DeviceStatus;
|
||||
import com.fastbee.common.exception.ServiceException;
|
||||
import com.fastbee.common.utils.DateUtils;
|
||||
import com.fastbee.common.utils.StringUtils;
|
||||
import com.fastbee.iot.domain.*;
|
||||
import com.fastbee.iot.model.AlertSceneSendVO;
|
||||
import com.fastbee.mqtt.manager.MqttRemoteManager;
|
||||
import com.fastbee.iot.service.*;
|
||||
import com.fastbee.mq.redischannel.producer.MessageProducer;
|
||||
import com.fastbee.notify.core.service.NotifySendService;
|
||||
import com.fastbee.sip.domain.SipDevice;
|
||||
import com.fastbee.sip.domain.SipDeviceChannel;
|
||||
import com.fastbee.sip.enums.DeviceChannelStatus;
|
||||
import com.fastbee.sip.mapper.SipDeviceChannelMapper;
|
||||
import com.fastbee.sip.mapper.SipDeviceMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author gsb
|
||||
* @date 2023/2/20 17:13
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DeviceJob {
|
||||
|
||||
@Resource
|
||||
private IDeviceService deviceService;
|
||||
|
||||
@Autowired
|
||||
private SipDeviceMapper sipDeviceMapper;
|
||||
|
||||
@Autowired
|
||||
private SipDeviceChannelMapper sipDeviceChannelMapper;
|
||||
|
||||
@Autowired
|
||||
private IDeviceLogService deviceLogService;
|
||||
|
||||
@Autowired
|
||||
private IAlertService alertService;
|
||||
|
||||
@Autowired
|
||||
private NotifySendService notifySendService;
|
||||
|
||||
@Autowired
|
||||
private IAlertLogService alertLogService;
|
||||
|
||||
@Autowired
|
||||
private IDeviceAlertUserService deviceAlertUserService;
|
||||
|
||||
@Autowired
|
||||
private ISceneScriptService sceneScriptService;
|
||||
|
||||
public void updateSipDeviceOnlineStatus(Integer timeout) {
|
||||
List<SipDevice> devs = sipDeviceMapper.selectOfflineSipDevice(timeout);
|
||||
devs.forEach(item -> {
|
||||
if (!Objects.equals(item.getDeviceSipId(), "")) {
|
||||
//更新iot设备状态
|
||||
Device dev = deviceService.selectDeviceBySerialNumber(item.getDeviceSipId());
|
||||
if (dev != null && dev.getStatus() == DeviceStatus.ONLINE.getType()) {
|
||||
log.warn("定时任务:=>设备:{} 已经下线,设备超过{}秒没上线!",item.getDeviceSipId(),timeout);
|
||||
dev.setStatus(DeviceStatus.OFFLINE.getType());
|
||||
deviceService.updateDeviceStatusAndLocation(dev,"");
|
||||
DeviceStatusBo bo = DeviceStatusBo.builder()
|
||||
.serialNumber(dev.getSerialNumber())
|
||||
.status(DeviceStatus.OFFLINE)
|
||||
.build();
|
||||
MessageProducer.sendStatusMsg(bo);
|
||||
}
|
||||
//更新通道状态
|
||||
List<SipDeviceChannel> channels = sipDeviceChannelMapper.selectSipDeviceChannelByDeviceSipId(item.getDeviceSipId());
|
||||
channels.forEach(citem -> {
|
||||
citem.setStatus(DeviceChannelStatus.offline.getValue());
|
||||
sipDeviceChannelMapper.updateSipDeviceChannel(citem);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查设备上报日志
|
||||
*
|
||||
* @param cycle 设备上报日志周期(分钟)
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public void checkDeviceReportData(String TriggerId, Integer cycle) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
Date now = new Date();
|
||||
calendar.setTime(now);
|
||||
calendar.add(Calendar.MINUTE, -cycle);
|
||||
deviceLogService.selectDeviceReportData(calendar.getTime(), now).forEach(item -> {
|
||||
if (!item.getUnReportList().isEmpty()) {
|
||||
item.getUnReportList().forEach(s -> {
|
||||
//产生告警 设备序列号 和 id无数据
|
||||
alertPush(TriggerId, item.getSerialNumber(), s);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void alertPush(String TriggerId, String serialNumber, String identity) {
|
||||
// 获取告警场景id
|
||||
SceneScript triggerScript = new SceneScript();
|
||||
SceneScript alertlog = new SceneScript();
|
||||
triggerScript.setId(TriggerId);
|
||||
List<SceneScript> list = sceneScriptService.selectSceneScriptList(triggerScript);
|
||||
if (!list.isEmpty()) {
|
||||
triggerScript = list.get(0);
|
||||
alertlog.setId(identity);
|
||||
alertlog.setValue("无数据上报");
|
||||
alertlog.setSceneId(triggerScript.getSceneId());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
List<AlertLog> alertLogList = new ArrayList<>();
|
||||
// 查询设备信息
|
||||
Device device = deviceService.selectDeviceBySerialNumber(serialNumber);
|
||||
Optional.ofNullable(device).orElseThrow(() -> new ServiceException("告警推送,设备不存在" + "[{" + serialNumber + "}]"));
|
||||
// 获取场景相关的告警参数,告警必须要是启动状态
|
||||
List<AlertSceneSendVO> sceneSendVOList = alertService.listByAlertIds(alertlog.getSceneId());
|
||||
if (CollectionUtils.isEmpty(sceneSendVOList)) {
|
||||
return;
|
||||
}
|
||||
// 获取告警推送参数
|
||||
AlertPushParams alertPushParams = new AlertPushParams();
|
||||
alertPushParams.setDeviceName(device.getDeviceName());
|
||||
alertPushParams.setSerialNumber(serialNumber);
|
||||
// 多租户改版查询自己配置的告警用户
|
||||
DeviceAlertUser deviceAlertUser = new DeviceAlertUser();
|
||||
deviceAlertUser.setDeviceId(device.getDeviceId());
|
||||
List<DeviceAlertUser> deviceUserList = deviceAlertUserService.selectDeviceAlertUserList(deviceAlertUser);
|
||||
if (CollectionUtils.isNotEmpty(deviceUserList)) {
|
||||
alertPushParams.setUserPhoneSet(deviceUserList.stream().map(DeviceAlertUser::getPhoneNumber).filter(StringUtils::isNotEmpty).collect(Collectors.toSet()));
|
||||
alertPushParams.setUserIdSet(deviceUserList.stream().map(DeviceAlertUser::getUserId).collect(Collectors.toSet()));
|
||||
}
|
||||
String address;
|
||||
if (StringUtils.isNotEmpty(device.getNetworkAddress())) {
|
||||
address = device.getNetworkAddress();
|
||||
} else if (StringUtils.isNotEmpty(device.getNetworkIp())) {
|
||||
address = device.getNetworkIp();
|
||||
} else if (Objects.nonNull(device.getLongitude()) && Objects.nonNull(device.getLatitude())) {
|
||||
address = device.getLongitude() + "," + device.getLatitude();
|
||||
} else {
|
||||
address = "未知地点";
|
||||
}
|
||||
alertPushParams.setAddress(address);
|
||||
alertPushParams.setAlertTime(DateUtils.parseDateToStr(DateUtils.YY_MM_DD_HH_MM_SS, new Date()));
|
||||
// 获取告警关联模版id
|
||||
for (AlertSceneSendVO alertSceneSendVO : sceneSendVOList) {
|
||||
List<AlertNotifyTemplate> alertNotifyTemplateList = alertService.listAlertNotifyTemplate(alertSceneSendVO.getAlertId());
|
||||
alertPushParams.setAlertName(alertSceneSendVO.getAlertName());
|
||||
for (AlertNotifyTemplate alertNotifyTemplate : alertNotifyTemplateList) {
|
||||
alertPushParams.setNotifyTemplateId(alertNotifyTemplate.getNotifyTemplateId());
|
||||
notifySendService.alertSend(alertPushParams);
|
||||
}
|
||||
List<AlertLog> alist = alertLogService.selectAlertLogListByCreateBy(alertlog.getSceneId().toString(), alertlog.getId(), 2);
|
||||
if (alist.isEmpty()) {
|
||||
AlertLog alertLog = buildAlertLog(alertSceneSendVO, device, alertlog);
|
||||
alertLogList.add(alertLog);
|
||||
} else {
|
||||
//重复未处理告警,只更新告警发生时间
|
||||
for (AlertLog alertLog : alist) {
|
||||
alertLog.setCreateTime(new Date());
|
||||
alertLogService.updateAlertLog(alertLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 保存告警日志
|
||||
alertLogService.insertAlertLogBatch(alertLogList);
|
||||
}
|
||||
|
||||
private AlertLog buildAlertLog(AlertSceneSendVO alertSceneSendVO, Device device, SceneScript Item) {
|
||||
AlertLog alertLog = new AlertLog();
|
||||
alertLog.setAlertName(alertSceneSendVO.getAlertName());
|
||||
alertLog.setAlertLevel(alertSceneSendVO.getAlertLevel());
|
||||
alertLog.setSerialNumber(device.getSerialNumber());
|
||||
alertLog.setProductId(device.getProductId());
|
||||
alertLog.setDeviceName(device.getDeviceName());
|
||||
alertLog.setUserId(device.getTenantId());
|
||||
alertLog.setStatus(2);
|
||||
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("id", Item.getId());
|
||||
jsonObject.put("value", Item.getValue());
|
||||
jsonObject.put("remark", "");
|
||||
alertLog.setDetail(jsonObject.toJSONString());
|
||||
alertLog.setCreateBy(Item.getSceneId().toString());
|
||||
alertLog.setRemark(Item.getId());
|
||||
alertLog.setCreateTime(new Date());
|
||||
return alertLog;
|
||||
}
|
||||
}
|
@ -0,0 +1,376 @@
|
||||
package com.fastbee.data.service.impl;
|
||||
|
||||
import com.fastbee.common.constant.ScheduleConstants;
|
||||
import com.fastbee.common.exception.job.TaskException;
|
||||
import com.fastbee.iot.domain.DeviceJob;
|
||||
import com.fastbee.iot.mapper.DeviceJobMapper;
|
||||
import com.fastbee.iot.service.IDeviceJobService;
|
||||
import com.fastbee.iot.cache.IDeviceCache;
|
||||
import com.fastbee.data.quartz.CronUtils;
|
||||
import com.fastbee.data.quartz.ScheduleUtils;
|
||||
import com.fastbee.quartz.domain.SysJob;
|
||||
import com.fastbee.quartz.mapper.SysJobMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 定时任务调度信息 服务层
|
||||
*
|
||||
* @author kerwincui
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class DeviceJobServiceImpl implements IDeviceJobService
|
||||
{
|
||||
@Autowired
|
||||
private Scheduler scheduler;
|
||||
|
||||
@Autowired
|
||||
private DeviceJobMapper jobMapper;
|
||||
|
||||
@Autowired
|
||||
private SysJobMapper sysJobMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() throws SchedulerException, TaskException
|
||||
{
|
||||
scheduler.clear();
|
||||
// 设备定时任务
|
||||
List<DeviceJob> jobList = jobMapper.selectJobAll();
|
||||
for (DeviceJob deviceJob : jobList)
|
||||
{
|
||||
ScheduleUtils.createScheduleJob(scheduler, deviceJob);
|
||||
}
|
||||
|
||||
// 系统定时任务
|
||||
List<SysJob> sysJobList = sysJobMapper.selectJobAll();
|
||||
for (SysJob job : sysJobList)
|
||||
{
|
||||
com.fastbee.quartz.util.ScheduleUtils.createScheduleJob(scheduler, job);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取quartz调度器的计划任务列表
|
||||
*
|
||||
* @param job 调度信息
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<DeviceJob> selectJobList(DeviceJob job)
|
||||
{
|
||||
return jobMapper.selectJobList(job);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过调度任务ID查询调度信息
|
||||
*
|
||||
* @param jobId 调度任务ID
|
||||
* @return 调度任务对象信息
|
||||
*/
|
||||
@Override
|
||||
public DeviceJob selectJobById(Long jobId)
|
||||
{
|
||||
return jobMapper.selectJobById(jobId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停任务
|
||||
*
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int pauseJob(DeviceJob job) throws SchedulerException
|
||||
{
|
||||
Long jobId = job.getJobId();
|
||||
String jobGroup = job.getJobGroup();
|
||||
job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
|
||||
int rows = jobMapper.updateJob(job);
|
||||
if (rows > 0)
|
||||
{
|
||||
scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复任务
|
||||
*
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int resumeJob(DeviceJob job) throws SchedulerException
|
||||
{
|
||||
Long jobId = job.getJobId();
|
||||
String jobGroup = job.getJobGroup();
|
||||
job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
|
||||
int rows = jobMapper.updateJob(job);
|
||||
if (rows > 0)
|
||||
{
|
||||
scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务后,所对应的trigger也将被删除
|
||||
*
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int deleteJob(DeviceJob job) throws SchedulerException
|
||||
{
|
||||
Long jobId = job.getJobId();
|
||||
String jobGroup = job.getJobGroup();
|
||||
int rows = jobMapper.deleteJobById(jobId);
|
||||
if (rows > 0)
|
||||
{
|
||||
scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除调度信息
|
||||
*
|
||||
* @param jobIds 需要删除的任务ID
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteJobByIds(Long[] jobIds) throws SchedulerException
|
||||
{
|
||||
for (Long jobId : jobIds)
|
||||
{
|
||||
DeviceJob job = jobMapper.selectJobById(jobId);
|
||||
deleteJob(job);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据设备Ids批量删除调度信息
|
||||
*
|
||||
* @param deviceIds 需要删除数据的设备Ids
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteJobByDeviceIds(Long[] deviceIds) throws SchedulerException
|
||||
{
|
||||
// 查出所有job
|
||||
List<DeviceJob> deviceJobs=jobMapper.selectShortJobListByDeviceIds(deviceIds);
|
||||
// 批量删除job
|
||||
int rows=jobMapper.deleteJobByDeviceIds(deviceIds);
|
||||
// 批量删除调度器
|
||||
for(DeviceJob job:deviceJobs){
|
||||
scheduler.deleteJob(ScheduleUtils.getJobKey(job.getJobId(), job.getJobGroup()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据告警Ids批量删除调度信息
|
||||
*
|
||||
* @param alertIds 需要删除数据的告警Ids
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteJobByAlertIds(Long[] alertIds) throws SchedulerException
|
||||
{
|
||||
// 查出所有job
|
||||
List<DeviceJob> deviceJobs=jobMapper.selectShortJobListByAlertIds(alertIds);
|
||||
// 批量删除job
|
||||
int rows=jobMapper.deleteJobByAlertIds(alertIds);
|
||||
// 批量删除调度器
|
||||
for(DeviceJob job:deviceJobs){
|
||||
scheduler.deleteJob(ScheduleUtils.getJobKey(job.getJobId(), job.getJobGroup()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据场景联动Ids批量删除调度信息
|
||||
*
|
||||
* @param sceneIds 需要删除数据的场景Ids
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteJobBySceneIds(Long[] sceneIds) throws SchedulerException
|
||||
{
|
||||
// 查出所有job
|
||||
List<DeviceJob> deviceJobs=jobMapper.selectShortJobListBySceneIds(sceneIds);
|
||||
// 批量删除job
|
||||
int rows=jobMapper.deleteJobBySceneIds(sceneIds);
|
||||
// 批量删除调度器
|
||||
for(DeviceJob job:deviceJobs){
|
||||
scheduler.deleteJob(ScheduleUtils.getJobKey(job.getJobId(), job.getJobGroup()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务调度状态修改
|
||||
*
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int changeStatus(DeviceJob job) throws SchedulerException
|
||||
{
|
||||
int rows = 0;
|
||||
String status = job.getStatus();
|
||||
if (ScheduleConstants.Status.NORMAL.getValue().equals(status))
|
||||
{
|
||||
rows = resumeJob(job);
|
||||
}
|
||||
else if (ScheduleConstants.Status.PAUSE.getValue().equals(status))
|
||||
{
|
||||
rows = pauseJob(job);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即运行任务
|
||||
*
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void run(DeviceJob job) throws SchedulerException
|
||||
{
|
||||
Long jobId = job.getJobId();
|
||||
String jobGroup = job.getJobGroup();
|
||||
DeviceJob properties = selectJobById(job.getJobId());
|
||||
// 参数
|
||||
JobDataMap dataMap = new JobDataMap();
|
||||
dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
|
||||
scheduler.triggerJob(ScheduleUtils.getJobKey(jobId, jobGroup), dataMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增任务
|
||||
*
|
||||
* @param deviceJob 调度信息 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int insertJob(DeviceJob deviceJob) throws SchedulerException, TaskException
|
||||
{
|
||||
int rows = jobMapper.insertJob(deviceJob);
|
||||
if (rows > 0)
|
||||
{
|
||||
ScheduleUtils.createScheduleJob(scheduler, deviceJob);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新任务的时间表达式
|
||||
*
|
||||
* @param deviceJob 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int updateJob(DeviceJob deviceJob) throws SchedulerException, TaskException
|
||||
{
|
||||
DeviceJob properties = selectJobById(deviceJob.getJobId());
|
||||
int rows = jobMapper.updateJob(deviceJob);
|
||||
if (rows > 0)
|
||||
{
|
||||
updateSchedulerJob(deviceJob, properties.getJobGroup());
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新任务
|
||||
*
|
||||
* @param deviceJob 任务对象
|
||||
* @param jobGroup 任务组名
|
||||
*/
|
||||
public void updateSchedulerJob(DeviceJob deviceJob, String jobGroup) throws SchedulerException, TaskException
|
||||
{
|
||||
Long jobId = deviceJob.getJobId();
|
||||
// 判断是否存在
|
||||
JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
|
||||
if (scheduler.checkExists(jobKey))
|
||||
{
|
||||
// 防止创建时存在数据问题 先移除,然后在执行创建操作
|
||||
scheduler.deleteJob(jobKey);
|
||||
}
|
||||
ScheduleUtils.createScheduleJob(scheduler, deviceJob);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验cron表达式是否有效
|
||||
*
|
||||
* @param cronExpression 表达式
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean checkCronExpressionIsValid(String cronExpression)
|
||||
{
|
||||
return CronUtils.isValid(cronExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceJob> listShortJobBySceneId(Long[] sceneIds) {
|
||||
return jobMapper.selectShortJobListBySceneIds(sceneIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteJobByJobTypeAndDatasourceIds(Long[] datasourceIds, int jobType) throws SchedulerException {
|
||||
// 查出所有job
|
||||
List<DeviceJob> deviceJobs = jobMapper.selectListByJobTypeAndDatasourceIds(datasourceIds, jobType);
|
||||
// 批量删除job
|
||||
int rows = jobMapper.deleteJobByJobTypeAndDatasourceIds(datasourceIds, jobType);
|
||||
// 批量删除调度器
|
||||
for(DeviceJob job:deviceJobs){
|
||||
scheduler.deleteJob(ScheduleUtils.getJobKey(job.getJobId(), job.getJobGroup()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceJob> selectListByJobTypeAndDatasourceIds(Long[] datasourceIds, int jobType) {
|
||||
return jobMapper.selectListByJobTypeAndDatasourceIds(datasourceIds, jobType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据条件批量删除定时任务
|
||||
* @param deviceId
|
||||
* @param jobType
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteJobByJobTypeAndDeviceId(Long deviceId, int jobType) throws SchedulerException {
|
||||
// 查出所有job
|
||||
DeviceJob deviceJob = new DeviceJob();
|
||||
deviceJob.setJobType(jobType);
|
||||
deviceJob.setDeviceId(deviceId);
|
||||
List<DeviceJob> deviceJobs = jobMapper.selectJobList(deviceJob);
|
||||
// 批量删除job
|
||||
jobMapper.deleteJobByJobTypeAndDeviceId(deviceId, jobType);
|
||||
// 批量删除调度器
|
||||
for(DeviceJob job:deviceJobs){
|
||||
scheduler.deleteJob(ScheduleUtils.getJobKey(job.getJobId(), job.getJobGroup()));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,215 @@
|
||||
package com.fastbee.data.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.fastbee.common.constant.FastBeeConstant;
|
||||
import com.fastbee.common.core.device.DeviceAndProtocol;
|
||||
import com.fastbee.common.core.mq.DeviceReportBo;
|
||||
import com.fastbee.common.core.mq.MQSendMessageBo;
|
||||
import com.fastbee.common.core.mq.message.DeviceMessage;
|
||||
import com.fastbee.common.core.mq.message.FunctionCallBackBo;
|
||||
import com.fastbee.common.core.mq.message.ModbusPollMsg;
|
||||
import com.fastbee.common.core.protocol.modbus.ModbusCode;
|
||||
import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem;
|
||||
import com.fastbee.common.enums.DeviceStatus;
|
||||
import com.fastbee.common.enums.ServerType;
|
||||
import com.fastbee.common.enums.TopicType;
|
||||
import com.fastbee.common.exception.ServiceException;
|
||||
import com.fastbee.common.utils.BitUtils;
|
||||
import com.fastbee.common.utils.DateUtils;
|
||||
import com.fastbee.common.utils.StringUtils;
|
||||
import com.fastbee.common.utils.gateway.CRC16Utils;
|
||||
import com.fastbee.common.utils.gateway.mq.TopicsUtils;
|
||||
import com.fastbee.common.utils.modbus.ModbusUtils;
|
||||
import com.fastbee.data.service.IDeviceMessageService;
|
||||
import com.fastbee.iot.cache.ITSLCache;
|
||||
import com.fastbee.iot.domain.ModbusConfig;
|
||||
import com.fastbee.iot.domain.ModbusJob;
|
||||
import com.fastbee.iot.enums.DeviceType;
|
||||
import com.fastbee.iot.model.DeviceStatusVO;
|
||||
import com.fastbee.iot.model.ThingsModels.ThingsModelValueItem;
|
||||
import com.fastbee.iot.model.VariableReadVO;
|
||||
import com.fastbee.iot.service.IDeviceService;
|
||||
import com.fastbee.iot.service.IModbusJobService;
|
||||
import com.fastbee.iot.service.IProductService;
|
||||
import com.fastbee.iot.service.ISubGatewayService;
|
||||
import com.fastbee.iot.util.SnowflakeIdWorker;
|
||||
import com.fastbee.modbus.codec.ModbusEncoder;
|
||||
import com.fastbee.modbus.codec.ModbusProtocol;
|
||||
import com.fastbee.modbus.model.ModbusRtu;
|
||||
import com.fastbee.mq.redischannel.producer.MessageProducer;
|
||||
import com.fastbee.mqttclient.PubMqttClient;
|
||||
import com.fastbee.pakModbus.codec.ModbusRtuPakEncoder;
|
||||
import com.fastbee.pakModbus.codec.ModbusRtuPakProtocol;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class DeviceMessageServiceImpl implements IDeviceMessageService {
|
||||
|
||||
@Resource
|
||||
private PubMqttClient mqttClient;
|
||||
@Resource
|
||||
private ModbusEncoder modbusMessageEncoder;
|
||||
@Resource
|
||||
private IDeviceService deviceService;
|
||||
@Resource
|
||||
private TopicsUtils topicsUtils;
|
||||
@Resource
|
||||
private ITSLCache itslCache;
|
||||
@Resource
|
||||
private ModbusProtocol modbusProtocol;
|
||||
@Resource
|
||||
private IModbusJobService modbusJobService;
|
||||
|
||||
@Override
|
||||
public void messagePost(DeviceMessage deviceMessage) {
|
||||
String topicName = deviceMessage.getTopicName();
|
||||
String serialNumber = deviceMessage.getSerialNumber();
|
||||
DeviceAndProtocol deviceAndProtocol = deviceService.selectProtocolBySerialNumber(serialNumber);
|
||||
String transport = deviceAndProtocol.getTransport();
|
||||
TopicType type = TopicType.getType(topicName);
|
||||
topicName = topicsUtils.buildTopic(deviceAndProtocol.getProductId(), serialNumber,type);
|
||||
switch (type){
|
||||
case FUNCTION_GET:
|
||||
if (transport.equals(ServerType.MQTT.getCode())){
|
||||
mqttClient.publish(0, false, topicName, deviceMessage.getMessage().toString());
|
||||
}else if (transport.equals(ServerType.TCP.getCode())){
|
||||
//处理TCP下发
|
||||
}
|
||||
break;
|
||||
case PROPERTY_POST:
|
||||
//下发的不经过mqtt或TCP直接转发到数据处理模块
|
||||
DeviceReportBo reportBo = DeviceReportBo.builder()
|
||||
.serverType(ServerType.explain(transport))
|
||||
.data(BitUtils.hexStringToByteArray(deviceMessage.getMessage().toString()))
|
||||
.platformDate(DateUtils.getNowDate())
|
||||
.serialNumber(serialNumber)
|
||||
.topicName(topicName).build();
|
||||
MessageProducer.sendPublishMsg(reportBo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String messageEncode(ModbusRtu modbusRtu) {
|
||||
//兼容15、16功能码
|
||||
if (modbusRtu.getCode() == ModbusCode.Write10.getCode()){
|
||||
//计算:字节数=2*N;N为寄存器个数
|
||||
modbusRtu.setBitCount(2 * modbusRtu.getCount());
|
||||
}else if (modbusRtu.getCode() == ModbusCode.Write0F.getCode()){
|
||||
//计算:字节数=N/8 余数为0是 N需要再+1。N是线圈个数
|
||||
int i = modbusRtu.getCount() / 8;
|
||||
if (modbusRtu.getCount() % 8!= 0){
|
||||
i++;
|
||||
}
|
||||
modbusRtu.setBitCount(i);
|
||||
//计算线圈值,前端返回二进制的字符串,需要将高低位先翻转,在转化为16进制
|
||||
String reverse = StringUtils.reverse(modbusRtu.getBitString());
|
||||
modbusRtu.setBitData(BitUtils.string2bytes(reverse));
|
||||
}
|
||||
ByteBuf out = modbusMessageEncoder.encode(modbusRtu);
|
||||
byte[] result = new byte[out.writerIndex()];
|
||||
out.readBytes(result);
|
||||
ReferenceCountUtil.release(out);
|
||||
return ByteBufUtil.hexDump(CRC16Utils.AddCRC(result));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ThingsModelSimpleItem> messageDecode(DeviceMessage deviceMessage) {
|
||||
// ProductCode productCode = productService.getProtocolBySerialNumber(deviceMessage.getSerialNumber());
|
||||
// ByteBuf buf = Unpooled.wrappedBuffer(ByteBufUtil.decodeHexDump(deviceMessage.getMessage()));
|
||||
// DeviceData deviceData = DeviceData.builder()
|
||||
// .buf(buf)
|
||||
// .productId(productCode.getProductId())
|
||||
// .serialNumber(productCode.getSerialNumber())
|
||||
// .data(ByteBufUtil.getBytes(buf))
|
||||
// .build();
|
||||
// return modbusRtuPakProtocol.decodeMessage(deviceData, deviceMessage.getSerialNumber());
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 变量读取
|
||||
* @param readVO
|
||||
*/
|
||||
@Override
|
||||
public void readVariableValue(VariableReadVO readVO){
|
||||
String serialNumber = readVO.getSerialNumber();
|
||||
assert !Objects.isNull(serialNumber) : "设备编号为空";
|
||||
DeviceAndProtocol deviceAndProtocol = deviceService.selectProtocolBySerialNumber(serialNumber);
|
||||
if (!deviceAndProtocol.getProtocolCode().equals(FastBeeConstant.PROTOCOL.ModbusRtu)) throw new ServiceException("非modbus协议请先配置主动采集协议");
|
||||
Long productId = deviceAndProtocol.getProductId();
|
||||
//如果是子设备,则获取网关子设备的产品id和设备编号
|
||||
Integer deviceType = deviceAndProtocol.getDeviceType();
|
||||
if (deviceType == DeviceType.SUB_GATEWAY.getCode()){
|
||||
serialNumber = deviceAndProtocol.getGwSerialNumber();
|
||||
productId = deviceAndProtocol.getGwProductId();
|
||||
}
|
||||
Integer type = readVO.getType();
|
||||
type = Objects.isNull(type) ? 1 : type;
|
||||
if (type == 1){
|
||||
//单个变量获取
|
||||
String identifier = readVO.getIdentifier();
|
||||
ThingsModelValueItem thingModels = itslCache.getSingleThingModels(deviceAndProtocol.getProductId(), identifier);
|
||||
ModbusConfig config = thingModels.getConfig();
|
||||
if (Objects.isNull(config)) throw new ServiceException("未配置modbus点位");
|
||||
thingModels.getConfig().setModbusCode(ModbusUtils.getReadModbusCode(config.getType(),config.getIsReadonly()));
|
||||
MQSendMessageBo messageBo = new MQSendMessageBo();
|
||||
messageBo.setThingsModel(JSON.toJSONString(thingModels));
|
||||
FunctionCallBackBo encode = modbusProtocol.encode(messageBo);
|
||||
List<String> commandList = new ArrayList<>();
|
||||
commandList.add(encode.getSources());
|
||||
ModbusPollMsg modbusPollMsg = new ModbusPollMsg();
|
||||
modbusPollMsg.setSerialNumber(serialNumber);
|
||||
modbusPollMsg.setProductId(productId);
|
||||
modbusPollMsg.setCommandList(commandList);
|
||||
DeviceStatusVO deviceStatusVO = deviceService.selectDeviceStatusAndTransportStatus(modbusPollMsg.getSerialNumber());
|
||||
modbusPollMsg.setTransport(deviceStatusVO.getTransport());
|
||||
if (deviceStatusVO.getStatus() != DeviceStatus.ONLINE.getType()){
|
||||
log.info("设备:[{}],不在线",modbusPollMsg.getSerialNumber());
|
||||
return;
|
||||
}
|
||||
MessageProducer.sendPropFetch(modbusPollMsg);
|
||||
// 测试将属性读取任务加入到队列
|
||||
// while (true){
|
||||
// try {
|
||||
// Thread.sleep(1010L);
|
||||
// MessageProducer.sendPropFetch(modbusPollMsg);
|
||||
// }catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
}else {
|
||||
//读取当前设备的所有变量,这里读取所有的,判断传递的设备是网关设备、网关子设备、直连设备
|
||||
DeviceType code = DeviceType.transfer(deviceType);
|
||||
List<ModbusJob> modbusJobList = modbusJobService.selectDevicesJobByDeviceType(code, readVO.getSerialNumber());
|
||||
List<String> commandList = modbusJobList.stream().map(ModbusJob::getCommand).collect(Collectors.toList());
|
||||
ModbusPollMsg msg = new ModbusPollMsg();
|
||||
msg.setCommandList(commandList);
|
||||
msg.setTransport(deviceAndProtocol.getTransport());
|
||||
msg.setProductId(productId);
|
||||
msg.setSerialNumber(serialNumber);
|
||||
MessageProducer.sendPropFetch(msg);
|
||||
//测试使用
|
||||
// while (true){
|
||||
// try {
|
||||
// Thread.sleep(5000L);
|
||||
// MessageProducer.sendPropFetch(msg);
|
||||
// }catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package com.fastbee.data.service.impl;
|
||||
|
||||
import com.fastbee.common.constant.FastBeeConstant;
|
||||
import com.fastbee.common.core.mq.ota.OtaUpgradeBo;
|
||||
import com.fastbee.common.core.mq.ota.OtaUpgradeDelayTask;
|
||||
import com.fastbee.common.exception.ServiceException;
|
||||
import com.fastbee.data.service.IOtaUpgradeService;
|
||||
import com.fastbee.iot.domain.Device;
|
||||
import com.fastbee.iot.domain.Firmware;
|
||||
import com.fastbee.iot.service.IDeviceService;
|
||||
import com.fastbee.iot.service.IFirmwareService;
|
||||
import com.fastbee.iot.service.IProductService;
|
||||
import com.fastbee.mq.service.IMessagePublishService;
|
||||
import com.fastbee.mqtt.manager.MqttRemoteManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* OTA延迟升级实现
|
||||
*
|
||||
* @author bill
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OtaUpgradeServiceImpl implements IOtaUpgradeService {
|
||||
|
||||
@Autowired
|
||||
private IFirmwareService firmwareService;
|
||||
@Autowired
|
||||
private IDeviceService deviceService;
|
||||
@Resource
|
||||
private IMessagePublishService messagePublishService;
|
||||
|
||||
|
||||
@Override
|
||||
public void upgrade(OtaUpgradeDelayTask task) {
|
||||
//查询固件版本信息
|
||||
Firmware firmware = firmwareService.selectFirmwareByFirmwareId(task.getFirmwareId());
|
||||
Optional.ofNullable(firmware).orElseThrow(() -> new ServiceException("固件版本不存在!"));
|
||||
// 处理单个或多个设备的OTA升级,根据设备单个升级
|
||||
if (!CollectionUtils.isEmpty(task.getDevices())) {
|
||||
for (String serialNumber : task.getDevices()) {
|
||||
Device device = deviceService.selectDeviceBySerialNumber(serialNumber);
|
||||
handleSingle(task, firmware, serialNumber, device.getDeviceName());
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 根据产品查询设备整个产品升级处理
|
||||
handleProduct(task, firmware);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单个设备升级
|
||||
*
|
||||
* @param task 升级bo
|
||||
* @param firmware 固件
|
||||
* @param serialNumber 设备编号
|
||||
*/
|
||||
private void handleSingle(OtaUpgradeDelayTask task, Firmware firmware, String serialNumber,String deviceName) {
|
||||
OtaUpgradeBo upgradeBo = OtaUpgradeBo.builder()
|
||||
.serialNumber(serialNumber)
|
||||
.taskId(task.getTaskId())
|
||||
.firmwareVersion(firmware.getVersion().toString())
|
||||
.otaId(firmware.getFirmwareId())
|
||||
.productId(firmware.getProductId())
|
||||
.otaUrl(firmware.getFilePath()) //文件升级URL
|
||||
.pushType(0) // 目前支持url升级,0表示url升级
|
||||
.seqNo(firmware.getSeqNo())
|
||||
.deviceName(deviceName)
|
||||
.firmwareName(firmware.getFirmwareName())
|
||||
.build();
|
||||
/* 校验设备是否在集群节点上*/
|
||||
if (MqttRemoteManager.checkDeviceStatus(serialNumber)) {
|
||||
// 客户端在本节点上,发布OTA升级,推送至MQ
|
||||
messagePublishService.publish(upgradeBo, FastBeeConstant.CHANNEL.UPGRADE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理整个产品的设备升级
|
||||
*
|
||||
* @param task 升级bo
|
||||
* @param firmware 固件
|
||||
*/
|
||||
private void handleProduct(OtaUpgradeDelayTask task, Firmware firmware) {
|
||||
//查询产品下的所有设备编码
|
||||
List<Device> deviceList = deviceService.selectDevicesByProductId(firmware.getProductId(),1);
|
||||
for (Device device : deviceList) {
|
||||
handleSingle(task, firmware, device.getSerialNumber(), device.getDeviceName());
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user