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.

ZMPT101B with ESP32 DevKit V1 — mains voltage on ADC1, safely

Read a ZMPT101B AC voltage sensor on an ESP32 DevKit V1: 3.3 V supply, OUT on ADC1 GPIO34, RMS over 10 cycles, calibration to a meter. Mains side is electrician-only.

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

Community draft — report a mistake

The ZMPT101B is a small voltage transformer with an op-amp that turns 230 V mains into a low-voltage sine wave an ESP32 can sample. It is the usual way to show mains voltage — for power-cut alerts, low-voltage warnings or stabiliser monitors.

On the ESP32 DevKit V1, power the module from 3V3 so its output stays inside the ADC range, and read it on GPIO34, an ADC1 pin that keeps working with Wi-Fi. The sketch computes an RMS value and scales it with a factor you get by comparing against a multimeter.

The mains side is electrician-only. You wire VCC, GND and OUT; the L/N terminals go in a closed box, fused and behind an MCB/RCCB, and are connected by a qualified electrician.

Wiring

ESP32 DevKit V1Only the pins used are shown · 3.3 V logicZMPT101B AC voltage sensorD34GND3V3VCCOUTGNDL → Mains live through a 0.5 A fuse — 230 V, electrician onlyN → Mains neutral — 230 V, electrician only
Also needed: 0.5 A fuse in an inline holder on the live wire, Closed plastic enclosure for the ZMPT101B, A trusted multimeter for calibration.
Every connection
ESP32 DevKit V1ZMPT101B AC voltage sensorWireNotes
—L—To Mains live through a 0.5 A fuse — 230 V, electrician only (not drawn)
—N—To Mains neutral — 230 V, electrician only (not drawn)
3V3VCCredFrom 3V3 the output stays centred near 1.65 V and never exceeds 3.3 V. If your module only works at 5 V, feed OUT through a 10 kΩ / 20 kΩ divider instead.
GNDGNDblack
D34OUTyellowGPIO34 is ADC1 and input-only — ideal for an analog sensor, and it keeps working if you add Wi-Fi.

5 V (some boards 3.3 V) part, 3.3 V board. OUT is an AC waveform centred on VCC/2. On ESP32/Pico power the module from 3.3 V if your board supports it, or divide OUT so it never exceeds 3.3 V.

Board quirks

  • The L and N terminals are at 230 V and the screw heads are exposed. Have an electrician wire them from a circuit with an MCB and RCCB, through a small fuse, with the module inside a closed plastic box. Never touch the board while it is plugged in, and never work on it with mains connected.
  • The module’s transformer isolates the low-voltage side, so VCC, GND and OUT are safe to wire on the bench — before the mains side is connected.
  • Use an ADC1 pin (D32, D33, D34, D35, VP, VN). The ADC2 pins (D4, D12–D15, D25–D27) stop reading as soon as Wi-Fi starts — a common surprise when the project later sends readings online.
  • The sketch uses analogReadMilliVolts(), which applies the ESP32’s factory ADC calibration. It removes the DC midpoint first and then takes the RMS over 200 ms (10 cycles at 50 Hz).
  • Turn the blue trimpot so the waveform is large but not clipped: about 1 V peak-to-peak on OUT is a good start. Then type cal while your meter reads the mains and copy the printed factor into the sketch.
  • Treat the result as an estimate (a few per cent after calibration). The ESP32 ADC is not linear near its ends and the reading shifts with the trimpot and temperature. For billing-grade numbers use a PZEM-004T.

Code

zmpt101b-esp32.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// ZMPT101B AC voltage sensor on an ESP32 DevKit V1 — RMS estimate of the 230 V / 50 Hz mains.
// Low-voltage side: VCC → 3V3, GND → GND, OUT → D34 (ADC1, input-only).
// The L/N screw terminals carry 230 V — electrician only, inside a closed box with a fuse.
// Readings are only as good as your calibration against a trusted multimeter.

constexpr uint8_t SENSE_PIN = 34;       // ADC1 → keeps working if you add Wi-Fi later
constexpr uint32_t WINDOW_MS = 200;     // 10 full cycles at 50 Hz
float CAL = 0.0f;                       // volts per mV-RMS; 0 = not calibrated yet
constexpr float MAINS_REF = 230.0f;     // what your multimeter reads while you calibrate

// RMS of the AC part of the signal, in millivolts at the ADC pin.
float acRmsMilliVolts() {
  // Pass 1: find the DC midpoint (about VCC/2) over the window.
  double sum = 0;
  uint32_t n = 0, t0 = millis();
  while (millis() - t0 < WINDOW_MS) {
    sum += analogReadMilliVolts(SENSE_PIN);
    n++;
  }
  const double mid = sum / n;
  // Pass 2: RMS of the deviation from that midpoint.
  double sq = 0;
  n = 0;
  t0 = millis();
  while (millis() - t0 < WINDOW_MS) {
    double d = analogReadMilliVolts(SENSE_PIN) - mid;
    sq += d * d;
    n++;
  }
  return sqrt(sq / n);
}

void setup() {
  Serial.begin(115200);
  analogSetPinAttenuation(SENSE_PIN, ADC_11db);  // full 0–3.1 V range
  Serial.println("ZMPT101B on GPIO34. Type cal while the meter shows 230 V to calibrate.");
}

void loop() {
  if (Serial.available()) {
    String cmd = Serial.readStringUntil('\n');
    cmd.trim();
    if (cmd == "cal") {
      CAL = MAINS_REF / acRmsMilliVolts();
      Serial.printf("CAL = %.4f — write it into the sketch\n", CAL);
    }
  }
  float mv = acRmsMilliVolts();
  if (mv < 5) Serial.println("No AC signal (mains off, or OUT not on GPIO34)");
  else if (CAL == 0) Serial.printf("Signal %.1f mV RMS (not calibrated)\n", mv);
  else Serial.printf("Mains ≈ %.0f V RMS  (signal %.1f mV)\n", mv * CAL, mv);
  delay(1000);
}

Expected serial output

Serial Monitor · 115200Output
ZMPT101B on GPIO34. Type cal while the meter shows 230 V to calibrate.
Signal 308.6 mV RMS (not calibrated)
CAL = 0.7453 — write it into the sketch
Mains ≈ 230 V RMS  (signal 308.6 mV)
Mains ≈ 226 V RMS  (signal 303.2 mV)

Common errors

“No AC signal” although mains is connected

OUT on the wrong pin, or the trimpot turned fully down. With mains off this message is expected. Don’t probe the mains side yourself — ask the electrician to check it.

Reading is far too high and flat-topped

The waveform is clipping at 0 or 3.3 V. Turn the trimpot back until the signal shrinks, then calibrate again.

Numbers jump by 10–20 V

Noise on a long OUT wire or a USB supply ripple. Keep OUT short, add 100 nF from OUT to GND, and average several readings.

↑↓ to move · Enter to open