更新在线状态逻辑

This commit is contained in:
磷叶 2025-02-12 10:33:40 +08:00
parent a88d5c407c
commit 2c64d6d72c
7 changed files with 114 additions and 45 deletions

View File

@ -273,7 +273,7 @@ public class RedisCache
* @param timeUnit 时间单位
* @return 累计后的值
*/
public long incrementCacheValue(final String key, final long timeout, final TimeUnit timeUnit) {
public Long incrementCacheValue(final String key, final long timeout, final TimeUnit timeUnit) {
// 使用 SET 命令的 NX EX 选项确保初始值设置和过期时间设置是原子性的
Boolean isNewKey = redisTemplate.opsForValue().setIfAbsent(key, 0, timeout, timeUnit);
if (isNewKey != null && isNewKey) {
@ -281,7 +281,7 @@ public class RedisCache
return 1L;
}
// 使用 INCR 命令累计值
long newValue = redisTemplate.opsForValue().increment(key);
Long newValue = redisTemplate.opsForValue().increment(key);
// 刷新过期时间
redisTemplate.expire(key, timeout, timeUnit);
return newValue;

View File

@ -41,4 +41,9 @@ public class MathUtils {
}
return result;
}
// 把Integer转为Long类型
public static Long IntegerToLong(Integer num) {
return num == null ? null : Long.valueOf(num);
}
}

View File

@ -1,5 +1,18 @@
package com.ruoyi.iot.service.impl;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.constant.CacheConstants;
@ -10,33 +23,32 @@ import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.core.redis.enums.RedisLockKey;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MathUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.oneNet.Token;
import com.ruoyi.iot.domain.*;
import com.ruoyi.iot.domain.response.*;
import com.ruoyi.iot.domain.CreateDeviceVo;
import com.ruoyi.iot.domain.CurrentDeviceData;
import com.ruoyi.iot.domain.HistoryDeviceData;
import com.ruoyi.iot.domain.IotDeviceDetail;
import com.ruoyi.iot.domain.IotDeviceInfo;
import com.ruoyi.iot.domain.response.CommandResponse;
import com.ruoyi.iot.domain.response.CurrentDataPointResponse;
import com.ruoyi.iot.domain.response.DetailResponse;
import com.ruoyi.iot.domain.response.HistoryDataPointResponse;
import com.ruoyi.iot.domain.response.ListResponse;
import com.ruoyi.iot.enums.IotHttpStatus;
import com.ruoyi.iot.interfaces.IotDevice;
import com.ruoyi.iot.service.IotConverter;
import com.ruoyi.iot.service.IotService;
import com.ruoyi.ss.commandLog.service.ICommandLogService;
import com.ruoyi.ss.device.domain.enums.DeviceOnlineStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.ruoyi.ss.device.service.DeviceService;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
/**
* @author wjh
@ -75,6 +87,12 @@ public class IotServiceImpl implements IotService {
@Autowired
private RedisLock redisLock;
@Autowired
private DeviceService deviceService;
@Autowired
private ScheduledExecutorService scheduledExecutorService;
// 查询OneNet设备在线状态
@Override
public String getOnlineStatus(String deviceName, String productId, String type) {
@ -88,35 +106,12 @@ public class IotServiceImpl implements IotService {
if (lock) {
// log.info("进入lock");
// 从缓存获取上次的在线状态若不存在则发命令防止短时间发送命令过于频繁
String cacheKey = CacheConstants.DEVICE_ONLINE_STATUS + deviceName;
String incrementCacheKey = CacheConstants.DEVICE_OFFLINE_INCREMENT + deviceName;
String cacheKey = this.getOnlineCacheKey(deviceName);
String status = redisCache.getCacheObject(cacheKey);
if (StringUtils.isBlank(status)) {
// log.info("进入command");
// 发送命令
CommandResponse res = uploadData(deviceName, productId, "获取在线状态");
// 若是离线则直接返回离线
if (res != null && res.isNotOnline()) {
status = DeviceOnlineStatus.OFFLINE.getStatus();
}
// 若是命令超时则累加redis数据超过2次则判断为离线
else if (res == null || res.isCmdTimeout()) {
long offlineCount = redisCache.incrementCacheValue(incrementCacheKey, 60, TimeUnit.SECONDS);
if (offlineCount >= 2) {
status = DeviceOnlineStatus.OFFLINE.getStatus();
} else {
status = DeviceOnlineStatus.ONLINE.getStatus();
}
}
// 若命令发送成功则清空redis累加数据
else if (res.isSuccess()) {
status = DeviceOnlineStatus.ONLINE.getStatus();
redisCache.deleteObject(incrementCacheKey);
}
// 缓存结果30秒
redisCache.setCacheObject(cacheKey, status, 30, TimeUnit.SECONDS);
status = this.parseToOnlineStatus(res, deviceName, false);
}
return status;
@ -137,6 +132,31 @@ public class IotServiceImpl implements IotService {
}
}
private String parseToOnlineStatus(CommandResponse res, String deviceName, boolean increment) {
String incrementCacheKey = CacheConstants.DEVICE_OFFLINE_INCREMENT + deviceName;
// 若命令发送成功则清空redis累加数据
if (res != null && res.isSuccess()) {
redisCache.deleteObject(incrementCacheKey);
return DeviceOnlineStatus.ONLINE.getStatus();
}
// 若是离线则直接返回离线
if (res != null && res.isNotOnline()) {
return DeviceOnlineStatus.OFFLINE.getStatus();
}
// 若是命令超时或者其他情况则累加redis数据超过2次则判断为离线
else {
Long offlineCount = MathUtils.IntegerToLong(redisCache.getCacheObject(incrementCacheKey));
if (increment) {
offlineCount = redisCache.incrementCacheValue(incrementCacheKey, 60, TimeUnit.SECONDS);
}
if (offlineCount != null && offlineCount >= 2) {
return DeviceOnlineStatus.OFFLINE.getStatus();
} else {
return DeviceOnlineStatus.ONLINE.getStatus();
}
}
}
@Override
public String getOnlineStatus(IotDevice device) {
String status = DeviceOnlineStatus.OFFLINE.getStatus();
@ -552,10 +572,17 @@ public class IotServiceImpl implements IotService {
// 记录成功日志
this.addCommandLog(deviceName, command, res.getMsg(), reason, res.getCode());
// 若返回数据为离线或者超时则判断设备是否在线
// if (IotHttpStatus.checkOnlineList().contains(res.getCode())) {
// deviceService.checkOnlineByCommandLogSync(deviceName);
// }
// 转为在线状态并缓存结果30秒
String status = this.parseToOnlineStatus(res, deviceName, true);
redisCache.setCacheObject(this.getOnlineCacheKey(deviceName), status, 30, TimeUnit.SECONDS);
// 异步更新设备在线状态
scheduledExecutorService.schedule(() -> {
int update = deviceService.updateOnlineStatusByMac(deviceName, status);
if (update != 1) {
log.error("异步更新设备在线状态失败,MAC={},status={}", deviceName, status);
}
},0, TimeUnit.SECONDS);
return res;
} catch (Exception e) {
this.addCommandLog(deviceName, command, "操作失败:" + e.getMessage(), reason, null);
@ -563,6 +590,10 @@ public class IotServiceImpl implements IotService {
}
}
private String getOnlineCacheKey(String deviceName) {
return CacheConstants.DEVICE_ONLINE_STATUS + deviceName;
}
// 异步添加日志
private void addCommandLog(String deviceName, String command, String result, String reason, Integer iotCode) {
LoginUser loginUser = null;

View File

@ -227,4 +227,9 @@ public interface DeviceMapper
* 查询ID列表
*/
List<Long> selectIds(@Param("query") DeviceQuery query);
/**
* 更新在线状态
*/
int updateOnlineStatusByMac(@Param("mac") String mac, @Param("status") String status);
}

