System Architecture

Verdify is deliberately boring infrastructure around a deterministic edge controller: one local VM runs TimescaleDB, the ingestor, MCP, FastAPI, Grafana, the publisher, and the Iris, the AI planner planning path. Iris reads greenhouse context through validated tools and writes bounded tactical setpoints. Weather data, public delivery, and optional mirrors still use external services where useful. If those services disappear, the ESP32 still owns relay state and continues enforcing the last valid bounded setpoints plus hard safety rails. The safety split is detailed in Why the AI Does Not Control Relays.

Architecture layer list:

  1. Physical greenhouse: plants, zones, equipment, intake/vent constraints, solar gain, slab thermal mass.
  2. ESP32 firmware: real-time relay state machine, hard safety rails, readbacks, and fallback setpoints.
  3. Local data plane: ingestor, TimescaleDB, scorecards, forecasts, setpoint dispatcher, and MCP tools.
  4. Planning plane: Iris, validated MCP tools, planner audit logs, Slack brief, and scorecard feedback.
  5. Public proof plane: Quartz pages, Grafana dashboards, generated plans, sample data, and known-limit documentation.

Planner availability note: model routing is not the safety layer. The ESP32 remains safe if the planner is unavailable.

The exact set of planner-writable parameters is documented in AI-Writable Tunables.

Verdify greenhouse control architecture

The Complete Loop

Sense

The ingestor subscribes to about 172 ESPHome entities from the ESP32 and records sensor, relay, setpoint, and controller state.

Store

Ingestor writes climate, equipment, energy, forecast, and setpoint data into TimescaleDB.

Analyze

Views and scorecard functions turn raw telemetry into stress, compliance, cost, and forecast accountability.

Plan

Iris reads MCP context, historical lessons, forecasts, scorecards, and prior plans, then writes tactical setpoints and plan journal entries.

Act

The dispatcher pushes changed tunables back to the ESP32; firmware enforces relay patterns every 5 seconds.

Learn

Measured outcomes score the plan and promote useful findings into lessons for the next cycle.

ESP32 Controller

8-state firmware, relay outputs, safety fallbacks, encrypted native API.

Ingestor Service

Sensor subscription, periodic tasks, forecast sync, setpoint dispatcher.

TimescaleDB

Climate rows, equipment state, setpoints, analytical views, planner scorecard.

MCP Server

Tools for climate, forecast, equipment, crops, alerts, scorecards, and tunables.

Iris Planner

Planning agent with MCP tools, retrieval context, scorecards, prior plans, and validated lessons.

Slack Briefs

Human-readable reasoning, plan summaries, and greenhouse notifications.

Three Layers

The system has three distinct control layers, each with a different time scale and responsibility:

Layer 1: Crop Target And Firmware Bands (minutes)

Computed from the diurnal profiles of all active crops. The dispatcher computes the active crop band, derives the whole-house VPD control band from zone targets, and pushes temp_low, temp_high, vpd_low, and vpd_high. Night: 62-65°F. Peak day: 72-78°F. Firmware does not model day/night policy; it enforces the latest firmware band plus hard safety rails. Plant science defines what conditions the greenhouse should target; the dispatcher translates that into one enforceable air-mass band.

Layer 2: Iris Planner (minutes to hours)

Iris responds to solar milestones and environmental changes. It reads live telemetry, forecast, crop bands, prior plans, scorecards, validated lessons, and the planner context window that describes the greenhouse’s physical constraints. It adjusts the required tactical plan parameters for each transition, with registry-approved tunables available as bounded escape hatches. These values shape hysteresis widths, mister timing, fog thresholds, thermal biases, and water-budget behavior. The planner decides how hard to try, not which relay to energize.

See AI-Writable Tunables for the names, defaults, bounds, ownership, and state-machine effects of those parameters.

Layer 3: ESP32 Mode Controller (seconds)

8 priority-ordered states evaluated every 5 seconds: 7 non-idle safety/control states plus IDLE. Pure C++ (greenhouse_logic.h) compiles identically on ESP32 and x86. The mode controller enforces the band + tunables with physical equipment. If the AI goes offline, the ESP32 keeps its last setpoints.

Crop Science

Defines what to target: hourly temperature and VPD bands from active crop profiles.

Iris

Defines how hard to try: hysteresis, misting, fog, fan, heat, and water-budget tactics.

ESP32

Defines how to enforce: 8 priority-ordered states in a 5-second loop.

Equipment

Fans, heaters, vent, misters, fog, grow lights, and irrigation.

