Page 1 of 1

Virtual ports for light functions

Posted: Wed Jul 20, 2016 9:04 am
by DmnYnkee
Finally have lights working as they should (Thanks Lee!). Now I want to start working on code for basic custom functions. Will want weather later, but have not seen where Colin incorporated SunLocation into his cloud/lightnig code.

Here is my first attempt, but it will not compile.

Code: Select all

// Virtual Port Functions

if (ReefAngel.Relay.On( Box1_Port1 )); // Set Lights 60/40
{
ReefAngel.PWM.SetChannel(0,60);  // Actinic Left
ReefAngel.PWM.SetChannel(2,60);  // Actinic Center
ReefAngel.PWM.SetChannel(4,60);  // Actinic Right

ReefAngel.PWM.SetChannel(1,40);  // Daylight Left
ReefAngel.PWM.SetChannel(3,40);  // Daylight Center
ReefAngel.PWM.SetChannel(5,40);  // Daylight Right
}
  

I get the following error: could not convert 'ReefAngelClass::Relay.RelayClass::On(11u)'to 'boot'

Re: Virtual ports for light functions

Posted: Wed Jul 20, 2016 2:07 pm
by lnevo
Please post the full code and the full error message i think it got cut off

Re: Virtual ports for light functions

Posted: Wed Jul 20, 2016 2:20 pm
by DmnYnkee
Full code below.

The error message was complete, but the end may be 'bool' instead of 'boot'

This portion is highlighted with the error: if (ReefAngel.Relay.On( Box1_Port1 )); // Set Lights 60/40

Code: Select all

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


////// Place global variable code below here
  
  SunLocation sl;
  
  int avgph[10];
    unsigned long totalavgph=0;
    byte avgindex=0;

void DrawCustomMain()
    {
      byte x;
      byte y = 2;
      char text[7];

      // *********** CHANGE TEMP READOUT COLOR DEPENDENT ON FAN AND HEATER STATUS ***********
      int TempColor;                                    // Color for drawing temperature
      boolean HeatOn = ReefAngel.Relay.Status(Port6);   // Get the status of the heater relay
      if (HeatOn) 
      {
        TempColor = COLOR_NAVY;                         // Blue text, too cold, heater is on
      }

      if (!HeatOn) 
      {
          TempColor = COLOR_GREEN;                      // Green text, no fan or heater on
      }
      // ***********************************************************************************
             int pHColor;                                 // Color for drawing pH
      boolean LowpH = (ReefAngel.Params.PH < 780) ;     // Check for Low pH Value
      boolean HighpH = (ReefAngel.Params.PH > 850);     // Check for High pH Value
      if (LowpH) 
      {
        pHColor = COLOR_NAVY;                          // Blue text, Low pH value
      }
      if (HighpH)   
      {
        pHColor = COLOR_RED;                           // Red text, High pH value
      }
      if (!LowpH && !HighpH) 
      {
        pHColor = COLOR_GREEN;                         // Green text, pH acceptable
      }
      // ***********************************************************************************
      ReefAngel.LCD.DrawLargeText(COLOR_DARKSLATEBLUE,DefaultBGColor, 6, 3, " Thunder Reef",Font8x8);   // Put a banner at the top
      ReefAngel.LCD.DrawDate(6, 119);                                                                   // Put the date and time at the bottom
      ReefAngel.LCD.Clear(COLOR_BLACK, 1, 12, 132, 12);                                                 // Draw a black line under the banner
      x = 6;
      y += MENU_START_ROW*1.4;                                                                          // MENU_START_ROW is 10, according to globals.h, so y=2+10+1=13
      ReefAngel.LCD.DrawLargeText(COLOR_BLUE, COLOR_WHITE, x, y+1, " Temp      pH");

      ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);                                    // Get T1 temp and convert
      x = 2;
      y += MENU_START_ROW*1.6;
      ReefAngel.LCD.DrawHugeNumbers(COLOR_BLACK, TempColor, x, y, text);                                // Draw the temperature, white numbers on a colored background
      ConvertNumToString(text, ReefAngel.Params.PH, 100);                                               // Get pH reading and convert
      x = 2;
      y = MENU_START_ROW*2.6;
      ReefAngel.LCD.DrawHugeNumbers(COLOR_YELLOW, pHColor, x+65, y+6, text);                            // Put pH on the screen
     
      x += 6;
      y += MENU_START_ROW*3.3;
  ReefAngel.LCD.DrawLargeText(COLOR_INDIGO,DefaultBGColor,25,y,"Sump Level",Font8x8);      // Draw the Sump Float switch status
  if (ReefAngel.LowATO.IsActive())
  {ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_RED);
  }
  else
  {
  ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_GREEN);
  }
  x += 6;
  y += MENU_START_ROW*2.0;
  ReefAngel.LCD.DrawLargeText(COLOR_INDIGO,DefaultBGColor,25,y,"Skimmer Cup",Font8x8);     // Draw the Skimmer Cup Float switch status
  if (ReefAngel.HighATO.IsActive()) {ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_GREEN);
  }
  else
  {
  ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_RED);
  }
      
      
      byte TempRelay = ReefAngel.Relay.RelayData;                                          // Code for drawing the relay box
      TempRelay &= ReefAngel.Relay.RelayMaskOff;
      TempRelay |= ReefAngel.Relay.RelayMaskOn;
      ReefAngel.LCD.DrawOutletBox(12, 100, TempRelay);
   }
