Skip navigation

Previous post: In-the-Air-Challenge: Exploring internally NDIR CO2 monitor

Next post: In-the-Air-Challenge: Laser-based dust counter using a photodiode, IoT connected



EXTECH CO100 air quality monitor has a very compact CO2 sensor module made by SenseAir  that puts out a PWM type signal proportional to concentration. To interface the EXTECH NDIR CO2 monitor with IoT I could very well use the Texas Instruments CC3200 Wi-Fi connectivity board donated by Element 14 for In-the-Air-Challenge. +5V power to the CC3200 board comes from the EXTECH circuit. I had to use a linear regression to fit LCD data with CC3200 data:


    ppm = ms * 10 * 1.0013 + 86


CC3200 uploading values to Xively is described in my  previous Backyard Challenge roadtest posts:

CC3200-LAUNCHXL program uploading data to IoT and hibernating


CO2 IoT.png

You can visit the Xively feed here:


CC3200 demo board works well but is quite large and can not fit inside the monitor enclosure. (ArduinoPro mini+ ESP8266 fits inside the EXTECH enclosure.)




Internet of Things simplifies life a lot. If there was no IoT then it would be much more effort and expensive to make a graph. Would need microcontroller, SD card, RTC, manually transfer file to a PC, plot it. So far I feel to be done with the CO2 monitoring electronics and next week will turn to photodiode circuit counting airborne dust  particles.


After a weekend there is some data to analyse:

co2 sun- mon.png

Sensor is inside the office in the downtown Riga. It shows that during working day air in the office is OK. In the city CO2 content decreases in the night and starts to rise  at 6:20 in the morning. After 19 pm the air becomes cleaner all over the night until at 6:20 morning traffic begins. Sensor is inside building so it takes extra hours until air ventilates.


On a short time scale there is some strange periodic spiking appearing roughly every 10 minutes. This could be some internal PID regulation inside the Sensair sensor.  There is a typical shape of the spike going upwards and then downwards. So the average value is not so much influenced. Spiking peak-to-peak amplitude is about 75 ppm that is consistent with the EXTECH datasheet specified precision of 75 ppm.

co2 spikes.png

Here is format how to get out picture from Xively for a defined period of time with manual vertical scale values:…

Previous post: In-the-Air-Challenge: Measuring CO2 levels during lectures with EXTECH CO2 monitor

Next post: In-the-Air-Challenge: NDIR CO2 meter connected to IoT via TI CC3200 Wi-Fi connectivity board


Opening the case of made in China EXTECH CO100 air quality monitor reveals a very compact NDIR CO2 sensor made by (Sweden) type model S8 004-0-0062. Connected to other electronics with just 3 wires: 5V, GND and output signal. On the sensor output signal is present a TTL pulse once a second (exactly every 1009ms) with PWM lineary proportional to CO2 concentration.


At 500 ppm CO2 the pulse width is 50ms. That is what I got today by opening the room window.

At 1200 ppm warning starts beeping and oscilloscope shows 120 ms pulse length.

At 10000 ppm the pulse width is 1s. Basically only a very short peak going down that is useable for triggering.


P1060123.JPG P1060126.JPG

Visually one can see through the air diffusion membrane that a small lamp is turning on once a second for a short while, and it is not very bright, so emmision peak is in the Mid-IR and lamp can last for 15 years according to specs.


P1060122.JPG P1060121.JPG


Schematics is nicely designed and assembled. On one side of the PCB following components can be identified. Large chip - LCD display driver. Small chip - touch sensor buttons driver. Moisture/temperature sensor model SHT. 3V Li cell for clock backup. 5V regulator working from 6.2 V at the input jack.

On the other PCB  side is a MSP430F microcontroller. USB and FTDI chip place is not populated. No RX or TX signals coming from the microcontroller.

So the only way how to connect external electronics is to measure the output of the CO2 sensor directly.


Measuring precisely the pulse length on one second time scale should be an easy task to do with a CC3200 board (or TI MSP430 + ESP8266). It was nice to learn this methoid how to enclode analog signals using PWM.


Conclusion and recommendation to electronics guys is: Buy just the NDIR sensor!


Continue reading: David Giorni NDIR CO2 detector

L. Crawley 2008 Dr. Thesis about NDIR trace gas detection

Previous posts:

In the Air Design Challenge - Pollen & Allergen Sensing

In the Air Design Challenge - Pollen & Allergen Sensing – Post 1 (Pollen Sensor)

In the Air Design Challenge - Pollen & Allergen Sensing – Post 2

In the Air Design Challenge - Pollen & Allergen Sensing – Post 3 (AirVantage Intro)

In the Air Design Challenge - Pollen & Allergen Sensing – Post 4 (Preparing the InTheAir Power Board)

In the Air Design Challenge - Pollen & Allergen Sensing – Post 5 (InTheAir Power Board)

In the Air Design Challenge - Pollen & Allergen Sensing – Post 6 (HDC1000 Sensor)

I was very busy at work the last couple of weeks so I couldn’t work that much but now I can concentrate on my build.


Power supply PCB + sensor connectors

Last week I received my prototype PCB from WE Direkt. I’m very happy with what they did. I’m not an expert since this is my second outsourced  PCB but it looks really great. SeeedStudio board that I ordered a couple of years ago was fine too, but this one is looking much more professional. Pads are gold plated (not really required but still).

Even though the price shown on WEDirekt site during checkout was a bit higher it was reduced after they did the “data check”. They take into account the board size and reduce the price if possible. So, I had to pay ~25€ after all and got the board in 7 days.

