////// Memory Locations used by all formulas#define Mem_B_AcclDay 100 // Note - 100 represents the hard coded Memory location used for this variable // not the value for the variable.// This variable represents the current day in Acclimation Cycle. Set this value to the same // number of days as your AcclDuration to begin the acclimation cycle or set it to 0 to use // your normal dimming end% values.#define Mem_B_AcclDuration 101 // Set this value to how many days you want your acclimation cycle to take.#define Mem_B_SlopeStart 102 // Set this to your desired starting acclimation end%.

////////// Variables used for all channels byte acclDay = InternalMemory.read(Mem_B_AcclDay); // What day in the acclimation cycle it is byte acclDuration = InternalMemory.read(Mem_B_AcclDuration); // Acclimation Duration in days byte startPercent = InternalMemory.read(Mem_B_SlopeStart); // Normal start% being used by all 3 channels

// At the end of the day, we need to decrement the acclimation counter. static boolean acclCounterReady=false; // We need a boolean so we only do this once per day if (now()%SECS_PER_DAY!=0) acclCounterReady=true; // If it's not midnight we'll get the boolean ready if (now()%SECS_PER_DAY==0 && acclCounterReady && acclDay>0) { // It's midnight, our bool is true and acclDay is more than 0 acclDay--; // Reduce the counter acclCounterReady=false; // Reset the boolean flag InternalMemory.write(Mem_B_AcclDay,acclDay); // Update memory}

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

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

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

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

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

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

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

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

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

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

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

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

