An end-to-end guide and technical documentation for building an AI-Powered, Agentic IoT Battery Management System (BMS) for Electric Vehicles using ESP32, n8n Automation, Telegram Voice Alerts, ThingSpeak, and Google Sheets.
1. Full Project Description
Electric Vehicle (EV) batteries require real-time tracking of parameters such as voltage, current draw, temperature, State of Charge (SoC), and State of Health (SoH). Traditional BMS units protect against overcharging or overheating locally, but lack predictive cloud intelligence and agentic automated interventions.
This project implements an Agentic AI Battery Management System:
-
Edge Layer (ESP32): Reads voltage, current (ACS712), and temperature (DS18B20/DHT11), manages load isolation via relays, and transmits metrics to the cloud over Wi-Fi/HTTP.
-
Telemetry & Visualization (ThingSpeak): Receives real-time sensor streams and provides live dashboard analytics.
-
Orchestration & AI Agent Layer (n8n): Serves as the central autonomous engine. It receives webhooks from the ESP32/ThingSpeak, evaluates anomalies, calls AI models (e.g., OpenAI API) to predict power consumption and thermal runaway, logs data to Google Sheets, and triggers Telegram voice notifications.
-
Alerting Engine (Telegram Voice Bot): Converts AI-generated text alerts into audio files using Text-to-Speech (TTS) engine and sends voice notes directly to the fleet operator's Telegram app.
2. Hardware Components List
| Component | Model / Specification | Function / Purpose |
| Microcontroller | ESP32-WROOM-32 Development Board | Edge processing, sensor reading, Wi-Fi connectivity |
| Current Sensor | ACS712 (20A or 30A module) | Measures current draw (Amperes) |
| Voltage Sensor | Voltage Divider / Voltage Sensor Module (0–25V) | Measures battery pack terminal voltage |
| Temperature Sensor | DS18B20 (Waterproof) or DHT11/DHT22 | Monitors battery surface temperature |
| Relay Module | 2-Channel 5V Relay Module | Battery protection cutout (Overvoltage / Overcurrent / Overheat) |
| Battery Pack | 12V LiFePO4 or 3S Li-ion Battery | EV main power source under test |
| Display (Optional) | 0.96" I2C OLED Display (SSD1306) | Local dashboard display |
| Miscellaneous | Resistors (10kΩ, 4.7kΩ), Jumper Wires, Breadboard/PCB | Circuit assembly & pull-ups |
3. Circuit Schematic & Wiring Guide
ESP32 Pin Connections
+-------------------------------------------------+
| ESP32-WROOM |
+-------------------------------------------------+
| Vin ---> 5V External Supply / Buck Converter |
| GND ---> Common Ground |
| GPIO 34 -> ACS712 OUT (Current Sensor) |
| GPIO 35 -> Voltage Sensor OUT |
| GPIO 4 -> DS18B20 Data (with 4.7k Pull-up) |
| GPIO 21 -> OLED SDA |
| GPIO 22 -> OLED SCL |
| GPIO 18 -> Relay 1 IN (Cut-off Relay) |
| GPIO 19 -> Relay 2 IN (Cooling Fan / Reserve) |
+-------------------------------------------------+
Detailed Wiring Instructions
-
ACS712 Current Sensor: Connect $V_{CC}$ to 5V, $GND$ to ESP32 $GND$, and $OUT$ to GPIO 34. Ensure voltage divider (e.g., 10k/20k) if output exceeds 3.3V.
-
Voltage Sensor Module: Connect $V_{CC}$ to Battery $(+)$, $GND$ to Battery $(-)$. Output pin goes to GPIO 35.
-
DS18B20 Temperature Sensor: Connect $V_{CC}$ to 3.3V, $GND$ to $GND$, Data wire to GPIO 4. Connect a 4.7kΩ resistor between Data and 3.3V.
-
Relay Module: Connect $V_{CC}$ to 5V, $GND$ to $GND$, $IN1$ to GPIO 18, $IN2$ to GPIO 19.
4. Flowchart & System Architecture
+----------------------------------------------------------+
| ESP32 Edge Microcontroller |
| - Sample Sensors (Voltage, Current, Temp) |
| - Compute SoC (%) & Power (W) |
| - Check Hardware Limits (Relay Trip if Critical) |
+----------------------------+-----------------------------+
|
Wi-Fi / HTTP POST
v
+--------------------------+--------------------------+
| |
v v
+-----------------------+ +-------------------------------+
| ThingSpeak Cloud | | n8n Agentic Workflow Engine |
| - Live Graphs | | - Webhook Trigger |
| - Historical Logs | | - Data Preprocessing |
+-----------------------+ +---------------+---------------+
|
+--------------+--------------+
| |
v v
+-------------------------------+ +-----------------------+
| AI Engine (LLM / ML Node) | | Google Sheets Node |
| - Predict Consumption | | - Append Telemetry |
| - Health / Anomaly Diagnosis | | Logs |
+---------------+---------------+ +-----------------------+
|
v
+-------------------------------+
| TTS Voice Generation Service |
| - Convert AI Alert to Audio |
+---------------+---------------+
|
v
+-------------------------------+
| Telegram Bot Service |
| - Dispatch Voice Note & Text |
+-------------------------------+
5. ESP32 Source Code
Flash this standard C++ sketch via Arduino IDE. Ensure libraries OneWire, DallasTemperature, Adafruit_SSD1306, and HTTPClient are installed.
#include <WiFi.h>
#include <HTTPClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// --- Network Configuration ---
const char* SSID = "YOUR_WIFI_SSID";
const char* PASSWORD = "YOUR_WIFI_PASSWORD";
// --- Endpoint URLs ---
const char* THINGSPEAK_URL = "http://api.thingspeak.com/update";
const char* THINGSPEAK_API_KEY = "YOUR_THINGSPEAK_WRITE_KEY";
const char* N8N_WEBHOOK_URL = "http://YOUR_N8N_SERVER_IP:5678/webhook/ev-bms-data";
// --- Hardware Pins ---
#define CURRENT_PIN 34
#define VOLTAGE_PIN 35
#define TEMP_PIN 4
#define RELAY_PIN 18
OneWire oneWire(TEMP_PIN);
DallasTemperature tempSensor(&oneWire);
Adafruit_SSD1306 display(128, 64, &Wire, -1);
// --- Global Variables ---
float voltage = 0.0;
float current = 0.0;
float temperature = 0.0;
float power = 0.0;
float soc = 0.0;
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH); // Relay closed by default
tempSensor.begin();
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("OLED Allocation Failed"));
}
display.clearDisplay();
display.setTextColor(WHITE);
WiFi.begin(SSID, PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi Connected");
}
void readSensors() {
// Voltage Reading (Calibrated for 0-25V Module)
int vAnalog = analogRead(VOLTAGE_PIN);
voltage = (vAnalog / 4095.0) * 3.3 * 5.0; // Voltage Divider Ratio ~5:1
// Current Reading (ACS712-20A: 100mV/A sensitivity, zero-current offset ~1.65V)
int iAnalog = analogRead(CURRENT_PIN);
float rawV = (iAnalog / 4095.0) * 3.3;
current = abs((rawV - 1.65) / 0.100);
// Temperature Reading
tempSensor.requestTemperatures();
temperature = tempSensor.getTempCByIndex(0);
// Derived Metrics
power = voltage * current;
// Basic SoC estimation for 12V LiFePO4 / Li-ion (10.0V = 0%, 12.6V = 100%)
soc = map(constrain(voltage * 100, 1000, 1260), 1000, 1260, 0, 100);
// Safety Hard Cutoff
if (temperature > 55.0 || current > 15.0 || voltage < 9.5) {
digitalWrite(RELAY_PIN, LOW); // Trip Relay
} else {
digitalWrite(RELAY_PIN, HIGH);
}
}
void sendTelemetry() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
// 1. Send to ThingSpeak
String tsUrl = String(THINGSPEAK_URL) + "?api_key=" + THINGSPEAK_API_KEY +
"&field1=" + String(voltage) +
"&field2=" + String(current) +
"&field3=" + String(temperature) +
"&field4=" + String(soc);
http.begin(tsUrl);
http.GET();
http.end();
// 2. Send JSON Payload to n8n Webhook
http.begin(N8N_WEBHOOK_URL);
http.addHeader("Content-Type", "application/json");
String payload = "{\"voltage\":" + String(voltage) +
",\"current\":" + String(current) +
",\"temperature\":" + String(temperature) +
",\"power\":" + String(power) +
",\"soc\":" + String(soc) + "}";
http.POST(payload);
http.end();
}
}
void updateDisplay() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,0);
display.printf("EV BMS AI System\n");
display.printf("Volt: %.2f V\n", voltage);
display.printf("Curr: %.2f A\n", current);
display.printf("Temp: %.1f C\n", temperature);
display.printf("Power: %.1f W\n", power);
display.printf("SoC: %.0f %%\n", soc);
display.display();
}
void loop() {
readSensors();
updateDisplay();
sendTelemetry();
delay(15000); // 15-second update interval
}
6. n8n Automation Workflow Setup
The n8n engine coordinates AI evaluation, spreadsheet logging, and Telegram messaging.
Workflow Execution Steps
-
Webhook Trigger Node: Receives
POSTrequest from ESP32 with JSON data (voltage,current,temperature,power,soc). -
Google Sheets Node: Appends a new row with timestamp, voltage, current, temperature, power, and SoC.
-
AI Agent / OpenAI Node: Analyzes parameters and generates structured predictive diagnostics.
-
If / Switch Node: Evaluates if AI flags an anomaly (e.g., thermal spike or battery strain).
-
TTS Node (ElevenLabs or OpenAI Audio API): Converts AI summary into audio (
.oggor.mp3). -
Telegram Node: Transmits audio alert to fleet operator's Telegram channel.
n8n Workflow JSON Export
You can import this JSON directly into your n8n workspace:
{
"name": "EV_BMS_Agentic_Automation",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "ev-bms-data",
"options": {}
},
"name": "Webhook ESP32",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [250, 300]
},
{
"parameters": {
"operation": "append",
"sheetId": "YOUR_GOOGLE_SHEET_ID",
"range": "Raw_Data!A:F",
"options": {}
},
"name": "Google Sheets Log",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"position": [500, 200]
},
{
"parameters": {
"model": "gpt-4o-mini",
"messages": {
"values": [
{
"content": "=Analyze EV battery metrics: Voltage={{$json.body.voltage}}V, Current={{$json.body.current}}A, Temp={{$json.body.temperature}}C, SoC={{$json.body.soc}}%. Provide a brief diagnostic summary (under 40 words) for driver voice alert. State if thermal risk or rapid drain exists."
}
]
}
},
"name": "AI Predictive Diagnostic",
"type": "@n8n/n8n-nodes-langchain.openAi",
"typeVersion": 1,
"position": [500, 400]
},
{
"parameters": {
"chatId": "YOUR_TELEGRAM_CHAT_ID",
"text": "={{$node[\"AI Predictive Diagnostic\"].json.message.content}}",
"additionalFields": {}
},
"name": "Telegram Alert",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1,
"position": [750, 400]
}
],
"connections": {
"Webhook ESP32": {
"main": [
[
{ "node": "Google Sheets Log", "type": "main", "index": 0 },
{ "node": "AI Predictive Diagnostic", "type": "main", "index": 0 }
]
]
},
"AI Predictive Diagnostic": {
"main": [
[
{ "node": "Telegram Alert", "type": "main", "index": 0 }
]
]
}
}
}
7. Telegram Bot & Voice Setup
Step-by-Step Telegram Setup
-
Search
@BotFatheron Telegram. -
Send
/newbot, name your bot (e.g.,EV_BMS_Agent_Bot), and obtain the HTTP API Token. -
Obtain your Chat ID by messaging
@userinfobot. -
In n8n, create a Telegram Credential using the API token.
Voice Generation Pipeline
To generate voice notes:
-
Add an HTTP Request Node after the AI node pointing to OpenAI TTS API (
[https://api.openai.com/v1/audio/speech](https://api.openai.com/v1/audio/speech)). -
Payload:
JSON{ "model": "tts-1", "input": "{{$node['AI Predictive Diagnostic'].json.message.content}}", "voice": "alloy" } -
Set Response Option to File / Binary.
-
In the Telegram Node, set Operation to
sendAudioorsendVoiceand attach the binary data.
8. Google Sheets Integration
-
Create a new Google Sheet named
EV_BMS_Cloud_Database. -
Name the first sheet
Raw_Dataand add headers in Row 1:Timestamp | Voltage (V) | Current (A) | Temp (°C) | Power (W) | SoC (%) -
Link n8n to your Google Account using OAuth2 credentials in n8n.
-
Select
Append Rowoperation and map the body variables to respective columns.
9. ThingSpeak Cloud Dashboard Setup
-
Sign up at
.ThingSpeak -
Create a new Channel named EV_BMS_Dashboard.
-
Define 4 Fields:
-
Field 1: Voltage (V)
-
Field 2: Current (A)
-
Field 3: Temperature (°C)
-
Field 4: State of Charge (%)
-
-
Copy the Write API Key and paste it into the ESP32 source code.
-
Add Visual Widgets (Gauges and Line Charts) for real-time fleet monitoring.
10. AI Power Consumption & Health Logic
The AI Agent evaluates three key algorithms:
-
Remaining Useful Range Prediction:
$$\text{Estimated Range (km)} = \left( \frac{\text{SoC} \times \text{Capacity}_{\text{kWh}}}{100} \right) \times \frac{1000}{\text{Current Avg Consumption (Wh/km)}}$$ -
Thermal Runaway Warning Logic:
$$\Delta T = T_{\text{current}} - T_{\text{previous}}$$If $\Delta T > 2.0^{\circ}\text{C/min}$ while $I > 10\text{A}$, trigger Immediate Isolation & Voice Warning.
-
State of Health (SoH) Estimation:
Comparing actual discharge curves against the ideal lithium chemistry lookup matrix to flag internal resistance deterioration over time.
11. Deployment Guide & Future Enhancements
Assemble circuit on breadboard. Power with bench power supply and verify sensor readings against a multimeter before connecting live battery packs.
Run n8n locally via Docker (docker run -it --rm --name n8n -p 5678:5678 n8nio/n8n) or deploy on a cloud server (AWS / DigitalOcean).
Program ESP32 with updated Wi-Fi credentials and API endpoints. Confirm HTTP 200 responses in Serial Monitor.
Enclose hardware in an IP65 rated junction box, add optocouplers for high-voltage isolation, and add CAN-bus transceiver modules (e.g., MCP2515) for industrial EV integration.
Future Roadmap
-
CAN-Bus Integration: Transition from raw analog sensors to OBD-II / CAN-bus reading directly from commercial EV battery controllers.
-
On-Edge TinyML: Quantize the thermal anomaly model to run directly on the ESP32 using TensorFlow Lite for Microcontrollers, reducing cloud dependency.

