Clouds/Lightning/Storms for 16 Channel PWM Expansion

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

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

Ok, so I know that this is wrong 'B0000010000000000'
You need to convert that to decimal. Arduino doesn't have that declared internally.
So, binary 0000010000000000 = decimal 1024
Also, you should actually rename your original libraries folder to something like libraries-original and you need to rename the libraries-dev to libraries.
The contents of libraries is what Arduino will be looking at.
Roberto.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

Ok, so I renamed my original library to librariesoriginal and the dev libraries to "libraries". I'm still getting the same errors. Also, the binary numbers were copied from someone else's lightning code that I've been using for quite a while. It was for the 6 channel PWM expansion, so I added 10 digits. Could this be why? How could I get the binary number to work? The code does a bit read to determine if a particular channel is to be flashed or not.
Thanks!
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

I got rid of the binary problem by adding word in front of the number so

#define Actinic_Channels B0000010000000000

became

#define word Actinic_Channels B0000010000000000

This is now my error log:



The following features were automatically added:
Watchdog Timer
Version Menu

The following features were detected:
16 Channel Dimming Expansion Module
Dimming Signal
Wifi Attachment
Relay Expansion Module
2014 Main Screen
Extra Font - Medium Size (8x8 pixels)
pH Expansion Module
Number of Relay Expansion Modules: 1
Simple Menu
In_Progress.cpp: In function 'void setup()':
In_Progress:147: error: 'class ReefAngelClass' has no member named 'Add16ChPWM'
In_Progress.cpp: In function 'void loop()':
In_Progress:196: error: 'PWMChannel' was not declared in this scope
In_Progress:233: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:234: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:235: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:236: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:237: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:238: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:239: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:240: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:241: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:242: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:243: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:244: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:245: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:246: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:247: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:248: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress.cpp: In function 'void CheckCloud()':
In_Progress:412: error: 'Actinic_Channels' was not declared in this scope
In_Progress:418: error: 'PWMChannel' was not declared in this scope
In_Progress:449: error: 'Daylight_Channels' was not declared in this scope
In_Progress:451: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:453: error: 'Wire' was not declared in this scope
In_Progress:468: error: 'Daylight_Channels' was not declared in this scope
In_Progress:470: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:472: error: 'Wire' was not declared in this scope
In_Progress:499: error: 'Daylight_Channels' was not declared in this scope
In_Progress:501: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:503: error: 'Wire' was not declared in this scope
In_Progress:517: error: 'Daylight_Channels' was not declared in this scope
In_Progress:519: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:521: error: 'Wire' was not declared in this scope
In_Progress:536: error: jump to case label
In_Progress:491: error: crosses initialization of 'int a'
In_Progress:547: error: 'Daylight_Channels' was not declared in this scope
In_Progress:549: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:551: error: 'Wire' was not declared in this scope
In_Progress:565: error: 'Daylight_Channels' was not declared in this scope
In_Progress:567: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:569: error: 'Wire' was not declared in this scope
In_Progress:584: error: jump to case label
In_Progress:491: error: crosses initialization of 'int a'
In_Progress:595: error: 'Daylight_Channels' was not declared in this scope
In_Progress:598: error: 'Wire' was not declared in this scope
In_Progress:613: error: 'Daylight_Channels' was not declared in this scope
In_Progress:616: error: 'Wire' was not declared in this scope
In_Progress:628: error: jump to case label
In_Progress:491: error: crosses initialization of 'int a'
In_Progress:632: error: expected `}' before 'else'


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

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

There are several things I found wrong:
You must declare variables you are using above loop.

Code: Select all

int PWMChannel[16];
int DaylightPWMValue;
You can't use this:

Code: Select all

#define Start_Cloud_After NumMins(08,30)
#define End_Cloud_Before NumMins(19,00)
You must enter the number of minutes yourself instead of a formula. 510 and 1140 respectively.
We are using a define statement instead of a variable.
If you declare that as a variable above setup(), you could use a formula, but that just complicates everything. Just use the numbers.
The 16 channel uses a different function.
Change SetChannel to Set16Channel.

There is something wrong with the Mega2 section of your code. I removed it and was able to compile. I think there is an extra or missing bracket somewhere.
Roberto.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

Ahh.. The binary can't be used like that.
You must represent it as a decimal or hex number.
Just use a calculator to convert. I already showed the conversion to decimal of one of them in the previous post.
Roberto.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

I'm still getting all the same errors. I think its not taking the dev libraries correctly.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

OK, so I uninstalled reefangel, reinstalled, and redid the dev libraries and these are the errors I'm getting now:



The following features were automatically added:
Watchdog Timer
Version Menu

The following features were detected:
16 Channel Dimming Expansion Module
Dimming Signal
Wifi Attachment
Relay Expansion Module
2014 Main Screen
Extra Font - Medium Size (8x8 pixels)
pH Expansion Module
Number of Relay Expansion Modules: 1
Simple Menu
In_Progress.cpp:400:20: error: invalid digit "8" in octal constant
In_Progress.cpp:400:38: error: invalid digit "8" in octal constant
In_Progress.cpp:400:75: error: invalid digit "8" in octal constant
In_Progress.cpp:654:29: error: invalid digit "8" in octal constant
In_Progress.cpp:654:67: error: invalid digit "8" in octal constant
In_Progress.cpp:654:116: error: invalid digit "8" in octal constant
In_Progress.cpp:654:154: error: invalid digit "8" in octal constant
In_Progress.cpp:654:222: error: invalid digit "8" in octal constant
In_Progress.cpp: In function 'void loop()':
In_Progress:199: error: 'PWMChannel' was not declared in this scope
In_Progress:236: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:237: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:238: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:239: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:240: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:241: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:242: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:243: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:244: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:245: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:246: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:247: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:248: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:249: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:250: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress:251: error: 'class RA_PWMClass' has no member named 'SetChannel'
In_Progress.cpp: In function 'void CheckCloud()':
In_Progress:322: error: expected initializer before numeric constant
In_Progress:415: error: 'Actinic_Channels' was not declared in this scope
In_Progress:421: error: 'PWMChannel' was not declared in this scope
In_Progress:433: error: 'LightningModes' was not declared in this scope
In_Progress:452: error: 'Daylight_Channels' was not declared in this scope
In_Progress:454: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:456: error: 'Wire' was not declared in this scope
In_Progress:471: error: 'Daylight_Channels' was not declared in this scope
In_Progress:473: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:475: error: 'Wire' was not declared in this scope
In_Progress:502: error: 'Daylight_Channels' was not declared in this scope
In_Progress:504: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:506: error: 'Wire' was not declared in this scope
In_Progress:520: error: 'Daylight_Channels' was not declared in this scope
In_Progress:522: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:524: error: 'Wire' was not declared in this scope
In_Progress:539: error: jump to case label
In_Progress:494: error: crosses initialization of 'int a'
In_Progress:550: error: 'Daylight_Channels' was not declared in this scope
In_Progress:552: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:554: error: 'Wire' was not declared in this scope
In_Progress:568: error: 'Daylight_Channels' was not declared in this scope
In_Progress:570: error: 'DaylightPWMValue' was not declared in this scope
In_Progress:572: error: 'Wire' was not declared in this scope
In_Progress:587: error: jump to case label
In_Progress:494: error: crosses initialization of 'int a'
In_Progress:598: error: 'Daylight_Channels' was not declared in this scope
In_Progress:601: error: 'Wire' was not declared in this scope
In_Progress:616: error: 'Daylight_Channels' was not declared in this scope
In_Progress:619: error: 'Wire' was not declared in this scope
In_Progress:631: error: jump to case label
In_Progress:494: error: crosses initialization of 'int a'
In_Progress:635: error: expected `}' before 'else'





