atmospheric carbon dioxide sensing with an Arduino

I was asked by my Lab Manager to investigate whether one of our CO2 incubators was working properly. Apparently there’s some doubt as to whether it was maintaining CO2 levels. CO2 is an easy gas to detect for the same reason that it causes global warming: it absorbs infrared radiation. You can now buy cheap Non-Dispersive InfraRed CO2 detectors for about US$40 from websites such as AliExpress. However, CO2 incubators typically enrich CO2 to about 5% by volume while most of the cheap sensors only measure up to around 0.5%, or 5,000 parts per million [ppm]. I found a sensor from Sandbox Electronics that works up to 10% by volume, or 100,000ppm. Perfect for testing CO2 incubators.

The MH-Z16 NDIR CO2 Sensor costs $67.95 and comes with a UART to I2C adapter. This makes powering it and communicating with it quite simple: just connect four wires to the development board of your choice! I used an Arduino Nano to read the values from the sensor and send them to the laptop over the USB connection that was also powering it. The sensor can be calibrated in atmospheric CO2 conditions at the push of a button. I have reservations about this one-point calibration but “you pays yer money…”, as my dad used to say.

The Nano is sitting on a screw terminal shield with mount holes for easy connections ($4 well spent for making secure, non-permanent connections to the Arduino). On the laptop screen you can see data coming in from the example sketch I copied from the vendor’s website and using the Arduino library they provided. The sketch sends a reading every second. The serial output shows a starting CO2 reading of 458ppm which climbs slowly to >1000ppm when the photo was taken. This is because I was sitting in front of the sensor taking the photos and it’s registering a local CO2 increase as a result of my breath. If I huffed on it it climbed to >10,000ppm, or 1% by volume. The sensor is very slow to adjust to changes. I had to huff on it for a good couple of minutes until it got that high. Wikipedia tells me that exhaled breath is normally 4-5% CO2 so I guess if I’d kept at it for a while it would have got up there. I might have passed out before then though! 😆 When I moved it away from me it took several more minutes to come back down to ambient levels. Not ideal but fine for my application and budget!

The next task was to make an enclosure to protect the sensor, logic boards and delicate wiring. A couple of evenings spent playing with OpenSCAD yielded an alpha version which I cut on the lasercutter today and tried out. I had to correct a few mistakes in the design but ultimately produced this:

Which became reality as this:

I would have taken a picture of the two boards mounted inside but the lasercut bits fitted together so snugly I didn’t want to try and separate them again in case something broke. You can see the lights of the Arduino inside through the ventilation holes  🙂

I’ve put the sensor in an (allegedly) working CO2 incubator and left it for 20 minutes to stabilise. The sensor read about 40,000ppm, or 4% by volume. As the incubator was meant to be maintaining 5% I’m not too sure what to make of this. I will have to find another incubator to make a replicate measurement. Maybe all of our incubators are a bit off! 😵 However, I’m very pleased with how simple the sensor was to get working and seeing as all you need to run it is a laptop with the Arduino drivers loaded and a serial terminal, such as PuTTY, it is very accessible to even the relatively non-technically minded. 😎


Using Adafruit Fona GSM/GPRS breakout to log data to Xively

Collecting and logging sensor data automatically is one of the most useful “sciencey” things you can do with programmable microprocessors like Arduino and Raspberry Pi. One problem with this is what to do with the data you are collecting. You can store it locally to the device, for example Arduinos can log temperatures or movement signals from PIR sensors to SD cards. However, you have to turn the device off and remove the card, put it into a laptop and copy the data off it before you can access it. Alternatively you can send the data over a serial connection or wirelessly to another device which will store the data for you for easier retrieval or even real-time plotting. Recently small GSM/GPRS modules have become available which are essentially the guts of a mobile phone with no screen, battery or keyboard. These enable you to use mobile phone networks to send data to the internet using protocols such as GPRS and 3G. This is very useful for science as field experimental sites rarely sport ethernet ports or wireless routers through which to transmit data from long-term monitoring sites.

