Monday, 19 October 2026

AI Wireless EV Charging Optimization System

AI-Powered Wireless EV Charging Optimization System

Complete project documentation: ESP32 + IoT Dashboard + AI Agent + n8n + Telegram Voice Alerts + Google Sheets + ThingSpeak

Frontiers | Design and experimental analysis for a high-power wireless charging system design for electric vehicles
 
 
ESP32 IOT Dashboard. | ESP32
 
 
MRS E-Mobility - Grow your business with Mcharger
 
 

This project combines wireless electric vehicle (EV) charging, ESP32-based monitoring, AI-assisted optimization, and automated cloud notifications into one integrated IoT system. The goal is to monitor charging performance, estimate energy consumption, detect abnormal operating conditions, optimize charging decisions, and notify the user through Telegram voice alerts.

The system uses:

  • ESP32 for sensor acquisition, wireless connectivity, and local safety control.

  • Wireless power transfer (WPT) for contactless energy transfer between transmitter and receiver coils.

  • AI agent for interpreting telemetry, identifying trends, and recommending charging adjustments.

  • n8n for workflow automation and connecting cloud services.

  • Telegram for text and generated voice notifications.

  • Google Sheets for storing historical charging data and reports.

  • ThingSpeak for IoT telemetry visualization.

  • Web dashboard for real-time monitoring, status indicators, and charging analytics.

Important engineering distinction: the ESP32, dashboard, and automation can be developed at low voltage first. Actual EV charging involves potentially hazardous power electronics, electromagnetic fields, heat, and battery-management requirements. The prototype described below is intended for a low-voltage demonstration; it is not a certified EV charging station.

1. Project abstract

The AI Wireless EV Charging Optimization System is an intelligent IoT prototype designed to demonstrate how wireless charging equipment can be monitored and optimized using embedded electronics, cloud analytics, and AI-driven automation.

A wireless charging transmitter creates a high-frequency magnetic field. A receiver coil captures part of that energy and converts it into electrical power for a suitable load or battery-charging subsystem. The ESP32 monitors electrical and thermal measurements and sends telemetry to the cloud.

The AI agent evaluates the collected data and classifies operating conditions such as:

  • Normal charging.

  • Low transfer efficiency.

  • Increasing coil temperature.

  • Abnormal voltage or current.

  • Possible receiver misalignment.

  • Charging session completed.

  • Sensor or network communication failure.

When an abnormal condition is detected, n8n can log the event, request an AI-generated explanation, append the measurements to Google Sheets, update a dashboard, and send a Telegram message or voice notification.

The system is designed around a critical rule: AI can recommend operating changes, but independent hardware protection must control electrical safety. Do not allow an AI model or cloud workflow to directly override overtemperature protection, battery limits, or hardware interlocks.

Project objectives

  1. Measure transmitter/receiver voltage and current, temperature, and estimated charging power.

  2. Calculate wireless charging efficiency using input and output measurements.

  3. Publish telemetry to ThingSpeak.

  4. Display current conditions on a web dashboard.

  5. Use an AI agent to interpret sensor data and suggest optimization actions.

  6. Automate event handling with n8n.

  7. Record measurements and alerts in Google Sheets.

  8. Deliver Telegram text and voice alerts.

  9. Maintain a safe local operating state when Wi-Fi or cloud services are unavailable.

  10. Provide a scalable architecture for future EV charging research.

2. System architecture

Wireless charging hardware

Transmitter coil · Receiver coil · Power conversion · Protected low-voltage load

Voltage · Current · Temperature · Alignment indicators

ESP32 monitoring controller

Sensor sampling · Local safety checks · Power calculations · Wi-Fi

HTTPS / REST API

ThingSpeak

Telemetry charts and history

n8n

Rules, automation and routing

 

AI agent

Analysis

Sheets

Records

Telegram

Voice and text

Web-based IoT dashboard

Live status · Measurements · Efficiency · Trends · Event history

How the components communicate

Component

Main responsibility

Communication

ESP32

