Progressive sunphase

Do you have a question on how to do something.
Ask in here.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Progressive sunphase

Post by Deckoz2302 »

Ok so I have been working on creating a progressive sunphase dependant on date and preset variables. So far the function is about 100 lines of code. still have a little way to go.

Code: Select all

void season()
{
	#define forceseasoncalculation
	#define longitude = ;

	static int ndays = 0;
	static byte ledch0base = 0;
	static byte ledch1base = 0;
	static byte ledch2base = 0;
	static byte ledch3base = 0;
	static byte ssnp = 0;
	static byte ssnpt = 0;
	byte rtime = 0;
	byte rhour = 0;
	byte rmin = 0;
	byte rsec = 0;
	byte stime = 0;
	byte shour = 0;
	byte smin = 0;
	byte ssec = 0;
	static int iDiffrise = 0;
	static int iDiffset = 0;
	int risediffperday = 0;
	int setdiffperday = 0;
	int totalrise = 0;
	int totalset = 0
	int atoi ( const char * str );

	
	int risehour[8]= {07,07,07,06,06,05,06,06};
	int riseminute[8]={00,30,00,30,00,30,00,30};
	int sethour[8] = {05,06,06,07,07,07,07,06};
	int setminute[8] = {30,00,30,00,00,30,00,00};


	if (hour()==0 && minute()==0 && second()==0) ssnp=0;
		#ifdef forceseasoncalculation
			If (ssnp==0)
	#else
		if (hour()==0 && minute()==0 && second()==1 && ssnp==0) 
	#endif
	{
		//leapyear or not?
		if (year()%4 == 0 && !(year()%100 == 0 && year()%400 != 0)) DaysPerMonth = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		//every other year
		else DaysPerMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		//adding up past months days
		for (i=0; i<month() - 1; i++) ndays += DaysPerMonth[i];
			//adding current months days, julian day number is output ex: nday = 192
			ndays += day(); 



		//define days between begin and middle season
		int seasons[8] ={0,45,96,135,187,238,283,328}

		//define season
		for (s=0; seasons[s]<ndays; s++);
		//define which sunrise/set array value to pull, if nday = 46, 46
		if (ndays < seasons[s]) ssnpt = s, ssnp = s-1;
		if (ssnpt >= 7) ssnpt = 1;
		
		

//calculate sunrise difference in time between array pulled days
char tm1[9] = "risehour[ssnp]:riseminute[ssnp]:00"; 
char tm2[9] = "risehour[ssnpt]:riseminute[ssnpt]:00";
tm1[2]=tm1[5]=tm2[2]=tm2[5]=0;
iDiffrise = (atoi(tm1)-atoi(tm2))*3600 + (atoi(tm1+3)-atoi(tm2+3))*60 + (atoi(tm1+6)-atoi(tm2+6));
char tm3[9] = "sethour[ssnp]:setminute[ssnp]:00"; 
char tm4[9] = "sethour[ssnpt]:setminute[ssnpt]:00";
tm3[2]=tm3[5]=tm4[2]=tm4[5]=0;
iDiffset = (atoi(tm3)-atoi(tm4))*3600 + (atoi(tm3+3)-atoi(tm4+3))*60 + (atoi(tm3+6)-atoi(tm4+6));
//calculate new sunrise/set difference from array value
risediffperday = idiffrise/(season[ssnp]-season[ssnpt]);
totalrise = risediffperday*(nday - season[ssnp]);
setdiffperday = idiffset/(season[ssnp]-season[ssnpt]);
totalset = setdiffperday*(nday - season[ssnp]);

//creating time in seconds
rtime=(risehour[ssnp]*3600)+(riseminute[ssnp]*60)+(risesecond[ssnp])
if (ssnp = 0 || ssnp = 2 || ssnp = 4 || ssnp = 6) rtime += totalrise;
else rtime -= totalrise;
stime=(sethour[ssnp]*3600)+(setminute[ssnp]*60)+(setsecond[ssnp])
if (ssnp = 1 || ssnp = 3 || ssnp = 5 || ssnp = 7) stime += totalset;
else stime -= totalset;

//turning seconds back to h m s
rhour=rtime/3600; 
rtime=rtime%3600;
rmin=rtime/60; 
rtime=rtime%60; 
rsec=rtime;
if(rsec > 30) rmin++; 
shour=stime/3600; 
stime=stime%3600;
smin=stime/60; 
stime=stime%60; 
ssec=stime;
if(ssec > 30) smin++;

//time for each active led channel to pull for sunrise
int Sunrise[2]={rhour,rmin};
int Sunset[2]={shour,smin};

//set LED channel PWM intensity values
ledch0int = random(25+(3*ssn),30+(3*ssn));
ledch1int = random(65+(3*ssn),70+(3*ssn));
ledch2int = random(65+(3*ssn),70+(3*ssn));
ledch3int = random(50+(3*ssn),55+(3*ssn));
}




anyway back to thinking lol
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

rimai
Be advised that buckpucks have a very strange configuration that does not isolate the output side to the dimming circuitry, which leads to a lot of noise that causes RA to crash. We had to create a special circuitry board to isolate the signal to make it work.
hmm...I just saw this post, I use buckpucks. What exactly does this circuit contain? got a parts list?
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

Humm...
Buckpucks... We had to create a special board with opto-isolators to eliminate the noise generated by the buckpucks. The other benefit of having this circuit was to invert the signal so the pucks repond to the same way that RA PWM signals are generated, which is 0%=off and 100%=on. For some reason buckpucks use inverted signals.
The opto chip used was LTV827.
http://search.digikey.com/us/en/product ... -ND/385838
Roberto.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

Just ordered my RA. got any input on this code or if I'm close? See anything wrong with what's posted already?
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

Alright here is what I got so far. However couple of problems trying to think of how to fix this error "initializer-string for array of chars is too long" for these lines

Code: Select all

		char tm1[9] = "risehour[ssnp]:riseminute[ssnp]:00"; 
		char tm2[9] = "risehour[ssn]:riseminute[ssn]:00";
		char tm3[9] = "sethour[ssnp]:setminute[ssnp]:00"; 
		char tm4[9] = "sethour[ssn]:setminute[ssn]:00";
Also Im not sure if I returned the values Sunrise & Sunset from Seasons to Loop properlly, my brain hurts >.<. Help would be appreciated.

Code: Select all

#include <ReefAngel_Colors.h>
#include <ReefAngel_CustomColors.h>
#include <ReefAngel_Features.h>
#include <ReefAngel_Globals.h>
#include <ReefAngel_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <ReefAngel_EEPROM.h>
#include <ReefAngel_NokiaLCD.h>
#include <ReefAngel_ATO.h>
#include <ReefAngel_Joystick.h>
#include <ReefAngel_LED.h>
#include <ReefAngel_TempSensor.h>
#include <ReefAngel_Relay.h>
#include <ReefAngel_PWM.h>
#include <ReefAngel_Timer.h>
#include <ReefAngel_Memory.h>
#include <ReefAngel.h>
//*********************************************************************************************************************************
//Start of PWM Expansion Code Header

// This is just how we are going to reference the PWM expansion ports within the code.
// You can change the labels if you would like, just as long as they are changed all throughout the code too.
#define LEDPWM0 0
#define LEDPWM1 1
#define LEDPWM2 2
#define LEDPWM3 3
#define LEDPWM4 4
#define LEDPWM5 5

// Initial values to all 6 channels at startup. They will always be 0.
byte PWMChannel[]={
  0,0,0,0,0,0};
byte cloudchance=0;
byte cloudduration=0;
int cloudstart=0;

//End of PWM Expansion Code Header
//*********************************************************************************************************************************

//Custom mainscreen copied from the custom main thread - constantly getting errors about LCD?
void setup()
{
    ReefAngel.Init();  //Initialize controller
    //WifiAuthentication("Brad:Blank");

    ReefAngel.FeedingModePorts = B10100000;
    ReefAngel.WaterChangePorts = B10101000;
    ReefAngel.OverheatShutoffPorts = B01000000;
    ReefAngel.LightsOnPorts = B00000010;

    // Ports that are always on
    ReefAngel.Relay.On(Port1);
    ReefAngel.Relay.On(Port2);
    ReefAngel.Relay.On(Port3);
    ReefAngel.Relay.On(Port4);
    ReefAngel.Relay.On(Port5);
    ReefAngel.Relay.On(Port6);
}

void loop()
{
	int Sunrise[2];
        int Sunset[2];
        int whSunrise[2];
        int whSunset[2];
        int vSunrise[2];
        int vSunset[2];
        
  	//Heater on&off
    	ReefAngel.StandardHeater(Port7,780,792);
   
		//Delay Skimmer
		ReefAngel.Relay.DelayedOn(Port8, 5);

		//call moonphase
		if ( hour() <= 6 || hour () >= 19 ) // Moonlights on from 7PM to 7AM
			{
				ReefAngel.PWM.SetActinic(MoonPhase());
				ReefAngel.PWM.SetDaylight(MoonPhase());
			}
		else
			{
				ReefAngel.PWM.SetActinic(0);
				ReefAngel.PWM.SetDaylight(0);
			}
                Seasons();
		// Calculate your regular sunrise/sunset PWM value
		PWMChannel[LEDPWM0]=PWMSlope(whSunrise[1],whSunrise[2],whSunset[1],whSunset[2],0,100,180,PWMChannel[LEDPWM0]);
		PWMChannel[LEDPWM1]=PWMSlope(vSunrise[1],vSunrise[2],vSunset[1],vSunset[2],0,100,180,PWMChannel[LEDPWM1]);
		PWMChannel[LEDPWM2]=PWMSlope(Sunrise[1],Sunrise[2],Sunset[1],Sunset[2],0,100,180,PWMChannel[LEDPWM2]);
		PWMChannel[LEDPWM3]=PWMSlope(Sunrise[1],Sunrise[2],whSunset[1],whSunset[2],0,100,180,PWMChannel[LEDPWM3]);
		//Call Cloud Check
		CheckCloud();
		//Draw PWM value
		//ReefAngel.LCD.DrawText(0,255,5,120,PWMChannel[LEDPWM0]);
		//ReefAngel.LCD.DrawText(0,255,35,120,PWMChannel[LEDPWM1]);
		//ReefAngel.LCD.DrawText(0,255,65,120,PWMChannel[LEDPWM2]);
		//ReefAngel.LCD.DrawText(0,255,95,120,PWMChannel[LEDPWM3]);
			
	        ReefAngel.ShowInterface();
}

//*********************************************************************************************************************************
//Start of PWM slope function code designed for the PWM Expansion module
void PWMExpansion(byte cmd, byte data)
{ 
Wire.beginTransmission(8); // transmit to device #2
Wire.send('$'); // sends $ 
Wire.send('$'); // sends $ 
Wire.send('$'); // sends $ 
Wire.send(cmd); // sends a value 
Wire.send(data); // sends 255 
Wire.endTransmission(); // stop transmitting
}
//End of PWM slope function code designed for the PWM Expansion module
//*********************************************************************************************************************************


//*********************************************************************************************************************************
// 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 3

  // 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 30

  // 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 20

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

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

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

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

  // 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 65

  // Channels used by the actinic LEDs on the PWM Expansion module
  // These channels will not be dimmed when the cloud effect is triggered
  // Number is a binary form. B001100 means channel 2 and 3 are used for actinics
#define Actinic_Channels B001110

  // Channels used by the daylight LEDs on the PWM Expansion module
  // These channels will be used for the spike when lightning effect is triggered
  // Number is a binary form. B000011 means channel 0 and 1 are used for daylights
#define Daylight_Channels B000001

  // 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))
    {
      // let's go through all channels to pick which ones will be dimmed
      for (int a=0;a<6;a++)
      {
        if (bitRead(Actinic_Channels,a)==0)
        {
          // this will slope down the channel from the current PWM to 0 within 3minutes.
          // then it will stay at 0 for the duration of the cycle
          // and finally slope up from 0 to PWM value within 3 minutes
          // it is basically an inversed slope
          PWMChannel[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[a],0,180);
        }
      }
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        for (int b=0;b<6;b++)
        {
          if (bitRead(Daylight_Channels,b)==1)
          {
            if (random(100)<20) lightningstatus=1; 
            else lightningstatus=0;
            if (lightningstatus) PWMChannel[b]=100; 
            else PWMChannel[b]=0;
            //delay(10);
          }
          else
          {
            PWMChannel[b]=20;
          }
        }
      }
    }
    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;
}

