How to synchronise street lighting with sunset-sunrise leds?

So I would like to expose a small but annoying problem that I have with a sketch.
I’m in HO model trains and I would like to combine a Sunset-Sunrise cycle with some street lights.
Therefore I’m using a Mega with a Robotdyn sensor shield, led strips of the type 2811 (for the moment only 12ea) and a single white led
The Sunset-Sunrise is performed by RGB led strips and the street lighting is for the white led.

The sketch is a mix of several items written by other authors and reassembled together by me. All the palettes are self-designed and should give a rather convincing day cycle, divided in 4 parts (and thus in 4 palettes). The reason for this is that I want to be able to lengthen or shorten each part of the cycle as needed.

While the the day cycle goes on and reaches dusk, the street lighting should remain Off. When dusk starts it should gradually go On to a maximum brightness. The latter one should occure around ‘midnight’.
So far the Sunset-Sunrise perform rather well (except some flickering probably due to a weak power feeding). Also, the street lighting performs well from nothing to maximum brightness and verso.

What I can’t achieve is to start (synchronise) the street lighting with the led strip(s)a precisely the “dusk” moment.

So is this possible?
If so, then how?

Thank you in advance.

This is the code:

[code]
/* Sunset & Sunrise Ver 2.0
The sketch is a mix of several items written by other authors and reassembled together by me.
All the palettes are self-designed and should give a rather convincing day cycle, divided in 4 parts (and thus in 4 palettes).
The reason for this is that I want to be able to lengthen or shorten each part of the cycle as needed.
While the the day cycle goes on and reaches dusk, the street lighting should remain Off.
When dusk starts it should gradually go On to a maximum brightness.
The latter one should occure around ‘midnight’.
*/


#define FASTLED_INTERNAL
#include <FastLED.h>
#include <millisDelay.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);                                                       // SET THE LCD ADDRESS TO 0x27 FOR A 16 CHARS AND 4 LINE DISPLAY - SDA = PIN 21 & SCL = PIN 21

//-----------------------------
//-----------TIMING------------

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;

unsigned long speedOfNightToMorning = 1;                                                  // DURATION MINUTES nightDayCycle ROUTINE (10 minutes: one step = 2343.75 milliseconds ~ 2.3 seconds)
unsigned long speedOfMorningToNoon = 2;                                                   // DURATION MINUTES dayNoonCycle ROUTINE (10 minutes: one step = 2343.75 milliseconds ~ 2.3 seconds)
unsigned long speedOfNoonToEvening = 2;                                                   // DURATION MINUTES noonEveningCycle ROUTINE (10 minutes: one step = 2343.75 milliseconds ~ 2.3 seconds)
unsigned long speedOfEveningToNight = 1;                                                  // DURATION MINUTES eveningNightCycleROUTINE (10 minutes: one step = 2343.75 milliseconds ~ 2.3 seconds)

unsigned long timeBaseInterval = speedOfEveningToNight + speedOfNightToMorning;           // TIMEBASE FOR THE EVENING + NIGHT CYCLE
unsigned long time_Now = 0;                                                               // USED FOR THE STREETLIGHT ROUTINE
unsigned long interval_STREET = 1000;                                                     // INTERVAL BETWEEN UP CYCLE & DOWN CYCLE (milliseconds) MUST BE EQUAL TO THE SUM OF BOTH "NIGHT" CYCLES

int STREET_LED = 44;                                                                      // THE PIN THAT THE STREET LEDs ARE ATTACHED TO (Uno = 3,5,6,9,10 & 11 - Mega = 2->13 & 44 -> 46)
int minBrightness_STREET = 0;                                                             // BRIGHTNESS OF THJE STREET LEDs AT STARTUP
int maxBrightness_STREET = 128;                                                           // BRIGHTNESS OF THJE STREET LEDs AT END OF ROUTINE
int fadeAmount = 1;                                                                       // KEEP THIS AMOUNT UNDER 5 FOR A NICE FADING OF THE STREET LEDs - 1 = BEST RESULTS
int i = 0;                                                                                // LED INTENSITY
int dir = 1;                                                                              // DIRECTION 1 = UP & 0 = DOWN
bool ledOn_STREET = false;                                                                // KEEP TRACK OF THE STREET_LED STATUS
millisDelay ledDelay_STREET;                                                              // DELAY AGAINST WHICH TO DRIFT

