Close Menu
  • Articles
    • Learn Electronics
    • Product Review
    • Tech Articles
  • Electronics Circuits
    • 555 Timer Projects
    • Op-Amp Circuits
    • Power Electronics
  • Microcontrollers
    • Arduino Projects
    • STM32 Projects
    • AMB82-Mini IoT AI Camera
    • BLE Projects
  • IoT Projects
    • ESP8266 Projects
    • ESP32 Projects
    • ESP32 MicroPython
    • ESP32-CAM Projects
    • LoRa/LoRaWAN Projects
  • Raspberry Pi
    • Raspberry Pi Projects
    • Raspberry Pi Pico Projects
    • Raspberry Pi Pico W Projects
  • Electronics Calculator
Facebook X (Twitter) Instagram
  • About Us
  • Disclaimer
  • Privacy Policy
  • Contact Us
  • Advertise With Us
Facebook X (Twitter) Instagram Pinterest YouTube LinkedIn
How To Electronics
  • Articles
    • Learn Electronics
    • Product Review
    • Tech Articles
  • Electronics Circuits
    • 555 Timer Projects
    • Op-Amp Circuits
    • Power Electronics
  • Microcontrollers
    • Arduino Projects
    • STM32 Projects
    • AMB82-Mini IoT AI Camera
    • BLE Projects
  • IoT Projects
    • ESP8266 Projects
    • ESP32 Projects
    • ESP32 MicroPython
    • ESP32-CAM Projects
    • LoRa/LoRaWAN Projects
  • Raspberry Pi
    • Raspberry Pi Projects
    • Raspberry Pi Pico Projects
    • Raspberry Pi Pico W Projects
  • Electronics Calculator
How To Electronics
Home » IoT AC Energy Meter with PZEM-004T & ESP32 WebServer
ESP32 Projects IoT Projects

IoT AC Energy Meter with PZEM-004T & ESP32 WebServer

Mamtaz AlamBy Mamtaz AlamUpdated:March 6, 20252 Comments9 Mins Read
Share Facebook Twitter LinkedIn Telegram Reddit WhatsApp
IoT AC Energy Meter with PZEM-004T & ESP32 WebServer
Share
Facebook Twitter LinkedIn Pinterest Email Reddit Telegram WhatsApp

Overview

In this project, we will create an IoT-based AC Energy Meter using the ESP32 microcontroller and the PZEM-004T module, a high-precision AC power monitoring solution. Unlike traditional Arduino-based setups with LCD displays, this project uses the ESP32’s Wi-Fi capabilities to host a local web server. The Webserver dynamically displays voltage, current, power, energy, frequency, and power factor on a responsive webpage. Data updates in real time without requiring manual page refreshes.

Earlier energy meter projects, such as those using the ZMPT101B voltage sensor and SCT-013 current sensor, are excellent for learning but lack precision. The PZEM-004T addresses this gap with industrial-grade accuracy.

You may take a look at the previous energy meter projects:

  • GSM-Based Prepaid Energy Meter
  • IoT DC Energy Meter using INA226 & ESP32
  • IoT AC Energy Meter with ESP32 & Blynk
  • Energy Meter using ESP32 & HMI Display

The PZEM-004T Multifunction AC Digital Meter communicates via Modbus-RTU over RS485, enabling reliable measurement of:

  • Voltage (V)
  • Current (A)
  • Active Power (W)
  • Energy (kWh)
  • Frequency (Hz)
  • Power Factor

In this project, the ESP32 reads data from the PZEM-004T using ModbusMaster library. The ESPAsyncWebServer and AsyncTCP libraries create a non-blocking web server. The webpage uses JavaScript to fetch live data from the ESP32 without reloading, ensuring smooth real-time visualization. By the end, you’ll have a robust IoT energy meter ready for home automation, industrial monitoring, or smart grid applications.


Bill of Materials

We need following components to build this IoT AC Energy Meter project. You can purchase all the components from the given links.

S.N.Components NameQuantityPurchase Link
1ESP32 Board1Amazon | AliExpress
2PZEM-004T AC Meter Module1Amazon | AliExpress
3Connecting Wires10Amazon | AliExpress
4Breadboard1Amazon | AliExpress




PZEM-004T Multifunction AC Digital Meter