Were you not getting these errors when you compiled?

Thanks again.


Code: Select all


#include <ReefAngel_Features.h>

#include <Globals.h>

#include <RA_Wifi.h>

#include <Wire.h>

#include <OneWire.h>

#include <Time.h>

#include <DS1307RTC.h>

#include <InternalEEPROM.h>

#include <RA_NokiaLCD.h>

#include <RA_ATO.h>

#include <RA_Joystick.h>

#include <LED.h>

#include <RA_TempSensor.h>

#include <Relay.h>

#include <RA_PWM.h>

#include <Timer.h>

#include <Memory.h>

#include <InternalEEPROM.h>

#include <RA_Colors.h>

#include <RA_CustomColors.h>

#include <Salinity.h>

#include <RF.h>

#include <IO.h>

#include <ORP.h>

#include <AI.h>

#include <PH.h>

#include <WaterLevel.h>

#include <Humidity.h>

#include <DCPump.h>

#include <ReefAngel.h>





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





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

ReefAngel.AddPHExpansion();  
// pH Expansion Module
    

// Ports toggled in Feeding Mode
    
ReefAngel.FeedingModePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit | Port8Bit;
    
ReefAngel.FeedingModePortsE[0] = Port1Bit;
    

// Ports toggled in Water Change Mode
    
ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit | Port8Bit;
    
ReefAngel.WaterChangePortsE[0] = Port1Bit;
    

// Ports toggled when Lights On / Off menu entry selected
    
ReefAngel.LightsOnPorts = 0;
    
ReefAngel.LightsOnPortsE[0] = 0;
    

// Ports turned off when Overheat temperature exceeded
    
ReefAngel.OverheatShutoffPorts = Port2Bit | Port3Bit;
    
ReefAngel.OverheatShutoffPortsE[0] = 0;
    

// Use T1 probe as temperature and overheat functions
    
ReefAngel.TempProbe = T1_PROBE;
    
ReefAngel.OverheatProbe = T1_PROBE;
    

// Set the Overheat temperature setting
    
InternalMemory.OverheatTemp_write( 869 );


    

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


// Add support for 16 channel PWM board
ReefAngel.Add16ChPWM();


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

int PWMChannel[16];
int DaylightPWMValue;
////// Place additional initialization code above here

}

void loop()

