Advice on LED code to fade in, remain at level, fade out

Hi All

So I am progressing through my home night time subdued lighting project and have recently installed a 12V analogue RGB LED strip on the stairway, activated by an appropriately positioned PIR, and all works fine.

I have a simple setting for the LED's which when the PIR detects a presence, they display a nice purple colour that fades in and out gently - by using two simple 'for' loops, until no presence is detected and they then turn off. What I want to do is something else though, and it's here I need some help and guidance.

Upon detection by the PIR, I want to be able to:

1 - slowly fade in the LED's
2 - have them remain on at that level for the set time as defined by the position of the potentiometer on the PIR sensor module
3 - At the end of the cycle have them gently fade out

Here's my problem, I am not sure how to get them to do this using the structure I have, as the control code is in the 'Void Loop' statement and thus continuously cycles through this loop. I could write the code to achieve what is in 1,2 and 3 above, but then this will continually cycle through fading in, remaining at a level then fading out - all in the cycle to be repeated at whatever speed the Arduino is opetating at etc. and this is not what I want.

So I am trying to figure out a way to have that effect and I am guessing it needs to be done on state change? Would that be the way to do this?

The PIR sensors have two onboard potentiomenters that control the time the detection is kept on, and the sensitivity of the sensor (how far away it will detect someone). The operation is such that upon detection the output is made high, and remains high until 'n' seconds (via onboard potentiometer) after last detection, then goes low, remains low for at least 3 seconds (part of the PIR sensor, don't know why this is the case) and then remains low until movement is detected et al.

So, do I need to learn about state changes so that I can construct some code that will only execute when the state of the PIR output changes etc rather than using the if then else statement I currently have, or is there another alternative, a better way I am not aware of?

Here's the current code I use to control the LED's

  // Code for LED Strip control

  if (PIRstairsValue == 0)
  {
    Driver.begin();
    Driver.SetColor(0, 0, 0);       // Make sure LED's are OFF
    Driver.end();
  }
  else
  {
    for (i = 50; i < 100; i++)      // Simple loop to fade brightness of colour (i) up
    {
      Driver.begin();
      Driver.SetColor(i, 0, i);     // Set colour value R-G-B (in this case it is Purple)
      Driver.end();
      delay(LEDdelay);
    }
    for (i = 100; i > 50; i--)      // Simple loop to fade brighness of colour (i) down
    {
      Driver.begin();
      Driver.SetColor(i, 0, i);
      Driver.end();
      delay(LEDdelay);
    }
  }
  // End of LED Strip Control code

Any pointers would be appreciated, thanks.

I would add a variable, for example pirActive. When you begin fadein set this variable to 1 or true.
In your if statements include this variable to make sure you only activate right modes.

PIRstairsValue == 0 && pirActive == 0 //everything off
PIRstairsValue == 1 && pirActive == 0 //Fade in and set pirActive=1
PIRstairsValue == 1 && pirActive == 1 //Stay on
PIRstairsValue == 0 && pirActive == 1 //fade out and set pirActive=0

Gabriel_swe:
I would add a variable, for example pirActive. When you begin fadein set this variable to 1 or true.
In your if statements include this variable to make sure you only activate right modes.

PIRstairsValue == 0 && pirActive == 0 //everything off
PIRstairsValue == 1 && pirActive == 0 //Fade in and set pirActive=1
PIRstairsValue == 1 && pirActive == 1 //Stay on
PIRstairsValue == 0 && pirActive == 1 //fade out and set pirActive=0

Now that's a great suggestion. Thanks Gabriel, defo going to try this!

And if you want easy fading, you can grab my library :slight_smile: Just call it to set the levels and you're off :slight_smile:

septillion:
And if you want easy fading, you can grab my library :slight_smile: Just call it to set the levels and you're off :slight_smile:

Oh wow, thanks for letting me know about this septillion, very kind. I shall try, thanks.
Having trouble at the minute though, as it's now not working as I expected. What's happening is the lights are coming on with no fade, then fading out - on a continual loop! Do I need to use 4 if statements WITH or WITHOUT else? Here's the code now;

  // Code for LED Strip control

  // PIRstairsValue == 0 && pirActive == 0  //everything off
  // PIRstairsValue == 1 && pirActive == 0  //Fade in and set pirActive=1
  // PIRstairsValue == 1 && pirActive == 1  //Stay on
  // PIRstairsValue == 0 && pirActive == 1  //fade out and set pirActive=0

  if (PIRstairsValue == 0 && pirActive == 0)     // everything OFF
  {
    Driver.begin();
    Driver.SetColor(0, 0, 0);
    Driver.end();
  }

  if (PIRstairsValue == 1 && pirActive == 0)    //Fade in and set pirActive=1
  {
    for (i = 0; i < 100; i++)                  // Simple loop to fade brightness of colour (i) up
    {
      Driver.begin();
      Driver.SetColor(i, 0, i);
      Driver.end();
      delay(LEDdelay);
    }
    pirActive = 1;
  }

  if (PIRstairsValue == 1 && pirActive == 1)    //Stay on
  {
    Driver.begin();
    Driver.SetColor(i, 0, i);
    Driver.end();
    delay(LEDdelay);
  }

  if (PIRstairsValue == 0 && pirActive == 1)    //fade out and set pirActive=0
    pirActive = 0;
  for (i = 100; i > 0; i--)                     // Simple loop to fade brighness of colour (i) down
  {
    Driver.begin();
    Driver.SetColor(i, 0, i);
    Driver.end();
    delay(LEDdelay);
  }

  Serial.print("Stairs PIR = ");
  Serial.println(PIRstairsValue);
  Serial.print("Stairs pirActive = ");
  Serial.println(pirActive);

  // End of LED Strip Control code

}
enum State {
  IDLE,
  FADING_IN,
  FULL_BRIGHTNESS,
  FADING_OUT
} state = IDLE;

const unsigned long FADING_IN_ms = 2000;
// we don't have a FULL_BRIGHTNESS_ms, becauyse that is determined by the potentimeter
const unsigned long FADING_OUT_ms = 2000;

unsigned long start_ms;

void setup() {
  set up pins;

  turn pir on;
}

void loop() {
  switch(state) {
    case IDLE: do_idle(); break;
    case FADING_IN: do_fadingIn(); break;
    case FULL_BRIGHTNESS: do_fullBrightness(); break;
    case FADING_OUT: do_fadingOut(); break;
  }
}

void do_idle() {
  if(we sensed pir) {
    turn pir off;
    state = FADING_IN;
    start_ms = millis();
  }
}

void do_fadingIn() {
  unsigned long tt = millis() - start_ms;
  if(tt >= FADING_IN_ms) {
    set the lights to full brightness;
    state = FULL_BRIGHTNESS;
    start_ms = millis();
  }
  else {
    int targetBrigthness = (double)tt / (double) FADING_IN_ms * 255;
    set the led brighness to the target brighness;
  }
}

void do_fullBrightness() {
  unsigned long tt = millis() - start_ms;
  unsigned long target_ms = read the potentiometer and compute ms;
  if(tt >= target_ms) {
    state = FADING_OUT;
    start_ms = millis();
  }
  else {
    // do nothing
  }
}

void do_fadingOut() {
  unsigned long tt = millis() - start_ms;
  if(tt >= FADING_OUT_ms) {
    set the lights to off;
    turn the pir back on;
    state = IDLE;
    start_ms = millis(); // don't need this for idle state
  }
  else {
    int targetBrigthness = 255 - (double)tt / (double) FADING_IN_ms * 255;
    set the led brighness to the target brighness;
  }
}

PaulMurrayCbr:

enum State {

IDLE,
 FADING_IN,
 FULL_BRIGHTNESS,
 FADING_OUT
} state = IDLE;

const unsigned long FADING_IN_ms = 2000;
....

Thanks for this Paul. Great way to make me learn too!! :slight_smile:

I sort of understand the gist of what you have suggested, I assume I still need to use if statements testing the conditions to call each relevant void function?

Yeah, just store what you are doing. Although if you use FadeLed you don't really need to store the state because FadeLed already does that and you can just read that.

But what is that Driver that you use?

I would also let the Arduino do all the timing. Then you can just set it in seconds instead of trail and error. Just set the PIR to the minimum time. That's how I use them.

theMusicMan:
to call each relevant void function?

Remove the word void from that sentence. It's just a function, void just tells you it does not return anything.

septillion:
Yeah, just store what you are doing. Although if you use FadeLed you don't really need to store the state because FadeLed already does that and you can just read that.

But what is that Driver that you use?

I would also let the Arduino do all the timing. Then you can just set it in seconds instead of trail and error. Just set the PIR to the minimum time. That's how I use them.
Remove the word void from that sentence. It's just a function, void just tells you it does not return anything.