The PZEM-004T is a compact, single-phase AC power monitoring module designed to measure electrical parameters such as voltage (80–260V), current (up to 100A via external CT), active power, energy consumption (kWh), frequency, and power factor.

PZEM-004T V3.0
Fig: PZEM-004T V3.0

It communicates via Modbus-RTU protocol over TTL serial (), making it easy to interface with microcontrollers like Arduino or ESP32. With built-in galvanic isolation and a non-invasive current transformer, it prioritizes safety. It is widely used in IoT applications, smart metering, and home automation projects.

PZEM-004T V3.0 Feature

  • Voltage: 80–260V, 0.1V resolution, 0.5% accuracy
  • Current: 0–10A (10A model), 0–100A (100A model), 0.001A resolution, 0.5% accuracy
  • Active Power: 0–2.3kW (10A model), 0–23kW (100A model), 0.1W resolution, 0.5% accuracy
  • Power Factor: 0.00–1.00, 0.01 resolution, 1% accuracy
  • Frequency: 45–65Hz, 0.1Hz resolution, 0.5% accuracy
  • Active Energy: 0–9999.99kWh, 1Wh resolution, 0.5% accuracy, resettable via software
  • Over Power Alarm: Settable threshold, triggers alarm on exceedance
  • Communication: RS485 (UART to RS485), 9600 baud, 8N1

Open CT & Close CT

Both Close CT and Open CT are 100A current transformers (Class 1.5 accuracy) compatible with the PZEM-004T module.

Fig: PZEM-004T Open CT & Close CT

The Closed Current Transformer (CT) version of the PZEM-004T comes with a built-in, non-detachable CT, ensuring accurate and stable measurements. It is ideal for fixed installations where the sensor remains permanently connected to the measured circuit.

The Open Current Transformer (CT) version features a detachable clamp-type CT, allowing easy installation without disconnecting wires. This is useful for retrofitting or temporary monitoring applications where quick and flexible deployment is required.



Pinout of PZEM-004T V3.0

The PZEM-004T is an energy monitoring module that communicates via UART (RS485) and has the following pin configuration:

Pinout of PZEM-004T V3.0

1. Power & Measurement Pins:

  • L (Live) & N (Neutral): Connect to AC mains for voltage measurement and module power.
  • CT+ & CT-: Connect to the current transformer (CT) for current measurement.

2. Communication Pins (TTL Serial or RS485):

  • 5V: Power supply for the module (external 5V required).
  • GND: Ground reference for communication.
  • TX (Transmit): Sends data to the microcontroller.
  • RX (Receive): Receives data from the microcontroller.

Module TTL Interface Note: This module’s TTL interface is passive and requires an external 5V power supply. All four pins (5V, RX, TX, GND) must be connected for proper communication. Operating temperature range: -20°C to +60°C.

Communication Protocol of PZEM-004T V3.0

1. Physical Layer Protocol

  • Uses UART to RS485 communication interface
  • Baud rate: 9600, 8 data bits, 1 stop bit, no parity

2. Application Layer Protocol

  • Uses Modbus-RTU protocol
  • Supported function codes:
    • 0x03 (Read Holding Register)
    • 0x04 (Read Input Register)
    • 0x06 (Write Single Register)
    • 0x41 (Calibration – internal use only, requires password 0x3721)
    • 0x42 (Reset Energy)

3. Addressing

  • Slave address range: 0x01 – 0xF7
  • 0x00: Broadcast address (slave does not reply)
  • 0xF8: General address (for single-slave environments and calibration)

4. Reading Measurement Results

  • Master command format (8 bytes):
    Slave Address + 0x04 + Register Address (High + Low) + No. of Registers (High + Low) + CRC (High + Low)
  • Correct Reply:
    Slave Address + 0x04 + No. of Bytes + Register Data + CRC
  • Error Reply:
    Slave Address + 0x84 + Error Code + CRC
    • 0x01: Illegal function
    • 0x02: Illegal address
    • 0x03: Illegal data
    • 0x04: Slave error

5. Register Mapping

Register Address Description Resolution
0x0000 Voltage 0.1V
0x0001-0x0002 Current (Low & High) 0.001A
0x0003-0x0004 Power (Low & High) 0.1W
0x0005-0x0006 Energy (Low & High) 1Wh
0x0007 Frequency 0.1Hz
0x0008 Power factor 0.01
0x0009 Alarm status (0xFFFF = Alarm, 0x0000 = No Alarm)

