When winding custom transformers, building subpanels, or troubleshooting legacy home wiring, guessing wire gauge or misinterpreting the electrical wire code for jacket colors can lead to catastrophic overcurrent failures. Visual inspection of faded THHN insulation is unreliable, and using calipers on stranded wire introduces massive measurement errors. Instead of guessing, we can build a bench-top embedded tool that injects a known constant current into a wire spool, measures the microvolt-level voltage drop with a 16-bit ADC, and calculates the exact AWG. Simultaneously, it uses an I2C color sensor to read the jacket and validate it against NEC color standards.
This guide details how to build this validator using the ESP32-WROOM-32 DevKit v1, targeting both the physical NEC Chapter 9 resistance tables and the NFPA 70 color code requirements.
NEC Electrical Wire Code & AWG Reference Table
Before writing the firmware, the ESP32 needs a reference baseline. The following table maps the physical resistance of uncoated copper wire (from NFPA 70 (NEC) Chapter 9, Table 8) to the standard THHN electrical wire code color assignments and ampacity limits. Our code will use the resistance values to reverse-calculate the AWG based on the measured voltage drop.
| AWG Size | Area (cmil) | Resistance (Ω/kft @ 75°C) | Standard NEC Electrical Wire Code (THHN) | Max Ampacity (75°C Col) |
|---|---|---|---|---|
| 14 AWG | 4,110 | 3.140 | White (Neutral), Black (Hot) | 15A (60°C limit) |
| 12 AWG | 6,530 | 1.980 | White, Black, Red | 20A |
| 10 AWG | 10,380 | 1.240 | White, Black, Red, Blue | 30A |
| 8 AWG | 16,510 | 0.778 | Black, Red, Blue, Yellow | 50A |
| 6 AWG | 26,240 | 0.491 | Black, Red, Blue, Yellow, Orange | 65A |
Parts List & Pin Mapping
This build relies on precision I2C sensors. Do not substitute the ADS1115 with the internal ESP32 ADC; the ESP32's internal 12-bit ADC is notoriously non-linear and lacks the differential microvolt resolution required for wire resistance testing.
Required Components
- Microcontroller: ESP32-WROOM-32 DevKit v1 (30-pin or 38-pin variant)
- ADC: Adafruit ADS1115 16-Bit I2C ADC Breakout (Product ID: 1085)
- Color Sensor: Adafruit TCS34725 RGB Color Sensor (Product ID: 1334)
- Display: 128x64 SSD1306 I2C OLED (0.96 inch)
- Current Source: LM317T configured as a 1.000A constant current sink (requires a 1.25Ω 2W sense resistor and a 5V/2A USB power feed)
- Probes: 2x Kelvin (4-wire) alligator clips or pogo-pin test leads
Pin Mapping Table
| Component | Pin | ESP32-WROOM-32 GPIO | Notes |
|---|---|---|---|
| ADS1115 | VDD | 3V3 | Do not use 5V |
| ADS1115 | GND | GND | Common ground |
| ADS1115 | SCL | GPIO 22 | I2C Clock |
| ADS1115 | SDA | GPIO 21 | I2C Data |
| ADS1115 | A0 / A1 | N/A | Differential inputs across wire |
| TCS34725 | VIN | 3V3 | 3.3V logic safe |
| TCS34725 | SCL / SDA | GPIO 22 / 21 | Shared I2C bus |
| SSD1306 | VCC / SCL / SDA | 3V3 / 22 / 21 | Shared I2C bus |
Assembly & Calibration Steps
- Build the Constant Current Source: Wire the LM317T to output exactly 1.000A. Connect a 1.25Ω precision resistor between the ADJ and OUT pins. Feed the IN pin from a stable 5V supply. This ensures that for every 1 milliohm of wire resistance, you get exactly 1 millivolt of drop ($V = I \times R$).
- Wire the I2C Bus: Connect the SDA (GPIO 21) and SCL (GPIO 22) lines to the ADS1115, TCS34725, and SSD1306. Because you have three devices on one bus, ensure the pull-up resistors on the Adafruit breakouts are intact. If the bus hangs, you may need to add external 4.7kΩ pull-ups to 3.3V.
- Connect Differential Probes: Connect the Kelvin clips to the ADS1115 A0 and A1 pins. The constant current source forces 1A through the wire under test, while the ADS1115 measures the differential voltage strictly across the wire, ignoring the resistance of the test leads.
- Calibrate the Color Sensor: The TCS34725 requires a white-balance calibration. Place a piece of standard white THHN insulation under the sensor and press the boot button on the ESP32 to lock the baseline RGB values in the firmware.
Complete ESP32 Validator Firmware
The following C++ code targets the ESP32-WROOM-32 DevKit v1 using the Arduino IDE. It initializes all three I2C sensors, reads the differential voltage to calculate AWG, and checks the jacket color against the electrical wire code database.
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
#include <Adafruit_TCS34725.h>
#include <Adafruit_SSD1306.h>
// Pin Definitions
#define I2C_SDA 21
#define I2C_SCL 22
#define CALIBRATE_BTN 0 // ESP32 BOOT button
// Display setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Sensors
Adafruit_ADS1115 ads;
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
// NEC Resistance (Ohms per 1000ft) for 14, 12, 10, 8, 6 AWG
const float awg_resistance[] = {3.140, 1.980, 1.240, 0.778, 0.491};
const int awg_sizes[] = {14, 12, 10, 8, 6};
const char* awg_colors[] = {"Wht/Blk", "Wht/Blk/Red", "W/B/R/Blu", "B/R/Blu/Yel", "B/R/Blu/Yel/Org"};
void setup() {
Serial.begin(115200);
Wire.begin(I2C_SDA, I2C_SCL);
// Initialize Display
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 init FAILED!"));
while(true); // Halt
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// Initialize ADS1115
if (!ads.begin()) {
display.println("ADS1115 NOT FOUND");
display.display();
Serial.println("ADS1115 init FAILED!");
while(true);
}
ads.setGain(GAIN_SIXTEEN); // +/- 0.256V range, 0.0078mV resolution
// Initialize TCS34725
if (tcs.begin()) {
Serial.println("Color sensor ready.");
} else {
display.println("TCS34725 init FAILED!");
display.display();
Serial.println("TCS34725 init FAILED!");
while(true);
}
display.println("System Ready.");
display.println("Attach wire & press BOOT");
display.display();
}
void loop() {
// Read differential voltage (A0 to A1)
int16_t adc_raw = ads.readADC_Differential_0_1();
float voltage_mv = ads.computeVolts(adc_raw) * 1000.0;
// Since I = 1.000A, Voltage in mV = Resistance in milliohms
float resistance_mohm = abs(voltage_mv);
float resistance_ohm_per_kft = (resistance_mohm / 1000.0) * 1000.0; // Adjust for length if known, assuming 1ft test
// Read Color
uint16_t clear, red, green, blue;
tcs.getRawData(&red, &green, &blue, &clear);
// Simple color heuristic for NEC THHN
String detected_color = "Unknown";
if (clear > 1000) {
if (red > green && red > blue) detected_color = "Black/Red";
else if (green > red && green > blue) detected_color = "Green";
else if (blue > red && blue > green) detected_color = "Blue";
else detected_color = "White/Gray";
}
// Match AWG (simplified nearest-neighbor for 1ft sample)
int matched_awg = 0;
float min_diff = 9999.0;
for(int i=0; i<5; i++) {
float diff = abs(resistance_ohm_per_kft - awg_resistance[i]);
if(diff < min_diff) {
min_diff = diff;
matched_awg = awg_sizes[i];
}
}
// Output to OLED
display.clearDisplay();
display.setCursor(0,0);
display.printf("AWG Calc: %d\n", matched_awg);
display.printf("R: %.3f Ohm/kft\n", resistance_ohm_per_kft);
display.printf("Jacket: %s\n", detected_color.c_str());
display.display();
delay(500);
}
Debugging: Sensor Init Failures & I2C Faults
When chaining multiple I2C devices on the ESP32-WROOM-32, bus capacitance and address conflicts are the primary failure points. If your serial monitor outputs the exact error string TCS34725 init FAILED! or ADS1115 NOT FOUND, follow these first three diagnostic steps:
- Verify Logic Levels and Power: The ESP32 is strictly a 3.3V logic device. If you accidentally wired the
VINorVDDpins of the sensors to the 5V pin on the DevKit, you may have damaged the sensor's internal I2C transceivers. Measure the VCC pin on each breakout with a multimeter; it must read 3.2V to 3.4V. - Check I2C Pull-Up Resistor Conflicts: The Adafruit ADS1115 and TCS34725 breakouts both include onboard 10kΩ pull-up resistors. When combined with the SSD1306 display, the parallel resistance drops, potentially pulling the I2C lines too low for the ESP32 to register a HIGH state. Use an oscilloscope to check the SDA line. If the HIGH level is below 2.5V, use a hobby knife to scratch the pull-up jumper pads on the TCS34725 breakout.
- Run an I2C Address Scanner: Upload a standard I2C scanner sketch. The ADS1115 should respond at
0x48, the TCS34725 at0x29, and the SSD1306 at0x3C. If the scanner hangs entirely, your SDA/SCL wires are swapped, or you have a short to ground on the breadboard.
Extending and Simplifying the Build
Depending on your workshop needs, you can scale this electrical wire code validator up or down.
How to Simplify
If the TCS34725 color sensor proves too finicky under varying shop lighting conditions, remove it entirely. Replace the sensor with a 5-way tactile switch matrix. Map the buttons to the standard NEC colors (White, Black, Red, Blue, Green). The ESP32 will still calculate the AWG via the ADS1115, and you manually input the jacket color. The firmware then cross-references your manual input against the calculated AWG to warn you if you are trying to use a 14 AWG white wire for a 20A hot leg, preventing a dangerous code violation.
How to Extend
For production panel shops doing QC on hundreds of custom harnesses, add an Adafruit MicroSD SPI Breakout (wired to SPI pins: MOSI=23, MISO=19, SCK=18, CS=5). Modify the loop() to append a CSV row containing the timestamp, measured resistance, calculated AWG, and detected color. This creates an immutable audit trail proving that every wire in a commercial subpanel was verified against NEC Chapter 9 standards before energization. You can also swap the LM317 constant current circuit for an INA219 I2C current sensor to measure the exact test current in real-time, compensating for any thermal drift in the power supply.






