Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!



Fade one color to a...
 
Share:
Notifications
Clear all

[Solved] Fade one color to another color Wemos / NodeMCU

18 Posts
2 Users
0 Reactions
6,165 Views
(@Anonymous)
Joined: 1 second ago
Posts: 0
Topic starter  

Hi,
I am looking for a way to fade from one color eg.(255,120,0) to another color (0,200,255) in a given time eg. 30 sec. using FastLED and Wemos D1 Mini or NodeMCU

Thanks in advance


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2796
 

You're looking at two "challenges" ...

First one is fading from one color to another this can be surprisingly challenging (depending on how "accurate" you want the fade to be). 
I had to look for a function as well, and found one here:

#include <FastLED.h>

// fadeTowardColor example code.
//
// Sample code that includes a function for fading one RGB color toward a target RGB color
// Also includes a function for fading a whole array of pixels toward a given color
//
// Both of these functions _modify_ the existing color, in place.
//
// All fades are done in RGB color space.
//
// Mark Kriegsman
// December 2016


#define NUM_LEDS 50
#define LED_PIN 3
#define LED_TYPE WS2811
#define COLOR_ORDER GRB

CRGB leds[NUM_LEDS];

void setup() {
  delay(3000); // sanity delay
  FastLED.addLeds<LED_TYPE,LED_PIN,COLOR_ORDER>(leds,NUM_LEDS);
}




// Helper function that blends one uint8_t toward another by a given amount
void nblendU8TowardU8( uint8_t& cur, const uint8_t target, uint8_t amount)
{
  if( cur == target) return;
  
  if( cur < target ) {
    uint8_t delta = target - cur;
    delta = scale8_video( delta, amount);
    cur += delta;
  } else {
    uint8_t delta = cur - target;
    delta = scale8_video( delta, amount);
    cur -= delta;
  }
}

// Blend one CRGB color toward another CRGB color by a given amount.
// Blending is linear, and done in the RGB color space.
// This function modifies 'cur' in place.
CRGB fadeTowardColor( CRGB& cur, const CRGB& target, uint8_t amount)
{
  nblendU8TowardU8( cur.red,   target.red,   amount);
  nblendU8TowardU8( cur.green, target.green, amount);
  nblendU8TowardU8( cur.blue,  target.blue,  amount);
  return cur;
}

// Fade an entire array of CRGBs toward a given background color by a given amount
// This function modifies the pixel array in place.
void fadeTowardColor( CRGB* L, uint16_t N, const CRGB& bgColor, uint8_t fadeAmount)
{
  for( uint16_t i = 0; i < N; i++) {
    fadeTowardColor( L[i], bgColor, fadeAmount);
  }
}


void loop() 
{
  CRGB bgColor( 0, 15, 2); // pine green ?
  
  // fade all existing pixels toward bgColor by "5" (out of 255)
  fadeTowardColor( leds, NUM_LEDS, bgColor, 5);

  // periodically set random pixel to a random color, to show the fading
  EVERY_N_MILLISECONDS( 300 ) {
    uint16_t pos = random16( NUM_LEDS);
    CRGB color = CHSV( random8(), 255, 255);
    leds[ pos ] = color;
  }

  FastLED.show();
  FastLED.delay(10);
}

Looking at this code, especially the "void loop()"; we see that the developer uses "fadeTowardColor()" to fade from one color to another with steps of "5" (bigger steps = faster and less accurate).

You'll now have to tinker a little to see where we want to add some "delay()" statements to make sure the fade doesn't go too fast and staying in your 30 seconds window.

Hope this helps to get you started, and apologies for the late reply 😁 


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
Topic starter  

Thank you Hans, I am looking forward to try out your code. Hope I understand the code although C++ isn’t my favorite programming language.


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2796
 

Haha, yeah, it's not my favorite either ... 

Feel free to post questions 😊 

 

