Sense of Smell

ESP32-Based Air Quality Meter

Kevin Norman

Issue 38, September 2020

Monitor the air quality in your home or workplace using an ESP32, LCD, environmental sensors, and a little ingenuity.

When Kevin wanted to keep an eye on the air quality in his home, he turned to Arduino and his coding skills instead of purchasing an expensive alternative. We caught up with Kevin to learn more about his air quality meter project.

We just love your approach to monitoring the air quality in your home. Before we discuss your project, please tell us a little bit about yourself

I’m a Software Engineer originally from Wales, now living in London, who likes to hack stuff together in my spare time. My entire life I’ve been fascinated by how things work - and was especially enamoured with the ‘How Its Made’ and ‘Junkyard Wars’ television series. I’ve been taking stuff apart for no good reason for longer than I remember, and have definitely broken far more stuff than I have improved!

We’re convinced it’s in a Maker’s DNA to pull things apart. What got you into electronics and programming?

When I was young, my father used to pick up random e-waste that people would leave on the side of the street (Think old televisions, stereos, and such!) and bring it home for me to take apart. I’d spend hours destroying these things, not really understanding exactly what I was doing. Eventually I got old enough to know that certain things were salvageable, and started building really simple things using the components I had salvaged. One particular story my father loves to tell is how he bought me a particularly expensive RC car for Christmas. By lunchtime the same day, it had been transformed into a fan.

Thanks to boards like the ESP32 and ESP8266, IoT projects are made so much easier for makers like us. What parts have you used in your project?

  • A Wemos LOLIN32 clone board but basically any ESP32 board will do. The Jaycar XC3800 looks good.
  • A CJMCU-680 sensor breakout board featuring the Bosch BME680 sensor but any breakout board will do. The Digikey 1778-1207-ND or the CE05772 from Core Electronics should also work.
  • 2004 LCD featuring an I2C interface. It looks like Jaycar sells the LCD QP5522 and the I2C board XC3706 separately.
  • 18650 battery holder (eg. Jaycar PH9205) and any old 18650 cell.
  • A toggle switch, and a project enclosure that fits all the components. I used a lunchbox from a local homeware shop.

Once I was in university, I started learning about Arduino, which was a gateway to learning more about the basics. The first truly useful thing I built was a simple Arduino powered thing that would listen out for me to press the red button on my television remote control (a totally useless button that does nothing on my particular TV as far as I can tell!) - and then toggles a MOSFET which supplies power through to my homemade amplifier.

Solving real-world problems with Arduino - we like it! Tell us what inspired you to make your Air Quality Meter project?

Most offices here in London have air handling units, air conditioners, and fans to keep air circulating. They help to keep the office workers comfortable and prevent Carbon Dioxide and VOC (Volatile organic compound) build-up. Most residential flats like the one I rent do not. Given I now spend close to 24 hours a day sitting in this flat, air quality seems important.

I looked up the cost of air quality meters and they were either fairly pricey or fairly useless. I wanted one that I could graph over time. I decided to go the DIY route! Another factor was my wish to play with Arduino type hardware. I’ve always found Arduino to be a wonderful platform for experimentation, but always been disappointed at how limited they can be. When I saw the ESP32 for the first time, I instantly started thinking about all the possibilities. An Arduino type board with proper network facilities and extremely low power requirements? I need one of those! This project was an excuse to play with an ESP32.

There does appear to be a few different varieties of ESP32 boards available. Is there a particular ESP32 that it needs or would most clones work?

Any ESP32 based dev board will work. Some might not feature the Lithium battery charging circuitry I used to make mine rechargeable, and others might have you perform a slightly different rain dance to flash them. However, the core of the dev boards is the same, and as such, apart from maybe different pin mappings, everything should translate reasonably well! The Jaycar part I suggest looks like a much nicer board than the one I got, but I take a perverse pleasure in getting strange Chinese parts with no documentation and making them work, hence my odd clone board.

Can you give us an overview of how it all works?

The high level function is very simple. The BME680 sensor comes with an unfortunately closed source library called BSEC which does 'sensor fusion' (the process of combining multiple 'real' sensors into a new 'fake' one based on the observations of those real sensors) in order to take the humidity, pressure, temperature, and a ‘gas resistance’ sensor, and combine these to generate what Bosch calls the Indoor Air Quality.

The gas sensor was particularly interesting. As far as I understand it, the sensor consists of a particular material which is heated to a given known temperature - at which point gas diffuses into the material and its resistance is then measured. This gas sensor is calibrated to estimate the VOCs or volatile organic compounds in the air. This seems to be why this particular sensor is so expensive.

This sensor along with its library is queried at its max query rate (once every 3 seconds) via the I2C bus. These values are then both displayed on the LCD, also connected via I2C and sent to an MQTT broker I host on a Raspberry Pi. The Air Quality Meter’s job is then done, and the Raspberry Pi takes over from there.

