Let's Build Troubadour11's Code

Share you PDE file with our community

Posts: 18
Joined: Tue Nov 12, 2013 2:24 pm
PostPosted: Thu Jul 23, 2015 7:56 am
Thanks so much for the speedy help. :D I knew I had to be missing how to input the variables.

So I inserted this into my code between the heater ports and light cycle like in the example from the wizard:
Code: Select all
void loop()
{
    ReefAngel.StandardHeater(Port1);
    ReefAngel.StandardHeater(Port2);
 
    ////// Place your custom code below here //////
   
    //Sets Port 7 on the Power Unit to a dosing pump running for 5 seconds every 2 hours.
    ReefAngel.DosingPumpRepeat( Port7,0,120,5 );
   
//-----------------------------------------------------------------------------------------------------------------------------------------------------// 
    //Set up for Refugium and Phytoplankton light cycle


Was I also correct to exclude Port7 from the "always on" list then?
Code: Select all
    //Ports that are always on
    ReefAngel.Relay.On( Port3 );
    ReefAngel.Relay.On( Port4 );
    ReefAngel.Relay.On( Port5 );
    ReefAngel.Relay.On( Port6 );
    //ReefAngel.Relay.On( Port7 );
    ReefAngel.Relay.On( Port8 );
      // Port1 = Heater
      // Port2 = Heater
      // Port3 = Refugium Light
      // Port4 = Phyto Light
      // Port5 = Return Pump
      // Port6 = Protein Skimmer
      // Port7 = Dosing Pump
      // Port8 = Refugium Pump
 
    ////// Place additional initialization code below here //////


And I also removed Portbit7 from the water change function since I had a different pump on here.
Code: Select all
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port5Bit | Port6Bit;


. . .

All right. So the code verified and looks like it's good to go. It's time for me to head off to work this morning. So I'm going to upload my modified full code and set up the vinegar dripping into a measuring cup to test it out during the day while at work. Hopefully I come home to the proper amount and will have this all set up and ready to go for my tank sitter :)

I'll try to report back on the results before I head out of town :D

Current full code:
Code: Select all
//*************************************************************************************************************
//Start of PWM Expansion Code Header

//This is just how we are going to reference the PWM expansion ports within the code.
//You can change the labels if you would like, just as long as they are changed all throughout the code too.
                  //Standard PowerRelay PWM Daylight = L-DT White/Color
                  //Standard PowerRelay PWM Actinic = L-DT Blue/UV
#define LEDPWM0 0 // R-DT = White/Color
#define LEDPWM1 1 // R-DT = Blue/UV
#define LEDPWM2 2 // L-DT = MoonLight
#define LEDPWM3 3 // R-DT = Moonlight
#define LEDPWM4 4 // - EMPTY -
#define LEDPWM5 5 // - EMPTY -

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

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

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

// - Creates a variable to control a "force cloud function" inside a menu.
boolean ForceCloud=false;

//added for custom menu set up
#include <avr/pgmspace.h>
// Create the menu entries
prog_char menu1_label[] PROGMEM = "Feeding";
prog_char menu2_label[] PROGMEM = "Water Change";
prog_char menu3_label[] PROGMEM = "ATO Clear";
prog_char menu4_label[] PROGMEM = "Overheat Clear";
prog_char menu5_label[] PROGMEM = "PH Calibration";
prog_char menu6_label[] PROGMEM = "Date / Time";
prog_char menu7_label[] PROGMEM = "Version";
prog_char menu8_label[] PROGMEM = "Storm Effect";
// Group the menu entries together
PROGMEM const char *menu_items[] = {menu1_label, menu2_label, menu3_label, menu4_label, menu5_label, menu6_label, menu7_label, menu8_label};
// Creating the custom menu fucntions. menu2_label corresponds to MenuEntry2 funtion
void MenuEntry1()
{
ReefAngel.FeedingModeStart();
}
void MenuEntry2()
{
ReefAngel.WaterChangeModeStart();
}
void MenuEntry3()
{
ReefAngel.ATOClear();
ReefAngel.DisplayMenuEntry("Clear ATO Timeout");
}
void MenuEntry4()
{
ReefAngel.OverheatClear();
ReefAngel.DisplayMenuEntry("Clear Overheat");
}
void MenuEntry5()
{
ReefAngel.SetupCalibratePH();
ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry6()
{
ReefAngel.SetupDateTime();
ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
ReefAngel.DisplayVersion();
}
// Trying to add a menu to the RA Head Unit so I can trigger a cloud effect on demand.
void MenuEntry8()
{
ForceCloud=true;
ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}

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

byte LDT_DaylightPWMValue=0;
byte LDT_ActinicPWMValue=0;
byte LDT_MoonLightANALOGValue=0;
byte RDT_DaylightPWMValue=0;
byte RDT_ActinicPWMValue=0;
byte RDT_MoonLightANALOGValue=0;

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


void setup()
{
    //This must be the first line.
    ReefAngel.Init();  //Initialize controller
    //This must be the first line.
 
    // Initialize the custom menu
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));

    ReefAngel.AddStandardMenu();  // Add Standard Menu
    ReefAngel.Use2014Screen();  // Let's use 2014 Screen
 
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = 0;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port5Bit | Port6Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = 0;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port1Bit | Port2Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;

    //Ports that are always on
    ReefAngel.Relay.On( Port3 );
    ReefAngel.Relay.On( Port4 );
    ReefAngel.Relay.On( Port5 );
    ReefAngel.Relay.On( Port6 );
    //ReefAngel.Relay.On( Port7 );
    ReefAngel.Relay.On( Port8 );
      // Port1 = Heater
      // Port2 = Heater
      // Port3 = Refugium Light
      // Port4 = Phyto Light
      // Port5 = Return Pump
      // Port6 = Protein Skimmer
      // Port7 = Dosing Pump
      // Port8 = Refugium Pump
 
    ////// Place additional initialization code below here //////
 
// ***PLEASE HELP HERE********************************************************************************************************************************************
     //Sets values of ALL lighting channels to 0% on Start Up correctly, I think.
     ReefAngel.PWM.SetDaylight(0);
     ReefAngel.PWM.SetActinic(0);
     ReefAngel.PWM.SetChannel(LEDPWM0,0);
     ReefAngel.PWM.SetChannel(LEDPWM1,0);
     ReefAngel.PWM.SetChannel(LEDPWM2,0);
     ReefAngel.PWM.SetChannel(LEDPWM3,0);
     ReefAngel.PWM.SetChannel(LEDPWM4,0);
     ReefAngel.PWM.SetChannel(LEDPWM5,0);
     // I believe using this got rid of my bright flash to 100% when I uploaded new code. Specifically setting the Standard Daylight/Actinic
//****************************************************************************************************************************************************************

    // Adds the date and time menu to controller so I can change for Daylight Savings Time. **Takes up memory space**
    // - Can be removed after change or adding wifi. Time can be changed in portal or through phone app. eventually
    //ReefAngel.AddDateTimeMenu();
       
    ////// Place additional initialization code above here //////
}