The Adafruit Fona is one of these devices and I obtained one with the intent of monitoring the temperatures in some of our more critical freezers and fridges in case one of them broke down, imperilling the irreplaceable scientific samples stored within. I’ve already set up one device using a GPRS shield from Elecrow. You can see the feed from it here. Its logging temperatures from three freezers in a shed on AUT’s North Campus where various valuable samples are stored. The Fona is a little smaller and a little cheaper and I wanted to make another couple of devices to deploy in our labs to keep an eye on the freezers there. These contain not only valuable samples but, in our molecular labs, thousands of dollars worth of reagents for the MiSeq, our next generation sequencing platform. The idea here is not just to keep an eye on the functionality of the freezers but to get notified if the power goes down. Freezers are well insulated so if the power goes off the temperature won’t immediately rise. If the power goes off on Friday evening, however…

In setting up the Fona I ran into problems getting code to work. The Fona code examples for GPRS access were limited to simple website recovery and not sending HTTP PUT requests, which is what is required to log data to Xively. Frustratingly the code I’d adapted from my previous GPRS logger didn’t work and I could find no indication as to why. Even more frustratingly the Arduino Xively libraries didn’t work either, probably because they had been written for use with WiFi or ethernet and not GPRS. Instructions are sent to the GPRS shields from your microprocessor using a special set of text commands, called AT commands. These commands need to be sent to the shield over a serial connection. The HTTP PUT requests sent to Xively must conform to something called REST, which is explained in somewhat inadequate detail in Xively’s API docs. So, to summarise: I had to use my Arduino to send AT commands to the Fona over serial that would instruct it to send PUT requests conveying my data to Xively. Three different communication protocols. Simples!  >_<

To cut a long story short I managed to use a Python library to send updates from my laptop to Xively by HTTP PUT requests. Using more Python I then managed to log the text of those HTTP requests and use that as a template that I could deconstruct and send to the Fona from my Arduino, inserting real-time data from sensor reads. The result is the code linked at the bottom of this post, which logs temperature, pressure and humidity data from an Adafruit BME280 sensor as well as the battery voltage of the Li-Ion cell connected to the Arduino and Fona. Credit to Limor Fried/Ladyada and Chip McLelland, whose example sketches I adapted to create this.

Here’s a quick pic of my setup. Its a Feather 32u4 LoRa, a uFL Fona and a BME280, all from Adafruit Industries. The Fona must have a lithium battery connected to it so I’ve added an 18650 Li-ion cell which is connected to both the Feather, which charges it, and the Fona. If the power does go out at work then the device will run for several hours on this battery, even without any low-power optimisation of the code. The enclosure is lasercut from 3mm acrylic. Its a beta version as I’ve yet to add mounts and an enclosure for the BME280. Ultimately I want this sketch to read three DS18B20 temperature sensors too, which will be in the freezers, but that’s a work in progress.


Download this code: Adafruit_Feather_Fona_BME280.ino

Hacking bathroom scales with an HX711 breakout

Hopefully this will be the start of a series of posts on the Internet of Bees, or the #IOBee. In case you didn’t realise, this is a play on the Internet of Things, or IoT. My intent with the IOBee is to document my application of some basic sensor technology to monitoring the health of bee hives.

There is an excellent writeup here of a conversion of a set of luggage scales to a real-time bee hive mass monitor. I have been wondering if I can do the same thing to monitor the mass of experimental bee hives in some research I’m planning looking at the effects of neonicotinoids upon honey bee colonies. In order to test this out I ventured onto eBay and bought a couple of HX711 breakouts, which you can get for just a couple of dollars.

HX711 breakout

I also bought a cheap set of bathroom scales from the Warehouse, despite the advice on MakeZine, which advised not to skimp. I intended this to be a proof-of-concept so I wasn’t going to be spending big bucks just yet.

