From dfe410e58ec21f439b4732468e8d439bdd39e5e5 Mon Sep 17 00:00:00 2001 From: tianyongbao Date: Sun, 28 Jun 2026 22:52:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=9B=90=E5=BA=A6=E8=A1=A5=E5=81=BF?= =?UTF-8?q?=E8=AE=BE=E5=AE=9A=EF=BC=8C=E5=A4=AA=E9=98=B3=E8=83=BD=E7=BD=91?= =?UTF-8?q?=E6=8E=A7=E7=BC=93=E5=AD=98=E9=80=BB=E8=BE=91=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../intc/iot/controller/IotController.java | 104 +++++++++++++----- .../intc/iot/handler/DeviceDataHandler.java | 47 ++++++++ .../service/impl/AmqpMessageHandlerImpl.java | 9 ++ .../service/impl/DeviceStatusServiceImpl.java | 9 ++ 4 files changed, 142 insertions(+), 27 deletions(-) diff --git a/intc-modules/intc-iot/src/main/java/com/intc/iot/controller/IotController.java b/intc-modules/intc-iot/src/main/java/com/intc/iot/controller/IotController.java index febf60c..df91a25 100644 --- a/intc-modules/intc-iot/src/main/java/com/intc/iot/controller/IotController.java +++ b/intc-modules/intc-iot/src/main/java/com/intc/iot/controller/IotController.java @@ -63,6 +63,7 @@ import java.util.Date; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.time.Duration; import java.util.List; import java.util.Map; @@ -2034,55 +2035,104 @@ public class IotController extends BaseController { return R.fail("设备已到期"); } - // 查询设备状态 + boolean isSolarDevice = Integer.valueOf(3).equals(device.getDeviceType()); + + if (isSolarDevice) { + if (!cachePendingSolarSalinity(device, request.getSalinityCompensation())) { + return R.fail("盐度缓存失败,请稍后重试"); + } + updateDeviceSalinityCompensation(device.getId(), request.getSalinityCompensation()); + log.info("太阳能网控盐度已缓存: userId={}, deviceId={}, deviceName={}, serialNum={}, salinityCompensation={}‰", + userId, device.getId(), device.getDeviceName(), device.getSerialNum(), request.getSalinityCompensation()); + return R.ok("设置成功"); + } + if (iotDeviceService == null) { return R.fail("飞燕平台配置未启用"); } - Map deviceDetail = iotDeviceService.queryDeviceInfo(device.getIotId()); - if (deviceDetail != null && deviceDetail.get("data") != null) { - try { - Object detailData = deviceDetail.get("data"); - java.lang.reflect.Method getStatusMethod = detailData.getClass().getMethod("getStatus"); - Object statusObj = getStatusMethod.invoke(detailData); - if (statusObj != null) { - String statusStr = statusObj.toString(); - if ("OFFLINE".equalsIgnoreCase(statusStr) || "offline".equals(statusStr)) { - return R.fail("设备离线或断电"); + try { + Map deviceDetail = iotDeviceService.queryDeviceInfo(device.getIotId()); + if (deviceDetail != null && deviceDetail.get("data") != null) { + try { + Object detailData = deviceDetail.get("data"); + java.lang.reflect.Method getStatusMethod = detailData.getClass().getMethod("getStatus"); + Object statusObj = getStatusMethod.invoke(detailData); + if (statusObj != null) { + String statusStr = statusObj.toString(); + if (!"ONLINE".equalsIgnoreCase(statusStr) && !"online".equalsIgnoreCase(statusStr)) { + return R.fail("设备离线或断电"); + } } + } catch (Exception ex) { + log.warn("获取设备状态失败: {}", ex.getMessage()); } - } catch (Exception ex) { - log.warn("获取设备状态失败: {}", ex.getMessage()); } + } catch (Exception ex) { + log.warn("查询设备状态失败: {}", ex.getMessage()); + return R.fail("设备状态查询失败,请稍后重试"); } - // 设置盐度补偿属性 - Map properties = new java.util.HashMap<>(); - properties.put("salinitySet", request.getSalinityCompensation()); - String propertiesJson = cn.hutool.json.JSONUtil.toJsonStr(properties); - - Map setResult = iotDeviceService.setDeviceProperty(device.getIotId(), propertiesJson); - if (setResult == null || !Boolean.TRUE.equals(setResult.get("success"))) { + if (!pushSalinitySetting(device.getIotId(), request.getSalinityCompensation())) { return R.fail("设置盐度补偿失败,请重试"); } - // 更新设备盐度补偿值 - deviceMapper.update(null, - new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper() - .eq(Device::getId, request.getId()) - .set(Device::getSalinityCompensation, request.getSalinityCompensation()) - ); + updateDeviceSalinityCompensation(device.getId(), request.getSalinityCompensation()); + clearPendingSolarSalinity(device.getSerialNum()); log.info("设置盐度补偿成功: userId={}, deviceId={}, deviceName={}, serialNum={}, salinityCompensation={}‰", userId, device.getId(), device.getDeviceName(), device.getSerialNum(), request.getSalinityCompensation()); - return R.ok(); + return R.ok("设置成功"); } catch (Exception e) { log.error("设置盐度补償失败: {}", e.getMessage(), e); return R.fail("设置盐度补償失败: " + e.getMessage()); } } + private boolean pushSalinitySetting(String iotId, Double salinityCompensation) throws Exception { + Map properties = new java.util.HashMap<>(); + properties.put("salinitySet", salinityCompensation); + String propertiesJson = cn.hutool.json.JSONUtil.toJsonStr(properties); + Map setResult = iotDeviceService.setDeviceProperty(iotId, propertiesJson); + return setResult != null && Boolean.TRUE.equals(setResult.get("success")); + } + + private boolean cachePendingSolarSalinity(Device device, Double salinityCompensation) { + try { + String key = DeviceDataHandler.PENDING_SOLAR_SALINITY_KEY_PREFIX + device.getSerialNum(); + Map cacheValue = new java.util.HashMap<>(); + cacheValue.put("deviceId", device.getId()); + cacheValue.put("iotId", device.getIotId()); + cacheValue.put("serialNum", device.getSerialNum()); + cacheValue.put("salinityCompensation", salinityCompensation); + cacheValue.put("updatedAt", System.currentTimeMillis()); + com.intc.common.redis.utils.RedisUtils.setCacheObject(key, cn.hutool.json.JSONUtil.toJsonStr(cacheValue), Duration.ofDays(7)); + log.info("太阳能网控盐度已缓存,等待上线补发: deviceId={}, serialNum={}, salinityCompensation={}", + device.getId(), device.getSerialNum(), salinityCompensation); + return true; + } catch (Exception e) { + log.error("缓存太阳能网控盐度失败: deviceId={}, serialNum={}, err={}", + device.getId(), device.getSerialNum(), e.getMessage(), e); + return false; + } + } + + private void updateDeviceSalinityCompensation(Long deviceId, Double salinityCompensation) { + deviceMapper.update(null, + new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper() + .eq(Device::getId, deviceId) + .set(Device::getSalinityCompensation, salinityCompensation) + ); + } + + private void clearPendingSolarSalinity(String serialNum) { + if (serialNum == null || serialNum.isBlank()) { + return; + } + com.intc.common.redis.utils.RedisUtils.deleteObject(DeviceDataHandler.PENDING_SOLAR_SALINITY_KEY_PREFIX + serialNum); + } + /** * 修改设备输入电压类型 * diff --git a/intc-modules/intc-iot/src/main/java/com/intc/iot/handler/DeviceDataHandler.java b/intc-modules/intc-iot/src/main/java/com/intc/iot/handler/DeviceDataHandler.java index 85035d4..7e9c898 100644 --- a/intc-modules/intc-iot/src/main/java/com/intc/iot/handler/DeviceDataHandler.java +++ b/intc-modules/intc-iot/src/main/java/com/intc/iot/handler/DeviceDataHandler.java @@ -58,6 +58,8 @@ import java.util.Map; @ConditionalOnBean(IDeviceSensorDataService.class) public class DeviceDataHandler { + public static final String PENDING_SOLAR_SALINITY_KEY_PREFIX = "device:pending:solar:salinity:"; + /** * TDengine 服务,用于存储设备时序数据 */ @@ -955,11 +957,56 @@ public class DeviceDataHandler { log.info("[离线告警] 设备已上线,取消离线告警: {}", deviceName); } + flushPendingSolarSalinity(deviceName); + // 同步更新 Device.warnCode,清除离线和休眠标志位 setDeviceWarnCodeBit(deviceName, DefineDeviceWarnCode.DeviceOffline, false); setDeviceWarnCodeBit(deviceName, DefineDeviceWarnCode.DeviceSleeping, false); } + private void flushPendingSolarSalinity(String deviceName) { + String redisKey = PENDING_SOLAR_SALINITY_KEY_PREFIX + deviceName; + Object rawPending = RedisUtils.getCacheObject(redisKey); + if (rawPending == null) { + return; + } + + try { + JSONObject pending = JSONUtil.parseObj(rawPending); + Double salinityCompensation = pending.getDouble("salinityCompensation"); + String iotId = pending.getStr("iotId"); + Long deviceId = pending.getLong("deviceId"); + if (salinityCompensation == null || iotId == null || deviceId == null) { + log.warn("[太阳能盐度] 缓存数据不完整,跳过补发: deviceName={}, pending={}", deviceName, pending); + return; + } + + Map properties = new HashMap<>(); + properties.put("salinitySet", salinityCompensation); + boolean success = iotCloudService.setProperty(iotId, properties, true, 2); + if (!success) { + log.warn("[太阳能盐度] 上线补发失败,保留缓存: deviceName={}, deviceId={}, salinityCompensation={}", + deviceName, deviceId, salinityCompensation); + return; + } + + Device updateDevice = new Device(); + updateDevice.setId(deviceId); + updateDevice.setSalinityCompensation(salinityCompensation); + int updated = deviceMapper.updateById(updateDevice); + if (updated > 0) { + RedisUtils.deleteObject(redisKey); + log.info("[太阳能盐度] 上线补发成功并清除缓存: deviceName={}, deviceId={}, salinityCompensation={}", + deviceName, deviceId, salinityCompensation); + } else { + log.warn("[太阳能盐度] 上线补发成功但设备表更新失败,保留缓存以便重试: deviceName={}, deviceId={}", + deviceName, deviceId); + } + } catch (Exception e) { + log.error("[太阳能盐度] 上线补发异常: deviceName={}, err={}", deviceName, e.getMessage(), e); + } + } + /** * 太阳能网控设备离线超时:从休眠状态转为真正离线 * 置 DeviceOffline 位,清 DeviceSleeping 位 diff --git a/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/AmqpMessageHandlerImpl.java b/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/AmqpMessageHandlerImpl.java index b6b71b6..c0f2aa6 100644 --- a/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/AmqpMessageHandlerImpl.java +++ b/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/AmqpMessageHandlerImpl.java @@ -50,6 +50,9 @@ public class AmqpMessageHandlerImpl implements AmqpMessageHandler { String topic = json.getStr("topic"); String method = json.getStr("method"); String status = json.getStr("status"); + if (status != null) { + status = status.trim().toLowerCase(); + } // 检查是否是设备上线/下线消息 if (status != null && ("online".equals(status) || "offline".equals(status))) { @@ -215,6 +218,9 @@ public class AmqpMessageHandlerImpl implements AmqpMessageHandler { private void handleStatusMessage(JSONObject json) { String deviceName = json.getStr("deviceName"); String status = json.getStr("status"); + if (status != null) { + status = status.trim().toLowerCase(); + } log.debug("设备状态: {} - {}", deviceName, status); @@ -235,6 +241,9 @@ public class AmqpMessageHandlerImpl implements AmqpMessageHandler { if (action == null) { action = json.getStr("status"); } + if (action != null) { + action = action.trim().toLowerCase(); + } log.debug("设备{}: {}", "online".equals(action) ? "上线" : "下线", deviceName); diff --git a/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/DeviceStatusServiceImpl.java b/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/DeviceStatusServiceImpl.java index 6a1d9ae..3e92e19 100644 --- a/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/DeviceStatusServiceImpl.java +++ b/intc-modules/intc-iot/src/main/java/com/intc/iot/service/impl/DeviceStatusServiceImpl.java @@ -2,11 +2,13 @@ package com.intc.iot.service.impl; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.intc.iot.handler.DeviceDataHandler; import com.intc.iot.domain.IotDeviceStatus; import com.intc.iot.mapper.IotDeviceStatusMapper; import com.intc.iot.service.DeviceStatusService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -28,6 +30,9 @@ public class DeviceStatusServiceImpl implements DeviceStatusService { private final IotDeviceStatusMapper deviceStatusMapper; + @Autowired(required = false) + private DeviceDataHandler deviceDataHandler; + @Override @Transactional(rollbackFor = Exception.class) public void handleStatusChange(Map statusData) { @@ -83,6 +88,10 @@ public class DeviceStatusServiceImpl implements DeviceStatusService { log.info("[设备状态] 新增设备状态记录 - ProductKey: {}, DeviceName: {}, Status: {}", productKey, deviceName, status); } + + if ("online".equalsIgnoreCase(status) && deviceDataHandler != null) { + deviceDataHandler.handleDeviceOnline(deviceName); + } } catch (Exception e) { log.error("[设备状态] 处理设备状态变更异常: {}", e.getMessage(), e); throw e;