AI Real-Time Air Quality Monitoring & Forecasting System using ESP32, IoT, n8n and Agentic AI
Complete project documentation • Hardware design • Circuit schematic • ESP32 firmware • AI forecasting • n8n workflows • Telegram voice alerts • Google Sheets • ThingSpeak dashboard
This project is an end-to-end smart environmental monitoring system that measures air pollution in real time, sends sensor data to the cloud, predicts possible air-quality deterioration, and automatically alerts users through Telegram—including voice notifications—using an ESP32, n8n automation, and an AI agent.
1. Project overview
The system combines five major functions:
-
Sensing: Collect air-quality, temperature, and humidity measurements from connected sensors.
-
IoT monitoring: Transmit readings from the ESP32 to ThingSpeak and Google Sheets.
-
AI forecasting: Analyze recent measurements and estimate whether air quality may deteriorate.
-
Agentic automation: Use n8n to evaluate conditions, coordinate AI analysis, and trigger appropriate actions.
-
Intelligent alerts: Send Telegram text and voice alerts when dangerous or abnormal conditions are detected.
The intended result is a live air-quality monitoring webpage and a connected automation system that works with minimal manual intervention.
Project capabilities
Real-time monitoring
Sensor readings and historical trends
AI forecasting
Predicted trends and risk assessment
n8n automation
Rules, decisions and scheduled workflows
Telegram voice alerts
Automated audio notifications and text
2. System architecture
The overall data flow is:
Air and environmental conditions
Particulate matter, gases, temperature, humidity
Sensor layer
PM2.5/PM10 sensor + optional gas sensor + temperature/humidity sensor
ESP32 microcontroller
Read, validate, timestamp and transmit measurements
Wi-Fi and HTTP / HTTPS
Secure data transmission to cloud services
n8n automation engine
Receive data, evaluate rules, call AI, log results and dispatch alerts
ThingSpeak
Live charts and trends
Google Sheets
Historical records
AI forecasting
Future risk estimate
Telegram
Text and audio alerts
The live webpage can read a backend API or ThingSpeak data; it need not connect directly to the ESP32.
End-to-end operating sequence
-
Sensors sample the air.
-
The ESP32 reads the measurements and checks that the values are valid.
-
The ESP32 transmits the data to the cloud at a configured interval.
-
n8n receives the data and checks for threshold violations, missing readings, and sensor faults.
-
An AI model evaluates trends and forecasts future air-quality risk.
-
n8n stores measurements and analysis results in Google Sheets and, where configured, ThingSpeak.
-
If an alert condition is met, n8n sends a Telegram message and optionally generates and delivers a voice message.
-
The dashboard displays current conditions, historical measurements, and forecast results.
The system should use deterministic safety rules for urgent alerts. The AI agent provides additional interpretation and forecasting rather than being the sole authority on whether a critical alert is sent.
3. Hardware components required
Use a particulate-matter sensor as the primary air-pollution measurement device. A gas sensor alone is not sufficient to measure PM2.5 or PM10.
1. ESP32 DevKit V1
The controller reads sensors, connects to Wi-Fi, and uploads readings to cloud services.
2. PMS5003 particulate-matter sensor
Measures PM1.0, PM2.5 and PM10 estimates. Communicates through UART serial.
3. DHT22 temperature/humidity sensor
Provides environmental context for the air-quality readings and forecasting model.
4. MQ-135 gas sensor (optional)
Provides a gas-sensitive analog signal. Requires warm-up and calibration; do not interpret raw ADC values as accurate ppm measurements.
5. Supporting components
Breadboard or PCB, jumper wires, suitable regulated power supply, and level shifting or voltage-divider components where needed.
Estimated project budget
These are indicative planning estimates in Indian rupees, not live quotations.
|
Component |
Estimated cost |
|---|---|
|
ESP32 development board |
₹400–900 |
|
PMS5003 particulate sensor |
₹1,200–2,500 |
|
DHT22 sensor |
₹150–350 |
|
Optional MQ-135 module |
₹100–250 |
|
Wiring, PCB and power components |
₹300–800 |
|
Estimated total |
₹2,150–4,800 |
Cloud hosting, an AI API, and voice-generation services may add costs depending on usage. A free or self-hosted n8n setup may reduce some expenses.
4. Circuit schematic and wiring
The following schematic uses the ESP32, PMS5003 and DHT22. The MQ-135 is optional.
Pin connection table
Example pin assignment for a classic ESP32 DevKit V1. Confirm the pinout and voltage requirements of your exact sensor modules before powering them.
|
Sensor pin |
ESP32 connection |
Purpose |
|---|---|---|
|
PMS5003 VCC |
Suitable regulated supply, typically 5 V |
Sensor power |
|
PMS5003 GND |
GND |
Common ground |
|
PMS5003 TX |
GPIO 16 (RX2) |
ESP32 receives sensor data |
|
PMS5003 RX |
GPIO 17 (TX2), optional |
ESP32 sends sensor commands |
|
DHT22 VCC |
3.3 V for a compatible module |
Sensor power |
|
DHT22 GND |
GND |
Common ground |
|
DHT22 DATA |
GPIO 4 |
Digital readings |
|
MQ-135 AO, optional |
GPIO 34 through a suitable voltage divider |
Analog reading |
Important electrical precautions
-
Check the PMS5003 model's supply requirements and ensure its UART signal voltage is safe for the ESP32.
-
The ESP32 GPIO inputs are not 5 V tolerant. Never connect a 5 V analog output directly to GPIO 34.
-
A bare DHT22 generally needs a pull-up resistor on its data line; many breakout modules already include one.
-
MQ-135 modules can have analog outputs approaching their supply voltage. Use a properly designed divider and check the maximum voltage under all conditions.
-
Use a stable supply and common ground. Do not power a sensor heater or other high-current load from an ESP32 GPIO.
5. Software and cloud services
Install or create these components before programming the device.
|
Software/service |
Purpose |
|---|---|
|
Arduino IDE |
ESP32 firmware development |
|
ESP32 Arduino core |
Board support and Wi-Fi |
|
Adafruit DHT sensor library |
Temperature/humidity readings |
|
ThingSpeak |
Time-series charts and data storage |
|
n8n |
Workflow automation and AI orchestration |
|
Google Sheets |
Historical log and reports |
|
Telegram Bot API |
Text and audio notifications |
|
AI model/API |
Forecast explanation and risk assessment |
|
Web dashboard |
Live readings, trends, alerts and predictions |
References: ESP32 Wi-Fi documentation , ThingSpeak write API , n8n documentation , n8n Telegram integration , and n8n Google Sheets integration .
6. ESP32 firmware — complete starter implementation
This firmware is designed to:
-
Connect to Wi-Fi.
-
Read PM1.0, PM2.5 and PM10 from the PMS5003.
-
Read temperature and humidity from the DHT22.
-
Upload data to ThingSpeak.
-
Send a JSON payload to an n8n webhook.
-
Retry network connections and report basic errors through the serial monitor.
Step 1: Configure the Arduino IDE
-
Install the ESP32 board package using Boards Manager.
-
Select the correct ESP32 board and serial port.
-
Install the
DHT sensor libraryby Adafruit and itsAdafruit Unified Sensordependency. -
Connect the PMS5003 TX to ESP32 GPIO 16.
-
Set the serial monitor to 115200 baud.
Step 2: Create a ThingSpeak channel
Create a channel with the following numeric fields:
-
Field 1: PM1.0 in µg/m³
-
Field 2: PM2.5 in µg/m³
-
Field 3: PM10 in µg/m³
-
Field 4: Temperature in °C
-
Field 5: Relative humidity in %
-
Field 6: Estimated AQI category code, if you implement a defined AQI calculation
Copy the channel's Write API Key. Keep it private.
Step 3: Create an n8n webhook
In n8n, create a workflow with a Webhook node configured as follows:
-
HTTP method:
POST -
Path:
air-quality -
Response mode: respond immediately or use a Respond to Webhook node
-
Expected body: JSON
Activate the workflow and copy its production webhook URL. For a deployed system, use an HTTPS URL.
Step 4: Upload this firmware
Replace the placeholder Wi-Fi credentials, ThingSpeak key and webhook URL before uploading.
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <DHT.h>
// ---------- USER CONFIGURATION ----------
const char* WIFI_SSID = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* THINGSPEAK_WRITE_KEY = "YOUR_WRITE_API_KEY";
// Use your real HTTPS n8n production webhook URL.
const char* N8N_WEBHOOK_URL =
"https://YOUR_N8N_HOST/webhook/air-quality";
// ---------- HARDWARE ----------
#define PMS_RX 16
#define PMS_TX 17
#define DHT_PIN 4
#define DHT_TYPE DHT22
HardwareSerial pmsSerial(2);
DHT dht(DHT_PIN, DHT_TYPE);
// ---------- DATA STRUCTURE ----------
struct PMData {
uint16_t pm1;
uint16_t pm25;
uint16_t pm10;
};
unsigned long lastSample = 0;
const unsigned long SAMPLE_INTERVAL = 20000;
// Read one valid 32-byte PMS5003 frame.
// The atmospheric/environmental PM values are used.
bool readPMS(PMData &out) {
static uint8_t frame[32];
static size_t pos = 0;
while (pmsSerial.available()) {
uint8_t b = pmsSerial.read();
if (pos == 0 && b != 0x42) continue;
if (pos == 1 && b != 0x4D) {
pos = (b == 0x42) ? 1 : 0;
continue;
}
frame[pos++] = b;
if (pos == 32) {
pos = 0;
uint16_t length =
(uint16_t(frame[2]) << 8) | frame[3];
uint16_t sum = 0;
for (int i = 0; i < 30; i++) {
sum += frame[i];
}
uint16_t received =
(uint16_t(frame[30]) << 8) | frame[31];
if (length != 28 || sum != received) {
return false;
}
out.pm1 =
(uint16_t(frame[10]) << 8) | frame[11];
out.pm25 =
(uint16_t(frame[12]) << 8) | frame[13];
out.pm10 =
(uint16_t(frame[14]) << 8) | frame[15];
return true;
}
}
return false;
}
bool ensureWiFi() {
if (WiFi.status() == WL_CONNECTED) return true;
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED &&
millis() - start < 15000) {
delay(250);
}
return WiFi.status() == WL_CONNECTED;
}
// Prototype helper: HTTPS with certificate verification disabled.
// Replace with CA certificate validation for deployment.
int httpsPostJson(const char* url, const String& body) {
WiFiClientSecure client;
client.setInsecure(); // Prototype only; not production-secure
HTTPClient http;
if (!http.begin(client, url)) return -1;
http.setTimeout(10000);
http.addHeader("Content-Type", "application/json");
int code = http.POST(body);
http.end();
return code;
}
bool uploadThingSpeak(
const PMData &pm, float temp, float humidity
) {
if (!ensureWiFi()) return false;
String url = "https://api.thingspeak.com/update?api_key=";
url += THINGSPEAK_WRITE_KEY;
url += "&field1=" + String(pm.pm1);
url += "&field2=" + String(pm.pm25);
url += "&field3=" + String(pm.pm10);
url += "&field4=" + String(temp, 1);
url += "&field5=" + String(humidity, 1);
WiFiClientSecure client;
client.setInsecure(); // Prototype only
HTTPClient http;
if (!http.begin(client, url)) return false;
http.setTimeout(10000);
int code = http.GET();
String response = http.getString();
http.end();
// ThingSpeak normally returns a nonzero entry ID.
response.trim();
return code == HTTP_CODE_OK &&
response.length() > 0 &&
response != "0";
}
void sendToN8N(
const PMData &pm, float temp, float humidity
) {
String json = "{";
json += "\"device_id\":\"esp32-air-01\",";
json += "\"pm1\":" + String(pm.pm1) + ",";
json += "\"pm25\":" + String(pm.pm25) + ",";
json += "\"pm10\":" + String(pm.pm10) + ",";
json += "\"temperature_c\":" + String(temp, 1) + ",";
json += "\"humidity_pct\":" + String(humidity, 1);
json += "}";
int code = httpsPostJson(N8N_WEBHOOK_URL, json);
Serial.print("n8n HTTP status: ");
Serial.println(code);
}
void setup() {
Serial.begin(115200);
pmsSerial.begin(
9600, SERIAL_8N1, PMS_RX, PMS_TX
);
dht.begin();
WiFi.mode(WIFI_STA);
ensureWiFi();
Serial.println("Air quality monitor started.");
}
void loop() {
if (millis() - lastSample < SAMPLE_INTERVAL) {
delay(50);
return;
}
lastSample = millis();
PMData pm;
if (!readPMS(pm)) {
Serial.println(
"No valid PMS5003 frame. Check wiring and sensor."
);
return;
}
float temp = dht.readTemperature();
float humidity = dht.readHumidity();
if (isnan(temp) || isnan(humidity)) {
Serial.println("DHT22 read failed; skipping upload.");
return;
}
Serial.printf(
"PM1=%u, PM2.5=%u, PM10=%u, "
"Temp=%.1f C, RH=%.1f%%\n",
pm.pm1, pm.pm25, pm.pm10, temp, humidity
);
if (!ensureWiFi()) {
Serial.println("Wi-Fi unavailable.");
return;
}
bool tsOK = uploadThingSpeak(pm, temp, humidity);
Serial.println(tsOK ?
"ThingSpeak upload OK" :
"ThingSpeak upload failed");
sendToN8N(pm, temp, humidity);
}
Firmware notes
-
The firmware sends data every 20 seconds. Check your ThingSpeak account's write-rate restrictions and increase the interval if necessary.
-
The PMS5003 must have time to initialize and sample the air. In a production version, maintain a rolling sample buffer and use timeouts rather than depending on a fresh complete sensor frame arriving at the exact polling instant.
-
The
setInsecure()calls disable TLS certificate verification. They are shown only to simplify a bench prototype. Use certificate validation before deployment. -
The example intentionally does not publish a fabricated AQI number. Add a jurisdiction-specific AQI calculation before showing an AQI value.
-
If Wi-Fi fails, this basic implementation does not maintain a persistent offline queue. That can be added using flash storage or an SD card.
7. n8n automation workflow
n8n is the automation layer. It receives the sensor readings, stores them, checks thresholds, calls the AI model, and routes the correct alert to Telegram.
Workflow A — real-time sensor processing
flowchart TD
A[ESP32 POST sensor JSON] --> B[Webhook Trigger]
B --> C[Validate required fields]
C --> D{Valid payload?}
D -- No --> E[Log invalid reading]
D -- Yes --> F[Normalize units and timestamp]
F --> G[Google Sheets: Append Row]
F --> H[Evaluate PM thresholds]
H --> I{Alert condition?}
I -- No --> J[Store normal status]
I -- Yes --> K[Create alert event]
K --> L[Telegram text notification]
K --> M[Voice message workflow]
F --> N[Collect recent history]
N --> O[AI forecast and explanation]
O --> P[Store forecast result]
P --> Q[Update dashboard data]
Step-by-step node configuration
Node 1 — Webhook
Set method to POST and path to air-quality. The input JSON should contain device_id, pm1, pm25, pm10, temperature_c and humidity_pct.
Use the production URL only after activating the workflow. The ESP32 firmware above sends this payload.
Node 2 — Validate and normalize
Use an Edit Fields (Set) node or Code node to validate numeric values, attach a timestamp, and reject malformed payloads. Do not silently replace missing sensor values with zero.
Node 3 — Google Sheets
Use the Google Sheets node with the Append Row operation. Map each field to the corresponding spreadsheet column.
Node 4 — IF / Switch
Compare the current PM2.5 reading against configured thresholds, or compare the reading against an applicable local AQI standard. Route normal and alert conditions separately.
Node 5 — AI forecast
Retrieve recent historical measurements, send the structured time series to a forecasting service or AI model, validate its output, and save the result. Use a Code node for mathematical forecasting if you want a reproducible baseline.
Node 6 — Telegram
Configure a Telegram bot credential and use Send Message for text alerts. Use Send Audio or Send Voice for audio delivery, depending on the generated file format and the operation supported by your n8n version.
Example data-validation Code node
Add a Code node after the Webhook node. This example expects the webhook body to be in $json.body and stops processing if any required measurement is invalid.
const input = $json.body ?? $json;
const fields = [
"pm1",
"pm25",
"pm10",
"temperature_c",
"humidity_pct"
];
for (const field of fields) {
if (
input[field] === undefined ||
input[field] === null ||
!Number.isFinite(Number(input[field]))
) {
throw new Error(`Invalid or missing field: ${field}`);
}
}
const pm1 = Number(input.pm1);
const pm25 = Number(input.pm25);
const pm10 = Number(input.pm10);
const temp = Number(input.temperature_c);
const humidity = Number(input.humidity_pct);
if (
pm1 < 0 || pm25 < 0 || pm10 < 0 ||
humidity < 0 || humidity > 100 ||
temp < -40 || temp > 85
) {
throw new Error("Measurement outside configured limits");
}
return [{
json: {
device_id: String(input.device_id ?? "unknown"),
timestamp: new Date().toISOString(),
pm1,
pm25,
pm10,
temperature_c: temp,
humidity_pct: humidity
}
}];
The limits above are data-validation limits, not health thresholds. Real deployments should also reject stale data, impossible sensor combinations, duplicate events, and persistent sensor faults.
8. AI agent and air-quality forecasting
A major project requirement is forecasting, not merely displaying current measurements. To achieve that, maintain a history of readings and use a forecasting method that has been evaluated against actual future measurements.
Three forecasting levels
Level 1 — Trend-based baseline
Level 2 — AI-assisted interpretation
Level 3 — Trained predictive model
Forecasting flowchart
flowchart TD
A[Historical sensor data] --> B[Remove invalid readings]
B --> C[Resample into fixed time intervals]
C --> D[Build time-series features]
D --> E[Forecast PM2.5 and PM10]
E --> F[Calculate prediction uncertainty]
F --> G[Compare with configured thresholds]
G --> H[AI generates plain-language explanation]
H --> I[Store prediction and model version]
I --> J[Dashboard and Telegram notification]
J --> K[Compare forecast with later observation]
K --> L[Calculate model error and improve model]
Example trend-based forecasting code
This is a baseline forecast, not a trained AI model. It predicts PM2.5 using the average change between successive readings. It should be replaced or benchmarked against a proper time-series model before making operational claims.
function forecastPM25(values, horizonSteps = 3) {
if (
values.length < 4 ||
!values.every(v => Number.isFinite(v) && v >= 0)
) {
throw new Error("At least four valid PM2.5 values required");
}
const last = values[values.length - 1];
const recent = values.slice(-6);
const differences = [];
for (let i = 1; i < recent.length; i++) {
differences.push(recent[i] - recent[i - 1]);
}
const meanChange =
differences.reduce((a, b) => a + b, 0) /
differences.length;
const predicted = [];
let current = last;
for (let i = 0; i < horizonSteps; i++) {
current = Math.max(0, current + meanChange);
predicted.push(Number(current.toFixed(2)));
}
return {
latest_pm25: last,
mean_change_per_step: Number(meanChange.toFixed(2)),
horizon_steps: horizonSteps,
forecast_pm25: predicted,
method: "recent_mean_difference_baseline"
};
}
// Example only: replace with actual historical data.
const history = [18, 20, 21, 24, 27, 29];
return [{ json: forecastPM25(history, 3) }];
If readings are sampled every 20 seconds, three steps correspond to only one minute. For a meaningful 30-minute or 1-hour forecast, aggregate measurements into suitable time intervals and collect sufficient historical data.
Agentic AI decision logic
The agent should have defined responsibilities rather than unrestricted control.
AI agent tools
-
Get latest readings: retrieve the current sensor measurements.
-
Get history: retrieve the latest 30–100 valid time-series samples.
-
Forecast pollution: invoke the baseline or trained forecasting service.
-
Assess risk: compare the forecast against configured policy thresholds.
-
Generate alert text: produce a concise explanation with values and uncertainty.
-
Record the decision: save the model version, forecast horizon and action taken.
Example system instruction for the AI node:
You are an air-quality monitoring assistant.
Use only the sensor measurements, historical data,
and forecasts provided to you.
1. Summarize current PM2.5 and PM10 measurements.
2. Identify whether recent readings are rising, stable,
or falling.
3. Explain the forecast horizon and uncertainty.
4. Never invent missing measurements or claim a forecast
is a confirmed observation.
5. Do not calculate or invent a regulatory AQI category.
6. Return structured JSON with:
status, trend, forecast_summary, uncertainty,
recommended_precautions, and reason.
7. Safety-critical alerts are controlled by deterministic
workflow rules, not by free-form AI decisions.
For an n8n AI Agent node, connect a chat-model node and the appropriate tools supported by your n8n version. If the forecasting tool returns numeric results, pass those results to the agent rather than asking the language model to guess the numbers.
9. AQI calculation and alert thresholds
PM2.5 concentration is not itself an AQI number. AQI depends on the relevant country's calculation method, pollutant breakpoints, averaging period, and rounding rules.
For an India-focused project, select and implement the applicable CPCB National Air Quality Index methodology. Do not label arbitrary PM2.5 thresholds as official Indian AQI categories.
Use two independent paths:
-
Measured-condition alerts: triggered from actual sensor measurements and the applicable rules.
-
Forecast alerts: triggered from predicted future conditions, clearly labeled as predictions.
For a prototype, you can use configurable engineering thresholds to test the automation. Mark them as test thresholds until you have implemented and verified the correct local standard.
A useful notification policy includes a persistence window, hysteresis, cooldown period, and sensor-fault detection. For example, require multiple consecutive valid samples before sending a non-emergency alert, but do not delay a required urgent alert because the AI service is unavailable.
10. Telegram text and voice notification system
This feature makes the project more interactive: when pollution rises or a forecast indicates elevated risk, the system can send a text message and a spoken audio alert.
Telegram setup
-
Open Telegram and search for
@BotFather. -
Send
/newbotand follow the instructions. -
Save the bot token securely.
-
Open your new bot and send it a message.
-
Obtain the chat ID using the Telegram Bot API or an n8n Telegram Trigger node.
-
In n8n, create Telegram credentials and configure the Send Message operation.
Never expose the bot token in frontend JavaScript, a public repository, or a shared spreadsheet.
Voice-alert workflow
flowchart TD
A[Alert event from n8n] --> B[Build alert text]
B --> C[Text-to-Speech service]
C --> D[Generate audio file]
D --> E{Audio generated?}
E -- Yes --> F[Telegram Send Voice or Audio]
E -- No --> G[Send text-only fallback]
F --> H[Log notification result]
G --> H
The text-to-speech service can be a hosted provider or a self-hosted TTS engine. Configure its output format to match the Telegram operation. A voice message typically uses an appropriate OGG/Opus format; an audio file can use other supported formats.
Example alert message
Air Quality Monitor Bot
AIR QUALITY WARNING
PM2.5: 86 µg/m³
PM10: 124 µg/m³
Temperature: 32.1 °C
Humidity: 61%
Trend: Increasing over recent samples.
Forecast: Possible continued deterioration. Forecast confidence must be assessed using the deployed model.
Illustrative sample values, not live measurements.
Example spoken message:
Air quality warning. The latest PM2.5 reading is 86 micrograms per cubic meter. Recent measurements show an increasing trend. Please check the local air-quality advisory and consider appropriate precautions.
The voice message should distinguish measured readings from predicted values. If the TTS service fails, n8n must still send the text alert.
11. Google Sheets integration
Create a spreadsheet called Air_Quality_Monitoring.
Use the following column structure:
|
Column |
Field |
|---|---|
|
A |
Timestamp |
|
B |
Device ID |
|
C |
PM1.0 |
|
D |
PM2.5 |
|
E |
PM10 |
|
F |
Temperature °C |
|
G |
Humidity % |
|
H |
Measured AQI, if properly calculated |
|
I |
Forecast PM2.5 |
|
J |
Forecast horizon |
|
K |
Alert status |
|
L |
Alert action |
|
M |
Model version |
In n8n:
-
Add a Google Sheets node after data validation.
-
Authenticate using Google OAuth2 credentials.
-
Select the spreadsheet and worksheet.
-
Choose Append Row.
-
Map the incoming values to the matching columns.
-
Add another Append Row operation after forecasting to record the prediction and model metadata.
-
Optionally create a separate
Alert_Logworksheet to track notifications and delivery failures.
Avoid writing an entire row repeatedly for the same device and timestamp. Add a unique event identifier if you need reliable deduplication.
12. ThingSpeak IoT cloud dashboard
ThingSpeak provides time-series storage and charts. The ESP32 firmware sends PM1.0, PM2.5, PM10, temperature and humidity to the channel.
Setup instructions
-
Create a ThingSpeak account and channel.
-
Enable the required fields.
-
Copy the channel ID and Write API Key.
-
Configure the firmware with the Write API Key.
-
Upload the code and confirm that new entries appear.
-
Create charts for PM2.5, PM10, temperature and humidity.
-
Keep the channel private unless public access is intentional.
-
Use a separate read key or controlled backend for any private dashboard integration.
Documentation: ThingSpeak channel data and charts .
Dashboard design
The web application should display:
Current PM2.5
Live value
µg/m³
PM10 trend
Time series
Historical readings
AI forecast
Future estimate
Show horizon and uncertainty
Alert status
Normal / Warning
Last notification event
13. Live IoT webpage implementation
A simple first version can use HTML, CSS and JavaScript. The following page is a frontend prototype with simulated readings. It does not connect to a real sensor until you replace the demo data source with a backend endpoint or ThingSpeak's read API.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>AI Air Quality Monitor</title>
<style>
body {
font-family: system-ui, sans-serif;
max-width: 950px;
margin: 30px auto;
padding: 0 16px;
background: #f4f7fb;
color: #182230;
}
h1 { color: #155e75; }
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 14px;
}
.card {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 10px #0000000c;
}
.value { font-size: 30px; font-weight: 700; }
.muted { color: #64748b; }
</style>
</head>
<body>
<h1>AI Air Quality Monitoring</h1>
<p class="muted" id="updated">Demo mode — not live sensor data</p>
<div class="grid">
<div class="card">
<div>PM2.5 (µg/m³)</div>
<div class="value" id="pm25">--</div>
</div>
<div class="card">
<div>PM10 (µg/m³)</div>
<div class="value" id="pm10">--</div>
</div>
<div class="card">
<div>Temperature (°C)</div>
<div class="value" id="temp">--</div>
</div>
<div class="card">
<div>Humidity (%)</div>
<div class="value" id="humidity">--</div>
</div>
</div>
<section class="card" style="margin-top:16px">
<h2>System status</h2>
<p id="status">Waiting for data</p>
<p id="forecast">Forecast unavailable</p>
</section>
<script>
// DEMO ONLY. Replace with a real backend request.
const demo = {
pm25: 24,
pm10: 41,
temp: 30.5,
humidity: 58
};
function render(data) {
document.getElementById("pm25").textContent = data.pm25;
document.getElementById("pm10").textContent = data.pm10;
document.getElementById("temp").textContent = data.temp;
document.getElementById("humidity").textContent =
data.humidity;
document.getElementById("status").textContent =
"Demo data — AQI category not calculated";
document.getElementById("updated").textContent =
"Updated: " + new Date().toLocaleString();
document.getElementById("forecast").textContent =
"No trained forecast model connected";
}
render(demo);
// Production pattern:
// fetch("/api/latest")
// .then(r => {
// if (!r.ok) throw new Error("API request failed");
// return r.json();
// })
// .then(render)
// .catch(() => {
// document.getElementById("status").textContent =
// "Unable to retrieve live sensor data";
// });
</script>
</body>
</html>
Connecting the webpage to real data
For a production implementation, create a backend endpoint such as /api/latest that reads the most recent sensor record from ThingSpeak or a database. The webpage calls that endpoint periodically.
Recommended production architecture:
-
ESP32 → ThingSpeak and/or n8n webhook.
-
n8n → historical database and Google Sheets.
-
Forecast service → prediction results.
-
Web backend → latest readings, forecasts and alerts.
-
Web frontend → charts, status cards and historical trends.
Do not place private API keys in the webpage's JavaScript. If the ThingSpeak channel is private, use a backend to read it and protect the credentials.
14. Complete workflow map
This is the final combined project architecture.
flowchart TB
subgraph DEVICE["Hardware layer"]
A[PMS5003]
B[DHT22]
C[ESP32]
A --> C
B --> C
end
subgraph CLOUD["Cloud and automation"]
D[HTTPS telemetry]
E[n8n Webhook]
F[Validation and rules]
G[Google Sheets]
H[ThingSpeak]
I[Forecast model]
J[AI interpretation]
K[Telegram text]
L[Text to speech]
M[Telegram voice]
end
subgraph UI["User interface"]
N[Live webpage]
O[Historical charts]
P[Forecast and alert panel]
end
C --> D
D --> E
C --> H
E --> F
F --> G
F --> I
I --> J
F --> K
F --> L
L --> M
H --> N
G --> O
I --> P
J --> P
K --> P
15. Testing and validation plan
Do not consider the project complete until each part has been tested independently.
Project test checklist
0 of 12
Forecast evaluation
Use chronological train/test separation rather than randomly mixing time-series records. Record at least these metrics:
-
MAE: mean absolute error of PM2.5 predictions.
-
RMSE: root mean squared error.
-
Forecast bias: whether the model systematically overpredicts or underpredicts pollution.
-
Alert performance: false alarms, missed events, and time between an event and its notification.
A low-cost sensor is useful for educational and indicative monitoring, but it should not automatically be treated as a regulatory-grade instrument. Compare it with a suitable reference monitor and follow the sensor manufacturer's operating requirements. The US EPA explains the importance of evaluating low-cost air sensors against reference measurements.
16. Security, reliability and limitations
For a deployment beyond a classroom prototype:
-
Use HTTPS with certificate verification.
-
Protect API keys and bot credentials using environment variables or a secrets manager.
-
Authenticate the n8n webhook, and validate the device identity.
-
Add a persistent offline queue and retry mechanism.
-
Store a timestamp and device ID with every observation.
-
Detect sensor disconnection and stale readings.
-
Add alert cooldowns and event deduplication.
-
Keep urgent threshold-based alerts independent of the AI API.
-
Back up n8n workflows and historical data.
-
Show a visible sensor-data timestamp and forecast uncertainty on the webpage.
Also remember that temperature, humidity and particulate concentration alone may not be sufficient to forecast outdoor air quality accurately. Weather, local emissions, traffic, seasonal effects and nearby sources can matter considerably.
17. Final project deliverables
The finished project should contain these deliverables:
|
Deliverable |
Contents |
|---|---|
|
Hardware prototype |
ESP32, PMS5003, DHT22 and optional gas sensor |
|
Circuit documentation |
Pin map, wiring diagram and electrical precautions |
|
Firmware |
Wi-Fi, sensor parsing, cloud uploads and error handling |
|
n8n workflows |
Ingestion, validation, logging, forecasting and alerts |
|
AI forecasting |
Baseline model, trained model if available, and evaluation results |
|
Telegram bot |
Text alerts and voice notifications |
|
Cloud storage |
ThingSpeak channel and Google Sheets log |
|
Web application |
Live values, historical charts and forecast panel |
|
Final report |
Architecture, implementation, testing and limitations |
Suggested report title
“AI-Powered Real-Time Air Quality Monitoring and Forecasting System Using ESP32, Agentic AI, n8n Automation, ThingSpeak, Google Sheets and Telegram Voice Notifications.”
This is a practical design for an academic or prototype project. The firmware and dashboard snippets provide a starting implementation; the full production system still requires configured credentials, a working n8n instance, a text-to-speech service, and a tested forecasting pipeline.
## Project Summary
AI-Powered Real-Time Air Quality Monitoring and Forecasting System Using ESP32, IoT, Agentic AI, n8n Automation, Telegram Voice Alerts, Google Sheets and ThingSpeak
This project develops an intelligent IoT system that monitors air quality in real time, forecasts potential pollution trends, and automatically notifies users when air quality deteriorates.
The ESP32 microcontroller collects environmental measurements using a PMS5003 particulate-matter sensor and a DHT22 temperature and humidity sensor. It transmits the data through Wi-Fi to ThingSpeak for cloud monitoring and to n8n for automated processing.
The n8n workflow validates sensor readings, stores historical data in Google Sheets, evaluates alert conditions, and connects to an AI model for forecasting and natural-language explanations. When configured thresholds are exceeded, the system sends Telegram text notifications and voice alerts using a text-to-speech service.
A web dashboard displays current sensor readings, historical trends, forecasts, and alert status.
### Main components
- Hardware: ESP32, PMS5003, DHT22, optional MQ-135 gas sensor.
- IoT cloud: ThingSpeak for sensor data visualization.
- Automation: n8n workflows for data processing and notifications.
- Artificial intelligence: Trend analysis, pollution forecasting and risk explanations.
- Communication: Telegram text and voice alerts.
- Data storage: Google Sheets for historical records.
- Web application: Real-time monitoring dashboard.
### System workflow
mermaid
```
flowchart TD
A[Air Quality Sensors] --> B[ESP32]
B --> C[Wi-Fi and Cloud Upload]
C --> D[ThingSpeak Dashboard]
C --> E[n8n Automation]
E --> F[Google Sheets]
E --> G[AI Forecasting]
G --> H[Risk Assessment]
H --> I[Telegram Text Alerts]
H --> J[Text-to-Speech]
J --> K[Telegram Voice Alerts]
D --> L[IoT Web Dashboard]
G --> L
```
### Expected outcomes
- Continuous air-quality data collection.
- Remote monitoring through a cloud dashboard.
- Early warnings of potentially deteriorating air quality.
- Automated text and voice notifications.
- Historical data analysis and forecast evaluation.
- Reduced need for manual monitoring.
Conclusion: The project integrates IoT hardware, cloud services, AI forecasting, and workflow automation into a unified environmental monitoring solution. It is suitable for an academic project, smart-city prototype, or environmental monitoring demonstration. Accurate forecasting and regulatory AQI reporting require validated models, appropriate sensor calibration, and the applicable official calculation methodology.

No comments:
Post a Comment