Verifying compliance with residential electrical panel code requirements usually requires a licensed electrician to perform a manual load calculation and thermal scan. However, for DIYers, home inspectors, and advanced makers, you can build a continuous compliance monitor using an ESP32. The National Electrical Code (NEC) strictly governs two major failure points in residential panels: continuous overloading (NEC 210.20/215.3) and ambient temperature derating (NEC 310.15). If a 200A main feeder carries more than 160A for three continuous hours, or if the ambient wall temperature exceeds 30°C (86°F) requiring THHN ampacity derating, your panel is technically out of code and at risk of thermal degradation.
This guide walks you through building an ESP32-based monitor that tracks true RMS amperage and ambient temperature, alerting you the moment your setup violates these specific residential electrical panel code requirements. We will use the ESP32-WROOM-32 DevKit v1 (30-pin variant), an SCT-013-103 current transformer, and a DS18B20 digital temperature sensor.
Decision Tree: Selecting the Right Sensors for Panel Monitoring
Before wiring anything, you must choose the right sensors. Measuring temperature inside or near an electrical panel involves trade-offs between safety, accuracy, and installation complexity. Below is the decision matrix to determine which sensor fits your build.
| Sensor Type | Pros | Cons | Best For |
|---|---|---|---|
| DS18B20 (Waterproof Probe) | Cheap ($3), highly accurate (±0.5°C), digital I2C/1-Wire, no calibration needed. | Requires physical contact; measures surface/ambient, not internal busbar temp directly. | Measuring ambient wall temp for NEC 310.15 derating checks. |
| MLX90114 (IR Non-Contact) | Measures internal busbar temp through a vent without touching live parts. | Expensive ($15), requires precise emissivity calibration, I2C wiring is fragile. | Targeting specific breaker lugs for NEC 110.14(C) terminal limits. |
| NTC 10k Thermistor | Extremely fast response time, very cheap. | Analog output requires voltage divider and ESP32 ADC calibration (notoriously non-linear). | High-speed thermal runaway detection in battery packs, not panels. |
Hardware Spec Sheet & Pin Mapping
This build targets the ESP32-WROOM-32 DevKit v1 (30-pin). Do not use the 38-pin variant without adjusting the GPIO numbers, as the internal ADC mapping differs. The SCT-013-103 is specifically chosen over the SCT-013-000 because it includes an internal 62-ohm burden resistor, outputting a safe 0-1V AC signal directly compatible with the ESP32's 3.3V ADC.
| Component | Model / Variant | ESP32 GPIO Pin | Notes |
|---|---|---|---|
| Microcontroller | ESP32-WROOM-32 DevKit v1 (30-pin) | N/A | Ensure Arduino Core v2.0.14+ is installed. |
| Temp Sensor | DS18B20 Waterproof Probe | GPIO 4 (Data) | Requires 4.7kΩ pull-up to 3.3V. |
| Current Transformer | SCT-013-103 (100A/1V output) | GPIO 34 (Input) | ADC1 channel. Do not use ADC2 (WiFi conflict). |
| Bias Network | 2x 100kΩ Resistors, 1x 10µF Cap | 3.3V & GND | Biases the AC CT signal to 1.65V DC offset. |
Wiring the ESP32 Monitor (Safety First)
- Prepare the CT Bias Network: The ESP32 ADC only reads 0-3.3V DC. The SCT-013 outputs AC. Connect two 100kΩ resistors in series between the ESP32 3.3V pin and GND to create a 1.65V virtual ground. Connect a 10µF electrolytic capacitor across the middle junction and GND to stabilize the bias.
- Wire the CT Sensor: Connect one wire of the SCT-013-103 to the 1.65V bias junction, and the other wire to GPIO 34. This centers the AC waveform at 1.65V, allowing the ESP32 to read both the positive and negative halves of the 60Hz sine wave.
- Wire the DS18B20: Connect the Red wire to 3.3V, Black to GND, and Yellow (Data) to GPIO 4. Solder a 4.7kΩ pull-up resistor directly between the Red and Yellow wires at the sensor head to prevent signal degradation over long cable runs.
- Mounting: Use double-sided foam tape to mount the ESP32 enclosure on the exterior wall adjacent to the panel. Zip-tie the DS18B20 probe directly to the panel's metal enclosure to measure the conductive ambient heat transfer.
Complete ESP32 Code with Error Handling
The following code samples the CT sensor at a high frequency to calculate True RMS current, bypassing the non-linearities of the ESP32 ADC by using analogReadMilliVolts(). It also includes strict error handling for the DS18B20 to prevent false code-violation alerts if the sensor disconnects.
#include <OneWire.h>
#include <DallasTemperature.h>
// --- PIN DEFINITIONS ---
#define ONE_WIRE_BUS 4
#define CT_SENSOR_PIN 34
// --- HARDWARE CONSTANTS ---
const float V_REF = 3300.0; // ESP32 reference voltage in mV
const float BIAS_VOLTAGE = 1650.0; // Virtual ground bias in mV
const float CT_SENSITIVITY = 50.0; // SCT-013-103: 50mA per 1A primary (1V out at 100A)
const int SAMPLES = 1200; // Samples per second (20 per 60Hz cycle)
// --- NEC CODE LIMITS ---
const float MAIN_BREAKER_RATING = 200.0; // 200A Main Panel
const float CONTINUOUS_LOAD_LIMIT = MAIN_BREAKER_RATING * 0.80; // NEC 210.20(A) 80% rule
const float MAX_AMBIENT_TEMP_C = 30.0; // NEC 310.15(B) base temp for THHN
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup() {
Serial.begin(115200);
analogReadResolution(12); // Force 12-bit resolution (0-4095)
pinMode(CT_SENSOR_PIN, INPUT);
sensors.begin();
Serial.println("ESP32 Panel Code Compliance Monitor Initialized.");
Serial.println("Target: NEC 210.20(A) Continuous Load & NEC 310.15 Ambient Derating");
}
void loop() {
// 1. Read Ambient Temperature
sensors.requestTemperatures();
float tempC = sensors.getTempCByIndex(0);
// Error Handling for DS18B20
if (tempC == -127.0) {
Serial.println("Error: DS18B20 returned -127.00°C (Device disconnected or pull-up missing)");
delay(2000);
return; // Abort loop to prevent false NEC violation alerts
}
// 2. Calculate True RMS Current
float sumSq = 0;
for (int i = 0; i < SAMPLES; i++) {
int rawAdc = analogReadMilliVolts(CT_SENSOR_PIN);
float voltageOffset = rawAdc - BIAS_VOLTAGE;
// Convert mV offset to primary Amps
// 100A primary = 1000mV secondary. So 1mV = 0.1A
float primaryAmps = voltageOffset * 0.1;
sumSq += (primaryAmps * primaryAmps);
delayMicroseconds(833); // ~1200Hz sampling rate
}
float rmsCurrent = sqrt(sumSq / SAMPLES);
// 3. Evaluate NEC Compliance
bool tempViolation = (tempC > MAX_AMBIENT_TEMP_C);
bool loadViolation = (rmsCurrent > CONTINUOUS_LOAD_LIMIT);
// 4. Output Telemetry
Serial.printf("Ambient: %.2f C | RMS Load: %.2f A\n", tempC, rmsCurrent);
if (tempViolation) {
Serial.printf("[CODE ALERT] Ambient temp %.1f C exceeds 30 C. Apply NEC Table 310.15(B)(16) derating factors!\n", tempC);
}
if (loadViolation) {
Serial.printf("[CODE ALERT] Continuous load %.1f A exceeds 80%% of %0.f A OCPD. NEC 210.20(A) Violation!\n", rmsCurrent, MAIN_BREAKER_RATING);
}
delay(5000); // Log every 5 seconds
}
Debugging: "Error: DS18B20 returned -127.00°C"
If your serial monitor outputs the exact string Error: DS18B20 returned -127.00°C (Device disconnected or pull-up missing), the DallasTemperature library has timed out waiting for the sensor's 1-Wire handshake. This is the most common failure mode when integrating 1-Wire sensors near high-current magnetic fields (like a residential panel).
The first three things to check when it fails:
- Verify the 4.7kΩ Pull-Up Resistor: The 1-Wire protocol is open-drain. Without a physical 4.7kΩ resistor pulling the data line HIGH to 3.3V, the ESP32 cannot read the sensor's response. Internal ESP32 pull-ups are too weak (~45kΩ) and will fail in electrically noisy environments.
- Check for Parasitic Power Wiring Errors: Ensure the DS18B20 Red wire (VDD) is connected to 3.3V, not left floating. While the DS18B20 supports 'parasitic power' (drawing power from the data line), this mode is highly unstable on the ESP32 due to the 3.3V logic threshold and current limits. Wire it for external power (VDD to 3.3V).
- Inspect GPIO 4 for Conflicts: Ensure GPIO 4 is not being used by an active SPI/I2C bus, and verify you are not using a DevKit variant where GPIO 4 is tied to an onboard status LED or flash memory pin. If in doubt, move the data wire to GPIO 16 and update the
#define ONE_WIRE_BUS 16in the code.
Extending and Simplifying the Build
Once your monitor is reliably logging data, you have two clear paths depending on your end goal:
To Simplify (Standalone Alerting):
Strip out the Serial telemetry and add a simple if (loadViolation) digitalWrite(ALARM_PIN, HIGH); block. Wire a 5V active-low piezo buzzer or a red LED to GPIO 25. This creates a dumb, standalone compliance alarm that requires no WiFi, no MQTT broker, and no home automation hub. It just works.
To Extend (Smart Home Integration):
Integrate the PubSubClient library to push the RMS current and temperature data to an MQTT broker (like Mosquitto on a Raspberry Pi) every 60 seconds. From there, you can pipe the data into Home Assistant. In Home Assistant, create a 'Derivative' sensor to calculate the 3-hour rolling average of your amperage. This perfectly mirrors the NEC's definition of a 'continuous load' (a load where the maximum current is expected to continue for 3 hours or more), allowing you to trigger automations only when the 80% rule is violated over the legally defined timeframe, rather than tripping on momentary inrush currents from HVAC compressors starting up.
For 95% of residential panel monitoring tasks, the DS18B20 paired with the SCT-013-103 on an ESP32-WROOM-32 is the definitive, most reliable choice. Build the bias network correctly, respect the mains voltage boundaries, and let the math verify your NEC compliance.