Event-Driven Planning

Instead of running on a fixed schedule, Iris responds to natural transition points in the greenhouse day. The ingestor computes solar milestones from ephemeris data each morning.

06:28 Sunrise

Full morning brief, scorecard review, and tactical plan.

15:01 Peak Stress

Maximum cooling, misting, and water-budget pressure.

17:01 Tree Shade

Reduce aggression as solar load drops on the east side.

18:34 Decline

Transition from heat rejection to evening stability.

19:34 Sunset

Full evening brief and overnight plan.

Sunrise and sunset produce full planning briefs — yesterday’s scorecard, today’s forecast, tunable adjustments with reasoning. Transitions are brief — Iris checks conditions and adjusts only if needed. Deviations trigger immediate response when observed conditions diverge from forecast.

Data Pipeline

About 172 ESPHome entities flow from the ESP32 through the encrypted native API into TimescaleDB at sub-minute freshness:

ESP32 sensorsaioesphomeapi, encrypted, about every 2 seconds

Writes zone climate, hydro, and outdoor merge data into the climate table.

ESP32 relaysaioesphomeapi, on change

Writes physical equipment transitions into equipment_state.

ESP32 modeaioesphomeapi, on change

Writes controller state transitions into the system-state stream.

WeatherTempest every 5 minutes, Open-Meteo hourly

Feeds outdoor context and 16-day forecast rows used by planning and forecast accountability.

Iris plannerMCP tools, event-driven

Reads greenhouse context and writes tactical setpoints and plan records through set_tunable() and plan-management tools.

Dispatcheraioesphomeapi push, every 5 minutes

Pushes changed tunables back to ESPHome number/switch entities and verifies the result through cfg_* readbacks.

The HTTP /setpoints surfaces still exist as key=value compatibility endpoints for diagnostics and recovery tooling. The current production firmware does not run an on-device HTTP poller; direct ESPHome API push plus readback confirmation is the live setpoint path.

Activity, Lighting, And Direct Wetting

The greenhouse has one global biological activity window. The main lighting circuit policy supplies the start hour and daily qualified-light-minutes target; the dispatcher mirrors those values into activity_start_hour, activity_start_minute, and activity_duration_min. Firmware uses the same activity window for direct-wet permission.

Each wetting zone then has its own tunable start offset and drydown hold:

Zone/pathDefault wet startDefault drydown before activity offApplies to
Wall dripactivity + 60 min120 minwall clean/fert drip and flush
South mistersactivity + 60 min120 minsouth clean/fert misters
West mistersactivity + 60 min120 minwest clean/fert misters
Center wettingactivity + 120 min180 mincenter mister and center clean/fert drip

The current live activity policy is 06:00-22:00 from a 960-minute main-light target. With the defaults above, the center wetting window is 08:00-19:00 and the wall/south/west wetting windows are 07:00-20:00, subject to the 65°F direct-wet minimum temperature and normal climate or irrigation demand.

Planner Score (KPI)

Performance is measured by an automated composite score:

80% Compliance

Time inside crop temperature and VPD bands.

20% Cost

Daily utility efficiency.

  • Compliance = % of day with temp AND VPD inside crop band. Target: >90%.
  • Cost efficiency = daily utility spend. <USD 5/day = full marks, USD 15+ = zero.
  • Stress hours tracked as 4 independent states: heat, cold, VPD-high, VPD-low.
  • Iris reviews the scorecard at every sunrise and sunset event.

Physical Constraints

367 sq ft

Elongated hexagon with six distinct microclimates.

5,090 ft

Thinner air and extreme spring VPD shape every control decision.

~87,000 BTU/hr

Peak solar gain drives the thermal problem.

~34k-39k BTU/hr

Effective cooling capacity after altitude and intake constraints.

~49,000 BTU/hr

Peak cooling deficit above 85°F without shade cloth.

24"×24" intake

Four square feet of vent area is undersized for 4,900 CFM exhaust.

800W AquaFog

About seven times more effective than mister pulses for VPD recovery.

54,000 BTU/hr gas heat

Altitude-derated output, still about 3.9× cheaper than electric heat.

~7,300 BTU/°F slab

Thermal mass creates an 11.5-hour time constant and 7-10°F overnight retention.

The system doesn’t pretend these limits don’t exist. The AI knows the cooling deficit. It knows fog is 7× more effective than misters. It plans around physics, not through it.


Deeper dives: The Planning Loop - Safety Architecture - Related Work - Lessons Learned