Why Automate Electrical Wire Code Colour Verification?
Misidentifying conductor insulation on a jobsite or in a complex control panel is a fast track to a dead short, a tripped main breaker, or worse, an energized grounding path. While experienced electricians memorize regional standards, hobbyists, trade students, and automation engineers frequently work with mixed-standard equipment—especially when integrating imported IEC-rated machinery into US NEC-compliant facilities. Verifying the electrical wire code colour before terminating a conductor is a critical safety step.
Relying on visual inspection under poor panel lighting or fading LED work lights can lead to confusing a faded brown IEC line wire for a black NEC hot wire. To solve this, we can build a benchtop Smart Wire Colour Verifier. By pairing an ESP32 microcontroller with a calibrated RGB color sensor, you can objectively measure the insulation pigment and cross-reference it against standard code tables. This project targets the ESP32 DevKit V1 (30-pin variant with the ESP32-WROOM-32 module), chosen for its robust I2C handling and 3.3V logic, which perfectly matches modern sensor breakouts.
NEC vs IEC Wire Colour Standards Reference
Before writing the firmware, the sensor's logic needs a reference matrix. The most common point of failure in international builds is assuming the US National Electrical Code (NEC) and the International Electrotechnical Commission (IEC 60446) share the same palette. They do not. The table below maps the critical 120/240V and 230/400V AC conductor roles to their mandated insulation colours and typical residential/light-commercial sizing.
| Conductor Function | NEC (US/Canada) 120/240V | IEC (UK/EU/AU) 230/400V | Typical Size (AWG / mm²) |
|---|---|---|---|
| Line / Hot (Phase 1) | Black | Brown | 14-10 AWG / 1.5-2.5 mm² |
| Line / Hot (Phase 2) | Red (or Blue in 3-phase) | Black (or Blue in 3-phase) | 14-10 AWG / 1.5-2.5 mm² |
| Neutral (Grounded) | White or Grey | Blue | 14-10 AWG / 1.5-2.5 mm² |
| Earth / Ground (PE) | Bare, Green, or Green/Yellow | Green/Yellow Stripe | 14-10 AWG / 1.5-2.5 mm² |
Note: NM-B cable sheathing colors (Yellow for 12 AWG, White for 14 AWG, Red for 10 AWG) are manufacturer conventions for the outer jacket, not NEC code requirements for the individual conductors inside. Always test the inner THHN/THWN insulation. For a comprehensive breakdown of global standards, refer to the Electrical Technology wiring color code guide and the official NFPA 70 (NEC) documentation.
Parts List and Pin Mapping for the ESP32 Tester
This build requires precision I2C communication. Do not substitute the color sensor with a cheap photoresistor array; you need raw RGB and lux data to differentiate between dark green (ground) and black (hot) under varying ambient light.
Estimated Time: 2 hours for assembly and code flashing.
Estimated Cost: ~$25 USD.
Required Components
- Microcontroller: ESP32 DevKit V1 (30-pin, ESP32-WROOM-32 module) — ~$6
- Sensor: Adafruit TCS34725 RGB Color Sensor Breakout (includes built-in IR blocking filter and LED) — ~$8
- Test Samples: 12 AWG THHN wire scraps in Black, Red, White, and Green — ~$5
- Hardware: Half-size breadboard, 4x female-to-male jumper wires, heat-shrink tubing.
- Enclosure: 3D-printed sensor shroud (or a black electrical tape wrap) to block ambient room light.
Pin Mapping Table
The TCS34725 operates strictly on 3.3V logic. The ESP32 DevKit V1 natively provides 3.3V on its I2C pins, making this a direct, level-shifter-free connection.
| ESP32 DevKit V1 Pin | TCS34725 Breakout Pin | Function |
|---|---|---|
| GPIO 21 | SDA | I2C Data Line |
| GPIO 22 | SCL | I2C Clock Line |
| 3V3 | VIN (or 3Vo) | Power (3.3V) |
| GND | GND | Common Ground |
Assembly, Code, and Calibration Steps
Wire the components according to the pin mapping table above. Before flashing the code, wrap the TCS34725 sensor in black electrical tape, leaving only the small square glass aperture exposed. PVC wire insulation is slightly glossy; without a light shroud, your overhead room lights will wash out the sensor's reading, causing false 'White' or 'Clear' outputs.
The firmware below initializes the sensor, reads the RGB values, calculates a simplified color distance against calibrated reference points for standard wire colours, and outputs the identified role to the Serial Monitor. For detailed sensor physics, consult the Adafruit TCS34725 guide.
#include <Wire.h>
#include "Adafruit_TCS34725.h"
// Pin Definitions for ESP32 DevKit V1 (30-pin)
#define I2C_SDA 21
#define I2C_SCL 22
#define STATUS_LED 2 // Built-in LED on most DevKit V1 boards
// Sensor initialization: 50ms integration time (fast but accurate for opaque PVC), 4X gain
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
// Calibrated RGB reference points for standard THHN insulation under the sensor's built-in LED
struct ColorRef {
String name;
String role;
uint16_t r, g, b;
};
ColorRef references[] = {
{"Black", "Hot (NEC) / N/A (IEC)", 15, 12, 10},
{"Red", "Hot 2 (NEC)", 180, 40, 30},
{"White", "Neutral (NEC)", 210, 205, 200},
{"Green", "Ground (NEC)", 30, 140, 40},
{"Brown", "Line 1 (IEC)", 110, 60, 30},
{"Blue", "Neutral (IEC)", 40, 60, 160}
};
void setup() {
Serial.begin(115200);
pinMode(STATUS_LED, OUTPUT);
Wire.begin(I2C_SDA, I2C_SCL);
if (tcs.begin()) {
Serial.println("TCS34725 initialized successfully.");
digitalWrite(STATUS_LED, HIGH);
} else {
Serial.println("ERROR: TCS34725 not found... check wiring!");
while (1) {
digitalWrite(STATUS_LED, !digitalRead(STATUS_LED));
delay(250);
}
}
}
void loop() {
uint16_t clear, red, green, blue;
tcs.setInterrupt(false); // Turn on built-in LED
delay(60); // Wait for sensor integration
tcs.getRawData(&red, &green, &blue, &clear);
tcs.setInterrupt(true); // Turn off LED to save power
// Find closest match using Euclidean distance in RGB space
float minDist = 999999;
String matchName = "Unknown";
String matchRole = "N/A";
for (int i = 0; i < 6; i++) {
float dist = sqrt(
pow(red - references[i].r, 2) +
pow(green - references[i].g, 2) +
pow(blue - references[i].b, 2)
);
if (dist < minDist) {
minDist = dist;
matchName = references[i].name;
matchRole = references[i].role;
}
}
Serial.print("Detected: ");
Serial.print(matchName);
Serial.print(" | Role: ");
Serial.print(matchRole);
Serial.print(" | Raw RGB: ");
Serial.print(red); Serial.print(",");
Serial.print(green); Serial.print(",");
Serial.println(blue);
delay(1000);
}
Calibration Step
The RGB values in the references array are baselines. Because every sensor has slight factory variances and your 3D-printed shroud will alter light bounce, you must calibrate. Run the code, place a known piece of black THHN under the sensor, and read the Raw RGB output from the Serial Monitor. Update the references array with your actual readings for all six colors before relying on the tool for jobsite verification.
Debugging: First Three Things to Check When It Fails
When working with I2C sensors on the ESP32, hardware initialization failures are the most common roadblock. If your Serial Monitor outputs the exact error string: ERROR: TCS34725 not found... check wiring!, follow this ranked troubleshooting path.
- I2C Voltage and Pull-Up Mismatch (Most Likely): The genuine Adafruit TCS34725 breakout includes an onboard 3.3V regulator and I2C pull-up resistors. If you bought a generic clone, it may lack pull-ups or expect 5V logic. The ESP32 GPIO 21 and 22 are strictly 3.3V. Feeding 5V into these pins will permanently brick the ESP32-WROOM-32 module. Verify your breakout board schematic. If it lacks pull-ups, add two 4.7kΩ resistors between SDA/SCL and the 3.3V pin.
- SDA and SCL Swapped: Unlike some Arduino boards where I2C pins are fixed and clearly silkscreened, the ESP32 DevKit V1 allows I2C mapping on almost any GPIO via software. However, the default hardware I2C bus is GPIO 21 (SDA) and GPIO 22 (SCL). If you swapped these physically on the breadboard, the
Wire.begin()handshake will fail. Swap the jumper wires and reset the board. - Ambient Light Washout Causing Logic Errors: While this won't trigger the 'not found' error, it will cause the code to output 'White' for every wire. If the sensor aperture is exposed to direct sunlight or a 5000K LED work light, the clear channel will saturate (max out at 65535), destroying the RGB ratios. Ensure your light shroud is completely opaque. Test this by covering the sensor with your thumb; the raw RGB values should drop near zero.
Extending and Simplifying the Build
This benchtop prototype is highly functional, but depending on your environment, you may need to adapt the hardware.
How to Simplify the Build
If you do not need WiFi/Bluetooth capabilities and want to reduce the BOM cost and physical footprint, swap the ESP32 DevKit V1 for an Arduino Nano v3 (ATmega328P). The Nano operates at 5V, which simplifies power delivery if you are running off a standard 9V battery clip. You will need to change the I2C pins in the code to A4 (SDA) and A5 (SCL), and ensure your TCS34725 breakout is the 5V-tolerant version with an onboard voltage regulator. The code provided above is fully compatible with the Arduino IDE for the Nano without modification to the core logic.
How to Extend for Jobsite Use
A Serial Monitor is useless when you are standing on a ladder at a subpanel. To make this a standalone field tool:
- Add an OLED Display: Wire an I2C SSD1306 128x64 OLED display to the same I2C bus (SDA/SCL). Update the code to print the
matchNameandmatchRoledirectly to the screen using theAdafruit_SSD1306library. - Add Haptic/Audio Feedback: Wire a 5V active buzzer to GPIO 25. Program the ESP32 to emit a single short beep for a valid Ground/Neutral match, and a continuous warning tone if the detected color does not match the expected role for the terminal you are wiring.
- Power Supply: Integrate a 3.7V 18650 Li-ion cell and a TP4056 charging module. Because the ESP32 and sensor draw less than 80mA combined, a single 3000mAh 18650 cell will provide over 30 hours of continuous runtime.






