Crop Steering System Guide

Version 2.3.1  |  6-Zone Coco Coir  |  Athena Nutrients  |  GroundWork Probes  |  April 2026

1. System Overview

This system automates irrigation and climate control for a 6-table cannabis grow room running coco coir with Athena nutrients and GroundWork substrate probes. Two layers run simultaneously:

Irrigation Package GW

Time-based irrigation scheduler (should be OFF when crop steering is active), environment control (CO2, dehumidifiers, humidifier), and safety watchdogs. Runs in HA via YAML packages at /config/packages/irrigation/.

Crop Steering AI CS

Sensor-driven 4-phase irrigation (P0–P3) with per-zone control, EC ratio logic, ML prediction, dryback detection, and emergency management. Runs as AppDaemon app + HA custom component. This is the active irrigation brain.

To prevent double-watering: Set input_boolean.irrigation_irrigation_enabled to OFF when crop steering is handling irrigation. GW environment controls remain active independently.

2. Hardware Map

Irrigation

ComponentGW EntityRaw EntityPhysical
Main Lineswitch.irrigation_mainlineswitch.mainlineMainline solenoid (KC868)
Zone 1–6 Valvesswitch.irrigation_table_N_valveswitch.table_NTable solenoids (KC868)
PumpNone — auto-startConstant pressure switch
Mains Waterswitch.irrigation_mains_waterswitch.mains_waterTank fill only (NOT irrigation)
Manifoldswitch.irrigation_manifoldswitch.manifoldTank mixing only (NOT irrigation)

Sensors (1 probe per zone)

ZoneVWCEC
1–6sensor.substrate_N_substrate_N_vwc_coco_coirsensor.substrate_N_substrate_N_pwec

GW mapping layer creates aliases: sensor.irrigation_table_N_vwc / _ec / _substrate_temp. Crop steering reads the raw entities directly.

Environment

SensorEntitySource
Room tempsensor.irrigation_room_1_tempAvg of 4 calibrated sensors
Room RHsensor.irrigation_room_1_rhAvg of 4 sensors
Room CO2sensor.irrigation_room_1_co2Avg of 3–4 CO2 sensors
Room VPDsensor.irrigation_room_1_vpdAvg from CO2 sensors
DeviceEntityNotes
CO2 solenoidswitch.irrigation_co2Solid state relay
Humidifierswitch.irrigation_humidifierSolid state relay
Dehumidifier (plug)switch.irrigation_dehumidifier_1TP-Link Kasa WiFi plug
Dehumidifier relays 1–4switch.irrigation_dehumidifier_relay_14Staggered 10s apart
AC 1–4climate.ac_*IR via ESPHome. Mapped, NOT automated.
Lightslight.grow_room_all_lightsESPHome group
Unmapped / not installed:

3. Architecture & Data Flow

Physical probes (ESPHome)
    |
Raw entities (sensor.substrate_N_substrate_N_vwc_coco_coir)
    |   [10_mapping.yaml]
GW contract entities (sensor.irrigation_table_N_vwc)
    |
    +-- crop_steering.env
    |
Crop Steering custom component (crop_steering_ prefixed entities)
    |
Home Assistant (state + events)
    |
AppDaemon master app (listen_state + REST API fallback)
    |
Hardware (valve switches via HA services)
Entity naming: Custom component entities have crop_steering_ prefix (e.g. switch.crop_steering_system_enabled). AppDaemon tries both prefixed and unprefixed names. Sensors created by AppDaemon use exact IDs shown.

GW Package Files

FilePurpose
00_core.yamlEmergency stop script, alert helper
10_mapping.yamlRaw ESPHome → irrigation_* contract aliases
20_model.yamlInput helpers (schedules, targets, timers)
30_irrigation.yamlTime-based scheduler + abort automations
40_environment.yamlDehumidifier, humidifier, CO2 automations
50_alerts_watchdogs.yamlValve watchdogs, sensor alerts, safety interlocks

AppDaemon Files

FilePurpose
master_crop_steering_app.py~5900 lines. Decision loop, phases, safety, analytics
phase_state_machine.pyPer-zone state machine
intelligent_sensor_fusion.pyOutlier detection, Kalman filtering
advanced_dryback_detection.pyPeak detection, rate prediction
intelligent_crop_profiles.pyStrain profiles, adaptive learning
ml_irrigation_predictor.pyPure-math ML predictor

4. The Four Phases CS

Each zone runs independently. Phases advance on sensor readings.

P0 — Morning Dryback

When: Lights on (08:00). No irrigation. Records peak VWC.
Exits: Dryback target met (50%) or min drop (15%) or max wait (120 min) or rate too slow. Min wait 30 min.
Exception: EC > 2.5x target → flush shot (10%).

P1 — Ramp-Up

When: P0 ends. Progressive shots: 2% + 0.5% × count, max 10%, × zone multiplier.
Exits: VWC ≥ 65% + min 3 shots, or max 6 shots. 15 min cooldown. EC-adjusted.

P2 — Maintenance

When: P1 target met. 5% shot when VWC < 60%.
EC > 1.2 → 1.5x shot. EC < 0.8 → 0.7x shot.
Exits: ML predicts insufficient overnight dryback time.

P3 — Pre-Lights-Off

When: Dryback prediction. Emergency only: VWC < 40% or EC > 2.0x.
Exits: Lights on next morning → P0.

Lights ONP0P1P2P3 → Lights OFF → P0

Phase state machine — what actually triggers each transition