{

ReefAngel.SingleATO( true,Port1,90,0 );
    
ReefAngel.StandardHeater( Port2,820,825 );
    
ReefAngel.StandardHeater( Port3,815,823 );
    
ReefAngel.WavemakerRandom( Port5,25,45 );
    
ReefAngel.WavemakerRandom( Port6,25,45 );
    
ReefAngel.StandardLights( Port7,21,0,7,0 );
    
ReefAngel.CO2Control( Port8,670,675 );
    
ReefAngel.DosingPumpRepeat( Box1_Port1,0,60,10 );
    



////// Place your custom code below here
    

    


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

    






//0 = White Far East
PWMChannel[0]=PWMParabola(8,0,20,30,0,80,0);
//1 = White Near East
PWMChannel[1]=PWMParabola(8,5,20,35,0,80,0);
//2 = White Near West
PWMChannel[2]=PWMParabola(8,10,20,40,0,80,0);
//3 = White Far West
PWMChannel[3]=PWMParabola(8,15,20,45,0,80,0);
//4 = Blue Far East
PWMChannel[4]=PWMParabola(7,15,21,15,0,80,0);
//5 = Blue Near East
PWMChannel[5]=PWMParabola(7,20,21,20,0,80,0);
//6 = Blue Near West
PWMChannel[6]=PWMParabola(7,25,21,25,0,80,0);
//7 = Blue Far West
PWMChannel[7]=PWMParabola(7,30,21,30,0,80,0);
//8 = OCW Far East
PWMChannel[8]=PWMParabola(8,15,20,15,0,60,0);
//9 = OCW Near East
PWMChannel[9]=PWMParabola(8,20,20,20,0,60,0);
//10 = OCW Near West
PWMChannel[10]=PWMParabola(8,25,20,25,0,60,0);
//11 = OCW Far West
PWMChannel[11]=PWMParabola(8,30,20,30,0,60,0);
//12 = Violets
PWMChannel[12]=PWMParabola(8,15,20,30,0,65,0);
//13 = Moonlight Far East
PWMChannel[13]=PWMParabola(20,15,8,30,0,15,0);
//14 = Moonlight Near East and West
PWMChannel[14]=PWMParabola(20,20,8,35,0,15,0);
//15 = Moonlight Far West
PWMChannel[15]=PWMParabola(20,25,8,40,0,15,0);



    
CheckCloud();

ReefAngel.PWM.SetChannel(0,PWMChannel[0]);
ReefAngel.PWM.SetChannel(1,PWMChannel[1]);
ReefAngel.PWM.SetChannel(2,PWMChannel[2]);
ReefAngel.PWM.SetChannel(3,PWMChannel[3]);
ReefAngel.PWM.SetChannel(3,PWMChannel[4]);
ReefAngel.PWM.SetChannel(3,PWMChannel[5]);
ReefAngel.PWM.SetChannel(3,PWMChannel[6]);
ReefAngel.PWM.SetChannel(3,PWMChannel[7]);
ReefAngel.PWM.SetChannel(3,PWMChannel[8]);
ReefAngel.PWM.SetChannel(3,PWMChannel[9]);
ReefAngel.PWM.SetChannel(3,PWMChannel[10]);
ReefAngel.PWM.SetChannel(3,PWMChannel[11]);
ReefAngel.PWM.SetChannel(3,PWMChannel[12]);
ReefAngel.PWM.SetChannel(3,PWMChannel[13]);
ReefAngel.PWM.SetChannel(3,PWMChannel[14]);
ReefAngel.PWM.SetChannel(3,PWMChannel[15]);









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



}









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

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

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

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

 // Minimum number of minutes for cloud duration. Don't use min 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 15

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

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

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

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

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

 // 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 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:  { 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[] = { Mega, Mega, Mega2, Calm, Calm, Fast };


 // 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))
    {
       // let's go through all channels to pick which ones will be dimmed
       for (int a=0;a<16;a++)
       {
          if (bitRead(Actinic_Channels,a)==0)
          {
             // this will slope down the DAYLIGHT channels from the current PWM to 0 within 3 minutes.
             // then it will stay at 0 for the duration of the cycle
             // and finally slope up from 0 to PWM value within 3 minutes
             // it is basically an inversed slope
             PWMChannel[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[a],0,180);
          }
       }




int newdata=4095;
byte channel=0;
      
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)
        {
          int a=random(1,5);    // Pick a number of consecutive flashes from 1 to 4.  
          for (int i=0; i<a; i++)
          {
            
      for (int g=0;g<16;g++)
       {
      
      if (bitRead(Daylight_Channels,g)==1)
       {
      newdata=random(DaylightPWMValue*40.95, 4095);
          channel=g;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          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
        
       for (int h=0;h<16;h++)
       {
      
      if (bitRead(Daylight_Channels,h)==1)
       {
      newdata=DaylightPWMValue*40.95;
          channel=h;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          Wire.endTransmission();
      }
      }

            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++)
          {


      for (int k=0;k<16;k++)
       {
      
      if (bitRead(Daylight_Channels,k)==1)
       {
      newdata=random(DaylightPWMValue*40.95, 4095);
          channel=k;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          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

      for (int l=0;l<16;l++)
       {
      
      if (bitRead(Daylight_Channels,l)==1)
       {
      newdata=DaylightPWMValue*40.95;
          channel=l;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          Wire.endTransmission();
      }
      }

            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++)
          {

            for (int e=0;e<16;e++)
       {
      
      if (bitRead(Daylight_Channels,e)==1)
       {
      newdata=random(DaylightPWMValue*40.95, 4095);
          channel=e;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          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
            
       for (int f=0;f<16;f++)
       {
      
      if (bitRead(Daylight_Channels,f)==1)
       {
      newdata=DaylightPWMValue*40.95;
          channel=f;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          Wire.endTransmission();
      }
      }

            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)
          {
            newdata=4095;
      for (int c=0;c<16;c++)
       {
      if (bitRead(Daylight_Channels,c)==1)
          {
         channel=c;
             Wire.beginTransmission(0x41);
             Wire.write(0x8+(4*channel));
             Wire.write(newdata&0xff);
             Wire.write(newdata>>8);
             Wire.endTransmission();   
         }   
      }
      
          }
          else 
          {
           
      newdata=0;
      for (int d=0;d<16;d++)
       {
      if (bitRead(Daylight_Channels,d)==1)
          {
         channel=d;
             Wire.beginTransmission(0x41);
             Wire.write(0x8+(4*channel));
             Wire.write(newdata&0xff);
             Wire.write(newdata>>8);
             Wire.endTransmission();   
         }   
      }

          }
          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.
if (LastNumMins!=NumMins(hour(),minute()))
 {
    LastNumMins=NumMins(hour(),minute());
    ReefAngel.LCD.Clear(255,0,120,132,132);
    ReefAngel.LCD.DrawText(0,255,5,120,"C");
    ReefAngel.LCD.DrawText(0,255,11,120,"00:00");
    ReefAngel.LCD.DrawText(0,255,45,120,"L");
    ReefAngel.LCD.DrawText(0,255,51,120,"00:00");
    
   if (cloudchance && (NumMins(hour(),minute())<cloudstart))
    {
       int x=0;
       if ((cloudstart/60)>=10) x=11; 
      else x=17;
       ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart/60));
       if ((cloudstart%60)>=10) x=29; 
      else x=35;
 ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart%60));
 }
 ReefAngel.LCD.DrawText(0,255,90,120,cloudduration);
 if (lightningchance) 
 {
 int x=0;
 if (((cloudstart+(cloudduration/2))/60)>=10) x=51; 
 else x=57;
 ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))/60));
 if (((cloudstart+(cloudduration/2))%60)>=10) x=69; 
 else x=75;
 ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))%60));
 }
 } 
}

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

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by lnevo »

Which libraries folder are you replacing? What is the full path?

There's one thats for the arduino app/executables and another for the ra libraries.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

I was, but I mentioned already what I did to fix the problem a couple posts above.
Roberto.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

I replaced the libraries folder in my documents and in program files/reefangel.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

Not that.
You need to declare the undeclared variables, you need to change the 16 bit binary number to a decimal and several other things I already mentioned throughout the post.
Please read back the previous posts and make those changes.
Roberto.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

I did the undeclared variables (unless I put them in the wrong place) as for the decimal thing I'm not understanding. Is that because it is 16 bits? The original code was written that way. You can see my updated code a couple posts back.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

Arduino libraries only have declarations for 8 bit binary numbers.
So, if you are trying to use 16bit, you must declare it as decimal or hexadecimal instead of binary.
Just use a calculator or online conversion like this: http://acc6.its.brooklyn.cuny.edu/~gurw ... 2tool.html
Roberto.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

Ok, I understand why now.

I am still getting all the same errors though.

I changed the

#define Actinic_Channels B0000111100000000
and
#define Daylight_Channels B1111000000000000


to

#define Actinic_Channels 384
and
#define Daylight_Channels 61440

I also have

int PWMChannel[16];
int DaylightPWMValue;

in void setup


Could you explain the NumMins thing? That also was copied from the original code. Sorry, it just helps me to understand why things are being done and what they're doing.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

The variable declarations can't be in setup()
It has to be above it or it will only be usable inside setup()
Since you are using them globally, you must declare them globally, which is above setup()

You can't use a function when you are declaring something as a #declare.
#declare is nothing more than an alias.
The compiler goes and changes every reference you have of the #declare to the number you declared. So, you can't use a function.
The exception is if you #declare it as a function too.
So, you either have to use this:

Code: Select all

#declare Start_Cloud_After 510
Or like this:

Code: Select all

#define Start_Cloud_After(h,m) NumMins(h,m)
And when you call it, you must call it like this:

Code: Select all

Start_Cloud_After(8,30)
Which just complicates things to read. Just use the first option. Much easier to read. Why complicate when it is so simple, right?
Roberto.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

OK, thanks for all your help! I got it to finally compile. Now its time to work on the other features.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

So now I'm trying to make the clouds start in the east and move to the west. I think I have it set up right. It compiles ok, but does this look like it will do what I'm trying to get it to do?

If this looks good, then I'm going to have it randomly choose to start in the east or west.

This is just the section I changed. I also of course declared my variables above like this:

static time_t DelayCount=millis();
static int DelayTiming1=2000;
static int DelayTiming2=4000;
static int DelayTiming3=6000;