void Seasons()
{
	#define forceseasoncalculation
	static short ndays = 0;
	static byte ledch0base = 0;
	static byte ledch1base = 0;
	static byte ledch2base = 0;
	static byte ledch3base = 0;
	static byte ssn = 0, ssnp = 0, ssnpt = 0;
	int wrtime = 0;
	int wstime = 0;
	int rtime = 0;
	int stime = 0;
	int vrtime = 0;
	int vstime = 0;
	byte wrhour = 0, wrrmin = 0, wrsec = 0,wshour = 0,wsmin = 0, wssec = 0, rhour = 0, rmin = 0, rsec = 0, shour = 0, smin = 0, ssec = 0, vrhour = 0, vrmin = 0, vrsec = 0, vshour = 0, vsmin = 0, vssec = 0;
	static byte iDiffrise = 0;
	static byte iDiffset = 0;
	short risediffperday = 0;
	short setdiffperday = 0;
	short totalrise = 0;
	short totalset = 0;
	int atoi ( const char * str );
        byte i = 0, tyd=0, s=0;
        int DaysPerMonth[12];
        byte DaysPerYear = 0;
        
	//rise and set times set by hour and minute. 
	int risehour[8]= {07,07,07,06,06,05,06,06};
	int riseminute[8]={00,30,00,30,00,30,00,30};
	int sethour[8] = {17,18,18,19,19,19,19,18};
	int setminute[8] = {30,00,30,00,00,30,00,00};

	//
	if (hour()==0 && minute()==0 && second()==0) ssnp=0;
		#ifdef forceseasoncalculation
			if (ssnp==0)
	#else
		if (hour()==0 && minute()==0 && second()==1 && ssnp==0)
	#endif
	{
		//leapyear or not?
		if (year()%4 == 0 && !(year()%100 == 0 && year()%400 != 0)) int DaysPerMonth[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		//every other year
		else int DaysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		//adding up past months days
		for (i=0; i<month() - 1; i++) ndays += DaysPerMonth[i];
			//adding current months days, julian day number is output ex: nday = 192
			ndays += day(); 
		//output total days in year for final season day count later in code
		for(tyd=0;tyd<11;tyd++)DaysPerYear += DaysPerMonth[tyd];
		//define days between begin and middle season
		int seasons[9] ={0,45,96,135,187,238,283,328,DaysPerYear};
		//define season and array pulling variable
		for (s=0; seasons[s] < ndays; s++) ssn = s, ssnpt = s, ssnp = s-1;
		//set loop on array time pulling variable to go back to beginning instead of increasing array size
		if (ssn > 7) ssn = 0;
		
		//calculate sunrise difference in time between array pulled days, in other words if seasons rise start is 730, and mid season rise start is 30 minutes
		char tm1[9] = "risehour[ssnp]:riseminute[ssnp]:00"; 
		char tm2[9] = "risehour[ssn]:riseminute[ssn]:00";
		tm1[2]=tm1[5]=tm2[2]=tm2[5]=0;
		iDiffrise = (atoi(tm1)-atoi(tm2))*3600 + (atoi(tm1+3)-atoi(tm2+3))*60 + (atoi(tm1+6)-atoi(tm2+6));
		char tm3[9] = "sethour[ssnp]:setminute[ssnp]:00"; 
		char tm4[9] = "sethour[ssn]:setminute[ssn]:00";
		tm3[2]=tm3[5]=tm4[2]=tm4[5]=0;
		iDiffset = (atoi(tm3)-atoi(tm4))*3600 + (atoi(tm3+3)-atoi(tm4+3))*60 + (atoi(tm3+6)-atoi(tm4+6));

		//calculate new sunrise/set difference from array value 
		//here we take the difference in day and get a difference in seconds per day. So if the time difference is 30 minutes from the last equation we divide that by the start day of season subtracted by the end day of season to get the number of days in the season
		//example: 30 minutes/(day 45 – day 0) = 30/45 = 0.66666
		//0.66666 is the difference of minutes each day throughout the season for sunrise
		risediffperday = idiffrise/(season[ssnpt]-season[ssnp]);
		totalrise = risediffperday*(nday - season[ssnp]);
		setdiffperday = idiffset/(season[ssnpt]-season[ssnp]);
		totalset = setdiffperday*(nday - season[ssnp]);

		//creating time in seconds
		rtime=(risehour[ssnp]*3600)+(riseminute[ssnp]*60)+(risesecond[ssnp])
		if (ssnp = 0 || ssnp = 2 || ssnp = 4 || ssnp = 6) rtime += totalrise;
			else rtime -= totalrise;
		stime=(sethour[ssnp]*3600)+(setminute[ssnp]*60)+(setsecond[ssnp])
		if (ssnp = 1 || ssnp = 3 || ssnp = 5 || ssnp = 7) stime += totalset;
			else stime -= totalset;

		//turning seconds back to h m s
		//here are three different times offset by half hour to have different colors rise and set at different times
		//standard times
		rhour=rtime/3600; 
			rtime=rtime%3600;
				rmin=rtime/60; 
					rtime=rtime%60; 
						rsec=rtime;
							if(rsec > 30) rmin++; 
		shour=stime/3600; 
			stime=stime%3600;
				smin=stime/60; 
					stime=stime%60; 
						ssec=stime;
							if(ssec > 30) smin++;
		//to change the offset change the number 1200 in seconds added or subtracted to rtime
		//half hour shorter
		wrtime = rtime + 1200;
			wrhour = wrtime/3600;
				wrtime=wrtime%3600;
					wrmin=wrtime/60;
						wrtime=wrtime%60;
							wrsec=wrtime;
								if(wrsec>30) wrmin++;
		wstime = stime - 1200;
			wshour = wstime/3600;
				wstime=wstime%3600;
					wsmin=wstime/60;
						wstime=wstime%60;
							wssec=wstime;
								if(wssec>30) wsmin++;
		//half hour longer
		vrtime = rtime - 1200;
			vrhour = vrtime/3600;
				vrtime=vrtime%3600;
					vrmin=vrtime/60;
						vrtime=vrtime%60;
							vrsec=vrtime;
								if(vrsec>30) vrmin++;
		vstime = stime + 1200;
			vshour = vstime/3600;
				vstime=vstime%3600;
					vsmin=vstime/60;
						vstime=vstime%60;
							vssec=vstime;
								if(vssec>30) vsmin++;


//time for each active led channel to pull for sunrise
return int Sunrise[2]={rhour,rmin};
return int Sunset[2]={shour,smin};
return int whSunrise[2]={wrhour,wrmin};
return int whSunset [2]={wshour,wsmin};
return int vSunrise[2]={vrhour,vrmin};
return int vSunset [2]={vshour,vsmin};
}
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

When you declare char tm1[9], you are declaring the variable tm1 is an array of char.
We can say that the variable char is one single ascii character to make it easier.
So, you variable tm1[9] is an array of characters, which is the same as a string.
In other words, the way to look a char [] is to look them as a string.
If you declare the char[9], the actual size of the string is 8, because the last character has to be always null. It's called null termination and the code knows that it has to look for a null when reading the memory.
http://www.arduino.cc/en/Reference/String
I'm confused as to what the code is trying to do.

Code: Select all

char tm1[9] = "risehour[ssnp]:riseminute[ssnp]:00"; 
If I look at the code, even though it is wrong, I can see that what you are trying to do is fill the variable tm1 with a human readable time string.
Let assign number for sake of example. risehour is 10 and riseminute is 15.
The tm1 variable would look like something like this "10:15:00"
Then this line throws me completely off.

Code: Select all

      tm1[2]=tm1[5]=tm2[2]=tm2[5]=0;
It's replacing the ":" on the tm1 string with null characters. So, the string would terminate right after 10.
The string would look like this "10\015\000", where \0 is the null character.
If that wasn't confusing enough, the next line just makes no sense.

Code: Select all

      iDiffrise = (atoi(tm1)-atoi(tm2))*3600 + (atoi(tm1+3)-atoi(tm2+3))*60 + (atoi(tm1+6)-atoi(tm2+6));
The function atoi(tm1) is turning the string tm1 back to integer for some math calculation. It doesn't make sense to turn risehour and riseminute from integer into a string, just to turn it back to integer again to do some math.
Maybe we can optmize this piece so you don't have to go from int to string and back to int again.
Could you explain a little what the intention of this piece of code is?
Roberto.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

yea....I couldnt figure out why I wrote it like that a month ago haha...I just rewrote it, although still unsure if its right. that peice of code was basically taking two different times say 730 and 700 and finding the difference between them in minutes. and the next block takes the number of days in the partial season say 45 days and divides the minutes by that to find the difference in sunrise/set per day. so 30/45 = 0.66666 or 41 seconds...ugh now im confusing myself lol

Code: Select all

int rise1 = calcSec(risehour[ssnp],riseminute[ssnp]);
                int rise2 = calcSec(risehour[ssn],riseminute[ssn]);
                iDiffrise = calcTime(rise1, rise2);
                int set1 = calcSec(sethour[ssnp],setminute[ssnp]);
                int set2 = calcSec(sethour[ssn],setminute[ssn]);
                iDiffset = calcTime(set1,set2);
they reference these two ints

Code: Select all

int calcSec(int hr, int minu)
{
    int hour = hr * 3600;
    int min = minu * 60;
    int totalseconds=hour+min;
    return totalseconds;
}

int calculateTime(int seconds1, int seconds2)
{
    int timediff=seconds1-seconds2;
    return timediff;
}
now im having a problem figuring this out now haha...man writing this stuff a month ago and coming back to it thinking wtf did i do this for...lol

Code: Select all

//creating time in seconds
		rtime=(risehour[ssnp]*3600)+(riseminute[ssnp]*60);
		if (ssnp = 0 || ssnp = 2 || ssnp = 4 || ssnp = 6) rtime =+ totalrise;
			else rtime =- totalrise;
		stime=(sethour[ssnp]*3600)+(setminute[ssnp]*60);
		if (ssnp = 1 || ssnp = 3 || ssnp = 5 || ssnp = 7) stime += totalset;
			else stime -= totalset;
on both if statements I get the error lvalue required as left opperand of assignment. Man now I remember why my teachers always said don't ever stop coding, cause you'll forget stuff...ugh

and for the last bit of code I posted the reason it is an if/else statement declaring whether to subtract the time or add the time is to account for whether the rise/set time is increasing or lowering in these four arrays

Code: Select all

int risehour[8]= {07,07,07,06,06,05,06,06};
	int riseminute[8]={00,30,00,30,00,30,00,30};
	int sethour[8] = {17,18,18,19,19,19,19,18};
	int setminute[8] = {30,00,30,00,00,30,00,00};
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

Much better :)
But, instead of reinventing the wheel, why not use the built-in time funtions we currently have?
We already have these:

Number of minutes from midnight:

Code: Select all

int NumMins(uint8_t ScheduleHour, uint8_t ScheduleMinute)
Leap year:

Code: Select all

bool IsLeapYear(int year)
Unix time, for more info, look in the Time.h and Time.cpp files:

Code: Select all

time_t makeTime(tmElements_t &tm){   
// assemble time elements into time_t 
// note year argument is offset from 1970 (see macros in time.h to convert to other formats)
// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9
Where the tm structure is like this:

Code: Select all

typedef struct  { 
  uint8_t Second; 
  uint8_t Minute; 
  uint8_t Hour; 
  uint8_t Wday;   // day of week, sunday is day 1
  uint8_t Day;
  uint8_t Month; 
  uint8_t Year;   // offset from 1970; 
} 	tmElements_t, TimeElements, *tmElementsPtr_t;
Roberto.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

BTW, the compile error is on the comparison sign.
In C, one "=" is assigning and "==" is comparison.
So your code has to look like this:

Code: Select all

      if (ssnp == 0 || ssnp == 2 || ssnp == 4 || ssnp == 6) rtime =+ totalrise;
Roberto.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

oh wow ...lol im simple lol and i dont know why im reinventing the wheel....probably cause I didnt look at what the wheel already had >.< or how to implement it...haha

Here is a cut down pde of just the seasons function and how it should work...took all the other stuff out to make it easier to look at for help

i think its close now...just trying to remember how to return the values at the end to the integer arrays in Loop for pwmslope to pull. The last quations will round up 1 minute if remaining seconds are above 30.

Code: Select all

#include <ReefAngel_Colors.h>
#include <ReefAngel_CustomColors.h>
#include <ReefAngel_Features.h>
#include <ReefAngel_Globals.h>
#include <ReefAngel_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <ReefAngel_EEPROM.h>
#include <ReefAngel_NokiaLCD.h>
#include <ReefAngel_ATO.h>
#include <ReefAngel_Joystick.h>
#include <ReefAngel_LED.h>
#include <ReefAngel_TempSensor.h>
#include <ReefAngel_Relay.h>
#include <ReefAngel_PWM.h>
#include <ReefAngel_Timer.h>
#include <ReefAngel_Memory.h>
#include <ReefAngel.h>
//*********************************************************************************************************************************
//Start of PWM Expansion Code Header

// This is just how we are going to reference the PWM expansion ports within the code.
// You can change the labels if you would like, just as long as they are changed all throughout the code too.
#define LEDPWM0 0
#define LEDPWM1 1
#define LEDPWM2 2
#define LEDPWM3 3
#define LEDPWM4 4
#define LEDPWM5 5

// Initial values to all 6 channels at startup. They will always be 0.
byte PWMChannel[]={
  0,0,0,0,0,0};
byte cloudchance=0;
byte cloudduration=0;
int cloudstart=0;

//End of PWM Expansion Code Header
//*********************************************************************************************************************************

int calcSec(int,int);
int calcTime(int,int);

void setup()
{
    ReefAngel.Init();  
}

void loop()
{
	int Sunrise[2];
        int Sunset[2];
        int whSunrise[2];
        int whSunset[2];
        int vSunrise[2];
        int vSunset[2];
        Seasons();
		// Calculate your regular sunrise/sunset PWM value
		PWMChannel[LEDPWM0]=PWMSlope(whSunrise[1],whSunrise[2],whSunset[1],whSunset[2],0,100,180,PWMChannel[LEDPWM0]);
		PWMChannel[LEDPWM1]=PWMSlope(vSunrise[1],vSunrise[2],vSunset[1],vSunset[2],0,100,180,PWMChannel[LEDPWM1]);
		PWMChannel[LEDPWM2]=PWMSlope(Sunrise[1],Sunrise[2],Sunset[1],Sunset[2],0,100,180,PWMChannel[LEDPWM2]);
		PWMChannel[LEDPWM3]=PWMSlope(Sunrise[1],Sunrise[2],whSunset[1],whSunset[2],0,100,180,PWMChannel[LEDPWM3]);
		
        ReefAngel.ShowInterface();
}

//*********************************************************************************************************************************
//Start of PWM slope function code designed for the PWM Expansion module
void PWMExpansion(byte cmd, byte data)
{ 
Wire.beginTransmission(8); // transmit to device #2
Wire.send('$'); // sends $ 
Wire.send('$'); // sends $ 
Wire.send('$'); // sends $ 
Wire.send(cmd); // sends a value 
Wire.send(data); // sends 255 
Wire.endTransmission(); // stop transmitting
}
//End of PWM slope function code designed for the PWM Expansion module
//*********************************************************************************************************************************

void Seasons()
{
	#define forceseasoncalculation
	short ndays = 0;
	static byte ledch0base = 0;
	static byte ledch1base = 0;
	static byte ledch2base = 0;
	static byte ledch3base = 0;
	static byte ssn = 0, ssnp = 0, ssnpt = 0;
	int wrtime = 0;
	int wstime = 0;
	int rtime = 0;
	int stime = 0;
	int vrtime = 0;
	int vstime = 0;
	int wrhour = 0, wrmin = 0, wrsec = 0,wshour = 0,wsmin = 0, wssec = 0, rhour = 0, rmin = 0, rsec = 0, shour = 0, smin = 0, ssec = 0, vrhour = 0, vrmin = 0, vrsec = 0, vshour = 0, vsmin = 0, vssec = 0;
	static byte iDiffrise = 0;
	static byte iDiffset = 0;
	short risediffperday = 0;
	short setdiffperday = 0;
	int totalrise = 0;
	int totalset = 0;
	int atoi ( const char * str );
        byte i = 0, tyd=0, s=0;
        int DaysPerMonth[12];
        byte DaysPerYear = 0;
        
	//rise and set times set by hour and minute. there are 4 seasons however there are 8 highs & lows in rise and set throughout the year first spot is second half of winter starting jan 1st 
	int risehour[8]= {07,07,07,06,06,05,06,06};
	int riseminute[8]={00,30,00,30,00,30,00,30};
	int sethour[8] = {17,18,18,19,19,19,19,18};
	int setminute[8] = {30,00,30,00,00,30,00,00};

	//
	if (hour()==0 && minute()==0 && second()==0) ssnp=0;
		#ifdef forceseasoncalculation
			if (ssnp==0)
	#else
		if (hour()==0 && minute()==0 && second()==1 && ssnp==0)
	#endif
	{
		//leapyear or not?
		if (year()%4 == 0 && !(year()%100 == 0 && year()%400 != 0)) int DaysPerMonth[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		//every other year
		else int DaysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		//adding up past months days
		for (i=0; i<month() - 1; i++) ndays += DaysPerMonth[i];
			//adding current months days, julian day number is output ex: nday = 192
			ndays += day(); 
		//output total days in year for final season day count later in code
		for(tyd=0;tyd<11;tyd++)DaysPerYear += DaysPerMonth[tyd];
		//define days between begin and middle season
		int seasons[9] ={0,45,96,135,187,238,283,328,DaysPerYear};
		//define season and array pulling variable
		for (s=0; seasons[s] < ndays; s++) ssn = s, ssnpt = s, ssnp = s-1;
		//set loop on array time pulling variable to go back to beginning instead of increasing array size
		if (ssn > 7) ssn = 0;
		
                //differece in seconds between season array times
                int rise1 = calcSec(risehour[ssnp],riseminute[ssnp]);
                int rise2 = calcSec(risehour[ssn],riseminute[ssn]);
                iDiffrise = calcTime(rise1, rise2);
                int set1 = calcSec(sethour[ssnp],setminute[ssnp]);
                int set2 = calcSec(sethour[ssn],setminute[ssn]);
                iDiffset = calcTime(set1,set2);
		
		//calculate new sunrise/set difference from array value 
		//here we take the difference in day and get a difference in seconds per day. So if the time difference is 30 minutes from the last equation we divide that by the start day of season subtracted by the end day of season to get the number of days in the season
		//example: 30 minutes/(day 45 – day 0) = 30/45 = 0.66666
		//0.66666 is the difference of minutes each day throughout the season for sunrise
		risediffperday = iDiffrise/(seasons[ssnpt]-seasons[ssnp]);
		totalrise = risediffperday*(ndays - seasons[ssnp]);
		setdiffperday = iDiffset/(seasons[ssnpt]-seasons[ssnp]);
		totalset = setdiffperday*(ndays - seasons[ssnp]);

		//creating time in seconds
		rtime=(risehour[ssnp]*3600)+(riseminute[ssnp]*60);
		if (ssnp == 0 || ssnp == 2 || ssnp == 4 || ssnp == 6) rtime =+ totalrise;
			else rtime =- totalrise;
		stime=(sethour[ssnp]*3600)+(setminute[ssnp]*60);
		if (ssnp == 1 || ssnp == 3 || ssnp == 5 || ssnp == 7) stime += totalset;
			else stime -= totalset;

		//turning seconds back to h m s
		//here are three different times offset by half hour to have different colors rise and set at different times
		//standard times
		rhour=rtime/3600; 
			rtime=rtime%3600;
				rmin=rtime/60; 
					rtime=rtime%60; 
						rsec=rtime;
							if(rsec > 30) rmin++; 
		shour=stime/3600; 
			stime=stime%3600;
				smin=stime/60; 
					stime=stime%60; 
						ssec=stime;
							if(ssec > 30) smin++;
		//to change the offset change the number 1200 in seconds added or subtracted to rtime
		//half hour shorter
		wrtime = rtime + 1200;
			wrhour = wrtime/3600;
				wrtime=wrtime%3600;
					wrmin=wrtime/60;
						wrtime=wrtime%60;
							wrsec=wrtime;
								if(wrsec>30) wrmin++;
		wstime = stime - 1200;
			wshour = wstime/3600;
				wstime=wstime%3600;
					wsmin=wstime/60;
						wstime=wstime%60;
							wssec=wstime;
								if(wssec>30) wsmin++;
		//half hour longer
		vrtime = rtime - 1200;
			vrhour = vrtime/3600;
				vrtime=vrtime%3600;
					vrmin=vrtime/60;
						vrtime=vrtime%60;
							vrsec=vrtime;
								if(vrsec>30) vrmin++;
		vstime = stime + 1200;
			vshour = vstime/3600;
				vstime=vstime%3600;
					vsmin=vstime/60;
						vstime=vstime%60;
							vssec=vstime;
								if(vssec>30) vsmin++;


//time for each active led channel to pull for sunrise
return int Sunrise[2]={rhour,rmin};
return int Sunset[2]={shour,smin};
return int whSunrise[2]={wrhour,wrmin};
return int whSunset [2]={wshour,wsmin};
return int vSunrise[2]={vrhour,vrmin};
return int vSunset [2]={vshour,vsmin};
}

int calcSec(int hr, int minu)
{
    int hour = hr * 3600;
    int min = minu * 60;
    int totalseconds=hour+min;
    return totalseconds;
}

int calculateTime(int seconds1, int seconds2)
{
    int timediff=seconds1-seconds2;
    return timediff;
}
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

ok...I remembered you cant return arrays in c soo i finished the code however the sketch is 2000bytes to big...ugh which leaves no room for wifi, vortech, custom main ato ect ect...its all lights :(

Code: Select all

#include <ReefAngel_Colors.h>
#include <ReefAngel_CustomColors.h>
#include <ReefAngel_Features.h>
#include <ReefAngel_Globals.h>
#include <ReefAngel_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <ReefAngel_EEPROM.h>
#include <ReefAngel_NokiaLCD.h>
#include <ReefAngel_ATO.h>
#include <ReefAngel_Joystick.h>
#include <ReefAngel_LED.h>
#include <ReefAngel_TempSensor.h>
#include <ReefAngel_Relay.h>
#include <ReefAngel_PWM.h>
#include <ReefAngel_Timer.h>
#include <ReefAngel_Memory.h>
#include <ReefAngel.h>
//*********************************************************************************************************************************
//Start of PWM Expansion Code Header

// This is just how we are going to reference the PWM expansion ports within the code.
// You can change the labels if you would like, just as long as they are changed all throughout the code too.
#define LEDPWM0 0
#define LEDPWM1 1
#define LEDPWM2 2
#define LEDPWM3 3
#define LEDPWM4 4
#define LEDPWM5 5

// Initial values to all 6 channels at startup. They will always be 0.
byte PWMChannel[]={
  0,0,0,0,0,0};
byte cloudchance=0;
byte cloudduration=0;
int cloudstart=0;

//End of PWM Expansion Code Header
//*********************************************************************************************************************************

int calcSec(int,int);
int calcTime(int,int);

//Custom mainscreen copied from the custom main thread - constantly getting errors about LCD?
void setup()
{
    ReefAngel.Init();  //Initialize controller
    //WifiAuthentication("Brad:Blank");

    ReefAngel.FeedingModePorts = B10100000;
    ReefAngel.WaterChangePorts = B10101000;
    ReefAngel.OverheatShutoffPorts = B01000000;
    ReefAngel.LightsOnPorts = B00000010;

    // Ports that are always on
    ReefAngel.Relay.On(Port1);
    ReefAngel.Relay.On(Port2);
    ReefAngel.Relay.On(Port3);
    ReefAngel.Relay.On(Port4);
    ReefAngel.Relay.On(Port5);
    ReefAngel.Relay.On(Port6);
}

void loop()
{
	      
  	//Heater on&off
    	ReefAngel.StandardHeater(Port7,780,792);
   
		//Delay Skimmer
		ReefAngel.Relay.DelayedOn(Port8, 5);

		//call moonphase
		if ( hour() <= 6 || hour () >= 19 ) // Moonlights on from 7PM to 7AM
			{
				ReefAngel.PWM.SetActinic(MoonPhase());
				ReefAngel.PWM.SetDaylight(MoonPhase());
			}
		else
			{
				ReefAngel.PWM.SetActinic(0);
				ReefAngel.PWM.SetDaylight(0);
			}
                //Seasons
                Seasons();
		//Call Cloud Check
		CheckCloud();
		//Draw PWM value
		//ReefAngel.LCD.DrawText(0,255,5,120,PWMChannel[LEDPWM0]);
		//ReefAngel.LCD.DrawText(0,255,35,120,PWMChannel[LEDPWM1]);
		//ReefAngel.LCD.DrawText(0,255,65,120,PWMChannel[LEDPWM2]);
		//ReefAngel.LCD.DrawText(0,255,95,120,PWMChannel[LEDPWM3]);
			
	        ReefAngel.ShowInterface();
}

//*********************************************************************************************************************************
//Start of PWM slope function code designed for the PWM Expansion module
void PWMExpansion(byte cmd, byte data)
{ 
Wire.beginTransmission(8); // transmit to device #2
Wire.send('$'); // sends $ 
Wire.send('$'); // sends $ 
Wire.send('$'); // sends $ 
Wire.send(cmd); // sends a value 
Wire.send(data); // sends 255 
Wire.endTransmission(); // stop transmitting
}
//End of PWM slope function code designed for the PWM Expansion module
//*********************************************************************************************************************************


//*********************************************************************************************************************************
// 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 3

  // 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 30

  // 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 20

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

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

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

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

  // 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 65

  // Channels used by the actinic LEDs on the PWM Expansion module
  // These channels will not be dimmed when the cloud effect is triggered
  // Number is a binary form. B001100 means channel 2 and 3 are used for actinics
#define Actinic_Channels B001110

  // Channels used by the daylight LEDs on the PWM Expansion module
  // These channels will be used for the spike when lightning effect is triggered
  // Number is a binary form. B000011 means channel 0 and 1 are used for daylights
#define Daylight_Channels B000001

  // 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))
    {
      // let's go through all channels to pick which ones will be dimmed
      for (int a=0;a<6;a++)
      {
        if (bitRead(Actinic_Channels,a)==0)
        {
          // this will slope down the channel from the current PWM to 0 within 3minutes.
          // then it will stay at 0 for the duration of the cycle
          // and finally slope up from 0 to PWM value within 3 minutes
          // it is basically an inversed slope
          PWMChannel[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[a],0,180);
        }
      }
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        for (int b=0;b<6;b++)
        {
          if (bitRead(Daylight_Channels,b)==1)
          {
            if (random(100)<20) lightningstatus=1; 
            else lightningstatus=0;
            if (lightningstatus) PWMChannel[b]=100; 
            else PWMChannel[b]=0;
            //delay(10);
          }
          else
          {
            PWMChannel[b]=20;
          }
        }
      }
    }
    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;
}

void Seasons()
{
	#define forceseasoncalculation
	short ndays = 0;
	static byte ssn = 0, ssnp = 0, ssnpt = 0;
	int wrtime = 0;
	int wstime = 0;
	int rtime = 0;
	int stime = 0;
	int vrtime = 0;
	int vstime = 0;
	int wrhour = 0, wrmin = 0, wrsec = 0,wshour = 0,wsmin = 0, wssec = 0, rhour = 0, rmin = 0, rsec = 0, shour = 0, smin = 0, ssec = 0, vrhour = 0, vrmin = 0, vrsec = 0, vshour = 0, vsmin = 0, vssec = 0;
	static byte iDiffrise = 0;
	static byte iDiffset = 0;
	short risediffperday = 0;
	short setdiffperday = 0;
	int totalrise = 0;
	int totalset = 0;
	byte i = 0, tyd=0, s=0;
        int DaysPerMonth[12];
        byte DaysPerYear = 0;
        
	//rise and set times set by hour and minute. there are 4 seasons however there are 8 highs & lows in rise and set throughout the year first spot is second half of winter starting jan 1st 
	int risehour[8]= {07,07,07,06,06,05,06,06};
	int riseminute[8]={00,30,00,30,00,30,00,30};
	int sethour[8] = {17,18,18,19,19,19,19,18};
	int setminute[8] = {30,00,30,00,00,30,00,00};

	//
	if (hour()==0 && minute()==0 && second()==0) ssnp=0;
		#ifdef forceseasoncalculation
			if (ssnp==0)
	#else
		if (hour()==0 && minute()==0 && second()==1 && ssnp==0)
	#endif
	{
		//leapyear or not?
		if (year()%4 == 0 && !(year()%100 == 0 && year()%400 != 0)) int DaysPerMonth[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		//every other year
		else int DaysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		//adding up past months days
		for (i=0; i<month() - 1; i++) ndays += DaysPerMonth[i];
			//adding current months days, julian day number is output ex: nday = 192
			ndays += day(); 
		//output total days in year for final season day count later in code
		for(tyd=0;tyd<11;tyd++)DaysPerYear += DaysPerMonth[tyd];
		//define days between begin and middle season
		int seasons[9] ={0,45,96,135,187,238,283,328,DaysPerYear};
		//define season and array pulling variable
		for (s=0; seasons[s] < ndays; s++) ssn = s, ssnpt = s, ssnp = s-1;
		//set loop on array time pulling variable to go back to beginning instead of increasing array size
		if (ssn > 7) ssn = 0;
		
                //differece in seconds between season array times
                int rise1 = calcSec(risehour[ssnp],riseminute[ssnp]);
                int rise2 = calcSec(risehour[ssn],riseminute[ssn]);
                iDiffrise = calcTime(rise1, rise2);
                int set1 = calcSec(sethour[ssnp],setminute[ssnp]);
                int set2 = calcSec(sethour[ssn],setminute[ssn]);
                iDiffset = calcTime(set1,set2);
		
		//calculate new sunrise/set difference from array value 
		//here we take the difference in day and get a difference in seconds per day. So if the time difference is 30 minutes from the last equation we divide that by the start day of season subtracted by the end day of season to get the number of days in the season
		//example: 30 minutes/(day 45 – day 0) = 30/45 = 0.66666
		//0.66666 is the difference of minutes each day throughout the season for sunrise
		risediffperday = iDiffrise/(seasons[ssnpt]-seasons[ssnp]);
		totalrise = risediffperday*(ndays - seasons[ssnp]);
		setdiffperday = iDiffset/(seasons[ssnpt]-seasons[ssnp]);
		totalset = setdiffperday*(ndays - seasons[ssnp]);

		//creating time in seconds
		rtime=(risehour[ssnp]*3600)+(riseminute[ssnp]*60);
		if (ssnp == 0 || ssnp == 2 || ssnp == 4 || ssnp == 6) rtime =+ totalrise;
			else rtime =- totalrise;
		stime=(sethour[ssnp]*3600)+(setminute[ssnp]*60);
		if (ssnp == 1 || ssnp == 3 || ssnp == 5 || ssnp == 7) stime += totalset;
			else stime -= totalset;

		//turning seconds back to h m s
		//here are three different times offset by half hour to have different colors rise and set at different times
		//standard times
		rhour=rtime/3600; 
			rtime=rtime%3600;
				rmin=rtime/60; 
					rtime=rtime%60; 
						rsec=rtime;
							if(rsec > 30) rmin++; 
		shour=stime/3600; 
			stime=stime%3600;
				smin=stime/60; 
					stime=stime%60; 
						ssec=stime;
							if(ssec > 30) smin++;
		//to change the offset change the number 1200 in seconds added or subtracted to rtime
		//half hour shorter
		wrtime = rtime + 1200;
			wrhour = wrtime/3600;
				wrtime=wrtime%3600;
					wrmin=wrtime/60;
						wrtime=wrtime%60;
							wrsec=wrtime;
								if(wrsec>30) wrmin++;
		wstime = stime - 1200;
			wshour = wstime/3600;
				wstime=wstime%3600;
					wsmin=wstime/60;
						wstime=wstime%60;
							wssec=wstime;
								if(wssec>30) wsmin++;
		//half hour longer
		vrtime = rtime - 1200;
			vrhour = vrtime/3600;
				vrtime=vrtime%3600;
					vrmin=vrtime/60;
						vrtime=vrtime%60;
							vrsec=vrtime;
								if(vrsec>30) vrmin++;
		vstime = stime + 1200;
			vshour = vstime/3600;
				vstime=vstime%3600;
					vsmin=vstime/60;
						vstime=vstime%60;
							vssec=vstime;
								if(vssec>30) vsmin++;



//time for each active led channel to pull for sunrise
int Sunrise[2]={rhour,rmin};
int Sunset[2]={shour,smin};
int whSunrise[2]={wrhour,wrmin};
int whSunset [2]={wshour,wsmin};
int vSunrise[2]={vrhour,vrmin};
int vSunset [2]={vshour,vsmin};

PWMChannel[LEDPWM0]=PWMSlope(whSunrise[1],whSunrise[2],whSunset[1],whSunset[2],0,100,180,PWMChannel[LEDPWM0]);
PWMChannel[LEDPWM1]=PWMSlope(vSunrise[1],vSunrise[2],vSunset[1],vSunset[2],0,100,180,PWMChannel[LEDPWM1]);
PWMChannel[LEDPWM2]=PWMSlope(Sunrise[1],Sunrise[2],Sunset[1],Sunset[2],0,100,180,PWMChannel[LEDPWM2]);
PWMChannel[LEDPWM3]=PWMSlope(Sunrise[1],Sunrise[2],whSunset[1],whSunset[2],0,100,180,PWMChannel[LEDPWM3]);
//return Sunrise, Sunset, whSunrise,whSunset,vSunrise,vSunset;
}}

int calcSec(int hr, int minu)
{
    int hour = hr * 3600;
    int min = minu * 60;
    int totalseconds=hour+min;
    return totalseconds;
}

int calcTime(int seconds1, int seconds2)
{
    int timediff=seconds1-seconds2;
    return timediff;
}


rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

Custom main actually may even decrease the code size if you remove the graph.
Try using simple menu to decrease the size.
Using custom menu will reduce even more.
Roberto.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

You asked me to post what I had so far so here it is. Since we will be moving the lighting code to the pwm module I would like to be able to still access the following info - sunrise/set time for standard non offset time(there are 3 sets of times), cloud & lightning times for main screen, the ability to send lightning times to controller to change RF module to storm mode(where is rf documentation for programming?).

Code: Select all

#include <ReefAngel_Features.h>
#include <ReefAngel_Globals.h>
#include <ReefAngel_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <ReefAngel_EEPROM.h>
#include <ReefAngel_NokiaLCD.h>
#include <ReefAngel_ATO.h>
#include <ReefAngel_Joystick.h>
#include <ReefAngel_LED.h>
#include <ReefAngel_TempSensor.h>
#include <ReefAngel_Relay.h>
#include <ReefAngel_PWM.h>
#include <ReefAngel_Timer.h>
#include <ReefAngel_Memory.h>
#include <ReefAngel.h>
#include <avr/pgmspace.h>
#include <ReefAngel_Colors.h>
#include <ReefAngel_CustomColors.h>
#include <ReefAngel_Salinity.h>
#include <ReefAngel.h>
#include <ReefAngel_RF.h>
#include <ReefAngel.h>  

//*********************************************************************************************************************************
//Start of PWM Expansion Code Header

// This is just how we are going to reference the PWM expansion ports within the code.
// You can change the labels if you would like, just as long as they are changed all throughout the code too.
#define LEDPWM0 0
#define LEDPWM1 1
#define LEDPWM2 2
#define LEDPWM3 3
#define LEDPWM4 4
#define LEDPWM5 5

// Initial values to all 6 channels at startup. They will always be 0.
byte PWMChannel[]={
  0,0,0,0,0,0};
byte cloudchance=0;
byte cloudduration=0;
int cloudstart=0;

//End of PWM Expansion Code Header
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Define Relay Ports
#define PowerCenter         1
#define LEDPSU              2
#define Refugium            3
#define Reactors            4
#define Vortechs            5
#define Return              6
#define Heater              7
#define Skimmer             8
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Seasons Seconds Calculator integers
int calcSec(int,int);
int calcTime(int,int);
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Custom Main, Graph & Menu
void ConvertNumToString(char* string, int num, byte decimal)
{
  char temptxt[3];
  int Temp = num;
  if (Temp==0xFFFF) Temp=0;
  itoa(Temp/decimal,string,10);
  if (decimal>1)
  {
      itoa(Temp%decimal,temptxt,10);
      strcat(string, ".");
      if (Temp%decimal<10 && decimal==100) strcat(string, "0");
      strcat(string, temptxt);
  }
}
void DrawCustomMain()
{
  byte x = 6;
  byte y = 2;
  byte t;
  ReefAngel.LCD.DrawDate(6, 2);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, 11, 132, 11);
  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, 
Font8x16);
  pingSerial();
  
  ConvertNumToString(text, ReefAngel.Params.Temp1, 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,"Sump:");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp2, T2TempColor, 
24, y+35, 10);
  ReefAngel.LCD.DrawText(T3TempColor,DefaultBGColor,x+8,y+25,"Room:");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp3, T3TempColor, 
x+24, y+35, 10);
  ConvertNumToString(SALtxt, ReefAngel.Params.Salinity, 10);
ReefAngel.LCD.DrawHugeNumbers(COLOR_LIMEGREEN, DefaultBGColor, 5, 55, SALtxt);

  //y += 39*2;
// x = 13;
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 92, TempRelay);
   // #ifdef RelayExp
  // draw 1st expansion relay
