Project tutorial
Air quality/weather station

Air quality/weather station © GPL3+

This is good starting project for people interested in Internet of Things devices and wishing to start with something both simple and fun.

  • 11,953 views
  • 9 comments
  • 35 respects

Components and supplies

About this project

An air quality or weather station that pushes the data on the Internet is a low complexity fun project to explore the Internet of Things revolution and understand the main concepts and protocols used.

So let's say you want to build such a contraption, you would need a physical device with the desired sensors and send the data to a cloud service to be displayed, shared or analysed. 

For the device we opted for Arduino Ethernet because of the strong community support and large base of supported sensors. We wanted to measure the CO2 concentration in the air, the temperature and noise level and compare it between two locations. So we had two of this devices with the same components and only sending the data to different endpoints. Speaking of endpoints, for the cloud solution we used DeviceHub.net  which offers both data in and data out in the form of gathering data from sensors and remote control devices by defining actuators on the platform first and then linking them to the hardware by using the API.


Here are the main hardware components used is this tutorial.

Be sure to protect the components with an outdoor case that will be protective against rain but also let the co2 sensor reach the air. A bell shaped cover works best.

The first step is to register on the platform and create a Device as an entry point for your data on the cloud. You can do that here https://dashboard.devicehub.net/register and follow the wizard there to create your device.

I created a device with all the data types the platform offers Sensors (analog, digital, string, map) and Actuators (digital, analog). All data types have means of both sending data to the platform and retrieving it. Every Device has a unique id (UUID) and an associated API key of the project it resides to make sending data secure and reliable.

You can find the code attached to this project gathering all the details just be sure to replace the specific ids and api keys for each device. We used the MQTT protocol offered by DeviceHub.net because of the advantages over the REST based communication. You can learn more about the differences between them here.


Here is a snapshot from both locations of the sensors and their current data.


Happy Hacking!

If you have any questions let me know,

Thank you.

Code

Arduino codeC/C++
 /*
Air Quality/Weather station
  |--> device that monitors the temperature, 
       noise and carbon dioxide levels via devicehub.net
 
 Hardware parts:
   1. Microcontroller board     
       ---> Arduino Ethernet
        |-> http://arduino.cc/en/Main/arduinoBoardEthernet
   
   2. Sound sensor              
       ---> Grove - Sound Sensor w/ LM358 amplifier and an electret microphone  
        |-> http://www.seeedstudio.com/wiki/index.php?title=Twig_-_Sound_Sensor
   
   3. Temperature sensor        
       ---> One Wire Temperature Sensor waterproof DS18B20   
       |-> http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf     
 
   4. CO2 sensor               
       ---> Grove - CO2 Sensor
        |-> http://www.seeedstudio.com/wiki/images/c/ca/MH-Z16_CO2_datasheet_EN.pdf
   
   5. Additional parts          
       ---> 4.7K resistor
 
 Connections:
   1. Sound sensor              
       ---> Arduino Analog A0
   
   2. Temperature sensor        
      ----> Arduino Digital 2
       |--> 4.7K resistor between signal and the power pin
   
   3. CO2 sensor               
       ---> Arduino Digital 3 ( TX )
        |-> Arduino Digital 4 ( RX )
 
 Libraries:
   1. OneWire
       ---> http://code.bildr.org/download/997.zip
   
   2. MQTT PubSubClient         
       ---> https://github.com/knolleary/pubsubclient/archive/v1.9.1.zip
   
   3. Dallas Temperature       
       ---> http://www.hacktronics.com/code/DallasTemperature.zip
     
 Web platform:    
   DeviceHUB.net                
       
 23.06.2015                         
 Author: Alexandru Gheorghe
*/


#include <SPI.h>  
#include <OneWire.h>  
#include <Ethernet.h>                            
#include <PubSubClient.h>
#include <SoftwareSerial.h>
#include <DallasTemperature.h>

// MAC Address of Arduino Ethernet (Sheild)
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

#define API_KEY           "paste_apikey_here"
#define PROJECT_ID        "paste_projectid_here"
#define TEMPERATURE_NAME  "paste_temp_sensor_name_here"
#define NOISE_NAME        "paste_noise_sensor_name_here"
#define CO2_NAME          "paste_co2_sensor_name_here"
#define DEVICE_UUID       "paste_device_uuid_name_here"