For example, to read 10 registers from slave address 0x01, the master sends:
0x01 + 0x04 + 0x00 + 0x00 + 0x00 + 0x0A + CRC



Indicator Lights of PZEM-004T V3.0

The module has multiple LEDs to indicate power, pulse, and communication status:

Indicator Lights of PZEM-004T V3.0
Fig: Indicator Lights of PZEM-004T V3.0
  • Power Indicator Light: Shows that the module is powered and operational.
  • Pulse Indicator Light: It blinks based on active energy measurement. The higher blinking rate indicates higher power consumption.
  • TX Communication Light: Blinks when the module transmits data via RS485.
  • RX Communication Light: Blinks when the module receives data from the master device (e.g., Arduino, ESP32).

Refer to PZEM-004T Datasheet for more information.


Interfacing PZEM-004T with ESP32 Microcontroller

Lets interface the PZEM-004T AC Energy Meter Module with ESP32 Microcontroller and read the energy meter data. For that, we will first connect the PZEM-004T with ESP32 and then write a C++ Code to fetch the PZEM-004T data.

Circuit Diagram & Connections

The following is the connection diagram between PZEM-004T & ESP32 which looks simple and straightforward.

PZEM-004T & ESP32 Connection
Fig: PZEM-004T & ESP32 Circuit & Connection

Connect the PZEM-004T’s 5V and GND to ESP32’s 5V and GND for power. Link TX (PZEM) → RX2 (ESP32 pin 16) and RX (PZEM) → TX (ESP32 pin 17) for serial communication.

Interfacing PZEM-004T with ESP32 Microcontroller
Fig: Interfacing PZEM-004T with ESP32

Connect the circuit on breadboard as per circuit diagram above.

Wire the live (L) and neutral (N) of your AC supply (120V/220V) to the PZEM’s AC input terminals (labeled “L” and “N”).

Fig: Current Transformer Connection

For Open CT (split-core): Clamp the CT around the live wire of the AC circuit you want to monitor (do NOT clamp neutral).
For Close CT (solid-core): Disconnect the circuit, thread the live wire through the CT’s core, and reconnect.

Caution: Isolate AC input (120/220V) wiring from Arduino circuits for safety.



Source Code/Program

Lets write a C++ Code to establish a Serial Communication between ESP32 & PZEM-004T Energy Meter Module. But before moving to the coding part, first install the PZEM-004T Arduino Library. The library is well written and does the Energy monitoring task using the ModBUS interface.

This code reads AC power parameters (voltage, current, power, energy, etc.) from the PZEM-004T sensor using an ESP32 via its Serial2 interface and prints the data to the Serial Monitor every 2 seconds. It includes error handling for failed sensor readings and allows optional energy counter resetting.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <PZEM004Tv30.h>
 
// Define the UART2 RX and TX pins on ESP32 (Connect these to PZEM-004T)
#define PZEM_RX_PIN 16  // ESP32 RX (Connect to PZEM TX)
#define PZEM_TX_PIN 17  // ESP32 TX (Connect to PZEM RX)
 
// Initialize the PZEM sensor using Hardware Serial2
PZEM004Tv30 pzem(Serial2, PZEM_RX_PIN, PZEM_TX_PIN);
 
void setup() {
    Serial.begin(115200);
    Serial.println("PZEM-004T V3.0 Power Meter - ESP32");
 
    // Uncomment to reset the energy counter
    // pzem.resetEnergy();
}
 
void loop() {
    Serial.print("Custom Address: ");
    Serial.println(pzem.readAddress(), HEX);
 
    // Read data from the PZEM sensor
    float voltage   = pzem.voltage();
    float current   = pzem.current();
    float power     = pzem.power();
    float energy    = pzem.energy();
    float frequency = pzem.frequency();
    float pf        = pzem.pf();
 
    // Original error handling (unchanged)
    if(isnan(voltage)){
        Serial.println("Error reading voltage");
    } else if (isnan(current)) {
        Serial.println("Error reading current");
    } else if (isnan(power)) {
        Serial.println("Error reading power");
    } else if (isnan(energy)) {
        Serial.println("Error reading energy");
    } else if (isnan(frequency)) {
        Serial.println("Error reading frequency");
    } else if (isnan(pf)) {
        Serial.println("Error reading power factor");
    } else {
        // Print values
        Serial.print("Voltage: ");      Serial.print(voltage);   Serial.println(" V");
        Serial.print("Current: ");      Serial.print(current);   Serial.println(" A");
        Serial.print("Power: ");        Serial.print(power);     Serial.println(" W");
        Serial.print("Energy: ");       Serial.print(energy, 3); Serial.println(" kWh");
        Serial.print("Frequency: ");    Serial.print(frequency); Serial.println(" Hz");
        Serial.print("Power Factor: "); Serial.println(pf);
    }
 
    Serial.println();
    delay(2000);  // Wait 2 seconds before next reading
}

