fix:太阳能网控下发盐度设置,增加30分钟冻结。
This commit is contained in:
@@ -2084,6 +2084,7 @@ public class IotController extends BaseController {
|
||||
return R.fail("盐度缓存失败,请稍后重试");
|
||||
}
|
||||
updateDeviceSalinityCompensation(device.getId(), request.getSalinityCompensation());
|
||||
setSalinityFreeze(device.getSerialNum(), request.getSalinityCompensation());
|
||||
log.info("太阳能网控盐度已缓存: userId={}, deviceId={}, deviceName={}, serialNum={}, salinityCompensation={}‰",
|
||||
userId, device.getId(), device.getDeviceName(), device.getSerialNum(), request.getSalinityCompensation());
|
||||
return R.ok("设置成功");
|
||||
@@ -2147,6 +2148,24 @@ public class IotController extends BaseController {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置盐度冻结标记,30分钟内阻止设备上报的旧值回写 DB
|
||||
*
|
||||
* @param serialNum 设备序列号
|
||||
* @param salinityCompensation 用户设定的盐度值
|
||||
*/
|
||||
private void setSalinityFreeze(String serialNum, Double salinityCompensation) {
|
||||
if (serialNum != null && !serialNum.isBlank() && salinityCompensation != null) {
|
||||
com.intc.common.redis.utils.RedisUtils.setCacheObject(
|
||||
DeviceDataHandler.SALINITY_SET_FREEZE_KEY_PREFIX + serialNum,
|
||||
salinityCompensation,
|
||||
Duration.ofMinutes(DeviceDataHandler.SALINITY_FREEZE_MINUTES)
|
||||
);
|
||||
log.info("[盐度冻结] 已设置冻结标记: serialNum={}, value={}, freezeMinutes={}",
|
||||
serialNum, salinityCompensation, DeviceDataHandler.SALINITY_FREEZE_MINUTES);
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "太阳能网控属性下发")
|
||||
@SaCheckPermission("fishery:solarControl:command")
|
||||
@PostMapping("/device/solar/property-command")
|
||||
@@ -2203,6 +2222,9 @@ public class IotController extends BaseController {
|
||||
return R.fail("指令缓存失败,请稍后重试");
|
||||
}
|
||||
syncDeviceFieldsAfterSolarCommand(device.getId(), properties);
|
||||
if (properties.containsKey("salinitySet")) {
|
||||
setSalinityFreeze(device.getSerialNum(), toDouble(properties.get("salinitySet")));
|
||||
}
|
||||
result.put("mode", "cached");
|
||||
result.put("cached", true);
|
||||
result.put("sent", false);
|
||||
@@ -2232,6 +2254,9 @@ public class IotController extends BaseController {
|
||||
|
||||
syncDeviceFieldsAfterSolarCommand(device.getId(), properties);
|
||||
removePendingSolarProperties(device, properties.keySet());
|
||||
if (properties.containsKey("salinitySet")) {
|
||||
setSalinityFreeze(device.getSerialNum(), toDouble(properties.get("salinitySet")));
|
||||
}
|
||||
|
||||
result.put("mode", "direct");
|
||||
result.put("cached", false);
|
||||
|
||||
@@ -72,6 +72,18 @@ public class DeviceDataHandler {
|
||||
*/
|
||||
private static final long SOLAR_PROPERTY_DELAY_MS = 5000L;
|
||||
|
||||
/**
|
||||
* 盐度设定防回写冻结标记 Redis key 前缀
|
||||
* value = 用户设定的盐度值,TTL = {@link #SALINITY_FREEZE_MINUTES} 分钟
|
||||
* 用户修改盐度后写入此标记,冻结期内设备上报的旧值不会回写 DB,避免客户误判修改未生效
|
||||
*/
|
||||
public static final String SALINITY_SET_FREEZE_KEY_PREFIX = "device:salinity:set:freeze:";
|
||||
|
||||
/**
|
||||
* 盐度设定冻结时长(分钟),与设备上报周期匹配,超时后恢复正常回写逻辑
|
||||
*/
|
||||
public static final int SALINITY_FREEZE_MINUTES = 30;
|
||||
|
||||
/**
|
||||
* TDengine 服务,用于存储设备时序数据
|
||||
*/
|
||||
@@ -1058,6 +1070,8 @@ public class DeviceDataHandler {
|
||||
}
|
||||
|
||||
syncDeviceFieldsAfterPropertySet(pendingProperty.deviceId, pendingProperty.properties);
|
||||
// 补发成功后,如果包含盐度设定,写入冻结标记
|
||||
setSalinityFreezeIfNeeded(deviceName, pendingProperty.properties);
|
||||
clearPendingSolarProperty(pendingProperty);
|
||||
log.info("[太阳能属性] {}补发成功并清除缓存: deviceName={}, cacheKey={}, deviceId={}, properties={}",
|
||||
trigger, deviceName, pendingProperty.redisKey, pendingProperty.deviceId, pendingProperty.properties);
|
||||
@@ -1204,6 +1218,27 @@ public class DeviceDataHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果属性中包含 salinitySet,写入盐度冻结标记到 Redis
|
||||
* 冻结期内设备上报的旧值不会被回写 DB
|
||||
*
|
||||
* @param deviceName 设备名称(serialNum)
|
||||
* @param properties 下发的属性
|
||||
*/
|
||||
private void setSalinityFreezeIfNeeded(String deviceName, Map<String, Object> properties) {
|
||||
if (StrUtil.isBlank(deviceName) || properties == null || !properties.containsKey("salinitySet")) {
|
||||
return;
|
||||
}
|
||||
Double value = toDouble(properties.get("salinitySet"));
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
String freezeKey = SALINITY_SET_FREEZE_KEY_PREFIX + deviceName;
|
||||
RedisUtils.setCacheObject(freezeKey, value, Duration.ofMinutes(SALINITY_FREEZE_MINUTES));
|
||||
log.info("[盐度冻结] 已设置冻结标记: deviceName={}, value={}, freezeMinutes={}",
|
||||
deviceName, value, SALINITY_FREEZE_MINUTES);
|
||||
}
|
||||
|
||||
private static class PendingSolarProperty {
|
||||
private final String redisKey;
|
||||
private final Long deviceId;
|
||||
@@ -2877,6 +2912,25 @@ public class DeviceDataHandler {
|
||||
if ("salinitySet".equals(k)) {
|
||||
Double salinitySet = params.getDouble(k);
|
||||
if (salinitySet != null) {
|
||||
// === 盐度冻结检查:用户修改盐度后30分钟内,忽略设备上报的旧值回写 ===
|
||||
String freezeKey = SALINITY_SET_FREEZE_KEY_PREFIX + deviceName;
|
||||
Object freezeObj = RedisUtils.getCacheObject(freezeKey);
|
||||
if (freezeObj != null) {
|
||||
Double frozenValue = toDouble(freezeObj);
|
||||
if (frozenValue != null && Math.abs(salinitySet - frozenValue) < 0.01) {
|
||||
// 上报值与冻结值一致,设备已跟上新设置,提前解冻
|
||||
RedisUtils.deleteObject(freezeKey);
|
||||
log.info("[盐度冻结] 设备上报值={} 与冻结值={} 一致,提前解冻: deviceName={}",
|
||||
salinitySet, frozenValue, deviceName);
|
||||
} else {
|
||||
// 冻结期内上报值与设定值不一致,跳过回写避免误导
|
||||
log.debug("[盐度冻结] 冻结期内跳过设备旧值回写: deviceName={}, reportValue={}, frozenValue={}",
|
||||
deviceName, salinitySet, frozenValue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// === 冻结检查结束 ===
|
||||
|
||||
try {
|
||||
Device device = deviceMapper.selectOne(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Device>()
|
||||
|
||||
Reference in New Issue
Block a user