Like most folks, I sometimes wonder about the quality of the air I breathe. Naturally, I turned to the possibility of a project designed to measure the quality of the air in my own home.

Finished Project

The finished Indoor Air Quality Monitor

Indoor air quality is not a simple concept to quantify. I assumed that too much CO2 (Carbon Dioxide) didn’t seem like a good idea. Furthermore, large concentrations of VOCs (volatile organic compounds) didn’t sound too pleasant either. So, I reasoned that these would be some important measures to have available.

After further investigation, I found only a few ICs available to build such a project around. I settled on the iAQ-Core module from AMS.

As I read more about measuring indoor air quality, I began to appreciate the complexity of the issue. The volatility of many compounds (the degree to which they vaporize into the air) depends, in part, on the temperature. Also, relative humidity can be a factor for some compounds. Thus, I decided to add temperature and relative humidity sensors to the project.

Of course, I wanted to use a microcomputer with a display to read sensor output. As an additional feature, I decided to include BLE connectivity to allow remote monitoring.

Let me state up front and without qualification (as in a complete disclaimer) that this project is an experiment driven by my curiosity. I don’t really know how meaningful it is as a decision tool for anything.


Reference Material

The following links are for datasheets for components used and additional relevant material. I found these to be essential and I strongly encourage you to read through them if you are interested in the project.


iAQ-Core Sensor Module

The iAQ-Core indoor air quality sensor module is the heart of the project and is used to provide CO2 and total volatile organic compounds (TVOC) equivalent predictions. The sensing range from the datasheet is as follows: 450-2000 ppm CO2 equivalents and 125-600 ppb TVOC equivalents. "Equivalents" are somewhat vague units and are not defined as well as I would have liked.

From doing a little background reading, it seems like a CO2 equivalent unit includes CO2 and other "greenhouse" gasses, apparently scaled to a property of CO2. TVOC equivalent units also appears to be a somewhat vague measure. It seems that there are a number of compounds considered to be VOCs with particular relevance to indoor air quality and these are totaled and expressed as some standardized measure.

In all fairness, I have seen the use of these "equivalent" units on several commercial indoor air monitors. Still, I would have liked to have seen a more rigorous definition.


iAQ Core

The iAQ Core C sensor module

The device uses Micro-Electro-Mechanical Systems (MEMS) metal oxide sensor technology. It is a 3.3v device that supports an I2C interface, and it is available with either a continuous (-C) or pulsed (-P) operating mode.

Interfacing the device is relatively easy. There are no commands to send. You do not write to the device's address at all, and the datasheet cautions that having the write bit set when addressing the chip can seriously interfere with its functionality. Instead, you simply read 9 bytes from the fixed I2C address.

Within those 9 bytes, you have a status byte (0x0 = ok, 0x01 = busy, 0x10 = warming up, which takes ~5 min, and 0x80 = error), sensor resistance (ohms) and, of course, the CO2 and TVOC equivalent values. The datasheet contains more details.


HIH-6131 Humidity/Temperature Sensor

To provide measurements for temperature and relative humidity, I chose the Honeywell HIH-6131. This SMT chip has a supply voltage range of 1.8v-5.5v, making it suitable for 3.3v operation. It also uses an I2C interface and the address can even be programmed, although I had no need for that feature. The chip has some alarm features, which I also did not need for this project.

Using the chip is relatively easy and there are Arduino libraries and code samples around for your use (example here). For my specific application, I did not need a library as you can get the humidity and temperature values with only a few lines of code.

Basically, after waking the chip up, you read 4 bytes of data. The first byte includes two status bits: 00 = normal, 01 = stale data (click here for the definition of "stale data"), 10 = in command mode, 11 = not used. All other bits in the four bytes are used to convey relative humidity and temperature data that can be easily converted to RH percentage and degrees Celsius (which I converted to Fahrenheit).



HIH-6131 humidity and temperature IC