// TempRelay = ReefAngel.Relay.RelayDataE[0];
// TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
//  TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
// ReefAngel.LCD.DrawOutletBox(12, 105, TempRelay);
//#endif   RelayExp

  
}
void DrawCustomGraph()
{
}

//End Custom
//*********************************************************************************************************************************
void setup()
{
    ReefAngel.Init();  //Initialize controller
    //WifiAuthentication("Brad:");

    ReefAngel.FeedingModePorts = B10100000;
    ReefAngel.WaterChangePorts = B10101000;
    ReefAngel.OverheatShutoffPorts = B01000000;
    ReefAngel.LightsOnPorts = B00000010;

    // Ports that are always on
    ReefAngel.Relay.On(PowerCenter);
    ReefAngel.Relay.On(Return);
    ReefAngel.Relay.On(Reactors);
    ReefAngel.Relay.On(Vortechs);
	ReefAngel.Relay.On(Refugium);
}

void loop()
{
	    //Heater on&off
    	ReefAngel.StandardHeater(Heater,780,792);
   
		//Delay Skimmer
		ReefAngel.Relay.DelayedOn(Skimmer, 5);

		//call moonphase
		if ( hour() <= 6 || hour () >= 19 ) // Moonlights on from 7PM to 7AM
			{
				ReefAngel.PWM.SetActinic(MoonPhase());
			}
		else
			{
				ReefAngel.PWM.SetActinic(0);
			}
        //Seasons
        Seasons();
		//Call Cloud Check
		CheckCloud();
		//Draw PWM value
		//ReefAngel.LCD.DrawText(0,255,5,120,PWMChannel[LEDPWM0]);
		//ReefAngel.LCD.DrawText(0,255,35,120,PWMChannel[LEDPWM1]);
		//ReefAngel.LCD.DrawText(0,255,65,120,PWMChannel[LEDPWM2]);
		//ReefAngel.LCD.DrawText(0,255,95,120,PWMChannel[LEDPWM3]);
			
	    ReefAngel.ShowInterface();
}

