Figure 1: A complete DIY EVSE (Electric Vehicle Supply Equipment) node that dynamically diverts surplus PV energy into your car, monitored live through Home Assistant.
⚠️ LETHAL VOLTAGE, HIGH CURRENT — READ THIS FIRST
- This Is Not a Plug Adapter: A real EV charger (EVSE) is not a "socket on a stick". It must implement the IEC 61851 / SAE J1772 control pilot protocol, detect ground faults, verify the protective earth, and modulate current via PWM. A simple relay + socket will not talk to the car and may damage its onboard charger.
- Currents That Kill: A 7 kW single-phase charger draws 32 A continuous for hours. A 22 kW three-phase unit draws 32 A per phase. Undersized wiring, loose terminals or the wrong breaker will start a fire inside your walls.
- RCD Type A or B Is Mandatory: The car's onboard charger contains a rectifier that can inject smooth DC into your installation. A standard AC RCD (Type AC) will blind itself and fail to trip on a real earth fault. You need a Type A RCD minimum, or a Type B if your EV manufacturer requires it (check the manual).
- Legal & Insurance: In most countries, a DIY EVSE used on a public road or connected to the grid must comply with local electrical codes (NEC Article 625 in the US, IEC 61851 in Europe, AS/NZS 3000 in Australia). An uninspected installation can void your home insurance and expose you to criminal liability. This guide is educational — have your final installation inspected by a licensed electrician.
- Never Work Live: Lockout/tagout the breaker, verify absence of voltage with a CAT III meter, and discharge any filter capacitors before touching anything.
Welcome back to TechFix Hub. You've built the solar array, the MPPT controller, the LiFePO4 battery pack with active balancing, and the whole-house energy monitor. Your roof is producing kilowatts your home can't use, your battery is full by 11 AM, and the grid is buying your surplus for pennies. Meanwhile, your electric car sits in the garage, waiting to be charged at 7 PM — when electricity is most expensive and least green.
The fix is a smart solar EV charger — a wallbox that talks to your car using the proper IEC 61851 protocol, reads your real-time PV surplus through a PZEM-004T or your utility meter, and dynamically adjusts the charging current between 6 A and 32 A every second. The result: your car charges on sunshine, for free, without ever importing from the grid or overloading your installation.
In this guide we'll build exactly that: an ESP32-controlled EVSE with proper safety interlocks, solar PV diversion logic, MQTT integration with Home Assistant, and optional OCPP support. If you've been searching for DIY EV charger, solar EVSE ESP32, PV charge diversion or OCPP home charger, this is the build.
🔌 1. Why a Real EVSE Is Not Just a Socket on a Relay
Many "DIY charger" tutorials online are just a contactor switched by an ESP32, feeding a domestic socket. That is a granny charger at best, and a fire hazard at worst. Here's what a real EVSE must do that a dumb socket cannot:
The Control Pilot (CP) wire is the brain of the whole system. It carries a +12 V / −12 V square wave at 1 kHz, and the duty cycle of that square wave is what tells the car "you may draw up to X amps". Change the duty cycle, and the car changes its draw within one second. That is the lever the ESP32 will pull to implement solar diversion.
🛠️ 2. Bill of Materials for a 7 kW Single-Phase Solar EVSE
This BOM is for a Type 2 / J1772, 32 A, single-phase 230 V charger — the most common home configuration. Scale up to three phases by tripling the contactor rating and RCD.
Total estimated cost: ~$260–420 for a fully compliant 7 kW solar EVSE — roughly one-third the price of a branded unit with the same features, and infinitely more hackable.
☀️ 3. The Brain: Solar Diversion Algorithm
The entire point of this build is to charge the car only from surplus PV, never importing from the grid. Here is the control loop the ESP32 runs every second:
- Read grid power from the PZEM-004T (or your utility meter). Positive = importing, negative = exporting.
- Compute available surplus:
surplus = -grid_power - house_baseline, wherehouse_baselineis a configurable buffer (e.g., 200 W to keep the fridge running). - Convert to amps:
target_I = surplus / 230. - Clamp to legal EVSE range: IEC 61851 requires the charger to offer between 6 A and 32 A in 1 A steps. Below 6 A the car will refuse to start; above 32 A you need three phases.
- Apply hysteresis: Don't change the setpoint unless the new value differs by ≥1 A for 5 consecutive seconds. This prevents contactor chatter when a cloud passes.
- Update the PWM duty cycle on the Control Pilot. The car adjusts its draw within one AC cycle.
- If surplus drops below 6 A for more than 60 s, transition the state machine from C (charging) back to B (connected, not charging) and open the contactor cleanly.
💡 Pro tip: Add a "minimum charge" mode that guarantees at least 6 A whenever the car is plugged in, even if it means briefly importing from the grid. Most EV owners prefer a guaranteed 30 km of range overnight over a pure solar-only policy.
⚡ 4. Wiring: The Safety-Critical Parts
The power path is straightforward. The control path is where mistakes become dangerous.
Grid ──► MCB (40A B/C) ──► RCD (Type A, 30mA) ──► Contactor ──► Type 2 Socket
│ │
│ ├── L1 → Pin 1 (car)
│ ├── N → Pin 3 (car)
│ └── PE → Pin 5 (car) ← NEVER skip
│
└──► Isolated 12V PSU ──► Contactor coil
└──► Buck 5V ──► ESP32
ESP32 GPIOs:
- CP PWM output → EVSE board CP driver
- CP ADC read → EVSE board CP sense (car state)
- PP ADC read → Proximity Pilot (cable rating)
- Relay out → Contactor coil (via MOSFET)
- NTC analog → Socket temperature
- UART RX/TX → PZEM-004T (Modbus)
- I²C → Optional OLED local display
Non-negotiable rules:
- Use 6 mm² copper minimum for a 32 A single-phase charger. 10 mm² if the run exceeds 15 m.
- The protective earth (PE) path must be continuous, low-impedance, and verified before the contactor is allowed to close.
- Torque every terminal to the manufacturer's specification. A loose 32 A terminal will heat, oxidise, and eventually arc.
- Route the low-voltage control wiring (CP, PP, ESP32) in a separate conduit from the power cables. EMI from a 32 A contactor will corrupt your CP signal otherwise.
💻 5. The Firmware: ESPHome + Solar Diversion Logic
For most makers, ESPHome is the right choice: native Home Assistant integration, OTA updates, and a clean YAML syntax. Below is a working skeleton that implements the solar diversion algorithm. Replace the PZEM reading with your own sensor source if you use a different meter.
# solar_evse.yaml — ESPHome config for a solar-diverting EVSE
esphome:
name: solar_evse
platform: ESP32
board: esp32dev
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
mqtt:
broker: !secret mqtt_broker
username: !secret mqtt_user
password: !secret mqtt_pass
uart:
id: pzem_uart
tx_pin: GPIO1
rx_pin: GPIO3
baud_rate: 9600
pzem004t_v3:
id: pzem
uart_id: pzem_uart
address: 1
sensor:
- platform: pzem004t_v3
current:
name: "Grid Current"
id: grid_current
power:
name: "Grid Power"
id: grid_power
on_value:
then:
- lambda: |-
// Solar diversion logic — runs every time grid power updates
float grid_w = x; // positive = import
float house_buffer_w = 200.0; // keep for fridge etc.
float surplus_w = -grid_w - house_buffer_w;
float target_a = surplus_w / 230.0;
// Clamp to IEC 61851 legal range
if (target_a < 6.0f) target_a = 0.0f; // stop
else if (target_a > 32.0f) target_a = 32.0f;
// Hysteresis: only change if stable for 5 readings
static float last_target = 0.0f;
static int stable_count = 0;
if (fabs(target_a - last_target) > 0.9f) {
stable_count = 0;
} else {
stable_count++;
}
if (stable_count >= 5 && target_a != last_target) {
id(evse_set_current).publish_state(target_a);
last_target = target_a;
// Here you'd call the EVSE library to update PWM duty
}
- platform: template
name: "EVSE Set Current"
id: evse_set_current
unit_of_measurement: "A"
accuracy_decimals: 0
- platform: ntc
sensor: socket_resistance
name: "Socket Temperature"
calibration:
b_constant: 3950
reference_temperature: 25°C
reference_resistance: 10kΩ
filters:
- throttle: 10s
- platform: template
name: "Energy Charged Today"
id: energy_charged
unit_of_measurement: "kWh"
accuracy_decimals: 2
switch:
- platform: gpio
pin: GPIO5
name: "EVSE Contactor"
id: contactor
restore_mode: ALWAYS_OFF
button:
- platform: template
name: "Force Max Charge"
on_press:
then:
- lambda: |-
id(evse_set_current).publish_state(32.0);
id(contactor).turn_on();
api:
encryption:
key: !secret api_key
ota:
platform: esphome
password: !secret ota_password
Three details that separate this from a toy project:
- Fail-safe defaults: The contactor is
ALWAYS_OFFat boot. If the ESP32 crashes, the car stops charging. The opposite design — fail-on — is how DIY chargers cause fires. - Thermal derating: If the socket NTC exceeds 65 °C, the firmware must reduce the setpoint by 1 A per degree, and open the contactor above 75 °C. IEC 61851 requires this.
- Encrypted OTA + API: Your charger is on your home network. An unauthenticated attacker could set it to 32 A on a 16 A circuit. Use ESPHome's native encryption.
🏠 6. Home Assistant: The Dashboard That Makes It Worth It
Once the ESP32 is discovered by Home Assistant, you get a complete charging dashboard for free:
- Live power flow card: Show PV production, house consumption, battery state and EV charging power on a single animated diagram (use the "Power Distribution Card").
- Cost & CO₂ tracker: Integrate your utility's hourly tariff (e.g., via the EmonCMS or Octopus Energy integration) and your grid's carbon intensity API. Display "€ saved today" and "kg CO₂ avoided" counters.
- Automation: cheap-hours top-up: If the car's SOC is below 40 % at 11 PM and the electricity price is below a threshold, force a 16 A charge until 6 AM — regardless of the sun.
- Automation: leave-home reminder: Using the
proximityintegration, send a notification when you walk away from home and the charger is still plugged in but idle. - Long-term statistics: Use the
statisticssensor to track kWh per month, compare to last year, and detect anomalies (a sudden drop in efficiency often means a dirty connector or a failing cable).
🚀 7. The "TechFix Hub" Upgrade: OCPP, RFID & Fleet Features
For makers who want to go further — or who plan to share the charger with neighbours — add these features:
- OCPP 1.6-J client: The Open Charge Point Protocol lets your home charger talk to any compliant backend (home assistant's OCPP integration, or a commercial platform). You get remote start/stop, smart charging profiles, and billing — the same stack used by public chargers.
- RFID authorisation: Add an RC522 or PN532 reader. Only authorised tags can close the contactor. Essential if the charger is in a shared garage.
- Mid-session PV re-evaluation: If clouds reduce PV for more than 5 minutes, gracefully drop the current rather than bouncing between charge and stop — the car's onboard charger will thank you.
- Load balancing across phases: For three-phase installations, measure each phase independently and limit the total to your contractual limit (e.g., 40 A per phase in many EU homes).
- Vehicle-side telemetry: Some cars (Tesla, Renault via CAN, Hyundai via BLE) expose their SOC. Reading it lets you stop charging at 80 % — the sweet spot for battery longevity.
🔧 8. Troubleshooting the Most Common Build Issues
- Car plugs in but doesn't charge (stays in state B): Check the CP signal with an oscilloscope. You should see a clean +12 V / −12 V square wave at 1 kHz. If the amplitude is wrong, the car won't recognise the EVSE. If the duty cycle is 0 %, the car is being told "no current available".
- Contactor chatters: Your hysteresis is too tight, or your PZEM readings are noisy. Add a 10-second moving average on the grid power before computing surplus.
- RCD trips randomly: Most likely a leaky Y-capacitor in the EVSE's EMI filter, or a neutral/earth swap somewhere. Measure insulation resistance with a megger before blaming the car.
- ESP32 reboots when contactor closes: The contactor coil's back-EMF is coupling into your 5 V rail. Add a flyback diode (1N4007) across the coil, and a 470 µF capacitor on the ESP32's 5 V input.
- Charging works but very slowly: Check the PP (Proximity Pilot) resistor in the Type 2 socket. It tells the car what cable rating is available. A missing or wrong PP resistor will limit the car to 13 A regardless of your PWM.
- Solar diversion never kicks in: Your PZEM's CT is probably on the wrong conductor or oriented backwards. Verify that grid power reads negative when the sun is producing more than the house uses.
🔗 Complete Your Solar + EV Ecosystem on TechFix Hub
This EVSE pairs perfectly with the rest of our energy stack:
- ☀️ DIY MPPT Solar Charge Controller with ESP32: Maximise Your Panel Efficiency
- 🔋 DIY LiFePO4 BMS with Active Balancing & ESP32 Thermal Monitoring
- 📊 Smart Home Energy Monitor with ESP32 & PZEM-004T
- 🔒 ESP32 Secure Boot & Flash Encryption: Protect Your IoT Devices
- 🌡️ Predictive Maintenance with ESP32-S3 & TinyML: Detect Motor Failures Early
✅ Conclusion
A smart solar EV charger is the missing link between your PV array and your electric car. It turns wasted midday sunshine into free kilometres, reduces your grid import to near zero, and gives you a level of visibility and control that no commercial wallbox matches. But it is also the most safety-critical DIY project you will ever build — 32 A at 230 V is not a hobby voltage. Respect the IEC 61851 protocol, use the right RCD, torque every terminal, and have a licensed electrician sign off on the final installation. Do that, and you'll have a charger that is safer, smarter, and cheaper than anything you could buy — and the satisfaction of knowing every kilometre you drive came from your own roof.
🛠️ Building your own solar EV charger?
Tell us your car model, PV array size and grid connection in the comments. The TechFix Hub community will help you size the contactor, pick the right RCD, and tune the diversion algorithm.