Code: Select all

        //dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[0],0,60);      
        PWMChannel[8]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[8],0,60); 
    
        //delay 2 seconds before starting next dimming
        DelayCount=millis();
        DelayTiming1=2000;
        
        if((millis()-DelayCount)>DelayTiming1)
        {
        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming1,PWMChannel[1],0,60);     
        PWMChannel[9]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming1,PWMChannel[9],0,60); 
        }
       
        DelayTiming2=4000;
        
        if((millis()-DelayCount)>DelayTiming2)
        {
        //dim down the near west channels
        PWMChannel[2]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming2,PWMChannel[2],0,60);     
        PWMChannel[10]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming2,PWMChannel[10],0,60);
        }
        
        DelayTiming3=6000;
        
        if((millis()-DelayCount)>DelayTiming3)
        {
        //dim down the far west channels
        PWMChannel[3]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming3,PWMChannel[3],0,60);     
        PWMChannel[11]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming3,PWMChannel[11],0,60);        
        }
      
     // let's go through all channels to pick which ones will be dimmed
      
/////////////////////////////////////////////////////////////////////////////////////////// 
/* 
      
////////                          replacing this with above                         ////////
     
       for (int a=0;a<16;a++)
       {
          if (bitRead(Actinic_Channels,a)==0)
          {
             // this will slope down the DAYLIGHT channels from the current PWM to 0 within 1 minutes.
             // then it will stay at 0 for the duration of the cycle
             // and finally slope up from 0 to PWM value within 1 minutes
             // it is basically an inversed slope
             PWMChannel[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[a],0,60);
          }
       }

*/
///////////////////////////////////////////////////////////////////////////////////////////////

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

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

This will never work:

Code: Select all

        DelayCount=millis();
        if((millis()-DelayCount)>DelayTiming1)
You are basically assigning DelayCount=millis(); and right after you are checking if the difference in time is > than your DelayTiming1. It will never happen.
You have to assign DelayCount when the cloud starts and not all the time.
Roberto.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

Oh yeah, I see that now, but I'm not sure exactly where to place it... Would this be right?

Code: Select all

 if (cloudchance)
 {
    //is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
        DelayCount=millis();
      
        //dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[0],0,60);      
        PWMChannel[8]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[8],0,60); 
               
        if((millis()-DelayCount)>DelayTiming1)
        {
        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming1,PWMChannel[1],0,60);     
        PWMChannel[9]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming1,PWMChannel[9],0,60); 
        }
             
        if((millis()-DelayCount)>DelayTiming2)
        {
        //dim down the near west channels
        PWMChannel[2]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming2,PWMChannel[2],0,60);     
        PWMChannel[10]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming2,PWMChannel[10],0,60);
        }
        
        if((millis()-DelayCount)>DelayTiming3)
        {
        //dim down the far west channels
        PWMChannel[3]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming3,PWMChannel[3],0,60);     
        PWMChannel[11]=ReversePWMSlope(cloudstart,cloudstart+cloudduration+DelayTiming3,PWMChannel[11],0,60);        
        }
      
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

...or maybe its not needed there at all. I have it declared above at the beginning of checkcloud():

static time_t DelayCount=millis();
static int DelayTiming1=2000;
static int DelayTiming2=4000;
static int DelayTiming3=6000;
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

You already had the code and the idea in place already... :)
You were just missing the same delay for when the cloud starts.
You need to have it offset by the start and duration.
Try something like this:

Code: Select all

      //dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[0],0,60);      
        PWMChannel[8]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[8],0,60); 
        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[1],0,60);     
        PWMChannel[9]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[9],0,60); 
[code]
Roberto.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

Oh duh.... That makes sense.

So this is my code so far. I made that change and added in a random effect for the speed of clouds. The next thing I'm going to work on (if this looks good) is that I would like to have it to where on the fast clouds, there would be no lightning and the cloud would not last long; maybe a minute or two at most.

Code: Select all

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

////// Place global variable code below here
int PWMChannel[16];
int DaylightPWMValue;
////// 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 
    

ReefAngel.AddPHExpansion();  
// pH Expansion Module
    

// Ports toggled in Feeding Mode
    
ReefAngel.FeedingModePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit | Port8Bit;
    
ReefAngel.FeedingModePortsE[0] = Port1Bit;
    

// Ports toggled in Water Change Mode
    
ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit | Port8Bit;
    
ReefAngel.WaterChangePortsE[0] = Port1Bit;
    

// Ports toggled when Lights On / Off menu entry selected
    
ReefAngel.LightsOnPorts = 0;
    
ReefAngel.LightsOnPortsE[0] = 0;
    

// Ports turned off when Overheat temperature exceeded
    
ReefAngel.OverheatShutoffPorts = Port2Bit | Port3Bit;
    
ReefAngel.OverheatShutoffPortsE[0] = 0;
    

// Use T1 probe as temperature and overheat functions
    
ReefAngel.TempProbe = T1_PROBE;
    
ReefAngel.OverheatProbe = T1_PROBE;
    

// Set the Overheat temperature setting
    
InternalMemory.OverheatTemp_write( 869 );


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


// Add support for 16 channel PWM board
ReefAngel.Add16ChPWM();


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

}

void loop()

{

ReefAngel.SingleATO( true,Port1,90,0 );
    
ReefAngel.StandardHeater( Port2,820,825 );
    
ReefAngel.StandardHeater( Port3,815,823 );
    
ReefAngel.WavemakerRandom( Port5,25,45 );
    
ReefAngel.WavemakerRandom( Port6,25,45 );
    
ReefAngel.StandardLights( Port7,21,0,7,0 );
    
ReefAngel.CO2Control( Port8,670,675 );
    
ReefAngel.DosingPumpRepeat( Box1_Port1,0,60,10 );
    

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


//0 = White Far East
PWMChannel[0]=PWMParabola(8,0,20,30,0,80,0);
//1 = White Near East
PWMChannel[1]=PWMParabola(8,5,20,35,0,80,0);
//2 = White Near West
PWMChannel[2]=PWMParabola(8,10,20,40,0,80,0);
//3 = White Far West
PWMChannel[3]=PWMParabola(8,15,20,45,0,80,0);
//4 = Blue Far East
PWMChannel[4]=PWMParabola(7,15,21,15,0,80,0);
//5 = Blue Near East
PWMChannel[5]=PWMParabola(7,20,21,20,0,80,0);
//6 = Blue Near West
PWMChannel[6]=PWMParabola(7,25,21,25,0,80,0);
//7 = Blue Far West
PWMChannel[7]=PWMParabola(7,30,21,30,0,80,0);
//8 = OCW Far East
PWMChannel[8]=PWMParabola(8,15,20,15,0,60,0);
//9 = OCW Near East
PWMChannel[9]=PWMParabola(8,20,20,20,0,60,0);
//10 = OCW Near West
PWMChannel[10]=PWMParabola(8,25,20,25,0,60,0);
//11 = OCW Far West
PWMChannel[11]=PWMParabola(8,30,20,30,0,60,0);
//12 = Violets
PWMChannel[12]=PWMParabola(8,15,20,30,0,65,0);
//13 = Moonlight Far East
PWMChannel[13]=PWMParabola(20,15,8,30,0,15,0);
//14 = Moonlight Near East and West
PWMChannel[14]=PWMParabola(20,20,8,35,0,15,0);
//15 = Moonlight Far West
PWMChannel[15]=PWMParabola(20,25,8,40,0,15,0);
   
CheckCloud();

ReefAngel.PWM.Set16Channel(0,PWMChannel[0]);
ReefAngel.PWM.Set16Channel(1,PWMChannel[1]);
ReefAngel.PWM.Set16Channel(2,PWMChannel[2]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[3]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[4]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[5]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[6]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[7]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[8]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[9]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[10]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[11]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[12]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[13]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[14]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[15]);

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

}


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

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

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

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

 // Minimum number of minutes for cloud duration. Don't use min 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 15

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

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

 // Always end the cloud effect before this setting
 // In this example, end could before 7:00pm
