Measuring CO2 with ESP8266 and MicroPython

As I wrote in Monitoring Air Quality Open Data I wanted to build a small device for monitoring the air quality and noxious gases, and since lately I have been hacking with Python for the ESP, I wanted to do it with MicroPython.

I used a MQ135 sensor (its datasheet can be found here) which among other gases detects NOx, NH3, CO2, alcohol and benzene, and researched different implementations of MQ135 libraries in order to see which one I would port to MicroPython.

Calibration

Most of the experiments, libraries and calibration details related to the MQ135 are based on two main articles:

  • Cheap CO2 meter using the MQ135 sensor with AVR ATmega by Davide Gironi, which uses the datasheet info to get the parts per million (PPM) for CO2, after reading the resistance value of the sensor (Rs) and sensor resistance at 100ppm of NH3 in the clean air (R0 or RZERO)
  • MQ135 Arduino library by Georg Krocker, which implements Davide Gironi’s approach as an Arduino library.

So, I followed the same approach and used Georg Krocker’s Arduino library as the base for porting the code to Python. Actually, I used Krocker’s library and the corrections from balk77 and Vilius Kraujutis as a reference.

Note: R0 (RZERO) may have different values in different sensors, so in case you want to have your sensor calibrated more precisely it is recommended to follow the next steps:

  • Connect the sensor to the circuit (see below), turn the power on and let it powered between 12 and 24 hours.
  • Put the device outside and read the value of RZERO, if possible at 20°C and 35% relative humidity (see here for more details).

Setup and usage

In case you want to test the device yourself, you need to install MicroPython for the ESP8266 first.

You can find a guide for installing MicroPython here, but in case you want to go straight to the point, it should be enough with:

Download MicroPython for ESP8266 from MicroPython web site, under “Firmware for ESP8266 boards” section,

wget http://micropython.org/resources/firmware/esp8266-20170823-v1.9.2.bin

Install ESPtool (the bootloader utility for ESP8266)

pip install esptool

Erase the flash and deploy MicroPython firmware

esptool.py --port /dev/ttyUSB0 erase_flash
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170823-v1.9.2.bin

Then, clone or download the MQ135 git repository

git clone https://github.com/rubfi/MQ135.git

Once the repository is cloned, you can use ampy for uploading the files to the device

export AMPY_PORT=/dev/ttyUSB0 # or your port to the ESP
ampy put mq135_example.py
ampy put mq135.py
ampy run -n mq135_example.py

and then connect to the device with the serial communication program (e.g.: minicom) to see the output.

MicroPython could be configured to load a script after the device boot. If you want to load the code just after the boot, use:

ampy put mq135_dht11_example.py main.py

Hardware

Although the library and the MQ135 sensor can work without temperature and humidity data, the resulting PPM gives better information when corrected for temperature and humidity. So, in order to have these values a DHT11 humidity sensor was included in the design.

The required hardware is just a breadboard, some wires and:

  • 1x ESP8266 Wemos D1 mini device
  • 1x DHT11 humidity sensor
  • 1x MQ135 air quality sensor

In the design above and the example below, the MQ135 sensor is connected to A0 and the DHT11 is connected to D2 (lines 7–9). Once per second (since MicroPython doesn’t recommend more than once per second calls to DHT11) the temperature and humidity are recorded (lines 14–16) and with these values the corrected PPM info is calculated (line 22).

Result

This is the final prototype, including the Wemos D1 mini and the MQ135 and DHT11 sensors.

Wemos D1 mini + MQ135 + DHT11

I wanted to show the results in a more visual way, so I used Dweet.io and Freeboard (Freeboard source code can be found here).

Dweet allows to easily upload to the cloud the values you got from your sensors and Freeboard is used to visualize the data in a dashboard.

For uploading the data to Dweet is enough to define the URL with a unique name (line 21) for logging your data, and then use Python urequest to get the URL with the parameters (lines 41–45).

Once the device is uploading data to the cloud you could see in the next URL if the data is being recorded in Dweet.

https://dweet.io/get/latest/dweet/for/UNIQUE_NAME

Dweet and Freeboard are well integrated, so, to show the data in the dashboard it is enough to add dweet.io as datasource, then add new pane to your dashboard and a gauge or text widget with the variable you want in the value field. The result could be something similar to this:

Freeboard MQ135+DHT11 dashboard