p.s. I do not think you'll need it, but just in case: I did write a small beginners course specifically for the Arduino - maybe its useful.


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
Topic starter  

Thank you for the Arduino Programming for Beginners. Maybe I can use some tips from it 🙂 

Regarding your code from above. It is working very well and I am implementing it in my Wemos project.
I havent fully testet it with my other code yet but I am confident that it wil work just fine.
One thing that surprises me is that I can't move the fadeTowardColor to a new tab. I get an error ('CRGB' does not name a type )


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2796
 

@henrikl2000 Not sure what you mean with moving fadeTowardColor to a new tab? You mean copy the code into your code?

Can you post the offending code and full error message?

Note: CRGB is defined in the FastLED library, so make sure it is in one of the #include lines.


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
Topic starter  

I just tried it again this time no error. Hmm ....


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
Topic starter  

I don’t know if I should start a new thread or just post it here.

I have a problem which I am afraid I need your help to solve.

If I fade from one color to two colors no problem, but if I fade from 2 colors to 2 different colors the leds flickers. I guess it something to do with the function CRGB fadeTowardColor( CRGB& cur, const CRGB& target, uint8_t amount)

Would you please take a look.

Thank you in advance

 

void loop() {
  if (update1Color == true) {
    setBright(brightness);
    setAll(colorRed, colorGreen, colorBlue);
  }
  if (update2Color == true) {
    setBright(brightness);
    set2Color(colorRed, colorGreen, colorBlue, colorRed2, colorGreen2, colorBlue2);
  }
  if (updateFadeColors1 == true) {
    fadeTo(fadeRed, fadeGreen, fadeBlue, fadeDelay, fadeAmount);
  }

  if (updateFadeColors2 == true) {
    fadeTo2(fadeRed, fadeGreen, fadeBlue, fadeRed2, fadeGreen2, fadeBlue2, fadeDelay, fadeAmount);
  }
  
  // 1 farve
  if ((leds[1].r == fadeRed) && (leds[1].g == fadeGreen) && (leds[1].b == fadeBlue)) {
    updateFadeColors1 = false;
  }
  
  // 2 farver
  if ((leds[0].r == fadeRed) && (leds[0].g == fadeGreen) && (leds[0].b == fadeBlue) && (leds[1].r == fadeRed2) && (leds[1].g == fadeGreen2) && (leds[1].b == fadeBlue2)) {
    updateFadeColors2 = false;
  }
}

void nblendU8TowardU8( uint8_t& cur, const uint8_t target, uint8_t amount)
{
  if( cur == target) return;
  
  if( cur < target ) {
    uint8_t delta = target - cur;
    delta = scale8_video( delta, amount);
    cur += delta;
  } else {
    uint8_t delta = cur - target;
    delta = scale8_video( delta, amount);
    cur -= delta;
  }
}

// Blend one CRGB color toward another CRGB color by a given amount.
// Blending is linear, and done in the RGB color space.
// This function modifies 'cur' in place.
CRGB fadeTowardColor( CRGB& cur, const CRGB& target, uint8_t amount)
{
  nblendU8TowardU8( cur.red,   target.red,   amount);
  nblendU8TowardU8( cur.green, target.green, amount);
  nblendU8TowardU8( cur.blue,  target.blue,  amount);
  return cur;
}

// Fade an entire array of CRGBs toward a given background color by a given amount
// This function modifies the pixel array in place.
void fadeTowardColor( CRGB* L, uint16_t N, const CRGB& bgColor, uint8_t fadeAmount)
{
  for( uint16_t i = 0; i < N; i++) {
    fadeTowardColor( L[i], bgColor, fadeAmount);
  }
}

void fadeTowardColor2( CRGB* L, uint16_t N, const CRGB& bgColor, const CRGB& bgColor2, uint8_t fadeAmount)
{
  for( uint16_t i = 0; i < N; i++) {
    if ((i % 2) == 0) {
      fadeTowardColor( L[i], bgColor, fadeAmount);
    } else {
      fadeTowardColor( L[i], bgColor2, fadeAmount);
    }
  }
}