bathroom scales

This turned out to be an excellent hacking subject. After taking the back off I found a circuit board carrying the integrated circuit, some components and some wires.


The two black pads you can see are the rubber feet on the bottom of the load cells. I prised one out to show you the other side.


The red white and blue wires coming from each of the four load cells needed to be joined together carefully according to the first image in this excellent post on StackExchange that I located after a modest amount of googling. I also found this how-to from SparkFun to be informative.

Once I had soldered the blue and white wires together to mimic the pattern shown and the red ones to the appropriate pads on the HX711 breakout I was left with this:


I also soldered the wires from a length of USB cable from an old mouse to the other side of the breakout. The four tabs and their wires were to VCC (red), GND (black), CLK (white) and SDA (green). I drilled a hole in the plastic chassis to pass the cable through and put a cable tie around it on the inside to prevent the wires being pulled off the board. The mount holes in the breakout board ( I love mount holes!) happened to be just the right width to allow me to screw it to the chassis through two of the holes that the original PCB was mounted on. The white thing is a piece of polyethylene milk bottle wall that I cut out and used to insulate the connections of the breakout and to hold it down as the screw heads were nearly as small as the holes. This arrangement allowed the breakout to be seen through the glass window where the LCD used to be. A nice touch. 😀


Having wired everything together I needed an electronic brain for my creation to talk to so I hooked it up to the Arduino Nano I’ve been using as a receiver for my solar-powered, wireless monitoring testbed. Ignore the BME280 and the NRF24 coming off it. VCC went to 5V, GND to GND, SCK to D4 and SDA to D5.


I downloaded the HX711 library written by bogde (thanks!) and also the HX711 breakout sketches from the SparkFun how-to linked above. I was pretty impressed to see numbers appear straight away on the serial monitor although this turned to mild disappointment when I placed a mass on the scales and the number went negative! Apparently I had got the polarity of the signal wires the wrong way around. 😦

Five minutes of soldering later I was back reading numbers and this time they went up with the mass on the scales. According to the instructions on the test sketch I kept adjusting the calibration factor until the scales read the correct mass for the object I’d put on it. Then came the acid test: now it was calibrated, would it get my mass right?


As you can see it worked almost perfectly. And I am somewhat overweight. :-/

A useful edit I made to the SparkFun code was to change the line

Serial.print(scale.get_units(), 1);


Serial.print(scale.get_units(), 3);

This gave me three decimal places instead of one and significantly more information. I was particularly pleased to see that these scales read quite consistently. The numbers for my weight jump about quite a lot because I wasn’t too worried about keeping still to get a stable reading but when I placed a fixed mass on the scales the second decimal place was pretty stable and only the third flicked up and down by 1-3 units. These scales were advertised as being accurate to +/- 100g so my results indicate I can do much better than that. And that’s without any of the tricks you can use with microprocessors to improve the accuracy of otherwise low resolution tools, such as polling them and taking a moving average.

More on the application of this very cool hack another day, once I’ve validated the calibration as described on MakeZine.

Arduino GSM shield

This week’s project: setting up this Arduino with GSM shield to monitor the UPS that powers my mass specs. If we get a power cut (or when- this is Auckland after all) it will send me an SMS so I can race in and shut the mass specs down before they crash. Full write up when I’ve managed to make it all work.


NB Apologies for the repost but tumblr didn’t want to load the image for yesterday’s post. 