//*********************************************************************************************************************************
//Start of PWM slope function code designed for the PWM Expansion module
void PWMExpansion(byte cmd, byte data)
{ 
Wire.beginTransmission(8); // transmit to device #2
Wire.send('$'); // sends $ 
Wire.send('$'); // sends $ 
Wire.send('$'); // sends $ 
Wire.send(cmd); // sends a value 
Wire.send(data); // sends 255 
Wire.endTransmission(); // stop transmitting
}
//End of PWM slope function code designed for the PWM Expansion module
//*********************************************************************************************************************************


//*********************************************************************************************************************************
// 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 3

  // 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 30

  // 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 20

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

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

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

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

  // 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 65

  // Channels used by the actinic LEDs on the PWM Expansion module
  // These channels will not be dimmed when the cloud effect is triggered
  // Number is a binary form. B001100 means channel 2 and 3 are used for actinics
#define Actinic_Channels B001110

  // Channels used by the daylight LEDs on the PWM Expansion module
  // These channels will be used for the spike when lightning effect is triggered
  // Number is a binary form. B000011 means channel 0 and 1 are used for daylights
#define Daylight_Channels B000001

  // 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))
    {
      // let's go through all channels to pick which ones will be dimmed
      for (int a=0;a<6;a++)
      {
        if (bitRead(Actinic_Channels,a)==0)
        {
          // this will slope down the channel from the current PWM to 0 within 3minutes.
          // then it will stay at 0 for the duration of the cycle
          // and finally slope up from 0 to PWM value within 3 minutes
          // it is basically an inversed slope
          PWMChannel[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[a],0,180);
        }
      }
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        for (int b=0;b<6;b++)
        {
          if (bitRead(Daylight_Channels,b)==1)
          {
            if (random(100)<20) lightningstatus=1; 
            else lightningstatus=0;
            if (lightningstatus) PWMChannel[b]=100; 
            else PWMChannel[b]=0;
            //delay(10);
          }
          else
          {
            PWMChannel[b]=20;
          }
        }
      }
    }
    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));
    }
  }   
}
//End Cloud Function
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Reverse PWM slope from cloud function
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;
}
//End Reverse PWM function
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Calculate Sunrise/set by date & predefined season & rise/set times
void Seasons()
{
	#define forceseasoncalculation
	short ndays = 0;
	static byte ssn = 0, ssnp = 0, ssnpt = 0;
	int wrtime = 0;
	int wstime = 0;
	int rtime = 0;
	int stime = 0;
	int vrtime = 0;
	int vstime = 0;
	int wrhour = 0, wrmin = 0, wrsec = 0,wshour = 0,wsmin = 0, wssec = 0, rhour = 0, rmin = 0, rsec = 0, shour = 0, smin = 0, ssec = 0, vrhour = 0, vrmin = 0, vrsec = 0, vshour = 0, vsmin = 0, vssec = 0;
	static byte iDiffrise = 0;
	static byte iDiffset = 0;
	short risediffperday = 0;
	short setdiffperday = 0;
	int totalrise = 0;
	int totalset = 0;
	byte i = 0, tyd=0, s=0;
        int DaysPerMonth[12];
        byte DaysPerYear = 0;
        
	//rise and set times set by hour and minute. there are 4 seasons however there are 8 highs & lows in rise and set throughout the year first spot is second half of winter starting jan 1st 
	int risehour[8]= {07,07,07,06,06,05,06,06};
	int riseminute[8]={00,30,00,30,00,30,00,30};
	int sethour[8] = {17,18,18,19,19,19,19,18};
	int setminute[8] = {30,00,30,00,00,30,00,00};

	//
	if (hour()==0 && minute()==0 && second()==0) ssnp=0;
		#ifdef forceseasoncalculation
			if (ssnp==0)
	#else
		if (hour()==0 && minute()==0 && second()==1 && ssnp==0)
	#endif
	{
		//leapyear or not?
		if (year()%4 == 0 && !(year()%100 == 0 && year()%400 != 0)) int DaysPerMonth[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		//every other year
		else int DaysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		//adding up past months days
		for (i=0; i<month() - 1; i++) ndays += DaysPerMonth[i];
			//adding current months days, julian day number is output ex: nday = 192
			ndays += day(); 
		//output total days in year for final season day count later in code
		for(tyd=0;tyd<11;tyd++)DaysPerYear += DaysPerMonth[tyd];
		//define days between begin and middle season
		int seasons[9] ={0,45,96,135,187,238,283,328,DaysPerYear};
		//define season and array pulling variable
		for (s=0; seasons[s] < ndays; s++) ssn = s, ssnpt = s, ssnp = s-1;
		//set loop on array time pulling variable to go back to beginning instead of increasing array size
		if (ssn > 7) ssn = 0;
		
                //differece in seconds between season array times
                int rise1 = calcSec(risehour[ssnp],riseminute[ssnp]);
                int rise2 = calcSec(risehour[ssn],riseminute[ssn]);
                iDiffrise = calcTime(rise1, rise2);
                int set1 = calcSec(sethour[ssnp],setminute[ssnp]);
                int set2 = calcSec(sethour[ssn],setminute[ssn]);
                iDiffset = calcTime(set1,set2);
		
		//calculate new sunrise/set difference from array value 
		//here we take the difference in day and get a difference in seconds per day. So if the time difference is 30 minutes from the last equation we divide that by the start day of season subtracted by the end day of season to get the number of days in the season
		//example: 30 minutes/(day 45 – day 0) = 30/45 = 0.66666
		//0.66666 is the difference of minutes each day throughout the season for sunrise
		risediffperday = iDiffrise/(seasons[ssnpt]-seasons[ssnp]);
		totalrise = risediffperday*(ndays - seasons[ssnp]);
		setdiffperday = iDiffset/(seasons[ssnpt]-seasons[ssnp]);
		totalset = setdiffperday*(ndays - seasons[ssnp]);

		//creating time in seconds
		rtime=(risehour[ssnp]*3600)+(riseminute[ssnp]*60);
		if (ssnp == 0 || ssnp == 2 || ssnp == 4 || ssnp == 6) rtime =+ totalrise;
			else rtime =- totalrise;
		stime=(sethour[ssnp]*3600)+(setminute[ssnp]*60);
		if (ssnp == 1 || ssnp == 3 || ssnp == 5 || ssnp == 7) stime += totalset;
			else stime -= totalset;

		//turning seconds back to h m s
		//here are three different times offset by half hour to have different colors rise and set at different times
		//standard times
		rhour=rtime/3600; 
			rtime=rtime%3600;
				rmin=rtime/60; 
					rtime=rtime%60; 
						rsec=rtime;
							if(rsec > 30) rmin++; 
		shour=stime/3600; 
			stime=stime%3600;
				smin=stime/60; 
					stime=stime%60; 
						ssec=stime;
							if(ssec > 30) smin++;
		//to change the offset change the number 1200 in seconds added or subtracted to rtime
		//half hour shorter
		wrtime = rtime + 1200;
			wrhour = wrtime/3600;
				wrtime=wrtime%3600;
					wrmin=wrtime/60;
						wrtime=wrtime%60;
							wrsec=wrtime;
								if(wrsec>30) wrmin++;
		wstime = stime - 1200;
			wshour = wstime/3600;
				wstime=wstime%3600;
					wsmin=wstime/60;
						wstime=wstime%60;
							wssec=wstime;
								if(wssec>30) wsmin++;
		//half hour longer
		vrtime = rtime - 1200;
			vrhour = vrtime/3600;
				vrtime=vrtime%3600;
					vrmin=vrtime/60;
						vrtime=vrtime%60;
							vrsec=vrtime;
								if(vrsec>30) vrmin++;
		vstime = stime + 1200;
			vshour = vstime/3600;
				vstime=vstime%3600;
					vsmin=vstime/60;
						vstime=vstime%60;
							vssec=vstime;
								if(vssec>30) vsmin++;



//time for each active led channel to pull for sunrise
int Sunrise[2]={rhour,rmin};
int Sunset[2]={shour,smin};
int whSunrise[2]={wrhour,wrmin};
int whSunset [2]={wshour,wsmin};
int vSunrise[2]={vrhour,vrmin};
int vSunset [2]={vshour,vsmin};

PWMChannel[LEDPWM0]=PWMSlope(whSunrise[1],whSunrise[2],whSunset[1],whSunset[2],0,100,180,PWMChannel[LEDPWM0]);
PWMChannel[LEDPWM1]=PWMSlope(vSunrise[1],vSunrise[2],vSunset[1],vSunset[2],0,100,180,PWMChannel[LEDPWM1]);
PWMChannel[LEDPWM2]=PWMSlope(Sunrise[1],Sunrise[2],Sunset[1],Sunset[2],0,100,180,PWMChannel[LEDPWM2]);
PWMChannel[LEDPWM3]=PWMSlope(Sunrise[1],Sunrise[2],whSunset[1],whSunset[2],0,100,180,PWMChannel[LEDPWM3]);
//return Sunrise, Sunset, whSunrise,whSunset,vSunrise,vSunset;
}}
//End Seasons Calculation
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Seconds Calculator for Seasons function
int calcSec(int hr, int minu)
{
    int hour = hr * 3600;
    int min = minu * 60;
    int totalseconds=hour+min;
    return totalseconds;
}

int calcTime(int seconds1, int seconds2)
{
    int timediff=seconds1-seconds2;
    return timediff;
}
//End Seconds calculator
//*********************************************************************************************************************************

rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

Ok, after a quick glance of your code, the only time RA needs to pass any values to the PWM module is for forced clouds, right?
Also, here is what I beleive are the values RA needs to pull from the PWM module to be displayed in your Custom Main Screen:
* All 6 PWM channels values
* Sunrise
* Sunset
* whSunrise
* whSunset
* vSunrise
* vSunset
* cloudstart
* cloudduration
Am I in the right path?
Roberto.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

Yea, your on the right path. However we could narrow the values sent to few. All 6 channels run at 100%. So Id use one channel for pwm% on. Really just need the main values Sunrise & Sunset, the offset variations will clutter the screen. And cloudstart cloudduration. So 1 channel pwm percentage, sunrise time & sunset time using (Sunrise/Sunset) excluding wh/v variants, and cloud/lightning stuff. Don't wanna clutter the main screen to much.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

Here is what I come up so far.
For the sake of getting it started, we will start with just pulling data and not pushing.
This is the test RA code:

Code: Select all

#include <ReefAngel_Features.h>
#include <ReefAngel_Globals.h>
#include <ReefAngel_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <ReefAngel_EEPROM.h>
#include <ReefAngel_NokiaLCD.h>
#include <ReefAngel_ATO.h>
#include <ReefAngel_Joystick.h>
#include <ReefAngel_LED.h>
#include <ReefAngel_TempSensor.h>
#include <ReefAngel_Relay.h>
#include <ReefAngel_PWM.h>
#include <ReefAngel_Timer.h>
#include <ReefAngel_Memory.h>
#include <ReefAngel.h>

void setup()
{
  ReefAngel.Init();  
}

void loop()
{
  ReefAngel.ShowInterface();
  Wire.requestFrom(8,8);
  Serial.println("Start");
  for (int a=0;a<8;a++)
  {
    if (Wire.available()) Serial.println(Wire.receive(),DEC);
  }
}
It will read 8 bytes from the PWM expansion module and send to the serial port.
You can use the Serial Monitor on Arduino IDE to view the data being printed.

Here is the PWM Expansion Custom Seasons code:

Code: Select all

#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include "ReefAngel_Globals.h"
#include "ReefAngel_Features.h"

#include <Wire.h>
#include <avr/wdt.h>

#define LEDPWM0 0
#define LEDPWM1 1
#define LEDPWM2 2
#define LEDPWM3 3
#define LEDPWM4 4
#define LEDPWM5 5

byte cloudduration=0;
int cloudstart=0;
int rhour = 0, rmin = 0, shour = 0, smin = 0;

byte PWMports[] ={
  3,5,6,9,10,11};
byte ChannelValue[] = {
  0,0,0,0,0,0};

// PWM, sunrisehour, sunriseminute, sunsethour, sunsetminute, cloudstarthout, cloudstartminute, cloudduration
byte SeasonsVar[]={
  0,0,0,0,0,0,0,0};

byte cmdnum=255;
byte datanum=255;
void setup()
{
  Serial.begin(57600);
  Wire.begin(8);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
  randomSeed(analogRead(0));
  pinMode(3,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  //wdt_enable(WDTO_1S);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  setSyncInterval(SECS_PER_HOUR);  // Changed to sync every hour.
  now();
}

void loop()
{
  wdt_reset();
  //Serial.println(ChannelValue[0],DEC);
  if (cmdnum!=255)
  {
    ProcessCMD(cmdnum,datanum);    
    cmdnum=255;
    datanum=255;
  }
  Seasons();
  CheckCloud();
//  Serial.println("Start");
//  Serial.println(ChannelValue[0],DEC);
//  Serial.println(rhour,DEC);
//  Serial.println(rmin,DEC);
//  Serial.println(shour,DEC);
//  Serial.println(smin,DEC);
//  Serial.println(cloudstart/60,DEC);
//  Serial.println(cloudstart%60,DEC);
//  Serial.println(cloudduration,DEC);
  for (int a=0;a<6;a++)
  {
    analogWrite(PWMports[a],ChannelValue[a]);
    
  }
}

void receiveEvent(int howMany) {
  wdt_reset();
  if (howMany==5)
  {
    byte cmd1, cmd2, cmd3, cmd4, cmd5;
    cmd1=Wire.receive();
    cmd2=Wire.receive();
    cmd3=Wire.receive();
    cmd4=Wire.receive();
    cmd5=Wire.receive();
    if (cmd1=='$' && cmd2=='$' && cmd3=='$')
    {
      cmdnum=cmd4;
      datanum=cmd5;
      //Serial.println(cmd4,DEC);
      //Serial.println(cmd5,DEC);
    }
  }
  else
  {
    for (int a=0;a<howMany;a++)
    {
      Wire.receive();
    }
  }  
}

void ProcessCMD(byte cmd, byte data)
{
  wdt_reset();
  // Individual Channel
  if (cmd>=0 && cmd<=5)
  {
    ChannelValue[cmd]=data;
    analogWrite(PWMports[cmd],data);
  }
}

void requestEvent() {
  SeasonsVar[0]=ChannelValue[0];
  SeasonsVar[1]=rhour;
  SeasonsVar[2]=rmin;
  SeasonsVar[3]=shour;
  SeasonsVar[4]=smin;
  SeasonsVar[5]=cloudstart/60;
  SeasonsVar[6]=cloudstart%60;
  SeasonsVar[7]=cloudduration;
  Wire.send(SeasonsVar,8);
}


//*********************************************************************************************************************************
// 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 100

  // 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 20

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

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

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

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

  // 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

  // Channels used by the actinic LEDs on the PWM Expansion module
  // These channels will not be dimmed when the cloud effect is triggered
  // Number is a binary form. B001100 means channel 2 and 3 are used for actinics
#define Actinic_Channels B001110

  // Channels used by the daylight LEDs on the PWM Expansion module
  // These channels will be used for the spike when lightning effect is triggered
  // Number is a binary form. B000011 means channel 0 and 1 are used for daylights
#define Daylight_Channels B000001

  // 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 
  // results 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 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))
    {
      // let's go through all channels to pick which ones will be dimmed
      for (int a=0;a<6;a++)
      {
        if (bitRead(Actinic_Channels,a)==0)
        {
          // this will slope down the channel from the current PWM to 0 within 3minutes.
          // then it will stay at 0 for the duration of the cycle
          // and finally slope up from 0 to PWM value within 3 minutes
          // it is basically an inversed slope
          ChannelValue[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,ChannelValue[a],0,180);
        }
      }
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        for (int b=0;b<6;b++)
        {
          if (bitRead(Daylight_Channels,b)==1)
          {
            if (random(100)<20) lightningstatus=1; 
            else lightningstatus=0;
            if (lightningstatus) ChannelValue[b]=100; 
            else ChannelValue[b]=0;
            //delay(10);
          }
          else
          {
            ChannelValue[b]=20;
          }
        }
      }
    }
    
    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;
      }
    }
  }
}
//End Cloud Function
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Reverse PWM slope from cloud function
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;
}
//End Reverse PWM function
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Calculate Sunrise/set by date & predefined season & rise/set times
void Seasons()
{
#define forceseasoncalculation
  short ndays = 0;
  static byte ssn = 0, ssnp = 0, ssnpt = 0;
  int wrtime = 0;
  int wstime = 0;
  int rtime = 0;
  int stime = 0;
  int vrtime = 0;
  int vstime = 0;
  int wrhour = 0, wrmin = 0, wrsec = 0,wshour = 0,wsmin = 0, wssec = 0, rsec = 0, ssec = 0, vrhour = 0, vrmin = 0, vrsec = 0, vshour = 0, vsmin = 0, vssec = 0;
  static byte iDiffrise = 0;
  static byte iDiffset = 0;
  short risediffperday = 0;
  short setdiffperday = 0;
  int totalrise = 0;
  int totalset = 0;
  byte i = 0, tyd=0, s=0;
  int DaysPerMonth[12];
  byte DaysPerYear = 0;

  //rise and set times set by hour and minute. there are 4 seasons however there are 8 highs & lows in rise and set throughout the year
  //first spot is second half of winter starting jan 1st 
    int risehour[8]= {
    07,07,07,06,06,05,06,06    };
  int riseminute[8]={
    00,30,00,30,00,30,00,30    };
  int sethour[8] = {
    17,18,18,19,19,19,19,18    };
  int setminute[8] = {
    30,00,30,00,00,30,00,00    };

  //
  if (hour()==0 && minute()==0 && second()==0) ssnp=0;
#ifdef forceseasoncalculation
  if (ssnp==0)
#else
    if (hour()==0 && minute()==0 && second()==1 && ssnp==0)
#endif
    {
      //leapyear or not?
      if (year()%4 == 0 && !(year()%100 == 0 && year()%400 != 0)) int DaysPerMonth[] = {
        31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31            };
      //every other year
      else int DaysPerMonth[] = {
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31            };
      //adding up past months days
      for (i=0; i<month() - 1; i++) ndays += DaysPerMonth[i];
      //adding current months days, julian day number is output ex: nday = 192
      ndays += day(); 
      //output total days in year for final season day count later in code
      for(tyd=0;tyd<11;tyd++)DaysPerYear += DaysPerMonth[tyd];
      //define days between begin and middle season
      int seasons[9] ={
        0,45,96,135,187,238,283,328,DaysPerYear            };
      //define season and array pulling variable
      for (s=0; seasons[s] < ndays; s++) ssn = s, ssnpt = s, ssnp = s-1;
      //set loop on array time pulling variable to go back to beginning instead of increasing array size
      if (ssn > 7) ssn = 0;

      //differece in seconds between season array times
      int rise1 = calcSec(risehour[ssnp],riseminute[ssnp]);
      int rise2 = calcSec(risehour[ssn],riseminute[ssn]);
      iDiffrise = calcTime(rise1, rise2);
      int set1 = calcSec(sethour[ssnp],setminute[ssnp]);
      int set2 = calcSec(sethour[ssn],setminute[ssn]);
      iDiffset = calcTime(set1,set2);

      //calculate new sunrise/set difference from array value 
      //here we take the difference in day and get a difference in seconds per day. So if the time difference is 30 minutes from the last e
      //uation we divide that by the start day of season subtracted by the end day of season to get the number of days in the season
        //example: 30 minutes/(day 45 – day 0) = 30/45 = 0.66666
      //0.66666 is the difference of minutes each day throughout the season for sunrise
      risediffperday = iDiffrise/(seasons[ssnpt]-seasons[ssnp]);
      totalrise = risediffperday*(ndays - seasons[ssnp]);
      setdiffperday = iDiffset/(seasons[ssnpt]-seasons[ssnp]);
      totalset = setdiffperday*(ndays - seasons[ssnp]);

      //creating time in seconds
      rtime=(risehour[ssnp]*3600)+(riseminute[ssnp]*60);
      if (ssnp == 0 || ssnp == 2 || ssnp == 4 || ssnp == 6) rtime =+ totalrise;
      else rtime =- totalrise;
      stime=(sethour[ssnp]*3600)+(setminute[ssnp]*60);
      if (ssnp == 1 || ssnp == 3 || ssnp == 5 || ssnp == 7) stime += totalset;
      else stime -= totalset;

      //turning seconds back to h m s
      //here are three different times offset by half hour to have different colors rise and set at different times
      //standard times
      rhour=rtime/3600; 
      rtime=rtime%3600;
      rmin=rtime/60; 
      rtime=rtime%60; 
      rsec=rtime;
      if(rsec > 30) rmin++; 
      shour=stime/3600; 
      stime=stime%3600;
      smin=stime/60; 
      stime=stime%60; 
      ssec=stime;
      if(ssec > 30) smin++;
      //to change the offset change the number 1200 in seconds added or subtracted to rtime
      //half hour shorter
      wrtime = rtime + 1200;
      wrhour = wrtime/3600;
      wrtime=wrtime%3600;
      wrmin=wrtime/60;
      wrtime=wrtime%60;
      wrsec=wrtime;
      if(wrsec>30) wrmin++;
      wstime = stime - 1200;
      wshour = wstime/3600;
      wstime=wstime%3600;
      wsmin=wstime/60;
      wstime=wstime%60;
      wssec=wstime;
      if(wssec>30) wsmin++;
      //half hour longer
      vrtime = rtime - 1200;
      vrhour = vrtime/3600;
      vrtime=vrtime%3600;
      vrmin=vrtime/60;
      vrtime=vrtime%60;
      vrsec=vrtime;
      if(vrsec>30) vrmin++;
      vstime = stime + 1200;
      vshour = vstime/3600;
      vstime=vstime%3600;
      vsmin=vstime/60;
      vstime=vstime%60;
      vssec=vstime;
      if(vssec>30) vsmin++;



      //time for each active led channel to pull for sunrise
      int Sunrise[2]={
        rhour,rmin            };
      int Sunset[2]={
        shour,smin            };
      int whSunrise[2]={
        wrhour,wrmin            };
      int whSunset [2]={
        wshour,wsmin            };
      int vSunrise[2]={
        vrhour,vrmin            };
      int vSunset [2]={
        vshour,vsmin            };

      ChannelValue[LEDPWM0]=PWMSlope(whSunrise[1],whSunrise[2],whSunset[1],whSunset[2],0,100,180,ChannelValue[LEDPWM0]);
      ChannelValue[LEDPWM1]=PWMSlope(vSunrise[1],vSunrise[2],vSunset[1],vSunset[2],0,100,180,ChannelValue[LEDPWM1]);
      ChannelValue[LEDPWM2]=PWMSlope(Sunrise[1],Sunrise[2],Sunset[1],Sunset[2],0,100,180,ChannelValue[LEDPWM2]);
      ChannelValue[LEDPWM3]=PWMSlope(Sunrise[1],Sunrise[2],whSunset[1],whSunset[2],0,100,180,ChannelValue[LEDPWM3]);
      //return Sunrise, Sunset, whSunrise,whSunset,vSunrise,vSunset;
    }
}
//End Seasons Calculation
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Seconds Calculator for Seasons function
int calcSec(int hr, int minu)
{
  int hour = hr * 3600;
  int min = minu * 60;
  int totalseconds=hour+min;
  return totalseconds;
}

