Automatic Staircase Lights Using Arduino And Ultrasonic Sensor
Automatic Staircase Lights Using Arduino And Ultrasonic Sensor

Automatic Staircase Lights Using Arduino And Ultrasonic Sensor

Walking up or down the stairs at night can be unsafe without proper lighting. Instead of turning on a bright floodlight, why not make your staircase intelligent and stylish? In this project, we’ll build an automatic staircase lighting system that turns on LED strips step by step as you climb, and then turns them off step by step as you exit. The system uses two ultrasonic sensors (one at the bottom, one at the top) to detect motion.

Features

  • Two ultrasonic sensors (top & bottom) detect entry/exit.
  • Sequential lighting: LEDs turn ON step by step as you walk in.
  • Automatic OFF: Lights turn OFF step by step when you reach the other end.
  • Configurable delay & distance for smooth lighting.
  • Failsafe timer: Lights will turn OFF automatically if no movement is detected.

Components Required

  • Arduino Uno (or any compatible board)
  • 2 × HC-SR04 Ultrasonic sensors
  • 12 × LEDs (or LED strips for each step)
  • 12 × Current limiting resistors (220Ω recommended)
  • Jumper wires
  • Breadboard or PCB
  • Power supply (depending on LED strip requirement)

Circuit Connections

  • Bottom sensor:

    • Trigger → A1

    • Echo → A0

  • Top sensor:

    • Trigger → A3

    • Echo → A2

  • LEDs: Connected to digital pins 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 (one per step, from bottom to top).

Circuit Diagram

Circuit Diagram Try Online: Click Here

Automatic Staircase Lights Using Arduino And Ultrasonic Sensor
Automatic Staircase Lights Using Arduino And Ultrasonic Sensor

Arduino Code

