Contents — 26 sections
Project Overview
Charges an EV as fast as the house wiring safely allows — dynamically sharing capacity with the home's other loads — and meters each session for billing, all via the standard charging protocol.
Charging an electric vehicle at home or at a shared charge point raises a problem a normal socket does not: an EV draws a large, sustained current for hours, and if it does so on top of the house's other loads it can overload the wiring or trip the main breaker. The naive fix — a fixed, low charge current — wastes time and capacity. The smart fix, and the heart of this project, is dynamic load management: the controller continuously measures how much of the supply the rest of the building is using and charges the EV with whatever capacity is left, so the car charges as fast as is safe right now, and automatically backs off when the house load rises (the kettle goes on) and speeds up when it falls.
It does this through the standard EV charging protocol. AC EV charging (IEC 61851 / SAE J1772, the "Type 1/Type 2" connectors) uses a control pilot signal — a PWM waveform whose duty cycle tells the car how much current it may draw. So the controller does not switch the car's current directly; it advertises a safe limit via the pilot, and the car obeys it. By varying that pilot duty cycle in response to the measured spare capacity, the controller safely modulates the charge rate in real time, and it follows the protocol's handshake (detecting the vehicle, confirming readiness, energising the contactor) so it interoperates with standard EVs.
On top of safe charging it adds metering and billing: it measures the energy delivered each session (real power/energy) and logs it per user/session, which is what a shared or workplace charge point needs to bill fairly. It reports status and energy to a dashboard, supports authorisation (who may charge), and schedules charging to cheap tariff windows where desired. This is genuinely safety-critical, high-power equipment, so the project is emphatic: EV charging is governed by standards and electrical codes, the power wiring and protection (RCD/RCBO, earthing) must be done by a qualified electrician, and a DIY controller must respect the protocol and safety interlocks — it is an educational build of the control logic, not a certified charger. But as a load-managing, protocol-correct, metered charging controller, it demonstrates exactly how smart EV charging works: fast when it can be, safe always, and accounted for.
What this project does
- Charges an EV via the standard control-pilot protocol (IEC 61851/J1772)
- Dynamically shares supply capacity with the home's other loads
- Advertises a safe current limit to the car via the pilot PWM duty cycle
- Follows the charging handshake (vehicle detect, ready, contactor)
- Meters energy per session for billing
- Supports authorisation and cheap-tariff scheduling
- Respects safety standards and interlocks (educational scope)
Real-World Applications
| Setting | How it is used |
|---|---|
| Home EV charging | Charging as fast as the house wiring safely allows without tripping the main breaker. |
| Shared / apartment charge points | Load-managed charging with per-session metering and billing. |
| Workplace charging | Authorised, metered charging across multiple bays sharing supply capacity. |
| Solar-aware charging | Charging preferentially from spare solar/cheap tariff windows. |
Deployment contexts where a build of this kind earns its keep.
Features & Capabilities
- Dynamic load management (charge with spare capacity)
- Standard control-pilot current signalling
- Protocol-correct handshake and interoperability
- Per-session energy metering for billing
- Authorisation and tariff scheduling
- Backs off/speeds up as house load changes
- Explicit safety-standard framing (not a certified charger)
Difficulty, Time & Required Skills
| Attribute | Value |
|---|---|
| Difficulty level | Advanced |
| Estimated completion time | 14–22 hours |
| Indicative build cost | ₹8,000 – ₹14,000 |
| Primary discipline | Energy |
| Reference platform | ESP32 DevKit V1 (ESP-WROOM-32) |
Skills you should have (or will pick up)
- EV charging protocol (control pilot PWM, handshake)
- Dynamic load management from whole-supply measurement
- Contactor control and safety interlocks
- Per-session energy metering and billing
- Authorisation and scheduling
Bill of Materials
Every part below is commonly available from Indian and international hobby-electronics suppliers. Prices are indicative 2026 retail figures in Indian rupees and will drift — treat them as a budgeting guide, not a quotation.
| Component | Key specification | Qty | Approx. cost |
|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly. | Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC | 1 | ₹450 |
| PZEM-004T v3 AC energy meter (100 A CT) The measurement side sits at mains potential — the opto-isolated UART is the only safe boundary. | 80–260 VAC, 0–100 A, voltage/current/power/energy/PF/frequency, ±0.5 % | 1 | ₹950 |
| ACS712 hall-effect current sensor (20 A) Zero-offset drifts with temperature — re-zero at boot with no load. | ±20 A, 100 mV/A, 80 kHz bandwidth, 1.2 mΩ internal resistance, 2.1 kV isolation | 1 | ₹180 |
| 5 V single-channel opto-isolated relay module Cut the JD-VCC jumper and feed the coil separately for true isolation. | SPDT contacts rated 10 A @ 250 VAC / 10 A @ 30 VDC, opto-isolated input | 1 | ₹90 |
| 0.96″ SSD1306 OLED display Static images burn in — invert or scroll the screen periodically. | 128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C | 1 | ₹250 |
| MFRC522 13.56 MHz RFID reader + card + fob Strictly 3.3 V — 5 V on the SPI pins kills the chip. | ISO/IEC 14443A, MIFARE Classic 1K, 0–60 mm range, up to 10 Mbit/s SPI | 1 | ₹180 |
| 5 V 3 A regulated SMPS adapter Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A. | 100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection | 1 | ₹350 |
| EVSE power stage (contactor + pilot/PP) Safety-critical; must meet the standard and be professionally installed | Contactor rated for the charge current, control-pilot & proximity circuitry per IEC 61851 | 1 | ₹3,000 |
| Whole-supply CT | CT on the incoming supply to measure total house load for dynamic management | 1 | ₹500 |
| Session energy meter | Real-power/energy metering of the charge for billing | 1 | ₹700 |
| RCD/RCBO + earthing (installer) Legally/technically required protection | Required protection for EV charging, installed by a qualified electrician | 1 | ₹2,000 |
Estimated total: ₹8,650, excluding tools, shipping and consumables.
Tools and consumables
- Soldering iron (temperature controlled, 350 °C) with 0.8 mm 60/40 or lead-free solder
- Digital multimeter — continuity, DC volts and current ranges
- Wire strippers, flush cutters and a small set of precision screwdrivers
- Heat-shrink tubing and a heat gun (or a lighter, carefully)
- A laptop with a USB port and the toolchain listed above
Hardware Specifications
| Part | Specification | Supply | Interface | Reference |
|---|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) | Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC | 3.3 V logic / 5 V USB | UART, SPI, I²C, I²S, CAN, PWM | Datasheet |
| PZEM-004T v3 AC energy meter (100 A CT) | 80–260 VAC, 0–100 A, voltage/current/power/energy/PF/frequency, ±0.5 % | 5 V logic side | UART Modbus-RTU 9600 | Datasheet |
| ACS712 hall-effect current sensor (20 A) | ±20 A, 100 mV/A, 80 kHz bandwidth, 1.2 mΩ internal resistance, 2.1 kV isolation | 5 V | Analogue | Datasheet |
| 5 V single-channel opto-isolated relay module | SPDT contacts rated 10 A @ 250 VAC / 10 A @ 30 VDC, opto-isolated input | 5 V coil | Digital (active-low) | Datasheet |
| 0.96″ SSD1306 OLED display | 128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C | 3.3–5 V | I²C (0x3C) | Datasheet |
| MFRC522 13.56 MHz RFID reader + card + fob | ISO/IEC 14443A, MIFARE Classic 1K, 0–60 mm range, up to 10 Mbit/s SPI | 2.5–3.6 V | SPI (also I²C/UART) | Datasheet |
| 5 V 3 A regulated SMPS adapter | 100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection | 5 V | DC barrel / USB | Datasheet |
Consolidated electrical and interface specifications for every active part in the build.
Power Budget & Supply Sizing
Add up the typical active current of every part, then size the supply with at least 50 % headroom so transmit bursts and motor inrush never brown out the controller.
| Load | Supply rail | Typical current (mA) | Notes |
|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) | 3.3 V logic / 5 V USB | 160 | Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly. |
| PZEM-004T v3 AC energy meter (100 A CT) | 5 V logic side | 20 | The measurement side sits at mains potential — the opto-isolated UART is the only safe boundary. |
| ACS712 hall-effect current sensor (20 A) | 5 V | 10 | Zero-offset drifts with temperature — re-zero at boot with no load. |
| 5 V single-channel opto-isolated relay module | 5 V coil | 70 | Cut the JD-VCC jumper and feed the coil separately for true isolation. |
| 0.96″ SSD1306 OLED display | 3.3–5 V | 20 | Static images burn in — invert or scroll the screen periodically. |
| MFRC522 13.56 MHz RFID reader + card + fob | 2.5–3.6 V | 26 | Strictly 3.3 V — 5 V on the SPI pins kills the chip. |
| 5 V 3 A regulated SMPS adapter | 5 V | 3000 | Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A. |
Summed typical draw is 3306 mA. With a 1.5× design margin the supply should deliver at least 5000 mA continuously at the stated rail voltage.
Software Requirements & Development Environment
Reference toolchain: Arduino IDE 2.3.x with the ESP32 board package 3.x (or PlatformIO on VS Code). Anything newer normally works; anything older may lack the board definitions used here.
- Install the Arduino IDE 2.3.x (or PlatformIO if you prefer a real editor and dependency locking).
- Add
https://espressif.github.io/arduino-esp32/package_esp32_index.jsonunder File → Preferences → Additional Board Manager URLs, then install esp32 from the Boards Manager. - Set the correct port under Tools → Port. On Linux add yourself to the
dialoutgroup:sudo usermod -aG dialout $USERand log out and back in. - Open the Serial Monitor at 115200 baud — every sketch here logs its state there.
- Keep File → Preferences → Show verbose output during: compilation switched on while you are debugging build errors.
Required libraries
| Library | Why it is needed | Install |
|---|---|---|
| WiFi (ESP32 core) bundled | Station/AP connection management for the ESP32. | Bundled with the ESP32 Arduino core |
| PubSubClient 2.8 | Lightweight MQTT 3.1.1 client for constrained devices. | Library Manager → "PubSubClient" by Nick O'Leary |
| Adafruit SSD1306 + GFX 2.5.x | Framebuffer and text/graphics primitives for the OLED. | Library Manager → "Adafruit SSD1306" |
| MFRC522 1.4.x | SPI driver and MIFARE authentication for the RC522 reader. | Library Manager → "MFRC522" by GithubCommunity |
| ModbusMaster 2.0.1 | Modbus-RTU master framing for RS-485 meters and drives. | Library Manager → "ModbusMaster" by Doc Walker |
| ArduinoJson 7.x | Zero-allocation JSON serialisation and parsing. | Library Manager → "ArduinoJson" by Benoit Blanchon |
| NTPClient / configTime bundled | Wall-clock time from an NTP server for timestamping. | Bundled (`configTime()` on ESP32) |
Block Diagram
The block diagram shows the functional decomposition of the system — what senses, what decides, what acts, and where the data ends up.
Circuit Diagram & Wiring
Every signal line in the build is shown below, followed by a pin-by-pin connection table you can work through with a multimeter in hand.
| Peripheral | Peripheral pin | Controller pin | Signal |
|---|---|---|---|
| Control pilot | PWM/ADC | GPIO 25 / 34 | CP: advertise limit + read state |
| Proximity (PP) | ADC | GPIO 35 | Cable presence/rating |
| Whole-supply CT | AOUT | GPIO 32 (ADC) | Total house load |
| RFID (authorise) | SPI | GPIO 18/19/23/5 | Who may charge |
| Contactor | IN | GPIO 26 | Energise (after handshake) |
| Session meter | UART | GPIO 16/17 | Energy for billing |
| OLED | SDA/SCL | GPIO 21/22 | Status/current |
| Wi-Fi | on-chip | — | Dashboard/billing |
Wire one row at a time and tick it off — most "it does not work" reports trace back to a single swapped pair.
Wiring explanation
- The power stage (contactor, control-pilot/proximity circuitry, protection) is safety-critical and must meet IEC 61851 and be installed by a qualified electrician with proper RCD/RCBO and earthing.
- The controller advertises a current limit via the control-pilot PWM duty cycle; it never switches the car's current directly — the car regulates to the advertised limit.
- Measure whole-supply current (CT on the incoming supply) so the controller knows the spare capacity for dynamic management.
- Only energise the contactor after the correct handshake (vehicle detected, ready) and interlocks.
- Meter the session energy for billing; add RFID/authorisation for shared use.
System Architecture
Read the stack from the bottom up: physical hardware, the firmware that drives it, the transport that moves data off the device, and the software a human actually looks at.
Working Principle
Home and shared EV charging has one dominant constraint — the supply is shared and finite — and the controller's core intelligence is managing that safely without wasting it. An EV is an unusually large, sustained load (often as much as the rest of the house combined), so charging it at full tilt on top of the household's other loads can exceed the wiring's or the breaker's rating. The unintelligent solutions are bad: charge slowly always (wastes hours of capacity you often have) or charge fast and risk tripping/overloading. Dynamic load management resolves this by making the charge current a live variable: the controller measures the whole-supply load, subtracts it from the safe maximum, and charges the car with the remaining capacity — fast when the house is quiet, backing off automatically the instant a big load switches on, and ramping back up when it switches off. The car always charges as fast as is safe at that moment.
The elegant part is how the controller sets the charge rate, via the control pilot of the standard AC charging protocol (IEC 61851 / SAE J1772). The charging cable carries a control-pilot line on which the charging equipment outputs a PWM signal, and — crucially — the duty cycle of that PWM encodes the maximum current the vehicle is permitted to draw (a defined linear relationship, e.g. a certain duty cycle means "you may draw up to N amps"). So the controller never switches the car's heavy current itself; it simply advertises a limit on the pilot, and the vehicle's onboard charger regulates its draw to stay within it. To modulate charging for load management, the controller just changes the pilot duty cycle — a low-power signalling action — and the car follows. This is what makes safe, smooth, dynamic current control possible.
Around that sits the protocol handshake and safety sequence, which the controller must follow to interoperate and to be safe. The control-pilot voltage also encodes state — no vehicle, vehicle connected, vehicle ready to charge (and ventilation-required states) — so the controller detects a plugged-in car, waits for the "ready" state, checks the proximity/cable rating, and only then energises the contactor to deliver power, de-energising when the car finishes or unplugs. It never applies power out of sequence. This handshake, plus the protection that must accompany EV charging (residual-current protection, proper earthing), is why the power stage is genuinely safety-critical and standards-governed.
On the safe-charging base, the controller adds the features a real charge point needs. Per-session metering — measuring the real energy delivered each charge — is what enables fair billing at shared, apartment or workplace points, logged per user/session. Authorisation (RFID or app) controls who may charge. Scheduling can steer charging into cheap tariff windows or toward surplus solar. And status/energy reporting feeds a dashboard. Throughout, the design is emphatically honest about scope and safety: EV charging is high-power, safety-critical equipment governed by standards and electrical codes; the power wiring, contactor and protection must be specified and installed by a qualified electrician, and a homebrew controller — however correct its logic — is an educational realisation of the control system, not a certified charger, and must respect the protocol and every interlock. Within that frame, it demonstrates exactly what smart EV charging is: use the standard pilot to charge as fast as the shared supply safely allows at every moment, follow the protocol and protection to do it safely, and meter it so it can be paid for.
The maths behind it
Dynamic load management
Charge with the spare capacity of the supply:
I_spare = I_supply_max − I_house
I_charge = clamp(I_spare, I_min_or_0, I_evse_max)
If I_spare < I_min → pause; else advertise I_charge.
Re-evaluate continuously so charging tracks the house load.
Control-pilot current signalling
The pilot PWM duty cycle encodes the allowed current
(IEC 61851 / J1772), e.g. for a common range:
I_allowed (A) ≈ duty(%) × 0.6 (6–51 A region)
→ to allow I amps: duty = I / 0.6 (%)
The car regulates its draw to ≤ I_allowed. The controller
sets duty; it does NOT switch the car current directly.
CP state + session energy
Pilot voltage encodes state:
12V none | 9V connected | 6V ready | (3V vent)
energise contactor only in the ready state.
Session energy for billing:
E_session = ∫ P dt (real power over the session)
Program Flowchart
The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.
Assembly Instructions
Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.
Install the safety-critical power stage (qualified)
Have a qualified electrician install the contactor, control-pilot/proximity circuitry, and the required protection (RCD/RCBO, earthing) per IEC 61851 and local codes. This is not DIY power work.
Set up load measurement and control
Measure whole-supply current for dynamic management, and wire the controller to output the control-pilot PWM and read its state, and to drive the contactor after the handshake.
Add metering, authorisation and reporting
Meter session energy for billing, add RFID/app authorisation, and report status/energy to a dashboard; add scheduling for tariff/solar.
Step-by-Step Implementation Guide
Work through these in order. Each step ends in something you can observe, so a failure is always localised to the step you just finished.
Compute safe current and advertise it
Compute the spare capacity from the whole-supply load, clamp to the EVSE limit, and set the control-pilot duty cycle to advertise it — re-evaluating continuously.
cppload-mgmt.ino#define I_SUPPLY_MAX 32.0f // A — the supply/wiring safe limit #define I_EVSE_MAX 32.0f // A — charger/cable limit #define I_MIN 6.0f // A — minimum EV charge current // Amps the EV may draw = spare capacity, clamped. float safeChargeCurrent(float houseCurrentA){ float spare = I_SUPPLY_MAX - houseCurrentA; if (spare < I_MIN) return 0; // not enough spare -> pause return fminf(spare, I_EVSE_MAX); } // Advertise the current to the car via control-pilot PWM duty. void setPilotCurrent(float amps){ float duty = amps / 0.6f; // IEC 61851 6-51 A region duty = constrain(duty, 10.0f, 90.0f); // valid PWM range setPilotDuty(duty); // car regulates to <= amps }float spare = I_SUPPLY_MAX - houseCurrentAThe spare capacity is the supply limit minus what the house is already drawing — the amount available to charge with, right now.if (spare < I_MIN) return 0;If there is not enough spare for the EV's minimum charge current, charging pauses rather than overloading the supply.float duty = amps / 0.6f;The allowed current is encoded into the control-pilot PWM duty cycle per the standard — the low-power signal the car obeys.setPilotDuty(duty); // car regulates to <= ampsThe controller advertises the limit; the vehicle's onboard charger regulates its draw to stay within it — the controller never switches the heavy current itself.Follow the handshake, meter and bill
Detect the vehicle and ready state via the pilot, energise the contactor only when ready, meter session energy per authorised user, and report — modulating the advertised current continuously with the house load.
Complete Source Code
The listing below is complete and compiles as written — there are no elided sections. Read the annotations under each block before you upload it.
/* ═══════════════════════════════════════════════════════════════
EV Charging Controller — ESP32 (control logic; EDUCATIONAL)
Dynamic load management: charges the EV with the supply's spare
capacity, advertised via the IEC 61851/J1772 control-pilot PWM, with
the protocol handshake, per-session metering and authorisation.
The power stage/protection is safety-critical — professional install.
══════════════════════════════════════════════════════════════════ */
#include <WiFi.h>
#include <PubSubClient.h>
#include <PZEM004Tv30.h>
#define PIN_CP_PWM 25 // control-pilot PWM out
#define PIN_CP_ADC 34 // control-pilot state (voltage)
#define PIN_HOUSE_CT 32 // whole-supply current
#define PIN_CONTACTOR 26
#define I_SUPPLY_MAX 32.0f
#define I_EVSE_MAX 32.0f
#define I_MIN 6.0f
PZEM004Tv30 session(Serial2, 16, 17); // session energy meter
WiFiClient net; PubSubClient mqtt(net);
bool authorised=false, charging=false;
enum CPState { CP_NONE, CP_CONNECTED, CP_READY, CP_UNKNOWN };
CPState readCP(){
int v = analogRead(PIN_CP_ADC); // map to CP voltage
float cp = v/4095.0f*12.0f; // simplified scaling
if (cp > 10) return CP_NONE; // ~12V no vehicle
if (cp > 7) return CP_CONNECTED; // ~9V connected
if (cp > 4) return CP_READY; // ~6V ready to charge
return CP_UNKNOWN;
}
float houseCurrent(){ return analogRead(PIN_HOUSE_CT)/4095.0f * 63.0f; } // A
float safeChargeCurrent(float house){
float spare = I_SUPPLY_MAX - house;
if (spare < I_MIN) return 0;
return fminf(spare, I_EVSE_MAX);
}
void setPilotCurrent(float amps){
float duty = constrain(amps/0.6f, 10.0f, 90.0f);
ledcWrite(0, (int)(duty/100.0f*1023)); // advertise via CP PWM
}
void setup(){
Serial.begin(115200);
pinMode(PIN_CONTACTOR, OUTPUT);
ledcSetup(0, 1000, 10); ledcAttachPin(PIN_CP_PWM, 0); // 1 kHz CP PWM
WiFi.begin(WIFI_SSID,WIFI_PASS); mqtt.setServer(MQTT_HOST,1883);
}
void loop(){
if(!mqtt.connected()&&WiFi.status()==WL_CONNECTED) mqtt.connect("evse-1");
mqtt.loop();
CPState st = readCP();
authorised = checkAuthorisation(); // RFID/app
if (st == CP_READY && authorised){
float amps = safeChargeCurrent(houseCurrent());
setPilotCurrent(amps); // advertise safe current
if (amps >= I_MIN){
if (!charging){ digitalWrite(PIN_CONTACTOR, HIGH); charging=true; } // energise
} else if (charging){
digitalWrite(PIN_CONTACTOR, LOW); charging=false; // pause (no spare)
}
} else { // not ready/authorised
if (charging){ digitalWrite(PIN_CONTACTOR, LOW); charging=false; }
setPilotCurrent(0);
}
float e = session.energy(); // session energy for billing
char m[200];
snprintf(m,sizeof m,
"{\"state\":%d,\"charging\":%s,\"house_A\":%.1f,"
"\"charge_A\":%.1f,\"session_kWh\":%.3f}",
st, charging?"true":"false", houseCurrent(),
safeChargeCurrent(houseCurrent()), e);
mqtt.publish("evse/1/status", m);
delay(1000);
}
Configuration & Calibration
Configuration steps
- Set the supply/wiring and EVSE current limits and the minimum charge current.
- Configure the control-pilot PWM (current encoding) and state thresholds, and the handshake/interlocks.
- Configure whole-supply measurement for load management, session metering, authorisation and tariff scheduling.
- Ensure the power stage/protection is professionally installed per standards.
Calibration procedure
An uncalibrated sensor produces confident, precise, wrong numbers. Do this once per physical unit and record the constants.
Pilot signalling
Verify the control-pilot PWM duty cycle correctly encodes the advertised current per the standard, and that the vehicle regulates to it.
Load management
Calibrate the whole-supply current measurement and confirm the charge current tracks spare capacity as house load changes.
Metering
Verify session energy against a reference for accurate billing.
Network Architecture & Connectivity
Communication protocol
Charge status, current and session energy publish continuously; multiple bays coordinate to share supply capacity (site-wide load management). OCPP integration suits managed charge points.
| Topic / endpoint | Direction | Payload |
|---|---|---|
evse/1/status | node → backend | state, charge/house current, session kWh |
evse/1/session | node → billing | user, energy, duration (billing) |
evse/site/limit | backend → nodes | site capacity allocation |
Message contract between the device and the broker.
Cloud platform configuration
A charge-point management/billing backend records sessions and energy, allocates site capacity across bays, and handles authorisation and billing (OCPP for standard integration).
Dashboard setup
Per-bay charge status and current vs house/site load, session energy/cost, and billing per user.
Mobile app integration
Charge-status and session-complete notifications; cost per session.
Security considerations
- Authenticate authorisation and billing; secure the backend.
- Keep the protocol handshake and safety interlocks robust; the power stage/protection is professionally installed.
- Coordinate multi-bay load management so the site limit is never exceeded.
Testing Procedure & Expected Output
Test from the bottom up. Confirm power, then each sensor in isolation, then the integrated loop — the first failing step tells you exactly where to look.
| Test | What you should see |
|---|---|
| Connect an EV (ready state) | Handshake completes; contactor energises; charging starts |
| Switch on a big house load | Advertised current drops; car ramps down; no overload |
| Switch it off | Advertised current rises; car ramps up |
| House load leaves no spare | Charging pauses; resumes when spare returns |
| Unauthorised user | No charging without authorisation |
| Complete a session | Session energy metered for billing |
Bench-test checklist. If a row fails, stop and fix it before moving on.
Expected output
The dashboard shows charge state, live charge current vs house load, session energy and cost, and billing per user/session.
{
"state": 2,
"charging": true,
"house_A": 14.0,
"charge_A": 18.0,
"session_kWh": 7.42
}
With the house drawing 14 A of a 32 A supply, the EV is advertised 18 A of spare capacity — charging fast but safe; when a big load starts, the advertised current drops automatically to protect the supply.
Troubleshooting: Common Errors & Fixes
Performance Optimisation
- Re-evaluate the safe charge current continuously so it tracks house/site load.
- Use the control pilot to modulate current smoothly; never switch the car current directly.
- Meter session energy accurately for billing.
- Coordinate multiple bays to share site capacity.
- Replace every
delay()with amillis()comparison — blocking delays are the single most common cause of dropped readings. - Sample sensors on a fixed cadence and publish on a slower one; you almost never need to transmit at the sampling rate.
- Move networking into its own FreeRTOS task so a slow DNS lookup cannot stall the control loop.
- Use
uint8_t/uint16_twhere the range allows; on an 8-bit AVR a 32-bit add costs four times as much. - Batch several samples into one MQTT publish. Radio time, not CPU time, dominates the energy budget.
- Set the MQTT keep-alive to a value that matches your reporting interval so the broker does not churn reconnections.
- For battery builds use deep sleep between samples: an ESP32 drops from ~160 mA awake to about 10 µA asleep, which is the difference between days and months of runtime.
Safety Precautions
- EV charging is high-power, safety-critical and standards-governed — the power stage, contactor and protection (RCD/RCBO, earthing) must be professionally installed per IEC 61851 and local codes.
- This is an educational build of the control logic, NOT a certified charger; respect the protocol and every interlock.
- Only energise in the correct handshake state; never apply power out of sequence.
- Dynamic load management protects the wiring — verify the supply limit and measurement.
- Mains voltage kills. Anything on the load side of the relay is at 230 V. Do not work on a powered circuit, and never leave exposed mains wiring on a bench where someone could touch it.
- Keep at least 6 mm of creepage between the mains and low-voltage sides of any board you make, and never route mains tracks under the microcontroller.
- Have a qualified electrician do the final installation into a consumer unit or wall fitting. In most jurisdictions this is a legal requirement, not a suggestion.
- Fit an RCD/RCBO upstream and fuse the load appropriately for its rating.
- Wear eye protection when soldering or cutting, and solder in a ventilated space — rosin flux fumes are a respiratory irritant.
- Power the circuit through a bench supply with a current limit while you are testing. A 300 mA limit turns a wiring mistake into a beep instead of a dead board.
- Disconnect power before changing any wiring. Hot-plugging a sensor onto a live bus is the fastest way to lose a controller.
Maintenance
- Verify pilot signalling, handshake and interlocks periodically.
- Check the load-management measurement and session-meter calibration.
- Inspect the power stage/protection (professionally).
- Update authorisation/billing and site-capacity allocation as needed.
- Re-check every screw terminal and header after the first week — thermal cycling loosens connections that felt tight on day one.
- Keep the broker and dashboard containers patched, and rotate device credentials at least once a year.
- Recalibrate at the interval given in the calibration section, and keep the constants in a text file next to the firmware — not only in flash.
- Keep a short logbook of firmware versions and what changed. Six months later you will not remember why that constant is 1.083.
Future Improvements & Upgrades
A working v1 is a platform, not a finish line. These are the upgrades that add the most capability for the least rework.
- Add OCPP for standard charge-point management integration.
- Add solar-surplus charging (charge from export).
- Add three-phase and vehicle-to-grid where supported.
- Add site-wide multi-bay dynamic load balancing.
- Design a proper PCB. Once the breadboard version has run for a month, moving to a two-layer board removes the intermittent-contact failures that dominate prototype faults.
- Add over-the-air firmware updates so you never have to physically reach a deployed node again.
- Add persistent local storage (microSD or the on-chip flash) so a network outage does not create a hole in your data.
- Move configuration out of the source: a captive-portal setup page or a JSON config file makes the build reusable without a recompile.
- Add a battery and solar option so the unit survives a power cut and can be sited away from a socket.
- Write a small test harness that feeds synthetic sensor values through the decision logic, so you can validate thresholds without physically triggering the event.
Frequently Asked Questions
References & Learning Resources
These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.