My almost completed pde

Share you PDE file with our community
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

My almost completed pde

Post by JNieuwenhuizen »

Hi

Well, here it is , its only the "vortech menu" I still need to work on, and spacing of display

Any comments welcome!

Code: Select all

// Autogenerated file by RAGen (v1.2.1.158), (03/08/2012 22:54)
/*Included Features File
#define DirectTempSensor
#define DisplayLEDPWM
#define wifi
#define SaveRelayState
#define RelayExp
#define InstalledRelayExpansionModules 1
#define PWMEXPANSION
#define CUSTOM_MAIN
#define SALINITYEXPANSION
#define RFEXPANSION
#define IOEXPANSION
#define CUSTOM_MAIN
#define CUSTOM_MENU_ENTRIES 9
#define COLORS_PDE
#define FONT_8x8
#define FONT_8x16
#define FONT_12x16
#define NUMBERS_8x8
#define NUMBERS_8x16
#define NUMBERS_12x16
#define NUMBERS_16x16
*/

#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 <ReefAngel.h>
#include <avr/pgmspace.h>>

//---------------------------------------------------- PWM Cloud ------------------------------------------------------------------
byte ActinicPWMValue=0;
byte DaylightPWMValue=0;
boolean ForceCloud=false;
boolean ForceLightning=false;
//
//*********************************************************************************************************************************
//--------------------------------------------------- Start of Global Variables ---------------------------------------------------
// 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.
#define LEDWhiteBlue  0 
#define LEDWhiteBlue1 1
#define LEDWhiteBlue2 2
#define MixedLED 3
#define LEDMoonlights 4

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

// Globals Needed for Params on Custom Main
byte x,y;
char text[10];
int v;
int maxTemp=0;
int minTemp=2000;
int maintemp=270;
int roomtemp=300;
int ph=700;
int maxPH=600;
int minPH=900;
byte TempRelay =15;
byte TempRelay2=15;

// Globals Needed for RF Mode on Custom Main
byte vtechmode;
boolean bFeeding=false;

//*********************************************************************************************************************************
//------------------------------------------------------ Custom Menu Code ---------------------------------------------------------
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 = "Salinity Calibration";
prog_char menu7_label[] PROGMEM = "Vortech Setup";
prog_char menu8_label[] PROGMEM = "Force Cloud";
prog_char menu9_label[] PROGMEM = "Force Lightning";

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.SetupCalibrateSalinity();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
  ReefAngel.SetupCalibrateSalinity();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry8()
{
 ForceCloud=true; 
 ReefAngel.DisplayedMenu=RETURN_MAIN_MODE;
}
void MenuEntry9()
{
ForceLightning=true;
ReefAngel.DisplayedMenu=RETURN_MAIN_MODE;
}

//------------------------------------------------------ Grouped Menu Entries ----------------------------------------------------
PROGMEM const char *menu_items[] = {
  menu1_label, menu2_label, menu3_label,
  menu4_label, menu5_label, menu6_label,
  menu7_label,menu8_label,menu9_label
};

//---------------------------------------------------------- Custom Main ----------------------------------------------------------
void DrawCircle(int a, int b, int r, byte color)
{
  int f = 1 - r;  
  int ddF_x = 1;  
  int ddF_y = -2 * r;  
  int x = 0;  
  int y = r;
  
ReefAngel.LCD.PutPixel(color, a, b+r);  
ReefAngel.LCD.PutPixel(color ,a, b-r);  
ReefAngel.LCD.PutPixel(color, a+r, b);  
ReefAngel.LCD.PutPixel(color, a-r, b);
 while (x<y) 
{    
if (f >= 0) 
{      y--;
       ddF_y += 2;      
       f += ddF_y;    
   }    
   x++;    
   ddF_x += 2;    
   f += ddF_x;
   
   ReefAngel.LCD.PutPixel(color, a + x, b + y);
   ReefAngel.LCD.PutPixel(color, a - x, b + y);
   ReefAngel.LCD.PutPixel(color, a + x, b - y);
   ReefAngel.LCD.PutPixel(color, a - x, b - y);
   ReefAngel.LCD.PutPixel(color, a + y, b + x);
   ReefAngel.LCD.PutPixel(color, a - y, b + x);
   ReefAngel.LCD.PutPixel(color, a + y, b - x);
   ReefAngel.LCD.PutPixel(color, a - y, b - x);
   }
}
void FillCircle(int a, int b, int r, byte color) 
{  
   int f = 1 - r;  
   int ddF_x = 1;  
   int ddF_y = -2 * r;  
   int x = 0;  
   int y = r;  
for (int i=b-r; i<=b+r; i++) 
{    
  ReefAngel.LCD.PutPixel(color, a, i);  
}  
while (x<y) 
{    
if (f >= 0) 
{      
   y--;      
   ddF_y += 2;      
   f += ddF_y;    
}    
   x++;    
   ddF_x += 2;    
   f += ddF_x;      
   for (int i=b-y; i<=b+y; i++) 
{      
ReefAngel.LCD.PutPixel(color, a+x, i);      
ReefAngel.LCD.PutPixel(color, a-x, i);    
}     
for (int i=b-x; i<=b+x; i++) 
{      
ReefAngel.LCD.PutPixel(color,a+y, i);     
ReefAngel.LCD.PutPixel(color,a-y, i);    
}      
}
}
void DrawCircleBox (byte x, byte y, byte RelayData)
{
 byte b = 0;
 byte c = 0;
 byte d = 0;
    for (byte a=0;a<2;a++)
      {
        DrawCircle ((a*10)+x,y+30,5,COLOR_BLACK);
        if ((RelayData&(1<<a))==1<<a) 
        {
          FillCircle((a*10)+x,y+30,3,OutletOnBGColor);
        }
        else 
        {
          FillCircle((a*10)+x,y+30,3,OutletOffBGColor);
        }
      }
   for (byte a=2;a<4;a++)
      {
        b=(a-2)*10;
       DrawCircle (b+x,y+20,5,COLOR_BLACK);
        if ((RelayData&(1<<a))==1<<a) 
        {
          FillCircle(b+x,y+20,3,OutletOnBGColor);
        }
        else 
        {
          FillCircle(b+x,y+20,3,OutletOffBGColor);
        }
      }
    for (byte a=4;a<6;a++)
      {
        c=(a-4)*10;
       DrawCircle (c+x,y+10,5,COLOR_BLACK);
        if ((RelayData&(1<<a))==1<<a) 
        {
          FillCircle(c+x,y+10,3,OutletOnBGColor);
        }
        else 
        {
          FillCircle(c+x,y+10,3,OutletOffBGColor);
        }
      }
    for (byte a=6;a<8;a++)
      {
        d=(a-6)*10;
       DrawCircle (d+x,y,5,COLOR_BLACK);
        if ((RelayData&(1<<a))==1<<a) 
        {
          FillCircle(d+x,y,3,OutletOnBGColor);
        }
        else 
        {
          FillCircle(d+x,y,3,OutletOffBGColor);
    
      }
      }
}
void DrawCustomMain()
{
  //Top Banner
  ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner 

  // Display T1 Header Text
  ReefAngel.LCD.DrawLargeText(COLOR_STEELBLUE,255,30,15,"Sump Temp", Font8x8);

  // Display the T1 Temp Value
 char text[7];
    ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
    ReefAngel.LCD.Clear(255, 35, 25, 50, 60);
    if (maintemp>270) ReefAngel.LCD.DrawHugeNumbers(COLOR_RED, 255, 35, 25, text);
    else if (maintemp>270) ReefAngel.LCD.DrawHugeNumbers(COLOR_ORANGE, 255, 35, 25, text);
    else ReefAngel.LCD.DrawHugeNumbers(COLOR_MIDNIGHTBLUE, 255, 35, 25, text);

  // Display the T2 Header Text
  ReefAngel.LCD.DrawLargeText(0,255,8,50,"Room Temp", Font8x8);

  // Display the T2 Temp Value
  ReefAngel.LCD.Clear(255, 90, 50, 132, 60);
  ConvertNumToString(text, ReefAngel.Params.Temp[T2_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(COLOR_MIDNIGHTBLUE, 255, 90, 50, text, Num8x8);

  // Display pH Header Text
  ReefAngel.LCD.DrawLargeText(COLOR_DARKSLATEBLUE,255,102,75,"pH", Font8x8);

  // Display pH Value
  ConvertNumToString(text, ph, 100);
  ReefAngel.LCD.Clear(0, 65, 62 , 65, 62);
  if (ph>840 || ph<790) ReefAngel.LCD.DrawLargeText(COLOR_RED, 255, 95, 88, text, Num8x8);
  else if (ph>830 || ph<800) ReefAngel.LCD.DrawLargeText(COLOR_ORANGE, 255, 95, 88, text, Num8x8);
  else ReefAngel.LCD.DrawLargeText(COLOR_MIDNIGHTBLUE, 255, 95, 88, text, Num8x8);

  // Display Vortech Mode
  ReefAngel.LCD.DrawLargeText(0,255,8,60,"Vortech", Font8x8);
  
  // Display EcoSmart Mode Value      
  ReefAngel.LCD.Clear(255, 90, 60, 132, 70);
  if (vtechmode == 0) ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN,255, 66, 60,"Constant");
  else if(vtechmode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255, 66, 60,"Lagoon");
  else if (vtechmode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255, 66, 60,"RCM");
  else if (vtechmode == 3) ReefAngel.LCD.DrawLargeText(COLOR_CORNFLOWERBLUE,255, 66, 60,"Short");
  else if (vtechmode == 4) ReefAngel.LCD.DrawLargeText(COLOR_PINK,255, 66, 60,"Long");
  else if (vtechmode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255, 66, 60,"NTM");
  else if (vtechmode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255, 66, 60,"TSM");
  else if (vtechmode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,255, 66, 60,"Night");

  // Display Salinity 
    ReefAngel.LCD.DrawLargeText(0,255,66,100,"Salinity", Font8x8);
    
  // Display Salinity Value 
    ReefAngel.LCD.Clear(255, 82, 85, 65, 95);
    ConvertNumToString(text, ReefAngel.Params.Salinity, 100);
    ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN, 255, 65, 110, text, Num8x8);

  //Start Moon Phase Display
  x += (16*4) + 8;
  y += MENU_START_ROW+3;
  if (ReefAngel.PWM.GetChannelValue(4) ==0) ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,5,75,"Off");
  else if(ReefAngel.PWM.GetChannelValue(4) >=1 && ReefAngel.PWM.GetChannelValue(4) < 5) ReefAngel.LCD.DrawText(20,255,81,75,"New");
  else if(ReefAngel.PWM.GetChannelValue(4) >=5 && ReefAngel.PWM.GetChannelValue(4) < 10) ReefAngel.LCD.DrawText(20,255,81,75,"Cresent");
  else if(ReefAngel.PWM.GetChannelValue(4) >=10 && ReefAngel.PWM.GetChannelValue(4) < 20) ReefAngel.LCD.DrawText(20,255,81,75,"Half");
  else if(ReefAngel.PWM.GetChannelValue(4) >=20 && ReefAngel.PWM.GetChannelValue(4) < 30) ReefAngel.LCD.DrawText(20,255,81,75,"Gibbous");
  else if(ReefAngel.PWM.GetChannelValue(4) >=30 && ReefAngel.PWM.GetChannelValue(4) < 45) ReefAngel.LCD.DrawText(20,255,81,75,"Full");
  //End Display Moon Phase Display
  
  // Display Main and Expansion Relay Box
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;  
    DrawCircleBox (10,90,TempRelay);
    DrawCircleBox (40,90,TempRelay2);

  
}

void DrawCustomGraph()  // Not Used
{
}
//*********************************************************************************************************************************
//-------------------------------------------------------- Begin Setup ------------------------------------------------------------
void setup()
{
  ReefAngel.Init();  //Initialize controller
  ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));
  ReefAngel.SetTemperatureUnit(1);
  ReefAngel.FeedingModePorts = 0;
  ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port6Bit;
  ReefAngel.OverheatShutoffPorts = Port6Bit;
  ReefAngel.LightsOnPorts = 0;

  //---------------------------------------------------- Ports that are always on ----------------------------------------------------
  ReefAngel.Relay.On(Port1);
  ReefAngel.Relay.On(Port4);
  ReefAngel.Relay.On(Port7);
  ReefAngel.Relay.On(Port8);
  ReefAngel.Relay.On(Box1_Port1);
  ReefAngel.Relay.On(Box1_Port2);
  ReefAngel.Relay.On(Box1_Port6);
  ReefAngel.Relay.On(Box1_Port7);
  ReefAngel.Relay.On(Box1_Port8);
  //--------------------------------------------------------- RF Module Setup -------------------------------------------------------
  // ReefAngel.RF.SetMode(Slave_Start,0,0);
  /*
    If you get a compile error similar to this:
   'class ReefAngelClass' has no member named 'RF'
   Please make sure that you enabled RF Expansion on your features file.
   
   Open RAGen and make sure you have RF Expansion checked under the Features tab.
   
   Or, you can manually edit the file.
   The file is located at "Documents\Arduino\libraries\ReefAngel_Features.h" file and has to include this line in it:
   #define RFEXPANSION  
   */
  InternalMemory.RFMode_write(0);
  InternalMemory.RFSpeed_write(128);
  InternalMemory.RFDuration_write(10);
}

//*********************************************************************************************************************************
//--------------------------------------------------------- Begin Loop ------------------------------------------------------------
void loop()
{
  //------------------------------------------------------ Specific functions -------------------------------------------------------
  ReefAngel.Relay.DelayedOn(Port2, 1);
  ReefAngel.StandardATO(Port3);
  ReefAngel.MoonLights(Port5);
  ReefAngel.StandardLights(Box1_Port6);
  ReefAngel.StandardLights(Box1_Port7,120);
  ReefAngel.MHLights(Box1_Port8);

  ReefAngel.StandardHeater(Port6);
  //------------------------------------------------ Start PWM Expansion Code for Slope ----------------------------------------------

  PWMChannel[LEDWhiteBlue]=PWMSlope(
  InternalMemory.StdLightsOnHour_read(),
  InternalMemory.StdLightsOnMinute_read(),
  InternalMemory.StdLightsOffHour_read(),
  InternalMemory.StdLightsOffMinute_read(),
  InternalMemory.PWMSlopeStartD_read(),
  InternalMemory.PWMSlopeEndD_read(),
  InternalMemory.PWMSlopeDurationD_read(),
  0);
  PWMChannel[MixedLED]=PWMSlope(
  InternalMemory.StdLightsOnHour_read(),
  InternalMemory.StdLightsOnMinute_read(),
  InternalMemory.StdLightsOffHour_read(),
  InternalMemory.StdLightsOffMinute_read(),
  InternalMemory.PWMSlopeStartA_read(),
  InternalMemory.PWMSlopeEndA_read(),
  InternalMemory.PWMSlopeDurationA_read(),
  0);    
  PWMChannel[LEDWhiteBlue1]=PWMChannel[LEDWhiteBlue];
  PWMChannel[LEDWhiteBlue2]=PWMChannel[LEDWhiteBlue];
  ReefAngel.PWM.SetChannel(0,PWMChannel[LEDWhiteBlue]);
  ReefAngel.PWM.SetChannel(1,PWMChannel[LEDWhiteBlue1]);
  ReefAngel.PWM.SetChannel(2,PWMChannel[LEDWhiteBlue2]);
  ReefAngel.PWM.SetChannel(3,PWMChannel[MixedLED]);
  
  //---------------------------------------------------------PWM Slope Per Channel-----------------------------------------------------

  MoonPWMValue=MoonPhase();
  if (hour()==22 || hour()==6)
    MoonPWMValue=PWMSlope(22,00,7,00,0,MoonPhase(),60,0);
  if (PWMChannel[LEDWhiteBlue]) MoonPWMValue=0;
  ReefAngel.PWM.SetChannel(4,MoonPWMValue);
  
     // PWMChannel[LEDWhiteBlue1]=PWMSlope(15,0,21,30,15,45,90,PWMChannel[LEDWhiteBlue1]);
    PWMChannel[LEDWhiteBlue]=PWMSlope(8,0,22,0,0,90,300,PWMChannel[LEDWhiteBlue]);
    PWMChannel[LEDWhiteBlue1]=PWMSlope(8,30,21,30,0,90,270,PWMChannel[LEDWhiteBlue1]);
    PWMChannel[LEDWhiteBlue2]=PWMSlope(9,0,21,0,0,90,240,PWMChannel[LEDWhiteBlue2]);
    PWMChannel[MixedLED]=PWMSlope(12,0,18,0,0,90,60,PWMChannel[MixedLED]);
    
    // In the example above, we are starting the slope at 8:00am with 0% and going up to 90% within 300 minutes, which would be 5:00pm.
    // Then it would stay at 90% from 13:00pm to 300 minutes prior to 10:00pm, which would be 5:00pm.
    // Then from 8:00pm, it would start sloping down from 45% all the way back to 15% within 90 minutes, which would be 9:30pm.
    //CheckCloud(); (May be used at a later date with cloud/storm effects)
    if (hour()>=22 || hour()<8)
    {
      ReefAngel.PWM.SetChannel(4,MoonPhase());  //Moon phase schedule between 10:00pm - 7:00am
    }
  else
    ReefAngel.PWM.Expansion(LEDWhiteBlue,int(PWMChannel[LEDWhiteBlue]));
    ReefAngel.PWM.Expansion(LEDWhiteBlue1,int(PWMChannel[LEDWhiteBlue1]));
    ReefAngel.PWM.Expansion(LEDWhiteBlue2,int(PWMChannel[LEDWhiteBlue2]));
    ReefAngel.PWM.Expansion(MixedLED,int(PWMChannel[MixedLED]));
    ReefAngel.ShowInterface();

  //------------------------------------------------- End PWM Expansion Code for Slope ----------------------------------------------

  //------------------------------------------------ Start Time-of-Day Based Functions ----------------------------------------------
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These are the mode numbers for the RF Expansion Module for reference ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //#define Constant      0
  //#define Random1       1 // Lagoonal
  //#define Random2       2 // Reef Crest
  //#define ShortWave     3
  //#define LongWave      4
  //#define Smart_NTM     5 // Nutrient Transport Mode
  //#define Smart_TSM     6 // Tidal Swell Mode
  //#define Feeding_Start 7
  //#define Feeding_Stop  8
  //#define Night         9
  //#define Slave_Start   97
  //#define Slave_Stop    98
  //#define None          99
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  //------------------------------------------------ Start Feeding Mode Schedule ----------------------------------------------------
  // if the hour is 7pm, minute is 30 and seconds is 0
  // start the feeding mode
  if ( ((hour() == 17) && 
    (minute() == 30) && 
    (second() == 0) ) )
  {
    ReefAngel.FeedingModeStart();
    vtechmode = InternalMemory.RFMode_read();     
  }

  //-------------------------------------------------------- Start RF Daytime Control -----------------------------------------------
  if (hour() >=8 && hour() <= 22)
  {  
    if (ReefAngel.DisplayedMenu==FEEDING_MODE) bFeeding=true;
    if (ReefAngel.DisplayedMenu==DEFAULT_MENU && bFeeding )
    {
      bFeeding=false; 
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Smart_NTM,155,5);
      ReefAngel.Timer[4].SetInterval(1800); // Timer for 30min
      ReefAngel.Timer[4].Start();
      vtechmode = 5;
    }
    if (ReefAngel.DisplayedMenu==DEFAULT_MENU && ReefAngel.Timer[4].IsTriggered())
    {
      ReefAngel.RF.UseMemory=true;
      vtechmode = InternalMemory.RFMode_read();
    }  
  }

  //-------------------------------------------------------- Start RF Nightmode Control ---------------------------------------------  


  if (hour()>=22 || hour()<8) // Defining "Nightmode" hours for VorTech = between 10 PM and 8 AM
  {
    ReefAngel.RF.UseMemory=false;
    ReefAngel.RF.SetMode(Night,15,0);
    vtechmode = 9;
  }
  else
  {
    ReefAngel.RF.SetMode(Feeding_Stop,0,0); //Temp fix for coming out of Night mode
    ReefAngel.RF.UseMemory=true;
    vtechmode = InternalMemory.RFMode_read();
  } 

  ReefAngel.Portal("JNieuwenhuizen");
  ReefAngel.ShowInterface();

}

//*********************************************************************************************************************************
// Random Cloud/Thunderstorm effects function
// From Roberto - THANKS ROBERTO!
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_5_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 25

  // 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 15

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

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

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

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

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

  // Channels used by the actinic LEDs on the PWM Expansion module
  // These channels will not be dimmed when the cloud effect is triggered
  // Number is a binary form. B001100 means channel 2 and 3 are used for actinics
#define Actinic_Channels B000101

  // Channels used by the daylight LEDs on the PWM Expansion module
  // These channels will be used for the spike when lightning effect is triggered
  // Number is a binary form. B000011 means channel 0 and 1 are used for daylights
#define Daylight_Channels B001010

  // 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(26); 
      // 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_5_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(36);
        // 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?
//is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      // let's go through all channels to pick which ones will be dimmed
      for (int a=0;a<6;a++)
      {
        if (bitRead(Actinic_Channels,a)==0)
        {
          // this will slope down the channel from the current PWM to 0 within 3minutes.
          // then it will stay at 0 for the duration of the cycle
          // and finally slope up from 0 to PWM value within 3 minutes
          // it is basically an inversed slope
          PWMChannel[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,PWMChannel[a],0,180);
        }
      }
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        for (int b=0;b<6;b++)
        {
          if (bitRead(Daylight_Channels,b)==1)
          {
            if (random(100)<20) lightningstatus=1; 
            else lightningstatus=0;
            if (lightningstatus) PWMChannel[b]=100; 
            else PWMChannel[b]=0;
            //delay(10);
          }
          else
          {
            PWMChannel[b]=20;
          }
        }
      }
    }
    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;
      }
    }
  }
  
     
}

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 
}


And this is still a bit wrong - should pull values from PWM expansion and not atinics. Is there a document on the forum with code explanations? like ReefAngel.PWM.GetAtinicValue , and then the function of it?

Code: Select all

  //Start Moon Phase Display
  x += (16*4) + 8;
  y += MENU_START_ROW+3;
  if (ReefAngel.PWM.GetActinicValue() ==0) ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,5,55,"Off");
  else if(ReefAngel.PWM.GetActinicValue() >=1 && ReefAngel.PWM.GetActinicValue() < 5)
         ReefAngel.LCD.DrawText(20,255,81,55,"New");
  else if(ReefAngel.PWM.GetActinicValue() >=5 && ReefAngel.PWM.GetActinicValue() < 10)
         ReefAngel.LCD.DrawText(20,255,81,55,"Cresent");
  else if(ReefAngel.PWM.GetActinicValue() >=10 && ReefAngel.PWM.GetActinicValue() < 20)
         ReefAngel.LCD.DrawText(20,255,81,55,"Half");
  else if(ReefAngel.PWM.GetActinicValue() >=20 && ReefAngel.PWM.GetActinicValue() < 30) 
         ReefAngel.LCD.DrawText(20,255,81,55,"Gibbous");
  else if(ReefAngel.PWM.GetActinicValue() >=30 && ReefAngel.PWM.GetActinicValue() < 45)   
         ReefAngel.LCD.DrawText(20,255,81,55,"Full");
  //End Display Moon Phase Display
Last edited by JNieuwenhuizen on Wed Apr 04, 2012 10:48 am, edited 1 time in total.
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

Ok, had a look in the RA_PWM.h file and got the correct "Get" value. It's "GetChannelValue(4)

So sorted.. Now only the Vortech bit left
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

ok, so 1 bit of code not working.

My Circle relay boxes

Code: Select all

void DrawCircle(int a, int b, int r, byte color)
{
  int f = 1 - r;  
  int ddF_x = 1;  
  int ddF_y = -2 * r;  
  int x = 0;  
  int y = r;
  
ReefAngel.LCD.PutPixel(color, a, b+r);  
ReefAngel.LCD.PutPixel(color ,a, b-r);  
ReefAngel.LCD.PutPixel(color, a+r, b);  
ReefAngel.LCD.PutPixel(color, a-r, b);
 while (x<y) 
{    
if (f >= 0) 
{      y--;
       ddF_y += 2;      
       f += ddF_y;    
   }    
   x++;    
   ddF_x += 2;    
   f += ddF_x;
   
   ReefAngel.LCD.PutPixel(color, a + x, b + y);
   ReefAngel.LCD.PutPixel(color, a - x, b + y);
   ReefAngel.LCD.PutPixel(color, a + x, b - y);
   ReefAngel.LCD.PutPixel(color, a - x, b - y);
   ReefAngel.LCD.PutPixel(color, a + y, b + x);
   ReefAngel.LCD.PutPixel(color, a - y, b + x);
   ReefAngel.LCD.PutPixel(color, a + y, b - x);
   ReefAngel.LCD.PutPixel(color, a - y, b - x);
   }
}
void FillCircle(int a, int b, int r, byte color) 
{  
   int f = 1 - r;  
   int ddF_x = 1;  
   int ddF_y = -2 * r;  
   int x = 0;  
   int y = r;  
for (int i=b-r; i<=b+r; i++) 
{    
  ReefAngel.LCD.PutPixel(color, a, i);  
}  
while (x<y) 
{    
if (f >= 0) 
{      
   y--;      
   ddF_y += 2;      
   f += ddF_y;    
}    
   x++;    
   ddF_x += 2;    
   f += ddF_x;      
   for (int i=b-y; i<=b+y; i++) 
{      
ReefAngel.LCD.PutPixel(color, a+x, i);      
ReefAngel.LCD.PutPixel(color, a-x, i);    
}     
for (int i=b-x; i<=b+x; i++) 
{      
ReefAngel.LCD.PutPixel(color,a+y, i);     
ReefAngel.LCD.PutPixel(color,a-y, i);    
}      
}
}
void DrawCircleBox (byte x, byte y, byte RelayData)
{
 byte b = 0;
 byte c = 0;
 byte d = 0;
    for (byte a=0;a<2;a++)
      {
        DrawCircle ((a*10)+x,y+30,5,COLOR_BLACK);
        if ((RelayData&(1<<a))==1<<a) 
        {
          FillCircle((a*10)+x,y+30,3,OutletOnBGColor);
        }
        else 
        {
          FillCircle((a*10)+x,y+30,3,OutletOffBGColor);
        }
      }
   for (byte a=2;a<4;a++)
      {
        b=(a-2)*10;
       DrawCircle (b+x,y+20,5,COLOR_BLACK);
        if ((RelayData&(1<<a))==1<<a) 
        {
          FillCircle(b+x,y+20,3,OutletOnBGColor);
        }
        else 
        {
          FillCircle(b+x,y+20,3,OutletOffBGColor);
        }
      }
    for (byte a=4;a<6;a++)
      {
        c=(a-4)*10;
       DrawCircle (c+x,y+10,5,COLOR_BLACK);
        if ((RelayData&(1<<a))==1<<a) 
        {
          FillCircle(c+x,y+10,3,OutletOnBGColor);
        }
        else 
        {
          FillCircle(c+x,y+10,3,OutletOffBGColor);
        }
      }
    for (byte a=6;a<8;a++)
      {
        d=(a-6)*10;
       DrawCircle (d+x,y,5,COLOR_BLACK);
        if ((RelayData&(1<<a))==1<<a) 
        {
          FillCircle(d+x,y,3,OutletOnBGColor);
        }
        else 
        {
          FillCircle(d+x,y,3,OutletOffBGColor);
    
      }
      }

  // Display Main and Expansion Relay Box
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;  
    DrawCircleBox (10,90,TempRelay);
    DrawCircleBox (40,90,TempRelay2);
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: My almost completed pde

Post by binder »

What is wrong with the circle relay boxes? Are they not showing up? Are they displaying incorrect?

If you are using 0.9.4 libraries, the Circles are included so those functions you have are not needed.
http://forum.reefangel.com/viewtopic.php?f=7&t=931
That shows you how to use the circles.
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

They seem not to disply the correct data.

I removed that code, it now only has this

Code: Select all

  // Display Main and Expansion Relay Box
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawCircleOutletBox(13, 97, TempRelay);
  pingSerial();

  TempRelay = ReefAngel.Relay.RelayDataE[0];
  TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawCircleOutletBox(13, 109, TempRelay);
  pingSerial();
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: My almost completed pde

Post by binder »

If they seem to not display the correct data, what are they showing? Are the ports backwards?

Check out my post on this page for how to use the circles code:
http://forum.reefangel.com/viewtopic.ph ... 7517#p7517
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

Ok, so now I updated my pde a little. I added multiple screens. Looks nice, only problem is I have some tweaking to do.

Complete pde

Code: Select all

// Autogenerated file by RAGen (v1.2.1.158), (03/08/2012 22:54)
/*Included Features File
#define DirectTempSensor
#define DisplayLEDPWM
#define wifi
#define SaveRelayState
#define RelayExp
#define InstalledRelayExpansionModules 1
#define CUSTOM_MENU
#define CUSTOM_MENU_ENTRIES 9
#define PWMEXPANSION
#define CUSTOM_MAIN
#define CUSTOM_VARIABLES
#define SALINITYEXPANSION
#define RFEXPANSION
#define IOEXPANSION
#define FONT_8x8
#define NUMBERS_8x8
#define NUMBERS_16x16
*/

#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 <ReefAngel.h>
#include <avr/pgmspace.h>>
//screen set-up
#define NumScreens 8
int ScreenID=0;
//---------------------------------------------------- PWM Cloud ------------------------------------------------------------------
boolean ForceCloud=false;
boolean ForceLightning=false;
//
//*********************************************************************************************************************************
//--------------------------------------------------- Start of Global Variables ---------------------------------------------------
//--------------------------- 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. ----------
#define LEDWhiteBlue  0 
#define LEDWhiteBlue1 1
#define LEDWhiteBlue2 2
#define MixedLED 3
#define LEDMoonlights 4

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

//MoonPhase Value Setting
byte MoonPWMValue;

//---------------------------------------------- VortechMenu Setting --------------------------------------------------------------
byte vtmode = 0;

//------------------------------------- Globals Needed for Params on Custom Main --------------------------------------------------
int maxTemp=0;
int minTemp=2000;
int maintemp=270;
int roomtemp=300;
int ph=700;
int maxPH=600;
int minPH=900;
byte x,y;
char text[10];
int v;
int moonlight=0;
byte TempRelay =15;
byte TempRelay2=15;
byte mhour;
byte mminute;
byte msecond;
byte mday;
byte mmonth;
byte myear;

//---------------------------------------- Globals Needed for RF Mode on Custom Main ---------------------------------------------
byte vtechmode;
boolean bFeeding=false;

//*********************************************************************************************************************************
//------------------------------------------------------ Custom Menu Code ---------------------------------------------------------
prog_char menu1_label[] PROGMEM = "Food!!";
prog_char menu2_label[] PROGMEM = "Cleanup";
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 = "Salty Calibration";
prog_char menu7_label[] PROGMEM = "Vortech Modes";
prog_char menu8_label[] PROGMEM = "Force Cloud";
prog_char menu9_label[] PROGMEM = "Force Lightning";

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.SetupCalibrateSalinity();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
   vtmode++;
   if ( vtmode == 7 ) vtmode = 9;
   if ( vtmode > 9 ) vtmode = 1;
   // 1st parameter is Mode, 2nd is speed, 3rd is duration
   ReefAngel.RF.SetMode(vtmode, InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
   ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}

void MenuEntry8()
{
 ForceCloud=true; 
 ReefAngel.DisplayedMenu=RETURN_MAIN_MODE;
}
void MenuEntry9()
{
ForceLightning=true;
ReefAngel.DisplayedMenu=RETURN_MAIN_MODE;
}

//------------------------------------------------------ Grouped Menu Entries ----------------------------------------------------
PROGMEM const char *menu_items[] = {
  menu1_label, menu2_label, menu3_label,
  menu4_label, menu5_label, menu6_label,
  menu7_label,menu8_label,menu9_label
};

//---------------------------------------------------------- Custom Main ----------------------------------------------------------
void DrawCircleOutline(byte x, byte y, byte radius, byte bordercolor);
void FillCircle(byte x, byte y, byte radius, byte fillcolor);
void DrawCircleOutletBox(byte x, byte y, byte RelayData, bool reverse = false);
//------------------------------------------------------ Analog Clock constants ---------------------------------------------------
    const float pi = 3.141592653;
    byte clock_center_x = 65;
    byte clock_center_y = 65;
    byte clock_radius = 55;
    byte secondhand_radius = 33;
    float secondangle;
    byte secondend_x;
    byte secondend_y;
    float minuteangle;
    float hourangle;
//------------------------------------------------------ Analog Clock Structure ----------------------------------------------------
       int minutebase_radius = 3;
       int minutehand_radius = 33;
       int hourbase_radius = 3;
       int hourhand_radius = 25;   
       int seconds_hand_x, seconds_hand_y, minutes_hand_x, minutes_hand_y, hours_hand_x, hours_hand_y;
       int hours_hand_base_x, hours_hand_base_y, hours_hand_base_x1, hours_hand_base_y1;
       int minutes_hand_base_x, minutes_hand_base_y, minutes_hand_base_x1, minutes_hand_base_y1; 
       int minutebase_x, minutebase_y, minutebase_x1, minutebase_y1; 
       int minuteend_x, minuteend_y; 
       int hourbase_x, hourbase_y, hourbase_x1, hourbase_y1; 
       int hourend_x, hourend_y; 
       float minfloat;
//----------------------------------------------------------- time stamp -----------------------------------------------------------
time_t tsmax=now();
time_t tsmin=now();
time_t PHmax=now();
time_t PHmin=now();
int mastertime;

//-------------------------------------------------------- Draw Minutes Hand -------------------------------------------------------
void draw_minute(int color)
{
  Drawline(minutebase_x, minutebase_y, minutebase_x1, minutebase_y1, color); 
  Drawline(minutebase_x, minutebase_y, minuteend_x, minuteend_y, color); 
  Drawline(minutebase_x1, minutebase_y1, minuteend_x, minuteend_y, color); 
}
//-------------------------------------------------------- Draw Hour Hand ----------------------------------------------------------
void draw_hour(int color)
{
   Drawline(hourbase_x, hourbase_y, hourbase_x1, hourbase_y1, color); 
   Drawline(hourbase_x, hourbase_y, hourend_x, hourend_y, color); 
   Drawline(hourbase_x1, hourbase_y1, hourend_x, hourend_y, color); 
}
void Drawline (int x0, int y0, int x1, int y1, int color) 
{
  int dy = y1 - y0;
  int dx = x1 - x0;
  int stepx, stepy;
  if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
  if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
  dy <<= 1; // dy is now 2*dy
  dx <<= 1; // dx is now 2*dx
  ReefAngel.LCD.PutPixel(color, x0, y0);
  if (dx > dy) {
    int fraction = dy - (dx >> 1); // same as 2*dy - dx
    while (x0 != x1) {
      if (fraction >= 0) {
        y0 += stepy;
        fraction -= dx; // same as fraction -= 2*dx
        }
      x0 += stepx;
      fraction += dy; // same as fraction -= 2*dy
      ReefAngel.LCD.PutPixel(color, x0, y0);
    }
  } else {
  int fraction = dx - (dy >> 1);
  while (y0 != y1) {
  if (fraction >= 0) {
    x0 += stepx;
    fraction -= dy;
    }
  y0 += stepy;
  fraction += dx;
  ReefAngel.LCD.PutPixel(color, x0, y0);
  }
  }}
void DrawTime(byte x, byte y, byte FGcolor, byte BGcolor, time_t ts)
{
    char text[13];
    char temp[]="  ";
    strcpy(text,"");
    itoa(hourFormat12(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    strcat(text,":");
    itoa(minute(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    strcat(text,":");
    itoa(second(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    if (isAM(ts))
    {
        strcat(text," AM");
    }
    else
    {
        strcat(text," PM");
    }
    ReefAngel.LCD.DrawText(FGcolor, BGcolor, x, y, text);
}
void DrawCircle(int a, int b, int r, byte color)
{
  int f = 1 - r;  
  int ddF_x = 1;  
  int ddF_y = -2 * r;  
  int x = 0;  
  int y = r;
  
ReefAngel.LCD.PutPixel(color, a, b+r);  
ReefAngel.LCD.PutPixel(color ,a, b-r);  
ReefAngel.LCD.PutPixel(color, a+r, b);  
ReefAngel.LCD.PutPixel(color, a-r, b);
 while (x<y) 
{    
if (f >= 0) 
{      y--;
       ddF_y += 2;      
       f += ddF_y;    
   }    
   x++;    
   ddF_x += 2;    
   f += ddF_x;
   
   ReefAngel.LCD.PutPixel(color, a + x, b + y);
   ReefAngel.LCD.PutPixel(color, a - x, b + y);
   ReefAngel.LCD.PutPixel(color, a + x, b - y);
   ReefAngel.LCD.PutPixel(color, a - x, b - y);
   ReefAngel.LCD.PutPixel(color, a + y, b + x);
   ReefAngel.LCD.PutPixel(color, a - y, b + x);
   ReefAngel.LCD.PutPixel(color, a + y, b - x);
   ReefAngel.LCD.PutPixel(color, a - y, b - x);
   }
}

void DrawWeeklyAvg (byte hr, int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 7;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (hour()==hr && minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
}
void DrawDailyAvg (int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 24;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
}

}
//-------------------------------------------------------- Begin Setup ------------------------------------------------------------
void setup()
{
  ReefAngel.Init();  //Initialize controller
  ReefAngel.Timer[LCD_TIMER].SetInterval(180);
  ReefAngel.Timer[LCD_TIMER].Start();  // start timer
  ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));
  ReefAngel.SetTemperatureUnit(1);
  ReefAngel.FeedingModePorts = 0;
  ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port6Bit | Box1_Port1 | Box1_Port2;
  ReefAngel.OverheatShutoffPorts = Port6Bit;
  ReefAngel.LightsOnPorts = 0;
    //---------------------------------------------------- Ports that are always on ----------------------------------------------------
  ReefAngel.Relay.On(Port1);
  ReefAngel.Relay.On(Port4);
  ReefAngel.Relay.On(Port7);
  ReefAngel.Relay.On(Port8);
  ReefAngel.Relay.On(Box1_Port1);
  ReefAngel.Relay.On(Box1_Port2);
    
}

//*********************************************************************************************************************************
  
void loop()
{
    //------------------------------------------------------ Specific functions -------------------------------------------------------
  ReefAngel.Relay.DelayedOn(Port2, 2);
  ReefAngel.Relay.DelayedOn(Box1_Port1, 2);
  ReefAngel.Relay.DelayedOn(Box1_Port2, 2);
  ReefAngel.StandardATO(Port3);
  ReefAngel.MoonLights(Port5);
  ReefAngel.StandardHeater(Port6);
  ReefAngel.MoonLights(Box1_Port4);//LEDMoonlights
  ReefAngel.StandardLights(Box1_Port5);//White and Blue LED 
  ReefAngel.StandardLights(Box1_Port6,8,30,21,30);//White and Blue LED1
  ReefAngel.StandardLights(Box1_Port7,9,0,22,0);//White and Blue LED2
  ReefAngel.StandardLights(Box1_Port8,12,0,17,0);//MixedLED
  ReefAngel.Portal("JNieuwenhuizen","Evandre1");
   
 


  //------------------------------------------------ Start PWM Expansion Code for Slope ----------------------------------------------

  ReefAngel.PWM.SetChannel(0,ChannelValue[LEDWhiteBlue]);
  ReefAngel.PWM.SetChannel(1,ChannelValue[LEDWhiteBlue1]);
  ReefAngel.PWM.SetChannel(2,ChannelValue[LEDWhiteBlue2]);
  ReefAngel.PWM.SetChannel(3,ChannelValue[MixedLED]);
  ReefAngel.PWM.SetChannel(4,ChannelValue[LEDMoonlights]);
  
  //*********************************************************************************************************************************
  setTime(mhour,mminute,msecond,mday,mmonth,myear);
  if ( ReefAngel.Timer[LCD_TIMER].IsTriggered() )  // process screensaver timeout
   {// Screensaver timeout expired
   ReefAngel.LCD.BacklightOff();
   }
     if ( ReefAngel.Joystick.IsButtonPressed())
   {// turn the backlight on
   ReefAngel.LCD.BacklightOn();
        }
  // TODO check Timer[LCD_TIMER] code
  if ( ReefAngel.Timer[LCD_TIMER].Trigger == 0 )
   {
   ReefAngel.Timer[LCD_TIMER].Start();
   return;
   }// update the min and max temps
  if (now()%86400==0)
  {
    minTemp=maintemp;
    maxTemp=maintemp;
  }
  if (maintemp<minTemp) 
  {
    minTemp=maintemp;
    tsmin=now();
  }
  if (maintemp>maxTemp) 
  {
    maxTemp=maintemp;
    tsmax=now();
  }
  // update the min and max pH
if (now()%86400==0)
{
  minPH=ph;
  maxPH=ph;
}
if (ph<minPH) 
{
  minPH=ph;
  PHmin=now();
  
  
}
if (ph>maxPH) 
{
  maxPH=ph;
  PHmax=now();
}
  if (ReefAngel.Joystick.IsLeft()) 
  {
    ReefAngel.ClearScreen(DefaultBGColor);
    ScreenID--;
  }
  if (ReefAngel.Joystick.IsRight()) 
    {
    ReefAngel.ClearScreen(DefaultBGColor);
    ScreenID++;
    }
  if (ScreenID<0) ScreenID=NumScreens;
  if (ScreenID>=NumScreens) ScreenID=0;
  switch (ScreenID)
  {
case 0:  //Initial first screen
  //Top Banner
  ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner 

  // Display T1 Header Text
  ReefAngel.LCD.DrawLargeText(COLOR_STEELBLUE,255,30,15,"Sump Temp", Font8x8);

  // Display the T1 Temp Value
 char text[7];
    ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
    ReefAngel.LCD.Clear(255, 35, 25, 50, 60);
    if (maintemp>270) ReefAngel.LCD.DrawHugeNumbers(COLOR_RED, 255, 35, 25, text);
    else if (maintemp>270) ReefAngel.LCD.DrawHugeNumbers(COLOR_ORANGE, 255, 35, 25, text);
    else ReefAngel.LCD.DrawHugeNumbers(COLOR_MIDNIGHTBLUE, 255, 35, 25, text);

  // Display the T2 Header Text
  ReefAngel.LCD.DrawLargeText(0,255,8,50,"Room Temp", Font8x8);

  // Display the T2 Temp Value
  ReefAngel.LCD.Clear(255, 90, 50, 132, 60);
  ConvertNumToString(text, ReefAngel.Params.Temp[T2_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(COLOR_MIDNIGHTBLUE, 255, 90, 50, text, Num8x8);

  // Display pH Header Text
  ReefAngel.LCD.DrawLargeText(COLOR_DARKSLATEBLUE,255,90,75,"pH", Font8x8);

  // Display pH Value
  ConvertNumToString(text, ph, 100);
  ReefAngel.LCD.Clear(0, 65, 62 , 65, 62);
  if (ph>840 || ph<790) ReefAngel.LCD.DrawLargeText(COLOR_RED, 255, 85, 88, text, Num8x8);
  else if (ph>830 || ph<800) ReefAngel.LCD.DrawLargeText(COLOR_ORANGE, 255, 85, 88, text, Num8x8);
  else ReefAngel.LCD.DrawLargeText(COLOR_MIDNIGHTBLUE, 255, 85, 88, text, Num8x8);

  // Display Vortech Mode
  ReefAngel.LCD.DrawLargeText(0,255,8,60,"Vortech", Font8x8);
  
  // Display EcoSmart Mode Value      
  ReefAngel.LCD.Clear(255, 66, 60, 132, 70);
  if (vtechmode == 0) ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN,255, 66, 60,"Constant");
  else if(vtechmode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255, 66, 60,"Lagoon");
  else if (vtechmode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255, 80, 60,"RCM");
  else if (vtechmode == 3) ReefAngel.LCD.DrawLargeText(COLOR_CORNFLOWERBLUE,255, 80, 60,"Short");
  else if (vtechmode == 4) ReefAngel.LCD.DrawLargeText(COLOR_PINK,255, 66, 60,"Long");
  else if (vtechmode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255, 80, 60,"NTM");
  else if (vtechmode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255, 80, 60,"TSM");
  else if (vtechmode == 9) ReefAngel.LCD.DrawLargeText(COLOR_GRAY,255, 80, 60,"Night");

  // Display Salinity 
    ReefAngel.LCD.DrawLargeText(0,255,66,100,"Salinity", Font8x8);
    
  // Display Salinity Value 
    ReefAngel.LCD.Clear(255, 82, 85, 65, 95);
    ConvertNumToString(text, ReefAngel.Params.Salinity, 100);
    ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN, 255, 85, 110, text, Num8x8);

  //Start Moon Phase Display
  if (MoonPhase() >=0 && MoonPhase() < 4) ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,75,"Off");
  else if(MoonPhase() >=1 && MoonPhase() < 5) ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,75,"New");
  else if(MoonPhase() >=6 && MoonPhase() < 10) ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,75,"Cresent");
  else if(MoonPhase() >=11 && MoonPhase() < 19) ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,75,"Half");
  else if(MoonPhase() >=20 && MoonPhase() < 29) ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,75,"Gibbous");
  else if(MoonPhase() >=30 && MoonPhase() < 45) ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,75,"Full");
  //End Display Moon Phase Display
  
  // Display Main and Expansion Relay Box
  TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawCircleOutletBox(10,90, TempRelay);
  pingSerial();

  TempRelay2 = ReefAngel.Relay.RelayDataE[0];
  TempRelay2 &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay2 |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawCircleOutletBox(40,90, TempRelay2);
  pingSerial();
  break;
  
   case 1:  //Temperature detail screen with sump and room temp, 24 hr. max/min, time stamps, and graph
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,10,15,"Temp Details", Font8x8);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,33,"Sump:");
    ReefAngel.LCD.DrawSingleMonitor(maintemp, COLOR_BLACK, 36, 33, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,43,"HI:");
    ReefAngel.LCD.DrawSingleMonitor(maxTemp, 0, 23, 43, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,48,43,"at");
    DrawTime(60,43,0, COLOR_WHITE,tsmax);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,53,"LO:");
    ReefAngel.LCD.DrawSingleMonitor(minTemp, 0, 23, 53, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,48,53,"at");
    DrawTime(60,53,0,COLOR_WHITE, tsmin);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,63,"Range:");
    ReefAngel.LCD.DrawSingleMonitor((maxTemp-minTemp), COLOR_BLACK, 46, 63, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,69,63,"degreesC");
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,73,"Avg:");
    DrawDailyAvg(maintemp, COLOR_BLACK, 43, 73, 1);  
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,83,"WeeklyAvg:");
    DrawWeeklyAvg(12,maintemp, COLOR_BLACK, 66, 83, 1);  
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor, 86,83,"at noon");
    ReefAngel.LCD.DrawText(T2TempColor,DefaultBGColor, 5 ,93,"Room:");
    ReefAngel.LCD.DrawSingleMonitor(roomtemp, COLOR_BLACK, 36, 93, 10);
    break;
    
  case 2:  //pH details
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,20,15,"pH Details", Font8x8);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,33,"pH:");
    ReefAngel.LCD.DrawSingleMonitor(ph, COLOR_BLACK, 36, 33, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,43,"HI:");
    ReefAngel.LCD.DrawSingleMonitor(maxPH, 0, 23, 43, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,48,43,"at");
    DrawTime(60,43,0, COLOR_WHITE,PHmax);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,53,"LO:");
    ReefAngel.LCD.DrawSingleMonitor(minPH, 0, 23, 53, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,48,53,"at");
    DrawTime(60,53,0,COLOR_WHITE, PHmin);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,63,"Range:");
    ReefAngel.LCD.DrawSingleMonitor((maxPH-minPH), COLOR_BLACK, 46, 63, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,73,"Avg:");
    DrawDailyAvg(ph, COLOR_BLACK, 43, 73, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,83,"WeeklyAvg:");
    DrawWeeklyAvg(12,ph, COLOR_BLACK, 66, 83, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor, 86,83,"at noon");
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,93,"WeeklyAvg:");
    DrawWeeklyAvg(0,ph, COLOR_BLACK, 66, 93, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor, 86,93,"at midnt");
    break;
 
    case 3:  //relay box key
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 0, "                 ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;  
    ReefAngel.LCD.DrawCircleOutletBox(56,46,TempRelay);
    
    ReefAngel.LCD.DrawLargeText(0,255,27,20,"RelayBox 1", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,7,44,"Return", Font8x8); //1
    ReefAngel.LCD.DrawLargeText(0,255,7,54,"ATU", Font8x8); //3
    ReefAngel.LCD.DrawLargeText(0,255,7,64,"SumpL", Font8x8); //5
    ReefAngel.LCD.DrawLargeText(0,255,7,74,"Salty", Font8x8); //7
    ReefAngel.LCD.DrawLargeText(0,255,75,44,"Skimer", Font8x8);  //2
    ReefAngel.LCD.DrawLargeText(0,255,75,54,"Reactr", Font8x8);  //4
    ReefAngel.LCD.DrawLargeText(0,255,75,64,"Heatr", Font8x8); //6
    ReefAngel.LCD.DrawLargeText(0,255,75,74,"Relay", Font8x8);  //8
    break;
    
  case 4:  //relay box key
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    TempRelay2 = ReefAngel.Relay.RelayDataE[0];
    TempRelay2 &= ReefAngel.Relay.RelayMaskOffE[0];
    TempRelay2 |= ReefAngel.Relay.RelayMaskOnE[0];  
    ReefAngel.LCD.DrawCircleOutletBox(56,46,TempRelay2);
    
    ReefAngel.LCD.DrawLargeText(0,255,27,20,"RelayBox 2", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,7,44,"VTech", Font8x8);//1
    ReefAngel.LCD.DrawLargeText(0,255,7,54,"Ozone", Font8x8);//3
    ReefAngel.LCD.DrawLargeText(0,255,7,64,"Day1", Font8x8);//5
    ReefAngel.LCD.DrawLargeText(0,255,7,74,"Day3", Font8x8);//7
    ReefAngel.LCD.DrawLargeText(0,255,75,44,"VTech", Font8x8);//2
    ReefAngel.LCD.DrawLargeText(0,255,75,54,"Moon", Font8x8);//4
    ReefAngel.LCD.DrawLargeText(0,255,75,64,"Day2", Font8x8);//6
    ReefAngel.LCD.DrawLargeText(0,255,75,74,"MLed", Font8x8);//8
    break;
    
    case 5:  //setclock
    // Analog clock is modified from the original source by Jeff Miller
  // Author: Jeff Miller   http://arduinofun.blogspot.com/
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    // Frame
    DrawCircle(clock_center_x, clock_center_y, clock_radius, COLOR_CORNFLOWERBLUE);
    DrawCircle(clock_center_x, clock_center_y, clock_radius - 1, COLOR_CORNFLOWERBLUE);        
    DrawCircle(clock_center_x, clock_center_y, clock_radius - 2, COLOR_CORNFLOWERBLUE);       
    // Face Tick Marks  (x = r cos theta, y = r sin theta)
    for (byte r=0; r < 12; r++) {
      float angle = (2 * pi / 12)*r;
      int tick_x_out = (clock_radius - 8) * cos (angle) + clock_center_x;
      int tick_y_out = (clock_radius - 8) * sin (angle) + clock_center_y;
      int tick_x_in = clock_radius *.72 * cos (angle) + clock_center_x;
      int tick_y_in = clock_radius * .72 * sin (angle) + clock_center_y;                
      Drawline(tick_x_in, tick_y_in, tick_x_out, tick_y_out, COLOR_CORNFLOWERBLUE);
      }
    // Face Characters
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 8,106," 6", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 8, 25,"12", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x + 34,clock_center_y," 3", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 50, clock_center_y - 4,"9 ", Font8x8);
   // Draw Seconds Hand
       secondangle = (2 * pi / 60) * second();
              if (second() > 15)
        {secondangle = secondangle -1.57;
        }
      else
        {secondangle = secondangle +4.71;
        }
       Drawline(clock_center_x, clock_center_y, secondend_x, secondend_y, WHITE);
       secondend_x = secondhand_radius * cos (secondangle) + clock_center_x;
       secondend_y = secondhand_radius * sin (secondangle) + clock_center_y;
       Drawline(clock_center_x, clock_center_y, secondend_x, secondend_y, BLACK);
