Fruiting Chamber Controller
Building a controller for my mushroom fruiting chamber.


Mushrooms require tightly controlled environments for maximal production.

Mycodo backup file (zip)


This controller is based on the Raspberry Pi Zero W (wireless). It is an old design and soon to be retired, but it is still a great base. It has python support, GPIO (no analog), and wifi.

edit Just three days ago the raspberry pi org announced the Zero 2 W!. I guess I won’t have to worry about finding an alternative platform after all… and it is already sold out.

Basically, we need a Raspian OS Lite headless install with a static IP, ssh, and Mycodo.


Download the latest version of Raspian OS Lite from the raspberry pi website. We want the lite version to avoid any extra software that they Zero can’t handle. Write the disk image to a SD card.

We are running headless, with the only access coming from mycodo through https. So we need to enable headless start, with a static IP, and ssh access.

Follow the directions for a headless setup.

In short, mount the boot partition and create a file called wpa_supplicant.conf with your wifi credentials and country code.

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev


Similarly, mount the rootfs partition and edit the /etc/dhcpcd.conf file. Modify the example static config to match your network settings. Make sure to change the interface name to wlan0 instead of the default eth0 that the non-wifi Raspberry Pis use.

If for some reason this doesn’t work, find the DHCP address manually and change it via ssh.

SSH is not enabled by default. Place a file called ssh (no extension) in the boot partition. E.g. sudo touch /media/user/boot/ssh. more info

Start your Zero. This will take 5-10 minutes for the first boot.

The first login credentials are
user: pi
password: raspberry

You can copy your ssh credentials from your computer to the pi using ssh-copy-id <USERNAME>@<IP-ADDRESS>.

After you have successfully established a connection, you can remove password authentication and change the ssh port for better security.

sudo nano /etc/ssh/sshd_config


Port 666
PasswordAuthentication no

Change your default password to something more secure: passwd. I suggest using a password manager.

Change your localisation options using sudo raspi-config and activate any interfaces you need (probably I2C, SPI, and 1-wire). Expand your SD card at the same time in the advanced sections. You can set the GPU memory to the lowest available option.

The update your pi sudo apt update && sudo apt upgrade -y and then reboot.

Log in using the new port. You can also do a dist upgrade sudo apt dist-upgrade if you used an old raspian os image for whatever reason.

Then install mycodo:

curl -L | bash

This will take upwards of 45 minutes to finish.



The system is controlled by a Raspberry Pi Zero W. An 8-channel relay board provides power to the (separable) 120V receptacle, four 12V barrel jacks, and two rj11 jacks. You can configure them however you wish, but they are labeled for your convenience.

The two rj11 jacks are useful for fan connections: a pair of wires for each positive and negative supply (for more current capacity), one for PWM, and one for tachometer.

I have included a mount point for an analog to digital converter (ADS1115) since the Zero does not have any analog pins. If you don’t have any analog peripherals, this isn’t necessary.

Description price quantity link
12V, 5A power supply $9 1
Raspberry Pi Zero W (with header) $14 1
SD card
8 channel relay board 1
ADS1115 breakout board (optional) 1
120V receptacle $3 1
120v switch
40mm fan
5.5x2.1mm barrel jack 4
rj11 jack


This will largely depend on your particular use-case. I will describe my own system as an example, but any sensor that works with a raspberry pi or ADC can be used.

Description price quantity link
DS18B20 temperature sensor
SEN0219 CO2 sensor $50 1
AM2320 humidity/temperature sensor $4 1
NMB-MAT 12V blower fan $9 1
12V water pump $7 1
5.5x2.1mm barrel plug $0.25 4
rj11 plug $0.10 7


Type peripheral caseID BCM Pi pin interface
input DS18B20 INPUT1 GPIO7 4 1-wire
input DS18B20 INPUT2 GPIO7 4 1-wire
input DS18B20 INPUT3 GPIO7 4 1-wire
input AM2320 INPUT4 GPIO3,4 2,3 I2C
input fan tach OUTPUT5 GPIO27 13 rpm (open-collector)
input ADS1115 internal GPIO3,4 2,3 I2C
output relay1 internal GPIO23 16 high/low
output relay2 internal GPIO24 17 high/low
output relay3 internal GPIO20 38 high/low
output relay4 internal GPIO21 40 high/low
output relay5 internal GPIO6 31 high/low
output relay6 internal GPIO13 33 high/low
output relay7 internal GPIO19 35 high/low
output relay8 internal GPIO26 37 high/low
output fan speed OUTPUT5 GPIO17 11 PWM