A couple of shots showing an Arduino Nano I’ve put into the aqualab to monitor the sump temperatures on the recirculation system for an upcoming ocean acidification project run by Kay Vopel ( The Nano is reading two waterproof DS18B20 temperature sensors, one in the sump and one on the outflow from the mixing barrel, as well as a DHT22 air temperature & humidity sensor. The sensors are fed through holes melted in the HDPE of the little tupperware container its mounted in and the holes have been sealed with hot glue. The Nano is on the end of a 5m USB cable that stretches over to the PC on the bench opposite.

The monitor is showing my Processing datalogger sketch running. There’s two incidences of the sketch running, as there’s two recirculation system so there’s two Arduinos. The second one doesn’t have a DHT22. The data is plotted, shown numerically at the top of the screen and logged to text file. One day I’ll hack out a solution to read data from two Arduinos into one sketch but for now this was a quick and dirty solution.

Both plots show a pink and a yellow line climbing gently across the screen. These are the water temperatures. The MSc student increased the temperature on the water cooler yesterday and the system’s still equilibrating. The blue zig-zag line shows the air temperature bouncing up and down as the aircon switches on and off.

Auckland Winter humidity problems

I’ve got a climate datalogger in my house here in West Auckland. Its based on an Etherten from Freetronics, which is an ethernet-enabled Arduino Uno compatible board. On that is sat a wing screw shield for easy connection of wires and on top of that is sat an Adafruit LCD shield showing the readings.


Inside or outside it are a DHT22 temperature and relative humidity sensor, a BMP085 air pressure and temperature sensor, a DS18B20 temperature sensor and a light dependent resistor. The sensors are polled every 20s and the data uploaded to Xively. The BMP temperature sensor reads a few degrees high because its inside the plastic box, exposed to the warmth from the circuitry. The DS18B20 generally reads a couple of degrees low because its hanging down the back of the shelves the logger sits on, away from ambient air movement (although this is, of course, still interesting [to me, anyway]). The whole affair runs off a 5V power supply connected by USB. 

Here’s a shot of the log from the last few days. The gap in the data is where the logger hung and had to be reset, by the way.

As you can see, after a series of cold, wet days- indicated by the small peaks in the ‘light’ plot at the top left- relative humidity climbs to nearly 100%. This is despite us leaving the heat pump and a pair of heaters running all night. This was not helped at all by the need to dry clothes inside when its too wet outside, adding to the moisture in the air.

As a consequence I now have mould growing on the shelves in my bedroom!


Yay, for houses with poorly fitting, single-glazed windows and no insulation!

Here’s the Arduino sketch, if anyone’s interest.

#include <SPI.h>
#include <Ethernet.h>
#include <HttpClient.h>
#include <Cosm.h>

int debug = 0;

// Sensor setup
#include “Wire.h”
#include “Adafruit_BMP085.h”
#include “DHT.h”
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>

// MAC address for your Ethernet shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip (192,168,1,65); // Available Static IP address on your Network. See Instructions

// Your Cosm key to let you upload data
char cosmKey[] = “@@@@@ your key goes between the quotes here @@@@@@@”;

#define FEED_ID 76854;
unsigned long feedID = FEED_ID;

// Define the strings for our datastream IDs
char sensorID0[] = “BMPp”;
char sensorID1[] = “DHTh”;
char sensorID2[] = “DSt”;
char sensorID3[] = “light”;
char sensorID4[] = “BMPt”;
char sensorID5[] = “DHTt”;

CosmDatastream datastreams[] = {
CosmDatastream(sensorID0, strlen(sensorID0), DATASTREAM_FLOAT),
CosmDatastream(sensorID1, strlen(sensorID1), DATASTREAM_FLOAT),
CosmDatastream(sensorID2, strlen(sensorID2), DATASTREAM_FLOAT),
CosmDatastream(sensorID3, strlen(sensorID3), DATASTREAM_FLOAT),
CosmDatastream(sensorID4, strlen(sensorID4), DATASTREAM_FLOAT),
CosmDatastream(sensorID5, strlen(sensorID5), DATASTREAM_FLOAT),

// Finally, wrap the datastreams into a feed
CosmFeed feed(feedID, datastreams, 6 /* number of datastreams */);

EthernetClient client;
CosmClient cosmclient(client);

// LCD shield

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
#define WHITE 0x7

Adafruit_BMP085 bmp;
//// Data wire is plugged into which pin on the Arduino?
#define ONE_WIRE_BUS 6
//// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
//// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

#define DHTPIN 3 // what pin we’re connected to
#define DHTTYPE DHT22 // DHT 22 (AM2302)

float light;

void setup() {
// put your setup code here, to run once:
lcd.begin(16, 2);

Serial.println(“Starting single datastream upload to Cosm…”);

if (debug < 1 ) {

while (Ethernet.begin(mac) != 1)
Serial.println(“Error getting IP address via DHCP, trying again…”);
// lcd.clear();
lcd.print(“Error getting IP”);

// set pin modes to power sensors
pinMode(7, OUTPUT);
pinMode(5, OUTPUT);
pinMode(4, OUTPUT);
pinMode(2, OUTPUT);

digitalWrite(7, LOW);
digitalWrite(5, HIGH);
digitalWrite(4, LOW);
digitalWrite(2, HIGH);

// initialise sensors



void loop() {
lcd.setCursor(0, 0);

// Get sensor readings
// BMP085
float BMPt = bmp.readTemperature();
float BMPp = bmp.readPressure() / 100.0;

// DHT22
float DHTh = dht.readHumidity();
float DHTt = dht.readTemperature();

// DS18B20
sensors.requestTemperatures(); // Send the command to get temperatures
float DSt = (sensors.getTempCByIndex(0));

// get light
light = analogRead(0)/ 10.23;


if (debug > 0) {

/*———–( Show the values inside the streams for test/debug )—–*/
Serial.println(“—–[ Test: Check values inside the Streams ]—–”);
Serial.print(“BMPp: ”);
Serial.println(datastreams[0].getFloat()); // Print datastream to serial monitor
Serial.print(“DHTh: ”);
Serial.println(datastreams[1].getFloat()); // Print datastream to serial monitor
Serial.print(“DSt: ”);
Serial.println(datastreams[2].getFloat()); // Print datastream to serial monitor
Serial.print(“light: ”);
Serial.println(datastreams[3].getFloat()); // Print datastream to serial monitor
Serial.print(“BMPt: ”);
Serial.println(datastreams[4].getFloat()); // Print datastream to serial monitor
Serial.print(“DHTt: ”);
Serial.println(datastreams[5].getFloat()); // Print datastream to serial monitor

if (debug < 1) {
Serial.println(“Uploading to Cosm”);
lcd.print(“sending to COSM”);
int ret = cosmclient.put(feed, cosmKey);

Serial.print(“COSM client returns: ”); // Get return result code, similar to HTTP code
lcd.print(“COSM client”);
lcd.print(“returned: ”);
lcd.print(“BMPp: ”);
lcd.print(“BMPt: ”);
lcd.print(“DHTh: ”);
lcd.print(“DHTt: ”);
lcd.print(“light: ”);
lcd.print(“DSt: ”);

logging thermocycler performance

My favourite PhD student (hi, squids!) was having issues with her PCR. She was ending up with empty tubes at the end of her program and was concerned that the machine wasn’t producing the right temperature cycle. As I had an Adafruit MAX6675 thermocouple board on my desk I offered to log the cycle to determine whether this was the case. I used a miniature breadboard to connect the Arduino Nano and MAX6675 breakout. The measurements were output to serial and logged to text file by a PC running my Processing datalogger sketch. Here’s the result:


There seems to be some real issues here as the temperatures don’t match the program well at all. There’s meant to be a 55C step immediately before each polymerisation hold at 62C and the sensor gets no where near this. This might be a result of poor heat transfer between the reaction tubes and the thermocouple but I figure that accurately reflects the same process of heat transfer between the block and the liquid in the reaction tubes. 

I’ve run the test again in a different well on the block. I’ll need to validate the thermocouple’s temperatures using another couple of thermometers to make sure its giving accurate temps but just this initial test has revealed a problem worthy of serious investigation. The fun continues another day … .