IoT Prepaid Energy Meter: ESP32 + PZEM-004T for Real-Time Prepaid Billing
February 7, 2026
Designing a Modern Prepaid Metering System
Traditional utility billing depends on manual meter readings. That process is labor-intensive, error-prone, and a common source of billing disputes. A prepaid smart meter solves this differently: consumers monitor their usage in real time, buy credits in advance, and stay aware of what they consume.This post walks through the design and testing of a complete IoT prepaid energy meter. The system uses a PZEM-004T AC measurement chip, an ESP32 microcontroller, a Google Cloud backend, and a Progressive Web App (PWA) for managing recharges and monitoring usage.
Hardware Design: ESP32 and PZEM-004T
The ESP32 is the core of the meter. It handles local billing calculations, controls a latching relay, and connects to the internet over Wi-Fi.For power measurement, I avoided simple current clamps or DIY voltage dividers connected to the microcontroller's ADC. Those are noisy and unsafe at mains voltages. Instead, I used the PZEM-004T module:
Measurements: Returns RMS Voltage, RMS Current, Active Power, Frequency, Energy (kWh), and Power Factor.
Safety: Optical isolation separates the high-voltage AC side from the low-voltage DC microcontroller side.
Current Sensing: A non-invasive current transformer (CT) clamp handles measurements up to 100A without interrupting the main wiring.
High-Voltage Control Stage
To enable remote disconnection when credit runs out, I added a latching relay on the AC mains. Unlike a standard electromagnetic relay, a latching relay only needs a short pulse of current to switch states, drawing no continuous power to hold its position. This matters for overall system efficiency.A transistor driver with an optocoupler handles isolation, and a flyback diode protects the circuit from inductive spikes.
Firmware Logic: The Local Billing Loop
A key design requirement was that the meter must keep working even when Wi-Fi drops. The billing engine runs locally on the ESP32, not in the cloud.
Local State Machine
Polling: Every 1 second, the ESP32 queries the PZEM-004T over UART for the latest active power reading in Watts.
Deduction: The firmware calculates the energy consumed in that second:Energy (Wh) = Power (W) * (1 second / 3600 seconds/hour)
Credit Tracking: It deducts this energy value from the local credit balance stored in the ESP32's non-volatile memory (NVS), so the balance survives a power cut.
Trip Conditions: When the balance hits zero, the ESP32 pulses the latching relay to disconnect the load.
Wi-Fi Sync: When Wi-Fi is active, the ESP32 publishes the current balance and power metrics to GCP via MQTT/HTTPS and checks for cloud-initiated recharges.
Cloud Infrastructure & PWA Interface
The backend runs on Google Cloud Platform (GCP):
Cloud Functions / Node.js: Handles API requests from the PWA (recharges, balance checks) and the ESP32 meter.
Firestore Database: Stores the real-time state of each meter (current balance, owner ID, active status) and transaction logs.
Firebase Authentication: Manages secure user logins.
The frontend is a Progressive Web App (PWA) built with React. It uses Firebase's real-time listeners. When a user completes a recharge, the updated balance pushes to Firestore, which triggers a message to the ESP32 to re-engage the latching relay within seconds.
Test Results and Validation
I tested the prototype using a resistive load bank (halogen lamps and heating elements) and compared readings against a calibrated commercial utility meter.
Accuracy: The PZEM-004T matched the commercial meter within ±1% for voltage and ±1.8% for current and active power.
Latching Relay Latency: The system disconnected the load within 340ms of the balance reaching zero.
Network Uptime Resiliency: When I disabled local Wi-Fi, the meter continued calculating power consumption locally. Once the connection restored, it synchronized the accumulated usage with Firestore.