Sunrise / sunset code based on location

Do you have a question on how to do something.
Ask in here.
rimai
Posts: 12857
Joined: Fri Mar 18, 2011 6:47 pm

Re: Sunrise / sunset code based on location

Post by rimai »

If you look inside the ReefAngel.cpp line 1054, you will see that they are the exact same thing :)

Code: Select all

void ReefAngelClass::DayLights(byte Relay)
{
	StandardLights(Relay);
}
Roberto.
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Sunrise / sunset code based on location

Post by lnevo »

Latest version I'm using
Attachments
SunLocation.zip
(4.17 KiB) Downloaded 458 times
DesignInstinct

Re: Dawn/dusk simulator

Post by DesignInstinct »

Hi, I'm looking for somebody to assist with a standalone Arduino project using this code to control LED lights.
Want to simulate accurate sunrise/set times...and *proper* twilight length of 60-90 minutes.
Need to ramp the LED lights smoothly over this time period. Just like what happens when looking out a window at the sun. Want to match real life fairly closely.

I'm also going to purchase a Reef Angel Plus anyway to do aquaponics/greenhouse control.

I'm NOT a programmer...but very computer literate.
Would NOT like to become a programmer ;)
Far too busy with other projects in other fields.

Will gladly pay to have this "done" for me.
Would like to do a lot of it over Team Viewer in realtime (voice/video).
I can work faster this way. Yes, they have Team Viewer for Linux. I'm on Win 8.1.

"Several inexpensive “light alarm clocks” have been marketed, cloning the DDS concept, but with rapid dawn ramps (far faster than natural dawns) and restricted fields of illumination. These mass-market products have not yet received adequate clinical evaluation. "

Yeah...that's an understatement.
Can't post links here so PM me for similar devices and why they fail at doing this.

This will benefit reef tanks, greenhouse applications, and humans living in dark houses up North.

I want to simulate sunrise/sunset and evening lighting no matter what the cloud cover outside. May be moving from New Mexico back to the frozen North and will need this badly. Most people need this and don't even know it.

Any improvements to the Reef Angel code and the standalone Arduino version code would be kept open source. This stuff is too important to be proprietary.

Google gizmag NASA led lights

Gonna let NASA and Boeing steal our thunder?
Any takers? Reply here, PM me whatever!
89delta
Posts: 157
Joined: Mon Oct 15, 2012 7:21 pm
Location: Leesburg, GA

Re: Sunrise / sunset code based on location

Post by 89delta »

lnevo....

I've just finished compiling my sketch for my RA+ I recently got and it works great. Am using the Clouds and weather patterns on the standard pwm channels from http://forum.reefangel.com/viewtopic.ph ... 8&start=50. ButI was wondering how to incorporate the location based sunrise/sunset code into it as i've only seen it being used for the standard lights on relays. Thanks for any help.

Code: Select all

#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <Humidity.h>
#include <DCPump.h>
#include <ReefAngel.h>

////// Place global variable code below here


byte ActinicPWMValue=0;
byte DaylightPWMValue=0;




void DrawCustomMain()
{
byte x = 6;
byte y = 2;
byte t;
ReefAngel.LCD.DrawLargeText(COLOR_BLACK, COLOR_WHITE, 6, 4, " Martin's BC29");
ReefAngel.LCD.DrawDate(6, 118);
ReefAngel.LCD.Clear(COLOR_BLACK, 1, 17, 132, 17);
pingSerial();
x = 12;
y += MENU_START_ROW+1;
ReefAngel.LCD.DrawText(COLOR_BLUE, COLOR_WHITE, x, y+6, " Display      PH");
char text[7];
ConvertNumToString(text, ReefAngel.Params.PH, 100);
ReefAngel.LCD.Clear(DefaultBGColor, x+16, y+65, x+65, y+16);
ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+75, y+18, text);
pingSerial();

ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
y += MENU_START_ROW*2;
x = 10;
ReefAngel.LCD.Clear(DefaultBGColor,x,y,x+(16*4),y+16);
pingSerial();
ReefAngel.LCD.DrawHugeNumbers(T1TempColor, DefaultBGColor, x, y, text);
pingSerial(); 
x += (16*4) + 8;
ReefAngel.LCD.DrawText(T2TempColor,DefaultBGColor,8,y+25,"Hood:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T2_PROBE], T2TempColor, 
9, y+35, 10);
ReefAngel.LCD.DrawText(T3TempColor,DefaultBGColor,x+8,y+25,"Room:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T3_PROBE], T3TempColor, 
x+9, y+35, 10);


