City Environmental Monitoring Device

by taifur in Circuits > Sensors

1616 Views, 23 Favorites, 0 Comments

City Environmental Monitoring Device

IMG_4175.JPG
IMG_4204.JPG

My city Dhaka (capital of Bangladesh) is one of the world's largest cities, with a population of 18.89 million people in the Greater Dhaka Area. It is also the 4th most densely populated city in the world.

Sorry to say that Dhaka has been ranked highest in the US Air Quality Index (AQI), for having the worst level of air pollution in the world. Noise also always goes far beyond the permissible level. Sound pollution has reached the highest 120-130 decibels (dB) at many points of the city -- almost double of the permissible level.

To save the city it is very high time to take necessary steps. Creating public awareness is first one of the steps. For creating public awareness we need real-time data of the noise we are creating every day. If everyone can see the noise level and air quality in real time it will create a mental pressure for taking steps against the pollution. The researcher will also be benefited from this open source real-time data.

From the thinking, I designed an open source real-time city pollution monitoring device which monitors noise level, air quality, temperature, and humidity and sends the data to the ThingSpeak. I used GSM for data transmission because the availability of wifi is very much limited in the city. The device gets power from a solar panel.

I tried to keep it very simple so that anybody can make his own device. No soldering is required to make the device. Just collect the required components, upload the code and plug and play all the modules. You are ready to go.

Shopping List

IMG_4095.JPG
LiPo_Rider_Pro1.jpg
seeeduinogprs.jpg

1. Seeeduino GPRS ( seeedstudio.com)

Seeeduino GPRS is an Arduino board with integrated GPRS module (SIM800) and support GSM, Bluetooth and FM. Instead of using it you may use Seeeduino V4 and Seeed Studio GPRS Shield V3.0.

2. Seeed Base Shield V2 ( seeedstudio.com)

Base Shield is very useful for connecting Grove Sensors to Arduino without any soldering.

3. Seeed 1W Solar Panel 80X100 (seeedstudio.com)

1W Solar Panel is required for charging the Battery and providing the required power for the kit. This panel is enough for delivering the power required to run the kit at least 48 hours with 4 hours sunlight. The size is important to adjust it in the 3D printed case.

4. Seeed LiPo Rider Pro ( seeedstudio.com)

The LiPo Rider Pro board allows you ride the solar wave to run your favorite 5V device. The LiPo Rider Pro board is the ideal green power solution for your outdoor sensor design. Attach the LiPo Rider Pro board to your sensor board and it can run on solar power forever! Instead of LiPo Rider Pro you may also use Solar Charger Shield v2.2.

5. Seeed Grove - Air quality sensor v1.3 ( seeedstudio.com)

The sensor can detect carbon monoxide, alcohol, acetone, thinner, formaldehyde and other slightly toxic gases. It is compatible with 5V and 3.3V power supply. The sensor is used to monitor the air quality of the environment.

6. Seeed Grove - Loudness Sensor ( seeedstudio.com)

The Grove - Loudness Sensor is designed to detect the loudness of environmental sound. Based on amplifier LM2904 and a built-in microphone, it amplifies and filters the high-frequency signal that received from the microphone, and outputs a positive envelope. This will make for Arduino's signal acquisition. The output value depends on the level of sound input. It gives an analog output. I mapped the analog value to dB with a sound level meter. The output dB is not accurate enough and for testing purpose only.

7. Seeed Grove - Temperature & Humidity Sensor (DHT11)( seeedstudio.com)

Different types of Temperature and Humidity Sensors are available with different accuracy and price. I used DHT11 for the project.

8. Li-Ion Battery 1000mAh (sparkfun.com)

1000mAh is required for powering the device for 48 hours assuming the data will be updated once in a minute. Capacity depends on the frequency of the data update.

Connecting Stuffs

IMG_4086.JPG
IMG_4075.JPG
IMG_4077.JPG
IMG_4078.JPG

The connection between the components is very simple. No soldering is required. Just plug all the module in the appropriate port.

