Build Notes
Verdify is not a turnkey kit today. These notes are a reference implementation path: enough to understand and rebuild the pattern, without pretending the exact greenhouse wiring is safe to copy blindly.
The safe pattern is:
deterministic edge controller + time-series database + local-first OpenClaw planner + public scorecard
The exact relay map, water pressure, gas heat, wiring, breaker layout, and fail-safes need a local electrician/grower/operator review before anyone copies them.
Hardware Shape
ESPHome firmware, encrypted native API, relay outputs, Modbus inputs, ADC inputs, and fallback HTTP setpoint pull.
Temperature and relative humidity by zone; VPD is computed from temperature and humidity.
Soil moisture, temperature, and EC where installed.
pH, EC, TDS, ORP, and solution temperature through Home Assistant.
Relay-backed equipment controlled by ESP32 firmware, not by the LLM.
Outdoor weather, forecast context, and resource cost/accountability.
See Equipment Inventory for the public-safe equipment inventory and high-level actuator list.
Runtime Stack
Reads sensors and enforces relay state every 5 seconds.
Subscribes to ESPHome state, writes TimescaleDB, runs dispatcher and alert tasks.
Stores climate, equipment, forecast, energy, water, plans, lessons, and scorecards.
Gives Iris (our OpenClaw AI agent) typed tools for state, forecast, scorecards, alerts, lessons, and tunables.
Routes routine events to Gemma 4 26B A4B (MoE), served locally under the gemma4-26b alias, escalates major reviews to a cloud peer, and writes tactical plans and hypotheses using the planner context window.
Publishes public pages, dashboards, daily plans, and sample datasets.
The exact tactical parameters Iris is allowed to write are documented in AI-Writable Tunables.
Example MQTT / Topic Shape
Verdify’s local controller currently uses ESPHome native API as the primary path, with MQTT present in the broader stack. A rebuildable MQTT-first version would use topics shaped like this:
greenhouses/{greenhouse_id}/start/climate/{zone}/temperature_f
greenhouses/{greenhouse_id}/start/climate/{zone}/relative_humidity_pct
greenhouses/{greenhouse_id}/start/climate/{zone}/vpd_kpa
greenhouses/{greenhouse_id}/equipment/{equipment_id}/state
greenhouses/{greenhouse_id}/controller/mode
greenhouses/{greenhouse_id}/setpoints/{parameter}
greenhouses/{greenhouse_id}/setpoints/{parameter}/readback
greenhouses/{greenhouse_id}/alerts/{alert_type}The important rule is not the exact topic naming. It is that every write carries greenhouse_id, every setpoint has a readback, and public data exports omit device identifiers.
Database Overview
| Surface | Tables/views | Purpose |
|---|---|---|
| Climate | climate, v_greenhouse_now, v_setpoint_compliance | What the greenhouse experienced. |
| Equipment | equipment_state, v_equipment_now, v_state_durations | What the controller physically did. |
| Planning | plan_journal, setpoint_plan, v_active_plan | What Iris intended and what is active. |
| Scorecards | daily_summary, v_planner_performance, fn_planner_scorecard() | Whether the plan worked. |
| Lessons | planner_lessons plus generated lesson page | What future plans should remember. |
| Static context | site markdown bundled by context scripts | The greenhouse’s documented physical constraints, equipment, zones, crops, and known limits. |
| Evidence | v_forecast_plan_outcome_mart, sample CSV exports | Public audit artifacts. |
See Data Model for the broader table/view map.
See AI-Writable Tunables for the planner-writable registry: defaults, bounds, ownership, and relay/state-machine impact.
Example Plan JSON
This is a shortened representation of one plan. The real plan journal contains more context and waypoints.
{
"plan_id": "iris-20260429-0605",
"created_local": "2026-04-29 06:04",
"horizon_hours": 72,
"hypothesis": "Cool mixed-cloud day with a short dry solar window. Keep fog conservative and use moderate mist readiness only when observed VPD rises.",
"changed_tunables": [
{
"parameter": "mister_engage_kpa",
"old_value": 2.5,
"new_value": 1.6,
"expected_effect": "Reduce midday VPD-high stress without causing overnight VPD-low stress."
},
{
"parameter": "fog_escalation_kpa",
"old_value": 1.0,
"new_value": 0.85,
"expected_effect": "Reserve fog for real VPD breakout on a cool day."
}
],
"success_criteria": {
"both_axis_compliance_pct": 60,
"vpd_high_stress_h_max": 1.5,
"cost_total_usd_max": 7.0
}
}Example Scorecard JSON
{
"date": "2026-04-29",
"planner_score": 73.5,
"compliance_pct": 74.3,
"temp_compliance_pct": 86.2,
"vpd_compliance_pct": 84.8,
"total_stress_h": 6.93,
"heat_stress_h": 0.88,
"vpd_high_stress_h": 3.28,
"water_gal": 159.0,
"mister_water_gal": 37.0,
"cost_total": 4.42
}Live scorecards are available from the public read-only API, for example /api/v1/scorecard?date=2026-04-29.
Not Production-Safe Yet
For launch, the public artifacts are the site, dashboards, sample CSVs, plan examples, scorecard examples, and build notes. The full live repo stays private until operational details are scrubbed.
The data trust ledger tracks these as instrumentation requirements, not completed capabilities.
Climate control is more mature than crop-outcome attribution.
Do not copy the wiring from photos as an installation guide.
The safety layer is the architecture. Removing it would make the system worse.
What We Would Copy First
- Keep real-time control local and deterministic.
- Put every setpoint behind a typed registry with clamps and readbacks.
- Store raw telemetry and derived scorecards separately.
- Publish failures and stale-data states, not just success charts.
- Treat every plan as a hypothesis that must be scored against the next day.
Next: Baseline vs Iris shows what the public scorecards say about an offline-vs-online planning window.