Where to put additional code

Share you PDE file with our community
Post Reply
jedimasterben
Posts: 25
Joined: Tue Dec 25, 2012 5:17 pm

Where to put additional code

Post by jedimasterben »

Hello all! I just ordered my RA yesterday and can't wait to get it! I should have added the wifi and PWM dimming expansions, but some stuff on eBay hasn't sold yet, so they'll be about a week behind, but I will go ahead and get the programming down (hopefully, experts here willing :D) for all of it. In the future, the RF and salinity expansions will be coming, but all of that in due time.

A bit about my tank. It's 80g (48x24x16), and I've got two MP10wES in the tank for flow. I really wish I had repaired my third one instead of selling it off. Oh well. My sump is a 40B (but probably gonna change it to a series of 10/20g tanks) with a section containing a powerful algae scrubber and the other section housing about 20 gallons of macros. All is LED-lit, the main tank has a four-channel full spectrum array run on Meanwel ELN-60-48P, and the algae scrubber and fuge have deep red/royal blue based arrays run on Meanwell LPC-35-700. I'm also running a reactor for Purigen and Rox 0.8 carbon.


I went ahead and generated a code via the RA Wizard, and here's what I got:

Code: Select all

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

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


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


void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port1Bit | Port2Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = Port7Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = 0;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    // Set the Overheat temperature setting
    InternalMemory.OverheatTemp_write( 820 );


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

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

    ////// Place additional initialization code above here
}

void loop()
{
    ReefAngel.StandardATO( Port2,300 );
    ReefAngel.StandardLights( Port3,21,0,9,0 );
    ReefAngel.StandardLights( Port4,18,0,12,0 );
    ReefAngel.DosingPumpRepeat( Port5,0,60,60 );
    ReefAngel.DosingPumpRepeat( Port6,30,60,60 );
    ReefAngel.StandardLights( Port7,6,0,21,0 );
    ReefAngel.DosingPumpRepeat( Port8,0,30,60 );
    ReefAngel.PWM.SetChannel( 0, PWMParabola(9,0,19,0,12,60,12) );
    ReefAngel.PWM.SetChannel( 1, PWMParabola(8,0,21,0,12,100,12) );
    ReefAngel.PWM.SetChannel( 2, PWMParabola(9,0,19,0,12,75,12) );
    ReefAngel.PWM.SetChannel( 3, PWMParabola(8,0,20,0,12,100,12) );
    ReefAngel.PWM.SetChannel( 4, MoonPhase() );
    ReefAngel.PWM.SetChannel( 5, MoonPhase() );
    ////// Place your custom code below here
    

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

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

void DrawCustomMain()
{
    int x,y;
    char text[10];
    // Dimming Expansion
    x = 15;
    y = 2;
    for ( int a=0;a<6;a++ )
    {
      if ( a>2 ) x = 75;
      if ( a==3 ) y = 2;
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x,y,"Ch :" );
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+12,y,a );
      ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,x+24,y,ReefAngel.PWM.GetChannelValue(a) );
      y += 10;
    }
    pingSerial();

    // Parameters
#if defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 43, ReefAngel.Params,
    ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue() );
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor( 15, 43, ReefAngel.Params );
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
    pingSerial();

    // Main Relay Box
    byte TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;
    ReefAngel.LCD.DrawOutletBox( 12, 84, TempRelay );
    pingSerial();

    // Date and Time
    ReefAngel.LCD.DrawDate( 6, 122 );
    pingSerial();
}

void DrawCustomGraph()
{
}

There are a few things that I want to add on top of that, but, frankly, I'm not sure how. I'd say I'm tech savvy, but when it comes to Arduino code, I know pretty much nothing.

I would like to rename the ports on the relay so I can remember which is which. :)

I would like to do sunrise/sunset based on location. I'd like to use the sunrise/sunset times for the Great Barrier Reef, but adjusted for my time zone (so length of day is the same as the GBR). (I can't post links or I'd link the thread)

I would like to do weather effects with clouds on all channels but lightning only on channels 0 and 2, if that's possible.