flowchart TD
    LightsOn(["☀️ Lights ON · 08:00"])
    P0["🟡 P0 — Morning Dryback\nNo watering at all.\nSystem records the peak VWC reading\nand waits for the substrate to dry out\nbefore starting the first watering."]
    P1["🟢 P1 — Ramp Up\nFirst waterings of the day.\nStarts with a tiny shot and grows\nslightly bigger each time.\nFires every 15 minutes."]
    P2["🔵 P2 — Day Maintenance\nKeeps substrate at a steady level.\nFires a 5% shot whenever VWC\ndrops below the lower threshold.\nRuns for most of the day."]
    P3["🔴 P3 — Lights-Off Wind-Down\nStops planned irrigation.\nLets substrate dry overnight.\nOnly emergency rescue shots allowed."]
    LightsOff(["🌙 Lights OFF · 20:00"])
    FlushShot["⚡ Flush Shot\n10% shot · emergency\nEC spiked above 2.5× target"]
    EmgShot["🚨 Emergency Rescue\n2% shot fires\nVWC dropped below 40%"]

    LightsOn --> P0
    P0 -- "✓ VWC dropped 15%+ from peak\n✓ At least 30 min elapsed" --> P1
    P0 -- "⏱ 120 min maximum\nAI forces transition" --> P1
    P0 -. "EC too high — flush first" .-> FlushShot
    FlushShot -. "returns to dryback wait" .-> P0
    P1 -- "✓ VWC reached 65%\n✓ At least 3 shots fired" --> P2
    P1 -- "⏱ 6 shots maximum\nforced transition" --> P2
    P2 -- "ML predicts not enough\ndryback time left today" --> P3
    P3 --> LightsOff
    LightsOff -- "Next morning" --> LightsOn
    P3 -. "VWC below 40% overnight" .-> EmgShot
    EmgShot -. "returns to overnight wait" .-> P3

    style LightsOn fill:#1c2128,stroke:#8b949e,color:#c9d1d9
    style LightsOff fill:#1c2128,stroke:#8b949e,color:#c9d1d9
    style P0 fill:#3a2600,stroke:#d29922,color:#e6edf3
    style P1 fill:#0f2d1b,stroke:#3fb950,color:#e6edf3
    style P2 fill:#0d1f3c,stroke:#58a6ff,color:#e6edf3
    style P3 fill:#2d0f0f,stroke:#f85149,color:#e6edf3
    style FlushShot fill:#2a1a2a,stroke:#bc8cff,color:#e6edf3
    style EmgShot fill:#2d0f0f,stroke:#f85149,color:#f85149

5. Daily Cycle

Lights 08:00–20:00, Cannabis_Athena, vegetative:

TimePhaseWhat Happens
08:00P0Lights on. Peak VWC recorded. No watering.
~09:30P1Dryback met. Progressive shots every 15 min.
~11:00P2VWC at 65%. Maintenance shots when < 60%.
~17:00P3Pre-lights-off. Emergency only.
20:00P3Lights off. P3 until morning.

Irrigation Sequence

  1. Main line on, wait 1s
  2. Zone valve on
  3. Wait shot duration
  4. Zone valve off, 1s
  5. Main line off, 1s
  6. 30s sensor stabilization
  7. Read post-VWC

Max 1 concurrent zone. finally block ensures hardware off on error.

What a Good Day Looks Like

This is what your VWC sensor should look like on a healthy vegetative day. The line color shows which phase is active. The dashed horizontal lines are the key thresholds the system watches. If your actual readings look very different from this, something needs tuning.

VWC % over 24 hours — healthy vegetative zone · Cannabis_Athena profile · lights 08:00–20:00

P0 Morning Dryback P1 Ramp-Up P2 Day Maintenance P3 / Overnight Key thresholds
Reading this chart: A healthy day starts with a controlled dryback (P0 — line drops), then a quick wet-up (P1 — line rises), then steady all-day maintenance (P2 — oscillates in a band), then dries slowly overnight (P3). If your zone never enters P1, check your dryback target. If P2 shots fire constantly, your P2 threshold may be too close to your P1 target. If VWC drops below the red emergency line overnight, something is wrong.

6. GW Time-Based Scheduler GW

Must be OFF when crop steering is active. Set input_boolean.irrigation_irrigation_enabled to OFF.

Checks every 5 min: system enabled, irrigation enabled, not maintenance, no leak, no tank low, within time window, interval elapsed. Opens mainline, runs each enabled table for configured duration sequentially, closes mainline.

SettingEntityDefault
Window start/endinput_datetime.irrigation_irrigate_start/end_timeSet in HA
Intervalinput_number.irrigation_irrigate_interval_min60 min
Durationinput_number.irrigation_irrigate_duration_sec60s
Table Ninput_boolean.irrigation_table_N_enabledOFF

7. Environment Control GW

Gated by input_boolean.irrigation_environment_enabled.

Dehumidifiers

4 relays stagger ON 10s apart. ON: RH > target + 5% for 3 min. OFF: RH < target − 2% for 2 min. TP-Link plug has separate UI automations at 75%/65%.

Humidifier

ON: RH < target − 5% for 3 min. OFF: RH > target + 2% for 2 min.

CO2

Pulsed: 1 min on / 4 min off. Inject: < 1100 ppm. Stop: ≥ 1400 ppm. Emergency off: ≥ 1800 ppm. Always off at lights-off. Only during lights-on.

AC

4 units mapped. No automated control yet — manual or separate automations.

EntityDefaultRangeUnitWhat It Controls
input_number.irrigation_temp_target_day2618–32°CReference day temperature target (lights-on). AC units are mapped but not yet automated — this value is used for VPD reference calculations and future AC logic. Set it to match your AC manual setpoint so dashboards display correctly.
input_number.irrigation_temp_target_night2215–28°CReference night temperature target (lights-off). Cannabis typically runs 2–4°C cooler at night. Not currently driving AC automation.
input_number.irrigation_rh_target_day5540–75%RHTarget RH during lights-on. ON rule: RH > target + 5% for 3 min → all 4 dehumidifier relays stagger on (10s apart). OFF rule: RH < target − 2% for 2 min → relays off. Hysteresis band prevents rapid cycling. Typical veg: 55–65%, flower: 45–55%.
input_number.irrigation_rh_target_night5040–70%RHTarget RH during lights-off. Night targets are usually 5–10% lower than day to reduce mold risk — transpiration slows at night and moisture can accumulate on leaves. Dehumidifier and humidifier both switch to this target at lights_off_hour.
input_number.irrigation_co2_target1200800–1600ppmTarget CO2 concentration during lights-on. Inject: ppm < this value. Stop: ppm ≥ this value + 200 (e.g. 1400). Emergency off: ≥ 1800 ppm always. CO2 solenoid pulses 1 min on / 4 min off to avoid overshooting. Always off at lights-off. Ambient is ~420 ppm; enriched growing targets 1000–1400 ppm. Above 1600 ppm provides diminishing returns and wastes CO2.

8. Entity Reference & Dashboard Variables

