Thursday, 22 October 2026

AI Footstep Power Generation Monitoring System

AI Footstep Power Generation Monitoring System

Complete IoT, ESP32, AI Agent, n8n Automation, Telegram Voice Alerts, Google Sheets & ThingSpeak Project

Design and Comparative Study of a Small-Stroke Energy Harvesting Floor Based on a Multi-Layer Piezoelectric Beam Structure | MDPI
 
 
ESP32 IOT Dashboard. | ESP32
 
 
Design piezoelectric energy harvesting circuit with fritzing, ltspice simulation by Kingsley_techn | Fiverr
 
 

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

Probots ESP32 30 Pin CP2102 Development Board - WiFi & Bluetooth IoT Module Buy Online India
 
 
30mm Piezo Disc - High-Quality Ceramic Transducer Element
 
 
Bridge Rectifier: Complete AC-DC Conversion Guide & Selection 2026
 
 

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:

  1. Harvesting path: Piezo array → rectifier → storage capacitor or energy-harvesting circuit → optional regulated load.

  2. 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

Solar Powered WiFi Weather Station V3.0 - Redeem Hardware Products, DIY Electronics, and Kits by PCBWay Beans - PCBWay
 
 

Use the following measurement connections after the piezo output has been safely rectified and limited:

text
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:

VADC=VINRBOTTOMRTOP+RBOTTOMVADC=VINRTOP+RBOTTOMRBOTTOM

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 .

— ESP-IDF Programming Guide latest documentation

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:

E=12CV2E=21CV2

The change in stored energy is:

ΔE=12C(V22−V12)ΔE=21C(V22−V12)

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

  1. Install the Arduino IDE.

  2. Add the ESP32 board support package using the official Arduino-ESP32 documentation .

    Espressif Documentation
  3. Select your ESP32 development board and serial port.

  4. 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)

  5. 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.

MATLAB & Simulink
+1

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.

cpp

#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_PULLDOWN and RISING must 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.

  • deltaEnergyJ can 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

Advanced IoT Data Processing with ThinkSpeak - Embedded Computing
 
 
ThingSpeak for Energy Monitoring - ThingSpeak IoT
 
 
Create Customized ThingSpeak Channel View - MATLAB & Simulink
 
 

6.1 Create the channel

  1. Open ThingSpeak .

  2. Sign in and select Channels → My Channels → New Channel.

  3. Name it AI Footstep Energy Monitor.

  4. 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

  1. Save the channel.

  2. Open its API Keys tab and copy the Write API Key into the firmware.

  3. Save the firmware and upload it to the ESP32.

  4. Open the Serial Monitor and confirm that uploads return a positive entry identifier.

  5. Return to ThingSpeak and confirm that the fields and charts update.

ThingSpeak supports REST-based channel writes and reads, including time-series field graphs.

MATLAB & Simulink
+2

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.

GitHub
+3

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.

GitHub
+1

7.2 Configure the HTTP Request node

Add an HTTP Request node after the Schedule Trigger.

  • Method: GET

  • URL:

text
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:

json
{
  "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:

javascript
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:

  1. Add a Google Sheets node.

  2. Authenticate with your Google account.

  3. Select the spreadsheet and worksheet.

  4. Choose Append Row.

  5. Map the incoming fields to the corresponding columns.

  6. Save and test the node with a sample entry.

The Google Sheets integration supports appending rows and other spreadsheet operations.

GitHub
+1

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.

GitHub
+1

8.2 Recommended system prompt

text

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:

json
{
  "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

Уведомления из сценариев Loginom при помощи Telegram | Loginom
 
 
Telegram Message Types | WOZTELL Platform Documentation
 
 
How to build voice Telegram AI bot with n8n, Whisper and ElevenLabs
 
 

9.1 Create a Telegram bot

  1. Open Telegram and search for the official @BotFather account.

  2. Send /newbot.

  3. Choose a bot name and username.

  4. Copy the generated bot token.

  5. Open your new bot and send /start.

  6. Obtain your chat ID using the Telegram Bot API or an n8n Telegram Trigger workflow.

  7. In n8n, create Telegram credentials using the bot token.

  8. 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

 
Sample notification
 

⚠️ 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.

Wyldhyde Technologies
 
 
IoT Energy Management & Monitoring with ThingsBoard | Use Cases | ThingsBoard
 
 
Cloudsty IS – platforma IoT do monitoringu i analizy | Cloudsty
 
 

10.1 Recommended dashboard layout

 

Footstep Energy Monitor

ESP32 · IoT telemetry · AI diagnostics

Demo layout

Conditioned voltage

— V

Awaiting live sensor data

Footsteps

—

Cumulative count

Stored energy

— J

Capacitor estimate

Device status

Unknown

Connect a data source

Voltage 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:

  1. Create a frontend using HTML, CSS and JavaScript or a framework such as React.

  2. Read channel data through the ThingSpeak REST API.

  3. Parse the latest measurements and render chart components.

  4. Poll at a reasonable interval or use a supported streaming approach.

  5. Display the data timestamp and stale-data status.

  6. 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

  1. A person steps on the piezo tile.
  2. The piezo element produces an AC pulse.
  3. A bridge rectifier converts it to DC.
  4. The capacitor and battery storage circuit smooth and store energy.
  5. ESP32 samples voltage and current.
  6. ESP32 calculates instantaneous power and accumulated energy.
  7. ESP32 sends a JSON payload to n8n and ThingSpeak.
  8. 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:

  • WiFi
  • HTTPClient
  • ArduinoJson
  • Adafruit GFX
  • Adafruit SSD1306
  • Adafruit Sensor
  • DHT sensor library, optional

Replace the placeholders:

  • YOUR_WIFI_SSID
  • YOUR_WIFI_PASSWORD
  • YOUR_THINGSPEAK_WRITE_API_KEY
  • YOUR_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

  1. Sign in at ThingSpeak.
  2. Go to Channels → My Channels → New Channel.
  3. Name it: AI Footstep Power Monitoring.
  4. 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 %
  1. Save the channel.
  2. Open API Keys and copy the Write API Key.
  3. 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

  1. Open Telegram and search for @BotFather.
  2. Send /newbot.
  3. Enter a display name, for example: Footstep Power AI Bot.
  4. Enter a username ending in bot, for example: footstep_power_ai_bot.
  5. Copy the bot token. It looks like:
1234567890:AAExampleBotTokenFromBotFather

Get your chat ID

  1. Send any message to your new bot.
  2. Open this URL in a browser:
https://api.telegram.org/botYOUR_BOT_TOKEN/getUpdates
  1. Find:
"chat": {
  "id": 123456789
}
  1. 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

  1. In n8n, open Credentials → Add Credential.
  2. Search for Google Sheets OAuth2 API.
  3. Create a Google Cloud project.
  4. Enable Google Sheets API and Google Drive API.
  5. Create OAuth Client ID credentials.
  6. Add the n8n redirect URL to authorized redirect URIs.
  7. Connect the Google account in n8n.
  8. Select your spreadsheet and worksheet in the Google Sheets node.
  9. 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

  1. Assemble the circuit on a breadboard.
  2. Upload ESP32 code using Arduino IDE.
  3. Open Serial Monitor at 115200 baud.
  4. Verify voltage, current, and power values.
  5. Test ThingSpeak using the ESP32 or browser URL.
  6. Start n8n locally.
  7. Import the n8n workflow JSON.
  8. Activate the webhook.
  9. Update the ESP32 with your n8n webhook URL.
  10. 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