Let's Build Troubadour11's Code

Share you PDE file with our community
User avatar
Posts: 5420
Joined: Fri Jul 20, 2012 9:42 am
PostPosted: Sun May 05, 2019 9:56 pm
Yeah, you just need to use the function:

ReefAngel.DosingPumpRepeat1(Port7);

The built in libraries support up to 3 pumps with the default memory variables which you can set in the uapp or on the portal.

Posts: 25
Joined: Tue Nov 12, 2013 2:24 pm
PostPosted: Mon May 06, 2019 11:50 am
Excellent. Thank you for the help with this!

So if I'm reading and understanding it correctly, I'd just modify my code to be like this as you said:
ReefAngel.DosingPumpRepeat1(Port7);

instead of original code: ReefAngel.DosingPumpRepeat( Port7,0,120,5 );

- Then go into the Memory function in the phone app and do a Read Value on Dosing Pump 1 Repeat Interval (is this every "x" minutes from midnight?).
- once I've read the value (currently it gives back a value of 60)
- I can then type in 120? (which is a repeat interval of every 120 minutes, or every 2 hrs?) into the value field
- Then click the Write Value button to update to the desired value

If that is correct, it's making sense to me so far and should be easy enough to implement.

In the new code layout using the built-in library support for up to 3 pumps. Where do I set the amount of time the pump run will run for each time?
- Is that just a read/write adjustment on the "Dosing Pump 1 Timer" in the uapp memory like the Repeat Interval?

I also see the memory positions for the Dosing Pump 1 On Hour/Minute. Do these need to be set up as well drive the pump correctly via the above update? Or can it be run with just the Repeat Interval and Timer settings?

Thanks again. I'm really looking forward to finally getting access to the internal memory for adjusting some things as needed. I appreciate the help.
User avatar
Posts: 5420
Joined: Fri Jul 20, 2012 9:42 am
PostPosted: Mon May 06, 2019 5:01 pm
I would recommend using the Uapp instead of the old ReefAngel app. The Internal Memory section is just like the portal page and you can browse the fields instead of trying to peek/poke the values directly.

There is a separate variable for Mem_B_DP1Timer and Mem_I_DP1RepeatInterval.

Yes the 120 would be 2 hours repeat and the time would be what is set in the Mem_B_DP1Timer variable.

Posts: 25
Joined: Tue Nov 12, 2013 2:24 pm
PostPosted: Sat May 18, 2019 7:51 am
Thanks for the help getting the Dosing Pump variable set up.

I was able to get it uploaded to the head unit and can adjust it accordingly now with the app.

I also went back to put in the DelayedOn function for my skimmer.

Does this look correct?

ReefAngel.Relay.DelayedOn(Port6, 5);

I also removed Port6 from the "Always On" list for the power unit in the setup section. This is because we want it off initially and then let it be controlled by the above line of code in the main loop, correct?

The code checked out fine when I tested it. But I just wanted to have it double checked to make sure it wouldn't cause any issues.
User avatar
Posts: 5420
Joined: Fri Jul 20, 2012 9:42 am
PostPosted: Sat May 18, 2019 9:43 pm
Yes, leave off the ,5 if you want to set that in memory as well. :)

Posts: 25
Joined: Tue Nov 12, 2013 2:24 pm
PostPosted: Sat Jul 27, 2019 7:47 pm
Here's the latest version of my code which I'm currently running:

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 );
    ReefAngel.DosingPumpRepeat1(Port7);
   
//-----------------------------------------------------------------------------------------------------------------------------------------------------// 
    //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
}

Posts: 25
Joined: Tue Nov 12, 2013 2:24 pm
PostPosted: Sat Jul 27, 2019 8:07 pm
A question on setting up my refugium light cycles with variables in memory.

In my current code shared in the previous post I have this section setting up my refugium lights on ports 3 & 4.

I do not need the ability to ramp the lighting at all on the fuge. Just turn it on/off at said times like I have hard-coded in there now. But I would like to set up the code like we did for my dosing pump so I can modify it for longer/shorter photo-periods through the app instead of uploading new hard-coded numbers.

Here's what I'm currently using clipped out for reference.

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)
     ReefAngel.StandardLights(Port3,22,30,8,30);
     ReefAngel.StandardLights(Port4,22,30,8,30);


How do I call some of the pre-set memory slots to use for the simple on/off times? Do I use the code below, similar to how we set up the dosing pump repeat function?
ReefAngel.StandardLights(Port3);
ReefAngel.StandardLights(Port4);

Then set the custom variables for StdLights On Hour/Minute and StdLights Off Hour/Minute and that will drive the on/off times?

Thanks for any help you can offer.

My hope is to take this and grow it out to my LED light controls so I can adjust the on/off and ramp times through memory instead of hard-coding them as well.

Posts: 12509
Joined: Fri Mar 18, 2011 6:47 pm
PostPosted: Sat Jul 27, 2019 8:43 pm
Yeah, that should work.
Roberto.
Previous

Return to My PDE/INO file

Who is online

Users browsing this forum: No registered users and 1 guest

cron