The only issue with the board (that I'm aware of) is my fault - I submitted BRD file and left some layer that wasn't supposed to be there. That's why there are overlapping silkscreen labels all over it.

I took these pictures using my phone so they’re not top quality. I will use a proper camera when I finish the board completely.

IMG-20150128-WA0007.jpgImage 1 - PCB from WE Direkt


Thanks to WE and especially sleuz I got the capacitor kit so I had all the necessary capacitors for my build.

2015-01-30 19.09.35.jpgImage 2 - Würth capacitor kit (0805)


However, I still didn’t receive inductor kits that everyone else got as part of challenge kit. As a workaround, Simon sent me just the required inductors until I (hopefully) receive those kits. Interesting thing about those inductors is that I had to pay duty + tax for 5 inductors from Simon that cost 1.15€! That’s really silly, but what can you do It was just around 0.35€ of duty and tax but it takes time to handle it so I’m still waiting for them too.

So, many thanks to Simon and WE!

Some resistors are still missing from the board but I will get those locally so they should be acquired quickly.


Current board state

This is my first ever SMD board/soldering but I think it might end up looking nice anyway. I was using hot air station (for SMD) and soldering iron (for through-hole parts).

Please disregard the HDC1000, I was just playing with it and forgot to take it out.


Image 3 - Semi-populated board



Those inductors should be here in a day or two so I will give an update post as soon as I finish populating the board.


I got my hot air station last year but didn’t get the chance to use it too much until now. It was really fun!

Hi everyone,


I will be giving a detailed update this weekend, I just wanted to say that part of my Element14 order was canceled by them due to parts being discontinued. They never informed me, only when I called to find out about the delay is when they let me know. They wouldn't allow me to substitute the item for another and said only the one who submitted the order could do this. They were pleasant to me but I feel that I should have been notified as soon as possible. The item missing was worth over $150 and am wondering if they realized the issue it has caused me. I will still complete the project but it will be a lot more difficult and maybe costly.


Sorry for the short rant,


Dale Winhold

Previous post: In-the-Air-Challenge: Spending the 500 USD parts budget

Next post: In-the-Air-Challenge: Inside the air quality CO2 monitor

EXTECH indoor air quality monitor model CO100 from Farnell is a great thing to have!


I tested the device during a lecture with ca 20 people. CO2 concentration raised to 2200 ppm after 50 minutes. During the next lecture one window was open to have a ca 10 cm gap and the CO2 concentration stabilized at 1500 ppm. This shows the importance of reasonable ventilation. After the lecture there were questions from attendants who asked what the device is doing and what it costs.




This triggered me to search for information what are acceptable CO2 levels?


  • In Earth atmosphere CO2 content has increased from 300 to 400 ppm=0.04% during the last 60 years. It is a greenhouse gas responsible for global warming. Less in sommers when plants absorb it. I think there is some global warming taking place because of diminishing glaciers and polar ice.  Melting  is an integral effect over years, while just measuring temperature is not precise enough because of large scatter.
  • 2000...5000 ppm sleepyness, headaches, loss of concentration, increased heart rate.
  • maximum allowed concentration within a 8 hour working period: 5000 ppm = 0.5%
  • slightly intoxicating, breathing and pulse rate increase, nausea: 30,000 ppm = 3%
  • above plus headaches and sight impairment: 50,000 ppm = 5%
  • unconscious, further exposure death: 100,000 ppm = 10%


Breath contains almoust stable amount of 3.8% CO2 (38000 ppm). In other words, exaled air contains about 100 times the concentration of carbon dioxide that inhaled air does. If a healthy person were to voluntarily stop breathing (i.e. hold his or her breath) for a long enough amount of time, he or she would loose consiousness, and the body would resume breathing on its own.  If one does not inhale, the level of carbon dioxide builds up in the blood. Is monitored while performing artificial lung ventilation in hospitals during surgeries.


Accidents have happened inside beer cellars, garages with car motor running, or while sleeping in a car and running engine against cold. In such extreme environments as submarines and space ships caustic soda or limewater can be used to absorb CO2 from air.


The ability to measure carbon dioxide (CO2) in the breath of a patient or capnometry, is one of the fundamental technological advances of modern medicine

By blowing into the Extech analyser I easily reached the maximum reading of 9999 ppm and the device became saturated.


Found a great overview article about CO2 measurement history:

M. B. Jaffe, Infrared Measurement of Carbon Dioxide in the Human Breath: “Breathe-Through” Devices from Tyndall to the Present Day , 2008.



There seems to be some contraversy in values from different sources. Seems that CO2 is not very toxic. We exhale it so much 38000 ppm in breath!

When you use CO2 sensing, energy savings can result because ventilation is based on actual occupancy of the rooms. One can estimate if the rooms are overventilated or not enought ventilated.

Recommended levels

  • 250 ‐ 350 ppm – background (normal) outdoor air level
  • 350‐ 1,000 ppm ‐ typical level found in occupied spaces with good air exchange.
  • 1,000 – 2,000 ppm ‐ level associated with complaints of drowsiness and poor air.
  • 2,000 – 5,000 ppm – level associated with headaches, sleepiness, and stagnant, stale, stuffy air.  Poor concentration, loss of attention, increased heart rate and slight nausea may also be present.
  • >5,000 ppm – Exposure may lead to serious oxygen deprivation resulting in permanent brain damage, coma and even death.


Regulatory limits in different countries


  • ASHRAE 62‐1989: CO2 concentration in occupied building should not exceed 1000ppm.
  • Building bulletin 101 (Bb101). UK standards for schools say that CO2 averaged over the entire day (i.e. 9am to 3.30 pm) should not exceed 1500ppm.
  • OSHA, Germany, Japan, Australia, UK: 8 hours weighted average occupational exposure limit is 5000ppm.

Today I tested the power supply section of the AirMobile board.

As you can read in this post, the feature of this board is that it is powered up by a Peltier cell, thus harvesting the wasted heat of a car radiator.

First of all, a note about the The step-up transformer turns ratio will determine how low the input voltage can be for the converter to start. Using a 1:100 ratio can yield start-up voltages as low as 20mV.

To make the test, I placed the hot face Peltier cell on a house radiator. I simulated the car movement by means of a fan that cools down the cool face of the cell itself.

Because the header pins is connected to the commanded 5V output, I pulled up the "5V-Enable" input pin of the LTC3108 circuit.


In video below the board being powered by the radiator heat can be seen.


During these first experiments, there are some aspects that needs further investigation:

  1. where is the high-frequency ripple on the Peltier cell's output from? It is present also when the cell has no load connected so it should not be due to an error in the board...
  2. when connected to the LTC3108 the cell's output voltage is constantly around 50 mV. Is it the LTC3108 that varies its input impedance to make the cell work with that specific output voltage? When tested with no load, the output of the Peltier cell is much higher than that..
  3. it would be very interesting to monitor the difference of temperature between the two surfaces of the Peltier cell
  4. It would be very interesting the measure the current that flows, but I don't have a multimeter that is enough precise
  5. It would be very interesting (may be later during this challenge) to compare the efficiency of different step-up transformers

Previous post:  In-the-Air-Challenge: A sheet of laser light for 2D visualization of dust flow

Next post: In-the-Air-Challenge: Measuring CO2 levels during lectures with EXTECH CO2 monitor


Almoust at the last moment I compiled a list of 500 USD budget for the parts of the challenge that amounts ca 430 EUR in Jan. 2015.


I was very impressed that Christian Defeo at Element 14 ordered everything in a couple of hours after I sent him an email with the long list. I was mostly interested in optical CO2 meter. Price for it varied a lot at Farnell webshops in different countries. I used prices from Germany website to add up to 430 EUR. And that was fine. No added VAT. Thanks a lot to Farnell.  The parts arrived to my home address with UPS truck in a couple of days. They were sent from UK location.




197,71 €

I will use this near-infrared non-dispersive type CO2 sensor to compare with electrochemical CO2 sensor module. NDIR sensor is callibrated against NIST traceable device, accuracy 75ppm or +-5%.

Good <800 ppm
Normal 800...1200 ppm
Bad >1200 ppm


First tests in the sleeping room at home showed that air was OK bad during the night 700...800ppm. In a confined space like a toilet CO2  content rised to 2000 ppm within 5 minutes. I will test the device during the lecture with ca 20 people this week.

This model has an empty battery compartment and USB hole is not populated. I will try to see if there is some place inside where analog voltage could be accessed with MSP430 or CC3200 and sent to IoT over Wi-Fi.




2,35 € * 4 pieces

This single-supply OPamp I plan to solder this week in a home-made dust particle counter to amplify photodiode signal after schematics in paper:

A. Morpurgo et al , "A low-cost instrument for environmental particulate analysis based on optical scattering"




19,42 €

Adjustable voltage 3...12V in steps. Current 600 mA. switching power supply adapter.




19,25 €

I would like to test this camera with RPi and compare with USB camera Logitech C270 that I use on Beagleboard/Rpi.




7,01 € * 2 pieces

Nice shielded alu boxes.





This platin wire sensor is good for absolute callibration of other sensors.




7,58 €  * 3 pieces




1,39 €    * 5 meters

Basically similar cable as used for USB.

Household energy consumption could be the highest contributor in one's carbon footprint.  By measuring how much energy we consume each day we may be able to adjust our usage patterns to save.  There are several ways to measure household energy, both invasive and non-invasive methods.  In this project, the focus will be on non-invasive method, specifically using a split core type current transformer sensor to create a power meter.  Hall-effect is another type of non-invasive method, such as using the ACS712 chip, which will be blogged another time.


(Current transformer) CT sensors are used to measure alternating current.  As any transformer, it has a primary winding, a magnetic core and secondary winding.  Split-type CTs can be clamped around the supply line of an electrical load to tell how much current is flowing through it.  It does this by acting as an inductor and responding to the magnetic field around the current carrying conductor.  In this case the primary will be the live or neutral wire (not both) and passed through the hole of the CT sensor.  The secondary is made up of multiple fine wires enclosed inside the transformer.  By reading the amount of current being produced by the coil, we can then calculate how much current is passing through the conductor. 

The CT sensor used in this project is a current output type and for this data to be useful, the induced current needs to be converted to voltage using a burden resistor.  This specific sensor has the following characteristics: 30A nominal, 60A maximum rated primary current and 2000 turns ratio.


The blog post in this link has a good explanation in the circuit design process and will be used as a guideline in designing a power meter for Texas Instrument's CC3200 Launchpad XL.



First, we need to know the maximum measurable peak current as:

Imax_measured = √2 * Imax_rms = √2 * (60A) = 84.8528 A

The current at the output would be proportional to the turns ratio, 1:2000.

Isensor = Imax_measured / no_of_turns = 84.8528 / 2000 = 0.04243A


The CC3200 ADC recommended maximum input level should be less than 1.45V, thus 1.4V will be used in this instance.  For maximum measurement resolution, the maximum voltage at the burden resistor will be half the maximum ADC input level.


Vburden = Vadc_max / 2 = 1.4V / 2 = 0.7 V


Given voltage and current values, we can derive the value for the burden resistor as:


Rburden = Vburden / Isensor = 0.7V / 0.04243A = 16.49 Ω


The ideal burden resistor is 16.49Ω, we will use the standard 16.5Ω value for this specific application.  We now have a basic circuit as shown in figure below.  Simulation was ran through Texas Intruments' TINA-TI Spice based program.


Remember that the voltage signal across the burden resistor is still AC (see right image above), and the ADC is not capable of measuring negative voltage.  So we have to add this AC voltage by 0.7V to make the voltage measurable between 0 and 1.4V.  This can be achieved by adding a clamping circuit as shown below.  The resistor values where calculated using the voltage divider equation to achieve 0.7V across R2 set at 10kΩ.


This completes the electronic design part of the power meter.

For the software, we will be porting EmonLib an Arduino Library from to a more portable C library.  Using the ported library, we can calculate the apparent power.  With the apparent power now known we can average the samples over a period of a second to resolve energy in Watt-sec which will determine the carbon footprint usage where 1KWh = 1.52 lbs CO2 (estimated EPA).  Snippet below.


static float aveS = 0;          // average apparent power
static uint32 n = 0;
float Irms = EmonC_CalculateIrms(1480);
float S = Irms * VAC_MAINS;    // S - apparent power, VAC_MAINS 230Vac

WEIGHTED_AVE(&aveS, &n);

  float co2 = CONVERT_TO_KWH(aveS) * 1.52f;
  DEBUG_LOG("co2: %3.2f\r\n", co2);
  ReportCO2(co2);          // send data to central hub  
  newSecond = false;



Attached partially ported energy monitor library.  Only RMS current calculation is ported atm as there is no hardware support for VI calculation for this project.

Update 2:

Its just now that I was able to verify this feature.  After some calibration and including the power factor (set at 50%), I got the power usage close enough to match a power meter.  There is a bit of difference but I guess that is caused by the resolution of calculation and that the meter would probably be calculating the actual power factor as well.  Anyways, I think its good enough for now.



Next posts will be about the enclosure, installation and actual testing.


Current monitoring with non-invasive sensor and arduino | Homautomation

How to build an arduino energy monitor - measuring current only | OpenEnergyMonitor

1 kilowatt-hour · BlueSkyModel

CC3200 + 430BOOST-SHARP96 with Energia:

In this chapter I will explain the CC3200, 430Boost-sharp96 and Energia. This should save lot of time with given code and example code for the existing hardware and software.

I have try the BBB and BB View 4.3" with no success, not even power up the display to show something @.@ so give up that for now.


CC3200 come with pre install program. User can test and play around with the hardware and software. I will not talk about that here.

All information about this can get from TI webpage or just follow the given info come together with the CC3200.

Hardware & Software:

I will put the hardware and software together because they related to each other.

Let go straight to the point for CC3200 and Energia.

Preparation for the CC3200 to use with Energia. There are few connection setting need to be done at CC3200.

Jumper 8 need to be remove, connection at P1 also need to be remove and make a connection at jumper 8 and JTAG

Picture show connection example.


Next is the Energia software where it look similar with the Arduino IDE.

Here just show  the LCD example code to the Energia for CC3200. The given link bellow is the example code.

Link to 430 boost-sharp96 code.Sharp Memory LCD BoosterPack | Energia

Unzip the downloaded folder, place them under related hardware libraries folder.

Picture show the example for the folder location for CC3200. Don't put the code under example folder it will not work.

After everything done you should be able to program CC3200.

Remove the jumper wire and plug in the LCD module. Power up the board and it should work.

Picture show the example for the LCD display. Sorry for the blur picture


The coming day will be programing, programing and programing.

Now stuck with value to display at the LCD. It took me more then 3 days and I still unable to convert the float value to char for the LCD.

I heard Energia is similar with Arduino. Now I realize that there are very different.

Place the code here in case some one can help .

//float to charactor convertion
float value = 12.3456789;
char res[10];
sprintf(res, "%4.3f", value);


char res1[10];
float valuek = 78.230984;
sprintf(res1, "%4.3f", valuek);


myScreen.text(10, 20, "Voltage:");
myScreen.text(10, 30, res);
myScreen.text(10, 40, res1);


myScreen.text(10, 10, "Haze Monitor");

screen show value 2.031. I have no idea at all where this number come from OMG.


Old style programing.

I think many people will comment about my programing.

Using the basic function in program to change the float to char(number only). It working at slow speed due to using fix for loop.

This program also just run up to XXXX.XXXX and it should be more then enough for this project.

I will optimize the programing is there is time to do it. For now keep to this first because cannot fine function to convert float to char in Energia.

Any suggestion are welcome to improve this programing .

//float to char convertion

    float value = sensorValue * a/ b;

    //float value = 9999.9999;// for testing

    int v1000 = 0;

    int v100 = 0;

    int v10 = 0;

    int v1 = 0;

    int v01 = 0;

    int v001 = 0;

    int v0001 = 0;

    int v00001 = 0;


    //make the reading to 0.XXX

    int x = 0;

    for (x = 0; x < 100; x ++)


    if (value > 1000)


      value = value - 1000;

      v1000 = v1000 + 1;


    else if (value > 100)


      value = value - 100;

      v100 = v100 +1;


    else if (value > 10)


      value = value - 10;

      v10 = v10 +1;


    else if (value > 1)


      value = value - 1;

      v1 = v1 +1;


    else if (value > 0.1)


      value = value - 0.1;

      v01 = v01 +1;


    else if (value > 0.01)


      value = value - 0.01;

      v001 = v001 +1;


    else if (value > 0.001)


      value = value - 0.001;

      v0001 = v0001 +1;


    else if (value > 0.0001)


      v00001 = v00001 +1;

      value = value - 0.0001;







    char res[1];

    sprintf(res, "%d", v1000);

    char res1[1];

    sprintf(res1, "%d", v100);

    char res2[1];

    sprintf(res2, "%d", v10);

    char res3[1];

    sprintf(res3, "%d", v1);

    char res4[1];

    sprintf(res4, "%d", v01);

    char res5[1];

    sprintf(res5, "%d", v001);

    char res6[1];

    sprintf(res6, "%d", v0001);

    char res7[1];

    sprintf(res7, "%d", v00001);





    myScreen.text(10, 20, "Voltage:");

    myScreen.text(10, 30, res);

    myScreen.text(15, 30, res1);

    myScreen.text(20, 30, res2);

    myScreen.text(25, 30, res3);

    myScreen.text(30, 30, ".");

    myScreen.text(35, 30, res4);

    myScreen.text(40, 30, res5);

    myScreen.text(45, 30, res6);

    myScreen.text(50, 30, res7);



Picture show the output for the given float value. Play around with some value and the output is still acceptable.



Dust, Temperature and Humidity Monitor Chapter 9



Dust, Temperature and Humidity Monitor Chapter 11


I have been busy with the IoT HOliday Lights project but after its completion, I have jumped right back here. I had the boards manufactured from Seeed and they look good. I will post a progress blog separately, but right now, I need to post about my experiments with the HDC I soldered.


I2C Testing with the Buspirate


This mini article is part of a larger project an I will link to it at the end. For this project, I was required to use the TI HDC1000 and instead of buying a module, I decided to get samples and a make a PCB of my own. This would be great except I had to create the footprints which are almost microscopic! Anyways I got it made from SeeedStudios and I bought one of those ultra cheap hot air stations with no indications about temperature or airflow and some paste and got started. The reflow happened painlessly and I was pretty happy with myself. Before I move on to mounting any other parts, I decided to see if the HDC1000 was alive or had kicked the bucked in my hotair experiment.

So I started with soldering the header as well as power test pins and I hooked up the BusPirate. Har har har! I think I can explain the rest via a video and so...


Reading the Temperature and Humidity


In order to read temperature and humidity, there is a set of commands you have fire at it. You should go through the datasheet but I am going to give you the quick and dirty on reading the temperature & RH. The first thing to do it configure the HDC1000 to take measurements. It is usually in deep-sleep so I need to wake it up and configure it. So I have to send...

[0x86 0x02 0x1e 0x00] Why I send that? Well the 0x86 is the address of the HDC1000 with write bit and 0x02 is the configuration register address. 0x1e & 0x00 is the configuration to write. Next we Trigger the reading by [0x96 0x00 Note that there is no ] at the end which means that I do not send a stop character. Next I send... [0x87 rrrr] Which sends another start of frame and the read address of the HDC1000. We read 4 bytes which are MSB then LSB for the Temperature and Humidity.




Using the BusPirate to get T & RH[/caption] I am getting the temperature but the humidity still boggles me and I think I may have burned it out. I will post more once I test another HDC1000 or someone helps me Till then,



Finally I (almost) completed the AirMobile sensor board

Here it is




If you think it's awful, I agree with you... I made too many mistakes, but component's  bottom views always confuse me.

Anyway, to complete the board I have to

  1. mount the MiCS2710 sensor
  2. mount the Bluetooth module


The next step is to test the power supply section...

Previous posts for this project:





In the past weeks, I experimented with the GP2Y10 dust sensor from Sharp. Using an Arduino all was well, but I was however running into problems when using it with the CC3200. It's not the only issue I encountered with the CC3200. There was also the fact that the I2C pins of the CC3200 and FuelTank did not match.


I've tried to tackle both issues with a custom BoosterPack (my first!).





To start, I searched for BoosterPack templates. I quickly came across the ones from TI: Build Your Own BoosterPack for TI LaunchPad


The BYOB kit from TI contains a variety of files for different tools: Eagle, Fritzing, ... Very nicely done and easy to find!





Using Eagle, I created a schematic and board. Now, I don't have much experience with Eagle. I did fiddle a bit with it during the Forget Me Not challenge, but never got to making an actual PCB. Fritzing seems to be more up my alley, but anyway ... let's proceed.


I loaded all the required parts in the schematic and started connecting all the dots. There are four parts to this schematic:

  • the opamp circuit as suggested by shabaz in Week 11
  • the circuit required to hook up the dust sensor
  • the launchpad headers
  • an optional I2C connection to overcome the mismatch between FuelTank and CC3200


This is the schematic:

Screen Shot 2015-01-25 at 19.55.27.png


For the board, I laid out the components across the available space and let Eagle do the routing. This is the resulting board:

Screen Shot 2015-01-25 at 19.55.14.png


Nothing spectacular, but I'll be more than happy if I manage to get it soldered and working

Best view 1920 X 1200

CAM editing:

Still editing the CAM file to make all hardware compatible with the PCB.

Having some down side due to different pin location but still able to solve the issue. Just need to be careful when using this PCB due to non command sense routing .

I hope nobody else will use this PCB, if not they sure hate me.


Picture show the almost complete merge job with CC3200 header not align with the BBB header.

Version 5 with solving all the issue for the merge jobs. The file will be ready for manufacture after the final checking.

Solving problem with the NC file for the BBB and CC3200 by manual hole placing over the given pad.

According to the plan, it should able to support BBB, CC3200, MSP430FR5969, fan, sensor and 430boost sharp96.

Now just hope that I not miss or mistake any major dimension and size.


This is the merge PCB for all the gerber file from TI and eagle.

Version 8 for the PCB with detail checking and modification. Solving some overlap silk screen and number.

4 design PCB been align, modifier and merge.


Picture show the example for the PCB in CAM after merge.



Clearing the overlap drill and unwanted silk. Final touch for the PCB and this what I get.

Better PCB for manufacture.


This is the PCB that going to send for manufacture. Hope everything go like planned.

I also making a prototype PCB to test the size and dimension:)


