diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java index a334a28f..e114b245 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/DeviceServiceImpl.java @@ -701,6 +701,24 @@ public class DeviceServiceImpl implements IDeviceService { eventLogService.saveBatch(eventLogList); } /* ★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 结束 ★★★★★★★★★★★★★★★★★★★★★★*/ + + /* ★★★★★★★★★★★★★★★★★★★★★★ 自动计算依赖物模型 - 开始 ★★★★★★★★★★★★★★★★★★★★★★*/ + // 记录所有已更新的物模型标识符(设备上报的) + Set 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 updatedIdentifiers, + String key, + Map maps, + List deviceLogList, + int type, + boolean isPowerOnTriggerReply) { + try { + // 查询产品下所有物模型 + com.fastbee.iot.domain.ThingsModel queryModel = new com.fastbee.iot.domain.ThingsModel(); + queryModel.setProductId(input.getProductId()); + List 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 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 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); + } + } + }