Page 5 of 6

Re: Custom Main Screens

Posted: Wed May 01, 2013 3:35 pm
by binder
I just fixed up my code in the previous post. I know the WHITE and Params errors should be gone now. I'm not sure why it is giving you the error about the WaterLevel member. It should be available because it found the Water Level Expansion Module.
Make sure you are running the latest libraries. Perhaps Roberto can shed some more light on this error.

Re: Custom Main Screens

Posted: Wed May 01, 2013 3:42 pm
by rimai
Make sure you add this in your includes up top:

Code: Select all

#include <WaterLevel.h>

Custom Main Screens

Posted: Wed May 01, 2013 10:59 pm
by Poiromaniax
Thanks guys, will give a shot in a bit later :)

Re: Custom Main Screens

Posted: Wed May 15, 2013 10:45 pm
by ReeferBee

Code: Select all


//*********************************************************************************************************************************
//Custom Main, Graph & Menu
void DrawCustomMain()
{
  byte x = 6;
  byte y = 2;
  byte t;
  char text[7];
  static byte vtechmode=0;

  ReefAngel.LCD.DrawDate(6, 2);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, 11, 132, 11);
  pingSerial();

  ReefAngel.LCD.DrawText(COLOR_TOMATO,255, 6, 90, "--------------------");
  ReefAngel.LCD.DrawText(COLOR_TOMATO,255, 6, 126, "--------------------");
  ReefAngel.LCD.DrawText(COLOR_TOMATO,255, 2, 93, "|");
  ReefAngel.LCD.DrawText(COLOR_TOMATO,255, 2, 103, "|");
  ReefAngel.LCD.DrawText(COLOR_TOMATO,255, 2, 113, "|");
  ReefAngel.LCD.DrawText(COLOR_TOMATO,255, 2, 123, "|");
  ReefAngel.LCD.DrawText(COLOR_TOMATO,255, 126, 93, "|");
  ReefAngel.LCD.DrawText(COLOR_TOMATO,255, 126, 103, "|");
  ReefAngel.LCD.DrawText(COLOR_TOMATO,255, 126, 113, "|");
  ReefAngel.LCD.DrawText(COLOR_TOMATO,255, 126, 123, "|");


  ReefAngel.LCD.DrawText(0,255,18,12,"EcoSmart Vortech");
  if (vtechmode == 0) ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN,255,35,22,"Constant");
  else if(vtechmode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,42,21,"Lagoon");
  else if (vtechmode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,25,21,"Reef Crest");
  else if (vtechmode == 3) ReefAngel.LCD.DrawLargeText(COLOR_CORNFLOWERBLUE,255,22,21,"Short Pulse");
  else if (vtechmode == 4) ReefAngel.LCD.DrawLargeText(COLOR_PINK,255,25,21,"Long Pulse");
  else if (vtechmode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,8,21,"Nutrient Trnsp.");
  else if (vtechmode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,23,21,"Tidal Swell");
  else if (vtechmode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,0,45,21,"Night");

  ReefAngel.LCD.DrawText(0,255,10,30,"Display");
  ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(COLOR_INDIANRED, 255, 10, 40, text, Num8x8);
  pingSerial();

  ReefAngel.LCD.DrawText(0,255,100,30,"pH");
  ConvertNumToString(text, ReefAngel.Params. PH, 100);
  ReefAngel.LCD.DrawLargeText(COLOR_PLUM, 255, 85, 40, text, Num8x8);
  pingSerial();

  ReefAngel.LCD.DrawText(0,255,43,48,"Salinity");
  ConvertNumToString(text, ReefAngel.Params.Salinity, 100);
  ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN, 255, 49, 58, text, Num8x8);
  pingSerial();

  pingSerial();
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 77, TempRelay);

  ReefAngel.LCD.DrawText(0,255,8,68,"Sump");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T3_PROBE], COLOR_CORNFLOWERBLUE, 40, 68, 10);

  ReefAngel.LCD.DrawText(0,255,70,68,"Room");
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T2_PROBE], COLOR_CORNFLOWERBLUE, 99, 68, 10);

}
void DrawCustomGraph()
{
}
Is it possible to mod this code to display the mode that my WP40 is running?

Re: Custom Main Screens

Posted: Thu May 16, 2013 7:39 am
by DrewPalmer04
That will display the mode your mp40 is running? Only if you're controlling it via the RF module? The RA sets the mode and then that code displays it on your custom main. I hope you have the RA+ or you'll run out of space quickly.

Re: Custom Main Screens

Posted: Thu May 16, 2013 8:43 am
by ReeferBee
DrewPalmer04 wrote:That will display the mode your mp40 is running? Only if you're controlling it via the RF module? The RA sets the mode and then that code displays it on your custom main. I hope you have the RA+ or you'll run out of space quickly.
Yes, using this part of the coding.

Code: Select all

 ReefAngel.LCD.DrawText(0,255,18,12,"EcoSmart Vortech");
  if (vtechmode == 0) ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN,255,35,22,"Constant");
  else if(vtechmode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,42,21,"Lagoon");
  else if (vtechmode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,25,21,"Reef Crest");
  else if (vtechmode == 3) ReefAngel.LCD.DrawLargeText(COLOR_CORNFLOWERBLUE,255,22,21,"Short Pulse");
  else if (vtechmode == 4) ReefAngel.LCD.DrawLargeText(COLOR_PINK,255,25,21,"Long Pulse");
  else if (vtechmode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,8,21,"Nutrient Trnsp.");
  else if (vtechmode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,23,21,"Tidal Swell");
  else if (vtechmode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,0,45,21,"Night");
I believe this only works with the RF module though. I want it to display the mode my WP40 are in, through the use of the wp40 harness and dimming ports. Yep, the plus was a must!

Re: Custom Main Screens

Posted: Thu May 16, 2013 9:26 am
by rimai
You can do that.... Can you open a new thread and post your code?

Re: Custom Main Screens

