Cloud and Lightning Code for Dimming Expansion

Do you have a question on how to do something.
Ask in here.
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

Post all of your code.

--Colin
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

Sorry i thought i had it all posted but i guess not

Code: Select all

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

////// Place global variable code below here
    int DaylightPWMValue=0;        // For cloud code


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


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


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

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

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

void loop()
{
    ReefAngel.StandardHeater( Port2 );
if ( ReefAngel.Params.Temp[T1_PROBE] < (InternalMemory.HeaterTempOn_read() - 10)) { ReefAngel.Relay.On(Port3); };
if ( ReefAngel.Params.Temp[T1_PROBE] > (InternalMemory.HeaterTempOff_read() - 5)) { ReefAngel.Relay.Off(Port3); };
    ReefAngel.SingleATOLow( Port5 );
        DaylightPWMValue=PWMSlopeHighRes(10,0,20,0,0,30,60,0);
     CheckCloud();
     ReefAngel.PWM.SetChannelRaw(0,DaylightPWMValue);
    ReefAngel.PWM.SetChannel(1,PWMSlopeHighRes(9,30,20,30,5,30,30,0));  // Blues from 0930 to 2230 on a slope
    ReefAngel.StandardLights(Port7,18,0,10,0);  // Fuge light from 1800 to 1000
    
    ////// Place your custom code below here
    

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

    // This should always be the last line
    ReefAngel.Portal( "MDB1029" );
    ReefAngel.DDNS( "Reef" ); // Your DDNS is MDB1029-Reef.myreefangel.com
    ReefAngel.ShowInterface();
}

      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 7

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

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

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

      // Only start the cloud effect after this setting
      // In this example, start cloud after noon
    #define Start_Cloud_After NumMins(12,00)

      // Always end the cloud effect before this setting
      // In this example, end cloud before 9:00pm
    #define End_Cloud_Before NumMins(21,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

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

      // Add Random Lightning modes
    #define Calm 0    // No lightning
    #define Slow 1    // 5 seconds of slow lightning in the middle of a cloud for ELN style (slow response) drivers
    #define Fast 2    // 5 seconds of fast lightning in the middle of a cloud for LDD style (fast response) drivers
    #define Mega 3    // Lightning throughout the cloud, higher chance as it gets darker
    #define Mega2 4   // Like Mega, but with more lightning
      // Set which modes you want to use
      // Example:  { Calm, Fast, Mega, Mega2 } to randomize all four modes. 
      // { Mega2 } for just Mega2.  { Mega, Mega, Fast} for Mega and Fast, with twice the chance of Mega.
      byte LightningModes[] = {Mega2,Mega,Mega};

      // 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;
      static byte lightningMode=0;
      static boolean chooseLightning=true;

      static time_t DelayCounter=millis();    // Variable for lightning timing. 
      static int DelayTime=random(1000);      // Variable for lightning timimg.

      // 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
        {
          randomSeed(millis());    // Seed the random number generator
          //Pick a random number between 0 and 99
          cloudchance=random(100);
          // if picked number is greater than Cloud_Chance_per_Day, we will not have clouds today
          if (cloudchance>Cloud_Chance_per_Day) cloudchance=0;
          // Check if today is day for clouds.
          if ((day()%Clouds_Every_X_Days)!=0) cloudchance=0;
          // If we have cloud today
          if (cloudchance)
          {
            // pick a random number for number of clouds between Min_Clouds_per_Day and Max_Clouds_per_Day
            numclouds=random(Min_Clouds_per_Day,Max_Clouds_per_Day);
            // pick the time that the first cloud will start
            // the range is calculated between Start_Cloud_After and the even distribuition of clouds on this day.
            cloudstart=random(Start_Cloud_After,Start_Cloud_After+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
            // pick a random number for the cloud duration of first cloud.
            cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
            //Pick a random number between 0 and 99
            lightningchance=random(100);
            // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
            if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
          }
        }
      // Now that we have all the parameters for the cloud, let's create the effect


      if (cloudchance)
      {
        //is it time for cloud yet?
        if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
        {
          DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,DaylightPWMValue/40.95,0,180)*40.95;
          if (chooseLightning)
          {
            lightningMode=LightningModes[random(100)%sizeof(LightningModes)];
            chooseLightning=false;
          }
          switch (lightningMode)
          {
          case Calm:
            break;
          case Mega:
            // Lightning chance from beginning of cloud through the end.  Chance increases with darkness of cloud.
            if (lightningchance && random(ReversePWMSlope(cloudstart,cloudstart+cloudduration,100,0,180))<1 && (millis()-DelayCounter)>DelayTime)
            {
              // Send the trigger
              Strike();
              DelayCounter=millis();    // If we just had a round of flashes, then lets put in a longer delay
              DelayTime=random(1000);   // of up to a second for dramatic effect before we do another round.
            }
            break;
          case Mega2:
            // Higher lightning chance from beginning of cloud through the end.  Chance increases with darkness of cloud.
            if (lightningchance && random(ReversePWMSlope(cloudstart,cloudstart+cloudduration,100,0,180))<2)
            {
              Strike();
            }
            break;
          case Fast:
            // 5 seconds of lightning in the middle of the cloud
            if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5 && (millis()-DelayCounter)>DelayTime)
            {
              Strike();

              DelayCounter=millis();    // If we just had a round of flashes, then lets put in a longer delay
              DelayTime=random(1000);   // of up to a second for dramatic effect before we do another round.
            }
            break;
          case Slow:
            // Slow lightning for 5 seconds in the middle of the cloud.  Suitable for slower ELN style drivers
            if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5)
            {
              if (random(100)<20) lightningstatus=1;
              else lightningstatus=0;
              if (lightningstatus)
              {
                DaylightPWMValue=4095;
              }
              else
              {
                DaylightPWMValue=0;
              }
              delay(1);
            }
            break;
          default:
            break;
          }
        }
        else
        {
          chooseLightning=true; // Reset the flag to choose a new lightning type
        }

        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;
          }
        }
      }

      // Write the times of the next cloud, next lightning, and cloud duration to the screen and into some customvars for the Portal.
      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));
          ReefAngel.CustomVar[3]=cloudstart/60; // Write the hour of the next cloud to custom variable for Portal reporting
          if ((cloudstart%60)>=10) x=29;
          else x=35;
          //ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart%60));
          ReefAngel.CustomVar[4]=cloudstart%60; // Write the minute of the next cloud to custom variable for Portal reporting

        }
        //ReefAngel.LCD.DrawText(0,255,90,120,cloudduration);
        ReefAngel.CustomVar[7]=(cloudduration);    // Put the duration of the next cloud in a custom var for the portal
        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));
          ReefAngel.CustomVar[5]=(cloudstart+(cloudduration/2))/60;    // Write the hour of the next lightning to a custom variable for the Portal
          if (((cloudstart+(cloudduration/2))%60)>=10) x=69;
          else x=75;
          //ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))%60)); // Write the minute of the next lightning to a custom variable for the Portal
            ReefAngel.CustomVar[6]=(cloudstart+(cloudduration/2))%60;
        }
      }   
    }

    void Strike()
    {
      int a=random(1,5);    // Pick a number of consecutive flashes from 1 to 4. 
      for (int i=0; i<a; i++)
      {
        // Flash on
        int newdata=4095;
        Wire.beginTransmission(0x40);      // Address of the dimming expansion module
        Wire.write(0x8+(4*1));             // 0x8 is channel 0, 0x12 is channel 1, etc.  I'm using channel 1.
        Wire.write(newdata&0xff);          // Send the data 8 bits at a time.  This sends the LSB
        Wire.write(newdata>>8);            // This sends the MSB
        Wire.endTransmission();
       
        int randy=random(20,80);    // Random number for a delay
        if (randy>71) randy=((randy-70)/2)*100;    // Small chance of a longer delay
        delay(randy);                // Wait from 20 to 69 ms, or 100-400 ms
       
        // Flash off.  Return to baseline.
        newdata=ReefAngel.PWM.GetChannelValueRaw(1);   // Use the channel number you're flashing here
        Wire.beginTransmission(0x40);    // Same as above
        Wire.write(0x8+(4*1));
        Wire.write(newdata&0xff);
        Wire.write(newdata>>8);
        Wire.endTransmission();
       
        delay(random(30,50));                // Wait from 30 to 49 ms
        wdt_reset();    // Reset watchdog timer to avoid re-boots
      }
    }

    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 (int) PWMStart;
    }

Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

Ah. Change this:

Code: Select all

    ReefAngel.PWM.SetChannel(1,PWMSlopeHighRes(9,30,20,30,5,30,30,0));  // Blues from 0930 to 2230 on a slope
To this:

Code: Select all

    ReefAngel.PWM.SetChannelRaw(1,PWMSlopeHighRes(9,30,20,30,5,30,30,0));  // Blues from 0930 to 2230 on a slope
Check custom variables 3 and 4 for the time of the next cloud (either using the app or the portal). 3 is the hour, and 4 is the minute of the next cloud. You can either wait for that time, or change the current time on the controller to the cloud time to make it happen now. Just make sure to change it back. Helps to do a reset afterwards, too.

--Colin
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

Thank you. Will make the changes now.
Image
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

The dimming is working perfectly now. I am sure I will mess somthing up forcing a cloud event. I saw it yesterday for a moment and it looked like the Blue on channel 1 was flashing. The only part i changed was what is in the code 2 posts up.
Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

Only channel 0 should flash. Are you sure the blues are flashing?
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

cosmith71 wrote:Only channel 0 should flash. Are you sure the blues are flashing?
Between the flashes it is blue but only looks like the blue is flashing and the white is not present.
Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

Can you do a video?
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

I can try if i am home during the next cloud. I may also disconnect the blue channel dimming wire and see what the result is.
Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

The blue should stay the same. The white should slowly dim with flashes of varying length and intensity, like the videos above.

--Colin
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

cosmith71 wrote:The blue should stay the same. The white should slowly dim with flashes of varying length and intensity, like the videos above.

--Colin
Got it on video if you want to see it but confirmed the white dim out on channel 0 and the blue are the ones flashing on channel 1. Is there something in the bottom part of the code which still has it flash on channel 1?

Code: Select all

    DaylightPWMValue=PWMSlopeHighRes(10,0,20,0,0,30,60,0);
     CheckCloud();
     ReefAngel.PWM.SetChannelRaw(0,DaylightPWMValue);
Only part i changed was this^

Also i just have a general question about this code (10,0,20,0,0,30,60,0) it is (Hour on, minute on,hour off, minute off,starting percentage,max percentage, minutes of ramp up, ?) not sure what this last one is?
Image
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

Should i just change the whites to channel 1 and the blues to channel 0 and switch them in the void loop?
Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

Doh!

Replace the void Strike() section with this.

Code: Select all

