Open hardware · design stage

A room controller for mushrooms, cheap enough to double.

One small board per grow room, each reading doubled and cross-checked, and every loop keeps running with the network unplugged. Anyone may build it, sell it or make it better.

DESIGNParts chosen and priced 2026-10-02
FIRMWARELogic outlined below; code not written yet
TESTEDNot yet: first units go into a working farm's rooms
LICENCECERN-OHL-P v2 hardware · MIT firmware
STATUSBUILDING IN THE OPEN

Why cheap, and why two of everything

A fruiting room sits at 85–95 % relative humidity, around the clock. That kills electronics, including expensive industrial sensors, just more slowly. So this design accepts that sensors die. Each one is cheap enough to keep a spare in a drawer and swap in a minute, and every critical reading has two of them.

How one installation is laid out

Room nodeESP32-S3 board, doubled sensors, relays and 0–10 V outputs. One per room. Runs the room by itself.
Air plant sensorsDuct temperatures, an airflow switch and a coil freeze switch for each fresh-air unit, wired to the nearest room node.
ActuatorsWhatever the room already uses: fans, dampers, humidifiers, dehumidifiers, a cooling unit, hot-water valves. Relays switch them; 0–10 V sets speed and position.
Supervisor (optional)A Raspberry Pi with a touchscreen. It logs every reading, shows all the rooms, and alarms. It never runs a loop, so the rooms don't need it.

The first installation is six rooms (a lab, an incubation room, two fruiting rooms, a pack room and an airlock), each with its own air supply. A grow tent is one room node.

Parts for one room node

Listed US prices on 2026-10-02, before tax, shipping and import tariffs. Links go to the listing priced.

PartWhat it doesQtyUSD
Adafruit ESP32-S3 FeatherThe room's controller117.50
Sensirion SHT45 with PTFE membraneTemperature and humidity, doubled224.30
Senseair S8 LPCO₂ (NDIR), doubled, for drier rooms257.46
Sensirion SDP810-125PaRoom pressure against the corridor or outdoors128.29
Optomax liquid-level switchLeak under the humidifier or drain pan139.95
SainSmart 8-channel relay boardSwitches fans, humidifier, dehumidifier, valves112.99
DFRobot GP8403 0–10 V moduleTwo analog outputs for fan speed or damper position219.80
Printed enclosureASA or PETG box, TPU gasket, two cable glands1about 10 (est.)
One room nodeabout 210

For a fruiting room, use two Sensirion SCD41 CO₂ sensors ($44.96 each) instead of the S8. The S8 is rated non-condensing, and the SCD41's published range runs to 95 % RH. That makes the node about $243. The enclosure cost is an estimate from filament use. A 24 V-to-5 V converter for the board isn't priced yet.

Each fresh-air unit adds

PartWhat it doesQtyUSD
DS18B20 stainless probeDuct temperatures before and after heat recovery217.92
Dwyer ADPS-08-2-N pressure switchProves airflow; a second one flags a dirty filter130.31
Snap-disc thermostat, closes at 35 °FFreeze warning on a hot-water coil115.99
Per fresh-air unit64.22

The supervisor, once per site

PartWhat it doesQtyUSD
Raspberry Pi 5, 2 GBLogger, display, alarms177.50
Raspberry Pi Touch Display 2, 7 inThe screen on the wall188.00
Raspberry Pi 27 W supplyPower for the Pi112.95
Mean Well HDR-150-2424 V for the nodes and relays136.50
APC BE600M1 UPSKeeps the controls up through a short outage183.99
Supervisor298.94

A six-room installation, with five fresh-air units and two of each sensor, comes to about $2,500 of parts. An industrial PLC with industrial sensors, priced for the same rooms the same day, was about $14,500.

How the firmware decides

The code isn't written yet. This is the logic it will follow, in plain pseudocode, so anyone can check the reasoning before the code exists. Each room node runs this loop once a second, on its own.

every second, on each room node:

  1. read
     temp/RH  from sensors A and B
     CO₂      from sensors A and B
     room pressure, leak switch, airflow switch,
     duct temperatures, coil freeze switch

  2. cross-check each doubled pair
     if A and B agree (within 1 °F, 4 % RH, 100 ppm CO₂)
         use their average                           → trusted
     else if one is missing, stuck or out of range
         use the other one, raise a warning          → degraded
     else
         trust neither, raise an alarm               → untrusted

  3. safety first (these override every loop)
     airflow not proven  → humidifier OFF, alarm
     leak detected       → humidifier OFF, water valve CLOSED, alarm
     coil freeze switch  → hot-water valve OPEN, fresh air to minimum, alarm
     CO₂ untrusted       → fresh air to a fixed protective rate, alarm
     temp untrusted      → hold the last good output for 10 minutes,
                           then heat to a fixed safe position, alarm
     RH untrusted        → humidifier OFF, alarm

  4. room loops (only with trusted or degraded readings)
     fresh air:   CO₂ above target → ramp fans and dampers up
                  CO₂ below target → ramp down, never below the minimum
     temperature: below setpoint − band → open the hot-water valve
                  above setpoint + band → run the cooling unit
                  never heat and cool at once, except to dry the air
     humidity:    below the RH band → humidifier ON (needs proven airflow)
                  above the RH band → dehumidifier ON
                  inside the band   → both OFF
     pressure:    trim exhaust against supply to hold the room's target

  5. write outputs
     relays and 0–10 V outputs
     minimum on and off times, so compressors and fans don't short-cycle

  6. tell the supervisor, if it's there
     readings, outputs and alarms every 10 seconds
     sound the room's own alarm whether or not anyone is listening

When things fail

The supervisor's job

on the Raspberry Pi:
  collect readings from every node   → log them, draw the history
  show every room on the touchscreen → readings, outputs, alarms
  send setpoint changes to the nodes → each node stores them itself
  alarm on any node's alarm, or on a node gone silent
  never run a room loop

Example setpoints

RoomTemperatureRH bandCO₂ target / limit
Blue oyster, fruiting58 °F ±285–90 %900 / 1,000 ppm
Lion's mane, fruiting64 °F ±285–90 %750 / 800 ppm
Incubation72 °F ±250–70 %900 / 1,000 ppm
Lab72 °F ±240–60 %900 / 1,000 ppm

These are the first installation's design setpoints, not universal values. Every number is a setting on the node.

If a cheap sensor doesn't survive

The same board takes industrial sensors. Upgrade the one that fails, not all of them:

ReadingCheap partIndustrial part on the same boardEach, USD
CO₂Senseair S8 / Sensirion SCD41Vaisala GMP252, heated head, 4–20 mA1,004.00
Temperature / RHSensirion SHT45Dwyer RHPX, IP66, 4–20 mA149.35
Room pressureSensirion SDP810Setra 264, ±25 Pa, 4–20 mA214.82

A 4–20 mA sensor needs a small current-to-voltage input on the node, not priced here.

What's next

Files will go up on this page as they're made. Anyone is welcome to build it, sell it or make a better one.