Posted: Thu May 16, 2013 1:02 pm
by ReeferBee
It's not my code. Anther member posted it in this thread. I just wanted to change it up a litte bit. Should I still open another thread with it? Thanks

Re: Custom Main Screens

Posted: Thu May 16, 2013 1:27 pm
by lnevo
Yes, but post your code and that code seperately so we can see how it needs to be integrated.

Re: Custom Main Screens

Posted: Tue May 21, 2013 8:32 pm
by ReeferBee
After a day of tweaking the code I think i finally have it the way I like it.

Image

Code: Select all

//Custom Main, Graph & Menu
void DrawCustomMain()
{
  byte x = 6;
  byte y = 2;
  byte t;
  char text[7];

  ReefAngel.LCD.DrawDate(6, 4);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, 11, 132, 11);
  pingSerial();

  ReefAngel.LCD.DrawLargeText(0,255,10,16,"  WP40 Mode:");
  if (vtechmode == 0) ReefAngel.LCD.DrawLargeText(COLOR_LIMEGREEN,255,35,27,"Constant");
  else if(vtechmode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,42,26,"Lagoon");
  else if (vtechmode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,25,26,"Reef Crest");
  else if (vtechmode == 3) ReefAngel.LCD.DrawLargeText(COLOR_CORNFLOWERBLUE,255,22,26,"Short Pulse");
  else if (vtechmode == 4) ReefAngel.LCD.DrawLargeText(COLOR_PINK,255,25,26,"Long Pulse");
  else if (vtechmode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,8,26,"Nutrient Trnsp.");
  else if (vtechmode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,23,26,"Tidal Swell");
  else if (vtechmode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,255,45,26,"Night");

  ReefAngel.LCD.DrawLargeText(0,255,17,49,"Sump");
  ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawHugeText(COLOR_RED, 255, 12, 65, text, Num12x16);
  pingSerial();

  ReefAngel.LCD.DrawLargeText(0,255,100,40,"pH");
  ConvertNumToString(text, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(COLOR_BLUE, 255, 89, 55, text, Num8x8);
  pingSerial();
  
  ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,15,89, "WP40L"); 
  ReefAngel.LCD.DrawText(COLOR_BLACK,255,20,100, ReefAngel.PWM.GetDaylightValue());
  ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,88,89, "WP40R"); 
  ReefAngel.LCD.DrawText(COLOR_BLACK,255,95,100, ReefAngel.PWM.GetActinicValue());

  pingSerial();
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 113, TempRelay);
  
  
}
void DrawCustomGraph()
{
}
I cant take credit, I mostly copied and pasted others codes from this thread.

Thanks!

Re: Custom Main Screens

Posted: Tue May 21, 2013 8:56 pm
by rimai
Super cool!!!
Can you post the code?

Re: Custom Main Screens

Posted: Tue May 21, 2013 9:23 pm
by ReeferBee
Thanks!
Done :)

Re: Custom Main Screens

Posted: Wed May 22, 2013 6:39 am
by binder
ReeferBee wrote:Thanks!
Done :)
Very nice looking screen! Great job!

Custom Main Screens

Posted: Wed May 22, 2013 10:04 am
by Poiromaniax
binder wrote:
ReeferBee wrote:Thanks!
Done :)
Very nice looking screen! Great job!

Agreed! Good job ReeferBee

I'm gonna use the basic layout and change a few parameters

Re: Custom Main Screens

Posted: Sat Mar 08, 2014 9:45 pm
by jegillis
IMAG0800.jpg
IMAG0800.jpg (54.87 KiB) Viewed 10298 times

Code: Select all

byte ActinicPWMValue=0;
byte DaylightPWMValue=0;
void DrawCustomMain()
{
  byte x = 6;
  byte y = 2;
  byte t;
  char text[7];
  //static byte vtechmode=0;

  ReefAngel.LCD.DrawDate(6, 2);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, 11, 132, 11);
  pingSerial();
  
  ReefAngel.LCD.DrawLargeText(3,255,8,16,"Redneck Reefin!", Font8x8);
  ReefAngel.LCD.DrawLargeText(3,255,8,56,"Jason & Sarah's", Font8x8);
  ReefAngel.LCD.DrawLargeText(3,255,32,65,"Money Pit", Font8x8);
  pingSerial();

  ReefAngel.LCD.DrawText(COLOR_BLACK,255, 6, 90, "--------------------");
  ReefAngel.LCD.DrawText(COLOR_BLACK,255, 6, 126, "--------------------");
  ReefAngel.LCD.DrawText(COLOR_BLACK,255, 2, 93, "|");
  ReefAngel.LCD.DrawText(COLOR_BLACK,255, 2, 103, "|");
  ReefAngel.LCD.DrawText(COLOR_BLACK,255, 2, 113, "|");
  ReefAngel.LCD.DrawText(COLOR_BLACK,255, 2, 123, "|");
  ReefAngel.LCD.DrawText(COLOR_BLACK,255, 126, 93, "|");
  ReefAngel.LCD.DrawText(COLOR_BLACK,255, 126, 103, "|");
  ReefAngel.LCD.DrawText(COLOR_BLACK,255, 126, 113, "|");
  ReefAngel.LCD.DrawText(COLOR_BLACK,255, 126, 123, "|");


  ReefAngel.LCD.DrawText(0,255,10,30,"Display");
  ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(COLOR_BLACK, 255, 10, 40, text, Num8x16);
  pingSerial();

  ReefAngel.LCD.DrawText(0,255,100,30,"pH");
  ConvertNumToString(text, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(COLOR_BLACK, 255, 85, 40, text, Num8x16);
  pingSerial();

  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 77, TempRelay);

  ReefAngel.LCD.DrawText(0,255,8,109, "CWLED");  
  ReefAngel.LCD.DrawText(COLOR_BLACK,255,15,119, ReefAngel.PWM.GetDaylightValue());
  //ReefAngel.PWM.GetDaylightValue(), 
  ReefAngel.LCD.DrawText(0,255,88,108, "RBLED");  
  ReefAngel.LCD.DrawText(COLOR_BLACK,255,90,119, ReefAngel.PWM.GetActinicValue());
  //ReefAngel.PWM.GetActinicValue());
  
  //ReefAngel.LCD.DrawMonitor(15, 60, ReefAngel.Params,
                            //ReefAngel.PWM.GetDaylightValue(), 
                            //ReefAngel.PWM.GetActinicValue());

}
void DrawCustomGraph()
{
}

