My PDE w/ Custom Main

Share you PDE file with our community
Post Reply
StuGotz
Posts: 95
Joined: Sat Oct 15, 2011 9:17 am

My PDE w/ Custom Main

Post by StuGotz »

Here's my 1st attempt at a custom main screen. There's definitely some tweaking I still have to do. The Cloud/Thunderstorm effects line was a real pain, so I'm procrastinating on fixing that. I probably shouldn't have started there! The EcoSmart line is a placeholder until I get my RF Module :D

Image

And if anyone is interested in my current PDE...

Code: Select all

// Autogenerated file by RAGen (v1.0.4.92), (10/15/2011 12:40)
// RA_101511_1240.pde
//
// This version designed for v0.8.5 Beta 12 or later

/* The following features are enabled for this PDE File: 
#define SIMPLE_MENU
#define DisplayLEDPWM
#define wifi
#define VersionMenu
#define CUSTOM_MAIN
#define NUMBERS_8x16
#define COLORS_PDE
*/

#include <ReefAngel_Features.h>
#include <ReefAngel_Globals.h>
#include <ReefAngel_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <ReefAngel_EEPROM.h>
#include <ReefAngel_NokiaLCD.h>
#include <ReefAngel_ATO.h>
#include <ReefAngel_Joystick.h>
#include <ReefAngel_LED.h>
#include <ReefAngel_TempSensor.h>
#include <ReefAngel_Relay.h>
#include <ReefAngel_PWM.h>
#include <ReefAngel_Timer.h>
#include <ReefAngel_Memory.h>
#include <ReefAngel.h>
#include <ReefAngel_Colors.h>
#include <ReefAngel_CustomColors.h>

#define Sump                1
#define DosingPump2         2
#define Refugium            3
#define Daylight            4
#define Actinic             5
#define Skimmer             6
#define Heater              7
#define DosingPump1         8

//Cloud & Lightning effects
byte ActinicPWMValue=0;
byte DaylightPWMValue=0;
boolean ForceCloud=false;
//

void DrawCustomMain()
{
  ReefAngel.LCD.DrawText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 0, "                       "); //Top Banner
  ReefAngel.LCD.DrawText(COLOR_WHITE, COLOR_CORNFLOWERBLUE, 0, 2, " BioCube 14 Nano Reef  "); //Top Banner
  ReefAngel.LCD.DrawDate(6, 123);
  pingSerial();
  
  // Display Temp Text
  ReefAngel.LCD.DrawText(0,255,12,12,"Temp");
  
  // Display the T1 temp value 10,22
  char text[7];
  ConvertNumToString(text, ReefAngel.Params.Temp1, 10);
  ReefAngel.LCD.Clear(255, 0, 22, 50, 36);
  ReefAngel.LCD.DrawLargeText(COLOR_CORNFLOWERBLUE, 255, 10, 22, text, Num8x16);
  pingSerial();
  
  // Display pH Text
  ReefAngel.LCD.DrawText(0,255,100,12,"pH");
  
  // Display pH Value
  ConvertNumToString(text, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.Clear(255, 90, 22, 98, 36);
  ReefAngel.LCD.DrawLargeText(COLOR_CORNFLOWERBLUE, 255, 90, 22, text, Num8x16);
  pingSerial();
   
  // Display Actinic Percentage Text
  ReefAngel.LCD.DrawText(0,255,8,40,"Actinic %");
  
  // Display the Actinic PWM channel value at 90,40
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetActinicValue(),COLOR_CORNFLOWERBLUE, 90, 40, 1);
  
  // Display Daylight Percentage Text
  ReefAngel.LCD.DrawText(0,255,8,50,"Daylight %");
    
  // Display the Daylight PWM channel value at 90,50
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(),COLOR_CORNFLOWERBLUE, 90, 50, 1);
  
  // Display T2 Temp Text
  ReefAngel.LCD.DrawText(0,255,8,60,"Canopy Temp");
  
  // Display the T2 temperature value at 90,60
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp2, COLOR_CORNFLOWERBLUE, 90, 60, 10);
  
  // Display T3 Temp Text
  ReefAngel.LCD.DrawText(0,255,8,70,"Ambient Temp");
  
  // Display the T3 temperature at 90,70
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp3, COLOR_CORNFLOWERBLUE, 90, 70, 10);
  
  // Display Vortech MP10ew Mode Text at 90, 80
  ReefAngel.LCD.DrawText(0,255,8,80,"EcoSmart Mode");
  
  // Display EcoSmart Mode Value
  ReefAngel.LCD.DrawText(COLOR_CORNFLOWERBLUE,255,90,80,"Storm");
  
  //#if defined DisplayLEDPWM && ! defined RemoveAllLights
    //ReefAngel.LCD.DrawMonitor(11, 60, ReefAngel.Params,
    //ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue());
  //#else // defined DisplayLEDPWM && ! defined RemoveAllLights
    //ReefAngel.LCD.DrawMonitor(11, 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(13, 97, TempRelay);
}
void DrawCustomGraph()
{
 // ReefAngel.LCD.DrawGraph(5,7);
}