Acquire sensor data and apply local limits

Wi-Fi, HTTP/HTTPS

WPT subsystem

Transfer power without a cable

Magnetic induction

ThingSpeak

Store and visualize time-series telemetry

REST API

n8n

Route events and execute workflows

Webhooks and integrations

AI agent

Explain trends and suggest adjustments

Structured prompts and model API

Google Sheets

Maintain an accessible project log

Google Sheets integration

Telegram

Deliver event and voice notifications

Telegram Bot API

Web dashboard

Present current system state

ESP32 HTTP server or cloud endpoint

ESP32 Wi-Fi capabilities are documented in the official Espressif Arduino-ESP32 Wi-Fi documentation . ThingSpeak provides channel-based telemetry storage and update APIs; see the ThingSpeak Write Data documentation .

— Arduino ESP32 latest documentation
+1

3. Hardware components required

The following is a practical bill of materials for a student or engineering-lab prototype. The exact ratings depend on your wireless power module and sensors.

GitHub - TronixLab/DOIT_ESP32_DevKit-v1_30P · GitHub
 
 

1. ESP32 development board

Quantity: 1

The main controller. It reads sensors, calculates power, checks temperature and sends telemetry over Wi-Fi.

 
5V 1A Inductive Wireless Charging Transmitter & Receiver Kit - Thingbits India
 
 

2. Wireless power transfer kit

Quantity: 1 matched transmitter/receiver pair

Use a commercially designed, current-limited low-voltage inductive power demonstrator. Choose a kit with specified input/output ratings and thermal protection.

 
Adafruit INA219 High Side DC Spannungs Sensor Breakout, 26V ±3.2A Max
 
 

3. INA219 voltage/current sensor

Quantity: 1–2, depending on measurement points

Measures DC bus voltage and current. Use it on compatible low-voltage DC input/output circuits. It is not suitable for directly measuring high-frequency coil current or AC power.

 
2pcs DS18B20 Temperature Sensor Module Kit with Waterproof Stainless S– AusPower Australia
 
 

4. Temperature sensor

Quantity: 1–3

Monitor coil surface, power electronics, or receiver temperature. A DS18B20 is convenient for a basic low-voltage demonstration.

 
Display the RGB Values on Blynk Application using RGB
 – REES52
 
 

5. Prototyping and power accessories

Breadboard or terminal blocks for signal wiring, suitable resistors, pull-up resistor for DS18B20, USB cable, current-limited supply, fuses, and insulated wiring.

Optional components include an alignment sensor, a display, an isolated measurement interface, a relay or enable input specifically supported by the wireless charging module, and a separate hardware temperature cutoff.

Important sensor selection notes

  • An INA219 is designed for DC voltage/current measurement, not direct measurement of the high-frequency AC waveform at a resonant coil.

  • For accurate wireless charging efficiency, measure input and output power at defined DC boundaries or use suitable isolated instrumentation and power analyzers.

  • For real battery charging, use a purpose-designed charger and battery-management system. The ESP32 is not a substitute for a battery-management system.

  • Do not connect a coil, a battery pack, mains voltage, or an inverter output directly to an ESP32 GPIO or ADC.

4. Circuit and schematic diagram

The following is the recommended low-voltage monitoring topology. It intentionally keeps the wireless power stage separate from the ESP32 signal circuits.