void DrawCustomGraph()
{
}



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


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


    // Ports that are always on
    ReefAngel.Relay.On( Port1 );
    
    // Delayed start for skimmer to allow sump level to return to normal after water change
    ReefAngel.Relay.DelayedOn( Port7,4 );

    ////// Place additional initialization code below here
   
    sl.Init(28.5708, -81.6995);    // Lat/long for Clermont, FL
    sl.SetOffset(-3,0,-3,0);       // rise_hour, rise_seconds, set_hour, set_seconds (set 1 hr later for better viewing time)

    randomSeed(now()%SECS_PER_DAY);
      
      //Custom Variable [0] =  Month/Season
    
    ReefAngel.CustomLabels[0]="Return";  
    ReefAngel.CustomLabels[1]="Daylights";  
    ReefAngel.CustomLabels[2]="Actinics";  
    ReefAngel.CustomLabels[3]="Fuge Light";  
    ReefAngel.CustomLabels[4]="Alk Dosing";  
    ReefAngel.CustomLabels[5]="Heater";  
    ReefAngel.CustomLabels[6]="Skimmer";  
    ReefAngel.CustomLabels[7]="ATO RoDi";  

    // Virtual Ports reserved for custom lighting functions and effects

    ReefAngel.CustomLabels[8]="Lights 60/40";  
    ReefAngel.CustomLabels[9]="Not Used";  
    ReefAngel.CustomLabels[10]="Not Used";  
    ReefAngel.CustomLabels[11]="Not Used";  
    ReefAngel.CustomLabels[12]="Weather";  
    ReefAngel.CustomLabels[13]="Weather";  
    ReefAngel.CustomLabels[14]="Weather";  
    ReefAngel.CustomLabels[15]="Weather";  


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