I would like to do moon phase using one of the RA moonlight units (I think that is built in to the code I have above, maybe?)

I would like to have the option to force cloud cover and a storm from the menu.

That's all I can really think of for now. If anyone can lend a hand in how to modify the existing codes for that stuff and where the code should go I'd appreciate it! This is all new to me and is very confusing!
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Where to put additional code

Post by rimai »

Welcome!!!
The port's don't show on the screen. Only numbers.
There has been a couple people that created custom screens with names in it.
Here is one: http://forum.reefangel.com/viewtopic.php?p=11197#p11197
If you are talking about just in the code, we can do that too.
You can use something like this:

Code: Select all

#define Reactor Port1
Then, you can reference the word Reactor as if it was Port1.

Code: Select all

ReefAngel.Relay.On(Reactor);
Roberto.
jedimasterben
Posts: 25
Joined: Tue Dec 25, 2012 5:17 pm

Re: Where to put additional code

Post by jedimasterben »

Thank you for your reply, Roberto, your legendary service is very much appreciated. :D

Ok, so no port names on the screen, I'm cool with that, as long as they show up in the Wifi interface it's all good!




Reef Angel in da house! :mrgreen:

Ok, a bit of a change of plans. I won't be getting the PWM expansion immediately, only the Wifi expansion, but it is on a 2 week backorder. If I go ahead and program the unit now without the code for the wifi, how hard is it to change the code once the wifi unit arrives? As easy as just plugging the unit back in and uploading the new code like normal?

This is what I have right now, with cloud/storms on the stock PWM channels:
#define Return pump Port1
#define ATS pump Port2
#define Scrubber light Port3
#define Fuge light Port4
#define Calcium doser Port5
#define Alk doser Port6
#define Food doser Port7
#define Main LED fan Port8

#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 <ReefAngel.h>

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


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


void setup()
{
// This must be the first line
ReefAngel.Init(); //Initialize controller
ReefAngel.AddStandardMenu(); // Add Standard Menu

// Ports toggled in Feeding Mode
ReefAngel.FeedingModePorts = Port1Bit;
// Ports toggled in Water Change Mode
ReefAngel.WaterChangePorts = Port1Bit;
// Ports toggled when Lights On / Off menu entry selected
ReefAngel.LightsOnPorts = Port3Bit | Port4Bit | Port8Bit;
// Ports turned off when Overheat temperature exceeded
ReefAngel.OverheatShutoffPorts = 0;
// Use T1 probe as temperature and overheat functions
ReefAngel.TempProbe = T1_PROBE;
ReefAngel.OverheatProbe = T1_PROBE;
// Set the Overheat temperature setting
InternalMemory.OverheatTemp_write( 820 );


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

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


////// Place additional initialization code above here
}

void loop()
{
ReefAngel.StandardLights( Port3,20,0,8,0 );
ReefAngel.StandardLights( Port4,18,0,12,0 );
ReefAngel.DosingPumpRepeat( Port5,0,60,60 );
ReefAngel.DosingPumpRepeat( Port6,30,60,60 );
ReefAngel.DosingPumpRepeat( Port7,0,30,60 );
ReefAngel.StandardLights( Port8,6,0,22,0 );
ReefAngel.PWM.SetDaylight( PWMParabola(8,0,20,0,12,80,12) );
ReefAngel.PWM.SetActinic( PWMParabola(7,0,21,0,12,100,12) );
////// Place your custom code below here
//*********************************************************************************************************************************
// Random Cloud/Thunderstorm effects function
void CheckCloud()
{

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

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

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

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

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

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

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

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

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

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

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

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


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

static byte cloudchance=255;
static byte cloudduration=0;
static int cloudstart=0;
static byte numclouds=0;
static byte lightningchance=0;
static byte cloudindex=0;
static byte lightningstatus=0;
static int LastNumMins=0;
// 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 for the cloud duration of first cloud.
cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
//Pick a random number between 0 and 99
lightningchance=random(100);
// if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
}
}
// Now that we have all the parameters for the cloud, let's create the effect

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

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

byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
long n=elapsedSecsToday(now());
cstart*=60;
cend*=60;
if (n<cstart) return PWMStart;
if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
if (n>cend) return PWMStart;
}

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

// This should always be the last line
ReefAngel.ShowInterface();
}
I would like to integrate this, though: http://forum.reefangel.com/viewtopic.php?f=12&t=1627 (still can't post links, but put a period in there)

I went to the last page and there were several things posted with a couple of files attached in a .cpp and a .h file, but I don't know what those are or how to implement them. AFAIK, it was written only for the PWM expansion channels and not the stock channels. Any advice as far as that goes?
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Where to put additional code

Post by rimai »

Yeah, you can see the labels in any of the apps :)
I changed your code for you.
Here is the original thread:
http://forum.reefangel.com/viewtopic.php?f=14&t=288

Code: Select all

#define Return pump Port1
#define ATS pump Port2
#define Scrubber light Port3
#define Fuge light Port4
#define Calcium doser Port5
#define Alk doser Port6
#define Food doser Port7
#define Main LED fan Port8

#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 <ReefAngel.h>

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

byte ActinicPWMValue=0;
byte DaylightPWMValue=0;

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


void setup()
{
 // This must be the first line
 ReefAngel.Init(); //Initialize controller
 ReefAngel.AddStandardMenu(); // Add Standard Menu

 // Ports toggled in Feeding Mode
 ReefAngel.FeedingModePorts = Port1Bit;
 // Ports toggled in Water Change Mode
 ReefAngel.WaterChangePorts = Port1Bit;
 // Ports toggled when Lights On / Off menu entry selected
 ReefAngel.LightsOnPorts = Port3Bit | Port4Bit | Port8Bit;
 // Ports turned off when Overheat temperature exceeded
 ReefAngel.OverheatShutoffPorts = 0;
 // Use T1 probe as temperature and overheat functions
 ReefAngel.TempProbe = T1_PROBE;
 ReefAngel.OverheatProbe = T1_PROBE;
 // Set the Overheat temperature setting
 InternalMemory.OverheatTemp_write( 820 );


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

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


 ////// Place additional initialization code above here
}

void loop()
{
 ReefAngel.StandardLights( Port3,20,0,8,0 );
 ReefAngel.StandardLights( Port4,18,0,12,0 );
 ReefAngel.DosingPumpRepeat( Port5,0,60,60 );
 ReefAngel.DosingPumpRepeat( Port6,30,60,60 );
 ReefAngel.DosingPumpRepeat( Port7,0,30,60 );
 ReefAngel.StandardLights( Port8,6,0,22,0 );
 ////// Place your custom code below here

  ActinicPWMValue=PWMParabola(8,0,20,0,12,80,12) ;
  DaylightPWMValue=PWMParabola(7,0,21,0,12,100,12);
  CheckCloud();
  ReefAngel.PWM.SetActinic(ActinicPWMValue);
  ReefAngel.PWM.SetDaylight(DaylightPWMValue);

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

 // This should always be the last line
 ReefAngel.Portal("jedimasterben");
 ReefAngel.ShowInterface();
}
// Random Cloud/Thunderstorm effects function
void CheckCloud()
{

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

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

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

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

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

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

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

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

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

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

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

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


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

 static byte cloudchance=255;
 static byte cloudduration=0;
 static int cloudstart=0;
 static byte numclouds=0;
 static byte lightningchance=0;
 static byte cloudindex=0;
 static byte lightningstatus=0;
 static int LastNumMins=0;
 // 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 for the cloud duration of first cloud.
 cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
 //Pick a random number between 0 and 99
 lightningchance=random(100);
 // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
 if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
 }
 }
 // Now that we have all the parameters for the cloud, let's create the effect

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

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

byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
 long n=elapsedSecsToday(now());
 cstart*=60;
 cend*=60;
 if (n<cstart) return PWMStart;
 if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
 if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
 if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
 if (n>cend) return PWMStart;
}
I also already added the wifi stuff... It's just one line...