// Redraw minutes hand since the section closest to the center gets erased by the seconds hand
       draw_minute(BLACK);
// Redraw hour hand
       draw_hour(BLACK);
// Draw Minutes Hand
       minuteangle = (2 * pi / 60) * minute();
       if (minute() > 15)
        {minuteangle = minuteangle -1.57;
        }
      else
        {minuteangle = minuteangle +4.71;
        }
        // Erase old minutes Hand
       draw_minute(WHITE);
  // Calculate Minute Hand Base
      minutebase_x = minutebase_radius * cos (minuteangle - pi/2) + clock_center_x;
      minutebase_y = minutebase_radius * sin (minuteangle - pi/2) + clock_center_y;
      minutebase_x1 = minutebase_radius * cos (minuteangle + pi/2) + clock_center_x;
      minutebase_y1 = minutebase_radius * sin (minuteangle + pi/2) + clock_center_y;
// Calculate Minute Hand Point
      minuteend_x = minutehand_radius * cos (minuteangle) + clock_center_x;
      minuteend_y = minutehand_radius * sin (minuteangle) + clock_center_y;
// Draw new minutes Hand
      draw_minute(BLACK);                         
// Redraw hour hand
      draw_hour(BLACK);
// Draw Hour Hand   
      minfloat = minute(); // Convert minute short to float
      hourangle = (2 * pi / 12) * ((hourFormat12()) + (minfloat/60)); // Find angle for hour hand
      hourangle = hourangle -1.57;
// Erase old Hour Hand
      draw_hour(WHITE);
// Calculate hour Hand Base
      hourbase_x = hourbase_radius * cos (hourangle - pi/2) + clock_center_x;
      hourbase_y = hourbase_radius * sin (hourangle - pi/2) + clock_center_y;
      hourbase_x1 = hourbase_radius * cos (hourangle + pi/2) + clock_center_x;
      hourbase_y1 = hourbase_radius * sin (hourangle + pi/2) + clock_center_y;
// Calculate hour Hand Point
      hourend_x = hourhand_radius * cos (hourangle) + clock_center_x;
      hourend_y = hourhand_radius * sin (hourangle) + clock_center_y;
// Draw new hours Hand
      draw_hour(BLACK);
    ReefAngel.LCD.DrawLargeText(0,255,110,110,"#8", Font8x8);
    ReefAngel.LCD.DrawDate(5,121);
    break;
    
 case 6: // Vortech Setup
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawText(0,255,20,50,"Assigning Slaves");
    ReefAngel.RF.SetMode(Slave_Start,0,0);
    InternalMemory.RFMode_write(0);
    InternalMemory.RFSpeed_write(128);
    InternalMemory.RFDuration_write(10);
  if (ReefAngel.Joystick.IsButtonPressed())
    {
      ReefAngel.RF.SetMode(Slave_Stop,0,0);
      ReefAngel.LCD.DrawText(0,255,50,60,"Done");
    }
    break;

  //---------------------------------------------------------PWM Parabola Per Channel-----------------------------------------------------

  MoonPWMValue=MoonPhase();
  if (hour()>=22 || hour()<=8)
    MoonPWMValue=PWMSlope(22,00,8,00,0,MoonPhase(),45,0);
  if (ChannelValue[LEDWhiteBlue]>=1) MoonPWMValue=0;
  ReefAngel.PWM.SetChannel(4,MoonPWMValue);
  
    
    ChannelValue[LEDWhiteBlue]=PWMParabola(8,0,22,0,0,90,300);
    ChannelValue[LEDWhiteBlue1]=PWMParabola(8,30,21,30,0,90,270);
    ChannelValue[LEDWhiteBlue2]=PWMParabola(9,0,21,0,0,90,240);
    ChannelValue[MixedLED]=PWMParabola(12,0,18,0,0,90,0);
    
    //CheckCloud(); //(May be used at a later date with cloud/storm effects)
  
    ReefAngel.PWM.Expansion(LEDWhiteBlue,int(ChannelValue[LEDWhiteBlue]));
    ReefAngel.PWM.Expansion(LEDWhiteBlue1,int(ChannelValue[LEDWhiteBlue1]));
    ReefAngel.PWM.Expansion(LEDWhiteBlue2,int(ChannelValue[LEDWhiteBlue2]));
    ReefAngel.PWM.Expansion(MixedLED,int(ChannelValue[MixedLED]));
    ReefAngel.PWM.Expansion(LEDMoonlights,int(ChannelValue[LEDMoonlights]));
    
  //------------------------------------------------- End PWM Expansion Code for Slope ----------------------------------------------
  
  //------------------------------------------------ Start Time-of-Day Based Functions ----------------------------------------------
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These are the mode numbers for the RF Expansion Module for reference ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //#define Constant      0
  //#define Random1       1 // Lagoonal
  //#define Random2       2 // Reef Crest
  //#define ShortWave     3
  //#define LongWave      4
  //#define Smart_NTM     5 // Nutrient Transport Mode
  //#define Smart_TSM     6 // Tidal Swell Mode
  //#define Feeding_Start 7
  //#define Feeding_Stop  8
  //#define Night         9
  //#define Slave_Start   97
  //#define Slave_Stop    98
  //#define None          99
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 //-------------------------------------------------------- Start RF Daytime Control -----------------------------------------------
  if (hour() >=8 && hour() <= 22)
  {  
    if (ReefAngel.DisplayedMenu==FEEDING_MODE) bFeeding=true;
    if (ReefAngel.DisplayedMenu==DEFAULT_MENU && bFeeding )
    {
      bFeeding=false; 
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Smart_NTM,155,5);
      ReefAngel.Timer[4].SetInterval(1800); // Timer for 30min
      ReefAngel.Timer[4].Start();
      vtechmode = 5;
    }
    if (ReefAngel.DisplayedMenu==DEFAULT_MENU && ReefAngel.Timer[4].IsTriggered())
    {
      ReefAngel.RF.UseMemory=true;
      vtechmode = InternalMemory.RFMode_read();
    }  
  }

  //-------------------------------------------------------- Start RF Nightmode Control ---------------------------------------------  


  if (hour()>=22 || hour()<8) // Defining "Nightmode" hours for VorTech = between 10 PM and 8 AM
  {
    ReefAngel.RF.UseMemory=false;
    ReefAngel.RF.SetMode(Night,15,0);
    vtechmode = 9;
  }
  else
  {
    ReefAngel.RF.SetMode(Feeding_Stop,0,0); //Temp fix for coming out of Night mode
    ReefAngel.RF.UseMemory=true;
    vtechmode = InternalMemory.RFMode_read();
  } 

}
}
// Random Cloud/Thunderstorm effects function
// From Roberto - THANKS ROBERTO!
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_5_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 25

  // 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 15

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

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

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

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

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

  // Channels used by the actinic LEDs on the PWM Expansion module
  // These channels will not be dimmed when the cloud effect is triggered
  // Number is a binary form. B001100 means channel 2 and 3 are used for actinics
#define Actinic_Channels B000101

  // Channels used by the daylight LEDs on the PWM Expansion module
  // These channels will be used for the spike when lightning effect is triggered
  // Number is a binary form. B000011 means channel 0 and 1 are used for daylights
#define Daylight_Channels B001010

  // 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(26); 
      // 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_5_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(36);
        // 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?
//is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      // let's go through all channels to pick which ones will be dimmed
      for (int a=0;a<6;a++)
      {
        if (bitRead(Actinic_Channels,a)==0)
        {
          // this will slope down the channel from the current PWM to 0 within 3minutes.
          // then it will stay at 0 for the duration of the cycle
          // and finally slope up from 0 to PWM value within 3 minutes
          // it is basically an inversed slope
          ChannelValue[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,ChannelValue[a],0,180);
        }
      }
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        for (int b=0;b<6;b++)
        {
          if (bitRead(Daylight_Channels,b)==1)
          {
            if (random(100)<20) lightningstatus=1; 
            else lightningstatus=0;
            if (lightningstatus) ChannelValue[b]=100; 
            else ChannelValue[b]=0;
            //delay(10);
          }
          else
          {
            ChannelValue[b]=20;
          }
        }
      }
    }
    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;
      }
    }
  }
  
     
}

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 
 
  ReefAngel.ShowInterface();
}
Last edited by JNieuwenhuizen on Mon Apr 09, 2012 2:59 am, edited 1 time in total.
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

Sorry Had to split this into 2 posts

I need help with this - Due to multiple screens, I dont have a menus.. Must be something like defining on what screen menu must be.
Defined Menus

Code: Select all

//------------------------------------------------------ Custom Menu Code ---------------------------------------------------------
prog_char menu1_label[] PROGMEM = "Food!!";
prog_char menu2_label[] PROGMEM = "Cleanup";
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 = "Salty Calibration";
prog_char menu7_label[] PROGMEM = "Vortech Modes";
prog_char menu8_label[] PROGMEM = "Force Cloud";
prog_char menu9_label[] PROGMEM = "Force Lightning";

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.SetupCalibrateSalinity();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
   vtmode++;
   if ( vtmode == 7 ) vtmode = 9;
   if ( vtmode > 9 ) vtmode = 1;
   // 1st parameter is Mode, 2nd is speed, 3rd is duration
   ReefAngel.RF.SetMode(vtmode, InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
   ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}

void MenuEntry8()
{
 ForceCloud=true; 
 ReefAngel.DisplayedMenu=RETURN_MAIN_MODE;
}
void MenuEntry9()
{
ForceLightning=true;
ReefAngel.DisplayedMenu=RETURN_MAIN_MODE;
}

//------------------------------------------------------ Grouped Menu Entries ----------------------------------------------------
PROGMEM const char *menu_items[] = {
  menu1_label, menu2_label, menu3_label,
  menu4_label, menu5_label, menu6_label,
  menu7_label,menu8_label,menu9_label
};

void Setup()
ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));

The Analogue clock is not pulling info from the controller - code used was pulling info from a second RA unit.

Code: Select all

//---------------------------------------------------------- Custom Main ----------------------------------------------------------
void DrawCircleOutline(byte x, byte y, byte radius, byte bordercolor);
void FillCircle(byte x, byte y, byte radius, byte fillcolor);
void DrawCircleOutletBox(byte x, byte y, byte RelayData, bool reverse = false);
//------------------------------------------------------ Analog Clock constants ---------------------------------------------------
    const float pi = 3.141592653;
    byte clock_center_x = 65;
    byte clock_center_y = 65;
    byte clock_radius = 55;
    byte secondhand_radius = 33;
    float secondangle;
    byte secondend_x;
    byte secondend_y;
    float minuteangle;
    float hourangle;
//------------------------------------------------------ Analog Clock Structure ----------------------------------------------------
       int minutebase_radius = 3;
       int minutehand_radius = 33;
       int hourbase_radius = 3;
       int hourhand_radius = 25;   
       int seconds_hand_x, seconds_hand_y, minutes_hand_x, minutes_hand_y, hours_hand_x, hours_hand_y;
       int hours_hand_base_x, hours_hand_base_y, hours_hand_base_x1, hours_hand_base_y1;
       int minutes_hand_base_x, minutes_hand_base_y, minutes_hand_base_x1, minutes_hand_base_y1; 
       int minutebase_x, minutebase_y, minutebase_x1, minutebase_y1; 
       int minuteend_x, minuteend_y; 
       int hourbase_x, hourbase_y, hourbase_x1, hourbase_y1; 
       int hourend_x, hourend_y; 
       float minfloat;
//----------------------------------------------------------- time stamp -----------------------------------------------------------
time_t tsmax=now();
time_t tsmin=now();
time_t PHmax=now();
time_t PHmin=now();
int mastertime;

//-------------------------------------------------------- Draw Minutes Hand -------------------------------------------------------
void draw_minute(int color)
{
  Drawline(minutebase_x, minutebase_y, minutebase_x1, minutebase_y1, color); 
  Drawline(minutebase_x, minutebase_y, minuteend_x, minuteend_y, color); 
  Drawline(minutebase_x1, minutebase_y1, minuteend_x, minuteend_y, color); 
}
//-------------------------------------------------------- Draw Hour Hand ----------------------------------------------------------
void draw_hour(int color)
{
   Drawline(hourbase_x, hourbase_y, hourbase_x1, hourbase_y1, color); 
   Drawline(hourbase_x, hourbase_y, hourend_x, hourend_y, color); 
   Drawline(hourbase_x1, hourbase_y1, hourend_x, hourend_y, color); 
}
void Drawline (int x0, int y0, int x1, int y1, int color) 
{
  int dy = y1 - y0;
  int dx = x1 - x0;
  int stepx, stepy;
  if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
  if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
  dy <<= 1; // dy is now 2*dy
  dx <<= 1; // dx is now 2*dx
  ReefAngel.LCD.PutPixel(color, x0, y0);
  if (dx > dy) {
    int fraction = dy - (dx >> 1); // same as 2*dy - dx
    while (x0 != x1) {
      if (fraction >= 0) {
        y0 += stepy;
        fraction -= dx; // same as fraction -= 2*dx
        }
      x0 += stepx;
      fraction += dy; // same as fraction -= 2*dy
      ReefAngel.LCD.PutPixel(color, x0, y0);
    }
  } else {
  int fraction = dx - (dy >> 1);
  while (y0 != y1) {
  if (fraction >= 0) {
    x0 += stepx;
    fraction -= dy;
    }
  y0 += stepy;
  fraction += dx;
  ReefAngel.LCD.PutPixel(color, x0, y0);
  }
  }}
