#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// -------- WiFi --------
const char* ssid = "Wokwi-GUEST";
const char* password = "";
String apiKey = "KKFB3R1UY0BY13S7";
const char* server = "http://api.thingspeak.com/update";
// -------- LCD --------
LiquidCrystal_I2C lcd(0x27, 16, 2);
// -------- Pins --------
#define GREEN_LED 25
#define YELLOW_LED 26
#define RED_LED 27
#define BUTTON_PIN 13
// -------- AQI --------
float calcAQI(float Cp, float Clow, float Chigh, float Ilow, float Ihigh) {
return ((Ihigh - Ilow) / (Chigh - Clow)) * (Cp - Clow) + Ilow;
}
float AQI_PM25(float pm) {
if (pm <= 30) return calcAQI(pm, 0, 30, 0, 50);
if (pm <= 60) return calcAQI(pm, 30, 60, 50, 100);
if (pm <= 90) return calcAQI(pm, 60, 90, 100, 200);
if (pm <= 120) return calcAQI(pm, 90, 120, 200, 300);
if (pm <= 250) return calcAQI(pm, 120, 250, 300, 400);
return calcAQI(pm, 250, 350, 400, 500);
}
// -------- VARIABLES --------
float pm25 = 150;
float CO = 1.0;
float O3 = 90;
float temp = 25;
float hum = 60;
float wind = 2.0;
// inertia buffers
float pm25_mem = 150;
float CO_mem = 1.0;
float O3_mem = 90;
// mitigation
bool mitigation = false;
unsigned long mitigationStart = 0;
const int mitigationDuration = 60;
bool lastButton = HIGH;
// -------- SETUP --------
void setup() {
Serial.begin(115200);
pinMode(GREEN_LED, OUTPUT);
pinMode(YELLOW_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
lcd.init();
lcd.backlight();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(300);
}
// -------- LOOP --------
void loop() {
unsigned long t = millis() / 1000;
bool isNight = (t % 7200 < 3600);
// -------- BUTTON --------
bool currentButton = digitalRead(BUTTON_PIN);
if (lastButton == HIGH && currentButton == LOW) {
mitigation = true;
mitigationStart = millis() / 1000;
}
lastButton = currentButton;
// -------- DAY/NIGHT BASELINES --------
float base_pm25 = isNight ? 170 : 110;
float base_CO = isNight ? 1.4 : 0.8;
float base_O3 = isNight ? 60 : 120;
float base_temp = isNight ? 18 : 32;
float base_hum = isNight ? 75 : 50;
float base_wind = isNight ? 1.2 : 3.0;
// -------- SLOW DRIFT --------
pm25 += (base_pm25 - pm25) * 0.003;
CO += (base_CO - CO) * 0.003;
O3 += (base_O3 - O3) * 0.003;
temp += (base_temp - temp) * 0.002;
hum += (base_hum - hum) * 0.002;
wind += (base_wind - wind) * 0.002;
// -------- SMALL FLUCTUATIONS --------
pm25 += random(-5, 6); // gives ±5 variation
CO += random(-2, 3) * 0.05;
O3 += random(-5, 6);
temp += random(-2, 3) * 0.2;
hum += random(-3, 4);
wind += random(-2, 3) * 0.1;
// -------- MITIGATION --------
if (mitigation) {
unsigned long now = millis() / 1000;
if (now - mitigationStart >= mitigationDuration) {
mitigation = false;
} else {
pm25 += (100 - pm25) * 0.02;
CO += (0.7 - CO) * 0.02;
O3 += (80 - O3) * 0.02;
wind += (3.5 - wind) * 0.02;
}
}
// -------- INERTIA --------
pm25_mem = pm25_mem * 0.9 + pm25 * 0.1;
CO_mem = CO_mem * 0.9 + CO * 0.1;
O3_mem = O3_mem * 0.9 + O3 * 0.1;
pm25 = pm25_mem;
CO = CO_mem;
O3 = O3_mem;
// -------- LIMITS --------
pm25 = constrain(pm25, 50, 300);
CO = constrain(CO, 0.5, 2.5);
O3 = constrain(O3, 40, 200);
temp = constrain(temp, 10, 40);
hum = constrain(hum, 20, 95);
wind = constrain(wind, 0.5, 5);
float PM10 = pm25 * 1.4;
float AQI = AQI_PM25(pm25);
// -------- ALERT --------
int alert = 0;
String text = "NORMAL";
if (AQI > 200) {
alert = 2;
text = "HOTSPOT";
} else if (AQI > 100) {
alert = 1;
text = "WARNING";
}
digitalWrite(GREEN_LED, alert == 0);
digitalWrite(YELLOW_LED, alert == 1);
digitalWrite(RED_LED, alert == 2);
// -------- LCD --------
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("AQI:");
lcd.print((int)AQI);
lcd.setCursor(0, 1);
lcd.print(text);
// -------- SERIAL (IMPORTANT FOR YOU) --------
Serial.print(isNight ? "NIGHT | " : "DAY | ");
Serial.print("AQI: "); Serial.print(AQI);
Serial.print(" | PM2.5: "); Serial.print(pm25);
Serial.print(" | CO: "); Serial.print(CO);
Serial.print(" | O3: "); Serial.print(O3);
Serial.print(" | T: "); Serial.print(temp);
Serial.print(" | H: "); Serial.print(hum);
Serial.print(" | W: "); Serial.println(wind);
// -------- THINGSPEAK --------
static unsigned long lastUpload = 0;
if (WiFi.status() == WL_CONNECTED && millis() - lastUpload > 15000) {
lastUpload = millis();
HTTPClient http;
String url = server;
url += "?api_key=" + apiKey;
url += "&field1=" + String(pm25);
url += "&field2=" + String(CO);
url += "&field3=" + String(O3);
url += "&field4=" + String(temp);
url += "&field5=" + String(AQI);
url += "&field6=" + String(hum);
url += "&field7=" + String(wind);
url += "&field8=" + String(alert);
http.begin(url);
http.GET();
http.end();
}
delay(1000);
}PM2.5
WIND SPEED
CO
O
3