Work Log

31 Mar 2021

For the ADS1115 + CO2 sensor:

  • Gain 2 (=-2.048V)

04 Jan 2022

Photoacoustic CO2 sensors are the future. The Sensirion SCD41 (eval board) looks awesome and has way 12 pages of the datasheet devoted to communicating with the sensor.

14 Dec 2021

Well it works. Not perfectly.

10 Dec 2021

After following the manual calibration procedure, my sensor is reading 185ppm for outdoor air, which is impossible.

Calibrating the DFRobot SEN0219 0-5000ppm NDIR infrared sensor is a PITA. Their product page is not really helpful. Neither is the wiki.

You have to search through the 4-year old comment section to find anything of value:

No, we don’t have proof about the calibration, but because the sensor is set to auto calibrate mode, you can calibrate the sensor by run it in the fresh air for 24 hours.

The calibration of the sensor is based on the air it stays, where the fresh air has the CO2 concentration under 400ppm, and the sensor would calibrate itself as zero point if the concentration is under 400ppm. -DFRobot support

What does that mean? After calibration will it put out 0.0V?

what happens if I run the sensor more than 24 hours continuosly in an atmosphere of 800 ppm…will it recalibrate and asuming this value is 400ppm? -customer

Yes, the output would be wrong. -DFRobot Support

How is that a good idea? In what circumstance would you ever want your CO2 sensor to continuously calibrate to whatever environment you place it in?

Anyway… To the good stuff.

The baud rate:9600, 8 bit,1 stop,none parity, then the command: 0xFF 0x01 0x79 0x00/0xA0 0x00 0x00 0x00 0x00 checksum. Here 0xA0 is enable auto calibration, 0x00 is disable auto calibration.

to active it: 0xFF 0x01 0x79 0xA0 0x00 0x00 0x00 0x00 checksum

The Checksum is to add the byte together, and for turn on/off auto calibration, there is no return value.

I completely removed the DFRobot hat and desoldered the header and attached my own. That was I could run a cable to the TX, RX, POW, GND, and ANALOG lines myself.

There is a datasheet for a different sensor that supposedly has the same UART transmission codes.

The core of the CO2 sensor is a STM32F051K8 arm MCU.

Commands contain 9 bytes. They always start with hex FF (b“” in python) followed by the default sensor number hex 01 (b“01” in python).

checksum = (invert (byte 1 +... + 7)) + 1

sudo pip3 install pyserial
import serial
ser = serial.Serial('/dev/ttyS0', baudrate=9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, timeout=1)

read_CO2 = b"\xFF\x01\x86\x00\x00\x00\x00\x00\x79"
calibrate_zero = b"\xFF\x01\x87\x00\x00\x00\x00\x00\x78"
calibrate_span = b"\xFF\x01\x88\x00\x00\x00\x00\x00\x7A"
disable_auto_calibrate = b"\xFF\x01\x79\x00\x00\x00\x00\x00\x86"
enable_auto_calibrate = b"\xFF\x01\x79\xA0\x00\x00\x00\x00\xE6"

def get_CO2():
  for h in range(9):
    val = int(,0)
    if h == 2:
      high = val
    if h == 3:
      low = val

  co2 = high * 256 + low
  return co2

Unfortunately, this didn’t work at all for me. No response on the serial connection. I have no idea what I am doing wrong (or right for that matter). I guess I’ll just have to stick with analog and never buy from DFRobot again.

09 Dec 2021

Scooped a Pi zero W2. Woot.

31 Oct 2021

I had to add IPQoS cs0 cs0 to the end of /etc/ssh/sshd_config to stop the constant freezing of my ssh connection to the Zero. This did not happen with my other Zero, although I haven’t tried it since I upgraded my router. ssh manpage: IPQoS

30 Oct 2021

Finally getting around to documentation while I am setting up a germination chamber.

20 Aug 2021

Page created. Project ongoing.