IIoT-Based Smart Industrial Monitoring and AI-Powered Alert System
Complete project documentation using ESP32, industrial sensors, n8n automation, an AI agent, Telegram voice alerts, Gmail, Google Sheets, and a live web dashboard.
1. Project overview
The proposed system is an Internet of Things (IoT) and Industrial Internet of Things (IIoT) solution that continuously monitors environmental and equipment conditions using an ESP32 microcontroller. The ESP32 collects readings from connected sensors, evaluates safety thresholds, and sends the data to a cloud automation workflow.
The n8n workflow processes the sensor data, detects abnormal conditions, uses an AI agent to generate understandable alert messages, and distributes notifications through Telegram, Gmail, Google Sheets, and a web dashboard. A text-to-speech service can convert critical alert messages into audio files that are delivered through Telegram.
The project combines real-time monitoring, automated hazard detection, cloud data logging, remote supervision, and AI-assisted communication in one system.
1. ESP32 sensor acquisition
Reads temperature, smoke/gas, light intensity, flame detection, and equipment vibration data. It can also perform local threshold checks.
2. Industrial condition monitoring
Measures changes in the surrounding environment and machine vibration to identify potentially unsafe conditions.
3. n8n automation and AI agent
Receives sensor data, validates readings, applies event-routing rules, and generates clear, context-aware alert descriptions.
4. Notifications and cloud logging
Sends Telegram text and voice alerts, emails Gmail recipients, records readings in Google Sheets, and updates a live dashboard.
Project objectives
-
Monitor industrial environmental conditions continuously.
-
Detect temperature, smoke/gas, flame, and vibration abnormalities.
-
Identify low-light or abnormal illumination conditions.
-
Notify operators remotely when configurable thresholds are exceeded.
-
Generate AI-assisted explanations of detected events.
-
Maintain timestamped sensor readings and event history.
-
Provide a web interface for monitoring current values and historical trends.
-
Reduce the delay between hazard detection and operator notification.
Important engineering note: This is a prototype and supervisory monitoring system, not a certified industrial fire alarm or safety instrumented system. Use independently certified detectors and hardwired protective circuits for actual industrial safety functions. AI and cloud automation must never be the only means of triggering emergency protection.
2. Complete list of project features
|
Feature |
Implementation |
|---|---|
|
Temperature monitoring |
Digital temperature sensor, such as DS18B20 |
|
Smoke and gas monitoring |
MQ-series sensor for prototype gas/smoke indication |
|
Light intensity |
LDR voltage-divider circuit |
|
Fire detection |
Digital flame sensor module, supplemented by a certified detector in real installations |
|
Equipment vibration |
SW-420 for simple vibration events or an accelerometer for quantitative measurements |
|
ESP32 connectivity |
Wi-Fi and HTTPS/HTTP requests |
|
Threshold detection |
ESP32 local rules and n8n event rules |
|
AI-generated alerts |
AI agent with structured sensor context |
|
Telegram text alerts |
Telegram Bot API |
|
Telegram voice alerts |
Text-to-speech service followed by Telegram audio delivery |
|
Gmail notifications |
Gmail integration in n8n |
|
Google Sheets logging |
Append timestamped readings and event records |
|
ThingSpeak integration |
Optional cloud time-series charts and channel logging |
|
Web dashboard |
ESP32-hosted page on the local network or a cloud-hosted dashboard |
|
Automated event routing |
n8n conditional branches |
|
Historical analysis |
Timestamped logs and charts |
|
Remote monitoring |
Dashboard and cloud notifications over the internet |
3. System architecture
The system has five main layers:
-
Sensing layer: sensors collect temperature, gas/smoke, illumination, flame, and vibration data.
-
Edge processing layer: the ESP32 reads sensors, checks basic safety thresholds, and sends JSON data.
-
Automation layer: n8n receives data, validates it, classifies events, and routes them to appropriate services.
-
AI and notification layer: an AI agent prepares alert explanations; Telegram, Gmail, and text-to-speech services deliver notifications.
-
Storage and visualization layer: Google Sheets, ThingSpeak, and the web dashboard display or retain measurements.
Overall system block diagram
Industrial Environment / Machine
Temperature · Smoke/Gas · LDR · Flame · Vibration
ESP32 Microcontroller
Sensor sampling · Local threshold checks · Wi-Fi · JSON payload
n8n Webhook and Automation
Validation · Event classification · Duplicate suppression · Routing
AI agent
Alert explanation
Notifications
Telegram · Gmail · Voice
Google Sheets
Event history
Dashboard
Webpage · ThingSpeak
n8n supports webhook-triggered workflows and integrations with services such as Telegram, Gmail, Google Sheets, and AI providers. See the official n8n documentation and Webhook documentation .
Data flow diagram
flowchart TD
A[Industrial Sensors] --> B[ESP32 Acquisition]
B --> C[Local Threshold Evaluation]
C --> D[Build JSON Payload]
D --> E[HTTPS POST to n8n]
E --> F[Validate and Normalize]
F --> G[Evaluate Event Severity]
G --> H{Hazard Detected?}
H -- No --> I[Log Normal Reading]
H -- Yes --> J[Create Event Record]
J --> K[AI Alert Message]
K --> L[Telegram Text]
K --> M[Gmail Notification]
K --> N[Text to Speech]
N --> O[Telegram Voice]
I --> P[Google Sheets]
J --> P
I --> Q[Web Dashboard / ThingSpeak]
J --> Q
Design principle: Do not wait for an AI response before raising a critical alarm. The ESP32 should identify known critical conditions locally, while n8n handles remote notifications. AI improves the explanation; it does not decide whether a dangerous condition is allowed to remain unreported.
4. Hardware components required
The following is a practical prototype bill of materials. You can substitute compatible sensors, but pin assignments and software must then be adjusted.
ESP32 DevKit V1
Quantity: 1
Main controller, Wi-Fi communication, ADC measurements, and local threshold detection.
DS18B20 temperature sensor
Quantity: 1
Digital temperature measurements. A 4.7 kΩ pull-up resistor is typically used between DATA and 3.3 V.
MQ-2 smoke/gas sensor module
Quantity: 1
Prototype gas/smoke response measurement. Requires warm-up and calibration; its analog output must be checked for ESP32-safe voltage.
LDR and 10 kΩ resistor
Quantity: 1 each
Forms a voltage divider to measure relative light intensity.
Flame sensor module
Quantity: 1
Demonstration-level infrared flame indication. Detection range and false-trigger susceptibility depend on the module and environment.
SW-420 vibration sensor
Quantity: 1
Detects vibration events through a digital output. For quantitative vibration monitoring, use an accelerometer such as an ADXL345 or an industrial vibration transmitter.
Supporting components
Breadboard or PCB, jumper wires, suitable power supply, pull-up resistor, LDR divider resistor, and optional buzzer/LED for local indication.
Additional software and services
-
Arduino IDE and ESP32 board support package.
-
DS18B20 libraries:
OneWireandDallasTemperature. -
An n8n instance, either hosted or self-hosted with a publicly reachable HTTPS endpoint.
-
Telegram bot and recipient chat ID.
-
Google Sheets and Gmail credentials configured in n8n.
-
An AI model provider supported by your n8n installation.
-
A text-to-speech provider or service that returns an audio file.
-
Optional ThingSpeak channel for cloud charts.
-
A local or hosted web dashboard.
5. Electrical schematic and connection table
The following is the proposed connection plan for an ESP32 DevKit V1. Confirm the exact pin labels on your board before wiring.
ESP32 sensor wiring schematic
Prototype-level connection diagram; use the detailed pin table below for exact connections.
ESP32 DEVKIT V1
+----------------------+
DS18B20 VDD | 3V3 GND |---- Common GND
DS18B20 DQ | GPIO 4 |
| | |
| 4.7kΩ |
| | |
| 3V3 |
| |
MQ-2 analog | GPIO 34 (ADC input) |
LDR divider | GPIO 35 (ADC input) |
Flame DO | GPIO 27 (digital in) |
SW-420 DO | GPIO 26 (digital in) |
+----------------------+
LDR voltage divider:
3V3 ---- LDR ----+---- GPIO 35
|
10kΩ
|
GND
DS18B20 DATA pull-up:
3V3 ---- 4.7kΩ ----+---- GPIO 4
|
DS18B20 DATA
Pin mapping
|
Device signal |
ESP32 pin |
Connection notes |
|---|---|---|
|
DS18B20 DATA |
GPIO 4 |
4.7 kΩ pull-up to 3.3 V |
|
DS18B20 VDD |
3V3 |
For normal three-wire operation |
|
DS18B20 GND |
GND |
Common ground |
|
MQ-2 AO |
GPIO 34 |
ADC input only; ensure safe voltage |
|
LDR divider midpoint |
GPIO 35 |
ADC input only |
|
Flame sensor DO |
GPIO 27 |
Confirm output is 3.3 V safe |
|
SW-420 DO |
GPIO 26 |
Confirm output is 3.3 V safe |
|
Optional LED |
GPIO 2 |
Board-dependent; use a suitable resistor |
Important electrical precautions
-
Never connect 5 V directly to an ESP32 GPIO or ADC input. Some MQ-series modules are powered from 5 V and can output voltages higher than the ESP32 input limit. Use a properly designed divider or level-shifting circuit.
-
All sensor signals must share an appropriate common ground with the ESP32 unless the interface is intentionally isolated.
-
MQ-series sensors can consume significant heater current. Supply them according to the manufacturer's specifications rather than assuming the ESP32 3.3 V output can power them.
-
Check flame and vibration module output levels before connecting their digital outputs.
-
Do not connect the prototype directly to mains-voltage equipment, industrial motor terminals, or high-voltage control wiring.
-
For industrial deployment, use isolated sensor interfaces, suitable enclosures, surge protection, and an engineered power supply.
The MQ-2 reading in this project is a raw relative sensor measurement. It is not a calibrated gas concentration in ppm and should not be represented as a certified gas alarm.
6. Step-by-step hardware assembly
Step 1 — Prepare the ESP32
-
Install Arduino IDE.
-
Open Preferences and add the Espressif ESP32 board package URL from the official ESP32 Arduino installation guide .
-
Open Boards Manager and install the ESP32 platform.
-
Select your ESP32 board and its USB serial port.
Step 2 — Connect the temperature sensor
Connect the DS18B20 in three-wire mode:
-
VDD to 3.3 V.
-
GND to GND.
-
DATA to GPIO 4.
-
Connect a 4.7 kΩ resistor between DATA and 3.3 V.
Install the OneWire and DallasTemperature libraries.
Step 3 — Connect the smoke/gas sensor
-
Power the MQ-2 module using its specified supply.
-
Connect its analog output through a suitable voltage divider or level shifter to GPIO 34.
-
Verify that the voltage at GPIO 34 never exceeds the ESP32 input limit.
-
Allow the sensor to warm up according to its datasheet before trusting readings.
Step 4 — Connect the LDR
-
Connect the LDR between 3.3 V and GPIO 35.
-
Connect a 10 kΩ resistor from GPIO 35 to GND.
-
Measure the ADC value under bright and dark conditions.
With this particular arrangement, a higher reading generally means more light. Calibration depends on the LDR and resistor values.
Step 5 — Connect the flame and vibration modules
-
Flame digital output to GPIO 27.
-
SW-420 digital output to GPIO 26.
-
Connect grounds appropriately.
-
Check whether each module's output is active-high or active-low. The example software assumes a LOW output means detection for both modules; change this if your modules behave differently.
Step 6 — Test sensors independently
Before connecting to n8n, verify that each sensor returns plausible readings. For the MQ-2, record baseline values and follow the required conditioning procedure. For vibration, test the sensor with gentle, repeatable vibration rather than potentially damaging equipment.
Step 7 — Enable Wi-Fi communication
Configure the ESP32 to connect to a Wi-Fi network and transmit JSON data to an HTTPS endpoint. Start with a test endpoint in n8n before enabling email, voice, and AI processing.
7. ESP32 firmware — complete starting implementation
This firmware combines all five sensor inputs, applies configurable threshold rules, sends measurements to an n8n webhook, and hosts a simple monitoring webpage on the ESP32's local network.
The code uses a practical polling model. It sends readings periodically and can transmit an additional event payload when a critical condition occurs. It is a prototype implementation; watchdogs, durable offline buffering, and robust delivery retries are recommended before deployment.
Step 7.1 — Install Arduino libraries
In Arduino IDE Library Manager, install:
-
OneWire -
DallasTemperature
WiFi, HTTPClient, WebServer, WiFiClientSecure, and ArduinoJson functionality are provided by the ESP32 platform or installed separately as noted below. This example constructs JSON manually, so it does not require ArduinoJson.
Step 7.2 — Set the configuration
Replace the Wi-Fi name, password, and webhook URL. Keep the n8n endpoint private and use HTTPS in production.
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// ---------- NETWORK CONFIGURATION ----------
const char* WIFI_SSID = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
// Use the production HTTPS URL from your n8n Webhook node.
const char* WEBHOOK_URL =
"https://YOUR_N8N_HOST/webhook/industrial-sensors";
// Prototype example only.
// Set a trusted CA certificate in production; do not use insecure TLS.
const char* ROOT_CA = R"PEM(
-----BEGIN CERTIFICATE-----
PASTE_THE_TRUSTED_ROOT_CA_CERTIFICATE_HERE
-----END CERTIFICATE-----
)PEM";
// ---------- PIN ASSIGNMENTS ----------
constexpr int TEMP_PIN = 4;
constexpr int GAS_PIN = 34;
constexpr int LDR_PIN = 35;
constexpr int FLAME_PIN = 27;
constexpr int VIB_PIN = 26;
constexpr int LED_PIN = 2;
// Set according to your modules.
constexpr int FLAME_ACTIVE = LOW;
constexpr int VIB_ACTIVE = LOW;
// ---------- THRESHOLDS: CALIBRATE ----------
float TEMP_LIMIT_C = 50.0;
int GAS_LIMIT_ADC = 1800;
int LIGHT_MIN_ADC = 800;
// Sampling and reporting interval
const unsigned long SAMPLE_MS = 2000;
const unsigned long REPORT_MS = 10000;
// ---------- SENSOR OBJECTS ----------
OneWire oneWire(TEMP_PIN);
DallasTemperature tempSensor(&oneWire);
WebServer server(80);
// ---------- STATE ----------
float temperatureC = NAN;
int gasRaw = 0;
int lightRaw = 0;
bool flameDetected = false;
bool vibrationDetected = false;
bool hazard = false;
unsigned long lastSample = 0;
unsigned long lastReport = 0;
unsigned long lastEventReport = 0;
String deviceId = "ESP32-INDUSTRIAL-01";
String lastEvent = "NORMAL";
// JSON escaping for string fields.
String jsonEscape(const String& input) {
String out;
for (size_t i = 0; i < input.length(); i++) {
char c = input[i];
if (c == '"' || c == '\\') out += '\\';
if (c == '\n') {
out += "\\n";
} else if (c == '\r') {
out += "\\r";
} else {
out += c;
}
}
return out;
}
String timestampPlaceholder() {
// The server should assign its own trusted UTC receipt timestamp.
// This device uptime is useful for debugging, not wall-clock time.
return String(millis());
}
String createPayload() {
String payload = "{";
payload += "\"device_id\":\"" + jsonEscape(deviceId) + "\",";
payload += "\"uptime_ms\":" + timestampPlaceholder() + ",";
payload += "\"temperature_c\":";
payload += isnan(temperatureC) ? "null" : String(temperatureC, 2);
payload += ",";
payload += "\"gas_raw\":" + String(gasRaw) + ",";
payload += "\"light_raw\":" + String(lightRaw) + ",";
payload += "\"flame_detected\":";
payload += flameDetected ? "true" : "false";
payload += ",";
payload += "\"vibration_detected\":";
payload += vibrationDetected ? "true" : "false";
payload += ",";
payload += "\"hazard_detected\":";
payload += hazard ? "true" : "false";
payload += ",";
payload += "\"event\":\"" + jsonEscape(lastEvent) + "\"";
payload += "}";
return payload;
}
void sampleSensors() {
tempSensor.requestTemperatures();
float t = tempSensor.getTempCByIndex(0);
if (t != DEVICE_DISCONNECTED_C &&
t >= -55.0 && t <= 125.0) {
temperatureC = t;
} else {
temperatureC = NAN;
}
gasRaw = analogRead(GAS_PIN);
lightRaw = analogRead(LDR_PIN);
flameDetected =
digitalRead(FLAME_PIN) == FLAME_ACTIVE;
vibrationDetected =
digitalRead(VIB_PIN) == VIB_ACTIVE;
bool previousHazard = hazard;
// Basic demonstration rules.
hazard =
(!isnan(temperatureC) && temperatureC >= TEMP_LIMIT_C) ||
gasRaw >= GAS_LIMIT_ADC ||
flameDetected;
// Vibration and low light are logged as conditions.
// They are not automatically classified as emergencies.
if (flameDetected) {
lastEvent = "FLAME_DETECTED";
} else if (gasRaw >= GAS_LIMIT_ADC) {
lastEvent = "GAS_THRESHOLD";
} else if (!isnan(temperatureC) &&
temperatureC >= TEMP_LIMIT_C) {
lastEvent = "HIGH_TEMPERATURE";
} else if (vibrationDetected) {
lastEvent = "VIBRATION_DETECTED";
} else if (lightRaw < LIGHT_MIN_ADC) {
lastEvent = "LOW_LIGHT";
} else {
lastEvent = "NORMAL";
}
digitalWrite(LED_PIN, hazard ? HIGH : LOW);
if (hazard && !previousHazard) {
Serial.println("NEW HAZARD: " + lastEvent);
}
Serial.println(createPayload());
}
bool sendToWebhook() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Wi-Fi disconnected");
return false;
}
WiFiClientSecure client;
// Fail safely if the certificate is missing or invalid.
if (String(ROOT_CA).indexOf("PASTE_THE_TRUSTED") >= 0) {
Serial.println("Configure the trusted TLS root CA first");
return false;
}
client.setCACert(ROOT_CA);
HTTPClient http;
if (!http.begin(client, WEBHOOK_URL)) {
Serial.println("HTTPS connection initialization failed");
return false;
}
http.setTimeout(5000);
http.addHeader("Content-Type", "application/json");
int status = http.POST(createPayload());
Serial.printf("Webhook HTTP status: %d\n", status);
String response = http.getString();
if (status < 200 || status >= 300) {
Serial.println(response);
}
http.end();
return status >= 200 && status < 300;
}
void handleDashboard() {
String page = R"HTML(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Industrial Monitor</title>
<style>
body{font-family:Arial;margin:24px;background:#101820;color:#f5f7fa}
.card{background:#202e3a;padding:16px;margin:10px 0;border-radius:10px}
.value{font-size:24px;font-weight:bold}
</style>
</head>
<body>
<h2>IIoT Industrial Monitoring</h2>
<div class="card">Temperature: <span id="t" class="value">--</span> °C</div>
<div class="card">Gas raw ADC: <span id="g" class="value">--</span></div>
<div class="card">Light ADC: <span id="l" class="value">--</span></div>
<div class="card">Flame: <span id="f" class="value">--</span></div>
<div class="card">Vibration: <span id="v" class="value">--</span></div>
<div class="card">Status: <span id="s" class="value">--</span></div>
<script>
async function refresh(){
try{
const r=await fetch('/data');
const d=await r.json();
document.getElementById('t').textContent=d.temperature_c ?? 'Sensor error';
document.getElementById('g').textContent=d.gas_raw;
document.getElementById('l').textContent=d.light_raw;
document.getElementById('f').textContent=d.flame_detected;
document.getElementById('v').textContent=d.vibration_detected;
document.getElementById('s').textContent=d.event;
}catch(e){}
}
refresh();
setInterval(refresh,2000);
</script>
</body>
</html>
)HTML";
server.send(200, "text/html", page);
}
void handleData() {
server.send(200, "application/json", createPayload());
}
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED &&
millis() - start < 20000) {
delay(500);
Serial.print(".");
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.print("Dashboard: http://");
Serial.println(WiFi.localIP());
} else {
Serial.println("Wi-Fi unavailable; local sampling continues");
}
}
void setup() {
Serial.begin(115200);
pinMode(FLAME_PIN, INPUT);
pinMode(VIB_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
analogReadResolution(12);
tempSensor.begin();
connectWiFi();
server.on("/", HTTP_GET, handleDashboard);
server.on("/data", HTTP_GET, handleData);
server.begin();
lastSample = millis() - SAMPLE_MS;
lastReport = millis();
}
void loop() {
unsigned long now = millis();
if (now - lastSample >= SAMPLE_MS) {
lastSample = now;
sampleSensors();
}
if (WiFi.status() == WL_CONNECTED) {
server.handleClient();
} else if (now % 30000 < 10) {
WiFi.reconnect();
}
bool newHazardDue =
hazard && (now - lastEventReport >= 10000);
bool periodicReportDue =
now - lastReport >= REPORT_MS;
if (WiFi.status() == WL_CONNECTED &&
(newHazardDue || periodicReportDue)) {
bool success = sendToWebhook();
if (success) {
lastReport = now;
if (newHazardDue) lastEventReport = now;
}
}
delay(5);
}
Step 7.3 — What the firmware does
-
Samples sensors approximately every two seconds.
-
Evaluates temperature, gas, and flame conditions for hazards.
-
Records vibration and low-light events.
-
Sends a JSON payload to the n8n webhook.
-
Provides a local web dashboard at the ESP32's assigned IP address.
-
Uses HTTPS certificate validation for outbound requests.
-
Continues sampling when Wi-Fi is unavailable.
Limitations to fix before a production demonstration:
-
Configure a valid trusted root CA for your webhook's TLS certificate.
-
Add Wi-Fi reconnection backoff and persistent storage for missed events.
-
Implement time synchronization with NTP if the device itself must record wall-clock timestamps.
-
Add sensor fault flags instead of treating failed readings as normal.
-
Add hysteresis and time-based debounce to prevent repeated alarms from noisy sensors.
-
Replace the vibration digital switch with an accelerometer if you need vibration amplitude, RMS, frequency, or machine-health analysis.
-
The local webpage is unauthenticated and should be restricted to a trusted local network; do not expose it directly to the public internet.
Example JSON payload
{
"device_id": "ESP32-INDUSTRIAL-01",
"uptime_ms": 125000,
"temperature_c": 52.6,
"gas_raw": 1940,
"light_raw": 2300,
"flame_detected": false,
"vibration_detected": true,
"hazard_detected": true,
"event": "GAS_THRESHOLD"
}
This payload is an illustrative example. Your actual sensor readings will vary with hardware and calibration.
8. n8n automation workflow — step by step
n8n is the central automation engine. It receives readings from the ESP32, classifies sensor conditions, records data, and distributes notifications. Its Webhook node can expose a test endpoint during development and a production endpoint when the workflow is activated.
Step 8.1 — Create an n8n instance
Choose either:
-
n8n Cloud for easier setup.
-
Self-hosted n8n using Docker or another supported deployment method.
For a self-hosted deployment, configure a public HTTPS endpoint or a secure tunnel appropriate for development. Do not expose the n8n editor or credentials to the public internet without authentication and appropriate network controls.
Step 8.2 — Create the main workflow
Create a workflow named:
IIoT Smart Industrial Monitoring and AI Alert System
Add these nodes in order:
01
Webhook
Receive ESP32 JSON payloads using POST.
02
Code
Validate the fields, classify events, and calculate severity.
03
Google Sheets
Append the reading and event record.
04
IF / Switch
Route normal, warning, and critical events.
05
AI Agent
Generate a concise explanation for the operator.
06
Telegram and Gmail
Send event notifications.
07
Text-to-Speech and Telegram
Generate an audio file and deliver it for important events.
Step 8.3 — Configure the Webhook node
Set the following properties:
|
Setting |
Value |
|---|---|
|
HTTP method |
|
|
Path |
|
|
Response |
Respond immediately with a success response, or use a Respond to Webhook node |
|
Authentication |
Prefer Header Auth or another supported authentication method |
|
Expected content |
JSON |
During development, use the test URL while the node is listening for test events. Once the workflow is configured, activate it and copy the production URL into the ESP32 firmware.
For additional security, configure a secret header in the ESP32 and require the matching credential in n8n. Do not embed a privileged API key in a webpage or expose it in public source code.
Step 8.4 — Validate and classify the incoming readings
Insert a Code node after the Webhook node. The following example accepts a payload, assigns a severity, and creates an alert message. The thresholds must match the actual sensors and operating conditions.
const input = $json.body ?? $json;
const required = [
"device_id",
"gas_raw",
"light_raw",
"flame_detected",
"vibration_detected"
];
for (const key of required) {
if (input[key] === undefined || input[key] === null) {
throw new Error(`Missing required field: ${key}`);
}
}
const finiteNumber = (value, name) => {
const n = Number(value);
if (!Number.isFinite(n)) {
throw new Error(`Invalid numeric field: ${name}`);
}
return n;
};
const gas = finiteNumber(input.gas_raw, "gas_raw");
const light = finiteNumber(input.light_raw, "light_raw");
const temp =
input.temperature_c === null ||
input.temperature_c === undefined
? null
: finiteNumber(input.temperature_c, "temperature_c");
const flame = input.flame_detected === true;
const vibration = input.vibration_detected === true;
const LIMITS = {
temperatureC: 50,
gasRaw: 1800,
lowLightAdc: 800
};
const reasons = [];
if (flame) reasons.push("FLAME_DETECTED");
if (gas >= LIMITS.gasRaw) reasons.push("GAS_THRESHOLD");
if (temp !== null && temp >= LIMITS.temperatureC) {
reasons.push("HIGH_TEMPERATURE");
}
if (vibration) reasons.push("VIBRATION_DETECTED");
if (light < LIMITS.lowLightAdc) reasons.push("LOW_LIGHT");
const critical =
flame ||
gas >= LIMITS.gasRaw ||
(temp !== null && temp >= LIMITS.temperatureC);
const warning = !critical && (vibration || light < LIMITS.lowLightAdc);
const severity = critical
? "CRITICAL"
: warning
? "WARNING"
: "NORMAL";
const now = new Date().toISOString();
return [{
json: {
device_id: String(input.device_id),
timestamp_utc: now,
temperature_c: temp,
gas_raw: gas,
light_raw: light,
flame_detected: flame,
vibration_detected: vibration,
severity,
event: reasons.length ? reasons.join(",") : "NORMAL",
alert_required: critical || warning,
alert_message: critical
? "CRITICAL: Immediate operator assessment required."
: warning
? "WARNING: Abnormal condition detected; inspect the equipment."
: "System operating within configured thresholds."
}
}];
Important: A Webhook node may expose incoming data under body, depending on its settings and the incoming request. Check an actual execution and adjust the Code node's input path if required. Keep the webhook authentication configuration aligned with the ESP32 request headers.
The Code node's timestamp is the n8n server's receipt/processing time, not necessarily the sensor measurement time. For accurate event tracking, add a synchronized device timestamp and separately retain the server receipt timestamp.
Step 8.5 — Configure Google Sheets logging
Create a Google spreadsheet named IIoT_Industrial_Monitoring.
Create two tabs.
Tab 1: Sensor_Log
|
Column |
Field |
|---|---|
|
A |
timestamp_utc |
|
B |
device_id |
|
C |
temperature_c |
|
D |
gas_raw |
|
E |
light_raw |
|
F |
flame_detected |
|
G |
vibration_detected |
|
H |
severity |
|
I |
event |
Tab 2: Event_Log
|
Column |
Field |
|---|---|
|
A |
timestamp_utc |
|
B |
device_id |
|
C |
severity |
|
D |
event |
|
E |
alert_message |
|
F |
notification_status |
In n8n:
-
Add a Google Sheets node.
-
Connect your Google account through n8n credentials.
-
Select the spreadsheet and
Sensor_Logworksheet. -
Choose the append-row operation.
-
Map each incoming field to its corresponding column.
-
Add another append-row node to
Event_Logon the alert branch. -
Execute the workflow with a test payload and verify the row values.
Log routine readings and events separately if you expect a high volume of sensor data. This reduces noise in the event history and makes incident review easier.
Step 8.6 — Configure conditional routing
Use an IF or Switch node based on severity.
-
CRITICAL: send Telegram immediately, send Gmail, and trigger the voice-alert branch. -
WARNING: send a Telegram text message and log the event. -
NORMAL: record the reading without generating an alarm every few seconds.
For critical events, send a short, deterministic alert first. Then run the AI explanation and supplemental notification steps. This avoids making the critical notification dependent on AI service availability.
9. AI agent configuration
The AI agent should convert structured sensor data into a readable alert, not invent measurements or independently make safety decisions.
Step 9.1 — Configure the AI node
In n8n, add an AI Agent node or the equivalent AI workflow nodes available in your version. Connect a supported chat model using stored credentials. Provide the normalized sensor fields as the agent's input.
Use this system prompt:
You are an industrial monitoring notification assistant.
Your role is to explain sensor events clearly and concisely.
Use only the sensor values and event classifications provided
in the input. Never invent measurements, causes, or actions
that have not been verified.
Rules:
1. Preserve the supplied severity classification.
2. Never downgrade a CRITICAL event.
3. For CRITICAL events, start with "CRITICAL ALERT".
4. State the device ID and available sensor readings.
5. State which configured threshold or sensor condition
was triggered when that information is supplied.
6. Recommend following the site's established emergency
procedure and having a qualified operator assess the area.
7. Do not claim that a fire, gas leak, or equipment failure
is confirmed unless a suitable verified signal supports it.
8. Do not control machinery, silence alarms, or change
thresholds.
9. Use simple English and keep the message under 100 words.
10. If the input is incomplete or contradictory, state that
the reading needs verification.
Step 9.2 — Example AI-generated message
For a temperature of 52.6 °C and gas raw ADC of 1940, with a configured temperature limit of 50 °C and gas threshold of 1800:
CRITICAL ALERT — Device ESP32-INDUSTRIAL-01 reports a temperature of 52.6 °C and a gas sensor reading of 1940 ADC counts. Both readings exceed the configured prototype thresholds. Verify the sensor readings and follow the site's established safety procedure. Have a qualified operator assess the area immediately.
This message is an example generated from hypothetical readings, not a report of an actual incident.
Step 9.3 — Recommended AI design
-
Use a structured input rather than a free-form prompt assembled from arbitrary external text.
-
Keep threshold evaluation in deterministic code.
-
Keep the AI output short enough for SMS-style notifications.
-
Add a fallback template when the AI provider is unavailable.
-
Store the original sensor values alongside the generated message.
-
Avoid giving the AI agent permission to operate machinery or modify safety settings.
10. Telegram text alerts
Telegram provides a Bot API for sending text messages and audio files. Its sendMessage method sends text, and sendAudio or sendVoice can deliver audio in supported formats.
Step 10.1 — Create a Telegram bot
-
Open Telegram and search for the official
@BotFatheraccount. -
Create a new bot using
/newbot. -
Copy the generated bot token and store it securely.
-
Open the new bot's chat and press Start.
-
Obtain your chat ID through a safe bot-update or integration method.
-
Store the bot token and chat ID in n8n credentials or protected configuration.
Do not publish the token in a public Git repository, frontend webpage, or project report.
Step 10.2 — Send text messages
Add the Telegram node to the CRITICAL and WARNING branches.
Example message:
🚨 INDUSTRIAL SAFETY ALERT
Device: ESP32-INDUSTRIAL-01
Severity: CRITICAL
Temperature: 52.6 °C
Gas raw ADC: 1940
Flame: false
Vibration: true
Event: HIGH_TEMPERATURE, GAS_THRESHOLD
Action: Follow the site's emergency procedure
and have a qualified operator assess the condition.
Map these fields dynamically from the normalized n8n data. The message above is an example.
Step 10.3 — Prevent notification spam
Use event-based notification logic:
-
Send an immediate alert when a condition first becomes active.
-
Send a repeat notification only after a configured interval.
-
Send a recovery message when the condition clears.
-
Keep a persistent event ID or event state to avoid duplicate notifications after workflow retries.
Do not suppress repeated critical events indefinitely. The repeat policy must be configured to match the site's response requirements.
11. AI-generated voice alerts through Telegram
The voice-alert feature requires a text-to-speech service in addition to Telegram. n8n orchestrates the process, but the AI agent alone does not automatically produce a playable audio file.
Voice notification workflow
flowchart TD
A[Critical Sensor Event] --> B[Create Deterministic Alert]
B --> C[AI Agent Creates Explanation]
C --> D[Text-to-Speech API]
D --> E[Receive Audio File]
E --> F{Audio Valid?}
F -- Yes --> G[Telegram sendVoice or sendAudio]
F -- No --> H[Send Text Alert and Log Failure]
G --> I[Log Notification Result]
H --> I
Step 11.1 — Choose a text-to-speech provider
Use a service that accepts text and returns an audio file or binary response. Configure its API credentials within n8n.
A basic speech message might be:
Critical alert. High temperature and abnormal gas sensor readings detected on industrial device one. Follow the site safety procedure and inspect the area.
Keep the spoken message concise. Avoid long technical explanations that delay the operator's understanding.
Step 11.2 — Configure audio generation
-
Pass the final alert text into the text-to-speech node or HTTP Request node.
-
Request a supported audio format.
-
Verify the response contains valid audio bytes, not JSON error text.
-
Configure the next node to receive the file as binary data.
-
Route the audio file to Telegram.
Step 11.3 — Deliver the audio file
-
Use
sendVoicefor a Telegram voice-note presentation when the audio is in a supported voice-note format. -
Use
sendAudiofor supported MP3/M4A audio files presented as audio. -
If the provider returns a different format, transcode it using an appropriate service or tool before uploading.
The official Telegram Bot API documents audio delivery requirements and accepted formats.
If audio generation fails, the workflow must still deliver the text alert. Voice notification is an enhancement, not a dependency for critical notification.
12. Gmail automated email notifications
Gmail provides a detailed notification channel for supervisors and maintenance teams. It is useful for incident records, summaries, and follow-up actions.
Step-by-step configuration
-
In n8n, create Gmail credentials using the supported Google authorization process.
-
Add a Gmail node to the critical-event branch.
-
Configure the recipient, subject, and message body.
-
Map the device ID, timestamp, event severity, sensor values, and recommended next step.
-
Add an error-handling branch to record unsuccessful email delivery.
Example email configuration:
SUBJECT
[CRITICAL] Industrial Monitoring Alert — ESP32-INDUSTRIAL-01
EMAIL BODY
Industrial monitoring system detected an abnormal condition.
-
Device: ESP32-INDUSTRIAL-01
-
Severity: CRITICAL
-
Temperature: 52.6 °C
-
Gas sensor: 1940 ADC counts
-
Flame sensor: Not detected
-
Event: HIGH_TEMPERATURE, GAS_THRESHOLD
Please verify the readings and follow the established site safety procedure. A qualified operator should assess the condition.
Illustrative email; values are examples.
Recommended email routing
-
Critical: immediate notification to the designated response team.
-
Warning: notification to the maintenance team according to site policy.
-
Normal: log the reading; avoid sending an email for every sample.
-
Recovery: send a separate message when the event clears, after verifying that the recovery conditions have remained stable.
13. Google Sheets event logging and reporting
Google Sheets serves as an accessible record of sensor data and incidents.
Recommended logging architecture
Sensor log
Periodic measurements, device identity, timestamps, and raw sensor readings.
Event log
Only warnings, critical conditions, recovery events, and notification outcomes.
Report and analysis
Maximum temperature, gas-reading trends, event counts, and equipment inspection history.
Example event-log row
|
Timestamp UTC |
Device |
Severity |
Event |
Notification |
|---|---|---|---|---|
|
2026-10-29T11:05:00Z |
ESP32-INDUSTRIAL-01 |
CRITICAL |
GAS_THRESHOLD |
Telegram sent |
The row is illustrative. In the actual workflow, map the values from each execution.
Data quality and retention
-
Store timestamps in a consistent timezone, preferably UTC.
-
Keep sensor values and AI-generated text in separate fields.
-
Record notification failures instead of silently dropping them.
-
Protect the spreadsheet with appropriate access controls.
-
Consider a database or time-series platform for larger installations, as spreadsheet services are not designed to be the sole high-volume industrial historian.
14. ThingSpeak integration and cloud dashboard
ThingSpeak is an optional addition for storing numeric sensor data and viewing time-series charts. It can be used alongside Google Sheets rather than replacing it.
The ThingSpeak write API accepts HTTP requests containing a channel API key and fields. A channel supports up to eight fields and stores entries with timestamps. Free-tier update intervals may be restricted, so check the current account limits before selecting the sampling rate.
Step 14.1 — Create a ThingSpeak channel
Create a channel called Industrial Monitoring.
Configure the fields as follows:
|
ThingSpeak field |
Sensor value |
|---|---|
|
Field 1 |
Temperature °C |
|
Field 2 |
Gas raw ADC |
|
Field 3 |
Light raw ADC |
|
Field 4 |
Flame detection (0/1) |
|
Field 5 |
Vibration detection (0/1) |
|
Field 6 |
Hazard detection (0/1) |
Copy the channel's Write API Key and store it securely.
Step 14.2 — Send data through n8n
Add an HTTP Request node after the normalization step:
-
Method:
POST -
URL:
https://api.thingspeak.com/update -
Content type:
application/x-www-form-urlencoded -
Body fields:
api_key,field1,field2, throughfield6
Map the values to the corresponding fields.
A simplified request looks like this:
POST https://api.thingspeak.com/update
api_key=YOUR_WRITE_API_KEY
field1=52.6
field2=1940
field3=2300
field4=0
field5=1
field6=1
This is a configuration example, not a request that has been executed. Check the HTTP response: ThingSpeak returns an entry identifier on success and may return 0 when the update fails.
Step 14.3 — Configure charts
Create charts for:
-
Temperature trend.
-
Gas sensor raw readings.
-
Light intensity.
-
Flame and vibration states.
-
Hazard events over time.
Use ThingSpeak for time-series visualization and Google Sheets for convenient tabular incident review.
15. Web dashboard design
The project can have two complementary interfaces.
A. ESP32 local dashboard
The firmware above serves a basic webpage at the ESP32's local IP address. This works while your computer or phone can reach the ESP32 over the same network.
Advantages:
-
Simple setup.
-
Direct access to the latest sensor readings.
-
Does not require a separate web server.
Limitations:
-
Local-network access only unless additional infrastructure is configured.
-
No built-in authentication or historical database.
-
Sensor readings stop updating if the device or its network is unavailable.
B. Cloud dashboard
A more complete dashboard can read from ThingSpeak, a database, or an authenticated backend. It can display:
-
Live temperature and gas readings.
-
Flame and vibration status.
-
Current alert severity.
-
Historical charts.
-
Event timestamps.
-
Notification delivery status.
-
Device connectivity and last-seen time.
Suggested dashboard layout
Industrial Monitoring
Example layoutTemperature
52.6 °C
Example: above threshold
Gas raw ADC
1940
Example: threshold exceeded
Flame sensor
Not detected
Vibration sensor
Detected
Static illustrative values only; this is not connected to the ESP32 or a live data source.
For a polished deployment, keep the cloud dashboard behind authenticated access and retrieve sensor data through a controlled backend. Never place secret API keys in browser-side JavaScript.
16. Complete event-routing logic
A reliable system should distinguish a measurement, a warning, a critical event, and recovery.
flowchart TD
A[Receive Sensor Data] --> B{Payload Valid?}
B -- No --> C[Log Invalid Payload]
C --> D[Record Diagnostic / Retry]
B -- Yes --> E[Evaluate Sensor Thresholds]
E --> F{Flame or Critical Threshold?}
F -- Yes --> G[CRITICAL]
F -- No --> H{Abnormal Vibration or Low Light?}
H -- Yes --> I[WARNING]
H -- No --> J[NORMAL]
G --> K[Immediate Text Alert]
K --> L[AI Explanation and Voice]
K --> M[Gmail Alert]
G --> N[Write Event Log]
I --> O[Warning Notification]
O --> N
J --> P[Write Sensor Log]
L --> Q[Record Delivery Status]
M --> Q
N --> Q
Example threshold configuration
The values below are starting points for software testing only, not universal industrial limits.
|
Parameter |
Demonstration threshold |
Action |
|---|---|---|
|
Temperature |
50 °C |
Critical alert |
|
MQ-2 raw ADC |
1800 |
Critical prototype alert |
|
Flame sensor |
Detection signal |
Critical prototype alert |
|
Vibration switch |
Detection signal |
Warning |
|
Light ADC |
Below 800 |
Warning |
Actual thresholds must be based on the process, equipment specifications, sensor calibration, and risk assessment. A gas raw ADC threshold cannot be translated into a reliable gas concentration without appropriate calibration and sensor characterization.
Threshold hysteresis
For temperature, for example, use separate alarm and recovery thresholds:
-
Activate the alarm at or above 50 °C.
-
Clear it only after temperature remains below 47 °C for a defined period.
This prevents rapid alert switching near the threshold. Apply similar validated filtering and debounce rules to other sensor inputs where appropriate.
17. Step-by-step testing and commissioning
Test the system in stages instead of connecting all services at once.
Commissioning checklist
0 of 11 complete
Expected test outcomes
|
Test scenario |
Expected result |
|---|---|
|
Normal readings |
Sensor log updated, no emergency notification |
|
High temperature |
Critical classification, Telegram and Gmail notification |
|
Gas threshold exceeded |
Critical prototype event and logged reading |
|
Flame input activated |
Immediate critical event routing |
|
Vibration detected |
Warning notification according to policy |
|
Low illumination |
Warning if the rule is enabled |
|
AI service unavailable |
Deterministic alert still delivered |
|
TTS service unavailable |
Text alert still delivered |
|
Wi-Fi lost |
Local sampling continues; transmission resumes after reconnection |
|
Invalid webhook payload |
Validation failure is recorded and not treated as a normal reading |
Use controlled simulation values or a test-mode input when verifying dangerous-event branches. Do not deliberately create a fire or expose personnel to hazardous gas to test a prototype.
18. Troubleshooting guide
|
Problem |
Likely cause |
Recommended fix |
|---|---|---|
|
DS18B20 reports |
Wiring, missing pull-up, or sensor disconnected |
Verify DATA wiring, pull-up, power, and ground |
|
MQ-2 reading fluctuates |
Warm-up, ambient conditions, power supply, or calibration |
Allow conditioning time, stabilize power, and characterize baseline |
|
LDR behaves backwards |
Divider orientation or threshold assumption |
Recheck wiring and calibrate the ADC threshold |
|
Flame alert remains active |
Module polarity or sensitivity setting |
Check active-high/active-low behavior and module adjustment |
|
Vibration alerts constantly |
High sensitivity or unstable mounting |
Adjust sensitivity and mount securely; use an accelerometer for real measurements |
|
ESP32 cannot reach n8n |
Wrong URL, firewall, DNS, Wi-Fi, or TLS certificate |
Check HTTPS URL, network access, and trusted CA |
|
Webhook receives no JSON |
Wrong method/path or inactive workflow |
Use POST, confirm the URL, and activate the production workflow |
|
Google Sheets append fails |
Incorrect account permissions or field mapping |
Reauthorize credentials and verify spreadsheet/tab selection |
|
Telegram returns an error |
Incorrect token, chat ID, or missing bot access |
Verify bot credentials and start the bot conversation |
|
Voice alert fails |
Incorrect audio format or binary-data mapping |
Inspect the TTS response and convert it to a supported format |
|
Repeated emails |
Event branch executes for every reading |
Add event-state tracking, debounce, and repeat-notification rules |
|
Dashboard does not load remotely |
Local-only server or network isolation |
Use a secure backend or VPN; do not expose the unauthenticated page publicly |
19. Security, reliability, and industrial safety
The following safeguards should be part of the final design rather than added only after testing.
Security
-
Use HTTPS and certificate validation for device-to-cloud traffic.
-
Require webhook authentication.
-
Store credentials in n8n's credential system or an equivalent secrets manager.
-
Restrict dashboard access and avoid publicly exposing the ESP32 web server.
-
Use least-privilege Google permissions.
-
Rotate compromised tokens and API keys.
-
Avoid including passwords, tokens, or sensitive network information in logs and screenshots.
Reliability
-
Use local threshold evaluation for immediate known conditions.
-
Add event persistence and retry handling for network failures.
-
Use debouncing and hysteresis to reduce nuisance alarms.
-
Record notification success or failure for each important event.
-
Add device heartbeat and last-seen monitoring.
-
Provide fallback notification text when the AI or TTS provider is unavailable.
-
Test restart behavior and recovery from loss of power or Wi-Fi.
Industrial safety
-
Do not use a generic MQ sensor or low-cost flame module as the sole certified detector.
-
Do not rely on cloud connectivity to activate a protective interlock.
-
Do not use the AI agent as a safety controller.
-
Use suitable certified detectors, engineered isolation, and independently designed protective controls for real machinery.
-
Ensure that threshold settings and response procedures are approved by qualified personnel.
IIoT-Based Smart Industrial Monitoring and AI-Powered Alert System
This project uses an ESP32 to monitor temperature, smoke/gas, light, fire, and machine vibration. It displays readings on a local webpage, sends events to n8n for logging and notifications, and can use an AI service to turn validated sensor events into clear alert messages. Similar monitoring systems combine microcontroller-connected sensors with condition-based alerts; this version adds web, cloud, and automation components.[backend.kab.ac][github]
Safety note: Treat this as an educational monitoring prototype—not a certified fire, gas, or machine-safety system. Use appropriately rated, certified detectors and independent safety controls in any real facility. Do not let an AI model decide whether an alarm is real or whether machinery should be shut down.
1. System overview
Temperature ─┐
Smoke/gas ───┤
Flame ────────┤
Light (LDR) ──┼──> ESP32 ──> Local webpage
Vibration ────┘ │
└──HTTPS/JSON──> n8n webhook
├── Validate and classify event
├── Log to Google Sheets
├── Send Gmail notification
├── Send Telegram text alert
└── Optional: generate audio alert
The ESP32 samples sensors, applies basic threshold checks, and publishes timestamped readings. n8n handles routing, logging, and notifications. The local webpage is useful on the same network; remote access requires a properly secured network or cloud endpoint.
2. Hardware
| Part | Purpose |
|---|---|
| ESP32 development board | Sensor reading, Wi-Fi, webpage, webhook requests |
| Temperature sensor, e.g. DS18B20 or a suitable industrial probe | Temperature measurement |
| Gas/smoke sensor module, selected for the target gas | Relative change detection; not a certified gas alarm |
| Flame sensor module | Prototype flame indication |
| LDR and fixed resistor | Relative light-level measurement |
| Vibration sensor or accelerometer | Machine vibration indication or measurement |
| Breadboard/prototype PCB, wires, enclosure | Assembly |
| Optional buzzer and indicator LEDs | Local prototype alerts |
Electrical cautions: ESP32 GPIO and ADC inputs are not 5 V tolerant. Verify each sensor’s output voltage; use a suitable divider or level shifter where needed. Some gas modules have heaters and need a separate, adequately rated supply. Do not power motors or industrial loads from ESP32 pins.
3. Example wiring
These are example pins only; check your board and sensor datasheets before wiring.
| Sensor signal | ESP32 example pin | Notes |
|---|---|---|
| Analog gas output | GPIO 34 | ADC input; ensure voltage stays within ESP32 limits |
| LDR divider midpoint | GPIO 35 | LDR and resistor form a voltage divider |
| Vibration digital output | GPIO 27 | Set threshold on module; basic event-only reading |
| Flame digital output | GPIO 26 | Confirm whether the module is active-high or active-low |
| DS18B20 data | GPIO 4 | Add the pull-up resistor recommended by the sensor documentation |
| Buzzer (optional) | GPIO 25 | Use a transistor driver if the buzzer current exceeds GPIO limits |
| Sensor ground | GND | Connect grounds as appropriate for the prototype |
3.3 V ── LDR ──┬── GPIO35 (ADC)
└── fixed resistor ── GND
Sensor output ───── ESP32 input (check voltage first)
Sensor GND ──────── ESP32 GND
Avoid connecting unknown sensor outputs directly to the ESP32. For industrial probes or long cable runs, use appropriate signal conditioning, isolation, and surge protection.
4. Data and event format
Send one JSON object per reading:
{
"device_id": "plant-demo-01",
"timestamp": "2026-10-29T16:35:00+05:30",
"temperature_c": 31.4,
"gas_raw": 820,
"light_raw": 1440,
"flame_detected": false,
"vibration_detected": true,
"status": "WARNING"
}
Raw ADC values are not calibrated gas concentration or lux measurements. Establish safe limits using the sensor’s documentation and a suitable calibration process. For this prototype, choose conservative demonstration thresholds and label them clearly as examples.
5. ESP32 Arduino example
Install the ESP32 board package and the OneWire and DallasTemperature libraries. Set Wi-Fi credentials, the n8n webhook URL, and thresholds before uploading. This example uses a DS18B20, analog gas and LDR inputs, and digital flame/vibration inputs.
#include <WiFi.h>
#include <HTTPClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASSWORD = "YOUR_PASSWORD";
const char* WEBHOOK_URL = "https://YOUR_N8N_HOST/webhook/industrial";
constexpr int PIN_TEMP = 4;
constexpr int PIN_GAS = 34;
constexpr int PIN_LDR = 35;
constexpr int PIN_VIBRATION = 27;
constexpr int PIN_FLAME = 26;
constexpr int GAS_LIMIT = 2500; // Example only; calibrate for your setup
constexpr int TEMP_LIMIT_C = 50; // Example only
constexpr int LDR_LIMIT = 3000; // Example only
OneWire oneWire(PIN_TEMP);
DallasTemperature tempSensor(&oneWire);
unsigned long lastPost = 0;
const unsigned long POST_INTERVAL_MS = 5000;
void connectWiFi() {
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void setup() {
Serial.begin(115200);
pinMode(PIN_VIBRATION, INPUT);
pinMode(PIN_FLAME, INPUT);
analogReadResolution(12);
tempSensor.begin();
connectWiFi();
}
void loop() {
if (WiFi.status() != WL_CONNECTED) connectWiFi();
if (millis() - lastPost < POST_INTERVAL_MS) {
delay(50);
return;
}
lastPost = millis();
tempSensor.requestTemperatures();
float temperatureC = tempSensor.getTempCByIndex(0);
int gasRaw = analogRead(PIN_GAS);
int lightRaw = analogRead(PIN_LDR);
bool vibration = digitalRead(PIN_VIBRATION);
bool flame = digitalRead(PIN_FLAME); // Invert if your module is active-low.
bool tempAlarm = temperatureC > TEMP_LIMIT_C;
bool gasAlarm = gasRaw > GAS_LIMIT;
bool lightAlarm = lightRaw > LDR_LIMIT;
bool alarm = tempAlarm || gasAlarm || flame || vibration || lightAlarm;
String status = alarm ? "ALERT" : "NORMAL";
String payload = "{";
payload += "\"device_id\":\"plant-demo-01\",";
payload += "\"temperature_c\":" + String(temperatureC, 1) + ",";
payload += "\"gas_raw\":" + String(gasRaw) + ",";
payload += "\"light_raw\":" + String(lightRaw) + ",";
payload += "\"flame_detected\":" + String(flame ? "true" : "false") + ",";
payload += "\"vibration_detected\":" + String(vibration ? "true" : "false") + ",";
payload += "\"status\":\"" + status + "\"";
payload += "}";
Serial.println(payload);
HTTPClient http;
http.begin(WEBHOOK_URL);
http.addHeader("Content-Type", "application/json");
http.setTimeout(4000);
int code = http.POST(payload);
Serial.printf("Webhook HTTP status: %d\n", code);
http.end();
}
For a real deployment, add a device key or signed request, TLS certificate validation, reconnect backoff, sensor-failure detection, and a monotonic event ID. Avoid putting secrets in public firmware repositories.
6. n8n workflow
Create a workflow with these nodes:
Webhook (POST)
↓
Validate fields / reject malformed payloads
↓
Set timestamp and derive event severity
↓
Google Sheets: append row
↓
IF status is ALERT
├── Gmail: send email
├── Telegram: send text message
└── Optional AI message → text-to-speech → Telegram audio
- Webhook: Create a POST webhook and copy its production URL into the ESP32 sketch.
- Validation: Check that required fields exist and are within plausible ranges. Reject malformed or oversized requests.
- Classification: Use deterministic rules for alarm status. Keep the thresholds in the workflow or firmware and document their units.
- Google Sheets: Append timestamp, device ID, sensor readings, status, and event ID to a sheet.
- Gmail: Send an email only for relevant events; include device, time, measured value, and recommended human verification.
- Telegram: Send a concise alert through a Telegram bot. Store the bot token in n8n credentials, not in the webpage or public code.
- Optional voice: Pass a short, fixed-format alert to a text-to-speech service and send its audio file using Telegram. Make this a secondary notification channel.
- Reliability: Configure retries and error handling; prevent duplicate alerts using event IDs or a cooldown period.
The AI agent may rewrite a validated event into readable language, but it should not invent measurements, set thresholds, suppress alarms, or control equipment. Include the original sensor values in every alert.
7. Local webpage
A simple local dashboard can display current values and status. Serve it from the ESP32 or from a separate local host. For a prototype, show readings, last update time, and Wi-Fi status. Protect any control endpoints; preferably make the dashboard read-only. Do not expose an unauthenticated ESP32 web server directly to the public internet.
8. Build and test steps
- Assemble the ESP32 and one sensor at a time; verify voltage levels and common ground.
- Upload a sensor-only test sketch and check serial readings.
- Confirm sensor polarity and response using safe, controlled tests.
- Configure Wi-Fi and the n8n webhook; verify a test JSON arrives.
- Add validation and Google Sheets logging, then check timestamps and column order.
- Add Gmail and Telegram notifications; test with a harmless test event.
- Add the optional AI wording and voice path only after deterministic alerts work.
- Test network loss, sensor disconnection, duplicate events, and n8n failure.
- Record the final wiring, pin mapping, thresholds, calibration notes, and known limitations.
9. Suggested project documentation
Include the project objective, block diagram, circuit and pin table, component list, firmware, n8n workflow export, Google Sheet column definitions, test cases, threshold rationale, security notes, and limitations. The prototype can demonstrate remote monitoring and event notifications, but sensor readings and thresholds must be validated for the actual environment before any safety use.








No comments:
Post a Comment