#define End_Cloud_Before 1140

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

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

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

 // 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 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:  { 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[] = { Mega, Mega, Mega2, Calm, Calm, Fast };

   // Add Random Cloud modes
#define FastEast 0  //Short cloud coming from the east
#define FastWest 1  //Short cloud coming from the west
#define SlowEast 2  //Long cloud coming from the east
#define SlowWest 3  //Long cloud coming from the west
  // Set which modes you want to use
  //Example:  {FastEast, FastWest, SlowEast, SlowWest } to randomize all four modes
  byte CloudModes[] = { FastEast, FastWest, FastEast, FastWest, SlowEast, SlowWest };



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

 static time_t DelayCounter=millis();    // Variable for lightning timing.  
 static int DelayTime=random(1000);      // Variable for lightning timimg.
 static time_t DelayCount=millis();
 static int DelayTiming1=2000;
 static int DelayTiming2=4000;
 static int DelayTiming3=6000;



 // 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))
    {
       
	if (chooseCloud)
		{
		cloudMode=CloudModes[random(100)%sizeof(CloudModes)];
		chooseCloud=false;
		}


	switch (cloudMode)
	{

	case FastEast;
	{

	//dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[0],0,20);      
        PWMChannel[8]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[8],0,20); 
        
        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[1],0,20);     
        PWMChannel[9]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[9],0,20); 
     
        //dim down the near west channels
        PWMChannel[2]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[2],0,20);     
        PWMChannel[10]=ReversePWMSlope(cloudstartDelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[10],0,20);  
     
        //dim down the far west channels
        PWMChannel[3]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[3],0,20);     
        PWMChannel[11]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[11],0,20);        
      
	break;
	}

	case FastWest;
	{

	//dim down the far west channels
        PWMChannel[3]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[3],0,20);      
        PWMChannel[11]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[11],0,20); 
        
        //dim down the near west channels
        PWMChannel[2]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[2],0,20);     
        PWMChannel[10]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[10],0,20); 
       
        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[1],0,20);     
        PWMChannel[9]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[9],0,20);       

        //dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[0],0,20);     
        PWMChannel[8]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[8],0,20);        
        
	break;
	}


	case SlowEast;
	{

	//dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[0],0,180);      
        PWMChannel[8]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[8],0,180); 
        
        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[1],0,180);     
        PWMChannel[9]=ReversePWMSlope(cloudstart+DelayTIming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[9],0,180); 
        
        //dim down the near west channels
        PWMChannel[2]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[2],0,180);     
        PWMChannel[10]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[10],0,180);

        //dim down the far west channels
        PWMChannel[3]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[3],0,180);     
        PWMChannel[11]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[11],0,180);        
      
	break;
	}

	case SlowWest;
	{

	//dim down the far west channels
        PWMChannel[3]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[3],0,180);      
        PWMChannel[11]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[11],0,180); 

        //dim down the near west channels
        PWMChannel[2]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[2],0,180);     
        PWMChannel[10]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[10],0,180); 

        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[1],0,180);     
        PWMChannel[9]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[9],0,180);

        //dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[0],0,180);     
        PWMChannel[8]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[8],0,180);        	

	break;
	}

	}

	else 
   	{
   	  chooseCloud=true; // Reset the flag to choose a new cloud type
    	}
      


int newdata=4095;
byte channel=0;
      
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 (lightning		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++)
          {
            for (int g=0;g<16;g++)
            {
      
              if (bitRead(Daylight_Channels,g)==1)
               {
                  newdata=random(DaylightPWMValue*40.95, 4095);
                  channel=g;
                  Wire.beginTransmission(0x41);
                  Wire.write(0x8+(4*channel));
                  Wire.write(newdata&0xff);
                  Wire.write(newdata>>8);
                  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
        
             for (int h=0;h<16;h++)
             {
      
                if (bitRead(Daylight_Channels,h)==1)
                 {
                    newdata=DaylightPWMValue*40.95;
                    channel=h;
                    Wire.beginTransmission(0x41);
                    Wire.write(0x8+(4*channel));
                    Wire.write(newdata&0xff);
                    Wire.write(newdata>>8);
                    Wire.endTransmission();
                  }
              }

            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++)
          {


      for (int k=0;k<16;k++)
       {
      
      if (bitRead(Daylight_Channels,k)==1)
       {
      newdata=random(DaylightPWMValue*40.95, 4095);
          channel=k;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          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

      for (int l=0;l<16;l++)
       {
      
      if (bitRead(Daylight_Channels,l)==1)
       {
      newdata=DaylightPWMValue*40.95;
          channel=l;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          Wire.endTransmission();
      }
      }

            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++)
          {

            for (int e=0;e<16;e++)
       {
      
      if (bitRead(Daylight_Channels,e)==1)
       {
      newdata=random(DaylightPWMValue*40.95, 4095);
          channel=e;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          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
            
       for (int f=0;f<16;f++)
       {
      
      if (bitRead(Daylight_Channels,f)==1)
       {
      newdata=DaylightPWMValue*40.95;
          channel=f;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          Wire.endTransmission();
      }
      }

            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)
          {
            newdata=4095;
      for (int c=0;c<16;c++)
       {
      if (bitRead(Daylight_Channels,c)==1)
          {
         channel=c;
             Wire.beginTransmission(0x41);
             Wire.write(0x8+(4*channel));
             Wire.write(newdata&0xff);
             Wire.write(newdata>>8);
             Wire.endTransmission();   
         }   
          }
          }
          }
          else 
          {
           
      newdata=0;
      for (int d=0;d<16;d++)
       {
      if (bitRead(Daylight_Channels,d)==1)
          {
         channel=d;
             Wire.beginTransmission(0x41);
             Wire.write(0x8+(4*channel));
             Wire.write(newdata&0xff);
             Wire.write(newdata>>8);
             Wire.endTransmission();   
         }   
      }

          }
          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.
if (LastNumMins!=NumMins(hour(),minute()))
 {
    LastNumMins=NumMins(hour(),minute());
    ReefAngel.LCD.Clear(255,0,120,132,132);
    ReefAngel.LCD.DrawText(0,255,5,120,"C");
    ReefAngel.LCD.DrawText(0,255,11,120,"00:00");
    ReefAngel.LCD.DrawText(0,255,45,120,"L");
    ReefAngel.LCD.DrawText(0,255,51,120,"00:00");
    
   if (cloudchance && (NumMins(hour(),minute())<cloudstart))
    {
       int x=0;
       if ((cloudstart/60)>=10) x=11; 
      else x=17;
       ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart/60));
       if ((cloudstart%60)>=10) x=29; 
      else x=35;
 ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart%60));
 }
 ReefAngel.LCD.DrawText(0,255,90,120,cloudduration);
 if (lightningchance) 
 {
 int x=0;
 if (((cloudstart+(cloudduration/2))/60)>=10) x=51; 
 else x=57;
 ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))/60));
 if (((cloudstart+(cloudduration/2))%60)>=10) x=69; 
 else x=75;
 ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))%60));
 }
 } 
}


byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
 long n=elapsedSecsToday(now());
 cstart*=60;
 cend*=60;
 if (n<cstart) return PWMStart;
 if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
 if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
 if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
 if (n>cend) return PWMStart;
}
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

So I haven't had a lot of time to work on this, but I think I have it doing most of what I want as far as the clouds go. My code is posted below. I do have a few concerns though. Is my code using 12-bit resolution for the dimming for light cycles as well as for clouds? When it is dimming for the clouds how quickly is it sending new data to the dimming expansion (once a second, minute, etc)?
Also, how would I be able to change the shortcloudduration to seconds instead of minutes?


Code: Select all

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

////// Place global variable code below here
int PWMChannel[16];
int DaylightPWMValue;
////// 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 
    

ReefAngel.AddPHExpansion();  
// pH Expansion Module
    

// Ports toggled in Feeding Mode
    
ReefAngel.FeedingModePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit | Port8Bit;
    
ReefAngel.FeedingModePortsE[0] = Port1Bit;
    

// Ports toggled in Water Change Mode
    
ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit | Port8Bit;
    
ReefAngel.WaterChangePortsE[0] = Port1Bit;
    

// Ports toggled when Lights On / Off menu entry selected
    
ReefAngel.LightsOnPorts = 0;
    
ReefAngel.LightsOnPortsE[0] = 0;
    

// Ports turned off when Overheat temperature exceeded
    
ReefAngel.OverheatShutoffPorts = Port2Bit | Port3Bit;
    
ReefAngel.OverheatShutoffPortsE[0] = 0;
    

// Use T1 probe as temperature and overheat functions
    
ReefAngel.TempProbe = T1_PROBE;
    
ReefAngel.OverheatProbe = T1_PROBE;
    

// Set the Overheat temperature setting
    
InternalMemory.OverheatTemp_write( 869 );


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


// Add support for 16 channel PWM board
ReefAngel.Add16ChPWM();


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

}

void loop()

{

ReefAngel.SingleATO( true,Port1,90,0 );
    
ReefAngel.StandardHeater( Port2,820,825 );
    
ReefAngel.StandardHeater( Port3,815,823 );
    
ReefAngel.WavemakerRandom( Port5,25,45 );
    
ReefAngel.WavemakerRandom( Port6,25,45 );
    
ReefAngel.StandardLights( Port7,21,0,7,0 );
    
ReefAngel.CO2Control( Port8,670,675 );
    
ReefAngel.DosingPumpRepeat( Box1_Port1,0,60,10 );
    

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


//0 = White Far East
PWMChannel[0]=PWMParabola(8,0,20,30,0,80,0);
//1 = White Near East
PWMChannel[1]=PWMParabola(8,5,20,35,0,80,0);
//2 = White Near West
PWMChannel[2]=PWMParabola(8,10,20,40,0,80,0);
//3 = White Far West
PWMChannel[3]=PWMParabola(8,15,20,45,0,80,0);
//4 = Blue Far East
PWMChannel[4]=PWMParabola(7,15,21,15,0,80,0);
//5 = Blue Near East
PWMChannel[5]=PWMParabola(7,20,21,20,0,80,0);
//6 = Blue Near West
PWMChannel[6]=PWMParabola(7,25,21,25,0,80,0);
//7 = Blue Far West
PWMChannel[7]=PWMParabola(7,30,21,30,0,80,0);
//8 = OCW Far East
PWMChannel[8]=PWMParabola(8,15,20,15,0,60,0);
//9 = OCW Near East
PWMChannel[9]=PWMParabola(8,20,20,20,0,60,0);
//10 = OCW Near West
PWMChannel[10]=PWMParabola(8,25,20,25,0,60,0);
//11 = OCW Far West
PWMChannel[11]=PWMParabola(8,30,20,30,0,60,0);
//12 = Violets
PWMChannel[12]=PWMParabola(8,15,20,30,0,65,0);
//13 = Moonlight Far East
PWMChannel[13]=PWMParabola(20,15,8,30,0,15,0);
//14 = Moonlight Near East and West
PWMChannel[14]=PWMParabola(20,20,8,35,0,15,0);
//15 = Moonlight Far West
PWMChannel[15]=PWMParabola(20,25,8,40,0,15,0);
   
CheckCloud();

ReefAngel.PWM.Set16Channel(0,PWMChannel[0]);
ReefAngel.PWM.Set16Channel(1,PWMChannel[1]);
ReefAngel.PWM.Set16Channel(2,PWMChannel[2]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[3]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[4]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[5]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[6]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[7]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[8]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[9]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[10]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[11]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[12]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[13]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[14]);
ReefAngel.PWM.Set16Channel(3,PWMChannel[15]);

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

}


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

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

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

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

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

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

 // Minimum number of minutes for short cloud duration.
#define Min_ShortCloud_Duration 1

 // Maximum number of minutes for short cloud duration.
#define Max_ShortCloud_Duration 2

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

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

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

 // Only start the cloud effect after this setting
 // In this example, start could after 8:30am (in minutes since midnight)
#define Start_Cloud_After 510

 // Always end the cloud effect before this setting
 // In this example, end could before 7:00pm (in minutes since midnight)
#define End_Cloud_Before 1140

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

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

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

 // 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 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 lightning 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[] = { Mega, Mega, Mega2, Calm, Calm, Fast };

   // Add Random Cloud modes