Upload the above code to the ESP32 microcontroller and your device is ready for test.

Power on the entire device, load and PZEM-004T Module.

Energy Meter with PZEM-004T & ESP32
Fig: PZEM-004T & ESP32 Powered On

Once powering is done, open the Serial Monitor.

Fig: Serial Output PZEM-004T with ESP32

The Serial Monitor will display the value of AC voltage, Current, Power, Energy, Frequency and Power Factor.




IoT AC Energy Meter with PZEM-004T & ESP32 WebServer

The above code worked perfectly and gives the output as expected. Now we can use the data and upload it on Internet to visualize it locally or globally. In this way, we can create an IoT based AC Energy Meter with PZEM-004T & ESP32.

Source Code/Program

We can modify the above code and add HTML, CSS & JavaScript to create a beautiful, responsive and AJAX based webserver. The following code creates an IoT web-based AC energy meter using ESP32 and PZEM-004T, featuring:

Web Interface (HTML/CSS/JS)

  1. Responsive Dashboard: Uses CSS Grid/Flexbox for a card-based layout that adapts to screen sizes, with Font Awesome icons and color-coded metrics.
  2. Auto-Refresh UI: JavaScript fetches JSON data via XMLHttpRequest every 2 seconds from /data endpoint, updating values like voltage, current, and power without page reloads (Ajax).
  3. Dynamic Placeholders: HTML uses %VARIABLE% syntax (e.g., %VOLTAGE%) replaced by ESP32’s processor() function during initial page load.

Backend (ESP32)

  1. Async Web Server: Hosts a non-blocking server using ESPAsyncWebServer to handle both the dashboard page (/) and JSON API (/data).
  2. Sensor Integration: Reads PZEM-004T data (voltage, current, etc.) and stores it in global variables, which are atomically updated every 2 seconds.
  3. Error Handling: Returns “Error” in JSON/UI if sensor readings fail (isnan() checks).

Copy the following code and paste it on your Arduino IDE editor window.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#include <PZEM004Tv30.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
 
// WiFi credentials
const char* ssid = "*******************";
const char* password = "*******************";
 
// PZEM Serial pins
#define PZEM_RX_PIN 16
#define PZEM_TX_PIN 17
 
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
 
// Initialize PZEM sensor
PZEM004Tv30 pzem(Serial2, PZEM_RX_PIN, PZEM_TX_PIN);
 
