Shankar Chavan
Published © GPL3+

Edge AI Air Quality Monitor & Pollution Anomaly Detector

Real-time offline air quality monitoring and hazard alerts using Arduino UNO Q, MQ135, and an optical dust sensor.

IntermediateFull instructions provided8 hours43
Edge AI Air Quality Monitor & Pollution Anomaly Detector

Things used in this project

Hardware components

Arduino UNO Q
Arduino UNO Q
×1
MQ 135 Air Quality/Gas Detector Sensor
×1
Solderless Breadboard Full Size
Solderless Breadboard Full Size
×1
Male/Male Jumper Wires
×1
Resistor 330 ohm
Resistor 330 ohm
×1
Buzzer
Buzzer
5V Active Electromagnetic Buzzer
×1
Electrolytic Capacitor, 250 µF
Electrolytic Capacitor, 250 µF
×1
Grove - Dust Sensor(PPD42NS)
Seeed Studio Grove - Dust Sensor(PPD42NS)
Used GP2Y1010AU0F Optical Dust Sensor Kit with Cable for Arduino
×1

Software apps and online services

Arduino App Lab

Story

Read more

Schematics

PuneAir Breadboard Wiring

Breadboard wiring layout - MQ135 gas sensor on A2, GP2Y1010 dust sensor (Vo on A3, LED control on D4), piezo buzzer on D8, all powered from UNO Q's 5V and GND.

Code

PuneAir.ino

C/C++
Final demo sketch - reads MQ135 gas sensor and GP2Y1010 dust sensor, classifies air quality as GOOD/MODERATE/HAZARDOUS, and drives onboard LED + buzzer alerts.
/*
  PuneAir - Edge AI Air Quality Monitor
  FINAL DEMO VERSION

  Hardware:
    MQ135 AOUT   -> A2
    Dust Vo      -> A3
    Dust LED     -> D4
    Buzzer       -> D8
    Onboard LED  -> LED_BUILTIN

  Current observed normal baseline:
    MQ135  170-190
    Dust   3-8 ug/m3

  Alert:
    GOOD      -> LED OFF, buzzer OFF
    MODERATE  -> LED slow blink
    HAZARDOUS -> LED fast blink + buzzer

  IMPORTANT:
    Thresholds below are project-defined thresholds.
    They are NOT official AQI limits.
*/

#include <Arduino_RouterBridge.h>


// =====================================================
// PIN DEFINITIONS
// =====================================================

const int MQ135_PIN    = A2;
const int DUST_VO_PIN  = A3;
const int DUST_LED_PIN = 4;
const int BUZZER_PIN   = 8;
const int LED_PIN      = LED_BUILTIN;


// =====================================================
// GP2Y1010 TIMING
// =====================================================

const int SAMPLING_TIME = 280;
const int DELTA_TIME    = 40;
const int SLEEP_TIME    = 9680;


// =====================================================
// MQ135 THRESHOLDS
// Based on your observed baseline ~170-190
// =====================================================

const int MQ135_MODERATE_RAW = 250;
const int MQ135_HAZARD_RAW   = 300;


// =====================================================
// DUST THRESHOLDS
// =====================================================

const float DUST_MODERATE_UGM3 = 100.0;
const float DUST_HAZARD_UGM3   = 300.0;


// =====================================================
// DUST SENSOR CALCULATION
// =====================================================

// Keep the same validated calculation for your current
// prototype so your existing readings remain comparable.


// =====================================================
// AIR QUALITY LEVEL
// =====================================================

enum AQILevel
{
  GOOD,
  MODERATE,
  HAZARDOUS
};


// =====================================================
// SETUP
// =====================================================

void setup()
{
  Serial.begin(9600);
  Monitor.begin();

  pinMode(DUST_LED_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);

  // GP2Y1010 LED is active LOW
  digitalWrite(DUST_LED_PIN, HIGH);

  digitalWrite(BUZZER_PIN, LOW);
  digitalWrite(LED_PIN, LOW);


  Monitor.println("");
  Monitor.println("=================================");
  Monitor.println("       PUNEAIR AIR MONITOR");
  Monitor.println("=================================");

  Monitor.println("");
  Monitor.println("MQ135  -> A2");
  Monitor.println("Dust Vo -> A3");
  Monitor.println("Dust LED -> D4");
  Monitor.println("Buzzer -> D8");

  Monitor.println("");
  Monitor.println("Letting MQ135 warm up for 30 seconds...");

  delay(30000);

  Monitor.println("Warm-up complete.");
  Monitor.println("Starting REAL SENSOR MODE...");
  Monitor.println("");
}


