From 2c64d6d72cc5ec1a090bc65d759b48ab31ae83e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A3=B7=E5=8F=B6?= <14103883+leaf-phos@user.noreply.gitee.com> Date: Wed, 12 Feb 2025 10:33:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=9C=A8=E7=BA=BF=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/common/core/redis/RedisCache.java | 4 +- .../com/ruoyi/common/utils/MathUtils.java | 5 + .../iot/service/impl/IotServiceImpl.java | 117 +++++++++++------- .../ruoyi/ss/device/mapper/DeviceMapper.java | 5 + .../ruoyi/ss/device/mapper/DeviceMapper.xml | 15 +++ .../ss/device/service/DeviceService.java | 5 + .../service/impl/DeviceServiceImpl.java | 8 ++ 7 files changed, 114 insertions(+), 45 deletions(-) diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java index fc2440b8..de588d96 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java @@ -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; diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/MathUtils.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/MathUtils.java index 54947c56..73d69d16 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/MathUtils.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/MathUtils.java @@ -41,4 +41,9 @@ public class MathUtils { } return result; } + + // 把Integer转为Long类型 + public static Long IntegerToLong(Integer num) { + return num == null ? null : Long.valueOf(num); + } } diff --git a/smart-switch-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java index 85647d6e..00b3f681 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java @@ -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; diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.java b/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.java index b3e32d69..5a7e1077 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.java @@ -227,4 +227,9 @@ public interface DeviceMapper * 查询ID列表 */ List selectIds(@Param("query") DeviceQuery query); + + /** + * 更新在线状态 + */ + int updateOnlineStatusByMac(@Param("mac") String mac, @Param("status") String status); } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.xml b/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.xml index 0f7736dd..dc90f94a 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.xml +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/mapper/DeviceMapper.xml @@ -726,6 +726,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where device_id = #{deviceId} + + 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} + + delete from sm_device where device_id = #{deviceId} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceService.java b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceService.java index 05d280d6..28ce383b 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceService.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceService.java @@ -436,4 +436,9 @@ public interface DeviceService * 查询商户设备列表 */ List selectByMchId(Long userId); + + /** + * 根据mac修改在线状态 + */ + int updateOnlineStatusByMac(String mac, String status); } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java index 27480b2a..d4f91863 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java @@ -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 selectIds(DeviceQuery query) { return deviceMapper.selectIds(query); }