Every entity below is accessible from the dashboard or Developer Tools. Entities prefixed switch.crop_steering_, select.crop_steering_, number.crop_steering_, and input_* are user-configurable. Sensor entities are read-only and described in the lower half of this section.

CS Master Switches

EntityDefaultWhat It DoesWhen to Change
switch.crop_steering_system_enabledONMaster kill switch. When OFF, the AppDaemon loop stops all irrigation decisions immediately, closes all valves, and holds at safe-idle. No watering occurs under any condition — including emergencies — while this is OFF.Turn OFF for extended maintenance, hardware work, or full manual control. Do not leave OFF if plants are unattended.
switch.crop_steering_auto_irrigation_enabledONEnables automatic phase-based irrigation decisions. When OFF, the phase logic still runs and sensor readings still update, but no valve opens automatically. Manual shots via button.crop_steering_zone_N_trigger_shot and emergency triggers still work when OFF.Turn OFF to observe phase behavior without any watering, or to pause automatic decisions while keeping the system in monitoring mode.
switch.crop_steering_ec_stacking_enabledOFFWhen ON, the system intentionally delivers smaller shots (or skips shots) when EC is below target, allowing nutrient concentration in the substrate to build up. This is a generative technique — high substrate EC creates mild stress that promotes flowering and resin production. When OFF, EC adjustments only go in the dilution direction (high EC = bigger flush shots).Turn ON during late vegetative or early flower to drive generative steering. Leave OFF during veg when you want stable, consistent EC and vigorous growth.
switch.crop_steering_zone_N_enabledONIncludes or excludes a zone from automatic scheduling and phase calculations. When OFF, the zone is skipped in all routine decisions. Emergency irrigation still fires for a disabled zone if VWC drops critically low — disabling does not override the safety net.Turn OFF for unused tables, zones under transplant, or any table you don't want touched by the scheduler.
switch.crop_steering_zone_N_manual_overrideOFFAbsolute lockout. When ON, this zone receives zero water from any source — automatic, emergency, manual trigger, or ML-driven. This flag is checked at 4 separate code points: zone selection, phase evaluation, valve actuation, and the safety interlock. Nothing bypasses it.Turn ON when a zone needs physical maintenance (hand-flushing, re-potting, dripper cleaning), when a probe is returning bad readings, or any time you need a hard guarantee of no-water for a zone.

CS Selects (Dropdowns)

EntityDefaultOptions & What They Do
select.crop_steering_crop_typeCannabis_AthenaSets the active crop profile, which defines EC target ranges, dryback percentage ranges, and shot size modifiers. Cannabis_Athena is tuned for Athena 2-part at higher EC (3–9 mS/cm). Cannabis_Indica: denser, shorter plants, slightly lower EC (2.8–8). Cannabis_Sativa: tall, stretchy, higher EC tolerance (3.2–9.5), deeper dryback. Cannabis_Hybrid: balanced defaults (3–8.5). Tomato / Lettuce: much lower EC, higher-frequency watering.
select.crop_steering_growth_stageVegetativeShifts EC targets and dryback aggressiveness across all zones simultaneously.
Vegetative: EC target 3.0–3.2 mS/cm, dryback 50% of peak VWC. Frequent watering, wet substrate, maximum vegetative growth.
Early_Flower: EC rises to ~3.5–5.0 mS/cm, dryback deepens to 40–45%. Initiates generative stress signal to promote flowering.
Late_Flower: EC 5.0–6.0+ mS/cm, dryback 35–40%. Maximum generative pressure for resin, density, and ripening.
select.crop_steering_zone_N_phase_overrideAutoLocks a zone into a specific phase regardless of sensor readings. Auto = normal sensor-driven progression (use this for normal operation). P0 = force morning dryback regardless of time. P1 = force ramp-up (useful after transplant or to manually trigger a wet-up). P2 = force maintenance mode. P3 = force pre-lights-off hold. Always return to Auto when done.
select.crop_steering_zone_N_groupUngroupedAssigns a zone to a sync group (A/B/C/D). When ≥50% of zones in a group need water, all zones in the group irrigate together even if some don't technically need it. Keeps tables on identical schedules and simplifies management. Zones in the same physical row or on the same strain usually share a group. Only one zone irrigates at a time even within a group.
select.crop_steering_zone_N_priorityNormalSets scheduling urgency. Score = Priority 40% + VWC Need 40% + Phase Urgency 20%. Priority weights: Critical = 4, High = 3, Normal = 2, Low = 1. Higher-scored zones get the next irrigation slot when multiple zones are waiting. Use Critical for large plants or high-value strains, Low for seedlings or plants needing minimal water.

CS System-Wide Numbers

All prefixed number.crop_steering_. These apply to all zones unless a per-zone override is set.

Entity (suffix)DefaultRangeUnitWhat It Controls
substrate_volume101–50LVolume of substrate (coco) per pot. Used to convert a percentage shot into liters. Formula: Shot volume (L) = substrate_volume × shot_% ÷ 100. With 10 L substrate, a 5% shot = 0.5 L. A 25 L pot needs this set to 25 or the system will dramatically under-water.
dripper_flow_rate1.20.5–10L/hrFlow rate of one dripper. Combined with drippers_per_plant and plant_count this determines how many seconds a valve stays open to deliver the required volume. Formula: Duration (s) = Volume (L) ÷ (flow_rate × drippers_per_plant × plant_count) × 3600. Wrong flow rate = wrong valve-open time = wrong actual volume delivered.
drippers_per_plant21–8countNumber of drippers per plant. Multiplied by flow_rate to get total delivery rate per plant. If you add a third dripper per pot, update this to 3 — otherwise the valve stays open too long and over-waters.
field_capacity7050–95%VWCMaximum VWC the substrate should reach. This is a hard safety cap: if VWC ≥ field_capacity, the shot is skipped regardless of phase or EC. Fresh coco saturates around 70–80%. If your probes read higher due to sensor calibration, raise this value — but never above what your substrate physically holds or you'll mask over-watering.
lights_on_hour80–23hour (24h)Hour of day when lights turn on. Triggers the P0 morning dryback phase and activates CO2 injection. Must match your actual light schedule exactly. If set 1 hour too late, P3 persists and plants miss their morning dryback window. If too early, P0 starts before lights are on.
lights_off_hour200–23hour (24h)Hour of day when lights turn off. Triggers transition to P3, cuts CO2, and tells the ML predictor how many overnight hours remain for dryback. Must match your timer or smart plug schedule. Mismatch causes the ML to mis-predict whether there's enough dryback time before lights-on.
p1_target_vwc6550–85%VWCVWC level that P1 ramp-up aims to reach before switching to P2 maintenance. P1 exits when VWC ≥ this value AND at least p1_min_shots (3) have been delivered. Higher = wetter substrate entering the day (more vegetative). Lower = drier entry to maintenance (more generative). Typical veg: 65–70%, early flower: 60–65%, late flower: 55–62%.
p2_vwc_threshold6040–80%VWCVWC level that triggers a P2 maintenance shot. When VWC drops below this during P2, a 5% shot fires. Should sit 3–10% below p1_target_vwc to give natural swing room. If set too close to the P1 target, the system constantly fires shots trying to maintain it. If set too low, plants get dry spells mid-day.
p3_emergency_vwc_threshold4020–60%VWCVWC level that triggers a rescue shot during P3 (lights-off period). Normally plants dry back overnight — this threshold should be low enough to allow normal dryback without triggering, but high enough to catch wilting risk. A zone hitting 40% VWC overnight usually indicates something is wrong (large plants, hot night, sensor issue).