View File

@ -726,6 +726,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where device_id = #{deviceId}
</update>
<update id="updateOnlineStatusByMac">
update sm_device
set online_status1 = if (#{mac} = mac, #{status}, online_status1),
online_status2 = if (#{mac} = mac2, #{status}, online_status2),
online_status = if (#{mac} = mac,
if (#{status} = '1' or online_status2 = '1', '1', '0'),
if (#{status} = '1' or online_status1 = '1', '1', '0')
),
last_online_time = if (#{mac} = mac,
if (#{status} = '1' or online_status2 = '1', now(), last_online_time),
if (#{status} = '1' or online_status1 = '1', now(), last_online_time)
)
where mac = #{mac} or mac2 = #{mac}
</update>
<delete id="deleteSmDeviceByDeviceId" parameterType="Long">
delete from sm_device where device_id = #{deviceId}
</delete>

View File

@ -436,4 +436,9 @@ public interface DeviceService
* 查询商户设备列表
*/
List<DeviceVO> selectByMchId(Long userId);
/**
* 根据mac修改在线状态
*/
int updateOnlineStatusByMac(String mac, String status);
}

View File

@ -1442,6 +1442,14 @@ public class DeviceServiceImpl implements DeviceService
return selectSmDeviceList(query);
}
@Override
public int updateOnlineStatusByMac(String mac, String status) {
if (StringUtils.isAnyBlank(mac, status)) {
return 0;
}
return deviceMapper.updateOnlineStatusByMac(mac, status);
}
private List<Long> selectIds(DeviceQuery query) {
return deviceMapper.selectIds(query);
}