void loop()
{
    ReefAngel.StandardHeater(Port1);
    ReefAngel.StandardHeater(Port2);
 
    ////// Place your custom code below here //////
   
    //Sets Port 7 on the Power Unit to a dosing pump running for 5 seconds every 2 hours.
    ReefAngel.DosingPumpRepeat( Port7,0,120,5 );
   
//-----------------------------------------------------------------------------------------------------------------------------------------------------// 
    //Set up for Refugium and Phytoplankton light cycle

    //USE THIS TO TOGGLE PORTS ON/OFF - ReefAngel.StandardLight(relay,onhour,onminute,offhour,offminute)
     //Turns Refugium Light plugged into port3 on at 9:30 pm and off at 9:30 am.
     ReefAngel.StandardLights(Port3,21,30,9,30);
     //Turns Phyto Light plugged into port4 on at 9:30 pm and off at 9:30 am.
     ReefAngel.StandardLights(Port4,21,30,9,30);

//-----------------------------------------------------------------------------------------------------------------------------------------------------//

//*********************************************************************************************************************************************************
                                   //// Calculate your regular sunrise/sunset PWM values ////
//*********************************************************************************************************************************************************
 //_____________________________________________________________________________________________________________
    // - Turns RDT - B/UV channel to 0% power between 8:55 p.m. and 10:00 a.m. to conserve energy
    // - Dimming Expansion - LEDPWM1 - RDT Blue/UV -
    // - Parabola dimming 11%-100%-11%
//_____________________________________________________________________________________________________________ 
 if ((NumMins(hour(now()),minute(now())) > NumMins(10,00)) && (NumMins(hour(now()),minute(now())) < NumMins(20,55)))
      {
         RDT_ActinicPWMValue=PWMSlope(10,00,20,55,11,100,240,RDT_ActinicPWMValue);
      }
      else
      {
         RDT_ActinicPWMValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//_____________________________________________________________________________________________________________
    // - Turns LDT - B/UV channel to 0% power between 9:05 p.m. and 10:15 p.m. to conserve energy
    // - RA Standard Power Unit - LDT Blue/UV -
    // - Parabola dimming 11%-100%-11%
//_____________________________________________________________________________________________________________
     if ((NumMins(hour(now()),minute(now())) > NumMins(10,15)) && (NumMins(hour(now()),minute(now())) < NumMins(21,05)))
     {
        LDT_ActinicPWMValue=PWMSlope(10,15,21,05,11,100,240,LDT_ActinicPWMValue);
      }
      else
      {
        LDT_ActinicPWMValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//_____________________________________________________________________________________________________________
    // - Turns RDT - W/C channel to 0% power between 8:30 p.m. and 10:25 a.m. to conserve energy
    // - Dimming Expansion - RDT White/Color -
    // - Parabola dimming 11%-100%-11%
//_____________________________________________________________________________________________________________
     if ((NumMins(hour(now()),minute(now())) > NumMins(10,25)) && (NumMins(hour(now()),minute(now())) < NumMins(20,30)))
     {
        RDT_DaylightPWMValue=PWMSlope(10,25,20,30,11,100,240,RDT_DaylightPWMValue);
      }
      else
      {
        RDT_DaylightPWMValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//_____________________________________________________________________________________________________________
    // - Turns LDT - W/C channel to 0% power between 8:45 p.m. and 10:35 a.m. to conserve energy
    // - RA Power Unit - LDT White/Color -
    // - Parabola dimming 11%-%100-11%
//_____________________________________________________________________________________________________________
     if ((NumMins(hour(now()),minute(now())) > NumMins(10,35)) && (NumMins(hour(now()),minute(now())) < NumMins(20,45)))
     {
        LDT_DaylightPWMValue=PWMSlope(10,35,20,45,11,100,240,LDT_DaylightPWMValue);
      }
      else
      {
        LDT_DaylightPWMValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                   //// Set MoonLights Cycles ////
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    LDT_MoonLightANALOGValue=PWMSlope(10,30,21,00,10,100,240,PWMSlope(21,20,23,15,20,MoonPhase()/5+10,30,LDT_MoonLightANALOGValue=0));
    RDT_MoonLightANALOGValue=PWMSlope(10,20,20,50,10,100,240,PWMSlope(21,15,23,15,20,MoonPhase()/5+10,30,RDT_MoonLightANALOGValue=0));

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    CheckCloud();
    ReefAngel.PWM.SetDaylight(LDT_DaylightPWMValue);
    ReefAngel.PWM.SetActinic(LDT_ActinicPWMValue);
    ReefAngel.PWM.SetChannel(LEDPWM2,LDT_MoonLightANALOGValue);
    ReefAngel.PWM.SetChannel(LEDPWM0,RDT_DaylightPWMValue);
    ReefAngel.PWM.SetChannel(LEDPWM1,RDT_ActinicPWMValue);
    ReefAngel.PWM.SetChannel(LEDPWM3,RDT_MoonLightANALOGValue);
//_________________________________________________________________________________________________

    ////// Place your custom code above here //////
 
    //Connects Reef Angel Head Unit to the Portal through WiFi Unit.
    ReefAngel.Portal("troubadour11");
    // This should always be the last line
    ReefAngel.ShowInterface();
}


//************************************************************************************************************************************************************************************************************************
  // - My lighting is set up as:
  //      - LDT (Left Display Tank) fixture on the "Standard" 2 (PWM signal) slots on my power relay box.
  //      - RDT (Right Display Tank) fixture on channels 0=daylight and 1=actinic (PWM signal) of the Dimming Expansion.
  //      - Moonlights = channels 2 and 3 of the PWM expansion. These drivers are Analog and the jumper pins have been set for 0-10v Analog in Dimming Expansion.
 
 // - I'd like to calculate the cloud effect for the LDT lights using the "Weather Sim for Standard PWM" code which I think
 //   I got copied, set up, and working correctly for the 1 fixture on the Standard Ports.
 //                 - Then find a way to feed those values into the RDT lights with a "Random Sample" of + or - a small time offset for the cloud effect on the RDT
 //                                - This way I could randomly generate a weather sim, and randomly have the cloud move Right-to-Left or Left-to-Right each time a cloud occurs

//                  - Lightning effect could either be off set with a similar way with +/- value OR left sync'd to LDT lightning (would need to test what looks good).
//                  - Or possibly more or less lightning per fixture during cloud.
//*************************************************************************************************************************************************************************************************************************

// 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
  // I should create a random variable here to randomize the days it has clouds?
#define Clouds_Every_X_Days 1

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

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

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

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

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

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

  // Always end the cloud effect before this setting
     // In this example, end must be before 6:45pm
#define End_Cloud_Before NumMins(19,45)

  // Percentage chance of lightning happening 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 50
 
  // Note: Make sure to choose correct values that will work within your PWMSLope settings.
  // For example, in our case, we could have a max of 5 clouds per day and they could last for 50 minutes.
  // Which could mean 250 minutes of clouds. We need to make sure the PWMSlope can accomodate 250 minutes of effects or unforseen results could happen.
    // Also, make sure that you can fit double those minutes between Start_Cloud_After and End_Cloud_Before.
  // In our example, we have 510 minutes between Start_Cloud_After and End_Cloud_Before, so double the 250 minutes (or 500 minutes) can fit in that 510 minutes window.
    // It's a tight fit, but it did.
//____________________________________________________________________________________________________________________________________________________________
  //***Question***
  // Why do you have to double the amount of time from 250 to 500 in your example? - This is just a question to understand the programming better, I don't see why it needs to be doubled.
  // I see it in the code dividing by (numclouds*2), etc. What's the purpose of multiplying it up by 2? I'm just trying to learn on this question if you have time to explain. Thanks :-)
//____________________________________________________________________________________________________________________________________________________________

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


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

  static byte cloudchance = 255;
  static byte cloudduration=0;
  static int cloudstart=0;
  static byte numclouds=0;
  //made individual lightningchance for each fixture
  static byte LDTlightningchance=0;
  //static byte RDTlightningchance=0;
  static byte cloudindex=0;
  //made separate lightning status for each fixture
  static byte LDTlightningstatus=0;
  //static byte RDTlightningstatus=0;
  static int LastNumMins=0;
//********************************************************************************************************************************************************
  // - I created this value to use as +/- offset value to make clouds pass left-to-right or vice-versa.
  //static int RDTcloudstartOffset=0;

  // - I added this to use as a randomly chosen value between (-)x to y.
  // - This will be added to "cloudstart" in order to determine the start time of the RDT cloud effect.
  //static byte RDTcloudstart=0;

  // - I added this to create a random sample between 80% and 100% dimming power for "random" lightning intensity effect on each fixture.
  static byte LDT_LightningFlashPower=0;
  static byte RDT_LightningFlashPower=0;

  // - I added these to create a variable to randomize when and how long each lightning strike happens for each cloud.
  //LDTlightningRandomStart=0;
  //LDTlightningLength=0;
  //RDTlightningRandomStart=0;
  //RDTlightningLength=0;
//********************************************************************************************************************************************************


  // Every day at midnight, we check for chance of cloud happening today
  if (hour()==0 && minute()==0 && second()==0) cloudchance=255;

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

//********************************************************************************************************************************************************
        // pick a random number between these values to offset the RDT cloud by this many minutes
        //RDTcloudstartOffset=random(-1,1);
        // adds the random offset value to "cloudstart" and sets the cloudstart time for RDT light fixture
        //RDTcloudstart=cloudstart+RDTcloudstartOffset;
//********************************************************************************************************************************************************

        // 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
        LDTlightningchance=random(100);
        //RDTlightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning on the next cloud.
        if (LDTlightningchance>Lightning_Change_per_Cloud) LDTlightningchance=0;
        //if (RDTlightningchance>Lightning_Change_per_Cloud) RDTlightningchance=0;
      }
    }
  // Now that we have all the parameters for the cloud, let's create the effect down below.

// Force Cloud from Menu Function jumps to here to start cloud effect immediately for a show!
if (ForceCloud)
{
ForceCloud=false;
cloudchance=1;
cloudduration=8;
LDTlightningchance=1;
//RDTlightningchance=1;
cloudstart=NumMins(hour(),minute())+2;
//RDTcloudstart=NumMins(hour(),minute())+1;
//RDTcloudstartOffset=random(-1,1);
//RDTcloudstart=cloudstart+RDTcloudstartOffset;
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // - Controls Cloud and Lightning Effect timings for both fixtures
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  if (cloudchance)
  {
    //is it time for cloud yet over Left Display Tank?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      // - Dims LDT to create cloud and back up to Daylight Parabola. - maybe change to 11 in order to make minimum cloud power 11% so the lights don't click off.
      RDT_DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,RDT_DaylightPWMValue,10,180);
      LDT_DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,LDT_DaylightPWMValue,10,180);
      RDT_ActinicPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,RDT_DaylightPWMValue,20,180);
      LDT_ActinicPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,LDT_DaylightPWMValue,20,180);
      RDT_MoonLightANALOGValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,RDT_MoonLightANALOGValue,11,180);
      LDT_MoonLightANALOGValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,LDT_MoonLightANALOGValue,11,180);

      // To adjust possible length of time of lightning strike, Change the "second()< 5 " ... where 5 is the # of seconds of lightning during cloud.
      // and the "minute())=(cloudstart_(cloudduration/2)))" sets start time... dividing by 2 is exactly half way through cloud to trigger 5 seconds lightning.
      // if there is lightning and current time is 1/2 way through cloud, but less then 1/2 way through cloud + 5 seconds

     // if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/LDTlightningRandomStart))) && second()<LDTlightningLength)
      if (LDTlightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5)
      {
        if (random(100)<20) LDTlightningstatus=1;
        else LDTlightningstatus=0;
        if (LDTlightningstatus)
        {
               // - This will correctly flash lightning up to 100% power every lightning strike.
          //LDT_DaylightPWMValue=100;
          //LDT_ActinicPWMValue=100;
//_______________________________________________________________________________________________________
          // - Trying to make a random sample between, say 80% & 100% for the brightness of the lightning?
          // - If there will be lightning, pick a random number between 80 and 100 for the lightning power.
          LDT_LightningFlashPower=random(80,100);
          RDT_LightningFlashPower=random(80,100);

          RDT_DaylightPWMValue=RDT_LightningFlashPower;
          RDT_ActinicPWMValue=RDT_LightningFlashPower;
          RDT_MoonLightANALOGValue=RDT_LightningFlashPower;
          LDT_DaylightPWMValue=LDT_LightningFlashPower;
          LDT_ActinicPWMValue=LDT_LightningFlashPower;
          LDT_MoonLightANALOGValue=LDT_LightningFlashPower;
//_______________________________________________________________________________________________________
        }
        else
        {
          // - Changed these values from 0 to 11 so at end of lightning cycle, the go to min. 11% power
          RDT_DaylightPWMValue=11;
          RDT_ActinicPWMValue=20;
          RDT_MoonLightANALOGValue=11;
          LDT_DaylightPWMValue=11;
          LDT_ActinicPWMValue=20;
          LDT_MoonLightANALOGValue=11;
//------------------------------------------------------------------
        }
        delay(1);
      }
    }
  }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      {
        cloudstart=random(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2),(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2))+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