Per-Zone Override Numbers

All prefixed number.crop_steering_zone_N_. Set to 0 to inherit the system-wide default above. Any value > 0 overrides just that zone. Use when one table has different pot sizes, dripper counts, plant sizes, or strain needs.

Entity (suffix)DefaultUnitWhat It Overrides
zone_N_plant_count4plantsPlant count for this zone. Directly affects valve-open time calculation. A zone with 6 plants has more drippers flowing simultaneously, so the valve opens for less time to deliver the same volume. Always update when plant count changes.
zone_N_max_daily_volume20LMaximum total water for this zone per calendar day (resets at midnight). Once hit, no further shots are delivered that day regardless of VWC. Safety ceiling against sensor malfunction or runaway watering. Raise to 25–35 L for large plants in peak veg or flower with high transpiration demand.
zone_N_shot_size_multiplier1.0×Scales all shot sizes for this zone. 1.2 = all shots 20% larger. 0.8 = all shots 20% smaller. Use to compensate for a zone with faster-draining substrate, different dripper spacing, or a VWC sensor that reads differently from the others. Adjust in 0.1 increments and observe VWC response.
zone_N_dryback_target0 (system)%VWCHow far VWC must drop from its morning peak before P0 exits and watering begins. Deeper dryback = more root zone oxygen = more generative stress. 0 = use the growth-stage default. Set a positive value (e.g. 45) to give this zone a custom dryback independent of the global growth stage setting.
zone_N_p1_target_vwc0 (system)%VWCVWC level the P1 ramp-up targets for this zone before switching to P2. 0 = use system p1_target_vwc. Override for zones with smaller pots that saturate faster, or strains needing a wetter/drier starting point.
zone_N_p2_vwc_threshold0 (system)%VWCVWC trigger for P2 maintenance shots for this zone. 0 = use system p2_vwc_threshold. Override for zones on a different substrate or with sensors that read 5–10% off from others.
zone_N_p3_emergency_vwc0 (system)%VWCEmergency rescue VWC threshold for this zone during lights-off. 0 = use system p3_emergency_vwc_threshold.

Trigger Buttons

button.crop_steering_zone_N_trigger_shot — Delivers one P2-sized shot (5% of substrate volume) immediately. Blocked only if zone_N_manual_override is ON. Works even when auto irrigation is disabled. Useful for manually topping off a zone, testing valve operation, or recovering after a missed irrigation window. The shot is logged to daily volume.

GW Toggles

EntityPurpose & Detail
input_boolean.irrigation_enableGW package master switch. Disabling stops the GW time-based scheduler and all GW environment automations simultaneously. Does not affect Crop Steering.
input_boolean.irrigation_irrigation_enabledMust be OFF when Crop Steering is active. Enables the GW time-based irrigation scheduler. When ON, GW will open valves on its own timer regardless of what Crop Steering is doing, causing double-watering.
input_boolean.irrigation_maintenance_modeEmergency close. When toggled ON, immediately closes all valve switches and blocks any further GW irrigation. Use when you need to physically work on the water system and want a software-level guarantee nothing opens. Turn OFF to resume normal operation.
input_boolean.irrigation_co2_enabledEnables the CO2 injection automation. When OFF, the CO2 solenoid will not open regardless of room ppm. Use to disable CO2 without touching the irrigation_co2_target setting.
input_boolean.irrigation_environment_enabledGates all GW climate automations: dehumidifiers, humidifier, and CO2 (CO2 also requires its own toggle). Turn OFF to fully disable climate control, e.g. during HVAC maintenance or when running the room manually.

Read-Only Sensors: What the Numbers Mean

Understanding VWC — What Do These Numbers Actually Mean?

VWC (Volumetric Water Content) tells you how full of water your substrate is, as a percentage of its total volume. A reading of 60% means 6 out of every 10 litres of your coco coir is water. Your GroundWork probes measure this by reading how easily electricity passes through the medium — wet coco conducts much better than dry coco.

~20%
🚨 Danger
Roots drying
out. Wilting.
40%
⚠️ Emergency
Rescue shot
fires here
~55%
P0 exit
Dryback goal
reached
60%
✅ P2 trigger
Maintenance
shot fires
65%
✅ P1 target
Ramp-up done
Enter P2
70%
🔵 Field cap.
Shots skip
above this
~90%
🚨 Flooded
No oxygen
Root rot risk

Understanding EC (pWEC) — What Do These Numbers Mean?

EC = Electrical Conductivity. Your probes measure pWEC (Pore Water EC) — the nutrient concentration in the actual water sitting in your substrate right now. Higher number = more concentrated nutrients. Units are mS/cm. Think of it like this: pure water = 0. Tap water = ~0.3–0.8. A proper nutrient solution = 2–6+. A salt flat = very high.

EC Below 2.0

Too Dilute

Nutrients being used faster than replenished. Plants may yellow or show deficiencies. Check feed concentration.

EC 3.0–4.0

Ideal Veg

Healthy range for vegetative growth with Athena nutrients. System aims to hold EC here during P2 maintenance.