void setup()
{
  ReefAngel.Init();  //Initialize controller
  ReefAngel.FeedingModePorts = B00100001; //Ports 6 & 1 turn off
  ReefAngel.WaterChangePorts = B00100001; //Ports 6 & 1 turn off
  ReefAngel.OverheatShutoffPorts = B00011000; //Ports 4 & 5 turn off
  ReefAngel.LightsOnPorts = B00011000; //Ports 4 & 5 turn on

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

void loop()
{
  ReefAngel.ShowInterface();
  
  // Delay Skimmer port 5 minutes whenever turned on
  // From Curt - THANKS CURT!
  ReefAngel.Relay.DelayedOn(Port6, 5);
  
  //Heater    
  ReefAngel.StandardHeater(Heater,775,780);  // Setup Heater to turn on at 77.5F and off at 78.0F
 
  //Lighting schedule
  ReefAngel.MHLights(Daylight,9,0,17,0,0);  //Daylight schedule 9:00am - 5:00pm with 0min cool down
  ReefAngel.StandardLights(Actinic,7,0,19,0);  //Actinic schedule 7:00am - 7:00pm
  ReefAngel.StandardLights(Refugium,19,0,7,0);  //Refugium schedule 7:00pm - 7:00am
  
  // Dosing pumps (OLD DOSING METHOD OF PUMP ONE ON THE HOUR, THEN PUMP2 5 MIN LATER - to use when tank is more mature
  //From Roberto - THANKS ROBERTO!
   /* if (ReefAngel.DisplayedMenu==255 && minute()==0 && second()<1)  //Alk Doser - Only works if Main screen is showing
      ReefAngel.Relay.On(DosingPump1);  //Turn Alk Doser on
    else
      ReefAngel.Relay.Off(DosingPump1);  //Turn Alk Doser off
    if (ReefAngel.DisplayedMenu==255 && minute()==5 && second()<1)  //CA Doser - Only works if Main screen is showing
      ReefAngel.Relay.On(DosingPump2);  //Turn CA Doser on
    else
      ReefAngel.Relay.Off(DosingPump2);  //Turn CA Doser off 
   */
 
  // Dosing pumps
  // From Roberto - THANKS ROBERTO!
  
  if (ReefAngel.DisplayedMenu==255 && hour()%2==0 && minute()==0 && second()<1) // 1 sec dosing on even hours
    ReefAngel.Relay.On(DosingPump1);  //Turn DosingPump1 Doser on
  else
    ReefAngel.Relay.Off(DosingPump1);  //Turn DosingPump1 Doser off
  if (ReefAngel.DisplayedMenu==255 && hour()%2==1 && minute()==0 && second()<1) // 1 sec dosing on odd hours
    ReefAngel.Relay.On(DosingPump2);  //Turn DosingPump2 Doser on
  else
    ReefAngel.Relay.Off(DosingPump2);  //Turn DosingPump2 Doser off

  // Cloud & Lightning effects - Calculate your regular sunrise/sunset PWM value
  // From Roberto - THANKS ROBERTO!
  // byte PWMSlope(byte startHour, byte startMinute, byte endHour, byte endMinute, byte startPWM, byte endPWM, byte Duration, byte oldValue)
  if (hour()>=19 || hour()<7)
    {
      ReefAngel.PWM.SetActinic(MoonPhase());  //Moon phase schedule between 7:00pm - 7:00am
    }
  else
    {
      ActinicPWMValue=PWMSlope(7,00,19,0,0,35,60,ActinicPWMValue); //Actinic turn on at 7am, off at 10am, and ramp up 0% to 50% PWM in 60 minutes
      //ActinicPWMValue=PWMSlope(16,00,19,0,0,50,60,ActinicPWMValue); //Actinic turn on at 4pm, off at 7pm, and ramp up 0% to 50% PWM in 60 minutes
      ReefAngel.PWM.SetActinic(ActinicPWMValue);
    }
  DaylightPWMValue=PWMSlope(9,00,17,0,0,75,60,DaylightPWMValue); //Daylight turn on at 9am, off at 5pm, and ramp up 0% to 50% PWM in 60 minutes
  CheckCloud(); 
  ReefAngel.PWM.SetDaylight(DaylightPWMValue);
}

//*********************************************************************************************************************************
// 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_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 6

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

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

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

  // Note: Make sure to choose correct values that will work within your PWMSLope settings.
  // For example, in our case, we could have a max of 5 clouds per day and they could last for 50 minutes.
  // Which could mean 250 minutes of clouds. We need to make sure the PWMSlope can accomodate 250 minutes of effects or unforseen result 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;
      }
    }
  
  //When cusotm menu Force cloud is selected
  if (ForceCloud)
  {
    ForceCloud=false;
    cloudchance=1;
    cloudduration=10;
    lightningchance=1;
    cloudstart=NumMins(hour(),minute())+1;
  }
  
  // Now that we have all the parameters for the cloud, let's create the effect
  if (cloudchance)
  {
    //is it time for cloud yet?
    if (NumMins(hour(),minute())>=cloudstart && NumMins(hour(),minute())<(cloudstart+cloudduration))
    {
      DaylightPWMValue=ReversePWMSlope(cloudstart,cloudstart+cloudduration,DaylightPWMValue,0,180);
      if (lightningchance && (NumMins(hour(),minute())==(cloudstart+(cloudduration/2))) && second()<5) 
      {
        if (random(100)<20) lightningstatus=1; 
        else lightningstatus=0;
        if (lightningstatus)
        {
          DaylightPWMValue=100; 
          ActinicPWMValue=100;
        }
        else 
        {
          DaylightPWMValue=0;
          ActinicPWMValue=0;
        }
        delay(1);
      }
    }
    if (NumMins(hour(),minute())>(cloudstart+cloudduration))
    {
      cloudindex++;
      if (cloudindex < numclouds)
      {
        cloudstart=random(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2),(Start_Cloud_After+(((End_Cloud_Before-Start_Cloud_After)/(numclouds*2))*cloudindex*2))+((End_Cloud_Before-Start_Cloud_After)/(numclouds*2)));
        // pick a random number for the cloud duration of first cloud.
        cloudduration=random(Min_Cloud_Duration,Max_Cloud_Duration);
        //Pick a random number between 0 and 99
        lightningchance=random(100);
        // if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
        if (lightningchance>Lightning_Change_per_Cloud) lightningchance=0;
      }
    }
  }

  if (LastNumMins!=NumMins(hour(),minute()))
  {
    LastNumMins=NumMins(hour(),minute());
    ReefAngel.LCD.Clear(255,0,113,132,121);
    ReefAngel.LCD.DrawText(0,255,12,113,"C");
    ReefAngel.LCD.DrawText(0,255,18,113,"00:00");
    ReefAngel.LCD.DrawText(0,255,52,113,"L");
    ReefAngel.LCD.DrawText(0,255,58,113,"00:00");
    ReefAngel.LCD.DrawText(0,255,93,113,"DUR");
    if (cloudchance && (NumMins(hour(),minute())<cloudstart))
    {
      int x=0;
      if ((cloudstart/60)>=10) x=18; 
      else x=24;
      ReefAngel.LCD.DrawText(0,255,x,113,(cloudstart/60));
      if ((cloudstart%60)>=10) x=36; 
      else x=42;
      ReefAngel.LCD.DrawText(0,255,x,113,(cloudstart%60));
    }
    ReefAngel.LCD.DrawText(0,255,114,113,cloudduration);
    if (lightningchance) 
    {
      int x=0;
      if (((cloudstart+(cloudduration/2))/60)>=10) x=88; 
      else x=94;
      ReefAngel.LCD.DrawText(0,255,x,113,((cloudstart+(cloudduration/2))/60));
      if (((cloudstart+(cloudduration/2))%60)>=10) x=109; 
      else x=112;
      ReefAngel.LCD.DrawText(0,255,x,113,((cloudstart+(cloudduration/2))%60));
    }
  }   
}