// =====================================================
// READ DUST
// =====================================================

float readDustDensity()
{
  // Turn dust LED ON
  digitalWrite(DUST_LED_PIN, LOW);

  delayMicroseconds(SAMPLING_TIME);

  // Read sensor output
  int rawVo = analogRead(DUST_VO_PIN);

  delayMicroseconds(DELTA_TIME);

  // Turn dust LED OFF
  digitalWrite(DUST_LED_PIN, HIGH);

  delayMicroseconds(SLEEP_TIME);


  // Existing 10-bit / 5V calculation
  float voltage = rawVo * (5.0 / 1024.0);


  // Existing dust calculation
  float dustDensity =
    (0.17 * voltage - 0.1) * 1000.0;


  // Prevent negative value
  if (dustDensity < 0)
  {
    dustDensity = 0;
  }


  return dustDensity;
}


// =====================================================
// CLASSIFY AIR
// =====================================================

AQILevel classifyAir(int mq135Raw, float dustDensity)
{
  // HAZARDOUS
  if (mq135Raw >= MQ135_HAZARD_RAW ||
      dustDensity >= DUST_HAZARD_UGM3)
  {
    return HAZARDOUS;
  }


  // MODERATE
  if (mq135Raw >= MQ135_MODERATE_RAW ||
      dustDensity >= DUST_MODERATE_UGM3)
  {
    return MODERATE;
  }


  // GOOD
  return GOOD;
}


// =====================================================
// ALERT SYSTEM
// =====================================================

void applyAlert(AQILevel level)
{
  // ===================================================
  // GOOD
  // ===================================================

  if (level == GOOD)
  {
    digitalWrite(LED_PIN, LOW);
    noTone(BUZZER_PIN);

    delay(1000);
  }


  // ===================================================
  // MODERATE
  // ===================================================

  else if (level == MODERATE)
  {
    noTone(BUZZER_PIN);

    // Slow blinking
    digitalWrite(LED_PIN, HIGH);
    delay(500);

    digitalWrite(LED_PIN, LOW);
    delay(500);
  }


  // ===================================================
  // HAZARDOUS
  // ===================================================

  else
  {
    // Fast LED + buzzer
    digitalWrite(LED_PIN, HIGH);
    tone(BUZZER_PIN, 2000);

    delay(150);

    digitalWrite(LED_PIN, LOW);
    noTone(BUZZER_PIN);

    delay(150);
  }
}


// =====================================================
// MAIN LOOP
// =====================================================

void loop()
{
  // ---------------------------------------------------
  // MQ135
  // ---------------------------------------------------

  int mq135Raw = analogRead(MQ135_PIN);

  float mq135Voltage =
    mq135Raw * (5.0 / 1024.0);


  // ---------------------------------------------------
  // DUST
  // ---------------------------------------------------

  float dustDensity = readDustDensity();


  // ---------------------------------------------------
  // CLASSIFICATION
  // ---------------------------------------------------

  AQILevel level =
    classifyAir(mq135Raw, dustDensity);


  // ---------------------------------------------------
  // PRINT READINGS
  // ---------------------------------------------------

  Monitor.println("---------------------------------");

  Monitor.print("MQ135 raw: ");
  Monitor.print(mq135Raw);

  Monitor.print("   Voltage: ");
  Monitor.print(mq135Voltage, 2);
  Monitor.println(" V");


  Monitor.print("Dust density: ");
  Monitor.print(dustDensity, 2);
  Monitor.println(" ug/m3");


  Monitor.print("AQI Level: ");


  if (level == GOOD)
  {
    Monitor.println("GOOD");
  }
  else if (level == MODERATE)
  {
    Monitor.println("MODERATE");
  }
  else
  {
    Monitor.println("HAZARDOUS");
  }


  Monitor.println("---------------------------------");


  // ---------------------------------------------------
  // ALERT
  // ---------------------------------------------------

  applyAlert(level);
}

Credits

Shankar Chavan
1 project • 1 follower
Final-year Computer Engineering student building Edge AI and IoT solutions for real-world impact.

Comments