Arduino + PIR_Motion Sensor + FastLED

Hi. I want to have a WS2812b LED strip turn on and off depending on the state of a PIR Sensor.

This is my first project with the aruino+programming in general, I’m doing my best!

The on state is supposed to be a smooth rainbow color, and when the Strip turns off, I want it to display a curtain effect. So that the strip fills red from both edges at the same time and back. Once it’s reached both ends of the strip, it is supposed to stay off until movement is detected.

Here’s what I’ve managed so far:

#include <FastLED.h>
#define DATA_PIN 6 // Pin for the LED_Strip
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define NUM_LEDS 150
CRGB leds[NUM_LEDS];

#define BRIGHTNESS 255
#define FRAMES_PER_SECOND 120

int pirInputPin = 2;              // choose the input pin (for PIR sensor)
int pirState = LOW;          // by default, no motion detected
int pirVal = 0;              // variable for reading the pin status

void setup() {
  delay(1000);
  // tell Fast LED about the LED strip configuration
  pinMode(LED_BUILTIN, OUTPUT);  // to verify if Motion Sensor works!
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);

  pinMode(pirInputPin, INPUT);    // initialize sensor as an input
  Serial.begin(9600);        // initialize serial
}


uint8_t gHue = 0;



void loop(){
  pirVal = digitalRead(pirInputPin);   // read sensor value
  if (pirVal == HIGH) {           // check if the sensor is HIGH
    digitalWrite(LED_BUILTIN, HIGH); // to verify if Motion Sensor works. On
// here follows what the WS2812B is supposed to do when Sensor = HIGH
    FastLED.setBrightness(255);
    FastLED.show();
    FastLED.delay(1000/FRAMES_PER_SECOND);
    EVERY_N_MILLISECONDS( 20 ) { gHue++; } // slowly cycle the "base color" through the rainbow
    rainbow();
    //FastLED.delay(10);                // delay 100 milliseconds

 //    strip.show();
 //   delay(10);
    if (pirState == LOW) {
      Serial.println("Motion detected! rainbow");
      pirState = HIGH;       // update variable state to HIGH
    }
  } else {
      digitalWrite(LED_BUILTIN, LOW); // to verify if Motion Sensor works. Off

 // here follows what the WS2812B is supposed to do when Sensor = LOW
      FastLED.clear();
      myownred();

  if (pirState == HIGH) {
        Serial.println("Motion stopped! red");
        pirState = LOW;       // update variable state to LOW
    }
  }
}

// this is where functions are defined
void rainbow()
{
  // FastLED's built-in rainbow generator
  fill_rainbow( leds, NUM_LEDS, gHue, 7);
}


void myownred() {
for(int dot = 0; dot < 75; dot++) {

            leds[dot] = CRGB::Red;
            FastLED.show();
            // clear this led for the next time around the loop
            //leds[dot] = CRGB::Snow;
            delay(60);

        }
for(int dot = (NUM_LEDS); dot >= 75; dot--) {
                    FastLED.show();
                    leds[dot] = CRGB::Red;

                    // clear this led for the next time around the loop
                    //leds[dot] = CRGB::Blue;
                    delay(60);
                }
}

I took snippets of the code from the examples and what I found about how to use the PIR sensor.

Now the rainbow, i.e. ON part does not look like in the demo: It has a moving red pixel in it which blinks This unwanted effect goes away if instead of myownred function I call another predefined function from demoReel100.

The OFF part, i.e. the red filling dots has several problems:

  1. it is not interruptable, if motion is detected, nothing happens until the whole function myownred is carried out.
  2. I don’t know how I can make it stay black/ all pixels turned off

Again, replacing myownred function with one from the demoReel100, for example juggle, the off state is interruptable

How can I fix my issues?

Coulomb_F: How can I fix my issues?

Don’t use EVERY_N_MILLISECONDS(){} nor delay nor built in blocking demo functions you need to handle timing yourself in a non blocking way, study a millis() tutorial (read the « Useful links - check here for reference posts / tutorials » link)

Thanks. But the EVERY_N_MILLISECONDS() is responsible for making the rainbow effect. If I remove it, there is no floating rainbow. I added the delay(); function because without it the red dots move way to fast.

But I will take a look at the tutorial

You could code the rainbow yourself...

Well, since this is my first project, I don’t know if coding a rainbow effect is a little bit too advanced for a beginner. I mean I am learning as I go. I have read the documentation of FastLED and they have a built in rainbow effect. It is called fill_rainbow. The problems I was having was with RainbowWithGlitter, I actually did manage to write that glitter function myself and add it to the fill_rainbow function.

void rainbow()
{
  // FastLED's built-in rainbow generator
  fill_rainbow( leds, NUM_LEDS, gHue, 7);
}

Now what I did and what worked was remove the delay(); functions but I kept the EVERY_N_MILLISECONDS.

Also, I have found another rainbow effect from this website: Tweaking4All.com - Arduino – All LEDStrip effects in one (NeoPixel and FastLED) . They have included a rainbow effect that seems like it was coded “from scratch”

void rainbowCycle(int SpeedDelay) {
  byte *c;
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< NUM_LEDS; i++) {
      c=Wheel(((i * 256 / NUM_LEDS) + j) & 255);
      setPixel(i, *c, *(c+1), *(c+2));
    }
    showStrip();
    delay(SpeedDelay);
  }
}

But I noticed that they use a Button to advance in the effects, and for that use the break; control structure.

I will try if I can make it work using that. I just have to figure out how I can change the program so that a Button Press will become a HIGH or LOW signal from my PIR sensor