Advancing Urban Microclimate Monitoring: The Development of an Environmental Data Measurement Station Using a Low-Tech Approach
 
 
text

              LOW-VOLTAGE WPT DEMONSTRATION

   Current-limited DC supply
             |
          [FUSE]
             |
   [WPT Transmitter Module]  ))))) magnetic field (((((
             |                                      |
      Input DC measurement                  [Receiver Coil]
        [INA219 #1]                                |
                                                   v
                                         [Rectifier / Regulator]
                                                   |
                                           [INA219 #2]
                                                   |
                                         [Protected DC Load]
                                                   |
                                              Return/GND


  SENSOR AND ESP32 SIGNAL WIRING

  ESP32 3V3  ---------------- INA219 VCC
  ESP32 GND  ---------------- INA219 GND
  ESP32 GPIO21 -------------- INA219 SDA
  ESP32 GPIO22 -------------- INA219 SCL

  ESP32 GPIO4  -------------- DS18B20 DATA
                                  |
                                4.7 kΩ
                                  |
                                 3V3

  DS18B20 VDD --------------- 3V3
  DS18B20 GND --------------- GND

  ESP32  <---- Wi-Fi / HTTPS ---->  n8n / ThingSpeak
                                      |
                              Google Sheets / AI
                                      |
                                   Telegram

This is a functional-block schematic, not a high-frequency power-stage construction drawing. Follow the manufacturer's wiring diagram for the specific WPT kit. Do not assume that the transmitter and receiver share a common ground. Connect grounds only where the module's documentation permits it.

ESP32 signal pin assignment

Signal

ESP32 pin

Notes

I²C SDA

GPIO 21

INA219 data

I²C SCL

GPIO 22

INA219 clock

DS18B20 data

GPIO 4

Use a 4.7 kΩ pull-up to 3.3 V

WPT enable

Optional, GPIO 25

Only if the module supports a compatible logic-level enable input

Local status LED

Optional, GPIO 2

Board-dependent; use an appropriate resistor

The I²C pins are common defaults for classic ESP32 DevKit boards, but verify the pinout of your particular board. The optional enable signal must not be treated as a safety-rated disconnect.

5. Working principle: step by step

  1. Power transfer begins

    The low-voltage DC supply powers the approved transmitter module. The transmitter coil produces a changing magnetic field, which induces voltage in the receiver coil when the coils are appropriately aligned.

  2. Electrical power is measured

    The input sensor measures transmitter supply voltage and current. A second sensor measures the receiver's regulated DC output and load current.

  3. Temperature and alignment are monitored

    The ESP32 reads temperature sensors and, optionally, an alignment or distance sensor. Temperature, voltage, current and alignment measurements help identify poor operating conditions.

  4. Power and efficiency are calculated

    The ESP32 calculates input power, output power, estimated efficiency, and energy delivered over time.

  5. Data is transmitted

    The ESP32 sends telemetry to ThingSpeak and posts a JSON record to an authenticated n8n webhook.

  6. Automation and AI analysis run

    n8n validates the measurements, evaluates fixed safety-alert rules, sends eligible telemetry to an AI agent, and chooses appropriate logging and notification actions.

  7. Data is recorded

    Google Sheets stores the timestamp, power readings, temperature, efficiency, system state, and any alert generated.

  8. Alerts and dashboard are updated

    The web dashboard and ThingSpeak charts show the measurements. Telegram sends a text alert and, if configured, a generated voice message.

6. Mathematical model and optimization logic

The project becomes more meaningful when it measures performance quantitatively rather than merely reporting sensor values.

6.1 Input and output power

For a DC input supply:

Pin=Vin×IinPin=Vin×Iin

For the receiver's regulated DC output:

Pout=Vout×IoutPout=Vout×Iout

Where voltage is measured in volts, current in amperes, and power in watts.

6.2 Wireless transfer efficiency

η=PoutPin×100%η=PinPout×100%

Example: if the input power is 20 W and the measured output power is 14 W:

η=1420×100=70%η=2014×100=70%

The remaining 30% represents losses within the selected measurement boundaries, including conversion losses and heat. This calculation is valid only when input and output measurements refer to the same operating interval and their measurement uncertainties are understood.

6.3 Energy delivered

For measurements taken at regular intervals:

EWh≈∑k=1nPout,kΔtk3600EWh≈k=1∑nPout,k3600Δtk

Here, ΔtkΔtk is the interval in seconds. For irregular sample intervals, use the actual elapsed time rather than assuming a constant interval.

6.4 Optimization strategy

The first version should use deterministic rules, followed by AI-assisted diagnosis.

Condition

Detection

Recommended response

Normal operation

Values within configured limits

Continue monitoring

Low efficiency

Efficiency below the configured target

Check coil alignment, spacing and temperature

Overtemperature

Temperature reaches the selected module's limit

Stop or inhibit power using independent protection

High input current

Current exceeds the approved operating limit

Hardware current protection and fault handling

Low output power

Output falls while input remains stable

Check alignment, receiver load and sensor readings

Sensor failure

Invalid or stale measurement

Mark telemetry invalid; enter the defined safe state

Wi-Fi/cloud failure

Network request times out

Continue local safety monitoring and buffer data if possible

Do not use a universal temperature or current threshold for every wireless power module. Set the limits from the hardware manufacturer's specifications and the characteristics of the load.

6.5 AI optimization objective

A research version could seek to maximize delivered power and efficiency while respecting temperature, current, and alignment constraints:

max⁡uJ=w1η+w2Pout−w3TumaxJ=w1η+w2Pout−w3T

Subject to:

T<Tmax⁡,I<Imax⁡,u∈UapprovedT<Tmax,I<Imax,u∈Uapproved

Here, uu represents approved adjustments, such as selecting a permitted charging mode or requesting a repositioning check. The weights w1,w2,w3w1,w2,w3 depend on the research objective.

For the initial prototype, the AI agent should recommend actions rather than directly adjust the power stage. An authorized controller can later implement validated optimization logic with hard limits and independent protection.

7. Software and cloud setup

Step 1 — Install the development environment

Install the Arduino IDE and configure ESP32 board support using the official Arduino-ESP32 documentation .

Install these Arduino libraries through Library Manager:

  • Adafruit INA219

  • OneWire

  • DallasTemperature

The firmware below uses the ESP32's built-in WiFi, HTTPClient, Wire, and WebServer libraries.

Step 2 — Create a ThingSpeak channel

Open ThingSpeak  and create a channel named AI Wireless EV Charging.

Configure these numeric fields:

Field

Name

Unit

Field 1

Input Voltage

V

Field 2

Input Current

A

Field 3

Input Power

W

Field 4

Output Voltage

V

Field 5

Output Current

A

Field 6

Output Power

W

Field 7

Efficiency

%

Field 8

Temperature

°C

Save the Channel ID and Write API Key. Use the Write API Key only for publishing data. Keep the channel private if its telemetry should not be publicly visible.

ThingSpeak's API accepts updates through HTTP GET or POST. Free-license update intervals are subject to the platform's rate limits, so the sample firmware publishes at intervals longer than 15 seconds. Check the current rules for your account.

MATLAB
+2

Step 3 — Create a Google Sheet

Create a spreadsheet named Wireless EV Charging Logs with a worksheet named Telemetry.

Use these column headers:

text
timestamp,device_id,input_voltage,input_current,input_power,
output_voltage,output_current,output_power,efficiency,
temperature_c,state,alert,ai_recommendation

The firmware sends measurements to n8n, and n8n appends the record to this sheet. This avoids exposing Google account credentials in the microcontroller firmware.

Step 4 — Set up n8n

Use n8n Cloud  or a properly secured self-hosted instance.

Create credentials for Google Sheets, Telegram, and your chosen AI model provider. Use the official n8n Webhook documentation  to create an endpoint that accepts POST requests. Configure authentication before using the production URL.

GitHub
+1

Step 5 — Create a Telegram bot

  1. Open Telegram and find the official @BotFather account.

  2. Create a bot and save the bot token securely.

  3. Open the bot and send it a message.

  4. Determine the authorized destination chat ID.

  5. Configure the Telegram credentials in n8n.

  6. Test a normal text notification before enabling voice notifications.

Do not publish the bot token, webhook secret, API keys, or private dashboard credentials in source code repositories.

8. Complete ESP32 firmware

This example is a starting point for a low-voltage bench prototype. It reads two INA219 sensors and a DS18B20 temperature sensor, calculates power and efficiency, publishes data to ThingSpeak, posts JSON to n8n, and exposes a small local webpage.

Before uploading: install the libraries listed above, enter your Wi-Fi credentials and API keys, and verify the wiring. The sketch assumes two INA219 sensors at I²C addresses 0x40 and 0x41. If both sensors use the same address and cannot be reconfigured, use an I²C multiplexer or another compatible sensor arrangement.

For a production deployment, replace the simplified TLS configuration with proper certificate validation, authenticate the webhook, and implement measurement validation and offline buffering.

cpp

/*
  AI Wireless EV Charging Monitor
  Platform: ESP32 DevKit
  Sensors: 2 x INA219, 1 x DS18B20
  Cloud: ThingSpeak + n8n
  Dashboard: ESP32 local web server

  LOW-VOLTAGE MONITORING PROTOTYPE ONLY.
  No direct control of an EV power stage.
*/

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <WebServer.h>
#include <Wire.h>
#include <Adafruit_INA219.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// ---------- USER CONFIGURATION ----------
const char* WIFI_SSID = "YOUR_WIFI_NAME";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";

const char* THINGSPEAK_KEY = "YOUR_THINGSPEAK_WRITE_KEY";

// Use the authenticated production URL from your n8n Webhook node.
const char* N8N_URL =
  "https://YOUR_N8N_HOST/webhook/ev-telemetry";

// Replace with a real secret configured and checked by n8n.
// Use a randomly generated value in your own deployment.
const char* WEBHOOK_SECRET = "REPLACE_WITH_LONG_RANDOM_SECRET";

const char* DEVICE_ID = "EV-WPT-ESP32-01";

// DS18B20 data pin
const int TEMP_PIN = 4;

// Example limit for a bench prototype only.
// Set from the actual sensor and module specifications.
const float TEMP_LIMIT_C = 50.0f;

// ThingSpeak free-tier-compatible sample interval
const unsigned long SAMPLE_MS = 20000;

// ---------- SENSOR OBJECTS ----------
Adafruit_INA219 inputSensor(0x40);
Adafruit_INA219 outputSensor(0x41);

OneWire oneWire(TEMP_PIN);
DallasTemperature tempSensor(&oneWire);

WebServer server(80);

unsigned long lastSample = 0;

struct Telemetry {
  float vin, iin, pin;
  float vout, iout, pout;
  float efficiency, temperature;
  bool valid;
  String state;
};

Telemetry data;

// ---------- HELPERS ----------
String jsonNumber(float value, int digits = 2) {
  if (!isfinite(value)) return "null";
  return String(value, digits);
}

String currentJson() {
  String j = "{";
  j += "\"device_id\":\"" + String(DEVICE_ID) + "\",";
  j += "\"input_voltage\":" + jsonNumber(data.vin) + ",";
  j += "\"input_current\":" + jsonNumber(data.iin) + ",";
  j += "\"input_power\":" + jsonNumber(data.pin) + ",";
  j += "\"output_voltage\":" + jsonNumber(data.vout) + ",";
  j += "\"output_current\":" + jsonNumber(data.iout) + ",";
  j += "\"output_power\":" + jsonNumber(data.pout) + ",";
  j += "\"efficiency\":" + jsonNumber(data.efficiency) + ",";
  j += "\"temperature_c\":" + jsonNumber(data.temperature) + ",";
  j += "\"valid\":" + String(data.valid ? "true" : "false") + ",";
  j += "\"state\":\"" + data.state + "\"";
  j += "}";
  return j;
}

void sampleSensors() {
  // Read regulated DC measurements only.
  float vin = inputSensor.getBusVoltage_V();
  float iin = inputSensor.getCurrent_mA() / 1000.0f;

  float vout = outputSensor.getBusVoltage_V();
  float iout = outputSensor.getCurrent_mA() / 1000.0f;

  tempSensor.requestTemperatures();
  float temp = tempSensor.getTempCByIndex(0);

  bool valid = isfinite(vin) && isfinite(iin) &&
               isfinite(vout) && isfinite(iout) &&
               temp != DEVICE_DISCONNECTED_C &&
               temp > -55.0f && temp <= 125.0f &&
               vin >= 0.0f && vout >= 0.0f &&
               iin >= 0.0f && iout >= 0.0f;

  data.vin = vin;
  data.iin = iin;
  data.pin = vin * iin;

  data.vout = vout;
  data.iout = iout;
  data.pout = vout * iout;

  data.temperature = temp;
  data.valid = valid;
  data.efficiency =
      (valid && data.pin > 0.1f)
      ? 100.0f * data.pout / data.pin
      : 0.0f;

  // Monitoring status only. This is not a safety-rated interlock.
  if (!valid) {
    data.state = "SENSOR_FAULT";
  } else if (temp >= TEMP_LIMIT_C) {
    data.state = "OVER_TEMPERATURE";
  } else if (data.pout > data.pin * 1.05f) {
    data.state = "CHECK_SENSOR_CALIBRATION";
  } else {
    data.state = "MONITORING";
  }

  Serial.println(currentJson());
}

bool postJson(const char* url, const String& body,
              bool includeSecret) {
  if (WiFi.status() != WL_CONNECTED) return false;

  WiFiClientSecure client;

  // DEVELOPMENT PLACEHOLDER ONLY:
  // setInsecure() disables certificate verification.
  // Replace it with CA certificate validation in production.
  client.setInsecure();

  HTTPClient http;
  if (!http.begin(client, url)) return false;

  http.setTimeout(5000);
  http.addHeader("Content-Type", "application/json");

  if (includeSecret) {
    http.addHeader("X-Webhook-Secret", WEBHOOK_SECRET);
  }

  int code = http.POST(body);
  String response = http.getString();

  Serial.printf("POST status: %d\n", code);
  if (code < 200 || code >= 300) {
    Serial.println(response);
  }

  http.end();
  return code >= 200 && code < 300;
}

bool publishThingSpeak() {
  if (!data.valid || WiFi.status() != WL_CONNECTED) {
    return false;
  }

  String body = "api_key=" + String(THINGSPEAK_KEY);
  body += "&field1=" + String(data.vin, 2);
  body += "&field2=" + String(data.iin, 3);
  body += "&field3=" + String(data.pin, 2);
  body += "&field4=" + String(data.vout, 2);
  body += "&field5=" + String(data.iout, 3);
  body += "&field6=" + String(data.pout, 2);
  body += "&field7=" + String(data.efficiency, 2);
  body += "&field8=" + String(data.temperature, 2);

  WiFiClientSecure client;
  // Development only; validate server certificates in production.
  client.setInsecure();

  HTTPClient http;
  if (!http.begin(client, "https://api.thingspeak.com/update")) {
    return false;
  }

  http.setTimeout(5000);
  http.addHeader("Content-Type",
                 "application/x-www-form-urlencoded");

  int code = http.POST(body);
  String response = http.getString();
  http.end();

  // A successful HTTP response may still contain entry ID 0
  // when ThingSpeak rejects an update.
  response.trim();
  bool ok = code == 200 && response.length() > 0 &&
            response != "0";

  Serial.printf("ThingSpeak HTTP=%d response=%s\n",
                code, response.c_str());
  return ok;
}

bool publishN8n() {
  String body = currentJson();
  return postJson(N8N_URL, body, true);
}

// ---------- LOCAL WEB DASHBOARD ----------
void handleRoot() {
  String page = R"HTML(
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Wireless EV Charging Monitor</title>
<style>
body{font-family:Arial;background:#101827;color:#f5f7fa;
margin:20px;max-width:800px}
.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}
.card{background:#202c3c;padding:16px;border-radius:12px}
.value{font-size:24px;font-weight:bold}
small{color:#bdc8d8}
</style>
</head>
<body>
<h2>AI Wireless EV Charging</h2>
<p>ESP32 local monitoring dashboard</p>
<div class="grid" id="grid"></div>
<p id="state">Connecting...</p>
<script>
async function update(){
 try{
  const r=await fetch('/api/status');
  const d=await r.json();
  const items=[
   ['Input Voltage',d.input_voltage,'V'],
   ['Input Current',d.input_current,'A'],
   ['Input Power',d.input_power,'W'],
   ['Output Voltage',d.output_voltage,'V'],
   ['Output Current',d.output_current,'A'],
   ['Output Power',d.output_power,'W'],
   ['Efficiency',d.efficiency,'%'],
   ['Temperature',d.temperature_c,'°C']
  ];
  document.getElementById('grid').innerHTML=items.map(x=>
   '<div class="card"><small>'+x[0]+'</small><div class="value">'+
   (x[1]===null?'--':Number(x[1]).toFixed(2))+' '+x[2]+
   '</div></div>').join('');
  document.getElementById('state').textContent=
   'State: '+d.state+' | Valid: '+d.valid;
 }catch(e){
  document.getElementById('state').textContent='Dashboard connection lost';
 }
}
update();
setInterval(update,3000);
</script>
</body>
</html>
)HTML";

  server.send(200, "text/html", page);
}

void handleStatus() {
  server.sendHeader("Cache-Control", "no-store");
  server.send(200, "application/json", currentJson());
}

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);

  tempSensor.begin();

  bool inOK = inputSensor.begin();
  bool outOK = outputSensor.begin();

  data.valid = false;
  data.state = (!inOK || !outOK)
               ? "SENSOR_INIT_FAULT"
               : "STARTING";

  if (!inOK || !outOK) {
    Serial.println("INA219 initialization failed. Check wiring.");
  }

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);

  Serial.print("Connecting to Wi-Fi");
  unsigned long start = millis();

  while (WiFi.status() != WL_CONNECTED &&
         millis() - start < 15000) {
    delay(300);
    Serial.print(".");
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println();
    Serial.print("Dashboard: http://");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("\nWi-Fi unavailable; local sampling continues.");
  }

  server.on("/", HTTP_GET, handleRoot);
  server.on("/api/status", HTTP_GET, handleStatus);
  server.begin();

  lastSample = millis() - SAMPLE_MS;
}

void loop() {
  server.handleClient();

  if (millis() - lastSample >= SAMPLE_MS) {
    lastSample = millis();

    sampleSensors();

    if (WiFi.status() == WL_CONNECTED) {
      publishThingSpeak();
      publishN8n();
    }
  }

  // No blocking safety loop is implemented here.
  // Add an independent hardware protection system for the
  // real power stage; this firmware is a monitor prototype.
}

How to run the firmware

  1. Replace the configuration placeholders.

  2. Upload the sketch using the ESP32 board and correct COM/serial port.

  3. Open Serial Monitor at 115200 baud.

  4. Check that both INA219 sensors initialize successfully.

  5. Open the IP address printed in Serial Monitor on a device connected to the same Wi-Fi network.

  6. Verify that the local dashboard displays voltage, current, power, efficiency and temperature.

  7. Confirm that ThingSpeak receives the measurements.

  8. Activate the n8n workflow and confirm that it receives the JSON data.

Firmware limitations to address before deployment

  • The sketch's status field reports monitoring conditions; it does not physically stop charging.

  • Sensor initialization errors need to be included in ongoing fault validation, not only startup messages.

  • The simple efficiency calculation can produce misleading results if sensor calibration, offsets, sampling intervals, or measurement boundaries are incorrect.

  • The local HTTP dashboard is not authenticated. Do not expose it directly to the public internet.

  • The TLS code is intentionally simplified for demonstration. Certificate validation must be enabled before use outside a trusted test environment.

  • The sample has no durable offline queue. Add a bounded buffer or local storage and a retry policy if data must survive network outages.

  • A real charging system requires independent hardware protection and a properly designed power controller.

9. n8n automation workflow design

Create the following workflow in n8n. It receives each telemetry record, checks whether an alert is needed, logs the measurements, uses AI to explain the condition, and sends notifications.