fix: 盐度补偿设定,太阳能网控缓存逻辑修改完善。
This commit is contained in:
@@ -63,6 +63,7 @@ import java.util.Date;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -2034,55 +2035,104 @@ public class IotController extends BaseController {
|
|||||||
return R.fail("设备已到期");
|
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) {
|
if (iotDeviceService == null) {
|
||||||
return R.fail("飞燕平台配置未启用");
|
return R.fail("飞燕平台配置未启用");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> deviceDetail = iotDeviceService.queryDeviceInfo(device.getIotId());
|
try {
|
||||||
if (deviceDetail != null && deviceDetail.get("data") != null) {
|
Map<String, Object> deviceDetail = iotDeviceService.queryDeviceInfo(device.getIotId());
|
||||||
try {
|
if (deviceDetail != null && deviceDetail.get("data") != null) {
|
||||||
Object detailData = deviceDetail.get("data");
|
try {
|
||||||
java.lang.reflect.Method getStatusMethod = detailData.getClass().getMethod("getStatus");
|
Object detailData = deviceDetail.get("data");
|
||||||
Object statusObj = getStatusMethod.invoke(detailData);
|
java.lang.reflect.Method getStatusMethod = detailData.getClass().getMethod("getStatus");
|
||||||
if (statusObj != null) {
|
Object statusObj = getStatusMethod.invoke(detailData);
|
||||||
String statusStr = statusObj.toString();
|
if (statusObj != null) {
|
||||||
if ("OFFLINE".equalsIgnoreCase(statusStr) || "offline".equals(statusStr)) {
|
String statusStr = statusObj.toString();
|
||||||
return R.fail("设备离线或断电");
|
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("设备状态查询失败,请稍后重试");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置盐度补偿属性
|
if (!pushSalinitySetting(device.getIotId(), request.getSalinityCompensation())) {
|
||||||
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"))) {
|
|
||||||
return R.fail("设置盐度补偿失败,请重试");
|
return R.fail("设置盐度补偿失败,请重试");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新设备盐度补偿值
|
updateDeviceSalinityCompensation(device.getId(), request.getSalinityCompensation());
|
||||||
deviceMapper.update(null,
|
clearPendingSolarSalinity(device.getSerialNum());
|
||||||
new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<Device>()
|
|
||||||
.eq(Device::getId, request.getId())
|
|
||||||
.set(Device::getSalinityCompensation, request.getSalinityCompensation())
|
|
||||||
);
|
|
||||||
|
|
||||||
log.info("设置盐度补偿成功: userId={}, deviceId={}, deviceName={}, serialNum={}, salinityCompensation={}‰",
|
log.info("设置盐度补偿成功: userId={}, deviceId={}, deviceName={}, serialNum={}, salinityCompensation={}‰",
|
||||||
userId, device.getId(), device.getDeviceName(), device.getSerialNum(), request.getSalinityCompensation());
|
userId, device.getId(), device.getDeviceName(), device.getSerialNum(), request.getSalinityCompensation());
|
||||||
|
|
||||||
return R.ok();
|
return R.ok("设置成功");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("设置盐度补償失败: {}", e.getMessage(), e);
|
log.error("设置盐度补償失败: {}", e.getMessage(), e);
|
||||||
return R.fail("设置盐度补償失败: " + e.getMessage());
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改设备输入电压类型
|
* 修改设备输入电压类型
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ import java.util.Map;
|
|||||||
@ConditionalOnBean(IDeviceSensorDataService.class)
|
@ConditionalOnBean(IDeviceSensorDataService.class)
|
||||||
public class DeviceDataHandler {
|
public class DeviceDataHandler {
|
||||||
|
|
||||||
|
public static final String PENDING_SOLAR_SALINITY_KEY_PREFIX = "device:pending:solar:salinity:";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TDengine 服务,用于存储设备时序数据
|
* TDengine 服务,用于存储设备时序数据
|
||||||
*/
|
*/
|
||||||
@@ -955,11 +957,56 @@ public class DeviceDataHandler {
|
|||||||
log.info("[离线告警] 设备已上线,取消离线告警: {}", deviceName);
|
log.info("[离线告警] 设备已上线,取消离线告警: {}", deviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flushPendingSolarSalinity(deviceName);
|
||||||
|
|
||||||
// 同步更新 Device.warnCode,清除离线和休眠标志位
|
// 同步更新 Device.warnCode,清除离线和休眠标志位
|
||||||
setDeviceWarnCodeBit(deviceName, DefineDeviceWarnCode.DeviceOffline, false);
|
setDeviceWarnCodeBit(deviceName, DefineDeviceWarnCode.DeviceOffline, false);
|
||||||
setDeviceWarnCodeBit(deviceName, DefineDeviceWarnCode.DeviceSleeping, 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 位
|
* 置 DeviceOffline 位,清 DeviceSleeping 位
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ public class AmqpMessageHandlerImpl implements AmqpMessageHandler {
|
|||||||
String topic = json.getStr("topic");
|
String topic = json.getStr("topic");
|
||||||
String method = json.getStr("method");
|
String method = json.getStr("method");
|
||||||
String status = json.getStr("status");
|
String status = json.getStr("status");
|
||||||
|
if (status != null) {
|
||||||
|
status = status.trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否是设备上线/下线消息
|
// 检查是否是设备上线/下线消息
|
||||||
if (status != null && ("online".equals(status) || "offline".equals(status))) {
|
if (status != null && ("online".equals(status) || "offline".equals(status))) {
|
||||||
@@ -215,6 +218,9 @@ public class AmqpMessageHandlerImpl implements AmqpMessageHandler {
|
|||||||
private void handleStatusMessage(JSONObject json) {
|
private void handleStatusMessage(JSONObject json) {
|
||||||
String deviceName = json.getStr("deviceName");
|
String deviceName = json.getStr("deviceName");
|
||||||
String status = json.getStr("status");
|
String status = json.getStr("status");
|
||||||
|
if (status != null) {
|
||||||
|
status = status.trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
log.debug("设备状态: {} - {}", deviceName, status);
|
log.debug("设备状态: {} - {}", deviceName, status);
|
||||||
|
|
||||||
@@ -235,6 +241,9 @@ public class AmqpMessageHandlerImpl implements AmqpMessageHandler {
|
|||||||
if (action == null) {
|
if (action == null) {
|
||||||
action = json.getStr("status");
|
action = json.getStr("status");
|
||||||
}
|
}
|
||||||
|
if (action != null) {
|
||||||
|
action = action.trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
log.debug("设备{}: {}", "online".equals(action) ? "上线" : "下线", deviceName);
|
log.debug("设备{}: {}", "online".equals(action) ? "上线" : "下线", deviceName);
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package com.intc.iot.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.intc.iot.handler.DeviceDataHandler;
|
||||||
import com.intc.iot.domain.IotDeviceStatus;
|
import com.intc.iot.domain.IotDeviceStatus;
|
||||||
import com.intc.iot.mapper.IotDeviceStatusMapper;
|
import com.intc.iot.mapper.IotDeviceStatusMapper;
|
||||||
import com.intc.iot.service.DeviceStatusService;
|
import com.intc.iot.service.DeviceStatusService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -28,6 +30,9 @@ public class DeviceStatusServiceImpl implements DeviceStatusService {
|
|||||||
|
|
||||||
private final IotDeviceStatusMapper deviceStatusMapper;
|
private final IotDeviceStatusMapper deviceStatusMapper;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private DeviceDataHandler deviceDataHandler;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void handleStatusChange(Map<String, Object> statusData) {
|
public void handleStatusChange(Map<String, Object> statusData) {
|
||||||
@@ -83,6 +88,10 @@ public class DeviceStatusServiceImpl implements DeviceStatusService {
|
|||||||
log.info("[设备状态] 新增设备状态记录 - ProductKey: {}, DeviceName: {}, Status: {}",
|
log.info("[设备状态] 新增设备状态记录 - ProductKey: {}, DeviceName: {}, Status: {}",
|
||||||
productKey, deviceName, status);
|
productKey, deviceName, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("online".equalsIgnoreCase(status) && deviceDataHandler != null) {
|
||||||
|
deviceDataHandler.handleDeviceOnline(deviceName);
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("[设备状态] 处理设备状态变更异常: {}", e.getMessage(), e);
|
log.error("[设备状态] 处理设备状态变更异常: {}", e.getMessage(), e);
|
||||||
throw e;
|
throw e;
|
||||||
|
|||||||
Reference in New Issue
Block a user