int calcTime(int seconds1, int seconds2)
{
  int timediff=seconds1-seconds2;
  return timediff;
}
//End Seconds calculator
//*********************************************************************************************************************************
Let me know if you have problems getting it together.
Roberto.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

If im not mistaken by your code this is the output im getting

Start
0 -channel0 PWM%
1 -Rise hour
27 - rise minute
0 - set hour
244 - set minute
11 -cloud start hour
34 - cloud start minute
17 - cloud duration

Hmm I wonder whats wrong, the Rise and set times dont make sense... hmm leme look at what i coulda done wrong in seasons()

Rewriting some things because some values arent coming out properly...
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

Yes, that is the order and I noticed the wrong numbers too, but those were coming from the Seasons() function. We may need to revisit the function.
Roberto.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

ok I've been playing with this the better part of the morning. Rewrote some things after going value by value and changing the months on the RA to make sure it was pulling stuff correctly for each month.

All values are referenced and pulled properly now. I have rtime outputting the proper time. but I cannot figure out why I get a negative value on stime or any of the offset values(wrtime, vrtime ect) I always get 0 for hour and a negative for minutes ugh

All previouse values are pulled correctly, and the code is exactly the same as rtime except for using sethour & minute but both the first line stime = comes out negative and way off (like -3495) and the if statement comes out negative also(duh haha) hmmmm my eyeballs hurt