Code: Select all

 ReefAngel.Portal("jedimasterben");
For the sunrise/sunset based on location, you should ask lnevo. I think he's got it on standard channels too.
Roberto.
jedimasterben
Posts: 25
Joined: Tue Dec 25, 2012 5:17 pm

Re: Where to put additional code

Post by jedimasterben »

Again with that legendary service! :)

Thank you very much for fixing my code, I knew I was gonna mess something up in it lol. Once I grab some velcro to get the main unit stuck where it needs to be, I'll get this puppy rolling!

And I'll definitely ask Inevo, thanks!
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Where to put additional code

Post by lnevo »

The sunrise/sunset code doesn't do anything with any channel :)

The standalone code calculates times.

The post with the attachment has instructions for use. It's as easy as unzipping the class zip file in your Libraries folder and adding a few statements.

I'll take a look at your code tomorrow if you can't figure it out. Hard to paste code on an iphone. The required code is only 2-3 lines...

Here's a question for Roberto. Can you use the StandardLight memory locations with the PWM ports? If not, then you'll need to use the function calls in your PWM calls to get the rise/set hour and minutes.

See what you can figure out, and we'll get you all squared away tomorrow, maybe even later tonight.

Happy New Year!!!
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Where to put additional code

Post by lnevo »

After you get the class installed in your libraries, you can use these functions to get the sunrise and sunset. You can assign the results to variables and then plug them into your schedules where needed or call them directly inside your PWMParabola function.

sl.GetRiseHour();
sl.GetRiseMinute();
sl.GetSetHour();
sl.GetSetMinute();

Like this:

ActinicPWMValue=PWMParabola(sl.GetRiseHour().sl.GetRiseMinute(),sl.GetSetHour(),sl.GetSetMinute(),12,80,12) ;
jedimasterben
Posts: 25
Joined: Tue Dec 25, 2012 5:17 pm

Re: Where to put additional code

Post by jedimasterben »

lnevo wrote:The sunrise/sunset code doesn't do anything with any channel :)

The standalone code calculates times.

The post with the attachment has instructions for use. It's as easy as unzipping the class zip file in your Libraries folder and adding a few statements.

I'll take a look at your code tomorrow if you can't figure it out. Hard to paste code on an iphone. The required code is only 2-3 lines...

Here's a question for Roberto. Can you use the StandardLight memory locations with the PWM ports? If not, then you'll need to use the function calls in your PWM calls to get the rise/set hour and minutes.

See what you can figure out, and we'll get you all squared away tomorrow, maybe even later tonight.

Happy New Year!!!
Ok, I extracted the folder to the /libraries folder, I got that down, but when I look at your post here:
lnevo wrote:Here is the latest code with the additions mentioned above. At this point, it should be feature complete and has been running for a while with no issues.

Installation: Just unzip the attached zip file into your libraries folder. To use in your code all you need to do is the following:

Code: Select all

// Add to includes
#include <SunLocation.h>

// Declare the object
SunLocation sl;

// In loop()
sl.CheckAndUpdate();
If you want to change the default coordinates from GBR:

Code: Select all

// In setup
sl.Init(latitude, longitude) // In decimal numbers (i.e. -18.285833, 147.699722)
If you want to set your offsets:

Code: Select all

sl.SetOffset(-9,0,-9,0); // rise_hour, rise_seconds, set_hour, set_seconds
If you use the default memory locations, you just need to declare the port for your Standard and Actinic lights as follows and the times will be set automatically

Code: Select all

ReefAngel.StandardLights( Port1 );
ReefAngel.ActinicLights( Port2 );
If you are hard coding or using the variables for other functions you can get the calculated results with the following functions

Code: Select all

sl.GetRiseHour();
sl.GetRiseMinute();
sl.GetSetHour();
sl.GetSetMinute();
Any questions on usage or improvements, feel free to discuss :)
and
lnevo wrote:After you get the class installed in your libraries, you can use these functions to get the sunrise and sunset. You can assign the results to variables and then plug them into your schedules where needed or call them directly inside your PWMParabola function.