byte TempRelay = ReefAngel.Relay.RelayData;
TempRelay &= ReefAngel.Relay.RelayMaskOff;
TempRelay |= ReefAngel.Relay.RelayMaskOn;
ReefAngel.LCD.DrawOutletBox(12, 93, TempRelay);

//ReefAngel.LCD.DrawText(0,255,20,80,MoonPhaseLabel());


}

void DrawCustomGraph()
{
}

////// Place global variable code above here


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    //ReefAngel.Use2014Screen();  // Let's use 2014 Screen 
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port1Bit | Port3Bit | Port6Bit | Port7Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit | Port7Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = 0;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port2Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;


    // Ports that are always on
    ReefAngel.Relay.On( Port1 );
    ReefAngel.Relay.On( Port3 );
    ReefAngel.Relay.On( Port7 );
    ReefAngel.Relay.On( Port8 );

    ////// Place additional initialization code below here
    

    ////// Place additional initialization code above here
}

void loop()
{
  

        
    ReefAngel.StandardHeater( Port2 );
    ReefAngel.DosingPumpRepeat1( Port4 );
    ReefAngel.DosingPumpRepeat2( Port5 );
    ReefAngel.StandardATO( Port6 );
    //ReefAngel.PWM.SetDaylight( MoonPhase() );
    //ReefAngel.PWM.SetActinic( MoonPhase() );
    ////// Place your custom code below here
    

    ////// Place your custom code above here

    // This should always be the last line
    ReefAngel.Portal( "89delta" );
    ReefAngel.ShowInterface();
    
    
  // Calculate your regular sunrise/sunset PWM value
  ActinicPWMValue=PWMSlope(10,00,22,15,0,50,40,ActinicPWMValue);
  DaylightPWMValue=PWMSlope(10,00,22,15,0,50,40,DaylightPWMValue);
  CheckCloud();
  ReefAngel.PWM.SetActinic(ActinicPWMValue);
  ReefAngel.PWM.SetDaylight(DaylightPWMValue);    
}