void loop()
{
  

    // seasonal temperatures
    SeasonalTemps();

// Lights on Dimming Expansion. (Left=East, Right=West)

ReefAngel.PWM.Channel0PWMParabola(0,-30);     // Actinic Left     - Starts at Sunrise, ends 30 minutes before Sunset
ReefAngel.PWM.Channel2PWMParabola(-15,-15);   // Actinic Center   - Starts 15 minute after Sunrise,  ends 15 minutes before Sunset
ReefAngel.PWM.Channel4PWMParabola(-30,0);     // Actinic Right    - Starts 30 minutes after Sunrise, ends at Sunset

ReefAngel.PWM.Channel1PWMParabola(-150,-180);  // Daylight Left   - Starts 150 minutes after Sunrise, ends 180 minutes before Sunset
ReefAngel.PWM.Channel3PWMParabola(-165,-165);  // Daylight Center - Starts 165 minutes after Sunrise, ends 165 minutes before Sunset 
ReefAngel.PWM.Channel5PWMParabola(-180,-150);  // Daylight Right  - Starts 180 minutes after Sunrise, ends 150 minutes before Sunset

// Turn Actinic outlet on if any % is >= 1
(ReefAngel.PWM.GetChannelValue(0)>=1 || ReefAngel.PWM.GetChannelValue(2)>=1 || ReefAngel.PWM.GetChannelValue(4)>=1) ?  ReefAngel.Relay.On( Port3 ) :  ReefAngel.Relay.Off( Port3 );

// Turn Daylight outlet on if any % is >=1   
(ReefAngel.PWM.GetChannelValue(1)>=1 || ReefAngel.PWM.GetChannelValue(3)>=1 || ReefAngel.PWM.GetChannelValue(5)>=1) ?  ReefAngel.Relay.On( Port2 ) : ReefAngel.Relay.Off( Port2 );

ReefAngel.MoonLights( Port4 );  // Refugium light.  Opposite Whites.

ReefAngel.DosingPumpRepeat( Port5,0,10,18 );
    
    
// Virtual Port Functions

if (ReefAngel.Relay.On( Box1_Port1 )); // Set Lights 60/40
{
ReefAngel.PWM.SetChannel(0,60);  // Actinic Left
ReefAngel.PWM.SetChannel(2,60);  // Actinic Center
ReefAngel.PWM.SetChannel(4,60);  // Actinic Right

ReefAngel.PWM.SetChannel(1,40);  // Daylight Left
ReefAngel.PWM.SetChannel(3,40);  // Daylight Center
ReefAngel.PWM.SetChannel(5,40);  // Daylight Right
}
  
    
    
    ////// Place your custom code below here

// Alk Dosing (1 tbs Baked Baking soda per gal), Port 5.  Between 9pm & 9am, Every 10 minutes run for 18 seconds.
if (hour()>=9 && hour()<21) ReefAngel.Relay.Off(Port5); 



// WP-25 powerheads schedule    
if (hour()>=9 && hour()<13)
{
 ReefAngel.PWM.SetDaylight( ReefCrestMode(52,12,true) ); // reefcrest at 55% +/- 12% on sync mode       (Day Mode)
 ReefAngel.PWM.SetActinic( ReefCrestMode(52,12,false) ); // reefcrest at 55% +/- 12% on Anti-sync mode  (Day mode)
}
else if (hour()>=13 && hour()<18)
{
 ReefAngel.PWM.SetDaylight( ShortPulseMode(1,68,408,true) ); // Short pulse at 68% with 408ms pulse on sync mode (3/4" surface wave)
 ReefAngel.PWM.SetActinic( ShortPulseMode(1,68,408,false) ); // Short pulse at 68% with 408ms pulse on Anti-sync mode (3/4" surface wave)
}
else if (hour()>=18 && hour()<19)
{
 ReefAngel.PWM.SetDaylight( LongPulseMode(35,70,2,true) ); // Long Pulse 35% ramping up to 70% for 2 seconds on sync mode (nutrient transport)
 ReefAngel.PWM.SetActinic( LongPulseMode(35,70,2,false) ); // Long Pulse 35% ramping up to 70% for 2 seconds on Anti-sync mode  (nutrient transport)
}
else if (hour()>=19 && hour()<20)
{
 ReefAngel.PWM.SetDaylight( ReefCrestMode(52,12,true) ); // reefcrest at 55% +/- 12% on sync mode       (Day Mode)
 ReefAngel.PWM.SetActinic( ReefCrestMode(52,12,false) ); // reefcrest at 55% +/- 12% on Anti-sync mode  (Day mode)
}
else
{
 ReefAngel.PWM.SetDaylight( ReefCrestMode(48,8,true) ); // reefcrest at 48% +/- 8% on sync mode       (night Mode)
 ReefAngel.PWM.SetActinic( ReefCrestMode(48,8,false) ); // reefcrest at 48% +/- 8% on Anti-sync mode  (night mode)
}
 
if( ReefAngel.DisplayedMenu==FEEDING_MODE )
{
 ReefAngel.PWM.SetActinic( LongPulseMode(0,37,1,true) );
 ReefAngel.PWM.SetDaylight( LongPulseMode(0,37,1,true) );
}

if( ReefAngel.DisplayedMenu==WATERCHANGE_MODE )
{
 ReefAngel.PWM.SetActinic(35);
 ReefAngel.PWM.SetDaylight(35);
}

// enter feeding mode at 11am & 5pm
 if ( (hour()==11 && minute()==0 && second()==0))
 {
 ReefAngel.FeedingModeStart(); // turn on feeding mode
 }
  if ( (hour()==17 && minute()==0 && second()==0))
 {
 ReefAngel.FeedingModeStart(); // turn on feeding mode
 }
 
 
if(ReefAngel.HighATO.IsActive())           //  Float switch in Skimmer Locker
{
ReefAngel.Relay.DelayedOn( Port7,4 );
}
 else
{
 ReefAngel.Relay.Off(Port7);               //  Turn off Skimmer when locker full.
}
 

// ATO, Port 8 is ATO using Clear RoDi

 ReefAngel.SingleATO(true,Port8,400,0);   //  Sump switch.  If ATO/RoDi runs for 400 seconds, then shut off and send alert.




 
  { 
    sl.CheckAndUpdate();  // handle updating sunrise and sunset values
  }
 
    ////// Place your custom code above here

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

 void SeasonalTemps ()
 {
  static int heatArray[][2] = { {796,800},                  // default in case of error in month=0 (June)
                    {781,785},//January (winter)            // 78.3
                    {784,788},//February (winter)           // 78.6
                    {787,791},//March (early spring)        // 78.9
                    {790,794},//April (spring)              // 79.2
                    {793,797},//May (spring)                // 79.5
                    {796,800},//June (early summer)         // 79.8
                    {799,803},//July (summer)               // 80.1
                    {802,806},//August (summer)             // 80.4
                    {798,802},//September (early fall)      // 80.0
                    {794,798},//October (fall)              // 79.6
                    {790,794},//November (fall)             // 79.2
                    {786,790} };//December (early winter)   // 78.8
                    
               
  ReefAngel.StandardHeater( Port6,heatArray[month()][0],heatArray[month()][1]);
 }//end seasonalTemps

Re: Virtual ports for light functions

Posted: Wed Jul 20, 2016 2:33 pm
by lnevo
Change On to Status :) you're doing a check there in an if statement.

