A pulse reader on the electricity meter tells you how much the whole house uses. It does not tell you how much of that goes to the heat pump, the boiler, the workshop or the kitchen circuit. For that you need a meter on the circuit itself, and the Peacefair PZEM-004T V3 is a cheap way to get one: a small board that measures voltage, current, power, energy, frequency and power factor, and reports them over a serial line that ESPHome reads directly.
This guide covers choosing the right variant, wiring the low-voltage side to an ESP32, the ESPHome configuration, running several modules from one board and getting the readings into the Home Assistant Energy dashboard.
Safety first
The PZEM-004T is connected to mains voltage. The voltage terminals go to live and neutral, and the 10 A variant carries the full load current through the board. Usually the module ends up in a distribution board next to the breakers. If you are not qualified to work on mains installations, have an electrician do the mains side. You can still do the ESP32 side, the configuration and everything in Home Assistant yourself.
Install the module in a closed enclosure, for example a DIN-rail box, so that nothing on the mains side can be touched, and never work on it while it is live. The low-voltage serial interface goes through optocouplers, which is why it is commonly connected to microcontrollers, but that is not a reason to leave the board exposed. Power the ESP32 from a proper, isolated 5 V supply. Cheap capacitive supplies without isolation have no place in this build.
10 A or 100 A
The module comes in two variants, and the datasheet lists the differences:
| PZEM-004T-10A | PZEM-004T-100A | |
|---|---|---|
| Current measurement | built-in shunt | external current transformer (clamp) |
| Current range | 0-10 A | 0-100 A |
| Power range | 0-2.3 kW | 0-23 kW |
| Starting current | 0.01 A | 0.02 A |
Both measure 80-260 V AC, frequency from 45 to 65 Hz, and energy up to 9999.99 kWh with 1 Wh resolution. Voltage, current, power, frequency and energy have a stated accuracy of 0.5%, power factor 1%.
For a circuit in a distribution board, the 100 A variant is the practical choice. The current transformer is a ring or a split clamp that you put around one conductor, so the load current never flows through the module and you do not have to cut into the circuit. The 10 A variant suits a single appliance where the load stays well under 10 A, but remember that the full current passes through its terminals.
Wiring the mains side
The module needs two things on the mains side: voltage on its L and N terminals, which is also what powers its metering chip, and the current from the circuit you want to measure.
With the 100 A variant, run only the live conductor of the measured circuit through the current transformer. If both live and neutral pass through the ring, their currents cancel and the module reads close to zero. The voltage terminals can be fed from the same circuit or from any other point on the same phase.
ESPHome's documentation has one non-obvious requirement here: the metering chip is powered from the AC side, and it has to be on when the ESPHome device starts. Otherwise the readings do not show up. In practice, power the ESP32 from the same circuit or make sure the PZEM has mains voltage before the ESP32 boots. If you later see a device that is online but reports nothing, restart the ESP32 first.
Wiring the low-voltage side
The serial interface has four pins: 5V, RX, TX and GND. The datasheet calls it a passive interface. It needs external power, and all four pins must be connected for communication to work. Cross the data lines: PZEM TX goes to the ESP32's RX pin, and PZEM RX to the ESP32's TX pin.
The problem is the voltage level. The interface was designed for 5 V, while ESP32 inputs work at 3.3 V. Builders use two approaches:
- 5 V and a level shifter. Power the interface from 5 V and put a logic level shifter on the line from PZEM TX to ESP32 RX, so the ESP32 never sees 5 V on its input. Many builders drive the PZEM's RX straight from the ESP32's 3.3 V output, but a bidirectional shifter on both lines removes the guesswork.
- 3.3 V on the 5V pin. Simpler, and it works for many people, because the logic levels then match. The catch is the RX optocoupler: its series resistor was sized for 5 V, so at 3.3 V it gets less current. The Tasmota documentation describes adding a 1 kΩ resistor in parallel with that resistor (R8 on the V3 board) to compensate. ESPHome's docs note that the PZEM-004T-100A-D-P board seems to work with 3.3 V on the 5V pin, at least over a few centimetres of wire, without a level shifter or resistor changes.
Whichever you choose, keep the serial wires short. Long, unshielded wires running next to mains cables pick up interference and can cause reading errors.
ESPHome configuration
The pzemac platform in ESPHome supports the V3 module. It communicates over Modbus on a UART at 9600 baud. A basic configuration for an ESP32:
uart:
rx_pin: GPIO16
tx_pin: GPIO17
baud_rate: 9600
modbus:
sensor:
- platform: pzemac
id: pzem_heat_pump
current:
name: "Heat pump current"
voltage:
name: "Heat pump voltage"
power:
name: "Heat pump power"
energy:
name: "Heat pump energy"
frequency:
name: "Heat pump frequency"
power_factor:
name: "Heat pump power factor"
update_interval: 10s
The pins are an example: any free GPIO pins that are not used for something else on the board will do. If nothing arrives, swap RX and TX in the YAML first. ESPHome's own UART documentation suggests the same, because the pin names depend on whose side you look from.
The default update_interval is 60 seconds. For a heat pump or a washing machine, where you want to see when it starts and stops, 10 seconds gives a much more useful graph. The energy value is a counter kept inside the module, so a longer interval does not lose any energy, only detail in the power graph.
Each sensor is optional, so you can skip frequency or voltage if you do not need them. Power factor is worth keeping for motors and compressors: if it drops well below 1, the module is telling you that the current and the real power do not match, which you would not see from watts alone.
The older PZEM-004T V1 uses a different protocol and a different platform, pzem004t, so check which version you have. ESPHome also warns that the PZEM-004T-100A-D-P has a "V1.0" silkscreen even though it works with pzemac.
The energy counter
The energy sensor reports watt-hours with the total_increasing state class, so Home Assistant treats it as a meter. The counter is stored in the module, not on the ESP32, which means it survives an ESP32 restart or a firmware update.
You can reset the counter with the pzemac.reset_energy action, for example from a button:
button:
- platform: template
name: "Reset heat pump energy"
on_press:
- pzemac.reset_energy: pzem_heat_pump
For the Energy dashboard, you do not need to reset anything. Home Assistant interprets a decreasing total_increasing value as the start of a new meter cycle, so a reset does not show up as negative consumption. Use the reset if you want the module's own counter to match a period you choose, such as a heating season.
Several modules on one ESP32
Each PZEM has a Modbus address, by default 1. Several modules can share one UART if each has its own address, from 0x01 to 0xF7. You set the address once per module, connecting only that module to the bus. ESPHome's documentation gives a configuration that writes the new address at boot through modbus_client.write_single_register. Flash it, wait for the log message confirming the change, then remove the code before connecting the next module. Do not leave it in the configuration.
Then give every sensor block its address:
sensor:
- platform: pzemac
address: 1
power:
name: "Kitchen power"
energy:
name: "Kitchen energy"
- platform: pzemac
address: 2
power:
name: "Workshop power"
energy:
name: "Workshop energy"
The difficult part is electrical, not the YAML. Each module's TX output drives the line, so you cannot simply connect several TX pins together. Builders on the Node-RED forum combine them with diodes and a pull-up resistor. On an ESP32 there is a simpler option for two or three modules: give each one a separate uart: entry with its own pins, a separate modbus: hub, and link each sensor to its hub with modbus_id. ESPHome uses the ESP32's hardware UART units for this.
Getting it into the Energy dashboard
In Settings > Dashboards > Energy, add the energy sensor under Individual devices. It does not belong under grid consumption. That place is for a meter that sees the whole house, such as a pulse reader on the main meter.
If you measure both the whole house and some of its circuits, set the house meter as the upstream device of the circuit sensors. Home Assistant then shows the circuits as part of the total instead of counting the same kilowatt-hours twice.
Common mistakes
- Both conductors through the current transformer. The currents cancel out and the reading is close to zero.
- RX and TX not crossed. PZEM TX goes to ESP32 RX. If nothing arrives, swap the pins in YAML first.
- The ESP32 started before the module had mains voltage. Restart the ESP32 after the PZEM is powered.
- Not all four serial pins connected. The interface needs its own supply. RX, TX and GND alone are not enough.
- Leaving the address-changing code in the firmware. It should run once per module, not at every boot.
- The 10 A variant on a circuit that draws more. Its power range ends at 2.3 kW, which one kettle or heater can reach on its own. For a whole circuit, use the 100 A variant with a clamp.