//************************************************************************************************************************************************************************************************
//// - I think this resets the random offset and cloudstart time for the RDT Fixture to match the new/next "cloudstart" time if there will be another cloud today ////
//************************************************************************************************************************************************************************************************
        // pick a random number between these values to offset the RDT cloud by this many minutes
        //RDTcloudstartOffset=random(-1,1);
        // adds the random offset value to "cloudstart" and sets the cloudstart time for RDT light fixture
        //RDTcloudstart=cloudstart+RDTcloudstartOffset;
//***********************************************************************************************************************************************************************
        //Pick a random number between 0 and 99
        LDTlightningchance=random(100);
        //RDTlightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (LDTlightningchance>Lightning_Change_per_Cloud) LDTlightningchance=0;
        //if (RDTlightningchance>Lightning_Change_per_Cloud) RDTlightningchance=0;

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

Posts: 18
Joined: Tue Nov 12, 2013 2:24 pm
PostPosted: Thu Jul 23, 2015 8:12 am
Oh, I forgot to ask.

In the new code:
Code: Select all
    //Sets Port 7 on the Power Unit to a dosing pump running for 5 seconds every 2 hours.
    ReefAngel.DosingPumpRepeat( Port7,0,120,5 );


What does the 0 represent?

I get that you're telling the controller to do a repeating dosing pump cycle on Port 7. Every 120 minutes, for 5 seconds. Are those numbers always in minutes and seconds no matter what? Using the .DosingPump code tells it those will be minutes and seconds?

I just want to fully understand all the variables in case I ever need to modify it further. Thanks! :)

Posts: 11845
Joined: Fri Mar 18, 2011 6:47 pm
PostPosted: Thu Jul 23, 2015 8:36 am
Correct, minutes for repeat and seconds to run.
The 0 is for offset.
If you were to dose alk and Ca, you would want to offset both of them.
Roberto.

Posts: 18
Joined: Tue Nov 12, 2013 2:24 pm
PostPosted: Sat Aug 08, 2015 10:33 am
So I didn't make it back to report the results before leaving town. But I was right at the amount expected after running a 12 hour test from 8am to 8pm. So I set it up into my sump and let it go. So far it seems to be working just fine!

Thanks so much for the timely help and for the follow up on the offset. Definitely good to know. If my system ever out-paces kalk dosing through my ATO, I'll be looking to use that to keep up.

Thanks again! :D

Posts: 18
Joined: Tue Nov 12, 2013 2:24 pm
PostPosted: Sat Sep 10, 2016 12:39 pm
I've been wanting to figure out how to set up my light cycles on variables using custom memory locations. That way I should be able to access the variables and adjust them as I desire without having to break out my laptop and upload a new hard coded version every time, correct? Either through the portal or the RA android app?

I spent some time attempting to get it going. I'm sure I am missing some things since I wasn't getting the results I expected.

Here is a copy of my full code that is currently running (without the custom memory locations):
Code: Select all
//*************************************************************************************************************
//Start of PWM Expansion Code Header

//This is just how we are going to reference the PWM expansion ports within the code.
//You can change the labels if you would like, just as long as they are changed all throughout the code too.
                  //Standard PowerRelay PWM Daylight = L-DT White/Color
                  //Standard PowerRelay PWM Actinic = L-DT Blue/UV
#define LEDPWM0 0 // R-DT = White/Color
#define LEDPWM1 1 // R-DT = Blue/UV
#define LEDPWM2 2 // L-DT = MoonLight
#define LEDPWM3 3 // R-DT = Moonlight
#define LEDPWM4 4 // - EMPTY -
#define LEDPWM5 5 // - EMPTY -

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

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

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

// - Creates a variable to control a "force cloud function" inside a menu.
boolean ForceCloud=false;

//added for custom menu set up
#include <avr/pgmspace.h>
// Create the menu entries
prog_char menu1_label[] PROGMEM = "Feeding";
prog_char menu2_label[] PROGMEM = "Water Change";
prog_char menu3_label[] PROGMEM = "ATO Clear";
prog_char menu4_label[] PROGMEM = "Overheat Clear";
prog_char menu5_label[] PROGMEM = "PH Calibration";
prog_char menu6_label[] PROGMEM = "Date / Time";
prog_char menu7_label[] PROGMEM = "Version";
prog_char menu8_label[] PROGMEM = "Storm Effect";
// Group the menu entries together
PROGMEM const char *menu_items[] = {menu1_label, menu2_label, menu3_label, menu4_label, menu5_label, menu6_label, menu7_label, menu8_label};
// Creating the custom menu fucntions. menu2_label corresponds to MenuEntry2 funtion
void MenuEntry1()
{
ReefAngel.FeedingModeStart();
}
void MenuEntry2()
{
ReefAngel.WaterChangeModeStart();
}
void MenuEntry3()
{
ReefAngel.ATOClear();
ReefAngel.DisplayMenuEntry("Clear ATO Timeout");
}
void MenuEntry4()
{
ReefAngel.OverheatClear();
ReefAngel.DisplayMenuEntry("Clear Overheat");
}
void MenuEntry5()
{
ReefAngel.SetupCalibratePH();
ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry6()
{
ReefAngel.SetupDateTime();
ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
ReefAngel.DisplayVersion();
}
// Trying to add a menu to the RA Head Unit so I can trigger a cloud effect on demand.
void MenuEntry8()
{
ForceCloud=true;
ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}

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

byte LDT_DaylightPWMValue=0;
byte LDT_ActinicPWMValue=0;
byte LDT_MoonLightANALOGValue=0;
byte RDT_DaylightPWMValue=0;
byte RDT_ActinicPWMValue=0;
byte RDT_MoonLightANALOGValue=0;

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


void setup()
{
    //This must be the first line.
    ReefAngel.Init();  //Initialize controller
    //This must be the first line.
 
    // Initialize the custom menu
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));

    ReefAngel.AddStandardMenu();  // Add Standard Menu
    ReefAngel.Use2014Screen();  // Let's use 2014 Screen
 
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = 0;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port5Bit | Port6Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = 0;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port1Bit | Port2Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;

    //Ports that are always on
    ReefAngel.Relay.On( Port3 );
    ReefAngel.Relay.On( Port4 );
    ReefAngel.Relay.On( Port5 );
    ReefAngel.Relay.On( Port6 );
    //ReefAngel.Relay.On( Port7 );
    ReefAngel.Relay.On( Port8 );
      // Port1 = Heater
      // Port2 = Heater
      // Port3 = Refugium Light
      // Port4 = Phyto Light
      // Port5 = Return Pump
      // Port6 = Protein Skimmer
      // Port7 = Dosing Pump
      // Port8 = Refugium Pump
 
    ////// Place additional initialization code below here //////
 
