第一次提交

This commit is contained in:
wyw
2024-08-08 00:31:26 +08:00
commit c202e2b63d
1819 changed files with 221890 additions and 0 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}
}
}
}
}

View File

@ -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;
}
}

View File

@ -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()));
}
}
}

View File

@ -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*NN为寄存器个数
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();
// }
// }
}
}
}

View File

@ -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());
}
}
}