PZEM-004T tutorial

PZEM Sensor Tutorial (Read current, voltage, power factor, power, frequency on Mains)

PZEM-004T is a very complete sensor module, it has current, voltage, power, power factor, frequency, and even an energy meter. In this tutorial, we are going to find out how to use it with Arduino and ESP-based board like nodeMCU.
Back in the day, when we want to make an energy meter, it is quite hard. We need many sensors, like the current, voltage, not to mention frequency and power factor sensors. We need to build that power factor sensor by ourselves. And also the AC voltage sensor in the market is sometimes just unstable I don’t know why.

But now I have this PZEM-004T sensor that actually solves all that problem, this module includes all our needs in energy or power meter. Even more complete with frequency and power factor sensors.

This sensor uses serial communication, to communicate. We have all data already calibrated, that’s great!
Since this module uses serial, then we got the tx and RX pins. So to use it with Arduino UNO we need the software serial, we can connect these pins to digital pins, and programmatically use the pins as serial. If you are using Arduino Mega, you can use the Hardware serial since it got 4 hardware serial. You can use any Serial.
In this example, I will use pins 8 and 9 as RX and TX. So sensor’s TX goes to arduino RX and vice versa.

PZEM-004T Wiring Diagram with Arduino

PZEM with Arduino
PZEM-004T with Arduino wiring diagram

This is the complete wiring diagram, don’t forget to give the sensor mains input and also to sense the current, one of the cables for load should go through the ct sensor.

The Code and Library

Before you start to code, you need to download or install the library first. Here the link for library.

#include <PZEM004Tv30.h>
#include <Wire.h>

PZEM004Tv30 pzem(8, 9); // Software Serial pin 8 (RX) & 9 (TX)

void setup() {
  Serial.begin(9600);
}

void loop() {
  float voltage = pzem.voltage();
  if (voltage != NAN) {
    Serial.print("Voltage: ");
    Serial.print(voltage);
    Serial.println("V");
  } else {
    Serial.println("Error reading voltage");
  }

  float current = pzem.current();
  if (current != NAN) {
    Serial.print("Current: ");
    Serial.print(current);
    Serial.println("A");
  } else {
    Serial.println("Error reading current");
  }

  float power = pzem.power();
  if (current != NAN) {
    Serial.print("Power: ");
    Serial.print(power);
    Serial.println("W");
  } else {
    Serial.println("Error reading power");
  }

  float energy = pzem.energy();
  if (current != NAN) {
    Serial.print("Energy: ");
    Serial.print(energy, 3);
    Serial.println("kWh");

  } else {
    Serial.println("Error reading energy");
  }

  float frequency = pzem.frequency();
  if (current != NAN) {
    Serial.print("Frequency: ");
    Serial.print(frequency, 1);
    Serial.println("Hz");
  } else {
    Serial.println("Error reading frequency");
  }

  float pf = pzem.pf();
  if (current != NAN) {
    Serial.print("PF: ");
    Serial.println(pf);
  } else {
    Serial.println("Error reading power factor");
  }

  Serial.println();
  delay(2000);
}

Just Upload the code and open the Serial Monitor, it now should print the reading result from sensor. If you got “Nan” value. maybe you forgot to give the Mains AC input to the sensor.

Easy right? now all the value already displayed.

Adding an LCD (Simple Wattmeter)

Now I want to add the LCD to display the sensor reading result. Here’s the wiring diagram. I use the I2C LCD. If you need a detail tutorial on this LCD. it’s already here.

PZEM-004T sensor with Arduino and LCD
#include <PZEM004Tv30.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

PZEM004Tv30 pzem(8, 9); // Software Serial pin 8 (RX) & 9 (TX)

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("PZEM Test");
  lcd.setCursor(0, 1);
  lcd.print("by Miliohm.com");
  delay(500);
  lcd.clear();
}

void loop() {
  float voltage = pzem.voltage();
  if (voltage != NAN) {
    Serial.print("Voltage: ");
    Serial.print(voltage);
    Serial.println("V");
    lcd.setCursor(0, 0);
    lcd.print("V:");
    lcd.print(voltage);
  } else {
    Serial.println("Error reading voltage");
  }

  float current = pzem.current();
  if (current != NAN) {
    Serial.print("Current: ");
    Serial.print(current);
    Serial.println("A");
    lcd.setCursor(0, 1);
    lcd.print("I:");
    lcd.print(current);
  } else {
    Serial.println("Error reading current");
  }

  float power = pzem.power();
  if (current != NAN) {
    Serial.print("Power: ");
    Serial.print(power);
    Serial.println("W");

    lcd.setCursor(8, 0);
    lcd.print("P:");
    lcd.print(power);
  } else {
    Serial.println("Error reading power");
  }

  float energy = pzem.energy();
  if (current != NAN) {
    Serial.print("Energy: ");
    Serial.print(energy, 3);
    Serial.println("kWh");

  } else {
    Serial.println("Error reading energy");
  }

  float frequency = pzem.frequency();
  if (current != NAN) {
    Serial.print("Frequency: ");
    Serial.print(frequency, 1);
    Serial.println("Hz");

    lcd.setCursor(8, 1);
    lcd.print("f:");
    lcd.print(frequency);
  } else {
    Serial.println("Error reading frequency");
  }

  float pf = pzem.pf();
  if (current != NAN) {
    Serial.print("PF: ");
    Serial.println(pf);
  } else {
    Serial.println("Error reading power factor");
  }

  Serial.println();
  delay(2000);
}
PZEM-004T displayed on LCD
The result on LCD

PZEM-004T with NodeMCU

PZEM-004T sensor with NodeMCU

Now I will try to use this sensor module with NodeMCU, we can use this sensor the same way with Arduino, surprisingly even the label is 5V. This sensor can be powered with 3V from the nodeMCU. So just edit the pins according to your wiring. And it’s done.

#include <PZEM004Tv30.h>

PZEM004Tv30 pzem(D3, D4); // Software Serial pin 8 (RX) & 9 (TX)

void setup() {
  Serial.begin(9600);
}

void loop() {
  float voltage = pzem.voltage();
  if (voltage != NAN) {
    Serial.print("Voltage: ");
    Serial.print(voltage);
    Serial.println("V");
  } else {
    Serial.println("Error reading voltage");
  }

  float current = pzem.current();
  if (current != NAN) {
    Serial.print("Current: ");
    Serial.print(current);
    Serial.println("A");
  } else {
    Serial.println("Error reading current");
  }

  float power = pzem.power();
  if (current != NAN) {
    Serial.print("Power: ");
    Serial.print(power);
    Serial.println("W");
  } else {
    Serial.println("Error reading power");
  }

  float energy = pzem.energy();
  if (current != NAN) {
    Serial.print("Energy: ");
    Serial.print(energy, 3);
    Serial.println("kWh");

  } else {
    Serial.println("Error reading energy");
  }

  float frequency = pzem.frequency();
  if (current != NAN) {
    Serial.print("Frequency: ");
    Serial.print(frequency, 1);
    Serial.println("Hz");
  } else {
    Serial.println("Error reading frequency");
  }

  float pf = pzem.pf();
  if (current != NAN) {
    Serial.print("PF: ");
    Serial.println(pf);
  } else {
    Serial.println("Error reading power factor");
  }

  Serial.println();
  delay(2000);
}

Now the sensor works perfectly with nodeMCU.