EC 4.0–6.0

Ideal Flower

Higher concentration for flowering. Mild stress from elevated EC promotes resin production. Target rises with Late_Flower stage.

EC 6.0–9.0

High

Salt buildup risk. System fires bigger shots to dilute. Plants may struggle to absorb water. Check drainage and feed ratio.

EC Above 9.0

Danger

Safety ceiling. Irrigation may pause. Likely salt accumulation from poor drainage or over-feeding. Manual flush required.

How Shot Size and Valve Duration Are Calculated

Every time the system decides to water, it converts a percentage into an exact valve-open time. You need to set substrate_volume, dripper_flow_rate, and drippers_per_plant correctly or it will over/under-water even if the phase logic is perfect.

Volume (L) per plant = Substrate Volume × Shot % ÷ 100
Example: 10 L substrate × 5% shot = 0.5 L per plant
Duration (min) = Volume ÷ (Flow Rate × Drippers per Plant) × 60
Example: 0.5 L ÷ (2 L/hr × 2 drippers) = 7.5 minutes valve open
⚙️ If your dripper is 1.6 L/hr but you have it set to 1.2, the valve stays open too long and you over-water by 33%. Measure your actual dripper flow rate with a cup and a timer.

System Health Score — sensor.crop_steering_system_health_score

A composite 0–100 score reflecting overall system health. 100 = all systems nominal, 0 = critical failure. Calculated from four 25-point components:

ComponentPointsWhat Reduces It
Sensor Health0–25Probes offline, stale (>10 min since last reading), or flagged faulty by the Kalman filter outlier check. Each degraded or offline sensor deducts proportionally. All 6 zones healthy = full 25 pts.
Phase Health0–25Zones stuck too long in a phase (P0 >4 h, P1 >3 h without VWC progress), phase mismatches vs. time of day, or zones that never advanced past P0 since lights-on.
Irrigation Health0–25VWC not responding to shots (possible clog or sensor issue), emergency shots firing, zones hitting their daily volume ceiling, or shot count exceeding 20/day per zone.
EC Health0–25EC ratio outside the 0.8–1.2 normal band, EC trending upward across multiple consecutive readings, or substrate EC approaching the maximum safe limit (9.0 mS/cm).
ScoreStatusSuggested Action
90–100ExcellentNo action needed.
75–89GoodMonitor. Minor degradation — check for trends.
60–74FairInvestigate. Check sensor status and EC ratios.
40–59PoorActive issues. Check for stuck phase, offline probe, or EC drift.
<40CriticalImmediate review. Hardware or sensor failure likely.

Health Score Breakdown — 4 components, 25 pts each

90–100 pts
All good. No action needed.
75–89 pts
Good. Minor issue somewhere — watch for trends.
60–74 pts
Fair. Check sensor status and EC ratios.
40–59 pts
Poor. Active problem — phase stuck, probe offline, or EC drifting.
Below 40 pts
Critical. Hardware or sensor failure likely. Review immediately.

Zone Safety Status — sensor.crop_steering_zone_N_safety_status

ValueMeaning & Action
safeAll 15 safety checks pass. Normal operation.
approaching_saturationVWC > 75% (nearing field capacity). Shots are skipped until VWC naturally drops. No action needed unless it persists for hours — if so, the sensor may be reading high.
emergencyVWC dropped below the emergency threshold. A rescue shot has fired or is queued. Check why VWC dropped — large plant demand, missed P2 shot, or sensor spike are common causes.
locked_outZone received 4+ consecutive emergency shots with <1% VWC lift each time. Permanent lockout activated — the system gave up trying because nothing is working. Likely cause: clogged dripper, no water pressure, or sensor malfunction. Fix the physical issue then fire crop_steering_reset_emergency event with {zone: N}.
sensor_errorVWC or EC probe is offline, stale, or returning out-of-range values. Zone holds its current state. Check ESPHome device for the relevant probe.
max_volume_reachedZone hit its zone_N_max_daily_volume limit for today. No more shots until midnight. If this fires regularly, the daily volume limit needs to be raised or something is causing excessive shots.

App Status — sensor.crop_steering_app_status

ValueMeaning
safe_idleAppDaemon running normally. No active irrigation. System is monitoring sensors and evaluating phase transitions every 60 s.
irrigating_zone_NZone N valve is currently open. Only one zone at a time. Typical duration: 3–15 min per shot depending on shot size.
startingApp just restarted. 120-second startup grace period — emergency irrigation is suppressed during this window to avoid false triggers on stale sensor data.
errorAppDaemon encountered an unhandled exception. Hardware is safe — the finally block closes all valves on any error. Check AppDaemon logs at Settings → Add-ons → AppDaemon → Log.

Zone Phase — sensor.crop_steering_zone_N_phase

Current phase for this zone: P0, P1, P2, or P3. If this shows an unexpected phase (e.g. stuck in P3 mid-morning), verify that lights_on_hour matches the actual light schedule and that select.crop_steering_zone_N_phase_override is set to Auto.

Daily Water Volume — sensor.crop_steering_zone_N_daily_water_app

Liters delivered to this zone today (resets at midnight). Compare against zone_N_max_daily_volume to see headroom. Healthy reference: 4 large plants in veg typically consume 15–25 L/day. Consistently near the daily limit suggests you need to raise the cap. Consistently very low (<5 L) suggests the zone may be stuck in P0/P3 or the VWC threshold is set too low to trigger shots.

Fused VWC / EC — sensor.crop_steering_fused_vwc & _fused_ec

Kalman-filtered weighted averages across all active zone sensors. Each probe is weighted by its reliability score (0.0–1.0): excellent sensors get 1.2× weight, degraded sensors get 0.8×. These fused values are not used for per-zone irrigation decisions (each zone uses its own probe exclusively), but are used by the AI heartbeat for system-level anomaly detection and on the dashboard overview cards.

AI Heartbeat — sensor.crop_steering_ai_heartbeat

Updates every 15 minutes. The sensor value is a summary string; the entity attributes contain a per-zone breakdown: current phase, VWC %, EC ratio, shot count, and any flagged anomalies. Anomalies listed in attributes: p0_stuck (P0 >4 h), sensor_stale (>15 min), no_vwc_response (VWC not rising after shots), ec_trending_up, excessive_shots (>20/day), override_long (>24 h). Zero anomalies = healthy.