#define sec               1000

char clientId[]        = "write_a_client_name_without_spaces"; // e.g. char clientId[] = "my_arduino"
char TempTopic[]       = "/a/"API_KEY"/p/"PROJECT_ID"/d/"DEVICE_UUID"/sensor/"TEMPERATURE_NAME"/data";
char NoiseTopic[]      = "/a/"API_KEY"/p/"PROJECT_ID"/d/"DEVICE_UUID"/sensor/"NOISE_NAME"/data";
char CO2Topic[]        = "/a/"API_KEY"/p/"PROJECT_ID"/d/"DEVICE_UUID"/sensor/"CO2_NAME"/data";
// server mqtt.devicehub.net ip
char server[]         = "104.155.7.31";
char message_buffer1[20];
char message_buffer2[20];
char message_buffer3[20];

EthernetClient apiClient;

void callback(char* topic, byte* payload, unsigned int length)
{
  // handle message arrived
}

PubSubClient client(server, 1883, callback, apiClient);

boolean conn = false;
unsigned long time;

#define DS18S20_Pin  2        // DS18S20 Signal pin on digital 2
OneWire ds(DS18S20_Pin);      // on digital pin 2
DallasTemperature sensors(&ds);

int counter = 0;

// CO2 sensor
#define pinTx  3
#define pinRx  4
SoftwareSerial sensorCo2(pinTx,pinRx);
const unsigned char cmd_get_sensor[] = {
0xff, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
const unsigned char cmd_c_sensor[] = {
0xff, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78};

// Noise variables
#define noise_pin        A0   // Microphone is connected to Analog 0
const int sampleWindow = 50;  // Sample window width in mS (50 mS = 20Hz)
unsigned int sample;
// variables for smoothing the microphone values
const int numReadings = 10;
int readings[numReadings];      
int index = 0;                  
int total = 0;                  
int average = 0;  

void setup(void)  
{
  // init serial for debugging
  Serial.begin(9600);
  initPins();

  if (Ethernet.begin(mac) == 0)  
  {
    Serial.println(F("Failed to configure Ethernet using DHCP"));
    Ethernet.begin(mac);
  }

  Serial.println(F("\nStarting connection to server..."));
  
  if(client.connect(clientId))  
  {
    conn = true;
    Serial.println(F("Successfuly connected and running!"));
  }
  else  
  {
    Serial.println(F("Connection problem"));
  }

  Serial.println(F("Starting..."));
  Serial.println(F("3 minutes warm-up CO2 sensor..."));
  // warm-up time for co2 sensor
  while(counter < 2)  {
    Serial.println(counter);
    delay(sec);
    counter++;
  }

  Serial.print('\n');
  Serial.println(F("Warm-up completed"));
  Serial.print('\n');

  // start a serial communication with the CO2 sensor
  sensorCo2.begin(9600);
  
  // cablibrate the zero point for CO2 sensor  
  Serial.println(F("Calibrating CO2 sensor..."));
    for(int i = 0; i < sizeof(cmd_c_sensor); i++)  {
    sensorCo2.write(cmd_c_sensor[i]);
  }

  delay(3*sec);  
  
  Serial.println(F("Calibration completed"));

}

void loop(void)  
{
  //if client it's not connected or disconnects here we try to reconnect
  if (!client.connected())
  { 
    Serial.println(F("reconnecting ..."));
    client.connect(clientId);
    delay(3*sec); 
    sendData();  
  }

  sendData();
}

void sendData(void) 
{
  float ThermometerTemperature = getTemp();
  float Noise = getNoise();
  int gas;
  int tempCo2;

  // get co2 value from function getCarbonDioxide
  if(getCarbonDioxide(&gas, &tempCo2))  {
    gas;
  }
  
  if(conn) 
  {
    //publishing new value every 5 seconds
    if (millis() > (time + 5*sec)) 
    {
      time = millis();
      
      String pubString1 = "{\"value\": " + String(ThermometerTemperature) + "}";
      String pubString2 = "{\"value\": " + String(Noise) + "}";
      String pubString3 = "{\"value\": " + String(gas) + "}";

      pubString1.toCharArray(message_buffer1, pubString1.length()+1);
      pubString2.toCharArray(message_buffer2, pubString2.length()+1);
      pubString3.toCharArray(message_buffer3, pubString3.length()+1);
    
      Serial.println(F("Publishing new value: "));
      Serial.println(ThermometerTemperature);
      Serial.println(Noise);
      Serial.println(gas);
      
      client.publish(TempTopic,  message_buffer1);
      client.publish(NoiseTopic, message_buffer2);
      client.publish(CO2Topic,   message_buffer3);
    }
    // MQTT client loop processing
    client.loop();
  }

}

void initPins()  
{
  pinMode(noise_pin, INPUT); 
}


// returns the temperature from DS18S20 in DEG Celsius
float getTemp(void)
{
  sensors.requestTemperatures();
  float currentTemp;
  currentTemp = sensors.getTempCByIndex(0);
  
  return currentTemp;
}

void sendcommand(uint8_t *pcommand)  
{
    uint8_t i;
   
    for (i=0;i<9;i++)  
    {
      sensorCo2.write(pcommand[i]);
    }   
}


// returns the gas strength from the CO2 sensor
bool getCarbonDioxide(int *gas_strength, int *temperatureGas)  
{
  for(int i = 0; i < sizeof(cmd_get_sensor); i++)  
  {
    sensorCo2.write(cmd_get_sensor[i]);
  }
  
  long cnt_timeout = 0;
  while(!sensorCo2.available())  
  {
    delay(1);
    cnt_timeout++;    
    if(cnt_timeout > 1000)
      return 0;
  }
  
  int len = 0;
  unsigned char dta[20];
  
  while(sensorCo2.available())  
  {
    dta[len++] = sensorCo2.read();
  }
  
  if((9 == len) && (0xff == dta[0]) && (0x86 == dta[1]))
  {
    *gas_strength = 256*dta[2]+dta[3];
    *temperatureGas = dta[4] - 40;
    delay(5*sec);
    return 1;
  }

  return 0;  

}

// returns the decibels from sound sensor
float getNoise()  
{
  unsigned long startMillis= millis();
  unsigned int peakToPeak = 0;

  unsigned int signalMax = 0;
  unsigned int signalMin = 750;

  while (millis() - startMillis < sampleWindow)  
  {
    sample = analogRead(noise_pin);
    if (sample < 1024)  
    {
      if (sample > signalMax)  
      {
        signalMax = sample;
      }
      else if (sample < signalMin)  
      {
         signalMin = sample;
      }
    }
  }

  peakToPeak = signalMax - signalMin;  
  
  // transform voltage to decibels 
  double dB = 3.1 * 20.0  * log10 (peakToPeak  +1.);
  
  // smoothing the values from sensor
  total= total - readings[index];         
  readings[index] = dB; 
  total= total + readings[index];       
  index = index + 1;                    
  
  if (index >= numReadings) 
    index = 0;               
    
  average = total / numReadings;         
  
  int realdB = map(average, 100, 190, 40,100);
  delay(30);
  // not send false values
  if(realdB > 4)  
  {
    delay(6*sec);
    return realdB;
  }

}

Comments

Similar projects you might like

Arduino UNO Mini-Weather Station

Project tutorial by Igor Fonseca Albuquerque

  • 25,833 views
  • 21 comments
  • 67 respects

Simple and Smart Air Purifier System

Project tutorial by Aaron Kow

  • 10,939 views
  • 4 comments
  • 36 respects

Indoor Air Quality Monitoring System

Project tutorial by Team East West University

  • 9,135 views
  • 3 comments
  • 40 respects

Arduino MKR1000 Weather Station

Project tutorial by Tadeas Dvoracek

  • 8,298 views
  • 4 comments
  • 22 respects

IoT@School: An IoT Implementation for Monitoring Air Quality

Project showcase by Koen Kempeneers

  • 5,752 views
  • 1 comment
  • 24 respects

$10 Portable Arduino Weather Station (AWS)

Project tutorial by Prajjwal Nag

  • 31,649 views
  • 6 comments
  • 59 respects
Add projectSign up / Login