/*
  Two-sensor staircase lights (sequential ON/OFF)
  – Sensor 1 (bottom): trig=t_s1, echo=e_s1
  – Sensor 2 (top):    trig=t_s2, echo=e_s2
  – LEDs in OutPins[] map from bottom (index 0) to top (last index)
  Behavior:
    Start at Sensor 1 -> cascade ON bottom->top; on reaching Sensor 2 -> cascade OFF top->bottom
    Start at Sensor 2 -> cascade ON top->bottom; on reaching Sensor 1 -> cascade OFF bottom->top
  Notes:
    – Uses millis() (non-blocking)
    – Debounces sensor triggers
    – Auto-timeout turns lights off if other sensor is never reached
*/
//////////////////// USER SETTINGS ////////////////////
int set_dis   = 8;      // Detection distance in cm (typ. 8–20 depending on placement)
int set_shift = 500;    // Step interval (ms) between LEDs turning on/off
int set_timer = 20;     // Max seconds to wait for the opposite sensor before auto OFF
// Map your LED pins from BOTTOM (index 0) to TOP (last index)
int OutPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};==
#define e_s1 A0 // Echo pin of Sensor 1 (bottom)
#define t_s1 A1 // Trig pin of Sensor 1 (bottom)
#define e_s2 A2 // Echo pin of Sensor 2 (top)
#define t_s2 A3 // Trig pin of Sensor 2 (top)
///////////////////////////////////////////////////////
const uint8_t N_STEPS = sizeof(OutPins) / sizeof(OutPins[0]);
// ———- Internal timing & state ———-
enum Direction { NONE, UP, DOWN };   // UP = bottom->top movement, DOWN = top->bottom
enum Phase     { IDLE, ON_CASCADE, WAITING_OPPOSITE, OFF_CASCADE };
Direction dir = NONE;
Phase     phase = IDLE;
int stepIndex = -1;                 // progress pointer for cascades
unsigned long lastStepMs = 0;       // for pacing cascade steps
unsigned long waitDeadline = 0;     // for WAITING_OPPOSITE timeout
// Sensor debounce / edge detect
bool s1PrevActive = false, s2PrevActive = false;
unsigned long s1LastEdgeMs = 0, s2LastEdgeMs = 0;
const unsigned long rearmMs = 800;   // ignore repeated triggers for this long
// —————— Helpers ——————
long readDistanceCM(uint8_t trig, uint8_t echo) {
  // Trigger the ultrasonic (HC-SR04 style)
  digitalWrite(trig, LOW);  delayMicroseconds(2);
  digitalWrite(trig, HIGH); delayMicroseconds(10);
  digitalWrite(trig, LOW);
  // 30,000 us timeout ≈ 5m; avoids long blocking if nothing is seen
  unsigned long dur = pulseIn(echo, HIGH, 30000UL);
  if (dur == 0) return 0;           // no reading
  long cm = dur / 58;               // µs to cm
  return cm;
}
void setAll(bool on) {
  for (uint8_t i = 0; i < N_STEPS; i++) digitalWrite(OutPins[i], on ? HIGH : LOW);
}
void allOff() { setAll(false); }
// Edge detection with basic debounce/rearm
bool sensorEdge(bool activeNow, bool &prevActive, unsigned long &lastEdgeMs) {
  unsigned long now = millis();
  bool rising = activeNow && !prevActive && (now – lastEdgeMs > rearmMs);
  prevActive = activeNow;
  if (rising) lastEdgeMs = now;
  return rising;
}
void startSequence(Direction startDir) {
  dir = startDir;
  phase = ON_CASCADE;
  lastStepMs = 0; // force immediate first step
  if (dir == UP) {
    // Turning ON from bottom to top
    stepIndex = 0;
  } else { // DOWN
    // Turning ON from top to bottom
    stepIndex = N_STEPS – 1;
  }
}
void startWaiting() {
  phase = WAITING_OPPOSITE;
  waitDeadline = millis() + (unsigned long)set_timer * 1000UL;
}
void startOffCascade() {
  phase = OFF_CASCADE;
  if (dir == UP) {
    // Turn OFF from top to bottom
    stepIndex = N_STEPS – 1;
  } else { // DOWN
    // Turn OFF from bottom to top
    stepIndex = 0;
  }
}
void finishSequence() {
  dir = NONE;
  phase = IDLE;
  stepIndex = -1;
}
// —————— Arduino Core ——————
void setup() {
  Serial.begin(9600);
  // LED pins
  for (uint8_t i = 0; i < N_STEPS; i++) {
    pinMode(OutPins[i], OUTPUT);
    digitalWrite(OutPins[i], LOW);
  }
  // Ultrasonic pins
  pinMode(t_s1, OUTPUT); pinMode(e_s1, INPUT);
  pinMode(t_s2, OUTPUT); pinMode(e_s2, INPUT);
  digitalWrite(t_s1, LOW);
  digitalWrite(t_s2, LOW);
  // Ready
  Serial.println(F(“Stair Lights Controller: READY”));
}
void loop() {
  // —- Read sensors once per loop —-
  long d1 = readDistanceCM(t_s1, e_s1);  // bottom
  long d2 = readDistanceCM(t_s2, e_s2);  // top
  bool s1Active = (d1 > 0 && d1 <= set_dis);
  bool s2Active = (d2 > 0 && d2 <= set_dis);
  bool s1EdgeRise = sensorEdge(s1Active, s1PrevActive, s1LastEdgeMs);
  bool s2EdgeRise = sensorEdge(s2Active, s2PrevActive, s2LastEdgeMs);
  // Uncomment for debugging:
  // Serial.print(“d1=”); Serial.print(d1); Serial.print(”  d2=”); Serial.println(d2);
  unsigned long now = millis();
  switch (phase) {
    case IDLE:
      // Start from whichever sensor sees a person first
      if (s1EdgeRise) {
        // starting bottom -> going UP
        startSequence(UP);
      } else if (s2EdgeRise) {
        // starting top -> going DOWN
        startSequence(DOWN);
      }
      break;
    case ON_CASCADE:
      if (now – lastStepMs >= (unsigned long)set_shift) {
        lastStepMs = now;
        if (dir == UP) {
          // Turn ON next LED from bottom to top
          digitalWrite(OutPins[stepIndex], HIGH);
          stepIndex++;
          if (stepIndex >= (int)N_STEPS) {
            startWaiting(); // wait to see the opposite sensor
          }
        } else { // DOWN
          // Turn ON next LED from top to bottom
          digitalWrite(OutPins[stepIndex], HIGH);
          stepIndex–;
          if (stepIndex < 0) {
            startWaiting();
          }
        }
      }
      break;
    case WAITING_OPPOSITE:
      // Wait for the opposite end sensor or timeout, then cascade OFF
      if (dir == UP) {
        if (s2EdgeRise) {
          startOffCascade();
        } else if ((long)(now – waitDeadline) >= 0) {
          // Timeout fallback
          startOffCascade();
        }
      } else { // DOWN
        if (s1EdgeRise) {
          startOffCascade();
        } else if ((long)(now – waitDeadline) >= 0) {
          startOffCascade();
        }
      }
      break;
    case OFF_CASCADE:
      if (now – lastStepMs >= (unsigned long)set_shift) {
        lastStepMs = now;
        if (dir == UP) {
          // Turn OFF from top to bottom
          digitalWrite(OutPins[stepIndex], LOW);
          stepIndex–;
          if (stepIndex < 0) {
            finishSequence();
          }
        } else { // DOWN
          // Turn OFF from bottom to top
          digitalWrite(OutPins[stepIndex], LOW);
          stepIndex++;
          if (stepIndex >= (int)N_STEPS) {
            finishSequence();
          }
        }
      }
      break;
  }
}

Leave a Reply