PZEM-004T Energy Sensor

Measure voltage, current, power, energy, frequency, and power factor with high accuracy

PZEM-004T Sensor

Safety Warning

PZEM-004T works with high voltage (AC 80-260V). Always disconnect power before wiring. Never touch exposed terminals when connected to mains power. Use proper insulation and enclosure for production deployment.

Specifications

Electrical Measurements
  • Voltage: 80-260V AC
  • Current: 0-100A
  • Power: 0-23kW
  • Energy: 0-9999.9 kWh
  • Frequency: 45-65Hz
  • Power Factor: 0.0-1.0
Accuracy & Performance
  • Voltage Accuracy: ±0.5%
  • Current Accuracy: ±0.5%
  • Power Accuracy: ±0.5%
  • Energy Accuracy: ±0.5%
  • Sampling Rate: 1-2 seconds
  • Operating Temp: -20°C to 60°C

Pin Configuration

PZEM-004T v3.0 has 4 connection pins for communication:

PinNameFunctionESP32 Connection
15VPower supply (5V DC)5V or VIN pin
2RXReceive data (TTL 5V)GPIO 17 (TX2)
3TXTransmit data (TTL 5V)GPIO 16 (RX2)
4GNDGroundGND pin

Logic Level Note

PZEM uses 5V TTL logic while ESP32 uses 3.3V. However, ESP32 pins are 5V tolerant for input, so direct connection usually works. For production, consider using a logic level converter for better reliability.

High Voltage Wiring

PZEM has 4 screw terminals for AC power measurement:

TerminalLabelConnection
1L inLive/Phase input from mains
2N inNeutral input from mains
3L outLive/Phase output to load
4N outNeutral output to load

Wiring Sequence

  1. Disconnect all AC power sources
  2. Connect L in and N in to mains power
  3. Connect L out and N out to your load (appliance)
  4. Current flows through L in → L out (measured by internal CT)
  5. Double-check all connections before powering on

Arduino Library Installation

1. Install PZEM004Tv30 Library

Open Arduino IDE → Sketch → Include Library → Manage Libraries → Search "PZEM004Tv30"

Library Managercpp
// Or install via Library Manager // Search: PZEM-004T-v30 // Author: Jakub Mandula

2. Include in Your Code

include_pzem.inocpp
#include <PZEM004Tv30.h>

// Initialize PZEM on Serial2 (GPIO 16/17)
PZEM004Tv30 pzem(Serial2, 16, 17); // RX, TX

Basic Reading Code

pzem_basic_read.inocpp
#include <PZEM004Tv30.h>

// Initialize PZEM on Serial2
// RX (GPIO 16), TX (GPIO 17)
PZEM004Tv30 pzem(Serial2, 16, 17);

void setup() {
  Serial.begin(115200);
  Serial.println("PZEM-004T Test");
  delay(1000);
}

void loop() {
  // Read voltage
  float voltage = pzem.voltage();
  if (!isnan(voltage)) {
    Serial.print("Voltage: ");
    Serial.print(voltage);
    Serial.println(" V");
  } else {
    Serial.println("Error reading voltage");
  }
  
  // Read current
  float current = pzem.current();
  if (!isnan(current)) {
    Serial.print("Current: ");
    Serial.print(current);
    Serial.println(" A");
  }
  
  // Read power
  float power = pzem.power();
  if (!isnan(power)) {
    Serial.print("Power: ");
    Serial.print(power);
    Serial.println(" W");
  }
  
  // Read energy
  float energy = pzem.energy();
  if (!isnan(energy)) {
    Serial.print("Energy: ");
    Serial.print(energy, 3);
    Serial.println(" kWh");
  }
  
  // Read frequency
  float frequency = pzem.frequency();
  if (!isnan(frequency)) {
    Serial.print("Frequency: ");
    Serial.print(frequency, 1);
    Serial.println(" Hz");
  }
  
  // Read power factor
  float pf = pzem.pf();
  if (!isnan(pf)) {
    Serial.print("Power Factor: ");
    Serial.println(pf);
  }
  
  Serial.println("----------------------------");
  delay(2000);
}

Complete Integration with WiFi

gridova_pzem_complete.inocpp
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <PZEM004Tv30.h>

// WiFi credentials
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

// API endpoint
const char* serverUrl = "https://api.gridova.com/sensor-data";
const char* deviceId = "ROOM_001";

// Initialize PZEM
PZEM004Tv30 pzem(Serial2, 16, 17);

void setup() {
  Serial.begin(115200);
  
  // Connect to WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConnected to WiFi");
}

void loop() {
  // Read all sensor values
  float voltage = pzem.voltage();
  float current = pzem.current();
  float power = pzem.power();
  float energy = pzem.energy();
  float frequency = pzem.frequency();
  float pf = pzem.pf();
  
  // Check if readings are valid
  if (isnan(voltage)) {
    Serial.println("Error reading PZEM sensor");
    delay(5000);
    return;
  }
  
  // Create JSON payload
  StaticJsonDocument<512> doc;
  doc["device_id"] = deviceId;
  doc["timestamp"] = millis();
  
  JsonObject data = doc.createNestedObject("data");
  data["voltage"] = voltage;
  data["current"] = current;
  data["power"] = power;
  data["energy"] = energy;
  data["frequency"] = frequency;
  data["power_factor"] = pf;
  
  String jsonString;
  serializeJson(doc, jsonString);
  
  // Send to server
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin(serverUrl);
    http.addHeader("Content-Type", "application/json");
    
    int httpCode = http.POST(jsonString);
    
    if (httpCode > 0) {
      Serial.printf("Server response: %d\n", httpCode);
    } else {
      Serial.printf("Error: %s\n", http.errorToString(httpCode).c_str());
    }
    
    http.end();
  }
  
  // Display on Serial Monitor
  Serial.println("===== PZEM Readings =====");
  Serial.printf("Voltage: %.2f V\n", voltage);
  Serial.printf("Current: %.3f A\n", current);
  Serial.printf("Power: %.2f W\n", power);
  Serial.printf("Energy: %.3f kWh\n", energy);
  Serial.printf("Frequency: %.1f Hz\n", frequency);
  Serial.printf("Power Factor: %.2f\n", pf);
  Serial.println("========================\n");
  
  delay(5000); // Send every 5 seconds
}

Energy Reset Function

Reset accumulated energy counter (useful for monthly billing):

reset_energy.inocpp
void resetEnergy() {
  Serial.println("Resetting energy counter...");
  
  if (pzem.resetEnergy()) {
    Serial.println("Energy counter reset successfully");
  } else {
    Serial.println("Failed to reset energy counter");
  }
}

// Call this function when needed
// For example, at the start of each month
void loop() {
  // Your normal code here
  
  // Check if it's the 1st day of month
  // Reset energy counter
  // resetEnergy();
}

Calibration (Optional)

PZEM-004T v3.0 is pre-calibrated from factory. However, if you need to adjust:

Current Transformer (CT) Selection

Default CT is 100A. If using different CT ratio, you may need to adjust readings in software:

ct_adjustment.inocpp
// Adjust for different CT ratio
float adjustedCurrent = pzem.current() * (actual_CT_rating / 100.0);

// Example: If using 50A CT
float current = pzem.current() * 0.5;

Troubleshooting

NaN or Error Readings
  • Check UART wiring (RX/TX may be swapped)
  • Ensure 5V power supply is stable
  • Verify baud rate (default is 9600)
  • Try adding delay after initialization
  • Check if PZEM address is correct (default 0x01)
Incorrect Current Reading
  • Ensure current flows through L in → L out only
  • Neutral wire should NOT go through the module
  • Check CT is not damaged or saturated
  • Verify load is actually drawing current
Power Factor Always 1.0
  • Normal for resistive loads (heaters, incandescent bulbs)
  • Inductive loads (motors, transformers) show PF < 1.0
  • If always 1.0 with inductive load, check wiring
Communication Timeout
  • Add delay(1000) in setup() after Serial2.begin()
  • Increase reading interval to 2-3 seconds minimum
  • Check for electromagnetic interference near cables
  • Use shielded cables for long distance communication

Safety Guidelines

Electrical Safety

  • Always disconnect AC power before making any connections
  • Use proper wire gauge rated for your load current
  • Secure all terminals - loose connections can cause arcing
  • Install in proper enclosure - never leave terminals exposed
  • Add circuit breaker/fuse for overcurrent protection
  • Follow local electrical codes and regulations
  • Have installations inspected by certified electrician
  • Never work on live circuits unless absolutely necessary and qualified

Next Steps

Setup Relay Control
Add relay module to control power based on sensor readings
Complete Wiring Diagram
See how PZEM integrates with ESP32 and relay in full system
API Integration
Send sensor data to Gridova backend via REST API