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 Arduino Uno — mains power, energy and safe wiring

Read voltage, current, power, kWh, frequency and power factor from a PZEM-004T v3 on an Arduino Uno R3 over SoftwareSerial — mains side by an electrician.

Arduino C++Verified — core avr 1.8.8, PZEM004Tv30 1.2.1, 3 Nov 2026Compile-only

Community draft — report a mistake

The PZEM-004T v3.0 is a complete single-phase energy meter on one board. It measures voltage, current, power, energy (kWh), frequency and power factor, and reports them over a serial link. For about ₹900 it is the basis of most DIY home-energy monitors in India.

On the Uno only the TTL side is your wiring: 5V, GND, and the serial lines to SoftwareSerial on D10/D11. The PZEM’s TX is pulled up to whatever feeds its 5V pin, so on a 5 V Uno it connects directly, with no divider. The mains side — L and N, and the current transformer clipped around the live wire — is electrician’s work, inside a closed enclosure.

The sketch uses the PZEM004Tv30 library and prints all six values every 2 seconds. It says clearly when the meter doesn’t answer, which on the bench (with no mains connected) is normal.

Wiring

Arduino Uno R3Only the pins used are shown · 5 V logicPZEM-004T v3.0 AC energy meter (100 A with CT)5VGNDD10D115VRXTXGNDL → Mains live, from an MCB-protected circuit (electrician only)N → Mains neutral (electrician only)CT1 → Current transformer lead 1 (CT clipped around the live wire to the load)CT2 → Current transformer lead 2
Also needed: The 100 A split or solid current transformer supplied with the PZEM, Closed enclosure, DIN-rail terminal block, MCB/RCCB upstream.
Every connection
Arduino Uno R3PZEM-004T v3.0 AC energy meter (100 A with CT)WireNotes
—L—To Mains live, from an MCB-protected circuit (electrician only) (not drawn)
—N—To Mains neutral (electrician only) (not drawn)
—CT1—To Current transformer lead 1 (CT clipped around the live wire to the load) (not drawn)
—CT2—To Current transformer lead 2 (not drawn)
5V5VredPowers the opto-isolated TTL side only.
GNDGNDblack
D10TXyellowPZEM TX → Uno SoftwareSerial RX. At 5 V no divider is needed (unlike ESP32/Pico).
D11RXgreenUno TX → PZEM RX.

TTL side 5 V from your board; measuring side powered from the 230 V it measures part, 5 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

  • Electrician only for L, N and the CT. The PZEM measures voltage from its own L/N terminals, which carry 230 V, and its board is not touch-safe. Mount it in a closed enclosure on an MCB- and RCCB-protected circuit. The CT clips around the live wire of the load only — never both live and neutral, or it reads zero.
  • The TTL side is opto-isolated, so the Uno never touches the mains — as long as you never connect the Uno’s GND to neutral.
  • The PZEM only answers when its L/N side is powered from the mains. On USB alone it stays silent: “No reply” on the bench is expected.
  • The Uno’s hardware serial is busy with USB, so the PZEM uses SoftwareSerial at 9600 baud, which is reliable at that speed.
  • The energy counter (kWh) is stored inside the PZEM and survives power cuts. Reset it with pzem.resetEnergy() when you start a new month.
  • Library Manager lists it as PZEM004Tv30 by Jakub Mandula.

Code

pzem-uno.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// PZEM-004T v3.0 energy meter on an Arduino Uno R3 (Modbus over SoftwareSerial).
// TTL side only: 5V → 5V, GND → GND, PZEM TX → D10 (Uno RX), PZEM RX ← D11 (Uno TX).
// L/N and the CT around the live wire are mains wiring - ELECTRICIAN ONLY.
#include <SoftwareSerial.h>
#include <PZEM004Tv30.h>

SoftwareSerial pzemSerial(10, 11);  // RX, TX
PZEM004Tv30 pzem(pzemSerial);

void setup() {
  Serial.begin(9600);
  Serial.println(F("PZEM-004T v3 on D10/D11"));
}

void loop() {
  float v = pzem.voltage();
  if (isnan(v)) {
    Serial.println(F("No reply - check TX/RX, 5V and that L/N are live"));
    delay(2000);
    return;
  }
  Serial.print(F("V "));
  Serial.print(v, 1);
  Serial.print(F("  A "));
  Serial.print(pzem.current(), 3);
  Serial.print(F("  W "));
  Serial.print(pzem.power(), 1);
  Serial.print(F("  kWh "));
  Serial.print(pzem.energy(), 3);
  Serial.print(F("  Hz "));
  Serial.print(pzem.frequency(), 1);
  Serial.print(F("  PF "));
  Serial.println(pzem.pf(), 2);
  delay(2000);
}

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

Expected serial output

Serial Monitor · 9600Output
PZEM-004T v3 on D10/D11
V 231.4  A 0.412  W 81.3  kWh 0.127  Hz 50.0  PF 0.85
V 231.2  A 0.415  W 81.9  kWh 0.127  Hz 50.0  PF 0.86

Common errors

“No reply”

TX/RX crossed wrongly (PZEM TX goes to D10), the 5V/GND pair missing, or the L/N side not powered — it must be live to answer.

Voltage correct, current and power 0

The CT isn’t around the load’s live wire, or it encloses both live and neutral (their fields cancel).

Power factor looks wrong for a heater

Resistive loads read close to 1.00; fans, fridges and LED drivers read 0.5–0.9. Very small loads (under 10 W) give noisy PF values.

↑↓ to move · Enter to open