Code: Select all

stime=(sethour[ssnp]*3600)+(setminute[ssnp]*60);
 		if (ssnp == 1 || ssnp == 3 || ssnp == 5 || ssnp == 7) stime += totalset;
			else stime -= totalset;
Here is the updated code of where I am at now

Code: Select all

//*********************************************************************************************************************************
//Global integers
int calcSec(int,int);
int calcTime(int,int);
short Ndays;   //Returns the number of day in the year
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Calculate Sunrise/set by date & predefined season & rise/set times
void Seasons()
{
	#define forceseasoncalculation
	static byte ssn , ssnp , ssnpt ;
	int wrtime = 0;
	int wstime = 0;
	int rtime = 0;
	int stime = 0;
	int vrtime = 0;
	int vstime = 0;
	int wrhour = 0, wrmin = 0, wrsec = 0,wshour = 0,wsmin = 0, wssec = 0, rhour = 0, rmin = 0, rsec = 0, shour = 0, smin = 0, ssec = 0, vrhour = 0, vrmin = 0, vrsec = 0, vshour = 0, vsmin = 0, vssec = 0;
	int iDiffrise = 0;
	int iDiffset = 0;
	int risediffperday = 0;
	int setdiffperday = 0;
	int totalrise = 0;
	int totalset = 0;
	byte s=0;
        int DaysPerYear;        
        
	//rise and set times set by hour and minute. there are 4 seasons however there are 8 highs & lows in rise and set throughout the year first spot is second half of winter starting jan 1st 
	int risehour[8]= {7,7,7,6,6,5,6,6};
	int riseminute[8]={00,30,00,30,00,30,00,30};
	int sethour[8] = {17,18,18,19,19,19,19,18};
	int setminute[8] = {30,00,30,00,00,30,00,00};

	//
	if (hour()==0 && minute()==0 && second()==0) ssnp=0;
		#ifdef forceseasoncalculation
			if (ssnp==0)
	#else
		if (hour()==0 && minute()==0 && second()==1 && ssnp==0)
	#endif
	{
		//leapyear or not - Define days per year
		if (year()%4 == 0 && !(year()%100 == 0 && year()%400 != 0)) {DaysPerYear=366;}
		//every other year
		else {DaysPerYear = 365;}
		//Call Day Number Calc
                DayNumber(year(),month(),day());
                //ReefAngel.LCD.DrawText(0,255,5,100,Ndays);
                //ReefAngel.LCD.DrawText(0,255,5,110,DaysPerYear);
                //define days between begin and middle season
		int seasons[9] ={0,45,96,135,187,238,283,328,DaysPerYear};
		//define season and array pulling variable
		for (s=0; seasons[s] < Ndays; s++) ssn = s+1, ssnpt = s+1, ssnp = s;
		//set loop on array time pulling variable to go back to beginning instead of increasing array size
		if (ssn >= 7) ssn = 0;
               
                              
                //differece in seconds between season array times
                int rise1 = calcSec(risehour[ssn],riseminute[ssn]);
                int rise2 = calcSec(risehour[ssnp],riseminute[ssnp]);
                iDiffrise = calcTime(rise1, rise2);
                int set1 = calcSec(sethour[ssn],setminute[ssn]);
                int set2 = calcSec(sethour[ssnp],setminute[ssnp]);
                iDiffset = calcTime(set1,set2);
                
                
		
                


		//calculate new sunrise/set difference from array value 
		//here we take the difference in day and get a difference in seconds per day. So if the time difference is 30 minutes from the last equation we divide that by the start day of season subtracted by the end day of season to get the number of days in the season
		//example: 30 minutes/(day 45 – day 0) = 30/45 = 0.66666
		//0.66666 is the difference of minutes each day throughout the season for sunrise
		risediffperday = iDiffrise/(seasons[ssnpt]-seasons[ssnp]);
		totalrise = risediffperday*(Ndays - seasons[ssnp]);
		setdiffperday = iDiffset/(seasons[ssnpt]-seasons[ssnp]);
		totalset = setdiffperday*(Ndays - seasons[ssnp]);
     

     
		//creating time in seconds
		rtime=(risehour[ssnp]*3600)+(riseminute[ssnp]*60);
		if (ssnp == 0 || ssnp == 2 || ssnp == 4 || ssnp == 6) rtime -= totalrise;
			else rtime += totalrise;
		stime=(sethour[ssnp]*3600)+(setminute[ssnp]*60);
 		if (ssnp == 1 || ssnp == 3 || ssnp == 5 || ssnp == 7) stime += totalset;
			else stime -= totalset;


		//turning seconds back to h m s
		//here are three different times offset by half hour to have different colors rise and set at different times
		//standard times
		rhour=rtime/3600; 
			rtime=rtime%3600;
				rmin=rtime/60; 
					rtime=rtime%60; 
						rsec=rtime;
							if(rsec > 30) rmin++; 
		shour=stime/3600; 
			stime=stime%3600;
				smin=stime/60; 
					stime=stime%60; 
						ssec=stime;
							if(ssec > 30) smin++;
		//to change the offset change the number 1200 in seconds added or subtracted to rtime
		//half hour shorter
		wrtime = rtime + 1200;
			wrhour = wrtime/3600;
				wrtime=wrtime%3600;
					wrmin=wrtime/60;
						wrtime=wrtime%60;
							wrsec=wrtime;
								if(wrsec>30) wrmin++;
		wstime = stime - 1200;
			wshour = wstime/3600;
				wstime=wstime%3600;
					wsmin=wstime/60;
						wstime=wstime%60;
							wssec=wstime;
								if(wssec>30) wsmin++;
		//half hour longer
		vrtime = rtime - 1200;
			vrhour = vrtime/3600;
				vrtime=vrtime%3600;
					vrmin=vrtime/60;
						vrtime=vrtime%60;
							vrsec=vrtime;
								if(vrsec>30) vrmin++;
		vstime = stime + 1200;
			vshour = vstime/3600;
				vstime=vstime%3600;
					vsmin=vstime/60;
						vstime=vstime%60;
							vssec=vstime;
								if(vssec>30) vsmin++;



//time for each active led channel to pull for sunrise
int Sunrise[2]={rhour,rmin};
int Sunset[2]={shour,smin};
int whSunrise[2]={wrhour,wrmin};
int whSunset [2]={wshour,wsmin};
int vSunrise[2]={vrhour,vrmin};
int vSunset [2]={vshour,vsmin};

PWMChannel[LEDPWM0]=PWMSlope(whSunrise[1],whSunrise[2],whSunset[1],whSunset[2],0,100,180,PWMChannel[LEDPWM0]);
PWMChannel[LEDPWM1]=PWMSlope(vSunrise[1],vSunrise[2],vSunset[1],vSunset[2],0,100,180,PWMChannel[LEDPWM1]);
PWMChannel[LEDPWM2]=PWMSlope(Sunrise[1],Sunrise[2],Sunset[1],Sunset[2],0,100,180,PWMChannel[LEDPWM2]);
PWMChannel[LEDPWM3]=PWMSlope(Sunrise[1],Sunrise[2],whSunset[1],whSunset[2],0,100,180,PWMChannel[LEDPWM3]);
ReefAngel.LCD.DrawText(0,255,5,120,rhour);
ReefAngel.LCD.DrawText(0,255,35,120,rmin);
ReefAngel.LCD.DrawText(0,255,65,120,shour);
ReefAngel.LCD.DrawText(0,255,95,120,smin);
}}
//End Seasons Calculation
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Calculators for Seasons function
int calcSec(int hr, int minu)
{
    int hour = hr * 3600;
    int min = minu * 60;
    int totalseconds=hour+min;
    return totalseconds;
}

