Stairs with arduino, WS2812B LED, PIR and IR remote controller

Hello everyone,

I made this post, because I am currently making a LED lights for my stairs. I was searching for a good solution for my problem, but I can not find anything suitable.

I want to make a LED stairs lights, strips mounted under the every step, summary I have 17 steps, but a lot of them have a different length from 96 to 135 cm, I want to mount it on the full length of the steps. I am using WS2812B 30/m LED strips connected to Arduino Uno, I am also using a two PIR sensors at the bottom and top of the stairs and one photosensitive sensor mounted at the bottom next to the PIR sensor. I decided to add also a IR remote controller to change a program of the lights. Everything is powered by the 5V 40A power supply.

For now I used some of the found codes and mixed it in one good working code, but this code is working only for the stairs with the same length of the steps, in my project only 9 from 17 stairs will have the same length.

I want also to use remote controller to change the ways of turning on the LED strips, for example:

  • button 1 & default - step 1 --> step 2 --> step 3 ...
  • button 2 - step 17 --> step 16 --> step 15 ...
  • button 3 - all steps from left to right
  • button 4 - all steps from right to left
  • button 5 - step 1, 3, 5, 7... from left to right, 2, 4, 6, 8... from right to left

And maybe some more, I have 9 numeric buttons on the remote controller.

Do you maybe have some idea what is the best way to separate every step for using every one by the own way?

I am attaching my code which, thanks in advance!

Stairs.ino (10.5 KB)

When doing a project split it up into small manageable parts. Do not work on it all at the same time.

Do you maybe have some idea what is the best way to separate every step for using every one by the own way?

You use an array to hold the number of LEDs in each step.

I can’t see your code because it is in a format my mobile device will not read. That is why we tell you how to post code if you could have been bothered reading the how to use this forum sticky post.

Thank you for information,

here is the code, I had to make it a little bit shorter, I tried to attach it like now but I had error about exceeding the maximum allowed length, could you tell me something more now?

#include <Adafruit_NeoPixel.h>
#include <IRremote.h>

#define PIN 6
#define NUM_LEDS 150
#define receiver 9  // IR receiver pin 

#define BUTTON_C 0xFFFFFFFF
#define BUTTON_1 0xFFA25D
#define BUTTON_2 0xFF629D

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);


// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.


// Set up Variables
unsigned long timeOut=60000;  // timestamp to remember when the PIR was triggered.
int downUp = 0;               // variable to rememer the direction of travel up or down the stairs
int alarmPinTop = 11;         // PIR at the top of the stairs
int alarmPinBottom =11;        // PIR at the bottom of the stairs
int alarmValueTop = LOW;      // Variable to hold the PIR status
int alarmValueBottom = LOW;   // Variable to hold the PIR status
int ledPin = 13;              // LED on the arduino board flashes when PIR activated
int LDRSensor = A0;           // Light dependant resistor
int LDRValue = 0;             // Variable to hold the LDR value
int colourArray[350];         // An array to hold RGB values
int change = 1;               // used in 'breathing' the LED's
int breathe = 0;              // used in 'breathing' the LED's
IRrecv irrecv(receiver); //create a new instance of receiver
decode_results results;
unsigned long lastCode;


void setup() {
     strip.begin();
     strip.setBrightness(50);                //adjust brightness here
     strip.show();                           // Initialize all pixels to 'off'
     Serial.begin (9600);                    // only requred for debugging
     pinMode(ledPin, OUTPUT);                // initilise the onboard pin 13 LED as an indicator
     pinMode(alarmPinTop, INPUT_PULLUP);     // for PIR at top of stairs initialise the input pin and use the internal restistor
     pinMode(alarmPinBottom, INPUT_PULLUP);  // for PIR at bottom of stairs initialise the input pin and use the internal restistor
     pinMode(receiver, INPUT_PULLUP);
     irrecv.enableIRIn();                    //start the receiver
     delay (2000);                           // it takes the sensor 2 seconds to scan the area around it before it can detect infrared presence
}


void loop() {

  if (irrecv.decode(&results)) { //we have received an IR code
  Serial.println(results.value, HEX);
  irrecv.resume();
  }
  translateIR();
}

void translateIR() {
  switch (results.value) {

    case BUTTON_1:
    stairs();
    break;

    case BUTTON_2:
    blueWhiteChase();
    break;

    case BUTTON_C:
    results.value = lastCode;
    break;

    default:
    stairs();
    break;
  }
  delay(0);
}

