fix: 盐度补偿设定,太阳能网控缓存逻辑修改完善。

This commit is contained in:
tianyongbao
2026-06-28 22:52:03 +08:00
parent 0e9e73f922
commit fe73e158bd
4 changed files with 142 additions and 27 deletions

View File

@@ -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<String, Object> 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<String, Object> 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<String, Object> properties = new java.util.HashMap<>();
properties.put("salinitySet", request.getSalinityCompensation());
String propertiesJson = cn.hutool.json.JSONUtil.toJsonStr(properties);
Map<String, Object> 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<Device>()
.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<String, Object> properties = new java.util.HashMap<>();
properties.put("salinitySet", salinityCompensation);
String propertiesJson = cn.hutool.json.JSONUtil.toJsonStr(properties);
Map<String, Object> 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<String, Object> 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<Device>()
.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);
}
/**
* 修改设备输入电压类型
*

View File

@@ -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<String, Object> 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 位

View File

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

View File

@@ -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<String, Object> 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;