The HIH-6131 is distinguished from the HIH-6130 by a condensation-resistant hydrophobic filter that is visible in the pictures.


HIH6131 mounted

HIH-6131 humidity and temperature IC on a carrier board


Because it is an SMT IC, I used a small carrier board. With some careful soldering, it is not too difficult to manage and will allow you to mount header pins for easy access to the IC pins. 


LCD Display

To display the sensor values, I decided to use a Grove RGB backlit LCD (available here and here). This I2C display has two particularly desirable features for the project.

First, while the LCD is 5v, the I2C I/O is 3.3v/5v compatible, making it easy to use with the Arduino 101 which has 3.3v I/O. Second, the backlight is configurable and I wanted to use that feature to communicate certain conditions. That is, green for normal and blue when a central device has connected over BLE.

The Arduino driver that I used and sample code are available here.



Grove RGB backlight LCD (2 x 16)


Arduino 101 board

I chose the Arduino 101 (USA) / Genuino 101 (outside of the USA) board for the microcomputer. This is a 3.3v board with the Intel Curie module, but also with a lot of Arduino familiarity and ease of use. Another feature is that it comes with BLE capabilities on the board and a CurieBLE library. In addition to the information links in the references section above, there is a dedicated forum for the board here.


Arduino 101

Arduino 101 / Genuino 101


Circuit and Schematic

Circuit schematic

Schematic for the Indoor Air Quality Monitor. Click to enlarge.


The complete circuit schematic appears in the figure above. It is straightforward and uses relatively few parts. Both sensors are attached to the Arduino's I2C pins and I used 2.2K pull-up resistors on the I2C bus, which is powered by the 3.3v line that is available on the Arduino header. The 3.3v line also powers the sensors. The LCD I/O is also on the 3.3v I2C bus, but it is powered by the 5v line, which is also available on the Arduino header.

Add a few capacitors and the circuit is complete. Note that I used a 0.22 μF polarized capacitor for C1 because that's what I had on hand, but a (non-polarized) ceramic capacitor is the standard choice for power-supply decoupling.

Component Description

Parts List for the Indoor Air Quality Monitor:

C1 0.22 μF polarized capacitor
C2 0.1 μF non-polarized capacitor
C3 0.01 μF non-polarized capacitor
R1,R2 2.2K resistor
U1 iAQ-Core-C sensor module
U2 HIH-6131 sensor
LCD1 RGB LCD 2 X 16 (see text)
Case see text
Extension see text
Miscellaneous circuit board, headers, sockets, jumpers


The iAQ-Core-C sensor module is available through several online suppliers including Mouser. The HIH-6131 sensor is also available from online sources including Digi-Key. I used a convenient case to enclose the project, and I also used this extension for the case.

From the picture of the finished project (at the beginning of the article), you can see how I mounted the sensors so that they are exposed to circulating air. And to allow for easy removal, I connected the sensor pins using sockets instead of direct soldering. In retrospect, I probably should have placed the HIH-6131 in the front of the case as it runs a few degrees (F) high (as far as I can tell) likely because of heat generated from the Arduino 101 board that sits below.


Operation and BLE testing

When you power up the air quality monitor, using either USB or through the Arduino external power connection (see specifications link), the display will light in a few seconds with a green backlight. From left to right and top to bottom, the diplay will show sensor output for: RH, Temperature (F), CO2 equivalent, and TVOC equivalent values.

As mentioned, normally, the iAQ Core chip takes a few minutes to warm up. During this time, you will see a warm-up code instead of the values. Similarly, if other errors occur with either sensor, the appropriate error code will be displayed instead of a value.

If you exhale close to either sensor, you should see a jump in the RH value as well as the CO2 equivalent value. If you place the monitor in various home environments, like the kitchen when cooking, you will get an idea of the range of values.

Note also that iAQ values outside of the specified sensing range can be displayed, as is mentioned in the datasheet, and I preserved that characteristic in the software. The LCD values will refresh every two seconds, and that rate can be changed in the program code.

An easy way to test the BLE connectivity is to use nRF Connect for mobile (previously called nRF Master Control Panel). This free software is an impressive tool. Install it on your device (I used one with an Android OS), run it, and scan for BLE devices. If you have powered up the monitor you should see it in the list.


Screenshot of the nRF Connect Scan—note the "AirQuali" device


Tap on "CONNECT" and you will see the list of all of the monitor's variables that are being transmitted. Notice also that the LCD backlight has changed to blue, denoting a connection.


Screenshot showing the monitor's six transmitted characteristics


Next, tap on each of the six triple downward arrows (the first one is circled). You will see the same list of characteristics, but now you will see their values and they will update every couple of seconds.


Screenshot showing the monitor's six transmitted characteristics and their values


Those values are the sensor values that are being transmitted by the monitor. In order, they are: iAQ Core status, iAQ Core CO2, iAQ Core TVOC, HIH status, HIH RH, and HIH temperature.

If you examine the program code, you will see where these variables are transmitted, as well as their type. For example, the second value, which is circled in red, is 0xc2, 0x01, 0x00, 0x00. This value is for the CO2 measure which is a 16-bit integer. The first two bytes of the value represent this integer in "LSB, MSB" format. That is, the integer value is 0x01c2, which is decimal 450, which was the CO2 reading on the LCD at the time of the screenshot.

The TVOC variable is a long integer (32 bits), and RH and temperature are floating-point values—you could translate those as well.

Examination of the code will also reveal the assignment of a universally unique identifier (UUID) for each characteristic. These are generated using random numbers and were the product of using an online generator.

The nRF Connect app does not replace a custom app for the monitor which you could write for your device, but it is a very easy way to see what is going on and to verify the BLE functionality.



Below, you can download the complete Arduino code for the Indoor Air Quality Monitor. It is straightforward and should not be too difficult for you to customize, if you are so inclined.

For reference, this is the setup I used to write the code:

  • Windows 7, 64 bit
  • Arduino 1.6.7
  • Intel Curie Board 1.0.6 (as installed through the Arduino Board Manager)
  • Samsung Galaxy Notepad Pro 12.2 (as a central BLE device)


  Indoor Air Quality Monitor Code  

Closing Thoughts

This has been an interesting, rewarding, and very educational project for me. I am, in fact, impressed by the sophistication of the sensors as well as the relative ease of the implementation.