sl.GetRiseHour();
sl.GetRiseMinute();
sl.GetSetHour();
sl.GetSetMinute();

Like this:

ActinicPWMValue=PWMParabola(sl.GetRiseHour().sl.GetRiseMinute(),sl.GetSetHour(),sl.GetSetMinute(),12,80,12) ;
is where I get lost. I know the #include goes at the top with the rest of the #includes, but I really don't know where to put the rest of the stuff, or how to assign variables. I'd never even seen Arduino coding before I ordered the RA. :)

And then the offsets is where I change the time offset to my location, since I'm 16 hours behind the time at the GBR?
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Where to put additional code

Post by lnevo »

I will fill in your code when i get home.

What devices do you want based on sunrise/sunset?

What is your timezone?
jedimasterben
Posts: 25
Joined: Tue Dec 25, 2012 5:17 pm

Re: Where to put additional code

Post by jedimasterben »

lnevo wrote:I will fill in your code when i get home.

What devices do you want based on sunrise/sunset?

What is your timezone?
You're awesome. :)

Just my lights. I can't think of anything else I'd need based on the time.

Timezone is EST (-5:00)


Happy new year!
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Where to put additional code

Post by lnevo »

Well, you have a lot of "lights"...Algae Scrubber and Fuge light...I didn't mess with those at all, but hopefully you can see how to adjust those if you want them based on the functions from SunLocation... if not, let me know I can help you there as well.

I set the offset to -13 hours so that it would match the longest light cycle you had which was your DayLight PWM... typically this is your Actinics btw.. if you ever wanted to use the Memory locations and utilize the ActinicOffset, you'd need to reverse your setup.

This will put your light's on tomorrow at 6:56am and off at 8:47pm with your Actinic's on one hour after sunrise and one hour before sunset. Keep in mind that we are currently in the "long" days in GBR time... so as we get to summer, your light cycle will shrink.... The difference between winter and summer at GBR though is only 2hours... not as big as here in the US :)

Anyway, here's your code, verified in Arduino. I added comments as well for what I added and why.

Let me know if you have any questions and I can explain further.

Lee

Code: Select all

#define Return pump Port1
#define ATS pump Port2
#define Scrubber light Port3
#define Fuge light Port4
#define Calcium doser Port5
#define Alk doser Port6
#define Food doser Port7
#define Main LED fan Port8

#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 <ReefAngel.h>
#include <SunLocation.h>

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

byte ActinicPWMValue=0;
byte DaylightPWMValue=0;

// We declare this here so we can use it in multiple functions
SunLocation sl;

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


void setup()
{
// This must be the first line
ReefAngel.Init(); //Initialize controller
ReefAngel.AddStandardMenu(); // Add Standard Menu

// Ports toggled in Feeding Mode
ReefAngel.FeedingModePorts = Port1Bit;
// Ports toggled in Water Change Mode
ReefAngel.WaterChangePorts = Port1Bit;
// Ports toggled when Lights On / Off menu entry selected
ReefAngel.LightsOnPorts = Port3Bit | Port4Bit | Port8Bit;
// Ports turned off when Overheat temperature exceeded
ReefAngel.OverheatShutoffPorts = 0;
// Use T1 probe as temperature and overheat functions
ReefAngel.TempProbe = T1_PROBE;
ReefAngel.OverheatProbe = T1_PROBE;
// Set the Overheat temperature setting
InternalMemory.OverheatTemp_write( 820 );

// Since we only need to set OffSet once, then it can go in setup()
// Great Barrier reef is currently +15 hours from us. 
// Current GBR Rise/Set is 4:56am/6:47am
// Instead of subtracing the 15 hours, I only subtracted 13.
// This will make it close to your 7am-9pm light cycle.
sl.SetOffset(-13,472,-13,506); // The 472/506 were corrections I made to the formula, you can leave them or set them to 0 if you want.

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

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


////// Place additional initialization code above here
}

