Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

PZEM-004T v3 with ESP32 DevKit V1 — Serial2 wiring and readings

Read voltage, current, power, kWh and PF from a PZEM-004T v3.0 on an ESP32 DevKit V1 over Serial2 (GPIO16/17), with a divider on its 5 V TX. Mains side: electrician only.

Arduino C++Verified — core esp32 3.3.12, PZEM004Tv30 1.2.1, 3 Nov 2026Compile-only

Community draft — report a mistake

The PZEM-004T v3.0 is a complete energy meter on a small board: it measures mains voltage, current (through its CT), power, energy, frequency and power factor, and sends the numbers over a 9600-baud TTL serial line. It is the standard part for home energy monitors and solar-export meters in India.

On the ESP32 DevKit V1, use the second hardware UART: RX2 (GPIO16) and TX2 (GPIO17), passed explicitly because core 3.x moved the defaults. The PZEM’s TX is a 5 V signal, so it goes through a 1 kΩ / 2 kΩ divider.

Everything on the L, N and CT side is 230 V and electrician-only. Only the four TTL pins are wired on the bench.

Wiring

ESP32 DevKit V1Only the pins used are shown · 3.3 V logicPZEM-004T v3.0 AC energy meter (100 A with CT)1k│2kGNDVINTX2 · 17RX2 · 165VRXTXGNDL → Mains live — 230 V, electrician onlyN → Mains neutral — 230 V, electrician onlyCT1 → Current-transformer lead (the CT clamps around the live wire only)CT2 → Current-transformer lead (other wire)
Also needed: 1 kΩ and 2 kΩ resistors, 100 A split-core or closed CT supplied with the PZEM, Closed plastic enclosure for the PZEM.
Every connection
ESP32 DevKit V1PZEM-004T v3.0 AC energy meter (100 A with CT)WireNotes
—L—To Mains live — 230 V, electrician only (not drawn)
—N—To Mains neutral — 230 V, electrician only (not drawn)
—CT1—To Current-transformer lead (the CT clamps around the live wire only) (not drawn)
—CT2—To Current-transformer lead (other wire) (not drawn)
VIN5VredPowers the opto-isolated TTL side (5 V while the ESP32 runs from USB).
GNDGNDblackTTL-side ground — isolated from mains by the optocouplers.
RX2TXyellowVia 1 kΩ / 2 kΩ divider — PZEM TX idles at 5 V. 1 kΩ from TX to RX2 (GPIO16), 2 kΩ from RX2 to GND → about 3.3 V.
TX2RXgreenGPIO17. 3.3 V from the ESP32 drives the PZEM’s opto input directly.

TTL side 5 V from your board; measuring side powered from the 230 V it measures part, 3.3 V board. The TTL side is opto-isolated and powered from your board. Its TX line is pulled up to whatever you feed the 5V pin: on ESP32/Pico, keep 5 V and put a 1 kΩ / 2 kΩ divider on PZEM TX → board RX (many v3.0 units also work with 3.3 V on the 5V pin). On Uno connect directly.

Board quirks

  • L, N and the CT are a 230 V installation. An electrician should wire L/N from an MCB- and RCCB-protected circuit and pass only the live wire through the CT, with the module in a closed box. You wire the four TTL pins, before mains is connected.
  • The PZEM’s meter chip is powered from the mains side. With L/N unconnected it never replies, even though the TTL LEDs may light — so a bench test without mains always shows “No reply”.
  • Arduino-ESP32 3.x moved the default Serial2 pins to RX 4 / TX 25. The library constructor takes the pins, so the sketch passes GPIO16 and GPIO17 (printed RX2 / TX2) explicitly.
  • Many v3.0 boards also work with 3.3 V on the 5V pin (then no divider is needed), but not all of them — 5 V plus the divider works on every board.
  • Energy (kWh) is stored inside the PZEM and survives power cuts. pzem.resetEnergy() clears it.
  • The CT must clamp the live wire alone. Around a cable holding live and neutral, the currents cancel and it reads zero.

Code

pzem004t-esp32.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// PZEM-004T v3.0 energy meter on an ESP32 DevKit V1 over Serial2 (Modbus-RTU, 9600 baud).
// Low-voltage side: 5V → VIN, GND → GND, PZEM TX → 1 kΩ/2 kΩ divider → RX2 (GPIO16), PZEM RX ← TX2 (GPIO17).
// L/N and the CT clamp are on 230 V — electrician only. The meter answers only while mains is connected.
#include <PZEM004Tv30.h>

constexpr uint8_t RX_PIN = 16, TX_PIN = 17;
// Name the pins: arduino-esp32 3.x would otherwise put Serial2 on RX 4 / TX 25.
PZEM004Tv30 pzem(Serial2, RX_PIN, TX_PIN);

void setup() {
  Serial.begin(115200);
  Serial.println("PZEM-004T v3.0 on Serial2 (RX2/TX2)");
}

void loop() {
  float v = pzem.voltage();
  if (isnan(v)) {
    Serial.println("No reply — is 230 V connected to L/N? Check TX/RX and the divider.");
  } else {
    Serial.printf("%.1f V  %.3f A  %.1f W  %.3f kWh  %.1f Hz  PF %.2f\n", v, pzem.current(), pzem.power(),
                  pzem.energy(), pzem.frequency(), pzem.pf());
  }
  delay(2000);
}

Library: PZEM004Tv30 (Jakub Mandula) — compiled with PZEM004Tv30 1.2.1.

Expected serial output

Serial Monitor · 115200Output
PZEM-004T v3.0 on Serial2 (RX2/TX2)
231.4 V  0.412 A  61.8 W  12.347 kWh  50.0 Hz  PF 0.65
230.9 V  0.415 A  62.1 W  12.347 kWh  50.0 Hz  PF 0.65

Common errors

“No reply” on every reading

Mains not connected to L/N (the meter chip needs it), TX/RX swapped, or the divider wired the wrong way round (1 kΩ on the PZEM side, 2 kΩ to GND). Also check the board is a v3.0 — the old v1/v2 use a different protocol.

Voltage is right but current reads 0

The CT isn’t around the live wire alone, the load is off, or the CT leads aren’t tight in CT1/CT2. Ask the electrician to check — don’t open the box with mains on.

Readings work, then stop after Wi-Fi starts

Not a Wi-Fi problem — UART is unaffected. Look for a loose divider resistor or a shared GND that is missing.

↑↓ to move · Enter to open