Link for the gerber file.


CC3200 | Wi-Fi (IEEE 802.11 / WLAN) | Wireless Connectivity | Tools & software


The PCB for this project: (The share download link will broken without notice)


Prepare for the worse, PCB ready to send out then come the connector issue. OMG it very difficult to find a PCB stack through connector.

No choice new PCB design with available connector need to come. So here introducing my new PCB design 2.





Tokyo Banana is not banana. It not mean banana grow in Tokyo japan.

It just cake with banana flavor made in Japan

Picture of it he..he..




Dust, Temperature and Humidity Monitor Chapter 8



Coming soon

WP_20150117_003 1.jpg

Since most of the foundation software for this system is functional, the next posts will be more on the hardware aspects of the system starting from the power supply.  As previously mentioned, the board design is more of a development platform than anything else, and so has a lot of provisions for alternative circuits and ease of modifications.  The board was also divided into two main parts, power supply and peripheral.


The supply block can be of any four power sources: (1) Battery, (2) Solar (3) 12-VDC vehicle battery and (4) AC-mains power. TI's TPS767D301 is used to provide regulated 5Vdc and 3.3Vdc.  Aside from having two output channels, this particular LDO regulator was chosen because of the high output current capability (up to 1A per regulator) yet an ultra low quiescent current.  The adjustable regulator can easily be set via external resistor divider.  See programming the TPS767D301 adjustable LDO regulator section page 17 of the datasheet.