void fadeTo(byte toRed, byte toGreen, byte toBlue, int fadeDelay, byte fadeAmount) {       //byte red, byte green, byte blue, byte toRed, byte toGreen, byte toBlue, int fadeDelay, byte fadeAmount) {
  // Syntax: toRed, toGreen, toBlue, fade delay, how much to fade)
    
  CRGB bgColor(toRed, toGreen , toBlue);
  fadeTowardColor( leds, NUM_LEDS, bgColor, fadeAmount);

  FastLED.show();
  FastLED.delay(fadeDelay);  
}

void fadeTo2(byte toRed, byte toGreen, byte toBlue, byte toRed2, byte toGreen2, byte toBlue2, int fadeDelay, byte fadeAmount) {       //byte red, byte green, byte blue, byte toRed, byte toGreen, byte toBlue, int fadeDelay, byte fadeAmount) {
  // Syntax: toRed, toGreen, toBlue, toRed2, toGreen2, toBlue2, fade delay, how much to fade)
    
  CRGB bgColor(toRed, toGreen , toBlue);
  CRGB bgColor2(toRed2, toGreen2, toBlue2);
  fadeTowardColor2( leds, NUM_LEDS, bgColor, bgColor2, fadeAmount);

  FastLED.show();
  FastLED.delay(fadeDelay);  
}

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2796
 

I presume it flickers when calling fadeTo2? (sorry - took me quite a bit of reading to figure out what you meant and what the code may be doing)

Not sure why it would flicker, but I can image there is room for improvement to speed up things.

A few ideas ...

To reduce confusion when reading code maybe it is better we change the name of this functions.
The original fade-to-color developer used the same names as the other function, which is not incorrect, but I found this to be confusing at times when reading code.

So let's change this function

CRGB fadeTowardColor( CRGB& cur, const CRGB& target, uint8_t amount)
{
  nblendU8TowardU8( cur.red,   target.red,   amount);
  nblendU8TowardU8( cur.green, target.green, amount);
  nblendU8TowardU8( cur.blue,  target.blue,  amount);
  return cur;
}

to maybe this (or whatever name you prefer):

CRGB fadeOneColor( CRGB& cur, const CRGB& target, uint8_t amount)
{
  nblendU8TowardU8( cur.red,   target.red,   amount);
  nblendU8TowardU8( cur.green, target.green, amount);
  nblendU8TowardU8( cur.blue,  target.blue,  amount);
  return cur;
}

You will have to update these two functions (fadeTowardColor and fadeTowardColor2) to this, so it uses the new name:

// Fade an entire array of CRGBs toward a given background color by a given amount
// This function modifies the pixel array in place.
void fadeTowardColor( CRGB* L, uint16_t N, const CRGB& bgColor, uint8_t fadeAmount)
{
  for( uint16_t i = 0; i < N; i++) {
    fadeOneColor( L[i], bgColor, fadeAmount);
  }
}

void fadeTowardColor2( CRGB* L, uint16_t N, const CRGB& bgColor, const CRGB& bgColor2, uint8_t fadeAmount)
{
  for( uint16_t i = 0; i < N; i++) {
    if ((i % 2) == 0) {
      fadeOneColor( L[i], bgColor, fadeAmount);
    } else {
      fadeOneColor( L[i], bgColor2, fadeAmount);
    }
  }
}

 

 

Next, the entire strip is either one or two colors, so instead of recalculating the new color for each individual LED, we could calculate the new color only one time and copy it to the other LEDs. This would potentially be significantly faster.

Maybe something like this (calculate once, and copy it for all LEDs);