// ***PLEASE HELP HERE********************************************************************************************************************************************
     //Sets values of ALL lighting channels to 0% on Start Up correctly, I think.
     ReefAngel.PWM.SetDaylight(0);
     ReefAngel.PWM.SetActinic(0);
     ReefAngel.PWM.SetChannel(LEDPWM0,0);
     ReefAngel.PWM.SetChannel(LEDPWM1,0);
     ReefAngel.PWM.SetChannel(LEDPWM2,0);
     ReefAngel.PWM.SetChannel(LEDPWM3,0);
     ReefAngel.PWM.SetChannel(LEDPWM4,0);
     ReefAngel.PWM.SetChannel(LEDPWM5,0);
     // I believe using this got rid of my bright flash to 100% when I uploaded new code. Specifically setting the Standard Daylight/Actinic
//****************************************************************************************************************************************************************

    // Adds the date and time menu to controller so I can change for Daylight Savings Time. **Takes up memory space**
    // - Can be removed after change or adding wifi. Time can be changed in portal or through phone app. eventually
    //ReefAngel.AddDateTimeMenu();
       
    ////// Place additional initialization code above here //////
}

void loop()
{
    ReefAngel.StandardHeater(Port1);
    ReefAngel.StandardHeater(Port2);
 
    ////// Place your custom code below here //////
   
    //Sets Port 7 on the Power Unit to a dosing pump running for 5 seconds every 2 hours.
    ReefAngel.DosingPumpRepeat( Port7,0,120,5 );
   
//-----------------------------------------------------------------------------------------------------------------------------------------------------// 
    //Set up for Refugium and Phytoplankton light cycle

    //USE THIS TO TOGGLE PORTS ON/OFF - ReefAngel.StandardLight(relay,onhour,onminute,offhour,offminute)
     //Turns Refugium Light plugged into port3 on at 10:30 pm and off at 5:30 am.
     ReefAngel.StandardLights(Port3,22,30,8,30);
     //Turns Phyto Light plugged into port4 on at 10:30 pm and off at 5:30 am.
     ReefAngel.StandardLights(Port4,22,30,8,30);

//-----------------------------------------------------------------------------------------------------------------------------------------------------//

//*********************************************************************************************************************************************************
                                   //// Calculate your regular sunrise/sunset PWM values ////
//*********************************************************************************************************************************************************
 //_____________________________________________________________________________________________________________
    // - Turns RDT - B/UV channel to 0% power between 8:55 p.m. and 10:00 a.m. to conserve energy
    // - Dimming Expansion - LEDPWM1 - RDT Blue/UV -
    // - Parabola dimming 11%-100%-11%
//_____________________________________________________________________________________________________________ 
 if ((NumMins(hour(now()),minute(now())) > NumMins(10,00)) && (NumMins(hour(now()),minute(now())) < NumMins(20,55)))
      {
         //RDT_ActinicPWMValue=PWMSlope(10,00,20,55,11,100,240,RDT_ActinicPWMValue);
         RDT_MoonLightANALOGValue=PWMSlope(10,00,20,55,11,100,240,RDT_MoonLightANALOGValue);
      }
      else
      {
         //RDT_ActinicPWMValue=0;
         RDT_MoonLightANALOGValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//_____________________________________________________________________________________________________________
    // - Turns LDT - B/UV channel to 0% power between 9:05 p.m. and 10:15 p.m. to conserve energy
    // - RA Standard Power Unit - LDT Blue/UV -
    // - Parabola dimming 11%-100%-11%
//_____________________________________________________________________________________________________________
     if ((NumMins(hour(now()),minute(now())) > NumMins(10,15)) && (NumMins(hour(now()),minute(now())) < NumMins(21,05)))
     {
        //LDT_ActinicPWMValue=PWMSlope(10,15,21,05,11,100,240,LDT_ActinicPWMValue);
        LDT_MoonLightANALOGValue=PWMSlope(10,15,21,05,11,100,240,LDT_MoonLightANALOGValue);
      }
      else
      {
        //LDT_ActinicPWMValue=0;
        LDT_MoonLightANALOGValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//_____________________________________________________________________________________________________________
    // - Turns RDT - W/C channel to 0% power between 8:30 p.m. and 10:25 a.m. to conserve energy
    // - Dimming Expansion - RDT White/Color -
    // - Parabola dimming 11%-50%-11%
//_____________________________________________________________________________________________________________
     if ((NumMins(hour(now()),minute(now())) > NumMins(10,25)) && (NumMins(hour(now()),minute(now())) < NumMins(20,30)))
     {
        RDT_DaylightPWMValue=PWMSlope(10,25,20,30,11,50,240,RDT_DaylightPWMValue);
      }
      else
      {
        RDT_DaylightPWMValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//_____________________________________________________________________________________________________________
    // - Turns LDT - W/C channel to 0% power between 8:45 p.m. and 10:35 a.m. to conserve energy
    // - RA Power Unit - LDT White/Color -
    // - Parabola dimming 11%-50%-11%
//_____________________________________________________________________________________________________________
     if ((NumMins(hour(now()),minute(now())) > NumMins(10,35)) && (NumMins(hour(now()),minute(now())) < NumMins(20,45)))
     {
        LDT_DaylightPWMValue=PWMSlope(10,35,20,45,11,50,240,LDT_DaylightPWMValue);
      }
      else
      {
        LDT_DaylightPWMValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                   //// Set MoonLights Cycles ////
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    //LDT_MoonLightANALOGValue=PWMSlope(10,30,21,00,10,100,240,PWMSlope(21,20,23,15,20,MoonPhase()/5+10,30,LDT_MoonLightANALOGValue=0));
    LDT_ActinicPWMValue=PWMSlope(10,30,21,00,10,100,240,PWMSlope(21,20,23,15,20,MoonPhase()/5+10,30,LDT_ActinicPWMValue=0));
    //RDT_MoonLightANALOGValue=PWMSlope(10,20,20,50,10,100,240,PWMSlope(21,15,23,15,20,MoonPhase()/5+10,30,RDT_MoonLightANALOGValue=0));
    RDT_ActinicPWMValue=PWMSlope(10,20,20,50,10,100,240,PWMSlope(21,15,23,15,20,MoonPhase()/5+10,30,RDT_ActinicPWMValue=0));

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    CheckCloud();
    ReefAngel.PWM.SetDaylight(LDT_DaylightPWMValue);
    ReefAngel.PWM.SetActinic(LDT_ActinicPWMValue);
    ReefAngel.PWM.SetChannel(LEDPWM2,LDT_MoonLightANALOGValue);
    ReefAngel.PWM.SetChannel(LEDPWM0,RDT_DaylightPWMValue);
    ReefAngel.PWM.SetChannel(LEDPWM1,RDT_ActinicPWMValue);
    ReefAngel.PWM.SetChannel(LEDPWM3,RDT_MoonLightANALOGValue);
//_________________________________________________________________________________________________

    ////// Place your custom code above here //////
 
    //Connects Reef Angel Head Unit to the Portal through WiFi Unit.
    ReefAngel.Portal("troubadour11");
    // This should always be the last line
    ReefAngel.ShowInterface();
}


//************************************************************************************************************************************************************************************************************************
  // - My lighting is set up as:
  //      - LDT (Left Display Tank) fixture on the "Standard" 2 (PWM signal) slots on my power relay box.
  //      - RDT (Right Display Tank) fixture on channels 0=daylight and 1=actinic (PWM signal) of the Dimming Expansion.
  //      - Moonlights = channels 2 and 3 of the PWM expansion. These drivers are Analog and the jumper pins have been set for 0-10v Analog in Dimming Expansion.
 
 // - I'd like to calculate the cloud effect for the LDT lights using the "Weather Sim for Standard PWM" code which I think
 //   I got copied, set up, and working correctly for the 1 fixture on the Standard Ports.
 //                 - Then find a way to feed those values into the RDT lights with a "Random Sample" of + or - a small time offset for the cloud effect on the RDT
 //                                - This way I could randomly generate a weather sim, and randomly have the cloud move Right-to-Left or Left-to-Right each time a cloud occurs

//                  - Lightning effect could either be off set with a similar way with +/- value OR left sync'd to LDT lightning (would need to test what looks good).
//                  - Or possibly more or less lightning per fixture during cloud.
//*************************************************************************************************************************************************************************************************************************

// 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
  // I should create a random variable here to randomize the days it has clouds?
#define Clouds_Every_X_Days 1

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

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

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

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

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

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

  // Always end the cloud effect before this setting
     // In this example, end must be before 6:45pm
#define End_Cloud_Before NumMins(19,45)

  // Percentage chance of lightning happening 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 50
 
  // Note: Make sure to choose correct values that will work within your PWMSLope settings.
  // For example, in our case, we could have a max of 5 clouds per day and they could last for 50 minutes.
  // Which could mean 250 minutes of clouds. We need to make sure the PWMSlope can accomodate 250 minutes of effects or unforseen results could happen.
    // Also, make sure that you can fit double those minutes between Start_Cloud_After and End_Cloud_Before.
  // In our example, we have 510 minutes between Start_Cloud_After and End_Cloud_Before, so double the 250 minutes (or 500 minutes) can fit in that 510 minutes window.
    // It's a tight fit, but it did.
//____________________________________________________________________________________________________________________________________________________________
  //***Question***
  // Why do you have to double the amount of time from 250 to 500 in your example? - This is just a question to understand the programming better, I don't see why it needs to be doubled.
  // I see it in the code dividing by (numclouds*2), etc. What's the purpose of multiplying it up by 2? I'm just trying to learn on this question if you have time to explain. Thanks :-)
//____________________________________________________________________________________________________________________________________________________________

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


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

  static byte cloudchance = 255;
  static byte cloudduration=0;
  static int cloudstart=0;
  static byte numclouds=0;
  //made individual lightningchance for each fixture
  static byte LDTlightningchance=0;
  //static byte RDTlightningchance=0;
  static byte cloudindex=0;
  //made separate lightning status for each fixture
  static byte LDTlightningstatus=0;
  //static byte RDTlightningstatus=0;
  static int LastNumMins=0;
//********************************************************************************************************************************************************
  // - I created this value to use as +/- offset value to make clouds pass left-to-right or vice-versa.
  //static int RDTcloudstartOffset=0;

  // - I added this to use as a randomly chosen value between (-)x to y.
  // - This will be added to "cloudstart" in order to determine the start time of the RDT cloud effect.
  //static byte RDTcloudstart=0;

  // - I added this to create a random sample between 80% and 100% dimming power for "random" lightning intensity effect on each fixture.
  static byte LDT_LightningFlashPower=0;
  static byte RDT_LightningFlashPower=0;

  // - I added these to create a variable to randomize when and how long each lightning strike happens for each cloud.
  //LDTlightningRandomStart=0;
  //LDTlightningLength=0;
  //RDTlightningRandomStart=0;
  //RDTlightningLength=0;
//********************************************************************************************************************************************************


  // Every day at midnight, we check for chance of cloud happening today
  if (hour()==0 && minute()==0 && second()==0) cloudchance=255;

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

//********************************************************************************************************************************************************
        // pick a random number between these values to offset the RDT cloud by this many minutes
        //RDTcloudstartOffset=random(-1,1);
        // adds the random offset value to "cloudstart" and sets the cloudstart time for RDT light fixture
        //RDTcloudstart=cloudstart+RDTcloudstartOffset;
//********************************************************************************************************************************************************

        // 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
        LDTlightningchance=random(100);
        //RDTlightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning on the next cloud.
        if (LDTlightningchance>Lightning_Change_per_Cloud) LDTlightningchance=0;
        //if (RDTlightningchance>Lightning_Change_per_Cloud) RDTlightningchance=0;
      }
    }
  // Now that we have all the parameters for the cloud, let's create the effect down below.

// Force Cloud from Menu Function jumps to here to start cloud effect immediately for a show!
if (ForceCloud)
{
ForceCloud=false;
cloudchance=1;
cloudduration=8;
LDTlightningchance=1;
//RDTlightningchance=1;
cloudstart=NumMins(hour(),minute())+2;
//RDTcloudstart=NumMins(hour(),minute())+1;
//RDTcloudstartOffset=random(-1,1);
//RDTcloudstart=cloudstart+RDTcloudstartOffset;
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // - Controls Cloud and Lightning Effect timings for both fixtures
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  if (cloudchance)
  {
    //is it time for cloud yet over Left Display Tank?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      // - Dims LDT to create cloud and back up to Daylight Parabola. - maybe change to 11 in order to make minimum cloud power 11% so the lights don't click off.
      RDT_DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,RDT_DaylightPWMValue,10,180);
      LDT_DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,LDT_DaylightPWMValue,10,180);
      RDT_ActinicPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,RDT_DaylightPWMValue,20,180);
      LDT_ActinicPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,LDT_DaylightPWMValue,20,180);
      RDT_MoonLightANALOGValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,RDT_MoonLightANALOGValue,11,180);
      LDT_MoonLightANALOGValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,LDT_MoonLightANALOGValue,11,180);

      // To adjust possible length of time of lightning strike, Change the "second()< 5 " ... where 5 is the # of seconds of lightning during cloud.
      // and the "minute())=(cloudstart_(cloudduration/2)))" sets start time... dividing by 2 is exactly half way through cloud to trigger 5 seconds lightning.
      // if there is lightning and current time is 1/2 way through cloud, but less then 1/2 way through cloud + 5 seconds

     // if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/LDTlightningRandomStart))) && second()<LDTlightningLength)
      if (LDTlightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5)
      {
        if (random(100)<20) LDTlightningstatus=1;
        else LDTlightningstatus=0;
        if (LDTlightningstatus)
        {
               // - This will correctly flash lightning up to 100% power every lightning strike.
          //LDT_DaylightPWMValue=100;
          //LDT_ActinicPWMValue=100;
//_______________________________________________________________________________________________________
          // - Trying to make a random sample between, say 80% & 100% for the brightness of the lightning?
          // - If there will be lightning, pick a random number between 80 and 100 for the lightning power.
          LDT_LightningFlashPower=random(80,100);
          RDT_LightningFlashPower=random(80,100);

          RDT_DaylightPWMValue=RDT_LightningFlashPower;
          RDT_ActinicPWMValue=RDT_LightningFlashPower;
          RDT_MoonLightANALOGValue=RDT_LightningFlashPower;
          LDT_DaylightPWMValue=LDT_LightningFlashPower;
          LDT_ActinicPWMValue=LDT_LightningFlashPower;
          LDT_MoonLightANALOGValue=LDT_LightningFlashPower;
//_______________________________________________________________________________________________________
        }
        else
        {
          // - Changed these values from 0 to 11 so at end of lightning cycle, the go to min. 11% power
          RDT_DaylightPWMValue=11;
          RDT_ActinicPWMValue=20;
          RDT_MoonLightANALOGValue=11;
          LDT_DaylightPWMValue=11;
          LDT_ActinicPWMValue=20;
          LDT_MoonLightANALOGValue=11;
//------------------------------------------------------------------
        }
        delay(1);
      }
    }
  }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      {
        cloudstart=random(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2),(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2))+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