const byte DATA_PIN = 6;
const byte NUM_LEDS = 12;
const byte maxBrightnessStrip = 128;                                                            // BETWEEN 0 & 255

DEFINE_GRADIENT_PALETTE (Night_To_Morning_gp) {                                           // NIGHT TO MORNING PALETTE (nightDayCycle)
  0, 0, 51, 102,                                  //Dark Midnight Blue
  64, 0, 35, 71,                                  //Oxford Blue
  102, 0, 0, 0,                                   //Rich Black
  153, 0, 0, 0,                                   //Rich Black
  191, 0, 35, 71,                                 //Oxford Blue
  255, 0, 51, 102,                                //Dark Midnight Blue
};

DEFINE_GRADIENT_PALETTE (Morning_To_Noon_gp) {                                            // MORNING TO NOON PALETTE (dayNoonCycle)
  0, 0, 63, 125,                                  //Dark Cerulean Blue
  36, 45, 45, 45,                                 //Charleston Green
  85, 34, 34, 34,                                 //Raisin Black
  167, 0, 69, 84,                                 //Midnight Green
  255, 255, 142, 0,                               //Dark Orange
};

DEFINE_GRADIENT_PALETTE (Noon_To_Evening_gp) {                                            // NIGHT TO DAY PALETTE (noonEveningCycle)
  0, 253, 119, 2,                                 //Heat Wave Orange
  90, 255, 80, 3,                                 //Aerospace International Orange
  100, 50, 50, 200,                               //Daylight
  155, 50, 50, 200,                               //Daylight
  175, 255, 80, 3,                                //Aerospace International Orange
  255, 253, 119, 2,                               //Heat Wave Orange
};

DEFINE_GRADIENT_PALETTE (Evening_To_Night_gp) {                                           // DAY TO NIGHT PALETTE (eveningNightCycle)
  0, 255, 142, 0,                                 //Dark Orange
  36, 0, 69, 84,                                  //Midnight Green
  85, 34, 34, 34,                                 //Raisin Black
  167, 45, 45, 45,                                //Charleston Green
  255, 0, 63, 125,                                //Dark Cerulean Blue

};

CRGBPalette16 myPal1 = Night_To_Morning_gp;                                               // CREATING PALETTE OBJECTS AS MANY AS THERE ARE PALETTES IN USE
CRGBPalette16 myPal2 = Morning_To_Noon_gp;
CRGBPalette16 myPal3 = Noon_To_Evening_gp;
CRGBPalette16 myPal4 = Evening_To_Night_gp;

struct CRGB leds[NUM_LEDS];                                                               // DEFINE OBJECT OF LEDS
static uint8_t paletteIndex = 0;

//------------------------------
//------------SETUP-------------
void setup()
{
  Serial.begin(9600);
  FastLED.addLeds<WS2811, DATA_PIN, BRG>(leds, NUM_LEDS);

  pinMode(STREET_LED, OUTPUT);
  analogWrite(STREET_LED, LOW);                                                             // TURN STREET_LED OFF
  ledOn_STREET = false;                                                                     // DELAY AGAINST WHICH TO DRIFT
  ledDelay_STREET.start(interval_STREET);                                                   // START THE DELAY

  lcd.init();                                                                               //INITIALIZE THE LCD
  lcd.backlight();                                                                          //OPEN THE LCD BACKLIGHT

  lcd.print("Sunset_To_Sunrise_Loop_TEST-Ver2.ino");
}