Re: Virtual ports for light functions

Posted: Wed Jul 20, 2016 3:37 pm
by DmnYnkee
When port is switched off, will it go back to normal setting automatically?

Re: Virtual ports for light functions

Posted: Wed Jul 20, 2016 5:07 pm
by DmnYnkee
Well, it compiled at least, but did not work as intended. It just set lights at 60/40 no matter what position the port switch was in (on/off/auto). I commented the 60/40 code out for the moment.

Newest code below. Added the virtual ports as "always off", Applied the Status logic to turn on refugium light opposite my daylights, since I have the offsets spread on all 3 lights in my code.

Code: Select all

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


////// Place global variable code below here
  
  SunLocation sl;
  
  int avgph[10];
    unsigned long totalavgph=0;
    byte avgindex=0;

void DrawCustomMain()
    {
      byte x;
      byte y = 2;
      char text[7];

      // *********** CHANGE TEMP READOUT COLOR DEPENDENT ON FAN AND HEATER STATUS ***********
      int TempColor;                                    // Color for drawing temperature
      boolean HeatOn = ReefAngel.Relay.Status(Port6);   // Get the status of the heater relay
      if (HeatOn) 
      {
        TempColor = COLOR_NAVY;                         // Blue text, too cold, heater is on
      }

      if (!HeatOn) 
      {
          TempColor = COLOR_GREEN;                      // Green text, no fan or heater on
      }
      // ***********************************************************************************
             int pHColor;                                 // Color for drawing pH
      boolean LowpH = (ReefAngel.Params.PH < 780) ;     // Check for Low pH Value
      boolean HighpH = (ReefAngel.Params.PH > 850);     // Check for High pH Value
      if (LowpH) 
      {
        pHColor = COLOR_NAVY;                          // Blue text, Low pH value
      }
      if (HighpH)   
      {
        pHColor = COLOR_RED;                           // Red text, High pH value
      }
      if (!LowpH && !HighpH) 
      {
        pHColor = COLOR_GREEN;                         // Green text, pH acceptable
      }
      // ***********************************************************************************
      ReefAngel.LCD.DrawLargeText(COLOR_DARKSLATEBLUE,DefaultBGColor, 6, 3, " Thunder Reef",Font8x8);   // Put a banner at the top
      ReefAngel.LCD.DrawDate(6, 119);                                                                   // Put the date and time at the bottom
      ReefAngel.LCD.Clear(COLOR_BLACK, 1, 12, 132, 12);                                                 // Draw a black line under the banner
      x = 6;
      y += MENU_START_ROW*1.4;                                                                          // MENU_START_ROW is 10, according to globals.h, so y=2+10+1=13
      ReefAngel.LCD.DrawLargeText(COLOR_BLUE, COLOR_WHITE, x, y+1, " Temp      pH");

      ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);                                    // Get T1 temp and convert
      x = 2;
      y += MENU_START_ROW*1.6;
      ReefAngel.LCD.DrawHugeNumbers(COLOR_BLACK, TempColor, x, y, text);                                // Draw the temperature, white numbers on a colored background
      ConvertNumToString(text, ReefAngel.Params.PH, 100);                                               // Get pH reading and convert
      x = 2;
      y = MENU_START_ROW*2.6;
      ReefAngel.LCD.DrawHugeNumbers(COLOR_YELLOW, pHColor, x+65, y+6, text);                            // Put pH on the screen
     
      x += 6;
      y += MENU_START_ROW*3.3;
  ReefAngel.LCD.DrawLargeText(COLOR_INDIGO,DefaultBGColor,25,y,"Sump Level",Font8x8);      // Draw the Sump Float switch status
  if (ReefAngel.LowATO.IsActive())
  {ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_RED);
  }
  else
  {
  ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_GREEN);
  }
  x += 6;
  y += MENU_START_ROW*2.0;
  ReefAngel.LCD.DrawLargeText(COLOR_INDIGO,DefaultBGColor,25,y,"Skimmer Cup",Font8x8);     // Draw the Skimmer Cup Float switch status
  if (ReefAngel.HighATO.IsActive()) {ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_GREEN);
  }
  else
  {
  ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_RED);
  }
      
      
      byte TempRelay = ReefAngel.Relay.RelayData;                                          // Code for drawing the relay box
      TempRelay &= ReefAngel.Relay.RelayMaskOff;
      TempRelay |= ReefAngel.Relay.RelayMaskOn;
      ReefAngel.LCD.DrawOutletBox(12, 100, TempRelay);
   }