#define FastEast 0  //Short cloud coming from the east - No Lightning
#define FastWest 1  //Short cloud coming from the west - No Lightning
#define SlowEast 2  //Long cloud coming from the east - Chance of Lightning
#define SlowWest 3  //Long cloud coming from the west - Chance of Lightning
  
  // Set which cloud modes you want to use
  //Example:  {FastEast, FastWest, SlowEast, SlowWest } to randomize all four modes
  byte CloudModes[] = { FastEast, FastWest, FastEast, FastWest, FastEast, FastWest, SlowEast, SlowWest };



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

 static time_t DelayCounter=millis();    // Variable for lightning timing.  
 static int DelayTime=random(1000);      // Variable for lightning timimg.
 static time_t DelayCount=millis();
 static int DelayTiming1=2000;
 static int DelayTiming2=4000;
 static int DelayTiming3=6000;



 // 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 for the short cloud duration
 shortcloudduration=random(Min_ShortCloud_Duration,Max_ShortCloud_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))
    {
       
	if (chooseCloud)
		{
		cloudMode=CloudModes[random(100)%sizeof(CloudModes)];
		chooseCloud=false;
		}


	switch (cloudMode)
	{

	case FastEast;
	{

	//dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart,cloudstart+shortcloudduration,PWMChannel[0],0,20);      
        PWMChannel[8]=ReversePWMSlope(cloudstart,cloudstart+shortcloudduration,PWMChannel[8],0,20); 
        
        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+shortcloudduration+DelayTiming1,PWMChannel[1],0,20);     
        PWMChannel[9]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+shortcloudduration+DelayTiming1,PWMChannel[9],0,20); 
     
        //dim down the near west channels
        PWMChannel[2]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+shortcloudduration+DelayTiming2,PWMChannel[2],0,20);     
        PWMChannel[10]=ReversePWMSlope(cloudstartDelayTiming2,cloudstart+shortcloudduration+DelayTiming2,PWMChannel[10],0,20);  
     
        //dim down the far west channels
        PWMChannel[3]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+shortcloudduration+DelayTiming3,PWMChannel[3],0,20);     
        PWMChannel[11]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+shortcloudduration+DelayTiming3,PWMChannel[11],0,20);        
      
	chooseLightning=false; 

	break;
	}

	case FastWest;
	{

	//dim down the far west channels
        PWMChannel[3]=ReversePWMSlope(cloudstart,cloudstart+shortcloudduration,PWMChannel[3],0,20);      
        PWMChannel[11]=ReversePWMSlope(cloudstart,cloudstart+shortcloudduration,PWMChannel[11],0,20); 
        
        //dim down the near west channels
        PWMChannel[2]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+shortcloudduration+DelayTiming1,PWMChannel[2],0,20);     
        PWMChannel[10]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+shortcloudduration+DelayTiming1,PWMChannel[10],0,20); 
       
        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+shortcloudduration+DelayTiming2,PWMChannel[1],0,20);     
        PWMChannel[9]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+shortcloudduration+DelayTiming2,PWMChannel[9],0,20);       

        //dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+shortcloudduration+DelayTiming3,PWMChannel[0],0,20);     
        PWMChannel[8]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+shortcloudduration+DelayTiming3,PWMChannel[8],0,20);        
        
	chooseLightning=false; 

	break;
	}


	case SlowEast;
	{

	//dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[0],0,180);      
        PWMChannel[8]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[8],0,180); 
        
        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[1],0,180);     
        PWMChannel[9]=ReversePWMSlope(cloudstart+DelayTIming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[9],0,180); 
        
        //dim down the near west channels
        PWMChannel[2]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[2],0,180);     
        PWMChannel[10]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[10],0,180);

        //dim down the far west channels
        PWMChannel[3]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[3],0,180);     
        PWMChannel[11]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[11],0,180);        
      
	break;
	}

	case SlowWest;
	{

	//dim down the far west channels
        PWMChannel[3]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[3],0,180);      
        PWMChannel[11]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[11],0,180); 

        //dim down the near west channels
        PWMChannel[2]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[2],0,180);     
        PWMChannel[10]=ReversePWMSlope(cloudstart+DelayTiming1,cloudstart+cloudduration+DelayTiming1,PWMChannel[10],0,180); 

        //dim down the near east channels
        PWMChannel[1]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[1],0,180);     
        PWMChannel[9]=ReversePWMSlope(cloudstart+DelayTiming2,cloudstart+cloudduration+DelayTiming2,PWMChannel[9],0,180);

        //dim down the far east channels
        PWMChannel[0]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[0],0,180);     
        PWMChannel[8]=ReversePWMSlope(cloudstart+DelayTiming3,cloudstart+cloudduration+DelayTiming3,PWMChannel[8],0,180);        	

	break;
	}

	}

	else 
   	{
   	  chooseCloud=true; // Reset the flag to choose a new cloud type
    	}
      


int newdata=4095;
byte channel=0;
      
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)
        {
          int a=random(1,5); // Pick a number of consecutive flashes from 1 to 4.  
          for (int i=0; i<a; i++)
          {
            for (int g=0;g<16;g++)
            {
      
              if (bitRead(Daylight_Channels,g)==1)
               {
                  newdata=random(DaylightPWMValue*40.95, 4095);
                  channel=g;
                  Wire.beginTransmission(0x41);
                  Wire.write(0x8+(4*channel));
                  Wire.write(newdata&0xff);
                  Wire.write(newdata>>8);
                  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
        
             for (int h=0;h<16;h++)
             {
      
                if (bitRead(Daylight_Channels,h)==1)
                 {
                    newdata=DaylightPWMValue*40.95;
                    channel=h;
                    Wire.beginTransmission(0x41);
                    Wire.write(0x8+(4*channel));
                    Wire.write(newdata&0xff);
                    Wire.write(newdata>>8);
                    Wire.endTransmission();
                  }
              }

            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++)
          {


      for (int k=0;k<16;k++)
       {
      
      if (bitRead(Daylight_Channels,k)==1)
       {
      newdata=random(DaylightPWMValue*40.95, 4095);
          channel=k;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          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

      for (int l=0;l<16;l++)
       {
      
      if (bitRead(Daylight_Channels,l)==1)
       {
      newdata=DaylightPWMValue*40.95;
          channel=l;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          Wire.endTransmission();
      }
      }

            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++)
          {

            for (int e=0;e<16;e++)
       {
      
      if (bitRead(Daylight_Channels,e)==1)
       {
      newdata=random(DaylightPWMValue*40.95, 4095);
          channel=e;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          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
            
       for (int f=0;f<16;f++)
       {
      
      if (bitRead(Daylight_Channels,f)==1)
       {
      newdata=DaylightPWMValue*40.95;
          channel=f;
          Wire.beginTransmission(0x41);
          Wire.write(0x8+(4*channel));
          Wire.write(newdata&0xff);
          Wire.write(newdata>>8);
          Wire.endTransmission();
      }
      }

            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)
          {
            newdata=4095;
      for (int c=0;c<16;c++)
       {
      if (bitRead(Daylight_Channels,c)==1)
          {
         channel=c;
             Wire.beginTransmission(0x41);
             Wire.write(0x8+(4*channel));
             Wire.write(newdata&0xff);
             Wire.write(newdata>>8);
             Wire.endTransmission();   
         }   
          }
          }
          }
          else 
          {
           
      newdata=0;
      for (int d=0;d<16;d++)
       {
      if (bitRead(Daylight_Channels,d)==1)
          {
         channel=d;
             Wire.beginTransmission(0x41);
             Wire.write(0x8+(4*channel));
             Wire.write(newdata&0xff);
             Wire.write(newdata>>8);
             Wire.endTransmission();   
         }   
      }

          }
          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
 	  // pick a random number for the short cloud duration
 	  shortcloudduration=random(Min_ShortCloud_Duration,Max_ShortCloud_Duration);
          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.
if (LastNumMins!=NumMins(hour(),minute()))
 {
    LastNumMins=NumMins(hour(),minute());
    ReefAngel.LCD.Clear(255,0,120,132,132);
    ReefAngel.LCD.DrawText(0,255,5,120,"C");
    ReefAngel.LCD.DrawText(0,255,11,120,"00:00");
    ReefAngel.LCD.DrawText(0,255,45,120,"L");
    ReefAngel.LCD.DrawText(0,255,51,120,"00:00");
    
   if (cloudchance && (NumMins(hour(),minute())<cloudstart))
    {
       int x=0;
       if ((cloudstart/60)>=10) x=11; 
      else x=17;
       ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart/60));
       if ((cloudstart%60)>=10) x=29; 
      else x=35;
 ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart%60));
 }
 ReefAngel.LCD.DrawText(0,255,90,120,cloudduration);
 if (lightningchance) 
 {
 int x=0;
 if (((cloudstart+(cloudduration/2))/60)>=10) x=51; 
 else x=57;
 ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))/60));
 if (((cloudstart+(cloudduration/2))%60)>=10) x=69; 
 else x=75;
 ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))%60));
 }
 } 
}


byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
 long n=elapsedSecsToday(now());
 cstart*=60;
 cend*=60;
 if (n<cstart) return PWMStart;
 if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
 if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
 if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
 if (n>cend) return PWMStart;
}
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

When dimming for the clouds, it sends data every second.
When dimming on regular parabola, it sends once a minute.
Yu would have to change the entire logic to make it in seconds, but when a cloud is activated it takes 20 seconds to ramp down and 20 seconds to ramp up. That's already 40 seconds as it is.
Unless you were planning to have a really fast ramp up/down, the benefit to refactor the entire code is not worth it.
Roberto.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

What I'm trying to recreate is the clouds that you see on a sunny day that are small and pass by really quickly.
The sun dims down very quickly, like in 1-2 seconds and the cloud may last for 5-30 seconds, and then the sun comes back just as quick.

Also, unless its a really slow dimming, the full 12-bit resolution is not being used if it is just updating once a minute (or once a second for the clouds).

Which parts would have to be changed?
Would this be too taxing for the controller?


Thanks!
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by AlanM »

rimai wrote:When dimming for the clouds, it sends data every second.
When dimming on regular parabola, it sends once a minute.
Yu would have to change the entire logic to make it in seconds, but when a cloud is activated it takes 20 seconds to ramp down and 20 seconds to ramp up. That's already 40 seconds as it is.
Unless you were planning to have a really fast ramp up/down, the benefit to refactor the entire code is not worth it.
I hven't been following the whole thread, but if you use ReefAngel.PWM.PWMParabola functions, they now use the HighRes versions and send once per second in the dev libraries. If you're calling PWMParabola directly from Globals then you can instead call PWMParabolaHighRes and get values once per second.

The output is different, though. In both of them you give an input of startPWM and endPWM as a percent, but the output of PWMParabola will be in percent and change once per minute.

The output of PWMParabolaHighRes will be in values from 0 to 4095 where 4095 is 100 percent, gets updated each second, and can be written to the 16 channel dimming expansion directly.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by rimai »

If you want a really fast cloud, you might as well just recreate a new ReversePWMSlope to use milliseconds instead of seconds and use the regular ReversePWMSlope for long clouds and your new ReversePWMSlope for fast clouds.
You code would also need to be conditional to call one of these depending on your preference.
Roberto.
dlplunkett44
Posts: 74
Joined: Mon Aug 05, 2013 3:16 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by dlplunkett44 »

As far as the high res stuff, would this be right?

Code: Select all

//0 = White Far East
PWMChannel[0]=PWMParabolaHighRes(8,0,20,30,0,80,0);
//1 = White Near East
PWMChannel[1]=PWMParabolaHighRes(8,5,20,35,0,80,0);
//2 = White Near West
PWMChannel[2]=PWMParabolaHighRes(8,10,20,40,0,80,0);
//3 = White Far West
PWMChannel[3]=PWMParabolaHighRes(8,15,20,45,0,80,0);
//4 = Blue Far East
PWMChannel[4]=PWMParabolaHighRes(7,15,21,15,0,80,0);
//5 = Blue Near East
PWMChannel[5]=PWMParabolaHighRes(7,20,21,20,0,80,0);
//6 = Blue Near West
PWMChannel[6]=PWMParabolaHighRes(7,25,21,25,0,80,0);
//7 = Blue Far West
PWMChannel[7]=PWMParabolaHighRes(7,30,21,30,0,80,0);
//8 = OCW Far East
PWMChannel[8]=PWMParabolaHighRes(8,15,20,15,0,60,0);
//9 = OCW Near East
PWMChannel[9]=PWMParabolaHighRes(8,20,20,20,0,60,0);
//10 = OCW Near West
PWMChannel[10]=PWMParabolaHighRes(8,25,20,25,0,60,0);
//11 = OCW Far West
PWMChannel[11]=PWMParabolaHighRes(8,30,20,30,0,60,0);
//12 = Violets
PWMChannel[12]=PWMParabolaHighRes(8,15,20,30,0,65,0);
//13 = Moonlight Far East
PWMChannel[13]=PWMParabolaHighRes(20,15,8,30,0,15,0);
//14 = Moonlight Near East and West
PWMChannel[14]=PWMParabolaHighRes(20,20,8,35,0,15,0);
//15 = Moonlight Far West
PWMChannel[15]=PWMParabolaHighRes(20,25,8,40,0,15,0);
   

or would I have to convert the 80, 60, 65, 15 to what they would be 0-4095?

Thanks
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by AlanM »

rimai wrote:If you want a really fast cloud, you might as well just recreate a new ReversePWMSlope to use milliseconds instead of seconds and use the regular ReversePWMSlope for long clouds and your new ReversePWMSlope for fast clouds.
You code would also need to be conditional to call one of these depending on your preference.
This is a great idea. I don't know how fast each loop will be with all that stuff in it, but I'd be interested in seeing how fast you can send new values to the 16 channel PWM for dimming. 8)
AlanM
Posts: 263
Joined: Wed Jan 01, 2014 7:26 am

Re: Clouds/Lightning/Storms for 16 Channel PWM Expansion

Post by AlanM »

I don't know if that will be right what you posted above because I don't know for sure what you're doing with those PWMChannel array values. Your inputs are fine as 80, 60, 65, but the PWMChannel array will not have larger numbers.

I suspect that you'll need to change something further down to account for the fact that those PWMChannel[x] now have values up to 4095 in them instead of up to 100 and maybe not multiply something by 40.95 before you're writing the values to the dimming expansion, but I'm not positive.
Post Reply