Siddhant Kumar
Project 073 · Energy

Grid Power-Quality Logger.

Captures the voltage sags, swells, surges and disturbances that damage equipment and trip processes — timestamped and characterised — so a supply problem can finally be diagnosed and proven.

Advanced 14–20 hours 30 min read GridSensorsLogs
Jump to source Bill of materials
Grid Power-Quality Logger — reference build illustration MCU VCC · GND · SIG · NC
Difficulty
Advanced
Build time
14–20 hours
Indicative cost
₹2,800 – ₹4,500
Platform
ESP32 DevKit V1 (ESP-WROOM-32)
Category
Energy
Last updated
28 July 2026
Contents — 26 sections

Project Overview

Captures the voltage sags, swells, surges and disturbances that damage equipment and trip processes — timestamped and characterised — so a supply problem can finally be diagnosed and proven.

When equipment mysteriously resets, a process trips for no obvious reason, or electronics fail early, the cause is often the power quality — brief voltage sags when a big motor starts nearby, swells and surges, spikes from switching, distortion from non-linear loads — events too fast and transient for anyone to see on a normal meter, but more than enough to disrupt or damage equipment. And because they are invisible and intermittent, they are almost impossible to diagnose: the utility says the supply is fine, the equipment vendor blames the site, and the problem persists. This project builds a logger that catches these disturbances — measuring the voltage waveform fast enough to see them, characterising each event, and timestamping it — so a supply problem can be diagnosed and, crucially, proven.

It samples the mains voltage at a high rate (many samples per cycle) so it can compute the true RMS voltage cycle-by-cycle and detect deviations that a slow meter averages away. From the waveform it captures the classic power-quality events: sags (dips, the most common and disruptive — a brief drop when a large load starts), swells (temporary rises), surges/transients (fast spikes), interruptions, and frequency deviations, and it can measure harmonic distortion (THD) from non-linear loads. Each event is recorded with its timestamp, type, magnitude and duration — the characterisation that turns "the power is bad" into "a 30% sag lasting 80 ms occurred at 14:32", which is evidence.

That evidence is the point. A timestamped log of characterised events lets you correlate disturbances with equipment failures ("the machine trips whenever that sag occurs"), pin down the source (on-site vs the utility), and make a documented case to the utility or the equipment vendor. The logger trends event frequency, alarms on severe disturbances, and exports the record. It is honest that measuring mains is hazardous and that a DIY logger is not a calibrated, standards-compliant power-quality analyser (which classifies events per IEC 61000-4-30) — but as a high-rate voltage logger that captures and characterises the sags, swells and surges a normal meter cannot see, it turns an invisible, intermittent, un-diagnosable supply problem into a measured, timestamped, provable one.

An ESP32 development board with the ESP-WROOM-32 module and USB connector
Power-quality events are too fast for a normal meter — the logger samples fast enough to catch them. Photograph sourced from Wikimedia Commons — ESP32 Espressif ESP-WROOM-32 Dev Board.jpg. Reused under the licence stated on that page; please check it before republishing.

What this project does

  • Samples the mains voltage at high rate to see fast disturbances
  • Computes true RMS voltage cycle-by-cycle
  • Captures sags, swells, surges/transients, interruptions and frequency deviations
  • Measures harmonic distortion (THD) from non-linear loads
  • Characterises each event (type, magnitude, duration) with a timestamp
  • Correlates disturbances with equipment problems and trends them
  • Exports an evidence-grade log for utility/vendor disputes

Real-World Applications

SettingHow it is used
Diagnosing equipment resets/tripsCorrelating mysterious failures with voltage sags/surges to find the cause.
Supply-quality disputesDocumented, timestamped evidence for the utility or an equipment vendor.
Sensitive-load protectionMonitoring power quality where equipment is disturbance-sensitive.
Site power assessmentCharacterising a site's supply before installing sensitive equipment.

Deployment contexts where a build of this kind earns its keep.

Features & Capabilities

  • High-rate waveform capture (fast enough for transients)
  • Cycle-by-cycle true RMS
  • Sag/swell/surge/interruption/frequency detection
  • THD / harmonic measurement
  • Timestamped, characterised event log
  • Correlation and trending
  • Honest: not a calibrated IEC power-quality analyser

Difficulty, Time & Required Skills

AttributeValue
Difficulty levelAdvanced
Estimated completion time14–20 hours
Indicative build cost₹2,800 – ₹4,500
Primary disciplineEnergy
Reference platformESP32 DevKit V1 (ESP-WROOM-32)

Skills you should have (or will pick up)

  • High-rate mains-voltage sampling (safe, isolated)
  • Cycle-by-cycle RMS and event detection
  • Sag/swell/surge/THD characterisation
  • Timestamped event logging and correlation
  • Evidence export and interpretation