The outdoor sensor module utilises harvested solar energy to charge the CR123A rechargeable battery while providing power to the sensor module.  Battery is managed by TI's BQ25504, an ultra-low power boost converter with built-in battery management unit.  This is the ideal power management IC solution for the outdoor sensor module.  The circuit used for this project was adopted from the Solar Application Circuit as described on page 18 of the datasheet. This section also has an example on how to calculate the R values for a specific application.  One would find the spreadsheet calculator to be very useful in the design process.


A couple lessons I've learned during the design process for this power source.


(1) if you are going to do/copy the schematic from the sample application, assume the OC and OK resistor values to be greater than 10MΩ, because


(2) the resolution of standard values above 10MΩ is low and would require a couple resistors to achieve the desired value.  i.e. 15.6MΩ would realistically be 10MΩ and 5.6MΩ in series and this should be noted in the design of the schematic and laying out of components in the PCB design.


I was not mindful initially when I designed this section of the board, and it can be obviously seen on the R35, I only had a place holder for a single 0402 resistor.  At least it was not that bad of a mod as there was room in the left side to accommodate two 0603s connected in series.




Below is the circuit in action connected to a solar panel MC-SP0.8-NF-GCS - MULTICOMP - SOLAR PANEL, 0.8W, 4V, NO FRAME | element14 New Zealand



Next one would be the supply block derived from AC mains.  This supply is the second simplest power circuit (simplest one is the straight connection of battery to the dual LDO).  Since this supply uses AC mains, and could potentially be dangerous, extreme care is fundamental during testing.  The core component for this power block is the compact single output AC-DC converter from Vigortronix.  VTX-214-005-105 - VIGORTRONIX - AC-DC CONV, FIXED, 1 O/P, 5W, 5V | element14 New Zealand.  The compact size and 5W output are the key features for this module.


Initially, I thought of implementing a transformer-less power supply because I do not want to use a bulky and costly transformer.  However, that can only provide low DC current and quite dangerous as there is no isolation from the high side.  This compact AC-DC converter ticked the supply requirements for the smart switch and plug modules.

Lastly, the emission sensor module will be mounted somewhere in the vehicle and will be powered from the vehicle battery.  For this specific module, TI's TPS62153A buck converter has been selected.  This power management silicon has the following key features which were considered key aspects in the component selection:

  • can provide up to 1A of continuous current at 5V output
  • low quiescent current
  • over temperature protection
  • short circuit protection
  • rated for automotive applications

WP_20150119_002 1.jpg


Hope you enjoyed this post as much as I enjoyed populating and testing the boards, 'til next update. 

Previous posts for this project:





I'm using a Beaglebone Black and BB View as the main user interface. Because the BB View is a touch screen, I want to avoid the need for another input device such as a keyboard.

In this post, I'll set up openHAB and Chromium to start automatically and visualise the openHAB GUI without having to enter an URL or open a browser manually.



First, I created a script which will launch the desired application, in this case: openHAB. The script will be put in "/usr/bin".


debian@beaglebone:~$ sudo nano /usr/bin/



The script needs to be made executable so it can be launched successfully.


debian@beaglebone:~$ sudo chmod u+x /usr/bin/


Next, create the service. Some prerequisites can be specified, for example the need of having the network up and running first.


debian@beaglebone:/usr/bin$ sudo nano /lib/systemd/openhab.service



Create a symbolic link to let the system know where to find the service:


debian@beaglebone:~$ cd /etc/systemd/system
debian@beaglebone:/etc/systemd/system$ sudo ln /lib/systemd/openahb.service openhab.service


Try starting the service to check for mistakes/errors. If all is well, the service can be enabled.


debian@beaglebone:/etc/systemd/system$ sudo systemctl daemon-reload
debian@beaglebone:/etc/systemd/system$ sudo systemctl start openhab.service
debian@beaglebone:/etc/systemd/system$ sudo systemctl enable openhab.service


As a final check, reboot the Beaglebone Black to confirm it's working as expected.


debian@beaglebone:/etc/systemd/system$ sudo reboot


After reboot, the openHAB start script seems to be running, this is a good sign. Checking the logs, openHAB is started as expected!


debian@beaglebone:~$ ps aux | grep start

root       758  0.0  0.0   1336   440 ?        S    18:59   0:00 /bin/sh /opt/openhab/
root       996  0.0  0.5   5864  2676 ?        Ss   18:59   0:00 /usr/sbin/apache2 -k start
www-data  1003  0.0  0.3   5644  1996 ?        S    18:59   0:00 /usr/sbin/apache2 -k start
www-data  1005  0.0  0.4 227056  2364 ?        Sl   18:59   0:00 /usr/sbin/apache2 -k start
www-data  1007  0.0  0.4 227048  2356 ?        Sl   18:59   0:00 /usr/sbin/apache2 -k start
debian    1323  0.0  0.1   1576   592 pts/0    S+   19:00   0:00 grep start


debian@beaglebone:~$ less /opt/openhab/logs/openhab.log

2015-01-14 19:00:39.422 [INFO ] [.o.core.internal.CoreActivator] - openHAB runtime has been started (v1.6.0).
2015-01-14 19:00:50.451 [INFO ] [o.o.i.s.i.DiscoveryServiceImpl] - mDNS service has been started
2015-01-14 19:00:51.111 [INFO ] [o.o.i.s.i.DiscoveryServiceImpl] - Service Discovery initialization completed.
2015-01-14 19:00:51.168 [INFO ] [.io.transport.mqtt.MqttService] - MQTT Service initialization completed.
2015-01-14 19:00:51.180 [INFO ] [o.i.t.m.i.MqttBrokerConnection] - Starting MQTT broker connection 'eclipseiot'
2015-01-14 19:00:57.860 [INFO ] [c.internal.ModelRepositoryImpl] - Loading model 'rrd4j.persist'
2015-01-14 19:00:59.817 [INFO ] [c.internal.ModelRepositoryImpl] - Loading model 'intheair.items'
2015-01-14 19:01:11.457 [INFO ] [c.internal.ModelRepositoryImpl] - Loading model 'intheair.sitemap'
2015-01-14 19:01:15.109 [INFO ] [] - Started REST API at /rest
2015-01-14 19:01:21.365 [INFO ] [.o.u.w.i.servlet.WebAppServlet] - Started Classic UI at /