MQTT is a publish/subscribe message bus geared towards IoT applications. Like most pubsub message buses, the principle is pretty basic. Publishers publish messages to the bus on a given topic.

MQTT has an interesting concept of ‘scoped’ topics. For instance, the meter broadcasts the current temperature on the 'bme680/temperature’ topic. A subscriber (someone who is interested in a topic) will receive the messages that are published to it. A subscriber here has two choices really, it could subscribe to the bme680/# topic - everything published in the bme680 topics and its subtopics (hash acts sort of like a wildcard here), or it can be more specific and subscribe to the bme680/temperature topic directly. In this case, the Raspberry Pi subscribes to itself on the bme680/# topic. I wrote a simple service in Golang which will take these values and stick them into an InfluxDB instance.

InfluxDB is a timeseries database that is specifically designed for this purpose, and it is really, really easy to work with. Once this data is in InfluxDB, it’s reasonably easy to then stick Grafana on that same Raspberry Pi and to connect it to that InfluxDB database as a data source. You can then play about with the GUI graph builder to build a dashboard to your liking. All the code and configuration instructions are detailed on my blog post, and it’s all free software (except for the BSEC library!).

Brilliant! For our readers not familiar with MQTT, how would you explain what that is?

MQTT is a messaging protocol designed specifically for IoT applications. It’s designed to be a particularly lightweight simple system for devices that don’t have the horsepower to maintain more high throughput/low latency connections such as websockets. It follows the standard Publish/Subscribe model I elaborated on in my previous answer. It has loads of particularly interesting features whose implementations depend on the message broker and clients implementing support for them - such as guaranteed message delivery, QoS, and more. Would recommend it.

Agreed. We’ve published a few articles and projects that use MQTT. Could you give us a short note of what I2C is as well for our readers?

I2C is a serial communication bus used for connecting peripherals to a microprocessor. It's low bandwidth compared to something like SPI, but is absolutely plenty for most low speed applications like this. It only requires two wires to work, and wiring it up is extremely simple.

If you wanted to connect multiple I2C devices to one ESP32 board, for instance, it would be as simple as connecting all the common pins.

The only pitfall I am aware of with I2C is that it relies on each device having an 'address' which is usually hardcoded into the peripheral. This sensor is not unique - two CJMCU-680s will have the same address. This means you cannot use two sensors on one I2C bus. Lots of peripherals will have a secondary address you can use instead of the primary address - usually configured with a jumper or similar. Up to 128 peripherals can be connected to one I2C bus, as long as they all have independent addresses, so you shouldn't run out of room!

I2C certainly saves on the wiring too - no more birds nests! You mentioned your project talks to a Raspberry Pi. Can you go into further detail about this?

The Raspberry Pi was an addition and the base implementation of this meter could work without it for sure. I added it purely because I wanted to have persistence of data, and the ESP32 does not have a particularly large amount of persistent storage available for use.

If you wanted an MQTT broker without wanting to host one, there are plenty of free and low cost solutions online such as HiveMQ which you could use instead. You'd still need to figure out where you're going to host your persistence layer, be it on some cloud hosting or....a Raspberry Pi! I went with a RPi rather than a cloud hosting solution like this because I'm trying to 'own' my data as much as possible. I'm one of those weirdos who doesn't use Gmail anymore for this reason. The ESP32 definitely isn't going to be hosting Grafana!

Please tell us a little more about this Grafana that you have used. What made you choose that and was it easy to use?

I used Grafana because it seemed to me to be the quickest way to go from data in a database to graphs on a screen. It's free software (as in beer, and as in freedom!), and is ridiculously easy to get running on a server. If you've got a Raspberry Pi running Docker or similar, it's as simple as running ‘docker run -d -p 3000:3000 grafana/grafana’ and visiting the servers IP address at port 3000!

It has a beautiful UI, and is quite easy for a novice to create impressive looking dashboards. I hadn't used Grafana before, and I was able to generate the dashboard shown in around 2 hours. It also natively supports InfluxDB, which meant there was no need to duplicate the data.

That’s very impressive. It’s great that boring lines of data can be made to look so impressive and so easily understood. Your enclosure with a wooden lid is interesting. Tell us about why you made it this way?

When it comes to maker projects, I always try to minimise the cost. I wanted to make something that had wife approval too, since this thing was going to permanently live on my desk once it was built.

Proper project boxes tend to have... unpleasant aesthetics, so I instead decided to go hunting in homeware shops for a tub that would be fairly simple to work in. DIY is not one of my strong suits, and the tools I have at my disposal are limited (Apartments in London are ridiculously expensive and space is at an extreme premium). Plastic is nice to work with since you can just melt your way through it, but the wooden lid which I've used as a fascia was fun to cut through. It was thicker than I expected, and so I had to engage in what was the most tedious thing I've ever done. This was drilling around 20 holes around the area I wanted to cut out and working my junior hacksaw into each hole. It probably took around 1.5 hours to cut the hole you see here, and it's a little rough. I think it adds to the rustic aesthetic too!