void DrawTime(byte x, byte y, byte FGcolor, byte BGcolor, time_t ts)
{
    char text[13];
    char temp[]="  ";
    strcpy(text,"");
    itoa(hourFormat12(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    strcat(text,":");
    itoa(minute(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    strcat(text,":");
    itoa(second(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    if (isAM(ts))
    {
        strcat(text," AM");
    }
    else
    {
        strcat(text," PM");
    }
    ReefAngel.LCD.DrawText(FGcolor, BGcolor, x, y, text);
}
void DrawCircle(int a, int b, int r, byte color)
{
  int f = 1 - r;  
  int ddF_x = 1;  
  int ddF_y = -2 * r;  
  int x = 0;  
  int y = r;
  
ReefAngel.LCD.PutPixel(color, a, b+r);  
ReefAngel.LCD.PutPixel(color ,a, b-r);  
ReefAngel.LCD.PutPixel(color, a+r, b);  
ReefAngel.LCD.PutPixel(color, a-r, b);
 while (x<y) 
{    
if (f >= 0) 
{      y--;
       ddF_y += 2;      
       f += ddF_y;    
   }    
   x++;    
   ddF_x += 2;    
   f += ddF_x;
   
   ReefAngel.LCD.PutPixel(color, a + x, b + y);
   ReefAngel.LCD.PutPixel(color, a - x, b + y);
   ReefAngel.LCD.PutPixel(color, a + x, b - y);
   ReefAngel.LCD.PutPixel(color, a - x, b - y);
   ReefAngel.LCD.PutPixel(color, a + y, b + x);
   ReefAngel.LCD.PutPixel(color, a - y, b + x);
   ReefAngel.LCD.PutPixel(color, a + y, b - x);
   ReefAngel.LCD.PutPixel(color, a - y, b - x);
   }
}
void loop()
    case 5:  //setclock
    // Analog clock is modified from the original source by Jeff Miller
  // Author: Jeff Miller   http://arduinofun.blogspot.com/
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    // Frame
    DrawCircle(clock_center_x, clock_center_y, clock_radius, COLOR_CORNFLOWERBLUE);
    DrawCircle(clock_center_x, clock_center_y, clock_radius - 1, COLOR_CORNFLOWERBLUE);        
    DrawCircle(clock_center_x, clock_center_y, clock_radius - 2, COLOR_CORNFLOWERBLUE);       
    // Face Tick Marks  (x = r cos theta, y = r sin theta)
    for (byte r=0; r < 12; r++) {
      float angle = (2 * pi / 12)*r;
      int tick_x_out = (clock_radius - 8) * cos (angle) + clock_center_x;
      int tick_y_out = (clock_radius - 8) * sin (angle) + clock_center_y;
      int tick_x_in = clock_radius *.72 * cos (angle) + clock_center_x;
      int tick_y_in = clock_radius * .72 * sin (angle) + clock_center_y;                
      Drawline(tick_x_in, tick_y_in, tick_x_out, tick_y_out, COLOR_CORNFLOWERBLUE);
      }
    // Face Characters
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 8,106," 6", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 8, 25,"12", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x + 34,clock_center_y," 3", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 50, clock_center_y - 4,"9 ", Font8x8);
   // Draw Seconds Hand
       secondangle = (2 * pi / 60) * second();
              if (second() > 15)
        {secondangle = secondangle -1.57;
        }
      else
        {secondangle = secondangle +4.71;
        }
       Drawline(clock_center_x, clock_center_y, secondend_x, secondend_y, WHITE);
       secondend_x = secondhand_radius * cos (secondangle) + clock_center_x;
       secondend_y = secondhand_radius * sin (secondangle) + clock_center_y;
       Drawline(clock_center_x, clock_center_y, secondend_x, secondend_y, BLACK);
// Redraw minutes hand since the section closest to the center gets erased by the seconds hand
       draw_minute(BLACK);
// Redraw hour hand
       draw_hour(BLACK);
// Draw Minutes Hand
       minuteangle = (2 * pi / 60) * minute();
       if (minute() > 15)
        {minuteangle = minuteangle -1.57;
        }
      else
        {minuteangle = minuteangle +4.71;
        }
        // Erase old minutes Hand
       draw_minute(WHITE);
  // Calculate Minute Hand Base
      minutebase_x = minutebase_radius * cos (minuteangle - pi/2) + clock_center_x;
      minutebase_y = minutebase_radius * sin (minuteangle - pi/2) + clock_center_y;
      minutebase_x1 = minutebase_radius * cos (minuteangle + pi/2) + clock_center_x;
      minutebase_y1 = minutebase_radius * sin (minuteangle + pi/2) + clock_center_y;
// Calculate Minute Hand Point
      minuteend_x = minutehand_radius * cos (minuteangle) + clock_center_x;
      minuteend_y = minutehand_radius * sin (minuteangle) + clock_center_y;
// Draw new minutes Hand
      draw_minute(BLACK);                         
// Redraw hour hand
      draw_hour(BLACK);
// Draw Hour Hand   
      minfloat = minute(); // Convert minute short to float
      hourangle = (2 * pi / 12) * ((hourFormat12()) + (minfloat/60)); // Find angle for hour hand
      hourangle = hourangle -1.57;
// Erase old Hour Hand
      draw_hour(WHITE);
// Calculate hour Hand Base
      hourbase_x = hourbase_radius * cos (hourangle - pi/2) + clock_center_x;
      hourbase_y = hourbase_radius * sin (hourangle - pi/2) + clock_center_y;
      hourbase_x1 = hourbase_radius * cos (hourangle + pi/2) + clock_center_x;
      hourbase_y1 = hourbase_radius * sin (hourangle + pi/2) + clock_center_y;
// Calculate hour Hand Point
      hourend_x = hourhand_radius * cos (hourangle) + clock_center_x;
      hourend_y = hourhand_radius * sin (hourangle) + clock_center_y;
// Draw new hours Hand
      draw_hour(BLACK);
    ReefAngel.LCD.DrawLargeText(0,255,110,110,"#8", Font8x8);
    ReefAngel.LCD.DrawDate(5,121);
    break;
And the pH - Temp Screens needs a bit of fine tuning, I believe they also pull info from a remote RA.

pH Screen

Code: Select all

//------------------------------------- Globals Needed for Params on Custom Main --------------------------------------------------
int maxTemp=0;
int minTemp=2000;
int maintemp=270;
int roomtemp=300;
int ph=700;
int maxPH=600;
int minPH=900;

void DrawWeeklyAvg (byte hr, int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 7;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (hour()==hr && minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
}
void DrawDailyAvg (int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 24;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
}

void Loop()
  // update the min and max pH
if (now()%86400==0)
{
  minPH=ph;
  maxPH=ph;
}
if (ph<minPH) 
{
  minPH=ph;
  PHmin=now();
  
  
}
if (ph>maxPH) 
{
  maxPH=ph;
  PHmax=now();
}
  case 2:  //pH details
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,20,15,"pH Details", Font8x8);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,33,"pH:");
    ReefAngel.LCD.DrawSingleMonitor(ph, COLOR_BLACK, 36, 33, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,43,"HI:");
    ReefAngel.LCD.DrawSingleMonitor(maxPH, 0, 23, 43, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,48,43,"at");
    DrawTime(60,43,0, COLOR_WHITE,PHmax);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,53,"LO:");
    ReefAngel.LCD.DrawSingleMonitor(minPH, 0, 23, 53, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,48,53,"at");
    DrawTime(60,53,0,COLOR_WHITE, PHmin);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,63,"Range:");
    ReefAngel.LCD.DrawSingleMonitor((maxPH-minPH), COLOR_BLACK, 46, 63, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,73,"Avg:");
    DrawDailyAvg(ph, COLOR_BLACK, 43, 73, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,83,"WeeklyAvg:");
    DrawWeeklyAvg(12,ph, COLOR_BLACK, 66, 83, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor, 86,83,"at noon");
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,93,"WeeklyAvg:");
    DrawWeeklyAvg(0,ph, COLOR_BLACK, 66, 93, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor, 86,93,"at midnt");
    break;
Temp Screen

Code: Select all

//------------------------------------- Globals Needed for Params on Custom Main --------------------------------------------------
int maxTemp=0;
int minTemp=2000;
int maintemp=270;
int roomtemp=300;
int ph=700;
int maxPH=600;
int minPH=900;

void DrawWeeklyAvg (byte hr, int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 7;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (hour()==hr && minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
}
void DrawDailyAvg (int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 24;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
void Loop()
   }// update the min and max temps
  if (now()%86400==0)
  {
    minTemp=maintemp;
    maxTemp=maintemp;
  }
  if (maintemp<minTemp) 
  {
    minTemp=maintemp;
    tsmin=now();
  }
  if (maintemp>maxTemp) 
  {
    maxTemp=maintemp;
    tsmax=now();
  }

   case 1:  //Temperature detail screen with sump and room temp, 24 hr. max/min, time stamps, and graph
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,10,15,"Temp Details", Font8x8);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,33,"Sump:");
    ReefAngel.LCD.DrawSingleMonitor(maintemp, COLOR_BLACK, 36, 33, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,43,"HI:");
    ReefAngel.LCD.DrawSingleMonitor(maxTemp, 0, 23, 43, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,48,43,"at");
    DrawTime(60,43,0, COLOR_WHITE,tsmax);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,53,"LO:");
    ReefAngel.LCD.DrawSingleMonitor(minTemp, 0, 23, 53, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,48,53,"at");
    DrawTime(60,53,0,COLOR_WHITE, tsmin);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,63,"Range:");
    ReefAngel.LCD.DrawSingleMonitor((maxTemp-minTemp), COLOR_BLACK, 46, 63, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,69,63,"degreesC");
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,73,"Avg:");
    DrawDailyAvg(maintemp, COLOR_BLACK, 43, 73, 1);  
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,83,"WeeklyAvg:");
    DrawWeeklyAvg(12,maintemp, COLOR_BLACK, 66, 83, 1);  
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor, 86,83,"at noon");
    ReefAngel.LCD.DrawText(T2TempColor,DefaultBGColor, 5 ,93,"Room:");
    ReefAngel.LCD.DrawSingleMonitor(roomtemp, COLOR_BLACK, 36, 93, 10);
    break;
Any help would be higly appreciated!
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: My almost completed pde

Post by rimai »

You have the function ShowInterface() in the wrong place.
This is the function that will deal with the menu stuff.
Problem is that if you add that in any of your custom screens, it will draw the standard screen too.
Curt would have more insight on this one.
Roberto.
User avatar
jsclownfish
Posts: 378
Joined: Mon Oct 24, 2011 7:52 pm
Location: Saint Louis

Re: My almost completed pde

Post by jsclownfish »

I'm not sure you can get multiple screens on your main window, but you can use one of your custom menu items to cycle through screens each time you go to that specific menu option. Please keep in mind many of the screens I put together for the auxillary display are still pretty new and may still have some bugs. You should be able to convert all of them to get data from the main directly. I planned to do that as well, but I just haven't found time (too busy playing with image displays. ;) )

Code: Select all

/*The following features are enabled for this File: 
#define DisplayImages
#define SetupExtras 
#define DateTimeSetup
#define VersionMenu
#define DisplayLEDPWM
#define wifi
#define RelayExp
#define WDT
#define CUSTOM_MENU
#define CUSTOM_MENU_ENTRIES 2
#define CUSTOM_MAIN
#define COLORS_PDE
#define FONT_8x8
#define NUMBERS_8x8

*/


#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 <ReefAngel.h>
#include <IO.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <avr/pgmspace.h>

// Custom Menu Code
prog_char menu1_label[] PROGMEM = "Step Selection";
prog_char menu2_label[] PROGMEM = "Changing Screens";
PROGMEM const char *menu_items[] = {
menu1_label, menu2_label
};

byte vtmode = 0;
//screen set-up
#define NumScreens 2
int ScreenID=0;

//increasing number when screen elected.
void MenuEntry1()
{
   vtmode++;
   if ( vtmode == 7 ) vtmode = 9;
   if ( vtmode > 9 ) vtmode = 1;
   ReefAngel.LCD.DrawSingleMonitor(vtmode, COLOR_BLACK, 36, 33, 100);

}
//changing the screen each time selected
void MenuEntry2()
{
  ScreenID++;
  if ( ScreenID == 2 ) ScreenID = 0;
  if ( ScreenID > 2 ) ScreenID = 0;
  switch (ScreenID)
  {
  case 0:  //Initial first screen
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 0, "                 ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Jon's Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,100,120,"#1", Font8x8);
    break;
  case 1:  //Initial first screen
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 0, "                 ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Jon's Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,100,120,"#2", Font8x8);
    break;
   }
}
void DrawCustomGraph()
{
}
void DrawCustomMain()
{
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 0, "                 ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Jon's Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,100,120,"MAIN", Font8x8);
}
void setup()
{
  ReefAngel.Init();  //Initialize controller and start web banner timer
  ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));
}
void loop()
{
  // Specific functions
  //1st Heater at 78.8, 2nd Heater at 77.0, MH on at 10AM off at 8PM, Actinics on at 9AM off at 9PM, Fan kicks on at 82.0
  ReefAngel.StandardHeater(Port1,788,792);
  ReefAngel.StandardHeater(Port2,770,792);
  ReefAngel.MHLights(Port3,10,0,20,0,5);
  ReefAngel.StandardLights(Port4,9,0,21,0);
  ReefAngel.StandardFan(Port8,792,820);
  ReefAngel.DosingPumpRepeat(Box1_Port7,0,60,4); // Dose for 4 seconds every 60 minutes with 0 minutes offset
  ReefAngel.DosingPumpRepeat(Box1_Port8,5,60,4); // Dose for 4 seconds every 60 minutes with 5 minutes offset
  ReefAngel.ShowInterface();
}
-Jon
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

Thank You Jon

The multiple screens do work on the main widow- its only menus that dont work.

I will wait for binder to reply , perhaps he has a idea of how to get the data and menus going
User avatar
jsclownfish
Posts: 378
Joined: Mon Oct 24, 2011 7:52 pm
Location: Saint Louis

Re: My almost completed pde

Post by jsclownfish »

No problem. When I said that it doesn't work, I meant that the menu's weren't available as you have observed as well.

-Jon
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

rimai - so showinterface will bring the menu to the screen? meaning if I add that to case 0 it will bring menus to case 0 , but also the standard screen?
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: My almost completed pde

Post by rimai »

yes
Roberto.
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

jsclownfish wrote:No problem. When I said that it doesn't work, I meant that the menu's weren't available as you have observed as well.

-Jon
Ok. We will sort the menu thing out Jon, but how about getting the code to look at internal values?

You know where you referenced what, could you help on the 3 screens - analog clock, pH and Temp?

Then at least its 1 thing down , 1 to go?
Last edited by JNieuwenhuizen on Fri Apr 13, 2012 2:33 pm, edited 1 time in total.
User avatar
jsclownfish
Posts: 378
Joined: Mon Oct 24, 2011 7:52 pm
Location: Saint Louis

Re: My almost completed pde

Post by jsclownfish »

It should be pretty straightforward to use these codes on the main, you'll just have to replace my variables with the actual values from the main unit....

maintemp replaced by ReefAngel.Params.Temp[T1_PROBE]
sumptemp replaced by ReefAngel.Params.Temp[T2_PROBE]
roomtemp replaced by ReefAngel.Params.Temp[T3_PROBE]
ph replaced by ReefAngel.Params.PH
mhour replaced by hour()
mminute replaced by minute()
msecond replaced by second()
mday replaced by day()
mmonth replaced by month()
myear replaced by year()

Let me know if that doesn't work and I'll try to test it on my RA.
-Jon
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

Thank You Jon

I have made the changes, and the code does compile , and I did remove all your variables.

I will test a bit later and let you know - again, thank you for the help Jon!

Anyone have any ideas on the menus with the multiple screens?
User avatar
jsclownfish
Posts: 378
Joined: Mon Oct 24, 2011 7:52 pm
Location: Saint Louis

Re: My almost completed pde

Post by jsclownfish »

Can you post your code?
-Jon
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

Hi Jon

Here is my pde - has to be split into 2 posts as its to big for 1 (site gives a error :o )

Code: Select all

/*Included Features File
#define DirectTempSensor
#define DisplayLEDPWM
#define wifi
#define SaveRelayState
#define RelayExp
#define InstalledRelayExpansionModules 1
#define CUSTOM_MENU
#define CUSTOM_MENU_ENTRIES 9
#define PWMEXPANSION
#define CUSTOM_MAIN
#define CUSTOM_VARIABLES
#define SALINITYEXPANSION
#define RFEXPANSION
#define IOEXPANSION
#define FONT_8x8
#define NUMBERS_8x8
#define NUMBERS_16x16
*/
#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 <ReefAngel.h>
#include <avr/pgmspace.h>>
//***************************************************************************************************************************************************************************
//-------------------------------------------------------------------------- Screen set-up ---------------------------------------------------------------------------------
#define NumScreens 8
int ScreenID=0;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- PWM Cloud -----------------------------------------------------------------------------------
boolean ForceCloud=false;
boolean ForceLightning=false;
//
//***************************************************************************************************************************************************************************
//--------------------------------------------------------------------------- PWM Channels ----------------------------------------------------------------------------------
#define LEDWhiteBlue  0 
#define LEDWhiteBlue1 1
#define LEDWhiteBlue2 2
#define MixedLED 3
#define LEDMoonlights 4
//***************************************************************************************************************************************************************************
//--------------------------------------------------------------------- Start of Global Variables ---------------------------------------------------------------------------
byte ChannelValue[]={
0,0,0,0,0,0};
byte SeasonsVar[]={
0,0,0,0,0,0};
byte PWMports[] ={
  3,5,6,9,10,11};
byte MoonPWMValue;
byte vtmode = 0;
byte vtechmode;
byte DayAge;
byte ThisPhase;
int JulianDate(int,int,int);
double MoonAge(int,int,int);
byte MoonState();
boolean bFeeding=false;
byte x,y;
int maxTemp=0;
int minTemp=200;
int maxPH=600;
int minPH=900;
char text[10];
int v;
int moonlight=0;
long calcSec(long,long);
long calcTime(long,long);
short Ndays;
int rhour = 0, rmin = 0, shour = 0, smin = 0;
byte TempRelay =15;
byte TempRelay2=15;
static byte lightningchance=0;
byte cloudduration=0;
int cloudstart=0;
//***************************************************************************************************************************************************************************
//----------------------------------------------------------------------- Custom Menu Code ----------------------------------------------------------------------------------
prog_char menu1_label[] PROGMEM = "Food!!";
prog_char menu2_label[] PROGMEM = "Cleanup";
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 = "Salty Calibration";
prog_char menu7_label[] PROGMEM = "Vortech Modes";
prog_char menu8_label[] PROGMEM = "Force Cloud";
prog_char menu9_label[] PROGMEM = "Force Lightning";

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.SetupCalibrateSalinity();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
   vtmode++;
   if ( vtmode == 7 ) vtmode = 9;
   if ( vtmode > 9 ) vtmode = 1;
   // 1st parameter is Mode, 2nd is speed, 3rd is duration
   ReefAngel.RF.SetMode(vtmode, InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
   ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}
