20251223:物模型支持计算(以另一个物模型上报数据计算得出)

This commit is contained in:
George 2025-12-23 08:40:13 +08:00
parent 898687ea09
commit 7e612e03eb

View File

@ -701,6 +701,24 @@ public class DeviceServiceImpl implements IDeviceService {
eventLogService.saveBatch(eventLogList);
}
/* ★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 结束 ★★★★★★★★★★★★★★★★★★★★★★*/
/* ★★★★★★★★★★★★★★★★★★★★★★ 自动计算依赖物模型 - 开始 ★★★★★★★★★★★★★★★★★★★★★★*/
// 记录所有已更新的物模型标识符(设备上报的)
Set<String> updatedIdentifiers = new HashSet<>();
for (ThingsModelSimpleItem item : input.getThingsModelValueRemarkItem()) {
String identity = item.getId();
if (identity.startsWith("array_")) {
identity = identity.substring(9);
}
updatedIdentifiers.add(identity);
}
// 自动计算依赖已更新物模型的其他物模型(纯计算型物模型)
if (!updatedIdentifiers.isEmpty() && !isShadow) {
calculateDependentThingsModels(input, updatedIdentifiers, key, maps, deviceLogList, type, isPowerOnTriggerReply);
}
/* ★★★★★★★★★★★★★★★★★★★★★★ 自动计算依赖物模型 - 结束 ★★★★★★★★★★★★★★★★★★★★★★*/
return list;
}
@ -2102,4 +2120,158 @@ public class DeviceServiceImpl implements IDeviceService {
}
}
/**
* 自动计算依赖已更新物模型的其他物模型(纯计算型物模型)
* 当设备只上报频率时,自动计算依赖频率的压力等物模型
*
* @param input 设备上报数据输入
* @param updatedIdentifiers 已更新的物模型标识符集合(设备上报的)
* @param key Redis缓存key
* @param maps 物模型值映射(用于批量更新缓存)
* @param deviceLogList 设备日志列表(用于存储历史数据)
* @param type 物模型类型(1=属性,2=功能,3=事件)
* @param isPowerOnTriggerReply 是否是设备上电触发回包
*/
private void calculateDependentThingsModels(ThingsModelValuesInput input,
Set<String> updatedIdentifiers,
String key,
Map<String, String> maps,
List<DeviceLog> deviceLogList,
int type,
boolean isPowerOnTriggerReply) {
try {
// 查询产品下所有物模型
com.fastbee.iot.domain.ThingsModel queryModel = new com.fastbee.iot.domain.ThingsModel();
queryModel.setProductId(input.getProductId());
List<com.fastbee.iot.domain.ThingsModel> allThingsModels = thingsModelService.selectThingsModelList(queryModel);
if (CollectionUtils.isEmpty(allThingsModels)) {
return;
}
// 获取设备信息(用于存储历史数据)
Device device = this.selectDeviceBySerialNumber(input.getDeviceNumber());
if (device == null) {
log.warn("=>自动计算依赖物模型时,设备不存在[{}]", input.getDeviceNumber());
return;
}
// 遍历所有物模型,找出依赖已更新物模型的计算型物模型
for (com.fastbee.iot.domain.ThingsModel thingsModel : allThingsModels) {
String dependentIdentifier = thingsModel.getIdentifier();
// 跳过已更新的物模型(设备已上报的)
if (updatedIdentifiers.contains(dependentIdentifier)) {
continue;
}
// 只处理有计算公式的物模型
String formula = thingsModel.getFormula();
if (StringUtils.isEmpty(formula)) {
continue;
}
// 检查计算公式是否引用了已更新的物模型
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\{([^}]+)\\}");
java.util.regex.Matcher matcher = pattern.matcher(formula);
Set<String> referencedIdentifiers = new HashSet<>();
while (matcher.find()) {
String identifier = matcher.group(1);
referencedIdentifiers.add(identifier);
}
// 检查是否至少引用了一个已更新的物模型
boolean hasDependency = false;
for (String refIdentifier : referencedIdentifiers) {
if (updatedIdentifiers.contains(refIdentifier)) {
hasDependency = true;
break;
}
}
// 如果没有依赖已更新的物模型,跳过
if (!hasDependency) {
continue;
}
// 检查所有引用的物模型是否都有值(从缓存中获取)
Map<String, String> params = new HashMap<>();
for (String refIdentifier : referencedIdentifiers) {
try {
ValueItem refValueItem = itslValueCache.getCacheIdentifier(
input.getProductId(),
input.getDeviceNumber(),
refIdentifier
);
if (refValueItem != null && StringUtils.isNotEmpty(refValueItem.getValue())) {
params.put("{" + refIdentifier + "}", refValueItem.getValue());
} else {
// 如果引用的物模型值不存在,使用0作为默认值
params.put("{" + refIdentifier + "}", "0");
log.warn("=>自动计算依赖物模型时,引用的物模型值不存在[{}],标识符:[{}],使用默认值0",
input.getProductId(), refIdentifier);
// 如果依赖的物模型没有值,仍然尝试计算(使用默认值0)
}
} catch (Exception e) {
log.error("=>自动计算依赖物模型时,获取引用的物模型值失败[{}],标识符:[{}],错误:{}",
input.getProductId(), refIdentifier, e.getMessage());
params.put("{" + refIdentifier + "}", "0");
}
}
// 如果公式中有 %s,使用0作为默认值(因为这是纯计算型物模型,没有设备上报的原始值)
if (formula.contains("%s")) {
params.put("%s", "0");
}
// 执行计算
String calculatedValue;
try {
calculatedValue = String.valueOf(CaculateUtils.execute(formula, params));
} catch (Exception e) {
log.error("=>自动计算依赖物模型时,计算公式执行失败[{}],标识符:[{}],公式:[{}],错误:{}",
input.getProductId(), dependentIdentifier, formula, e.getMessage());
continue;
}
// 更新缓存
ValueItem valueItem = new ValueItem();
valueItem.setId(dependentIdentifier);
valueItem.setValue(calculatedValue);
valueItem.setShadow(calculatedValue);
valueItem.setTs(DateUtils.getNowDate());
maps.put(dependentIdentifier, JSONObject.toJSONString(valueItem));
// 获取物模型详细信息(用于存储历史数据)
ThingsModelValueItem thingModelValue = thingsModelService.getSingleThingModels(
input.getProductId(), dependentIdentifier);
if (thingModelValue != null && thingModelValue.getType() == 1 && thingModelValue.getIsHistory() == 1) {
// 存储历史数据(仅属性类型且启用了历史存储)
DeviceLog deviceLog = new DeviceLog();
deviceLog.setSerialNumber(input.getDeviceNumber());
deviceLog.setLogType(type);
deviceLog.setMode(2); // 在线模式
deviceLog.setLogValue(calculatedValue);
deviceLog.setRemark("自动计算"); // 标记为自动计算
deviceLog.setIdentity(dependentIdentifier);
deviceLog.setCreateTime(DateUtils.getNowDate());
deviceLog.setUserId(device.getTenantId());
deviceLog.setUserName(device.getTenantName());
deviceLog.setTenantId(device.getTenantId());
deviceLog.setTenantName(device.getTenantName());
deviceLog.setModelName(thingModelValue.getName());
deviceLog.setIsMonitor(thingModelValue.getIsMonitor());
deviceLogList.add(deviceLog);
}
log.debug("=>自动计算依赖物模型成功[{}],标识符:[{}],计算公式:[{}],计算结果:[{}]",
input.getProductId(), dependentIdentifier, formula, calculatedValue);
}
} catch (Exception e) {
log.error("=>自动计算依赖物模型时发生异常[{}],设备编号:[{}],错误:{}",
input.getProductId(), input.getDeviceNumber(), e.getMessage(), e);
}
}
}