AI-Powered Railway Accident Prevention & Crack Detection System
Agentic IoT using ESP32 + AI + n8n Automation + Telegram Voice Alerts + Google Sheets + ThingSpeak Cloud Dashboard
Complete project documentation IoT + AI + Automation
This project is designed as an intelligent railway track condition monitoring and early-warning system. It combines an ESP32 microcontroller, IoT sensors, AI-based anomaly analysis, n8n workflow automation, Telegram notifications with voice alerts, Google Sheets data logging, and a ThingSpeak cloud dashboard.
The main objective is to identify unusual track conditions, monitor vibration and environmental changes, record suspected defects, and immediately notify railway maintenance personnel.
Important engineering distinction: A low-cost ESP32 sensor prototype can demonstrate condition monitoring and anomaly detection, but it cannot certify the presence or absence of structural rail cracks. Actual railway crack inspection requires validated non-destructive testing (NDT), such as qualified ultrasonic inspection, and professional railway engineering procedures. This project must remain a supplementary research and educational prototype, not a railway signalling, braking, or safety-control system.
1. Project overview
Project title
AI-Based Railway Accident Prevention and Crack Detection Monitoring System Using ESP32, Agentic IoT, n8n Automation and Telegram Voice Alerts.
Technologies used
|
Component |
Technology |
|---|---|
|
Microcontroller |
ESP32 |
|
Programming |
Arduino IDE / C++ |
|
Sensor monitoring |
Vibration, temperature, environmental sensors |
|
Crack inspection research |
Ultrasonic NDT / simulated defect inputs |
|
IoT communication |
Wi-Fi, HTTP, MQTT |
|
Automation |
n8n |
|
AI analysis |
AI agent / LLM through n8n |
|
Mobile alerts |
Telegram Bot |
|
Voice notification |
Telegram audio message |
|
Data storage |
Google Sheets |
|
Cloud dashboard |
ThingSpeak |
|
Web interface |
HTML, CSS, JavaScript |
|
Backend |
n8n Webhook |
|
Power |
Regulated DC supply |
Main objectives
-
Monitor railway track vibration and abnormal movement.
-
Identify unusual sensor patterns.
-
Detect possible anomalies that need inspection.
-
Send sensor data to an IoT cloud platform.
-
Use AI to summarize and classify monitoring events.
-
Automate alerts through n8n.
-
Send Telegram text and voice notifications.
-
Save historical readings in Google Sheets.
-
Display sensor readings and trends on ThingSpeak.
-
Provide a webpage for monitoring sensor status and event history.
2. Complete system architecture
The project consists of six major layers.
System architecture
RAILWAY TRACK MONITORING
Vibration • Temperature • Environmental monitoring • Inspection data
ESP32 IoT CONTROLLER
Sensor acquisition • Filtering • Threshold checks • Wi-Fi transmission
CLOUD COMMUNICATION
HTTP / Webhook • ThingSpeak • n8n
n8n AUTOMATION + AI AGENT
Data validation • Anomaly classification • Event management • Alert generation
Telegram
Text and voice alerts
Google Sheets
Event history and reports
ThingSpeak
Cloud graphs
IoT Webpage
Live monitoring
How the complete system works
-
Sensors collect measurements from a laboratory track model or approved monitoring test setup.
-
ESP32 reads the sensor values.
-
ESP32 applies basic filtering and threshold checks.
-
ESP32 sends the readings to n8n through an HTTP webhook.
-
n8n validates the data.
-
An AI agent generates a human-readable interpretation of the event.
-
n8n sends alerts to Telegram.
-
An optional text-to-speech service generates an audio announcement.
-
Google Sheets stores the readings.
-
ThingSpeak visualizes the sensor history.
-
The webpage displays the latest monitoring status.
3. Hardware components required
|
No. |
Component |
Quantity |
Purpose |
|---|---|---|---|
|
1 |
ESP32 DevKit V1 |
1 |
Main controller |
|
2 |
ADXL345 accelerometer |
1 |
Vibration and acceleration monitoring |
|
3 |
SW-420 vibration module |
1 |
Basic vibration event input |
|
4 |
DS18B20 |
1 |
Temperature monitoring |
|
5 |
HC-SR04 |
1 |
Demonstration of distance/displacement changes |
|
6 |
Breadboard |
1 |
Circuit assembly |
|
7 |
Jumper wires |
As needed |
Connections |
|
8 |
USB power supply |
1 |
ESP32 power |
|
9 |
Wi-Fi connection |
1 |
Internet communication |
|
10 |
Optional ultrasonic NDT instrument |
1 |
Qualified rail inspection research |
Important: HC-SR04, SW-420 and ADXL345 are demonstration sensors, not railway crack-detection instruments. In particular, an accelerometer detects motion and vibration, not an internal rail fracture. Do not connect a hobby ultrasonic module to a rail and interpret its distance measurement as proof of structural integrity.
3.1 Sensor descriptions
A. ADXL345 accelerometer
Measures acceleration on three axes:
-
X-axis acceleration
-
Y-axis acceleration
-
Z-axis acceleration
It can be used to monitor changes in vibration and movement.
B. SW-420 vibration sensor
Detects vibration events. It is useful for basic demonstrations, but it does not provide calibrated structural measurements.
C. DS18B20 temperature sensor
Monitors temperature changes in the demonstration environment.
D. Ultrasonic testing
Professional ultrasonic NDT uses suitable transducers, coupling, calibration standards, inspection procedures and qualified interpretation. For this project, inspection results can be entered as externally verified inspection observations.
4. Circuit and schematic diagram
4.1 ESP32 connection table
The following is a low-voltage laboratory demonstration circuit.
|
Sensor |
Sensor pin |
ESP32 pin |
|---|---|---|
|
ADXL345 |
VCC |
3.3V |
|
ADXL345 |
GND |
GND |
|
ADXL345 |
SDA |
GPIO 21 |
|
ADXL345 |
SCL |
GPIO 22 |
|
SW-420 |
VCC |
3.3V |
|
SW-420 |
GND |
GND |
|
SW-420 |
DO |
GPIO 27 |
|
DS18B20 |
VCC |
3.3V |
|
DS18B20 |
GND |
GND |
|
DS18B20 |
DATA |
GPIO 4 |
Add a 4.7 kΩ pull-up resistor between DS18B20 DATA and 3.3V.
Electrical precautions: Do not connect a 5V sensor output directly to an ESP32 GPIO. Check each sensor's electrical specifications and use appropriate level shifting where required. Avoid installing hobby electronics on operational railway infrastructure.
4.2 Schematic diagram
The following simplified connection drawing shows the wiring concept:
USB 5V
|
+-------------+
| ESP32 |
| |
3.3V ------+-------------+------------------+
| | |
GPIO 21 <---+---- SDA | DS18B20 DATA
GPIO 22 <---+---- SCL | |
GPIO 27 <---+---- DO | 4.7KΩ
GPIO 4 <---+-------------+ |
| 3.3V
+-------------+
| GND
|
+---------+----------+
| | |
ADXL345 SW-420 DS18B20
| | |
+---------+----------+
GND
4.3 Complete data-flow diagram
flowchart TD
A[Railway Monitoring Test Setup] --> B[ADXL345]
A --> C[SW-420]
A --> D[DS18B20]
B --> E[ESP32 Controller]
C --> E
D --> E
E --> F[Filtering and Data Validation]
F --> G[Wi-Fi HTTP Request]
G --> H[n8n Webhook]
H --> I[Validate Incoming Data]
I --> J[AI Event Analysis]
J --> K{Event Classification}
K -->|Normal| L[Store Monitoring Data]
K -->|Warning| M[Telegram Warning]
K -->|Critical Suspected Anomaly| N[Urgent Human Inspection Alert]
L --> O[Google Sheets]
L --> P[ThingSpeak]
M --> O
N --> O
O --> Q[IoT Web Dashboard]
P --> Q
5. Software architecture and installation
The software is divided into five parts.
|
Software |
Role |
|---|---|
|
Arduino IDE |
ESP32 programming |
|
n8n |
Workflow automation |
|
AI API |
Event interpretation |
|
Telegram Bot |
Notifications |
|
Google Sheets + ThingSpeak |
Data storage and visualization |
Step 1: Install Arduino IDE
Download: Arduino IDE official website
Then:
-
Install Arduino IDE.
-
Open Preferences.
-
Add the ESP32 board manager URL if it is not already configured.
-
Open Boards Manager.
-
Search for ESP32.
-
Install the Espressif ESP32 package.
-
Select your ESP32 development board.
-
Select the correct COM port.
Step 2: Install libraries
Open Arduino IDE → Library Manager.
Install:
-
Adafruit ADXL345
-
Adafruit Unified Sensor
-
OneWire
-
DallasTemperature
-
ArduinoJson
Step 3: Configure Wi-Fi
You will need:
-
Wi-Fi SSID
-
Wi-Fi password
-
ESP32 board
-
n8n webhook URL
Step 4: Create an n8n account
Use either a self-hosted installation or the hosted service.
n8n is the automation engine connecting the ESP32 to AI, Telegram, Google Sheets and other cloud services.
6. ESP32 programming – complete starter code
This firmware demonstrates sensor acquisition, basic anomaly screening and sending data to an n8n webhook.
It is deliberately a monitoring-only implementation. It does not calculate rail crack dimensions or make railway safety decisions.
6.1 ESP32 Arduino code
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <ArduinoJson.h>
// -------- WiFi configuration --------
const char* WIFI_SSID = "YOUR_WIFI_NAME";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
// -------- n8n webhook --------
const char* WEBHOOK_URL =
"https://YOUR_N8N_HOST/webhook/rail-monitor";
// -------- Sensor pins --------
#define VIBRATION_PIN 27
#define TEMP_PIN 4
Adafruit_ADXL345_Unified accel =
Adafruit_ADXL345_Unified(12345);
OneWire oneWire(TEMP_PIN);
DallasTemperature tempSensor(&oneWire);
unsigned long previousMillis = 0;
const unsigned long interval = 10000;
// Demonstration thresholds only.
// Calibrate for your laboratory setup.
const float VIBRATION_THRESHOLD = 15.0;
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
Serial.print("Connecting");
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED &&
millis() - start < 20000) {
delay(500);
Serial.print(".");
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.println("WiFi connected");
Serial.println(WiFi.localIP());
} else {
Serial.println("WiFi unavailable");
}
}
void setup() {
Serial.begin(115200);
pinMode(VIBRATION_PIN, INPUT);
Wire.begin(21, 22);
if (!accel.begin()) {
Serial.println("ADXL345 not detected");
} else {
accel.setRange(ADXL345_RANGE_16_G);
Serial.println("ADXL345 initialized");
}
tempSensor.begin();
connectWiFi();
}
void sendData(
float ax,
float ay,
float az,
float temperature,
int vibration,
bool anomaly
) {
if (WiFi.status() != WL_CONNECTED) {
connectWiFi();
}
if (WiFi.status() != WL_CONNECTED) {
Serial.println("No network; data not transmitted");
return;
}
HTTPClient http;
http.begin(WEBHOOK_URL);
http.addHeader("Content-Type", "application/json");
JsonDocument doc;
doc["device_id"] = "RAIL-ESP32-01";
doc["ax"] = ax;
doc["ay"] = ay;
doc["az"] = az;
doc["temperature"] = temperature;
doc["vibration"] = vibration;
doc["anomaly"] = anomaly;
doc["status"] = anomaly ? "WARNING" : "NORMAL";
String payload;
serializeJson(doc, payload);
int responseCode = http.POST(payload);
Serial.print("HTTP response: ");
Serial.println(responseCode);
http.end();
}
void loop() {
if (millis() - previousMillis >= interval) {
previousMillis = millis();
sensors_event_t event;
accel.getEvent(&event);
float ax = event.acceleration.x;
float ay = event.acceleration.y;
float az = event.acceleration.z;
tempSensor.requestTemperatures();
float temperature =
tempSensor.getTempCByIndex(0);
int vibration = digitalRead(VIBRATION_PIN);
float magnitude = sqrt(
ax * ax + ay * ay + az * az
);
bool anomaly =
(magnitude > VIBRATION_THRESHOLD);
Serial.println("----- RAIL MONITOR -----");
Serial.printf("X: %.2f\n", ax);
Serial.printf("Y: %.2f\n", ay);
Serial.printf("Z: %.2f\n", az);
Serial.printf(
"Temperature: %.2f C\n", temperature
);
Serial.printf(
"Vibration input: %d\n", vibration
);
Serial.printf(
"Acceleration magnitude: %.2f\n",
magnitude
);
Serial.println(
anomaly ? "WARNING" : "NORMAL"
);
sendData(
ax, ay, az,
temperature,
vibration,
anomaly
);
}
}
6.2 How the code works
-
ESP32 connects to the Wi-Fi network.
-
ADXL345 measures acceleration.
-
DS18B20 measures temperature.
-
SW-420 provides a digital vibration input.
-
ESP32 calculates acceleration magnitude.
-
The example compares the magnitude against a demonstration threshold.
-
Data is packaged as JSON.
-
HTTP POST sends the JSON to n8n.
Example JSON message:
{
"device_id": "RAIL-ESP32-01",
"ax": 0.45,
"ay": 0.32,
"az": 9.81,
"temperature": 32.5,
"vibration": 0,
"anomaly": false,
"status": "NORMAL"
}
Technical limitation: This example uses instantaneous acceleration magnitude, including gravity, rather than calibrated vibration RMS or frequency-domain analysis. The threshold is illustrative and must not be treated as a crack-detection threshold. A research-grade vibration system should use calibrated sampling, baseline comparison, filtering, RMS/FFT features and repeatability testing.
7. n8n workflow automation
This is the main automation section of the project.
7.1 Create a webhook
-
Open n8n.
-
Create a new workflow.
-
Add a Webhook node.
-
Set HTTP Method to
POST. -
Set Path to
rail-monitor. -
Set response mode to respond to webhook.
-
Save the workflow.
-
Activate the workflow when ready.
Your endpoint will resemble:
https://YOUR_N8N_HOST/webhook/rail-monitor
Use the test URL while developing and the production URL when the workflow is active.
7.2 Complete n8n workflow diagram
flowchart TD
A[Webhook: ESP32 Data] --> B[Validate JSON]
B --> C[Extract Sensor Values]
C --> D[IF: Anomaly or Invalid Data?]
D -->|No anomaly| E[Google Sheets: Append Row]
D -->|Anomaly| F[AI Agent: Analyze Event]
F --> G[Structured Event Summary]
G --> H[Google Sheets: Append Row]
G --> I[Telegram Text Alert]
G --> J[Text-to-Speech Service]
J --> K[Telegram Voice Message]
E --> L[ThingSpeak Update]
H --> L
L --> M[Webhook Response]
I --> M
K --> M
7.3 Required n8n nodes
|
Node |
Function |
|---|---|
|
Webhook |
Receives ESP32 readings |
|
Edit Fields |
Extracts and prepares values |
|
IF |
Checks event conditions |
|
AI Agent |
Summarizes monitoring anomalies |
|
Google Sheets |
Saves readings |
|
HTTP Request |
Sends readings to ThingSpeak |
|
Telegram |
Sends text alerts |
|
HTTP Request / TTS |
Generates voice audio |
|
Telegram |
Sends generated audio |
|
Respond to Webhook |
Returns HTTP response |
7.4 Configure the IF node
Create a condition based on:
{{ $json.body.anomaly === true }}
-
True: send the event for further investigation.
-
False: record the normal reading.
Also validate that all required fields are present and numeric. A missing sensor reading must not be interpreted as a normal reading.
7.5 Configure the AI Agent
The AI agent should summarize the data and recommend a human inspection. It should not independently authorize a railway track as safe or unsafe.
Example AI system instruction:
You are a Railway Condition Monitoring Assistant.
Your responsibility is to analyze laboratory and
supplementary railway monitoring sensor readings.
You receive:
- Device ID
- X, Y and Z acceleration
- Temperature
- Vibration event
- Sensor health information
Your tasks:
1. Summarize the sensor readings.
2. Identify unusual patterns.
3. Classify the observation as NORMAL,
WARNING or SENSOR_FAULT.
4. Explain which sensor triggered the event.
5. Recommend a human engineering inspection
when unusual measurements are observed.
6. Clearly state when data is insufficient.
Important restrictions:
- Never claim that a rail is crack-free.
- Never calculate actual crack dimensions from
ordinary vibration measurements.
- Never declare railway infrastructure safe.
- Never control railway signalling or braking.
- Never suppress an alert based on an AI opinion.
- Treat missing, stale or invalid data as
a monitoring fault requiring investigation.
Output structured JSON only.
Example AI output:
{
"classification": "WARNING",
"device_id": "RAIL-ESP32-01",
"observation": "Unusual acceleration reading detected.",
"reason": "Acceleration exceeded the configured demonstration threshold.",
"recommended_action": "Arrange human inspection of the test setup.",
"confidence": "Not calibrated",
"infrastructure_safety_status": "NOT ASSESSED"
}
8. Telegram notification and voice alert system
The Telegram bot sends immediate messages when the monitoring system identifies an unusual sensor reading.
8.1 Create a Telegram bot
-
Open Telegram.
-
Search for
@BotFather. -
Start a conversation.
-
Send
/newbot. -
Enter a bot name.
-
Enter a username ending in
bot. -
Copy the generated bot token.
-
Keep the token private.
Official website: Telegram Bot API documentation .
8.2 Obtain your chat ID
-
Open your new bot.
-
Press Start.
-
Send a test message.
-
Use Telegram's Bot API
getUpdatesmethod to identify your chat ID. -
Store it in n8n credentials or secure configuration.
Do not publish your bot token in your Arduino source code, public webpage or GitHub repository.
8.3 Configure Telegram text notification
In n8n:
-
Add Telegram node.
-
Select Send Message.
-
Configure bot credentials.
-
Enter your chat ID.
-
Set the message using the AI output.
Example notification:
Railway Monitoring Bot
Example
AI Railway Monitoring Alert
-
Device: RAIL-ESP32-01
-
Event: Unusual vibration
-
Acceleration: 15.8 m/s²
-
Temperature: 32.5°C
-
Time: 14:25:30
AI observation: An unusual acceleration reading was detected.
Recommended action: Arrange human inspection of the test setup and verify sensor operation.
This is a supplementary monitoring alert, not a certified railway safety determination.
8.4 Telegram voice notifications
The voice alert feature can convert the AI-generated text into speech.
Voice notification workflow
flowchart TD
A[AI Agent Output] --> B[Prepare Alert Text]
B --> C[Text-to-Speech API]
C --> D[Generate MP3 or OGG Audio]
D --> E[Telegram Send Audio]
E --> F[Maintenance Team Receives Voice Alert]
Example voice message:
Attention! Railway monitoring warning. Unusual vibration has been detected by monitoring device RAIL-ESP32-01. Please arrange a human inspection and verify the sensor readings. This is a supplementary monitoring alert.
How to configure this in n8n
-
Connect the AI Agent output to an Edit Fields node.
-
Create a field named
alert_text. -
Pass the text to a compatible text-to-speech service.
-
Configure the service to return an MP3 or OGG file.
-
Send the generated binary audio to Telegram.
-
Use Telegram's Send Audio or Send Voice node, depending on the desired format.
The TTS service can be selected based on available credentials and pricing. The AI Agent creates the announcement; the TTS service converts it into speech.
9. Google Sheets integration
Google Sheets is used as the historical database for sensor measurements and alerts.
9.1 Create a spreadsheet
Create a Google Sheet named:
AI_Railway_Monitoring_System
Create the following columns:
|
Column |
Field |
|---|---|
|
A |
Timestamp |
|
B |
Device_ID |
|
C |
Acceleration_X |
|
D |
Acceleration_Y |
|
E |
Acceleration_Z |
|
F |
Temperature |
|
G |
Vibration |
|
H |
Anomaly |
|
I |
AI_Classification |
|
J |
AI_Observation |
|
K |
Recommended_Action |
9.2 Configure Google Sheets in n8n
-
Add Google Sheets node.
-
Connect Google account credentials.
-
Select your spreadsheet.
-
Select the worksheet.
-
Choose Append Row.
-
Map the incoming JSON fields to spreadsheet columns.
-
Test the workflow.
Example data:
|
Time |
Device |
Temperature |
Anomaly |
Classification |
|---|---|---|---|---|
|
10:00 |
RAIL-01 |
30.2 |
False |
NORMAL |
|
10:01 |
RAIL-01 |
31.1 |
False |
NORMAL |
|
10:02 |
RAIL-01 |
32.5 |
True |
WARNING |
|
10:03 |
RAIL-01 |
32.2 |
False |
NORMAL |
This information can be used for:
-
Historical analysis.
-
Daily monitoring reports.
-
Sensor performance evaluation.
-
Maintenance inspection records.
-
Research project documentation.
10. ThingSpeak cloud dashboard
ThingSpeak provides an IoT cloud platform for storing and visualizing measurements.
Website: ThingSpeak official platform .
10.1 Create a ThingSpeak channel
-
Create a ThingSpeak account.
-
Open Channels.
-
Select New Channel.
-
Enter channel name:
Railway Monitoring. -
Enable these fields:
|
Field |
Name |
|---|---|
|
Field 1 |
Acceleration X |
|
Field 2 |
Acceleration Y |
|
Field 3 |
Acceleration Z |
|
Field 4 |
Temperature |
|
Field 5 |
Vibration |
|
Field 6 |
Anomaly |
-
Save the channel.
-
Open API Keys.
-
Copy the Write API Key.
-
Keep the API key private.
10.2 Send ESP32 data to ThingSpeak through n8n
Add an HTTP Request node after your data validation node.
Configure:
|
Setting |
Value |
|---|---|
|
Method |
GET |
|
URL |
|
|
Query parameter |
|
|
Query parameter |
|
|
Query parameter |
|
|
Query parameter |
|
|
Query parameter |
|
|
Query parameter |
|
|
Query parameter |
|
Use expressions for the incoming values:
field1 = {{ $json.body.ax }}
field2 = {{ $json.body.ay }}
field3 = {{ $json.body.az }}
field4 = {{ $json.body.temperature }}
field5 = {{ $json.body.vibration }}
field6 = {{ $json.body.anomaly ? 1 : 0 }}
Use the actual API key through secure n8n credentials or protected configuration.
Note: ThingSpeak channels have update-rate restrictions. For a standard free channel, the minimum update interval is generally 15 seconds. Configure your ESP32 and workflow accordingly.
10.3 Dashboard visualization
Create the following graphs:
-
X-axis acceleration graph.
-
Y-axis acceleration graph.
-
Z-axis acceleration graph.
-
Temperature monitoring graph.
-
Vibration event graph.
-
Anomaly event graph.
The dashboard provides historical trends and supports the monitoring webpage.
11. AI-powered IoT webpage
The webpage is the main user interface for the project.
It displays:
-
Device connection status.
-
Current sensor values.
-
Acceleration readings.
-
Temperature.
-
Vibration status.
-
Latest monitoring event.
-
AI observation.
-
Cloud monitoring information.
11.1 Webpage architecture
flowchart TD
A[ESP32 Sensors] --> B[n8n Webhook]
B --> C[Data Processing]
C --> D[Google Sheets]
C --> E[ThingSpeak]
C --> F[AI Analysis]
F --> G[Event Summary]
D --> H[Webpage]
E --> H
G --> H
H --> I[Monitoring Dashboard]
11.2 Example webpage code
This is a simple standalone dashboard. It uses the public ThingSpeak channel's read API for graph-independent latest-reading display. Configure your own channel ID and read key.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width,initial-scale=1">
<title>AI Railway Monitoring Dashboard</title>
<style>
body {
font-family: Arial, sans-serif;
background: #101827;
color: white;
margin: 0;
padding: 20px;
}
h1 { color: #54c7ec; }
.grid {
display: grid;
grid-template-columns:
repeat(auto-fit,minmax(190px,1fr));
gap: 15px;
}
.card {
background: #1e2b40;
padding: 20px;
border-radius: 12px;
}
.value {
font-size: 27px;
color: #54c7ec;
margin-top: 12px;
}
.status {
padding: 10px;
background: #244d37;
border-radius: 8px;
}
.warning {
background: #73441e;
}
small { color: #b6c5d9; }
</style>
</head>
<body>
<h1>🚆 AI Railway Monitoring System</h1>
<p>ESP32 + IoT + AI + n8n Automation</p>
<div class="status" id="connection">
Connecting to cloud...
</div>
<div class="grid">
<div class="card">
<h3>Acceleration X</h3>
<div class="value" id="ax">--</div>
<small>m/s²</small>
</div>
<div class="card">
<h3>Acceleration Y</h3>
<div class="value" id="ay">--</div>
<small>m/s²</small>
</div>
<div class="card">
<h3>Acceleration Z</h3>
<div class="value" id="az">--</div>
<small>m/s²</small>
</div>
<div class="card">
<h3>Temperature</h3>
<div class="value" id="temp">--</div>
<small>°C</small>
</div>
<div class="card">
<h3>Vibration</h3>
<div class="value" id="vibration">--</div>
</div>
<div class="card">
<h3>Monitoring Event</h3>
<div class="value" id="event">--</div>
</div>
</div>
<h2>Latest Monitoring Information</h2>
<div class="card">
<p id="lastUpdate">Waiting for data...</p>
<p id="description">
Monitoring data has not yet arrived.
</p>
</div>
<script>
// Configure your own ThingSpeak channel
const CHANNEL_ID = "YOUR_CHANNEL_ID";
const READ_KEY = "YOUR_READ_API_KEY";
async function updateDashboard() {
const url =
`https://api.thingspeak.com/channels/${CHANNEL_ID}/feeds/last.json?api_key=${READ_KEY}`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error("Cloud request failed");
}
const data = await response.json();
document.getElementById("ax").textContent =
data.field1 ?? "--";
document.getElementById("ay").textContent =
data.field2 ?? "--";
document.getElementById("az").textContent =
data.field3 ?? "--";
document.getElementById("temp").textContent =
data.field4 ?? "--";
document.getElementById("vibration").textContent =
data.field5 ?? "--";
const anomaly = Number(data.field6);
const event = document.getElementById("event");
event.textContent =
anomaly === 1 ? "WARNING" : "NORMAL";
event.parentElement.className =
anomaly === 1 ? "card warning" : "card";
document.getElementById("connection")
.textContent = "Cloud connected";
document.getElementById("lastUpdate")
.textContent =
"Last update: " + data.created_at;
document.getElementById("description")
.textContent =
anomaly === 1
? "An unusual monitoring event was recorded. Human inspection is required."
: "No configured anomaly flag was reported in the latest cloud reading.";
} catch (error) {
document.getElementById("connection")
.textContent = "Cloud connection unavailable";
document.getElementById("description")
.textContent =
"Unable to retrieve the latest sensor readings.";
}
}
// Initial reading and periodic refresh
updateDashboard();
setInterval(updateDashboard, 20000);
</script>
</body>
</html>
11.3 Webpage limitations
This dashboard is a basic read-only example. It does not provide:
-
Authenticated maintenance-user accounts.
-
A secure backend.
-
Historical event filtering.
-
Role-based access.
-
A validated AI decision record.
-
Real-time streaming.
For a production-quality demonstration, use a private backend or authenticated API rather than exposing private cloud read keys in browser JavaScript.
12. Complete project workflow – from sensor to voice notification
sequenceDiagram
participant S as Sensors
participant E as ESP32
participant N as n8n
participant A as AI Agent
participant T as Telegram
participant G as Google Sheets
participant C as ThingSpeak
participant W as Web Dashboard
S->>E: Sensor readings
E->>N: JSON over HTTP
N->>N: Validate sensor data
N->>A: Send event context
A-->>N: Classification and explanation
N->>G: Append monitoring record
N->>C: Update cloud channel
N->>T: Send text alert
N->>T: Send voice notification
C-->>W: Latest cloud measurements
G-->>W: Historical records through backend
W->>W: Display monitoring status
Example operating scenarios
|
Scenario |
System response |
|---|---|
|
Normal vibration |
Record data |
|
Unusual vibration |
Generate warning |
|
Temperature anomaly |
Record and notify |
|
Sensor disconnected |
Sensor fault notification |
|
Wi-Fi disconnected |
Local monitoring continues; flag communication loss |
|
AI service unavailable |
Preserve raw readings and use deterministic rules |
|
Cloud unavailable |
Buffer data locally if storage is provided |
A particularly important design feature is that the AI service must never be the only alerting mechanism. Deterministic monitoring rules and sensor-fault detection should operate independently of AI availability.
13. Project testing and implementation
Before presenting the project, test each component independently.
13.1 Testing procedure
|
Test |
Input |
Expected output |
|---|---|---|
|
Test 1 |
ESP32 powered ON |
ESP32 starts |
|
Test 2 |
Wi-Fi available |
Connected |
|
Test 3 |
ADXL345 connected |
Acceleration readings |
|
Test 4 |
DS18B20 connected |
Temperature readings |
|
Test 5 |
Vibration input activated |
Vibration event |
|
Test 6 |
Webhook receives JSON |
n8n executes |
|
Test 7 |
Anomaly flag enabled |
Warning workflow |
|
Test 8 |
Telegram configured |
Text notification |
|
Test 9 |
TTS configured |
Voice notification |
|
Test 10 |
Google Sheets connected |
New row inserted |
|
Test 11 |
ThingSpeak connected |
New graph point |
|
Test 12 |
Webpage opened |
Latest readings displayed |
13.2 Sample expected output
ESP32 serial monitor
Example normal condition
WiFi connected
ADXL345 initialized
----- RAIL MONITOR -----
X: 0.45
Y: 0.32
Z: 9.81
Temperature: 30.50 C
Vibration input: 0
Acceleration magnitude: 9.83
NORMAL
HTTP response: 200
Example warning condition
----- RAIL MONITOR -----
X: 12.50
Y: 4.20
Z: 9.10
Temperature: 32.50 C
Vibration input: 1
Acceleration magnitude: 15.97
WARNING
HTTP response: 200
14. AI agentic automation – advanced features
To make this project more than a basic IoT monitoring system, you can add the following agentic features.
|
AI capability |
Function |
|---|---|
|
Event interpretation |
Explain unusual readings |
|
Pattern analysis |
Compare readings with historical baselines |
|
Maintenance assistance |
Generate inspection recommendations |
|
Automated reporting |
Prepare daily reports |
|
Voice notification |
Announce important monitoring events |
|
Fault analysis |
Identify missing or inconsistent sensor data |
|
Trend analysis |
Identify recurring monitoring abnormalities |
Suggested AI agent workflow
flowchart TD
A[Incoming Sensor Data] --> B[Data Quality Agent]
B --> C[Anomaly Analysis Agent]
C --> D[Historical Comparison]
D --> E[Event Summary Agent]
E --> F[Human Review Queue]
F --> G[Telegram Notification]
F --> H[Maintenance Report]
H --> I[Google Sheets]
H --> J[Dashboard]
Recommended architecture: Keep AI agents advisory. Use deterministic rules for event triggering, independent watchdogs for communication faults, and human approval for maintenance decisions. Do not let an LLM autonomously modify railway infrastructure or control railway operations.
15. Project security
Since the system uses cloud services and remote communication, security is important.
-
Use HTTPS for webhook communication.
-
Use a secret authentication key for the ESP32 webhook.
-
Store API keys in n8n credentials.
-
Never publish Wi-Fi passwords.
-
Never expose Telegram bot tokens.
-
Protect Google Sheets access.
-
Use private ThingSpeak channels when appropriate.
-
Validate incoming JSON.
-
Reject malformed or stale sensor readings.
-
Keep event timestamps.
-
Maintain local records when the internet is unavailable.
-
Apply rate limiting and duplicate-alert suppression.
For an actual railway deployment, cybersecurity and functional safety would require a separate professional assessment.
16. Limitations and future enhancements
Current prototype limitations
-
Low-cost vibration sensors cannot reliably identify internal rail cracks.
-
Vibration anomalies may be caused by external disturbances.
-
ESP32 Wi-Fi depends on network availability.
-
AI analysis can produce incorrect interpretations.
-
ThingSpeak and Google Sheets are not safety-critical real-time systems.
-
The example threshold requires calibration.
-
The prototype is not certified for railway use.
Future enhancements
1. Professional ultrasonic NDT integration
Incorporate externally validated inspection measurements and inspection records.
2. Advanced vibration analytics
Add calibrated RMS, FFT, frequency analysis and historical baseline comparisons.
3. AI computer vision
Analyze images of track surfaces for visible defects, with human verification.
4. Multiple ESP32 monitoring nodes
Add multiple identified devices for distributed laboratory monitoring.
5. Predictive maintenance
Study historical sensor trends to identify conditions that may require inspection.
17. Project abstract for college documentation
AI-Powered Railway Accident Prevention and Crack Detection Monitoring System Using ESP32, IoT, AI Agent and n8n Automation
Abstract
Railway infrastructure requires continuous inspection and maintenance to minimize the possibility of accidents caused by track deterioration and abnormal operating conditions. This project proposes an AI-powered railway condition monitoring prototype using ESP32, IoT sensors, cloud services and workflow automation.
The proposed system uses an ESP32 microcontroller connected to vibration, acceleration and temperature sensors to collect monitoring data from a laboratory railway track model or an approved test environment. The collected sensor readings are transmitted through Wi-Fi to an n8n automation platform using HTTP webhooks.
An AI agent processes the incoming monitoring information, identifies unusual sensor patterns and generates human-readable event summaries and inspection recommendations. When a monitoring anomaly or sensor fault is identified, n8n automatically initiates a notification workflow.
The system integrates Telegram for instant text notifications and generated voice alerts, Google Sheets for historical monitoring records, and ThingSpeak for cloud-based sensor visualization. A web-based dashboard provides a convenient interface for viewing the latest sensor measurements and monitoring events.
The proposed prototype demonstrates the integration of embedded systems, artificial intelligence, Internet of Things technology and agentic workflow automation. It aims to support early identification of abnormal monitoring conditions and improve maintenance awareness.
Actual railway crack verification requires qualified non-destructive testing equipment and validated inspection procedures. Therefore, the proposed system is intended as a supplementary educational and research prototype rather than a certified railway safety or accident-prevention control system.
Keywords
ESP32, Railway Monitoring, IoT, Artificial Intelligence, Agentic AI, n8n Automation, Vibration Monitoring, Crack Inspection, Telegram Voice Alerts, Google Sheets, ThingSpeak, Predictive Maintenance.
18. Suggested project report structure
For a final-year engineering project, organize your documentation into these chapters:
|
Chapter |
Title |
|---|---|
|
1 |
Introduction |
|
2 |
Existing System and Proposed System |
|
3 |
Literature Survey |
|
4 |
Hardware Requirements |
|
5 |
Software Requirements |
|
6 |
System Architecture |
|
7 |
Circuit Diagram and Connections |
|
8 |
ESP32 Programming |
|
9 |
IoT and Cloud Integration |
|
10 |
n8n Workflow Automation |
|
11 |
AI Agent Implementation |
|
12 |
Telegram Voice Alert System |
|
13 |
Google Sheets and ThingSpeak |
|
14 |
Web Dashboard |
|
15 |
Testing and Results |
|
16 |
Limitations |
|
17 |
Future Scope |
|
18 |
Conclusion |
|
19 |
References |
19. Official software and technical resources
These are useful resources for implementation:
20. Recommended final project demonstration
For your college presentation or project exhibition, I recommend demonstrating the system in this sequence:
Live project demonstration
-
Show the ESP32 hardware
Display the connected sensors and power up the monitoring system.
-
Show normal sensor readings
Display acceleration, temperature and vibration values in Serial Monitor.
-
Introduce a controlled test disturbance
Apply a repeatable vibration to the laboratory test fixture, not to operational railway infrastructure.
-
Show the anomaly event
Demonstrate how the ESP32 transmits the measurement to n8n.
-
Show AI analysis
Display the AI-generated event summary and inspection recommendation.
-
Show Telegram alerts
Demonstrate the text notification and generated voice announcement.
-
Show Google Sheets
Display the automatically recorded monitoring event.
-
Show ThingSpeak and the webpage
Demonstrate sensor graphs and the live monitoring dashboard.
21. Next step: prepare the complete implementation package
The documentation above provides the architecture, circuit plan, firmware starter, workflow design and webpage starter. To turn it into a complete buildable project, the remaining deliverables should be prepared together:
-
Complete ESP32 firmware with sensor filtering, calibration and fault handling.
-
Importable n8n workflow JSON with AI, Telegram, TTS, Sheets and ThingSpeak nodes.
-
Full responsive HTML/CSS/JavaScript dashboard.
-
Detailed pin-to-pin wiring diagram.
-
Google Sheets template.
-
ThingSpeak channel configuration.
-
Testing checklist and project presentation.
One important question: Is this project for a college final-year demonstration using a small railway track model, or are you planning research on actual railway track inspection?
That determines whether the next implementation should focus on a low-cost ESP32 prototype or integration with professional ultrasonic NDT inspection equipment.
AI Railway Accident Prevention & Crack Detection System
This project is an IoT-based railway safety prototype that monitors a model railway track for cracks, obstacles, abnormal vibration, and unsafe conditions using an ESP32. It sends sensor data to ThingSpeak, logs events in Google Sheets, and uses an n8n AI agent workflow to classify the event and send Telegram text + voice alerts. Railway prototypes commonly use ultrasonic distance sensing, IR crack sensing, vibration sensing, GPS, and cloud dashboards for this purpose.[ijarcce][jetir][ijert]
Safety note: This is an educational prototype, not a certified railway-safety product. Never deploy it on live railway infrastructure without approval, fail-safe design, and compliance with railway authority standards.
Project Overview
The ESP32 acts as the edge device. It reads sensors, runs local threshold/ML-based anomaly detection, displays status, sounds a buzzer, and posts data to the cloud. The n8n workflow receives the event, uses an AI agent to generate a clear incident report, creates a voice file, and notifies maintenance staff through Telegram. n8n’s Telegram node supports sending messages, audio, photos, documents, and location updates.[docs.n8n]
Main capabilities
- Detects simulated rail cracks using IR reflectance sensors.
- Detects surface deformation or obstacles using an HC-SR04 ultrasonic sensor.
- Detects abnormal vibration using MPU6050/GY-521.
- Measures temperature and humidity using DHT22.
- Adds GPS location for incident reporting using NEO-6M.
- Displays live status on an OLED and a local ESP32 web dashboard.
- Uploads readings to ThingSpeak for charts and remote monitoring.
- Logs every anomaly in Google Sheets.
- Sends Telegram text alerts and voice alerts through n8n.
- Uses an AI agent to summarize severity, likely cause, and recommended action.
- Activates a buzzer and warning LED locally.
System Architecture
┌──────────────────────────────┐
│ RAILWAY TRACK │
│ IR sensors / ultrasonic / │
│ vibration / DHT22 / GPS │
└───────────────┬──────────────┘
│
┌──────▼──────┐
│ ESP32 │
│ Edge AI + │
│ Web Server │
└──┬───────┬──┘
Buzzer/LED/OLED│ │Wi-Fi HTTP POST
│ │
┌───────────▼─┐ ┌─▼───────────────┐
│ Local Alarm │ │ ThingSpeak │
└─────────────┘ └─┬───────────────┘
│ Webhook / Read API
┌──────────▼──────────┐
│ n8n Cloud │
│ Webhook + AI Agent │
│ TTS + Telegram Bot │
└──────┬───────┬───────┘
│ │
┌────────────▼─┐ ┌─▼─────────────┐
│ Google Sheets │ │ Telegram App │
│ Incident Log │ │ Text + Voice │
└───────────────┘ └───────────────┘
Hardware Required
| Component | Purpose | Typical connection |
|---|---|---|
| ESP32 DevKit V1 | Main controller, Wi-Fi, web server | — |
| 2 × IR obstacle/reflectance sensors | Detect dark crack/gap on rail surface | Left: GPIO 34, Right: GPIO 35 |
| HC-SR04 ultrasonic sensor | Detect track gap, deformation, obstacle | TRIG: GPIO 5, ECHO: GPIO 18 |
| MPU6050 accelerometer/gyro | Detect vibration anomalies | SDA: GPIO 21, SCL: GPIO 22 |
| DHT22 | Temperature and humidity | DATA: GPIO 4 |
| NEO-6M GPS | Incident coordinates | GPS TX: GPIO 16, GPS RX: GPIO 17 |
| 0.96" OLED SSD1306 | Local status display | SDA: GPIO 21, SCL: GPIO 22 |
| Buzzer | Local audible alarm | GPIO 23 |
| Red LED | Fault indicator | GPIO 25 |
| Green LED | Normal indicator | GPIO 26 |
| 5 V relay/module, optional | Stop model train / signal | GPIO 27 |
| Breadboard, jumper wires, 5 V supply | Prototype assembly | — |
The ultrasonic sensor measures distance by transmitting a 10 microsecond trigger pulse and converting the echo pulse width into distance; it is widely used for crack, deformation, and obstacle detection in railway prototypes.[jetir][jetir]
Circuit Schematic
ESP32 DevKit
┌────────────────┐
IR LEFT OUT ───────► GPIO 34 │
IR RIGHT OUT ───────► GPIO 35 │
│
HC-SR04 TRIG ───────► GPIO 5 │
HC-SR04 ECHO ──[1k]──► GPIO 18 │
HC-SR04 ECHO ──[2k to GND] │
│
DHT22 DATA ──[10k to 3.3V]─► GPIO 4 │
│
MPU6050 SDA ─────────► GPIO 21 │
MPU6050 SCL ─────────► GPIO 22 │
│
NEO-6M TX ───────────► GPIO 16 │
NEO-6M RX ──[level shift]─► GPIO 17 │
│
OLED SDA ────────────► GPIO 21 │
OLED SCL ────────────► GPIO 22 │
│
Buzzer + ────────────► GPIO 23 │
Red LED + ──[220R]───► GPIO 25 │
Green LED + ─[220R]──► GPIO 26 │
Relay IN ────────────► GPIO 27 │
│
All sensor VCC → 3.3 V / 5 V as required
All GND → common GND
Important: HC-SR04 output is commonly 5 V. Use a voltage divider or logic-level converter on ECHO before connecting it to ESP32. The NEO-6M TX is usually 3.3 V-safe, but verify your module specification.
Detection Logic
The system uses a hybrid approach:
- Rule-based edge detection on ESP32 for immediate safety response.
- AI agent classification in n8n for context-aware reporting.
- Cloud analytics in ThingSpeak for trends and visualization.
Crack detection
IR reflectance sensors detect a sudden drop in reflected infrared light when the beam crosses a crack, gap, or dark discontinuity. A common prototype approach reads the sensor several times and marks a crack only if multiple readings agree, reducing false alarms.[ijert]
Normal rail: IR output HIGH
Crack/gap: IR output LOW
Decision: 3 or more LOW readings out of 5 = CRACK
Distance anomaly
The ultrasonic sensor measures distance to the rail surface. If the measured distance differs too much from a calibrated baseline, the system flags deformation, missing material, or an obstacle. HC-SR04 modules are typically specified for roughly 2 cm to 400 cm range.[jetir]
distance_deviation = |current_distance - baseline_distance|
if distance_deviation > 2.0 cm:
status = TRACK_DEFORMATION_OR_OBSTACLE
Vibration anomaly
The MPU6050 provides acceleration on X, Y, and Z axes. A moving inspection trolley or model train produces a baseline vibration level; sudden spikes may indicate a fault, loose joint, or impact. Similar railway IoT systems combine ultrasonic, vibration, and environmental data before sending status to ThingSpeak.[ijarcce]
vibration_magnitude = sqrt(ax² + ay² + az²)
if vibration_magnitude > threshold:
status = HIGH_VIBRATION
AI risk score
The ESP32 calculates a simple weighted risk score:
Risk = 0.40C + 0.30D + 0.20V + 0.10E
Where:
C= crack severity, 0 to 1D= distance/deformation severity, 0 to 1V= vibration severity, 0 to 1E= environmental severity, 0 to 1
| Risk score | AI classification | Action |
|---|---|---|
| 0.00–0.24 | NORMAL | Green LED, log normal reading |
| 0.25–0.49 | WARNING | Yellow/orange status, Telegram warning |
| 0.50–0.74 | HIGH RISK | Buzzer, Telegram text + voice alert |
| 0.75–1.00 | CRITICAL | Buzzer, relay stop, emergency Telegram voice alert |
Software Flowchart
┌─────────────┐
│ START │
└──────┬──────┘
▼
┌────────────────────────┐
│ Initialize Wi-Fi, │
│ sensors, OLED, GPS │
└───────────┬────────────┘
▼
┌────────────────────────┐
│ Read IR left/right │
│ Read ultrasonic │
│ Read MPU6050 │
│ Read DHT22 │
│ Read GPS │
└───────────┬────────────┘
▼
┌────────────────────────┐
│ Run crack detection │
│ Calculate distance │
│ Calculate vibration │
│ Calculate risk score │
└───────────┬────────────┘
▼
┌─────────────┐
│ Risk > 0.25?│
└──┬───────┬──┘
Yes │ │ No
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ Activate buzzer/ │ │ Green LED │
│ red LED/relay │ │ Send to │
│ Send event to │ │ ThingSpeak │
│ n8n webhook │ └──────────────────┘
└────────┬─────────┘
▼
┌──────────────────────────┐
│ n8n AI Agent analyzes │
│ event and severity │
└────────────┬─────────────┘
▼
┌──────────────────────────┐
│ Append row to Google │
│ Sheets │
└────────────┬─────────────┘
▼
┌──────────────────────────┐
│ Generate voice alert │
│ Send Telegram message │
│ Send Telegram voice │
└────────────┬─────────────┘
▼
┌─────────┐
│ LOOP │
└─────────┘
ESP32 Arduino Code
Install these Arduino libraries:
WiFi.hHTTPClient.hAdafruit_GFXAdafruit_SSD1306Adafruit MPU6050DHT sensor libraryTinyGPSPlusArduinoJson
/*
* AI Railway Accident Prevention & Crack Detection System
* ESP32 + IR + Ultrasonic + MPU6050 + DHT22 + GPS
* ThingSpeak + n8n AI Agent + Telegram Voice Alerts
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <TinyGPSPlus.h>
#include <ArduinoJson.h>
// ---------- Wi-Fi ----------
const char* WIFI_SSID = "YOUR_WIFI_NAME";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
// ---------- ThingSpeak ----------
const char* THINGSPEAK_HOST = "api.thingspeak.com";
String THINGSPEAK_WRITE_KEY = "YOUR_THINGSPEAK_WRITE_KEY";
// ---------- n8n ----------
String N8N_WEBHOOK_URL = "https://YOUR_N8N_DOMAIN/webhook/railway-alert";
// ---------- Pins ----------
#define IR_LEFT_PIN 34
#define IR_RIGHT_PIN 35
#define TRIG_PIN 5
#define ECHO_PIN 18
#define DHT_PIN 4
#define BUZZER_PIN 23
#define RED_LED_PIN 25
#define GREEN_LED_PIN 26
#define RELAY_PIN 27
#define GPS_RX_PIN 16
#define GPS_TX_PIN 17
// ---------- Objects ----------
DHT dht(DHT_PIN, DHT22);
Adafruit_MPU6050 mpu;
Adafruit_SSD1306 display(128, 64, &Wire, -1);
TinyGPSPlus gps;
HardwareSerial gpsSerial(2);
// ---------- Calibration ----------
float baselineDistance = 10.0; // Set after calibration
float vibrationThreshold = 12.0;
// ---------- Variables ----------
float distanceCm = 0;
float temperatureC = 0;
float humidity = 0;
float ax = 0, ay = 0, az = 0;
float vibration = 0;
float lat = 0, lng = 0;
bool crackLeft = false;
bool crackRight = false;
bool crackDetected = false;
bool distanceFault = false;
bool vibrationFault = false;
float riskScore = 0;
String eventStatus = "NORMAL";
String severity = "LOW";
void setup() {
Serial.begin(115200);
gpsSerial.begin(9600, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
pinMode(IR_LEFT_PIN, INPUT);
pinMode(IR_RIGHT_PIN, INPUT);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(RED_LED_PIN, OUTPUT);
pinMode(GREEN_LED_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(RED_LED_PIN, LOW);
digitalWrite(GREEN_LED_PIN, HIGH);
digitalWrite(RELAY_PIN, LOW);
Wire.begin(21, 22);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED not found");
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Rail Safety AI");
display.println("Starting...");
display.display();
dht.begin();
if (!mpu.begin()) {
Serial.println("MPU6050 not found");
}
WiFi.begin(WIFI_SSID, WIFI_PASS);
Serial.print("Connecting Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWi-Fi connected:");
Serial.println(WiFi.localIP());
display.clearDisplay();
display.setCursor(0, 0);
display.println("Wi-Fi Connected");
display.println(WiFi.localIP());
display.display();
}
float readUltrasonicCm() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000);
if (duration == 0) {
return -1;
}
return duration * 0.0343 / 2.0;
}
bool detectIrCrack(int pin) {
int lowCount = 0;
for (int i = 0; i < 5; i++) {
if (digitalRead(pin) == LOW) {
lowCount++;
}
delay(2);
}
return lowCount >= 3;
}
void readSensors() {
crackLeft = detectIrCrack(IR_LEFT_PIN);
crackRight = detectIrCrack(IR_RIGHT_PIN);
crackDetected = crackLeft || crackRight;
distanceCm = readUltrasonicCm();
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
ax = a.acceleration.x;
ay = a.acceleration.y;
az = a.acceleration.z;
vibration = sqrt(ax * ax + ay * ay + az * az);
temperatureC = dht.readTemperature();
humidity = dht.readHumidity();
while (gpsSerial.available()) {
gps.encode(gpsSerial.read());
}
if (gps.location.isValid()) {
lat = gps.location.lat();
lng = gps.location.lng();
}
if (distanceCm > 0 && abs(distanceCm - baselineDistance) > 2.0) {
distanceFault = true;
} else {
distanceFault = false;
}
vibrationFault = vibration > vibrationThreshold;
}
void calculateRisk() {
float crackSeverity = crackDetected ? 1.0 : 0.0;
float distanceSeverity = distanceFault ? 1.0 : 0.0;
float vibrationSeverity = vibrationFault ? 1.0 : 0.0;
float envSeverity = 0;
if (!isnan(temperatureC) && temperatureC > 45) {
envSeverity = 0.7;
}
riskScore =
0.40 * crackSeverity +
0.30 * distanceSeverity +
0.20 * vibrationSeverity +
0.10 * envSeverity;
if (riskScore >= 0.75) {
eventStatus = "CRITICAL_FAULT";
severity = "CRITICAL";
} else if (riskScore >= 0.50) {
eventStatus = "HIGH_RISK";
severity = "HIGH";
} else if (riskScore >= 0.25) {
eventStatus = "WARNING";
severity = "MEDIUM";
} else {
eventStatus = "NORMAL";
severity = "LOW";
}
}
void localAlarm() {
if (riskScore >= 0.50) {
digitalWrite(RED_LED_PIN, HIGH);
digitalWrite(GREEN_LED_PIN, LOW);
digitalWrite(BUZZER_PIN, HIGH);
if (riskScore >= 0.75) {
digitalWrite(RELAY_PIN, HIGH); // Stop model train / activate signal
}
} else {
digitalWrite(RED_LED_PIN, LOW);
digitalWrite(GREEN_LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(RELAY_PIN, LOW);
}
}
void updateDisplay() {
display.clearDisplay();
display.setCursor(0, 0);
display.println("RAIL SAFETY AI");
display.println("----------------");
display.print("Status: ");
display.println(eventStatus);
display.print("Risk: ");
display.println(riskScore);
display.print("Dist: ");
display.print(distanceCm);
display.println(" cm");
display.print("Vib: ");
display.println(vibration);
display.print("Temp: ");
display.print(temperatureC);
display.println(" C");
display.display();
}
void sendThingSpeak() {
if (WiFi.status() != WL_CONNECTED) return;
HTTPClient http;
String url = "http://" + String(THINGSPEAK_HOST) + "/update?api_key=" +
THINGSPEAK_WRITE_KEY +
"&field1=" + String(distanceCm) +
"&field2=" + String(vibration) +
"&field3=" + String(temperatureC) +
"&field4=" + String(humidity) +
"&field5=" + String(crackDetected ? 1 : 0) +
"&field6=" + String(riskScore) +
"&field7=" + String(lat, 6) +
"&field8=" + String(lng, 6);
http.begin(url);
int code = http.GET();
Serial.print("ThingSpeak response: ");
Serial.println(code);
http.end();
}
void sendN8nAlert() {
if (WiFi.status() != WL_CONNECTED) return;
if (riskScore < 0.25) return;
HTTPClient http;
http.begin(N8N_WEBHOOK_URL);
http.addHeader("Content-Type", "application/json");
StaticJsonDocument<768> doc;
doc["device_id"] = "RAIL-ESP32-001";
doc["status"] = eventStatus;
doc["severity"] = severity;
doc["risk_score"] = riskScore;
doc["crack_left"] = crackLeft;
doc["crack_right"] = crackRight;
doc["distance_cm"] = distanceCm;
doc["baseline_cm"] = baselineDistance;
doc["vibration"] = vibration;
doc["temperature_c"] = temperatureC;
doc["humidity"] = humidity;
doc["latitude"] = lat;
doc["longitude"] = lng;
String payload;
serializeJson(doc, payload);
int code = http.POST(payload);
Serial.print("n8n response: ");
Serial.println(code);
http.end();
}
void loop() {
readSensors();
calculateRisk();
localAlarm();
updateDisplay();
sendThingSpeak();
sendN8nAlert();
delay(15000); // ThingSpeak free plan commonly accepts 15-second updates
}
ThingSpeak accepts sensor values through its update endpoint using a channel-specific Write API key; the example above sends distance, vibration, temperature, humidity, crack status, risk score, latitude, and longitude to eight fields.[cosmiclearn]
n8n Automation Design
Workflow overview
ESP32 HTTP POST
│
▼
n8n Webhook node
│
▼
AI Agent node
│
├──► Google Sheets: Append incident row
│
├──► Telegram: Send text alert
│
└──► Telegram: Send voice/audio alert
1. Webhook node
Create a webhook named:
railway-alert
Set:
- HTTP Method: POST
- Path:
railway-alert - Response Mode: Immediately
The ESP32 posts JSON such as:
{
"device_id": "RAIL-ESP32-001",
"status": "HIGH_RISK",
"severity": "HIGH",
"risk_score": 0.72,
"crack_left": true,
"crack_right": false,
"distance_cm": 14.6,
"baseline_cm": 10.0,
"vibration": 15.8,
"temperature_c": 38.4,
"humidity": 61.0,
"latitude": 17.385044,
"longitude": 78.486671
}
2. AI Agent node
Use an AI Agent or an LLM Chain node with this system prompt:
You are an AI railway maintenance assistant.
You will receive JSON sensor data from an ESP32 railway monitoring device.
Your tasks:
1. Classify the incident as NORMAL, WARNING, HIGH_RISK, or CRITICAL.
2. Identify the most likely issue: rail crack, track deformation, obstacle, excessive vibration, overheating, or sensor error.
3. Estimate urgency.
4. Write a short incident report for railway maintenance staff.
5. Write a short voice-alert script of no more than 30 words.
Return valid JSON only:
{
"classification": "",
"likely_issue": "",
"urgency": "",
"incident_report": "",
"voice_script": "",
"recommended_action": ""
}
Use this user prompt:
Sensor data:
{{ $json.body }}
The AI agent can use the n8n Telegram node as a tool; n8n documents that the Telegram node can be used with AI agents and supports human-in-the-loop approval.[docs.n8n]
3. Google Sheets node
Create a Google Sheet named:
Railway_Incident_Log
Use columns:
| Timestamp | Device ID | Status | Severity | Risk Score | Crack Left | Crack Right | Distance cm | Vibration | Temperature C | Humidity | Latitude | Longitude | AI Classification | Likely Issue | Recommended Action |
|---|
Configure the Google Sheets node:
- Operation: Append Row
- Document: Railway_Incident_Log
- Sheet: Sheet1
- Map fields from the webhook and AI output.
4. Telegram text alert
Use the Telegram → Message → Send Message operation. n8n’s Telegram node supports sending messages to a chat or channel using a Chat ID or channel username.[docs.n8n]
Message text:
🚨 RAILWAY SAFETY ALERT
Status: {{ $json.classification }}
Likely issue: {{ $json.likely_issue }}
Urgency: {{ $json.urgency }}
{{ $json.incident_report }}
Recommended action:
{{ $json.recommended_action }}
Device: {{ $('Webhook').item.json.body.device_id }}
Risk score: {{ $('Webhook').item.json.body.risk_score }}
Location:
https://maps.google.com/?q={{ $('Webhook').item.json.body.latitude }},{{ $('Webhook').item.json.body.longitude }}
5. Telegram voice alert
There are two practical options:
| Method | How it works | Best for |
|---|---|---|
| Pre-recorded MP3 | Upload normal.mp3, warning.mp3, critical.mp3; n8n selects the correct file |
Simple, reliable demo |
| AI TTS API | AI agent creates text, ElevenLabs/OpenAI TTS/Google TTS creates MP3, n8n sends audio | Dynamic voice alerts |
For a dynamic alert:
- AI Agent returns
voice_script. - Add an HTTP Request node to your TTS provider.
- Save the returned MP3 as binary data.
- Add Telegram → Message → Send Audio.
- Set Binary File to the TTS output field.
- Add a caption such as
Railway fault voice alert.
n8n’s Telegram node includes a Send Audio operation that can send an audio file from binary data or from a URL.[docs.n8n]
Web Dashboard Code
Add this inside the ESP32 sketch to create a lightweight live dashboard. It shows sensor values, risk status, and allows a manual test alert.
#include <WebServer.h>
WebServer server(80);
void handleRoot() {
String html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>AI Railway Safety Dashboard</title>
<style>
body { font-family: Arial; background:#0b1220; color:white; text-align:center; }
.card { background:#152238; margin:12px auto; padding:16px; max-width:420px; border-radius:12px; }
.normal { color:#4ade80; }
.warning { color:#facc15; }
.danger { color:#f87171; }
button { padding:12px 20px; border:none; border-radius:8px; background:#2563eb; color:white; }
</style>
</head>
<body>
<h2>🚆 AI Railway Safety Dashboard</h2>
<div class="card">
<h3>Status</h3>
<p id="status" class="normal">NORMAL</p>
<p>Risk Score: <span id="risk">0</span></p>
</div>
<div class="card">
<h3>Sensor Readings</h3>
<p>Distance: <span id="distance">0</span> cm</p>
<p>Vibration: <span id="vibration">0</span></p>
<p>Temperature: <span id="temperature">0</span> °C</p>
<p>Humidity: <span id="humidity">0</span> %</p>
<p>Crack Left: <span id="crackLeft">NO</span></p>
<p>Crack Right: <span id="crackRight">NO</span></p>
</div>
<div class="card">
<button onclick="fetch('/test')">Send Test Alert</button>
</div>
<script>
async function update() {
const r = await fetch('/data');
const d = await r.json();
document.getElementById('status').innerText = d.status;
document.getElementById('status').className =
d.risk >= 0.5 ? 'danger' : d.risk >= 0.25 ? 'warning' : 'normal';
document.getElementById('risk').innerText = d.risk;
document.getElementById('distance').innerText = d.distance;
document.getElementById('vibration').innerText = d.vibration;
document.getElementById('temperature').innerText = d.temperature;
document.getElementById('humidity').innerText = d.humidity;
document.getElementById('crackLeft').innerText = d.crackLeft ? 'YES' : 'NO';
document.getElementById('crackRight').innerText = d.crackRight ? 'YES' : 'NO';
}
setInterval(update, 2000);
update();
</script>
</body>
</html>
)rawliteral";
server.send(200, "text/html", html);
}
void handleData() {
String json = "{";
json += "\"status\":\"" + eventStatus + "\",";
json += "\"risk\":" + String(riskScore) + ",";
json += "\"distance\":" + String(distanceCm) + ",";
json += "\"vibration\":" + String(vibration) + ",";
json += "\"temperature\":" + String(temperatureC) + ",";
json += "\"humidity\":" + String(humidity) + ",";
json += "\"crackLeft\":" + String(crackLeft ? "true" : "false") + ",";
json += "\"crackRight\":" + String(crackRight ? "true" : "false");
json += "}";
server.send(200, "application/json", json);
}
void handleTest() {
riskScore = 0.85;
eventStatus = "CRITICAL_FAULT";
severity = "CRITICAL";
sendN8nAlert();
server.send(200, "text/plain", "Test alert sent");
}
void startWebServer() {
server.on("/", handleRoot);
server.on("/data", handleData);
server.on("/test", handleTest);
server.begin();
}
Call startWebServer(); at the end of setup() and add server.handleClient(); at the beginning of loop().
ThingSpeak Channel Setup
Create a ThingSpeak channel with these fields:
| Field | Data |
|---|---|
| 1 | Ultrasonic distance in cm |
| 2 | Vibration magnitude |
| 3 | Temperature in °C |
| 4 | Humidity in % |
| 5 | Crack status: 0 = normal, 1 = crack |
| 6 | AI risk score |
| 7 | Latitude |
| 8 | Longitude |
ThingSpeak uses a Write API key to authorize and route incoming data points to the correct channel. Similar published railway-monitoring systems use fields for vibration axes, temperature, humidity, crack status, distance, position, and combined vibration index.[ijarcce][cosmiclearn]
Step-by-Step Build Procedure
Step 1: Assemble the prototype
- Place the ESP32 on a breadboard.
- Connect both IR sensors to GPIO 34 and GPIO 35.
- Connect HC-SR04 TRIG to GPIO 5 and ECHO to GPIO 18 through a voltage divider.
- Connect MPU6050 and OLED to I²C pins GPIO 21 and GPIO 22.
- Connect DHT22 data to GPIO 4 with a 10 kΩ pull-up resistor.
- Connect GPS TX/RX to GPIO 16/17.
- Connect the buzzer, LEDs, and optional relay.
- Use a common ground for all modules.
Step 2: Calibrate the sensors
- Place the ultrasonic sensor at a known distance from a flat rail section.
- Record that distance in
baselineDistance. - Place the IR sensors above a clean rail surface.
- Verify that normal rail gives HIGH and a simulated crack gives LOW.
- Move the trolley or shake the setup gently to establish a normal vibration range.
- Adjust
vibrationThresholdto avoid false alarms.
Step 3: Configure ThingSpeak
- Create a ThingSpeak account and channel.
- Enable eight fields.
- Copy the Write API key.
- Replace
YOUR_THINGSPEAK_WRITE_KEYin the ESP32 code. - Upload the code and confirm values appear in the channel.
- Create line charts for distance, vibration, temperature, and risk score.
Step 4: Create the Telegram bot
- Open Telegram and search for @BotFather.
- Send
/newbot. - Choose a bot name and username.
- Copy the bot token.
- Create a Telegram group or channel for maintenance staff.
- Add the bot as an administrator if using a channel.
- Obtain the chat ID using a Telegram trigger or bot API method.
n8n notes that a bot must be added to a channel before it can send messages there.[docs.n8n]
Step 5: Build the n8n workflow
- Add a Webhook node: POST
/railway-alert. - Add an AI Agent node.
- Connect an LLM chat model node.
- Paste the AI system prompt and user prompt.
- Add a Google Sheets → Append Row node.
- Add a Telegram → Send Message node.
- Add an HTTP Request node for TTS.
- Add a Telegram → Send Audio node.
- Activate the workflow.
- Copy the production webhook URL into the ESP32 code.
Step 6: Test the complete system
| Test | Expected result |
|---|---|
| Normal track | Green LED, NORMAL status, ThingSpeak update |
| Black tape crack under IR sensor | Crack detected, risk increases, alert sent |
| Move ultrasonic target away by 3 cm | Distance fault detected |
| Shake MPU6050 | Vibration fault detected |
| Simulate critical condition | Buzzer, red LED, relay trigger, Telegram text and voice |
| Check Google Sheets | New row with sensor values and AI recommendation |
| Check Telegram | Text alert plus voice/audio alert received |
Google Sheets Automation
A typical logged incident row may look like this:
| Timestamp | Device ID | Status | Severity | Risk | Crack | Distance | Vibration | AI Classification | Action |
|---|---|---|---|---|---|---|---|---|---|
| 2026-10-31 14:25:10 | RAIL-ESP32-001 | HIGH_RISK | HIGH | 0.72 | YES | 14.6 | 15.8 | Rail crack likely | Inspect section and restrict movement |
The Google Sheets node should append this row whenever the webhook receives an event with risk score above 0.25.
AI Agent Sample Output
For an input with crack detected, distance deviation, and high vibration:
{
"classification": "CRITICAL",
"likely_issue": "Probable rail surface crack combined with track deformation and abnormal vibration",
"urgency": "Immediate inspection required",
"incident_report": "Device RAIL-ESP32-001 detected a crack signal on the left IR sensor. Ultrasonic distance increased from the 10 cm baseline to 14.6 cm, and vibration reached 15.8. The combined risk score is 0.85.",
"voice_script": "Critical railway fault detected. Crack and track deformation suspected. Immediate inspection required.",
"recommended_action": "Stop model train movement, mark the section as unsafe, dispatch maintenance staff, and inspect the left rail and track alignment."
}
Project Documentation Structure
Use these sections for your college or project report:
- Title: AI Railway Accident Prevention and Crack Detection System Using ESP32, IoT, n8n, and Telegram Voice Alerts
- Abstract: Explain how the system detects cracks and abnormal track conditions, uploads data to the cloud, and sends AI-generated alerts.
- Objectives: Detect cracks, monitor vibration, prevent accidents, automate alerts, and maintain an incident history.
- Existing system: Manual inspection is periodic, slow, and may miss early defects.
- Proposed system: Continuous sensor monitoring, edge decision-making, cloud logging, and automated AI alerts.
- Block diagram: Include the architecture diagram above.
- Circuit diagram: Include the schematic and pin table.
- Hardware description: Explain each sensor and module.
- Software description: Arduino IDE, ESP32 libraries, ThingSpeak, n8n, Telegram Bot API, Google Sheets, and TTS.
- Algorithm: Sensor reading, filtering, threshold detection, risk score, cloud upload, alerting.
- Flowchart: Include the software flowchart.
- Implementation: Show wiring photos, serial monitor output, ThingSpeak charts, n8n workflow, Telegram alerts, and Google Sheet.
- Testing: Include the test table and observed results.
- Advantages: Low-cost, real-time, scalable, remote monitoring, automated reporting.
- Limitations: Prototype-level accuracy, weatherproofing needed, requires calibration, not certified for real railway deployment.
- Future scope: Camera-based deep-learning crack detection, LoRaWAN for long-range coverage, solar power, edge TinyML, digital twin, automatic train-stop integration.
Future Improvements
- Add an ESP32-CAM to capture crack images and send them to Telegram.
- Train a CNN/YOLO model on rail-crack images for visual detection.
- Use LoRa or GSM for areas without Wi-Fi.
- Add solar power and battery monitoring.
- Use multiple sensor nodes along the track and map incidents on a dashboard.
- Add predictive maintenance using historical ThingSpeak data.
- Add automatic gate/track-circuit simulation and emergency stop.
This design gives you a complete demonstration-ready project: ESP32 edge sensing, AI-assisted decision-making, cloud dashboard, automated spreadsheet recordkeeping, and Telegram voice notifications. Telegram’s n8n integration supports both standard messages and audio files, making it suitable for text-plus-voice safety alerts.[docs.n8n]