Re: Custom Main Screens

Posted: Sat Mar 08, 2014 11:12 pm
by rimai
I like it :)

Re: Custom Main Screens

Posted: Tue Mar 11, 2014 8:32 pm
by jegillis
IMAG0801.jpg
IMAG0801.jpg (45.11 KiB) Viewed 10288 times
Well that didn't last long before I had to tinker would anyone have an idea on how I could have the temps change color if they are over a set limit?

Code: Select all

#define SIMPLE_MENU
#define NUMBERS_8x16
#define FONT_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 <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <Humidity.h>
#include <DCPump.h>
#include <ReefAngel.h>

////// Place global variable code below here
byte ActinicPWMValue=0;
byte DaylightPWMValue=0;
void DrawCustomMain()
{
  byte x = 6;
  byte y = 2;
  byte t;
  char text[7];
  //static byte vtechmode=0;

  ReefAngel.LCD.DrawDate(6, 2);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, 11, 132, 11);
  pingSerial();
  
  ReefAngel.LCD.DrawLargeText(3,255,8,14,"Redneck Reefin!", Font8x8);
  ReefAngel.LCD.DrawLargeText(3,255,8,55,"Jason & Sarah's", Font8x8);
  ReefAngel.LCD.DrawLargeText(3,255,32,64,"Money Pit", Font8x8);
  pingSerial();

  ReefAngel.LCD.DrawText(COLOR_RED,255, 6, 88, "--------------------");
  ReefAngel.LCD.DrawText(COLOR_RED,255, 6, 125, "--------------------");
  ReefAngel.LCD.DrawText(COLOR_RED,255, 2, 93, "|");
  ReefAngel.LCD.DrawText(COLOR_RED,255, 2, 103, "|");
  ReefAngel.LCD.DrawText(COLOR_RED,255, 2, 113, "|");
  ReefAngel.LCD.DrawText(COLOR_RED,255, 2, 123, "|");
  ReefAngel.LCD.DrawText(COLOR_RED,255, 126, 93, "|");
  ReefAngel.LCD.DrawText(COLOR_RED,255, 126, 103, "|");
  ReefAngel.LCD.DrawText(COLOR_RED,255, 126, 113, "|");
  ReefAngel.LCD.DrawText(COLOR_RED,255, 126, 123, "|");

  ReefAngel.LCD.DrawLargeText(0,255,8,25,"TANK", Font8x8);
  ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(224, 255, 42, 25, text, Font8x8);
  pingSerial();
  
  ReefAngel.LCD.DrawLargeText(0,255,8,35,"HOOD", Font8x8);
  ConvertNumToString(text, ReefAngel.Params.Temp[T2_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(153, 255, 42, 35, text, Font8x8);
  pingSerial();
  
  ReefAngel.LCD.DrawLargeText(0,255,8,45,"ROOM", Font8x8);
  ConvertNumToString(text, ReefAngel.Params.Temp[T3_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(66, 255, 42, 45, text, Font8x8);

  ReefAngel.LCD.DrawText(0,255,100,25,"pH");
  ConvertNumToString(text, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(COLOR_BLACK, 255, 85, 35, text, Num8x16);
  pingSerial();

  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 75, TempRelay);
  pingSerial();
  
    ReefAngel.LCD.DrawText(0,255,8,96, "White=");  
  ReefAngel.LCD.DrawText(197,255,46,96, ReefAngel.PWM.GetDaylightValue());
  //ReefAngel.PWM.GetDaylightValue()), 
  ReefAngel.LCD.DrawText(0,255,72,96, "Blue=");   
  ReefAngel.LCD.DrawText(3,255,106,96, ReefAngel.PWM.GetActinicValue());
  //ReefAngel.PWM.GetActinicValue());


}
void DrawCustomGraph()
{
}


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


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

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

void loop()
{
    ReefAngel.SingleATOLow( Port1 );
    ReefAngel.Relay.Set( Port2, !ReefAngel.Relay.Status( Port3 ) );
    ReefAngel.ActinicLights( Port3 );
    ReefAngel.DayLights( Port4 );
    ReefAngel.Wavemaker1( Port5 );
    ReefAngel.Wavemaker2( Port6 );
    ReefAngel.DosingPumpRepeat1( Port7 );
    ReefAngel.StandardFan( Port8 );
    ReefAngel.PWM.DaylightPWMSlope();
    ReefAngel.PWM.ActinicPWMSlope();
    
    // Calculate your regular sunrise/sunset PWM value
    ActinicPWMValue=PWMSlope(12,15,22,45,15,100,60,ActinicPWMValue);
    DaylightPWMValue=PWMSlope(13,0,22,0,15,100,60,DaylightPWMValue);
    CheckCloud();
    ReefAngel.PWM.SetActinic(ActinicPWMValue);
    ReefAngel.PWM.SetDaylight(DaylightPWMValue);

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

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

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

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

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

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

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

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

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

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

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


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

  static byte cloudchance=255;
  static byte cloudduration=0;
  static int cloudstart=0;
  static byte numclouds=0;
  static byte lightningchance=0;
  static byte cloudindex=0;
  static byte lightningstatus=0;
  static int LastNumMins=0;
  // Every day at midnight, we check for chance of cloud happening today
  if (hour()==0 && minute()==0 && second()==0) cloudchance=255;

#ifdef forcecloudcalculation
    if (cloudchance==255)
#else
    if (hour()==0 && minute()==0 && second()==1 && cloudchance==255) 
#endif
    {
      //Pick a random number between 0 and 99
      cloudchance=random(100); 
      // if picked number is greater than Cloud_Chance_per_Day, we will not have clouds today
      if (cloudchance>Cloud_Chance_per_Day) cloudchance=0;
      // Check if today is day for clouds. 
      if ((day()%Clouds_Every_X_Days)!=0) cloudchance=0; 
      // If we have cloud today
      if (cloudchance)
      {
        // pick a random number for number of clouds between Min_Clouds_per_Day and Max_Clouds_per_Day
        numclouds=random(Min_Clouds_per_Day,Max_Clouds_per_Day);
        // pick the time that the first cloud will start
        // the range is calculated between Start_Cloud_After and the even distribuition of clouds on this day. 
        cloudstart=random(Start_Cloud_After,Start_Cloud_After+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
      }
    }
  // Now that we have all the parameters for the cloud, let's create the effect

  if (cloudchance)
  {
    //is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,DaylightPWMValue,15,180);
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5)
      {
        if (random(100)<20) lightningstatus=1; 
        else lightningstatus=0;
        if (lightningstatus)
        {
          DaylightPWMValue=100; 
          ActinicPWMValue=100;
        }
        else 
        {
          DaylightPWMValue=0;
          ActinicPWMValue=15;
        }
        delay(1);
      }
    }
    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      {
        cloudstart=random(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2),(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2))+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
      }
    }
  }
  
  if (LastNumMins!=NumMins(hour(),minute()))
  {
    LastNumMins=NumMins(hour(),minute());
    ReefAngel.LCD.Clear(255,0,120,132,132);
    ReefAngel.LCD.DrawText(0,255,8,108,"Cloud");
    ReefAngel.LCD.DrawText(0,255,8,118,"00:00");
    ReefAngel.LCD.DrawText(0,255,90,108,"Storm");
    ReefAngel.LCD.DrawText(0,255,48,108,"Length");
    ReefAngel.LCD.DrawText(0,255,90,118,"00:00");
    if (cloudchance && (NumMins(hour(),minute())<cloudstart))
    {
      int x=0;
      if ((cloudstart/60)>=10) x=8; else x=14;
      ReefAngel.LCD.DrawText(37,255,x,118,(cloudstart/60));
      if ((cloudstart%60)>=10) x=58; else x=64;
      ReefAngel.LCD.DrawText(37,255,x,118,(cloudstart%60));
    }
    if (lightningchance) 
    {
      int x=0;
      if (((cloudstart+(cloudduration/2))/60)>=10) x=90; else x=96;
      ReefAngel.LCD.DrawText(37,255,x,118,((cloudstart+(cloudduration/2))/60));
      if (((cloudstart+(cloudduration/2))%60)>=10) x=108; else x=114;
      ReefAngel.LCD.DrawText(37,255,x,118,((cloudstart+(cloudduration/2))%60));
    }
  }   
}

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

