Inspired by Jonathan Oxer’s Air Quality project, I decided to build my own, but with my own twist and my own software. This project was an adventure bridging my long-held Arduino skills with modern Ethernet microcontrollers, object-oriented programming, and a lesson in how important mechanical design is.

Concept Design

Jon’s sensor uses a Plantower PMS5003, and later adds a Bosch BME680 air quality sensor. I decided to use the similar Plantower PMS7003, Bosch BME680, and also a CCS811 environmental sensor which measures eCO2 for comparison to the BME680.

I decided to try a new microcontroller, the Espressif ESP32. I’ve used the older ESP8266 in the past for a few WiFi enabled projects in college, using the Arduino IDE. For this project, I wanted the sensor to be a permanent fixture in the house, and WiFi isn’t ideal for that, so I found an ESP32 development board with wired Ethernet - the Olimex ESP32-PoE. The ESP32 has a native Ethernet MAC built-in, so it just needs a dev board that includes a PHY, but that’s easier said than done. Again, I used the Arduino IDE for this project, based on my familiarity with it and the ESP8266.

Building the Node

Unlike the PMS5003 that Jon uses, the PMS7003 has a connector designed to be PCB mounted instead of crimped to flying leads. This made it significantly more difficult to work with. I soldered and heat-shrunk small wires to the 4 required pins (VCC, Gnd, TX, RX) on the sensor, but the small pins were very fragile. For the BME680 and CCS811, both use the I2C bus, so I soldered the two PCBs together with heat shrink covering the wires between them. I then soldered this whole mess to the ESP32-PoE board, completing the sensor node. This open-concept design would never come back to haunt me.

Completed sensor node

Completed Sensor Node

Designing the software

For the software, I had grand aspirations of building a cool universal sensor node firmware that I could configure with #defines and flash onto whatever target I wanted. I quickly found out that this was easier said than done. Arduino is C++ based, although it’s largely bogged down with hacks done back when the Atmel AVR processors didn’t have enough memory to run any real code. For example, printf() and stdout are not implemented, instead there are a series of print functions which print a single type of item (string literal, integer, hexadecimal, float) and you must call them in sequence to print the whole thing. In addition, the Arduino port for the Espressif microcontrollers is backed by the ESP-IDF library from Espressif, which provides many of its own useful functions already.

With all of that out of the way, I eventually cobbled together external libraries from Adafruit and others to get all of my sensors working, and merged them with my own code to poll them and publish the results to MQTT. The only function I never got to work was the BME680, since the Bosch official library (which is required for eCO2 measurement) is distributed in binary-only form. It does have a version for ESP32, but it requires the user to store a binary blob of data between resets which contains data the library has learned about the individual calibration of the sensor. I did not get this storage to work right, and as a result the BME680 library continuously reports an eCO2 error. I still get temperature and humidity, so I guess that’s something useful, right?

The code is a bit of a mess, but you can still feel free to browse the code on github.. Going forward, I am going to find an alternative to Arduino for these microcontrollers.

Late 2020 Update

As expected, the tiny wire connections to the PMS7003 eventually failed. The sensor continues to operate with just the BME680 and CCS811, and those are still reporting data.