int calcTime(int seconds1, int seconds2)
{
    int timediff=abs(seconds1-seconds2);
    abs(timediff);
    return timediff;
}

void DayNumber(unsigned int y, unsigned int m, unsigned int d)
{
  int days[]={0,31,59,90,120,151,181,212,243,273,304,334};    // Number of days at the beginning of the month in a not leap year.
//Start to calculate the number of day
  if (m==1 || m==2){
    Ndays = days[(m-1)]+d;			   //for any type of year, it calculate the number of days for January or february
  }				// Now, try to calculate for the other months
  else if ((y % 4 == 0 && y % 100 != 0) ||  y % 400 == 0){  //those are the conditions to have a leap year
    Ndays = days[(m-1)]+d+1;     // if leap year, calculate in the same way but increasing one day
  }
  else {					  //if not a leap year, calculate in the normal way, such as January or February
    Ndays = days[(m-1)]+d;
  }
} 

//End calculators
//*********************************************************************************************************************************

Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

omg this is driving me insane that Im getting negative numbers and that theyre way off

Code: Select all

stime=calcSec(sethour[ssnp],setminute[ssnp]);
This line for today is pulling the value 18 for set hour and 00 for set minute and for some ungodly reason im getting the value -736 from this equation. When I should be getting 64800 seconds from it. it references this sub function

Code: Select all

int calcSec(int hr, int minu)
{
    int hour = hr * 3600;
    int minut = minu * 60;
    int totalseconds=hour+minut;
    return totalseconds;
}


so rtime,rhour,rmin are the only ints giving theyre proper values throughout the whole year. and all of the offsets such as wrhour, vrhour ect ect dont work....its as if after that first one it just takes a crap, even though all the values its pulling are correct..and they all use the same code ugh
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

int numbers are 16bit resolution (15 bit number with a 1 bit for signal), so it ranges from -32768 to +32768.
http://arduino.cc/en/Reference/Int
You are overflowing the variable if hr is anything over 9.
You must use long variables.
Try this:

Code: Select all

long calcSec(int hr, int minu)
{
    long totalseconds;
    totalseconds=(hr*3600)+(minu*60);
    return totalseconds;
}
I'm not sure if this will work, but give it a shot.
Roberto.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

yea i figured that out in the past while...it doesnt work. i changed all of the variables that held anything over 32768...still getting -789 output ugh

Uh I need to take a break I've been wasting my day away tinkering and reloading coded a million times lol
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

For anyone that wants it here is the finalized pde...all offsets are working


all thanks goto roberto for the wire transfer protocol. otherwise it wouldt of been possible

to change the hours find this code- change each to match, ie if you change the first one to be a half hour later change them all to be half hour later ect

Code: Select all

 //rise and set times set by hour and minute. there are 4 seasons however there are 8 highs & lows in rise and set throughout the year
  //first spot is second half of winter starting jan 1st 
    int risehour[8]= {
    7,7,7,6,6,5,6,6      };
  int riseminute[8]={
    00,30,00,30,00,30,00,30      };
  int sethour[8] = {
    17,18,18,19,19,19,19,18      };
  int setminute[8] = {
    30,00,30,00,00,30,00,00      };
if you change the up/down comepletely you will need to rewrite these if statements to match the new up/down variation you create

Code: Select all

//creating time in seconds
      rtime=calcSec(risehour[ssnp],riseminute[ssnp]);
      if (ssnp == 0 || ssnp == 2 || ssnp == 4 || ssnp == 6){ 
        rtime -= totalrise;
      }
      else {
        rtime += totalrise;
      }
      stime=calcSec(sethour[ssnp],setminute[ssnp]);
      if (ssnp == 1 || ssnp == 3 || ssnp == 5 || ssnp == 7){ 
        stime -= totalset;
      }
      else {
        stime += totalset;
      }
if you want to change the ammount of time offset for different colors change 1200 to whatever you want in seconds

Code: Select all

wrtime = rtime + 1200;
      wstime = stime - 1200;
      vrtime = rtime - 1200;
      vstime = stime + 1200;
RA - add to loop this to your loop

Code: Select all

 Wire.requestFrom(8,8);
  Serial.println("Start");
  for (int a=0;a<8;a++)
  {
    if (Wire.available()) Serial.println(Wire.receive(),DEC);
  }
PWM MODULE PDE:

Code: Select all

#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include "ReefAngel_Globals.h"
#include "ReefAngel_Features.h"

#include <Wire.h>
#include <avr/wdt.h>

#define LEDPWM0 0
#define LEDPWM1 1
#define LEDPWM2 2
#define LEDPWM3 3
#define LEDPWM4 4
#define LEDPWM5 5


//*********************************************************************************************************************************
//Globals integers
long calcSec(long,long);
long calcTime(long,long);
short Ndays;   //Returns the number of day in the year
//*********************************************************************************************************************************

byte cloudduration=0;
int cloudstart=0;
int rhour = 0, rmin = 0, shour = 0, smin = 0;

byte PWMports[] ={
  3,5,6,9,10,11};
byte ChannelValue[] = {
  0,0,0,0,0,0};

// PWM, sunrisehour, sunriseminute, sunsethour, sunsetminute, cloudstarthout, cloudstartminute, cloudduration
byte SeasonsVar[]={
  0,0,0,0,0,0,0,0};

byte cmdnum=255;
byte datanum=255;
void setup()
{
  Serial.begin(57600);
  Wire.begin(8);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
  randomSeed(analogRead(0));
  pinMode(3,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT);
  //wdt_enable(WDTO_1S);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  setSyncInterval(SECS_PER_HOUR);  // Changed to sync every hour.
  now();
}

void loop()
{
  wdt_reset();
  //Serial.println(ChannelValue[0],DEC);
  if (cmdnum!=255)
  {
    ProcessCMD(cmdnum,datanum);    
    cmdnum=255;
    datanum=255;
  }
  Seasons();
  CheckCloud();
//  Serial.println("Start");
//  Serial.println(ChannelValue[0],DEC);
//  Serial.println(rhour,DEC);
//  Serial.println(rmin,DEC);
//  Serial.println(shour,DEC);
//  Serial.println(smin,DEC);
//  Serial.println(cloudstart/60,DEC);
//  Serial.println(cloudstart%60,DEC);
//  Serial.println(cloudduration,DEC);
  for (int a=0;a<6;a++)
  {
    analogWrite(PWMports[a],ChannelValue[a]);
    
  }
}