One nice side effect of using a tub like this is that it is very easy to open and work inside of. No screws to remove!

That’s a great approach. Particularly for makers who don’t have a 3D printer. Can you tell us a little about how the project is powered?

The power solution in this device is a little janky because I didn't have the parts on hand to do it properly.

The ESP32 board itself is pretty simple to power, either feed it 5v via the onboard MicroUSB port, or feed it via the LiPo battery port. If you've got a LiPo battery attached, and you connect to the USB port, the battery will charge. The jankiness comes from the LCD requiring a fair bit of current to start up - more than the ESP32 can deliver via its 5v pin. Instead, I just directly connected the LCD to the battery, which means that the LCD is operating on a lower than specified voltage, but it seems to work fine.

I would recommend adding some sort of battery protection circuitry and bypassing the ESP32s LiPo charger altogether - since in my solution if I was to leave the charger disconnected, the ESP32 board would eventually cut off since the cell voltage would drop below the 'safe' voltage. Whereas the LCD will quite happily keep sipping away until the cell enters ‘explodey’ battery territory. This is fine for me since the only use of the battery is as a UPS.

Nobody wants to see the smoke come out of their battery! Can users simply connect the project to a USB port for permanent operation?

This is exactly what I do. It remains connected to a USB port on my computer permanently unless I've decided I need to disconnect it for a period to free up a USB port temporarily or I'd like to relocate it.

Important to note, however, I've read reports online claiming that the power conversion circuitry found on these clone boards is particularly inefficient, so it's not recommended to power the ESP32 via the USB port if power efficiency matters to you (i.e. connecting a power bank to the ESP32 board wastes a tonne of power compared to just directly connecting a LiPo cell to the ESP32 board).

Good advice for anyone wanting a portable solution. What challenges did you encounter and how did you overcome them?

The biggest challenge was the stupid wood cutting I had to do. Honestly, I should have probably just invested in a Jigsaw, but instead I went the long and painful route I elaborated on above. Another challenge was with this cheap clone board with its annoying undocumented 'bug' where it will NOT enter flash mode unless you hold the IO0 pin low temporarily. Most of the 'proper' ESP32 dev boards have a specific button for putting the ESP32 into flash mode, but mine was missing this button, and therefore I had to figure this out myself. Looking up the ESP32 Boot Mode Selection was massively helpful. Everything else for this project just sort of fell together, far better than I expected!

Sometimes it’s easy to forget the much better user experience you get when using genuine boards. If you were to start the build again, what would you do differently?

Easy, I'd get one of these new fangled E-Ink displays that have become available. They look absolutely incredible, and the LCD I used is quite limiting.

I'd love it if the display on the device itself could feature some rudimentary graphs so I didn't have to check my Grafana dashboard if I wanted to see if the temperature was dropping or rising!

I'd almost certainly buy a jigsaw to cut the large rectangle out of the wooden tub, and I'd have bought proper power delivery circuitry.

I'd maybe incorporate a PM2.5 dust sensor too.

An e-ink display would significantly reduce the power requirements as well. Is there anything we haven’t covered that our readers would likely want to know?

I don't think so! Just pay extra attention to the battery charging circuitry to make sure it doesn't explode!

If our readers would like to build one for themselves, do you have details about your build and code?

All code and build details can be found on my blog https://kn100.me/aqi and I am very happy to field questions via twitter @normankev141

We admire makers who make their projects available for other makers. Finally, any words of advice to inspire our maker readers looking to start making projects for themselves just like you have?

Making things is an extremely valuable hobby of mine. I find it to be quite therapeutic. Sometimes the things I make are impractical, stupid, or more expensive than if I'd just bought the same thing premade, but It helps me to remember how fun software and hardware can be.

I'd encourage any of your readers to just make something. It doesn't need to be saleable or practical, because it's your thing.

It's never been a better time to be a maker, and there are so many wonderful innovations happening out there that put SO much power in the makers’ hands. 3d printers, IoT platforms like MQTT, Arduino, magazines just like DIYODE, and more mean that there are more resources in our hands than there ever have been.

You don’t have to give in to our cloud hosting overlords. You don’t have to buy into the insecure awful IoT platforms that exist today. There’s a whole community of makers out there doing absolutely incredible things. They’re a very welcoming bunch. Go join them!

Awesome! Well done on your amazing project and thank you for sharing it with us. We look forward to seeing more builds from you in the future.

Kevin Norman

Kevin Norman

Software Engineer and Maker.