Events

EventPayloadWhat It Does
crop_steering_trigger_zone_shot{zone: N, source: "manual"}Fires one immediate shot for the specified zone. Same as the dashboard trigger button. Blocked by manual_override.
crop_steering_reset_emergency{zone: N} or omit zone for allClears the emergency lockout counter and permanent lockout flag for the specified zone(s). Use after fixing the physical issue that caused 4+ failed emergency shots.
crop_steering_manual_override{zone: N, action: "enable"/"disable", timeout_minutes: 60}Programmatically sets or clears a timed manual override. The override auto-releases after timeout_minutes. AI heartbeat flags overrides active longer than 24 h.

9. Configuration Files

crop_steering.env

ZONE_1_SWITCH=switch.irrigation_table_1_valve
ZONE_1_VWC_SENSORS=sensor.substrate_1_substrate_1_vwc_coco_coir
ZONE_1_EC_SENSORS=sensor.substrate_1_substrate_1_pwec
ZONE_1_PLANT_COUNT=4
ZONE_1_MAX_DAILY_VOLUME=20.0
ZONE_1_SHOT_MULTIPLIER=1.0

apps.yaml

master_crop_steering:
  module: crop_steering.master_crop_steering_app
  class: MasterCropSteeringApp
  hardware:
    pump_master: null
    main_line: switch.irrigation_mainline
    zone_valves: {1: switch.irrigation_table_1_valve, ...}
  timing: {phase_check_interval: 60}
  thresholds: {emergency_vwc: 40.0}

Lights: lights_on_hour = 8, lights_off_hour = 20.


10. Dashboards

DashboardPathPurpose
GW Irrigationgw-irrigationTimer scheduler, table enables, hardware, safety
Crop Steering AIcrop-steeringPhases, VWC/EC, zone tuning, AI oversight, all parameters
CO2 & Environmentco2-environmentCO2, dehumidifier, temp/RH targets

11. Zone Management CS

zone_N_enabledzone_N_manual_override
PurposeInclude/excludeAbsolute lockout
Emergency?Still gets emergencyNo. Nothing waters.
Use forZone unusedMaintenance, flushing
Override = absolute. No auto, no emergency, no manual trigger, no ML. Checked at selection, evaluation, and valve actuation.

Groups: A/B/C/D. ≥50% needing water → all irrigate. Max 1 concurrent zone.
Priority: Critical(4) > High(3) > Normal(2) > Low(1). Score = Priority 40% + VWC Need 40% + Phase Urgency 20%.


12. Phase Parameters CS

These are the underlying numeric parameters that drive phase behavior. Most are accessible as number.crop_steering_* entities. Adjusting these allows fine-grained control of the irrigation strategy beyond just changing growth stage.

P0 — Morning Dryback Parameters

ParameterDefaultRangeWhat It Does & Why You'd Change It
veg_dryback_target50%20–80%How far VWC must fall from its morning peak before P0 exits and P1 starts. Expressed as % of peak, not absolute VWC. If peak VWC is 70% and this is 50%, P0 exits when VWC reaches 35% (70 × 0.50 = 35). Higher value = deeper dryback = more generative stress. Lower = shallower, quicker exit to watering. Vegetative: 45–55%. Early flower: 40–50%. Late flower: 35–45%.
gen_dryback_target40%20–70%Same as above but used when growth stage is Early_Flower or Late_Flower. Allows the system to automatically apply a different (deeper) dryback in flowering without manual adjustment. The crop profile's generative setting kicks in automatically when you change the growth stage dropdown.
p0_min_wait30 min10–180 minMinimum time P0 must run before it can exit, even if the dryback target is already met. Prevents instant P0 exit if sensors are fluctuating or if VWC was already low at lights-on. Ensures at least some dryback window occurs every morning.
p0_max_wait120 min30–360 minMaximum time P0 is allowed to run before it is forced to exit to P1 even if the dryback target was never met. Safety valve against substrate that dried too slowly, miscalibrated sensors, or cool/humid conditions where evapotranspiration is very slow. The AI heartbeat also independently forces P1 at 4 h.
p0_dryback_drop15%5–40%Minimum absolute VWC drop (not relative to peak) required before P0 can exit. Even if the relative target is met, VWC must have dropped by at least this many percentage points from peak. Prevents P0 from exiting if the substrate started very dry and the relative target would be met after only a tiny drop.

P1 — Ramp-Up Parameters

ParameterDefaultRangeWhat It Does & Why You'd Change It
p1_initial_shot2%1–10%Size of the very first shot when P1 begins. Starting small avoids shocking a dry root zone with too much water at once, and gives the sensor time to confirm VWC is actually rising. Smaller initial shots are better for fine coco and sensitive strains. Larger if substrate drains very fast and needs more water to register a reading.
p1_increment0.5%0.1–3%How much each successive P1 shot grows beyond the last. Shot size = p1_initial_shot + (p1_increment × shot_count). Progressive ramping avoids over-saturating the substrate at the start of the day. With defaults: shot 1 = 2%, shot 2 = 2.5%, shot 3 = 3%, etc. Lower increment = more gradual ramp. Higher = faster wet-up.
p1_max_shot10%3–20%Cap on how large a single P1 shot can grow. Even as the progressive formula increases shot size, it cannot exceed this value. Prevents a runaway ramp from over-saturating late in P1 if VWC is slow to respond.
p1_time_between15 min5–60 minCooldown between P1 shots. After a shot fires, the system waits this long before the next shot even if VWC hasn't reached target yet. Allows the substrate and sensor to equilibrate after each shot — coco can take 5–15 min to fully absorb a shot and for VWC readings to stabilize. Reduce if sensors stabilize quickly; increase if readings spike then drop.
p1_min_shots31–10Minimum number of P1 shots that must be delivered before P1 can exit to P2, even if p1_target_vwc is already met. Ensures some ramp-up happens even if the substrate started near the target. Prevents instant P1-to-P2 transition on sensor noise.
p1_max_shots63–20Maximum P1 shots before P1 is forced to exit to P2 even if target VWC was never reached. Safety cap. If P1 fires 6 shots and VWC still hasn't hit 65%, something is wrong (possible clog, or target is too high for this substrate). After 6 shots, the system moves on to P2 maintenance mode.