void MenuEntry8()
{
 ForceCloud=true; 
ReefAngel.DisplayedMenu=RETURN_MAIN_MODE;
}
void MenuEntry9()
{
ForceLightning=true;
ReefAngel.DisplayedMenu=RETURN_MAIN_MODE;
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------- Grouped Menu Entries ----------------------------------------------------------------------------
PROGMEM const char *menu_items[] = {
  menu1_label, menu2_label, menu3_label,
  menu4_label, menu5_label, menu6_label,
  menu7_label,menu8_label,menu9_label};
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------- Custom Main -------------------------------------------------------------------------------
void DrawCircleOutline(byte x, byte y, byte radius, byte bordercolor);
void FillCircle(byte x, byte y, byte radius, byte fillcolor);
void DrawCircleOutletBox(byte x, byte y, byte RelayData, bool reverse = false);
//***************************************************************************************************************************************************************************
//-------------------------------------------------------------------------- Analog Clock constants -------------------------------------------------------------------------
    const float pi = 3.141592653;
    byte clock_center_x = 65;
    byte clock_center_y = 65;
    byte clock_radius = 55;
    byte secondhand_radius = 33;
    float secondangle;
    byte secondend_x;
    byte secondend_y;
    float minuteangle;
    float hourangle;
//***************************************************************************************************************************************************************************
//--------------------------------------------------------------------------- Analog Clock Structure ------------------------------------------------------------------------
       int minutebase_radius = 3;
       int minutehand_radius = 33;
       int hourbase_radius = 3;
       int hourhand_radius = 25;   
       int seconds_hand_x, seconds_hand_y, minutes_hand_x, minutes_hand_y, hours_hand_x, hours_hand_y;
       int hours_hand_base_x, hours_hand_base_y, hours_hand_base_x1, hours_hand_base_y1;
       int minutes_hand_base_x, minutes_hand_base_y, minutes_hand_base_x1, minutes_hand_base_y1; 
       int minutebase_x, minutebase_y, minutebase_x1, minutebase_y1; 
       int minuteend_x, minuteend_y; 
       int hourbase_x, hourbase_y, hourbase_x1, hourbase_y1; 
       int hourend_x, hourend_y; 
       float minfloat;
//***************************************************************************************************************************************************************************       
//--------------------------------------------------------------------------------Time Stamp --------------------------------------------------------------------------------
time_t tsmax=now();
time_t tsmin=now();
time_t PHmax=now();
time_t PHmin=now();
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Minutes Hand --------------------------------------------------------------------------
void draw_minute(int color)
{
  Drawline(minutebase_x, minutebase_y, minutebase_x1, minutebase_y1, color); 
  Drawline(minutebase_x, minutebase_y, minuteend_x, minuteend_y, color); 
  Drawline(minutebase_x1, minutebase_y1, minuteend_x, minuteend_y, color); 
}
//***************************************************************************************************************************************************************************
//--------------------------------------------------------------------------- Draw Hour Hand --------------------------------------------------------------------------------
void draw_hour(int color)
{
   Drawline(hourbase_x, hourbase_y, hourbase_x1, hourbase_y1, color); 
   Drawline(hourbase_x, hourbase_y, hourend_x, hourend_y, color); 
   Drawline(hourbase_x1, hourbase_y1, hourend_x, hourend_y, color); 
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Line ----------------------------------------------------------------------------------
void Drawline (int x0, int y0, int x1, int y1, int color) 
{
  int dy = y1 - y0;
  int dx = x1 - x0;
  int stepx, stepy;
  if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
  if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
  dy <<= 1; // dy is now 2*dy
  dx <<= 1; // dx is now 2*dx
  ReefAngel.LCD.PutPixel(color, x0, y0);
  if (dx > dy) {
    int fraction = dy - (dx >> 1); // same as 2*dy - dx
    while (x0 != x1) {
      if (fraction >= 0) {
        y0 += stepy;
        fraction -= dx; // same as fraction -= 2*dx
        }
      x0 += stepx;
      fraction += dy; // same as fraction -= 2*dy
      ReefAngel.LCD.PutPixel(color, x0, y0);
    }
  } else {
  int fraction = dx - (dy >> 1);
  while (y0 != y1) {
  if (fraction >= 0) {
    x0 += stepx;
    fraction -= dy;
    }
  y0 += stepy;
  fraction += dx;
  ReefAngel.LCD.PutPixel(color, x0, y0);
  }
  }
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Time ----------------------------------------------------------------------------------
void DrawTime(byte x, byte y, byte FGcolor, byte BGcolor, time_t ts)
{
    char text[13];
    char temp[]="  ";
    strcpy(text,"");
    itoa(hourFormat12(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    strcat(text,":");
    itoa(minute(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    strcat(text,":");
    itoa(second(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    if (isAM(ts))
    {
        strcat(text," AM");
    }
    else
    {
        strcat(text," PM");
    }
    ReefAngel.LCD.DrawText(FGcolor, BGcolor, x, y, text);
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Circle --------------------------------------------------------------------------------
void DrawCircle(int a, int b, int r, byte color)
{
  int f = 1 - r;  
  int ddF_x = 1;  
  int ddF_y = -2 * r;  
  int x = 0;  
  int y = r;
  
ReefAngel.LCD.PutPixel(color, a, b+r);  
ReefAngel.LCD.PutPixel(color ,a, b-r);  
ReefAngel.LCD.PutPixel(color, a+r, b);  
ReefAngel.LCD.PutPixel(color, a-r, b);
 while (x<y) 
{    
if (f >= 0) 
{      y--;
       ddF_y += 2;      
       f += ddF_y;    
   }    
   x++;    
   ddF_x += 2;    
   f += ddF_x;
   
   ReefAngel.LCD.PutPixel(color, a + x, b + y);
   ReefAngel.LCD.PutPixel(color, a - x, b + y);
   ReefAngel.LCD.PutPixel(color, a + x, b - y);
   ReefAngel.LCD.PutPixel(color, a - x, b - y);
   ReefAngel.LCD.PutPixel(color, a + y, b + x);
   ReefAngel.LCD.PutPixel(color, a - y, b + x);
   ReefAngel.LCD.PutPixel(color, a + y, b - x);
   ReefAngel.LCD.PutPixel(color, a - y, b - x);
   }
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Weekly ------------------------------------------------------------------------------
void DrawWeeklyAvg (byte hr, int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 7;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (hour()==hr && minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Daily ---------------------------------------------------------------------------------
void DrawDailyAvg (int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 24;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Begin Setup --------------------------------------------------------------------------------
void setup()
{
  ReefAngel.Init();  //Initialize controller
  ReefAngel.Timer[LCD_TIMER].SetInterval(180);
  ReefAngel.Timer[LCD_TIMER].Start();  // start timer
  ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));
  ReefAngel.SetTemperatureUnit(1);
  ReefAngel.FeedingModePorts = 0;
  ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port6Bit | Box1_Port1 | Box1_Port2;
  ReefAngel.OverheatShutoffPorts = Port6Bit;
  ReefAngel.LightsOnPorts = 0;
//------------------------------------------------------------------------- Ports that are always on ------------------------------------------------------------------------
  ReefAngel.Relay.On(Port1);
  ReefAngel.Relay.On(Port4);
  ReefAngel.Relay.On(Port7);
  ReefAngel.Relay.On(Port8);
  ReefAngel.Relay.On(Box1_Port1);
  ReefAngel.Relay.On(Box1_Port2);
}
//***************************************************************************************************************************************************************************
Last edited by JNieuwenhuizen on Mon Apr 16, 2012 3:33 am, edited 4 times in total.
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

And

Code: Select all

void loop()
{
  CheckCloud();
//--------------------------------------------------------------------------- Specific Functions ----------------------------------------------------------------------------
  ReefAngel.Relay.DelayedOn(Port2, 2);
  ReefAngel.Relay.DelayedOn(Box1_Port1, 2);
  ReefAngel.Relay.DelayedOn(Box1_Port2, 2);
  ReefAngel.StandardATO(Port3);
  ReefAngel.MoonLights(Port5);
  ReefAngel.StandardHeater(Port6);
  ReefAngel.MoonLights(Box1_Port4);//LEDMoonlights
  ReefAngel.StandardLights(Box1_Port5);//White and Blue LED 
  ReefAngel.StandardLights(Box1_Port6,8,30,21,30);//White and Blue LED1
  ReefAngel.StandardLights(Box1_Port7,9,0,22,0);//White and Blue LED2
  ReefAngel.StandardLights(Box1_Port8,12,0,17,0);//MixedLED
  ReefAngel.Portal("JNieuwenhuizen","Evandre1");
  //---------------------------------------------------------------------------- PWM Channel Set -----------------------------------------------------------------------------
  ReefAngel.PWM.SetChannel(0,ChannelValue[LEDWhiteBlue]);
  ReefAngel.PWM.SetChannel(1,ChannelValue[LEDWhiteBlue1]);
  ReefAngel.PWM.SetChannel(2,ChannelValue[LEDWhiteBlue2]);
  ReefAngel.PWM.SetChannel(3,ChannelValue[MixedLED]);
  ReefAngel.PWM.SetChannel(4,ChannelValue[LEDMoonlights]);
//------------------------------------------------------------------------------ Multiple Screens ----------------------------------------------------------------------------
  setTime(hour(),minute(),second(),day(),month(),year());
  // update the min and max temps
  if (now()%86400==0)
  {
    minTemp=ReefAngel.Params.Temp[T1_PROBE];
    maxTemp=ReefAngel.Params.Temp[T1_PROBE];
  }
  if (ReefAngel.Params.Temp[T1_PROBE]<minTemp) 
  {
    minTemp=ReefAngel.Params.Temp[T1_PROBE];
    tsmin=now();
  }
  if (ReefAngel.Params.Temp[T1_PROBE]>maxTemp) 
  {
    maxTemp=ReefAngel.Params.Temp[T1_PROBE];
    tsmax=now();
  }
  // update the min and max pH
if (now()%86400==0)
{
  minPH=ReefAngel.Params.PH;
  maxPH=ReefAngel.Params.PH;
}
if (ReefAngel.Params.PH<minPH) 
{
  minPH=ReefAngel.Params.PH;
  PHmin=now();
}
if (ReefAngel.Params.PH>maxPH) 
{
  maxPH=ReefAngel.Params.PH;
  PHmax=now();
}
  if (ReefAngel.Joystick.IsLeft()) 
  {
    ReefAngel.ClearScreen(DefaultBGColor);
    ScreenID--;
  }
  if (ReefAngel.Joystick.IsRight()) 
    {
    ReefAngel.ClearScreen(DefaultBGColor);
    ScreenID++;
    }
  if (ScreenID<0) ScreenID=NumScreens;
  if (ScreenID>=NumScreens) ScreenID=0;
  switch (ScreenID)
  {
 //---------------------------------------------------------------------------- Screen Code 1--------------------------------------------------------------------------------   
case 0: 
  //Top Banner
  ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner 
  // Display T1 Header Text
  ReefAngel.LCD.DrawLargeText(COLOR_STEELBLUE,255,30,15,"Sump Temp", Font8x8);
  // Display the T1 Temp Value
 char text[7];
    ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
    ReefAngel.LCD.Clear(255, 35, 25, 50, 60);
    if (ReefAngel.Params.Temp[T1_PROBE]>270) ReefAngel.LCD.DrawHugeNumbers(COLOR_RED, 255, 35, 25, text);
    else if (ReefAngel.Params.Temp[T1_PROBE]>270) ReefAngel.LCD.DrawHugeNumbers(COLOR_ORANGE, 255, 35, 25, text);
    else ReefAngel.LCD.DrawHugeNumbers(COLOR_MIDNIGHTBLUE, 255, 35, 25, text);
  // Display the T2 Header Text
  ReefAngel.LCD.DrawLargeText(0,255,8,50,"Room Temp", Font8x8);
  // Display the T2 Temp Value
  ReefAngel.LCD.Clear(255, 90, 50, 132, 60);
  ConvertNumToString(text, ReefAngel.Params.Temp[T2_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(COLOR_MIDNIGHTBLUE, 255, 90, 50, text, Num8x8);
  // Display pH Header Text
  ReefAngel.LCD.DrawLargeText(COLOR_DARKSLATEBLUE,255,90,75,"pH", Font8x8);
  // Display pH Value
  ConvertNumToString(text, ReefAngel.Params.PH, 100); // check code
  ReefAngel.LCD.Clear(0, 65, 62 , 65, 62);
  if (ReefAngel.Params.PH>840 || ReefAngel.Params.PH<790) ReefAngel.LCD.DrawLargeText(COLOR_RED, 255, 85, 88, text, Num8x8);
  else if (ReefAngel.Params.PH>830 || ReefAngel.Params.PH<800) ReefAngel.LCD.DrawLargeText(COLOR_ORANGE, 255, 85, 88, text, Num8x8);
  else ReefAngel.LCD.DrawLargeText(COLOR_MIDNIGHTBLUE, 255, 85, 88, text, Num8x8);
  // Display Vortech Mode
  ReefAngel.LCD.DrawLargeText(0,255,8,60,"Vortech", Font8x8);
  // Display EcoSmart Mode Value      
  ReefAngel.LCD.Clear(255, 66, 60, 132, 70);
  if (vtechmode == 0) ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN,255, 66, 60,"Constant");
  else if(vtechmode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255, 66, 60,"Lagoon");
  else if (vtechmode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255, 80, 60,"RCM");
  else if (vtechmode == 3) ReefAngel.LCD.DrawLargeText(COLOR_CORNFLOWERBLUE,255, 80, 60,"Short");
  else if (vtechmode == 4) ReefAngel.LCD.DrawLargeText(COLOR_PINK,255, 66, 60,"Long");
  else if (vtechmode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255, 80, 60,"NTM");
  else if (vtechmode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255, 80, 60,"TSM");
  else if (vtechmode == 9) ReefAngel.LCD.DrawLargeText(COLOR_GRAY,255, 80, 60,"Night");
// Display Salinity 
    ReefAngel.LCD.DrawLargeText(0,255,66,100,"Salinity", Font8x8);
// Display Salinity Value 
    ReefAngel.LCD.Clear(255, 82, 85, 65, 95);
    ConvertNumToString(text, ReefAngel.Params.Salinity, 10);
    ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN, 255, 85, 110, text, Num8x8);
//Start Moon Phase,Cloud or Storm Display
  SeasonsVar[0]=ChannelValue[LEDWhiteBlue];
  SeasonsVar[1]=rhour;
  SeasonsVar[2]=rmin;
  SeasonsVar[3]=shour;
  SeasonsVar[4]=smin;
  SeasonsVar[5]=cloudstart/60;
  SeasonsVar[6]=cloudstart%60;
  SeasonsVar[7]=cloudduration;
  SeasonsVar[8]=lightningchance;
  SeasonsVar[9]=ChannelValue[LEDWhiteBlue1];
  SeasonsVar[10]=ChannelValue[LEDWhiteBlue2];
  SeasonsVar[11]=ChannelValue[MixedLED];
  SeasonsVar[12]=ChannelValue[LEDMoonlights];
//Start Moon Phase,Cloud or Storm Display
  if (SeasonsVar[12] > 0)//if moon phase is active display state and pwm %
  {
   DayAge = MoonAge(day(), month(), year());
    MoonState(DayAge);
    char* ThisPhaseLabel[]={"New","Waxing C","First Q","Waxing G","Full","Waning G","Last Q","Waning C"};
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,75,ThisPhaseLabel[ThisPhase]);
    ReefAngel.LCD.DrawText(0,255,25,99,"%");
    ReefAngel.LCD.DrawSingleMonitor(COLOR_CORNFLOWERBLUE,255, 25, 102, SeasonsVar[12]);//spacing
    
   if (SeasonsVar[12]=MoonPWMValue);
  MoonPWMValue=MoonPhase();
      if (hour()>=22 || hour()<=8)
  MoonPWMValue=PWMSlope(22,00,8,00,1,MoonPhase(),45,1);
     if (SeasonsVar[0]>=1) MoonPWMValue=0;
          ReefAngel.PWM.SetChannel(4,MoonPWMValue);
  }
  else if (SeasonsVar[5] > 0) //or if there is a cloud display clouds instead
  {
    if (SeasonsVar[8] > 0) ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,75, "Storm"); //decide between dislaying storm or cloud based on lightningchance
    else ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,75,"Cloud");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,85, SeasonsVar[5]); 
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,90, ":");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,95, SeasonsVar[6]); 
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,105,"Length");  
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,125, SeasonsVar[7]); 
  }
  else if (hour() >=8 && hour() <=14 && SeasonsVar[5,6,7] ==0)
  {
    ReefAngel.LCD.DrawText(0,255,8,109, "Sunrise");  
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,15,119, SeasonsVar[0]);
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,20,119, ":");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,25,119, SeasonsVar[9]);
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,20,119, ":");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,15,119, SeasonsVar[10]);
  }
   else if (hour() >=14 && hour() <=22 && SeasonsVar[5,6,7] ==0)
   {
    ReefAngel.LCD.DrawText(0,255,88,109, "Sunset");  
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,90,119, SeasonsVar[0]);
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,102,119, ":");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,107,119, SeasonsVar[9]);
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,102,119, ":");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,107,119, SeasonsVar[10]);
   }
  //End Display Moon Phase Display
  
  // Display Main and Expansion Relay Box
  TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawCircleOutletBox(10,90, TempRelay);
  pingSerial();

  TempRelay2 = ReefAngel.Relay.RelayDataE[0];
  TempRelay2 &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay2 |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawCircleOutletBox(40,90, TempRelay2);
  pingSerial();
  break;
 //***************************************************************************************************************************************************************************
 //---------------------------------------------------------------------------- Screen Code 2---------------------------------------------------------------------------------  
   case 1:  //Temperature detail screen with sump and room temp, 24 hr. max/min, time stamps, and graph
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,10,15,"Temp Details", Font8x8);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,33,"Sump:");
    ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T1_PROBE], COLOR_BLACK, 36, 33, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,43,"HI:");
    ReefAngel.LCD.DrawSingleMonitor(maxTemp, 0, 23, 43, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,48,43,"at");
    DrawTime(60,43,0, COLOR_WHITE,tsmax);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,53,"LO:");
    ReefAngel.LCD.DrawSingleMonitor(minTemp, 0, 23, 53, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,48,53,"at");
    DrawTime(60,53,0,COLOR_WHITE, tsmin);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,63,"Range:");
    ReefAngel.LCD.DrawSingleMonitor((maxTemp-minTemp), COLOR_BLACK, 46, 63, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,69,63,"degreesC");
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,73,"Avg:");
    DrawDailyAvg(ReefAngel.Params.Temp[T1_PROBE], COLOR_BLACK, 43, 73, 1);  
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,83,"WeeklyAvg:");
    DrawWeeklyAvg(12,ReefAngel.Params.Temp[T1_PROBE], COLOR_BLACK, 66, 83, 1);  
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor, 86,83,"at noon");
    ReefAngel.LCD.DrawText(T2TempColor,DefaultBGColor, 5 ,93,"Room:");
    ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T2_PROBE], COLOR_BLACK, 36, 93, 10);
    break;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- Screen Code 3--------------------------------------------------------------------------------- 
  case 2:  //pH details
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,20,15,"pH Details", Font8x8);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,33,"pH:");
    ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.PH, COLOR_BLACK, 36, 33, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,43,"HI:");
    ReefAngel.LCD.DrawSingleMonitor(maxPH, 0, 23, 43, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,48,43,"at");
    DrawTime(60,43,0, COLOR_WHITE,PHmax);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,53,"LO:");
    ReefAngel.LCD.DrawSingleMonitor(minPH, 0, 23, 53, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,48,53,"at");
    DrawTime(60,53,0,COLOR_WHITE, PHmin);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,63,"Range:");
    ReefAngel.LCD.DrawSingleMonitor((maxPH-minPH), COLOR_BLACK, 46, 63, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,73,"Avg:");
    DrawDailyAvg(ReefAngel.Params.PH, COLOR_BLACK, 43, 73, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,83,"WeeklyAvg:");
    DrawWeeklyAvg(12,ReefAngel.Params.PH, COLOR_BLACK, 66, 83, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor, 86,83,"at noon");
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,93,"WeeklyAvg:");
    DrawWeeklyAvg(0,ReefAngel.Params.PH, COLOR_BLACK, 66, 93, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor, 86,93,"at midnt");
    break;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- Screen Code 4---------------------------------------------------------------------------------
    case 3:  //relay box key
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;  
    ReefAngel.LCD.DrawCircleOutletBox(56,46,TempRelay);
    pingSerial();
    
    ReefAngel.LCD.DrawLargeText(0,255,27,20,"RelayBox 1", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,7,44,"Return", Font8x8); //1
    ReefAngel.LCD.DrawLargeText(0,255,7,54,"ATU", Font8x8); //3
    ReefAngel.LCD.DrawLargeText(0,255,7,64,"SumpL", Font8x8); //5
    ReefAngel.LCD.DrawLargeText(0,255,7,74,"Salty", Font8x8); //7
    ReefAngel.LCD.DrawLargeText(0,255,75,44,"Skimer", Font8x8);  //2
    ReefAngel.LCD.DrawLargeText(0,255,75,54,"Reactr", Font8x8);  //4
    ReefAngel.LCD.DrawLargeText(0,255,75,64,"Heatr", Font8x8); //6
    ReefAngel.LCD.DrawLargeText(0,255,75,74,"Relay", Font8x8);  //8
    break;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- Screen Code 5---------------------------------------------------------------------------------    
  case 4:  //relay box key
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    TempRelay2 = ReefAngel.Relay.RelayDataE[0];
    TempRelay2 &= ReefAngel.Relay.RelayMaskOffE[0];
    TempRelay2 |= ReefAngel.Relay.RelayMaskOnE[0];  
    ReefAngel.LCD.DrawCircleOutletBox(56,46,TempRelay2);
    pingSerial();
    
    ReefAngel.LCD.DrawLargeText(0,255,27,20,"RelayBox 2", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,7,44,"VTech", Font8x8);//1
    ReefAngel.LCD.DrawLargeText(0,255,7,54,"Ozone", Font8x8);//3
    ReefAngel.LCD.DrawLargeText(0,255,7,64,"Day1", Font8x8);//5
    ReefAngel.LCD.DrawLargeText(0,255,7,74,"Day3", Font8x8);//7
    ReefAngel.LCD.DrawLargeText(0,255,75,44,"VTech", Font8x8);//2
    ReefAngel.LCD.DrawLargeText(0,255,75,54,"Moon", Font8x8);//4
    ReefAngel.LCD.DrawLargeText(0,255,75,64,"Day2", Font8x8);//6
    ReefAngel.LCD.DrawLargeText(0,255,75,74,"MLed", Font8x8);//8
    break;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- Screen Code 6---------------------------------------------------------------------------------    
    case 5:  //setclock
    // Analog clock is modified from the original source by Jeff Miller
  // Author: Jeff Miller   http://arduinofun.blogspot.com/
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    // Frame
    DrawCircle(clock_center_x, clock_center_y, clock_radius, COLOR_CORNFLOWERBLUE);
    DrawCircle(clock_center_x, clock_center_y, clock_radius - 1, COLOR_CORNFLOWERBLUE);        
    DrawCircle(clock_center_x, clock_center_y, clock_radius - 2, COLOR_CORNFLOWERBLUE);       
    // Face Tick Marks  (x = r cos theta, y = r sin theta)
    for (byte r=0; r < 12; r++) {
      float angle = (2 * pi / 12)*r;
      int tick_x_out = (clock_radius - 8) * cos (angle) + clock_center_x;
      int tick_y_out = (clock_radius - 8) * sin (angle) + clock_center_y;
      int tick_x_in = clock_radius *.72 * cos (angle) + clock_center_x;
      int tick_y_in = clock_radius * .72 * sin (angle) + clock_center_y;                
      Drawline(tick_x_in, tick_y_in, tick_x_out, tick_y_out, COLOR_CORNFLOWERBLUE);
      }
    // Face Characters
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 8,106," 6", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 8, 25,"12", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x + 34,clock_center_y," 3", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 50, clock_center_y - 4,"9 ", Font8x8);
   // Draw Seconds Hand
       secondangle = (2 * pi / 60) * second();
              if (second() > 15)
        {secondangle = secondangle -1.57;
        }
      else
        {secondangle = secondangle +4.71;
        }
       Drawline(clock_center_x, clock_center_y, secondend_x, secondend_y, WHITE);
       secondend_x = secondhand_radius * cos (secondangle) + clock_center_x;
       secondend_y = secondhand_radius * sin (secondangle) + clock_center_y;
       Drawline(clock_center_x, clock_center_y, secondend_x, secondend_y, BLACK);
// Redraw minutes hand since the section closest to the center gets erased by the seconds hand
       draw_minute(BLACK);
// Redraw hour hand
       draw_hour(BLACK);
// Draw Minutes Hand
       minuteangle = (2 * pi / 60) * minute();
       if (minute() > 15)
        {minuteangle = minuteangle -1.57;
        }
      else
        {minuteangle = minuteangle +4.71;
        }
        // Erase old minutes Hand
       draw_minute(WHITE);
  // Calculate Minute Hand Base
      minutebase_x = minutebase_radius * cos (minuteangle - pi/2) + clock_center_x;
      minutebase_y = minutebase_radius * sin (minuteangle - pi/2) + clock_center_y;
      minutebase_x1 = minutebase_radius * cos (minuteangle + pi/2) + clock_center_x;
      minutebase_y1 = minutebase_radius * sin (minuteangle + pi/2) + clock_center_y;
// Calculate Minute Hand Point
      minuteend_x = minutehand_radius * cos (minuteangle) + clock_center_x;
      minuteend_y = minutehand_radius * sin (minuteangle) + clock_center_y;
// Draw new minutes Hand
      draw_minute(BLACK);                         
// Redraw hour hand
      draw_hour(BLACK);
// Draw Hour Hand   
      minfloat = minute(); // Convert minute short to float
      hourangle = (2 * pi / 12) * ((hourFormat12()) + (minfloat/60)); // Find angle for hour hand
      hourangle = hourangle -1.57;
// Erase old Hour Hand
      draw_hour(WHITE);
// Calculate hour Hand Base
      hourbase_x = hourbase_radius * cos (hourangle - pi/2) + clock_center_x;
      hourbase_y = hourbase_radius * sin (hourangle - pi/2) + clock_center_y;
      hourbase_x1 = hourbase_radius * cos (hourangle + pi/2) + clock_center_x;
      hourbase_y1 = hourbase_radius * sin (hourangle + pi/2) + clock_center_y;
// Calculate hour Hand Point
      hourend_x = hourhand_radius * cos (hourangle) + clock_center_x;
      hourend_y = hourhand_radius * sin (hourangle) + clock_center_y;
// Draw new hours Hand
      draw_hour(BLACK);
    ReefAngel.LCD.DrawDate(5,121);
    break;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- Screen Code 7---------------------------------------------------------------------------------    
case 6: // Vortech Setup
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawText(0,255,20,50,"Assigning Slaves");
    ReefAngel.RF.SetMode(Slave_Start,0,0);
    InternalMemory.RFMode_write(0);
    InternalMemory.RFSpeed_write(80);
    InternalMemory.RFDuration_write(7);
  if (ReefAngel.Joystick.IsButtonPressed())
    {
      ReefAngel.RF.SetMode(Slave_Stop,0,0);
      ReefAngel.LCD.DrawText(0,255,50,60,"Done");
    }
    break;
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------- PWM Channels ------------------------------------------------------------------------------------
  MoonPWMValue=MoonPhase();
  if (hour()>=22 || hour()<=8)
    MoonPWMValue=PWMSlope(22,00,8,00,1,MoonPhase(),45,1);
  if (ChannelValue[LEDWhiteBlue]>=1) MoonPWMValue=0;
  ReefAngel.PWM.SetChannel(4,MoonPWMValue);
 
  ReefAngel.PWM.Expansion(LEDWhiteBlue,int(ChannelValue[LEDWhiteBlue]));
  ReefAngel.PWM.Expansion(LEDWhiteBlue1,int(ChannelValue[LEDWhiteBlue1]));
  ReefAngel.PWM.Expansion(LEDWhiteBlue2,int(ChannelValue[LEDWhiteBlue2]));
  ReefAngel.PWM.Expansion(MixedLED,int(ChannelValue[MixedLED]));
  ReefAngel.PWM.Expansion(LEDMoonlights,int(ChannelValue[LEDMoonlights]));
    