// Global variables to store sensor data
float voltage = 0.0;
float current = 0.0;
float power = 0.0;
float energy = 0.0;
float frequency = 0.0;
float pf = 0.0;
 
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
  <title>ESP32 Power Monitor</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 20px;
      background-color: #f0f0f0;
    }
    .grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
      gap: 20px;
      max-width: 1200px;
      margin: 0 auto;
    }
    .card {
      background: white;
      border-radius: 15px;
      padding: 25px;
      box-shadow: 0 4px 8px rgba(0,0,0,0.1);
      display: flex;
      align-items: center;
      text-align: left;
    }
    .icon {
      font-size: 40px;
      margin-right: 25px;
      min-width: 50px;
      text-align: center;
    }
    .content {
      display: flex;
      flex-direction: column;
    }
    .label {
      font-size: 16px;
      color: #7f8c8d;
      margin-bottom: 5px;
      font-weight: bold;
    }
    .value {
      font-size: 24px;
      color: #2c3e50;
      display: flex;
      align-items: baseline;
    }
    .unit {
      font-size: 16px;
      color: #95a5a6;
      margin-left: 5px;
    }
    .fa-bolt { color: #f1c40f; }
    .fa-exchange-alt { color: #3498db; }
    .fa-plug { color: #e74c3c; }
    .fa-chart-line { color: #2ecc71; }
    .fa-wave-square { color: #9b59b6; }
    .fa-percent { color: #e67e22; }
    h1 {
      text-align: center;
      margin: 30px 0;
      color: #2c3e50;
    }
  </style>
  <script>
    function updateData() {
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          var data = JSON.parse(this.responseText);
          document.getElementById('voltage').innerHTML = data.voltage + '<span class="unit">V</span>';
          document.getElementById('current').innerHTML = data.current + '<span class="unit">A</span>';
          document.getElementById('power').innerHTML = data.power + '<span class="unit">W</span>';
          document.getElementById('energy').innerHTML = data.energy + '<span class="unit">kWh</span>';
          document.getElementById('frequency').innerHTML = data.frequency + '<span class="unit">Hz</span>';
          document.getElementById('pf').innerHTML = data.pf;
        }
      };
      xhttp.open("GET", "/data", true);
      xhttp.send();
    }
    setInterval(updateData, 2000);
    window.onload = updateData;
  </script>
</head>
<body>
  <h1><i class="fas fa-plug"></i> ESP32 Power Monitor</h1>
  <div class="grid">
    <div class="card">
      <i class="fas fa-bolt icon"></i>
      <div class="content">
        <div class="label">VOLTAGE</div>
        <div class="value" id="voltage">%VOLTAGE%<span class="unit">V</span></div>
      </div>
    </div>
    <div class="card">
      <i class="fas fa-exchange-alt icon"></i>
      <div class="content">
        <div class="label">CURRENT</div>
        <div class="value" id="current">%CURRENT%<span class="unit">A</span></div>
      </div>
    </div>
    <div class="card">
      <i class="fas fa-plug icon"></i>
      <div class="content">
        <div class="label">POWER</div>
        <div class="value" id="power">%POWER%<span class="unit">W</span></div>
      </div>
    </div>
    <div class="card">
      <i class="fas fa-chart-line icon"></i>
      <div class="content">
        <div class="label">ENERGY</div>
        <div class="value" id="energy">%ENERGY%<span class="unit">kWh</span></div>
      </div>
    </div>
    <div class="card">
      <i class="fas fa-wave-square icon"></i>
      <div class="content">
        <div class="label">FREQUENCY</div>
        <div class="value" id="frequency">%FREQUENCY%<span class="unit">Hz</span></div>
      </div>
    </div>
    <div class="card">
      <i class="fas fa-percent icon"></i>
      <div class="content">
        <div class="label">POWER FACTOR</div>
        <div class="value" id="pf">%PF%</div>
      </div>
    </div>
  </div>
</body>
</html>
)rawliteral";
 
String processor(const String& var) {
  if(var == "VOLTAGE") return isnan(voltage) ? "Error" : String(voltage, 1);
  else if(var == "CURRENT") return isnan(current) ? "Error" : String(current, 2);
  else if(var == "POWER") return isnan(power) ? "Error" : String(power, 1);
  else if(var == "ENERGY") return isnan(energy) ? "Error" : String(energy, 3);
  else if(var == "FREQUENCY") return isnan(frequency) ? "Error" : String(frequency, 1);
  else if(var == "PF") return isnan(pf) ? "Error" : String(pf, 2);
  return String();
}
 
void setup() {
  Serial.begin(115200);
  
  // Connect to WiFi
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConnected to WiFi");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
 
  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });
 
  // Route for JSON data
  server.on("/data", HTTP_GET, [](AsyncWebServerRequest *request){
    String json = "{";
    json += "\"voltage\":\"" + String(isnan(voltage) ? "Error" : String(voltage, 1)) + "\",";
    json += "\"current\":\"" + String(isnan(current) ? "Error" : String(current, 2)) + "\",";
    json += "\"power\":\"" + String(isnan(power) ? "Error" : String(power, 1)) + "\",";
    json += "\"energy\":\"" + String(isnan(energy) ? "Error" : String(energy, 3)) + "\",";
    json += "\"frequency\":\"" + String(isnan(frequency) ? "Error" : String(frequency, 1)) + "\",";
    json += "\"pf\":\"" + String(isnan(pf) ? "Error" : String(pf, 2)) + "\"";
    json += "}";
    request->send(200, "application/json", json);
  });
 
  // Start server
  server.begin();
}
 
void loop() {
  // Read all values first
  float v = pzem.voltage();
  float c = pzem.current();
  float p = pzem.power();
  float e = pzem.energy();
  float f = pzem.frequency();
  float pf_val = pzem.pf();
 
  // Update global variables atomically
  voltage = v;
  current = c;
  power = p;
  energy = e;
  frequency = f;
  pf = pf_val;
 
  // Serial output
  Serial.print("Voltage: "); Serial.print(voltage); Serial.println("V");
  Serial.print("Current: "); Serial.print(current); Serial.println("A");
  Serial.print("Power: "); Serial.print(power); Serial.println("W");
  Serial.print("Energy: "); Serial.print(energy,3); Serial.println("kWh");
  Serial.print("Frequency: "); Serial.print(frequency); Serial.println("Hz");
  Serial.print("PF: "); Serial.println(pf);
  Serial.println("-------------------");
 
  delay(2000);
}



From the above code, you need to change the Wi-Fi SSID and password. Replace it with your network credentials.

1
2
3
// WiFi credentials
const char* ssid = "*******************";
const char* password = "*******************";

Finally, after making the changes you can upload the code to the ESP32 microcontroller.

Testing the IoT Energy Meter

After core uploading is done, wire the PZEM-004T to the AC mains (e.g., a power strip or appliance) for live measurements. Now the system is ready for test.

Open the Arduino IDE Serial Monitor (115200 baud).

The ESP32 will try connecting to the WiFi network using the given credentials. If connection is successful, it will show WiFi connection success, and the IP address is printed.

Fig: ESP32 PZEM-004T WebServer IP Address

The Serial Monitor shows PZEM-004T data (voltage, current, power, energy, frequency, power factor) which is updated every 2 seconds. Ensure that No “Error” messages are in readings.

On any device (phone/PC), connect to the same WiFi network as the ESP32. Open a browser and enter the ESP32’s IP address (from Serial Monitor). From the computer dashboard, the web page appears as this:

Fig: Webpage showing energy meter data

You may open the same IP address link on your mobile phone. It will display the same energy meter parameters.

IoT AC Dimmer ESP32 PZEM-004T Webserver

The expected result is a polished dashboard with real-time AC parameters (e.g., Voltage: 230V, Current: 0.5A). The values auto-update every 2 seconds without page refresh (Ajax).

Fig: Energy Meter Parameters on AJAX-Based Webpage

You may run the system for 24+ hours to check stability and memory leaks. Also disconnect/reconnect WiFi to verify automatic reconnection. Try to test dashboard access from external networks.

Uncomment pzem.resetEnergy() in setup() to reset kWh counter.

If all steps work, your IoT energy meter is ready for deployment!

Share. Facebook Twitter Pinterest LinkedIn Tumblr Email Reddit Telegram WhatsApp
Previous ArticleDIY AC Energy Meter using PZEM-004T & Arduino
Next Article DIY Pedometer with ESP32 & BMI160 – Steps Counter

Related Posts

IoT Based PM & Air Quality Monitoring System using ESP32

IoT Based PM & Air Quality Monitoring System using ESP32

DIY ESP32 MLX90640 IR Thermal Camera with Live Web Display

DIY ESP32 MLX90640 IR Thermal Camera with Live Web Display

Updated:May 10, 20261K
IoT Activity Tracker with ESP32 & Accelerometer Gyroscope

IoT Activity Tracker with ESP32 & Accelerometer/Gyroscope

Updated:May 2, 2026

ESP32 IoT Vehicle Motion Analyzer with MPU6050 & LIS3MDL

Updated:April 27, 20261K
High-Accuracy Pitch, Roll, Yaw with ESP32 & BNO08x IMU

High-Accuracy Pitch, Roll, Yaw with ESP32 & BNO08x IMU

Updated:April 27, 20262K
DIY Colorimeter using AS7265x Spectroscopy Sensor & ESP32

DIY Colorimeter using AS7265x Spectroscopy Sensor & ESP32

Updated:February 1, 20261K
View 2 Comments

2 Comments

  1. Graham Dooley on March 11, 2025 4:27 PM

    It appears to me that the photograph of the PZEM etc has the live wire connected to the wrong terminal on the PZEM. Am I interpreting the picture correctly?

    Reply
    • Dave Grout on August 20, 2025 5:58 PM

      It’s AC mains. Makes no difference to the PZEM.

      Reply

CommentsCancel reply

Latest Posts
IoT Based PM & Air Quality Monitoring System using ESP32

IoT Based PM & Air Quality Monitoring System using ESP32

May 31, 2026
DIY ESP32 MLX90640 IR Thermal Camera with Live Web Display

DIY ESP32 MLX90640 IR Thermal Camera with Live Web Display

May 10, 2026
IoT Activity Tracker with ESP32 & Accelerometer Gyroscope

IoT Activity Tracker with ESP32 & Accelerometer/Gyroscope

May 2, 2026
A Guide to Sourcing Obsolete ICs for Vintage Projects

Beyond AliExpress: A Guide to Sourcing Obsolete ICs for Vintage Projects

April 21, 2026

ESP32 IoT Vehicle Motion Analyzer with MPU6050 & LIS3MDL

April 27, 2026
Building a Smart Sensor Node with a BLE Microcontroller

Building a Smart Sensor Node with a BLE Microcontroller

February 26, 2026
High-Accuracy Pitch, Roll, Yaw with ESP32 & BNO08x IMU

High-Accuracy Pitch, Roll, Yaw with ESP32 & BNO08x IMU

April 27, 2026
DIY Colorimeter using AS7265x Spectroscopy Sensor & ESP32

DIY Colorimeter using AS7265x Spectroscopy Sensor & ESP32

February 1, 2026
Top Posts & Pages
  • How to use INA219 DC Current Sensor Module with Arduino
    How to use INA219 DC Current Sensor Module with Arduino
  • 12V DC to 220V AC Inverter Circuit & PCB
    12V DC to 220V AC Inverter Circuit & PCB
  • Buck Converter: Basics, Working, Design & Application
    Buck Converter: Basics, Working, Design & Application
  • Designing of MPPT Solar Charge Controller using Arduino
    Designing of MPPT Solar Charge Controller using Arduino
  • How to use INA226 DC Current Sensor with Arduino
    How to use INA226 DC Current Sensor with Arduino
  • IoT AC Energy Meter with PZEM-004T & ESP32 WebServer
    IoT AC Energy Meter with PZEM-004T & ESP32 WebServer
  • ECG Graph Monitoring with AD8232 ECG Sensor & Arduino
    ECG Graph Monitoring with AD8232 ECG Sensor & Arduino
  • How to use Modbus RTU with ESP32 to read Sensor Data
    How to use Modbus RTU with ESP32 to read Sensor Data
Categories
  • Arduino Projects (197)
  • Articles (60)
    • Learn Electronics (19)
    • Product Review (15)
    • Tech Articles (28)
  • Electronics Circuits (46)
    • 555 Timer Projects (21)
    • Op-Amp Circuits (7)
    • Power Electronics (13)
  • IoT Projects (204)
    • ESP32 MicroPython (7)
    • ESP32 Projects (81)
    • ESP32-CAM Projects (15)
    • ESP8266 Projects (76)
    • LoRa/LoRaWAN Projects (22)
  • Microcontrollers (38)
    • AMB82-Mini IoT AI Camera (4)
    • BLE Projects (18)
    • STM32 Projects (19)
  • Raspberry Pi (93)
    • Raspberry Pi Pico Projects (57)
    • Raspberry Pi Pico W Projects (12)
    • Raspberry Pi Projects (24)
Follow Us
  • Facebook
  • Twitter
  • Pinterest
  • Instagram
  • YouTube
About Us

“‘How to Electronics’ is a vibrant community for electronics enthusiasts and professionals. We deliver latest insights in areas such as Embedded Systems, Power Electronics, AI, IoT, and Robotics. Our goal is to stimulate innovation and provide practical solutions for students, organizations, and industries. Join us to transform learning into a joyful journey of discovery and innovation.

Copyright © How To Electronics. All rights reserved.
  • About Us
  • Disclaimer
  • Privacy Policy
  • Contact Us
  • Advertise With Us

Type above and press Enter to search. Press Esc to cancel.

Ad Blocker Enabled!
Ad Blocker Enabled!
Looks like you're using an ad blocker. Please allow ads on our site. We rely on advertising to help fund our site.