Re: Custom Main Screens

Posted: Wed Mar 12, 2014 4:45 am
by lnevo
I know someone did some code to base their temp color off the value, but I can't find it at the moment.

I did help add a function to the library so that if you go over a certain limit it will flash. Take a look at this thread:

http://forum.reefangel.com/viewtopic.ph ... nitoralarm

Oh and here is the post in this thread where someone changed the temp colors to be based on range

http://forum.reefangel.com/viewtopic.php?p=23651#p23651

Re: Custom Main Screens

Posted: Wed Mar 12, 2014 4:23 pm
by jegillis
Thanks, I used the color change the flashing is cool but I had no idea what I was looking at on that code

Re: Custom Main Screens

Posted: Thu Mar 13, 2014 8:11 am
by jsclownfish
Here is the code I used. I don't know if it ever went into the libraries...

Code: Select all

//function to flash warning (parameter, high limt, low limit, x, y, decimal)
void Warningflash(int param, int high, int low, byte x, byte y, byte z)
{
  int mod=second()%2;
  if (param > high || param < low) 
 {
     if (mod==0) ReefAngel.LCD.Clear(DefaultBGColor,x,y,x+40,y+10);
     else ReefAngel.LCD.DrawSingleMonitor(param, COLOR_RED, x, y, z);
 }
 else ReefAngel.LCD.DrawSingleMonitor(param, DefaultFGColor, x, y, z);
}

Re: Custom Main Screens

Posted: Thu Mar 13, 2014 8:15 am
by lnevo
Yes, I added it :) I think Roberto took the pull request...

Re: Custom Main Screens

Posted: Mon Mar 17, 2014 11:29 pm
by SEANTADEZ
SuperDodge wrote:Image

Here's where my screen seems to have settled at during my first week of tinkering with my Reef Angel.