//-----------------------------
//------------LOOP-------------
void loop()
{
currentMillis = millis();                                                                 // CAPTURE THE LATEST VALUE OF millis() IS EQUIVALENT TO NOTING THE TIME FROM A CLOCK                                                  
  
  if(millis() >= time_Now + timeBaseInterval){
        time_Now += timeBaseInterval;
        streetLightFading();

    } 
  eveningNightCycle();
  nightDayCycle();
  dayNoonCycle();
  noonEveningCycle();
  
  FastLED.show();
}

//--------------------------------
//-------4 CYCLES OF 1 DAY--------
void nightDayCycle()
{
  //static const float transitionDuration1 = 2; // Minutes (10 minutes: one step = 2343.75 milliseconds ~ 2.3 seconds)
  static const float interval = ((float)(speedOfNightToMorning * 60) / 256) * 1000;     // STEPS IN milliseconds
  static uint8_t paletteIndex = 0;                                                      // CURRENT GRADIENT PALETTE COLOUR
  CRGB colour = ColorFromPalette(myPal1, paletteIndex, maxBrightnessStrip, LINEARBLEND);
  fill_solid(leds, NUM_LEDS, colour);                                                   // ILLUMINATE THE WHOLE STRIP WITH THE COLOUR FETCHED FROM THE PALETTE

  EVERY_N_MILLISECONDS(interval) {                                                      // TRAVERSE THE COMPLETE PALETTE
    if (paletteIndex < 255) {
      paletteIndex++;
    }
    if (paletteIndex == 255) {
      paletteIndex = 0;
    }
  }
}                                                                                       // End of nightDayCycle

void dayNoonCycle()
{
  //static const float transitionDuration2 = 2; // Minutes (10 minutes: one step = 2343.75 milliseconds ~ 2.3 seconds)
  static const float interval = ((float)(speedOfMorningToNoon * 60) / 256) * 1000;      // STEPS IN milliseconds
  static uint8_t paletteIndex = 0;                                                      // CURRENT GRADIENT PALETTE COLOUR
  CRGB colour = ColorFromPalette(myPal2, paletteIndex, maxBrightnessStrip, LINEARBLEND);
  fill_solid(leds, NUM_LEDS, colour);                                                   // ILLUMINATE THE WHOLE STRIP WITH THE COLOUR FETCHED FROM THE PALETTE

  EVERY_N_MILLISECONDS(interval) {                                                      // TRAVERSE THE COMPLETE PALETTE
    if (paletteIndex < 255) {
      paletteIndex++;
    }
    if (paletteIndex == 255) {
      paletteIndex = 0;
    }
  }
}                                                                                       // End of dayNoonCycle

void noonEveningCycle()
{
  //static const float transitionDuration3 = 2; // Minutes (10 minutes: one step = 2343.75 milliseconds ~ 2.3 seconds)
  static const float interval = ((float)(speedOfNoonToEvening * 60) / 256) * 1000;      // STEPS IN milliseconds
  static uint8_t paletteIndex = 0;                                                      // CURRENT GRADIENT PALETTE COLOUR
  CRGB colour = ColorFromPalette(myPal3, paletteIndex, maxBrightnessStrip, LINEARBLEND);
  fill_solid(leds, NUM_LEDS, colour);                                                   // ILLUMINATE THE WHOLE STRIP WITH THE COLOUR FETCHED FROM THE PALETTE

  EVERY_N_MILLISECONDS(interval) {                                                      // TRAVERSE THE COMPLETE PALETTE
    if (paletteIndex < 255) {
      paletteIndex++;
    }
    if (paletteIndex == 255) {
      paletteIndex = 0;
    }
  }
}                                                                                       // End of noonEveningCycle

