diff --git a/fastbee-iot-data/src/main/java/com/fastbee/iot/data/executor/ConditionTriggerTaskExecutor.java b/fastbee-iot-data/src/main/java/com/fastbee/iot/data/executor/ConditionTriggerTaskExecutor.java new file mode 100644 index 00000000..92f87225 --- /dev/null +++ b/fastbee-iot-data/src/main/java/com/fastbee/iot/data/executor/ConditionTriggerTaskExecutor.java @@ -0,0 +1,218 @@ +package com.fastbee.iot.data.executor; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.fastbee.common.constant.FastBeeConstant; +import com.fastbee.common.core.mq.message.DeviceMessage; +import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem; +import com.fastbee.common.utils.StringUtils; +import com.fastbee.iot.data.service.IDeviceMessageService; +import com.fastbee.iot.domain.ModbusJob; +import com.fastbee.iot.service.IModbusJobService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * 条件触发任务执行器(cycleType=4) + *

+ * 每次设备上报属性/功能数据时,检查是否存在满足条件的 Modbus 任务, + * 满足则立即下发对应的 Modbus 指令(与上电触发使用同一套指令下发通道)。 + *

+ * 条件存储在 {@code iot_modbus_job.remark} 字段中,JSON 格式: + *

{"identifier":"temp","operator":">","value":"50"}
+ * 支持的 operator:{@code = != > < >= <=} + * + * @author Sumuxi + */ +@Slf4j +@Component +public class ConditionTriggerTaskExecutor { + + @Resource + private IModbusJobService modbusJobService; + + @Resource + private IDeviceMessageService deviceMessageService; + + /** + * 异步检查并执行条件触发任务。 + * 由 {@code DataHandlerImpl.reportData()} 在每次属性/功能上报后调用。 + * + * @param serialNumber 上报数据的设备编号(子设备或直连设备) + * @param thingsModelSimpleItems 本次上报的物模型值列表 + */ + @Async(FastBeeConstant.TASK.TRIGGER_POWER_ON_TASK_ASYNC) + public void checkAndTrigger(String serialNumber, List thingsModelSimpleItems) { + if (StringUtils.isEmpty(serialNumber) || CollectionUtils.isEmpty(thingsModelSimpleItems)) { + return; + } + + // 查询该设备所有状态正常的条件触发任务 + ModbusJob query = new ModbusJob(); + query.setSubSerialNumber(serialNumber); + query.setStatus("0"); + query.setCycleType(4); + List jobList = modbusJobService.selectModbusJobList(query); + if (CollectionUtils.isEmpty(jobList)) { + return; + } + + for (ModbusJob job : jobList) { + try { + if (isConditionMet(job, thingsModelSimpleItems)) { + dispatchCommand(serialNumber, job); + } + } catch (Exception e) { + log.error("[条件触发] 执行异常,设备:{},任务ID:{}", serialNumber, job.getTaskId(), e); + } + } + } + + /** + * 判断本次上报数据是否满足任务配置的条件。 + *

+ * 支持两种 remark 格式: + *

+ * logic 为 "or" 时任一条件满足即触发;默认("and")要求全部满足。 + */ + private boolean isConditionMet(ModbusJob job, List thingsModelSimpleItems) { + String remark = job.getRemark(); + if (StringUtils.isEmpty(remark)) { + log.warn("[条件触发] 任务 {} remark 为空,跳过", job.getTaskId()); + return false; + } + + JSONObject json; + try { + json = JSON.parseObject(remark); + } catch (Exception e) { + log.warn("[条件触发] 任务 {} remark 解析失败:{}", job.getTaskId(), remark); + return false; + } + + JSONArray conditions = json.getJSONArray("conditions"); + if (conditions == null || conditions.isEmpty()) { + log.warn("[条件触发] 任务 {} conditions 为空", job.getTaskId()); + return false; + } + String logic = json.getString("logic"); + boolean isOr = "or".equalsIgnoreCase(logic); + for (int i = 0; i < conditions.size(); i++) { + JSONObject cond = conditions.getJSONObject(i); + boolean met = evaluateSingleCondition(cond, thingsModelSimpleItems, job.getTaskId()); + if (isOr && met) return true; + if (!isOr && !met) return false; + } + return !isOr; // AND:全部通过; OR:无一通过 + } + + /** + * 评估单个条件对象(含 identifier / operator / value 字段)。 + */ + private boolean evaluateSingleCondition(JSONObject condition, + List items, + Long taskId) { + String identifier = condition.getString("identifier"); + String operator = condition.getString("operator"); + String condValue = condition.getString("value"); + + if (StringUtils.isEmpty(identifier) || StringUtils.isEmpty(operator) || condValue == null) { + log.warn("[条件触发] 任务 {} 条件配置不完整:{}", taskId, condition); + return false; + } + + String reportedValue = null; + for (ThingsModelSimpleItem item : items) { + if (identifier.equals(item.getId())) { + reportedValue = item.getValue(); + break; + } + } + if (reportedValue == null) { + // 本次上报不含该属性,条件视为不满足 + return false; + } + + return evaluate(reportedValue, operator, condValue); + } + + /** + * 条件表达式计算。 + * 优先尝试数值比较,失败则降级为字符串比较。 + */ + private boolean evaluate(String actual, String operator, String expected) { + try { + BigDecimal a = new BigDecimal(actual.trim()); + BigDecimal b = new BigDecimal(expected.trim()); + int cmp = a.compareTo(b); + switch (operator) { + case "=": return cmp == 0; + case "!=": return cmp != 0; + case ">": return cmp > 0; + case "<": return cmp < 0; + case ">=": return cmp >= 0; + case "<=": return cmp <= 0; + default: + log.warn("[条件触发] 不支持的操作符:{}", operator); + return false; + } + } catch (NumberFormatException e) { + // 非数值,降级为字符串等于/不等于 + switch (operator) { + case "=": return actual.equals(expected); + case "!=": return !actual.equals(expected); + default: + log.warn("[条件触发] 非数值不支持操作符 {},actual={}", operator, actual); + return false; + } + } + } + + /** + * 下发 Modbus 指令(HEX 格式)。 + * 复用与上电触发相同的消息通道。 + */ + private void dispatchCommand(String serialNumber, ModbusJob job) { + String command = job.getCommand(); + if (StringUtils.isEmpty(command)) { + log.warn("[条件触发] 任务 {} 指令为空,跳过下发", job.getTaskId()); + return; + } + + DeviceMessage msg = new DeviceMessage(); + msg.setSerialNumber(serialNumber); + msg.setTopicName("/function/get"); + msg.setDataType("hex"); + msg.setMessage(command); + + try { + deviceMessageService.messagePost(msg); + // 记录执行时间 + updateExecuteTime(job.getTaskId()); + log.info("[条件触发] 下发成功,设备:{},任务ID:{},指令:{}", serialNumber, job.getTaskId(), command); + } catch (Exception e) { + log.error("[条件触发] 下发异常,设备:{},任务ID:{}", serialNumber, job.getTaskId(), e); + } + } + + /** + * 更新任务最近执行时间。 + */ + private void updateExecuteTime(Long taskId) { + if (taskId == null) return; + ModbusJob update = new ModbusJob(); + update.setTaskId(taskId); + update.setExecuteTime(new Date()); + modbusJobService.updateModbusJob(update); + } +} diff --git a/fastbee-iot-data/src/main/java/com/fastbee/iot/data/ruleEngine/SceneContext.java b/fastbee-iot-data/src/main/java/com/fastbee/iot/data/ruleEngine/SceneContext.java index 718e6dd6..090de17b 100644 --- a/fastbee-iot-data/src/main/java/com/fastbee/iot/data/ruleEngine/SceneContext.java +++ b/fastbee-iot-data/src/main/java/com/fastbee/iot/data/ruleEngine/SceneContext.java @@ -89,6 +89,7 @@ public class SceneContext { /** * 处理规则脚本 * 静默时间:silent,在静默时间内即使满足触发条件也不执行动作 + * * @return */ private boolean process(String json) throws InterruptedException { @@ -96,7 +97,8 @@ public class SceneContext { ScriptTemplate scriptTemplate = JSON.parseObject(json, ScriptTemplate.class); String requestId = "scene/" + scriptTemplate.getChainName(); scene_logger.info("[{}]=====+>场景联动规则开始执行!", requestId); - scene_logger.info("[{}]=====+>规则引擎脚本配置:{},规则引擎上下文:{}", requestId, JSON.toJSONString(scriptTemplate), JSON.toJSONString(this)); + scene_logger.info("[{}]=====+>规则引擎脚本配置:{},规则引擎上下文:{}", requestId, JSON.toJSONString(scriptTemplate), + JSON.toJSONString(this)); // MDC.put("id", scriptTemplate.getChainName()); // 触发器 if (scriptTemplate.getPurpose() == 2) { @@ -513,7 +515,8 @@ public class SceneContext { alertPushParams.setDeviceId(device.getDeviceId()); alertPushParams.setDeviceName(device.getDeviceName()); alertPushParams.setSerialNumber(sceneThingsModelItem.getDeviceNumber()); - // List deviceUserList = deviceUserService.getDeviceUserAndShare(device.getDeviceId()); + // List deviceUserList = + // deviceUserService.getDeviceUserAndShare(device.getDeviceId()); // 多租户改版查询自己配置的告警用户 默认优先推送本账号超级管理员 Set userIdSet = new HashSet<>(); try { @@ -547,7 +550,8 @@ public class SceneContext { return alertPushParams; } - private AlertLog getTerminalUserAlertLog(SceneTerminalUserVO sceneTerminalUserVO, Device device, SceneThingsModelItem sceneThingsModelItem) { + private AlertLog getTerminalUserAlertLog(SceneTerminalUserVO sceneTerminalUserVO, Device device, + SceneThingsModelItem sceneThingsModelItem) { AlertLog alertLog = new AlertLog(); alertLog.setAlertName("设备告警"); alertLog.setAlertLevel(1L); diff --git a/fastbee-iot-data/src/main/java/com/fastbee/iot/data/service/impl/DataHandlerImpl.java b/fastbee-iot-data/src/main/java/com/fastbee/iot/data/service/impl/DataHandlerImpl.java index 8a9546bb..7eae4549 100644 --- a/fastbee-iot-data/src/main/java/com/fastbee/iot/data/service/impl/DataHandlerImpl.java +++ b/fastbee-iot-data/src/main/java/com/fastbee/iot/data/service/impl/DataHandlerImpl.java @@ -17,6 +17,7 @@ import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.date.LocalDateTimeUtils; import com.fastbee.common.utils.gateway.mq.TopicsUtils; import com.fastbee.iot.cache.SceneModelTagCache; +import com.fastbee.iot.data.executor.ConditionTriggerTaskExecutor; import com.fastbee.iot.data.service.IDataHandler; import com.fastbee.iot.data.service.IMqttMessagePublish; import com.fastbee.iot.data.service.IRuleEngine; @@ -59,6 +60,8 @@ public class DataHandlerImpl implements IDataHandler { @Resource private IRuleEngine ruleEngine; @Resource + private ConditionTriggerTaskExecutor conditionTriggerExecutor; + @Resource private MqttRemoteManager remoteManager; @Resource private TopicsUtils topicsUtils; @@ -100,6 +103,8 @@ public class DataHandlerImpl implements IDataHandler { // todo 只有设备上报进入规则引擎流程 if (bo.isRuleEngine() && !bo.getSerialNumber().startsWith("server-")) { ruleEngine.ruleMatch(bo); + // 条件触发任务检查:根据本次上报值决定是否下发 Modbus 指令 + conditionTriggerExecutor.checkAndTrigger(bo.getSerialNumber(), result); } // 发送至前端 PushMessageBo messageBo = new PushMessageBo(); diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ModbusJob.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ModbusJob.java index 67e7c89b..d4a43d23 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ModbusJob.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/domain/ModbusJob.java @@ -84,13 +84,13 @@ public class ModbusJob extends BaseEntity { private String remarkStr; /** - * 时间周期类型(1-周期循环,2-自定义时间段,3-设备上电触发) + * 时间周期类型(1-周期循环,2-自定义时间段,3-设备上电触发,4-条件触发) */ @ApiModelProperty("时间周期类型") private Integer cycleType; /** - * 执行时间(仅设备上电触发任务使用,记录任务执行的时间) + * 执行时间(仅设备上电触发/条件触发任务使用,记录最近一次执行的时间) */ @ApiModelProperty("执行时间") private Date executeTime; diff --git a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ModbusJobServiceImpl.java b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ModbusJobServiceImpl.java index 0e118fcd..0396fab7 100644 --- a/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ModbusJobServiceImpl.java +++ b/fastbee-service/fastbee-iot-service/src/main/java/com/fastbee/iot/service/impl/ModbusJobServiceImpl.java @@ -1,5 +1,6 @@ package com.fastbee.iot.service.impl; +import com.alibaba.fastjson2.JSONObject; import com.fastbee.common.core.device.DeviceAndProtocol; import com.fastbee.common.core.mq.SubDeviceBo; import com.fastbee.common.exception.ServiceException; @@ -69,9 +70,13 @@ public class ModbusJobServiceImpl implements IModbusJobService { List modbusJobList = modbusJobMapper.selectModbusJobList(modbusJob); if (!CollectionUtils.isEmpty(modbusJobList)) { for (ModbusJob job : modbusJobList) { - // 直接使用数据库中的 cycleType 判断 - if (job.getCycleType() != null && job.getCycleType() == 3) { + Integer ct = job.getCycleType(); + if (ct != null && ct == 3) { job.setRemarkStr("设备上电触发"); + } else if (ct != null && ct == 4) { + // 条件触发:remark 是 JSON 对象,解析后展示为可读描述 + String condDesc = buildConditionDesc(job.getRemark()); + job.setRemarkStr("条件触发:" + condDesc); } else { job.setRemarkStr(JobCronUtils.handleCronCycle(1, job.getRemark()).getDesc()); job.setCycleType(1); // 周期循环(默认) @@ -83,13 +88,14 @@ public class ModbusJobServiceImpl implements IModbusJobService { } /** - * 检查是否是设备上电触发(直接使用 cycleType 判断) + * 检查是否是非定时触发类型(上电触发 cycleType=3 或条件触发 cycleType=4) + * 这两种类型不需要创建 Quartz 定时任务,而是通过事件驱动触发。 * * @param cycleType 时间周期类型 - * @return true表示是设备上电触发 + * @return true 表示不需要创建定时任务 */ - private boolean isPowerOnTrigger(Integer cycleType) { - return cycleType != null && cycleType == 3; + private boolean isNonScheduleTrigger(Integer cycleType) { + return cycleType != null && (cycleType == 3 || cycleType == 4); } /** @@ -107,7 +113,8 @@ public class ModbusJobServiceImpl implements IModbusJobService { } // 查询关联的网关设备 - DeviceAndProtocol deviceAndProtocol = deviceService.selectProtocolBySerialNumber(modbusJob.getSubSerialNumber()); + DeviceAndProtocol deviceAndProtocol = deviceService + .selectProtocolBySerialNumber(modbusJob.getSubSerialNumber()); // 如果是网关子设备 if (deviceAndProtocol.getDeviceType() == DeviceType.SUB_GATEWAY.getCode() || deviceAndProtocol.getDeviceType() == DeviceType.GATEWAY.getCode()) { @@ -129,14 +136,12 @@ public class ModbusJobServiceImpl implements IModbusJobService { deviceJob.setSerialNumber(deviceAndProtocol.getGwSerialNumber()); deviceJob.setProductId(deviceAndProtocol.getGwProductId()); deviceJob.setCreateTime(DateUtils.getNowDate()); - // 处理时间转换 - // 检查是否是设备上电触发(使用 cycleType 判断) - if (isPowerOnTrigger(modbusJob.getCycleType())) { - // 设备上电触发不需要 cron 表达式,设置为null - // DeviceJobServiceImpl.insertJob 会检查并跳过创建定时任务 + // 上电触发(3)和条件触发(4)不需要 cron 表达式 + if (isNonScheduleTrigger(modbusJob.getCycleType())) { deviceJob.setCronExpression(null); } else { - SceneModelTagCycleVO sceneModelTagCycleVO = JobCronUtils.handleCronCycle(1, deviceJob.getRemark()); + SceneModelTagCycleVO sceneModelTagCycleVO = JobCronUtils.handleCronCycle(1, + deviceJob.getRemark()); deviceJob.setCronExpression(sceneModelTagCycleVO.getCron()); } deviceJobService.insertJob(deviceJob); @@ -150,7 +155,7 @@ public class ModbusJobServiceImpl implements IModbusJobService { DeviceJob deviceJob = new DeviceJob(); deviceJob.setDeviceId(deviceAndProtocol.getDeviceId()); // 用网关自己的deviceId buildSaveDeviceJob(modbusJob, deviceAndProtocol, deviceJob); - } else { + } else { throw new ServiceException("请先绑定网关"); } } else { @@ -200,7 +205,8 @@ public class ModbusJobServiceImpl implements IModbusJobService { if (scheduleChanged) { // 计算新的 remark / cycleType(允许只传 cycleType 或只传 remark) String newRemark = modbusJob.getRemark() != null ? modbusJob.getRemark() : existingJob.getRemark(); - Integer newCycleType = modbusJob.getCycleType() != null ? modbusJob.getCycleType() : existingJob.getCycleType(); + Integer newCycleType = modbusJob.getCycleType() != null ? modbusJob.getCycleType() + : existingJob.getCycleType(); if (newCycleType == null) { newCycleType = 1; } @@ -228,15 +234,20 @@ public class ModbusJobServiceImpl implements IModbusJobService { create.setSerialNumber(oldDeviceJob.getSerialNumber()); create.setProductId(oldDeviceJob.getProductId()); create.setJobType(5); - create.setJobName(StringUtils.isNotEmpty(oldDeviceJob.getJobName()) ? oldDeviceJob.getJobName() : "modbus poll"); - create.setJobGroup(StringUtils.isNotEmpty(oldDeviceJob.getJobGroup()) ? oldDeviceJob.getJobGroup() : "MODBUS"); - create.setMisfirePolicy(StringUtils.isNotEmpty(oldDeviceJob.getMisfirePolicy()) ? oldDeviceJob.getMisfirePolicy() : "2"); - create.setConcurrent(StringUtils.isNotEmpty(oldDeviceJob.getConcurrent()) ? oldDeviceJob.getConcurrent() : "1"); + create.setJobName( + StringUtils.isNotEmpty(oldDeviceJob.getJobName()) ? oldDeviceJob.getJobName() : "modbus poll"); + create.setJobGroup( + StringUtils.isNotEmpty(oldDeviceJob.getJobGroup()) ? oldDeviceJob.getJobGroup() : "MODBUS"); + create.setMisfirePolicy( + StringUtils.isNotEmpty(oldDeviceJob.getMisfirePolicy()) ? oldDeviceJob.getMisfirePolicy() + : "2"); + create.setConcurrent( + StringUtils.isNotEmpty(oldDeviceJob.getConcurrent()) ? oldDeviceJob.getConcurrent() : "1"); create.setIsAdvance(oldDeviceJob.getIsAdvance() != null ? oldDeviceJob.getIsAdvance() : 0); create.setStatus("0"); create.setRemark(newRemark); - if (isPowerOnTrigger(newCycleType)) { + if (isNonScheduleTrigger(newCycleType)) { create.setCronExpression(null); } else { SceneModelTagCycleVO vo = JobCronUtils.handleCronCycle(newCycleType, newRemark); @@ -258,13 +269,14 @@ public class ModbusJobServiceImpl implements IModbusJobService { int rows = modbusJobMapper.updateModbusJob(modbusJob); // 如发生重绑且旧 jobId 无引用,则删除旧 DeviceJob(同时会清理 quartz trigger/job) - if (scheduleChanged && oldDeviceJobId != null && modbusJob.getJobId() != null && !oldDeviceJobId.equals(modbusJob.getJobId())) { + if (scheduleChanged && oldDeviceJobId != null && modbusJob.getJobId() != null + && !oldDeviceJobId.equals(modbusJob.getJobId())) { ModbusJob q = new ModbusJob(); q.setJobId(oldDeviceJobId); List left = modbusJobMapper.selectModbusJobList(q); if (CollectionUtils.isEmpty(left)) { try { - deviceJobService.deleteJobByIds(new Long[]{oldDeviceJobId}); + deviceJobService.deleteJobByIds(new Long[] { oldDeviceJobId }); } catch (SchedulerException e) { throw new ServiceException(e.getMessage()); } @@ -332,7 +344,8 @@ public class ModbusJobServiceImpl implements IModbusJobService { case GATEWAY: // 网关设备需要查询所有子设备的modbus任务 List subDeviceList = subGatewayService.getSubDeviceListByGw(serialNumber); - List serialNumberList = subDeviceList.stream().map(SubDeviceBo::getSubDeviceNo).collect(Collectors.toList()); + List serialNumberList = subDeviceList.stream().map(SubDeviceBo::getSubDeviceNo) + .collect(Collectors.toList()); // 把网关自身SN也加入查询 serialNumberList.add(serialNumber); modbusJob.setSubDeviceList(serialNumberList); @@ -360,9 +373,10 @@ public class ModbusJobServiceImpl implements IModbusJobService { /** * 组装并保存设备任务 - * @param modbusJob 待新增的modbus任务 - * @param deviceAndProtocol 设备协议 - * @param deviceJob 设备任务 + * + * @param modbusJob 待新增的modbus任务 + * @param deviceAndProtocol 设备协议 + * @param deviceJob 设备任务 */ private void buildSaveDeviceJob(ModbusJob modbusJob, DeviceAndProtocol deviceAndProtocol, DeviceJob deviceJob) { deviceJob.setRemark(modbusJob.getRemark()); @@ -379,13 +393,10 @@ public class ModbusJobServiceImpl implements IModbusJobService { deviceJob.setSerialNumber(deviceAndProtocol.getSerialNumber()); // 网关自己的SN deviceJob.setProductId(deviceAndProtocol.getProductId()); deviceJob.setCreateTime(DateUtils.getNowDate()); - // 检查是否是设备上电触发(使用 cycleType 判断) - if (isPowerOnTrigger(modbusJob.getCycleType())) { - // 设备上电触发不需要 cron 表达式,设置为null - // DeviceJobServiceImpl.insertJob 会检查并跳过创建定时任务 + // 上电触发(3)和条件触发(4)不需要 cron 表达式 + if (isNonScheduleTrigger(modbusJob.getCycleType())) { deviceJob.setCronExpression(null); } else { - // 处理时间转换 SceneModelTagCycleVO sceneModelTagCycleVO = JobCronUtils.handleCronCycle(1, deviceJob.getRemark()); deviceJob.setCronExpression(sceneModelTagCycleVO.getCron()); } @@ -400,4 +411,48 @@ public class ModbusJobServiceImpl implements IModbusJobService { modbusJob.setJobId(job.getJobId()); } } + + /** + * 将条件触发的 remark JSON 转换为可读描述,用于列表展示。 + * 示例:{"identifier":"temperature","operator":">","value":"50"} → "temperature > + * 50" + */ + private String buildConditionDesc(String remark) { + if (StringUtils.isEmpty(remark)) { + return "(条件未配置)"; + } + try { + JSONObject json = JSONObject.parseObject(remark); + // 多条件格式 + if (json.containsKey("conditions")) { + com.alibaba.fastjson2.JSONArray conditions = json.getJSONArray("conditions"); + if (conditions == null || conditions.isEmpty()) { + return "(条件未配置)"; + } + String logic = json.getString("logic"); + String sep = "or".equalsIgnoreCase(logic) ? " 或 " : " 且 "; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < conditions.size(); i++) { + JSONObject cond = conditions.getJSONObject(i); + String id = cond.getString("identifier"); + String op = cond.getString("operator"); + String val = cond.getString("value"); + if (i > 0) + sb.append(sep); + sb.append(id).append(op).append(val); + } + return sb.toString(); + } + // 单条件旧格式 + String id = json.getString("identifier"); + String op = json.getString("operator"); + String val = json.getString("value"); + if (StringUtils.isEmpty(id) || StringUtils.isEmpty(op) || val == null) { + return remark; + } + return id + " " + op + " " + val; + } catch (Exception e) { + return remark; + } + } } diff --git a/yack-web/src/views/iot/device/device-modbus-task.vue b/yack-web/src/views/iot/device/device-modbus-task.vue index 226d3507..7c82d971 100644 --- a/yack-web/src/views/iot/device/device-modbus-task.vue +++ b/yack-web/src/views/iot/device/device-modbus-task.vue @@ -66,6 +66,7 @@ 周期循环 自定义时间段 设备上电触发 + 条件触发 - @@ -83,7 +84,11 @@ - - + + +