The line that says "Lagoon" will eventually update with my Vortech status (when I save some coin for the RF adapter. The line is always centered

The line that says "Clear Skies" will update to say "Cloudy(XX:XX)" or "Storms(XX:XX)" if there is a cloud or a cloud with lightning coming. This line is always centered.

The moon status updates throughout the month and is always centered.

The line that says W:100% B:100% R:100% updates in real-time to reflect all three channels on my AI Nano fixture. The line is always centered as the position of the numbers changes depending on the number of digits.

THANKS TO EVERYONE WHO PROVIDED GREAT CODE AND IDEAS THROUGHOUT THIS THREAD!

CODE REMOVED BECAUSE I FOUND AN ERROR - WILL REPOST WHEN FIXED
Really Cool design but, i can't find where did you post the code...

Re: Custom Main Screens

Posted: Tue Mar 18, 2014 11:04 am
by SEANTADEZ
Can anybody help me with this code? I don't know what's wrong but i can't get the DrawHugeNumbers working, i don't get any error just no highlight and obviously doesn't work, also i have like a flashing display, very anoint...




//CUSTOM SCREEM

void DrawCustomMain()
{
byte x = 6;
byte y = 2;
byte t;
ReefAngel.LCD.DrawLargeText(COLOR_ORANGE, COLOR_WHITE, 6, 5, " SEANTADEZ");
ReefAngel.LCD.DrawDate(6, 118);
ReefAngel.LCD.Clear(COLOR_BLACK, 1, 17, 132, 17);
pingSerial();
x = 12;
y += MENU_START_ROW+1;
ReefAngel.LCD.DrawText(COLOR_DARKTURQUOISE, COLOR_WHITE, x, y+6, "TEMP. PH");
char text[7];
ConvertNumToString(text, ReefAngel.Params.PH, 100);
ReefAngel.LCD.Clear(DefaultBGColor, x+16, y+65, x+65, y+16);
ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+75, y+18, text);
pingSerial();

ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
y += MENU_START_ROW*2;
x = 10;
ReefAngel.LCD.Clear(DefaultBGColor,x,y,x+(16*4),y+16);
pingSerial();
ReefAngel.LCD.DrawHugeNumbers(T1TempColor, DefaultBGColor, x, y, text);
pingSerial();
x += (16*4) + 8;
ReefAngel.LCD.DrawText(COLOR_DARKTURQUOISE,DefaultBGColor,8,y+25,"Room:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T2_PROBE], COLOR_BLUE,
9, y+35, 10);

//*** Doser's Status ***********
boolean Dose1On = ReefAngel.Relay.Status(Port1);
boolean Dose2On = ReefAngel.Relay.Status(Port2);
//*** End Doser Status ********

// ***** START DOSING IF IS CALCIUM THEN....

if (Dose1On)
{
ReefAngel.LCD.DrawText(COLOR_DARKTURQUOISE,DefaultBGColor,58,y+25," Adding:");
ReefAngel.LCD.DrawText(COLOR_GREEN, DefaultBGColor, 58,y+35, " CALC. ");
}

// ****** **** START DOSING IF IS ALK THEN....
if (Dose2On)
{
ReefAngel.LCD.DrawText(COLOR_DARKTURQUOISE,DefaultBGColor,58,y+25," Adding:");
ReefAngel.LCD.DrawText(COLOR_RED, DefaultBGColor, 58,y+35, "ALK");
}
else
{
ReefAngel.LCD.DrawText(COLOR_DARKTURQUOISE,DefaultBGColor,58,y+25," Adding:");
ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor, 58,y+35, "Nothing");
}


//**** end doser status ********


byte TempRelay = ReefAngel.Relay.RelayData;
TempRelay &= ReefAngel.Relay.RelayMaskOff;
TempRelay |= ReefAngel.Relay.RelayMaskOn;
ReefAngel.LCD.DrawOutletBox(12, 93, TempRelay);

}

void DrawCustomGraph()
{
}

//End

Re: Custom Main Screens

Posted: Thu Mar 20, 2014 9:08 am
by rimai
The huge numbers are showing just fine.
What do you mean with can't get it working?
The flashing is because you are erasing and painting something over in the same spot.
It flashes because you erase white and paint red, so the white and red causes it to look like it's flashing.
You just have to be careful with painting and erasing. When in doubt, it is easier to erase in a different color other than white to clearly see where you are erasing. I usually use red or green and then I change to white when I'm satisfied with the positioning of what I'm erasing.
This is the line that is doing that:

Code: Select all

ReefAngel.LCD.Clear(DefaultBGColor, x+16, y+65, x+65, y+16);

Re: Custom Main Screens

Posted: Thu Mar 20, 2014 10:16 am
by SEANTADEZ
Great i figured it out it's working great for the last few days. thanks a lot. I'm learning

Re: Custom Main Screens

Posted: Wed Mar 22, 2017 7:41 am
by GugsJr
Got my tank going and started diving in further into my Reef Angel.

Here is what Display looks like, I modified reefer's code. I added the center channel and added code to display the offset speed of the antisync pump
MyRADisplay.jpg
MyRADisplay.jpg (111.28 KiB) Viewed 10405 times

Code: Select all

//Custom Main, Graph & Menu

static unsigned long PumpSpeed = InternalMemory.DCPumpSpeed_read(); //Sets Value to pump speed
static int PumpOffset = (PumpSpeed*1.10); //Change Value to match AntiSyncOffset value

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

 ReefAngel.LCD.DrawLargeText(COLOR_BLACK,COLOR_WHITE, 6, 2, " GugsJr's Reef");
 ReefAngel.LCD.DrawDate(6, 118);
 ReefAngel.LCD.Clear(COLOR_BLACK, 1, 17, 132, 17);
 pingSerial();

  ReefAngel.LCD.DrawLargeText(COLOR_BLUE,COLOR_WHITE, 24,16,"Jebao Mode:");
       if  (now()%SECS_PER_DAY<52200|| now()%SECS_PER_DAY >=1800) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,28,26,"Night Mode");
  else if  (InternalMemory.DCPumpMode_read()==Lagoon) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,42,26,"Lagoon");
  else if  (InternalMemory.DCPumpMode_read()==ReefCrest) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,25,26,"Reef Crest");
  else if  (InternalMemory.DCPumpMode_read()==ShortPulse) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,22,26,"Short Pulse");
  else if  (InternalMemory.DCPumpMode_read()==LongPulse) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,25,26,"Long Pulse");
  else if  (InternalMemory.DCPumpMode_read()==NutrientTransport) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,8,26,"Nutrient Trnsp.");
  else if  (InternalMemory.DCPumpMode_read()==TidalSwell) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,23,26,"Tidal Swell");
  else if  (InternalMemory.DCPumpMode_read()==Custom) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,23,26,"Custom");
  else if  (InternalMemory.DCPumpMode_read()==Else) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,23,26,"Tidal Else");
  else if  (InternalMemory.DCPumpMode_read()==Sine) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,23,26,"Sine");
  else if  (InternalMemory.DCPumpMode_read()==Gyre) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,23,26,"Gyre");
  else if  (InternalMemory.DCPumpMode_read()== Constant) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,35,27,"Constant");

  ReefAngel.LCD.DrawLargeText(0,255,17,36,"Display");
  ReefAngel.LCD.DrawLargeText(0,255,17,49,"Temp");
  ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawHugeText(COLOR_RED, 255, 12, 65, text, Num12x16);
  pingSerial();

  ReefAngel.LCD.DrawLargeText(0,255,100,45,"pH");
  ConvertNumToString(text, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(COLOR_BLUE, 255, 89, 65, text, Num8x8);
  pingSerial();
  
  ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,5,80, "Jebao");
  ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,10,89, "Left"); 
  ReefAngel.LCD.DrawText(COLOR_BLACK,255,16,100, InternalMemory.DCPumpSpeed_read());
  ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,50,80, "Jebao");
  ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,49,89, "Center"); 
  ReefAngel.LCD.DrawText(COLOR_BLACK,255,59,100, PumpOffset);
  ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,93,80, "Jebao");
  ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,88,89, " Right"); 
  ReefAngel.LCD.DrawText(COLOR_BLACK,255,100,100, InternalMemory.DCPumpSpeed_read());

  pingSerial();
 
  
  
}
void DrawCustomGraph()
{
}