Awesome, thanks septillion! I'm heading to Cardiff today for a few hours (interview) but will dive into your code library later this evening with a bottle of wine! Though that might not be such a great idea, eh! ;D

Hehe :slight_smile: I spend a great deal of time on the examples and documentation so you should be able to get it working before your first glass is empty :smiley:

septillion:
But what is that Driver that you use?

Do you mean the library or the physical driver module?
The library is one I found on the net, it's pretty simple and straightforward which is all I need for this LED use anyways. I use it for night time lighting so wouldn't want any fancy flashing or multi-coloured effects, just a simple and pleasing fade in, remain on until several seconds after no movement detected, then similar fade out.
The hardware module (linked in OP) is one that uses two wires instead of 4 so frees up some pins on my UNO for other use.

septillion:
Hehe :slight_smile: I spend a great deal of time on the examples and documentation so you should be able to get it working before your first glass is empty :smiley:

Haha... now there's a challenge I will accept - though I do want to move on to my second glass!! :o

theMusicMan:
Do you mean the library or the physical driver module?

Both :slight_smile: And I might be blind but I can't find links to the module nor the library ::slight_smile:

septillion:
Both :slight_smile: And I might be blind but I can't find links to the module nor the library ::slight_smile:

Oh heck!!! So sorry, I was certain I'd posted the links to these in my original post!

This is the hardware driver - Hardware Driver on eBay

This is the GITHub software driver library link - LED Driver Library

Hope these work!

Hehe, can happen :wink: But what happened to the eBay link? :o

But with a external driver like that you can't use it directly with my library :confused: When you talked about a normal RGB strip I assumed PWM from the Arduino (which uses 3 pins, not 4). And my library uses analogWrite(). I'm still thinking about splitting the library so you can use it with other functions but I'm not planning to do that very soon...

But you can still look at the library to get an idea how I do it. And you can even use the gamma table.

septillion:
Hehe, can happen :wink: But what happened to the eBay link? :o

But with a external driver like that you can't use it directly with my library :confused: When you talked about a normal RGB strip I assumed PWM from the Arduino (which uses 3 pins, not 4). And my library uses analogWrite(). I'm still thinking about splitting the library so you can use it with other functions but I'm not planning to do that very soon...

But you can still look at the library to get an idea how I do it. And you can even use the gamma table.

Blimey - I don't seem to be having much luck with links recently, do I??

Try this one where I won't insert the actual URL code tags! http://www.ebay.co.uk/itm/201679938407

Oh, and re the LED strip, I used one of my strips with this driver module, but I also have three more sections of LED strip to use in the house and will be using your method with these. I don't intend to purchase any more of those LED driver modules.

;D

theMusicMan:
Thanks for this Paul. Great way to make me learn too!! :slight_smile:

I sort of understand the gist of what you have suggested, I assume I still need to use if statements testing the conditions to call each relevant void function?

Well - yeah. I'm not quite sure what you are asking. Each of the functions that I wrote has if() statements in them.

PaulMurrayCbr:
Well - yeah. I'm not quite sure what you are asking. Each of the functions that I wrote has if() statements in them.

Sure Paul, you certainly did - but I couldn't see how the tt variable you introduced and the logic tested for in my code married up, that's all.

theMusicMan:
Sure Paul, you certainly did - but I couldn't see how the tt variable you introduced and the logic tested for in my code married up, that's all.

In each of those functions, tt is the number of milliseconds between the time that the sketch started doing whateber it is doing now and the current time. tt is
"it has been 500 milliseconds since I started fading in"
"it has been 500 milliseconds since I started fading in"
"it has been 501 milliseconds since I started fading in"
"it has been 501 milliseconds since I started fading in"
"it has been 502 milliseconds since I started fading in"

as the sketch executes. The time at which th sketch started fading in (or out, or whatever) is set when the previous execution of the loop determined that it was now time to move to a new state.

"it has been 1000 ms since I stated fading in! That means I need to put the light to full brighness, write down what time it is right now, and make a note that now we are holding at full bightness."

"it has been 0 milliseconds since I started holding at full brightness"
"it has been 0 milliseconds since I started holding at full brightness"
"it has been 1 milliseconds since I started holding at full brightness"

and so on.

Awesome, thanks Paul. I shall endeavor to understand more fully! Appreciate you helping. Thanks.