void receiveEvent(int howMany) {
  wdt_reset();
  if (howMany==5)
  {
    byte cmd1, cmd2, cmd3, cmd4, cmd5;
    cmd1=Wire.receive();
    cmd2=Wire.receive();
    cmd3=Wire.receive();
    cmd4=Wire.receive();
    cmd5=Wire.receive();
    if (cmd1=='$' && cmd2=='$' && cmd3=='$')
    {
      cmdnum=cmd4;
      datanum=cmd5;
      //Serial.println(cmd4,DEC);
      //Serial.println(cmd5,DEC);
    }
  }
  else
  {
    for (int a=0;a<howMany;a++)
    {
      Wire.receive();
    }
  }  
}

void ProcessCMD(byte cmd, byte data)
{
  wdt_reset();
  // Individual Channel
  if (cmd>=0 && cmd<=5)
  {
    ChannelValue[cmd]=data;
    analogWrite(PWMports[cmd],data);
  }
}

void requestEvent() {
  SeasonsVar[0]=ChannelValue[0];
  SeasonsVar[1]=rhour;
  SeasonsVar[2]=rmin;
  SeasonsVar[3]=shour;
  SeasonsVar[4]=smin;
  SeasonsVar[5]=cloudstart/60;
  SeasonsVar[6]=cloudstart%60;
  SeasonsVar[7]=cloudduration;
  Wire.send(SeasonsVar,8);
}


//*********************************************************************************************************************************
// 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 100

  // 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 20

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

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

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

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

  // 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

  // Channels used by the actinic LEDs on the PWM Expansion module
  // These channels will not be dimmed when the cloud effect is triggered
  // Number is a binary form. B001100 means channel 2 and 3 are used for actinics
#define Actinic_Channels B001110

  // Channels used by the daylight LEDs on the PWM Expansion module
  // These channels will be used for the spike when lightning effect is triggered
  // Number is a binary form. B000011 means channel 0 and 1 are used for daylights
#define Daylight_Channels B000001

  // 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 
  // results 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 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))
    {
      // let's go through all channels to pick which ones will be dimmed
      for (int a=0;a<6;a++)
      {
        if (bitRead(Actinic_Channels,a)==0)
        {
          // this will slope down the channel from the current PWM to 0 within 3minutes.
          // then it will stay at 0 for the duration of the cycle
          // and finally slope up from 0 to PWM value within 3 minutes
          // it is basically an inversed slope
          ChannelValue[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,ChannelValue[a],0,180);
        }
      }
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        for (int b=0;b<6;b++)
        {
          if (bitRead(Daylight_Channels,b)==1)
          {
            if (random(100)<20) lightningstatus=1; 
            else lightningstatus=0;
            if (lightningstatus) ChannelValue[b]=100; 
            else ChannelValue[b]=0;
            //delay(10);
          }
          else
          {
            ChannelValue[b]=20;
          }
        }
      }
    }
    
    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;
      }
    }
  }
}
//End Cloud Function
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Reverse PWM slope from cloud function
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;
}
//End Reverse PWM function
//*********************************************************************************************************************************
//*********************************************************************************************************************************
//Calculate Sunrise/set by date & predefined season & rise/set times
void Seasons()
{
#define forceseasoncalculation
  static byte ssn , ssnp , ssnpt ;
  long stime, wstime, vstime, wrtime, rtime, vrtime;
  long wrhour,wrmin,wrsec,wshour,wsmin,wssec,rhour,rmin,rsec,shour,smin,ssec,vrhour,vrmin,vrsec,vshour,vsmin,vssec;
  int iDiffrise = 0;
  int iDiffset = 0;
  int risediffperday = 0;
  int setdiffperday = 0;
  int totalrise = 0;
  int totalset = 0;
  byte s=0;
  int DaysPerYear;        

  //rise and set times set by hour and minute. there are 4 seasons however there are 8 highs & lows in rise and set throughout the year
  //first spot is second half of winter starting jan 1st 
    int risehour[8]= {
    7,7,7,6,6,5,6,6      };
  int riseminute[8]={
    00,30,00,30,00,30,00,30      };
  int sethour[8] = {
    17,18,18,19,19,19,19,18      };
  int setminute[8] = {
    30,00,30,00,00,30,00,00      };

  //
  if (hour()==0 && minute()==0 && second()==0) ssnp=0;
#ifdef forceseasoncalculation
  if (ssnp==0)
#else
    if (hour()==0 && minute()==0 && second()==1 && ssnp==0)
#endif
    {
      //leapyear or not - Define days per year
      if (year()%4 == 0 && !(year()%100 == 0 && year()%400 != 0)) {
        DaysPerYear=366;
      }
      //every other year
      else {
        DaysPerYear = 365;
      }
      //Call Day Number Calc
      DayNumber(year(),month(),day());
      //define days between begin and middle season
      int seasons[9] ={
        0,45,96,135,187,238,283,328,DaysPerYear                  };
      //define season and array pulling variable
      for (s=0; seasons[s] < Ndays; s++) ssn = s+1, ssnpt = s+1, ssnp = s;
      //set loop on array time pulling variable to go back to beginning instead of increasing array size
      if (ssn >= 7) ssn = 0;

      //differece in seconds between season array times
      long rise1 = calcSec(risehour[ssn],riseminute[ssn]);
      long rise2 = calcSec(risehour[ssnp],riseminute[ssnp]);
      iDiffrise = calcTime(rise1, rise2);
      long set1 = calcSec(sethour[ssn],setminute[ssn]);
      long set2 = calcSec(sethour[ssnp],setminute[ssnp]);
      iDiffset = calcTime(set1,set2);             

      //calculate new sunrise/set difference from array value 
      //here we take the difference in day and get a difference in seconds per day. So if the time difference is 30 minutes from the last e
      //uation we divide that by the start day of season subtracted by the end day of season to get the number of days in the season
        //example: 30 minutes/(day 45 – day 0) = 30/45 = 0.66666
      //0.66666 is the difference of minutes each day throughout the season for sunrise
      risediffperday = iDiffrise/(seasons[ssnpt]-seasons[ssnp]);
      totalrise = risediffperday*(Ndays - seasons[ssnp]);
      setdiffperday = iDiffset/(seasons[ssnpt]-seasons[ssnp]);
      totalset = setdiffperday*(Ndays - seasons[ssnp]);

      //creating time in seconds
      rtime=calcSec(risehour[ssnp],riseminute[ssnp]);
      if (ssnp == 0 || ssnp == 2 || ssnp == 4 || ssnp == 6){ 
        rtime -= totalrise;
      }
      else {
        rtime += totalrise;
      }
      stime=calcSec(sethour[ssnp],setminute[ssnp]);
      if (ssnp == 1 || ssnp == 3 || ssnp == 5 || ssnp == 7){ 
        stime -= totalset;
      }
      else {
        stime += totalset;
      }
           wrtime = rtime + 1200;
      wstime = stime - 1200;
      vrtime = rtime - 1200;
      vstime = stime + 1200;
      //turning seconds back to h m s
      //here are three different times offset by half hour to have different colors rise and set at different times
      //standard times
      rhour=rtime/3600; 
      rtime=rtime%3600;
      rmin=rtime/60; 
      rtime=rtime%60; 
      rsec=rtime;
      if(rsec > 30) rmin++; 
      shour=stime/3600; 
      stime=stime%3600;
      smin=stime/60; 
      stime=stime%60; 
      ssec=stime;
      if(ssec > 30) smin++;
      //to change the offset change the number 1200 in seconds added or subtracted to rtime
      //half hour shorter
      wrhour = wrtime/3600;
      wrtime=wrtime%3600;
      wrmin=wrtime/60;
      wrtime=wrtime%60;
      wrsec=wrtime;
      if(wrsec>30) wrmin++;
      wshour = wstime/3600;
      wstime=wstime%3600;
      wsmin=wstime/60;
      wstime=wstime%60;
      wssec=wstime;
      if(wssec>30) wsmin++;
      //half hour longer
      vrhour = vrtime/3600;
      vrtime=vrtime%3600;
      vrmin=vrtime/60;
      vrtime=vrtime%60;
      vrsec=vrtime;
      if(vrsec>30) vrmin++;
      vshour = vstime/3600;
      vstime=vstime%3600;
      vsmin=vstime/60;
      vstime=vstime%60;
      vssec=vstime;
      if(vssec>30) vsmin++;



      //time for each active led channel to pull for sunrise
      int Sunrise[2]={
        rhour,rmin                  };
      int Sunset[2]={
        shour,smin                  };
      int whSunrise[2]={
        wrhour,wrmin                  };
      int whSunset [2]={
        wshour,wsmin                  };
      int vSunrise[2]={
        vrhour,vrmin                  };
      int vSunset [2]={
        vshour,vsmin                  };

      ChannelValue[LEDPWM0]=PWMSlope(whSunrise[1],whSunrise[2],whSunset[1],whSunset[2],0,100,180,ChannelValue[LEDPWM0]);
      ChannelValue[LEDPWM1]=PWMSlope(vSunrise[1],vSunrise[2],vSunset[1],vSunset[2],0,100,180,ChannelValue[LEDPWM1]);
      ChannelValue[LEDPWM2]=PWMSlope(Sunrise[1],Sunrise[2],Sunset[1],Sunset[2],0,100,180,ChannelValue[LEDPWM2]);
      ChannelValue[LEDPWM3]=PWMSlope(Sunrise[1],Sunrise[2],whSunset[1],whSunset[2],0,100,180,ChannelValue[LEDPWM3]);
      //return Sunrise, Sunset, whSunrise,whSunset,vSunrise,vSunset;
    }
}
//End Seasons Calculation
//*********************************************************************************************************************************

//*********************************************************************************************************************************
//Calculators for Seasons function
long calcSec(long hr, long minu)
{
    long totalseconds;
    totalseconds=(hr*3600)+(minu*60);
    return totalseconds;
}

long calcTime(long seconds1, long seconds2)
{
  long timediff=abs(seconds1-seconds2);
  return timediff;
}

void DayNumber(unsigned int y, unsigned int m, unsigned int d)
{
  int days[]={
    0,31,59,90,120,151,181,212,243,273,304,334      };    // Number of days at the beginning of the month in a not leap year.
  //Start to calculate the number of day
  if (m==1 || m==2){
    Ndays = days[(m-1)]+d;			   //for any type of year, it calculate the number of days for January or february
  }				// Now, try to calculate for the other months
  else if ((y % 4 == 0 && y % 100 != 0) ||  y % 400 == 0){  //those are the conditions to have a leap year
    Ndays = days[(m-1)]+d+1;     // if leap year, calculate in the same way but increasing one day
  }
  else {					  //if not a leap year, calculate in the normal way, such as January or February
    Ndays = days[(m-1)]+d;
  }
} 

//End calculators
//*********************************************************************************************************************************

      
    
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

Roberto, im trying to call the values to print them on main screen trying to deciefer your code...lol guess im not doing so hot haha

if (Wire.available()) ReefAngel.LCD.DrawText(0,255,5,120,(Wire.receive()); shows a value of 10 and I cant call them by SeasonsVar or a number..hmmuhh
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

Ok, so for your RA PDE, you need to declare an array above setup()

Code: Select all

byte SeasonsVar[]={
  0,0,0,0,0,0,0,0};
Then, on your loop(), add this instead of what you posted above:

Code: Select all

  Wire.requestFrom(8,8);
  for (int a=0;a<8;a++)
  {
    if (Wire.available()) SeasonsVar[a]=Wire.receive();
  }
  ReefAngel.LCD.DrawText(0,255,5,120,SeasonsVar[0]); 
This way, you can use the SeasonsVar anywhere within your PDE.
Roberto.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

nice, thank you roberto!
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

Hmm finally getting around to using the cloud function roberto, The time and length of the cloud changes every 2 seconds and I cant seem to figure out why. Also how would I send data to the pwm to say force a thunderstorm?
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

How does it change?
Does it change to always to the future?
Or it always stays within a certain time window?
Roberto.
Deckoz2302
Posts: 149
Joined: Tue Nov 01, 2011 11:05 am

Re: Progressive sunphase

Post by Deckoz2302 »

ok for example when i posted that, the hour was always 15 and the minutes changed every 2 seconds from 0-59, the duration changed every second or so within the predefined parameters i have which are 6min 30max

so hour stayed the same but minute would change every two seconds, until it rolls into the next hour then it says the current hour and minutes constantly change

it does the same thing over serial.println if turn off autoscroll and look at each set of seasonvars the cloudtime and duration is different each time
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Progressive sunphase

Post by rimai »

Can you post your latest PWM pde?
Roberto.
Post Reply