fix:太阳能网控下发盐度设置,增加30分钟冻结。

This commit is contained in:
tianyongbao
2026-07-01 23:02:48 +08:00
parent 6b8b4c5499
commit 4207a6582f
2 changed files with 79 additions and 0 deletions

View File

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

View File

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