Now that I have explored reading the CO2 sensor using PWM using an Arduino (GitHub location of Arduino sketch), I want to do the same using Micropython.  Since I got a nifty WiPy awhile back, I thought I’d start with using this hardware rich micro python platform.  Getting to the punch line, I was able to calculate what appears to be a reasonable CO2 value using Pin interrupts.  I am not sure how reasonable because I cannot test/calibrate with Leaf Spa readings for a few days.  I stumbled over several challenges including my lack of python knowledge.  But…I also became frustrated and lost time because of whimsicalities I ran into using the WiPy PyMakr IDE as well as the WiPy implementation 1.8.7 of pycom I was using.  At this point, I am not convinced micro python is ready for me to use for the Leaf Spa.  However, I plan to continue exploring micro python using Adafruit’s feather Huzzah.


I’ve used PWM for blinking lights and such.  But until the MH-Z19, I haven’t had the opportunity to read PWM high/low signals.  So I thought I’d start by making sure I understood PWM a bit more.  Here’s a nice image:

As noted in the All About Circuits article on PWM:  “a PWM signal is a sequence of periods in which the duration of the logic-high (or logic-low) voltage varies according to external conditions, and these variations can be used to transmit information.”

So the folks who designed and built the MH-Z19 encoded CO2 readings by modulating the ON/HIGH (which determines the OFF) time within a cycle.

As noted in benripley’s excellent post, Three Ways to read a PWM signal, “…what we are really looking for is the length of time the signal remains high for each cycle.  I’ll be looking at two of these to see if I can read the MH-Z19 using PWM:

  • is there an equivalent pulseIn function to the one I used to create this Arduino sketch to read the MH-Z19?  Not really.
  • is there a pin change interrupt API that fires when the pin changes state from high to low and from low to high? Yes.

Calculating the CO2

Now that I feel more comfortable with working with a sensor that sends values through a pwm channel, I wrote this script.  Argh!  My knowledge of python is so low!  But the micro python code running on the WiPy seems to do the trick.  The gist of the code:

  • set the Pin reading the pwm to callback to rising() when the rising part of the pulse is detected.
  • once rising() is called back, start a ms timer that once a falling edge is detected will give us the th value.  Set the Pin to callback to falling() when the rising pulse is detected.
  • once falling() is called back, stop the timer and set th.  Set the Pin to callback to rising() one last time so we can set the tl value.
  • rising() gets called back one last time.  Set tl.
  • calculate the CO2 based on the formula given in the MH-Z19 data sheet (section 7.1):

WiPy Whimsicalities

Identifying the Pin

The way I was able to finally reference the pin I was using for PWM in was time consuming/frustrating.  This is because the documentation (to me) is confusing. 

The documentation of  Pin class within the machine module of the WiPy’s version of micro python  discusses the Pin callback:

from machine import Pin

def pin_handler(arg):
    print("got an interrupt in pin %s" % (

p_in = Pin('P10', mode=Pin.IN, pull=Pin.PULL_UP)
p_in.callback(Pin.IRQ_FALLING | Pin.IRQ_RISING, pin_handler)

That didn’t work for me.  I finally stumbled upon this text:


Contains all Pin objects supported by the expansion board. Examples:

led = Pin(Pin.exp_board.G16, mode=Pin.OUT)

which seems to by in the 1.8.4 WiPy documentation, but missing from the 1.8.7 documentation! ….Grrrrr…..

Figuring pin identification was exacerbated by this statement in the 1.8.7 documentation….Grrrrr…..

On the WiPy board the pins are identified by their string id:

from machine import Pin
g = machine.Pin('GP9', mode=Pin.OUT, pull=None, drive=Pin.MED_POWER, alt=-1)

Using the USB Port to Program the WiPy

I’m plugging in the expansion board into one of my Mac’s two USB ports.  It was very common for me to receive:

> Could not enter friendly repl. (click to attempt to reconnect)

Googling this obtuse message seems to mean PyMakr can’t connect to the expansion board through the USB port.….Grrrrr…..  I put my Mac away for a few hours and come back to it.  The USB port magically starts working.  Hmmm…


Well…I’m stopping my exploration into measuring CO2 using the MH-Z19 connected to a WiPy for now.  When I get back home, I’ll test/calibrate within the Leaf Spa.