//************************************************************************************************************************************************************************************************
//// - I think this resets the random offset and cloudstart time for the RDT Fixture to match the new/next "cloudstart" time if there will be another cloud today ////
//************************************************************************************************************************************************************************************************
        // pick a random number between these values to offset the RDT cloud by this many minutes
        //RDTcloudstartOffset=random(-1,1);
        // adds the random offset value to "cloudstart" and sets the cloudstart time for RDT light fixture
        //RDTcloudstart=cloudstart+RDTcloudstartOffset;
//***********************************************************************************************************************************************************************
        //Pick a random number between 0 and 99
        LDTlightningchance=random(100);
        //RDTlightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (LDTlightningchance>Lightning_Change_per_Cloud) LDTlightningchance=0;
        //if (RDTlightningchance>Lightning_Change_per_Cloud) RDTlightningchance=0;

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


To start out my attempt at setting this up, I used my refugium lights which are just 2 spots on a timer running on Port3 and Port4 of my power strip.

Here is how I modified the code... it resulted in my refugium lights being set to on at noon when I was testing it.

I added this section into the top, I copied the lines above and below what I added to clip out the changes;
Code: Select all
// Trying to add a menu to the RA Head Unit so I can trigger a cloud effect on demand.
void MenuEntry8()
{
ForceCloud=true;
ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}