void stairs() {
    LDRValue = analogRead(LDRSensor);
    //Serial.println(LDRValue);

  if (LDRValue > 600) {                  // only switch on LED's at night when LDR senses low light conditions - you may have to change the number for your circumstances!

    if (timeOut+15700 < millis()) {        // idle state - 'breathe' the top and bottom LED to show program is looping
       uint32_t blue = (0, 0, breathe);
       breathe = breathe + change;
       strip.setPixelColor(0, blue);
       strip.setPixelColor(34, blue);
       strip.setPixelColor(35, blue);
       strip.setPixelColor(69, blue);
       strip.show();
       if (breathe == 100 || breathe == 0) change = -change;      // breathe the LED from 0 = off to 100 = fairly bright
       if (breathe == 100 || breathe == 0); delay (50);           // Pause at beginning and end of each breath
       delay(10);
  }
  
      alarmValueTop = digitalRead(alarmPinTop);                   // Constantly poll the PIR at the top of the stairs
      //Serial.println(alarmPinTop);
      alarmValueBottom = digitalRead(alarmPinBottom);             // Constantly poll the PIR at the bottom of the stairs
      //Serial.println(alarmPinBottom);

      if (alarmValueTop == HIGH && downUp != 2)  {                // the 2nd term allows timeOut to be contantly reset if one lingers at the top of the stairs before decending but will not allow the bottom PIR to reset timeOut as you decend past it.
          timeOut=millis();                                       // Timestamp when the PIR is triggered.  The LED cycle wil then start.
          downUp = 1;
          //clearStrip();
          topdown();                                              // lights up the strip from top down
      }

      if (alarmValueBottom == HIGH && downUp != 1)  {             // the 2nd term allows timeOut to be contantly reset if one lingers at the bottom of the stairs before decending but will not allow the top PIR to reset timeOut as you decend past it.
          timeOut=millis();                                       // Timestamp when the PIR is triggered.  The LED cycle wil then start.
          downUp = 2;
          //clearStrip();
          bottomup();                                             // lights up the strip from bottom up
      }

      if (timeOut+10000 < millis() && timeOut+15000 < millis()) {             //switch off LED's in the direction of travel.
          if (downUp == 1) {
              colourWipeDown(strip.Color(0, 0, 0), 100); // Off
          }
          if (downUp == 2)  {
              colourWipeUp(strip.Color(0, 0, 0), 100);   // Off
          }
          downUp = 0; 
      }  
  } 

   else if (LDRValue < 600) {
    colourWipeUp(strip.Color(0, 0, 0), 100);
   }
}


void topdown() {
    Serial.println ("detected top");                          // Helpful debug message
    colourWipeDown(strip.Color(255, 241, 224), 25 );          // Warm White
    //for(int i=0; i<3; i++) {                                // Helpful debug indication flashes led on Arduino board twice
      //digitalWrite(ledPin,HIGH);
      //delay(200);
      //digitalWrite(ledPin,LOW);
      //delay(200);
    //}
}


void bottomup() {
    Serial.println ("detected bottom");            // Helpful debug message
    colourWipeUp(strip.Color(255, 241, 224), 25);  // Warm White
    //for(int i=0; i<3; i++) {                     // Helpful debug indication flashes led on Arduino board twice
      //digitalWrite(ledPin,HIGH);
      //delay(200);
      //digitalWrite(ledPin,LOW);
      //delay(200);
    //}
}


// Fade light each step strip
void colourWipeDown(uint32_t c, uint16_t wait) {

  for (uint16_t j = 0; j < 15; j++){
  int start = strip.numPixels()/15 *j;
  Serial.println(j);
    
        for (uint16_t i = start; i < start + 35; i++){
    strip.setPixelColor(i, c);
        }
      strip.show();  
  delay(wait);
  }
}


void clearStrip(){
  for (int l=0; l<strip.numPixels(); l++){
    strip.setPixelColor(l, (0,0,0));
  } 
}


// Fade light each step strip
void colourWipeUp(uint32_t c, uint16_t wait) {
   for (uint16_t j = 15; j > 0; j--){
   int start = strip.numPixels()/15 *j;
   Serial.println(j);
      //start = start-1;
          for (uint16_t i = start; i > start - 35; i--){
          strip.setPixelColor(i-1, c);
         }
          strip.show();
  delay(wait);
  }  
}


void blueWhiteChase() {
  static int i = 0;
  for (int j = -5; j < 150; j = j + 6) {
    if (j+i < 0);
    strip.setPixelColor(j+i, 0, 0, 30);
    strip.setPixelColor(j+i+1, 0, 0, 100);
    strip.setPixelColor(j+i+2, 0, 0, 255);
    strip.setPixelColor(j+i+3, 30, 30, 30);
    strip.setPixelColor(j+i+4, 90, 90, 90);
    strip.setPixelColor(j+i+5, 180, 180, 180);
  }
  strip.show();
  i = (i+1)%600;
}

The code is a lot of a mess. Like I said you are trying to do too much at once without getting bits of it going at once. Using IR messages in a project with WS2812 LEDs is always going to be tricky because sending data to the LEDs is going to blind side the IR receiver code while this happens.

For example the blueWhiteChase() function has the variable i ranging between 0 and 600, this is added to j which can be between 0 and 150 plus a constant that can be up to 5 which means you are addressing LED number 755. Now you only have 150 LEDs so you are writing outside the reserved memory for the array. This can cause unexpected behavior to say the least.

You have

int colourArray[350];

But you never use this array, fortunately the compiler is likely to just ignore this otherwise you would waste 700 bytes of program memory.

I think you need to start again. Start simply by writing a function that lights up one step when you pass it the step number and the RGB values of the colour you want to set it.
So you will need an array that specifies the number of LEDs in each step and and array that specifies the start LED number of each step.

Try that and come back for help or adding the next stage.

Thank you for information.

I don't need a perfect program, I need just a working program. For now IR remote is working properly, I see any problems with it.

blueWhiteChase() is for now just a simple program to check how the IR remote controlling is working, at the end I will delete it.

I tried to separate all steps this way:

void program1() {
  int i = 0;
  for (i = 0; i <= 29; i++) {              // Step 1
    strip.setPixelColor(i, strip.Color(255, 255, 255));
    strip.show();
    delay(0);
  }
    for (i = 59; i >= 30; i--) {           // Step 2
    strip.setPixelColor(i, strip.Color(255, 255, 255));
    strip.show();
    delay(0);
  }
}

but I think that it is too much code if I will have to make 17 steps and maybe 9 programs. That's why I decided to make this topic and ask in the first post:

Do you maybe have some idea what is the best way to separate every step for using every one by the own way?

What's your idea for separating every step in the code?

“I don't need a perfect program, I need just a working program. ”

To achieve a working program, you need a perfect program.

1 Like

To achieve a working program, you need a perfect program.

Thank you for information, but I wrote this because of:

The code is a lot of a mess.

but I wrote before:

is working properly

I am now thinking not about the Arduino but about other things - is this forum made for solving the problems and for helping people answering the questions or just for people who don't have anything to do so they can stop here for a while and get people off track or send people back to other places like books and simple programs?

I am only hobbyist, I am doing only sometimes thing like this, I am not working as a developer so I can not know it all, learning all language only for do the light for stairs also don't have any sens.

In my topic I only asked for one thing:

Do you maybe have some idea what is the best way to separate every step for using every one by the own way?

So people please, don't make "a lot of a mess" on this forum. If somebody is able to just answer this question and want to do this, I will be grateful for help.

Not sure what you are asking for exactly.

Are you familiar with using ‘state machine coding’.

So one more time.

I what to make a LED WS2812B lights for my stairs. I found three different codes (first for stairs with one LED strip on the side of the stairs with a photosensitive sensor, second for stairs where every step have own LED strip but without a photosensitive sensor and third for a controlling something by the IR remote controller) and combined it.

For now everything is working correct, but my stairs are a little bit different than all from the codes. In the code somebody had 15 steps, 35 LED on every step, every step had the same length. I have a stairs where every step have a different length, for example:

  • step 1 - 164 cm, 49 LED,
  • step 2 - 88 cm, 26 LED,
  • step 3 - 88 cm - 26 LED,
  • step 4 - 96 cm - 29 LED,
  • step 5 - 122 cm - 37 LED,
  • step 6 - 103 cm - 31 LED,
  • step 7 - 88 cm - 26 LED,
  • step 8 - 88 cm - 26 LED,
  • step 9 - 88 cm - 26 LED
  • step 10 - 88 cm - 26 LED.

In the project I also want to use the IR remote controller for turning it on static or to change the turning on mode.

I can do this by something like:

void program1() {
  int start = 0;
  for (uint16_t i = start; i < start + 10; i++){
    strip.setPixelColor(i, strip.Color(255, 241, 0));
        }
      strip.show();  
  delay(100);  

  for (uint16_t i = 10; i < 10 + 10; i++){
    strip.setPixelColor(i, strip.Color(255, 0, 0));
        }
      strip.show();  
  delay(100); 

  for (uint16_t i = 20; i < 20 + 10; i++){
    strip.setPixelColor(i, strip.Color(255, 0, 255));
        }
      strip.show();  
  delay(100);
}

but maybe somebody have some better idea?

About the "state machine coding" - not so much I was only making a simple changes on the websites, so I know a little bit how to edit the code, that's why I am asking for help on the forum.

Help yourself and us by adding comments to your lines of code.

example: // turning on the pixels to white on the first stair.

The only thing you are having problems is with the 10 steps portion of code?

Are the the pixels on the steps all wired in series or does each step go to a separate output on the controller?

What do you think this is doing?
for (uint16_t i = start; i < start + 10; i++){ . . .

So one more time.

So one more time this question has been answered. You choose not to take the advice then what are we to do? I for one am not going to do it for you but I am willing to help you solve the problem and help you learn about what you are doing and what you need to do.

But your repeated refusals to engage in meaningful cooperation is not helping you. If there is something you don't understand about the advice I have given you then ask about what you don't understand, do not turn your back and think everything is fine. Do not imagine you have your code anywhere near complete and just need a small tweek to get it working.

For now everything is working correct

No it is not or you would not be asking here. Your code does what it dose and changes in what you want it to do will require changes that I have told you about.

In case you missed it I said:-

you will need an array that specifies the number of LEDs in each step and and an array that specifies the start LED number of each step.

So the choice is yours, engage or ship out.