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 local Iris (our OpenClaw AI agent) path. OpenClaw routes Iris to Gemma 4 26B A4B (MoE), served locally under the gemma4-26b alias, for routine inference and to a larger cloud peer for heavyweight reviews. 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:
- Physical greenhouse: plants, zones, equipment, intake/vent constraints, solar gain, slab thermal mass.
- ESP32 firmware: real-time relay state machine, hard safety rails, readbacks, and fallback setpoints.
- Local data plane: ingestor, TimescaleDB, scorecards, forecasts, setpoint dispatcher, and MCP tools.
- Planning plane: OpenClaw, Iris, local-first
gemma4-26b, cloud peer routing, Slack brief, and audit stamps. - Public proof plane: Quartz pages, Grafana dashboards, generated plans, sample data, and known-limit documentation.
Cloud reasoning note: the cloud peer is a labeled planning route for heavyweight reviews, not the safety layer and not an invisible fallback. The ESP32 remains safe if both local and cloud model routes are unavailable.
The exact set of planner-writable parameters is documented in AI-Writable Tunables.
The Complete Loop
The ingestor subscribes to about 172 ESPHome entities from the ESP32 and records sensor, relay, setpoint, and controller state.
Ingestor writes climate, equipment, energy, forecast, and setpoint data into TimescaleDB.
Views and scorecard functions turn raw telemetry into stress, compliance, cost, and forecast accountability.
OpenClaw routes Iris to Gemma 4 26B A4B (MoE), served locally under the gemma4-26b alias, or a labeled cloud peer; Iris reads MCP context and writes tactical setpoints and plan journal entries.
The dispatcher pushes changed tunables back to the ESP32; firmware enforces relay patterns every 5 seconds.
Measured outcomes score the plan and promote useful findings into lessons for the next cycle.
8-state firmware, relay outputs, safety fallbacks, encrypted native API.
Sensor subscription, periodic tasks, forecast sync, setpoint dispatcher.
Climate rows, equipment state, setpoints, analytical views, planner scorecard.
Tools for climate, forecast, equipment, crops, alerts, scorecards, and tunables.
OpenClaw agent with Gemma 4 26B A4B (MoE), served locally under the gemma4-26b alias, plus cloud escalation for heavyweight reviews.
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 Band (minutes)
Computed from the diurnal profiles of all active crops. The dispatcher computes the one active crop band every 5 minutes 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 active band plus hard safety rails. Plant science defines what conditions the greenhouse should target.
Layer 2: Iris Planner (minutes to hours)
Iris uses OpenClaw to respond to solar milestones and environmental changes. Routine triggers run through Gemma 4 26B A4B (MoE), served locally under the gemma4-26b alias; major reviews can route to a heavyweight cloud peer. Iris 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 24 required tactical plan parameters for each transition, with additional 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.
Defines what to target: hourly temperature and VPD bands from active crop profiles.
Defines how hard to try: hysteresis, misting, fog, fan, heat, and water-budget tactics.
Defines how to enforce: 8 priority-ordered states in a 5-second loop.
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.
Full morning brief, scorecard review, and tactical plan.
Maximum cooling, misting, and water-budget pressure.
Reduce aggression as solar load drops on the east side.
Transition from heat rejection to evening stability.
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:
Writes zone climate, hydro, and outdoor merge data into the climate table.
Writes physical equipment transitions into equipment_state.
Writes controller state transitions into the system-state stream.
Feeds outdoor context and 16-day forecast rows used by planning and forecast accountability.
Routes routine work to Gemma 4 26B A4B (MoE), served locally under the gemma4-26b alias, escalates major reviews to the cloud peer, and writes tactical setpoints and plan records through set_tunable() and plan-management tools.
Pushes changed tunables back to the ESP32 while HTTP pull remains as a fallback.
Planner Score (KPI)
Performance is measured by an automated composite score:
Time inside crop temperature and VPD bands.
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
Elongated hexagon with six distinct microclimates.
Thinner air and extreme spring VPD shape every control decision.
Peak solar gain drives the thermal problem.
Effective cooling capacity after altitude and intake constraints.
Peak cooling deficit above 85°F without shade cloth.
Four square feet of vent area is undersized for 4,900 CFM exhaust.
About seven times more effective than mister pulses for VPD recovery.
Altitude-derated output, still about 3.9× cheaper than electric heat.
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