//*********************************************************************************************************************************
// Random Cloud/Thunderstorm effects function
void CheckCloud()
{

  // ------------------------------------------------------------
  // Change the values below to customize your cloud/storm effect

  // Frequency in days based on the day of the month - number 2 means every 2 days, for example (day 2,4,6 etc)
  // For testing purposes, you can use 1 and cause the cloud to occur everyday
#define Clouds_Every_X_Days 1 

  // Percentage chance of a cloud happening today
  // For testing purposes, you can use 100 and cause the cloud to have 100% chance of happening
#define Cloud_Chance_per_Day 50

  // Minimum number of minutes for cloud duration.  Don't use max duration of less than 6
#define Min_Cloud_Duration 5

  // Maximum number of minutes for the cloud duration. Don't use max duration of more than 255
#define Max_Cloud_Duration 15

  // Minimum number of clouds that can happen per day
#define Min_Clouds_per_Day 3

  // Maximum number of clouds that can happen per day
#define Max_Clouds_per_Day 10

  // Only start the cloud effect after this setting
  // In this example, start could after 11:30am
#define Start_Cloud_After NumMins(11,30)

  // Always end the cloud effect before this setting
  // In this example, end could before 8:00pm
#define End_Cloud_Before NumMins(18,30)

  // Percentage chance of a lightning happen for every cloud
  // For testing purposes, you can use 100 and cause the lightning to have 100% chance of happening
#define Lightning_Change_per_Cloud 100

  // Note: Make sure to choose correct values that will work within your PWMSLope settings.
  // For example, in our case, we could have a max of 5 clouds per day and they could last for 50 minutes.
  // Which could mean 250 minutes of clouds. We need to make sure the PWMSlope can accomodate 250 minutes of effects or unforseen resul could happen.
    // Also, make sure that you can fit double those minutes between Start_Cloud_After and End_Cloud_Before.
  // In our example, we have 510 minutes between Start_Cloud_After and End_Cloud_Before, so double the 250 minutes (or 500 minutes) can fit in that 510 minutes window.
    // It's a tight fit, but it did.

    //#define printdebug // Uncomment this for debug print on Serial Monitor window
  #define forcecloudcalculation // Uncomment this to force the cloud calculation to happen in the boot process. 


  // Change the values above to customize your cloud/storm effect
  // ------------------------------------------------------------
  // Do not change anything below here

  static byte cloudchance=255;
  static byte cloudduration=0;
  static int cloudstart=0;
  static byte numclouds=0;
  static byte lightningchance=0;
  static byte cloudindex=0;
  static byte lightningstatus=0;
  static int LastNumMins=0;
  // Every day at midnight, we check for chance of cloud happening today
  if (hour()==0 && minute()==0 && second()==0) cloudchance=255;

#ifdef forcecloudcalculation
    if (cloudchance==255)
#else
    if (hour()==0 && minute()==0 && second()==1 && cloudchance==255) 
#endif
    {
      //Pick a random number between 0 and 99
      cloudchance=random(100); 
      // if picked number is greater than Cloud_Chance_per_Day, we will not have clouds today
      if (cloudchance>Cloud_Chance_per_Day) cloudchance=0;
      // Check if today is day for clouds. 
      if ((day()%Clouds_Every_X_Days)!=0) cloudchance=0; 
      // If we have cloud today
      if (cloudchance)
      {
        // pick a random number for number of clouds between Min_Clouds_per_Day and Max_Clouds_per_Day
        numclouds=random(Min_Clouds_per_Day,Max_Clouds_per_Day);
        // pick the time that the first cloud will start
        // the range is calculated between Start_Cloud_After and the even distribuition of clouds on this day. 
        cloudstart=random(Start_Cloud_After,Start_Cloud_After+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
      }
    }
  // Now that we have all the parameters for the cloud, let's create the effect

  if (cloudchance)
  {
    //is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,DaylightPWMValue,0,180);
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        if (random(100)<20) lightningstatus=1; 
        else lightningstatus=0;
        if (lightningstatus)
        {
          DaylightPWMValue=100; 
          ActinicPWMValue=100;
        }
        else 
        {
          DaylightPWMValue=0;
          ActinicPWMValue=0;
        }
        delay(1);
      }
    }
    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      {
        cloudstart=random(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2),(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2))+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
      }
    }
  }
  
  if (LastNumMins!=NumMins(hour(),minute()))
  {
    LastNumMins=NumMins(hour(),minute());
    ReefAngel.LCD.Clear(255,0,120,132,132);
    ReefAngel.LCD.DrawText(0,255,5,120,"C");
    ReefAngel.LCD.DrawText(0,255,11,120,"00:00");
    ReefAngel.LCD.DrawText(0,255,45,120,"L");
    ReefAngel.LCD.DrawText(0,255,51,120,"00:00");
    if (cloudchance && (NumMins(hour(),minute())<cloudstart))
    {
      int x=0;
      if ((cloudstart/60)>=10) x=11; else x=17;
      ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart/60));
      if ((cloudstart%60)>=10) x=29; else x=35;
      ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart%60));
    }
    ReefAngel.LCD.DrawText(0,255,90,120,cloudduration);
    if (lightningchance) 
    {
      int x=0;
      if (((cloudstart+(cloudduration/2))/60)>=10) x=51; else x=57;
      ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))/60));
      if (((cloudstart+(cloudduration/2))%60)>=10) x=69; else x=75;
      ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))%60));
    }
  }   
}

byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
  long n=elapsedSecsToday(now());
  cstart*=60;
  cend*=60;
  if (n<cstart) return PWMStart;
  if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
  if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
  if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
  if (n>cend) return PWMStart;
}
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Sunrise / sunset code based on location

Post by lnevo »

You would use it in the section that says Calculate your regular sunrise/sunset PWM value. The sunlocation class which i dont see declared will have methods to get the rise hour/minute and set hour/minute. You'll plug those into the pwmslope function arguments.
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Sunrise / sunset code based on location

Post by lnevo »

You would use it in the section that says Calculate your regular sunrise/sunset PWM value. The sunlocation class which i dont see declared will have methods to get the rise hour/minute and set hour/minute. You'll plug those into the pwmslope function arguments.
89delta
Posts: 157
Joined: Mon Oct 15, 2012 7:21 pm
Location: Leesburg, GA

Re: Sunrise / sunset code based on location

Post by 89delta »