//------------------------------------------------------------------- End PWM Expansion Code for Slope ---------------------------------------------------------------------
//***************************************************************************************************************************************************************************  
//------------------------------------------------------------------ Start Time-of-Day Based Functions ----------------------------------------------------------------------
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These are the mode numbers for the RF Expansion Module for reference ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //#define Constant      0
  //#define Random1       1 // Lagoonal
  //#define Random2       2 // Reef Crest
  //#define ShortWave     3
  //#define LongWave      4
  //#define Smart_NTM     5 // Nutrient Transport Mode
  //#define Smart_TSM     6 // Tidal Swell Mode
  //#define Feeding_Start 7
  //#define Feeding_Stop  8
  //#define Night         9
  //#define Slave_Start   97
  //#define Slave_Stop    98
  //#define None          99
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 //----------------------------------------------------------------- Start RF Daytime Control ------------------------------------------------------------------------------
  if (hour() >=8 && hour() <= 22)
  {  
    if (ReefAngel.DisplayedMenu==FEEDING_MODE) bFeeding=true;
    if (ReefAngel.DisplayedMenu==DEFAULT_MENU && bFeeding )
    {
      bFeeding=false; 
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Smart_NTM,80,7);
      ReefAngel.Timer[4].SetInterval(4600); // Timer for 60min
      ReefAngel.Timer[4].Start();
      vtechmode = 5;
    }
    if (ReefAngel.DisplayedMenu==DEFAULT_MENU && ReefAngel.Timer[4].IsTriggered())
   {
     bFeeding=false; 
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Random2,80,7);
      vtechmode = 2;
    }  
  }
 //--------------------------------------------------------------- Start RF Nightmode Control -----------------------------------------------------------------------------  
   if (hour()>=22 || hour()<8) // Defining "Nightmode" hours for VorTech = between 10 PM and 8 AM
   {
     ReefAngel.RF.UseMemory=false;
     ReefAngel.RF.SetMode(Night,15,0);
     vtechmode = 9;
   }
   else
   {
     ReefAngel.RF.SetMode(Feeding_Stop,0,0); //Temp fix for coming out of Night mode
     ReefAngel.RF.UseMemory=true;
     vtechmode = InternalMemory.RFMode_read();
   } 
  }
}
//***************************************************************************************************************************************************************************
//-------------------------------------------------- Random Cloud/Thunderstorm effects function -----------------------------------------------------------------------------
//------------------------------------------------------- From Roberto - THANKS ROBERTO! ------------------------------------------------------------------------------------
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_5_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 25
  // 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 15
  // Minimum number of clouds that can happen per day
#define Min_Clouds_per_Day 3
  // Maximum number of clouds that can happen per day
#define Max_Clouds_per_Day 6
  // Only start the cloud effect after this setting
  // In this example, start could after 11:30am
#define Start_Cloud_After NumMins(12,00)
  // Always end the cloud effect before this setting
  // In this example, end could before 4:30pm
#define End_Cloud_Before NumMins(18,0)
  // 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
  // Channels used by the actinic LEDs on the PWM Expansion module
  // These channels will not be dimmed when the cloud effect is triggered
  // Number is a binary form. B001100 means channel 2 and 3 are used for actinics
#define Actinic_Channels B011000
  // Channels used by the daylight LEDs on the PWM Expansion module
  // These channels will be used for the spike when lightning effect is triggered
  // Number is a binary form. B000011 means channel 0 and 1 are used for daylights
#define Daylight_Channels B000111
  // 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(26); 
      // 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_5_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(36);
        // 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?
//is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      // let's go through all channels to pick which ones will be dimmed
      for (int a=0;a<6;a++)
      {
        if (bitRead(Actinic_Channels,a)==0)
        {
          // this will slope down the channel from the current PWM to 0 within 3minutes.
          // then it will stay at 0 for the duration of the cycle
          // and finally slope up from 0 to PWM value within 3 minutes
          // it is basically an inversed slope
          ChannelValue[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,ChannelValue[a],0,180);
        }
      }
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        for (int b=0;b<6;b++)
        {
          if (bitRead(Daylight_Channels,b)==1)
          {
            if (random(100)<20) lightningstatus=1; 
            else lightningstatus=0;
            if (lightningstatus) ChannelValue[b]=100; 
            else ChannelValue[b]=0;
            //delay(10);
          }
          else
          {
            ChannelValue[b]=20;
          }
        }
      }
    }
    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      ReefAngel.RF.UseMemory=true;
      {
        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;
      }
    }
  }
}
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 ------------------------------------------------------------------------------------
//***************************************************************************************************************************************************************************
//----------------------------------------------------------- Calculators for Seasons function ------------------------------------------------------------------------------
  long calcSec(long hr, long minu) //if (hour()==hr && minute()==minu);
   {
    long totalseconds;
    totalseconds= (hr*3600)+(minu*60);
    return totalseconds;
   }
    long calcTime(long seconds1, long seconds2) //if (second()==seconds1 && second()==seconds2);
   {
    long timediff=abs(seconds1-seconds2);
    return timediff;
   }

void DayNumber(unsigned int y, unsigned int m, unsigned int d)
{
  int days[]={
    0,31,59,90,120,151,181,212,243,273,304,334      };    // Number of days at the beginning of the month in a not leap year.
  //Start to calculate the number of day
  if (m==1 || m==2)
  {
    Ndays = days[(m-1)] +d;            //for any type of year, it calculate the number of days for January or february
  }            // Now, try to calculate for the other months
  else if ((y % 4 == 0 && y % 100 != 0) ||  y % 400 == 0){  //those are the conditions to have a leap year
    Ndays = days[(m-1)]+d+1;     // if leap year, calculate in the same way but increasing one day
  }
  else {                 //if not a leap year, calculate in the normal way, such as January or February
    Ndays = days[(m-1)]+d;
  }
} 
//End calculators
//***************************************************************************************************************************************************************************
//Calculate Sunrise/set by date & predefined season & rise/set times
void Seasons()
{
  //Set the hour you want the calculations of rise an set to be based on
  int UserRiseHour = 8;
  int UserSetHour =  22;
  
  #define forceseasoncalculation
  static byte ssn , ssnp = 0 , ssnpt ;
  long stime, wstime, vstime, wrtime, rtime, vrtime;
  int wrhour,wrmin,wrsec,wshour,wsmin,wssec,rsec,ssec,vrhour,vrmin,vrsec,vshour,vsmin,vssec;
  int iDiffrise = 0;
  int iDiffset = 0;
  int risediffperday = 0;
  int setdiffperday = 0;
  int totalrise = 0;
  int totalset = 0;
  byte s=0;
  int DaysPerYear; 
  //rise and set times set by hour and minute. there are 4 seasons however there are 8 highs & lows in rise and set throughout the year
  //first spot is second half of winter starting jan 1st - DO NOT CHANGE
    int risehour[8]= {UserRiseHour+1,UserRiseHour+1,UserRiseHour+1,UserRiseHour,UserRiseHour,UserRiseHour-1,UserRiseHour,UserRiseHour};/*{
    7,7,7,6,6,5,6,6      };*/
  int riseminute[8]={
    00,30,00,30,00,30,00,30      };
  int sethour[8] = {UserSetHour-2,UserSetHour-1,UserSetHour-1,UserSetHour,UserSetHour,UserSetHour,UserSetHour,UserSetHour-1};/*{
    17,18,18,19,19,19,19,18      };*/
  int setminute[8] = {
    30,00,30,00,00,30,00,00      };

  if (hour()==0 && minute()==0 && second()==0) ssnp=0;
#ifdef forceseasoncalculation
  if (ssnp==0)
#else
    if (hour()==0 && minute()==0 && second()==1 && ssnp==0)
#endif
     {
      //leapyear or not to define DaysPerYear - DO NOT CHANGE
      if (year()%4 == 0 && !(year()%100 == 0 && year()%400 != 0)) {
        DaysPerYear=366;
      }
      else {
            DaysPerYear = 365;
           }
      //Call Day Number Calc to determin day ie december 31st on a non leap year is day 365 - DO NOT CHANGE
      DayNumber(year(),month(),day());
      //define days between beginning, middle and end of seasons high peaks -  DO NOT CHANGE
      int seasons[9] ={0,45,96,135,187,238,283,328,DaysPerYear};
      //define season and array pulling variable - DO NOT CHANGE
      for (s=0; seasons[s] < Ndays; s++) ssn = s+1, ssnpt = s+1, ssnp = s;
      //set loop on array time pulling variable to go back to beginning instead of increasing array size - DO NOT CHANGE
      if (ssn >= 7) ssn = 0;

      //differece in seconds between two rise/set array times pulled - DO NOT CHANGE
      long rise1 = calcSec(risehour[ssn],riseminute[ssn]);
      long rise2 = calcSec(risehour[ssnp],riseminute[ssnp]);
      iDiffrise = calcTime(rise1, rise2);
      long set1 = calcSec(sethour[ssn],setminute[ssn]);
      long set2 = calcSec(sethour[ssnp],setminute[ssnp]);
      iDiffset = calcTime(set1,set2);             

      //calculate new sunrise/set difference from array value & last group of code - DO NOT CHANGE
      risediffperday = iDiffrise/(seasons[ssnpt]-seasons[ssnp]);
      totalrise = risediffperday*(Ndays - seasons[ssnp]);
      setdiffperday = iDiffset/(seasons[ssnpt]-seasons[ssnp]);
      totalset = setdiffperday*(Ndays - seasons[ssnp]);

      //creating time in seconds for main sun rise/set number - DO NOT CHANGE
      rtime=calcSec(risehour[ssnp],riseminute[ssnp]);
      if (ssnp == 0 || ssnp == 2 || ssnp == 4 || ssnp == 6){ 
        rtime -= totalrise;
      }
      else {
        rtime += totalrise;
      }
      stime=calcSec(sethour[ssnp],setminute[ssnp]);
      if (ssnp == 1 || ssnp == 3 || ssnp == 5 || ssnp == 7){ 
        stime -= totalset;
      }
      else {
        stime += totalset;
      }
      
      //These are the off set times, standard rtime and stime are for Royal Blues & Blues
      // DO NOT CHANGE the operators in these equations ie +- 
      // The number is in seconds (1200) change this number to change the offset for each color
      wrtime = rtime + 1200;
      wstime = stime - 1200;
      vrtime = rtime - 1200;
      vstime = stime + 1200;
      
      //turning seconds back to Hours:Minutes:Seconds
      //Blues
      rhour=rtime/3600; 
      rtime=rtime%3600;
      rmin=rtime/60; 
      rtime=rtime%60; 
      rsec=rtime;
      if(rsec > 30) rmin++; 
      shour=stime/3600; 
      stime=stime%3600;
      smin=stime/60; 
      stime=stime%60; 
      ssec=stime;
      if(ssec > 30) smin++;
      //White
      wrhour = wrtime/3600;
      wrtime=wrtime%3600;
      wrmin=wrtime/60;
      wrtime=wrtime%60;
      wrsec=wrtime;
      if(wrsec>30) wrmin++;
      wshour = wstime/3600;
      wstime=wstime%3600;
      wsmin=wstime/60;
      wstime=wstime%60;
      wssec=wstime;
      if(wssec>30) wsmin++;
      //Violet
      vrhour = vrtime/3600;
      vrtime=vrtime%3600;
      vrmin=vrtime/60;
      vrtime=vrtime%60;
      vrsec=vrtime;
      if(vrsec>30) vrmin++;
      vshour = vstime/3600;
      vstime=vstime%3600;
      vsmin=vstime/60;
      vstime=vstime%60;
      vssec=vstime;
      if(vssec>30) vsmin++;



      //time for each active led channel to pull for sunrise - DO NOT CHANGE
      int Sunrise[2]={
        rhour,rmin                  };
      int Sunset[2]={
        shour,smin                  };
      int whSunrise[2]={
        wrhour,wrmin                  };
      int whSunset [2]={
        wshour,wsmin                  };
      int vSunrise[2]={
        vrhour,vrmin                  };
      int vSunset [2]={
        vshour,vsmin                  };
        
      //This is the PWM Slope for each channel, each channel pulls an array value from above(hour,minute) to use, how you set them is up to you. 
      //Just always use a Rise hour in a Rise spot, always a set hour in a set spot ect ect
  ChannelValue[LEDWhiteBlue]=PWMSlope(vSunrise[1],vSunrise[2],vSunset[1],vSunset[2],0,70,1,ChannelValue[LEDWhiteBlue]);
  ChannelValue[LEDWhiteBlue1]=PWMSlope(whSunrise[1],whSunrise[2],whSunset[1],whSunset[2],0,70,1,ChannelValue[LEDWhiteBlue1]);
  ChannelValue[LEDWhiteBlue2]=PWMSlope(Sunrise[1],Sunrise[2],Sunset[1],Sunset[2],0,70,1,ChannelValue[LEDWhiteBlue2]);
  ChannelValue[MixedLED]=PWMSlope(Sunrise[1],Sunrise[2],whSunset[1],whSunset[2],0,70,1,ChannelValue[MixedLED]);

    }
}
//------------------------------------------------------------------- End Seasons Calculation -------------------------------------------------------------------------------
//***************************************************************************************************************************************************************************
int JulianDate(int d, int m, int y)
{ 
  int mm, yy;
  int k1, k2, k3;
  int j;

  yy = y - (int)((12 - m) / 10);
  mm = m + 9;
  if (mm >= 12)
  {
    mm = mm - 12;
  }
  k1 = (int)(365.25 * (yy + 4712));
  k2 = (int)(30.6001 * mm + 0.5);
  k3 = (int)((int)((yy / 100) + 49) * 0.75) - 38;
  // 'j' for dates in Julian calendar:
  j = k1 + k2 + d + 59;
  if (j > 2299160)
  {
    // For Gregorian calendar:
    j = j - k3; // 'j' is the Julian date at 12h UT (Universal Time)
  }
  return j;
}

double MoonAge(int d, int m, int y)
{ 
  int j = JulianDate(d, m, y);
  //Calculate the approximate phase of the moon
  int ip = (j + 4.867) / 29.53059;
  ip = ip - abs(ip); 
  //After several trials I've seen to add the following lines, 
  //which gave the result was not bad 
  if(ip < 0.5)
    int ag = ip * 29.53059 + 29.53059 / 2;
  else
    int ag = ip * 29.53059 - 29.53059 / 2;
  // Moon's age in days
  byte ag = abs(ag) + 1;
  return ag;
}

byte MoonState(byte D)
{
  switch(D){
  case 1: 
    0, 29;
    ThisPhase = 0;
  case 2: 
    1, 2, 3, 4, 5, 6;
    ThisPhase = 1;
  case 3: 
    7;
    ThisPhase = 2;
  case 4: 
    8, 9, 10, 11, 12, 13;
    ThisPhase = 3;
  case 5: 
    14;
    ThisPhase = 4;
  case 6: 
    15, 16, 17, 18, 19, 20, 21;
    ThisPhase = 5;
  case 7: 
    22;
    ThisPhase = 6;
  case 8: 
    23, 24, 25, 26, 27, 28;
    ThisPhase = 7;
  default: 
    return 0;
  }
 }
I still need to do some spacing, and get the main menu to show on the case 0 screen, and the vortech Menu that selects the next mode. Exept for that, everything works.
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

Hi Jon.

Have you had a chance to look at the code?

- Jean
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: My almost completed pde

Post by binder »

I hate to say this but there are a lot of things wrong with this PDE file. I'm honestly surprised that it actually works based on what you posted.

There is a big problem with your screen selection code. At the end of "case 6", you have a break command. Then you proceed onward with your PWM channel stuff as well as your RF control code. That code after the break command is not ever going to be executed. It's within the switch statement but it has no case clause to execute it. It truthfully should not be inside the switch statement at all. It appears that it needs to run all the time. So that needs to be fixed.

Now, you are saying that the vortech menu stuff I wrote doesn't work. Based on your code, it won't ever work. You are using other variables to monitor your vortech mode (vtechmode to be exact). That variable only gets set by you in your modes. So my code I wrote won't do you a bit of good here. It won't update the mode on your display or anything. Also, you have your own daytime and nighttime modes that are forced by your code. Anything you do from the menu that I wrote "might" take place for a split second. Otherwise, your code completely overrides it. You need to move a "}" (curly brace) to be just after the break in case 6. Then remove a "}" (curly brace) above the Random Cloud and Thunderstorm effects function comment line.

What you want the menu system to do with the vortech code will not work without additional changes and updates. More thought has to be put into it and more changes (a lot more changes) have to be made.
I can tell you first off, my menu code I wrote will need to use your vtechmode variable in order for it to update your display properly. Also, this block of code:

Code: Select all

//------------------------------------------------------------------ Start Time-of-Day Based Functions ----------------------------------------------------------------------
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These are the mode numbers for the RF Expansion Module for reference ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            //#define Constant      0
            //#define Random1       1 // Lagoonal
            //#define Random2       2 // Reef Crest
            //#define ShortWave     3
            //#define LongWave      4
            //#define Smart_NTM     5 // Nutrient Transport Mode
            //#define Smart_TSM     6 // Tidal Swell Mode
            //#define Feeding_Start 7
            //#define Feeding_Stop  8
            //#define Night         9
            //#define Slave_Start   97
            //#define Slave_Stop    98
            //#define None          99
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
//----------------------------------------------------------------- Start RF Daytime Control ------------------------------------------------------------------------------
            if ( hour() >= 8 && hour() <= 22 )
            {
                if ( ReefAngel.DisplayedMenu == FEEDING_MODE ) bFeeding = true;
 
                if ( ReefAngel.DisplayedMenu == DEFAULT_MENU && bFeeding )
                {
                    bFeeding = false;
                    ReefAngel.RF.UseMemory = false;
                    ReefAngel.RF.SetMode( Smart_NTM, 80, 7 );
                    ReefAngel.Timer[4].SetInterval( 4600 ); // Timer for 60min
                    ReefAngel.Timer[4].Start();
                    vtechmode = 5;
                }
 
                if ( ReefAngel.DisplayedMenu == DEFAULT_MENU && ReefAngel.Timer[4].IsTriggered() )
                {
                    bFeeding = false;
                    ReefAngel.RF.UseMemory = false;
                    ReefAngel.RF.SetMode( Random2, 80, 7 );
                    vtechmode = 2;
                }
            }
 
//--------------------------------------------------------------- Start RF Nightmode Control -----------------------------------------------------------------------------
            if ( hour() >= 22 || hour() < 8 ) // Defining "Nightmode" hours for VorTech = between 10 PM and 8 AM
            {
                ReefAngel.RF.UseMemory = false;
                ReefAngel.RF.SetMode( Night, 15, 0 );
                vtechmode = 9;
            }
            else
            {
                ReefAngel.RF.SetMode( Feeding_Stop, 0, 0 ); //Temp fix for coming out of Night mode
                ReefAngel.RF.UseMemory = true;
                vtechmode = InternalMemory.RFMode_read();
            }
will need improvements to allow for overrides via the menu.
I do not have the time to do this for you right now. I'm just pointing you in the right direction on what needs to be done to get it working like you want.
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

Than you binder. It's much appreciated.

I have done what you suggested. And the rest I will try and figure out.

- Jean
pilonstar
Posts: 64
Joined: Tue Mar 20, 2012 2:56 am

Re: My almost completed pde

Post by pilonstar »

JNieuwenhuizen wrote:Than you binder. It's much appreciated.

I have done what you suggested. And the rest I will try and figure out.