byte ReversePWMSlope(long cstart,long cend,byte PWMStart,byte PWMEnd, byte clength)
{
  long n=elapsedSecsToday(now());
  cstart*=60;
  cend*=60;
  if (n<cstart) return PWMStart;
  if (n>=cstart && n<=(cstart+clength)) return map(n,cstart,cstart+clength,PWMStart,PWMEnd);
  if (n>(cstart+clength) && n<(cend-clength)) return PWMEnd;
  if (n>=(cend-clength) && n<=cend) return map(n,cend-clength,cend,PWMEnd,PWMStart);
  if (n>cend) return PWMStart;
  //End Cloud & Lighting 
}
I welcome any and all suggestions!
Last edited by StuGotz on Sun Dec 18, 2011 4:29 pm, edited 1 time in total.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: My PDE w/ Custom Main

Post by rimai »

Nice :)
Roberto.
StuGotz
Posts: 95
Joined: Sat Oct 15, 2011 9:17 am

Re: My PDE w/ Custom Main

Post by StuGotz »

Thanks Roberto! It didn't look like the DrawDate Function supported font colors. Can I just use ConvertNumToString to convert the value to a string and use ReefAngel.LCD.DrawText to make it the color I want?
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: My PDE w/ Custom Main

Post by rimai »

Yeah, you can.
Roberto.
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: My PDE w/ Custom Main