First, place the base shield on the Seeeduino GPRS board.

Then, connect:

Air Quality Sensor to Analog A0 of the base shield.

Sound Sensor to Analog A1

DHT 11 Sensor to Digital 4

Then, connect Lipo rider pro to Seeeduino board using a short micro USB cable. Connect solar panel to the port marked as solar of Lipo rider board and battery to the battery port. Your connection is ready. So simple.

Uploading Code & Testing

500px-Seeeduino_gprs_b.jpg
seeeduino_gprs_select_board.png
seeeduino_gprs_select_com.png

After making the previous connection remove the Lipo rider board from the micro USB cable and connect the Seeeduino board to USB port of your computer using the micro USB cable. Choose the Arduino Leonardo from the board selection menu of the Arduino IDE. Copy the following code and paste into your Arduino environment. Replace the ThingSpeak API key with your own API key and upload the program to the board. It will start sending data to the ThingSpeak server and you will be able to observe it from your ThingSpeak channel. For uploading the code successfully you will be required to add Seeed Air quality and DHT sensor library. The code and library are attached.

#include <SoftwareSerial.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
#include "AirQuality.h"
#include "Arduino.h"
#include "DHT.h"

/* Create object named GPRS of the class SoftwareSerial */
SoftwareSerial GPRS(8, 7);

#define DHTPIN 4     // what digital pin DHT sensor connected to
#define DHTTYPE DHT11   // model of the sensor DHT11 

#define SIM800_POWER_PIN        9
#define SIM800_POWER_STATUS     12
#define DEFAULT_TIMEOUT     5
#define DTR_PIN 11

DHT dht(DHTPIN, DHTTYPE);

AirQuality airqualitysensor;
int current_quality =-1;

//replace with your own API key
String API_KEY = "api_key=B3FPE7GTVY1ISGQS";
String field = "";

//Value for watchdog timer interrupt.
volatile int f_wdt = 1;
int seconds = 0;
int minutes = 2;
int hours = 0;
int interval = ((hours*60*60) + (minutes*60) + (seconds))/8;
int timerCounter = 0;

const int sampleWindow = 50;                              // Sample window width in mS (50 mS = 20Hz)
unsigned int sample;
float value;
float temp, humid;
int airQuality;


//ISR for watchdog timer.
ISR(WDT_vect)
{
  if(f_wdt == 0)
  {
    f_wdt=1;
    timerCounter++;
  }
  else
  {
    Serial.println("WDT Overrun!!!");
  }
}

 //--------------------------------------------------------------------------------------------
 //                                            SETUP
 //--------------------------------------------------------------------------------------------
void setup() 
{
   GPRS.begin(9600);  /* Define baud rate for software serial communication */
   airqualitysensor.init(14);
   dht.begin();
   setupWdt();
   //start sim800
   pinMode(SIM800_POWER_PIN, OUTPUT);
   digitalWrite(SIM800_POWER_PIN,HIGH);
   delay(200);
   digitalWrite(SIM800_POWER_PIN,LOW);
   delay(2000);
   digitalWrite(SIM800_POWER_PIN,HIGH);
   delay(3000);  
   pinMode(DTR_PIN, OUTPUT);
   digitalWrite(DTR_PIN, HIGH); //this pin should be high to enable sleep mode of sim800

}
 
//--------------------------------------------------------------------------------------------
 //                                         MAIN LOOP
 //--------------------------------------------------------------------------------------------
  