- Jean
How things going? I am trying to setup a menu for the radion And vortech... Hard :(
Slow down to speed up
Image
Image
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

pilonstar wrote:
JNieuwenhuizen wrote:Than you binder. It's much appreciated.

I have done what you suggested. And the rest I will try and figure out.

- Jean
How things going? I am trying to setup a menu for the radion And vortech... Hard :(
Hi. I need some high-end users to help me. All works, its only the menus on multiple screens, and the vortech modes menu.

Don't know who else can hep wth this.
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: My almost completed pde

Post by binder »

I'll see if I can take a look at this more. I think I saw something that will work for fixing the menu displaying but I don't recall now. I have to re-look at things.
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: My almost completed pde

Post by binder »

pilonstar wrote:
JNieuwenhuizen wrote:Than you binder. It's much appreciated.

I have done what you suggested. And the rest I will try and figure out.

- Jean
How things going? I am trying to setup a menu for the radion And vortech... Hard :(
What type of menu are you trying to setup? One like what is mentioned in this thread? If so, it would be best if you created another thread / topic of your INO file that contains your INO and what you want to do.
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

binder wrote:I'll see if I can take a look at this more. I think I saw something that will work for fixing the menu displaying but I don't recall now. I have to re-look at things.

Hi binder. It would be much appreciated. This is the code that I would like to run. Its only the Menu Structure on the multiple screens, and the Vortech Menu that I need help with.

Regards
Jean
The current PDE file -

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 <ReefAngel.h>
#include <avr/pgmspace.h>>
//***************************************************************************************************************************************************************************
//-------------------------------------------------------------------------- Screen set-up ---------------------------------------------------------------------------------
#define NumScreens 7
int ScreenID=0;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- PWM Cloud -----------------------------------------------------------------------------------
boolean ForceCloud=false;
boolean ForceLightning=false;
//
//***************************************************************************************************************************************************************************
//--------------------------------------------------------------------------- PWM Channels ----------------------------------------------------------------------------------
#define LEDWhiteBlue  0 
#define LEDWhiteBlue1 1
#define LEDWhiteBlue2 2
#define MixedLED 3
#define LEDMoonlights 4
//***************************************************************************************************************************************************************************
//--------------------------------------------------------------------- Start of Global Variables ---------------------------------------------------------------------------
byte ChannelValue[]={
0,0,0,0,0,0};
byte SeasonsVar[]={
0,0,0,0,0,0};
byte MoonPWMValue;
byte vtechmode = 0;
byte DayAge;
byte ThisPhase;
int JulianDate(int,int,int);
double MoonAge(int,int,int);
byte MoonState();
boolean bFeeding=false;
byte x,y;
int maxTemp=0;
int minTemp=2000;
int maxPH=600;
int minPH=900;
char text[10];
int v;
int moonlight=0;
long calcSec(long,long);
long calcTime(long,long);
short Ndays;
int rhour = 0, rmin = 0, shour = 0, smin = 0;
byte TempRelay =15;
byte TempRelay2=15;
static byte lightningchance=0;
byte cloudduration=0;
int cloudstart=0;
//***************************************************************************************************************************************************************************
//----------------------------------------------------------------------- Custom Menu Code ----------------------------------------------------------------------------------
prog_char menu1_label[] PROGMEM = "Food!!";
prog_char menu2_label[] PROGMEM = "Cleanup";
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 = "Salty Calibration";
prog_char menu7_label[] PROGMEM = "Vortech Modes";
prog_char menu8_label[] PROGMEM = "Force Cloud";
prog_char menu9_label[] PROGMEM = "Force Lightning";

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.SetupCalibrateSalinity();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
   vtechmode++;
   if ( vtechmode == 7 ) vtechmode = 9;
   if ( vtechmode > 9 ) vtechmode = 1;
   // 1st parameter is Mode, 2nd is speed, 3rd is duration
   ReefAngel.RF.SetMode(vtechmode, InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
   ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}
void MenuEntry8()
{
 ForceCloud=true; 
ReefAngel.DisplayedMenu=RETURN_MAIN_MODE;
}
void MenuEntry9()
{
ForceLightning=true;
ReefAngel.DisplayedMenu=RETURN_MAIN_MODE;
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------- Grouped Menu Entries ----------------------------------------------------------------------------
PROGMEM const char *menu_items[] = {
  menu1_label, menu2_label, menu3_label,
  menu4_label, menu5_label, menu6_label,
  menu7_label,menu8_label,menu9_label};
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------- Custom Main -------------------------------------------------------------------------------
void DrawCircleOutline(byte x, byte y, byte radius, byte bordercolor);
void FillCircle(byte x, byte y, byte radius, byte fillcolor);
void DrawCircleOutletBox(byte x, byte y, byte RelayData, bool reverse = false);
//***************************************************************************************************************************************************************************
//-------------------------------------------------------------------------- Analog Clock constants -------------------------------------------------------------------------
    const float pi = 3.141592653;
    byte clock_center_x = 65;
    byte clock_center_y = 65;
    byte clock_radius = 55;
    byte secondhand_radius = 33;
    float secondangle;
    byte secondend_x;
    byte secondend_y;
    float minuteangle;
    float hourangle;
//***************************************************************************************************************************************************************************
//--------------------------------------------------------------------------- Analog Clock Structure ------------------------------------------------------------------------
       int minutebase_radius = 3;
       int minutehand_radius = 33;
       int hourbase_radius = 3;
       int hourhand_radius = 25;   
       int seconds_hand_x, seconds_hand_y, minutes_hand_x, minutes_hand_y, hours_hand_x, hours_hand_y;
       int hours_hand_base_x, hours_hand_base_y, hours_hand_base_x1, hours_hand_base_y1;
       int minutes_hand_base_x, minutes_hand_base_y, minutes_hand_base_x1, minutes_hand_base_y1; 
       int minutebase_x, minutebase_y, minutebase_x1, minutebase_y1; 
       int minuteend_x, minuteend_y; 
       int hourbase_x, hourbase_y, hourbase_x1, hourbase_y1; 
       int hourend_x, hourend_y; 
       float minfloat;
//***************************************************************************************************************************************************************************       
//--------------------------------------------------------------------------------Time Stamp --------------------------------------------------------------------------------
time_t tsmax=now();
time_t tsmin=now();
time_t PHmax=now();
time_t PHmin=now();
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Minutes Hand --------------------------------------------------------------------------
void draw_minute(int color)
{
  Drawline(minutebase_x, minutebase_y, minutebase_x1, minutebase_y1, color); 
  Drawline(minutebase_x, minutebase_y, minuteend_x, minuteend_y, color); 
  Drawline(minutebase_x1, minutebase_y1, minuteend_x, minuteend_y, color); 
}
//***************************************************************************************************************************************************************************
//--------------------------------------------------------------------------- Draw Hour Hand --------------------------------------------------------------------------------
void draw_hour(int color)
{
   Drawline(hourbase_x, hourbase_y, hourbase_x1, hourbase_y1, color); 
   Drawline(hourbase_x, hourbase_y, hourend_x, hourend_y, color); 
   Drawline(hourbase_x1, hourbase_y1, hourend_x, hourend_y, color); 
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Line ----------------------------------------------------------------------------------
void Drawline (int x0, int y0, int x1, int y1, int color) 
{
  int dy = y1 - y0;
  int dx = x1 - x0;
  int stepx, stepy;
  if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
  if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
  dy <<= 1; // dy is now 2*dy
  dx <<= 1; // dx is now 2*dx
  ReefAngel.LCD.PutPixel(color, x0, y0);
  if (dx > dy) {
    int fraction = dy - (dx >> 1); // same as 2*dy - dx
    while (x0 != x1) {
      if (fraction >= 0) {
        y0 += stepy;
        fraction -= dx; // same as fraction -= 2*dx
        }
      x0 += stepx;
      fraction += dy; // same as fraction -= 2*dy
      ReefAngel.LCD.PutPixel(color, x0, y0);
    }
  } else {
  int fraction = dx - (dy >> 1);
  while (y0 != y1) {
  if (fraction >= 0) {
    x0 += stepx;
    fraction -= dy;
    }
  y0 += stepy;
  fraction += dx;
  ReefAngel.LCD.PutPixel(color, x0, y0);
  }
  }
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Time ----------------------------------------------------------------------------------
void DrawTime(byte x, byte y, byte FGcolor, byte BGcolor, time_t ts)
{
    char text[13];
    char temp[]="  ";
    strcpy(text,"");
    itoa(hourFormat12(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    strcat(text,":");
    itoa(minute(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    strcat(text,":");
    itoa(second(ts),temp,10);
    if (temp[1]==0) strcat(text,"0");
    strcat(text,temp);
    if (isAM(ts))
    {
        strcat(text," AM");
    }
    else
    {
        strcat(text," PM");
    }
    ReefAngel.LCD.DrawText(FGcolor, BGcolor, x, y, text);
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Circle --------------------------------------------------------------------------------
void DrawCircle(int a, int b, int r, byte color)
{
  int f = 1 - r;  
  int ddF_x = 1;  
  int ddF_y = -2 * r;  
  int x = 0;  
  int y = r;
  
ReefAngel.LCD.PutPixel(color, a, b+r);  
ReefAngel.LCD.PutPixel(color ,a, b-r);  
ReefAngel.LCD.PutPixel(color, a+r, b);  
ReefAngel.LCD.PutPixel(color, a-r, b);
 while (x<y) 
{    
if (f >= 0) 
{      y--;
       ddF_y += 2;      
       f += ddF_y;    
   }    
   x++;    
   ddF_x += 2;    
   f += ddF_x;
   
   ReefAngel.LCD.PutPixel(color, a + x, b + y);
   ReefAngel.LCD.PutPixel(color, a - x, b + y);
   ReefAngel.LCD.PutPixel(color, a + x, b - y);
   ReefAngel.LCD.PutPixel(color, a - x, b - y);
   ReefAngel.LCD.PutPixel(color, a + y, b + x);
   ReefAngel.LCD.PutPixel(color, a - y, b + x);
   ReefAngel.LCD.PutPixel(color, a + y, b - x);
   ReefAngel.LCD.PutPixel(color, a - y, b - x);
   }
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Weekly ------------------------------------------------------------------------------
void DrawWeeklyAvg (byte hr, int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 7;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (hour()==hr && minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Draw Daily ---------------------------------------------------------------------------------
void DrawDailyAvg (int sensor, byte color, byte x, byte y, byte z)
{
  const int numReadings = 24;
  int dailyread;
  int readings[numReadings];      // the readings from the analog input
  int index = 0;                  // the index of the current reading
  int total = 0;                  // the running total
  int average = 0;                // the average
  if (minute()==0 && second()==0) 
  {
    dailyread=sensor;  
  total= total - readings[index];   // subtract the last reading:         
  readings[index] = dailyread;   // read from the sensor: 
  total= total + readings[index];   // add the reading to the total:       
     index = index + 1;  // advance to the next position in the array:                   
  if (index >= numReadings)     // if we're at the end of the array...           
    index = 0;       // ...wrap around to the beginning:                         
  average = total / numReadings;    // calculate the average:
  delay (1000);
  ReefAngel.LCD.DrawSingleMonitor(average, color, x, y, z);
  }
}
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------------ Begin Setup --------------------------------------------------------------------------------
void setup()
{
  ReefAngel.Init();  //Initialize controller
  ReefAngel.Timer[LCD_TIMER].SetInterval(180);
  ReefAngel.Timer[LCD_TIMER].Start();  // start timer
  ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));
  ReefAngel.SetTemperatureUnit(1);
  ReefAngel.FeedingModePorts = 0;
  ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port6Bit | Box1_Port1 | Box1_Port2;
  ReefAngel.OverheatShutoffPorts = Port6Bit;
  ReefAngel.LightsOnPorts = 0;
//------------------------------------------------------------------------- Ports that are always on ------------------------------------------------------------------------
  ReefAngel.Relay.On(Port1);
  ReefAngel.Relay.On(Port4);
  ReefAngel.Relay.On(Port7);
  ReefAngel.Relay.On(Port8);
  ReefAngel.Relay.On(Box1_Port1);
  ReefAngel.Relay.On(Box1_Port2);
}
//***************************************************************************************************************************************************************************
void loop()
{
  CheckCloud();
//--------------------------------------------------------------------------- Specific Functions ----------------------------------------------------------------------------
  ReefAngel.Relay.DelayedOn(Port2, 2);
  ReefAngel.Relay.DelayedOn(Box1_Port1, 2);
  ReefAngel.Relay.DelayedOn(Box1_Port2, 2);
  ReefAngel.StandardATO(Port3);
  ReefAngel.MoonLights(Port5);
  ReefAngel.StandardHeater(Port6);
  ReefAngel.MoonLights(Box1_Port4);//LEDMoonlights
  ReefAngel.StandardLights(Box1_Port5);//White and Blue LED 
  ReefAngel.StandardLights(Box1_Port6,8,30,21,30);//White and Blue LED1
  ReefAngel.StandardLights(Box1_Port7,9,0,22,0);//White and Blue LED2
  ReefAngel.StandardLights(Box1_Port8,12,0,17,0);//MixedLED
  ReefAngel.Portal("JNieuwenhuizen","Evandre1");
  //---------------------------------------------------------------------------- PWM Channel Set -----------------------------------------------------------------------------
  ReefAngel.PWM.SetChannel(0,ChannelValue[LEDWhiteBlue]);
  ReefAngel.PWM.SetChannel(1,ChannelValue[LEDWhiteBlue1]);
  ReefAngel.PWM.SetChannel(2,ChannelValue[LEDWhiteBlue2]);
  ReefAngel.PWM.SetChannel(3,ChannelValue[MixedLED]);
  ReefAngel.PWM.SetChannel(4,ChannelValue[LEDMoonlights]);
//------------------------------------------------------------------------------ Multiple Screens ----------------------------------------------------------------------------
  setTime(hour(),minute(),second(),day(),month(),year());
  // update the min and max temps
  if (now()%86400==0)
  {
    minTemp=ReefAngel.Params.Temp[T1_PROBE];
    maxTemp=ReefAngel.Params.Temp[T1_PROBE];
  }
  if (ReefAngel.Params.Temp[T1_PROBE]<minTemp) 
  {
    minTemp=ReefAngel.Params.Temp[T1_PROBE];
    tsmin=now();
  }
  if (ReefAngel.Params.Temp[T1_PROBE]>maxTemp) 
  {
    maxTemp=ReefAngel.Params.Temp[T1_PROBE];
    tsmax=now();
  }
  // update the min and max pH
if (now()%86400==0)
{
  minPH=ReefAngel.Params.PH;
  maxPH=ReefAngel.Params.PH;
}
if (ReefAngel.Params.PH<minPH) 
{
  minPH=ReefAngel.Params.PH;
  PHmin=now();
}
if (ReefAngel.Params.PH>maxPH) 
{
  maxPH=ReefAngel.Params.PH;
  PHmax=now();
}
  if (ReefAngel.Joystick.IsLeft() || ReefAngel.Joystick.IsDown()) 
  {
    ReefAngel.ClearScreen(DefaultBGColor);
    ScreenID--;
  }
  if (ReefAngel.Joystick.IsRight() || ReefAngel.Joystick.IsUp()) 
    {
    ReefAngel.ClearScreen(DefaultBGColor);
    ScreenID++;
    }
  if (ScreenID<0) ScreenID=NumScreens;
  if (ScreenID>=NumScreens) ScreenID=0;
  switch (ScreenID)
   {
 //---------------------------------------------------------------------------- Screen Code 1--------------------------------------------------------------------------------   
case 0:
void DrawCustomMain();
{
    // the graph is drawn/updated when we exit the main menu &
    // when the parameters are saved
    ReefAngel.LCD.DrawDate(6, 112);
    pingSerial();
#if defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor(15, 60, ReefAngel.Params,
    ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue());
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
    ReefAngel.LCD.DrawMonitor(15, 60, ReefAngel.Params);
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
    pingSerial();
    byte TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;
    ReefAngel.LCD.DrawOutletBox(12, 93, TempRelay);
}

void DrawCustomGraph();
{
    ReefAngel.LCD.DrawGraph(5, 5);
}
{
ReefAngel.ShowInterface();
}
break;

case 1:

  //Top Banner
  ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank   ", Font8x8); //Top Banner 
  // Display T1 Header Text
  ReefAngel.LCD.DrawLargeText(COLOR_STEELBLUE,255,5,15,"Sump Temp", Font8x8);
  // Display the T1 Temp Value
 char text[7];
    ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
    ReefAngel.LCD.Clear(255, 10, 25, 50, 60);
    if (ReefAngel.Params.Temp[T1_PROBE]>270) ReefAngel.LCD.DrawHugeNumbers(COLOR_RED, 255, 10, 25, text);
    else if (ReefAngel.Params.Temp[T1_PROBE]>270) ReefAngel.LCD.DrawHugeNumbers(COLOR_ORANGE, 255, 10, 25, text);
    else ReefAngel.LCD.DrawHugeNumbers(COLOR_MIDNIGHTBLUE, 255, 10, 25, text);
  // Display the T2 Header Text
  ReefAngel.LCD.DrawLargeText(0,255,5,45,"Room Temp", Font8x8);
  // Display the T2 Temp Value
  ReefAngel.LCD.Clear(255, 90, 50, 132, 60);
  ConvertNumToString(text, ReefAngel.Params.Temp[T2_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(COLOR_MIDNIGHTBLUE, 255, 90, 45, text, Num8x8);
  // Display pH Header Text
  ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN,255,95,15,"pH", Font8x8);
  // Display pH Value
  ConvertNumToString(text, ReefAngel.Params.PH, 100); // check code
  ReefAngel.LCD.Clear(0, 65, 62 , 65, 62);
  if (ReefAngel.Params.PH>840 || ReefAngel.Params.PH<790) ReefAngel.LCD.DrawLargeText(COLOR_RED, 255, 85, 25, text, Num8x8);
  else if (ReefAngel.Params.PH>830 || ReefAngel.Params.PH<800) ReefAngel.LCD.DrawLargeText(COLOR_ORANGE, 255, 85, 25, text, Num8x8);
  else ReefAngel.LCD.DrawLargeText(COLOR_MIDNIGHTBLUE, 255, 85, 25, text, Num8x8);
  // Display Vortech Mode
  ReefAngel.LCD.DrawLargeText(0,255,5,55,"Vortech", Font8x8);
  // Display EcoSmart Mode Value      
  ReefAngel.LCD.Clear(255, 66, 60, 132, 70);
  if (vtechmode == 0) ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN,255, 66, 55,"Constant");
  else if(vtechmode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255, 66, 55,"Lagoon");
  else if (vtechmode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255, 80, 55,"RCM");
  else if (vtechmode == 3) ReefAngel.LCD.DrawLargeText(COLOR_CORNFLOWERBLUE,255, 80, 55,"Short");
  else if (vtechmode == 4) ReefAngel.LCD.DrawLargeText(COLOR_PINK,255, 66, 55,"Long");
  else if (vtechmode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255, 80, 55,"NTM");
  else if (vtechmode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255, 80, 55,"TSM");
  else if (vtechmode == 9) ReefAngel.LCD.DrawLargeText(COLOR_GRAY,255, 80, 55,"Night");
// Display Salinity 
    ReefAngel.LCD.DrawLargeText(0,255,64,114,"Salinity", Font8x8);
// Display Salinity Value 
    ReefAngel.LCD.Clear(255, 82, 85, 65, 95);
    ConvertNumToString(text, ReefAngel.Params.Salinity, 10);
    ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN, 255, 85, 122, text, Num8x8);
//Start Moon Phase,Cloud or Storm Display
  SeasonsVar[0]=ChannelValue[LEDWhiteBlue];
  SeasonsVar[1]=rhour;
  SeasonsVar[2]=rmin;
  SeasonsVar[3]=shour;
  SeasonsVar[4]=smin;
  SeasonsVar[5]=cloudstart/60;
  SeasonsVar[6]=cloudstart%60;
  SeasonsVar[7]=cloudduration;
  SeasonsVar[8]=lightningchance;
  SeasonsVar[9]=ChannelValue[LEDWhiteBlue1];
  SeasonsVar[10]=ChannelValue[LEDWhiteBlue2];
  SeasonsVar[11]=ChannelValue[MixedLED];
  SeasonsVar[12]=ChannelValue[LEDMoonlights];
//Start Moon Phase,Cloud or Storm Display
  if (SeasonsVar[12] > 0)//if moon phase is active display state and pwm %
   {
    DayAge = MoonAge(day(), month(), year());
    MoonState(DayAge);
    char* ThisPhaseLabel[]={"New","Waxing C","First Q","Waxing G","Full","Waning G","Last Q","Waning C"};
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,70,105,ThisPhaseLabel[ThisPhase]);
   } 
  else if (SeasonsVar[5] > 0) //or if there is a cloud display clouds instead
   {
    if (SeasonsVar[8] > 0) ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,60,85, "Storm"); //decide between dislaying storm or cloud based on lightningchance
    else ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,95,85,"Cloud");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,60,95, SeasonsVar[5]); 
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,75,94, ":");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,80,95, SeasonsVar[6]); 
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,93,95,"Lnt");  
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,113,95, SeasonsVar[7]); 
    }
   else if (hour() >=8 && hour() <=14 && SeasonsVar[5,6,7] ==0)
    {
    ReefAngel.LCD.DrawLargeText(COLOR_ORANGERED,255,3,65, "Sunrise",Font8x8);  
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,3,75, SeasonsVar[0]);
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,20,74, ":");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,24,75, SeasonsVar[9]);
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,41,74, ":");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,45,75, SeasonsVar[10]);
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,66,75, "|");
    }
   else if (hour() >=14 && hour() <=22 && SeasonsVar[5,6,7] ==0)
    {
    ReefAngel.LCD.DrawLargeText(COLOR_ORANGE,255,75,65, "Sunset",Font8x8);  
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,70,75, SeasonsVar[0]);
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,87,74, ":");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,91,75, SeasonsVar[9]);
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,108,74, ":");
    ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,112,75, SeasonsVar[10]);
    }
  //End Display Moon Phase Display
  
  // Display Main and Expansion Relay Box
  TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawCircleOutletBox(10,90, TempRelay);
  pingSerial();

  TempRelay2 = ReefAngel.Relay.RelayDataE[0];
  TempRelay2 &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay2 |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawCircleOutletBox(40,90, TempRelay2);
  pingSerial();
  break;
 //***************************************************************************************************************************************************************************
 //---------------------------------------------------------------------------- Screen Code 2---------------------------------------------------------------------------------  
   case 2:  //Temperature detail screen with sump and room temp, 24 hr. max/min, time stamps, and graph
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,10,15,"Temp Details", Font8x8);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,33,"Sump:");
    ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T1_PROBE], COLOR_BLACK, 36, 33, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,43,"HI:");
    ReefAngel.LCD.DrawSingleMonitor(maxTemp, 0, 23, 43, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,48,43,"at");
    DrawTime(60,43,0, COLOR_WHITE,tsmax);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,53,"LO:");
    ReefAngel.LCD.DrawSingleMonitor(minTemp, 0, 23, 53, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,48,53,"at");
    DrawTime(60,53,0,COLOR_WHITE, tsmin);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,63,"Range:");
    ReefAngel.LCD.DrawSingleMonitor((maxTemp-minTemp), COLOR_BLACK, 46, 63, 10);
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,69,63,"Degrees C");
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,73,"Avg:");
    DrawDailyAvg(ReefAngel.Params.Temp[T1_PROBE], COLOR_BLACK, 43, 73, 1);  
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,5,83,"WeeklyAvg:");
    DrawWeeklyAvg(12,ReefAngel.Params.Temp[T1_PROBE], COLOR_BLACK, 66, 83, 1);  
    ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor, 86,83,"at noon");
    ReefAngel.LCD.DrawText(T2TempColor,DefaultBGColor, 5 ,93,"Room:");
    ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T2_PROBE], COLOR_BLACK, 36, 93, 10);
    break;

//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- Screen Code 3--------------------------------------------------------------------------------- 
  case 3:  //pH details
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawLargeText(0,255,20,15,"pH Details", Font8x8);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,33,"pH:");
    ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.PH, COLOR_BLACK, 36, 33, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,43,"HI:");
    ReefAngel.LCD.DrawSingleMonitor(maxPH, 0, 23, 43, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,48,43,"at");
    DrawTime(60,43,0, COLOR_WHITE,PHmax);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,53,"LO:");
    ReefAngel.LCD.DrawSingleMonitor(minPH, 0, 23, 53, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,48,53,"at");
    DrawTime(60,53,0,COLOR_WHITE, PHmin);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,63,"Range:");
    ReefAngel.LCD.DrawSingleMonitor((maxPH-minPH), COLOR_BLACK, 46, 63, 100);
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,73,"Avg:");
    DrawDailyAvg(ReefAngel.Params.PH, COLOR_BLACK, 43, 73, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,83,"WeeklyAvg:");
    DrawWeeklyAvg(12,ReefAngel.Params.PH, COLOR_BLACK, 66, 83, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor, 86,83,"at noon");
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,5,93,"WeeklyAvg:");
    DrawWeeklyAvg(0,ReefAngel.Params.PH, COLOR_BLACK, 66, 93, 100);  
    ReefAngel.LCD.DrawText(PHColor,DefaultBGColor, 86,93,"at midnt");
    break;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- Screen Code 4---------------------------------------------------------------------------------
  case 4:  //relay box key
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    TempRelay = ReefAngel.Relay.RelayData;
    TempRelay &= ReefAngel.Relay.RelayMaskOff;
    TempRelay |= ReefAngel.Relay.RelayMaskOn;  
    ReefAngel.LCD.DrawCircleOutletBox(56,46,TempRelay);
    pingSerial();
    ReefAngel.LCD.DrawLargeText(0,255,27,20,"RelayBox 1", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,3,44,"Return", Font8x8); //1
    ReefAngel.LCD.DrawLargeText(0,255,7,54,"ATU", Font8x8); //3
    ReefAngel.LCD.DrawLargeText(0,255,7,64,"SumpL", Font8x8); //5
    ReefAngel.LCD.DrawLargeText(0,255,7,74,"Salty", Font8x8); //7
    ReefAngel.LCD.DrawLargeText(0,255,75,44,"Skimer", Font8x8);  //2
    ReefAngel.LCD.DrawLargeText(0,255,75,54,"Reactr", Font8x8);  //4
    ReefAngel.LCD.DrawLargeText(0,255,75,64,"Heatr", Font8x8); //6
    ReefAngel.LCD.DrawLargeText(0,255,75,74,"Relay", Font8x8);  //8
    break;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- Screen Code 5---------------------------------------------------------------------------------    
  case 5:  //relay box key
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    TempRelay2 = ReefAngel.Relay.RelayDataE[0];
    TempRelay2 &= ReefAngel.Relay.RelayMaskOffE[0];
    TempRelay2 |= ReefAngel.Relay.RelayMaskOnE[0];  
    ReefAngel.LCD.DrawCircleOutletBox(56,46,TempRelay2);
    pingSerial();
    ReefAngel.LCD.DrawLargeText(0,255,27,20,"RelayBox 2", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,7,44,"VTech", Font8x8);//1
    ReefAngel.LCD.DrawLargeText(0,255,7,54,"Ozone", Font8x8);//3
    ReefAngel.LCD.DrawLargeText(0,255,7,64,"Day1", Font8x8);//5
    ReefAngel.LCD.DrawLargeText(0,255,7,74,"Day3", Font8x8);//7
    ReefAngel.LCD.DrawLargeText(0,255,75,44,"VTech", Font8x8);//2
    ReefAngel.LCD.DrawLargeText(0,255,75,54,"Moon", Font8x8);//4
    ReefAngel.LCD.DrawLargeText(0,255,75,64,"Day2", Font8x8);//6
    ReefAngel.LCD.DrawLargeText(0,255,75,74,"MLed", Font8x8);//8
    break;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- Screen Code 6---------------------------------------------------------------------------------    
    case 6:  //setclock
    // Analog clock is modified from the original source by Jeff Miller
  // Author: Jeff Miller   http://arduinofun.blogspot.com/
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    // Frame
    DrawCircle(clock_center_x, clock_center_y, clock_radius, COLOR_CORNFLOWERBLUE);
    DrawCircle(clock_center_x, clock_center_y, clock_radius - 1, COLOR_CORNFLOWERBLUE);        
    DrawCircle(clock_center_x, clock_center_y, clock_radius - 2, COLOR_CORNFLOWERBLUE);       
    // Face Tick Marks  (x = r cos theta, y = r sin theta)
    for (byte r=0; r < 12; r++) {
      float angle = (2 * pi / 12)*r;
      int tick_x_out = (clock_radius - 8) * cos (angle) + clock_center_x;
      int tick_y_out = (clock_radius - 8) * sin (angle) + clock_center_y;
      int tick_x_in = clock_radius *.72 * cos (angle) + clock_center_x;
      int tick_y_in = clock_radius * .72 * sin (angle) + clock_center_y;                
      Drawline(tick_x_in, tick_y_in, tick_x_out, tick_y_out, COLOR_CORNFLOWERBLUE);
      }
    // Face Characters
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 8,106," 6", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 8, 25,"12", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x + 34,clock_center_y," 3", Font8x8);
    ReefAngel.LCD.DrawLargeText(0,255,clock_center_x - 50, clock_center_y - 4,"9 ", Font8x8);
   // Draw Seconds Hand
       secondangle = (2 * pi / 60) * second();
              if (second() > 15)
        {secondangle = secondangle -1.57;
        }
      else
        {secondangle = secondangle +4.71;
        }
       Drawline(clock_center_x, clock_center_y, secondend_x, secondend_y, WHITE);
       secondend_x = secondhand_radius * cos (secondangle) + clock_center_x;
       secondend_y = secondhand_radius * sin (secondangle) + clock_center_y;
       Drawline(clock_center_x, clock_center_y, secondend_x, secondend_y, BLACK);
// Redraw minutes hand since the section closest to the center gets erased by the seconds hand
       draw_minute(BLACK);
// Redraw hour hand
       draw_hour(BLACK);
// Draw Minutes Hand
       minuteangle = (2 * pi / 60) * minute();
       if (minute() > 15)
        {minuteangle = minuteangle -1.57;
        }
      else
        {minuteangle = minuteangle +4.71;
        }
        // Erase old minutes Hand
       draw_minute(WHITE);
  // Calculate Minute Hand Base
      minutebase_x = minutebase_radius * cos (minuteangle - pi/2) + clock_center_x;
      minutebase_y = minutebase_radius * sin (minuteangle - pi/2) + clock_center_y;
      minutebase_x1 = minutebase_radius * cos (minuteangle + pi/2) + clock_center_x;
      minutebase_y1 = minutebase_radius * sin (minuteangle + pi/2) + clock_center_y;
// Calculate Minute Hand Point
      minuteend_x = minutehand_radius * cos (minuteangle) + clock_center_x;
      minuteend_y = minutehand_radius * sin (minuteangle) + clock_center_y;
// Draw new minutes Hand
      draw_minute(BLACK);                         
// Redraw hour hand
      draw_hour(BLACK);
// Draw Hour Hand   
      minfloat = minute(); // Convert minute short to float
      hourangle = (2 * pi / 12) * ((hourFormat12()) + (minfloat/60)); // Find angle for hour hand
      hourangle = hourangle -1.57;
// Erase old Hour Hand
      draw_hour(WHITE);
// Calculate hour Hand Base
      hourbase_x = hourbase_radius * cos (hourangle - pi/2) + clock_center_x;
      hourbase_y = hourbase_radius * sin (hourangle - pi/2) + clock_center_y;
      hourbase_x1 = hourbase_radius * cos (hourangle + pi/2) + clock_center_x;
      hourbase_y1 = hourbase_radius * sin (hourangle + pi/2) + clock_center_y;
// Calculate hour Hand Point
      hourend_x = hourhand_radius * cos (hourangle) + clock_center_x;
      hourend_y = hourhand_radius * sin (hourangle) + clock_center_y;
// Draw new hours Hand
      draw_hour(BLACK);
    ReefAngel.LCD.DrawDate(5,121);
    break;
//***************************************************************************************************************************************************************************
//---------------------------------------------------------------------------- Screen Code 7---------------------------------------------------------------------------------    
case 7: // Vortech Setup
    ReefAngel.Refresh();
    ReefAngel.LCD.DrawLargeText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 1, " Drop Reef Tank ", Font8x8); //Top Banner
    ReefAngel.LCD.DrawText(0,255,20,50,"Assigning Slaves");
    ReefAngel.RF.SetMode(Slave_Start,0,0);
    InternalMemory.RFMode_write(0);
    InternalMemory.RFSpeed_write(80);
    InternalMemory.RFDuration_write(7);
  if (ReefAngel.Joystick.IsButtonPressed())
    {
      ReefAngel.RF.SetMode(Slave_Stop,0,0);
      ReefAngel.LCD.DrawText(0,255,50,60,"Done");
    }
    break;
    
   }
//***************************************************************************************************************************************************************************
//------------------------------------------------------------------------- PWM Channels ------------------------------------------------------------------------------------
   if (SeasonsVar[12]=MoonPWMValue);
     MoonPWMValue=MoonPhase();
   if (hour()>=22 || hour()<=8)
     MoonPWMValue=PWMSlope(22,00,8,00,1,MoonPhase(),45,1);
   if (SeasonsVar[0]>=1) MoonPWMValue=0;
     ReefAngel.PWM.SetChannel(4,MoonPWMValue);
  ReefAngel.PWM.Expansion(LEDWhiteBlue,int(ChannelValue[LEDWhiteBlue]));
  ReefAngel.PWM.Expansion(LEDWhiteBlue1,int(ChannelValue[LEDWhiteBlue1]));
  ReefAngel.PWM.Expansion(LEDWhiteBlue2,int(ChannelValue[LEDWhiteBlue2]));
  ReefAngel.PWM.Expansion(MixedLED,int(ChannelValue[MixedLED]));
  ReefAngel.PWM.Expansion(LEDMoonlights,int(ChannelValue[LEDMoonlights]));
    
//------------------------------------------------------------------- End PWM Expansion Code for Slope ---------------------------------------------------------------------
//*************************************************************************************************************************************************************************** 
Last edited by JNieuwenhuizen on Sat Apr 28, 2012 12:31 am, edited 1 time in total.
User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

Code: Select all

//------------------------------------------------------------------ Start Time-of-Day Based Functions ----------------------------------------------------------------------
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These are the mode numbers for the RF Expansion Module for reference ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //#define Constant      0
  //#define Random1       1 // Lagoonal
  //#define Random2       2 // Reef Crest
  //#define ShortWave     3
  //#define LongWave      4
  //#define Smart_NTM     5 // Nutrient Transport Mode
  //#define Smart_TSM     6 // Tidal Swell Mode
  //#define Feeding_Start 7
  //#define Feeding_Stop  8
  //#define Night         9
  //#define Slave_Start   97
  //#define Slave_Stop    98
  //#define None          99
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 //----------------------------------------------------------------- Start RF Daytime Control ------------------------------------------------------------------------------
  if (hour() >=8 && hour() <= 14)
  {  
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Smart_NTM,80,7);
      vtechmode = 5;
    }
  if (hour() >=14 && hour() <= 22)
   {
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Random2,60,7);
      vtechmode = 2;
    }  
  
 //--------------------------------------------------------------- Start RF Nightmode Control -----------------------------------------------------------------------------  
   if (hour()>=22 || hour()<8) // Defining "Nightmode" hours for VorTech = between 10 PM and 8 AM
   {
     ReefAngel.RF.UseMemory=false;
     ReefAngel.RF.SetMode(Night,15,0);
     vtechmode = 9;
   }
   else
   {
     ReefAngel.RF.SetMode(Feeding_Stop,0,0); //Temp fix for coming out of Night mode
     ReefAngel.RF.UseMemory=false;
     ReefAngel.RF.SetMode(Smart_NTM,80,7);
     vtechmode = 5;
   } 
  }

//***************************************************************************************************************************************************************************
//-------------------------------------------------- Random Cloud/Thunderstorm effects function -----------------------------------------------------------------------------
//------------------------------------------------------- From Roberto - THANKS ROBERTO! ------------------------------------------------------------------------------------
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_5_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 25
  // 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 15
  // Minimum number of clouds that can happen per day
#define Min_Clouds_per_Day 3
  // Maximum number of clouds that can happen per day
#define Max_Clouds_per_Day 6
  // Only start the cloud effect after this setting
  // In this example, start could after 11:30am
#define Start_Cloud_After NumMins(12,00)
  // Always end the cloud effect before this setting
  // In this example, end could before 4:30pm
#define End_Cloud_Before NumMins(18,0)
  // 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
  // Channels used by the actinic LEDs on the PWM Expansion module
  // These channels will not be dimmed when the cloud effect is triggered
  // Number is a binary form. B001100 means channel 2 and 3 are used for actinics
#define Actinic_Channels B011000
  // Channels used by the daylight LEDs on the PWM Expansion module
  // These channels will be used for the spike when lightning effect is triggered
  // Number is a binary form. B000011 means channel 0 and 1 are used for daylights
#define Daylight_Channels B000111
  // 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(26); 
      // 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_5_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(36);
        // 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?
//is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      // let's go through all channels to pick which ones will be dimmed
      for (int a=0;a<6;a++)
      {
        if (bitRead(Actinic_Channels,a)==0)
        {
          // this will slope down the channel from the current PWM to 0 within 3minutes.
          // then it will stay at 0 for the duration of the cycle
          // and finally slope up from 0 to PWM value within 3 minutes
          // it is basically an inversed slope
          ChannelValue[a]=ReversePWMSlope(cloudstart,cloudstart+cloudduration,ChannelValue[a],0,180);
        }
      }
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        for (int b=0;b<6;b++)
        {
          if (bitRead(Daylight_Channels,b)==1)
          {
            if (random(100)<20) lightningstatus=1; 
            else lightningstatus=0;
            if (lightningstatus) ChannelValue[b]=100; 
            else ChannelValue[b]=0;
            //delay(10);
          }
          else
          {
            ChannelValue[b]=20;
          }
        }
      }
    }
    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      ReefAngel.RF.UseMemory=true;
      {
        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;
      }
    }
  }
}
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 ------------------------------------------------------------------------------------
//***************************************************************************************************************************************************************************
//----------------------------------------------------------- Calculators for Seasons function ------------------------------------------------------------------------------
  long calcSec(long hr, long minu) //if (hour()==hr && minute()==minu);
   {
    long totalseconds;
    totalseconds= (hr*3600)+(minu*60);
    return totalseconds;
   }
    long calcTime(long seconds1, long seconds2) //if (second()==seconds1 && second()==seconds2);
   {
    long timediff=abs(seconds1-seconds2);
    return timediff;
   }

void DayNumber(unsigned int y, unsigned int m, unsigned int d)
{
  int days[]={
    0,31,59,90,120,151,181,212,243,273,304,334      };    // Number of days at the beginning of the month in a not leap year.
  //Start to calculate the number of day
  if (m==1 || m==2)
  {
    Ndays = days[(m-1)] +d;            //for any type of year, it calculate the number of days for January or february
  }            // Now, try to calculate for the other months
  else if ((y % 4 == 0 && y % 100 != 0) ||  y % 400 == 0){  //those are the conditions to have a leap year
    Ndays = days[(m-1)]+d+1;     // if leap year, calculate in the same way but increasing one day
  }
  else {                 //if not a leap year, calculate in the normal way, such as January or February
    Ndays = days[(m-1)]+d;
  }
} 
//End calculators
//***************************************************************************************************************************************************************************
//Calculate Sunrise/set by date & predefined season & rise/set times
void Seasons()
{
  //Set the hour you want the calculations of rise an set to be based on
  int UserRiseHour = 8;
  int UserSetHour =  22;
  
  #define forceseasoncalculation
  static byte ssn , ssnp = 0 , ssnpt ;
  long stime, wstime, vstime, wrtime, rtime, vrtime;
  int wrhour,wrmin,wrsec,wshour,wsmin,wssec,rsec,ssec,vrhour,vrmin,vrsec,vshour,vsmin,vssec;
  int iDiffrise = 0;
  int iDiffset = 0;
  int risediffperday = 0;
  int setdiffperday = 0;
  int totalrise = 0;
  int totalset = 0;
  byte s=0;
  int DaysPerYear; 
  //rise and set times set by hour and minute. there are 4 seasons however there are 8 highs & lows in rise and set throughout the year
  //first spot is second half of winter starting jan 1st - DO NOT CHANGE
    int risehour[8]= {UserRiseHour+1,UserRiseHour+1,UserRiseHour+1,UserRiseHour,UserRiseHour,UserRiseHour-1,UserRiseHour,UserRiseHour};/*{
    7,7,7,6,6,5,6,6      };*/
  int riseminute[8]={
    00,30,00,30,00,30,00,30      };
  int sethour[8] = {UserSetHour-2,UserSetHour-1,UserSetHour-1,UserSetHour,UserSetHour,UserSetHour,UserSetHour,UserSetHour-1};/*{
    17,18,18,19,19,19,19,18      };*/
  int setminute[8] = {
    30,00,30,00,00,30,00,00      };

  if (hour()==0 && minute()==0 && second()==0) ssnp=0;
#ifdef forceseasoncalculation
  if (ssnp==0)
#else
    if (hour()==0 && minute()==0 && second()==1 && ssnp==0)
#endif
     {
      //leapyear or not to define DaysPerYear - DO NOT CHANGE
      if (year()%4 == 0 && !(year()%100 == 0 && year()%400 != 0)) {
        DaysPerYear=366;
      }
      else {
            DaysPerYear = 365;
           }
      //Call Day Number Calc to determin day ie december 31st on a non leap year is day 365 - DO NOT CHANGE
      DayNumber(year(),month(),day());
      //define days between beginning, middle and end of seasons high peaks -  DO NOT CHANGE
      int seasons[9] ={0,45,96,135,187,238,283,328,DaysPerYear};
      //define season and array pulling variable - DO NOT CHANGE
      for (s=0; seasons[s] < Ndays; s++) ssn = s+1, ssnpt = s+1, ssnp = s;
      //set loop on array time pulling variable to go back to beginning instead of increasing array size - DO NOT CHANGE
      if (ssn >= 7) ssn = 0;

      //differece in seconds between two rise/set array times pulled - DO NOT CHANGE
      long rise1 = calcSec(risehour[ssn],riseminute[ssn]);
      long rise2 = calcSec(risehour[ssnp],riseminute[ssnp]);
      iDiffrise = calcTime(rise1, rise2);
      long set1 = calcSec(sethour[ssn],setminute[ssn]);
      long set2 = calcSec(sethour[ssnp],setminute[ssnp]);
      iDiffset = calcTime(set1,set2);             

      //calculate new sunrise/set difference from array value & last group of code - DO NOT CHANGE
      risediffperday = iDiffrise/(seasons[ssnpt]-seasons[ssnp]);
      totalrise = risediffperday*(Ndays - seasons[ssnp]);
      setdiffperday = iDiffset/(seasons[ssnpt]-seasons[ssnp]);
      totalset = setdiffperday*(Ndays - seasons[ssnp]);

      //creating time in seconds for main sun rise/set number - DO NOT CHANGE
      rtime=calcSec(risehour[ssnp],riseminute[ssnp]);
      if (ssnp == 0 || ssnp == 2 || ssnp == 4 || ssnp == 6){ 
        rtime -= totalrise;
      }
      else {
        rtime += totalrise;
      }
      stime=calcSec(sethour[ssnp],setminute[ssnp]);
      if (ssnp == 1 || ssnp == 3 || ssnp == 5 || ssnp == 7){ 
        stime -= totalset;
      }
      else {
        stime += totalset;
      }
      
      //These are the off set times, standard rtime and stime are for Royal Blues & Blues
      // DO NOT CHANGE the operators in these equations ie +- 
      // The number is in seconds (1200) change this number to change the offset for each color
      wrtime = rtime + 1200;
      wstime = stime - 1200;
      vrtime = rtime - 1200;
      vstime = stime + 1200;
      
      //turning seconds back to Hours:Minutes:Seconds
      //Blues
      rhour=rtime/3600; 
      rtime=rtime%3600;
      rmin=rtime/60; 
      rtime=rtime%60; 
      rsec=rtime;
      if(rsec > 30) rmin++; 
      shour=stime/3600; 
      stime=stime%3600;
      smin=stime/60; 
      stime=stime%60; 
      ssec=stime;
      if(ssec > 30) smin++;
      //White
      wrhour = wrtime/3600;
      wrtime=wrtime%3600;
      wrmin=wrtime/60;
      wrtime=wrtime%60;
      wrsec=wrtime;
      if(wrsec>30) wrmin++;
      wshour = wstime/3600;
      wstime=wstime%3600;
      wsmin=wstime/60;
      wstime=wstime%60;
      wssec=wstime;
      if(wssec>30) wsmin++;
      //Violet
      vrhour = vrtime/3600;
      vrtime=vrtime%3600;
      vrmin=vrtime/60;
      vrtime=vrtime%60;
      vrsec=vrtime;
      if(vrsec>30) vrmin++;
      vshour = vstime/3600;
      vstime=vstime%3600;
      vsmin=vstime/60;
      vstime=vstime%60;
      vssec=vstime;
      if(vssec>30) vsmin++;



      //time for each active led channel to pull for sunrise - DO NOT CHANGE
      int Sunrise[2]={
        rhour,rmin                  };
      int Sunset[2]={
        shour,smin                  };
      int whSunrise[2]={
        wrhour,wrmin                  };
      int whSunset [2]={
        wshour,wsmin                  };
      int vSunrise[2]={
        vrhour,vrmin                  };
      int vSunset [2]={
        vshour,vsmin                  };
        
      //This is the PWM Slope for each channel, each channel pulls an array value from above(hour,minute) to use, how you set them is up to you. 
      //Just always use a Rise hour in a Rise spot, always a set hour in a set spot ect ect
  ChannelValue[LEDWhiteBlue]=PWMSlope(vSunrise[1],vSunrise[2],vSunset[1],vSunset[2],2,50,2,ChannelValue[LEDWhiteBlue]);
  ChannelValue[LEDWhiteBlue1]=PWMSlope(whSunrise[1],whSunrise[2],whSunset[1],whSunset[2],2,50,2,ChannelValue[LEDWhiteBlue1]);
  ChannelValue[LEDWhiteBlue2]=PWMSlope(Sunrise[1],Sunrise[2],Sunset[1],Sunset[2],2,50,2,ChannelValue[LEDWhiteBlue2]);
  ChannelValue[MixedLED]=PWMSlope(Sunrise[1],Sunrise[2],whSunset[1],whSunset[2],2,50,2,ChannelValue[MixedLED]);

    }
}
//------------------------------------------------------------------- End Seasons Calculation -------------------------------------------------------------------------------
//***************************************************************************************************************************************************************************
int JulianDate(int d, int m, int y)
{ 
  int mm, yy;
  int k1, k2, k3;
  int j;

  yy = y - (int)((12 - m) / 10);
  mm = m + 9;
  if (mm >= 12)
  {
    mm = mm - 12;
  }
  k1 = (int)(365.25 * (yy + 4712));
  k2 = (int)(30.6001 * mm + 0.5);
  k3 = (int)((int)((yy / 100) + 49) * 0.75) - 38;
  // 'j' for dates in Julian calendar:
  j = k1 + k2 + d + 59;
  if (j > 2299160)
  {
    // For Gregorian calendar:
    j = j - k3; // 'j' is the Julian date at 12h UT (Universal Time)
  }
  return j;
}

double MoonAge(int d, int m, int y)
{ 
  int j = JulianDate(d, m, y);
  //Calculate the approximate phase of the moon
  int ip = (j + 4.867) / 29.53059;
  ip = ip - abs(ip); 
  //After several trials I've seen to add the following lines, 
  //which gave the result was not bad 
  if(ip < 0.5)
    int ag = ip * 29.53059 + 29.53059 / 2;
  else
    int ag = ip * 29.53059 - 29.53059 / 2;
  // Moon's age in days
  byte ag = abs(ag) + 1;
  return ag;
}

byte MoonState(byte D)
{
  switch(D){
  case 1: 
    0, 29;
    ThisPhase = 0;
  case 2: 
    1, 2, 3, 4, 5, 6;
    ThisPhase = 1;
  case 3: 
    7;
    ThisPhase = 2;
  case 4: 
    8, 9, 10, 11, 12, 13;
    ThisPhase = 3;
  case 5: 
    14;
    ThisPhase = 4;
  case 6: 
    15, 16, 17, 18, 19, 20, 21;
    ThisPhase = 5;
  case 7: 
    22;
    ThisPhase = 6;
  case 8: 
    23, 24, 25, 26, 27, 28;
    ThisPhase = 7;
  default: 
    return 0;
  }
 }


User avatar
JNieuwenhuizen
Posts: 96
Joined: Thu Feb 16, 2012 12:39 am
Location: South Africa

Re: My almost completed pde

Post by JNieuwenhuizen »

Can anyone help me?
Post Reply