To automatically start applications when the desktop loads, an "autostart" file can be edited to add the required applications.


At the end of the file, I appended a line to start Chromium automatically and open the openHAB web interface. I've also added the "--kiosk" option, which will load Chromium in full screen mode without the possibility to close it. This will be useful to avoid anyone accidentally closing the application or tampering with the system.


debian@beaglebone:~$ sudo nano /etc/xdg/lxsession/LXDE/autostart

@lxpanel --profile LXDE
@pcmanfm --desktop --profile LXDE
@chromium --kiosk "http://localhost:9090/"


The result after having applied the changes and rebooting the system, is the following:

photo 1.JPG


There are two issues with the above screenshot:

  • Chromium is started and attempting to open the openHAB GUI before openHAB is fully started
  • There is a warning message at the top regarding missing API keys


On the good side: Chromium is started in kiosk mode and trying to open the correct URL, meaning the command works.


To solve the first issue, I chose the quick and dirty solution of adding a delay. Because other "custom" commands might be needed, I moved the delay and startup of Chromium to a separate script and called that script in the "autostart" instead.


I added a 2 minute sleep before starting Chromium, giving openHAB enough time to start properly.


debian@beaglebone:~$ sudo nano

sleep 120 && chromium --kiosk "http://localhost:9090/"

debian@beaglebone:~$ sudo chmod u+x


debian@beaglebone:~$ sudo nano /etc/xdg/lxsession/LXDE/autostart

@lxpanel --profile LXDE
@pcmanfm --desktop --profile LXDE
@sh /home/debian/


After rebooting, Chromium is started 2 minutes later as expected and the openHAB GUI loads properly. Ideally, I should check for openHAB's status until fully started and then launch Chromium.

photo 2.JPG


The get rid of the second issue, the Google API keys warning, some environment variables need to be set:


debian@beaglebone:~$ export GOOGLE_API_KEY="no"
debian@beaglebone:~$ export GOOGLE_DEFAULT_CLIENT_ID="no"
debian@beaglebone:~$ export GOOGLE_DEFAULT_CLIENT_SECRET="no"


Using "set", it is possible to confirm the variables have been set. Unfortunately, setting them like this is not permanent and a reboot will lose the information.


debian@beaglebone:~$ set



This is where the custom script from earlier comes in handy. I added the "export" statements into the script, which results in them being executed at every startup.


debian@beaglebone:~$ sudo nano

export GOOGLE_API_KEY=no
sleep 120 && chromium --kiosk "http://localhost:9090/"


The annoying warning is finally gone:





After powering on the Beaglebone Black, the openHAB GUI will open automatically on the touch screen without user intervention. Hooray!

Over the couple weeks or so, I have been focused on the central hub application where I have been successfully sending device information and sample data to AirVantage.  However, I couldn't seem to retrieve the data from the cloud-platform on to another device or even on the same device.  This is a major road block for the system, since data from the central hub needs to be updated with the information sent by the mobile application.  Likewise, the mobile application will have to retrieve the central hub's status so it can be presented on the app.




Looking through the AirVantage documentation, there is the concept of tasks, a way to receive messages from AirVantage server.  However, tasks can either be initiated from the AirVantage dashboard, or scheduled, but not from the remote device.  Although, there are two types of tasks, read and write, these are actually equivalent to request current status and set device parameter.  Again, a feature that does not satisfy the system requirements, which is to (iterate again), system information to be stored on a cloud-platform which can be retrieved by any remote device.  I'm thinking within the lines of a hosted database but without having to configure the server and write API's to access the information.  AirVantage fulfils half the requirements and perhaps it does provide a mechanism to access the data, through alerts and web hooks to another webby enterprise application.  Taking this route though would require more development time, a resource that is slowly becoming unavailable for this project.



It is possible to retrieve data from AirVantage from any device using REST api.  amgalbu and tomaja have covered on how to do this in their posts AirMobile - 12 - AirVantage REST API by Ambrogio and In the Air Design Challenge - Pollen & Allergen Sensing – Post 3 (AirVantage Intro) by Dragan.  After reading through their examples, I found what caused my troubles.  I used the following API from the documentation as is:


where in should've been





As an alternative solution, I will be using Parse, a backend service provider.  I have been using this platform for a number of applications and have found it to be the best BAAS atm.  The service is FREE for a generous cloud resource, see below.




This framework is also backed up with a thorough documentation and you will have your application (embedded, mobile, desktop, or cloud) fully integrated within an hour.

Other alternatives include Firebase, Buddy, etc.


Not All That Bad At All


AirVantage is not all that bad after all.  IMO, AirVantage has not just been designed for [remote] device management but is a good backend platform as wellA little polish on the documentation though would be nice to be explicitly clear with their examples.  AirVantage will be good for tasks like:

  • monitoring device status which would trigger an alert when it is in trouble
  • geo-locating mobile devices
  • remote deploy
  • delivery of firmware/software updates
  • integration with ERP systems or other customed enterprise applications




AirVantage is the cloud platform suggested in this design challenge.  However, with proposed Carbon Footprint Monitoring System, AirVantage as a backend platform is not suitable for this particular application and will be using Parse as the alternative back up solution, and will be switching my API calls to this service when my AirVantage 6-month trial expires.  I've got the code for both platforms working anyway.


The current application using AirVantage is not going to be scrapped. AirVantage will still play a role in this system.  AirVantage's tasks and alerts will be used to send scheduled reports and notification to an assigned email.  It will also be used to remotely configure the device, i.e. update Carbon Budget settings, which can be done through the 'Write Task'.


Final Notes


If anyone in this group who have been able to retrieve data either via MQTT or REST protocol or through some other approach, sharing this bit of information may help not just me but others who are experiencing the difficulty as well.


Thanks to amgalbu and tomaja for the help.

Earlier this challenge, I have been setting up the development environment using Visual Studio and in one of those posts, I did mention on how to configure Visual Studio to develop Linux applications using VisualGDB.  SysProgs has a very good tutorial here.  This is very much useful if writing apps using C/C++, as the debugging experience in Visual Studio is exceptional.  However, my initial plan to use C/C++ for the Linux application on the BeagleBone Black has changed and have been using node.js for application development.


By default, node.js is not a one of the available JavaScript templates in Visual Studio.  This blog post will walk you through on how to get node.js development on Visual Studio for the BeagleBone Black.  To do so, just follow the steps below.


  1. Before starting, ensure that the latest updates on Visual Studio are installed.  You can get the latest update here.
  2. Next, install WebEssentials extension, download it from here.
  3. Then, install node.js from their site.
  4. Lastly, install NTVS (node.js Tools for Visual Studio) as the main component to transform Visual Studio into node.js development environment.


Now, from the New Project window, you can select Node.js application template.

vs new project.PNG

Run and start debugging the node.js application as you would any other VS application.


Installing node.js Packages


Since MQTT is vital in this design challenge, we can install node.js modules through the built-in npm (node.js package manager).  To get the MQTT module, expand the node.js project, then right-click on npm, which will then bring up the npm install window (see below).


npm install.PNG

Just type the module name in the search bar and click on Install Package to add the specific node.js module in the project.


Transferring Files to Beagle Bone Black


Once you have done enough coding and debugging and would like to do testing on the target machine, the Beagle Bone Black in this case, simply copy the files from the Visual Studio project directory to BeagleBoneBlack's cloud9 directory ( /var/lib/cloud9 ) using FileZilla or similar tool.


js transfer.PNG


There we have it, node.js development using Visual Studio which targets the Beagle Bone Black.

Just coming back from Las Vegas, US. Sorry for no weekly update


Power Bank:

Getting this power bank few day ago. It look quite solid and nice. Took me more then 7hour to fully charged this power bank with 2A 5V adapter.

Look like the power indicated is correct for 10400mah capacity. This also mean the battery is original .

Few reason for choosing this power bank for this project. First is their capacity with 10400mah it enough to run 2A 5V at lease 4hour.

Second is the price with SGD$14, I don't think your can get other better then this and the last one is their function that able to working while charging.


This picture show the complete set for the power bank. They not come with charger.


Next is the important testing for the power bank that related with this project. The test include output power test to support the project hardware and charging function while the output running.

This helpful for the project mean that I don't need to build another step up converter to running the hardware. It can be tap directly powered from the power bank because it work all the time while charging or not.