void loop() 
{
 if(f_wdt == 1)
  {
    if (timerCounter == interval)
    {
      //wdt_disable();
      //Serial.println(F("Tried to stop the watchdog."));
      //wdt_reset();

      value = calculate_sound_in_db();
      airQuality = calculate_air_quality();
      calculate_temp_humid();
      //field should be according to ThingSpeak chennel seting
      API_KEY = "api_key=B3FPE7GTVY1ISGQS";
      API_KEY += "&field1=";
      API_KEY += value;
      API_KEY += "&field2=";
      API_KEY += temp;
      API_KEY += "&field3=";
      API_KEY += humid;
      API_KEY += "&field4=";
      API_KEY += airQuality;
      send_data();

      //Reset timer.
      timerCounter = 0;
      //wdt_enable();
      //Serial.println(F("Tried to re-enable watchdog."));
    }

    /* Don't forget to clear the flag. */
    f_wdt = 0;

    /* Re-enter sleep mode. */
    enterSleep();
  }
  else
  {
    /* Do nothing. */
  }

}

//this function calculate sound level in dB
float calculate_sound_in_db(){
   unsigned long startMillis= millis();                   // Start of sample window
   float peakToPeak = 0;                                  // peak-to-peak level
 
   unsigned int signalMax = 0;                            //minimum value
   unsigned int signalMin = 1024;                         //maximum value
 
                                                          // collect data for 50 mS
   while (millis() - startMillis < sampleWindow)
   {
      sample = analogRead(A1);                             //get reading from microphone
      if (sample < 1024)                                  // toss out spurious readings
      {
         if (sample > signalMax)
         {
            signalMax = sample;                           // save just the max levels
         }
         else if (sample < signalMin)
         {
            signalMin = sample;                           // save just the min levels
         }
      }
   }
   peakToPeak = signalMax - signalMin;                    // max - min = peak-peak amplitude
   //Serial.println(peakToPeak);                                     //write calibrated deciBels
   float db = map(peakToPeak,0,1000,48,120);             //calibrate for deciBels
   return db;
}

int calculate_air_quality(){
  current_quality=airqualitysensor.slope();
  return current_quality;
}

void calculate_temp_humid(){
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t)) {
    return;
  }

  temp = t;
  humid = h;
}
//this function sends data to ThingSpeak server
//it takes approximately 13 seconds to send data to server using GPRSS
void send_data(){  
  GPRS.println("AT"); /* Check Communication */
  delay(200);
  GPRS.println("AT"); /* Check Communication */
  delay(2);
  GPRS.println("AT+CSCLK=0"); /* disable sleep mode */
  delay(500);
  /* Configure bearer profile 1 */
  GPRS.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRSS\"");  /* Connection type GPRSS */
  delay(500);
  GPRS.println("AT+SAPBR=3,1,\"APN\",\"gpinternet\"");  /* APN of the provider */
  delay(1500);
  GPRS.println("AT+SAPBR=1,1"); /* Open GPRSS context */
  delay(1500);
  wdt_reset(); //manually reset wdt timer to prevent interrupt
  GPRS.println("AT+SAPBR=2,1"); /* Query the GPRSS context */
  delay(1500);
  GPRS.println("AT+HTTPINIT");  /* Initialize HTTP service */
  delay(1500); 
  GPRS.println("AT+HTTPPARA=\"CID\",1");  /* Set parameters for HTTP session */
  delay(1500);
  wdt_reset();
  GPRS.println("AT+HTTPPARA=\"URL\",\"api.thingspeak.com/update\"");  
  delay(2000);
  GPRS.println("AT+HTTPDATA=33,10000"); 
  delay(2000);
  wdt_reset();
  //GPRS.println("api_key=B3FPE7GTVY1ISGQS&field1=2");
  GPRS.println(API_KEY);
  delay(2000);
  GPRS.println("AT+HTTPACTION=1");  /* Start POST session */
  delay(2000); 
  wdt_reset();
  GPRS.println("AT+HTTPTERM");  /* Terminate HTTP service */
  delay(2000);
  GPRS.println("AT+SAPBR=0,1"); /* Close GPRSS context */
  delay(2000);
  wdt_reset();
  GPRS.println("AT+CSCLK=2"); /* enable sleep mode */
  delay(500);
}

void enterSleep(void)
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();

  /* Now enter sleep mode. */
  sleep_mode();

  /* The program will continue from here after the WDT timeout*/
  sleep_disable(); /* First thing to do is disable sleep. */

  /* Re-enable the peripherals. */
  power_all_enable();
}