Post by binder »

Looks pretty sweet.

The DrawDate function does not support font colors, but there is a way to change the font with it. This way includes the ability to change a lot of the default colors.

http://forum.reefangel.com/viewtopic.ph ... olors#p653

Halfway down in the original post, there is an example about using the ReefAngel_CustomColors.h file. This file will allow you to alter the "default" colors to whatever you want without altering the libraries and preserving your changes through code (library) updates. The line you will want to focus on is this one:

Code: Select all

#define DateTextColor       COLOR_RED  // color of the date on home screen
Then, when you alter that line, you will be able to use the DrawDate function and not have to "re-invent" the wheel to get a different color date & time.

Let me know if you have more questions about it.

curt
StuGotz
Posts: 95
Joined: Sat Oct 15, 2011 9:17 am

Re: My PDE w/ Custom Main

Post by StuGotz »

Sweet, that did the trick. So when I update my libraries, ReefAngel_CustomColors.h will not be overwritten, like how the ReefAngel_Features.h is no longer overwritten?
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: My PDE w/ Custom Main

Post by binder »

StuGotz wrote:Sweet, that did the trick. So when I update my libraries, ReefAngel_CustomColors.h will not be overwritten, like how the ReefAngel_Features.h is no longer overwritten?
It "shouldn't" be overwritten. I do not know what the updater does when it updates the libraries. Roberto may have to update his utility to not overwrite that file too. I would suggest making a copy of it to be on the safe side at least.

curt
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: My PDE w/ Custom Main

Post by rimai »

I just updated the utility to check for this file too. :)
Roberto.
Post Reply