//Define Custom Memory Locations
#define Mem_B_Refugium03_onHour    100
#define Mem_B_Refugium03_onMins    101
#define Mem_B_Refugium03_offHour   102
#define Mem_B_Refugium03_offMins   103
#define Mem_B_Refugium04_onHour    104
#define Mem_B_Refugium04_onMins    105
#define Mem_B_Refugium04_offHour   106
#define Mem_B_Refugium04_offMins   107
         
void init_memory() {
  // Initialize Custom Memory Locations
  InternalMemory.write(Mem_B_Refugium03_onHour,22);
  InternalMemory.write(Mem_B_Refugium03_onMins,30);
  InternalMemory.write(Mem_B_Refugium03_offHour,8);
  InternalMemory.write(Mem_B_Refugium03_offMins,30);
  InternalMemory.write(Mem_B_Refugium04_onHour,22);
  InternalMemory.write(Mem_B_Refugium04_onMins,30);
  InternalMemory.write(Mem_B_Refugium04_offHour,8);
  InternalMemory.write(Mem_B_Refugium04_offMins,30);
}

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


and then adjusted my refugium light schedule section like this:
Code: Select all
//-----------------------------------------------------------------------------------------------------------------------------------------------------// 
    //Set up for Refugium and Phytoplankton light cycle
    //USE THIS TO TOGGLE PORTS ON/OFF - ReefAngel.StandardLight(relay,onhour,onminute,offhour,offminute)

     //Turns Refugium Light plugged into port3 on/off at times specified by internal memory via web or app
     ReefAngel.StandardLights(Port3,
         InternalMemory.read(Mem_B_Refugium03_onHour),
         InternalMemory.read(Mem_B_Refugium03_onMins),
         InternalMemory.read(Mem_B_Refugium03_offHour),
         InternalMemory.read(Mem_B_Refugium03_offMins));
     //Turns Refugium Light plugged into port3 on at 10:30 pm and off at 5:30 am. - older code
     //ReefAngel.StandardLights(Port3,22,30,5,30); - old code
     
     //Turns Refugium Light plugged into port4 on/off at times specified by internal memory via web or app
     ReefAngel.StandardLights(Port4,
         InternalMemory.read(Mem_B_Refugium04_onHour),
         InternalMemory.read(Mem_B_Refugium04_onMins),
         InternalMemory.read(Mem_B_Refugium04_offHour),
         InternalMemory.read(Mem_B_Refugium04_offMins));
     //Turns Phyto Light plugged into port4 on at 10:30 pm and off at 5:30 am. - old code
     //ReefAngel.StandardLights(Port4,22,30,5,30); - old code

//-----------------------------------------------------------------------------------------------------------------------------------------------------//


My only guess right now is that I need to create custom global variables and set them to the InternalMemory.read?

So create the variables for each custom memory location and set them like this?
Code: Select all
////// Place global variable code below here //////

byte Refugium03_onHour=InternalMemory.read(Mem_B_Refugium03_onHour);

byte LDT_DaylightPWMValue=0;
byte LDT_ActinicPWMValue=0;
byte LDT_MoonLightANALOGValue=0;
byte RDT_DaylightPWMValue=0;
byte RDT_ActinicPWMValue=0;
byte RDT_MoonLightANALOGValue=0;

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


And then insert each custom variable into the light schedule code similar to this?
Code: Select all
     //Turns Refugium Light plugged into port3 on/off at times specified by internal memory via web or app
     ReefAngel.StandardLights(Port3,Refugium03_onHour,Refugium03_onMins,Refugium03_offHour,Refugium03_offMins);


I appreciate any help I can get on setting this up. I'd love to be able to adjust my light schedule quickly and easily at times. This can open the door to controlling a lot more things eventually without having to hard code the values.

Then once I get it coded right, I need to find them via the app or portal. This previous attempt didn't yield many results as I couldn't find any Mem_B_Refugium03_onHour , etc. labels anywhere. But first, I need to make sure it's coded to work right and then I can go about finding them to be able to adjust them.

Posts: 18
Joined: Tue Nov 12, 2013 2:24 pm
PostPosted: Sun Sep 11, 2016 10:21 am
Now I have another question and need some help with the DelayedOn command for my skimmer. I really do not understand why this is not working.

Here is a copy of my working code without the custom memory stuff I'm also working on where I tried to add in a simple delayed start for my skimmer so it doesn't over flow at times. It seemed like this would be easy to implement. I commented out Port6 from the always on list in the start up and added the delayed on command at the beginning of my main loop.

Code: Select all
//*************************************************************************************************************
//Start of PWM Expansion Code Header

//This is just how we are going to reference the PWM expansion ports within the code.
//You can change the labels if you would like, just as long as they are changed all throughout the code too.
                  //Standard PowerRelay PWM Daylight = L-DT White/Color
                  //Standard PowerRelay PWM Actinic = L-DT Blue/UV
#define LEDPWM0 0 // R-DT = White/Color
#define LEDPWM1 1 // R-DT = Blue/UV
#define LEDPWM2 2 // L-DT = MoonLight
#define LEDPWM3 3 // R-DT = Moonlight
#define LEDPWM4 4 // - EMPTY -
#define LEDPWM5 5 // - EMPTY -

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

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

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

// - Creates a variable to control a "force cloud function" inside a menu.
boolean ForceCloud=false;

//added for custom menu set up
#include <avr/pgmspace.h>
// Create the menu entries
prog_char menu1_label[] PROGMEM = "Feeding";
prog_char menu2_label[] PROGMEM = "Water Change";
prog_char menu3_label[] PROGMEM = "ATO Clear";
prog_char menu4_label[] PROGMEM = "Overheat Clear";
prog_char menu5_label[] PROGMEM = "PH Calibration";
prog_char menu6_label[] PROGMEM = "Date / Time";
prog_char menu7_label[] PROGMEM = "Version";
prog_char menu8_label[] PROGMEM = "Storm Effect";
// Group the menu entries together
PROGMEM const char *menu_items[] = {menu1_label, menu2_label, menu3_label, menu4_label, menu5_label, menu6_label, menu7_label, menu8_label};
// Creating the custom menu fucntions. menu2_label corresponds to MenuEntry2 funtion
void MenuEntry1()
{
ReefAngel.FeedingModeStart();
}
void MenuEntry2()
{
ReefAngel.WaterChangeModeStart();
}
void MenuEntry3()
{
ReefAngel.ATOClear();
ReefAngel.DisplayMenuEntry("Clear ATO Timeout");
}
void MenuEntry4()
{
ReefAngel.OverheatClear();
ReefAngel.DisplayMenuEntry("Clear Overheat");
}
void MenuEntry5()
{
ReefAngel.SetupCalibratePH();
ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry6()
{
ReefAngel.SetupDateTime();
ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
ReefAngel.DisplayVersion();
}
// Trying to add a menu to the RA Head Unit so I can trigger a cloud effect on demand.
void MenuEntry8()
{
ForceCloud=true;
ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}

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

byte LDT_DaylightPWMValue=0;
byte LDT_ActinicPWMValue=0;
byte LDT_MoonLightANALOGValue=0;
byte RDT_DaylightPWMValue=0;
byte RDT_ActinicPWMValue=0;
byte RDT_MoonLightANALOGValue=0;

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


void setup()
{
    //This must be the first line.
    ReefAngel.Init();  //Initialize controller
    //This must be the first line.
 
    // Initialize the custom menu
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));

    ReefAngel.AddStandardMenu();  // Add Standard Menu
    ReefAngel.Use2014Screen();  // Let's use 2014 Screen
 
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = 0;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port5Bit | Port6Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = 0;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port1Bit | Port2Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;

    //Ports that are always on
    ReefAngel.Relay.On( Port3 );
    ReefAngel.Relay.On( Port4 );
    ReefAngel.Relay.On( Port5 );
    //ReefAngel.Relay.On( Port6 ); // removed to add delayed start feature to skimmer in main loop
    //ReefAngel.Relay.On( Port7 );
    ReefAngel.Relay.On( Port8 );
      // Port1 = Heater
      // Port2 = Heater
      // Port3 = Refugium Light
      // Port4 = Phyto Light
      // Port5 = Return Pump
      // Port6 = Protein Skimmer
      // Port7 = Dosing Pump
      // Port8 = Refugium Pump
 
    ////// Place additional initialization code below here //////
 
     //Sets values of ALL lighting channels to 0% on Start Up correctly, I think.
     ReefAngel.PWM.SetDaylight(0);
     ReefAngel.PWM.SetActinic(0);
     ReefAngel.PWM.SetChannel(LEDPWM0,0);
     ReefAngel.PWM.SetChannel(LEDPWM1,0);
     ReefAngel.PWM.SetChannel(LEDPWM2,0);
     ReefAngel.PWM.SetChannel(LEDPWM3,0);
     ReefAngel.PWM.SetChannel(LEDPWM4,0);
     ReefAngel.PWM.SetChannel(LEDPWM5,0);
     // I believe using this got rid of my bright flash to 100% when I uploaded new code. Specifically setting the Standard Daylight/Actinic

    // Adds the date and time menu to controller so I can change for Daylight Savings Time. **Takes up memory space**
    // - Can be removed after change or adding wifi. Time can be changed in portal or through phone app. eventually
    //ReefAngel.AddDateTimeMenu();
       
    ////// Place additional initialization code above here //////
}

