
自动控制逻辑开发阈值触发自动浇水、自动通风、温控联动作者黒漂技术佬前面四篇文章都在讲数据怎么采集、怎么传输、怎么存储。这当然重要——但说实话纯「数据大屏」的项目农户看了只会说一句「好是好但能不能帮我干点活」本文就来回答这个问题怎么让系统自动干活。温度高了自动开风机土壤干了自动浇水光照不够自动补光——真正的智慧农业数据不是终点控制才是。一、自动化的核心价值传统大棚种植最痛苦的是什么是「人不能离」。夏天中午棚内温度飙升到 40℃你必须冲进去开风机开天窗凌晨湿度骤降又得爬起来开加湿器。一个疏忽一季的收成就打了水漂。自动化控制要解决的就是这个痛点。它的核心价值有三层解放人力24 小时自动值守人不用绑在大棚里精准控制传感器采集的精度远超人的感知28.5℃ 和 30℃ 的区别你感觉不到但机器能联动决策温度和湿度不是孤立问题——开风机降温的同时会带走湿度系统能自动计算平衡点人就很难做到二、控制闭环架构自动控制的本质是一个「感知→决策→执行→反馈」的闭环┌─────────┐ 传感器数据 ┌─────────────┐ 控制指令 ┌─────────┐ │ 传感器 │ ───────────────→ │ 规则引擎 │ ──────────────→ │ 执行器 │ │ (温度等) │ │ (阈值判断) │ │ (风机等) │ └─────────┘ └─────────────┘ └─────────┘ ↑ │ │ ┌─────────┐ │ └───────────────────────│ 反馈 │←───────────────────────┘ 传感器持续采集验证效果 └─────────┘ 执行后传感器值变化举个具体例子温度传感器上报 32℃ → 规则引擎判断超阈值 → 下发「开风机」指令 → 风机启动 → 1 分钟后温度降到 29℃ → 规则引擎判断达标 → 关闭风机。这就是一个完整的控制闭环。三、阈值触发规则设计先列一个智慧农业的典型控制规则表控制场景触发条件执行动作恢复条件高温降温温度 30℃开风机 开天窗温度 28℃低温加热温度 15℃关天窗 开加热器温度 18℃土壤干旱浇水土壤湿度 30%开水泵灌溉湿度 70%湿度过高排湿湿度 90%开风机排湿湿度 80%湿度过低加湿湿度 60%开喷雾/加湿器湿度 70%光照不足补光光照 5000 Lux开补光灯光照 8000 LuxCO2不足补充CO2 300ppm开CO2发生器CO2 500ppm注意每个规则都有触发阈值和恢复阈值而且两者不同这叫「滞回控制」。比如温度高于 30℃ 开风机要等温度降到 28℃ 才关——如果触发和恢复用同一个阈值设备就会在边界上疯狂开关振荡电机烧了都不知道为啥。四、规则引擎实现三种方案对比方案一定时轮询最简单适合初期ComponentpublicclassThresholdCheckScheduler{AutowiredprivateInfluxDBServiceinfluxDBService;AutowiredprivateControlServicecontrolService;// 每30秒检查一次阈值Scheduled(fixedDelay30000)publicvoidcheckThresholds(){// 查询最近一次所有传感器的读数ListSensorReadinglatestReadingsinfluxDBService.queryLatestReadings();for(SensorReadingreading:latestReadings){ThresholdRuleruleruleConfig.getRule(reading.getGreenhouseId(),reading.getSensorType());if(rule.isExceeded(reading.getValue())){controlService.execute(reading.getGreenhouseId(),rule.getAction());}}}}优点是实现简单缺点是有延迟最多 30 秒而且每条规则都要查库传感器多了效率低。方案二MQTT 实时消费推荐直接在消息消费时判断阈值延迟最低ComponentpublicclassRealTimeThresholdHandler{AutowiredprivateControlServicecontrolService;AutowiredprivateRuleConfigruleConfig;// 防抖计数器Key greenhouseId:sensorType, Value 连续超阈值次数privatefinalMapString,IntegerexceedCountersnewConcurrentHashMap();// 冷却记录Key greenhouseId:action, Value 上次触发时间privatefinalMapString,LongcooldownMapnewConcurrentHashMap();privatestaticfinalintDEBOUNCE_COUNT3;// 连续3次超阈值才触发privatestaticfinallongCOOLDOWN_MS300_000;// 5分钟冷却publicvoidonSensorData(SensorDatadata){StringruleKeydata.getGreenhouseId():data.getSensorType();ThresholdRuleruleruleConfig.getRule(ruleKey);if(rulenull||!rule.isExceeded(data.getValue())){// 未超阈值重置防抖计数器exceedCounters.remove(ruleKey);return;}// 超阈值 → 防抖计数 1intcountexceedCounters.merge(ruleKey,1,Integer::sum);if(countDEBOUNCE_COUNT){return;// 还不够次数继续观察}// 检查冷却时间避免频繁触发同一个设备StringactionKeydata.getGreenhouseId():rule.getAction().getName();LonglastTriggercooldownMap.get(actionKey);if(lastTrigger!nullSystem.currentTimeMillis()-lastTriggerCOOLDOWN_MS){return;}// 触发控制cooldownMap.put(actionKey,System.currentTimeMillis());exceedCounters.remove(ruleKey);// 触发后重置计数器controlService.execute(data.getGreenhouseId(),rule.getAction());log.info(阈值触发: 大棚{}, 传感器{}, 当前值{}, 阈值{}, 动作{},data.getGreenhouseId(),data.getSensorType(),data.getValue(),rule.getThreshold(),rule.getAction().getName());}}这里有两个关键的保护机制防抖Debounce传感器可能因为电磁干扰等原因偶尔读到一个异常值比如温度突然跳到 50℃ 又瞬间回来。如果读到一次异常就触发控制就可能误开风机。解决方案是「连续 N 次超阈值才触发」——连续 3 次如果是 5 秒一次采集就是 15 秒内持续超标才算真的超标。冷却Cooldown控制操作执行后环境变化需要时间。比如开水泵灌溉后土壤湿度不会立刻从 25% 跳到 60%。如果不加冷却接下来的 5 分钟内系统会反复检测到「湿度 30%需要浇水」。冷却机制规定「同一设备同一动作 5 分钟内不再重复触发」避免控制指令满天飞。方案三EMQX 规则引擎Broker 内置如果你用的是 EMQX 企业版它的规则引擎可以直接在 Broker 侧做简单的阈值判断-- EMQX 规则引擎 SQLSELECTpayload.temperatureastemp,payload.humidityashum,topicFROMagriculture///sensor/#WHEREpayload.temperature30超阈值后可以直接触发 HTTP 回调到你的控制服务。这个方案的好处是延迟极低处理发生在 Broker 内部适合对实时性要求极高的场景。缺点是逻辑不能太复杂而且依赖 EMQX 企业版。推荐组合拳方案二 方案三。EMQX 规则引擎做第一层快速过滤对超出明显安全范围的数据直接触发告警SpringBoot 消费者做第二层精细化判断考虑防抖、冷却、联动逻辑。五、联动控制别顾此失彼温室环境是相互耦合的——你不能孤立地控制某一个参数。举个典型场景温度 33℃超了、湿度 55%也低了。如果只看温度系统开风机降温——结果风机一吹湿度从 55% 降到了 40%掉进更低的坑里。正确的联动做法是publicclassLinkedControlLogic{publicvoidhandleTemperatureHigh(SensorDatadata){doubletempdata.getTemperature();doublehumiditydata.getHumidity();// 开风机降温controlService.sendCommand(data.getGreenhouseId(),fan_on);// 联动如果温度高且湿度低同时开启加湿器if(humidity60){log.info(联动降温同时加湿当前湿度{}%,humidity);controlService.sendCommand(data.getGreenhouseId(),humidifier_on);}// 联动开风机前检查天窗是否已开DeviceStatusskylightdeviceService.getStatus(data.getGreenhouseId(),skylight);if(!skylight.isOpen()){controlService.sendCommand(data.getGreenhouseId(),skylight_open);}}}联动逻辑的核心是「不要只看一个变量」。在做任何控制决策时都要检查组关联参数是否在安全范围内。六、手动/自动模式切换自动控制再聪明也得给人留个「刹车」。有时候农户要进棚作业、要喷药、要采摘——这些场景下自动控制可能会帮倒忙。Topic 设计agriculture/{farmId}/{greenhouseId}/mode Payload: {mode: auto} 或 {mode: manual}控制服务在执行前必须检查当前模式publicvoidexecute(StringgreenhouseId,ControlActionaction){// 先查模式StringmoderedisService.get(greenhouse:mode:greenhouseId);if(manual.equals(mode)){log.info(手动模式跳过自动控制: 大棚{}, 动作{},greenhouseId,action.getName());return;}// 自动模式正常执行mqttCommandService.sendCommand(greenhouseId,action);// 记录控制日志controlLogService.record(ControlLog.builder().greenhouseId(greenhouseId).action(action.getName()).mode(auto).triggerCondition(action.getTriggerCondition()).threshold(action.getThreshold()).currentValue(action.getCurrentValue()).timestamp(System.currentTimeMillis()).result(success).build());}手动模式优先级高于自动——这是铁律。机器可以辅助人但不能凌驾于人。七、控制日志审计比控制还重要每执行一次控制操作都要留下完整的日志记录。不是为了形式主义而是有实际价值CREATETABLEcontrol_log(idBIGINTPRIMARYKEYAUTO_INCREMENT,greenhouse_idVARCHAR(50)NOTNULL,actionVARCHAR(50)NOTNULLCOMMENTfan_on/humidifier_on/pump_on等,modeVARCHAR(10)NOTNULLCOMMENTauto/manual,trigger_conditionVARCHAR(200)COMMENT触发条件描述,threshold_valueDECIMAL(10,2)COMMENT阈值,current_valueDECIMAL(10,2)COMMENT触发时的传感器值,execute_timeDATETIMENOTNULL,resultVARCHAR(20)NOTNULLCOMMENTsuccess/fail,fail_reasonVARCHAR(500)COMMENT失败原因,INDEXidx_time(execute_time),INDEXidx_greenhouse(greenhouse_id,execute_time));这些日志的用途事后排查哪天作物状态不对可以回溯「当时系统干了什么」阈值优化统计分析触发频率——如果降温风机一天开了 50 次说明你阈值设得有问题设备健康度某水泵触发频率突然翻倍可能是传感器失准或管路泄漏的预警信号总结自动控制的五条军规滞回控制触发和恢复用不同阈值避免设备振荡防抖 冷却连续 N 次超标才触发触发后 N 分钟内不重复联动判断做任何控制前检查关联参数手动优先手动模式一开自动全部让路控制必记日志没有审计的控制是定时炸弹数据采集做得再好最终产生价值的还是「控制」。毕竟农户要的不是漂亮的温湿度曲线而是好收成。