Bill of Materials

Every part below is commonly available from Indian and international hobby-electronics suppliers. Prices are indicative 2026 retail figures in Indian rupees and will drift — treat them as a budgeting guide, not a quotation.

ComponentKey specificationQtyApprox. cost
ESP32 DevKit V1 (ESP-WROOM-32)
Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly.
Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC1₹450
ZMPT101B AC voltage sensor
Trim the on-board pot so the idle output sits exactly at Vcc/2.
0–250 VAC input, 2 mA:2 mA precision transformer, ±1 % linearity1₹220
0.96″ SSD1306 OLED display
Static images burn in — invert or scroll the screen periodically.
128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C1₹250
microSD card 32 GB A1 class
For 24/7 loggers buy a high-endurance card — normal cards die in months.
A1 rated, 10 MB/s random write, UHS-I, endurance-grade recommended1₹450
DS3231 precision RTC + CR2032 backup
Vastly better than DS1307; some boards trickle-charge a non-rechargeable cell — cut that resistor.
±2 ppm (±1 min/year), temperature-compensated crystal, alarms, 32 kHz out1₹180
5 V 3 A regulated SMPS adapter
Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A.
100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection1₹350
Isolated voltage sensing
Isolation is safety-critical
ZMPT101b or isolated voltage transformer for safe mains-voltage measurement1₹400
High-rate ADC / front-endFast ADC front-end for many samples/cycle (transient capture)1₹500
Accurate time sourceRTC/GPS for precise event timestamps (correlation)1₹300
DIN enclosure + isolationSafe mains-side enclosure1₹500

Estimated total: ₹3,600, excluding tools, shipping and consumables.

Tools and consumables

  • Soldering iron (temperature controlled, 350 °C) with 0.8 mm 60/40 or lead-free solder
  • Digital multimeter — continuity, DC volts and current ranges
  • Wire strippers, flush cutters and a small set of precision screwdrivers
  • Heat-shrink tubing and a heat gun (or a lighter, carefully)
  • A laptop with a USB port and the toolchain listed above

Hardware Specifications

PartSpecificationSupplyInterfaceReference
ESP32 DevKit V1 (ESP-WROOM-32)Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC3.3 V logic / 5 V USBUART, SPI, I²C, I²S, CAN, PWMDatasheet
ZMPT101B AC voltage sensor0–250 VAC input, 2 mA:2 mA precision transformer, ±1 % linearity5 VAnalogueDatasheet
0.96″ SSD1306 OLED display128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C3.3–5 VI²C (0x3C)Datasheet
microSD card 32 GB A1 classA1 rated, 10 MB/s random write, UHS-I, endurance-grade recommended3.3 VSDIO / SPIDatasheet
DS3231 precision RTC + CR2032 backup±2 ppm (±1 min/year), temperature-compensated crystal, alarms, 32 kHz out2.3–5.5 VI²C (0x68)Datasheet
5 V 3 A regulated SMPS adapter100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection5 VDC barrel / USBDatasheet

Consolidated electrical and interface specifications for every active part in the build.

Power Budget & Supply Sizing

Add up the typical active current of every part, then size the supply with at least 50 % headroom so transmit bursts and motor inrush never brown out the controller.

LoadSupply railTypical current (mA)Notes
ESP32 DevKit V1 (ESP-WROOM-32)3.3 V logic / 5 V USB160Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly.
ZMPT101B AC voltage sensor5 V20Trim the on-board pot so the idle output sits exactly at Vcc/2.
0.96″ SSD1306 OLED display3.3–5 V20Static images burn in — invert or scroll the screen periodically.
microSD card 32 GB A1 class3.3 V100For 24/7 loggers buy a high-endurance card — normal cards die in months.
DS3231 precision RTC + CR2032 backup2.3–5.5 V0.2Vastly better than DS1307; some boards trickle-charge a non-rechargeable cell — cut that resistor.
5 V 3 A regulated SMPS adapter5 V3000Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A.

Summed typical draw is 3300.2 mA. With a 1.5× design margin the supply should deliver at least 5000 mA continuously at the stated rail voltage.

Software Requirements & Development Environment

Reference toolchain: Arduino IDE 2.3.x with the ESP32 board package 3.x (or PlatformIO on VS Code). Anything newer normally works; anything older may lack the board definitions used here.

  • Install the Arduino IDE 2.3.x (or PlatformIO if you prefer a real editor and dependency locking).
  • Add https://espressif.github.io/arduino-esp32/package_esp32_index.json under File → Preferences → Additional Board Manager URLs, then install esp32 from the Boards Manager.
  • Set the correct port under Tools → Port. On Linux add yourself to the dialout group: sudo usermod -aG dialout $USER and log out and back in.
  • Open the Serial Monitor at 115200 baud — every sketch here logs its state there.
  • Keep File → Preferences → Show verbose output during: compilation switched on while you are debugging build errors.

