So it's been awhile since I was last in here. I spent some time messing with the actual aquarium rather then the code stuff for the RA unit lately.
I did get the custom menu I was working on previously up and running. So I can easily test my storm function when I try to develop it further. Right now I have it working where it's firing the clouds and everything randomly. I had to step back a bit and remove the delay's and offsets. When I was trying to get that, one fixture wouldn't run the cloud sim at all. So I rolled back to having them both run correctly at the same time and will work on building in the offset more in the future.
Right now I do have a couple questions that maybe someone could help me solve.
The first place I could use a little help is just getting a couple relay's on the power strip turning on/off according to my time schedule. When I looked in the example code for switching relays, it looked like the command
Code: Select all
ReefAngel.Relay.On( Port3 );
Here is the beginning of my code from the void setup() and into the beginning of the void loop(). The Refugium and Phyto lights are on Ports 3 and 4 as noted in the set up section. And the if/else statement to toggle the ports on/off according to time is basically the first bit of code in my loop. There is more code beyond what I've pasted here, but that all has to do with dimming the LEDs and the storm function mostly.
Code: Select all
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 | Port7Bit;
// 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 = UV Sterilizer
// 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()
{
ReefAngel.StandardHeater(Port1);
ReefAngel.StandardHeater(Port2);
////// Place your custom code below here //////
//Set up for Refugium and Phytoplankton light cycle
if ((NumMins(hour(now()),minute(now())) > NumMins(21,30)) && (NumMins(hour(now()),minute(now())) < NumMins(9,30)))
{
ReefAngel.Relay.On( Port3 );
ReefAngel.Relay.On( Port4 );
}
else
{
ReefAngel.Relay.Off( Port3 );
ReefAngel.Relay.Off( Port4 );
}
I believe I previously tried reversing the time and the less-than/greater-than signs in the if/else statement. But that didn't seem to work and was awhile ago now. I've just been manually changing it since.
Any ideas why I'm failing to get this command to work?
The second thing I've been trying to figure out is why my moonlight drivers don't turn down to 0% when not in use. I have them coded in a similar way to my other lights which all show 0% at the appropriate times. However my 2 moonlight drivers turn to 2% and 3% whenever they are not running the lights.
Here is the section of code in my loop that deals with the LED drivers:
Code: Select all
//*********************************************************************************************************************************************************
//// Calculate your regular sunrise/sunset PWM values ////
//*********************************************************************************************************************************************************
//_____________________________________________________________________________________________________________
// - Turns RDT - B/UV channel to 0% power between 8:30 p.m. and 11:00 a.m. to conserve energy
// - Dimming Expansion - LEDPWM1 - RDT Blue/UV -
// - Parabola dimming 11%-85%-11%
//_____________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(11,00)) && (NumMins(hour(now()),minute(now())) < NumMins(20,30)))
{
RDT_ActinicPWMValue=PWMParabola(11,00,20,30,11,85,RDT_ActinicPWMValue);
}
else
{
RDT_ActinicPWMValue=0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//_____________________________________________________________________________________________________________
// - Turns LDT - B/UV channel to 0% power between 9:00 p.m. and 11:15 p.m. to conserve energy
// - RA Standard Power Unit - LDT Blue/UV -
// - Parabola dimming 11%-85%-11%
//_____________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(11,15)) && (NumMins(hour(now()),minute(now())) < NumMins(21,00)))
{
LDT_ActinicPWMValue=PWMParabola(11,15,21,00,11,85,LDT_ActinicPWMValue);
}
else
{
LDT_ActinicPWMValue=0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//_____________________________________________________________________________________________________________
// - Turns RDT - W/C channel to 0% power between 8:30 p.m. and 11:25 a.m. to conserve energy
// - Dimming Expansion - RDT White/Color -
// - Parabola dimming 11%-60%-11%
//_____________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(11,25)) && (NumMins(hour(now()),minute(now())) < NumMins(20,30)))
{
RDT_DaylightPWMValue=PWMParabola(11,25,20,30,11,60,RDT_DaylightPWMValue);
}
else
{
RDT_DaylightPWMValue=0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//_____________________________________________________________________________________________________________
// - Turns LDT - W/C channel to 0% power between 9:00 p.m. and 11:40 a.m. to conserve energy
// - RA Power Unit - LDT White/Color -
// - Parabola dimming 11%-60%-11%
//_____________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(11,40)) && (NumMins(hour(now()),minute(now())) < NumMins(21,00)))
{
LDT_DaylightPWMValue=PWMParabola(11,40,21,00,11,60,LDT_DaylightPWMValue);
}
else
{
LDT_DaylightPWMValue=0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CheckCloud();
ReefAngel.PWM.SetDaylight(LDT_DaylightPWMValue);
ReefAngel.PWM.SetActinic(LDT_ActinicPWMValue);
ReefAngel.PWM.SetChannel(LEDPWM0,RDT_DaylightPWMValue);
ReefAngel.PWM.SetChannel(LEDPWM1,RDT_ActinicPWMValue);
//_________________________________________________________________________________________________
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//// Set MoonLights Cycles ////
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//_________________________________________________________________________________________________________________________________________________
// - Turns RDT Moonlights to 0% power between 11:15 p.m. and 9:15 p.m. to conserve energy.
// - Slope dimming 10% up to 1/5 * MoonPhase +10 (to offest for 10% min driver start power). Fades up to current Moonphase over 30 minutes.
// - Dimming Expansion - LEDPWM3 - RDT Moonlight - on @ 9:15 p.m. - off @ 11:15 p.m.
//_________________________________________________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(23,15)) && (NumMins(hour(now()),minute(now())) < NumMins(11,45)))
{
ReefAngel.PWM.SetChannel(LEDPWM3,0);
}
else if ((NumMins(hour(now()),minute(now())) > NumMins(11,40)) && (NumMins(hour(now()),minute(now())) < NumMins(20,30)))
{
ReefAngel.PWM.SetChannel(LEDPWM3,PWMParabola(11,40,20,30,10,30,LEDPWM3));
}
else
{
ReefAngel.PWM.SetChannel(LEDPWM3,PWMSlope(21,15,23,15,10,MoonPhase()/5+10,30,LEDPWM3));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//_________________________________________________________________________________________________________________________________________________
// - Turns LDT Moonlights to 0% power between 11:30 p.m. and 9:30 p.m. to conserve energy
// - Slope dimming - 10% up to 1/5 * MoonPhase +10 (to offest for 10% min driver start power). Fades up to current Moonphase over 30 minutes
// - Dimming Expansion - LEDPWM2 - LDT Moonlight - on @ 9:30 p.m. - off @ 11:30 a.m.
//_________________________________________________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(23,30)) && (NumMins(hour(now()),minute(now())) < NumMins(21,35)))
{
ReefAngel.PWM.SetChannel(LEDPWM2,0);
}
else if ((NumMins(hour(now()),minute(now())) > NumMins(11,55)) && (NumMins(hour(now()),minute(now())) < NumMins(21,00)))
{
ReefAngel.PWM.SetChannel(LEDPWM2,PWMParabola(11,55,21,00,10,30,LEDPWM2));
}
else
{
ReefAngel.PWM.SetChannel(LEDPWM2,PWMSlope(21,30,23,30,10,MoonPhase()/5+10,30,LEDPWM2));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
////// Place your custom code above here //////
My next step beyond asking for help is to try to create some variables for the moonlights similar to the variables I use for the daylight drivers. Then set the values that way and see if it fixes the issue. But I've been stuck on this for a bit now and thought someone might have a quick answer for me that would let me move on to other sections of the code.
Thanks
Oh, and here is the current version of my entire code all in one spot if you're interested in seeing that:
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 RDT_DaylightPWMValue=0;
byte RDT_ActinicPWMValue=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 | Port7Bit;
// 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 = UV Sterilizer
// 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 //////
//Set up for Refugium and Phytoplankton light cycle
if ((NumMins(hour(now()),minute(now())) > NumMins(21,30)) && (NumMins(hour(now()),minute(now())) < NumMins(9,30)))
{
ReefAngel.Relay.On( Port3 );
ReefAngel.Relay.On( Port4 );
}
else
{
ReefAngel.Relay.Off( Port3 );
ReefAngel.Relay.Off( Port4 );
}
//*********************************************************************************************************************************************************
//// Calculate your regular sunrise/sunset PWM values ////
//*********************************************************************************************************************************************************
//_____________________________________________________________________________________________________________
// - Turns RDT - B/UV channel to 0% power between 8:30 p.m. and 11:00 a.m. to conserve energy
// - Dimming Expansion - LEDPWM1 - RDT Blue/UV -
// - Parabola dimming 11%-85%-11%
//_____________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(11,00)) && (NumMins(hour(now()),minute(now())) < NumMins(20,30)))
{
RDT_ActinicPWMValue=PWMParabola(11,00,20,30,11,85,RDT_ActinicPWMValue);
}
else
{
RDT_ActinicPWMValue=0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//_____________________________________________________________________________________________________________
// - Turns LDT - B/UV channel to 0% power between 9:00 p.m. and 11:15 p.m. to conserve energy
// - RA Standard Power Unit - LDT Blue/UV -
// - Parabola dimming 11%-85%-11%
//_____________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(11,15)) && (NumMins(hour(now()),minute(now())) < NumMins(21,00)))
{
LDT_ActinicPWMValue=PWMParabola(11,15,21,00,11,85,LDT_ActinicPWMValue);
}
else
{
LDT_ActinicPWMValue=0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//_____________________________________________________________________________________________________________
// - Turns RDT - W/C channel to 0% power between 8:30 p.m. and 11:25 a.m. to conserve energy
// - Dimming Expansion - RDT White/Color -
// - Parabola dimming 11%-60%-11%
//_____________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(11,25)) && (NumMins(hour(now()),minute(now())) < NumMins(20,30)))
{
RDT_DaylightPWMValue=PWMParabola(11,25,20,30,11,60,RDT_DaylightPWMValue);
}
else
{
RDT_DaylightPWMValue=0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//_____________________________________________________________________________________________________________
// - Turns LDT - W/C channel to 0% power between 9:00 p.m. and 11:40 a.m. to conserve energy
// - RA Power Unit - LDT White/Color -
// - Parabola dimming 11%-60%-11%
//_____________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(11,40)) && (NumMins(hour(now()),minute(now())) < NumMins(21,00)))
{
LDT_DaylightPWMValue=PWMParabola(11,40,21,00,11,60,LDT_DaylightPWMValue);
}
else
{
LDT_DaylightPWMValue=0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CheckCloud();
ReefAngel.PWM.SetDaylight(LDT_DaylightPWMValue);
ReefAngel.PWM.SetActinic(LDT_ActinicPWMValue);
ReefAngel.PWM.SetChannel(LEDPWM0,RDT_DaylightPWMValue);
ReefAngel.PWM.SetChannel(LEDPWM1,RDT_ActinicPWMValue);
//_________________________________________________________________________________________________
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//// Set MoonLights Cycles ////
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//_________________________________________________________________________________________________________________________________________________
// - Turns RDT Moonlights to 0% power between 11:15 p.m. and 9:15 p.m. to conserve energy.
// - Slope dimming 10% up to 1/5 * MoonPhase +10 (to offest for 10% min driver start power). Fades up to current Moonphase over 30 minutes.
// - Dimming Expansion - LEDPWM3 - RDT Moonlight - on @ 9:15 p.m. - off @ 11:15 p.m.
//_________________________________________________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(23,15)) && (NumMins(hour(now()),minute(now())) < NumMins(11,45)))
{
ReefAngel.PWM.SetChannel(LEDPWM3,0);
}
else if ((NumMins(hour(now()),minute(now())) > NumMins(11,40)) && (NumMins(hour(now()),minute(now())) < NumMins(20,30)))
{
ReefAngel.PWM.SetChannel(LEDPWM3,PWMParabola(11,40,20,30,10,30,LEDPWM3));
}
else
{
ReefAngel.PWM.SetChannel(LEDPWM3,PWMSlope(21,15,23,15,10,MoonPhase()/5+10,30,LEDPWM3));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//_________________________________________________________________________________________________________________________________________________
// - Turns LDT Moonlights to 0% power between 11:30 p.m. and 9:30 p.m. to conserve energy
// - Slope dimming - 10% up to 1/5 * MoonPhase +10 (to offest for 10% min driver start power). Fades up to current Moonphase over 30 minutes
// - Dimming Expansion - LEDPWM2 - LDT Moonlight - on @ 9:30 p.m. - off @ 11:30 a.m.
//_________________________________________________________________________________________________________________________________________________
if ((NumMins(hour(now()),minute(now())) > NumMins(23,30)) && (NumMins(hour(now()),minute(now())) < NumMins(21,35)))
{
ReefAngel.PWM.SetChannel(LEDPWM2,0);
}
else if ((NumMins(hour(now()),minute(now())) > NumMins(11,55)) && (NumMins(hour(now()),minute(now())) < NumMins(21,00)))
{
ReefAngel.PWM.SetChannel(LEDPWM2,PWMParabola(11,55,21,00,10,30,LEDPWM2));
}
else
{
ReefAngel.PWM.SetChannel(LEDPWM2,PWMSlope(21,30,23,30,10,MoonPhase()/5+10,30,LEDPWM2));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
////// 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,50,180);
LDT_ActinicPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,LDT_DaylightPWMValue,50,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;
LDT_DaylightPWMValue=LDT_LightningFlashPower;
LDT_ActinicPWMValue=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=50;
LDT_DaylightPWMValue=11;
LDT_ActinicPWMValue=50;
//------------------------------------------------------------------
}
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
}