AI Footstep Power Generation Monitoring System
Complete IoT, ESP32, AI Agent, n8n Automation, Telegram Voice Alerts, Google Sheets & ThingSpeak Project
This project is an intelligent footstep energy-harvesting and monitoring system that converts the mechanical pressure of a person's footsteps into electrical energy, measures the generated output using an ESP32, sends data to a cloud dashboard, and uses an AI-enabled automation workflow to generate alerts and reports.
The proposed system combines five major technologies:
-
Energy harvesting: Piezoelectric sensors or piezoelectric discs generate electrical pulses when someone steps on the platform.
-
ESP32 + IoT: Measures voltage, counts footsteps, calculates estimated energy, and transmits readings over Wi-Fi.
-
ThingSpeak: Displays live measurements and historical graphs.
-
n8n + AI Agent: Processes readings, identifies unusual output, summarizes performance, and automates notifications.
-
Telegram + Google Sheets: Sends text or voice alerts and stores measurement records for analysis.
The following documentation is organized as a project report, hardware design, circuit schematic, software implementation, automation workflow, AI-agent configuration, testing plan, and future enhancements.
Important engineering note: Piezoelectric discs can generate high-voltage, low-current pulses. Their output must be rectified, limited, and conditioned before connecting it to an ESP32. The ESP32 must never be connected directly to a raw piezoelectric disc.
1. Project overview
1.1 Project title
AI-Powered Footstep Energy Generation Monitoring and Agentic IoT Alert System Using ESP32, n8n, Telegram Voice Notifications, Google Sheets and ThingSpeak
1.2 Abstract
The project aims to develop a smart floor tile that harvests small amounts of electrical energy from footsteps using piezoelectric transducers. An ESP32 microcontroller collects sensor readings and transmits them through Wi-Fi to a cloud monitoring platform. ThingSpeak provides visualization of voltage, footstep count, and other recorded measurements, while Google Sheets maintains a structured data log.
An n8n workflow acts as the automation layer. It validates incoming measurements, evaluates configurable thresholds, invokes an AI agent to explain system performance, and sends notifications through Telegram. An optional text-to-speech service converts alert messages into audio files that Telegram can deliver as voice-style notifications.
The system can also host a web dashboard showing current status, generated voltage, estimated energy, total footstep count, alerts, and historical trends.
1.3 Objectives
-
Design a piezoelectric footstep energy-harvesting prototype.
-
Measure conditioned electrical output safely using the ESP32 ADC.
-
Count detected footstep events and estimate harvested energy.
-
Transmit sensor readings to ThingSpeak.
-
Log readings and system events in Google Sheets.
-
Automate data processing and alerting using n8n.
-
Use an AI agent to generate human-readable performance summaries.
-
Deliver Telegram text and optional audio alerts.
-
Build a web dashboard for real-time and historical monitoring.
-
Evaluate sensor accuracy, connectivity, energy output, and system reliability.
1.4 Applications
-
Smart flooring demonstrations in colleges and laboratories.
-
Footstep energy-harvesting research.
-
Public-building energy awareness systems.
-
Railway stations, corridors, and entrance platforms.
-
Smart campus monitoring.
-
Interactive renewable-energy educational exhibits.
These are potential applications, not a claim that a small prototype can power an entire building.
2. System architecture
Footstep energy harvesting tile
Piezoelectric discs + mechanical platform
Power conditioning and measurement
Rectifier → capacitor → voltage divider → ESP32 ADC
ESP32 Wi-Fi controller
Footstep events, voltage readings, estimated energy, health status
HTTPS / cloud API
ThingSpeak
Live fields and historical charts
n8n automation
Validation, rules and AI agent
Telegram
Text/audio alerts
Google Sheets
Records and reports
Web dashboard
Status and trends
2.1 How the components work together
|
Component |
Main responsibility |
|---|---|
|
Piezoelectric transducers |
Convert mechanical stress into electrical pulses |
|
Rectifier and capacitor |
Convert pulses into a more usable DC voltage and temporarily store charge |
|
ESP32 |
Read measurements, count events, and communicate with the cloud |
|
ThingSpeak |
Store and graph time-series measurements |
|
n8n |
Connect cloud data, AI processing, Google Sheets and Telegram |
|
AI agent |
Explain readings, summarize trends, and recommend checks |
|
Telegram |
Deliver alerts and optional generated audio |
|
Google Sheets |
Maintain a searchable measurement history |
|
Web dashboard |
Present live status and performance indicators |
For a dependable first version, use ESP32 → ThingSpeak → n8n → Google Sheets/Telegram. Add a separate authenticated ESP32-to-n8n webhook later if you need lower-latency alerts or more flexible data routing.
3. Hardware requirements
3.1 Bill of materials
The following is a prototype-oriented parts list; quantities and ratings should be finalized after measuring your particular piezoelectric array.
|
Item |
Suggested specification |
Purpose |
|---|---|---|
|
Microcontroller |
ESP32 DevKit |
Processing and Wi-Fi |
|
Transducers |
Piezoelectric discs or commercial piezo floor elements |
Footstep energy generation |
|
Mechanical platform |
Spring-supported plate or flexible tile |
Transfers foot pressure to transducers |
|
Rectifier |
Low-leakage diodes or suitable bridge rectifier |
Rectifies AC-like pulses |
|
Capacitor |
Appropriately rated capacitor |
Smooths and stores charge |
|
Voltage divider |
Precision resistors |
Scales voltage for ADC |
|
Protection |
Clamp, TVS or suitable input protection |
Limits transients |
|
Footstep sensor |
Separate switch, force sensor or threshold detector |
Reliable event counting |
|
Optional sensor |
INA219/INA226 or suitable energy-metering circuit |
Current and power measurement |
|
Power supply |
Regulated USB supply for ESP32 |
Powers the controller |
|
Wiring |
Insulated wires, PCB and connectors |
Electrical connections |
|
Cloud services |
ThingSpeak, n8n, Telegram and Google account |
Monitoring and automation |
Important: Keep the ESP32 powered from a regulated supply initially. Do not assume the harvested energy is sufficient to run the ESP32 or transmit Wi-Fi packets. The project can monitor harvested energy while the controller is externally powered.
3.2 Two separate electrical paths
The project should distinguish between:
-
Harvesting path: Piezo array → rectifier → storage capacitor or energy-harvesting circuit → optional regulated load.
-
Measurement path: Conditioned voltage signal → protection and voltage divider → ESP32 ADC.
A large capacitor may store energy for a demonstration, but it also smooths short pulses and can hide individual footsteps. For accurate footstep counting, use a separate event sensor or a suitable peak/event-detection circuit.
4. Electrical schematic diagram
4.1 Overall hardware schematic
Piezoelectric disc array
Multiple discs mechanically coupled to a footstep plate
Bridge rectifier
AC-like piezo pulses → rectified DC
Storage capacitor + voltage protection
Component voltage ratings and clamp limits selected from measured output
Energy path
Optional harvesting regulator and load
Measurement path
Voltage divider → ADC input
ESP32 DevKit
GPIO34 / ADC1 on a classic ESP32; verify the pin on your board
The diagram shows the functional arrangement. The following circuit is a simplified starting point for a low-voltage, conditioned measurement signal, not a complete piezoelectric protection design.
4.2 ADC voltage-divider schematic
Use the following measurement connections after the piezo output has been safely rectified and limited:
Conditioned DC output (+)
|
R_TOP
|
+---------------- GPIO34 / ADC1
|
R_BOTTOM
|
GND ------+---------------- ESP32 GND
For example, use RTOP=100 kΩRTOP=100kΩ and RBOTTOM=100 kΩRBOTTOM=100kΩ for a nominal 2:1 divider, provided the source is already safely limited and the resistors are suitable for the actual circuit.
The divider output is:
For equal resistors, a 2.0 V conditioned input produces approximately 1.0 V at the ADC.
-
Use a common ground between the conditioned measurement circuit and ESP32.
-
Verify the board's ADC input range and attenuation settings.
-
Add suitable transient protection and filtering.
-
Never connect an unconditioned piezo disc or an unknown capacitor voltage directly to the ADC.
-
If the piezo array can produce substantial voltage, design the front end using measured peak voltage and current, component ratings, and a proper protection circuit.
The ESP32 ADC is not a precision laboratory voltmeter; calibrate it against a multimeter before using its readings for energy calculations. Espressif documents ADC calibration and reference variation in its ADC calibration guide .
4.3 Recommended measurement upgrade
If you want genuine harvested energy rather than a simple voltage demonstration, add a suitable current-measurement circuit or measure the energy-storage capacitor under controlled conditions.
For a capacitor:
The change in stored energy is:
where CC is capacitance in farads and voltages are in volts. The result is in joules.
This measures the change in stored capacitor energy, not necessarily all energy generated by the piezo array. Rectifier losses, leakage, and energy consumed by the load must be considered. Do not label voltage alone as power or energy.
5. ESP32 firmware
The first firmware version below measures the conditioned DC voltage, counts pulses from a separate digital footstep-event detector, and uploads readings to ThingSpeak.
It deliberately separates event detection from voltage measurement. A piezoelectric pulse can be brief, so periodically reading the ADC is not a reliable way to count every footstep.
5.1 Wiring
|
ESP32 pin |
Connection |
|---|---|
|
GPIO34 |
Conditioned analog voltage signal (classic ESP32) |
|
GPIO27 |
Digital output of a suitable footstep-event detector |
|
GND |
Common signal ground |
|
USB |
Regulated power for ESP32 |
The GPIO27 input must produce a clean, 3.3 V-compatible digital signal. Use a pull-up or pull-down appropriate to the detector output. Do not connect a raw piezo disc directly to GPIO27.
5.2 Arduino IDE setup
-
Install the Arduino IDE.
-
Add the ESP32 board support package using the official Arduino-ESP32 documentation .
Espressif Documentation -
Select your ESP32 development board and serial port.
-
Create a ThingSpeak channel with fields:
-
Field 1: Conditioned DC voltage (V)
-
Field 2: Cumulative footstep count
-
Field 3: Estimated stored energy (J)
-
Field 4: Wi-Fi signal strength (dBm)
-
-
Copy the channel's Write API Key from its API Keys tab.
ThingSpeak accepts channel updates through its REST API; a successful update returns an entry identifier, while a failed update may return 0.
5.3 Complete starter code
Replace the Wi-Fi credentials, ThingSpeak write key, divider values, and capacitance with your actual configuration. This example is for a classic ESP32 DevKit and Arduino-ESP32.
#include <WiFi.h>
#include <HTTPClient.h>
#include <math.h>
// ---------- USER CONFIGURATION ----------
const char* WIFI_SSID = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* THINGSPEAK_WRITE_KEY = "YOUR_WRITE_API_KEY";
// Classic ESP32 DevKit example pins
const int VOLTAGE_PIN = 34; // ADC1 input
const int FOOTSTEP_PIN = 27; // Conditioned digital event signal
// Divider resistors in ohms
const float R_TOP = 100000.0f;
const float R_BOTTOM = 100000.0f;
// Enter the real storage capacitor value.
// This is only an example value: 4700 uF = 0.0047 F.
const float CAPACITANCE_F = 0.0047f;
// Calibrate against a multimeter before trusting readings.
const float ADC_CALIBRATION = 1.000f;
// Sampling interval; obey your ThingSpeak plan's limits.
const unsigned long UPLOAD_INTERVAL_MS = 20000;
// ---------- STATE ----------
volatile unsigned long footstepCount = 0;
volatile unsigned long lastPulseUs = 0;
unsigned long lastUploadMs = 0;
float measuredVoltage = 0.0f;
float previousStoredEnergyJ = 0.0f;
void IRAM_ATTR onFootstep() {
unsigned long now = micros();
// Basic interrupt debounce / event lockout.
if (now - lastPulseUs > 150000UL) {
footstepCount++;
lastPulseUs = now;
}
}
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 < 20000UL) {
delay(300);
Serial.print(".");
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.print("Connected. IP: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("Wi-Fi unavailable; will retry.");
}
}
float readConditionedVoltage() {
const int samples = 32;
uint32_t totalMv = 0;
for (int i = 0; i < samples; i++) {
totalMv += analogReadMilliVolts(VOLTAGE_PIN);
delay(2);
}
float adcVoltage = (totalMv / (float)samples) / 1000.0f;
float sourceVoltage =
adcVoltage *
((R_TOP + R_BOTTOM) / R_BOTTOM) *
ADC_CALIBRATION;
return sourceVoltage;
}
float calculateStoredEnergy(float voltage) {
return 0.5f * CAPACITANCE_F * voltage * voltage;
}
bool uploadToThingSpeak(float voltage,
unsigned long steps,
float energyJ,
int rssi) {
if (WiFi.status() != WL_CONNECTED) {
connectWiFi();
}
if (WiFi.status() != WL_CONNECTED) {
return false;
}
HTTPClient http;
http.setTimeout(5000);
String url =
"https://api.thingspeak.com/update?api_key=" +
String(THINGSPEAK_WRITE_KEY) +
"&field1=" + String(voltage, 3) +
"&field2=" + String(steps) +
"&field3=" + String(energyJ, 6) +
"&field4=" + String(rssi);
if (!http.begin(url)) {
return false;
}
int httpCode = http.GET();
String response = http.getString();
http.end();
Serial.print("ThingSpeak HTTP code: ");
Serial.println(httpCode);
Serial.print("ThingSpeak response: ");
Serial.println(response);
// Successful updates normally return a positive entry ID.
return httpCode == HTTP_CODE_OK &&
response.toInt() > 0;
}
void setup() {
Serial.begin(115200);
pinMode(FOOTSTEP_PIN, INPUT_PULLDOWN);
attachInterrupt(
digitalPinToInterrupt(FOOTSTEP_PIN),
onFootstep,
RISING
);
analogReadResolution(12);
analogSetPinAttenuation(VOLTAGE_PIN, ADC_11db);
connectWiFi();
Serial.println("Footstep energy monitoring started.");
}
void loop() {
if (millis() - lastUploadMs >= UPLOAD_INTERVAL_MS) {
lastUploadMs = millis();
measuredVoltage = readConditionedVoltage();
float storedEnergyJ = calculateStoredEnergy(measuredVoltage);
// Snapshot the interrupt counter safely.
noInterrupts();
unsigned long steps = footstepCount;
interrupts();
int rssi = WiFi.status() == WL_CONNECTED
? WiFi.RSSI()
: 0;
float deltaEnergyJ = storedEnergyJ - previousStoredEnergyJ;
previousStoredEnergyJ = storedEnergyJ;
Serial.println("------ Footstep Monitor ------");
Serial.printf("Voltage: %.3f V\n", measuredVoltage);
Serial.printf("Steps: %lu\n", steps);
Serial.printf("Stored energy: %.6f J\n", storedEnergyJ);
Serial.printf("Energy change: %.6f J\n", deltaEnergyJ);
Serial.printf("Wi-Fi RSSI: %d dBm\n", rssi);
bool ok = uploadToThingSpeak(
measuredVoltage, steps, storedEnergyJ, rssi
);
Serial.println(ok ? "Upload OK" : "Upload failed");
}
delay(10);
}
5.4 What the firmware does
-
Connects to Wi-Fi.
-
Counts digital footstep events using an interrupt.
-
Averages 32 ADC readings to reduce noise.
-
Converts ADC voltage back to the conditioned source voltage using the divider ratio.
-
Estimates energy stored in a known capacitor.
-
Uploads four fields to ThingSpeak.
-
Prints measurements and upload status to the serial monitor.
Limitations of this starter code
-
analogReadMilliVolts()still requires calibration for your board and front end. -
A 20-second upload interval is an example; follow the current limits of your ThingSpeak account.
-
INPUT_PULLDOWNandRISINGmust match your event detector's electrical output. -
The energy calculation assumes the measured voltage is actually across the stated capacitor. If the voltage divider measures a different node, change the formula accordingly.
-
deltaEnergyJcan be negative when the capacitor discharges; it is not a direct measurement of energy generated during that interval. -
The code does not yet implement persistent footstep counting, secure firmware provisioning, or offline upload buffering.
6. ThingSpeak cloud dashboard
6.1 Create the channel
-
Open ThingSpeak .
-
Sign in and select Channels → My Channels → New Channel.
-
Name it
AI Footstep Energy Monitor. -
Enable these fields:
|
Field |
Name |
Unit |
|---|---|---|
|
Field 1 |
Conditioned DC Voltage |
V |
|
Field 2 |
Total Footsteps |
count |
|
Field 3 |
Stored Capacitor Energy |
J |
|
Field 4 |
Wi-Fi RSSI |
dBm |
-
Save the channel.
-
Open its API Keys tab and copy the Write API Key into the firmware.
-
Save the firmware and upload it to the ESP32.
-
Open the Serial Monitor and confirm that uploads return a positive entry identifier.
-
Return to ThingSpeak and confirm that the fields and charts update.
ThingSpeak supports REST-based channel writes and reads, including time-series field graphs.
6.2 Create the graphs
Configure separate visualizations for:
-
Voltage over time.
-
Cumulative footsteps over time.
-
Stored energy over time.
-
Wi-Fi signal strength over time.
Use a cumulative footstep count if you want to observe the overall count. If you want activity per interval, add another field for the number of new footsteps during each measurement period.
6.3 Display the dashboard on a webpage
You can display a public ThingSpeak chart inside your own webpage using an iframe. For example:
<iframe
width="100%"
height="300"
style="border:1px solid #cccccc"
src="https://thingspeak.com/channels/YOUR_CHANNEL_ID/charts/1?bgcolor=%23ffffff&color=%23007acc&dynamic=true&results=60">
</iframe>
Replace YOUR_CHANNEL_ID with your actual channel ID.
For private channels, configure the appropriate access permissions or use an authenticated backend. Do not put private read keys or write keys into public HTML or JavaScript.
7. n8n automation workflow
n8n connects the IoT data source with cloud logging, AI analysis, and notifications. Its built-in AI Agent, HTTP Request, Telegram, and Google Sheets nodes support the main workflow described here.
7.1 Main workflow diagram
1. Schedule Trigger
Run every 1–5 minutes initially
2. HTTP Request
Read the latest ThingSpeak channel entry
3. Code / Edit Fields
Parse data, validate fields, calculate freshness and status
4. IF node
Check voltage, stale data, abnormal output and alert cooldown
Normal path
Append row to Google Sheets
Alert path
AI Agent → notification text
Google Sheets
Telegram
The Schedule Trigger is a practical starting point because ThingSpeak acts as the shared data source. For low-latency alerts, you can later use an authenticated ESP32 webhook trigger instead. n8n's Schedule Trigger must be configured, saved, and published for scheduled execution.
7.2 Configure the HTTP Request node
Add an HTTP Request node after the Schedule Trigger.
-
Method:
GET -
URL:
https://api.thingspeak.com/channels/YOUR_CHANNEL_ID/feeds/last.json
-
Authentication: none for a public channel; use the appropriate supported authenticated request for a private channel.
-
Query parameters: for a private channel, include the appropriate read key securely using n8n credentials or protected configuration.
-
Response format: JSON.
The latest feed should contain fields similar to:
{
"created_at": "2026-10-22T12:00:00Z",
"field1": "1.250",
"field2": "42",
"field3": "0.003672",
"field4": "-55"
}
This is an illustrative example, not live data from your device.
7.3 Normalize the data
Add an Edit Fields node or Code node after the HTTP Request.
For a Code node in JavaScript, a basic normalization step is:
const d = $input.first().json;
const voltage = Number(d.field1);
const steps = Number(d.field2);
const energy = Number(d.field3);
const rssi = Number(d.field4);
if (![voltage, steps, energy, rssi].every(Number.isFinite)) {
throw new Error("Invalid or missing ThingSpeak measurements");
}
return [{
json: {
timestamp: d.created_at,
voltage_V: voltage,
total_steps: steps,
stored_energy_J: energy,
wifi_rssi_dBm: rssi,
alert_required: voltage < 0.2,
data_valid: true
}
}];
The 0.2 V threshold is only an example. It is not a universal definition of a fault; select a threshold from the calibrated prototype's baseline.
For stale-data detection, compare the entry timestamp with the current time. If the latest entry is older than the permitted interval, generate a separate device offline or telemetry stale alert instead of interpreting an old voltage as a new reading.
7.4 Add Google Sheets logging
Create a spreadsheet called Footstep Energy Monitoring.
Use these column headings:
|
Column |
Heading |
|---|---|
|
A |
Timestamp |
|
B |
Voltage_V |
|
C |
Total_Footsteps |
|
D |
Stored_Energy_J |
|
E |
WiFi_RSSI_dBm |
|
F |
Status |
|
G |
AI_Analysis |
|
H |
Alert_Sent |
In n8n:
-
Add a Google Sheets node.
-
Authenticate with your Google account.
-
Select the spreadsheet and worksheet.
-
Choose Append Row.
-
Map the incoming fields to the corresponding columns.
-
Save and test the node with a sample entry.
The Google Sheets integration supports appending rows and other spreadsheet operations.
Important: If your workflow runs every minute, it can log the same ThingSpeak entry repeatedly when the device uploads less frequently. Store the ThingSpeak entry_id as an additional column and use it to deduplicate records, or compare the latest timestamp with the last processed timestamp.
8. AI Agent configuration
The AI agent should interpret validated measurements, explain possible causes, and prepare a concise report. It should not replace electrical protection, calibration, or deterministic fault detection.
8.1 AI Agent node
Add the following to your n8n workflow:
-
AI Agent node.
-
A supported chat-model node with credentials.
-
A system prompt.
-
Optional tools such as a read-only measurement-history workflow or a Google Sheets lookup workflow.
The n8n AI Agent uses a connected model and, where configured, tools to decide how to handle a task.
8.2 Recommended system prompt
You are the AI monitoring assistant for a piezoelectric
footstep energy harvesting prototype.
Your responsibilities:
1. Analyze only the sensor data provided to you.
2. Summarize voltage, total footstep count, stored energy,
Wi-Fi signal strength, and data freshness.
3. Explain possible abnormal readings using cautious language.
4. Recommend practical checks when output is unexpectedly low.
5. Generate a short Telegram alert when requested.
6. Produce a daily summary when requested.
Rules:
- Do not invent measurements or sensor events.
- Distinguish measured voltage from actual power and energy.
- Do not claim that voltage alone proves energy generation.
- Flag missing, invalid, stale, or inconsistent data.
- Treat deterministic safety thresholds as authoritative.
- Do not change hardware settings or control actuators.
- Keep alerts concise, factual, and understandable.
- State when the available data is insufficient for a diagnosis.
8.3 Example AI output
Input:
{
"voltage_V": 0.18,
"total_steps": 125,
"stored_energy_J": 0.00008,
"wifi_rssi_dBm": -68,
"status": "LOW_OUTPUT"
}
Illustrative output:
Footstep monitoring alert: The measured conditioned voltage is below the configured threshold. The recorded footstep count is 125. Check the mechanical coupling, piezoelectric connections, rectifier, measurement divider, and capacitor condition. Confirm the reading with a multimeter before concluding that the harvesting system has failed.
The AI should summarize and contextualize the reading, while the IF node determines whether a threshold has been crossed.
8.4 What makes this an agentic IoT system?
A workflow that only forwards measurements to Telegram is ordinary automation. To make it more agentic, give the AI agent defined tools and a controlled decision-making role.
For example, the agent may:
-
Query recent measurements from a read-only history tool.
-
Compare current readings with recent averages.
-
Summarize recurring low-output events.
-
Draft a diagnostic checklist based on measured evidence.
-
Prepare a daily performance report.
Initially, keep the agent read-only. Require human approval before any action that could change hardware configuration or affect safety.
9. Telegram text and voice alerts
9.1 Create a Telegram bot
-
Open Telegram and search for the official
@BotFatheraccount. -
Send
/newbot. -
Choose a bot name and username.
-
Copy the generated bot token.
-
Open your new bot and send
/start. -
Obtain your chat ID using the Telegram Bot API or an n8n Telegram Trigger workflow.
-
In n8n, create Telegram credentials using the bot token.
-
Select your bot credentials and configure the target chat ID in the Telegram node.
Treat the bot token as a password. Never publish it in your firmware, website, spreadsheet, or public repository.
9.2 Configure text notifications
After the IF node identifies an alert, connect a Telegram node:
-
Resource: Message.
-
Operation: Send Message.
-
Chat ID: your authorized chat ID.
-
Text: use the validated measurement fields and AI-generated summary.
Example message:
Footstep Monitor Bot
⚠️ LOW ENERGY OUTPUT
Conditioned voltage: 0.18 V
Total footsteps: 125
Stored capacitor energy: 0.00008 J
Status: Check harvesting and measurement circuits.
Illustrative values only
9.3 Generate voice-style alerts
There are two useful options:
-
Audio file: Convert the AI-generated alert text to speech using a compatible text-to-speech service, then send the resulting audio file through Telegram.
-
Telegram voice message: If you want the familiar round voice-message presentation, generate an appropriate OGG/Opus voice file and use the corresponding voice-message operation. A normal MP3 attachment is not the same thing.
Recommended workflow:
AI Agent
Produces concise alert text
HTTP Request / TTS service
Converts text into spoken audio
Audio conversion, if needed
Produces a Telegram-compatible audio format
Telegram Send Audio / Send Voice
Delivers audio to the configured chat
The exact TTS node and parameters depend on the provider you choose. Keep the TTS API key in n8n credentials. If the provider returns a binary audio file, ensure the next node receives the file as binary data rather than only a JSON URL.
Example spoken alert:
Attention. The footstep energy monitoring system has detected low output. Please inspect the sensor connections and verify the voltage measurement.
9.4 Avoid repeated alerts
Add a cooldown mechanism so the same condition does not send a Telegram message every time the workflow runs.
A practical policy is:
-
Send an immediate notification when the status changes from normal to abnormal.
-
Repeat the alert only after a configurable cooldown, such as 15 minutes.
-
Send a recovery message after readings return to normal for several consecutive checks.
-
Send a separate offline notification when data becomes stale.
For production use, store alert state in a persistent data store or database rather than relying on temporary workflow memory.
10. Web dashboard design
The dashboard is the user-facing monitoring interface. It can be hosted on a local computer, a small web server, or a static website with an authenticated backend.
10.1 Recommended dashboard layout
Footstep Energy Monitor
ESP32 · IoT telemetry · AI diagnostics
Conditioned voltage
— V
Awaiting live sensor dataFootsteps
—
Cumulative countStored energy
— J
Capacitor estimateDevice status
Unknown
Connect a data sourceVoltage trend
AI system summary
No readings available yet. Connect ThingSpeak or the authenticated backend to populate the dashboard.
This is a layout preview, not a live-connected dashboard.
10.2 Recommended dashboard functions
-
Display current voltage, total footsteps, stored energy and connectivity.
-
Plot voltage and energy history.
-
Show alert history and last data-received time.
-
Provide date-range filters.
-
Display AI-generated summaries.
-
Link to ThingSpeak and Google Sheets.
-
Export reports as CSV.
-
Allow authorized users to acknowledge alerts.
10.3 How to connect the webpage to ThingSpeak
For a quick prototype, use public ThingSpeak chart embeds. For a more complete custom dashboard:
-
Create a frontend using HTML, CSS and JavaScript or a framework such as React.
-
Read channel data through the ThingSpeak REST API.
-
Parse the latest measurements and render chart components.
-
Poll at a reasonable interval or use a supported streaming approach.
-
Display the data timestamp and stale-data status.
-
Route private API requests through a backend to protect credentials.
Do not expose the ThingSpeak write key, Telegram token, AI provider key, or n8n credentials in browser code.
11. Complete workflow diagrams
11.1 End-to-end data flow
Below is a complete, build-ready documentation package for an AI Footstep Power Generation Monitoring System using ESP32, piezo/energy-harvesting hardware, ThingSpeak, Google Sheets, n8n automation, Telegram voice alerts, and an AI prediction/agent layer.
ThingSpeak supports device-to-cloud updates through REST or MQTT, and its /update endpoint accepts a channel Write API Key plus field values. Telegram’s Bot API supports sendMessage for text alerts and sendVoice for playable voice notifications. n8n’s HTTP Request node can call REST APIs such as Telegram, Google Sheets, ThingSpeak, and your ML endpoint.[mathworks][in.mathworks][core.telegram][docs.n8n][docs.n8n]
1. Project Overview
The system converts mechanical energy from footsteps into electrical energy using piezoelectric transducers, rectifies and stores it, then measures voltage/current/power using an ESP32. The ESP32 sends live readings to ThingSpeak and an n8n webhook. n8n stores history in Google Sheets, applies AI-based prediction/anomaly rules, and sends Telegram text and voice alerts when abnormal generation, low battery, overload, or predicted low output is detected.
Core capabilities
- Measure footstep-generated voltage, current, power, energy, and battery status.
- Publish live data to a ThingSpeak IoT dashboard.
- Log every reading to Google Sheets through n8n.
- Detect anomalies such as zero generation, voltage spikes, low battery, or abnormal footfall rate.
- Predict next-hour power generation using an ML model.
- Send Telegram text alerts and pre-generated voice alerts.
- Provide an IoT web dashboard using ThingSpeak and an optional Flutter/Blynk-style mobile dashboard.
- Support future expansion with multiple tiles, load control, weather correlation, and cloud ML.
2. System Architecture
Footsteps
│
▼
Piezoelectric tiles / discs
│
▼
Bridge rectifier + smoothing capacitor
│
▼
TP4056 / BMS + 18650 battery + boost converter
│
├──> Load / LED / small DC device
│
▼
Voltage divider + ACS712 current sensor
│
▼
ESP32
│
├── HTTPS POST ──> ThingSpeak dashboard
│
└── HTTPS POST ──> n8n Webhook
│
├──> Google Sheets logging
├──> AI prediction API / rule engine
├──> Telegram text alert
└──> Telegram voice alert
Data flow
- A person steps on the piezo tile.
- The piezo element produces an AC pulse.
- A bridge rectifier converts it to DC.
- The capacitor and battery storage circuit smooth and store energy.
- ESP32 samples voltage and current.
- ESP32 calculates instantaneous power and accumulated energy.
- ESP32 sends a JSON payload to n8n and ThingSpeak.
- n8n logs the data, runs AI/rule logic, and issues alerts.
ThingSpeak can receive data from internet-connected devices via REST or MQTT and chart numeric channel data.[mathworks]
3. Components List
| Component | Quantity | Purpose |
|---|---|---|
| ESP32 DevKit V1 | 1 | Main IoT controller |
| Piezoelectric discs/tiles, 27 mm or larger | 4–8 | Convert footstep pressure to electricity |
| Bridge rectifier, DB107 or 1N4007 diode bridge | 1 per tile/group | Convert AC pulses to DC |
| Schottky diodes, 1N5819 | Optional | Reduce rectifier loss |
| Electrolytic capacitor, 1000 µF / 16 V | 1–2 | Smooth harvested pulses |
| TP4056 charging module with protection | 1 | Charge 3.7 V lithium cell |
| 18650 lithium-ion battery, 2000–3400 mAh | 1 | Energy storage |
| MT3608 boost converter | 1 | Boost battery voltage to 5 V if required |
| ACS712 5A/20A current sensor | 1 | Measure load/generated current |
| Voltage divider resistors: 100 kΩ and 10 kΩ | 1 pair | Scale battery/harvester voltage for ESP32 ADC |
| 0.96-inch OLED, I2C SSD1306 | Optional | Local display |
| DHT22/DHT11 | Optional | Temperature/humidity context |
| PIR or IR sensor | Optional | Detect footstep/person presence |
| Buzzer | 1 | Local warning |
| LEDs and resistors | As needed | Local status indication |
| Breadboard, wires, connectors | As needed | Prototyping |
| 5 V USB power supply | 1 | Development/testing power |
| Enclosure and anti-slip footpad | 1 | Safe mechanical installation |
Important safety note
Use proper insulation, a fuse, and a protected lithium-ion charging circuit. Do not connect raw piezo pulses directly to the ESP32; always use a rectifier, voltage limiter/Zener protection, and voltage divider.
4. Circuit Schematic Diagram
Text-based schematic
PIEZO TILE ARRAY
PZ1 ──┐
PZ2 ──┤
PZ3 ──┼──[BRIDGE RECTIFIER]──+──────┬───────────────┬───────────────┐
PZ4 ──┘ │ │ │ │
GND │ │ │
C1 TP4056 VOLTAGE DIVIDER
1000uF/16V B+ / B- 100k / 10k
│ │ │
GND 18650 CELL │
│ ├──> ESP32 GPIO34
│ │
├──> MT3608 ────┼──> 5V LOAD
│ │
GND GND
ACS712 CURRENT SENSOR
Harvester/load positive wire ──> ACS712 IP+
ACS712 IP- ──> Load positive terminal
ACS712 VCC ──> 5V
ACS712 GND ──> ESP32 GND
ACS712 OUT ──> ESP32 GPIO35
ESP32 CONNECTIONS
GPIO34 <── Voltage divider output
GPIO35 <── ACS712 output
GPIO21 <── OLED SDA
GPIO22 <── OLED SCL
GPIO25 ──> Buzzer
GPIO2 ──> Status LED
GPIO4 ──> Relay/module control, optional
Full circuit diagram image
Use the following Mermaid diagram as a documentation-ready schematic representation. You can render it in GitHub, Mermaid Live Editor, draw.io, or Figma.
flowchart LR
A[Footstep Pressure] --> B[Piezo Tiles x4]
B --> C[Bridge Rectifier]
C --> D[Smoothing Capacitor]
D --> E[TP4056 Charger]
E --> F[18650 Battery]
F --> G[MT3608 Boost Converter]
G --> H[DC Load / LED / Sensor Supply]
D --> I[Voltage Divider 100k/10k]
I --> J[ESP32 GPIO34 ADC]
F --> K[ACS712 Current Sensor]
K --> L[ESP32 GPIO35 ADC]
J --> M[ESP32]
L --> M
M --> N[ThingSpeak Cloud Dashboard]
M --> O[n8n Webhook]
O --> P[Google Sheets]
O --> Q[AI Prediction / Anomaly Agent]
Q --> R[Telegram Text Alert]
Q --> S[Telegram Voice Alert]
5. Pin Mapping
| ESP32 Pin | Connected To | Notes |
|---|---|---|
| 3V3 | Voltage divider top rail, sensors if 3.3 V | Use only for low-power sensors |
| GND | Common ground | All grounds must be common |
| GPIO34 | Voltage divider output | ADC1, input only |
| GPIO35 | ACS712 output | ADC1, input only |
| GPIO21 | OLED SDA | I2C data |
| GPIO22 | OLED SCL | I2C clock |
| GPIO25 | Buzzer | Optional local alert |
| GPIO2 | Status LED | Optional |
| GPIO4 | Relay/load control | Optional |
| EN / BOOT | Programming buttons | Standard ESP32 pins |
Avoid using ADC2 pins when Wi-Fi is active. Use ADC1 pins such as GPIO32–GPIO39 for analog measurements.
6. ESP32 Source Code
Install these Arduino libraries:
WiFiHTTPClientArduinoJsonAdafruit GFXAdafruit SSD1306Adafruit SensorDHT sensor library, optional
Replace the placeholders:
YOUR_WIFI_SSIDYOUR_WIFI_PASSWORDYOUR_THINGSPEAK_WRITE_API_KEYYOUR_N8N_WEBHOOK_URL
/*
AI Footstep Power Generation Monitoring System
ESP32 + Piezo Energy Harvesting + ThingSpeak + n8n + Telegram Automation
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ---------------- WiFi ----------------
const char* WIFI_SSID = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
// ---------------- ThingSpeak ----------------
const char* THINGSPEAK_URL = "http://api.thingspeak.com/update";
const char* THINGSPEAK_WRITE_KEY = "YOUR_THINGSPEAK_WRITE_API_KEY";
// ---------------- n8n Webhook ----------------
const char* N8N_WEBHOOK_URL = "https://YOUR_N8N_DOMAIN/webhook/footstep-power";
// ---------------- Pins ----------------
#define VOLTAGE_PIN 34
#define CURRENT_PIN 35
#define BUZZER_PIN 25
#define LED_PIN 2
// ---------------- Calibration ----------------
// Adjust these after measuring your actual circuit.
const float ADC_REF = 3.3;
const float ADC_RESOLUTION = 4095.0;
const float VOLTAGE_DIVIDER_FACTOR = 11.0; // (100k + 10k) / 10k
const float ACS712_ZERO = 2.5; // Sensor output at 0A
const float ACS712_SENSITIVITY = 0.185; // For ACS712-5A: 185mV/A
// ---------------- Thresholds ----------------
const float LOW_GENERATION_VOLTAGE = 0.5;
const float HIGH_VOLTAGE_ALERT = 12.0;
const float LOW_CURRENT_ALERT = 0.02;
const float HIGH_POWER_ALERT = 5.0;
// ---------------- Timing ----------------
const unsigned long SEND_INTERVAL = 20000; // 20 seconds
unsigned long lastSend = 0;
// ---------------- Energy ----------------
float totalEnergyWh = 0.0;
unsigned long stepCount = 0;
Adafruit_SSD1306 display(128, 64, &Wire, -1);
void setup() {
Serial.begin(115200);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
analogReadResolution(12);
analogSetAttenuation(ADC_11db);
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("Footstep Power AI");
display.println("Starting...");
display.display();
connectWiFi();
}
void loop() {
float voltage = readVoltage();
float current = readCurrent();
float power = voltage * current;
if (power > 0.05) {
stepCount++;
}
// Energy: Wh = W * hours
totalEnergyWh += power * (SEND_INTERVAL / 3600000.0);
if (millis() - lastSend >= SEND_INTERVAL) {
lastSend = millis();
bool lowGeneration = voltage < LOW_GENERATION_VOLTAGE;
bool highVoltage = voltage > HIGH_VOLTAGE_ALERT;
bool highPower = power > HIGH_POWER_ALERT;
sendToThingSpeak(voltage, current, power, totalEnergyWh, stepCount);
sendToN8N(voltage, current, power, totalEnergyWh, stepCount,
lowGeneration, highVoltage, highPower);
updateDisplay(voltage, current, power, totalEnergyWh, stepCount);
if (highVoltage || highPower) {
localAlert();
}
}
delay(500);
}
void connectWiFi() {
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("Connected. IP: ");
Serial.println(WiFi.localIP());
}
float readVoltage() {
long raw = 0;
for (int i = 0; i < 30; i++) {
raw += analogRead(VOLTAGE_PIN);
delay(2);
}
raw = raw / 30;
float adcVoltage = (raw * ADC_REF) / ADC_RESOLUTION;
return adcVoltage * VOLTAGE_DIVIDER_FACTOR;
}
float readCurrent() {
long raw = 0;
for (int i = 0; i < 30; i++) {
raw += analogRead(CURRENT_PIN);
delay(2);
}
raw = raw / 30;
float sensorVoltage = (raw * ADC_REF) / ADC_RESOLUTION;
float current = (sensorVoltage - ACS712_ZERO) / ACS712_SENSITIVITY;
if (current < 0) {
current = 0;
}
return current;
}
void sendToThingSpeak(float voltage, float current, float power,
float energy, unsigned long steps) {
if (WiFi.status() != WL_CONNECTED) {
connectWiFi();
}
HTTPClient http;
String url = String(THINGSPEAK_URL) +
"?api_key=" + THINGSPEAK_WRITE_KEY +
"&field1=" + String(voltage, 3) +
"&field2=" + String(current, 4) +
"&field3=" + String(power, 4) +
"&field4=" + String(energy, 5) +
"&field5=" + String(steps);
http.begin(url);
int code = http.GET();
http.end();
Serial.print("ThingSpeak response: ");
Serial.println(code);
}
void sendToN8N(float voltage, float current, float power,
float energy, unsigned long steps,
bool lowGeneration, bool highVoltage, bool highPower) {
if (WiFi.status() != WL_CONNECTED) {
connectWiFi();
}
HTTPClient http;
http.begin(N8N_WEBHOOK_URL);
http.addHeader("Content-Type", "application/json");
StaticJsonDocument<512> doc;
doc["device_id"] = "FOOTSTEP_ESP32_01";
doc["location"] = "Main Entrance";
doc["voltage"] = voltage;
doc["current"] = current;
doc["power"] = power;
doc["energy_wh"] = energy;
doc["steps"] = steps;
doc["low_generation"] = lowGeneration;
doc["high_voltage"] = highVoltage;
doc["high_power"] = highPower;
doc["timestamp"] = millis();
String body;
serializeJson(doc, body);
int code = http.POST(body);
http.end();
Serial.print("n8n response: ");
Serial.println(code);
}
void updateDisplay(float voltage, float current, float power,
float energy, unsigned long steps) {
display.clearDisplay();
display.setCursor(0, 0);
display.println("Footstep Power AI");
display.setCursor(0, 16);
display.print("V: ");
display.println(voltage, 2);
display.print("I: ");
display.println(current, 3);
display.print("P: ");
display.println(power, 3);
display.print("E: ");
display.println(energy, 4);
display.print("Steps: ");
display.println(steps);
display.display();
}
void localAlert() {
digitalWrite(LED_PIN, HIGH);
digitalWrite(BUZZER_PIN, HIGH);
delay(300);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_PIN, LOW);
}
7. ThingSpeak Setup
Create the channel
- Sign in at ThingSpeak.
- Go to Channels → My Channels → New Channel.
- Name it:
AI Footstep Power Monitoring. - Enable and name these fields:
| Field | Name | Unit |
|---|---|---|
| Field 1 | Voltage | V |
| Field 2 | Current | A |
| Field 3 | Power | W |
| Field 4 | Energy | Wh |
| Field 5 | Footsteps | count |
| Field 6 | AI Predicted Power | W |
| Field 7 | Anomaly Score | 0–1 |
| Field 8 | Battery Status | V or % |
- Save the channel.
- Open API Keys and copy the Write API Key.
- Put that key into the ESP32 code.
ThingSpeak’s write API uses the channel Write API Key and supports multiple fieldX values in one request.[in.mathworks]
Test URL
https://api.thingspeak.com/update?api_key=YOUR_WRITE_KEY&field1=3.42&field2=0.18&field3=0.61&field4=1.25&field5=12
Dashboard widgets
Add these widgets:
- Voltage chart
- Current chart
- Power chart
- Energy cumulative chart
- Footstep count chart
- MATLAB Visualization for anomaly score
- Status indicator using last value
8. n8n Automation Workflow
Required n8n nodes
| Node | Purpose |
|---|---|
| Webhook | Receives ESP32 JSON data |
| Set / Edit Fields | Cleans and formats incoming data |
| Google Sheets | Appends one row per reading |
| IF | Checks alert conditions |
| HTTP Request | Calls Telegram Bot API |
| HTTP Request | Calls Python ML API |
| Code | Calculates anomaly score and alert message |
| Schedule Trigger | Runs hourly prediction and daily report |
n8n’s Webhook node can start a workflow from an external device event, while its HTTP Request node can call REST APIs.[docs.n8n][n8n]
ESP32 to n8n JSON format
{
"device_id": "FOOTSTEP_ESP32_01",
"location": "Main Entrance",
"voltage": 4.12,
"current": 0.24,
"power": 0.98,
"energy_wh": 12.45,
"steps": 87,
"low_generation": false,
"high_voltage": false,
"high_power": false,
"timestamp": 12345678
}
n8n workflow logic
ESP32
│
▼
Webhook: /webhook/footstep-power
│
▼
Set Node: normalize fields
│
├──> Google Sheets: Append row
│
├──> IF: high voltage OR high power OR low generation
│ │
│ ├──> Code: build alert message
│ │
│ ├──> Telegram: sendMessage
│ │
│ └──> HTTP Request: AI voice generation service
│ │
│ └──> Telegram: sendVoice
│
└──> HTTP Request: ML prediction API
│
└──> ThingSpeak: write predicted power
Ready-to-import n8n workflow JSON
Save this as footstep-power-n8n-workflow.json, then in n8n choose Import from File.
{
"name": "AI Footstep Power Generation Monitoring System",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "footstep-power",
"responseMode": "onReceived",
"options": {}
},
"id": "webhook-node",
"name": "ESP32 Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [0, 0],
"webhookId": "footstep-power-webhook"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "device_id",
"name": "device_id",
"value": "={{ $json.body.device_id }}",
"type": "string"
},
{
"id": "location",
"name": "location",
"value": "={{ $json.body.location }}",
"type": "string"
},
{
"id": "voltage",
"name": "voltage",
"value": "={{ Number($json.body.voltage) }}",
"type": "number"
},
{
"id": "current",
"name": "current",
"value": "={{ Number($json.body.current) }}",
"type": "number"
},
{
"id": "power",
"name": "power",
"value": "={{ Number($json.body.power) }}",
"type": "number"
},
{
"id": "energy_wh",
"name": "energy_wh",
"value": "={{ Number($json.body.energy_wh) }}",
"type": "number"
},
{
"id": "steps",
"name": "steps",
"value": "={{ Number($json.body.steps) }}",
"type": "number"
},
{
"id": "low_generation",
"name": "low_generation",
"value": "={{ Boolean($json.body.low_generation) }}",
"type": "boolean"
},
{
"id": "high_voltage",
"name": "high_voltage",
"value": "={{ Boolean($json.body.high_voltage) }}",
"type": "boolean"
},
{
"id": "high_power",
"name": "high_power",
"value": "={{ Boolean($json.body.high_power) }}",
"type": "boolean"
}
]
},
"options": {}
},
"id": "normalize-node",
"name": "Normalize ESP32 Data",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [220, 0]
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "YOUR_GOOGLE_SHEET_DOCUMENT_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "FootstepPowerData",
"mode": "name"
},
"columns": {
"mappingMode": "autoMapInputData",
"matchingColumns": [],
"schema": []
},
"options": {}
},
"id": "google-sheet-node",
"name": "Log to Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [440, -160],
"credentials": {
"googleSheetsOAuth2Api": {
"id": "REPLACE_WITH_CREDENTIAL_ID",
"name": "Google Sheets account"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"leftValue": "={{ $json.high_voltage }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true"
}
},
{
"leftValue": "={{ $json.high_power }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true"
}
},
{
"leftValue": "={{ $json.low_generation }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true"
}
}
],
"combinator": "or"
},
"options": {}
},
"id": "alert-if-node",
"name": "Check Alert Conditions",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [440, 120]
},
{
"parameters": {
"jsCode": "const d = $input.first().json;\n\nlet issue = [];\n\nif (d.high_voltage) issue.push('high voltage detected');\nif (d.high_power) issue.push('abnormal power level detected');\nif (d.low_generation) issue.push('low footstep power generation detected');\n\nconst message = `⚠️ Footstep Power Alert\\n\\nDevice: ${d.device_id}\\nLocation: ${d.location}\\nVoltage: ${d.voltage.toFixed(2)} V\\nCurrent: ${d.current.toFixed(3)} A\\nPower: ${d.power.toFixed(3)} W\\nEnergy: ${d.energy_wh.toFixed(3)} Wh\\nSteps: ${d.steps}\\n\\nIssue: ${issue.join(', ')}`;\n\nconst voiceText = `Attention. Footstep power system alert at ${d.location}. ${issue.join(', ')}. Voltage ${d.voltage.toFixed(1)} volts. Power ${d.power.toFixed(2)} watts.`;\n\nreturn [{ json: { ...d, alert_message: message, voice_text: voiceText } }];"
},
"id": "alert-message-node",
"name": "Build AI Alert Message",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [660, 120]
},
{
"parameters": {
"method": "POST",
"url": "https://api.telegram.org/botYOUR_TELEGRAM_BOT_TOKEN/sendMessage",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ chat_id: YOUR_TELEGRAM_CHAT_ID, text: $json.alert_message, parse_mode: 'HTML' }) }}",
"options": {}
},
"id": "telegram-text-node",
"name": "Telegram Text Alert",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [880, 40]
},
{
"parameters": {
"method": "POST",
"url": "http://YOUR_AI_SERVER:8000/generate-voice",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ text: $json.voice_text }) }}",
"options": {}
},
"id": "voice-generation-node",
"name": "Generate Voice Alert",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [880, 220]
},
{
"parameters": {
"method": "POST",
"url": "https://api.telegram.org/botYOUR_TELEGRAM_BOT_TOKEN/sendVoice",
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"name": "chat_id",
"value": "YOUR_TELEGRAM_CHAT_ID"
},
{
"parameterType": "formBinaryData",
"name": "voice",
"inputDataFieldName": "data"
}
]
},
"options": {}
},
"id": "telegram-voice-node",
"name": "Telegram Voice Alert",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1100, 220]
}
],
"connections": {
"ESP32 Webhook": {
"main": [
[
{
"node": "Normalize ESP32 Data",
"type": "main",
"index": 0
}
]
]
},
"Normalize ESP32 Data": {
"main": [
[
{
"node": "Log to Google Sheets",
"type": "main",
"index": 0
},
{
"node": "Check Alert Conditions",
"type": "main",
"index": 0
}
]
]
},
"Check Alert Conditions": {
"main": [
[
{
"node": "Build AI Alert Message",
"type": "main",
"index": 0
}
]
]
},
"Build AI Alert Message": {
"main": [
[
{
"node": "Telegram Text Alert",
"type": "main",
"index": 0
},
{
"node": "Generate Voice Alert",
"type": "main",
"index": 0
}
]
]
},
"Generate Voice Alert": {
"main": [
[
{
"node": "Telegram Voice Alert",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Telegram’s sendVoice method accepts OGG/OPUS, MP3, or M4A audio for a playable voice message.[core.telegram]
9. Telegram Bot Setup
Create the bot
- Open Telegram and search for @BotFather.
- Send
/newbot. - Enter a display name, for example:
Footstep Power AI Bot. - Enter a username ending in
bot, for example:footstep_power_ai_bot. - Copy the bot token. It looks like:
1234567890:AAExampleBotTokenFromBotFather
Get your chat ID
- Send any message to your new bot.
- Open this URL in a browser:
https://api.telegram.org/botYOUR_BOT_TOKEN/getUpdates
- Find:
"chat": {
"id": 123456789
}
- Use that numeric ID as
YOUR_TELEGRAM_CHAT_ID.
Test text alert
https://api.telegram.org/botYOUR_BOT_TOKEN/sendMessage?chat_id=YOUR_CHAT_ID&text=Footstep%20Power%20System%20Online
Test voice alert
For automated voice, generate an .ogg Opus file or .mp3 file, then send it using Telegram sendVoice. Telegram supports these formats for voice messages.[core.telegram]
10. Google Sheets Integration
Sheet structure
Create a Google Sheet named:
AI Footstep Power Generation Monitoring
Create a tab named:
FootstepPowerData
Add headers in row 1:
| Timestamp | Device ID | Location | Voltage V | Current A | Power W | Energy Wh | Steps | Low Generation | High Voltage | High Power | AI Predicted Power W | Anomaly Score |
|---|
Connect n8n to Google Sheets
- In n8n, open Credentials → Add Credential.
- Search for Google Sheets OAuth2 API.
- Create a Google Cloud project.
- Enable Google Sheets API and Google Drive API.
- Create OAuth Client ID credentials.
- Add the n8n redirect URL to authorized redirect URIs.
- Connect the Google account in n8n.
- Select your spreadsheet and worksheet in the Google Sheets node.
- Set operation to Append.
11. AI Power Prediction Logic
Simple on-device prediction
A lightweight moving-average model can predict the next reading:
P_{\text{predicted}} = \alpha P_{\text{current}} + (1-\alpha)P_{\text{previous average}}
Use \alpha = 0.3 for stable predictions.
Advanced ML model
Use historical features:
- Hour of day
- Day of week
- Previous 1-hour average power
- Previous 24-hour average power
- Footstep count
- Voltage
- Current
- Temperature
- Humidity
- Location/tile ID
Target:
Next-hour average power
Python ML model
Install dependencies:
pip install pandas scikit-learn joblib flask flask-cors gunicorn
Create ml_model.py:
import pandas as pd
import numpy as np
import joblib
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, r2_score
# ---------------- Load Dataset ----------------
df = pd.read_csv("footstep_power_dataset.csv")
df["timestamp"] = pd.to_datetime(df["timestamp"])
df["hour"] = df["timestamp"].dt.hour
df["dayofweek"] = df["timestamp"].dt.dayofweek
df["power_lag_1"] = df["power"].shift(1)
df["power_lag_24"] = df["power"].shift(24)
df["rolling_power_1h"] = df["power"].rolling(6).mean()
df["rolling_power_24h"] = df["power"].rolling(144).mean()
df = df.dropna()
features = [
"hour",
"dayofweek",
"voltage",
"current",
"power",
"steps",
"temperature",
"humidity",
"power_lag_1",
"power_lag_24",
"rolling_power_1h",
"rolling_power_24h"
]
target = "next_hour_power"
X = df[features]
y = df[target]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
model = RandomForestRegressor(
n_estimators=250,
max_depth=18,
min_samples_leaf=2,
random_state=42,
n_jobs=-1
)
model.fit(X_train, y_train)
predictions = model.predict(X_test)
print("MAE:", mean_absolute_error(y_test, predictions))
print("R2 Score:", r2_score(y_test, predictions))
joblib.dump(model, "footstep_power_model.pkl")
joblib.dump(features, "model_features.pkl")
Dataset CSV format
Create footstep_power_dataset.csv:
timestamp,device_id,location,voltage,current,power,steps,temperature,humidity,next_hour_power
2026-10-22 08:00:00,FOOTSTEP_ESP32_01,Main Entrance,4.1,0.22,0.90,42,28.5,65,0.95
2026-10-22 09:00:00,FOOTSTEP_ESP32_01,Main Entrance,4.4,0.28,1.23,68,29.1,63,1.35
Flask AI prediction API
Create app.py:
from flask import Flask, request, jsonify
from flask_cors import CORS
import joblib
import numpy as np
app = Flask(__name__)
CORS(app)
model = joblib.load("footstep_power_model.pkl")
features = joblib.load("model_features.pkl")
@app.route("/predict", methods=["POST"])
def predict():
data = request.get_json()
try:
input_values = [float(data[feature]) for feature in features]
except KeyError as e:
return jsonify({
"error": f"Missing feature: {str(e)}",
"required_features": features
}), 400
prediction = model.predict([input_values])[0]
anomaly_score = 0.0
if prediction < 0.2:
anomaly_score = 0.8
elif data.get("voltage", 0) > 12:
anomaly_score = 0.9
elif data.get("power", 0) > 5:
anomaly_score = 0.95
return jsonify({
"predicted_next_hour_power": round(float(prediction), 4),
"anomaly_score": anomaly_score,
"status": "low_generation_alert" if anomaly_score >= 0.8 else "normal"
})
@app.route("/health", methods=["GET"])
def health():
return jsonify({"status": "AI service running"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Run:
python app.py
Test:
curl -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-d '{"hour":9,"dayofweek":3,"voltage":4.2,"current":0.25,"power":1.05,"steps":65,"temperature":29,"humidity":64,"power_lag_1":1.0,"power_lag_24":0.9,"rolling_power_1h":0.98,"rolling_power_24h":0.85}'
12. Voice Notification Automation
Option A: Use a TTS API
Use a text-to-speech service such as:
- Google Cloud Text-to-Speech
- Amazon Polly
- ElevenLabs
- Microsoft Azure Speech
- Local Coqui TTS server
Example request to your local TTS service:
{
"text": "Attention. Footstep power generation is low at the main entrance. Please inspect the system."
}
Your TTS API should return an audio file in .ogg, .mp3, or .m4A. Telegram can send these formats through sendVoice.[core.telegram]
Option B: Python TTS microservice
Create voice_service.py:
from flask import Flask, request, jsonify, send_file
from gtts import gTTS
import uuid
import os
app = Flask(__name__)
@app.route("/generate-voice", methods=["POST"])
def generate_voice():
data = request.get_json()
text = data.get("text", "Footstep power system alert.")
filename = f"{uuid.uuid4()}.mp3"
filepath = os.path.join("/tmp", filename)
tts = gTTS(text=text, lang="en")
tts.save(filepath)
return send_file(
filepath,
mimetype="audio/mpeg",
as_attachment=True,
download_name="alert.mp3"
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Install:
pip install flask gTTS
Run:
python voice_service.py
In n8n, set the Generate Voice Alert HTTP Request URL to:
http://YOUR_SERVER_IP:8000/generate-voice
Set response format to File, then pass the binary field to Telegram sendVoice.
13. Mobile App Dashboard
Option A: Blynk alternative
Use Blynk if you want a fast mobile dashboard:
- Add ESP32 using Blynk library.
- Create widgets for voltage, current, power, energy, and steps.
- Add notification events for high voltage, low generation, and high power.
Option B: Flutter dashboard
Create a Flutter app that reads from ThingSpeak’s read API:
https://api.thingspeak.com/channels/YOUR_CHANNEL_ID/feeds.json?api_key=YOUR_READ_API_KEY&results=20
Flutter dependencies
dependencies:
flutter:
sdk: flutter
http: ^1.2.0
fl_chart: ^0.68.0
Flutter example
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:fl_chart/fl_chart.dart';
void main() {
runApp(const FootstepPowerApp());
}
class FootstepPowerApp extends StatelessWidget {
const FootstepPowerApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Footstep Power AI',
theme: ThemeData.dark(useMaterial3: true),
home: const DashboardPage(),
);
}
}
class DashboardPage extends StatefulWidget {
const DashboardPage({super.key});
@override
State<DashboardPage> createState() => _DashboardPageState();
}
class _DashboardPageState extends State<DashboardPage> {
List<double> powerData = [];
double latestPower = 0;
double latestVoltage = 0;
double latestCurrent = 0;
double latestEnergy = 0;
final String channelId = "YOUR_THINGSPEAK_CHANNEL_ID";
final String readApiKey = "YOUR_THINGSPEAK_READ_API_KEY";
@override
void initState() {
super.initState();
loadData();
}
Future<void> loadData() async {
final url = Uri.parse(
"https://api.thingspeak.com/channels/$channelId/feeds.json"
"?api_key=$readApiKey&results=20"
);
final response = await http.get(url);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final feeds = data["feeds"] as List;
setState(() {
powerData = feeds
.map((e) => double.tryParse(e["field3"].toString()) ?? 0)
.toList();
if (feeds.isNotEmpty) {
final last = feeds.last;
latestVoltage = double.tryParse(last["field1"].toString()) ?? 0;
latestCurrent = double.tryParse(last["field2"].toString()) ?? 0;
latestPower = double.tryParse(last["field3"].toString()) ?? 0;
latestEnergy = double.tryParse(last["field4"].toString()) ?? 0;
}
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Footstep Power AI")),
body: RefreshIndicator(
onRefresh: loadData,
child: ListView(
padding: const EdgeInsets.all(16),
children: [
Row(
children: [
metricCard("Voltage", "$latestVoltage V"),
metricCard("Current", "$latestCurrent A"),
],
),
const SizedBox(height: 10),
Row(
children: [
metricCard("Power", "$latestPower W"),
metricCard("Energy", "$latestEnergy Wh"),
],
),
const SizedBox(height: 20),
const Text("Live Power Generation"),
SizedBox(
height: 250,
child: LineChart(
LineChartData(
lineBarsData: [
LineChartBarData(
spots: powerData
.asMap()
.entries
.map(
(e) => FlSpot(
e.key.toDouble(),
e.value,
),
)
.toList(),
isCurved: true,
barWidth: 3,
dotData: const FlDotData(show: false),
)
],
),
),
),
],
),
),
);
}
Widget metricCard(String title, String value) {
return Expanded(
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Text(title),
const SizedBox(height: 8),
Text(
value,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
);
}
}
14. GitHub-Ready Project Structure
ai-footstep-power-monitoring-system/
│
├── README.md
├── LICENSE
├── .gitignore
├── requirements.txt
│
├── esp32/
│ └── footstep_power_esp32.ino
│
├── n8n/
│ └── footstep-power-n8n-workflow.json
│
├── ai_model/
│ ├── ml_model.py
│ ├── app.py
│ ├── footstep_power_model.pkl
│ ├── model_features.pkl
│ └── footstep_power_dataset.csv
│
├── voice_service/
│ ├── voice_service.py
│ └── requirements.txt
│
├── mobile_app/
│ ├── pubspec.yaml
│ └── lib/
│ └── main.dart
│
├── docs/
│ ├── circuit_diagram.md
│ ├── flowchart.md
│ ├── installation_guide.md
│ └── deployment_guide.md
│
└── images/
├── circuit_diagram.png
├── system_architecture.png
└── dashboard_screenshot.png
requirements.txt
pandas
numpy
scikit-learn
joblib
flask
flask-cors
gunicorn
gTTS
.gitignore
__pycache__/
*.pyc
.venv/
venv/
*.pkl
*.csv
.env
node_modules/
Do not commit real API keys, Telegram tokens, Google credentials, or Wi-Fi passwords. Use .env files or n8n credentials.
15. Deployment Guide
Local testing
- Assemble the circuit on a breadboard.
- Upload ESP32 code using Arduino IDE.
- Open Serial Monitor at 115200 baud.
- Verify voltage, current, and power values.
- Test ThingSpeak using the ESP32 or browser URL.
- Start n8n locally.
- Import the n8n workflow JSON.
- Activate the webhook.
- Update the ESP32 with your n8n webhook URL.
- Test Telegram text and voice alerts.
Production deployment
| Component | Recommended Deployment |
|---|---|
| ESP32 | Permanent enclosure near footpath/tile |
| n8n | Cloud VPS, Docker, Railway, Render, or local server |
| AI model | Flask API on VPS with Gunicorn |
| Voice service | Same VPS or separate microservice |
| Google Sheets | Google Drive cloud storage |
| ThingSpeak | Public/private IoT dashboard |
| Mobile app | Flutter APK or Play Store release |
Docker command for n8n
docker run -it --rm \
--name n8n \
-p 5678:5678 \
-v n8n_data:/home/node/.n8n \
docker.n8n.io/n8nio/n8n
Run AI API with Gunicorn
gunicorn -w 2 -b 0.0.0.0:8000 app:app
Run voice API
gunicorn -w 2 -b 0.0.0.0:8001 voice_service:app
16. Testing Checklist
- ESP32 connects to Wi-Fi.
- Voltage reading changes when pressure is applied.
- Current sensor returns near zero at idle.
- Power calculation is correct:
P = V \times I. - ThingSpeak fields update every 20 seconds.
- n8n webhook receives JSON.
- Google Sheets receives a new row.
- Telegram text alert is delivered.
- Voice alert is generated and delivered.
- AI API returns prediction and anomaly score.
- Low-generation alert triggers correctly.
- High-voltage alert triggers correctly.
- System runs for at least 24 hours without failure.
17. Future Enhancements
- Add multiple footstep tiles with separate ESP32 nodes.
- Use MQTT instead of HTTP for lower latency and lower power use.
- Add supercapacitors for burst-energy storage.
- Add MPPT-based energy-harvesting optimization.
- Use LSTM/GRU or XGBoost for improved generation forecasting.
- Add weather and footfall-pattern correlation.
- Add automatic load switching using a relay.
- Add GPS/location tagging for multi-site installations.
- Add anomaly detection using Isolation Forest or autoencoders.
- Add a React or Flutter admin dashboard with historical analytics.
- Add WhatsApp, email, SMS, and dashboard notifications.
- Add solar-assisted hybrid power generation.
- Add digital twin visualization of foot traffic and energy generation.
18. Key Formulas
Instantaneous electrical power:
P = V \times I
Energy over time:
E = P \times t
Energy in watt-hours:
E_{\text{Wh}} = \frac{P \times t_{\text{seconds}}}{3600}
Voltage divider output:
V_{\text{ESP32}} = V_{\text{input}} \times \frac{R_2}{R_1 + R_2}
For R_1 = 100\,\text{k}\Omega and R_2 = 10\,\text{k}\Omega:
V_{\text{ESP32}} = V_{\text{input}} \times \frac{1}{11}
Therefore:
V_{\text{input}} = V_{\text{ESP32}} \times 11
This documentation gives you a complete academic/project-report-ready system: hardware, circuit, firmware, cloud dashboard, automation, AI prediction, voice alerts, mobile dashboard, and deployment workflow.

No comments:
Post a Comment