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 mains voltage sensor with Arduino Uno — true RMS, safely

Measure 230 V mains with a ZMPT101B and an Arduino Uno R3 on A0: true-RMS sampling, one-number calibration and the electrician-only safety rules.

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

Community draft — report a mistake

Voltage in Indian homes often swings from 180 V to over 250 V, and fridges, ACs and pumps suffer at both ends. The ZMPT101B module has a small precision transformer and an op-amp. It turns the mains voltage into a small, isolated AC signal that an Uno can read safely — provided the mains side is wired and boxed properly.

On the Uno the low-voltage side is simple: 5V, GND and OUT to A0. At 5 V the output wave is centred at 2.5 V, right in the middle of the Uno’s ADC range. The L/N terminals go to the mains through a 250 mA fuse, inside a closed enclosure. That part is an electrician’s job.

The sketch samples A0 for 10 mains cycles and calculates the true RMS voltage. It flags LOW below 190 V and HIGH above 250 V, and shows NO SUPPLY during a power cut instead of a misleading low reading.

Wiring

Arduino Uno R3Only the pins used are shown · 5 V logic230 V AC via 250 mA fuse (electrician only)ZMPT101B AC voltage sensorLN5VGNDA0VCCOUTGNDLN
Also needed: Inline fuse holder with a 250 mA fuse, Closed plastic enclosure and a proper mains terminal block.
Every connection
Arduino Uno R3ZMPT101B AC voltage sensorWireNotes
5VVCCredAt 5 V the output swings around 2.5 V, centred in the Uno’s 0–5 V ADC range.
GNDGNDblack
A0OUTgreen
230 V AC via 250 mA fuse (electrician only) · LLbrownLive through an inline 250 mA fuse — electrician only.
230 V AC via 250 mA fuse (electrician only) · NNblueNeutral. The module’s transformer isolates this side from the Uno.

5 V (some boards 3.3 V) part, 5 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

  • Electrician only. The L/N screw terminals and the solder joints under them carry 230 V. Mount the module in a closed enclosure, feed it through a 250 mA fuse from a circuit protected by an MCB and RCCB, and never touch the board while it is plugged in. Test the Uno side on USB from a laptop on battery first.
  • The transformer isolates the Uno from the mains, but only when the module is wired as shown. Don’t connect the Uno’s GND to the mains neutral.
  • AC must be measured as RMS. The sketch samples for 200 ms (ten 50 Hz cycles), removes the DC centre and takes the square root of the variance — what a true-RMS meter shows.
  • Calibrate once against a true-RMS multimeter on the same socket: adjust VOLTS_PER_COUNT until both agree. The module’s blue trimmer also changes the gain — set it so the waveform is not clipped (check with the Serial Plotter), then leave it alone.
  • The Uno’s ADC is more linear than the ESP32’s, so a single calibration point usually stays within a few volts across 180–260 V. If you care most about low-voltage alarms, calibrate near 200 V.

Code

zmpt101b-uno.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// ZMPT101B AC voltage sensor on an Arduino Uno R3 - true-RMS mains voltage.
// Low-voltage side only: VCC → 5V, GND → GND, OUT → A0.
// L/N terminals: 230 V through a 250 mA fuse, in a closed enclosure - ELECTRICIAN ONLY.
// Calibrate VOLTS_PER_COUNT against a true-RMS multimeter on the same socket.
const uint8_t ZMPT_PIN = A0;
float VOLTS_PER_COUNT = 0.89;     // change until the reading matches your meter
const unsigned long WINDOW_MS = 200;  // 10 cycles of 50 Hz

void setup() {
  Serial.begin(9600);
  Serial.println(F("ZMPT101B on A0 - mains RMS every second"));
}

float readRmsCounts() {
  // One pass: running mean and variance (Welford), so the DC midpoint drops out by itself.
  unsigned long start = millis();
  unsigned int n = 0;
  float mean = 0, m2 = 0;
  while (millis() - start < WINDOW_MS) {  // ~1700 samples at the Uno's ~112 µs per analogRead
    float x = analogRead(ZMPT_PIN);
    n++;
    float d = x - mean;
    mean += d / n;
    m2 += d * (x - mean);
  }
  return n > 1 ? sqrt(m2 / n) : 0;
}

void loop() {
  float rmsCounts = readRmsCounts();
  float volts = rmsCounts * VOLTS_PER_COUNT;
  Serial.print(F("RMS counts "));
  Serial.print(rmsCounts, 1);
  Serial.print(F("  Mains "));
  if (volts < 20) {
    Serial.println(F("NO SUPPLY"));
  } else {
    Serial.print(volts, 0);
    Serial.print(F(" V"));
    if (volts < 190) Serial.println(F("  LOW"));
    else if (volts > 250) Serial.println(F("  HIGH"));
    else Serial.println();
  }
  delay(800);
}

Expected serial output

Serial Monitor · 9600Output
ZMPT101B on A0 - mains RMS every second
RMS counts 262.4  Mains 234 V
RMS counts 261.9  Mains 233 V
RMS counts 207.8  Mains 185 V  LOW

Common errors

Reads NO SUPPLY with mains connected

The fuse has blown, or the trimmer is turned to minimum gain. With power OFF, check the fuse; then, with the enclosure closed, adjust the trimmer through its access hole only.

Reading jumps by 10–20 V

The waveform is clipped (trimmer too high) or the Uno’s 5V is noisy. Lower the trimmer gain, recalibrate, and average more windows.

Correct at 230 V but wrong at low voltage

Recalibrate at the voltage you care about most, or do a two-point calibration (one low, one normal).

↑↓ to move · Enter to open