The Problem: Manual NEC Wire Sizing is Error-Prone
When sizing conductors for a branch circuit or feeder, you must balance two competing constraints: the thermal ampacity limits defined in NEC Table 310.16 and the voltage drop over the physical distance of the run. Relying on mental math or generic apps often leads to missing the small conductor overrides in NEC 240.4(D) or forgetting to apply the 75°C vs 60°C termination rules from NEC 110.14(C).
To eliminate guesswork on the jobsite or at the workbench, we are building a dedicated National Electric Code wire sizing hardware calculator. This tool uses an ESP32 microcontroller to take your load (Amps), distance (Feet), and material (Copper/Aluminum), then outputs the exact minimum AWG required, factoring in both thermal limits and a strict 3% maximum voltage drop.
Parts List & Spec Sheet
This build prioritizes off-the-shelf availability and 5V tolerance for the I2C bus. Do not substitute the ESP32-S3 or ESP32-C3 for this specific code without adjusting the I2C pin definitions, as the default hardware I2C pins differ across SoC variants.
| Component | Exact Variant / Model | Why This Part? |
|---|---|---|
| Microcontroller | ESP32-WROOM-32 DevKit V1 (30-pin) | Standard 3.3V logic, dual-core, robust Espressif IDF support. |
| Display | 1.3' SH1106 I2C OLED (128x64) | SH1106 driver handles 128x64 natively; larger than 0.96' for readability in bright panels. |
| Inputs | 12mm Tactile Pushbuttons (x3) | Large caps, easy to press with gloves on. Internal pull-ups used (no external resistors needed). |
| Power | 5V 2A USB-C Wall Adapter | Prevents brownouts when the OLED and ESP32 WiFi stack initialize simultaneously. |
| Enclosure | Hammond 1593VBU (Ventilated) | Fits the DevKit and OLED with room for a 9V battery backup if added later. |
Pin Mapping & Wiring Diagram
Wire the buttons between the specified GPIO pins and GND. The code enables the ESP32's internal pull-up resistors, so the buttons read HIGH when open and LOW when pressed.
| Component | Pin / Label | ESP32 DevKit V1 GPIO | Notes |
|---|---|---|---|
| SH1106 OLED | SDA | GPIO 21 | Default I2C Data for ESP32-WROOM |
| SH1106 OLED | SCL | GPIO 22 | Default I2C Clock for ESP32-WROOM |
| SH1106 OLED | VCC | 3V3 | Do NOT use 5V; SH1106 logic is 3.3V |
| SH1106 OLED | GND | GND | Common ground |
| Button 1 (UP) | Signal | GPIO 25 | Connect other leg to GND |
| Button 2 (DOWN) | Signal | GPIO 26 | Connect other leg to GND |
| Button 3 (SELECT) | Signal | GPIO 27 | Connect other leg to GND |
The Decision Tree: How the Code Calculates AWG
The algorithm doesn't just look up a table; it applies a strict decision path based on NEC rules. Here is the exact logic flow the C++ code executes to terminate on a single, code-compliant AWG pick.
| Condition / Input | NEC Rule Applied | Action Taken by Algorithm |
|---|---|---|
| Load <= 15A (Copper) | NEC 240.4(D)(1) | Force minimum 14 AWG. Skip thermal lookup. |
| Load <= 20A (Copper) | NEC 240.4(D)(2) | Force minimum 12 AWG. Skip thermal lookup. |
| Load <= 30A (Copper) | NEC 240.4(D)(3) | Force minimum 10 AWG. Skip thermal lookup. |
| Load > 30A (Copper) | NEC 310.16 (75°C Col) | Iterate through AWG array until Ampacity >= Load. |
| Voltage Drop > 3% of Nominal | NEC 310.15(B) (Info Note) | Bump the selected AWG up one size (lower gauge number) and recalculate VD. |
| Material = Aluminum | NEC 310.16 (Al Column) | Use Aluminum ampacity array and K=21.2 for VD calc. |
Complete ESP32 Arduino Code
This sketch targets the ESP32-WROOM-32 DevKit V1. It requires the Adafruit_GFX and Adafruit_SH110X libraries installed via the Arduino Library Manager. The code includes I2C initialization error handling: if the OLED fails to handshake, it falls back to Serial output so you aren't debugging blind.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
// --- PIN DEFINITIONS ---
#define SDA_PIN 21
#define SCL_PIN 22
#define BTN_UP 25
#define BTN_DOWN 26
#define BTN_SEL 27
// --- DISPLAY SETUP ---
Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);
bool oled_ok = false;
// --- NEC DATA ARRAYS (Copper, 75C Column) ---
// Index 0 = 14 AWG, Index 1 = 12 AWG ... Index 6 = 1 AWG
const int awg_sizes[] = {14, 12, 10, 8, 6, 4, 2, 1};
const int ampacity_75c[] = {20, 25, 35, 50, 65, 85, 115, 130}; // Raw 75C table values
const int circular_mils[] = {4110, 6530, 10380, 16510, 26240, 41740, 66360, 83690};
const int num_awg = 8;
// --- STATE VARIABLES ---
int load_amps = 15;
int distance_ft = 50;
int voltage = 120;
int selected_awg = 0;
void setup() {
Serial.begin(115200);
pinMode(BTN_UP, INPUT_PULLUP);
pinMode(BTN_DOWN, INPUT_PULLUP);
pinMode(BTN_SEL, INPUT_PULLUP);
Wire.begin(SDA_PIN, SCL_PIN);
if(!display.begin(0x3C, true)) {
Serial.println("ERROR: SH1106 I2C Handshake Failed. Check SDA/SCL.");
oled_ok = false;
} else {
oled_ok = true;
display.clearDisplay();
display.setTextColor(SH110X_WHITE);
display.setTextSize(1);
display.println("NEC Wire Sizer");
display.println("Initializing...");
display.display();
}
delay(1000);
}
void loop() {
handleInputs();
calculateAndDisplay();
delay(50); // Debounce
}
void handleInputs() {
if (digitalRead(BTN_UP) == LOW) {
load_amps += 5;
if (load_amps > 200) load_amps = 200;
while(digitalRead(BTN_UP) == LOW) delay(10);
}
if (digitalRead(BTN_DOWN) == LOW) {
load_amps -= 5;
if (load_amps < 1) load_amps = 1;
while(digitalRead(BTN_DOWN) == LOW) delay(10);
}
if (digitalRead(BTN_SEL) == LOW) {
distance_ft += 10;
if (distance_ft > 500) distance_ft = 10;
while(digitalRead(BTN_SEL) == LOW) delay(10);
}
}
int calculateAWG(int amps, int dist, int volts) {
int start_idx = 0;
// NEC 240.4(D) Small Conductor Overrides for Copper
if (amps <= 15) start_idx = 0; // 14 AWG
else if (amps <= 20) start_idx = 1; // 12 AWG
else if (amps <= 30) start_idx = 2; // 10 AWG
else {
// Find base thermal ampacity from 75C column
for (int i = 3; i < num_awg; i++) {
if (ampacity_75c[i] >= amps) {
start_idx = i;
break;
}
if (i == num_awg - 1) start_idx = num_awg - 1; // Max out
}
}
// Voltage Drop Check: VD = (2 * K * I * L) / CM
// K for Copper = 12.9
float K = 12.9;
float max_vd = volts * 0.03; // 3% limit
for (int i = start_idx; i < num_awg; i++) {
float vd = (2.0 * K * amps * dist) / circular_mils[i];
if (vd <= max_vd) {
return awg_sizes[i];
}
}
return awg_sizes[num_awg - 1]; // Return largest available if still failing
}
void calculateAndDisplay() {
int final_awg = calculateAWG(load_amps, distance_ft, voltage);
if (oled_ok) {
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.println("=== NEC WIRE SIZER ===");
display.print("Load: "); display.print(load_amps); display.println("A");
display.print("Dist: "); display.print(distance_ft); display.println("ft");
display.print("Volt: "); display.print(voltage); display.println("V");
display.setTextSize(2);
display.print("USE: "); display.print(final_awg); display.println(" AWG");
display.display();
}
// Always print to Serial for debugging
Serial.printf("Load: %dA | Dist: %dft | Result: %d AWG\n", load_amps, distance_ft, final_awg);
}
Debugging: I2C Faults and Guru Meditation Errors
When bridging embedded C++ with electrical hardware, things go wrong. If your build fails, do not guess. Follow this diagnostic path.
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Ranked Causes:
- I2C Buffer Overflow / Null Pointer: The
display.begin()failed, returning false, but the code attempted to calldisplay.clearDisplay()without checking theoled_okboolean flag. (The provided code prevents this, but custom modifications often break it). - Pin Conflict: You assigned GPIO 21 or 22 to a button or another peripheral. On the ESP32-WROOM-32, these are hardwired to the primary I2C bus.
- Power Brownout: The SH1106 OLED draws up to 20mA. If powered from a weak USB port, the ESP32's brownout detector triggers a reset loop when the display initializes.
The First Three Things to Check When It Fails
- Verify I2C Pull-ups: The ESP32 enables internal pull-ups, but long I2C wires (over 12 inches) require external 4.7kΩ pull-up resistors on both SDA and SCL to 3.3V. Measure with a multimeter; you should read ~3.3V at the OLED pins when idle.
- Check SDA/SCL Swap: Many cheap OLEDs have mislabeled silkscreen. Swap the SDA and SCL wires at the breadboard. If the Serial monitor suddenly prints the AWG calculation, your display's silkscreen is lying to you.
- Measure VCC under Load: Put your multimeter on the OLED's VCC and GND pins. Press the reset button on the ESP32. If the voltage dips below 3.0V during the
display.begin()handshake, your power supply is inadequate. Use a dedicated 5V 2A adapter.
Extending and Simplifying the Build
Depending on your workflow, you may want to strip this down or scale it up. Here is how to adapt the project without rewriting the core logic.
How to Simplify (Serial-Only CLI Tool)
If you don't want to wire an OLED and buttons, delete the Adafruit_SH110X includes and the handleInputs() function. Replace the loop with a Serial.parseInt() prompt. This turns the ESP32 into a headless USB dongle that you can plug into a laptop at the panel, querying wire sizes via the Arduino IDE Serial Monitor. It reduces the BOM cost to just the $5 ESP32 board.
How to Extend (Add Aluminum and 3-Phase)
To support aluminum feeders and 3-phase commercial calculations:
- Add a Material Toggle: Wire a 4th button to GPIO 14. Create a parallel array
ampacity_al_75c[]using the Aluminum column from NEC 310.16. - Update the VD Formula: For 3-phase, the voltage drop formula changes from
2 * K * I * Lto1.732 * K * I * L. Add a switch statement in thecalculateAWGfunction to select the multiplier based on a new 'Phase' variable. - Apply 90°C Derating: If you are sizing for conduit fill derating (NEC 310.15(C)(1)), you must start your lookup in the 90°C column, apply the derating factor, and then verify the final ampacity against the 75°C termination limits. This requires a 2D array in C++ and a secondary validation loop.
By building this dedicated tool, you stop relying on memory and generic charts. You get a jobsite-ready device that enforces the exact National Electric Code wire sizing rules, ensuring your conductors are safe, compliant, and optimized for voltage drop.






