MH-Z19 CO2 sensor reader, logger and visualiser

MH-Z19 CO2 sensor reader, logger and visualiser

  • Reads data from UART(serial)-connected MH-Z19 (or MH-Z14) sensor using python 3.
  • If you dare to install nodejs you can visualise the logged data (using html and plotly.js library).

Repository: sammcj/CO2-Logger

Note this post is from 2016, in 2021 I replaced my custom Co2 loggers with an Aranet4. While very expensive, is and excellent off-the-shelf solution, with many features.

Sensor can be queried using 3.3v UART at 9600 bps. Sensor main feed voltage is 5v.

Can be connected to computer using almost any USB-UART converter if voltage matches.

  • Python3
  • pip3 install serial pyserial
  • A USB -> Serial UART connector (Could also be used with Raspberry Pi, ESP8266, Arduino etc…)
  • MH-Z19 Co2 Sensor (Around $25AUD on eBay)
$ python3 --tty=/dev/tty.SLAB_USBtoUART --timeout=2
Connected to /dev/tty.SLAB_USBtoUART
2019-02-25 07:44:48 558 58
2019-02-25 07:44:49 558 58
2019-02-25 07:44:51 558 58

3 fields separated by tab: timestamp, CO2 concentration (ppm), internal sensor temperature (Celsius)

Use stream redirection to save data series to file:

touch co2.log
python3 --tty=/dev/tty.SLAB_USBtoUART --timeout=2 >>co2.log
  • --tty (optional) tty to connect to (default is /dev/tty.SLAB_USBtoUART)
  • --single (optional) perform a single measurement and exit
  • --quit (optional) connect to the sensor and quit immediately
  • --timeout (optional) time between requests (defaults to 10 seconds)
  • --command (optional) raw command to pass to the sensor - use carefully (default is to read Co2 levels)

Raw commands can be passed to the Co2 sensor, these to be used with caution.


python3 --tty=/dev/tty.SLAB_USBtoUART --timeout=1 --command='0xff, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79'

0xff, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79

0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6

0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86

(Note: Untested)

  • 1000 = 0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x03, 0xE8, 0x7B
  • 2000 = 0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x8F
  • 3000 = 0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x0B, 0xB8, 0xA3
  • 5000 = 0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x13, 0x88, 0xCB
  • Run this for 10mins + in 400ppm Environment


0xFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78

  1. Install npm dependencies npm install
  2. Start server python3 -m http.server 8088 --bind
  3. Open browser at
  4. Select your log file in input field
Target gasCarbon Dioxide CO2
Operating Voltage3.6 to 5.5 Vdc
Operating current< 18mA average
Interface levels3.3 Vdc
Output signal formatUART or PWM
Preheat time3 min
Response time<60 s
Accuracy± (50 ppm+5% reading value)
Measuring range0 to 5000 ppm
Operating temperature range0 to + 50°C
FunctionUART / SignalMH-Z19 pin
Vcc +5V+5V6 Vin

Don’t use this function unless you know what you are doing or you may incorrectly calibrate the sensor!

(Australia has an average of around 400-410PPM and Sensor zero point is 400PPM)

MIT licence

Related Content