P1 Shot Progression — shots get progressively larger (default settings: 10 L substrate, 4 plants, 2 drippers × 2 L/hr each)

Why does P1 start small and grow? A dry substrate after overnight dryback can't absorb a large shot instantly — the water would channel through and drain before the roots can use it. Starting with a 2% shot lets the root zone re-wet slowly, gives the VWC sensor 15 minutes to stabilize, and confirms the substrate is actually absorbing water (not just running straight through a clogged zone) before committing to a bigger shot.

P2 — Maintenance Parameters

ParameterDefaultRangeWhat It Does & Why You'd Change It
p2_vwc_threshold60%40–80%VWC trigger for maintenance shots. When VWC drops below this level during P2, a shot fires. This is the "keep full" level for the day. Should be 3–10% below p1_target_vwc to allow natural VWC swing without constant triggering. Raising this makes the system water more frequently (wetter/vegetative). Lowering gives more dryback between shots during the day (drier/generative).
p2_shot_size5%1–20%Size of each P2 maintenance shot as a percent of substrate volume. Larger shots mean less-frequent irrigation with bigger swings in VWC. Smaller shots mean more frequent, gentler top-ups. For high-frequency irrigation (5–10 shots/day), smaller shots (3–5%) are typical. For low-frequency (2–4 shots/day), larger shots (7–10%) are used.
p2_ec_high_ratio1.21.0–3.0EC ratio threshold above which shots are enlarged. If substrate_EC ÷ target_EC > 1.2, the shot is scaled up by 1.5× to flush excess salts. Lowering this threshold makes the system flush more aggressively at lower EC ratios. Raise it if EC naturally runs slightly above target and you don't want constant larger shots.
p2_ec_low_ratio0.80.3–1.0EC ratio threshold below which shots are reduced. If substrate_EC ÷ target_EC < 0.8, the shot is scaled down by 0.7× to conserve nutrients and let EC build. Only active when ec_stacking_enabled is ON. If ec_stacking is OFF, low EC has no effect on shot size.

P3 — Pre-Lights-Off / Overnight Parameters

ParameterDefaultRangeWhat It Does & Why You'd Change It
p3_emergency_vwc40%20–60%VWC level that triggers an emergency rescue shot during P3. Normally plants dry overnight without any irrigation. If VWC drops below this threshold, it means the plant is at risk of wilting stress. The threshold must be low enough to allow a full overnight dryback without triggering, but high enough to catch genuine emergency depletion. Raise if you have large plants with high overnight demand; lower if your substrate holds water well overnight.
p3_emergency_shot2%1–10%Size of the rescue shot fired during P3 emergencies. Small by design — just enough to pull the plant back from the edge without disrupting the overnight dryback trajectory. Larger shot = more dryback interrupted. Keep this small (2–4%) and rely on the next morning's P1 for full wet-up.

13. EC Targets CS

RatioResponse
< 0.8Reduce shot (conserve)
0.8–1.2Normal
> 1.2Increase shot (flush)
> 2.0 (P3)Emergency shot
> 2.5 (P0)Flush during dryback
PhaseVegGen
P03.04.0
P13.05.0
P23.26.0
P33.04.5
Flush0.8

EC Ratio Visual — How the System Adjusts Shot Size

The system doesn't just react to the raw EC number — it divides your measured substrate EC by the phase target EC to get a ratio. A ratio of 1.0 means you're exactly on target. The ratio tells it whether to water more (flush salts) or less (let EC build). This is what the ratio means visually:

EC Ratio = Measured Substrate EC ÷ Phase Target EC

EC Stacking
Build EC
(if enabled)
⬇ Reduce
shot size
✅ Normal
No adjustment
⬆ Bigger
shot (flush)
🚨 Emergency
P3 flush
P0
Flush shot
0–0.7
0.8
0.8 — 1.2
1.2 — 2.0
2.0
2.5+
Worked example: You're in P2 veg. Target EC = 3.2 mS/cm. Your probe reads 4.6 mS/cm. Ratio = 4.6 ÷ 3.2 = 1.44 — above 1.2, so the system fires a 1.5× larger shot to dilute the substrate. If it still reads high next shot, it fires another large shot.
Another example: Probe reads 2.1 mS/cm. Ratio = 2.1 ÷ 3.2 = 0.66 — below 0.8. If EC Stacking is ON, the system reduces shot size to let EC build back up. If EC Stacking is OFF, it ignores it and waters normally.

14. Per-Zone Targets CS

0 = use system default. > 0 overrides for that zone.

TargetSystemPer-Zone
Drybackveg_dryback_targetzone_N_dryback_target
P1 VWCp1_target_vwczone_N_p1_target_vwc
P2 thresholdp2_vwc_thresholdzone_N_p2_vwc_threshold
P3 emergencyp3_emergency_vwc_thresholdzone_N_p3_emergency_vwc

15. Manual Override CS

ON = nothing waters. No auto, no emergency, no trigger. 4-layer detection. AI flags >24h active. Timed overrides via event.

16. Emergency Irrigation CS

VWC < 40% → 60s shot. 120s startup grace. 300s cooldown. Skips overridden zones.

CountLockout
1st2h
2nd4h
3rd8h
4th+Permanent

VWC lift < 1% over 3+ shots → sets ceiling. Reset: crop_steering_reset_emergency event.


17. AI Heartbeat CS

Every 15 min. 6 checks:

#AnomalyAction
1P0 stuck >4hForce P1
2Sensor stale >15mWarning
3VWC no responseSet ceiling
4EC trending upWarning
5>20 shots/dayWarning
6Override >24hWarning

18. Safety Layers BOTH

Crop Steering (per shot)

  1. System enabled
  2. Auto irrigation (auto only)
  3. Zone enabled
  4. Override OFF
  5. Tank not filling
  6. VWC < field capacity (80%)
  7. EC < max (9.0)
  8. Daily volume < 20L
  9. VWC < 90%
  10. EC < 15.0
  11. >10 min since last
  12. <50 shots/day
  13. Phase-specific
  14. Max 1 concurrent zone
  15. Async lock

Watchdog (60s): flag/hardware mismatch detection. Sensor fail-safe: all offline + hardware on → stop. Clean shutdown on terminate.

Safety Gate — every shot request passes through ALL of these checks in order. Any single NO = shot is blocked, no exceptions.

