ESP32 Controller

ESPHome 2026.3.0 on a Kincony KC868-E16P board. 198 entities across sensors, relays, switches, tunables, and diagnostics. The ESP32 evaluates two independent axes — temperature (6 states) and humidity (7 states) — every 5 seconds, producing 42 possible state combinations. Each maps to a specific relay pattern.

Firmware Structure

FileLinesContent
greenhouse-v2.yaml380Top-level: WiFi, SNTP, MQTT, buttons
hardware.yaml292I²C, UART, Modbus, relay definitions
sensors.yaml1,202All sensors, derived metrics, DLI accumulator
globals.yaml584State variables, setpoints, counters
controls.yaml1,050Climate + irrigation + mister state machines
tunables.yaml851HA number/switch/button entities (57 numbers, 8 switches)

Temperature States

StateConditionEquipment
HEAT_S2temp < temp_low - d_heat_stage_2 (55°F)Heat1 + Heat2 (gas)
HEAT_S1temp < temp_low (58°F)Heat1 (electric)
TEMP_IDLEtemp_low ≤ temp ≤ temp_highNothing
COOL_S1temp > temp_high (82°F)Fan1 (lead) + vent
COOL_S2temp > temp_high + d_cool_s2 (85°F)Both fans + vent
COOL_S3temp > 87°FEmergency + evaporative fog

Humidity States (Inverted Hierarchy)

Misters first, fog as escalation. Misters are cheap, targeted, and work with the vent open.

StateConditionEquipment
HUM_IDLEVPD in bandNothing
DEHUMVPD < vpd_low (0.5 kPa)Vent opens
HUMID_S1VPD > vpd_high + hysteresis (2.30 kPa)Mister pulse rotation (highest-VPD zone)
HUMID_S2VPD sustained despite S1Aggressive all-zone mister rotation
HUMID_S3VPD still criticalFOG (1,644W) — aerosol, vent closes

Mister Pulse Model

S1: Pick highest-VPD zone
    → mister_pulse_on_s (60s) burst
    → mister_pulse_gap_s (45s) gap
    → re-read VPDs
    → repeat

S2: Rotate all 3 zones
    → driest zone gets mister_vpd_weight (1.5×) burst
    → 30s gaps between zones
    → re-rank each rotation

Hard rule: Never more than one mister zone simultaneously (water pressure constraint).

Key Interactions

Temp StateHumidity StateBehavior
COOL_S1HUMID_S1Misters pulse freely. Fog suppressed (vent open = aerosol wasted).
COOL_S1+HUMID_S2Aggressive mister rotation. Fog only as S3 escalation.
COOL_S3HUMID_S3Fog WITH vent open — evaporative cooling benefit.
TEMP_IDLEHUMID_S1+Both misters and fog available.
HEAT_S1+HUM_IDLEHeaters only. No humidity conflict.

Safety Rails

ParameterValuePurpose
safety_min45°FEmergency heat below this
safety_max95°FEmergency cooling above this
safety_vpd_min0.3 kPaEmergency dehumidification
safety_vpd_max3.0 kPaEmergency humidification

Key Design Decisions

  1. ESP32 owns real-time control. The AI adjusts setpoints (boundaries), never relay states directly. The firmware makes real-time tradeoffs at 5-second resolution.

  2. Dual-path setpoint delivery. Push via aioesphomeapi (immediate) + pull via HTTP /setpoints (300s fallback). If both fail, hardcoded defaults keep the greenhouse safe.

  3. Inverted humidity hierarchy. Misters first (cheap, targeted, work with vent open), fog as S3 escalation (expensive, vent must close). This was a significant change from the original firmware which used fog first.

  4. Pulse-rotation model. Never more than one mister zone simultaneously. VPD-weighted burst allocation. 60s on / 45s gap is the tuned sweet spot.

  5. Autonomous safety. Safety rails (45–95°F, 0.3–3.0 kPa VPD) override all setpoints. The controller operates independently of the AI layer.

Autonomy

The ESP32 operates independently. If the AI planning layer (Iris) goes offline and both push and pull paths fail, the controller falls back to hardcoded default setpoints and continues managing the greenhouse. Iris makes it smarter, but it doesn’t depend on Iris to survive.