void setupWdt()
{
  /*** Setup the WDT ***/

  /* Clear the reset flag. */
  MCUSR &= ~(1<

For saving power Sleep mode for both Arduino and SIM800 is implemented. Watchdog timer is used to wake up Arduino from sleep mode. Sleep duration can be changed from the variable minute, second and hour. Here, it is set for 2 minutes.

For SIM800 module sleep mode 2 is used. DTR pin of the SIM800 module must be set to high to enable the sleep mode. The module wakes up from the sleep mode after receiving AT command.

3D Printing

IMG_4103.JPG
IMG_4109.JPG
IMG_4110.JPG
IMG_4112.JPG
IMG_4106.JPG

A 3D printed casing is designed to make the device portable and environment proof. After placing all the components inside the case you can place the device anywhere you prefer to collect data. The solar panel is placed at the top of the case with an angle so that the sunlight directly fall onto the panel. Two STL files are attached. Print the attached files. One for the main box and another for the front cover. The original design was made by instructable user deba168 for his instructable (https://www.instructables.com/id/Solar-Powered-WiFi-Weather-Station/). Thanks to deba168 for his nice design. I modified his design according to my requirement. After printing, you may require some polishing to adjust front cover with the main board. Use sandpaper to do it if required.

Connecting Solar Panel and Main Board

IMG_4124.JPG
IMG_4126.JPG
IMG_4130.JPG
IMG_4134.JPG

First, attach the base shield to the Seeeduino GPRS and place these inside the printed box. You can add some hot glue for tightly attaching the modules with the box.

Then, connect Grove sound sensor to A0, Air quality sensor to A1 and Temperature and Humidity sensor to D4 connector of the base shield. If you want to change the port number, don't forget to change it in the Arduino sketch accordingly.

Now, place the solar panel at the top of the box and bring out the wires inside the box through the hole. Use some glue to fix the solar panel with the box.

Finally, fix all the sensor modules and the GPRS antenna to a suitable location inside the box using hot glue.

Assembling the Solar Charger

IMG_4139.JPG
IMG_4144.JPG
IMG_4145.JPG
IMG_4149.JPG
LiPo_Rider_Pro.jpg
IMG_4152.JPG
tinspeak.png

After placing all the sensors and solar panel in the appropriate place and fixing it with glue, it is the right time to add the solar charger and battery. For powering the device I used 1000mAh Li-ion battery. To charge the battery by a solar panel I used Lipo rider pro from Seeed studio. Instead of using lipo rider pro you can also use solar charger shield from seeedstudio.com.

The LiPo Rider Pro is an enhancement of Lipo Rider. It supplies heavier load output(1A peak) than Lipo Rider. The LiPo Rider Pro board allows you ride the solar wave to run your favourite 5V device. The LiPo Rider Pro board is the ideal green power solution for your outdoor sensor design. Attach the LiPo Rider Pro board to your sensor board and it can run on solar power forever!

The LiPo Rider Pro is extremely affordable and easy to use. No programming is required. Plug it in and it works. The internal charger IC handles all the power flow between the various components.

Lipo rider pro has onboard JST connector for connecting solar panel and battery. The connectors are clearly marked on the board. Connect the solar panel and battery to appropriate connector of the LiPo Rider pro module and place inside the box as shown in the photo below. Turn on the power switch and place the top cover of the box.

If everything goes well the device will start sending data to ThingSpeak. The graphs look like following

If this is the first time you are using ThingSpeak you may visit https://www.codeproject.com/Articles/845538/An-Introduction-to-ThingSpeak and https://roboindia.com/tutorials/thingspeak-setup.

The Final Device

IMG_4176.JPG
IMG_4179.JPG
IMG_4195.JPG
last.jpg

Congratulation!!!

Your device is ready. Place it in a right location and start contributing to the community with your data. Aware people about pollution!!!