void DrawCustomGraph()
{
}



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


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


    // Ports that are always on
    ReefAngel.Relay.On( Port1 );
    
    // Virtual Ports that are always off
    ReefAngel.Relay.Off( Box1_Port1);
    ReefAngel.Relay.Off( Box1_Port2);
    ReefAngel.Relay.Off( Box1_Port3);
    ReefAngel.Relay.Off( Box1_Port4);
    ReefAngel.Relay.Off( Box1_Port5);
    ReefAngel.Relay.Off( Box1_Port6);
    ReefAngel.Relay.Off( Box1_Port7);
    ReefAngel.Relay.Off( Box1_Port8);
    
    
    // Delayed start for skimmer to allow sump level to return to normal after water change
    ReefAngel.Relay.DelayedOn( Port7,4 );

    ////// Place additional initialization code below here
   
    sl.Init(28.5700, -81.6800);    // Lat/long for Clermont, FL
    sl.SetOffset(-3,0,-3,0);       // rise_hour, rise_seconds, set_hour, set_seconds (set 1 hr later for better viewing time)

    randomSeed(now()%SECS_PER_DAY);
      
      //Custom Variable [0] =  Month/Season
    
    ReefAngel.CustomLabels[0]="Return";  
    ReefAngel.CustomLabels[1]="Daylights";  
    ReefAngel.CustomLabels[2]="Actinics";  
    ReefAngel.CustomLabels[3]="Fuge Light";  
    ReefAngel.CustomLabels[4]="Alk Dosing";  
    ReefAngel.CustomLabels[5]="Heater";  
    ReefAngel.CustomLabels[6]="Skimmer";  
    ReefAngel.CustomLabels[7]="ATO RoDi";  

    // Virtual Ports reserved for custom lighting functions and effects

    ReefAngel.CustomLabels[8]="Lights 60/40";  
    ReefAngel.CustomLabels[9]="Not Used";  
    ReefAngel.CustomLabels[10]="Not Used";  
    ReefAngel.CustomLabels[11]="Not Used";  
    ReefAngel.CustomLabels[12]="Weather";  
    ReefAngel.CustomLabels[13]="Weather";  
    ReefAngel.CustomLabels[14]="Weather";  
    ReefAngel.CustomLabels[15]="Weather";  


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

