Posted on 20 Comments

#40: DIY air quality sensor, part 3 – software

You can build the Air Quality Sensor project without understanding how the software works, but if you want to know what’s really going on behind the scenes you can join me for a deep dive into the source code.

Part 1 showed how to make the simplest possible air quality sensor. Part 2 added a 128×32 pixel OLED display and a mode button.


20 thoughts on “#40: DIY air quality sensor, part 3 – software

  1. Hi Jonathan,

    Thanks for the episodes on the DIY Air Quality sensor. I’ve ordered my senors and some cases from you already and can’t wait for them to arrive.

    I was just planning on using the basic version without the screen and Tasmota.

    However your latest video you mention that the sensor life can be extended significantly by turning it off between readings and that Tasmota doesn’t do this.

    Can I modify your code to work without a screen by commenting out the renderScreen() function call from the Main Loop?

    Or do I need to make more significant edits to your code?

    Thanks for the video, the inspiratrion and the code! I learned a lot.


    1. I pushed a PR that should be in the latest versions of Tasmota that allow for the sensors to go to sleep.

      1. Thanks Gene, I’m still waiting for the sensors to arrive.. they’re still somewhere between China and Oz.

        I’ll make sure I have the latest version when I flash the Wemos.



      2. Thanks for your work on the update Gene.. I’ve been using it for a week or so now. However I’m finding that I’m not getting and readings (taken or sent) after about 16-24hrs.

        I’m using the sensor version of tasmota ( on a Wemos D1 Mini Pro. Sensor18 is set to 300

  2. Hi Guys,
    Just wondering if the fan should go off in the sleep period? Getting data on this unit is tricky..
    I’ve not tried it yet, but does setting pin 6 (Reset) to 0V stop the fan?

    1. Looks like my fan isn’t spinning down, but measurements are coming in every 20 minutes as I commanded tasmota to do.

      Which means two possibilities:
      1) My TX isn’t hooked up correctly at all, and the command to pause the sensor is going ignored, but tasmota reads once every 20 minutes because that’s what it’s been told to do, and since the PMSx003 is always reading, it’s always ready to give a result back. Or
      2) The fan isn’t meant to go to sleep, and this is fine.

      So, I guess all I can do is, as a person from the future (me) is ask person of the past (Mark) whether their PMSx003 has lasted the 3 years since without degrading, indicating that it is indeed going to sleep since expected lifetime is only 6000 hours = 250 days @ 24/7 duty.

  3. Is this a typo.?..

    sprintf(g_mqtt_message_buffer, “{\”PMS5003\”:{\”PM1\”:%i,\”PM2.5\”:%i,\”PM10\”:%i,\”PB0.3\”:%i,\”PB0.5\”:%i,\”PB1\”:%i,\”PB2.5\”:%i,\”PB5\”:%i,\”PB10\”:%i}}”,
    g_pm1p0_ae_value, g_pm2p5_ae_value, g_pm10p0_ae_value,
    g_pm0p3_ppd_value, g_pm0p3_ppd_value, g_pm1p0_ppd_value,
    g_pm2p5_ppd_value, g_pm5p0_ppd_value, g_pm10p0_ppd_value);
    } else {

    Hmmm…. Change
    Line 536 — g_pm0p3_ppd_value, g_pm0p3_ppd_value,g_pm1p0_ppd_value,
    Line 536 ++ g_pm0p3_ppd_value, g_pm0p5_ppd_value,g_pm1p0_ppd_value,

    1. Looks to be fixed now. Line 544 in
      In the video, it did look like the two reported values were drawing just one line with identical values, so maybe this was the explanation.

  4. Extra connection, D0 to RST.
    Only see it on #40 video, I have watched, rad and listened, I built it, it works without;
    Have I missed something? Thanks, great project.

  5. When part 4? really wanting the BME680


  6. Hi Jonathan,

    thank you so much for providing such excellent howtos. I used your source code as a starting point for my own sensors. I extended it so that it can handle multiple different sensors with different timing needs. The first sensor I added is BME/BMP280 for temperature, humidity and pressure. It can be connected to the I2C-Bus with the display. The major change I did (besides adding more variables for values) was to introduce a timer class to replace the global “state” variables. I am still working on a change to the display.

    My fork can be found on GitHub:

  7. Hello and thanks for the project. It is working great for me.

    I just wanted to know if there is any way to stop the built-in blue led in the wemos. It blinks every second in both the systems (tasmota and custom sketch) and I don’t have a case yet so it gets very annoying in the night and I have to turn it off.

    1. I haven’t tried this personally, but if you pull pin D4 (GPIO2) high, it will turn off the LED. It could be done with the config in Tasmota by setting GPIO2 to an output and permanently turning it on, or it could be done in the custom firmware by adding 2 lines of code inside setup():

      pinMode(LED_BUILTIN, OUTPUT);
      digitalWrite(LED_BUILTIN, HIGH);

      There’s some info here:

      1. Hi Jonathan,
        in your example on you connected the PMS5003 pin 5 (Tx) to D1 Mini pin D4 which is also the PIN for the D1’s builtin LED. cf.

        On the webpage the PIN layout is:
        PMS5003 pin 4 (Rx) to D1 Mini pin D6
        PMS5003 pin 5 (Tx) to D1 Mini pin D4

        In the source code on github it is:
        #define PMS_RX_PIN D4 // Rx from PMS (== PMS Tx)
        #define PMS_TX_PIN D8 // Tx to PMS (== PMS Rx)

        I think that is the cause for the wild blinking because some users might simply change the config.h after they soldered their wires according to the example. I did it this way 😉

        1. Oh, woops, thanks for letting me know!

    2. I have this in the kitchen and rather like the LED flashing as a sort of, “it’s alive” but in another location it would be super annoying.
      Saw the posted solution so I may build another for a different room now.

    3. The reason for the blinking is that on the Wemos D1 Mini, the D4 PIN is also connected to the builtin LED.

      Yes, you can change the RX PIN from D4 to D7. Simply change the definition for PMS_RX_PIN in config.h and connect the PMS5003 accordingly.

      1. I did this and it worked great. Thanks all for the help 🙂

      2. Doing this (D7 instead of D4) also properly grounds the BUTTON on Pin D3. I couldn’t figure out the grounding issue for the life of me, but it had to do with the constant input from the TX line to pin D4.

  8. Muchas gracias.!

Leave a Reply

Your email address will not be published. Required fields are marked *