Thanks for the fast reply lnevo...I know i've still gotta add the rest of the code to my sketch, but something like this:

Code: Select all

#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <Humidity.h>
#include <DCPump.h>
#include <ReefAngel.h>
#include <SunLocation.h>

////// Place global variable code below here

SunLocation sl;


byte ActinicPWMValue=0;
byte DaylightPWMValue=0;




void DrawCustomMain()
{
byte x = 6;
byte y = 2;
byte t;
ReefAngel.LCD.DrawLargeText(COLOR_BLACK, COLOR_WHITE, 6, 4, " Martin's BC29");
ReefAngel.LCD.DrawDate(6, 118);
ReefAngel.LCD.Clear(COLOR_BLACK, 1, 17, 132, 17);
pingSerial();
x = 12;
y += MENU_START_ROW+1;
ReefAngel.LCD.DrawText(COLOR_BLUE, COLOR_WHITE, x, y+6, " Display      PH");
char text[7];
ConvertNumToString(text, ReefAngel.Params.PH, 100);
ReefAngel.LCD.Clear(DefaultBGColor, x+16, y+65, x+65, y+16);
ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+75, y+18, text);
pingSerial();

ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
y += MENU_START_ROW*2;
x = 10;
ReefAngel.LCD.Clear(DefaultBGColor,x,y,x+(16*4),y+16);
pingSerial();
ReefAngel.LCD.DrawHugeNumbers(T1TempColor, DefaultBGColor, x, y, text);
pingSerial(); 
x += (16*4) + 8;
ReefAngel.LCD.DrawText(T2TempColor,DefaultBGColor,8,y+25,"Hood:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T2_PROBE], T2TempColor, 
9, y+35, 10);
ReefAngel.LCD.DrawText(T3TempColor,DefaultBGColor,x+8,y+25,"Room:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T3_PROBE], T3TempColor, 
x+9, y+35, 10);


byte TempRelay = ReefAngel.Relay.RelayData;
TempRelay &= ReefAngel.Relay.RelayMaskOff;
TempRelay |= ReefAngel.Relay.RelayMaskOn;
ReefAngel.LCD.DrawOutletBox(12, 93, TempRelay);

//ReefAngel.LCD.DrawText(0,255,20,80,MoonPhaseLabel());


}

void DrawCustomGraph()
{
}

////// Place global variable code above here


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    //ReefAngel.Use2014Screen();  // Let's use 2014 Screen 
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port1Bit | Port3Bit | Port6Bit | Port7Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit | Port7Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = 0;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port2Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;


    // Ports that are always on
    ReefAngel.Relay.On( Port1 );
    ReefAngel.Relay.On( Port3 );
    ReefAngel.Relay.On( Port7 );
    ReefAngel.Relay.On( Port8 );

    ////// Place additional initialization code below here
    
  sl.Init(-18.285833, 147.699722); // In decimal numbers (i.e. -18.285833, 147.699722)

    ////// Place additional initialization code above here
}

void loop()
{
  

        
    ReefAngel.StandardHeater( Port2 );
    ReefAngel.DosingPumpRepeat1( Port4 );
    ReefAngel.DosingPumpRepeat2( Port5 );
    ReefAngel.StandardATO( Port6 );
    //ReefAngel.PWM.SetDaylight( MoonPhase() );
    //ReefAngel.PWM.SetActinic( MoonPhase() );
    ////// Place your custom code below here
    
    // handle updating sunrise and sunset values
    sl.CheckAndUpdate();
    sl.SetOffset(0,0,0,0); // rise_hour, rise_seconds, set_hour, set_seconds
    
    ////// Place your custom code above here

    // This should always be the last line
    ReefAngel.Portal( "89delta" );
    ReefAngel.ShowInterface();
    
    
  // Calculate your regular sunrise/sunset PWM value
  ActinicPWMValue=PWMSlope(sl.GetRiseHour(),sl.GetRiseMinute(),sl.GetSetHour(),sl.GetSetMinute(),0,50,40,ActinicPWMValue);
  DaylightPWMValue=PWMSlope(sl.GetRiseHour(),sl.GetRiseMinute(),sl.GetSetHour(),sl.GetSetMinute(),0,50,40,DaylightPWMValue);
  CheckCloud();
  ReefAngel.PWM.SetActinic(ActinicPWMValue);
  ReefAngel.PWM.SetDaylight(DaylightPWMValue);    
}





