PZEM-004T v3.0 energy meter (10 A)
Energy meter for the mains (alternating current): it measures voltage, current, power, accumulated energy, frequency and power factor, and sends the values over the UART with the Modbus RTU protocol (9600 baud, 8N1). The program sends a request with a CRC and checks the CRC of the answer before using the numbers. On the bench the load (power, power factor, mains voltage) is chosen in the part panel. On the real module the mains side carries 127/220 V: only wire it with your teacher.
Pinout
| Pin | Connect to | Note |
|---|---|---|
| 5V | VIN (5 V) | the TTL connector is passive: it needs 5 V from outside |
| RX | UART TX (e.g. TX2, GPIO17) | the Modbus request comes in here |
| TX | UART RX (e.g. RX2, GPIO16) | the answer goes out here |
| GND | GND | without all 4 wires it does not communicate |
The AI that remembers your life and lives on your computer
- Long-term memory with the source of every answer
- Works offline: your data stays on your PC
- Reads PDFs, slides, photos and meeting recordings
Essential plan free forever
MicroPython example
from machine import UART
import struct, time
# PZEM RX to TX2 (GPIO17), PZEM TX to RX2 (GPIO16), 5V to VIN, GND to GND
# timeout_char longer than the 26 ms of the 25-byte answer at 9600 baud
uart = UART(2, 9600, tx=17, rx=16, timeout=200, timeout_char=50)
def crc16(dados):
crc = 0xFFFF
for b in dados:
crc ^= b
for _ in range(8):
crc = (crc >> 1) ^ 0xA001 if crc & 1 else crc >> 1
return crc
def ler_medidas(endereco=0x01):
pedido = bytes([endereco, 0x04, 0, 0, 0, 10]) # 10 registers starting at 0x0000
c = crc16(pedido)
uart.write(pedido + bytes([c & 0xFF, c >> 8])) # CRC: low byte first
r = uart.read(25)
if r is None or len(r) != 25 or crc16(r[:-2]) != r[-2] | r[-1] << 8:
return None # no answer or wrong CRC: drop it
v = struct.unpack('>10H', r[3:23])
return {'V': v[0] / 10, 'A': (v[1] | v[2] << 16) / 1000, 'W': (v[3] | v[4] << 16) / 10,
'Wh': v[5] | v[6] << 16, 'Hz': v[7] / 10, 'FP': v[8] / 100}
while True:
print(ler_medidas())
time.sleep(2)
Specifications
| Item | Value | Source |
|---|---|---|
| Communication | 9600 baud, 8 bits, no parity, 1 stop bit; Modbus RTU | Manual "PZEM-004T V3.0 User Manual" (AC communication module), narodmon.com/img/sens/PZEM-004Tv3.pdf |
| TTL connector | 5V, RX, TX, GND; passive, needs 5 V from outside; all 4 connected | Manual "PZEM-004T V3.0 User Manual" (AC communication module), narodmon.com/img/sens/PZEM-004Tv3.pdf |
| Addresses | 0x01–0xF7; 0x00 = broadcast (no answer); 0xF8 = general (a single device on the line) | Manual "PZEM-004T V3.0 User Manual" (AC communication module), narodmon.com/img/sens/PZEM-004Tv3.pdf |
| Functions | 0x04 reads measurements, 0x03 reads parameters, 0x06 writes a parameter, 0x42 resets the energy, 0x41 calibration | Manual "PZEM-004T V3.0 User Manual" (AC communication module), narodmon.com/img/sens/PZEM-004Tv3.pdf |
| Measurement registers (0x04) | 0x0000 voltage (0.1 V); 0x0001–0x0002 current (1 mA); 0x0003–0x0004 power (0.1 W); 0x0005–0x0006 energy (1 Wh); 0x0007 frequency (0.1 Hz); 0x0008 PF (0.01); 0x0009 alarm (0xFFFF) | Manual "PZEM-004T V3.0 User Manual" (AC communication module), narodmon.com/img/sens/PZEM-004Tv3.pdf |
| Parameters (0x03/0x06) | 0x0001 alarm threshold (1 W); 0x0002 address (0x0001–0x00F7) | Manual "PZEM-004T V3.0 User Manual" (AC communication module), narodmon.com/img/sens/PZEM-004Tv3.pdf |
| Ranges (10 A model) | 80–260 V; 0–10 A (measures from 0.01 A); 0–2.3 kW (from 0.4 W); 45–65 Hz; PF 0.00–1.00; 0–9999.99 kWh | Manual "PZEM-004T V3.0 User Manual" (AC communication module), narodmon.com/img/sens/PZEM-004Tv3.pdf |
| Errors | function + 0x80 and the code: 0x01 function, 0x02 address, 0x03 data, 0x04 slave | Manual "PZEM-004T V3.0 User Manual" (AC communication module), narodmon.com/img/sens/PZEM-004Tv3.pdf |
| CRC | CRC-16, polynomial 0xA001, low byte first | MODBUS over Serial Line V1.02 (modbus.org), sections 2.5.1 and 6.2.2; github.com/mandulaj/PZEM-004T-v30 (src/PZEM004Tv30.cpp, setCRC) — Under review: the manual tables put the high byte first |
| Reading the answer | 25 bytes take ≈ 26 ms at 9600 baud: use a timeout_char above that (e.g. 50 ms) | MicroPython v1.29.0: ports/esp32/machine_uart.c (mp_machine_uart_read) |
| Response and update time | not in the manual; here it answers 3.5 characters after the end of the request and measures right away | MODBUS over Serial Line V1.02 (modbus.org), sections 2.5.1 and 6.2.2 — Under review: measure on the module |
| Factory address and threshold | 0x01 and 2300 W in the simulator | PyPlaca component catalog — Under review: the manual does not give the factory values |
| Faults on the bench | no answer, invalid CRC, answer from another address: they simulate the line, not the device | PyPlaca component catalog |
Values marked "Under review" will still be checked against the parts in the lab.