void loop()
{

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

    ReefAngel.StandardHeater(Port1);
    ReefAngel.StandardHeater(Port2);

    // Always on ports that have a delay. These ports will delay turning on for the specified MINUTE_DELAY during the following modes:
      // Controller Power Up
      // Feeding Mode (if toggled during mode)
      // Water Change Mode (if toggled during mode)
    // This function needs to be placed inside loop() and not inside setup()
    // Usage is DelayedOn(PORT, MINUTE DELAY) 
    ReefAngel.DelayedOn(Port6, 5);
   
    //Sets Port 7 on the Power Unit to a dosing pump running for 5 seconds every 2 hours.
    ReefAngel.DosingPumpRepeat( Port7,0,120,5 );
   
//-----------------------------------------------------------------------------------------------------------------------------------------------------// 
    //Set up for Refugium and Phytoplankton light cycle

    //USE THIS TO TOGGLE PORTS ON/OFF - ReefAngel.StandardLight(relay,onhour,onminute,offhour,offminute)
     //Turns Refugium Light plugged into port3 on at 10:30 pm and off at 5:30 am.
     ReefAngel.StandardLights(Port3,22,30,8,30);
     //Turns Phyto Light plugged into port4 on at 10:30 pm and off at 5:30 am.
     ReefAngel.StandardLights(Port4,22,30,8,30);

//-----------------------------------------------------------------------------------------------------------------------------------------------------//

//*********************************************************************************************************************************************************
                                   //// Calculate your regular sunrise/sunset PWM values ////
//*********************************************************************************************************************************************************
 //_____________________________________________________________________________________________________________
    // - Turns RDT - B/UV channel to 0% power between 8:55 p.m. and 10:00 a.m. to conserve energy
    // - Dimming Expansion - LEDPWM1 - RDT Blue/UV -
    // - Parabola dimming 11%-100%-11%
//_____________________________________________________________________________________________________________ 
 if ((NumMins(hour(now()),minute(now())) > NumMins(10,00)) && (NumMins(hour(now()),minute(now())) < NumMins(20,55)))
      {
         //RDT_ActinicPWMValue=PWMSlope(10,00,20,55,11,100,240,RDT_ActinicPWMValue);
         RDT_MoonLightANALOGValue=PWMSlope(10,00,20,55,11,100,240,RDT_MoonLightANALOGValue);
      }
      else
      {
         //RDT_ActinicPWMValue=0;
         RDT_MoonLightANALOGValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//_____________________________________________________________________________________________________________
    // - Turns LDT - B/UV channel to 0% power between 9:05 p.m. and 10:15 p.m. to conserve energy
    // - RA Standard Power Unit - LDT Blue/UV -
    // - Parabola dimming 11%-100%-11%
//_____________________________________________________________________________________________________________
     if ((NumMins(hour(now()),minute(now())) > NumMins(10,15)) && (NumMins(hour(now()),minute(now())) < NumMins(21,05)))
     {
        //LDT_ActinicPWMValue=PWMSlope(10,15,21,05,11,100,240,LDT_ActinicPWMValue);
        LDT_MoonLightANALOGValue=PWMSlope(10,15,21,05,11,100,240,LDT_MoonLightANALOGValue);
      }
      else
      {
        //LDT_ActinicPWMValue=0;
        LDT_MoonLightANALOGValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//_____________________________________________________________________________________________________________
    // - Turns RDT - W/C channel to 0% power between 8:30 p.m. and 10:25 a.m. to conserve energy
    // - Dimming Expansion - RDT White/Color -
    // - Parabola dimming 11%-50%-11%
//_____________________________________________________________________________________________________________
     if ((NumMins(hour(now()),minute(now())) > NumMins(10,25)) && (NumMins(hour(now()),minute(now())) < NumMins(20,30)))
     {
        RDT_DaylightPWMValue=PWMSlope(10,25,20,30,11,50,240,RDT_DaylightPWMValue);
      }
      else
      {
        RDT_DaylightPWMValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//_____________________________________________________________________________________________________________
    // - Turns LDT - W/C channel to 0% power between 8:45 p.m. and 10:35 a.m. to conserve energy
    // - RA Power Unit - LDT White/Color -
    // - Parabola dimming 11%-50%-11%
//_____________________________________________________________________________________________________________
     if ((NumMins(hour(now()),minute(now())) > NumMins(10,35)) && (NumMins(hour(now()),minute(now())) < NumMins(20,45)))
     {
        LDT_DaylightPWMValue=PWMSlope(10,35,20,45,11,50,240,LDT_DaylightPWMValue);
      }
      else
      {
        LDT_DaylightPWMValue=0;
      }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                   //// Set MoonLights Cycles ////
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    //LDT_MoonLightANALOGValue=PWMSlope(10,30,21,00,10,100,240,PWMSlope(21,20,23,15,20,MoonPhase()/5+10,30,LDT_MoonLightANALOGValue=0));
    LDT_ActinicPWMValue=PWMSlope(10,30,21,00,10,100,240,PWMSlope(21,20,23,15,20,MoonPhase()/5+10,30,LDT_ActinicPWMValue=0));
    //RDT_MoonLightANALOGValue=PWMSlope(10,20,20,50,10,100,240,PWMSlope(21,15,23,15,20,MoonPhase()/5+10,30,RDT_MoonLightANALOGValue=0));
    RDT_ActinicPWMValue=PWMSlope(10,20,20,50,10,100,240,PWMSlope(21,15,23,15,20,MoonPhase()/5+10,30,RDT_ActinicPWMValue=0));

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    CheckCloud();
    ReefAngel.PWM.SetDaylight(LDT_DaylightPWMValue);
    ReefAngel.PWM.SetActinic(LDT_ActinicPWMValue);
    ReefAngel.PWM.SetChannel(LEDPWM2,LDT_MoonLightANALOGValue);
    ReefAngel.PWM.SetChannel(LEDPWM0,RDT_DaylightPWMValue);
    ReefAngel.PWM.SetChannel(LEDPWM1,RDT_ActinicPWMValue);
    ReefAngel.PWM.SetChannel(LEDPWM3,RDT_MoonLightANALOGValue);
//_________________________________________________________________________________________________

    ////// Place your custom code above here //////
 
    //Connects Reef Angel Head Unit to the Portal through WiFi Unit.
    ReefAngel.Portal("troubadour11");
    // This should always be the last line
    ReefAngel.ShowInterface();
}


//************************************************************************************************************************************************************************************************************************
  // - My lighting is set up as:
  //      - LDT (Left Display Tank) fixture on the "Standard" 2 (PWM signal) slots on my power relay box.
  //      - RDT (Right Display Tank) fixture on channels 0=daylight and 1=actinic (PWM signal) of the Dimming Expansion.
  //      - Moonlights = channels 2 and 3 of the PWM expansion. These drivers are Analog and the jumper pins have been set for 0-10v Analog in Dimming Expansion.
 
 // - I'd like to calculate the cloud effect for the LDT lights using the "Weather Sim for Standard PWM" code which I think
 //   I got copied, set up, and working correctly for the 1 fixture on the Standard Ports.
 //                 - Then find a way to feed those values into the RDT lights with a "Random Sample" of + or - a small time offset for the cloud effect on the RDT
 //                                - This way I could randomly generate a weather sim, and randomly have the cloud move Right-to-Left or Left-to-Right each time a cloud occurs

//                  - Lightning effect could either be off set with a similar way with +/- value OR left sync'd to LDT lightning (would need to test what looks good).
//                  - Or possibly more or less lightning per fixture during cloud.
//*************************************************************************************************************************************************************************************************************************

// 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
  // I should create a random variable here to randomize the days it has clouds?
#define Clouds_Every_X_Days 1

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

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

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

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

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

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

  // Always end the cloud effect before this setting
     // In this example, end must be before 6:45pm
#define End_Cloud_Before NumMins(19,45)

  // Percentage chance of lightning happening 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 50
 
  // Note: Make sure to choose correct values that will work within your PWMSLope settings.
  // For example, in our case, we could have a max of 5 clouds per day and they could last for 50 minutes.
  // Which could mean 250 minutes of clouds. We need to make sure the PWMSlope can accomodate 250 minutes of effects or unforseen results could happen.
    // Also, make sure that you can fit double those minutes between Start_Cloud_After and End_Cloud_Before.
  // In our example, we have 510 minutes between Start_Cloud_After and End_Cloud_Before, so double the 250 minutes (or 500 minutes) can fit in that 510 minutes window.
    // It's a tight fit, but it did.
//____________________________________________________________________________________________________________________________________________________________
  //***Question***
  // Why do you have to double the amount of time from 250 to 500 in your example? - This is just a question to understand the programming better, I don't see why it needs to be doubled.
  // I see it in the code dividing by (numclouds*2), etc. What's the purpose of multiplying it up by 2? I'm just trying to learn on this question if you have time to explain. Thanks :-)
//____________________________________________________________________________________________________________________________________________________________

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


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

  static byte cloudchance = 255;
  static byte cloudduration=0;
  static int cloudstart=0;
  static byte numclouds=0;
  //made individual lightningchance for each fixture
  static byte LDTlightningchance=0;
  //static byte RDTlightningchance=0;
  static byte cloudindex=0;
  //made separate lightning status for each fixture
  static byte LDTlightningstatus=0;
  //static byte RDTlightningstatus=0;
  static int LastNumMins=0;
//********************************************************************************************************************************************************
  // - I created this value to use as +/- offset value to make clouds pass left-to-right or vice-versa.
  //static int RDTcloudstartOffset=0;

  // - I added this to use as a randomly chosen value between (-)x to y.
  // - This will be added to "cloudstart" in order to determine the start time of the RDT cloud effect.
  //static byte RDTcloudstart=0;

  // - I added this to create a random sample between 80% and 100% dimming power for "random" lightning intensity effect on each fixture.
  static byte LDT_LightningFlashPower=0;
  static byte RDT_LightningFlashPower=0;

  // - I added these to create a variable to randomize when and how long each lightning strike happens for each cloud.
  //LDTlightningRandomStart=0;
  //LDTlightningLength=0;
  //RDTlightningRandomStart=0;
  //RDTlightningLength=0;
//********************************************************************************************************************************************************


  // Every day at midnight, we check for chance of cloud happening today
  if (hour()==0 && minute()==0 && second()==0) cloudchance=255;

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

//********************************************************************************************************************************************************
        // pick a random number between these values to offset the RDT cloud by this many minutes
        //RDTcloudstartOffset=random(-1,1);
        // adds the random offset value to "cloudstart" and sets the cloudstart time for RDT light fixture
        //RDTcloudstart=cloudstart+RDTcloudstartOffset;
//********************************************************************************************************************************************************

        // 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
        LDTlightningchance=random(100);
        //RDTlightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning on the next cloud.
        if (LDTlightningchance>Lightning_Change_per_Cloud) LDTlightningchance=0;
        //if (RDTlightningchance>Lightning_Change_per_Cloud) RDTlightningchance=0;
      }
    }
  // Now that we have all the parameters for the cloud, let's create the effect down below.

// Force Cloud from Menu Function jumps to here to start cloud effect immediately for a show!
if (ForceCloud)
{
ForceCloud=false;
cloudchance=1;
cloudduration=8;
LDTlightningchance=1;
//RDTlightningchance=1;
cloudstart=NumMins(hour(),minute())+2;
//RDTcloudstart=NumMins(hour(),minute())+1;
//RDTcloudstartOffset=random(-1,1);
//RDTcloudstart=cloudstart+RDTcloudstartOffset;
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // - Controls Cloud and Lightning Effect timings for both fixtures
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  if (cloudchance)
  {
    //is it time for cloud yet over Left Display Tank?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      // - Dims LDT to create cloud and back up to Daylight Parabola. - maybe change to 11 in order to make minimum cloud power 11% so the lights don't click off.
      RDT_DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,RDT_DaylightPWMValue,10,180);
      LDT_DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,LDT_DaylightPWMValue,10,180);
      RDT_ActinicPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,RDT_DaylightPWMValue,20,180);
      LDT_ActinicPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,LDT_DaylightPWMValue,20,180);
      RDT_MoonLightANALOGValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,RDT_MoonLightANALOGValue,11,180);
      LDT_MoonLightANALOGValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,LDT_MoonLightANALOGValue,11,180);

      // To adjust possible length of time of lightning strike, Change the "second()< 5 " ... where 5 is the # of seconds of lightning during cloud.
      // and the "minute())=(cloudstart_(cloudduration/2)))" sets start time... dividing by 2 is exactly half way through cloud to trigger 5 seconds lightning.
      // if there is lightning and current time is 1/2 way through cloud, but less then 1/2 way through cloud + 5 seconds

     // if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/LDTlightningRandomStart))) && second()<LDTlightningLength)
      if (LDTlightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5)
      {
        if (random(100)<20) LDTlightningstatus=1;
        else LDTlightningstatus=0;
        if (LDTlightningstatus)
        {
               // - This will correctly flash lightning up to 100% power every lightning strike.
          //LDT_DaylightPWMValue=100;
          //LDT_ActinicPWMValue=100;
//_______________________________________________________________________________________________________
          // - Trying to make a random sample between, say 80% & 100% for the brightness of the lightning?
          // - If there will be lightning, pick a random number between 80 and 100 for the lightning power.
          LDT_LightningFlashPower=random(80,100);
          RDT_LightningFlashPower=random(80,100);

          RDT_DaylightPWMValue=RDT_LightningFlashPower;
          RDT_ActinicPWMValue=RDT_LightningFlashPower;
          RDT_MoonLightANALOGValue=RDT_LightningFlashPower;
          LDT_DaylightPWMValue=LDT_LightningFlashPower;
          LDT_ActinicPWMValue=LDT_LightningFlashPower;
          LDT_MoonLightANALOGValue=LDT_LightningFlashPower;
//_______________________________________________________________________________________________________
        }
        else
        {
          // - Changed these values from 0 to 11 so at end of lightning cycle, the go to min. 11% power
          RDT_DaylightPWMValue=11;
          RDT_ActinicPWMValue=20;
          RDT_MoonLightANALOGValue=11;
          LDT_DaylightPWMValue=11;
          LDT_ActinicPWMValue=20;
          LDT_MoonLightANALOGValue=11;
//------------------------------------------------------------------
        }
        delay(1);
      }
    }
  }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      {
        cloudstart=random(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2),(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2))+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
