Preview:
/*
  Touchless ESP32 Switch
  ----------------------

  WIRING NOTES

  1. POWER
     Power bank 5V  -> ESP32 VIN/5V
     Power bank GND -> ESP32 GND

     Power bank 5V  -> Relay VCC
     Power bank GND -> Relay GND

     Power bank 5V  -> IR Sensor VCC
     Power bank GND -> IR Sensor GND

     IMPORTANT:
     All grounds must be common.

  2. IR SENSOR
     IR Sensor OUT -> GPIO 27

     Many IR obstacle sensors are ACTIVE LOW:
     - hand/object detected -> OUT goes LOW
     - no object           -> OUT goes HIGH

     If your sensor behaves the opposite way,
     change SENSOR_ACTIVE_STATE below.

  3. RELAY MODULE
     Relay IN -> GPIO 26

     Many relay modules are ACTIVE LOW:
     - GPIO LOW  -> relay ON
     - GPIO HIGH -> relay OFF

     If your relay behaves the opposite way,
     change RELAY_ACTIVE_STATE below.

  4. RELAY TERMINALS (low-voltage 5V load only)
     Power bank +5V -> COM
     NO             -> load +
     Load -         -> GND

     This makes the load OFF by default and ON when relay activates.

  5. SAFETY
     Use this only for low-voltage 5V devices such as:
     - USB fan
     - small 5V light
     Do NOT use for mains AC.
*/

const int sensorPin = 27;
const int relayPin  = 26;

// Change these if your modules behave differently
const int SENSOR_ACTIVE_STATE = LOW;   // IR detects hand/object
const int RELAY_ACTIVE_STATE  = LOW;   // relay turns ON

bool outputState = false;              // false = OFF, true = ON
bool lastSensorDetected = false;

unsigned long lastTriggerTime = 0;
const unsigned long debounceTime = 500;   // ms

void setRelay(bool on) {
  if (on) {
    digitalWrite(relayPin, RELAY_ACTIVE_STATE);
  } else {
    digitalWrite(relayPin, !RELAY_ACTIVE_STATE);
  }
}

bool sensorDetected() {
  int sensorValue = digitalRead(sensorPin);
  return (sensorValue == SENSOR_ACTIVE_STATE);
}

void setup() {
  Serial.begin(115200);

  pinMode(sensorPin, INPUT);
  pinMode(relayPin, OUTPUT);

  // Start with output OFF
  setRelay(false);

  Serial.println("Touchless switch ready.");
}

void loop() {
  bool detected = sensorDetected();
  unsigned long now = millis();

  // Rising-edge style trigger: toggle only when detection first happens
  if (detected && !lastSensorDetected && (now - lastTriggerTime > debounceTime)) {
    outputState = !outputState;
    setRelay(outputState);

    Serial.print("Sensor triggered. Output is now: ");
    Serial.println(outputState ? "ON" : "OFF");

    lastTriggerTime = now;
  }

  lastSensorDetected = detected;

  delay(20);
}
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter