20260413:支持数据采集页面查看跨设备计算物模型物理量展示
This commit is contained in:
parent
8c9fe1e355
commit
acea720181
@ -17,6 +17,12 @@ import java.util.regex.Pattern;
|
|||||||
*/
|
*/
|
||||||
public class CalculateUtils {
|
public class CalculateUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公式中跨设备引用正则:{slaveId:N.identifier}
|
||||||
|
*/
|
||||||
|
private static final Pattern CROSS_DEVICE_REF = Pattern.compile("\\{slaveId:(\\d+)\\.([^}]+)}");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* /*
|
* /*
|
||||||
* 支持加减乘除、幂运算、取余及括号的应用
|
* 支持加减乘除、幂运算、取余及括号的应用
|
||||||
@ -219,6 +225,25 @@ public class CalculateUtils {
|
|||||||
return isNum.matches();
|
return isNum.matches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析公式中所有跨设备引用占位符
|
||||||
|
*
|
||||||
|
* @param formula 计算公式,形如 {slaveId:1.Ang_z} + {slaveId:2.Ang_z}
|
||||||
|
* @return key=slaveId:N.identifier, value=identifier
|
||||||
|
*/
|
||||||
|
public static Map<String, String> parseCrossDeviceRefs(String formula) {
|
||||||
|
Map<String, String> refs = new LinkedHashMap<>();
|
||||||
|
if (formula == null || formula.isEmpty()) {
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
|
Matcher m = CROSS_DEVICE_REF.matcher(formula);
|
||||||
|
while (m.find()) {
|
||||||
|
String key = "slaveId:" + m.group(1) + "." + m.group(2);
|
||||||
|
refs.put(key, m.group(2));
|
||||||
|
}
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
|
|
||||||
public static String calculateReplace(String str, Map<String, String> map) {
|
public static String calculateReplace(String str, Map<String, String> map) {
|
||||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||||
// 对于包含特殊字符的占位符(如 {identifier}),需要转义正则表达式特殊字符
|
// 对于包含特殊字符的占位符(如 {identifier}),需要转义正则表达式特殊字符
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import com.fastbee.common.core.notify.config.WeChatConfigParams;
|
|||||||
import com.fastbee.common.core.notify.msg.WechatMsgParams;
|
import com.fastbee.common.core.notify.msg.WechatMsgParams;
|
||||||
import com.fastbee.common.core.redis.RedisKeyBuilder;
|
import com.fastbee.common.core.redis.RedisKeyBuilder;
|
||||||
import com.fastbee.common.enums.DataLevelEnum;
|
import com.fastbee.common.enums.DataLevelEnum;
|
||||||
import com.fastbee.common.utils.CalculateUtils;
|
|
||||||
import com.fastbee.common.utils.StringUtils;
|
import com.fastbee.common.utils.StringUtils;
|
||||||
import com.fastbee.common.utils.wechat.WechatUtils;
|
import com.fastbee.common.utils.wechat.WechatUtils;
|
||||||
import com.fastbee.common.wechat.WeChatAppResult;
|
import com.fastbee.common.wechat.WeChatAppResult;
|
||||||
@ -58,8 +57,6 @@ public class ThingsModelPushHandler {
|
|||||||
|
|
||||||
private static final RestTemplate REST_TEMPLATE = new RestTemplate();
|
private static final RestTemplate REST_TEMPLATE = new RestTemplate();
|
||||||
private static final Pattern VAR_PATTERN = Pattern.compile("\\{\\{([^}]+)}}");
|
private static final Pattern VAR_PATTERN = Pattern.compile("\\{\\{([^}]+)}}");
|
||||||
/** 公式中跨设备引用:{slaveId:N.identifier} */
|
|
||||||
private static final Pattern CROSS_DEVICE_REF = Pattern.compile("\\{slaveId:(\\d+)\\.([^}]+)}");
|
|
||||||
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
|
||||||
@ -258,6 +255,7 @@ public class ThingsModelPushHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算网关跨设备计算物模型的当前值(只基于各从机当前缓存值)
|
* 计算网关跨设备计算物模型的当前值(只基于各从机当前缓存值)
|
||||||
|
* 委托 IThingsModelService.computeCrossDeviceCurrentValue 统一计算
|
||||||
*/
|
*/
|
||||||
private ComputedValue tryComputeGatewayCalculatedValue(ThingsModelPushConfig config,
|
private ComputedValue tryComputeGatewayCalculatedValue(ThingsModelPushConfig config,
|
||||||
String gwSerialNumber,
|
String gwSerialNumber,
|
||||||
@ -286,65 +284,16 @@ public class ThingsModelPushHandler {
|
|||||||
model.getIsCalculated() != 1 || StringUtils.isEmpty(model.getFormula())) {
|
model.getIsCalculated() != 1 || StringUtils.isEmpty(model.getFormula())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Map<String, String> refs = parseCrossDeviceRefs(model.getFormula());
|
List<SubDeviceListVO> subDeviceList = subDeviceBySlaveId != null
|
||||||
if (refs.isEmpty()) {
|
? new ArrayList<>(subDeviceBySlaveId.values())
|
||||||
|
: Collections.emptyList();
|
||||||
|
ValueItem result = thingsModelService.computeCrossDeviceCurrentValue(model.getFormula(), subDeviceList);
|
||||||
|
if (result == null) {
|
||||||
|
log.warn("[Push] configId={} sn={} identifier={} 跨设备公式计算失败",
|
||||||
|
config.getId(), gwSerialNumber, identifier);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return new ComputedValue(result.getValue(), result.getTs());
|
||||||
Map<String, String> replaceMap = new HashMap<>();
|
|
||||||
Date maxTs = null;
|
|
||||||
for (Map.Entry<String, String> ref : refs.entrySet()) {
|
|
||||||
String refKey = ref.getKey(); // slaveId:N.identifier
|
|
||||||
int slaveId;
|
|
||||||
try {
|
|
||||||
slaveId = Integer.parseInt(refKey.split("\\.")[0].replace("slaveId:", ""));
|
|
||||||
} catch (Exception e) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SubDeviceListVO sub = subDeviceBySlaveId != null ? subDeviceBySlaveId.get(slaveId) : null;
|
|
||||||
String subSn = sub != null ? sub.getSubDeviceNo() : null;
|
|
||||||
Long subProductId = sub != null ? sub.getSubProductId() : null;
|
|
||||||
String subIdentifier = ref.getValue();
|
|
||||||
String val = "0";
|
|
||||||
if (subProductId != null && StringUtils.isNotEmpty(subSn) && StringUtils.isNotEmpty(subIdentifier)) {
|
|
||||||
try {
|
|
||||||
ValueItem v = thingsModelService.getCacheIdentifierValue(subProductId, subSn, subIdentifier);
|
|
||||||
if (v != null && StringUtils.isNotEmpty(v.getValue())) {
|
|
||||||
val = v.getValue();
|
|
||||||
}
|
|
||||||
if (v != null && v.getTs() != null) {
|
|
||||||
// if (maxTs == null || v.getTs().after(maxTs)) {
|
|
||||||
// maxTs = v.getTs();
|
|
||||||
// }
|
|
||||||
maxTs = v.getTs();
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
replaceMap.put("{" + refKey + "}", val);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Object computed = CalculateUtils.execute(model.getFormula(), replaceMap);
|
|
||||||
String computedStr = computed != null ? computed.toString() : null;
|
|
||||||
return new ComputedValue(computedStr, maxTs);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("[Push] configId={} sn={} identifier={} 公式计算失败 formula={} err={}",
|
|
||||||
config.getId(), gwSerialNumber, identifier, model.getFormula(), e.getMessage());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, String> parseCrossDeviceRefs(String formula) {
|
|
||||||
Map<String, String> refs = new LinkedHashMap<>();
|
|
||||||
if (StringUtils.isEmpty(formula)) {
|
|
||||||
return refs;
|
|
||||||
}
|
|
||||||
Matcher m = CROSS_DEVICE_REF.matcher(formula);
|
|
||||||
while (m.find()) {
|
|
||||||
String key = "slaveId:" + m.group(1) + "." + m.group(2);
|
|
||||||
refs.put(key, m.group(2));
|
|
||||||
}
|
|
||||||
return refs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -163,7 +163,7 @@ public class ToolController extends BaseController {
|
|||||||
@ApiOperation("mqtt认证")
|
@ApiOperation("mqtt认证")
|
||||||
@PostMapping("/mqtt/authv5")
|
@PostMapping("/mqtt/authv5")
|
||||||
public ResponseEntity mqttAuthv5(@RequestBody JSONObject json) throws Exception {
|
public ResponseEntity mqttAuthv5(@RequestBody JSONObject json) throws Exception {
|
||||||
log.info("-----------auth-json:" + json + "---------------");
|
log.info("-----------auth-json:{}---------------", json);
|
||||||
String clientid = json.getString("clientid");
|
String clientid = json.getString("clientid");
|
||||||
String username = json.getString("username");
|
String username = json.getString("username");
|
||||||
String password = json.getString("password");
|
String password = json.getString("password");
|
||||||
@ -173,7 +173,7 @@ public class ToolController extends BaseController {
|
|||||||
if (clientid.startsWith("server")) {
|
if (clientid.startsWith("server")) {
|
||||||
// 服务端认证:配置的账号密码认证
|
// 服务端认证:配置的账号密码认证
|
||||||
if (mqttConfig.getUsername().equals(username) && mqttConfig.getPassword().equals(password)) {
|
if (mqttConfig.getUsername().equals(username) && mqttConfig.getPassword().equals(password)) {
|
||||||
log.info("-----------服务端mqtt认证成功,clientId:" + clientid + "---------------");
|
log.info("-----------服务端mqtt认证成功,clientId:{}---------------", clientid);
|
||||||
ret.put("result", "allow");
|
ret.put("result", "allow");
|
||||||
return ResponseEntity.ok().body(ret);
|
return ResponseEntity.ok().body(ret);
|
||||||
} else {
|
} else {
|
||||||
@ -188,7 +188,7 @@ public class ToolController extends BaseController {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
|
Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
|
||||||
log.info("-----------移动端/Web端mqtt认证成功,clientId:" + clientid + "---------------");
|
log.info("-----------移动端/Web端mqtt认证成功,clientId:{}---------------", clientid);
|
||||||
ret.put("result", "allow");
|
ret.put("result", "allow");
|
||||||
return ResponseEntity.ok().body(ret);
|
return ResponseEntity.ok().body(ret);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
@ -255,7 +255,7 @@ public class ToolController extends BaseController {
|
|||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
log.error("发生错误:" + ex.getMessage());
|
log.error("发生错误:{}", ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ public class ToolController extends BaseController {
|
|||||||
if (peername.indexOf(":") != -1) {
|
if (peername.indexOf(":") != -1) {
|
||||||
ipAddress = peername.substring(0, peername.indexOf(":"));
|
ipAddress = peername.substring(0, peername.indexOf(":"));
|
||||||
}
|
}
|
||||||
log.info("webhook:" + event + ",clientid:" + clientid + ",peername:" + peername);
|
log.info("webhook:{},clientid:{},peername:{}", event, clientid, peername);
|
||||||
// 过滤服务端、web端和手机端
|
// 过滤服务端、web端和手机端
|
||||||
if (clientid.startsWith("server") || clientid.startsWith("web") || clientid.startsWith("phone")) {
|
if (clientid.startsWith("server") || clientid.startsWith("web") || clientid.startsWith("phone")) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -111,6 +111,11 @@ public class ThingsModelDTO extends BaseEntity {
|
|||||||
|
|
||||||
private Integer modelOrder;
|
private Integer modelOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物模型来源类型(0-设备上报,1-纯计算,2-其他预留)
|
||||||
|
*/
|
||||||
|
private Integer isCalculated;
|
||||||
|
|
||||||
private String value = "";
|
private String value = "";
|
||||||
|
|
||||||
private String ts;
|
private String ts;
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import com.fastbee.iot.model.ThingsModelPerm;
|
|||||||
import com.fastbee.iot.model.ThingsModelSimVO;
|
import com.fastbee.iot.model.ThingsModelSimVO;
|
||||||
import com.fastbee.iot.model.ThingsModels.*;
|
import com.fastbee.iot.model.ThingsModels.*;
|
||||||
import com.fastbee.iot.model.dto.ThingsModelDTO;
|
import com.fastbee.iot.model.dto.ThingsModelDTO;
|
||||||
|
import com.fastbee.iot.model.gateWay.SubDeviceListVO;
|
||||||
import com.fastbee.iot.model.modbus.ModbusAndThingsVO;
|
import com.fastbee.iot.model.modbus.ModbusAndThingsVO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -202,4 +203,14 @@ public interface IThingsModelService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<ThingsModel> selectThingsModelBySerialNumber(Long deviceId);
|
List<ThingsModel> selectThingsModelBySerialNumber(Long deviceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算跨设备计算物模型当前值
|
||||||
|
* 从子设备 Redis 缓存获取各引用变量的值,按公式实时计算
|
||||||
|
*
|
||||||
|
* @param formula 物模型公式,含 {slaveId:N.identifier} 占位符
|
||||||
|
* @param subDevices 网关下的子设备列表
|
||||||
|
* @return 计算结果(value + ts),公式无跨设备引用或计算失败时返回 null
|
||||||
|
*/
|
||||||
|
ValueItem computeCrossDeviceCurrentValue(String formula, List<SubDeviceListVO> subDevices);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,8 +21,6 @@ import org.springframework.stereotype.Service;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,8 +56,6 @@ public class DataCenterServiceImpl implements DataCenterService {
|
|||||||
@Resource
|
@Resource
|
||||||
private com.fastbee.iot.cache.ITSLCache itslCache;
|
private com.fastbee.iot.cache.ITSLCache itslCache;
|
||||||
|
|
||||||
/** 公式中跨设备引用:{slaveId:N.identifier} */
|
|
||||||
private static final Pattern CROSS_DEVICE_REF = Pattern.compile("\\{slaveId:(\\d+)\\.([^}]+)\\}");
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<JSONObject> deviceHistory(DeviceHistoryParam deviceHistoryParam) {
|
public List<JSONObject> deviceHistory(DeviceHistoryParam deviceHistoryParam) {
|
||||||
@ -515,13 +511,7 @@ public class DataCenterServiceImpl implements DataCenterService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, String> parseCrossDeviceRefs(String formula) {
|
private Map<String, String> parseCrossDeviceRefs(String formula) {
|
||||||
Map<String, String> refs = new LinkedHashMap<>();
|
return CalculateUtils.parseCrossDeviceRefs(formula);
|
||||||
Matcher m = CROSS_DEVICE_REF.matcher(formula);
|
|
||||||
while (m.find()) {
|
|
||||||
String key = "slaveId:" + m.group(1) + "." + m.group(2);
|
|
||||||
refs.put(key, m.group(2));
|
|
||||||
}
|
|
||||||
return refs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Date> buildMinuteSlots(String beginTime, String endTime) {
|
private List<Date> buildMinuteSlots(String beginTime, String endTime) {
|
||||||
|
|||||||
@ -2030,11 +2030,38 @@ public class DeviceServiceImpl implements IDeviceService {
|
|||||||
}
|
}
|
||||||
list.addAll(subList);
|
list.addAll(subList);
|
||||||
}
|
}
|
||||||
|
// 对跨设备计算物模型(isCalculated=1,公式含 slaveId 引用)实时计算当前值
|
||||||
|
computeCrossDeviceValuesForList(list, subDeviceListVOList);
|
||||||
// 指令控制
|
// 指令控制
|
||||||
jurisdictionThingsModel(list, deviceId);
|
jurisdictionThingsModel(list, deviceId);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对列表中所有跨设备计算物模型实时计算当前值(从子设备缓存取值,按公式计算)
|
||||||
|
*/
|
||||||
|
private void computeCrossDeviceValuesForList(List<ThingsModelDTO> list, List<SubDeviceListVO> subDevices) {
|
||||||
|
if (org.springframework.util.CollectionUtils.isEmpty(subDevices)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (ThingsModelDTO dto : list) {
|
||||||
|
if (!Integer.valueOf(1).equals(dto.getIsCalculated())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String formula = dto.getFormula();
|
||||||
|
if (StringUtils.isEmpty(formula) || !formula.contains("slaveId:")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ValueItem result = thingsModelService.computeCrossDeviceCurrentValue(formula, subDevices);
|
||||||
|
if (result != null && StringUtils.isNotEmpty(result.getValue())) {
|
||||||
|
dto.setValue(result.getValue());
|
||||||
|
if (result.getTs() != null) {
|
||||||
|
dto.setTs(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, result.getTs()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void jurisdictionThingsModel(List<ThingsModelDTO> list, Long deviceId) {
|
private void jurisdictionThingsModel(List<ThingsModelDTO> list, Long deviceId) {
|
||||||
Long userId = SecurityUtils.getUserId();
|
Long userId = SecurityUtils.getUserId();
|
||||||
// 查询是否有指令控制
|
// 查询是否有指令控制
|
||||||
|
|||||||
@ -9,9 +9,11 @@ import com.fastbee.common.core.redis.RedisCache;
|
|||||||
import com.fastbee.common.core.redis.RedisKeyBuilder;
|
import com.fastbee.common.core.redis.RedisKeyBuilder;
|
||||||
import com.fastbee.common.enums.scenemodel.SceneModelVariableTypeEnum;
|
import com.fastbee.common.enums.scenemodel.SceneModelVariableTypeEnum;
|
||||||
import com.fastbee.common.exception.ServiceException;
|
import com.fastbee.common.exception.ServiceException;
|
||||||
|
import com.fastbee.common.utils.CalculateUtils;
|
||||||
import com.fastbee.common.utils.DateUtils;
|
import com.fastbee.common.utils.DateUtils;
|
||||||
import com.fastbee.common.utils.SecurityUtils;
|
import com.fastbee.common.utils.SecurityUtils;
|
||||||
import com.fastbee.common.utils.StringUtils;
|
import com.fastbee.common.utils.StringUtils;
|
||||||
|
import com.fastbee.iot.model.gateWay.SubDeviceListVO;
|
||||||
import com.fastbee.iot.cache.ITSLCache;
|
import com.fastbee.iot.cache.ITSLCache;
|
||||||
import com.fastbee.iot.domain.*;
|
import com.fastbee.iot.domain.*;
|
||||||
import com.fastbee.iot.mapper.*;
|
import com.fastbee.iot.mapper.*;
|
||||||
@ -646,6 +648,8 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
otherThingsModel.setDatatype(datatype);
|
otherThingsModel.setDatatype(datatype);
|
||||||
otherThingsModel.setModelOrder(thingsModel.getModelOrder());
|
otherThingsModel.setModelOrder(thingsModel.getModelOrder());
|
||||||
otherThingsModel.setCreateTime(thingsModel.getCreateTime());
|
otherThingsModel.setCreateTime(thingsModel.getCreateTime());
|
||||||
|
otherThingsModel.setFormula(thingsModel.getFormula());
|
||||||
|
otherThingsModel.setIsCalculated(thingsModel.getIsCalculated());
|
||||||
resultList.add(otherThingsModel);
|
resultList.add(otherThingsModel);
|
||||||
}
|
}
|
||||||
return resultList;
|
return resultList;
|
||||||
@ -766,6 +770,50 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
return thingsModelMapper.selectThingsModelBySerialNumber(deviceId, SecurityUtils.getLanguage());
|
return thingsModelMapper.selectThingsModelBySerialNumber(deviceId, SecurityUtils.getLanguage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueItem computeCrossDeviceCurrentValue(String formula, List<SubDeviceListVO> subDevices) {
|
||||||
|
Map<String, String> refs = CalculateUtils.parseCrossDeviceRefs(formula);
|
||||||
|
if (refs.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Map<String, String> replaceMap = new HashMap<>();
|
||||||
|
Date maxTs = null;
|
||||||
|
for (Map.Entry<String, String> ref : refs.entrySet()) {
|
||||||
|
String refKey = ref.getKey(); // slaveId:N.identifier
|
||||||
|
int slaveId;
|
||||||
|
try {
|
||||||
|
slaveId = Integer.parseInt(refKey.split("\\.")[0].replace("slaveId:", ""));
|
||||||
|
} catch (Exception e) {
|
||||||
|
replaceMap.put("{" + refKey + "}", "0");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SubDeviceListVO sub = subDevices.stream()
|
||||||
|
.filter(s -> s.getSlaveId() != null && s.getSlaveId() == slaveId)
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
if (sub == null || sub.getSubProductId() == null || StringUtils.isEmpty(sub.getSubDeviceNo())) {
|
||||||
|
replaceMap.put("{" + refKey + "}", "0");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String subIdentifier = ref.getValue();
|
||||||
|
ValueItem v = this.getCacheIdentifierValue(sub.getSubProductId(), sub.getSubDeviceNo(), subIdentifier);
|
||||||
|
String val = (v != null && StringUtils.isNotEmpty(v.getValue())) ? v.getValue() : "0";
|
||||||
|
replaceMap.put("{" + refKey + "}", val);
|
||||||
|
if (v != null && v.getTs() != null) {
|
||||||
|
maxTs = v.getTs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Object computed = CalculateUtils.execute(formula, replaceMap);
|
||||||
|
ValueItem result = new ValueItem();
|
||||||
|
result.setValue(computed != null ? computed.toString() : "");
|
||||||
|
result.setTs(maxTs);
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("[ThingsModel] 跨设备公式计算失败 formula={} err={}", formula, e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private ThingsModel propertyDtoChangeThingsModel(ThingsModelValueItem valueItem) {
|
private ThingsModel propertyDtoChangeThingsModel(ThingsModelValueItem valueItem) {
|
||||||
ThingsModel thingsModel = new ThingsModel();
|
ThingsModel thingsModel = new ThingsModel();
|
||||||
thingsModel.setIdentifier(valueItem.getId());
|
thingsModel.setIdentifier(valueItem.getId());
|
||||||
@ -779,6 +827,8 @@ public class ThingsModelServiceImpl implements IThingsModelService {
|
|||||||
thingsModel.setType(valueItem.getType());
|
thingsModel.setType(valueItem.getType());
|
||||||
thingsModel.setModelId(valueItem.getModelId());
|
thingsModel.setModelId(valueItem.getModelId());
|
||||||
thingsModel.setCreateTime(valueItem.getCreateTime());
|
thingsModel.setCreateTime(valueItem.getCreateTime());
|
||||||
|
thingsModel.setFormula(valueItem.getFormula());
|
||||||
|
thingsModel.setIsCalculated(valueItem.getIsCalculated());
|
||||||
return thingsModel;
|
return thingsModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user