void eveningNightCycle()
{
  //static const float transitionDuration4 = 2; // Minutes (10 minutes: one step = 2343.75 milliseconds ~ 2.3 seconds)
  static const float interval = ((float)(speedOfEveningToNight * 60) / 256) * 1000;     // STEPS IN milliseconds
  static uint8_t paletteIndex = 0;                                                      // CURRENT GRADIENT PALETTE COLOUR
  CRGB colour = ColorFromPalette(myPal4, paletteIndex, maxBrightnessStrip, LINEARBLEND);
  fill_solid(leds, NUM_LEDS, colour);                                                   // ILLUMINATE THE WHOLE STRIP WITH THE COLOUR FETCHED FROM THE PALETTE

  EVERY_N_MILLISECONDS(interval) {                                                      // TRAVERSE THE COMPLETE PALETTE
    if (paletteIndex < 255) {
      paletteIndex++;
    }
    if (paletteIndex == 255) {
      paletteIndex = 0;
    }
  }
}                                                                                       // End of eveningNightCycle

//-------------------------------------
//--------FADING STREET LIGHTS---------

void streetLightFading()
{
unsigned long currentMillis = millis();

Serial.println(i);                                                                      // ONLY FOR TEST PURPOSES

  if(i <= minBrightness_STREET) {
    dir = 1;
  }
  if(i >= maxBrightness_STREET) {
    dir = 0;
  // checkToggleLed();
  }
  
  if(currentMillis - previousMillis > interval_STREET && dir == 1)
  //if(currentMillis - previousMillis > timeBaseInterval && dir == 1)
  {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;
    i = i + 2;
    analogWrite(STREET_LED, i); // set the LED brightness           
    }

  if(currentMillis - previousMillis > interval_STREET && dir == 0)
  //if(currentMillis - previousMillis > timeBaseInterval && dir == 0)
  {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;
    i = i - 2;
    analogWrite(STREET_LED, i); // set the LED brightness           
    }

}

//--------------------------------- ----
//--------MONITOR STREET LIGHTS---------

void checkToggleLed() {

  if (ledDelay_STREET.justFinished()) {                                                     // CHECK IF THE DELAY HAS TIMED OUT
    ledDelay_STREET.repeat();                                                               // REPEAT THE DELAY & TOGGLE STREET_LED
    ledOn_STREET = !ledOn_STREET;
    if (ledOn_STREET) {
      analogWrite(STREET_LED, HIGH);
    } else {
      analogWrite(STREET_LED, LOW);
    }
  }
}
[/code]

In the code you posted all four time periods are being run all the time. Or it looks like that.

I tried to run your code and it seems to just reset and start over and over - have you posted a working sketch and can you say (Again?) what it is doing now?

a7

alto777, as far as I am concerned ... yes it's a working sketch. Well not 100% really as I have the above mentioned problem.
You say that it reset and starts all over again ... and that is almost exact.
My goal is to use it as a ambiance lighting in the background of a model train circuit.

So to answer your question; it should start at eveningNightCycle() and further proceed to nightDayCycle(), then to dayNoonCycle() and finally to noonEveningCycle() for a time of about 30 minutes.
At that point it has to re-run eveningNightCycle() and the following ones.
During this whole process it should run streetLightFading() during the combined timing of eveningNightCycle() and nightDayCycle() marked as the "dusk" here above.

Hello and welcome, and well done for posting code in code tags :smiley:

The sketch is a mix of several items written by other authors and reassembled together by me.

I think that's the heart of your problem, I don't think you know how it works. The problem for me trying to help is I don't know how it works either. There are things in there that look wrong, or maybe I am about to learn something new about C++, I don't know.

What I can see is that the code looks completely blocking, so it doesn't do the street light bit until the other bits are done. Also, although not the main problem, the way you use millis is wrong and will fail after about 49 days.

I can't tell you some simple fix for the existing code. I suggest you start again and develop in in steps you understand until you have the whole thing. One essential thing is to make the code non-blocking. Here are some tutorials to help with that:

Using millis for timing
Demonstration for several things at the same time
Finite state machine tutorial

This little gem… I don’t think the four routines block, but they are all being given attention all the time.