Picture show the power bank still working to charging my Ipad/Iphone while it in charging mode.

Maybe I should upload better picture to explain or show this function . Let me know if require.




This is version 4 for the PCB. Almost all the hardware been put together and some wrong measurement for hardware been corrected.

80 pin connector been share and same go to BBB. Additional 12 pin for BBB can be connected by hard wire. Thinking this should be more then enough.

Next should be the CC3200 and LCD. Maybe will do this in the merge work at CAM side or just wire up.

Screen Shot 2015-01-14 at 12.59.23 pm.png

Picture show the updated 2 layer PCB design for the BBB, fan, dust sensor and connector.


Attached picture show the CAM for merge PCB. Look good just some minor issue with overlap hole

Now just hope the manufacture can make it with small spacing gap .

But for sure our prototype machine cannot make it


CAM Editing:


Having some issue with the CC3200 drill file. Look like some of the drill hole is not align with the pad. Any idea everyone?


Picture show there are missing drill hole at the right side of the header and place at the left side of the PCB.


Still in Jetlag mode .



Big 3D printer



3D printed music equipment + nice music



3D printed food




Dust, Temperature and Humidity Monitor Chapter 7



Dust, Temperature and Humidity Monitor Chapter 9

Bluetooth protocol

Everytime I search something in the opensource community, a quote from Isaac Newton comes into my mind


"We are dwarfs on the shoulders of giants"


It's unbelievable the health of information is available for you to give form to all your ideas!!


I was looking for an Android application that I could use as a starting point. The main requirements were very simple

  • Connect via Bluetooth to the AirMobile sensor
  • Cache data local visualization
  • Push data to the AirVantage cloud through MQTT

I was very lucky because I found an application that also met my idea about the Bluetooth protocol (see my post here) The application Bluetooth protocol is a very simple one-way (from sensor to application) procotol and so I decided to adopt it for the AirMobile sensor.

Here is the protocol specifications:


<Measurement value>;<Sensor package name>;<Sensor name>;<Type of measurement>;<Short type of measurement>;<Unit name>;<Unit symbol/abbreviation>;<T1>;<T2>;<T3>;<T4>;<T5>


  • The Sensor package name is the external sensor name (in this case "AirMobile")
  • The Sensor name should be different for each sensor.
  • Type of measurements is a string that identifies what we are measuring
  • Short type of measurement is used (in my case) internally to identify the dataset to update in the AirVantage cloud
  1. T1..T5 are integer thresholds which guide how values should be displayed -
    lower than T1 - extremely low / won't be displayed
  2. between T1 and T2 - low / green
  3. between T2 and T3 - medium / yellow
  4. between T3 and T4 - high / orange
  5. between T4 and T5 - very high / red
  6. higher than T5 - extremely high / won't be displayed


Just to give an example, the AirMobile sensor will send out strings like this


  23.5;AirMobile;TMP36;Temperature;temperature;degrees Celsius;°C;-40;-10;30;40;60
  10;AirMobile;TGS2442;CO ppm;co;ppm;ppm;30;40;100;500;1000
   20;AirMobile;MiCS-2710;N02 ppb;no2;ppb;ppb;200;200;500;1000;2000

Memory retention

AirMobile sensor is going to be switched off abruptly whenever the Peltier cell does not provide enough energy. I need to save application status to resume execution properly after a "black-out"

The MSP430FR MCUs features an internal FRAM to store persistent data in place of the typical Flash. FRAM is a non-volatile memory technology that is uniquely flexible and can be used for program or data memory. It can be written to in a bit-wise fashion and with virtually unlimited write cycles

Variables are allocated in SRAM by the default linker command files. FRAM-based MSP430FR5969 device has 2KB of SRAM. If the variable size is too large to fit in SRAM, the linker command file can be modified or C-language #pragma directives can be used to allocate specific variables or structures in FRAM memory.

The toolchains available for MSP430 all ship with linker command files that define a default memory setup and partitioning, typically allocating program code and constant data into FRAM, and variable data and the system stack to SRAM. In addition, C compiler language extensions are provided that allow you to locate selected variables and data structures into FRAM, allowing you to utilize the benefits of using FRAM for persistent data storage without any further considerations regarding memory partitioning or modifications of the linker command files.

In CCS, there are two C language pragma statements that can be used: #pragma PERSISTENT and #pragma NOINIT. PERSISTENT causes variables to not get initialized by the C startup routine, but rather the debug tool chain initializes them for the first time as the application code is loaded onto the target device. Subsequently, those variables do not get initialized, for example, after a power cycle as they have been completely excluded from the C startup initialization process. Declaring variables as PERSISTENT causes them to get allocated into the .TI.persistent linker memory segment.

Here is a code snippet showing how the variable is declared as persistent:


#pragma PERSISTENT(x)
 unsigned int x = 5;


NOINIT works similar to PERSISTENT but the variables are never initially initialized by the project’s binary image file and the debug tool chain during code download. Declaring variables as NOINIT causes them to get allocated into the .TI.noinit linker memory segment. Note that unlike PERSISTENT, variables declared as NOINIT do not get located in FRAM by the default linker command files, requiring a minor modification of the linker command file if such functionality is required. Here is a corresponding code snippet:

#pragma NOINIT(x)
unsigned int x;

The basic flowchart of the AirMobile firmware is very simple


FW Flowchart.png


So I decided to save the application status and the last readings of the 5 sensors

#pragma PERSISTENT(gAppPhase);

typedef struct
      float temperature;
      float humidity;
      float CO;
      float NO2;
      float dust;


The application status is saved for obvious reason.

The last readings are saved in order to make a mobile average over the samples

Previous post: In-the-Air-Challenge: Dust counting with Beagle Bone Black and a webcam

Next post: In-the-Air-Challenge: Spending the 500 USD parts budget


Greetings with the New Year 2015!

I decided to compose a new blog post this week instead of adding material to the previous post. Because older blog posts people might not check over again.


My collegue Ilja Fescenko came up with an idea  to bounce light between two parallel mirrors allowing to recycle laser power and monitor scattered light by dust in relatively large area.


sheet of light for dust visualization.JPG

Green laser pointer 5 mW is OK, with a 30 mW laser visibility is better.

Front coated alu mirrors from an old scanner are used. One mirror is fixed. Second mirror and laser direction can be fine adjusted.


If both mirrors are parallel then the spots make equidistant straight pattern. One can make a parabolic pattern or a spiraling one just by tilting laser beam and one mirror.


A sheet of laser light shows that we are swimming is a see of dust. Dust very nicely visualizes air turbulences.



We are testing now different filters.  HEPA13 from a vacuum cleaner, car air filters, cotton wool, electrostatic plastic spiral filter.

This method of observation from a 50 cm distance is sensitive to large dust particles. In order to see the fine dust one needs to use a macro lens (microscope) and then the observation gets smaller.

Previous posts for this project:





As you'll notice, week 9 and 10 have gone missing. I wasn't able to put enough time in the project during the holiday period to justify a blog post (or two).

With the family visits all over Belgium done, I'm gradually able to put more time back in my projects. Here goes week 11 ...

During week 7, I experimented with my dust sensor using an Arduino. This made it easier to understand the sensor using a microcontroller I'm familiar with.

For this post, I thought I'd hook up the dust sensor to the CC3200. Shouldn't be too hard, right ? Well ... just a little bit harder than expected!





It would seem that the ADC on the CC3200 only supports input levels up to 1.46V and not the 5V I had on the Arduino!

For testing purposes I used a voltage divider, with a ratio of 1/3. Because the maximum analog output voltage of the dust sensor is approximately 3.5V, that should do.


Another thing to be aware of, is that the analog value read using the analogRead() function results in a value between 0 and 4095 (as opposed to 0 and 1023 on Arduino).


I adapted my measuring function to the new conditions as follows:


void readDustSensor() {
  digitalWrite(ledPin, LOW); // turn LED on
  delayMicroseconds(delaySampling); // wait before sampling

  sensorValue = analogRead(sensorPin); // sample
  delayMicroseconds(delayLed); // wait before turning LED off

  digitalWrite(ledPin, HIGH); // turn LED off
  delayMicroseconds(delayCycle); // wait for end of cycle

  // max voltage of 1.46V, represented by values from 0 to 4095, times 3 to compensate for the voltage divider
  voltage = sensorValue * (1.46 / 4095.0) * 3;


I was expecting this to return the same value (or at least close to it) as during my tests with the Arduino. Somewhere around 0.74V.


Unfortunately, I'm getting values reported around 2.0V! Why ?!

Screen Shot 2015-01-09 at 22.56.40.png


Using the TBS 1052B oscilloscope from the previous challenge, I tried to understand what was going on. With both probes, I tried to visualise the (divided) output of the dust sensor and the trigger of the IR LED.


This was the resulting snapshot:


Using the cursors, I measured 0.280ms between the IR LED being turned on (fCursor 1 - falling edge on Ch2) and the dust sensor's (divided) analog output (Cursor 2 - Ch1).


As you can see, the snapshot matches the expected behaviour as documented in the sensor's datasheet rather well:

Screen Shot 2014-12-11 at 20.11.39.png

Cursor 2 on Ch1 reports an amplitude of 220mV, times 3 to compensate for the divider, that results in 660mv. So why is the analogRead() reporting 2.0V ??


With the scope reporting a plausible value, I'm thinking the issue lies in the analogRead() itself. So I started searching for similar issues online.

I came across following issue where multiple analogRead() attempts must be made before a correct value is obtained (what's the deal with that?).

Not having better options at this stage, I decided to give it a try. But adding multiple analogRead() calls would surely affect the sampling timing.


To assess the impact, I report the microseconds using micros() right before and after the four dummy analogRead(), measuring how long it takes to execute.

This delay is then subtracted from the 0.280ms sampling delay.

Screen Shot 2015-01-09 at 22.42.19.png

The four dummy analogRead() introduce a delay of 0.040ms, so that's what I'll subtract from the 0.280ms delay.


The good news is that the readings after those changes are much closer to what I had measured with the Arduino, and are in line with what is measured with the scope.

The bad news is that the results fluctuate a lot more, losing the ability for proper monitoring of dust levels.

Screen Shot 2015-01-09 at 22.55.06.png


Smoke however, is still properly identifiable at 3.6V, as it results in the maximum output value of the sensor.

Screen Shot 2015-01-09 at 22.54.30.png




Well, that wasn't as easy as I had expected ... at all.


Unfortunately, it looks like this approach won't give me reliable and stable readings. I'll have to find another solution and make it work in the remaining seven weeks of the challenge.

That will be a challenge on its own On the bright side, I now know these limitations/issues with the CC3200/Energia and am able to take it into account for future projects. Oh well.


(Unless I did something very wrong in all of this and someone will point out the obvious ...)

This week I have been mostly busy around the design of the flow of data in the system.  Working from the high-level architecture presented from this post, the diagram below presents how data flows within the different component of the system.


From the left, the Emission Sensor will transmit CO2 levels and accelerometer over Bluetooth Smart connection to a smartphone application.  The accelerometer information will be used by the Smartphone app to determine the vehicle's state (off, idle, running).  Using the accelerometer data and GPS information from the smartphone, the mobile app can determine travel time, idle time, and distance travelled, which will then be sent to Sierra Wireless AirVantage application.  This defines the first AirVantage application model:


  <encoding type="MQTT">
  <asset default-label="CarbonMobile" id="mobile">
   <variable default-label="TravelTime" path="travelTime" type="double"/>
   <variable default-label="IdleTime" path="idleTime" type="double"/>
   <setting default-label="DistanceTravelled" path="distanceTravelled" type="int"/>
   <setting default-label="CO2Level" path="co2Level" type="double"/>
   <setting default-label="VehicleState" path="vehicleState" type="int"/>


On the right side of the diagram, data from the environment (indoor/outdoor) sensors, smart plug, and smart switch metrics are transmitted to the Central Hub via WiFi.  Some of the metrics include power consumption in Watt-sec, environment conditions.  Power consumption will then be translated into equivalent carbon footprint as 1.52 lbs for every kilowatt-hour (references below).  The application on the central hub then deducts this carbon usage against the set carbon budget.  This defines the second AirVantage application model:


  <encoding type="MQTT">
  <asset default-label="CarbonHub" id="hub">
   <variable default-label="IndoorTemperature" path="indoorTemperature" type="double"/>
   <variable default-label="IndoorHumidity" path="indoorHumidity" type="double"/>
   <variable default-label="OutdoorTemperature" path="outdoorTemperature" type="double"/>
   <variable default-label="OutdoorHumidity" path="outdoorHumidity" type="double"/>
   <variable default-label="CarbonBudget" path="carbonBudget" type="double"/>
   <variable default-label="CarbonUsage" path="carbonUsage" type="double"/>
   <variable default-label="SwitchState" path="switchState" type="boolean"/>
   <variable default-label="PlugState" path="plugState" type="boolean"/>


The downlink arrows on both sides represents the data being sent to smartphone and central hub apps respectively.  Each app subscribes from the events and updates of the other.  Central Hub metrics will be used by the mobile app for display, while the mobile app data will be used to determine the carbon footprint of the vehicle and counted against the budget.





The AirMobile case

While struggling to find a cheap 3D printing service to print the sensor case, (this challenge is actually costing me more than I planned!), I saw just in front of me a nice case from Wurth Elektronik






I noted down the dimensions of the box and, surprisingly, they fitted exactly my hardware! After some minor reworking, the case was ready for hosting the AirMobile sensor





To tell the truth, this case is bigger than I initially designed, but thanks to its limited height, it can be still mounted in the space  between the car radiator and the car front mask

Hi everyone!!


This is Chrystal writing this post on our progress. Sorry about the delay in getting the update posted, the holidays distracted us a bit, but now that Christmas is over and everything has slowed down (except school) we have got a fair bit done on our project.


So here is the long update (With photos I took):


I have the microscope working!! I have it at about 80X, it isn't up to the power we need yet, but it works great. I took apart some old cameras to salvage their lenses (Don't want to waste) and attached them to a web camera. So far it is just cardboard and duct tape (My dad is right, duct tape is for everything) but I got some good photos from it. To run the web cam we (actually Dad) programmed the Beaglebone Black to run a program called "Cheese". I looked it up on-line to see what would work for running the camera and came across this program (I also liked the name!!).


Below are some pictures I took through the microscope with a description of what your seeing.


First is a magnified LED light. You can see the close-up of the inside quite clearly!!



Next is a picture of cork.



While I was looking for things to magnify I found this tiny ball of solder on my dad's workbench (His bench is a mess and he complains about my room)



This last photo is of a piece of construction paper. I wanted to take a picture of my dad's workspace (To show how messy it is) but he said NO!!




The microscope is still work in progress but will be complete soon.


Next is the centrifuge, we ended up building our own as we are still waiting for parts. With time going by fast we decided to build one so we can complete on time. This was driving my dad crazy, such an easy machine but how to make it safe and balanced. I found a small fan that had one of the fins broken (Salvage parts, no wasting). So we took it apart and got the motor and speed control, added a hard plastic storage container and 4 vials. Attached is a picture (Without safety cover so you can see).



I took the picture with the web cam attached to the Beaglebone (No lenses to magnify). The centrifuge spins fast (We need to calculate speed yet) and is very well balanced. There is no wobble and the vials are very secure. We don't turn it on without the safety cover attached. This weekend we will test how well and long it takes to separate particles to look at. There will be lots of photos and a video of this part of the project working.


It is getting late so we will update more this weekend.


Chrystal and Dale Winhold

Representing data on the map

In this post I will talk about the representation of data collected by AirMobile on a map. Representing data o the map is the easiest way to understand the locations to avoid when doing outdoor activities. The solution I was thinking of is to draw a vertical line on the map at the position where the sample was taken. The height of the line is proportional to the sample value.

To implement this feature, some technical background about Google Maps is required



In order to determine the screen coordinate of a given location (expressed in terms of latitude and longitude), an overlay is required. To create an overlay,


 overlay = new google.maps.OverlayView();
 overlay.draw = function () { };

Map projection

After the overlay is created, a projection object is required in order to perform the conversion. The projection can be obtained by calling the projection.getProjection() method. However, the getProjection() method returns undefined when the map is not ready on the screen. For this reason, a event listener is installed waiting for the map entering the 'idle' state. When the map is in the 'idle' state, we are sure that the getProjection() method returns a valid projection.

After the projection is available, values can be drawn


 // Wait for idle map
 google.maps.event.addListener(map, 'idle', function () {
 // Get projection
 projection = overlay.getProjection();
 setTimeout(loadData, 100);

Getting data values

To get data values from the AirVantage cloud, I leveraged the jQuery's ajax object


 loadData = function () {
 var dataIds = "airmobile_" + measure + ".value," + 
                            "airmobile_" + measure + ".latitude," + 
                            "airmobile_" + measure + ".longitude";
 url: "" +
 "?access_token=" + accessToken + 
 "&dataIds=" + dataIds + 
 "&targetIds=" + systemUid,
 success: function (data, status, jqXhr) {
                    // data returned successfully

Scaling sample values

Raw values should be scaled to get the height (in pixels) of the polygon to draw. I found out 50 pixels in height to give good readability to the graph. In order to make evident changes in the values, I first find the minimum and maximum values in the array of samples returned by the AirVantage cloud, and I show these limits in the upper left corner of the page in order for the user to understand the graph scale. Minimum and maximum values are then used to calculated the height of the polygon by means of the following function


mapPixels= function(value, min, max) {
      var delta = max - min;
      var deltaPixels = 50;

      var pixels = deltaPixels / delta * value;
      return pixels;



Converting latitude and longitude to screen coordinates

The projection object has a convenient method to convert the latitude and longitude into screen coordinates. So it's easy to implement an helper function

convertCoords = function (lat, lon) {
      return projection.fromLatLngToContainerPixel(new google.maps.LatLng(lat, lon));


Drawing the polygon

To draw the polygon, some geometry is required. The polygon I want to draw has four vertexes: two are included in the AirVantage's response. The other two points are on the perpendicular line passing through each of these two points, as shown in picture



Line between two points equation

The equation for the line between two points (in explicit form) is


Formula 17_01.png

Being p1 and p2 two points, we can determine m and q using the code below

var value1 = values[i];
var value2 = values[i + 1];
var p1 = convertCoords(value1.latitude, value1.longitude);
var p2 = convertCoords(value2.latitude, value2.longitude);

var m = (p1.y - p2.y) / (p1.x - p2.x);
var q = p1.y - (m * p1.x);



The equation of the perpendicular line is


  Formula 17_02.png


(where m is the value calculated in previous section)

So, the parameters of the two perpendicular lines can be calculated using the following code


var pm = -1 / m;
var pq1 = p1.y - (pm * p1.x);
var pq2 = p2.y - (pm * p2.x);


To compute the other point, I need to use the formula of the distance between a line and a point


Formula 17_03.png


The coordinates of the point (YP, Xp) lays on the perpendicular line, so YP can also be written as


Formula 17_04.png

The distance from the line is given by

var d1 = mapPixels(value1.value, min, max);


Because I already have the distance, I can calculate the point coordinate using the previous formulas. The code is as follow

var x1 = (d1 * Math.sqrt(1 + (m * m)) - pq1 + q) / (pm - m);
var y1 = (pm * x1) + pq1;


Here is comes a small problem: hot to draw the polygon on the same side? The equation of the distance between a line and a point has an absolute value, which leads to two possible solutions. Which one do I have to choose? I experimented with the normal of the polygon...

Surface normal

The normal vector to a surface is a vector which is perpendicular to the tangent plane to the surface. A surface normal for a polygon can be calculated by taking the vector cross product of all edges of that polygon. The order of the vertices used in the calculation will affect the direction of the normal (in or out of the face). This latter property of the surface normal is the one I want to use to try to draw all the polygons on the same side of the path determined by the samples positions

Because the polygon lies on the X-Y plane, I can just compute the Z component of the normal vector

computeNormal = function(p1, p2, p3, p4) {
      var nz = 0;

      var vertexes = [p1, p2, p3, p4];
      for (var i=0; i<vertexes.length-1; i++) {
            var curr = vertexes[i];
            var next = vertexes[i + 1];

            nz += (curr.x * next.x) * (curr.y * next.y);

      return nz;


If the Z component is positive, I will select the other solution of the equation and re-calculate the polygon points using the new formula

var x1 = (d1 * Math.sqrt(1 + (m * m)) - (-pq1 + q)) / (- (pm - m));
var y1 = (pm * x1) + pq1;



This is the first version of the AirMobile data visualization page.  To be improved, but the foundations are there...



Low-power delay

The CCS ULP Advisor tool is a great tool because it provides useful hints to squeeze microampers out of an application.

One of the suggestions was to get rid of delay loops. So I investigated how to implement a delay using timers. Implementation was not as difficult as I would expect.

First of all, the counter the timer has to reach is calculated.


uint32_t lcounter = HW_ACLK_FREQUENCY * ms10th;
    lcounter = lcounter / 10000;
    uint16_t counter = (uint16_t)lcounter - 1;

Then, Timer A needs to be initialized


/* Configure TimerA in up mode */

    /* Start TimerA counter */


Next, the MCU is put in Low power mode 3 (see my previous post for details about different power modes)


    /* LPM3, TIMER_A1_ISR will force exit */
    __bis_SR_register(LPM3_bits + GIE);     


The interrupt routine is even simpler: just stop the timer and exit Low power mode 3

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMER1_A0_VECTOR
#elif defined(__GNUC__)
void TIMER1_A0_ISR_HOOK(void)
    /* USER CODE START (section: TIMER1_A0_ISR_HOOK) */
    LPM3_EXIT;   // Exit active CPU
    /* USER CODE END (section: TIMER1_A0_ISR_HOOK) */

Previous posts:

In the Air Design Challenge - Pollen & Allergen Sensing

In the Air Design Challenge - Pollen & Allergen Sensing – Post 1 (Pollen Sensor)

In the Air Design Challenge - Pollen & Allergen Sensing – Post 2

In the Air Design Challenge - Pollen & Allergen Sensing – Post 3 (AirVantage Intro)

In the Air Design Challenge - Pollen & Allergen Sensing – Post 4 (Preparing the InTheAir Power Board)

In the Air Design Challenge - Pollen & Allergen Sensing – Post 5 (InTheAir Power Board)


Interfacing with HDC1000 Temperature and Humidity sensor


Thanks to Texas Instruments I received my HDC1000EVM - TEXAS INSTRUMENTS - EVAL BOARD, HDC1000 TEMP/HUMIDITY SENSOR | Farnell element14 UK evaluation module.


Figure 1. HDC1000 Evaluation module


This small module is based on a USB<->I2C interface made using MSP430 MCU. It also contains a HDC1000 chip soldered to specially designed board that can be broken into three separate pieces so that you can use the same HDC1000 chip in your own test circuit. I think that this is really great because you don’t have to make a breakout board to test it in your circuit – it’s already provided.


This module can be used out-of-the-box by just connecting to a Windows PC USB port and running the Qt based sample GUI application. The sample application features nice interface for HDC1000 configuration and data acquisition and display. Temperature and humidity values are shown on two separate charts. Data sampling rate can also be easily changed using this GUI app.


Figure 2. HDC1000 Windows GUI Application (Board was already broken so the app is not connected to it)

Under the hood, this application is using serial port to send and receive data. I couldn’t find source code or any additional details about this application so I did my own research. It turned out that the application sends very simple and short commands to the USB module. For example, sending ‘1’ over serial port will result in module sending back the temperature value in hexadecimal format, ‘2’ is used to request humidity. ‘3’ is used to request continuous updates with both temperature and humidity values and ‘4’ stops that. I didn't really have to inspect this but I was curious and it was fun .

It would be even better if this application was provided with source code so that it can be built for other OSs too.


The next step was to test the sensor without the USB motherboard. For this, I used the Bus Pirate 4.0 (nice little tool that can be used to test different devices).

I soldered the male headers to the broken board so that I can easily hook up the probes.


Figure 3. Bus Pirate 4.0 with HDC1000 broken off the evaluation module



HiZ>m                          <- Choose mode
HiZ>3                          <- I2C
I2C>2                          <- Hardware version
I2C>1                          <- 100KHz
I2C>W                          <- Enable PSU
I2C>P                          <- Enable Pull-Up resistors
I2C>v                          <- Check voltage levels
I2C>(1)                        <- Scan I2C bus
Searching I2C address space. Found devices at:
0x80(0x40 W) 0x81(0x40 R)      <- This is HDC1000 with the address 0x40


So, our sensor is configured to use 0x40 address (0x80 write address and 0x81 read address). BTW, you can use Bus Pirate to convert value between binary, decimal and hexadecimal:

0x40 = 64 = 0b01000000

Address can be changed by adding the 0R resistors (shorting pins). Check the datasheet for details, I’m fine with this address at the moment.


At this point I have the Bus Pirate set to send/receive over I2C.

According to datasheet, HDC1000 can be used to retrieve both temperature and humidity simultaneously or to retrieve them separately. I chose to acquire both simultaneously.

For that, you first have to configure the sensor by writing the configuration data into configuration register (0x02).

I chose to use 14bit precision for both temperature and humidity so I had to write 0x1000 to the configuration register.

I2C>[0x80 0x02 0x10 0x00


After the sensor is configured, you need to issue the measurement command by writing 0x00.

I2C>[0x80 0x00


After the data is ready you can read it (read 4 consecutive bytes from sensor). You can just give the sensor enough time to do the conversion or wait for DRDYn signal. Since I’m entering addresses and data manually, it gives the sensor more than enough time to prepare the data between commands.

I2C>[0x81 rrrr
READ: 0x62
READ: ACK 0x34


The first two bytes are for temperature and the bytes 3 and 4 are the humidity value.


Temperature in Celsius degrees is calculated like this:

(0x6234 / 0x10000) * 165 - 40 = (25140 / 65536) * 165 - 40 = 23.295°C


Humidity is calculated like this:

(0x8DE0 / 0x10000) * 100 = 55.4%


For my project, I will use the broken board as it is now. This way I will have a small sensor module that has a small thermal mass and can be placed away from the board and battery.

That's all for this update


Have a Happy New Year!