if (cloudchance) { //is it time for cloud yet? if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration)) { DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,DaylightPWMValue,0,180); if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) { if (random(100)<20) lightningstatus=1; else lightningstatus=0; if (lightningstatus) { DaylightPWMValue=100; ActinicPWMValue=100; } else { DaylightPWMValue=0; ActinicPWMValue=0; } delay(1); } } if (NumMins(hour(),minute())>(cloudstart+cloudduration)) { cloudindex++; if (cloudindex < numclouds) { cloudstart=random(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2),(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2))+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))); // pick a random number for the cloud duration of first cloud. cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration); //Pick a random number between 0 and 99 lightningchance=random(100); // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0; } } }

////// Memory Locations used by all formulas#define Mem_B_AcclDay 100 // Note - 100 represents the hard coded Memory location used for this variable // not the value for the variable.// This variable represents the current day in Acclimation Cycle. Set this value to the same // number of days as your AcclDuration to begin the acclimation cycle or set it to 0 to use // your normal dimming end% values.#define Mem_B_AcclDuration 101 // Set this value to how many days you want your acclimation cycle to take.#define Mem_B_SlopeStart 102 // Set this to your desired starting acclimation end%.

// Add random mode if we set to Mode to Custom in portal static int rmode; static boolean changeMode=true;

// These are the modes we can cycle through. You can add more and even repeat... byte modes[] = { Lagoon, ReefCrest, TidalSwell, Sine, Gyre, NutrientTransport, Else, ShortPulse };

if (now()%SECS_PER_DAY==0 || changeMode==true) { // Change at midnight or if controller rebooted rmode=random(100)%sizeof(modes); // Change the mode once per day to pick from our array changeMode=false; }

// Set timer when in feeding mode static unsigned long feeding; if (ReefAngel.DisplayedMenu==FEEDING_MODE) feeding=now();

////////// Variables used for all channels byte acclDay = InternalMemory.read(Mem_B_AcclDay); // What day in the acclimation cycle it is byte acclDuration = InternalMemory.read(Mem_B_AcclDuration); // Acclimation Duration in days byte startPercent = InternalMemory.read(Mem_B_SlopeStart); // Normal start% being used by all 3 channels

// At the end of the day, we need to decrement the acclimation counter. static boolean acclCounterReady=false; // We need a boolean so we only do this once per day if (now()%SECS_PER_DAY!=0) acclCounterReady=true; // If it's not midnight we'll get the boolean ready if (now()%SECS_PER_DAY==0 && acclCounterReady && acclDay>0) { // It's midnight, our bool is true and acclDay is more than 0 acclDay--; // Reduce the counter acclCounterReady=false; // Reset the boolean flag InternalMemory.write(Mem_B_AcclDay,acclDay); // Update memory}

// handle updating sunrise and sunset values sl.CheckAndUpdate();

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

// This should always be the last line ReefAngel.Portal( ); ReefAngel.ShowInterface();

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

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

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

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

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

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

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

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

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

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

// Add Random Lightning modes#define Slow 0 // 5 seconds of slow lightning in the middle of a cloud for ELN style (slow response) drivers#define Fast 1 // 5 seconds of fast lightning in the middle of a cloud for LDD style (fast response) drivers#define Mega 2 // Lightning throughout the cloud, higher chance as it gets darker#define Mega2 3 // Like Mega, but with more lightning // Set which modes you want to use // Example: { Slow, 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[] = { Fast, Mega, Mega2 };

// 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,0,180); if (chooseLightning) { lightningMode=LightningModes[random(100)%sizeof(LightningModes)]; chooseLightning=false; } switch (lightningMode) { 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) { int a=random(1,5); // Pick a number of consecutive flashes from 1 to 4. for (int i=0; i<a; i++) { analogWrite(daylightPWMPin,random(DaylightPWMValue*2.55,255)); // Flash on 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 analogWrite(daylightPWMPin,DaylightPWMValue*2.55); // Flash off delay(random(30,50)); // Wait from 30 to 49 ms wdt_reset(); } 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 && (millis()-DelayCounter)>DelayTime) { int a=random(1,5); // Pick a number of consecutive flashes from 1 to 4. for (int i=0; i<a; i++) { analogWrite(daylightPWMPin,random(DaylightPWMValue*2.55,255)); // Flash on 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 analogWrite(daylightPWMPin,DaylightPWMValue*2.55); // Flash off delay(random(30,50)); // Wait from 30 to 49 ms wdt_reset(); } 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 Fast: // 5 seconds of lightning in the middle of the cloud if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5 && (millis()-DelayCounter)>DelayTime) { int a=random(1,5); // Pick a number of consecutive flashes from 1 to 4. for (int i=0; i<a; i++) { analogWrite(daylightPWMPin,random(DaylightPWMValue*2.55,255)); // Flash on 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 analogWrite(daylightPWMPin,DaylightPWMValue*2.55); // Flash off delay(random(30,50)); // Wait from 30 to 49 ms wdt_reset(); } 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=100; } 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; } } }

////// Memory Locations used by all formulas#define Mem_B_AcclDay 100 // Note - 100 represents the hard coded Memory location used for this variable // not the value for the variable.// This variable represents the current day in Acclimation Cycle. Set this value to the same // number of days as your AcclDuration to begin the acclimation cycle or set it to 0 to use // your normal dimming end% values.#define Mem_B_AcclDuration 101 // Set this value to how many days you want your acclimation cycle to take.#define Mem_B_SlopeStart 102 // Set this to your desired starting acclimation end%.

// Add random mode if we set to Mode to Custom in portal static int rmode; static boolean changeMode=true;

// These are the modes we can cycle through. You can add more and even repeat... byte modes[] = { Lagoon, ReefCrest, TidalSwell, Sine, Gyre, NutrientTransport, Else };

if (now()%SECS_PER_DAY==0 || changeMode==true) { // Change at midnight or if controller rebooted rmode=random(100)%sizeof(modes); // Change the mode once per day to pick from our array changeMode=false; }

// Set timer when in feeding mode static unsigned long feeding; if (ReefAngel.DisplayedMenu==FEEDING_MODE) feeding=now();

////////// Variables used for all channels byte acclDay = InternalMemory.read(Mem_B_AcclDay); // What day in the acclimation cycle it is byte acclDuration = InternalMemory.read(Mem_B_AcclDuration); // Acclimation Duration in days byte startPercent = InternalMemory.read(Mem_B_SlopeStart); // Normal start% being used by all 3 channels

// At the end of the day, we need to decrement the acclimation counter. static boolean acclCounterReady=false; // We need a boolean so we only do this once per day if (now()%SECS_PER_DAY!=0) acclCounterReady=true; // If it's not midnight we'll get the boolean ready if (now()%SECS_PER_DAY==0 && acclCounterReady && acclDay>0) { // It's midnight, our bool is true and acclDay is more than 0 acclDay--; // Reduce the counter acclCounterReady=false; // Reset the boolean flag InternalMemory.write(Mem_B_AcclDay,acclDay); // Update memory}

// handle updating sunrise and sunset values sl.CheckAndUpdate();

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

// This should always be the last line ReefAngel.Portal( "89delta","collin1123" ); ReefAngel.ShowInterface();

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

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

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

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

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

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

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

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

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

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

// Add Random Lightning modes#define Slow 0 // 5 seconds of slow lightning in the middle of a cloud for ELN style (slow response) drivers#define Fast 1 // 5 seconds of fast lightning in the middle of a cloud for LDD style (fast response) drivers#define Mega 2 // Lightning throughout the cloud, higher chance as it gets darker#define Mega2 3 // Like Mega, but with more lightning // Set which modes you want to use // Example: { Slow, 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[] = { Fast, Mega, Mega2 };

// 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,0,180); if (chooseLightning) { lightningMode=LightningModes[random(100)%sizeof(LightningModes)]; chooseLightning=false; } switch (lightningMode) { 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) { int a=random(1,5); // Pick a number of consecutive flashes from 1 to 4. for (int i=0; i<a; i++) { analogWrite(daylightPWMPin,random(DaylightPWMValue*2.55,255)); // Flash on 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 analogWrite(daylightPWMPin,DaylightPWMValue*2.55); // Flash off delay(random(30,50)); // Wait from 30 to 49 ms wdt_reset(); } 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 && (millis()-DelayCounter)>DelayTime) { int a=random(1,5); // Pick a number of consecutive flashes from 1 to 4. for (int i=0; i<a; i++) { analogWrite(daylightPWMPin,random(DaylightPWMValue*2.55,255)); // Flash on 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 analogWrite(daylightPWMPin,DaylightPWMValue*2.55); // Flash off delay(random(30,50)); // Wait from 30 to 49 ms wdt_reset(); } 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 Fast: // 5 seconds of lightning in the middle of the cloud if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5 && (millis()-DelayCounter)>DelayTime) { int a=random(1,5); // Pick a number of consecutive flashes from 1 to 4. for (int i=0; i<a; i++) { analogWrite(daylightPWMPin,random(DaylightPWMValue*2.55,255)); // Flash on 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 analogWrite(daylightPWMPin,DaylightPWMValue*2.55); // Flash off delay(random(30,50)); // Wait from 30 to 49 ms wdt_reset(); } 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=100; } 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; } } }