Hopefully, you will also find it interesting. If you do build one, or something similar, please let us know how it went for you.




  • Syed Ahmed Hussain 2016-09-17

    Brother don’t mind anything for asking this silly question!!So,what am gonna do with my air quality!Is that a reliable thing that wch ppl can use it eco friendly!Ur idea is too good and your project idea really blown my mind away! But, the thing always said by my teacher,“If you’re innovating something let it be useful to the people”.Dont think am saying this isn’t useful..thou if you make this project in step ahead wch can be the day to day life of ppl..witnessing usefulness…that will be more appreciable!This is a suggestion bro don’t take it wrong grin anyway your hardwork didn’t let you down! Congrats grin

  • latonita 2016-09-20

    Project is nice, however I’m curious whats BOM and total cost of parts used in this solution? smile
    Altogether it might be ridiculously expensive for this learning project. Only if those are laying around for free somewhere in the Uni lab smile

    • Raymond Genovese 2016-09-20

      Thanks for the kind words and taking the time to respond. I guess it all depends on what you call “ridiculously expensive”.  The total price that I calculated was ~ $100 USD. $20-Arduino 101 (, iAQ Core chip ($35), Temp/humidity sensor ($15), LCD ($14), Case with insert ($13). A few bucks for caps, sockets, etc.. and that is it (I left out a power supply if you wanted to use an external).  You could probably get that a bit lower with a more generic LCD, a cheaper temp/humidity sensor, and a cheaper case.

  • Tomtentp 2016-09-25

    Very interesting project indeed! I was wondering about the power decoupling for the ICs. Are those from recommendations for the specific ICs or are they something you came up with on your own and in that case what is the reason behind them?

    Should you genrally decouple all ICs and devices in a cirquit and in that case why wasnt the LCD decoupled?

    Thank you for the learning experience!

  • Wiky5 2016-09-30

    Nice article!
    I am interested in building a keyless, wireless ignition “switch” so as to not need keys on an old Jeep, and somewhat as an anti theft device asi it has no doors. I was thinking about using an arduino to enable the ignition and a start button whenever a paired phone is close enough, like 5 or less meters, and doing other simple logic tasks. Is BLE a good way to implement this?
    I also plan on changing almost all relays with 110A mosfets, waterproofing everything and other electrical improvements, without losing the original aspect of the Jeep.
    Do not worry, I know how to use arduinos, though I’ve never programmed anything with bluetooth.

    • Raymond Genovese 2016-10-02

      Thanks for the kind words. Sounds like you are thinking about a very sophisticated project - there is a lot there. To be honest, I don’t really know how well BLE might or might not work for something like that.

  • werner95661 2016-10-18

    Thanks for this great project!
    I built it and got it to run - somewhat…..
    Here is where I could need a little assistance:

    The display shows as follows:

    RH=E01     T=E01     0   (the “0"s are zeroes)
    CO2=0626   VOC=169     (the values obviously change over time)

    So, my interpretation is that CO2 and VOC are working correctly, but what is going on with RH and T? And what is that trailing “0” about?

    Is this an indication of a sensor malfunction? Or is this the “Stale Data” indication?
    If it is Stale Data, how can one kick-start the sensor to go back to normal?
    BTW: The AQM has now been ON for more than 48 hours, so I do not thing it has to to with a “dehydrated” RH sensor.

    Any advice will be highly appreciated.

    • Raymond Genovese 2016-10-18

      Hi and thanks for the kind words. When you see ‘E01’ on the display for RH and T, it indicates a stale data error *OR* that the HIH6131 has malfunctioned. That is, if the HIH6131 is working, it will appropriately send out an error code that will be displayed as ‘E01’. This should very rarely happen, if ever, and it should be cleared after the next read. If there is a wiring error or the chip is bad, the program could read the data as an ‘E01’, because unpredictable results can occur in that case.

      Here is what I suggest: First, very carefully check your wiring on the HIH6131. Make absolutely certain that the chip is oriented correctly so that what you think is pin 1 is, in fact pin 1. It is easy to make an error because it is small and there is no distinct pin 1 marking, You can identify pin 1 by the orientation of the circular area that is the sensor window - take a look at the linked data sheet carefully. Also, notice that the schematic in the data sheet does not have sequential pin numbers and the schematic in my article does. Triple check that you have wired it up correctly, including pull-up resistors on the I2C lines.

      If it is wired up correctly, I would advise that you isolate the HIH6131 and connect it up directly to the Arduino without any other circuitry. You can follow the wiring guidelines in the linked library article . Then, run the code in that library article and see if you get reasonable values. If not, you may have a bad chip.

      Those would be the first two things to test: check your wiring and independently verify that the HIH6131 is functioning.

      Hope this helps and please let us know how it goes.

      • Raymond Genovese 2016-10-18

        I reread your post and there is something else that I don’t understand. I missed it or skipped over it but when you say that you see:
        “RH=E01   T=E01   0   (the “0"s are zeroes)”
        You are saying that you are getting a trailing 0 on the display - that is, E01   0.

        Here are the code lines for that section:
          case 1:    // stale
            lcd.write(“E01 “);
            lcd.write(“E01 “);
        I just can’t see where you can be getting that extra 0. Could you have modified the code somewhere?

      • werner95661 2016-10-21

        There is indeed that spurious “0” at the end of the first display line.
        Checked the code, no mistake in the case 1 coding. (I did not modify your code at all)
        Tested the HIH6131 as a stand-alone device: works perfectly (i.e. all pins correctly identified by me).
        Now it is back to the rest of the project. Somewhere must be a glitch.
        I will let you know what I find.

    • Raymond Genovese 2016-10-22

      werner95661, This morning, on a whim, I installed the newest Curie Library, 1.07 [I wrote the article using 1.06 as stated and it was the most current at that time]. Guess what? I see exactly what you are reporting with the trailing 0. I reinstalled 1.06 and all is well again.

      I don’t know why this should be happening and nothing jumps out at me from a quick look at the changelog for 1.07. For now, could you please try to use 1.06 (you can do this directly from the Arduino IDE Boards manager) and see if it does not fix your problem?

      • werner95661 2016-10-24

        That did it!  It is the drive for the latest and greatest that will doom us…...

      • werner95661 2016-10-25

        ...and there is always another fly in the ointment:
        With board library 1.06 the sensor reading and display works, but BLE does not work (when trying to connect with nRF Connect version 1.5 on the iPad (mini 4) and iPhone 6S). nRF shows other BLE devices I have, but not the AQM.  With board library 1.07 the Rh and T display is messed up, but the BLE - nRF connection works. The interesting thing is that with 1.07 the AQM is only identified as Arduino 101, not with Air Quality… The display background color changes to blue when connected and back to green when disconnected.
        Seems that the combination of updates in the board library and nRF is not compatible .....

      • Raymond Genovese 2016-10-25

        BLE works well with 1.06 and my android Galaxy. Not sure what is going on with iOS as I don’t have one to test. I note some issues have been reported, see

        !.07 has made some speed improvements and other changes to the I2C and, right now, it is problematic for me to read the HIH6131 at all - even when using I2C_slow. I will keep looking into this, but I am not overly optimistic. As I understand, 1.07 is an interim release, on the way to 2.0 which should support central and peripheral BLE, so maybe it will undergo further fixes along the way…I hope.

      • werner95661 2016-10-26

        Strange things are happening! (Maybe because we are approaching Halloween?
        Turns out that my units needed some sort of a kick-start. When I used a third board, all of a sudden all of them came up on BLE through nRF Connect. The primary identifier shown is “ARDUINO 101-xxxx (where the xxxx looks like the last digits of a MAC address); Then, underneath under “Complete Local Name” there it is:  AirQuali (just that).
        I can confirm though that the T reading from the HIH show about 6 F high. I presume that can be corrected by a factor in the software.

        I will keep playing with the device(s) and report any new discoveries.

        In the meantime: Thanks for your help

      • Raymond Genovese 2016-10-26

        Glad that you are seeing some progress and you’re welcome. I noticed on the Forum board folks are having to press the master reset button to ‘wake up’ BLE. I have never had to do that but I wonder if it is an iOS issue?

        My temp runs hot (not 6 degrees, but a few degrees) as I mentioned in the article. Frankly, I should not have mounted the sensor that close to the 101 board because it generates heat, and if you move it, I think you will see the accuracy improve.

      • Raymond Genovese 2016-11-04

        werner95661, note the small code change that I posted to make to get the code working with 1.07. Can you please try that and see if works for you?

  • Raymond Genovese 2016-11-04

    *** UPDATE ***
    Since writing the article, the Intel Curie Boards package in the Arduino has been updated from 1.06 to 1.07. To make the software work with 1.07 make the following changes in the void getRhT() function.

    Find these lines…
      // make a measurement request by sending a write command (without data, just with the write bit set)
      Wire.endTransmission(FALSE);      // starts the measurement cycle and HOLDS the bus
      // note: it is necessary to use the FALSE above or the 6131 will hang Arduino I2C in my experience

    remove them and insert these lines in their place…
      // make a measurement request by sending a write command with 0xff data as a dummy
      Wire.write(0xff);            // send 0xff as dummy

    That change should get the HIH6131 working again without the stale data error