Ambient Display of Air Quality

Since assembling the RGB LCD Shield, I’ve been thinking about what types of data could take advantage of being able to easily change the backlight color.  Air quality index is a good fit; AIRNow provides colored ranges for the index which indicate air quality at a broad level using green, yellow, and red.  I revisited the code for having the Internet of Things Printer fetch a data feed from Pachube and updated it to optionally track a single datastream within the feed.  I’m using:

Ambient AQI RGB LCD Parts

I inserted the pins on the shield stacking headers into the headers on the Arduino, then inserted the shield’s pins into the stacking headers.  The added height of the stacking headers means the RGB LCD shield clears the Ethernet jack on the Arduino; but, the overall structure is still stable and reasonably compact.

Ambient AQI RGB LCD Assembled

During setup, the backlight is set to teal to distinguish from the green / yellow / red of the actual data screens.  I’m also displaying the IP address for a few seconds to help with troubleshooting any network issues.

// Short delay so the IP can be spot checked.
lcd.setCursor(0, 1);

Ambient AQI RGB LCD Init Screen

With the backpack and accompanying library, it’s straightforward to change the color of the backlight.  These calls can be wrapped in an if-else structure to map ranges of values to different colors:

if (curValue <= 50) {
} else if (curValue <= 100) {
} else {

The result is that, at a glance, I can see that the air quality is good today.  If I’m interested, I can take a closer look and see when the data was collected and the exact value of the index.

Amient AQI RGB LCD Data Screen

Fortunately for me (but unfortunately for grabbing example images), our air quality was good every time I checked.  I ended up mocking up some data to show how things would look if the air quality were moderate.

Amient AQI RGB LCD Mock Moderate

And then again if the air quality were poor.

Ambient AQI RGB LCD Mock Poor

This general approach can be modified and used with a variety of data.  One example is display temperature and using blue to indicate when the temperature is too cold and red to indicate too hot.  It’s also possible to use a local sensor reading to generate the value which determines the backlight color.

Modifying the original code to handle datastream entries resulted in a few areas that need some explanation.  The most straightforward change was in the request URL; which now conditionally includes a datastream ID:

client->print("GET /v2/feeds/");
if (datastreamId != NULL) {

When working with the feed API, I made use of the Last-Modified header in the HTTP response to decide if the data had changed.  Unfortunately, the response for the datastream does not include a Last-Modified header field.  Fortunately, it does include an ETag header field which changes when the data changes.

if (datastreamId == NULL) {
    foundHeader = client->findUntil("Last-Modified:", "\r\n\r\n");
} else {
    foundHeader = client->findUntil("ETag:", "\r\n\r\n");

Finally, the original JSON parsing code viewed the end of the outermost object as the end of the parse and assumed all data had already been processed:

if(!depth) return true; // End of file
// process data

In order to handle a JSON feed where the outermost object contains the data, I changed this conditional to continue to the processing code and exit afterward if the flag variable isDataObjectRoot has been set (this flag defaults false, and is set to true if and only if a datastream ID has been specified):

if(!depth && !isDataObjectRoot) return true; // End of file
// process data
if(!depth && isDataObjectRoot) return true; // End of file

Otherwise, processing one datastream entry was very similar to processing the entire feed.  The full source code is available on GitHub and can be modified to track other data by opening the LCDFeed example and filling in the following fields:

char *apiKey = "";          // Developer API key
char *feedId = "";          // Feed ID
char *datastreamId = "";    // Datastream ID

I’m interested in seeing what other data can be displayed using this general approach and what types of conditions could be indicated by other colors.

Make a robot friend with Adafruit’s CRICKIT – A Creative Robotics & Interactive Construction Kit. It’s an add-on to our popular Circuit Playground Express, FEATHER and other platforms to make and program robots with CircuitPython, MakeCode, and Arduino. Start controlling motors, servos, solenoids. You also get signal pins, capacitive touch sensors, a NeoPixel driver and amplified speaker output. It complements & extends your boards so you can still use all the goodies on the microcontroller, now you have a robotics playground as well.

Join 7,500+ makers on Adafruit’s Discord channels and be part of the community! http://adafru.it/discord

CircuitPython in 2018 – Python on Microcontrollers is here!

Have an amazing project to share? Join the SHOW-AND-TELL every Wednesday night at 7:30pm ET on Google+ Hangouts.

Join us every Wednesday night at 8pm ET for Ask an Engineer!

Follow Adafruit on Instagram for top secret new products, behinds the scenes and more https://www.instagram.com/adafruit/

Maker Business — Fewer startups, and other collateral damage from the 2018 tariffs

Wearables — Light as a Worbla feather

Electronics — How to make your own magnetic field probe!

Biohacking — The State of DNA Analysis in Three Mindmaps

Python for Microcontrollers — One year of CircuitPython weeklies!

Get the only spam-free daily newsletter about wearables, running a "maker business", electronic tips and more! Subscribe at AdafruitDaily.com !


  1. Making a display for a PCR machine would also work for this display

  2. I used the exact same shield and Arduino combo to fetch the weather data from our local airfield’s station here in the desert from http://www.rssweather.com.
    If it’s yellow then it’s a sand/dust storm. Blue means less than 80F. Green is 80F-89F. Red is temps above 90F.
    Code is posted somewhere in the forums.

  3. @anonymous – Interesting idea, are you thinking in terms of measuring the current temperature in the PCR machine? Or some aspect of the cycle?

    @DavidM – I looked up your forum post http://forums.adafruit.com/viewtopic.php?f=31&t=27003 and read through the code – I see in addition to using the color at that level you’re also using the text for details (type of dust condition, temperature, wind speed, etc.) Very nice!

  4. Chris O'Sullivan

    Nice, I assume you could use the same setup for any value such as pollen or mold count locally if there is a source of data for that.

  5. Chris – Thanks! Yup, should work for those types of values if there’s a source of data. I’m actually having trouble finding an official JSON APIs to fetch pollen/mold counts.

Sorry, the comment form is closed at this time.