Toggle Switches

Wiring and reading SPST and SPDT toggle switches on an ESP32 for cockpit overhead panels and control inputs.

Toggle Switch Types

Toggle switches maintain their position — ON stays ON until flipped OFF. Unlike push-buttons there is no need to track state in software; you can always read the physical position directly. Aviation panels use two main configurations:

TypePoles / ThrowsPositionsCockpit use
SPSTSingle Pole Single ThrowON / OFFMaster battery, avionics master, fuel pump
SPDT ON-ONSingle Pole Double ThrowUP / DOWNFuel selector (L / R tank), carb heat
SPDT ON-OFF-ONSingle Pole Double ThrowUP / OFF / DOWNMagneto (L / BOTH / R), trim
DPDTDouble Pole Double ThrowTwo independent SPDTRarely needed; useful for isolated circuits
Wiring — SPST Toggle
GPIO 23 GND SPST Toggle INPUT_PULLUP LOW = ON HIGH = OFF

Connect one terminal to the GPIO pin and the other terminal to GND. Enable the internal pull-up in firmware. When the switch is closed (ON) the pin is pulled to GND and reads LOW. When open (OFF) the internal pull-up holds the pin HIGH.

Switch terminalConnect to
Terminal 1GPIO pin
Terminal 2GND
Wiring — SPDT Toggle (3-Position)
GPIO 23 (A) Common → GND GPIO 22 (B) GND SPDT Toggle (arm shown at A)

An SPDT switch has three terminals: Common, A (e.g. UP), and B (e.g. DOWN). Connect Common to GND and each throw to a separate GPIO configured as INPUT_PULLUP. Only the active throw is pulled LOW; both HIGH indicates the centre-off position (ON-OFF-ON type only).

Switch positionGPIO 23 (A)GPIO 22 (B)
UP (A)LOWHIGH
Centre (OFF)HIGHHIGH
DOWN (B)HIGHLOW
Arduino Code — Single SPST

Toggle switches do not bounce significantly, so debouncing is usually not required. The switch state can simply be polled each loop iteration.

// SPST toggle — INPUT_PULLUP, LOW = switch ON
const int SW_PIN = 23;

void setup() {
    Serial.begin(115200);
    pinMode(SW_PIN, INPUT_PULLUP);
}

void loop() {
    bool isOn = (digitalRead(SW_PIN) == LOW);
    Serial.println(isOn ? "Switch: ON" : "Switch: OFF");
    delay(200);
}
Arduino Code — Overhead Panel (8 Switches)

Only report state changes rather than printing every poll tick. This produces clean serial output that maps directly to simulator dataref writes.

// Overhead panel — 8 toggle switches, only report on state change
const int SW_PINS[]    = { 23, 22, 21, 19, 18, 5, 4, 2 };
const char* SW_NAMES[] = {
    "MASTER BAT", "MASTER ALT", "AVIONICS",
    "FUEL PUMP",  "BEACON",     "LAND LIGHT",
    "TAXI LIGHT", "STROBE"
};
const int SW_COUNT = 8;

bool swStates[SW_COUNT];

void setup() {
    Serial.begin(115200);
    for (int i = 0; i < SW_COUNT; i++) {
        pinMode(SW_PINS[i], INPUT_PULLUP);
        swStates[i] = digitalRead(SW_PINS[i]);
    }
}

void loop() {
    for (int i = 0; i < SW_COUNT; i++) {
        bool state = digitalRead(SW_PINS[i]);
        if (state != swStates[i]) {
            swStates[i] = state;
            Serial.print(SW_NAMES[i]);
            Serial.println(state == LOW ? " -> ON" : " -> OFF");
        }
    }
    delay(20);   // 50 Hz poll — fast enough for human input
}
Arduino Code — SPDT (3-Position)
// SPDT toggle — two GPIOs, exactly one LOW when switch is thrown
// Common → GND;  Terminal A → GPIO 23;  Terminal B → GPIO 22
const int PIN_A = 23;
const int PIN_B = 22;

void setup() {
    Serial.begin(115200);
    pinMode(PIN_A, INPUT_PULLUP);
    pinMode(PIN_B, INPUT_PULLUP);
}

void loop() {
    bool a = (digitalRead(PIN_A) == LOW);
    bool b = (digitalRead(PIN_B) == LOW);

    if      (a) { Serial.println("Position: UP (A)");   }
    else if (b) { Serial.println("Position: DOWN (B)"); }
    else        { Serial.println("Position: CENTRE (OFF)"); }
    // ON-OFF-ON type: both HIGH = centre off position

    delay(200);
}

For a magneto switch (L / BOTH / R) the BOTH position is inferred when both A and B are HIGH on an ON-OFF-ON type, or use a 3-position rotary switch with three separate GPIOs instead.

Cockpit Applications
ApplicationSwitch typeNotes
Master battery / alternatorSPST (red guard cover)Map to sim electrical system datarefs
Avionics masterSPSTCan simulate boot-up delay in firmware before enabling avionics datarefs
Fuel selector (L / R)SPDT ON-ONTwo throws map to two tank datarefs
Magneto (L / BOTH / R)SPDT ON-OFF-ONThree states encoded with two GPIO pins
Pitot heat / de-iceSPSTDirect ON/OFF toggle to anti-ice dataref
Gear override guardSPST (guard cover)Guard physically prevents accidental actuation