Re: Custom Main Screens

Posted: Sat Jun 24, 2017 7:56 pm
by binder
Since I am redoing my 75g saltwater tank and making upgrades, I decided my controller's main screen needed an "update". So, I worked out a new custom screen and figured I would share with everybody.
I have a maxspect gyre xf230 that is controlled via the Daylight port. I have a specific mode that I run it at during the "night" hours. I have created a specific set of internal memory locations just for the night modes.
curt custom main screen
curt custom main screen
curt_custom_main.jpg (49.89 KiB) Viewed 10297 times
___TEST CODE___ at the top is changed to the current date and time when it's running normally.
I have T2 and T3 set to only display when the probes are connected.
I have the Water Level Expansion and Salinity Expansion on my tank, so those values are included.
Water is the water level attachment that I have for my reservoir tank.
The screenshot is a test screen. I have hard coded values when I enabled the test mode that way I can get a better idea of how the screen layout is.
I took the bar graph code from the "2014 home screen" in the libraries and shrunk it down to half the size, so I can squeeze it in smaller spaces.
The word "Constant" is the current mode the DC Pump is running in and the bar with number is the speed of the pump on the Daylight channel.
I'm using the standard outlet box but have thought about switching over to the horizontal circle outlet box. I haven't looked at the circle outlets for a long time, so I'm not sure if I will do it or not.
Anyways, here's the FULL code that I'm running. I'm including my FULL code since I had to create extra functions to get what I wanted done.

Code: Select all

// RA+ for 75 Gallon tank
//
// Updated:  6/18/2017
//
// Expansion Modules Added:
//   Expansion Hub
//   Salinity
//   Water Level
//
// Features:
//   T1 - Tank Temperature probe
//   T2 - Room Temperature probe
//   AP - N/A
//   DP - Gyre XF230
//   Water Level - Water Level of reservoir
//   PH - probe in sump
//   Salinity - probe in sump
//
//
// Ports:
//   1 - Skimmer
//   2 - WM Left
//   3 - Heater
//   4 - Return
//   5 - Maxspect Gyre XF230
//   6 - PhosBan 150 Reactor
//   7 - Hydra 26 HD Power Supply
//   8 - Hydra 26 HD Power Supply
//
//

#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 <Salinity.h>
#include <WaterLevel.h>
#include <DCPump.h>
#include <ReefAngel.h>

// Global variables
// used for test controller
//#define __TEST__
// starting point for left edge of screen
#define LEFT_EDGE 8
// DC Pump mode text strings
String PUMP_MODES[] = {"Constant","Lagoon","ReefCrest","Short Pulse","Long Pulse","Nutrient",
                       "Tidal Swell","Feeding","","Night","","Custom","Else","Sine","Gyre"};
// graphics for the water level bar
const unsigned PROGMEM char BAR_CENTER[] = {0x92, 0x92, 0xFF, 0xFF, 0xFF, 0xFF, 0xDB, 0xDB, 0xB6, 0xB6, 0xB6, 0xB6};
const unsigned PROGMEM char BAR_WL_LEFT[] = {0x29, 0x29, 0x2A, 0x72, 0x72, 0x96};
const unsigned PROGMEM char BAR_WL_RIGHT[] = {0x6E, 0x92, 0x96, 0xDB, 0xDB, 0xDB};
const unsigned PROGMEM char BAR_DP_LEFT[] = {0xAB, 0xAB, 0xAF, 0xD3, 0xD7, 0xFB};
const unsigned PROGMEM char BAR_DP_RIGHT[] = {0xB7, 0xB7, 0xB7, 0xDB, 0xDB, 0xDB};

// Memory Locaitons
#define CURT_MEMORY              50
#define DCPUMP_NIGHT_MODE        CURT_MEMORY
#define DCPUMP_NIGHT_SPEED       DCPUMP_NIGHT_MODE + 1
#define DCPUMP_NIGHT_DURATION    DCPUMP_NIGHT_MODE + 2
#define DCPUMP_NIGHT_THRESHOLD   DCPUMP_NIGHT_MODE + 3

// Custom functions
boolean isNightTime();
void checkCustomMemoryValues();
uint8_t DCPumpNightMode_read();
uint8_t DCPumpNightSpeed_read();
uint8_t DCPumpNightDuration_read();
uint8_t DCPumpNightThreshold_read();
uint8_t CustomRead(int address);
void CustomWrite(int address, const uint8_t value);

void setup()
{
    ReefAngel.Init();  //Initialize controller
    checkCustomMemoryValues();
    ReefAngel.AddWifi();
    ReefAngel.AddStandardMenu();
    ReefAngel.AddSalinityExpansion();

    // Default Salinity compensation
    ReefAngel.Salinity.SetCompensation(0);

    ReefAngel.WaterChangePorts = Port4Bit;
    ReefAngel.OverheatShutoffPorts = Port3Bit | Port7Bit | Port8Bit;
    ReefAngel.OverheatProbe = T1_PROBE;

    // Feeding and water change mode speeds
    ReefAngel.DCPump.FeedingSpeed = 0;
    ReefAngel.DCPump.WaterChangeSpeed = 0;

    // Ports that are always on
    ReefAngel.Relay.On(Port1);  // Skimmer
    ReefAngel.Relay.On(Port4);  // Return
    ReefAngel.Relay.On(Port5);  // Gyre XF230
    ReefAngel.Relay.On(Port6);  // PhosBan Reactor
    ReefAngel.Relay.On(Port7);  // Hydra 26 HD
    ReefAngel.Relay.On(Port8);  // Hydra 26 HD

    // Ports that are not in use
    ReefAngel.Relay.Off(Port2);
}

