To wire a button to an Arduino for controlling a load, use the internal pull-up resistor configuration. Connect one button terminal to GND using a black wire, and the other terminal to a digital input pin (e.g., D2) using a red wire. In your code, set the pin mode to INPUT_PULLUP. This eliminates the need for external resistors, prevents floating-pin errors, and provides a clean, active-LOW signal when the button is pressed. When driving a 120V AC load, you will route this logic signal through an optocoupler-isolated 5V relay module.
Tools, Materials, and Wire Sizing
Before stripping any wire, ensure you have the correct gauge and device ratings for both the low-voltage logic side and the high-voltage mains side. Mixing these up is a primary cause of melted terminals and board damage.
Logic Side (5V DC)
- Microcontroller: Arduino Uno R3 or R4 Minima.
- Switch: 6x6mm momentary tactile pushbutton (e.g., Omron B3F series) or a panel-mount SPST momentary switch.
- Wire: 22 AWG solid-core copper. Solid core is mandatory for breadboard holes; if using screw terminals, use 22 AWG stranded with crimped ferrules. Insulation rating: 300V minimum. Current load: <50mA.
- Relay Module: 5V DC single-channel relay module with an optocoupler and flyback diode (e.g., Songle SRD-05VDC-SL-C based modules). Rated for 10A at 120VAC resistive loads.
Mains Side (120V AC)
- Wire: 14 AWG THHN copper (stranded or solid). Rated for 600V, 90°C. Ampacity: 15A (per NEC 310.16 60°C column for standard branch circuits).
- Connectors: Wire nuts or Wago 221 lever-nuts for in-line splices; crimp spade terminals for relay screw connections.
- Enclosure: NEMA 1 or NEMA 3R junction box to house the relay and mains splices. Never leave mains relay terminals exposed on a workbench.
Mains Safety and Isolation Rules
While the Arduino button operates at a safe 5V DC, the relay module switches 120V AC. Working on the mains side of the relay requires strict adherence to electrical safety protocols. Before making any connections to the relay's COM, NO, or NC screw terminals:
- De-energize: Turn off the circuit breaker supplying the 120V line at the main panel.
- Lock/Tag: Apply a lockout/tagout device to the breaker so it cannot be accidentally switched on while you are wiring.
- Verify Dead: Use a CAT III or CAT IV non-contact voltage tester (NCVT) and a multimeter to verify 0V AC between the Hot and Neutral, and Hot and Ground wires.
NEC-style guidance: Low-voltage (Class 2) control wiring must be physically separated from line-voltage wiring inside enclosures unless separated by a permanent barrier. Your local AHJ has final authority on enclosure fill and separation rules.
The Decision Path: Internal Pull-Up vs. External Resistors
When wiring a button to a microcontroller, the digital pin must never be left 'floating' (disconnected from a defined voltage) when the button is open. You have three ways to solve this. Use the decision tree below to select your configuration.
| Configuration | Wiring | Code Logic | Pros & Cons |
|---|---|---|---|
| Internal Pull-Up | Button between Pin and GND | Active-LOW (Press = 0) | Pros: Zero extra parts, clean wiring. Cons: Inverted logic (requires mental flip). |
| External Pull-Down | Button between 5V and Pin; 10kΩ resistor from Pin to GND | Active-HIGH (Press = 1) | Pros: Intuitive logic. Cons: Requires breadboard space, extra 10kΩ resistor. |
| External Pull-Up | Button between Pin and GND; 10kΩ resistor from Pin to 5V | Active-LOW (Press = 0) | Pros: Stronger noise immunity for long wire runs. Cons: Unnecessary for short runs. |
Step-by-Step Wiring Procedure
Follow these steps to wire the logic side and the mains side. Wire colors are explicitly defined for every termination to maintain standard DC polarity and AC line conventions.
Part 1: Low-Voltage Logic Wiring (De-energized USB)
- Button to Ground: Strip 1/4 inch of insulation from a black 22 AWG wire. Insert one end into the breadboard row connected to Button Pin 2. Insert the other end into the Arduino's GND pin.
- Button to Digital Input: Strip a red 22 AWG wire. Insert one end into the breadboard row connected to Button Pin 1. Insert the other end into Arduino Digital Pin 2 (D2).
- Relay Power (VCC): Run a red 22 AWG wire from the Arduino 5V pin to the relay module's VCC screw terminal (or header pin).
- Relay Ground: Run a black 22 AWG wire from a second Arduino GND pin to the relay module's GND screw terminal.
- Relay Signal: Run a yellow 22 AWG wire from Arduino Digital Pin 3 (D3) to the relay module's IN (or Signal) terminal.
Part 2: Mains Load Wiring (Breaker OFF, Verified Dead)
- Mains Hot to Relay: Strip 3/8 inch of the black 14 AWG THHN Hot wire from your wall junction box. Crimp a spade terminal and land it on the relay's COM (Common) screw terminal. Tighten to 0.5 Nm.
- Relay to Load Hot: Crimp a spade terminal on a second black 14 AWG wire. Land it on the relay's NO (Normally Open) screw terminal. Route the other end to your load's Hot terminal.
- Neutral Bypass: The relay does not switch neutral. Connect the white 14 AWG Mains Neutral wire directly to the white Load Neutral wire using a Wago lever-nut.
- Equipment Ground: Connect the green/bare 14 AWG Mains Ground wire to the green/bare Load Ground wire and bond it to the metal junction box if applicable.
Verify and Test: Expected Meter Readings
Do not plug the Arduino into USB or turn on the mains breaker until you have verified the circuit with a digital multimeter (DMM).
- Set DMM to the 200Ω continuity range.
- Place probes across Button Pin 1 and Pin 2. Expected: OL (Open Loop) when released; < 1.0 Ω (and an audible beep) when pressed.
- Place one probe on Arduino D2 and the other on Button Pin 1. Expected: < 1.0 Ω (verifies the red wire path).
- Set DMM to 200kΩ resistance.
- Measure between the relay COM screw and the relay coil VCC pin. Expected: OL. (If you read low resistance, the relay's optocoupler isolation has failed; discard the module).
- Plug in Arduino USB. Set DMM to 20V DC. Measure between Arduino 5V and GND. Expected: 4.8V to 5.1V.
- Measure between Arduino D2 and GND. Expected: ~5.0V (pulled high by internal resistor). Press button: Expected: drops to 0.0V.
- Turn on mains breaker. Set DMM to 200V AC. Measure across the load's Hot and Neutral. Expected: 0V AC (relay open). Trigger the code to close the relay: Expected: 114V - 126V AC.
The Most Common Botch: Floating Pins and Phantom Triggers
The most frequent mistake when wiring a button to an Arduino is connecting the button between 5V and the digital pin without adding an external pull-down resistor to GND.
The Symptom: The relay clicks erratically, or the serial monitor prints random button presses when you wave your hand near the breadboard.
The Physics: When the button is open (not pressed), the digital pin is disconnected from both 5V and GND. It enters a high-impedance 'floating' state. In this state, the pin and its attached wire act as an antenna, picking up 60Hz electromagnetic interference from nearby mains wiring, fluorescent lights, or even the static charge on your body. The Arduino reads this noise as rapid HIGH/LOW transitions.
The Fix: Always use INPUT_PULLUP in your code and wire the button to GND, or physically wire a 10kΩ resistor from the digital pin to GND if you must use an active-HIGH configuration. Never leave a digital input pin unterminated.
Complete Debounced Code for INPUT_PULLUP
Mechanical buttons suffer from 'contact bounce'—the metal contacts physically rattle for a few milliseconds when pressed, causing the Arduino to read multiple rapid presses. The code below uses a non-blocking millis() timer to debounce the signal without relying on external libraries.
// Pin Definitions
const int BUTTON_PIN = 2; // Red wire to button, black wire to GND
const int RELAY_PIN = 3; // Yellow wire to relay IN
// Debounce Variables
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50; // 50ms debounce window
int lastButtonState = HIGH; // INPUT_PULLUP defaults to HIGH
int currentRelayState = LOW;
void setup() {
// Initialize Serial for debugging
Serial.begin(115200);
// Configure pins
pinMode(BUTTON_PIN, INPUT_PULLUP); // Enables internal 20k-50k pull-up resistor
pinMode(RELAY_PIN, OUTPUT);
// Ensure relay is safely OFF at boot
digitalWrite(RELAY_PIN, LOW);
}
void loop() {
// Read the button state (LOW means pressed due to pull-up)
int reading = digitalRead(BUTTON_PIN);
// Check for state change and debounce
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// If the state has stabilized and the button is currently pressed (LOW)
if (reading == LOW && lastButtonState == HIGH) {
// Toggle the relay state
currentRelayState = !currentRelayState;
digitalWrite(RELAY_PIN, currentRelayState);
Serial.print("Relay Toggled: ");
Serial.println(currentRelayState == HIGH ? "ON" : "OFF");
}
}
// Save the current reading for the next loop iteration
lastButtonState = reading;
}
For deeper understanding of microcontroller pin configurations, refer to the official Arduino pinMode() documentation. When integrating this circuit into a permanent home installation, always consult the NFPA 70 National Electrical Code (NEC) regarding low-voltage and line-voltage separation requirements in junction boxes.