void loop()
{
  

    // seasonal temperatures
    SeasonalTemps();

// Lights on Dimming Expansion. (Left=East, Right=West)

ReefAngel.PWM.Channel0PWMParabola(0,-30);     // Actinic Left     - Starts at Sunrise, ends 30 minutes before Sunset
ReefAngel.PWM.Channel2PWMParabola(-15,-15);   // Actinic Center   - Starts 15 minute after Sunrise,  ends 15 minutes before Sunset
ReefAngel.PWM.Channel4PWMParabola(-30,0);     // Actinic Right    - Starts 30 minutes after Sunrise, ends at Sunset

ReefAngel.PWM.Channel1PWMParabola(-150,-180);  // Daylight Left   - Starts 150 minutes after Sunrise, ends 180 minutes before Sunset
ReefAngel.PWM.Channel3PWMParabola(-165,-165);  // Daylight Center - Starts 165 minutes after Sunrise, ends 165 minutes before Sunset 
ReefAngel.PWM.Channel5PWMParabola(-180,-150);  // Daylight Right  - Starts 180 minutes after Sunrise, ends 150 minutes before Sunset

// Turn Actinic outlet on if any % is >= 2
(ReefAngel.PWM.GetChannelValue(0)>=2 || ReefAngel.PWM.GetChannelValue(2)>=2 || ReefAngel.PWM.GetChannelValue(4)>=2) ?  ReefAngel.Relay.On( Port3 ) :  ReefAngel.Relay.Off( Port3 );

// Turn Daylight outlet on if any % is >=2   
(ReefAngel.PWM.GetChannelValue(1)>=2 || ReefAngel.PWM.GetChannelValue(3)>=2 || ReefAngel.PWM.GetChannelValue(5)>=2) ?  ReefAngel.Relay.On( Port2 ) : ReefAngel.Relay.Off( Port2 );

ReefAngel.Relay.Set(Port4, !ReefAngel.Relay.Status(Port2));  // Refugium light.  Opposite Whites.

ReefAngel.DosingPumpRepeat( Port5,0,10,18 );
    
    
// Virtual Port Functions

//if (ReefAngel.Relay.Status( Box1_Port1 )); // Set Lights 60/40
//{
//ReefAngel.PWM.SetChannel(0,60);  // Actinic Left
//ReefAngel.PWM.SetChannel(2,60);  // Actinic Center
//ReefAngel.PWM.SetChannel(4,60);  // Actinic Right

//ReefAngel.PWM.SetChannel(1,40);  // Daylight Left
//ReefAngel.PWM.SetChannel(3,40);  // Daylight Center
//ReefAngel.PWM.SetChannel(5,40);  // Daylight Right
//}
  
    
    
    ////// Place your custom code below here

// Alk Dosing (1 tbs Baked Baking soda per gal), Port 5.  Between 9pm & 9am, Every 10 minutes run for 18 seconds.
if (hour()>=9 && hour()<21) ReefAngel.Relay.Off(Port5); 



// WP-25 powerheads schedule    
if (hour()>=9 && hour()<13)
{
 ReefAngel.PWM.SetDaylight( ReefCrestMode(52,12,true) ); // reefcrest at 52% +/- 12% on sync mode       (Day Mode)
 ReefAngel.PWM.SetActinic( ReefCrestMode(52,12,false) ); // reefcrest at 52% +/- 12% on Anti-sync mode  (Day mode)
}
else if (hour()>=13 && hour()<18)
{
 ReefAngel.PWM.SetDaylight( ShortPulseMode(1,68,408,true) ); // Short pulse at 68% with 408ms pulse on sync mode (3/4" surface wave)
 ReefAngel.PWM.SetActinic( ShortPulseMode(1,68,408,false) ); // Short pulse at 68% with 408ms pulse on Anti-sync mode (3/4" surface wave)
}
else if (hour()>=18 && hour()<19)
{
 ReefAngel.PWM.SetDaylight( LongPulseMode(35,70,2,true) ); // Long Pulse 35% ramping up to 70% for 2 seconds on sync mode (nutrient transport)
 ReefAngel.PWM.SetActinic( LongPulseMode(35,70,2,false) ); // Long Pulse 35% ramping up to 70% for 2 seconds on Anti-sync mode  (nutrient transport)
}
else if (hour()>=19 && hour()<20)
{
 ReefAngel.PWM.SetDaylight( ReefCrestMode(52,12,true) ); // reefcrest at 52% +/- 12% on sync mode       (Day Mode)
 ReefAngel.PWM.SetActinic( ReefCrestMode(52,12,false) ); // reefcrest at 52% +/- 12% on Anti-sync mode  (Day mode)
}
else
{
 ReefAngel.PWM.SetDaylight( ReefCrestMode(48,8,true) ); // reefcrest at 48% +/- 8% on sync mode       (night Mode)
 ReefAngel.PWM.SetActinic( ReefCrestMode(48,8,false) ); // reefcrest at 48% +/- 8% on Anti-sync mode  (night mode)
}
 
if( ReefAngel.DisplayedMenu==FEEDING_MODE )
{
 ReefAngel.PWM.SetActinic( LongPulseMode(1,37,1,true) );
 ReefAngel.PWM.SetDaylight( LongPulseMode(1,37,1,true) );
}

if( ReefAngel.DisplayedMenu==WATERCHANGE_MODE )
{
 ReefAngel.PWM.SetActinic(35);
 ReefAngel.PWM.SetDaylight(35);
}

// enter feeding mode at 11am & 5pm
 if ( (hour()==11 && minute()==0 && second()==0))
 {
 ReefAngel.FeedingModeStart(); // turn on feeding mode
 }
  if ( (hour()==17 && minute()==0 && second()==0))
 {
 ReefAngel.FeedingModeStart(); // turn on feeding mode
 }
 
 
if(ReefAngel.HighATO.IsActive())           //  Float switch in Skimmer Locker
{
ReefAngel.Relay.DelayedOn( Port7,4 );
}
 else
{
 ReefAngel.Relay.Off(Port7);               //  Turn off Skimmer when locker full.
}
 

// ATO, Port 8 is ATO using Clear RoDi

 ReefAngel.SingleATO(true,Port8,400,0);   //  Sump switch.  If ATO/RoDi runs for 400 seconds, then shut off and send alert.




 
  { 
    sl.CheckAndUpdate();  // handle updating sunrise and sunset values
  }
 
    ////// Place your custom code above here

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

 void SeasonalTemps ()
 {
  static int heatArray[][2] = { {796,800},                  // default in case of error in month=0 (June)
                    {781,785},//January (winter)            // 78.3
                    {784,788},//February (winter)           // 78.6
                    {787,791},//March (early spring)        // 78.9
                    {790,794},//April (spring)              // 79.2
                    {793,797},//May (spring)                // 79.5
                    {796,800},//June (early summer)         // 79.8
                    {799,803},//July (summer)               // 80.1
                    {802,806},//August (summer)             // 80.4
                    {798,802},//September (early fall)      // 80.0
                    {794,798},//October (fall)              // 79.6
                    {790,794},//November (fall)             // 79.2
                    {786,790} };//December (early winter)   // 78.8
                    
               
  ReefAngel.StandardHeater( Port6,heatArray[month()][0],heatArray[month()][1]);
 }//end seasonalTemps