flowchart LR
    REQ(["💧 Shot\nRequested"])
    C1{"System\nEnabled?"}
    C2{"Manual\nOverride\nOFF?"}
    C3{"Auto\nIrrigation\nEnabled?"}
    C4{"VWC below\nField Cap?"}
    C5{"Daily Volume\nunder limit?"}
    C6{"10+ min\nsince last\nshot?"}
    C7{"EC under\nmax 9.0?"}
    C8{"Under 50\nshots today?"}
    FIRE(["✅ Valve\nOpens"])
    STOP(["🚫 Shot\nBlocked"])

    REQ --> C1
    C1 -- "NO" --> STOP
    C1 -- "YES" --> C2
    C2 -- "Override ON\nabsolute block" --> STOP
    C2 -- "OFF" --> C3
    C3 -- "NO\n(manual shots\nstill allowed)" --> C4
    C3 -- "YES" --> C4
    C4 -- "Already full\nor over 90%" --> STOP
    C4 -- "YES" --> C5
    C5 -- "Daily limit\nhit" --> STOP
    C5 -- "OK" --> C6
    C6 -- "Too soon" --> STOP
    C6 -- "OK" --> C7
    C7 -- "Too high" --> STOP
    C7 -- "OK" --> C8
    C8 -- "Too many" --> STOP
    C8 -- "OK" --> FIRE

    style REQ fill:#1c2128,stroke:#58a6ff,color:#e6edf3
    style STOP fill:#2d0f0f,stroke:#f85149,color:#f85149
    style FIRE fill:#0f2d1b,stroke:#3fb950,color:#3fb950
Why won't my zone water? Work through this flowchart left to right. The most common reasons (in order of frequency): 1) Manual override is ON — check zone_N_manual_override. 2) It already watered too recently — 10-minute cooldown. 3) Zone hit its daily volume limit — check zone_N_max_daily_volume. 4) VWC probe is offline or stuck — check ESPHome device status. 5) VWC is already above field capacity — it doesn't need water yet.

GW Safety

ProtectionWhat
Valve watchdogOpen >180s → force close + alert
Mains watchdogOpen >24 min → kill
Leak abortEmergency stop (sensor unmapped*)
Tank lowClose all (sensor unmapped*)
Maintenance modeClose all immediately
Sensor offlineAlert after 10 min. CO2 offline → close solenoid.
Daily audit 3 AMForce-close all + CO2
CO2 lights-offAlways close at lights off

* Leak and tank-low are hardcoded false. Won't fire until sensors installed.


19. Sensor Fusion CS

  1. Outlier — VWC 0–100, EC 0–20, >4 sigma. Min deviation: VWC 5%, EC 1.0.
  2. Reliability — 0–1 per sensor.
  3. Health — excellent/good/degraded/faulty/offline (30+ min).
  4. Fusion — Weighted average. Excellent 1.2x, degraded 0.8x.
  5. Kalman — Separate VWC/EC filters.

Stale: 600s (10m). AI flags: 900s (15m).


20. Crop Profiles CS

ProfileDrybackECBest For
Cannabis_Athena15–25%3–9Athena nutrients
Cannabis_Indica12–22%2.8–8Dense, short
Cannabis_Sativa18–30%3.2–9.5Tall, stretchy
Cannabis_Hybrid15–25%3–8.5General
Tomato8–15%2–4.5High-freq
Lettuce5–10%1.2–2.5Very high-freq

Stages: Vegetative → Early Flower → Late Flower. Adaptive: 0.1 rate, 0.8 momentum, min 10 samples.


21. Persistent State CS

Saved 5 min + on irrigation. Restores: phases (corrected for lights), P0/P1 tracking, water usage (same-day/week), overrides (with timeout), last irrigation. 10MB limit.


22. Commissioning

1. Verify Hardware

  1. ESPHome devices online: Settings → Devices → ESPHome
  2. sensor.irrigation_table_1_vwc shows number. Check all 6.
  3. Test each valve via Developer Tools. Listen for click. Off immediately.
  4. Test mainline briefly — pump should start.

2. Configure Crop Steering

  1. Verify crop_steering.env entity IDs
  2. Add integration: Settings → Integrations → Crop Steering → Load from .env
  3. Set lights_on=8, lights_off=20
  4. Set irrigation_irrigation_enabled OFF

3. Environment

  1. Set temp/RH/CO2 targets on CO2 & Environment dashboard
  2. Enable irrigation_co2_enabled and irrigation_environment_enabled

4. Start

  1. crop_steering_system_enabled ON
  2. Check app_status = safe_idle
  3. Watch for P0→P1 after lights on

23. Troubleshooting

SymptomFix
Zone not wateringCheck override OFF, enabled ON. Reset emergency if locked out.
Too many shotsDripper blocked or sensor bad. Auto-lockout after 4 rapid shots.
Stuck in P3Check lights_on/off_hour match schedule.
Stuck in P0Lower dryback target. AI forces P1 after 4h.
Phase changes ignoredZone phase override must be "Auto".
"Entity not found"Entities have crop_steering_ prefix.
VWC "Unavailable"ESPHome device offline. Check network.
Double wateringirrigation_irrigation_enabled must be OFF.
CO2 not injectingLights must be on + irrigation_co2_enabled ON.
Valves stuckirrigation_maintenance_mode ON, or script.irrigation_emergency_stop, or power off relay.

Emergency Stop

  1. irrigation_maintenance_mode ON
  2. script.irrigation_emergency_stop
  3. crop_steering_system_enabled OFF
  4. Power off relay board

24. Known Issues & Unmapped Hardware

Unmapped

ItemImpact
Leak sensorCRITICAL: Abort hardcoded false
Tank float switchCRITICAL: Abort hardcoded false
Tank pH/ECUnavailable on dashboard
Waste valve, ceiling ventTODO placeholders
AC automationEntities mapped, no logic

Software

Shot Reference

10L substrate, 2 L/hr drippers, 2 per plant, 4 plants:

TypeSizeTimeVolume
P1 initial2%3 min0.8L
P2 maintenance5%7.5 min2.0L
P0 flush10%15 min4.0L

Notifications: notify.mobile_app_damians_iphone.


Crop Steering System Guide v2.3.1 — April 2026 — Verified from codebase audit