void Strike()
    {
      int a=random(1,5);    // Pick a number of consecutive flashes from 1 to 4. 
      for (int i=0; i<a; i++)
      {
        // Flash on
        int newdata=4095;
        Wire.beginTransmission(0x40);      // Address of the dimming expansion module
        Wire.write(0x8+(4*0));             // 0x8 is channel 0, 0x12 is channel 1, etc.  I'm using channel 0.
        Wire.write(newdata&0xff);          // Send the data 8 bits at a time.  This sends the LSB
        Wire.write(newdata>>8);            // This sends the MSB
        Wire.endTransmission();
       
        int randy=random(20,80);    // Random number for a delay
        if (randy>71) randy=((randy-70)/2)*100;    // Small chance of a longer delay
        delay(randy);                // Wait from 20 to 69 ms, or 100-400 ms
       
        // Flash off.  Return to baseline.
        newdata=ReefAngel.PWM.GetChannelValueRaw(0);   // Use the channel number you're flashing here
        Wire.beginTransmission(0x40);    // Same as above
        Wire.write(0x8+(4*0));
        Wire.write(newdata&0xff);
        Wire.write(newdata>>8);
        Wire.endTransmission();
       
        delay(random(30,50));                // Wait from 30 to 49 ms
        wdt_reset();    // Reset watchdog timer to avoid re-boots
      }
    }
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

So I had an issue when i tried this yesterday. At first it had dimmed out the blue instead of the white and was flashing in white, so white channel on and flashing white. Then it switched to having the blues on and still flashing white. Instead of tinkering with the code and trying to make sure all the channels are aligned, I am going to switch the channels and reenter code from the first post and see if this fixes the problem.
Image
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

Just a question about the code.

I don't understand what this does, can you break it down to me like i am 5 years old

Code: Select all

     //#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.
Thanks for you in advance
Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

Well, #define's main use is to substitute one thing for another. Take this line for example:

Code: Select all

#define ReturnPump        Port1
When you go to compile and upload your code, the compiler goes through and replaces all the instances of ReturnPump with Port1. So this line:

Code: Select all

ReefAngel.Relay.On(ReturnPump);
is seen as this by the compiler:

Code: Select all

ReefAngel.Relay.On(Port1);
This is a common way to give your ports easy to remember names. You don't have to remember what port your return pump is plugged in to, you just tell it ReturnPump and it knows what you're talking about.

THIS IS NOT HOW THIS IS USED HERE!

A second use, which is really just a clever programming trick, is to #define something just so it shows as #defined. They are used as a type of switch That's what these two lines do.

Code: Select all

     //#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.
So notice that the second part of the #define is missing. We aren't doing a search and replace like in the first usage so we don't need that second part.

Down in the code is this:

Code: Select all

#ifdef forcecloudcalculation
  if (cloudchance==255)
#else
    if (hour()==0 && minute()==0 && second()==1 && cloudchance==255) 
#endif
This says "if forecloudcalculation has been defined, then insert 'if(cloudchange==255)' when you compile the code, if it hasn't been defined (else) then insert ' if (hour()==0 && minute()==0 && second()==1 && cloudchance==255) '".

These things exist outside of the compiled code. The compiler goes through and makes these substitutions and insertions before it compiles the code. It's a sneaky way to have the code write itself on the fly depending on what we want.

If we want the #else to be used instead we would just comment out the line like this so that forcedcloudcalculation isn't #defined. Remember that '//' causes everything after it (on the same line) to be ignored.

Code: Select all

    //#define forcecloudcalculation // Uncomment this to force the cloud calculation to happen in the boot process.
Hope this makes sense. It's been a long day. :mrgreen:

--Colin
jjdezek
Posts: 329
Joined: Fri May 17, 2013 1:35 pm

Re: Cloud and Lightning Code for Dimming Expansion

Post by jjdezek »

Well that's a lot of info. I see some have two channels for there lights. I have lights I built with 3 different heat sinks and have each one on its own channel, as in my left heat sink whites and other colors on say channel 1 with the blues on channel 2. Middle heat sink whites and other colors on channel 3 blues channel 4. 3rd heat sink whites and other colors on channel5 blues on channel 6. Not sure if that's the exact set up but that's the general idea how there set up, so I can ramp up each set individually. I'm using analog dimming expansion with DDR drivers. Any special coding I need for clouds and lightning? I know the old dimmer could have a cloud come across the tank from left to right, is this possible with these codes or does it just dim all at the same time?
Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

With this code, they all dim at the same time with clouds. As for the lightning, it's just a matter of adding code for the additional channels. I run left and right white channels on mine and they can flash individually or together.

I'm not familiar with DDR drivers. Do you have a link?

--Colin
jjdezek
Posts: 329
Joined: Fri May 17, 2013 1:35 pm

Re: Cloud and Lightning Code for Dimming Expansion

Post by jjdezek »

http://www.rapidled.com/mean-well-eln-6 ... le-driver/

Have you looked at the coding that went directly into the old dimmer?
Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

I don't think I've seen it. Do you have a link to it?

I'm familiar with those drivers (ELN). They don't have a fast enough response time for the best lightning effects, but they still work.
jjdezek
Posts: 329
Joined: Fri May 17, 2013 1:35 pm

Re: Cloud and Lightning Code for Dimming Expansion

Post by jjdezek »

This is the code I was running in my old dimmer expansion. it worked as its own system, independent from the main controller. the only way I could adjust anything was to hook up to the inside of the expansion and rewrite the code. the controller wouldn't display what the actual lights were running at. for example if my lights with this code were running at 70% there was no display or signal to the main controller to show that. this would do random clouds coming across the tank at random times and also had lighting at random. you could also set your light schedule for anywhere on earth that you wanted such as Hawaii, Australia, etc. it was pretty awesome to have. don't know that it can be used for the new dimmer expansion at all.

Code: Select all