//*********************************************************************************************************************************
// Random Cloud/Thunderstorm effects function
void CheckCloud()
{

  // ------------------------------------------------------------
  // Change the values below to customize your cloud/storm effect

  // Frequency in days based on the day of the month - number 2 means every 2 days, for example (day 2,4,6 etc)
  // For testing purposes, you can use 1 and cause the cloud to occur everyday
#define Clouds_Every_X_Days 1 

  // Percentage chance of a cloud happening today
  // For testing purposes, you can use 100 and cause the cloud to have 100% chance of happening
#define Cloud_Chance_per_Day 50

  // Minimum number of minutes for cloud duration.  Don't use max duration of less than 6
#define Min_Cloud_Duration 6

  // Maximum number of minutes for the cloud duration. Don't use max duration of more than 255
#define Max_Cloud_Duration 15

  // Minimum number of clouds that can happen per day
#define Min_Clouds_per_Day 3

  // Maximum number of clouds that can happen per day
#define Max_Clouds_per_Day 10

  // Only start the cloud effect after this setting
  // In this example, start could after 11:30am
#define Start_Cloud_After NumMins(11,30)

  // Always end the cloud effect before this setting
  // In this example, end could before 8:00pm
#define End_Cloud_Before NumMins(18,30)

  // Percentage chance of a lightning happen for every cloud
  // For testing purposes, you can use 100 and cause the lightning to have 100% chance of happening
#define Lightning_Change_per_Cloud 100

  // Note: Make sure to choose correct values that will work within your PWMSLope settings.
  // For example, in our case, we could have a max of 5 clouds per day and they could last for 50 minutes.
  // Which could mean 250 minutes of clouds. We need to make sure the PWMSlope can accomodate 250 minutes of effects or unforseen resul could happen.
    // Also, make sure that you can fit double those minutes between Start_Cloud_After and End_Cloud_Before.
  // In our example, we have 510 minutes between Start_Cloud_After and End_Cloud_Before, so double the 250 minutes (or 500 minutes) can fit in that 510 minutes window.
    // It's a tight fit, but it did.

    //#define printdebug // Uncomment this for debug print on Serial Monitor window
  #define forcecloudcalculation // Uncomment this to force the cloud calculation to happen in the boot process. 


  // Change the values above to customize your cloud/storm effect
  // ------------------------------------------------------------
  // Do not change anything below here

  static byte cloudchance=255;
  static byte cloudduration=0;
  static int cloudstart=0;
  static byte numclouds=0;
  static byte lightningchance=0;
  static byte cloudindex=0;
  static byte lightningstatus=0;
  static int LastNumMins=0;
  // Every day at midnight, we check for chance of cloud happening today
  if (hour()==0 && minute()==0 && second()==0) cloudchance=255;

#ifdef forcecloudcalculation
    if (cloudchance==255)
#else
    if (hour()==0 && minute()==0 && second()==1 && cloudchance==255) 
#endif
    {
      //Pick a random number between 0 and 99
      cloudchance=random(100); 
      // if picked number is greater than Cloud_Chance_per_Day, we will not have clouds today
      if (cloudchance>Cloud_Chance_per_Day) cloudchance=0;
      // Check if today is day for clouds. 
      if ((day()%Clouds_Every_X_Days)!=0) cloudchance=0; 
      // If we have cloud today
      if (cloudchance)
      {
        // pick a random number for number of clouds between Min_Clouds_per_Day and Max_Clouds_per_Day
        numclouds=random(Min_Clouds_per_Day,Max_Clouds_per_Day);
        // pick the time that the first cloud will start
        // the range is calculated between Start_Cloud_After and the even distribuition of clouds on this day. 
        cloudstart=random(Start_Cloud_After,Start_Cloud_After+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
      }
    }
  // Now that we have all the parameters for the cloud, let's create the effect

  if (cloudchance)
  {
    //is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,DaylightPWMValue,0,180);
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        if (random(100)<20) lightningstatus=1; 
        else lightningstatus=0;
        if (lightningstatus)
        {
          DaylightPWMValue=100; 
          ActinicPWMValue=100;
        }
        else 
        {
          DaylightPWMValue=0;
          ActinicPWMValue=0;
        }
        delay(1);
      }
    }
    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      {
        cloudstart=random(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2),(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2))+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
      }
    }
  }
  
  if (LastNumMins!=NumMins(hour(),minute()))
  {
    LastNumMins=NumMins(hour(),minute());
    ReefAngel.LCD.Clear(255,0,120,132,132);
    ReefAngel.LCD.DrawText(0,255,5,120,"C");
    ReefAngel.LCD.DrawText(0,255,11,120,"00:00");
    ReefAngel.LCD.DrawText(0,255,45,120,"L");
    ReefAngel.LCD.DrawText(0,255,51,120,"00:00");
    if (cloudchance && (NumMins(hour(),minute())<cloudstart))
    {
      int x=0;
      if ((cloudstart/60)>=10) x=11; else x=17;
      ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart/60));
      if ((cloudstart%60)>=10) x=29; else x=35;
      ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart%60));
    }
    ReefAngel.LCD.DrawText(0,255,90,120,cloudduration);
    if (lightningchance) 
    {
      int x=0;
      if (((cloudstart+(cloudduration/2))/60)>=10) x=51; else x=57;
      ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))/60));
      if (((cloudstart+(cloudduration/2))%60)>=10) x=69; else x=75;
      ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))%60));
    }
  }   
}

byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
  long n=elapsedSecsToday(now());
  cstart*=60;
  cend*=60;
  if (n<cstart) return PWMStart;
  if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
  if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
  if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
  if (n>cend) return PWMStart;
}
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Sunrise / sunset code based on location

Post by lnevo »

I see you figured it out! Yes exactly :) let us know if that worked for you?
89delta
Posts: 157
Joined: Mon Oct 15, 2012 7:21 pm
Location: Leesburg, GA

Re: Sunrise / sunset code based on location

Post by 89delta »

Nice....thanks for looking lnevo. My other question is in regards to the moon phases. Can I use sl.GetRiseHour(),sl.GetRiseMinute(),sl.GetSetHour(),sl.GetSetMinute() in switching over to the moonphase() for my blue leds after the day has finished.
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Sunrise / sunset code based on location

Post by lnevo »

Yes, but you might want to also look at my moon rise/set class that you can use too which calculates the rise/set times for the the Moon :) However, you can use the sl.GetXXX() for whatever scheduling you want. You could also look at the option sl.UseMemory=true which will set the StandardLight schedule into memory so you could have other devices that aren't dimming let's say based off the sunrise/sunset schedule.
89delta
Posts: 157
Joined: Mon Oct 15, 2012 7:21 pm
Location: Leesburg, GA

Re: Sunrise / sunset code based on location

Post by 89delta »

How would I incorporate your moon class into it lnevo.....thanks for your help.
89delta
Posts: 157
Joined: Mon Oct 15, 2012 7:21 pm
Location: Leesburg, GA

Re: Sunrise / sunset code based on location

Post by 89delta »

Sweet....thank lnevo. Will try it out tonight when i get home.

Sent from my SAMSUNG-SGH-I717 using Tapatalk
89delta
Posts: 157
Joined: Mon Oct 15, 2012 7:21 pm
Location: Leesburg, GA

Re: Sunrise / sunset code based on location

Post by 89delta »

So everything is working correctly with my sketch, Sunrise/sunset, Weather and moon phases. Although i've noticed that the sunrise/sunset times don't really change but by +/- 2 minutes. Is that normal for the most part? My Long/Lat is set to the GBR between Paul Reef and Storm Reef off of Queensland,AU.

sl.Init(-21.285833, 150.999722); // In decimal numbers (i.e. -18.285833, 147.699722)
sl.SetOffset(11,0,11,0); // rise_hour, rise_seconds, set_hour, set_seconds
User avatar
lnevo
Posts: 5422
Joined: Fri Jul 20, 2012 9:42 am

Re: Sunrise / sunset code based on location

Post by lnevo »

Yep, try tracking it over the course of a month or two. Area's closer to the equator are going to have the smallest amount of shift daily as the fluctuation is only going to be +/- 2 hours or so over the course of the seasons.
89delta
Posts: 157
Joined: Mon Oct 15, 2012 7:21 pm
Location: Leesburg, GA

Re: Sunrise / sunset code based on location

Post by 89delta »

Ok, thanks for the clarification lnevo. Love everything you guys have done with coding and everything else.

Sent from my SAMSUNG-SGH-I717 using Tapatalk
Post Reply