void loop()
{
ReefAngel.StandardLights( Port3,20,0,8,0 );
ReefAngel.StandardLights( Port4,18,0,12,0 );
ReefAngel.DosingPumpRepeat( Port5,0,60,60 );
ReefAngel.DosingPumpRepeat( Port6,30,60,60 );
ReefAngel.DosingPumpRepeat( Port7,0,30,60 );
ReefAngel.StandardLights( Port8,6,0,22,0 );
////// Place your custom code below here

  // Each day we're going to update Sunrise/Sunset, so it's part of the loop() function
  sl.CheckAndUpdate();

  // We've replaced the 7,0,21,0 with the Rise/Set Hour/Minute. Current GBR Rise/Set is 4:56am/6:47am
  DaylightPWMValue=PWMParabola(sl.GetRiseHour(),sl.GetRiseMinute(),sl.GetSetHour(),sl.GetSetMinute(),12,100,12);
  // We've replaced the 8,0,20,0 with the Rise/Set Hour/Minute +1/-1 to from GBR Rise/Set
  ActinicPWMValue=PWMParabola(sl.GetRiseHour()+1,sl.GetRiseMinute(),sl.GetSetHour()-1,sl.GetSetMinute(),12,80,12) ;
  CheckCloud();
  ReefAngel.PWM.SetActinic(ActinicPWMValue);
  ReefAngel.PWM.SetDaylight(DaylightPWMValue);

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

// This should always be the last line
ReefAngel.Portal("jedimasterben");
ReefAngel.ShowInterface();
}
// Random Cloud/Thunderstorm effects function
void CheckCloud()
{

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

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

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

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

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

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

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

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

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

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

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

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


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

static byte cloudchance=255;
static byte cloudduration=0;
static int cloudstart=0;
static byte numclouds=0;
static byte lightningchance=0;
static byte cloudindex=0;
static byte lightningstatus=0;
static int LastNumMins=0;
// 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 for the cloud duration of first cloud.
cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
//Pick a random number between 0 and 99
lightningchance=random(100);
// if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
}
}
// Now that we have all the parameters for the cloud, let's create the effect

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

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

byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
long n=elapsedSecsToday(now());
cstart*=60;
cend*=60;
if (n<cstart) return PWMStart;
if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
if (n>cend) return PWMStart;
}
jedimasterben
Posts: 25
Joined: Tue Dec 25, 2012 5:17 pm

Re: Where to put additional code

Post by jedimasterben »

lnevo wrote:Well, you have a lot of "lights"...Algae Scrubber and Fuge light...I didn't mess with those at all, but hopefully you can see how to adjust those if you want them based on the functions from SunLocation... if not, let me know I can help you there as well.

I set the offset to -13 hours so that it would match the longest light cycle you had which was your DayLight PWM... typically this is your Actinics btw.. if you ever wanted to use the Memory locations and utilize the ActinicOffset, you'd need to reverse your setup.

This will put your light's on tomorrow at 6:56am and off at 8:47pm with your Actinic's on one hour after sunrise and one hour before sunset. Keep in mind that we are currently in the "long" days in GBR time... so as we get to summer, your light cycle will shrink.... The difference between winter and summer at GBR though is only 2hours... not as big as here in the US :)

Anyway, here's your code, verified in Arduino. I added comments as well for what I added and why.

Let me know if you have any questions and I can explain further.

Lee

Code: Select all

#define Return pump Port1
#define ATS pump Port2
#define Scrubber light Port3
#define Fuge light Port4
#define Calcium doser Port5
#define Alk doser Port6
#define Food doser Port7
#define Main LED fan Port8

#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 <ReefAngel.h>
#include <SunLocation.h>

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

byte ActinicPWMValue=0;
byte DaylightPWMValue=0;

// We declare this here so we can use it in multiple functions
SunLocation sl;

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