[quote]
[color=#7E7E7E]//By Matthew Hockin 2012.  [/color]
[color=#7E7E7E]//SWFLTEK library functions, #includes, and #define were copied directly from the Epherma library[/color]
[color=#7E7E7E]//Epherma (SWFLTEK.com) was written by Michael Rice- thanks Michael it works great. [/color]
[color=#7E7E7E]//If you copy from this (its all open source) please [/color]
[color=#7E7E7E]//acknowledge Michael for SWFLTEK library code (obviously labeled) or Matthew Hockin (for the rest).[/color]

#include <Time.h>
#include <[color=#CC6600]Wire[/color].h>
#include <[color=#CC6600]OneWire[/color].h>
#include <Time.h>
#include <DS1307RTC.h>
#include <avr/wdt.h>
[color=#7E7E7E]//includes for SWFLTEK functions[/color]
#include <stdlib.h>
#include <math.h>


[color=#7E7E7E]//***********************************ARRAYS YOU MUST MODIFY TO MAKE YOUR TANK SET UP WORK*****************************[/color]
[color=#7E7E7E]//YOU MUST READ EVERY WORD IN THIS SECTION IN ORDER TO APPROPRIATELY CONFIGURE THIS PROGERAM- READ EVERY LINE BELOW///[/color]
[color=#CC6600]byte[/color] ChMax[]={255,220,255,220,255,220,0,0};[color=#7E7E7E]//Incremental value (Max-flicker) above flicker you want as max intensity (!!!!!!! Light Set Point is ChMax PLUS Flicker !!!!!!) [/color]
[color=#CC6600]byte[/color] flicker[]={29,29,29,29,29,29,0,0};[color=#7E7E7E]//need to input actual values here for flicker point on all channels in PWM expansion box[/color]
[color=#CC6600]boolean[/color] Wchannel[]={0,1,0,1,0,1,0,0}; [color=#7E7E7E]//use 1 to designate white channel (i.e. off during storm and used for lightning).  Array corresponds to PWM channel 0-5 in order[/color]
[color=#7E7E7E]//Array to give direction to dimming.  e.g. DimOrder[]={0,0,1,1,0,0} (cloud chase effects, just group channels you want to dim together during a cloud or storm [/color]
[color=#7E7E7E]//as either a 0 or a 1, i.e. all left side channels are 0 all right are 1 or all front are 0 all back are 1 or whatever[/color]
[color=#7E7E7E]//(which is zero or 1 will change who dims first).  set them all to 0 if your tank has no left/right or front/back lights.[/color]
[color=#CC6600]byte[/color] DimOrder[]={0,0,0,1,1,1,0,0};
[color=#7E7E7E]//set all channel positions that you would like to use for the lightning strike effect to 1 (0-5 are PWM channels 6,7 are Main PWM outs)- and channels with a 0 are not used in strike[/color]
[color=#CC6600]byte[/color] StrikeChannel[]={0,1,0,1,0,1,0,0};
[color=#CC6600]byte[/color] MoonCh[]={0,0,0,0,0,0,0,0};[color=#7E7E7E]//place a 1 in the array position of all lighting channels you would like to use a moon lighting (this does not preclude their use in other phases (day, storm etc)[/color]
[color=#7E7E7E]//**********************************DONE CHANGING THINGS HERE BUT YOU MUST CHANGE ChOffset array IN CalcSUN function******[/color]


[color=#7E7E7E]//defines for SWFLTEK functions[/color]
[color=#7E7E7E]// arc-seconds per radian[/color]
#define _sec_rad 206264.806247096370813

[color=#7E7E7E]// axial tilt of earth at epoch, in radians[/color]
#define _tilt 0.409092804222329

[color=#7E7E7E]// tropical year in seconds... rounding error accumulates to 26 seconds by the year 2136[/color]
#define _tropical_year 31556925

[color=#7E7E7E]// 'zenith' of rising (setting) sun in radians (360 - 2 * 90.833 degrees)[/color]
#define _zenith 3.11250383272322

[color=#7E7E7E]//*******************GLOBAL VARIABLE DECLERATIONS FOR MHOCKIN Weather package*************************************[/color]
[color=#7E7E7E]//Unless your planning on editing the program DO NOT CHANGE ANYTHING HERE[/color]
[color=#CC6600]long[/color] latitude, longitude;
[color=#CC6600]byte[/color] TrueIntensity[8];[color=#7E7E7E]//array used to place hold final write values for PWM intensity setting[/color]
[color=#CC6600]long[/color] elapsedTime;[color=#7E7E7E]//used multiple places as elapsed since midnight[/color]
[color=#CC6600]long[/color] newDay;
[color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] rise;[color=#7E7E7E]//time in seconds from the year 2000 (GMT) for sunrise[/color]
[color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] set;[color=#7E7E7E]//time in seconds from the year 2000 (GMT) for sunrise[/color]
[color=#CC6600]long[/color] ChRiseSet[16];[color=#7E7E7E]//times of rise and set for all 8 channels based upon offsets from calc rise and set values[/color]
[color=#CC6600]float[/color] ChSlope[16];[color=#7E7E7E]//slopes for 1/2 day calculations based upon time from offset to midday for channel 1-8[/color]
[color=#CC6600]long[/color] CloudMaster[20];[color=#7E7E7E]// Set up array to hold start and end times for clouds for the day-[/color]
[color=#CC6600]long[/color] midDay;[color=#7E7E7E]// exactly 1/2 way between rise and set, i.e. solar noon for latitudes <60 close enough for us... [/color]
[color=#CC6600]byte[/color] PWMports[] ={
    3,5,6,9,10,11};
[color=#CC6600]byte[/color] ChannelValue[8];[color=#7E7E7E]// Array to store output of insolaiton which may be modified and stored in TrueIntensity which is used to write to the PWM channels[/color]
[color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] StrikeStart;[color=#7E7E7E]//timer to keep track of strike sequence[/color]
[color=#CC6600]int[/color] StrikeMaster[20];[color=#7E7E7E]//Array to hold random strike pattern generated by weather array is sized to MAX needed given strike patter generator (8 strikes=16 positions)[/color]
[color=#CC6600]byte[/color] StrikeNumber;[color=#7E7E7E]//place to hold total number of strikes this sequence[/color]
[color=#CC6600]boolean[/color] StrikeNow;[color=#7E7E7E]//starts lightning strike sequence in loop state change made in weather/storm loop[/color]
[color=#CC6600]byte[/color] StrikeCount;[color=#7E7E7E]//Used to properly sequence strike sequence for delay between strikes[/color]
[color=#CC6600]byte[/color] cmdnum=255;
[color=#CC6600]byte[/color] datanum=255;
[color=#CC6600]byte[/color] dow=0;[color=#7E7E7E]//day of week[/color]
[color=#CC6600]byte[/color] strikePattern, strikeTime;[color=#7E7E7E]//used in Lightning() for timing of particular instance of strike [/color]
[color=#CC6600]boolean[/color] Cloud;[color=#7E7E7E]// are we in a cloud interval on days that have clouds[/color]
[color=#CC6600]boolean[/color] CloudToday;[color=#7E7E7E]//set in CalcSun if randomization yields a day with clouds.[/color]
[color=#CC6600]boolean[/color] IsStorm;[color=#7E7E7E]// are we in a storm[/color]
[color=#CC6600]byte[/color] CloudsTotal;[color=#7E7E7E]// how many clouds today[/color]
[color=#CC6600]long[/color] lastmillis;[color=#7E7E7E]// variable to track millis to enable cloud and insolation loop restriction by time[/color]
[color=#CC6600]boolean[/color] StormAdvance;[color=#7E7E7E]//storm timer for light effect advance[/color]
[color=#CC6600]boolean[/color] InsolationAdvance;[color=#7E7E7E]//when true we recalculate light intensity during clear sky (every 3 seconds seems more than often enough)[/color]
[color=#CC6600]byte[/color] counter;[color=#7E7E7E]//used to track millis advance for insolation,cloud trigger[/color]
[color=#7E7E7E]//****************************************[/color]
[color=#7E7E7E]//END HEADER/Global Variable declaration//[/color]
[color=#7E7E7E]//****************************************[/color]

[color=#7E7E7E]//Setup[/color]
[color=#CC6600]void[/color] [color=#CC6600][b]setup[/b][/color](){
    [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]begin[/color](57600);
    [color=#CC6600]Wire[/color].[color=#CC6600]begin[/color](8);
    [color=#7E7E7E]//Wire.onReceive(receiveEvent);[/color]
    [color=#7E7E7E]//Wire.onRequest(requestEvent);[/color]

    [color=#CC6600]pinMode[/color](3,[color=#006699]OUTPUT[/color]);
    [color=#CC6600]pinMode[/color](5,[color=#006699]OUTPUT[/color]);
    [color=#CC6600]pinMode[/color](6,[color=#006699]OUTPUT[/color]);
    [color=#CC6600]pinMode[/color](9,[color=#006699]OUTPUT[/color]);
    [color=#CC6600]pinMode[/color](10,[color=#006699]OUTPUT[/color]);
    [color=#CC6600]pinMode[/color](11,[color=#006699]OUTPUT[/color]);
    wdt_enable(WDTO_1S);
    [color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] seed=0, count=32;
    [color=#CC6600]while[/color] (--count){
      seed = (seed<<1) | ([color=#CC6600]analogRead[/color](5)&1);
    }
      [color=#CC6600]randomSeed[/color](seed);[color=#7E7E7E]//start random generator at a different point each time (not perfect but whatever its gonna be pretty damn random)[/color]
    [color=#CC6600]setSyncProvider[/color](RTC.[color=#CC6600]get[/color]);   [color=#7E7E7E]// the function to get the time from the RTC[/color]
    [color=#CC6600]setSyncInterval[/color](SECS_PER_HOUR);  [color=#7E7E7E]// Changed to sync every hour.[/color]
    
    dow=0;[color=#7E7E7E]//set Day Of Week (dow) to a 0 value which is impossible (day()=1-7)... so we trigger calcSun on restart [/color]
    StrikeNow=[color=#CC6600]false[/color];[color=#7E7E7E]//no lightning strike yet[/color]
    CloudToday=[color=#CC6600]false[/color];[color=#7E7E7E]//set to no clouds so CalcSun can set correctly if should be true[/color]
    Cloud=[color=#CC6600]false[/color];[color=#7E7E7E]//set cloud to false[/color]
    IsStorm=[color=#CC6600]false[/color];[color=#7E7E7E]//set storm to false[/color]
    lastmillis=[color=#CC6600]millis[/color]();[color=#7E7E7E]//start our millis timer now[/color]
    counter=0;[color=#7E7E7E]//used in weather for triggering a storm, triggering lightning in a storm.[/color]
    StrikeCount=0;[color=#7E7E7E]//Number of lightning strikes in the sequence.. set to zero until initialized in sequence[/color]
}
[color=#7E7E7E]//End Setup[/color]
[color=#7E7E7E]//*********************************************************************************************************************************[/color]

[color=#7E7E7E]//*********************************************************************************************************************************[/color]
[color=#7E7E7E]//Loop[/color]
[color=#CC6600]void[/color] [color=#CC6600][b]loop[/b][/color](){ 
    elapsedTime=([color=#CC6600]now[/color]()-newDay);[color=#7E7E7E]//Elapsed time is seconds from midnight of today- local processor time.[/color]
    wdt_reset();
    [color=#CC6600]if[/color] (cmdnum!=255){
        ProcessCMD(cmdnum,datanum);    
        cmdnum=255;
        datanum=255;
    }
    
    [color=#CC6600]if[/color] (dow!=[color=#CC6600]day[/color]()){ [color=#7E7E7E]//used to see that were in a new day and need to recalculate sunrise and sunset[/color]
      CalSun();
      dow=[color=#CC6600]day[/color]();
    }
  
    [color=#7E7E7E]//Use millis to enable tracking of time interval[/color]
    [color=#CC6600]if[/color] (([color=#CC6600]millis[/color]()-lastmillis)>=100){
        lastmillis=[color=#CC6600]millis[/color]();
        counter+=1;
        StormAdvance=[color=#CC6600]true[/color];
        [color=#7E7E7E]//now a bunch of stuff that may or may not be true at the same time but that all needs to happen when its true[/color]
        [color=#CC6600]if[/color] (counter==0){
          InsolationAdvance=[color=#CC6600]true[/color];[color=#7E7E7E]//so that it runs on start up to provide light immediately [/color]
        }  
        [color=#CC6600]if[/color] (counter%30==0){
          InsolationAdvance=[color=#CC6600]true[/color];
        }
        [color=#CC6600]if[/color] (counter==210) counter=0; 
    }     

   [color=#CC6600]if[/color] (InsolationAdvance==[color=#CC6600]true[/color]) Insolation();[color=#7E7E7E]//calculate clear sky solar intensity as the day advances[/color]
   Weather();[color=#7E7E7E]//run the weather overlay (cloud, storm)[/color]
   [color=#7E7E7E]//check to see if were need to have a lightning strike[/color]
    [color=#CC6600]if[/color] (StrikeNow==[color=#CC6600]true[/color]){
       [color=#CC6600]if[/color] (([color=#CC6600]millis[/color]()-StrikeStart)>=StrikeMaster[(StrikeCount*2)]){[color=#7E7E7E]//check if time has passed the delay (position 0,2,4,6,8 etc in StrikeMaster)-StrikeCount is indexed up by 1 after each strike so we see positions 0,2,4,6,etc in sequence[/color]
          [color=#CC6600]byte[/color] intensity;
          intensity=[color=#CC6600]random[/color](180,256);[color=#7E7E7E]// this little bit should generate a randomly bright flash variation between the series of flashes in StrikeMaster[/color]
              [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] b=0; b<6; b++){
                  [color=#CC6600]if[/color] (StrikeChannel[b]==1) [color=#CC6600]analogWrite[/color](PWMports[b],intensity);[color=#7E7E7E]// set all strike channels to intensity of strike[/color]
              }
          [color=#CC6600]delay[/color](StrikeMaster[((StrikeCount*2)+1)]);[color=#7E7E7E]//index to +1 position in array from 0,2,4, etc to 1,3,5 etc[/color]
          StrikeCount++;[color=#7E7E7E]//so that the next time we look at elapsed time were looking at the right array position[/color]
          [color=#CC6600]if[/color] (StrikeCount==(StrikeNumber-1)){
            StrikeNow=[color=#CC6600]false[/color];
            StrikeCount=0;
          }
       }
    }
    [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] a=0;a<6;a++){[color=#7E7E7E]//using all prior mods to light intensity (Insolation-->Cloud-->Storm) lets make some light[/color]
      [color=#CC6600]analogWrite[/color](PWMports[a],TrueIntensity[a]);[color=#7E7E7E]//dont change this to 8 to refelct array for channels.. we only have 6 here![/color]
    }
}
[color=#7E7E7E]//End Loop[/color]
[color=#7E7E7E]//*********************************************************************************************************************************[/color]

[color=#7E7E7E]//*********************************************************************************************************************************[/color]
[color=#7E7E7E]//Standard PWM Functions Receive/Process[/color]
[color=#CC6600]void[/color] receiveEvent([color=#CC6600]int[/color] howMany) {
    wdt_reset();
    [color=#CC6600]if[/color] (howMany==5){
        [color=#CC6600]byte[/color] cmd1, cmd2, cmd3, cmd4, cmd5;
        cmd1=[color=#CC6600]Wire[/color].[color=#CC6600]read[/color]();
        cmd2=[color=#CC6600]Wire[/color].[color=#CC6600]read[/color]();
        cmd3=[color=#CC6600]Wire[/color].[color=#CC6600]read[/color]();
        cmd4=[color=#CC6600]Wire[/color].[color=#CC6600]read[/color]();
        cmd5=[color=#CC6600]Wire[/color].[color=#CC6600]read[/color]();
        [color=#CC6600]if[/color] (cmd1==[color=#006699]'$'[/color] && cmd2==[color=#006699]'$'[/color] && cmd3==[color=#006699]'$'[/color]){
            cmdnum=cmd4;
            datanum=cmd5;
            [color=#7E7E7E]//Serial.println(cmd4,DEC);[/color]
            [color=#7E7E7E]//Serial.println(cmd5,DEC);[/color]
        }
    }
    [color=#CC6600]else[/color]{
        [color=#CC6600]for[/color] ([color=#CC6600]int[/color] a=0;a<howMany;a++){
            [color=#CC6600]Wire[/color].[color=#CC6600]read[/color]();
        }
    }  
}

[color=#CC6600]void[/color] ProcessCMD([color=#CC6600]byte[/color] cmd, [color=#CC6600]byte[/color] data){
    wdt_reset(); 
}

[color=#7E7E7E]//End Standard Functions[/color]
[color=#7E7E7E]//*********************************************************************************************************************************[/color]
[color=#7E7E7E]//Start of sunrise, sunset and cloud calculations- runs on reset and once a day thereafter.[/color]
[color=#CC6600]void[/color] CalSun(){
   [color=#7E7E7E]//Serial.println("CalSun Run Now");[/color]

        [color=#7E7E7E]//*********************YOU NEED TO CHANGE THESE VALUES Read instructions in their ENTIRETY and CAREFULLY change to values for your tank and geographical region***************************[/color]
        [color=#7E7E7E]//channels 0-5 are PWM expansion board lights 6,7 are ReefAngel Controller PWM outputs[/color]
        [color=#7E7E7E]//offsets for rise/set all values in seconds offset from calculated rise or set value (-) am offset=longer day****** (-)pm offset=shorter day)[/color]
        [color=#7E7E7E]//array order is ch0 am offset, pm offset, ch1 am offset, pm offset etc..[/color]
        [color=#7E7E7E]//THESE values are the number of seconds that a particular channel will be offset from the rise/set time, i.e. negative to rise earlier/set earlier[/color]
        [color=#CC6600]int[/color] Choffset[]={
            5000,6000,6000,5000,5400,6800,6800,5400,6400,7200,7200,6400,0,0,0,0};
        [color=#7E7E7E]// NOW SET YOUR LATIDTUDE AND LONGITUDE COORDINATES as Degrees, Minutes, Seconds of Lat and Lon[/color]
        [color=#7E7E7E]//If Your NORTH of the equator your LONGITUDE must START with a NEGATIVE number (the rest are positive) e.g. All of North America, Europe, Russia etc are negative[/color]
        [color=#7E7E7E]//If Your EAST of the Prime Meridian your LATITUDE must START with a NEGATIVE number (the rest are positive), e.g. Most of Europe, All of China, India, Austraila, Russia etc are negative[/color]
       latitude=dmsToSeconds(20,54,00);[color=#7E7E7E]//United States of America- Salt Lake City, local time is -7 hours GMT [/color]
       longitude=dmsToSeconds(-155,35,00);
        [color=#7E7E7E]//**********************ok now were done changing things IF YOU CHANGED the Top part of the GLOBAL variable decleration AND this... your FULLY configured and ready to load******************************************** [/color]
   
    [color=#CC6600]if[/color] (dow==0){[color=#7E7E7E]//if the controller has resarted we need to find midnight[/color]
      [color=#CC6600]long[/color] hours, minutes;[color=#7E7E7E]//store current elapsed local hours as total seconds from midnight[/color]
      [color=#CC6600]time_t[/color] t=[color=#CC6600]now[/color]();[color=#7E7E7E]//store current clock time to parse[/color]
      hours=[color=#CC6600]hour[/color](t);
      hours=(hours*3600);[color=#7E7E7E]//current hour number 0-23 as seconds[/color]
      minutes=[color=#CC6600]minute[/color](t);
      minutes=(minutes*60);[color=#7E7E7E]//minutes of current hour as seconds[/color]
      newDay=[color=#CC6600]now[/color]();
      newDay-=(hours+minutes);[color=#7E7E7E]//Convert current local unix epoch time to local unix epoch time of midnight[/color]
    }
    [color=#CC6600]else[/color] [color=#CC6600]if[/color] (dow!=0){[color=#7E7E7E]//if we did not restart but the day is new then it is midnight and were good to go..[/color]
      newDay=[color=#CC6600]now[/color]();
    }
      
    [color=#7E7E7E]//#define SECS_YR_2000 (946684800) the time at the start of y2k (need to subtract from unix epoch time to bring to Y2K origin[/color]
    newDay-=946684800;[color=#7E7E7E]//convert GMT unix Epoch to seconds elasped since 2000 for GMT midnight of today[/color]
    
    rise=newDay;[color=#7E7E7E]//set value to send to SunRise as midnight GMT in seconds from Y2K[/color]
    set=newDay;[color=#7E7E7E]//[/color]
    [color=#7E7E7E]//Calculate rise time and set time using Epherma Library functions (see end of code) [/color]
    SunRise(&rise);[color=#7E7E7E]//call to Epherma function[/color]
    SunSet(&set);[color=#7E7E7E]//Call to Epherma functionunsigned long newDay;[/color]
  
   [color=#7E7E7E]/*Serial.print("rise and set=  ");[/color]
[color=#7E7E7E]   Serial.println(rise);[/color]
[color=#7E7E7E]   Serial.println(set);[/color]
[color=#7E7E7E]   Serial.print("newDay as seconds since 2000 to todays midnight=  ");[/color]
[color=#7E7E7E]   Serial.println(newDay);*/[/color]
    rise=(rise-newDay);[color=#7E7E7E]// set to elapsed seconds of day[/color]
    set=(set-newDay);
   [color=#7E7E7E]/*Serial.print("rise and set as elapsed seconds of day=  ");[/color]
[color=#7E7E7E]   Serial.println(rise);[/color]
[color=#7E7E7E]   Serial.println(set);*/[/color]
    newDay+=946684800;[color=#7E7E7E]//Convert newDay back to unix epoch GMT midnight today (used in loop to determine how far we are into the day) [/color]
   [color=#7E7E7E]/*Serial.print("newDay as seconds since since 1970 to todays midnight=  ");[/color]
[color=#7E7E7E]   Serial.println(newDay);[/color]
[color=#7E7E7E]   Serial.print("elapsed is");[/color]
[color=#7E7E7E]   long elapsed=now()-newDay;[/color]
[color=#7E7E7E]   Serial.println(elapsed);*/[/color]
   
        [color=#7E7E7E]//Calculate rise and set times for all channels in equivlants to elapsed seconds from midnight today[/color]
        [color=#7E7E7E]//populate array for chRise and Set as well as chSlope for 0.5pi/ half day lenght for each channel from midday (asymmetric days are allowed)[/color]
        [color=#CC6600]float[/color] deltaY=1.570796327;[color=#7E7E7E]//1/2 * pi as integer by scaling* 10^9 to fill UL[/color]
        midDay=(((set-rise)/2)+rise);
        [color=#CC6600]long[/color] HalfDayLength=((set-rise)/2);
       
        [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] b=0;b<16;b++){[color=#7E7E7E]//working as of April 5 2012 serial tested[/color]
            [color=#CC6600]if[/color] (b%2==0){
                ChRiseSet[b]=rise+(Choffset[b]);
                ChSlope[b]=(deltaY/([color=#CC6600]float[/color])(HalfDayLength-(Choffset[b])));
            }
            [color=#CC6600]else[/color] [color=#CC6600]if[/color] (b%2==1){
                ChRiseSet[b]=set+(Choffset[b]);
                ChSlope[b]=(deltaY/([color=#CC6600]float[/color])(HalfDayLength+(Choffset[b])));
            }
        }  
        
        [color=#7E7E7E]//***************** to CHANGE THE chance of Clouds actually occuring on a given day************************[/color]
        [color=#CC6600]byte[/color] CloudChance=80;[color=#7E7E7E]//% Chance of a Cloud every day[/color]
        [color=#7E7E7E]//****************************now were done- did you use a value from 0-100 without a decimal?****************[/color]
        
  
        [color=#CC6600]byte[/color] RainMaker=[color=#CC6600]random[/color](1,101); 
        [color=#CC6600]if[/color] (RainMaker<=CloudChance){
            CloudToday=[color=#CC6600]true[/color];[color=#7E7E7E]//used to trigger weather function, can also be used to send flag to controller[/color]
        }
        [color=#CC6600]else[/color] [color=#CC6600]if[/color] (RainMaker>CloudChance){
            CloudToday=[color=#CC6600]false[/color];[color=#7E7E7E]//see above comment on CloudToday[/color]
            [color=#CC6600]return[/color];
        }
        [color=#CC6600]long[/color] dayLength=0;
        [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] a=1;a<16;a=(a+2)){[color=#7E7E7E]//determine maximum day length given light on tank that is not moon light, this will yield night clouds and storms (and a storm after dark is severe... always[/color]
          [color=#CC6600]if[/color] (a==0){
            [color=#CC6600]if[/color] (((set+Choffset[a])-rise)>(set-rise)){
              dayLength=((set+Choffset[a])-rise);  
            }
            [color=#CC6600]else[/color] dayLength=(set-rise);
          }
          [color=#CC6600]else[/color] [color=#CC6600]if[/color] (a!=0){
            [color=#CC6600]if[/color] (dayLength<((set+Choffset[a])-rise)){
              dayLength=((set+Choffset[a])-rise);
            }
          }
        }
        
        [color=#7E7E7E]// number of clouds possible for the day, max and min[/color]
        [color=#CC6600]byte[/color] CloudsMax=5;[color=#7E7E7E]//DONT INCREASE BEYOND 10 or it will DIE, or increase array size to handle it (among other things)[/color]
        [color=#CC6600]byte[/color] CloudsMin=2;[color=#7E7E7E]//use 2 as a minimum[/color]
        CloudsTotal=[color=#CC6600]random[/color](CloudsMin,(CloudsMax+1));
        
        [color=#7E7E7E]// Average day is 50,000 secs so if 4 clouds and 10% that gets you 5,000 seconds of clouds (about 1800 seconds length for each of the 4 clouds in independent segments (if 4 is # clouds)[/color]
        [color=#CC6600]byte[/color] OvercastMin=((CloudsTotal*10)/5);[color=#7E7E7E]//Min cloud length will be about 1000 seconds (15 mins)- 1 hour min of clouds if you have 4, 2 hours if you have 8[/color]
        [color=#CC6600]byte[/color] OvercastMax=((CloudsTotal*10)/2);[color=#7E7E7E]//max cloud length will be about 2500 seconds (45 mins)- 6 hours max of clouds if you have 8, 3 hours max if you have 4[/color]
        [color=#CC6600]float[/color] Overcast=[color=#CC6600]random[/color](OvercastMin,OvercastMax);
        Overcast=(Overcast/100);
        
        [color=#7E7E7E]// split the total lenght of time for clouds into equal segments and then to randomly chop or add time to the [/color]
        [color=#7E7E7E]//segments such that cloud length is variable.  Then distribute into random parts of the day and fill array with start,duration pairs for clouds[/color]
        [color=#CC6600]int[/color] CloudLength;
        CloudLength=((dayLength*Overcast)/CloudsTotal);[color=#7E7E7E]//average cloud length[/color]
        [color=#CC6600]long[/color] SunSegment=((dayLength-(dayLength*Overcast))/(CloudsTotal+1));[color=#7E7E7E]//average sun length between clouds[/color]
        [color=#CC6600]float[/color] CloudFraction=0;
        [color=#CC6600]float[/color] SunFraction=0;
       
        [color=#7E7E7E]//start by zero filling CloudMaster array[/color]
        [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] a=0; a<20; a++){
          CloudMaster[a]=0;
        }
        
        [color=#CC6600]byte[/color] b=0;[color=#7E7E7E]//used to get pairs of fraction for SunFraction in for loop[/color]
        [color=#CC6600]byte[/color] c=0;[color=#7E7E7E]//used to get pairs of fraction for CloudFraction in for loop[/color]
        [color=#7E7E7E]//now randomize cloud length and sunsegment length as pairs to get different looking days- [/color]
        [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] a=0; a<(CloudsTotal*2); a++){
          [color=#CC6600]if[/color] (a%2==0){
            [color=#CC6600]if[/color] (b==0){
              [color=#CC6600]if[/color] (a==0){
                SunFraction=[color=#CC6600]random[/color](20,181);[color=#7E7E7E]//vary each pair of SunSegments from 20%-180% of possible length such that every pair =2*SunSegment in length[/color]
                SunFraction=(SunFraction/100);
                CloudMaster[a]=(SunFraction*SunSegment);
              }
              [color=#CC6600]else[/color] [color=#CC6600]if[/color] (a<((CloudsTotal*2)-2)){
                SunFraction=[color=#CC6600]random[/color](20,181);[color=#7E7E7E]//vary each pair of SunSegments from 20%-180% of possible length such that every pair =2*SunSegment in length[/color]
                SunFraction=(SunFraction/100);
                CloudMaster[a]=(SunFraction*SunSegment);
                b++;
              }
              [color=#CC6600]else[/color] [color=#CC6600]if[/color] (a==((CloudsTotal*2)-2)){
                SunFraction=(2-(([color=#CC6600]float[/color])CloudMaster[0]/([color=#CC6600]float[/color])SunSegment));
                CloudMaster[a]=(SunFraction*SunSegment);
              }
                
            }
            [color=#CC6600]else[/color] [color=#CC6600]if[/color] (b==1){
              [color=#CC6600]if[/color] (a<((CloudsTotal*2)-2)){
                SunFraction=(2-SunFraction);[color=#7E7E7E]//were on the second part of a pair[/color]
                CloudMaster[a]=(SunFraction*SunSegment);
                b=0;[color=#7E7E7E]//reset so next time we start a new fraction[/color]
              }
              [color=#CC6600]else[/color] [color=#CC6600]if[/color] (a==((CloudsTotal*2)-2)){
                SunFraction=(2-(([color=#CC6600]float[/color])CloudMaster[0]/([color=#CC6600]float[/color])SunSegment));
                CloudMaster[a]=(SunFraction*SunSegment); 
              }
            }
          }
          [color=#CC6600]else[/color] [color=#CC6600]if[/color] (a%2==1){[color=#7E7E7E]//if were in odd positions we need to determine cloud lengths in random pairs such that each pair =2*CloudLength in length[/color]
            [color=#CC6600]if[/color] (c==0){
              CloudFraction=[color=#CC6600]random[/color](20,181);[color=#7E7E7E]//vary each pair of SunSegments from 20%-180% of possible length such that every pair =2*SunSegment in length[/color]
              CloudFraction=(CloudFraction/100);
              CloudMaster[a]=(CloudFraction*CloudLength);
              c++;       
            }
            [color=#CC6600]else[/color] [color=#CC6600]if[/color] (c==1){
              CloudFraction=(2-CloudFraction);
              CloudMaster[a]=(CloudFraction*CloudLength);
              c=0;[color=#7E7E7E]//reset so next loop finds a new fraction[/color]
            }
         }
      }
        [color=#7E7E7E]/*Serial.println("here is cloud master in is entirety prior to forming start and end pairs");[/color]
[color=#7E7E7E]        for (byte a=0;a<20;a++){[/color]
[color=#7E7E7E]          Serial.println(CloudMaster[a]);[/color]
[color=#7E7E7E]        }*/[/color]
      [color=#7E7E7E]//reframe array to generate cloud start, cloud end, cloud start, cloud end[/color]
      [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] a=0; a<(CloudsTotal*2); a++){
        [color=#CC6600]if[/color] (a==0){[color=#7E7E7E]// if were starting our first cloud we need to add to rise value to first sun segment[/color]
          CloudMaster[a]=rise+CloudMaster[a];
        }
        [color=#CC6600]else[/color] {
          CloudMaster[a]=(CloudMaster[a-1]+CloudMaster[a]);[color=#7E7E7E]//just add prior values together e.g. (second position is cloud end so to find end add rise corrected start time with duration)[/color]
                                                           [color=#7E7E7E]// subsequent start would be end of 1st cloud + next sunsegment fraction[/color]
        }
      }
        [color=#7E7E7E]/*Serial.println("here is cloud master in is entirety as start and end pairs");[/color]
[color=#7E7E7E]        for (byte a=0;a<20;a++){[/color]
[color=#7E7E7E]          if (a%2==0){[/color]
[color=#7E7E7E]            Serial.print("Start time=");[/color]
[color=#7E7E7E]            Serial.println(CloudMaster[a]);[/color]
[color=#7E7E7E]          }[/color]
[color=#7E7E7E]          else {[/color]
[color=#7E7E7E]            Serial.print("End time=");[/color]
[color=#7E7E7E]            Serial.println(CloudMaster[a]);[/color]
[color=#7E7E7E]          }[/color]
[color=#7E7E7E]        }*/[/color]
}[color=#7E7E7E]//END SunCalc FUNCTION[/color]

[color=#CC6600]void[/color] Insolation()
{
  InsolationAdvance=[color=#CC6600]false[/color];[color=#7E7E7E]//reset this flag now that we have entered function[/color]

        [color=#7E7E7E]//define Pi as delta Y for slope since cos 0.5-1.5 Pi goes 0-1-0 in 0.5 pI increments slope of 1/2 day (0-1 intensity) delta Y is 1/2 Pi [/color]
        [color=#CC6600]float[/color] Pi=3.1415926;[color=#7E7E7E]//scale to 10^8[/color]
        [color=#CC6600]float[/color] PiHalf=1.5707963;[color=#7E7E7E]//scale to 10^8[/color]
        
        [color=#CC6600]float[/color] secSoFar;[color=#7E7E7E]//variable to account for seconds elapsed for each channel 1/2 day period from rise-->midDay and midDay-->set[/color]
        
        [color=#7E7E7E]/* using -cos(pi/2+elapsedTime/slope) calculate fractional intensity of each channel throughout the day[/color]
[color=#7E7E7E]         use flicker points to adjust minimum intensity to stable light.  Turn off lights after set or before rise etc.[/color]
[color=#7E7E7E]         by splitting into half days centered on midday (1/2 ofset-rise) we center exactly the cos function for every channel so color blends are maintained [/color]
[color=#7E7E7E]         throughout intensity ramp... more or less ... change intensity every 120 seconds throughout the day*/[/color]
         [color=#CC6600]if[/color] (elapsedTime<=midDay){
           [color=#CC6600]byte[/color] c=0;[color=#7E7E7E]//loop counter[/color]
            [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] b=0;b<16;b=(b+2)){
                [color=#CC6600]if[/color] (elapsedTime>=ChRiseSet[b]){
                    secSoFar=(elapsedTime-ChRiseSet[b]);[color=#7E7E7E]//just account for length of every channel 1/2 day and switch at midDay[/color]
                    ChannelValue[c]=flicker[c]+ChMax[c]*(-[color=#CC6600]cos[/color](PiHalf+(ChSlope[b]*secSoFar)));
                 }
                 [color=#CC6600]else[/color] [color=#CC6600]if[/color] (elapsedTime<ChRiseSet[b]){
                   [color=#CC6600]if[/color] (MoonCh[c]==1){  
                      [color=#CC6600]byte[/color] MoonToday=[color=#CC6600]MoonPhase[/color]()*0.5;[color=#7E7E7E]//SCALE FACTOR to DIM moon setting for use with HIGH power LED as moon light[/color]
                      [color=#CC6600]if[/color] (MoonToday==0) ChannelValue[c]=0;
                      [color=#CC6600]else[/color] [color=#CC6600]if[/color] (MoonToday<flicker[c]) ChannelValue[c]=flicker[c];
                      [color=#CC6600]else[/color] ChannelValue[c]=MoonToday;
                   }
                   [color=#CC6600]else[/color] [color=#CC6600]if[/color] (MoonCh[c]==0){
                     ChannelValue[c]=0;[color=#7E7E7E]//its dark and this is not a moon phase channel[/color]
                   }
                 }
              c++;[color=#7E7E7E]//index by one so we count 0-7 as b goes 0-14 by twos[/color]
            }
        }  
        [color=#CC6600]else[/color] [color=#CC6600]if[/color] (elapsedTime>midDay){
            [color=#CC6600]byte[/color] c=0;[color=#7E7E7E]//loop counter[/color]
            [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] b=1;b<16;b=b+2){
              [color=#CC6600]if[/color] (elapsedTime<=ChRiseSet[b]){
                    secSoFar=(elapsedTime-midDay);
                    ChannelValue[c]=flicker[c]+ChMax[c]*(-[color=#CC6600]cos[/color](Pi+(ChSlope[b]*secSoFar)));          
               }
               [color=#CC6600]else[/color] [color=#CC6600]if[/color] (elapsedTime>ChRiseSet[b]){
                   [color=#CC6600]if[/color] (MoonCh[c]==1){  
                      [color=#CC6600]byte[/color] MoonToday=[color=#CC6600]MoonPhase[/color]()*0.5;[color=#7E7E7E]//SCALE FACTOR to DIM moon setting for use with HIGH power LED as moon light[/color]
                      [color=#CC6600]if[/color] (MoonToday==0) ChannelValue[c]=0;
                      [color=#CC6600]else[/color] [color=#CC6600]if[/color] (MoonToday<flicker[c]) ChannelValue[c]=flicker[c];
                      [color=#CC6600]else[/color] ChannelValue[c]=MoonToday;
                   }
                   [color=#CC6600]else[/color] [color=#CC6600]if[/color] (MoonCh[c]==0){
                     ChannelValue[c]=0;[color=#7E7E7E]//its dark and this is not a moon phase channel[/color]
                   }
                }
              c++;[color=#7E7E7E]//index to count 0-7 as b counts 1-15 by twos.[/color]
            }
        }   
}[color=#7E7E7E]//END function[/color]
[color=#7E7E7E]//WEATHER FUNCTION BEGIN[/color]
[color=#CC6600]void[/color] Weather ()  
{
    [color=#CC6600]static[/color] [color=#CC6600]byte[/color] loopCount;
    [color=#CC6600]static[/color] [color=#CC6600]float[/color] CloudCover; [color=#7E7E7E]// variable to store value in random walk - declared static to accumulate Cloud effect[/color]
    [color=#CC6600]static[/color] [color=#CC6600]float[/color] PriorCloudCover;  [color=#7E7E7E]//used to "delay" one side of the tank from the other in cloud passing effects[/color]
    [color=#CC6600]static[/color] [color=#CC6600]long[/color] StormStart;
    [color=#CC6600]static[/color] [color=#CC6600]long[/color] StormEnd;
    [color=#CC6600]static[/color] [color=#CC6600]long[/color] CloudEnd;
    [color=#CC6600]static[/color] [color=#CC6600]boolean[/color] wtrigger;[color=#7E7E7E]//use to track the first run of functions to calculate random times that become fixed, see change from cloud to storm for useage[/color]
    [color=#CC6600]static[/color] [color=#CC6600]byte[/color] Counter;[color=#7E7E7E]//used to trigger storms from cloud you can change its if loop comparison to decrease or increase storm rate see below in cloud==true if loop[/color]
    [color=#CC6600]static[/color] [color=#CC6600]byte[/color] Severity;
    [color=#CC6600]static[/color] [color=#CC6600]byte[/color] StormCount;[color=#7E7E7E]// used to limit X storms per cloud and to choose which cloud can have a storm[/color]
    [color=#CC6600]static[/color] [color=#CC6600]int[/color] StepSize;
    [color=#CC6600]static[/color] [color=#CC6600]int[/color] LastStepSize;
    [color=#7E7E7E]//check to see if were having a scheduled cloud[/color]
    [color=#CC6600]if[/color] (Cloud==[color=#CC6600]false[/color]){
      [color=#7E7E7E]//Write Insolation values to TrueIntensity so the loop will pick them up and the cloud/storm will get the right data (since intensity changes during the day)[/color]
      [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] a=0; a<8; a++){[color=#7E7E7E]//this must be above the next loop[/color]
            TrueIntensity[a]=ChannelValue[a];[color=#7E7E7E]//this is where intensity is set for the PWM channel analog write in the loop... don't mess with this.[/color]
        }   
      [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] a=0; a<(CloudsTotal*2); a=(a+2)){[color=#7E7E7E]//if its time for a cloud, run it[/color]
         [color=#CC6600]if[/color] ((elapsedTime>=CloudMaster[a]) && (elapsedTime<=CloudMaster[(a+1)])) {
             CloudEnd=CloudMaster[(a+1)];[color=#7E7E7E]//to avoid this loop running true during the compute cycles at the end of the cloud and before elapsedTime advances a second, actual cloud does not[/color]
             [color=#7E7E7E]//Serial.print("We started a cloud and its end is=");[/color]
             [color=#7E7E7E]//Serial.println(CloudEnd);[/color]
             CloudCover=CloudStart(CloudMaster[a]);[color=#7E7E7E]//CloudStart modifies TrueIntensity to get us to 50% intensity at the start of the cloud effect and also sets cloud=true to bypass this[/color]
             Counter=0;
             StormCount=[color=#CC6600]random[/color](0,3);[color=#7E7E7E]//the number of storms MAX that may occur in this cloud (remember Random is range= -1 on high end)[/color]
             loopCount=1;
             LastStepSize=0;[color=#7E7E7E]//zero out cloud random walk variables[/color]
             StepSize=0;[color=#7E7E7E]//zero out cloud ranodm walk variables[/color]
             [color=#CC6600]return[/color];[color=#7E7E7E]//exit having started a cloud in CLoudStart routine called above[/color]
         }
       } 
     }
         
    [color=#CC6600]else[/color] [color=#CC6600]if[/color] ((Cloud==[color=#CC6600]true[/color]) && (IsStorm==[color=#CC6600]false[/color])){
        [color=#CC6600]if[/color] (StormAdvance==[color=#CC6600]false[/color]){[color=#7E7E7E]//use millis tracker to run this loop every 2 seconds[/color]
            [color=#CC6600]return[/color];
        }
        StormAdvance=[color=#CC6600]false[/color];[color=#7E7E7E]//reset to false when true so we run this once, until time advance is true again[/color]
        [color=#CC6600]if[/color] (elapsedTime>=CloudEnd){
            ClearSky(CloudCover, CloudEnd); 
            [color=#CC6600]return[/color];
        }
        
        [color=#7E7E7E]/*Use fractional intensity to set minimum value for any channel.  Dimming is proportional to actual intensity output [/color]
[color=#7E7E7E]         and constrained by flicker point.  Random walk uses static variable "CloudCover" constrained to 0-100 to represent fractional intensity (i.e. (1-(CloudCover/100))*Insolation SetPoint [/color]
[color=#7E7E7E]         is how the current cloud intensity is set, i.e. cloud cover of 90 gives 10% insolation setpoint unless below flicker in which case = flicker*/[/color]
        [color=#CC6600]if[/color] (loopCount==1){
          PriorCloudCover=CloudCover; [color=#7E7E7E]//e.g. PriorCloudCover=CloudCover with no float math to screw things up[/color]
          LastStepSize=StepSize;
          StepSize=([color=#CC6600]random[/color](5,21));[color=#7E7E7E]// in Percent% (0-100) This is how much light intensity will change over the loop count interval (this actual time is dependent upon the call frequency of StromAdvance as set in the loop)[/color]
          [color=#CC6600]if[/color] (([color=#CC6600]random[/color](0,2)!=1)) StepSize=-(StepSize);
          [color=#CC6600]if[/color] ((CloudCover+StepSize)>=100){[color=#7E7E7E]//cannot shut off lights more than 100% so limit here[/color]
            StepSize=(100-CloudCover);[color=#7E7E7E]//[/color]
            Counter++;
          }
          [color=#CC6600]else[/color] [color=#CC6600]if[/color] ((CloudCover+StepSize)<=0){[color=#7E7E7E]//cannot be brighter than 100% so since were in a cloud dont "limit" it but reflect it back down[/color]
            StepSize=-(StepSize);
            [color=#CC6600]if[/color] (Counter>=50) Counter-=[color=#CC6600]random[/color](-1,2);[color=#7E7E7E]//since we got bright... lets further delay and randomize storm occurence  [/color]
          }
          CloudCover=CloudCover+StepSize;
        }

        [color=#CC6600]if[/color] ((Counter>=60) && ((CloudEnd-elapsedTime)>=300)) {[color=#7E7E7E]//if Counter (indexes when cloud cover reaches 100) has accumulated and we still have time lets make a storm[/color]
        [color=#7E7E7E]//to change the frequency of storms increase or decrease the number comparison for counter in the if statement above (larger #== less storms).[/color]
        [color=#7E7E7E]//if you change counter comparison here change it in the next loop as well[/color]
           [color=#CC6600]if[/color] (StormCount>=1){[color=#7E7E7E]//if we can have storms in this cloud (random- statisticly 1/3 clouds = no storm, 1/3 = 1 possible storm, 1/3 = 2 possible storms)[/color]
             [color=#CC6600]byte[/color] RandomStorm;
             RandomStorm=[color=#CC6600]random[/color](0,11);[color=#7E7E7E]//this randomizes for longer clouds without storm, avg cloud is much longer prior to storm occuring- thus short clouds will not generally have a storm[/color]
               [color=#CC6600]if[/color] (RandomStorm>=4){
                 StormCount-=1;[color=#7E7E7E]//count down by 1 the number of storms in this cloud- this will not roll the byte since the loop requires it to be at least 1 to ever subtract here. [/color]
                 Counter=0;[color=#7E7E7E]//reset this variable since Storm loop uses it as well.[/color]
                 [color=#CC6600]int[/color] LongestStorm;[color=#7E7E7E]//used to pass max possible time to storm if loop from cloud loop within weather function[/color]
                 LongestStorm=(CloudEnd-elapsedTime);
                 Severity=StartStorm(LongestStorm, IsStorm, StormEnd);
                 loopCount=1;[color=#7E7E7E]//reset counting loop for the storm[/color]
               } 
           }
        }
        [color=#CC6600]else[/color] [color=#CC6600]if[/color] ((Counter>=60) && ((CloudEnd-elapsedTime)<300)){
           Counter=0;[color=#7E7E7E]//just reset the counter (does not really matter in this case but its clean)[/color]
        }
        
        [color=#CC6600]for[/color] ([color=#CC6600]int[/color] a=0;a<8;a++){
            [color=#CC6600]if[/color] (ChannelValue[a]==0) TrueIntensity[a]=0;[color=#7E7E7E]// if were in an evening storm dont reset intensity (it would go to flicker point and possibly flicker)[/color]
            [color=#CC6600]else[/color] [color=#CC6600]if[/color] (DimOrder[a]==0){
                TrueIntensity[a]=(flicker[a]+((([color=#CC6600]float[/color])(ChannelValue[a]-flicker[a]))*(1-((CloudCover-(StepSize-(StepSize/4)*loopCount))/100))));
            }
            [color=#CC6600]else[/color] [color=#CC6600]if[/color] (DimOrder[a]==1){
                TrueIntensity[a]=(flicker[a]+((([color=#CC6600]float[/color])(ChannelValue[a]-flicker[a]))*(1-((PriorCloudCover-(LastStepSize-(LastStepSize/4)*loopCount))/100))));
            }     
         }
         loopCount++;
         [color=#CC6600]if[/color] (loopCount>4) loopCount=1;
    }  
    [color=#7E7E7E]//enable a flag sent from controller to triger a storm, i.e. IsStorm=true[/color]
    [color=#7E7E7E]// set channel intensities for all but white with random walk continuing from above using static variable so should be seamless[/color]
    [color=#CC6600]else[/color] [color=#CC6600]if[/color] (((Cloud==[color=#CC6600]true[/color]) && (IsStorm==[color=#CC6600]true[/color])) || ((Cloud==[color=#CC6600]false[/color]) && (IsStorm==[color=#CC6600]true[/color]))){
        [color=#7E7E7E]//current else statement covers possibility of triggering storm from controller (i.e. not coming out of a cloud) but remember you need to flag wtrigger as TRUE when you do this[/color]
        [color=#CC6600]if[/color] (StormAdvance==[color=#CC6600]false[/color]){[color=#7E7E7E]//Every 1 second duing a storm change intensity, clouds are movin fast baby[/color]
           [color=#CC6600]return[/color];
        }
        
        StormAdvance=[color=#CC6600]false[/color];[color=#7E7E7E]//reset so we run again in 1 second.[/color]
        
       [color=#CC6600]if[/color] (elapsedTime>=StormEnd){ [color=#7E7E7E]//if were done with the storm we need to stop this loop, but were probably still cloudy so dont mess with that here[/color]
            IsStorm=[color=#CC6600]false[/color];
            Counter=0;
            [color=#CC6600]return[/color];
        }
        [color=#CC6600]if[/color] (loopCount==1){
          PriorCloudCover=CloudCover; [color=#7E7E7E]//e.g. PriorCloudCover=CloudCover with no float math to screw things up[/color]
          LastStepSize=StepSize;
          StepSize=([color=#CC6600]random[/color](5,21));[color=#7E7E7E]// in Percent% (0-100) This is how much light intensity will change over the loop count interval (this actual time is dependent upon the call frequency of StromAdvance as set in the loop)[/color]
          [color=#CC6600]if[/color] (([color=#CC6600]random[/color](0,2)!=1)) StepSize=-(StepSize);
          [color=#CC6600]if[/color] ((CloudCover+StepSize)>=100){[color=#7E7E7E]//cannot shut off lights more than 100% so limit here[/color]
            StepSize=(100-CloudCover);
            Counter++;
          }
          [color=#CC6600]else[/color] [color=#CC6600]if[/color] ((CloudCover+StepSize)<=0){[color=#7E7E7E]//cannot be brighter than 100% so since were in a cloud dont "limit" it but reflect it back down[/color]
            StepSize=-(StepSize);
            [color=#CC6600]if[/color] (Counter>=2) Counter-=[color=#CC6600]random[/color](0,2);[color=#7E7E7E]//since we got bright... lets further delay and randomize strike occurence    [/color]
          }
          [color=#CC6600]if[/color] (Counter>(Severity+2)) Counter=0;[color=#7E7E7E]//allow if to accumulate on ocassion to train strike sequences 2-3 in a row but then dump it [/color]
          CloudCover=CloudCover+StepSize;
        }
   
        [color=#CC6600]if[/color] ((Counter>=(Severity+[color=#CC6600]random[/color](-1,4))) && (StrikeNow==[color=#CC6600]false[/color])) {[color=#7E7E7E]//this is where a storm is triggered.  Counter indexes when cloud cover reaches 100 on the random walk[/color]
        [color=#7E7E7E]//to change the frequency of lightning strikes increase or decrease the number comparison for counter in the if statement above (larger #== less storms).[/color]
          [color=#CC6600]byte[/color] RandomStriker;
          RandomStriker=[color=#CC6600]random[/color](1,11);
          [color=#CC6600]if[/color] (RandomStriker>4){
            StrikeNumber=([color=#CC6600]random[/color](2,11)); [color=#7E7E7E]//random high =x-1 so max strike =12 each strike requires a duration and a delay thus StrikeMaster is 18 positions[/color]
            [color=#7E7E7E]//ensure the array is zeroed out past the last position required for this strike pattern so each pattern is only as long as generated[/color]
            [color=#7E7E7E]//Array is in pairs, position in arry of (0,1) (2,3) etc as strike (delay,duration)[/color]
            [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] a=0;a<20;a++){
                [color=#CC6600]if[/color] (a>=(StrikeNumber*2)){
                    StrikeMaster[a]=0;
                }
                [color=#CC6600]if[/color] (a%2==0){
                   [color=#CC6600]if[/color] (a==0){
                      StrikeMaster[a]=[color=#CC6600]random[/color](300,1601);[color=#7E7E7E]//no need for random here but I am leaving it since I wrote it that way.  This must be independent from a=2,4,6 etc...[/color]
                    }
                    [color=#CC6600]else[/color] {
                       StrikeMaster[a]=(StrikeMaster[(a-2)]+[color=#CC6600]random[/color](200,1401));[color=#7E7E7E]//position 0,2,4,6,8.. is strike delay[/color]
                    } 
                 }
                 [color=#CC6600]else[/color] [color=#CC6600]if[/color](a%2!=0){
                    StrikeMaster[a]=[color=#CC6600]random[/color](50,110);[color=#7E7E7E]//position 1,3,5,7,9... is strike duration (I tried real lightning strike durations and its too short this is adjusted for visual effect[/color]
                 }
            }
            StrikeNow=[color=#CC6600]true[/color]; [color=#7E7E7E]//Trigger to start strike sequence in loop[/color]
            StrikeStart=[color=#CC6600]millis[/color]();[color=#7E7E7E]//set timer to "zero" now- sequence will start in loop after this function[/color]
            StrikeCount=0;
          }
          Counter=0;
        }
        
        [color=#CC6600]if[/color] (Severity>5){
          [color=#CC6600]for[/color] ([color=#CC6600]int[/color] a=0;a<8;a++) {
              [color=#CC6600]if[/color] (ChannelValue[a]==0) TrueIntensity[a]=0;
              [color=#CC6600]else[/color] [color=#CC6600]if[/color] (Wchannel[a]==1){[color=#7E7E7E]//if were in a storm but not a severe storm constrain whites to 50% of Insolation intensity[/color]
                [color=#CC6600]if[/color] (DimOrder[a]==0){
                      TrueIntensity[a]=(flicker[a]+(((([color=#CC6600]float[/color])(ChannelValue[a]-flicker[a])/4))*(1-((CloudCover-(StepSize-(StepSize/3)*loopCount))/100)))); 
                  }
                  [color=#CC6600]else[/color] [color=#CC6600]if[/color] (DimOrder[a]==1){
                      TrueIntensity[a]=(flicker[a]+(((([color=#CC6600]float[/color])(ChannelValue[a]-flicker[a])/4))*(1-((PriorCloudCover-(LastStepSize-(LastStepSize/3)*loopCount))/100))));
                  }
              }
              [color=#CC6600]else[/color] [color=#CC6600]if[/color] (Wchannel[a]==0){[color=#7E7E7E]//if were blue, we chase as for a cloud[/color]
                  [color=#CC6600]if[/color] (DimOrder[a]==0){
                      TrueIntensity[a]=(flicker[a]+((([color=#CC6600]float[/color])((ChannelValue[a]-flicker[a])))*(1-((CloudCover-(StepSize-(StepSize/3)*loopCount))/100)))); 
                  }
                  [color=#CC6600]else[/color] [color=#CC6600]if[/color] (DimOrder[a]==1){
                      TrueIntensity[a]=(flicker[a]+(((([color=#CC6600]float[/color])(ChannelValue[a]-flicker[a])))*(1-((PriorCloudCover-(LastStepSize-(LastStepSize/3)*loopCount))/100))));
                  }
              }    
          }
        }
        [color=#CC6600]else[/color] [color=#CC6600]if[/color] (Severity<=5){[color=#7E7E7E]// severe storms occur throughout the day, but EVERY storm after sunset is severe...[/color]
          [color=#CC6600]for[/color] ([color=#CC6600]int[/color] a=0;a<8;a++) {
              [color=#CC6600]if[/color] (ChannelValue[a]==0) TrueIntensity[a]=0;
              [color=#CC6600]else[/color] [color=#CC6600]if[/color] (Wchannel[a]==1){[color=#7E7E7E]//if were white we need to be off in a storm[/color]
                TrueIntensity[a]=0;
              }
              [color=#CC6600]else[/color] [color=#CC6600]if[/color] (ChannelValue[a]==0){[color=#7E7E7E]//if this light channel is dark... e.g. after sunset for this channel- it produces no cloud effect[/color]
                  TrueIntensity[a]=0;
              }
              [color=#CC6600]else[/color] [color=#CC6600]if[/color] (Wchannel[a]==0){[color=#7E7E7E]//if were not shut off in a strom and not after our daylight period (this channel) then we produce storm light sequences.[/color]
                  [color=#CC6600]if[/color] (DimOrder[a]==0){[color=#7E7E7E]//if we dim first... do it[/color]
                      TrueIntensity[a]=(flicker[a]+((([color=#CC6600]float[/color])((ChannelValue[a]-flicker[a])))*(1-((CloudCover-(StepSize-(StepSize/3)*loopCount))/100)))); 
                  }
                  [color=#CC6600]else[/color] [color=#CC6600]if[/color] (DimOrder[a]==1){[color=#7E7E7E]//else we dim second[/color]
                      TrueIntensity[a]=(flicker[a]+(((([color=#CC6600]float[/color])(ChannelValue[a]-flicker[a])))*(1-((PriorCloudCover-(LastStepSize-(LastStepSize/3)*loopCount))/100))));
                  }
              }[color=#7E7E7E]//end of CWHchannel==0 being true[/color]
           }[color=#7E7E7E]//end of for loop in severity <5 == true loop[/color]
        }[color=#7E7E7E]//end severity compairson loop no more else statements[/color]
       
        loopCount++;
        [color=#CC6600]if[/color] (loopCount>3) loopCount=1;
    }[color=#7E7E7E]//end of storm if loop[/color]
}[color=#7E7E7E]//End Weather function[/color]

[color=#7E7E7E]//CloudStart drops light intensity to 50% of whatever daylight setting is to start the cloud at 50[/color]
[color=#CC6600]int[/color] CloudStart([color=#CC6600]long[/color] StartTime){
    [color=#CC6600]byte[/color] elapsed;
    elapsed=(elapsedTime-StartTime);[color=#7E7E7E]//counts up since we start this at elapsedTime=StartTime and StartTime is fixed[/color]
    [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] a=0; a<8; a++){ 
      TrueIntensity[a]=(flicker[a]+((([color=#CC6600]float[/color])((ChannelValue[a]-flicker[a])))*(1-(elapsed*2.5)/100))); 
    [color=#CC6600]if[/color] (elapsed>=20);
      Cloud=[color=#CC6600]true[/color];[color=#7E7E7E]//start the cloud[/color]
    }
    [color=#CC6600]return[/color] 50;[color=#7E7E7E]//set CloudCover to 50 [/color]
}[color=#7E7E7E]//end CloudStart function[/color]

[color=#7E7E7E]//StartStorm sets up duration and severity of storm. Its currently limited to 90-600 sec in length- it will rarely be lower than 3 minutes[/color]
[color=#CC6600]byte[/color] StartStorm([color=#CC6600]int[/color] MaxLength, [color=#CC6600]boolean[/color]& trigger, [color=#CC6600]long[/color]& EndTime){
      [color=#CC6600]byte[/color] LightningIntensity;
      [color=#CC6600]int[/color] StormDuration;
      MaxLength-=120;[color=#7E7E7E]//remove 2 mins from longest storm so that we end up with 2 minutes of cloud after the storm before the sky clears to daylight[/color]
      [color=#CC6600]if[/color] (MaxLength>720){
         MaxLength=720;[color=#7E7E7E]//modify local variable[/color]
         StormDuration=[color=#CC6600]random[/color]((MaxLength/3),(MaxLength+1));
         EndTime=(elapsedTime+StormDuration);[color=#7E7E7E]//Set by reference StormEnd static variable in weather[/color]
      }
      [color=#CC6600]else[/color] {
         StormDuration=[color=#CC6600]random[/color]((MaxLength/2),(MaxLength+1));
         EndTime=(elapsedTime+StormDuration);[color=#7E7E7E]//Set by reference StormEnd static variable in weather[/color]
      }
      [color=#CC6600]if[/color] (elapsedTime<midDay){
         LightningIntensity=[color=#CC6600]random[/color](3,11);[color=#7E7E7E]//morning storms are generally less severe[/color]
      }
      [color=#CC6600]else[/color] [color=#CC6600]if[/color] (elapsedTime>midDay){[color=#7E7E7E]//afternoon storms are more likely to be severe (every 10-15 sec or less) to about once in a minute or maybe less[/color]
         [color=#CC6600]if[/color] (elapsedTime>(set-rise)){[color=#7E7E7E]//Storms after sunset are always severe... it just looks too cool![/color]
           LightningIntensity=3;
         }
         [color=#CC6600]else[/color] {
         LightningIntensity=[color=#CC6600]random[/color](3,8);
         }
      }
      trigger=[color=#CC6600]true[/color];
      [color=#CC6600]return[/color] (LightningIntensity);
}
[color=#7E7E7E]//End Storm Start Function[/color]
[color=#7E7E7E]//Similar to Cloud start but in reverse... now ramp intensity from wherever we were at the end of the cloud to the value set by Insolation[/color]
[color=#CC6600]void[/color] ClearSky([color=#CC6600]int[/color] CloudPercent, [color=#CC6600]long[/color] TerminationTime)
{
    [color=#CC6600]byte[/color] elapsed=(elapsedTime-TerminationTime);[color=#7E7E7E]//Counts up from the scheduled end of the cloud in seconds[/color]
    [color=#CC6600]float[/color] slope=(CloudPercent/30);[color=#7E7E7E]//Just calculate how much to increment every second to go from CloudCover to clear sky (CloudCover of zero)[/color]
    [color=#CC6600]float[/color] LightAdvance;
    LightAdvance=(CloudPercent-(slope*elapsed));[color=#7E7E7E]//were reducing CloudCover from start to zero over 10 seconds.[/color]
    [color=#CC6600]for[/color] ([color=#CC6600]byte[/color] a=0; a<8; a++){ 
    TrueIntensity[a]=(flicker[a]+((([color=#CC6600]float[/color])(ChannelValue[a]-flicker[a]))*(1-(LightAdvance/100)))); 
    }
    [color=#CC6600]if[/color] (elapsed>=30){[color=#7E7E7E]//at this point lights are back to full Insolation setting so cancel the cloud and start waiting for the next one[/color]
        Cloud=[color=#CC6600]false[/color];[color=#7E7E7E]//stop the cloud we are now outside of a true condition in the if loop so it will now stay false and lights are back on[/color]
        IsStorm=[color=#CC6600]false[/color];[color=#7E7E7E]//just to be redundant this is not called from a storm... [/color]
    }
}[color=#7E7E7E]//End Clear Sky function[/color]

[color=#CC6600]byte[/color] [color=#CC6600]MoonPhase[/color]()
{
   [color=#CC6600]int[/color] m,d,y;
   [color=#CC6600]int[/color] yy,mm;
   [color=#CC6600]long[/color] K1,K2,K3,J,V;
   [color=#CC6600]byte[/color] PWMvalue;
   m = [color=#CC6600]month[/color]();
   d = [color=#CC6600]day[/color]();
   y = [color=#CC6600]year[/color]();
   yy = y-((12-m)/10);
   mm = m+9;
   [color=#CC6600]if[/color] (mm>=12) mm -= 12;
   K1 = 365.25*(yy+4712);
   K2 = 30.6*mm+.5;
   K3 = [color=#CC6600]int[/color]([color=#CC6600]int[/color]((yy/100)+49)*.75)-38;
   J = K1+K2+d+59-K3;
   V = (J-2451550.1)/0.29530588853;
   V -= [color=#CC6600]int[/color](V/100)*100;
   V = [color=#CC6600]abs[/color](V-50);
   PWMvalue = 4*[color=#CC6600]abs[/color](50-V);  [color=#7E7E7E]// 5.12=100%    4=~80%[/color]
   [color=#7E7E7E]//pinMode(lowATOPin,OUTPUT);[/color]
   [color=#7E7E7E]//return (PWMvalue*100)/255; //output is 0-100[/color]
   [color=#CC6600]return[/color] PWMvalue;[color=#7E7E7E]//output is 0-255 [/color]
}

[color=#7E7E7E]//********************** DO NOT MESS WITH THIS UNLESS YOU KNOW WHAT YOUR DOING****************************[/color]
[color=#7E7E7E]//THE CODE BELOW THIS copied directly from the SWFLTEK Epherma library constructed by Michael Rice.  [/color]
[color=#7E7E7E]//this code is being used freely with attribution to Micahel Rice in accord with his request[/color]
[color=#7E7E7E]//  A big thank you for these library functions.  Its great! [/color]


[color=#7E7E7E]//convert degrees to seconds of arc[/color]


[color=#7E7E7E]// decimal degrees[/color]
[color=#CC6600]long[/color] ddToSeconds([color=#CC6600]float[/color] dd){
   [color=#CC6600]return[/color] dd * 3600.0;
}

[color=#7E7E7E]//Degrees, minutes, seconds[/color]
[color=#CC6600]long[/color] dmsToSeconds([color=#CC6600]int[/color] d, [color=#CC6600]unsigned[/color] [color=#CC6600]char[/color] m, [color=#CC6600]unsigned[/color] [color=#CC6600]char[/color] s){
[color=#CC6600]long[/color] ret;

   ret = labs(([color=#CC6600]long[/color])d);
   ret = ret * 3600L + 60L * m + s;
   ret = (d<0L) ? -ret : ret;
   [color=#CC6600]return[/color] ret;
}
[color=#7E7E7E]/* ------------------------------------------------------------------------------------------------[/color]
[color=#7E7E7E]   'Equation of Time'[/color]
[color=#7E7E7E]   We use the 'short form equation, which has a theoretical accuracy of about 40 seconds.[/color]
[color=#7E7E7E]   The returned value is in seconds.[/color]
[color=#7E7E7E]*/[/color]
[color=#CC6600]int[/color] equation_of_time([color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] dt){
[color=#CC6600]double[/color] t;

   dt -= 192540UL; [color=#7E7E7E]// refer to Jan 3 2000 05:29 (first periapsis)[/color]
   dt %= _tropical_year;
   t = dt;
   t /= _tropical_year;
   t *= 6.283185307179586;
   t = -459.27672 * [color=#CC6600]sin[/color](t) + 575.333472 * [color=#CC6600]sin[/color](2.0 * t + 3.588414);
   [color=#CC6600]return[/color] t;
}

[color=#7E7E7E]/*[/color]
[color=#7E7E7E]   'Solar Noon' adjusts the passed time stamp to the time (GMT) of local solar noon.[/color]
[color=#7E7E7E]   The accuracy is about 40 seconds (set by the equation of time).[/color]
[color=#7E7E7E]*/[/color]
[color=#CC6600]void[/color] SolarNoon([color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] * dt){
[color=#CC6600]long[/color] r;

   [color=#7E7E7E]// Set stamp to noon GMT[/color]
   *dt /= 86400UL;
   *dt *= 86400UL;
   *dt += 43200UL;

   [color=#7E7E7E]// adjust for equation of time, at noon GMT[/color]
   *dt -= equation_of_time(*dt);

   [color=#7E7E7E]// rotate to our longitude[/color]
   r = longitude / 15L;
   *dt -= r;
}

[color=#7E7E7E]/* -----------------------------------------------------------------------------------------------[/color]
[color=#7E7E7E]   'Solar Declination'[/color]
[color=#7E7E7E]   Returns declination in radians[/color]
[color=#7E7E7E]   Accurate to within 50 arc-seconds[/color]
[color=#7E7E7E]*/[/color]

[color=#CC6600]double[/color] SolarDeclination([color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] dt){
[color=#CC6600]double[/color] y;

   dt %= _tropical_year;
   y = dt;
   y /= _tropical_year; [color=#7E7E7E]// fractional year[/color]
   y *= 6.283185307179586;
   y=0.006918-0.399912*[color=#CC6600]cos[/color](y)+0.070257*[color=#CC6600]sin[/color](y)-0.006758*[color=#CC6600]cos[/color](y*2)+0.000907*[color=#CC6600]sin[/color](y*2)-0.002697*[color=#CC6600]cos[/color](y*3)+0.00148*[color=#CC6600]sin[/color](y*3);
   [color=#CC6600]return[/color] y;
}

[color=#7E7E7E]/* ------------------------------------------------------------------------------------------------[/color]
[color=#7E7E7E]   Return the period between sunrise and sunset, in seconds.[/color]
[color=#7E7E7E]   At high latitudes around the time of the solstices, this could be zero, or all day.[/color]
[color=#7E7E7E]*/[/color]
[color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] daylightseconds([color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] dt){
[color=#CC6600]float[/color] l, d, e;
[color=#CC6600]long[/color] n;

   d = -SolarDeclination(dt); [color=#7E7E7E]// will be positive in Northern winter[/color]
   l = latitude / _sec_rad; [color=#7E7E7E]// latitude in radians[/color]

   e += 60.0 * l * [color=#CC6600]tan[/color](l + d); [color=#7E7E7E]// latitudinal error[/color]
   d = [color=#CC6600]tan[/color](l) * [color=#CC6600]tan[/color](d); [color=#7E7E7E]//[/color]

   [color=#CC6600]if[/color](d>1.0) [color=#CC6600]return[/color] 86400UL;
   [color=#CC6600]if[/color](d < -1.0) [color=#CC6600]return[/color] 0UL;

   d = [color=#CC6600]acos[/color](d);
   d /= _zenith;

   n = 86400UL * d;
   n += e;
   [color=#CC6600]return[/color] n;
}


[color=#7E7E7E]/* ------------------------------------------------------------------------------------------------[/color]
[color=#7E7E7E]   Modify the passed time stamp to the time of sunrise (or sunset if 'set' is non-zero).[/color]
[color=#7E7E7E]   Returns 0 to signal 'normal' completion. If the position is in a polar circle, 1 will be[/color]
[color=#7E7E7E]   returned if the sun is above the horizon all day, and -1 if the sun is below the horizon[/color]
[color=#7E7E7E]   all day.[/color]

[color=#7E7E7E]*/[/color]
[color=#CC6600]char[/color] SunRiseSet([color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] * dt, [color=#CC6600]char[/color] set){
[color=#CC6600]unsigned[/color] [color=#CC6600]long[/color] daylen;

   daylen = daylightseconds(*dt);
   [color=#CC6600]if[/color](daylen == 86400UL) [color=#CC6600]return[/color] 1;   [color=#7E7E7E]// there is no 'night' today (midnight sun)[/color]
   [color=#CC6600]if[/color](daylen == 0UL) [color=#CC6600]return[/color] -1; [color=#7E7E7E]// there is no 'day' today[/color]

   *dt /= 86400UL;
   *dt *= 86400UL;
   *dt += 43200UL; [color=#7E7E7E]// set the time stamp to 12:00:00 GMT[/color]

   *dt -= daylen / 2; [color=#7E7E7E]//        sunrise at the prime meridian[/color]
   [color=#CC6600]if[/color](set) *dt += daylen; [color=#7E7E7E]//     sunset at the prime meridian[/color]

   *dt -= equation_of_time(*dt);

   [color=#7E7E7E]//*dt -= longitude / 15.0; // rotate to our own meridian[/color]

   [color=#CC6600]return[/color] 0;
}
[color=#7E7E7E]// 'short' forms of SunRiseSet[/color]
[color=#CC6600]char[/color] SunRise([color=#CC6600]unsigned[/color] [color=#CC6600]long[/color]* when){
    [color=#CC6600]return[/color] SunRiseSet(when, 0);
}
[color=#CC6600]char[/color] SunSet([color=#CC6600]unsigned[/color] [color=#CC6600]long[/color]* when){
    [color=#CC6600]return[/color] SunRiseSet(when, 1);
}

[/quote]
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Cloud and Lightning Code for Dimming Expansion

Post by lnevo »

We have SunLocation as part of the libraries now to take care of GPS rise/set times. Also there's a class for Moon implementation. Add in seasonal temperature control and the cloud / lightning that Colin added and you're better off than before :)
jjdezek
Posts: 329
Joined: Fri May 17, 2013 1:35 pm

Re: Cloud and Lightning Code for Dimming Expansion

Post by jjdezek »

So how would I write the code for my set up?
Image
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Cloud and Lightning Code for Dimming Expansion

Post by lnevo »

Look at my INO for examples on using it. There is also a thread for SunLocation if you search the forum. Colin can help you with the clouds. I don't know what your setup is...
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

Code: Select all

// Minimum number of clouds that can happen per day
        #define Min_Clouds_per_Day 1
Can this be 0?
Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

Not sure, but probably. There are other variables that determine no clouds for the day, though.
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

i thought some of the other variables did but i didn't know if this would cause there to definitely be a cloud per day or not.
Image
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Cloud and Lightning Code for Dimming Expansion

Post by cosmith71 »

If the minimum was 0, then there is a chance the minimum would be 0 and therefore no clouds.
MDB1029
Posts: 178
Joined: Wed Nov 12, 2014 3:10 pm
Location: An Oklahoman in Ohio

Re: Cloud and Lightning Code for Dimming Expansion

Post by MDB1029 »

that makes sense. Thanks for the info.
Image
pyroboy1der
Posts: 17
Joined: Fri Mar 02, 2012 10:27 am

Re: Cloud and Lightning Code for Dimming Expansion

Post by pyroboy1der »

Right now the clouds dim my white all the way down to 0. Is there a way to make it only dim to a set point or to have it dim as a given percentage of the previous value, such as 1/2?
Post Reply