Required libraries

LibraryWhy it is neededInstall
WiFi (ESP32 core) bundledStation/AP connection management for the ESP32.Bundled with the ESP32 Arduino core
PubSubClient 2.8Lightweight MQTT 3.1.1 client for constrained devices.Library Manager → "PubSubClient" by Nick O'Leary
Adafruit SSD1306 + GFX 2.5.xFramebuffer and text/graphics primitives for the OLED.Library Manager → "Adafruit SSD1306"
NTPClient / configTime bundledWall-clock time from an NTP server for timestamping.Bundled (`configTime()` on ESP32)
SQLite 3.45+Zero-configuration embedded database for local logs.Bundled with Python (`import sqlite3`)
ArduinoJson 7.xZero-allocation JSON serialisation and parsing.Library Manager → "ArduinoJson" by Benoit Blanchon

Block Diagram

The block diagram shows the functional decomposition of the system — what senses, what decides, what acts, and where the data ends up.

Grid Power-Quality Logger — system block diagramFunctional block diagram of the Grid Power-Quality Logger system. CaptureVoltage waveformhigh-rateTimeRTC/GPSAnalyseESP32cycle RMSDetectsag/swell/surge/THDRecordEvent logtype/mag/dur/timeTrendfrequencyProveCorrelatewith failuresExportevidencerightrightnone
Grid Power-Quality Logger — system block diagram

Circuit Diagram & Wiring

Every signal line in the build is shown below, followed by a pin-by-pin connection table you can work through with a multimeter in hand.

Grid Power-Quality Logger — wiring schematicConnection schematic showing which controller pin drives each peripheral. Sensors / InputsControllerActuators / OutputsESP32 DevKit V1(ESP-WROOM-32)3.3 V logic / 5 V USBIsolated V senseGPIO 34 (ADC)Mains voltagewaveformDS3231 RTC/GPSGPIO 21/22Event timestampsOLEDGPIO 21/22RMS/event displaymicroSDGPIO 18/19/23/5Event log / waveformWi-FiDashboard/alertsIsolated supply3V3 regPower
Grid Power-Quality Logger — wiring schematic
PeripheralPeripheral pinController pinSignal
Isolated V senseAOUTGPIO 34 (ADC)Mains voltage waveform
DS3231 RTC/GPSSDA/SCLGPIO 21/22Event timestamps
OLEDSDA/SCLGPIO 21/22RMS/event display
microSDSPIGPIO 18/19/23/5Event log / waveform
Wi-Fion-chipDashboard/alerts
Isolated supply+/–3V3 regPower

Wire one row at a time and tick it off — most "it does not work" reports trace back to a single swapped pair.

Wiring explanation

  • Use isolated voltage sensing (ZMPT101b/isolated transformer) — measuring mains directly is dangerous; have a qualified person make the mains-side connection.
  • Sample many times per cycle (e.g. 32–128 samples/cycle at 50/60 Hz) so transients and sub-cycle events are captured, not averaged away.
  • Give the logger an accurate time source (RTC/GPS) for precise, correlatable event timestamps.
  • Log events (and optionally waveform snippets) to local storage; keep an off-device copy for evidence.
  • Keep the low-voltage electronics isolated from the mains sensing.
A Grafana time-series dashboard
ESP32 module computing cycle-by-cycle RMS and characterising sags, swells and surges. Photograph sourced from Wikimedia Commons — Grafana dashboard.png. Reused under the licence stated on that page; please check it before republishing.

System Architecture

Read the stack from the bottom up: physical hardware, the firmware that drives it, the transport that moves data off the device, and the software a human actually looks at.

Grid Power-Quality Logger — architecture stackLayered architecture from hardware to user interface. Hardware layerESP32 DevKit V1 (ESP-WROOM-32) · ZMPT101B AC voltage sensorDriver layerwifi · pubsub · ssd1306 · ntpApplication logicsampling loop · filtering · thresholds · state machineTransport layerWi-Fi + MQTT → power-quality dashboard · TLS · retry and backoffPresentation layerdashboard · mobile notifications · historical charts
Grid Power-Quality Logger — architecture stack

Working Principle

Power-quality problems are hard precisely because they are fast, transient and intermittent — a voltage sag when a nearby motor starts might last only a few cycles (tens of milliseconds), a surge a fraction of a cycle — and a normal meter, which reports a slow average, simply cannot see them: it smooths the disturbance into a number that looks fine. Yet these brief events are more than enough to reset a controller, trip a drive, corrupt data, or, over time, degrade equipment. So the whole approach hinges on measuring fast enough to see what a meter misses, and then turning each fleeting event into a permanent, characterised record.

Seeing the events requires high-rate waveform sampling — many samples per mains cycle — from which the logger computes the true RMS voltage cycle by cycle. This cycle-resolved RMS is the key measurement: it reveals a sag as a run of cycles where the RMS drops below normal, a swell as a run above, an interruption as RMS collapsing, all with the timing a slow average destroys. On top of RMS, the raw samples let the logger catch faster transients/surges (a spike within a cycle) and compute harmonic distortion (THD) — the waveform distortion caused by non-linear loads (drives, power supplies) that stresses equipment and indicates supply or load problems. The single design decision that makes everything possible is sampling density; everything else is analysis on top of a fast, faithful capture of the waveform.

The value comes from characterisation and timestamping, because a raw waveform is not actionable but a characterised event is. Each disturbance is classified by type (sag, swell, surge, interruption, frequency deviation, high THD), and recorded with its magnitude (how far the voltage deviated), duration (how long), and an accurate timestamp. This transforms a vague complaint into a precise fact: not "the power is bad" but "a sag to 70% of nominal lasting 80 ms occurred at 14:32:07". A log of such facts is evidence — the currency of any power-quality investigation.

That evidence enables the two things that actually solve power-quality problems: correlation and attribution. Correlation matches disturbances against symptoms — if the machine trips at 14:32 and the logger recorded a deep sag at 14:32, you have found your culprit and can stop guessing. Attribution helps locate the source: a sag that coincides with an on-site load starting points inward (fix your own installation or supply capacity), while disturbances arriving from the incoming supply point to the utility — and a timestamped record is what lets you make a documented, defensible case to the utility or an equipment vendor rather than a losing argument of assertions. The design is honest about its limits: mains measurement is genuinely hazardous and must be done safely and isolated, and a homebrew logger is not a calibrated, standards-compliant power-quality analyser (the ones that classify events strictly per IEC 61000-4-30 for formal disputes). But as an instrument that captures, characterises and timestamps the sags, swells and surges a normal meter cannot see, it does the essential thing: it makes an invisible, intermittent, previously un-diagnosable supply problem visible, measured and provable.

The maths behind it

Cycle-by-cycle true RMS

plainCycle-by-cycle true RMS
From N samples v[n] over one mains cycle:

  V_rms = sqrt( (1/N) Σ v[n]^2 )

Compute per cycle (needs many samples/cycle). A slow meter
averages over seconds and hides sub-second events.

Sag / swell / interruption

plainSag / swell / interruption
Relative to nominal V_nom:

  sag        : 0.1·V_nom ≤ V_rms < 0.9·V_nom
  swell      : V_rms > 1.1·V_nom
  interruption: V_rms < 0.1·V_nom

Record each event's magnitude (% of nominal) and duration
(number of affected cycles → time).

Harmonic distortion (THD)

plainHarmonic distortion (THD)
From the FFT of the voltage waveform:

  THD = sqrt(Σ_{h≥2} V_h^2) / V_1

V_1 = fundamental (50/60 Hz), V_h = harmonic amplitudes.
High THD = waveform distortion from non-linear loads.

Program Flowchart

The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.

Grid Power-Quality Logger — firmware flowchartControl flow through the main program loop. Sample waveform (high-rate)Compute cycle RMS + frequencyRMS out of band /transient / high THD?Characterise + timestamp eventContinueCharacterise + timestamp eventContinueLog; trend; alarm on severeCorrelate/export
Grid Power-Quality Logger — firmware flowchart

Assembly Instructions

Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.

  1. Set up isolated high-rate voltage sensing

    Use isolated voltage sensing and a fast ADC front-end to sample the mains waveform many times per cycle, with the mains-side connection made by a qualified person and the electronics isolated.

    Add an accurate time source (RTC/GPS) for event timestamps.

  2. Set up detection and logging

    Compute cycle RMS, frequency and THD, detect and characterise events, and log them (with optional waveform snippets) locally and off-device.

  3. Set up correlation and export

    Provide correlation/trending and an evidence export, and alarms on severe disturbances.

Step-by-Step Implementation Guide

Work through these in order. Each step ends in something you can observe, so a failure is always localised to the step you just finished.

  1. Compute cycle RMS and detect events

    Compute true RMS per cycle, compare to nominal for sags/swells/interruptions, detect transients and high THD, and characterise each with type/magnitude/duration/timestamp.

    cpppq-detect.ino
    #define V_NOM 230.0f
    #define SAMPLES_PER_CYCLE 64
    
    float cycleRMS(const float *v, int n){
      double ss=0; for(int i=0;i<n;i++) ss += (double)v[i]*v[i];
      return sqrtf(ss/n);
    }
    
    struct Event { const char* type; float magPct; };
    
    Event classify(float vrms){
      float pct = vrms / V_NOM;
      if (pct < 0.10f) return {"interruption", pct*100};
      if (pct < 0.90f) return {"sag", pct*100};          // most common/disruptive
      if (pct > 1.10f) return {"swell", pct*100};
      return {nullptr, 100};                              // normal
    }
    
    // Track an ongoing event to record its duration.
    struct EvState { bool active=false; const char* type=nullptr;
                     uint32_t startCycle=0; float peakPct=100; } ev;
    
    void onCycle(float vrms, uint32_t cycle, DateTime t){
      Event e = classify(vrms);
      if (e.type){
        if (!ev.active){ ev.active=true; ev.type=e.type; ev.startCycle=cycle; ev.peakPct=e.magPct; }
        if (fabsf(e.magPct-100) > fabsf(ev.peakPct-100)) ev.peakPct=e.magPct;
      } else if (ev.active){                              // event ended
        uint32_t cycles = cycle - ev.startCycle;
        logEvent(ev.type, ev.peakPct, cycles, t);         // type/mag/duration/time
        ev.active=false;
      }
    }
    float cycleRMS(const float *v, int n)Computes the true RMS of each mains cycle from many samples — the cycle-resolved measurement that reveals sub-second events a slow meter hides.
    if (pct < 0.90f) return {"sag", pct*100}A cycle RMS below 90% of nominal is a sag — the most common and disruptive disturbance — classified with its magnitude as a percentage of nominal.
    if (!ev.active){ ev.active=true; ev.type=e.type;An event is tracked from its first affected cycle so its duration and peak magnitude can be recorded, not just that it happened.
    logEvent(ev.type, ev.peakPct, cycles, t)When the event ends it is logged with type, peak magnitude, duration (in cycles → time) and timestamp — the characterisation that makes it evidence.
  2. Log, correlate and export

    Log characterised events with timestamps, compute THD, trend event frequency, alarm on severe disturbances, and export an evidence record for correlation with failures and for the utility/vendor.

Complete Source Code

The listing below is complete and compiles as written — there are no elided sections. Read the annotations under each block before you upload it.

cppgrid-power-quality-logger.ino
/* ═══════════════════════════════════════════════════════════════
   Grid Power-Quality Logger — ESP32 (isolated, high-rate)

   Samples the mains voltage many times per cycle, computes cycle RMS,
   frequency and THD, and captures/characterises sags, swells, surges,
   interruptions with timestamps — evidence for supply diagnosis.
   Mains measurement is hazardous; a DIY logger is indicative, not a
   calibrated IEC 61000-4-30 analyser.
   ══════════════════════════════════════════════════════════════════ */

#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <RTClib.h>
#include <math.h>

#define PIN_V     34
#define V_NOM     230.0f
#define SPC       64            // samples per cycle
#define MAINS_HZ  50

RTC_DS3231 rtc; WiFiClient net; PubSubClient mqtt(net);
float VCAL;                     // ADC->volts calibration
struct EvState { bool active=false; const char* type=nullptr;
                 uint32_t startMs=0; float peakPct=100; } ev;

float sampleCycleRMS(){
  const uint32_t period_us = 1000000UL/(MAINS_HZ*SPC);
  double ss=0; uint32_t next=micros();
  for(int i=0;i<SPC;i++){
    while((int32_t)(micros()-next)<0){} next+=period_us;
    float v = (analogRead(PIN_V) - 2048)/2048.0f * VCAL;   // centred, scaled
    ss += (double)v*v;
  }
  return sqrtf(ss/SPC);
}

const char* classify(float vrms, float &pct){
  pct = vrms/V_NOM*100;
  if (pct < 10) return "interruption";
  if (pct < 90) return "sag";
  if (pct > 110) return "swell";
  return nullptr;
}

void setup(){
  Serial.begin(115200);
  analogSetPinAttenuation(PIN_V, ADC_11db);
  Wire.begin(21,22); rtc.begin();
  WiFi.begin(WIFI_SSID,WIFI_PASS); mqtt.setServer(MQTT_HOST,1883);
}

void loop(){
  if(!mqtt.connected()&&WiFi.status()==WL_CONNECTED) mqtt.connect("pq-1");
  mqtt.loop();

  float vrms = sampleCycleRMS();          // one mains cycle
  uint32_t now = millis();
  float pct; const char* type = classify(vrms, pct);

  if (type){
    if (!ev.active){ ev.active=true; ev.type=type; ev.startMs=now; ev.peakPct=pct; }
    if (fabsf(pct-100) > fabsf(ev.peakPct-100)) ev.peakPct=pct;
  } else if (ev.active){                    // event ended -> record it
    uint32_t dur = now - ev.startMs;
    DateTime t = rtc.now();
    char m[200];
    snprintf(m,sizeof m,
      "{\"type\":\"%s\",\"mag_pct\":%.0f,\"dur_ms\":%lu,"
      "\"time\":\"%04d-%02d-%02d %02d:%02d:%02d\"}",
      ev.type, ev.peakPct, (unsigned long)dur,
      t.year(),t.month(),t.day(),t.hour(),t.minute(),t.second());
    logLocal(m);                            // evidence log (local + mirror)
    mqtt.publish("pq/1/event", m);
    if (ev.peakPct < 80 || ev.peakPct > 115) mqtt.publish("pq/1/alarm", m);
    ev.active=false;
  }

  // periodic RMS/THD status
  static uint32_t last=0;
  if (now-last > 1000){ last=now;
    char s[120]; snprintf(s,sizeof s,"{\"vrms\":%.1f}", vrms);
    mqtt.publish("pq/1/status", s);
  }
}
float sampleCycleRMS()Samples one full mains cycle at 64 points per cycle and computes true RMS — fast enough to catch sub-second disturbances a normal meter averages away.
const char* classify(float vrms, float &pct)Classifies the cycle as an interruption, sag or swell by comparing its RMS to nominal, capturing the event's magnitude as a percentage.
if (!ev.active){ ev.active=true; ev.type=type; ev.startMs=now;An event is tracked from its onset so its duration and peak magnitude are recorded — the characterisation that makes it usable evidence.
logLocal(m); // evidence log (local + mirror)Each characterised, timestamped event is logged locally and mirrored — a permanent record for correlation and dispute.
if (ev.peakPct < 80 || ev.peakPct > 115)Severe disturbances raise an immediate alarm, while all events are logged for trending and correlation.

Configuration & Calibration

Configuration steps

  • Set the nominal voltage, samples-per-cycle and event thresholds (sag/swell/interruption/THD).
  • Calibrate the voltage scaling and configure the time source for accurate timestamps.
  • Configure local + off-device logging and waveform-snippet capture.
  • Set severe-disturbance alarm thresholds.

Calibration procedure

An uncalibrated sensor produces confident, precise, wrong numbers. Do this once per physical unit and record the constants.

  1. Voltage scaling

    Calibrate the ADC-to-volts scaling against a reference so RMS and event magnitudes are accurate.

  2. Sampling

    Confirm the samples-per-cycle rate is steady and sufficient to capture transients; verify RMS matches a reference under steady voltage.

  3. Time

    Verify the RTC/GPS timestamps are accurate for correlation.

Network Architecture & Connectivity

Grid Power-Quality Logger — network topologyPath taken by telemetry from field node to end user. Edge nodesGatewayCloudClientsPQ loggerESP32Other pointsper-locationWi-Fi 2.4 GHzRouterto serverMQTT 1883PQ dashboardevents + trendsDashboardevents/RMSEngineeralerts/export
Grid Power-Quality Logger — network topology

Communication protocol

RMS/THD status publishes periodically; characterised events and severe-disturbance alarms publish immediately. The local log is the evidence record, mirrored off-device.

Topic / endpointDirectionPayload
pq/1/eventnode → dashboardtype, magnitude, duration, timestamp
pq/1/alarmnode → engineersevere disturbance
pq/1/statusnode → dashboardRMS, frequency, THD

Message contract between the device and the broker.

Cloud platform configuration

A dashboard shows RMS/THD and an event timeline, trends event frequency, and exports the record for correlation with failures and for utility/vendor disputes.

Dashboard setup

Live RMS/frequency/THD, an event timeline with magnitude/duration, trend of event frequency, and export.

Mobile app integration

Alerts on severe disturbances; daily disturbance summaries.

Security considerations

  • Keep the local evidence log authoritative and mirrored; timestamp accurately.
  • Authenticate nodes; secure the data.
  • Note a calibrated, standards-compliant analyser may be required for formal disputes.

Testing Procedure & Expected Output

Test from the bottom up. Confirm power, then each sensor in isolation, then the integrated loop — the first failing step tells you exactly where to look.

TestWhat you should see
Steady nominal voltageAccurate RMS; no events
Induce a sag (start a big load)Sag captured with magnitude, duration, timestamp
Induce a swell/surgeSwell/transient captured and characterised
Add a non-linear loadTHD rises; measured
Correlate an event with a tripTimestamps match — cause identified
Export the logTimestamped, characterised evidence record

Bench-test checklist. If a row fails, stop and fix it before moving on.

Expected output

The dashboard shows live RMS/frequency/THD and a timeline of characterised events (type/magnitude/duration/time) with alarms and export.

jsonpq-event.json
{
  "type": "sag",
  "mag_pct": 71,
  "dur_ms": 82,
  "time": "2026-07-27 14:32:07"
}

A sag to 71% of nominal lasting 82 ms at 14:32:07 — a characterised, timestamped event that a normal meter would never have shown, and exactly the evidence needed to correlate with an equipment trip and take to the utility.

A city skyline at night
A timestamped event log turns an invisible supply problem into provable evidence. Photograph sourced from Wikimedia Commons — Smart city.jpg. Reused under the licence stated on that page; please check it before republishing.

Troubleshooting: Common Errors & Fixes

Events not captured

Likely cause. Sampling too slow (averaging)

Fix. Sample many times per cycle; compute cycle-by-cycle RMS

Magnitudes wrong

Likely cause. Voltage scaling uncalibrated

Fix. Calibrate ADC-to-volts against a reference

Timestamps unreliable

Likely cause. No accurate time source

Fix. Use RTC/GPS; correlation depends on accurate time

Can't prove to the utility

Likely cause. Uncharacterised or non-standard log

Fix. Characterise events (type/mag/dur/time); note a calibrated IEC analyser may be needed for formal disputes

Safety concern

Likely cause. Direct mains measurement

Fix. Use isolated sensing; qualified person for mains connection

The sketch will not upload — "Failed to connect" or "avrdude: stk500_recv()"

Likely cause. The bootloader is not being reached: wrong port, wrong board, a serial monitor holding the port open, or a USB cable that only carries power.

Fix. Close every serial monitor, confirm Tools → Board and Port, and swap to a known data-capable USB cable. On an ESP32 hold BOOT while the IDE prints "Connecting…", then release. If a peripheral is wired to the UART pins (GPIO 1/3 on ESP32, D0/D1 on Uno) unplug it — it fights the programmer.

The board resets in a loop, or the serial monitor prints "Brownout detector was triggered"

Likely cause. The supply cannot deliver peak current. Wi-Fi transmit bursts, relay coils and servos all pull far more than their average draw.

Fix. Power peripherals from a separate regulated supply with a common ground rather than from the board 5 V pin. Add a 470–1000 µF electrolytic capacitor across the supply near the load, and use a real power adapter rather than a laptop USB port.

Serial monitor shows garbage characters

Likely cause. Baud rate mismatch between Serial.begin() and the monitor, or a floating/shared UART line.

Fix. Set the monitor to 115200 to match the sketch. If it still garbles, the crystal or the USB bridge is being confused by noise — shorten the cable and keep motor wiring away from the USB lead.

An I²C device is not detected

Likely cause. Wrong address, missing pull-ups, swapped SDA/SCL, or a bus too long for the pull-up value.

Fix. Run an I²C scanner sketch first — it should print the device address. Most breakout boards include 4.7 kΩ pull-ups, but if you have chained four of them the parallel resistance is too low; remove the pull-ups from all but one board. Keep the bus under 30 cm at 100 kHz.

Wi-Fi connects but MQTT never does (state -2)

Likely cause. Wrong broker address or port, a firewall in the way, or the broker requiring credentials the sketch is not sending.

Fix. Test from a laptop on the same network first: mosquitto_sub -h <broker> -t "#" -v. If that works, the problem is on the device — check the IP literal, port 1883 (or 8883 for TLS), and that client.setServer() runs before connect(). PubSubClient state codes are documented in its header.

Readings arrive for a while and then stop

Likely cause. The Wi-Fi or MQTT session dropped and the sketch never reconnects, or the broker dropped the client on keep-alive timeout.

Fix. Never assume the link stays up. Check WiFi.status() and client.connected() at the top of every loop and reconnect with exponential backoff. Add a watchdog so a wedged network stack reboots the device instead of going silent.

Performance Optimisation

  • Sample many times per cycle at a steady rate — this determines what you can see.
  • Compute cycle RMS and event detection efficiently to keep up with the sampling.
  • Log events (and snippets) locally and mirror; alarm on severe events.
  • Trend event frequency for correlation and reporting.
  • Replace every delay() with a millis() comparison — blocking delays are the single most common cause of dropped readings.
  • Sample sensors on a fixed cadence and publish on a slower one; you almost never need to transmit at the sampling rate.
  • Move networking into its own FreeRTOS task so a slow DNS lookup cannot stall the control loop.
  • Use uint8_t / uint16_t where the range allows; on an 8-bit AVR a 32-bit add costs four times as much.
  • Batch several samples into one MQTT publish. Radio time, not CPU time, dominates the energy budget.
  • Set the MQTT keep-alive to a value that matches your reporting interval so the broker does not churn reconnections.
  • For battery builds use deep sleep between samples: an ESP32 drops from ~160 mA awake to about 10 µA asleep, which is the difference between days and months of runtime.

Safety Precautions

  • Measuring mains is dangerous — use isolated sensing and a qualified person for the mains-side connection.
  • Keep the low-voltage electronics isolated from the mains sensing.
  • A DIY logger is indicative, not a calibrated, standards-compliant (IEC 61000-4-30) power-quality analyser; formal disputes may need certified equipment.
  • Investigate/act on power-quality findings with appropriate electrical expertise.
  • Mains voltage kills. Anything on the load side of the relay is at 230 V. Do not work on a powered circuit, and never leave exposed mains wiring on a bench where someone could touch it.
  • Keep at least 6 mm of creepage between the mains and low-voltage sides of any board you make, and never route mains tracks under the microcontroller.
  • Have a qualified electrician do the final installation into a consumer unit or wall fitting. In most jurisdictions this is a legal requirement, not a suggestion.
  • Fit an RCD/RCBO upstream and fuse the load appropriately for its rating.
  • Wear eye protection when soldering or cutting, and solder in a ventilated space — rosin flux fumes are a respiratory irritant.
  • Power the circuit through a bench supply with a current limit while you are testing. A 300 mA limit turns a wiring mistake into a beep instead of a dead board.
  • Disconnect power before changing any wiring. Hot-plugging a sensor onto a live bus is the fastest way to lose a controller.

Maintenance

  • Verify voltage calibration and timestamp accuracy periodically.
  • Check the log and off-device mirror; export/archive evidence.
  • Confirm sampling rate/integrity after any change.
  • Correlate events with equipment issues and act.
  • Re-check every screw terminal and header after the first week — thermal cycling loosens connections that felt tight on day one.
  • Rotate the microSD card annually and keep an image of the working system. Cards used as loggers wear out silently.
  • Keep the broker and dashboard containers patched, and rotate device credentials at least once a year.
  • Recalibrate at the interval given in the calibration section, and keep the constants in a text file next to the firmware — not only in flash.
  • Keep a short logbook of firmware versions and what changed. Six months later you will not remember why that constant is 1.083.

Future Improvements & Upgrades

A working v1 is a platform, not a finish line. These are the upgrades that add the most capability for the least rework.

  • Add current channels for full power-quality (flicker, unbalance, power).
  • Add standards-aligned event classification and reporting.
  • Add waveform capture/streaming for detailed analysis.
  • Correlate multiple loggers to locate disturbance sources.
  • Design a proper PCB. Once the breadboard version has run for a month, moving to a two-layer board removes the intermittent-contact failures that dominate prototype faults.
  • Add over-the-air firmware updates so you never have to physically reach a deployed node again.
  • Add persistent local storage (microSD or the on-chip flash) so a network outage does not create a hole in your data.
  • Move configuration out of the source: a captive-portal setup page or a JSON config file makes the build reusable without a recompile.
  • Add a battery and solar option so the unit survives a power cut and can be sited away from a socket.
  • Write a small test harness that feeds synthetic sensor values through the decision logic, so you can validate thresholds without physically triggering the event.

Frequently Asked Questions

Why can't a normal meter see these problems?

Because they are fast and brief — a sag may last only tens of milliseconds. A normal meter reports a slow average that smooths the disturbance away. You must sample many times per cycle to see it.

What is a voltage sag and why does it matter?

A brief dip in voltage, often when a large load starts nearby. It is the most common and disruptive power-quality event — enough to reset controllers or trip processes — yet invisible to ordinary metering.

How does this help me prove a supply problem?

It characterises each disturbance (type, magnitude, duration) with an accurate timestamp, producing an evidence log you can correlate with equipment failures and take to the utility or vendor — facts, not assertions.

Is it accurate enough for a formal dispute?

It is indicative evidence. Formal disputes may require a calibrated, standards-compliant (IEC 61000-4-30) analyser. This logger is excellent for diagnosis and building a case, honestly labelled as such.

Is it safe to build?

Only with isolated voltage sensing and a qualified person making the mains-side connection. Measuring mains directly is dangerous; keep the electronics isolated.

References & Learning Resources

These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.

  1. Power quality — overviewReference
  2. Voltage sag (dip) and swellReference
  3. Total harmonic distortion (THD)Reference
  4. IEC 61000-4-30 power-quality measurementReference
  5. RMS and waveform measurementReference