//************************************************************************************************************************************************************************************************
//// - I think this resets the random offset and cloudstart time for the RDT Fixture to match the new/next "cloudstart" time if there will be another cloud today ////
//************************************************************************************************************************************************************************************************
        // pick a random number between these values to offset the RDT cloud by this many minutes
        //RDTcloudstartOffset=random(-1,1);
        // adds the random offset value to "cloudstart" and sets the cloudstart time for RDT light fixture
        //RDTcloudstart=cloudstart+RDTcloudstartOffset;
//***********************************************************************************************************************************************************************
        //Pick a random number between 0 and 99
        LDTlightningchance=random(100);
        //RDTlightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (LDTlightningchance>Lightning_Change_per_Cloud) LDTlightningchance=0;
        //if (RDTlightningchance>Lightning_Change_per_Cloud) RDTlightningchance=0;

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


I looked up both the example files and code examples here in the forum and I can't find anything that I'm doing incorrectly.

When I try to verify the code, I get the following error:
Code: Select all
The following features were automatically added:
Watchdog Timer
Version Menu

The following features were detected:
Dimming Expansion Module
Dimming Signal
Wifi Attachment
Date/Time Setup Menu
Custom Menu
2014 Main Screen
Extra Font - Medium Size (8x8 pixels)
Number of Menu Options: 8
sketch_sept_11a_delayedOn.cpp: In function 'void setup()':
sketch_sept_11a_delayedOn:148: error: 'class ReefAngelClass' has no member named 'DelayedOn'


I was previously already running libraries 1.1.3 but had upgraded them from an old installer. Since it was not finding the class, I backed up my sketches, uninstalled the controller, deleted my documents/arduino and programs/arduino folders, restarted the computer, and re-installed from the ReefAngelInstaller_1.1.3 installer.

When I opened it back up, I'm still getting the same error. Based off the reference material I found, I'm not sure how else I'm supposed to use it in order to get it to function.
Previous

Return to My PDE/INO file

Who is online

Users browsing this forum: No registered users and 3 guests