void setup()
{
// This must be the first line
ReefAngel.Init(); //Initialize controller
ReefAngel.AddStandardMenu(); // Add Standard Menu

// Ports toggled in Feeding Mode
ReefAngel.FeedingModePorts = Port1Bit;
// Ports toggled in Water Change Mode
ReefAngel.WaterChangePorts = Port1Bit;
// Ports toggled when Lights On / Off menu entry selected
ReefAngel.LightsOnPorts = Port3Bit | Port4Bit | Port8Bit;
// Ports turned off when Overheat temperature exceeded
ReefAngel.OverheatShutoffPorts = 0;
// Use T1 probe as temperature and overheat functions
ReefAngel.TempProbe = T1_PROBE;
ReefAngel.OverheatProbe = T1_PROBE;
// Set the Overheat temperature setting
InternalMemory.OverheatTemp_write( 820 );

// Since we only need to set OffSet once, then it can go in setup()
// Great Barrier reef is currently +15 hours from us. 
// Current GBR Rise/Set is 4:56am/6:47am
// Instead of subtracing the 15 hours, I only subtracted 13.
// This will make it close to your 7am-9pm light cycle.
sl.SetOffset(-13,472,-13,506); // The 472/506 were corrections I made to the formula, you can leave them or set them to 0 if you want.

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

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


////// Place additional initialization code above here
}

void loop()
{
ReefAngel.StandardLights( Port3,20,0,8,0 );
ReefAngel.StandardLights( Port4,18,0,12,0 );
ReefAngel.DosingPumpRepeat( Port5,0,60,60 );
ReefAngel.DosingPumpRepeat( Port6,30,60,60 );
ReefAngel.DosingPumpRepeat( Port7,0,30,60 );
ReefAngel.StandardLights( Port8,6,0,22,0 );
////// Place your custom code below here

  // Each day we're going to update Sunrise/Sunset, so it's part of the loop() function
  sl.CheckAndUpdate();

  // We've replaced the 7,0,21,0 with the Rise/Set Hour/Minute. Current GBR Rise/Set is 4:56am/6:47am
  DaylightPWMValue=PWMParabola(sl.GetRiseHour(),sl.GetRiseMinute(),sl.GetSetHour(),sl.GetSetMinute(),12,100,12);
  // We've replaced the 8,0,20,0 with the Rise/Set Hour/Minute +1/-1 to from GBR Rise/Set
  ActinicPWMValue=PWMParabola(sl.GetRiseHour()+1,sl.GetRiseMinute(),sl.GetSetHour()-1,sl.GetSetMinute(),12,80,12) ;
  CheckCloud();
  ReefAngel.PWM.SetActinic(ActinicPWMValue);
  ReefAngel.PWM.SetDaylight(DaylightPWMValue);

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

// This should always be the last line
ReefAngel.Portal("jedimasterben");
ReefAngel.ShowInterface();
}
// Random Cloud/Thunderstorm effects function
void CheckCloud()
{

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

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

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

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

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

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

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

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

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

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

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

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


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

static byte cloudchance=255;
static byte cloudduration=0;
static int cloudstart=0;
static byte numclouds=0;
static byte lightningchance=0;
static byte cloudindex=0;
static byte lightningstatus=0;
static int LastNumMins=0;
// 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 for the cloud duration of first cloud.
cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
//Pick a random number between 0 and 99
lightningchance=random(100);
// if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
}
}
// Now that we have all the parameters for the cloud, let's create the effect

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

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

byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
long n=elapsedSecsToday(now());
cstart*=60;
cend*=60;
if (n<cstart) return PWMStart;
if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
if (n>cend) return PWMStart;
}
Oh! lol. Just the main lights. They're actually controlled solely via PWM, so I'm not even putting them on a relay at this point. And I had gotten the daylight/actinics mixed up lol. No biggie, when I hook it all up tomorrow I'll just swap the two PWM ports physically. I've actually got four channels, but I keep violet and royal blue one the same time and percentage, and the neutral white and deep red/cyan/cool blue together, so technically I can do with just two channels.

And does this need the Wifi module to function properly, or is the coding built into the library I moved over?

Thanks for all your help, I appreciate it very much!
jedimasterben
Posts: 25
Joined: Tue Dec 25, 2012 5:17 pm