And when I say reset, I literally mean that the program runs and the setup() function is called over and over… that is not normal and may mean something seemingly unrelated is very wrong.

I looked at EVERY_N_MILLISECONDS when I first saw it some time ago, a gimm8ck . I’d rather just roll my own code to do the same thing and then understand what it is doing.

a7

I ran it on my usual test Uno, which has nothing attached but a few LEDs. I didn't see a restart, just the serial print from streetLightFading. Maybe I didn't run it long enough.

I simulated it on an UNO, had to change the STREET LED. No more reseting.

It just calls the four routines over and over, ee nothing on the LEDs yet.

a7

It looks to me like your sketch only APPEARS to be working.
The function noonEveningCycle() is called last so its "fill_solid(leds, NUM_LEDS, colour);" overwrites the previous three. It's orange at both ends and 'Daylight' in the middle so it sort of looks like a full day.

I would replace the four gradients with two: Sunrise and Sunset. You could probably even use one and run it forward and backward.

All four eveningNightCycle() -like functions are designed to run by calling them very frequently, the logic takes a step every interval. In this case every 468 ms or 234 ms.

There is nothing that keeps all four from free running all the time. So first you'll have to figure out how to start, time and stop the CYCLES OF 1 day functions. Perhaps some number of complete fade cycles could be counted off before turning to the next effect.

The street lamp thing is on its own timer. In order to synchronize these disparate effects, you need some common factor in the timing, or some kind of master timing variable that could march through the CYCLES OF 1 functions and inform the street lamp output.

The CYCLES OF 1 day functions also do quite a bit more fill_solid than strictly necessary. If you have the time, no large deal, but the fill_solid can be done only EVERY_N_MILLISECONDS along with the paletteIndex maths - if the paletteIndex doesn't change, there is no reason to fill the pixel buffer again.

a7

Sorry for not responding sooner but over here it was night :slight_smile:

To resume all the comments (please correct me if I’m wrong, thanks):

  1. Obviously there are too many palettes and every palettes has too many elements. This should be condensed into 2 palettes, a Sunrise and a Sunset, with less steps between the colours.
    Also they should be run forward and backward. How should I perform this?

  2. My way of using the “millis” is wrong and should fail after a while … OK, but what wrong do I do?
    This sketch should only run a few hours per evening/afternoon.

  3. “There is nothing that keeps all four from free running all the time.”
    For my discharge I would like to mention that I planned this part, obviously a very important one, at the end of this project, when all is running smooth.
    My intention being to use a single switch to start/stop the sketch.

  4. As alto777’s writes, counting the performed cycles could be a solution for the synchronisation of the street lights part and the sunset part.
    Should I use similar lines as for the street lighting?

So I see that I have a long way to go.

If the program runs continuously for about 49 days it will fail. If, as you say, you only run it (as in power it up) for a few hours at a time then it will be OK. However at least as something to learn the tutorial I linked to about millis tells you the correct way to use it to avoid the problem. I imagine that if you study the tutorial you will learn a lot more than just the correct way to use millis, I imagine you will learn other things that will help you.

Your project is perfectly doable and you will learn a lot doing it.

Good luck.

I certainly do appreciate every advice given. Over the last months I gathered a lot of good advices here and in other places (eg Youtube).
I'm not mastering the English language ans sometimes my remarks may not reflect what I exactly mean.

I had not noticed that English was not your first language. I took any misunderstanding to be due to you not knowing about electronics and micro-controllers.

Well, my first languages are French and Dutch.
Many years ago I was in the (military) computer branch and had very little to do with programming.
As for electronics ... sorry but I'm not clever enough; I understand the very basics but there it ends.

The Arduino project and this forum is for people like you! People come here as complete beginners and some of them end up experts. Like any subject, learning it well requires time and effort, but the people trying to help are happy to do so as long as the person learning is making an effort. Do that and you'll get all the help you want.