// Fade an entire array of CRGBs toward a given background color by a given amount
// This function modifies the pixel array in place.
void fadeTowardColor( CRGB* L, uint16_t N, const CRGB& bgColor, uint8_t fadeAmount)
{
  fadeOneColor( L[0], bgColor, fadeAmount); // first LED - calc new color

  for( uint16_t i = 0; i < N; i++) {
     L[i] = L[0]; // copy color from first LED
  }
}

void fadeTowardColor2( CRGB* L, uint16_t N, const CRGB& bgColor, const CRGB& bgColor2, uint8_t fadeAmount)
{
  fadeOneColor( L[0], bgColor, fadeAmount); // Calc new color first LED
  fadeOneColor( L[1], bgColor, fadeAmount); // and second LED

  for( uint16_t i = 0; i < N; i++) {
    if ((i % 2) == 0) {
      L[i] = L[0];  // copy 1st LED color
    } else {
      L[i] = L[1]; // copy seconde LED color
    }
  }
}

 

Next, I'd strip your code (in a copy of course) to just the 2 color fade related code ... just to make sure we get that to work first.
So remove as much as you can, just to stick to the barebones 2 color fade.


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
Topic starter  

I agree with you regarding the function naming.
I fully understand your lack of time, since I am sure many need your help.

I think the flickering may be caused by the part

if (updateFadeColors2 == true) {
    fadeTo2(fadeRed, fadeGreen, fadeBlue, fadeRed2, fadeGreen2, fadeBlue2, fadeDelay, fadeAmount);
  }

Even when finished fading the fadeTo2 continues to start.

I am not sure where to set the updateFadeColors2 to false in order to stop the fadeTo2

Maybe if possible, I could send you the whole Wemos project (about 20 Kb)

By the way I am also using WiFi and OTA in my project


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2796
 

Cleaning up code (naming, indentation, etc), and testing the bare minimum (making sure a specific function actually works), is something I do quite often myself as well. It just makes it easier to read (cleaning up code) and easier to debug issues.

As for time, and this happens to all of us;
The biggest issue is how much time it takes to read and decipher source codes that has been posted. 
Besides that, sometimes the question or explanation is not entirely clear to me. 😜 
(same goes for me as well when I post a question myself haha)

Sending the entire project is probably not going to help, in fact it will makes it even harder to go through and find the details.

Coming back to your code, I'm not sure what is going on in your void loop().

This part:

void loop() {
  if (update1Color == true) {
    setBright(brightness);
    setAll(colorRed, colorGreen, colorBlue);
  }
  if (update2Color == true) {
    setBright(brightness);
    set2Color(colorRed, colorGreen, colorBlue, colorRed2, colorGreen2, colorBlue2);
  }
  if (updateFadeColors1 == true) {
    fadeTo(fadeRed, fadeGreen, fadeBlue, fadeDelay, fadeAmount);
  }

  if (updateFadeColors2 == true) {
    fadeTo2(fadeRed, fadeGreen, fadeBlue, fadeRed2, fadeGreen2, fadeBlue2, fadeDelay, fadeAmount);
  }
  
  // 1 farve
  if ((leds[1].r == fadeRed) && (leds[1].g == fadeGreen) && (leds[1].b == fadeBlue)) {
    updateFadeColors1 = false;
  }
  
  // 2 farver
  if ((leds[0].r == fadeRed) && (leds[0].g == fadeGreen) && (leds[0].b == fadeBlue) && (leds[1].r == fadeRed2) && (leds[1].g == fadeGreen2) && (leds[1].b == fadeBlue2)) {
    updateFadeColors2 = false;
  }
}

Where are update1Color and update2Color set? Are they always true? Both of them?
Or are they mutual exclusive (I would guess so?)?
How does that correlate with updateFadeColors1 and 2? 

Maybe we can look at that and get that structured a little better? Maybe one call interferes with the other?

 


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
Topic starter  

When a new mqtt message arrives

    if (msg.startsWith("F1C")) {       
      splitNeoMsgFade1Color(msg);
    } else if (msg.startsWith("F2C")) {
      splitNeoMsgFade2Color(msg);
    }

 