void loop()
{
    ReefAngel.StandardHeater(Port3);

    ReefAngel.DCPump.DaylightChannel = Sync;

    /*
    Night mode - use alternate memory locations
    Day mode - default memory locations
    */
    if ( isNightTime() ) {
        // force in either Constant mode or Long Pulse mode
        // use the nighttime memory locations
        ReefAngel.DCPump.UseMemory = false;
        ReefAngel.DCPump.Mode = DCPumpNightMode_read();
        ReefAngel.DCPump.Speed = DCPumpNightSpeed_read();
        ReefAngel.DCPump.Duration = DCPumpNightDuration_read();
        ReefAngel.DCPump.Threshold = DCPumpNightThreshold_read();
    } else {
        // use default memory values for the modes
        ReefAngel.DCPump.UseMemory = true;
    }

    ReefAngel.ShowInterface();
}

#define LINE1   19
#define LINE2   47
#define LINE3   70
#define WL_BAR_OFFSET 41
#define DC_BAR_OFFSET 4
void DrawCustomMain()
{
    // Fonts in use:   NUMBERS_16x16, FONT_8x16
    byte x = 6;
    byte y = 3;
    byte t;
    char text[11];
    boolean fNight = isNightTime();

#ifdef __TEST__
    ReefAngel.LCD.DrawText(COLOR_RED, DefaultBGColor, x, y, "_____TEST CODE_____");
#else
    // Date & time
    ReefAngel.LCD.DrawDate(x, y);
#endif  // __TEST__

    // Divider line
    ReefAngel.LCD.Clear(COLOR_BLACK, 1, 11, 128, 11);

    // Draw T1
    ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
    x = 8;
    y = LINE1;  // 19
    // NOTE huge numbers are 16x16 (width x height)
    ReefAngel.LCD.Clear(DefaultBGColor, x, y, x+64, y+16);
    ReefAngel.LCD.DrawHugeNumbers(T1TempColor, DefaultBGColor, x, y, text);

    // Draw T2
    // NOTE 4 digits for T1 (16 width, 16*4 pixels)
    x = 80;
#ifdef __TEST__
    ReefAngel.Params.Temp[T2_PROBE] = 810;
#endif  // __TEST__
    if(ReefAngel.Params.Temp[T2_PROBE] > 0) {
        ReefAngel.LCD.DrawText(T2TempColor, DefaultBGColor, x, y, "T2:");
        // NOTE "T2:" is 3 chars of 5 pixels each (15 pixels), plus 2 pixels space after, start on 3rd pixel
        ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T2_PROBE], T2TempColor, x+18, y, 10);
    } else {
        // No, T2, clear the entire space for it
        ReefAngel.LCD.Clear(DefaultBGColor, x, y, x+38, y+8);
    }

    // Draw T3 if present
    y = 29;
#ifdef __TEST__
    ReefAngel.Params.Temp[T3_PROBE] = 796;
#endif  // __TEST__
    if(ReefAngel.Params.Temp[T3_PROBE] > 0) {
        ReefAngel.LCD.DrawText(T3TempColor, DefaultBGColor, x, y, "T3:");
        // NOTE "T3:" is 3 chars of 5 pixels each (15 pixels), plus 2 pixels space after, start on 3rd pixel
        ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T3_PROBE], T3TempColor, x+18, y, 10);
    } else {
        // No, T3, clear the entire space for it
        ReefAngel.LCD.Clear(DefaultBGColor, x, y, x+38, y+8);
    }

    // Draw PH
    y = LINE2;
#ifdef __TEST__
    strcpy(text, "8.20");
#else
    ConvertNumToString(text, ReefAngel.Params.PH, 100);
#endif // __TEST__
    // NOTE ph max is X.XX, 4 digits
    ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, 3, y, "pH:", Font8x16);
    x = 29;
    // TODO confirm width to clear
    ReefAngel.LCD.Clear(DefaultBGColor, x, y, x+32, y+16);
    ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x, y, text, Font8x16);

    // Draw Salinity
#ifdef __TEST__
    strcpy(text, "35.0");
#else
    ConvertNumToString(text, ReefAngel.Params.Salinity, 10);
#endif // __TEST__
    // NOTE Salinity max is XX.X, 4 digits
    x = 69;
    // TODO confirm width to clear
    ReefAngel.LCD.Clear(DefaultBGColor, x, y, x+32, y+16);
    ReefAngel.LCD.DrawLargeText(COLOR_CRIMSON, DefaultBGColor, x, y, text, Font8x16);
    ReefAngel.LCD.DrawLargeText(COLOR_CRIMSON, DefaultBGColor, 102, y, "ppt", Font8x16);

    pingSerial();

    // Draw Water Level Box (used code from libraries)
    y = LINE3;
    // TODO determine color to use for WATER level (COLOR_ROYALBLUE)
    ReefAngel.LCD.DrawText(COLOR_ROYALBLUE, DefaultBGColor, 8, y, "Water");
#ifdef __TEST__
    t = 79;
#else
    t = ReefAngel.WaterLevel.GetLevel(0);
#endif  // __TEST__
    // sanity check, ensure level isn't greater than 100
    if(t > 100) {
        t = 100;
    }
    x = 99;
    // draw value to the right of the bar
    ReefAngel.LCD.DrawText(COLOR_ROYALBLUE, DefaultBGColor, 99, y, "    ");
    sprintf(text, "%d%%", t);
    ReefAngel.LCD.DrawText(COLOR_ROYALBLUE, DefaultBGColor, 99, y, text);
    // Water level is truncated to 50 pixels instead of 100
    // Every 2% equals 1 pixel
    // divide water level by 2
    t = t / 2;
    byte b;
    // draw the image to the left of the center line, filled bar background
    for(b = 0; b < t; b++)
    {
        // swidth,sheight, X, Y, img
        ReefAngel.LCD.DrawImage(1, 6, b + WL_BAR_OFFSET, y + 2, BAR_WL_LEFT);
    }
    // draw the center image, indicator
    ReefAngel.LCD.DrawImage(2, 6, t + WL_BAR_OFFSET, y + 2, BAR_CENTER);
    // draw the image to the right of the center line, unfilled bar background
    for(b = t; b < 50; b++)
    {
        ReefAngel.LCD.DrawImage(1, 6, b + WL_BAR_OFFSET + 2, y + 2, BAR_WL_RIGHT);
    }

    // Draw DC Pump Mode (next line)
    y = 88;
    x = 4;
    if (fNight) {
      t = DCPumpNightMode_read();
    } else {
      t = InternalMemory.DCPumpMode_read();
    }
    // copy the string from the global array into a buffer of 11 chars for display on screen
    PUMP_MODES[t].toCharArray(text, 11);
    // NOTE text is max of 11 chars, 11*5=55 pixels
    ReefAngel.LCD.Clear(DefaultBGColor, x, y, x+55, y+8);
    ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, x, y, text);

    // Draw Day/Night schedule (same line as pump mode)
    // NOTE Center text in available space between column 72 and 128
    if (fNight) {
      strcpy(text, "Night");
      b = COLOR_BLACK;
      t = COLOR_WHITE;
      x = 82;
    } else {
      strcpy(text, "Day");
      b = DefaultBGColor;
      t = COLOR_BLACK;
      x = 90;
    }
    // clear entire space with the background color
    // clear bigger space than just for the text to line up
    // the bottom of the square with the dc pump speed bar
    ReefAngel.LCD.Clear(b, 74, y, 128, y+18);
    ReefAngel.LCD.DrawLargeText(t, b, x, y+1, text, Font8x16);

    // Draw DC Pump Speed bar
    y = 98;
    x = 58;
#ifdef __TEST__
    t = 65;
#else
    t = ReefAngel.PWM.GetDaylightValue();
#endif  // __TEST__
    ReefAngel.LCD.Clear(DefaultBGColor, x, y, x+15, y+8);
    ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, x, y, t);
    // scale bar to be half width, divide value by 2
    t = t / 2;
    for(b = 0; b < t; b++)
    {
        ReefAngel.LCD.DrawImage(1, 6, b + DC_BAR_OFFSET, y + 2, BAR_DP_LEFT);
    }
    ReefAngel.LCD.DrawImage(2, 6, t + DC_BAR_OFFSET, y + 2, BAR_CENTER);
    for(b = t; b < 50; b++)
    {
        ReefAngel.LCD.DrawImage(1, 6, b + DC_BAR_OFFSET + 2, y + 2, BAR_DP_RIGHT);
    }

    // Draw outlet bar
    t = ReefAngel.Relay.RelayData;
    t &= ReefAngel.Relay.RelayMaskOff;
    t |= ReefAngel.Relay.RelayMaskOn;
    ReefAngel.LCD.DrawOutletBox(12, 112, t);

    pingSerial();
}

void DrawCustomGraph()
{
}

boolean isNightTime()
{
    boolean fResult = false;
    byte bOffHour = InternalMemory.StdLightsOffHour_read();
    byte bOffMinute = InternalMemory.StdLightsOffMinute_read();
    byte bOnHour = InternalMemory.StdLightsOnHour_read();
    byte bOnMinute = InternalMemory.StdLightsOnMinute_read();

    /*
    If current hour is off hour and current minute is equal or after off minute, night time is true
    if current hour is after off hour, night time is true
    (beyond midnight, aka early hours in morning, overnight wrap)
    if current hour is before on hour, night time is true
    if current hour is on hour and current minute is before off minute, night time is true
    */
    if ( ((hour() == bOffHour) && (minute() >= bOffMinute)) ||
         (hour() > bOffHour) ||
         (hour() < bOnHour) ||
         ((hour() == bOnHour) && (minute() < bOnMinute)) )
    {
        fResult = true;
    }

    return fResult;
}

void checkCustomMemoryValues()
{
    if ( DCPumpNightMode_read() > 14 )
    {
        // Default to Constant Mode
        CustomWrite(DCPUMP_NIGHT_MODE, 0);
    }
    if ( DCPumpNightSpeed_read() > 100 )
    {
        // Default to 0 speed
        CustomWrite(DCPUMP_NIGHT_SPEED, 0);
    }
    if ( DCPumpNightDuration_read() > 100 )
    {
        // Default to 0 duration
        CustomWrite(DCPUMP_NIGHT_DURATION, 0);
    }
    if ( DCPumpNightThreshold_read() > 100 )
    {
        // Default to 30 threshold
        CustomWrite(DCPUMP_NIGHT_THRESHOLD, 30);
    }
}

uint8_t DCPumpNightMode_read()
{
    return CustomRead(DCPUMP_NIGHT_MODE);
}

uint8_t DCPumpNightSpeed_read()
{
    return CustomRead(DCPUMP_NIGHT_SPEED);
}

uint8_t DCPumpNightDuration_read()
{
    return CustomRead(DCPUMP_NIGHT_DURATION);
}

uint8_t DCPumpNightThreshold_read()
{
    return CustomRead(DCPUMP_NIGHT_THRESHOLD);
}

uint8_t CustomRead(int address)
{
#if not defined __SAM3X8E__
    return eeprom_read_byte((unsigned char *) address);
#else
    return SPIEEPROM.Read(address);
#endif
}

void CustomWrite(int address, const uint8_t value)
{
    if (CustomRead(address) != value )
    {
#if not defined __SAM3X8E__
        eeprom_write_byte((unsigned char *) address, value);
#else
        SPIEEPROM.Write(address, value);
#endif
    }
}
Enjoy! :-)