Re: Where to put additional code

Post by jedimasterben »

Well, I went to upload the code and it says that it is too large - 39,142 bytes of 32,256 maximum. :(


EDIT: I tried also removing all the // comments in the sketch and it still says it's too big. :(

EDIT 2: Didn't realize the default sketch would be 27,790 bytes.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Where to put additional code

Post by lnevo »

Comments do not take up space when compiled.

Unfortunately, it seems this feature may be too much for the plain RA. There may be some things Roberto can point you in to free up space on the RA. I know things like the time and date menu chew up a lot of space...

You could also consider getting the plus upgrade. There is a good chance we can get it squeezed in though, but I would worry about future upgrades.

Lee
jedimasterben
Posts: 25
Joined: Tue Dec 25, 2012 5:17 pm

Re: Where to put additional code

Post by jedimasterben »

lnevo wrote:Comments do not take up space when compiled.

Unfortunately, it seems this feature may be too much for the plain RA. There may be some things Roberto can point you in to free up space on the RA. I know things like the time and date menu chew up a lot of space...

You could also consider getting the plus upgrade. There is a good chance we can get it squeezed in though, but I would worry about future upgrades.

Lee
Even just doing the sketch that Roberto posted with storms (not even with the sunrise/set) was way too big. :(

Well, looks like instead of the wifi module I'll be getting the upgraded board.
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Where to put additional code

Post by binder »

I would remove the StandardMenu and switch to the Simple Menu. The Standard Menu takes up a lot of space. If you "must" have some of those features, then creating a custom menu would be the next best option for you. If you have to do some configurations, then I would simplify your main code and then do your configurations and lastly load up the simple menu.
jedimasterben
Posts: 25
Joined: Tue Dec 25, 2012 5:17 pm

Re: Where to put additional code

Post by jedimasterben »

binder wrote:I would remove the StandardMenu and switch to the Simple Menu. The Standard Menu takes up a lot of space. If you "must" have some of those features, then creating a custom menu would be the next best option for you. If you have to do some configurations, then I would simplify your main code and then do your configurations and lastly load up the simple menu.
Frankly, I don't even know where to start with that. :(
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Where to put additional code

Post by rimai »

Remove this line:

Code: Select all

ReefAngel.AddStandardMenu(); // Add Standard Menu
Roberto.
jedimasterben
Posts: 25
Joined: Tue Dec 25, 2012 5:17 pm

Re: Where to put additional code

Post by jedimasterben »

rimai wrote:Remove this line:

Code: Select all

ReefAngel.AddStandardMenu(); // Add Standard Menu
lol, I swear I looked for anything 'Standard menu'. I removed that and it's down to 33,930 bytes, so still a fuzz too big!
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Where to put additional code

Post by lnevo »

If you remove the line to connect to the portal, it will drop the code to 27,378. You don't need this since you don't have the wifi yet (unless you are using the Windows Client to update the profile). But at least for now you can get the module up and working :)

ReefAngel.portal("jedimasterben");
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Where to put additional code

Post by lnevo »

jedimasterben wrote: Oh! lol. Just the main lights. They're actually controlled solely via PWM, so I'm not even putting them on a relay at this point. And I had gotten the daylight/actinics mixed up lol. No biggie, when I hook it all up tomorrow I'll just swap the two PWM ports physically. I've actually got four channels, but I keep violet and royal blue one the same time and percentage, and the neutral white and deep red/cyan/cool blue together, so technically I can do with just two channels.

And does this need the Wifi module to function properly, or is the coding built into the library I moved over?

Thanks for all your help, I appreciate it very much!
You should be ok without the wifi plugged in even if it's in the code. The last post though I had you remove the line that connects to the portal, so the portal will not be updated, but when you do get the wifi you should still be able to control it remotely and even use the portal, but you won't have history or alerts until you free up more memory or upgrade the controller or remove clouds or sunrise/sunset. A few ways to go...

As far as swapping ports, if you do flip the ports you may want to change the variable names or the settings for which one comes on first :) to reflect the change.
Post Reply