void splitNeoMsgFade1Color(String Val)
{
  if (Val.length() > 0) {
    // ********** Split function **********
    // Syntax for sending : "red, green, blue, brightness, fade delay, fade amount" (255,0,0,64,100,5)    
    Val.replace("F1C","");
    
    int idxRed = Val.indexOf(',');
    int idxGreen = Val.indexOf(',', idxRed + 1);
    int idxBlue = Val.indexOf(',', idxGreen + 1);
    int idxBright = Val.indexOf(',', idxBlue + 1);
    int idxFadeDelay = Val.indexOf(',', idxBright +1);
    int idxFadeAmount = Val.indexOf(',', idxFadeDelay + 1);
    
    String r = Val.substring(0, idxRed); // Start, længde
    String g = Val.substring(idxRed + 1, idxGreen);
    String b = Val.substring(idxGreen + 1, idxBlue);
    String bright = Val.substring(idxBlue + 1, idxBright);
    String fDelay = Val.substring(idxBright + 1, idxFadeDelay);
    String fAmount = Val.substring(idxFadeDelay + 1, idxFadeAmount);
    
    fadeRed = r.toInt();
    fadeGreen = g.toInt();
    fadeBlue = b.toInt();
    brightness = bright.toInt();
    fadeDelay = fDelay.toInt();
    fadeAmount = fAmount.toInt();
    
    updateFadeColors1 = true;
    brigtnessUpdated = false;
    Val = "";
  }

As you can see in the loop only if updateFadeColors1 or updateFadeColors2 is true the fade should begin.

When the fade is done the updateFadeColors1 /  updateFadeColors2 should be set false

I hope this helps to clarify the code.


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2796
 

So when can both updateFadeColors1 and updateFadeColors2 be true at the same time?
(I would not expect that)

If none or only one can be true, then maybe rewrite this ...

  if (updateFadeColors1 == true) {
    fadeTo(fadeRed, fadeGreen, fadeBlue, fadeDelay, fadeAmount);
  }

  if (updateFadeColors2 == true) {
    fadeTo2(fadeRed, fadeGreen, fadeBlue, fadeRed2, fadeGreen2, fadeBlue2, fadeDelay, fadeAmount);
  }

... to a more correct;

  if (updateFadeColors1 == true) {
    fadeTo(fadeRed, fadeGreen, fadeBlue, fadeDelay, fadeAmount);
  } else if (updateFadeColors2 == true) {
    fadeTo2(fadeRed, fadeGreen, fadeBlue, fadeRed2, fadeGreen2, fadeBlue2, fadeDelay, fadeAmount);
  }

(Ditto for the other if-then loop)

 

It will not fix any problems, its just more correct unless both can be true at the same time of course.


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
Topic starter  

After some testing stripping the code to the bare minimum it works without flicker. As soon as I add the WiFi part setup_wifi(); it starts to flicker again. I tried the meteorRain also (which I by way requested a couple of years ago). With the WiFi the meteorRain also flickers.

 

void setup_wifi() {
  WiFi.hostname(deviceName);
  WiFi.setSleepMode(WIFI_NONE_SLEEP);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  WiFi.config(ip, gateway, subnet, dns);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2796
 

@henrikl2000 Sounds like the WiFi is triggering an interrupt that interferes somehow with FastLED or one of "our" functions.

Really not having tested any of this, maybe replace WIFI_NONE_SLEEP with WIFI_LIGHT_SLEEP - just to see what happens. Wifi should remain connected, but I would assume the polling of WiFi is brought down a notch. (I could be totally guessing this wrong of course - but testing won't hurt.

WiFi.setSleepMode(WIFI_LIGHT_SLEEP); 

 Let us know if that made a difference. 😊 


   
ReplyQuote
Page 1 / 2
Share: