Why a True RMS Power Analyzer is a Top-Tier Electrical Engineering Project for Resume Portfolios
When hiring managers review electrical engineering projects for resume portfolios, they look for evidence that a candidate can bridge physical AC circuit theory with modern embedded systems. Blinking an LED or reading a basic DC temperature sensor does not demonstrate an understanding of impedance, phase shift, or sampling theorem limitations. Building a True RMS (Root Mean Square) AC Power Analyzer does.
This project measures real-world AC voltage, current, real power (Watts), apparent power (VA), and power factor. By bypassing the ESP32's internal ADC—which is notoriously non-linear and noisy on newer variants—and implementing an external 16-bit I2C ADC, you signal to recruiters that you understand hardware datasheet limitations, not just how to copy-paste Arduino tutorials.
Hardware Spec Sheet & Exact Parts List
To ensure accuracy at 50/60Hz, we must sample the AC waveform at a minimum of 1kHz to capture harmonics. The original ESP32-WROOM-32 has a usable internal ADC, but the modern ESP32-S3 requires an external ADC for precision analog work. We use the Texas Instruments ADS1115 for 16-bit resolution.
| Component | Exact Variant / Model | Purpose in Circuit | Approx Cost (2026) |
|---|---|---|---|
| Microcontroller | ESP32-S3-DevKitC-1 (N8R8) | Main processing, WiFi telemetry, I2C master | $7.50 |
| External ADC | Adafruit ADS1115 Breakout | 16-bit precision analog-to-digital conversion | $9.95 |
| Voltage Sensor | ZMPT101B Module | Steps down 120/230V AC to 0-3.3V analog | $3.20 |
| Current Sensor | ACS724 (30A variant) | Hall-effect current measurement (ratiometric) | $4.50 |
| Display | SSD1306 128x64 OLED (I2C) | Local readout for V, I, W, and PF | $3.80 |
Pin Mapping & Wiring the Analog Front-End
The analog sensors output biased AC waveforms (centered around 1.65V). These must be routed to the ADS1115, not directly to the ESP32-S3.
| ESP32-S3 Pin | Target Module | Module Pin | Notes |
|---|---|---|---|
| GPIO 8 | ADS1115 / OLED | SDA | I2C Data (Requires 4.7kΩ pull-up to 3.3V) |
| GPIO 9 | ADS1115 / OLED | SCL | I2C Clock (Requires 4.7kΩ pull-up to 3.3V) |
| 3V3 | ADS1115 | VDD | Power for ADC logic |
| GND | All Modules | GND | Common ground reference |
| N/A (Analog) | ZMPT101B | OUT to ADS1115 A0 | AC Voltage waveform |
| N/A (Analog) | ACS724 | OUT to ADS1115 A1 | AC Current waveform |
Complete ESP32-S3 Firmware (Arduino IDE 2.x)
This firmware targets the ESP32-S3-DevKitC-1. It uses the Adafruit ADS1X15 library. The code calculates True RMS by squaring the samples, averaging them over a 20ms window (covering one full 50Hz cycle or slightly more than one 60Hz cycle), and taking the square root. It includes explicit I2C error handling to prevent silent failures.
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
// --- PIN DEFINITIONS ---
#define I2C_SDA 8
#define I2C_SCL 9
#define ADS_ADDR 0x48
// --- CALIBRATION CONSTANTS ---
// Adjust these based on your specific sensor modules and multimeter readings
#define V_CALIBRATION 0.085 // Volts per ADC step for ZMPT101B
#define I_CALIBRATION 0.045 // Amps per ADC step for ACS724
#define V_BIAS 13500 // ADC zero-crossing offset (approx 1.65V on 16-bit)
#define I_BIAS 13500
Adafruit_ADS1115 ads;
void setup() {
Serial.begin(115200);
delay(1000);
Wire.begin(I2C_SDA, I2C_SCL);
// Initialize ADS1115 with error handling
if (!ads.begin(ADS_ADDR)) {
Serial.println("[FATAL] ADS1115 init failed. I2C bus hung or address 0x48 NACK.");
while (1) { delay(100); } // Halt execution
}
// Set gain to +/- 4.096V (1 bit = 0.125mV) for 3.3V sensor outputs
ads.setGain(GAIN_ONE);
ads.setDataRate(RATE_ADS1115_860SPS); // Max sampling rate for 50/60Hz capture
Serial.println("System Initialized. Measuring AC Parameters...");
}
void loop() {
unsigned long startMicros = micros();
unsigned long windowMicros = 20000; // 20ms window for 50Hz (covers 60Hz safely)
double sumSqV = 0;
double sumSqI = 0;
double sumP = 0;
int sampleCount = 0;
while (micros() - startMicros < windowMicros) {
int16_t rawV = ads.readADC_SingleEnded(0);
int16_t rawI = ads.readADC_SingleEnded(1);
double v_inst = (rawV - V_BIAS) * V_CALIBRATION;
double i_inst = (rawI - I_BIAS) * I_CALIBRATION;
sumSqV += (v_inst * v_inst);
sumSqI += (i_inst * i_inst);
sumP += (v_inst * i_inst); // Instantaneous power
sampleCount++;
}
if (sampleCount > 0) {
double vRms = sqrt(sumSqV / sampleCount);
double iRms = sqrt(sumSqI / sampleCount);
double realPower = sumP / sampleCount;
double apparentPower = vRms * iRms;
double powerFactor = (apparentPower > 0) ? (realPower / apparentPower) : 0;
Serial.printf("V_RMS: %.2f V | I_RMS: %.3f A | Real: %.2f W | PF: %.2f\n",
vRms, iRms, realPower, powerFactor);
}
delay(100); // Small pause before next 20ms capture window
}
Debugging: I2C Faults and Hardware Failure Modes
When working with mixed-signal boards, I2C communication drops are the most common point of failure. If your serial monitor outputs the exact error string: [FATAL] ADS1115 init failed. I2C bus hung or address 0x48 NACK., the microcontroller cannot see the ADC.
The first three things to check when it fails:
- Verify I2C Pull-Up Resistors: The ESP32-S3 internal pull-ups are often too weak (typically 45kΩ) for high-speed I2C. Ensure you have physical 4.7kΩ resistors pulling SDA and SCL up to 3.3V. Some cheap ADS1115 clone boards omit these entirely.
- Check Logic Level Mismatch: The ADS1115 is powered by 3.3V on the VDD pin. If you accidentally wired VDD to the ESP32's 5V (VIN) pin, you may have permanently damaged the I2C transceivers inside the chip. Measure VDD with a multimeter; it must read 3.2V - 3.4V.
- Confirm I2C Address: Run an I2C scanner sketch. The default address is
0x48(ADDR pin tied to GND). If the ADDR pin is floating or shorted to SDA, the address shifts, causing a NACK (No Acknowledge) on the bus.
Scaling the Project: How to Extend or Simplify the Build
A strong resume project shows you understand scope management. Be prepared to explain how you would alter this design for different production constraints.
- How to Simplify (Cost Reduction): If the $10 ADS1115 is too expensive for a mass-produced IoT plug, switch to the older ESP32-WROOM-32 (not the S3) and use its internal 12-bit ADC. You will lose precision on low-current measurements and must implement software oversampling, but it cuts the BOM cost by 35%.
- How to Extend (Feature Addition): To push this from a bench tool to a smart-home product, implement the
PubSubClientlibrary to push the JSON payload via MQTT to Home Assistant. For advanced electrical engineering roles, add an FFT (Fast Fourier Transform) using the ESP-DSP library to calculate Total Harmonic Distortion (THD) of the AC waveform.
FAQ: Electrical Engineering Projects for Resume
What are the best electrical engineering projects for resume portfolios if I only have basic components?
If you lack specialized AC sensors, build a Programmable DC Electronic Load using an op-amp (like the LM358), a power MOSFET (IRFZ44N), and a shunt resistor. This demonstrates closed-loop control theory, PID tuning, and power dissipation calculations without requiring dangerous mains voltage wiring.
How should I document embedded electrical engineering projects for resume submissions?
Do not just post a GitHub link to raw code. Hiring managers want to see the engineering process. Include a block diagram, a schematic (exported from KiCad or EasyEDA), a BOM (Bill of Materials) with costs, and a short section on trade-offs considered (e.g., why you chose an I2C ADC over an SPI ADC). Host this on a personal site or a well-formatted GitHub README.
Do hiring managers care about AC theory in electrical engineering projects for resume reviews?
Yes, especially for roles in power electronics, renewable energy, or industrial automation. Understanding the difference between Real Power (Watts) and Apparent Power (VA), and knowing why True RMS measurement is required for non-linear loads (like LED drivers and switching power supplies), proves you understand real-world grid behavior, not just ideal textbook circuits.






