Got my controller,

New members questions
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Got my controller,

Post by rimai »

Roberto.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Got my controller,

Post by lnevo »

Yes only with the app. It does like half the screen..
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Got my controller,

Post by lnevo »

Ok, have some bug fixes and some cleanup. My Vortech's were going in and out of night mode all night because of how I was setting the timer. I hope this resolves it. I also implemented the SunLocation class that binder put together from the code I scraped together. Deails on that class are located on this post (with fixes) http://forum.reefangel.com/viewtopic.php?p=14508#p14508

I have one issue still.. I'm trying to add a menu option to toggle the refugium light.. not working as I'd hope. If there is a simple way to do it, I'd be grateful :)

Thanks and Enjoy

Code: Select all

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

////// Place global variable code below here
#define CUSTOM_MENU
#define CUSTOM_MENU_ENTRIES   8
#define NUMBERS_8x16

// Custom Menu Code
#include <avr/pgmspace.h>
prog_char menu1_label[] PROGMEM = "Feeding";
prog_char menu2_label[] PROGMEM = "Water Change";
prog_char menu3_label[] PROGMEM = "Vortech Mode";
prog_char menu4_label[] PROGMEM = "Refugium Light";
prog_char menu5_label[] PROGMEM = "ATO Clear";
prog_char menu6_label[] PROGMEM = "PH Calibration";
prog_char menu7_label[] PROGMEM = "Date / Time";
prog_char menu8_label[] PROGMEM = "Version";

// Group the menu entries together
PROGMEM const char *menu_items[] = {
menu1_label, menu2_label, menu3_label,
menu4_label, menu5_label, menu6_label,
menu7_label, menu8_label
};

// Vortech Defaults
byte vtMode=Random2;
byte vtSpeed=45;
byte vtDuration=5;

byte vtNTMSpeed=65;
byte vtNTMDuration=5;
byte vtNightSpeed=10;
byte vtNightDuration=20;

byte vtPrevMode;
byte vtPrevSpeed;
byte vtPrevDuration;

boolean isNight=false;
boolean isFeeding=false;
boolean vtOverride=false;

SunLocation sl;
byte SunriseHour, SunriseMin, SunsetHour, SunsetMin;

//Define Relay Ports
#define Return             1
#define Skimmer            2
#define WhiteLEDs          3
#define BlueLEDs           4
#define UPS                5
#define Heater             6
#define Refugium           7
#define Vortech            8

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

// Setup on controller startup/reset
void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Initialize Menu
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));

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

    // Ports that are always on
    ReefAngel.Relay.On( Return );
    ReefAngel.Relay.On( Vortech );
    ReefAngel.Relay.On( UPS );
    
    ////// Place additional initialization code below here

    // Setup SunLocation class
    sl.Init(-18.285833, 147.699722);
    sl.SetOffset(-9,472,-9,506);
    
    // Save previous used vortech mode.
    vtPrevMode=InternalMemory.RFMode_read();
    vtPrevSpeed=InternalMemory.RFSpeed_read();
    vtPrevDuration=InternalMemory.RFDuration_read();
    
    ////// Place additional initialization code above here
}

void loop()
{
    ReefAngel.Relay.DelayedOn( Skimmer, 20 );
    ReefAngel.StandardHeater( Heater,778,782 );
    
    ////// Place your custom code below here
    sl.CheckAndUpdate();
    
    SunriseHour=sl.GetRiseHour(); SunriseMin=sl.GetRiseMinute();
    SunsetHour=sl.GetSetHour(); SunsetMin=sl.GetSetMinute();
    
    // Send the SunLocation info to the portal
    ReefAngel.CustomVar[0]=SunriseHour; ReefAngel.CustomVar[1]=SunriseMin;
    ReefAngel.CustomVar[2]=SunsetHour; ReefAngel.CustomVar[3]=SunsetMin;

    // Turn the lights on
    ReefAngel.StandardLights( WhiteLEDs,SunriseHour+1,SunriseMin,SunsetHour-3, SunsetMin );
    ReefAngel.StandardLights( BlueLEDs,SunriseHour,SunriseMin,SunsetHour,SunsetMin );

    // Let's make the time one number so we can figure out it's night or day...
    int currTime = hour()*100+minute();
    int riseTime=SunriseHour*100+SunriseMin; 
    int setTime=SunsetHour*100+SunsetMin;
    
    if ( (currTime <= riseTime) || (currTime >= setTime) ) isNight=true; else isNight=false;

    if (isNight) 
    {
      ReefAngel.PWM.SetDaylight( MoonPhase() );
      ReefAngel.PWM.SetActinic( MoonPhase() );
      ReefAngel.Relay.On( Refugium );
      
      if (vtOverride==false && isFeeding==false) {
        setRFmode(Night,vtNightSpeed,vtNightDuration);
      }
    } else { 
      // It's Daytime!
      ReefAngel.PWM.SetDaylight( 0 );
      ReefAngel.PWM.SetActinic( 0 );
     
      ReefAngel.Relay.Off( Refugium );
      
      if (vtOverride==false && vtMode==Night) {
        setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
      }
    }   

    if (ReefAngel.DisplayedMenu==FEEDING_MODE) isFeeding=true;
    if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE) ReefAngel.Relay.On( Refugium );
 
    if (ReefAngel.DisplayedMenu==DEFAULT_MENU && isFeeding )
    {
      isFeeding=false;
      setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration);
    }

    if (vtOverride && ReefAngel.Timer[1].IsTriggered()) 
    {
      vtOverride=false;
      setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
    } else {
      setRFmode(); // Update if set externally
    }

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

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

// Vortech Helper functions
void setRFmode(int mode, int speed, int duration) {

  // Check if mode has changed
  if (mode!=vtMode) {  
    vtPrevMode=vtMode;
    vtMode=mode; 
  
    if (mode!=InternalMemory.RFMode_read()) { 
      InternalMemory.RFMode_write(mode);
    }
    
    // Temp fix for coming out of night mode
    if (vtPrevMode==Night) {
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Feeding_Stop,0,0);
      ReefAngel.RF.UseMemory=true;
    }
    
    if ( (isNight && vtMode != Night) || vtMode==Smart_NTM) {
      setRFtimer(30);
    }
  } 

  // Check if speed has changed
  if (speed!=vtSpeed) {  
    vtPrevSpeed=vtSpeed;
    vtSpeed=speed;
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    } 
  }

  // Check if duration has changed
  if (duration!=vtDuration) {  
    vtPrevDuration=vtDuration;
    vtDuration=duration; 
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    }
  }
}
void setRFmode() {
  setRFmode(InternalMemory.RFMode_read(), InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
}
void setRFtimer(int minutes) {
  ReefAngel.Timer[1].SetInterval(minutes*60);
  ReefAngel.Timer[1].Start();
  vtOverride=true;
}

// Menu Code
void MenuEntry1()
{
  ReefAngel.FeedingModeStart();
}
void MenuEntry2()
{
  ReefAngel.WaterChangeModeStart();
}
void MenuEntry3()
{
  byte mode, speed,duration;
  mode=vtMode;
  mode++;
  
  if (mode > 9 ) { 
    mode=0; 
    speed=50; duration=0; // Constant
  } else if (mode == 1) { 
    speed=40; duration=0; // Lagoon
  } else if (mode == 2) { 
    speed=45; duration=0; // Reef Crest
  } else if (mode == 3) {  
    speed=50; duration=10; // Short Pulse
  } else if (mode == 4) {
    speed=50; duration=20; // Long Pulse
  } else if (mode == 6) {
    speed=45; duration=10; // Smart_TSM
  } else if (mode == 5) {
    speed=vtNTMSpeed; duration=vtNTMDuration; // Smart_NTM
  } else if (mode == 7) {
    speed=vtNightSpeed; duration=vtNightDuration; // Night
    mode=9; 
  }  

  setRFmode(mode,speed,duration);
  
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}
void MenuEntry4()
{
  ReefAngel.Relay.Toggle ( Refugium );
  
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}
void MenuEntry5()
{
  ReefAngel.ATOClear();
  ReefAngel.DisplayMenuEntry("Clear ATO Timeout");
}
void MenuEntry6()
{
  ReefAngel.SetupCalibratePH();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
  ReefAngel.SetupDateTime();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry8()
{
  ReefAngel.DisplayVersion();
}

// Custom Main Screen
void DrawCustomMain()
{
  char buf[16];
  byte x = 5;
  byte y = 2;
  byte t;

  if (isFeeding) { ReefAngel.ClearScreen(DefaultBGColor); return; }

  // Main Header
  ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 35, y,"Lee's Reef");
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, y+9, 128, y+9);

  // Param Header
  y+=18; 
  ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,x+5,y,"Temp:");
  ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,x+60, y, "PH:");

  // Temp and PH
  y+=8; 
  ConvertNumToString(buf, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(T1TempColor, DefaultBGColor, x+5, y, buf, Num8x16);
  ConvertNumToString(buf, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+60, y, buf, Num8x16);
  pingSerial();
  
  /// Display Sunrise / Sunset (to be calculated later...)
  y+=20; t=x;
  sprintf(buf, "%02d:%02d", SunriseHour, SunriseMin);
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Rise:"); t+=31;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf); 
  sprintf(buf, "%02d:%02d", SunsetHour, SunsetMin); t+=36;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Set:"); t+=25;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf);

  // MoonPhase
  y+=10; 
  ReefAngel.LCD.DrawText(0,255,x,y,"Moon:");
  ReefAngel.LCD.Clear(DefaultBGColor,x+32,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_MAGENTA,255,x+32,y,MoonPhaseLabel());
  pingSerial();
  
  // MoonLight %
  y+=10;
  t = intlength(ReefAngel.PWM.GetDaylightValue()) + 1;  t *= 5;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MoonLights:"); 
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(), DPColor, x+68, y, 1);
  ReefAngel.LCD.DrawText(DPColor, DefaultBGColor, x+68+t, y, "%");
  pingSerial();

  // Vortech Mode
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF:"); t+=20;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  if (vtMode == 0) ReefAngel.LCD.DrawLargeText(COLOR_GREEN,255,t,y,"Constant");
  else if(vtMode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Lagoon");
  else if (vtMode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Reef Crest");
  else if (vtMode == 3) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Short Pulse");
  else if (vtMode == 4) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Long Pulse");
  else if (vtMode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Smart NTM");
  else if (vtMode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Tidal Swell");
  else if (vtMode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,0,t,y,"Night");
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF Speed:"); t+=60;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFSpeed_read()); t+=15;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,"/"); t+=10;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFDuration_read());
  pingSerial();
  
  // Relays
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 103, TempRelay);
  pingSerial();
  
  // Date+Time
  ReefAngel.LCD.DrawDate(6, 122);
  pingSerial();
}

void DrawCustomGraph()
{
}
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Got my controller,

Post by rimai »

lnevo wrote:Also, sometimes when going into feeding mode, the LCD does not clear completely even though i added a flag to return and clearscreen in my CustomMain.
Can you help me replicate this issue?
I was unable to do so...
I'd like to fix in the libraries, but I can't get it to do that.
Roberto.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Got my controller,

Post by lnevo »

I'll take a few more peaks the next few feedings and see if I'm still experiencing it. If you have any troubleshooting you'd like me to try... You could also run my code (but now you'll need the SunLocation class :) ) as a test...if I'm just crazy...
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Got my controller,

Post by lnevo »

Modified my code to use heater temp settings from memory so I can modify without changing code. I also added a function to the SunLocation class so I can have my lighting times controlled by memory. I'll be posting that separately. I also added my float switches and set the Low to turn off my pump / skimmer when the water level in the return chamber gets too low (drain problem, ato problem?). The high I am using to send me an alert if something happens and the sump gets too full (return pump issue, return line obstruction...) Next up waiting for my water level sensor and I'll be able to monitor my ATO reservoir.

Edit: Needed to add a flag instead of just checking the mode, otherwise it would never turn return pumps back on after water change / feeding mode... The flag is used if triggered, mode change, or controller restart and is reset once the HighATO.IsActive function comes up false. This way it's only disabled once and not when we trigger it on purpose.

Here's the code.

Code: Select all

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

////// Place global variable code below here
#define CUSTOM_MENU
#define CUSTOM_MENU_ENTRIES   8
#define NUMBERS_8x16

// Custom Menu Code
#include <avr/pgmspace.h>
prog_char menu1_label[] PROGMEM = "Feeding";
prog_char menu2_label[] PROGMEM = "Water Change";
prog_char menu3_label[] PROGMEM = "Vortech Mode";
prog_char menu4_label[] PROGMEM = "Refugium Light";
prog_char menu5_label[] PROGMEM = "ATO Clear";
prog_char menu6_label[] PROGMEM = "PH Calibration";
prog_char menu7_label[] PROGMEM = "Date / Time";
prog_char menu8_label[] PROGMEM = "Version";

// Group the menu entries together
PROGMEM const char *menu_items[] = {
menu1_label, menu2_label, menu3_label,
menu4_label, menu5_label, menu6_label,
menu7_label, menu8_label
};

// Vortech Defaults
byte vtPrevMode=0;
byte vtPrevSpeed=0;
byte vtPrevDuration=0;

byte vtMode=Random2;
byte vtSpeed=45;
byte vtDuration=5;

byte vtNTMSpeed=55;
byte vtNTMDuration=5;
byte vtNightSpeed=10;
byte vtNightDuration=20;

boolean isNight=false;
boolean isFeeding=false;
boolean vtOverride=false;
boolean activatedHighATO=true;

SunLocation sl;

//Define Relay Ports
#define Return             1
#define Skimmer            2
#define WhiteLEDs          3
#define BlueLEDs           4
#define UPS                5
#define Heater             6
#define Refugium           7
#define Vortech            8

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

// Setup on controller startup/reset
void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Initialize Menu
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));

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

    // Ports that are always on
    ReefAngel.Relay.On( Return );
    ReefAngel.Relay.On( Vortech );
    ReefAngel.Relay.On( UPS );
    
    ////// Place additional initialization code below here

    // Setup SunLocation class
    sl.Init(-18.285833, 147.699722); // GBR
    sl.SetOffset(-9,472,-9,506); // 9 hour difference
    
    // Save previous used vortech mode.
    vtPrevMode=InternalMemory.RFMode_read();
    vtPrevSpeed=InternalMemory.RFSpeed_read();
    vtPrevDuration=InternalMemory.RFDuration_read();
        
    ////// Place additional initialization code above here
}

void loop()
{
    ReefAngel.Relay.DelayedOn( Skimmer, 5 );
    ReefAngel.StandardHeater( Heater );
    
    ////// Place your custom code below here
    sl.CheckAndUpdate();
        
    // Turn on the lights   
    ReefAngel.StandardLights( WhiteLEDs );
    ReefAngel.ActinicLights( BlueLEDs );

    // Let's make the time one number so we can figure out it's night or day...
    int currTime=NumMins(hour(),minute());
    int riseTime=NumMins(sl.GetRiseHour(),sl.GetRiseMinute()); 
    int setTime=NumMins(sl.GetSetHour(),sl.GetSetMinute());
    
    if ( (currTime <= riseTime) || (currTime >= setTime) ) isNight=true; else isNight=false;

    if (isNight) 
    {
      ReefAngel.PWM.SetDaylight( MoonPhase() );
      ReefAngel.PWM.SetActinic( MoonPhase() );
      ReefAngel.Relay.On( Refugium );
      
      if (vtOverride==false && isFeeding==false) {
        setRFmode(Night,vtNightSpeed,vtNightDuration);
      }
      
      // Trigger night mode again to extend built-in timer
      if ( ((hour() == 6) && (minute() == 00) && (second() == 00) ) ) {
        setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
      }
    } else { 
      // It's Daytime!
      ReefAngel.PWM.SetDaylight( 0 );
      ReefAngel.PWM.SetActinic( 0 );
     
      ReefAngel.Relay.Off( Refugium );
      
      if (vtOverride==false && vtMode==Night) {
        setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
        ReefAngel.Timer[1].ForceTrigger();
      }
    }   

    if (ReefAngel.DisplayedMenu==FEEDING_MODE) isFeeding=true;
    if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE) ReefAngel.Relay.On( Refugium );
    if (ReefAngel.DisplayedMenu==FEEDING_MODE || ReefAngel.DisplayedMenu==WATERCHANGE_MODE) activatedHighATO=true;
    
    if (ReefAngel.DisplayedMenu==DEFAULT_MENU && isFeeding )
    {
      isFeeding=false; 
      setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration);
    } 
    else if (vtOverride && ReefAngel.Timer[1].IsTriggered()) 
    {
      vtOverride=false;
      setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
    } 
    else 
    {
      setRFmode(); // Update if set externally
    }

    if ( ((hour() == 15) && (minute() == 00) && (second() == 00) ) ) {
      setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration);
    }
    
    if (ReefAngel.LowATO.IsActive()) {
      bitClear(ReefAngel.Relay.RelayMaskOff,Return-1);
      bitClear(ReefAngel.Relay.RelayMaskOff,Skimmer-1);
    } 
 
    if (ReefAngel.HighATO.IsActive()) {
      if (!activatedHighATO) {
        activatedHighATO=true;
        ReefAngel.CustomVar[0]=2;
        bitClear(ReefAngel.Relay.RelayMaskOff,Return-1);
        bitClear(ReefAngel.Relay.RelayMaskOff,Skimmer-1);  
      }  
    } else {
      ReefAngel.CustomVar[0]=1;
      activatedHighATO=false;
    }  
      
    // Turn off Skimmer if Return pump is shutoff.   
    if (bitRead(ReefAngel.Relay.RelayMaskOff,Return-1)==0) {
      bitClear(ReefAngel.Relay.RelayMaskOff,Skimmer-1);
    }
    
    ////// Place your custom code above here

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

// Vortech Helper functions
void setRFmode(int mode, int speed, int duration) {

  // Check if mode has changed
  if (mode!=vtMode) {  
    vtPrevMode=vtMode;
    vtMode=mode; 
  
    if (mode!=InternalMemory.RFMode_read()) { 
      InternalMemory.RFMode_write(mode);
    }
    
    // Temp fix for coming out of night mode
    if (vtPrevMode==Night) {
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Feeding_Stop,0,0);
      ReefAngel.RF.UseMemory=true;
    }
    
    if ( (isNight && vtMode != Night) || vtMode==Smart_NTM) {
      setRFtimer(30);
    }
  } 

  // Check if speed has changed
  if (speed!=vtSpeed) {  
    vtPrevSpeed=vtSpeed;
    vtSpeed=speed;
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    } 
  }

  // Check if duration has changed
  if (duration!=vtDuration) {  
    vtPrevDuration=vtDuration;
    vtDuration=duration; 
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    }
  }
}
void setRFmode() {
  setRFmode(InternalMemory.RFMode_read(), InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
}
void setRFtimer(int minutes) {
  ReefAngel.Timer[1].SetInterval(minutes*60);
  ReefAngel.Timer[1].Start();
  vtOverride=true;
}

// Menu Code
void MenuEntry1()
{
  ReefAngel.FeedingModeStart();
}
void MenuEntry2()
{
  ReefAngel.WaterChangeModeStart();
}
void MenuEntry3()
{
  byte mode,speed,duration,prev_mode,prev_speed,prev_dur;
  mode=vtMode;
  mode++;
  
  if (mode > 9 ) { 
    mode=0; 
    speed=50; duration=0; // Constant
  } else if (mode == 1) { 
    speed=40; duration=0; // Lagoon
  } else if (mode == 2) { 
    speed=45; duration=0; // Reef Crest
  } else if (mode == 3) {  
    speed=50; duration=10; // Short Pulse
  } else if (mode == 4) {
    speed=50; duration=20; // Long Pulse
  } else if (mode == 6) {
    speed=45; duration=10; // Smart_TSM
  } else if (mode == 5) {
    speed=vtNTMSpeed; duration=vtNTMDuration; // Smart_NTM
  } else if (mode == 7) {
    speed=vtNightSpeed; duration=vtNightDuration; // Night
    mode=9; 
  }  

  prev_mode=vtPrevMode; prev_speed=vtPrevSpeed; prev_dur=vtPrevDuration;
  setRFmode(mode,speed,duration);
  
  if (!isNight) {
    vtPrevMode=prev_mode; vtPrevSpeed=prev_speed; vtPrevDuration=prev_dur;
  }
  
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}
void MenuEntry4()
{
  if (isNight) {
    if (bitRead(ReefAngel.Relay.RelayMaskOff,Refugium-1)==1) {
      bitClear(ReefAngel.Relay.RelayMaskOff,Refugium-1);
    } else {
      bitSet(ReefAngel.Relay.RelayMaskOff,Refugium-1);
    }
  } else { 
    if (bitRead(ReefAngel.Relay.RelayMaskOn,Refugium-1)==1) {
      bitClear(ReefAngel.Relay.RelayMaskOn,Refugium-1);
    } else {
      bitSet(ReefAngel.Relay.RelayMaskOn,Refugium-1);
    }
  }
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}
void MenuEntry5()
{
  ReefAngel.ATOClear();
  ReefAngel.DisplayMenuEntry("Clear ATO Timeout");
}
void MenuEntry6()
{
  ReefAngel.SetupCalibratePH();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
  ReefAngel.SetupDateTime();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry8()
{
  ReefAngel.DisplayVersion();
}

// Custom Main Screen
void DrawCustomMain()
{
  char buf[16];
  byte x = 5;
  byte y = 2;
  byte t;

  if (isFeeding) { ReefAngel.ClearScreen(DefaultBGColor); return; }

  // Main Header
  ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 35, y,"Lee's Reef");
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, y+9, 128, y+9);

  // Param Header
  y+=18; 
  ReefAngel.LCD.DrawText(T1TempColor,DefaultBGColor,x+5,y,"Temp:");
  ReefAngel.LCD.DrawText(PHColor,DefaultBGColor,x+60, y, "PH:");

  // Temp and PH
  y+=8; 
  ConvertNumToString(buf, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(T1TempColor, DefaultBGColor, x+5, y, buf, Num8x16);
  ConvertNumToString(buf, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+60, y, buf, Num8x16);
  pingSerial();
  
  /// Display Sunrise / Sunset (to be calculated later...)
  y+=20; t=x;
  sprintf(buf, "%02d:%02d", sl.GetRiseHour(), sl.GetRiseMinute());
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Rise:"); t+=31;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf); 
  sprintf(buf, "%02d:%02d", sl.GetSetHour(), sl.GetSetMinute()); t+=36;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Set:"); t+=25;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf);

  // MoonPhase
  y+=10; 
  ReefAngel.LCD.DrawText(0,255,x,y,"Moon:");
  ReefAngel.LCD.Clear(DefaultBGColor,x+32,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_MAGENTA,255,x+32,y,MoonPhaseLabel());
  pingSerial();
  
  // MoonLight %
  y+=10;
  t = intlength(ReefAngel.PWM.GetDaylightValue()) + 1;  t *= 5;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MoonLights:"); 
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(), DPColor, x+68, y, 1);
  ReefAngel.LCD.DrawText(DPColor, DefaultBGColor, x+68+t, y, "%");
  pingSerial();

  // Vortech Mode
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF:"); t+=20;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  if (vtMode == 0) ReefAngel.LCD.DrawLargeText(COLOR_GREEN,255,t,y,"Constant");
  else if(vtMode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Lagoon");
  else if (vtMode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Reef Crest");
  else if (vtMode == 3) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Short Pulse");
  else if (vtMode == 4) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Long Pulse");
  else if (vtMode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Smart NTM");
  else if (vtMode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Tidal Swell");
  else if (vtMode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,0,t,y,"Night");
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF Speed:"); t+=60;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFSpeed_read()); t+=15;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,"/"); t+=10;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFDuration_read());
  pingSerial();
  
  // Relays
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, 103, TempRelay);
  pingSerial();
  
  // Date+Time
  ReefAngel.LCD.DrawDate(6, 122);
  pingSerial();
}

void DrawCustomGraph()
{
}
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Got my controller,

Post by lnevo »

Added my relay expansion yesterday. Lot's of new additions to the code. The following features have been added:

Vacation Mode - Use WL sensor and turn the extension cord I have plugged in, into an ATO port
ATO Refill - Use WL sensor to fill my ATO reservoir to 100%
Power Outage detection - Turn off all unnecessary items if we lose power.
Complete Darkness - Added 2 hours without moonlghts to my schedule
Smart_NTM Delay - Added a delay after feeding mode before Smart_NTM is activated
Dosing Pumps - Added these, but I need to get better pumps ;)
Coral Acclimation Schedule - Need to test this, but should be working good.

Code: Select all

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

////// Place global variable code below here
#define CUSTOM_MENU
#define CUSTOM_MENU_ENTRIES   8
#define NUMBERS_8x16

// Custom Menu Code
#include <avr/pgmspace.h>
prog_char menu1_label[] PROGMEM = "Feeding";
prog_char menu2_label[] PROGMEM = "Water Change";
prog_char menu3_label[] PROGMEM = "Vortech Mode";
prog_char menu4_label[] PROGMEM = "Refugium Light";
prog_char menu5_label[] PROGMEM = "Clear Overrides";
prog_char menu6_label[] PROGMEM = "PH Calibration";
prog_char menu7_label[] PROGMEM = "WLS Calibration";
prog_char menu8_label[] PROGMEM = "Date / Time";
prog_char menu9_label[] PROGMEM = "Version";

// Group the menu entries together
PROGMEM const char *menu_items[] = {
menu1_label, menu2_label, menu3_label,
menu4_label, menu5_label, menu6_label,
menu7_label, menu8_label, menu9_label
};

// Vortech Defaults
byte vtPrevMode=0;
byte vtPrevSpeed=0;
byte vtPrevDuration=0;

byte vtMode=Random2;
byte vtSpeed=45;
byte vtDuration=5;

byte vtNTMSpeed=65;
byte vtNTMDuration=5;
byte vtNightSpeed=20;
byte vtNightDuration=10;


boolean isNight=false;
boolean isFeeding=false;
boolean feedDelay=false;
boolean vtOverride=false;
boolean floatHigh=true;
boolean powerOutage=true;

int riseOffset=472;
int setOffset=506;
byte acclTime=0;
SunLocation sl;

//Define Custom Memory Location
#define Mem_B_RefillATO   100
#define Mem_B_Vacation    101
#define Mem_B_AcclTime    102

//Define Relay Ports
#define Return             1
#define Skimmer            2
#define WhiteLEDs          3
#define BlueLEDs           4
#define Extension          5
#define Heater             6
#define Refugium           7
#define Reactor            8

#define Unused1            Box1_Port1
#define Unused2            Box1_Port2
#define Vortech1           Box1_Port3
#define Vortech2           Box1_Port4
#define VortechUPS         Box1_Port5
#define Unused3            Box1_Port6
#define DPump1             Box1_Port7
#define DPump2             Box1_Port8


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

// Setup on controller startup/reset
void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Initialize Menu
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));

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

    // Ports that are always on
    ReefAngel.Relay.On( Return );
    ReefAngel.Relay.On( Vortech1 );
    ReefAngel.Relay.On( Vortech2 );
    ReefAngel.Relay.On( VortechUPS );
    ReefAngel.Relay.Off( Extension );
    ReefAngel.Relay.Off( Unused1 );
    ReefAngel.Relay.Off( Unused2 );
    ReefAngel.Relay.Off( Unused3 );
    
    ////// Place additional initialization code below here

    // Setup SunLocation class
    sl.Init(-18.285833, 147.699722); // GBR
    
    // Save previous used vortech mode.
    vtPrevMode=InternalMemory.RFMode_read();
    vtPrevSpeed=InternalMemory.RFSpeed_read();
    vtPrevDuration=InternalMemory.RFDuration_read();
    
    ReefAngel.CustomVar[7]=255;
    
    ////// Place additional initialization code above here
}

void loop()
{
    ReefAngel.StandardHeater( Heater );
    ReefAngel.DosingPumpRepeat1( DPump1 );
    ReefAngel.DosingPumpRepeat2( DPump2 );
    ReefAngel.StandardLights( WhiteLEDs );
    ReefAngel.ActinicLights( BlueLEDs );
    
    if (powerOutage && ReefAngel.Relay.IsRelayPresent(EXP1_RELAY))
    {
      powerOutage=false;
      LastStart=now();
      ReefAngel.CustomVar[1]=0;
    }
    ReefAngel.Relay.DelayedOn( Skimmer, 5 );
    ReefAngel.Relay.DelayedOn( Reactor, 10 );
    
    if (InternalMemory.read( Mem_B_Vacation )==1) {
      ReefAngel.WaterLevelATO( Extension,30,61,63 );
      ReefAngel.CustomVar[3]=1;  
    } else {
      ReefAngel.CustomVar[3]=0;
      ReefAngel.Relay.Off( Extension );
    }
    
    if (InternalMemory.read( Mem_B_RefillATO )==1) {
       if (ReefAngel.WaterLevel.GetLevel()<=100) {
         ReefAngel.Relay.On( Extension );
         ReefAngel.CustomVar[2]=1;
       } else {
         ReefAngel.Relay.Off( Extension );
         InternalMemory.write( Mem_B_RefillATO, 0);
         ReefAngel.CustomVar[2]=0;
       }
    }
    
    acclTime=InternalMemory.read( Mem_B_AcclTime );
    if (acclTime > 0) { 
      ReefAngel.CustomVar[4]=acclTime;
      if ( (hour()==0) && (minute()==0) && (second()==0)) {
        acclTime--;
        InternalMemory.write( Mem_B_AcclTime, acclTime );
      } 
    }
    
    ////// Place your custom code below here
    sl.SetOffset(-9,riseOffset+(acclTime*240),-9,setOffset+(acclTime*120)); // 9 hour difference
    sl.CheckAndUpdate();
            
    // Let's make the time one number so we can figure out it's night or day...
    int currTime=NumMins(hour(),minute());
    int riseTime=NumMins(sl.GetRiseHour(),sl.GetRiseMinute()); 
    int setTime=NumMins(sl.GetSetHour(),sl.GetSetMinute());
    if ( (currTime <= riseTime) || (currTime >= setTime) ) isNight=true; else isNight=false;
    
    if (isNight) 
    {
      if ((hour()>=3) && (hour()<=5)) {
        ReefAngel.PWM.SetDaylight( 0 );
        ReefAngel.PWM.SetActinic( 0 );
      } else {
        ReefAngel.PWM.SetDaylight( MoonPhase() );
        ReefAngel.PWM.SetActinic( MoonPhase() );
      }  
      
      if (vtOverride==false && isFeeding==false) {
        setRFmode(Night,vtNightSpeed,vtNightDuration);
      }
      
      ReefAngel.Relay.On( Refugium );
      
    } else { 
      // It's Daytime!
      ReefAngel.PWM.SetDaylight( 0 );
      ReefAngel.PWM.SetActinic( 0 );
      ReefAngel.Relay.Off( Refugium );
      
      if (vtOverride==false && vtMode==Night) {
        setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
        ReefAngel.Timer[1].ForceTrigger();
      }
    }   
    
    if (ReefAngel.DisplayedMenu==FEEDING_MODE) isFeeding=true;
    if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE) ReefAngel.Relay.On( Refugium );
    if (ReefAngel.DisplayedMenu==FEEDING_MODE || ReefAngel.DisplayedMenu==WATERCHANGE_MODE) floatHigh=true;
    
    if (ReefAngel.DisplayedMenu==DEFAULT_MENU && isFeeding )
    {
      isFeeding=false; 
      feedDelay=true;
      setRFtimer(30); // Stay in FeedMode for a while longer.
    } 
    else if (vtOverride && ReefAngel.Timer[1].IsTriggered()) 
    {
      vtOverride=false;

      if(feedDelay) {
        feedDelay=false;
        setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration);
      } else {
        setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
      }
    } 
    else 
    {
      setRFmode(); // Update if set externally
    }

    if ( ((hour() == 15) && (minute() == 00) && (second() == 00) ) ) {
      setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration);
    }
    
    if (ReefAngel.LowATO.IsActive()) {
      bitClear(ReefAngel.Relay.RelayMaskOff,Return-1);
      bitClear(ReefAngel.Relay.RelayMaskOff,Skimmer-1);
    } 
 
    if (ReefAngel.HighATO.IsActive()) {
      if (!floatHigh) {
        floatHigh=true;
        ReefAngel.CustomVar[0]=1;
        bitClear(ReefAngel.Relay.RelayMaskOff,Return-1);
        bitClear(ReefAngel.Relay.RelayMaskOff,Skimmer-1);  
      }  
    } else {
      ReefAngel.CustomVar[0]=0;
      floatHigh=false;
    }  
      
    // Turn off Skimmer if Return pump is shutoff.   
    if (bitRead(ReefAngel.Relay.RelayMaskOff,Return-1)==0) {
      bitClear(ReefAngel.Relay.RelayMaskOff,Skimmer-1);
    }
    
    // Power Outage - Only Return Pump
    if (!ReefAngel.Relay.IsRelayPresent(EXP1_RELAY)) // Exp1 Relay NOT present
    {
      powerOutage=true;
      ReefAngel.Relay.Off (Skimmer); 
      ReefAngel.Relay.Off (WhiteLEDs); 
      ReefAngel.Relay.Off (BlueLEDs); 
      ReefAngel.Relay.Off (Extension);
      ReefAngel.Relay.Off (Heater);
      ReefAngel.Relay.Off (Refugium); 
      ReefAngel.Relay.Off (Reactor); 
      ReefAngel.CustomVar[1]=1;
    }
    ////// Place your custom code above here

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

// Vortech Helper functions
void setRFmode(int mode, int speed, int duration) {

  // Check if mode has changed
  if (mode!=vtMode) {  
    vtPrevMode=vtMode;
    vtMode=mode; 
  
    if (mode!=InternalMemory.RFMode_read()) { 
      InternalMemory.RFMode_write(mode);
    }
    
    // Temp fix for coming out of night mode
    if (vtPrevMode==Night) {
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Feeding_Stop,0,0);
      ReefAngel.RF.UseMemory=true;
    }
    
    if ( (isNight && vtMode != Night) || vtMode==Smart_NTM) {
      setRFtimer(60);
    }
  } 

  // Check if speed has changed
  if (speed!=vtSpeed) {  
    vtPrevSpeed=vtSpeed;
    vtSpeed=speed;
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    } 
  }

  // Check if duration has changed
  if (duration!=vtDuration) {  
    vtPrevDuration=vtDuration;
    vtDuration=duration; 
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    }
  }
}
void setRFmode() {
  setRFmode(InternalMemory.RFMode_read(), InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
}
void setRFtimer(int minutes) {
  ReefAngel.Timer[1].SetInterval(minutes*60);
  ReefAngel.Timer[1].Start();
  vtOverride=true;
}

// Menu Code
void MenuEntry1()
{
  ReefAngel.FeedingModeStart();
}
void MenuEntry2()
{
  ReefAngel.WaterChangeModeStart();
}
void MenuEntry3()
{
  byte mode,speed,duration,prev_mode,prev_speed,prev_dur;
  mode=vtMode;
  mode++;
  
  prev_mode=vtPrevMode; prev_speed=vtPrevSpeed; prev_dur=vtPrevDuration;
  
  if (mode > 9 ) { 
    mode=0; 
    speed=50; duration=0; // Constant
  } else if (mode == 1) { 
    speed=40; duration=0; // Lagoon
  } else if (mode == 2) { 
    speed=45; duration=0; // Reef Crest
  } else if (mode == 3) {  
    speed=55; duration=10; // Short Pulse
  } else if (mode == 4) {
    speed=55; duration=20; // Long Pulse
  } else if (mode == 6) {
    speed=50; duration=10; // Smart_TSM
  } else if (mode == 5) {
    speed=vtNTMSpeed; duration=vtNTMDuration; // Smart_NTM
  } else if (mode == 7) {
    speed=vtNightSpeed; duration=vtNightDuration; // Night
    mode=9; 
  }  

  prev_mode=vtPrevMode; prev_speed=vtPrevSpeed; prev_dur=vtPrevDuration;
  setRFmode(mode,speed,duration);
  
  if (!isNight) {
    vtPrevMode=prev_mode; vtPrevSpeed=prev_speed; vtPrevDuration=prev_dur;
  }
  
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}
void MenuEntry4()
{
  if (isNight) {
    if (bitRead(ReefAngel.Relay.RelayMaskOff,Refugium-1)==1) {
      bitClear(ReefAngel.Relay.RelayMaskOff,Refugium-1);
    } else {
      bitSet(ReefAngel.Relay.RelayMaskOff,Refugium-1);
    }
  } else { 
    if (bitRead(ReefAngel.Relay.RelayMaskOn,Refugium-1)==1) {
      bitClear(ReefAngel.Relay.RelayMaskOn,Refugium-1);
    } else {
      bitSet(ReefAngel.Relay.RelayMaskOn,Refugium-1);
    }
  }
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}
void MenuEntry5()
{
  ReefAngel.ATOClear();
  ReefAngel.DisplayMenuEntry("Clear ATO Timeout");
  ReefAngel.OverheatClear();
  ReefAngel.DisplayMenuEntry("Clear Overheat");
}
void MenuEntry6()
{
  ReefAngel.SetupCalibratePH();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry7()
{
  ReefAngel.SetupCalibrateWaterLevel();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry8()
{
  ReefAngel.SetupDateTime();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry9()
{
  ReefAngel.DisplayVersion();
}

// Custom Main Screen
void DrawCustomMain()
{
  char buf[16];
  byte x = 5;
  byte y = 2;
  byte t;

//  if (isFeeding) { ReefAngel.ClearScreen(DefaultBGColor); return; }

  // Main Header
//  ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 35, y,"Lee's Reef");
  
  // Date+Time
  ReefAngel.LCD.DrawDate(x+1, y);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, y+9, 128, y+9);
  
  // Param Header
  y+=12; 
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x+5,y,"Temp:");
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x+80, y, "PH:");
  // Temp and PH
  y+=2;
  ConvertNumToString(buf, ReefAngel.Params.Temp[T2_PROBE], 10);
  ReefAngel.LCD.DrawText(T2TempColor, DefaultBGColor, x+45, y, buf);
  y+=6; 
  ConvertNumToString(buf, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(T1TempColor, DefaultBGColor, x+5, y, buf, Num8x16);
  ConvertNumToString(buf, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+80, y, buf, Num8x16);
  y+=5;
  ConvertNumToString(buf, ReefAngel.Params.Temp[T3_PROBE], 10);
  ReefAngel.LCD.DrawText(T3TempColor, DefaultBGColor, x+45, y, buf);
  pingSerial();
    
  /// Display Sunrise / Sunset (to be calculated later...)
  y+=15; t=x;
  sprintf(buf, "%02d:%02d", sl.GetRiseHour(), sl.GetRiseMinute());
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Rise:"); t+=31;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf); 
  sprintf(buf, "%02d:%02d", sl.GetSetHour(), sl.GetSetMinute()); t+=36;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Set:"); t+=25;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf);
  pingSerial();

  // MoonPhase
  y+=10; 
  ReefAngel.LCD.DrawText(0,255,x,y,"Moon:");
  ReefAngel.LCD.Clear(DefaultBGColor,x+32,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_MAGENTA,255,x+32,y,MoonPhaseLabel());
  pingSerial();
  
  // MoonLight %
  y+=10;
  t = intlength(ReefAngel.PWM.GetDaylightValue()) + 1;  t *= 5;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MoonLights:"); 
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(), DPColor, x+68, y, 1);
  ReefAngel.LCD.DrawText(DPColor, DefaultBGColor, x+68+t, y, "%");
  pingSerial();

  // Display Water level
  y+=10; t=x;
  ConvertNumToString(buf, ReefAngel.WaterLevel.GetLevel(), 1);
  strcat(buf,"  ");
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"AT0 Level:"); t+=60;
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,t,y,buf);

  // Vortech Mode
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF:"); t+=20;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  if (vtMode == 0) ReefAngel.LCD.DrawLargeText(COLOR_GREEN,255,t,y,"Constant");
  else if(vtMode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Lagoon");
  else if (vtMode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Reef Crest");
  else if (vtMode == 3) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Short Pulse");
  else if (vtMode == 4) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Long Pulse");
  else if (vtMode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Smart NTM");
  else if (vtMode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Tidal Swell");
  else if (vtMode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,0,t,y,"Night");
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF Speed:"); t+=60;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFSpeed_read()); t+=15;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,"/"); t+=10;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFDuration_read());
  pingSerial();
  
  y+=15;
  // Relays
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, y, TempRelay);
  pingSerial();
  
  y+=12;
  TempRelay = ReefAngel.Relay.RelayDataE[0];
  TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawOutletBox(12, y, TempRelay);
  pingSerial();
}

void DrawCustomGraph()
{
}
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Got my controller,

Post by lnevo »

Bugs worked out with Coral Acclimation counter and a lot of comments / code cleanup

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 <RA_Colors.h>
#include <RA_CustomColors.h>
//#include <Salinity.h>
//#include <IO.h>
//#include <ORP.h>
//#include <AI.h>
#include <RF.h>
#include <ReefAngel.h>
#include <SunLocation.h>
#include <WaterLevel.h>

////// Place global variable code below here
#define CUSTOM_MENU
#define CUSTOM_MENU_ENTRIES   8
#define NUMBERS_8x16

// Custom Menu Code
#include <avr/pgmspace.h>
prog_char menu1_label[] PROGMEM = "Feeding";
prog_char menu2_label[] PROGMEM = "Water Change";
prog_char menu3_label[] PROGMEM = "Vortech Mode";
prog_char menu4_label[] PROGMEM = "Refugium Light";
prog_char menu5_label[] PROGMEM = "ATO Clear";
prog_char menu6_label[] PROGMEM = "Overheat Clear";
prog_char menu7_label[] PROGMEM = "PH Calibration";
prog_char menu8_label[] PROGMEM = "WLS Calibration";
prog_char menu9_label[] PROGMEM = "Date / Time";

// Group the menu entries together
PROGMEM const char *menu_items[] = {
menu1_label, menu2_label, menu3_label,
menu4_label, menu5_label, menu6_label,
menu7_label, menu8_label, menu9_label
};

// Vortech Defaults
byte vtPrevMode=0;
byte vtPrevSpeed=0;
byte vtPrevDuration=0;
// Default Mode
byte vtMode=Random2;
byte vtSpeed=45;
byte vtDuration=5;
// NTM mode
byte vtNTMSpeed=65;
byte vtNTMDuration=5;
// Night Mode
byte vtNightSpeed=20;
byte vtNightDuration=10;


boolean isNight=false;
boolean isFeeding=false;
boolean feedDelay=false;
boolean vtOverride=false;
boolean floatHigh=true;
boolean powerOutage=true;

byte acclTime=0;
SunLocation sl;

//Define Custom Memory Location
#define Mem_B_RefillATO   100
#define Mem_B_Vacation    101
#define Mem_B_AcclTime    102
#define Mem_B_ClearATO    103

//Define Relay Ports by Name
#define Return             1
#define Skimmer            2
#define WhiteLEDs          3
#define BlueLEDs           4
#define Extension          5
#define Heater             6
#define Refugium           7
#define Reactor            8

#define Unused1            Box1_Port1
#define Unused2            Box1_Port2
#define Vortech1           Box1_Port3
#define Vortech2           Box1_Port4
#define VortechUPS         Box1_Port5
#define Unused3            Box1_Port6
#define DPump1             Box1_Port7
#define DPump2             Box1_Port8


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

// Setup on controller startup/reset
void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Initialize Menu
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));

    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port1Bit | Port2Bit | Port8Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | 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 | Port6Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    // Set the Overheat temperature setting
    InternalMemory.OverheatTemp_write( 820 );

    // Ports that default on
    ReefAngel.Relay.On( Return );
    ReefAngel.Relay.On( Vortech1 );
    ReefAngel.Relay.On( Vortech2 );
    ReefAngel.Relay.On( VortechUPS );
    // Ports that default off
    ReefAngel.Relay.Off( Extension );
    ReefAngel.Relay.Off( Unused1 );
    ReefAngel.Relay.Off( Unused2 );
    ReefAngel.Relay.Off( Unused3 );
    
    ////// Place additional initialization code below here

    // Setup SunLocation class
    sl.Init(-18.285833, 147.699722); // Great Barrier Reef
    
    // What was our previous modes before we restarted?
    vtPrevMode=InternalMemory.RFMode_read();
    vtPrevSpeed=InternalMemory.RFSpeed_read();
    vtPrevDuration=InternalMemory.RFDuration_read();
    
    ReefAngel.CustomVar[7]=255;
    
    ////// Place additional initialization code above here
}

void loop()
{
  // Default port modes. Use Memory settings for external control
  ReefAngel.StandardHeater( Heater );
  ReefAngel.DosingPumpRepeat1( DPump1 );
  ReefAngel.DosingPumpRepeat2( DPump2 );
  ReefAngel.StandardLights( WhiteLEDs );
  ReefAngel.ActinicLights( BlueLEDs );
    
  ////// Place your custom code below here
    
  // See if power is back on so DelayedOn ports will reset.
  if (powerOutage && ReefAngel.Relay.IsRelayPresent(EXP1_RELAY))
  {
    powerOutage=false;
    LastStart=now();
    ReefAngel.CustomVar[1]=0;
  }
  ReefAngel.Relay.DelayedOn( Skimmer ); 
  ReefAngel.Relay.DelayedOn( Reactor ); 

  // We're on vacation! Use external pump to top off the top off.    
  if (InternalMemory.read( Mem_B_Vacation )==1) {
    ReefAngel.WaterLevelATO( Extension,30,61,63 );
    ReefAngel.CustomVar[3]=1;  
  } else {
    ReefAngel.CustomVar[3]=0;
    ReefAngel.Relay.Off( Extension );
  }
  
  // Real ATO Clear
  if (InternalMemory.read( Mem_B_ClearATO )==1) {
    ReefAngel.ATOClear();
  }  
  // ATO Refill mode. Top off ATO reservoir until it's at 100%    
  if (InternalMemory.read( Mem_B_RefillATO )==1) {
     if (ReefAngel.WaterLevel.GetLevel()<=100) {
       ReefAngel.Relay.On( Extension );
       ReefAngel.CustomVar[2]=1;
     } else {
       ReefAngel.Relay.Off( Extension );
       InternalMemory.write( Mem_B_RefillATO, 0);
       ReefAngel.CustomVar[2]=0;
     }
  }
    
  // See if we are acclimating corals and decrement the countdown each night
  static boolean acclCounterReady=false;
  if ( acclCounterReady && now()%86400==0) {
    acclTime--;
    acclCounterReady=false;
    InternalMemory.write( Mem_B_AcclTime, acclTime );
  } 
  if ( now()%86400!=0 ) acclCounterReady=true;
    
  // -9 hour difference for time zone. 472/506 seconds were calculation corrections
  // The acclTime will adjust the sunrise/sunset if we are adjusting for new coral
  sl.SetOffset(-9,472+(acclTime*240),-9,506-(acclTime*120)); 
  // Calculate the new Sunrise / Sunset based on our GPS coordinates
  sl.CheckAndUpdate();
            
  // Let's make the time one number so we can figure out it's night or day...
  int currTime=NumMins(hour(),minute());
  int riseTime=NumMins(sl.GetRiseHour(),sl.GetRiseMinute()); 
  int setTime=NumMins(sl.GetSetHour(),sl.GetSetMinute());
  if ( (currTime <= riseTime) || (currTime >= setTime) ) isNight=true; else isNight=false;
    
  if (isNight) 
  {
    if ((hour()>=3) && (hour()<=5)) {
      // Some complete darkness
      ReefAngel.PWM.SetDaylight( 0 );
      ReefAngel.PWM.SetActinic( 0 );
    } else {
      // Set moonlights to the MoonPhase
      ReefAngel.PWM.SetDaylight( MoonPhase() );
      ReefAngel.PWM.SetActinic( MoonPhase() );
    }  
      
    // Vortech's to night mode.
    if (vtOverride==false && isFeeding==false) {
      setRFmode(Night,vtNightSpeed,vtNightDuration);
    }
    
    // Turn on refugium light opposite normal lights
    ReefAngel.Relay.On( Refugium );
  
  } else { // It's Daytime!
    // Regular lights are controlled by Memory variables set in SunLocation class
    ReefAngel.PWM.SetDaylight( 0 );
    ReefAngel.PWM.SetActinic( 0 );
    ReefAngel.Relay.Off( Refugium );
      
    // Go back to our regularly scheduled program.
    if (vtOverride==false && vtMode==Night) {
      setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
      // Force the trigger to make sure we break feeding/night modes.
      ReefAngel.Timer[1].ForceTrigger();
    }
  }   
    
  // Enable Feeding Mode flag
  if (ReefAngel.DisplayedMenu==FEEDING_MODE) isFeeding=true;
  // Turn on Refugium light during water change mode
  if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE) ReefAngel.Relay.On( Refugium );
  // Enable ATOHigh flag on purpose during feed/water change mode so we don't get alerts.
  if (ReefAngel.DisplayedMenu==FEEDING_MODE || ReefAngel.DisplayedMenu==WATERCHANGE_MODE) floatHigh=true;
    
  /*** RF Modes ***/
  // Here's what we do if we're just out of feeding mode...
  if (ReefAngel.DisplayedMenu==DEFAULT_MENU && isFeeding ) {
    isFeeding=false; 
    feedDelay=true; // This will let us know we want some extra time before Smart_NTM
    setRFtimer(30); // Start Smart_NTM in 30 minutes...
  } else if (vtOverride && ReefAngel.Timer[1].IsTriggered()) { // Our RF timer is over. 
    vtOverride=false; // Stop overriding the default RF mode

    // First let's deal with that extra 30 minutes
    if(feedDelay) {
      feedDelay=false; // Reset the feedDelay flag
      setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration); // Smart_NTM time!
    } else {
      // Otherwise go to Previous settings
      setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration); 
    }
  } else   {
    setRFmode(); // Update the mode if we change it remotely
  }
    
  // A little extra Smart_NTM never hurt anyone
  if ( ((hour() == 15) && (minute() == 00) && (second() == 00) ) ) {
    setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration);
  }
  /*** End of RF modes ***/
    
  // Turn off return pump if we run out of water!
  if (ReefAngel.LowATO.IsActive()) {
    bitClear(ReefAngel.Relay.RelayMaskOff,Return-1);
  } 
 
  // Turn off return if we are somehow overflowing the sump
  if (ReefAngel.HighATO.IsActive()) {
    if (!floatHigh) {
      floatHigh=true;
      ReefAngel.CustomVar[0]=1;
      bitClear(ReefAngel.Relay.RelayMaskOff,Return-1);
    }  
  } else {
    ReefAngel.CustomVar[0]=0;
    floatHigh=false;
  }  
      
  // Turn off Skimmer if Return pump is shutoff.   
  if (bitRead(ReefAngel.Relay.RelayMaskOff,Return-1)==0) {
    bitClear(ReefAngel.Relay.RelayMaskOff,Skimmer-1);
  }
    
  // Power Outage - Only Return Pump should be active
  if (!ReefAngel.Relay.IsRelayPresent(EXP1_RELAY)) // Expansion Relay NOT present
  {
    powerOutage=true;
    ReefAngel.Relay.Off (Skimmer); 
    ReefAngel.Relay.Off (WhiteLEDs); 
    ReefAngel.Relay.Off (BlueLEDs); 
    ReefAngel.Relay.Off (Extension);
    ReefAngel.Relay.Off (Heater);
    ReefAngel.Relay.Off (Refugium); 
    ReefAngel.Relay.Off (Reactor); 
    ReefAngel.CustomVar[1]=1;
  }
    
  ////// Place your custom code above here

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

// Vortech Helper functions
void setRFmode(int mode, int speed, int duration) {

  // Check if mode has changed
  if (mode!=vtMode) {  
    vtPrevMode=vtMode;
    vtMode=mode; 
  
    if (mode!=InternalMemory.RFMode_read()) { 
      InternalMemory.RFMode_write(mode); 
    }
    
    // Fix for coming out of night mode
    if (vtPrevMode==Night) {
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Feeding_Stop,0,0);
      ReefAngel.RF.UseMemory=true;
    }
    
    // If it's at night or we are setting NTM, do this only temporarily
    if ( (isNight && vtMode != Night) || vtMode==Smart_NTM) {
      setRFtimer(60);
    }
  } 

  // Check if speed has changed
  if (speed!=vtSpeed) {  
    vtPrevSpeed=vtSpeed;
    vtSpeed=speed;
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    } 
  }

  // Check if duration has changed
  if (duration!=vtDuration) {  
    vtPrevDuration=vtDuration;
    vtDuration=duration; 
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    }
  }
}
void setRFmode() {
  setRFmode(InternalMemory.RFMode_read(), InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
}
void setRFtimer(int minutes) {
  ReefAngel.Timer[1].SetInterval(minutes*60);
  ReefAngel.Timer[1].Start();
  vtOverride=true;
}

// Menu Code
void MenuEntry1() {
  ReefAngel.FeedingModeStart();
}
void MenuEntry2() {
  ReefAngel.WaterChangeModeStart();
}
void MenuEntry3() {
  byte mode,speed,duration;
  byte prev_mode,prev_speed,prev_dur;
  
  mode=vtMode;
  mode++;
  
  prev_mode=vtPrevMode; prev_speed=vtPrevSpeed; prev_dur=vtPrevDuration;
  
  if (mode > 9 ) { 
    mode=0; 
    speed=50; duration=0; // Constant
  } else if (mode == 1) { 
    speed=40; duration=0; // Lagoon
  } else if (mode == 2) { 
    speed=45; duration=0; // Reef Crest
  } else if (mode == 3) {  
    speed=55; duration=10; // Short Pulse
  } else if (mode == 4) {
    speed=55; duration=20; // Long Pulse
  } else if (mode == 6) {
    speed=50; duration=10; // Smart_TSM
  } else if (mode == 5) {
    speed=vtNTMSpeed; duration=vtNTMDuration; // Smart_NTM
  } else if (mode == 7) {
    speed=vtNightSpeed; duration=vtNightDuration; // Night
    mode=9; 
  }  

  prev_mode=vtPrevMode; prev_speed=vtPrevSpeed; prev_dur=vtPrevDuration;
  setRFmode(mode,speed,duration);
  
  // If it's night time, don't overwrite the default daytime mode when using the menu
  if (!isNight) {
    vtPrevMode=prev_mode; vtPrevSpeed=prev_speed; vtPrevDuration=prev_dur;
  }
  
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}
void MenuEntry4() {
  if (isNight) { // Turn off the Refugium light
    if (bitRead(ReefAngel.Relay.RelayMaskOff,Refugium-1)==1) {
      bitClear(ReefAngel.Relay.RelayMaskOff,Refugium-1);
    } else {
      bitSet(ReefAngel.Relay.RelayMaskOff,Refugium-1);
    }
  } else { // Turn on the Refugium light
    if (bitRead(ReefAngel.Relay.RelayMaskOn,Refugium-1)==1) {
      bitClear(ReefAngel.Relay.RelayMaskOn,Refugium-1);
    } else {
      bitSet(ReefAngel.Relay.RelayMaskOn,Refugium-1);
    }
  }
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}
void MenuEntry5() {
  ReefAngel.ATOClear();
  ReefAngel.DisplayMenuEntry("Clear ATO Timeout");
}
void MenuEntry6() {
  ReefAngel.OverheatClear();
  ReefAngel.DisplayMenuEntry("Clear Overheat");
}
void MenuEntry7() {
  ReefAngel.SetupCalibratePH();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry8() {
  ReefAngel.SetupCalibrateWaterLevel();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry9() {
  ReefAngel.SetupDateTime();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}

// Custom Main Screen
void DrawCustomMain() {
  char buf[16];
  byte x = 5;
  byte y = 2;
  byte t;


  // Main Header
  //  ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 35, y,"Lee's Reef");
  
  // Date+Time
  ReefAngel.LCD.DrawDate(x+1, y);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, y+9, 128, y+9);
  
  // Param Header
  y+=12; 
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x+5,y,"Temp:");
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x+80, y, "PH:");
  // Temp and PH
  y+=2;
  ConvertNumToString(buf, ReefAngel.Params.Temp[T2_PROBE], 10);
  ReefAngel.LCD.DrawText(T2TempColor, DefaultBGColor, x+45, y, buf);
  y+=6; 
  ConvertNumToString(buf, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(T1TempColor, DefaultBGColor, x+5, y, buf, Num8x16);
  ConvertNumToString(buf, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+80, y, buf, Num8x16);
  y+=5;
  ConvertNumToString(buf, ReefAngel.Params.Temp[T3_PROBE], 10);
  ReefAngel.LCD.DrawText(T3TempColor, DefaultBGColor, x+45, y, buf);
  pingSerial();
    
  /// Display Sunrise / Sunset (to be calculated later...)
  y+=15; t=x;
  sprintf(buf, "%02d:%02d", sl.GetRiseHour(), sl.GetRiseMinute());
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Rise:"); t+=31;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf); 
  sprintf(buf, "%02d:%02d", sl.GetSetHour(), sl.GetSetMinute()); t+=36;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Set:"); t+=25;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf);
  pingSerial();

  // MoonPhase
  y+=10; 
  ReefAngel.LCD.DrawText(0,255,x,y,"Moon:");
  ReefAngel.LCD.Clear(DefaultBGColor,x+32,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_MAGENTA,255,x+32,y,MoonPhaseLabel());
  pingSerial();
  
  // MoonLight %
  y+=10;
  t = intlength(ReefAngel.PWM.GetDaylightValue()) + 1;  t *= 5;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MoonLights:"); 
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(), DPColor, x+68, y, 1);
  ReefAngel.LCD.DrawText(DPColor, DefaultBGColor, x+68+t, y, "%");
  pingSerial();

  // Display Water level
  y+=10; t=x;
  ConvertNumToString(buf, ReefAngel.WaterLevel.GetLevel(), 1);
  strcat(buf,"  ");
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"AT0 Level:"); t+=60;
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,t,y,buf);

  // Vortech Mode
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF:"); t+=20;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  if (vtMode == 0) ReefAngel.LCD.DrawLargeText(COLOR_GREEN,255,t,y,"Constant");
  else if(vtMode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Lagoon");
  else if (vtMode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Reef Crest");
  else if (vtMode == 3) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Short Pulse");
  else if (vtMode == 4) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Long Pulse");
  else if (vtMode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Smart NTM");
  else if (vtMode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Tidal Swell");
  else if (vtMode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,0,t,y,"Night");
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF Speed:"); t+=60;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFSpeed_read()); t+=15;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,"/"); t+=10;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFDuration_read());
  pingSerial();
  
  y+=15;
  // Relays
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(12, y, TempRelay);
  pingSerial();
  
  y+=12;
  TempRelay = ReefAngel.Relay.RelayDataE[0];
  TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawOutletBox(12, y, TempRelay);
  pingSerial();
}

void DrawCustomGraph() {
}
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Got my controller,

Post by lnevo »

Hmm timer bug not worked out...
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Got my controller,

Post by lnevo »

Ok, figured out what happened. I overwrote the code that reads the timer from memory and updates my CustomVar when I pasted roberto's timer change. So acclTime reverted to 0 and memory was written as 255. Portal showed 0 since I was no longer updating that variable. I will post my fixes and final code tonight.
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Got my controller,

Post by lnevo »

Ok, more bugs fixed with the acclimation timer and final changes from SunLocation incorporated. Also added a display for the acclimation counter if its active. Some more comments and cleanup.

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 <RA_Colors.h>
#include <RA_CustomColors.h>
#include <RF.h>
#include <ReefAngel.h>
#include <SunLocation.h>
#include <WaterLevel.h>

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

// Custom Menu Code
#include <avr/pgmspace.h>
prog_char menu1_label[] PROGMEM = "Feeding";
prog_char menu2_label[] PROGMEM = "Water Change";
prog_char menu3_label[] PROGMEM = "Vortech Mode";
prog_char menu4_label[] PROGMEM = "Refugium Light";
prog_char menu5_label[] PROGMEM = "ATO Clear";
prog_char menu6_label[] PROGMEM = "Overheat Clear";
prog_char menu7_label[] PROGMEM = "PH Calibration";
prog_char menu8_label[] PROGMEM = "WLS Calibration";
prog_char menu9_label[] PROGMEM = "Date / Time";

// Group the menu entries together
PROGMEM const char *menu_items[] = {
menu1_label, menu2_label, menu3_label,
menu4_label, menu5_label, menu6_label,
menu7_label, menu8_label, menu9_label
};

// Vortech Defaults
byte vtPrevMode=0;
byte vtPrevSpeed=0;
byte vtPrevDuration=0;
// Default Mode
byte vtMode=Random2;
byte vtSpeed=45;
byte vtDuration=5;
// NTM mode
byte vtNTMSpeed=65;
byte vtNTMDuration=5;
// Night Mode
byte vtNightSpeed=20;
byte vtNightDuration=10;

boolean isNight=false;
boolean isFeeding=false;
boolean feedDelay=false;
boolean vtOverride=false;
boolean floatHigh=true;
boolean powerOutage=true;

SunLocation sl;
byte acclDay=0;
byte vacationMode=0;

//Define Custom Memory Location
#define Mem_B_RefillATO   100
#define Mem_B_ClearATO    101
#define Mem_B_Vacation    102
#define Mem_B_AcclDay     103

#define Var_HighATO    0
#define Var_Power      1
#define Var_Vacation   2
#define Var_AcclDay    3

//Define Relay Ports by Name
#define Return             1
#define Skimmer            2
#define WhiteLEDs          3
#define BlueLEDs           4
#define Extension          5
#define Heater             6
#define Refugium           7
#define Reactor            8

#define Unused1            Box1_Port1
#define Unused2            Box1_Port2
#define Vortech1           Box1_Port3
#define Vortech2           Box1_Port4
#define VortechUPS         Box1_Port5
#define Unused3            Box1_Port6
#define DPump1             Box1_Port7
#define DPump2             Box1_Port8

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

// Setup on controller startup/reset
void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Initialize Menu
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));

    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port1Bit | Port2Bit | Port8Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | 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 | Port6Bit;
    // Use T1 probe as temperature and overheat functions
    ReefAngel.TempProbe = T1_PROBE;
    ReefAngel.OverheatProbe = T1_PROBE;
    
    // Ports that default on
    ReefAngel.Relay.On(Return);
    ReefAngel.Relay.On(Vortech1);
    ReefAngel.Relay.On(Vortech2);
    ReefAngel.Relay.On(VortechUPS);
    // Ports that default off
    ReefAngel.Relay.Off(Extension);
    ReefAngel.Relay.Off(Unused1);
    ReefAngel.Relay.Off(Unused2);
    ReefAngel.Relay.Off(Unused3);
    
    ////// Place additional initialization code below here

    // What was our previous modes before we restarted?
    vtPrevMode=InternalMemory.RFMode_read();
    vtPrevSpeed=InternalMemory.RFSpeed_read();
    vtPrevDuration=InternalMemory.RFDuration_read();
    
    // Dummy CustomVar to activate portal feature
    ReefAngel.CustomVar[7]=255;
    
    ////// Place additional initialization code above here
}

void loop()
{
  // Default port modes. Use Memory settings for external control
  ReefAngel.StandardHeater(Heater);
  ReefAngel.DosingPumpRepeat1(DPump1);
  ReefAngel.DosingPumpRepeat2(DPump2);
  ReefAngel.StandardLights(WhiteLEDs);
  ReefAngel.ActinicLights(BlueLEDs);
    
  ////// Place your custom code below here
 
  // See if power is back on so DelayedOn ports will reset.
  if (powerOutage && ReefAngel.Relay.IsRelayPresent(EXP1_RELAY))
  {
    powerOutage=false;
    LastStart=now();
    ReefAngel.CustomVar[Var_Power]=0;
  }
  ReefAngel.Relay.DelayedOn(Skimmer); 
  ReefAngel.Relay.DelayedOn(Reactor); 

  // Find out if we are on vacation
  ReefAngel.CustomVar[Var_Vacation]=InternalMemory.read(Mem_B_Vacation);
  vacationMode=ReefAngel.CustomVar[Var_Vacation];
  
  // We're on vacation! Use external pump to top off the top off.    
  if (vacationMode==1) {
    ReefAngel.WaterLevelATO(Extension,30,61,63);
  } else {
    ReefAngel.Relay.Off(Extension);
  }
  
  // Real ATO Clear
  if (InternalMemory.read(Mem_B_ClearATO)==1) {
    ReefAngel.ATOClear();
    InternalMemory.write(Mem_B_ClearATO, 0);
  }  
  
  // ATO Refill mode. Top off ATO reservoir until it's at 100%    
  if (InternalMemory.read(Mem_B_RefillATO)==1) {
     if (ReefAngel.WaterLevel.GetLevel()<=100) {
       ReefAngel.Relay.On(Extension);
     } else {
       ReefAngel.Relay.Off(Extension);
       InternalMemory.write(Mem_B_RefillATO, 0);
     }
  }
  
  // See if we are acclimating corals and decrement the countdown each night
  static boolean acclCounterReady=false;
  if (now()%SECS_PER_DAY!=0) acclCounterReady=true;
  
  acclDay=InternalMemory.read(Mem_B_AcclDay);
  ReefAngel.CustomVar[Var_AcclDay]=acclDay;
  if (acclDay > 0) { 
    if (acclCounterReady && now()%SECS_PER_DAY==0) {
      acclDay--;
      acclCounterReady=false;
      InternalMemory.write(Mem_B_AcclDay,acclDay);
    }
  }  
      
  // -9 hour difference for time zone. 472/506 seconds were calculation corrections
  // The acclDay will adjust the sunrise/sunset if we are adjusting for new coral
  sl.SetOffset(-9,472+(acclDay*240),-9,506-(acclDay*120)); 
  
  // Calculate the new Sunrise / Sunset based on our GPS coordinates
  sl.CheckAndUpdate();
              
  // Let's make the time one number so we can figure out it's night or day...
  int currTime=NumMins(hour(),minute());
  int riseTime=NumMins(sl.GetRiseHour(),sl.GetRiseMinute()); 
  int setTime=NumMins(sl.GetSetHour(),sl.GetSetMinute());
  if ( (currTime <= riseTime) || (currTime >= setTime) ) isNight=true; else isNight=false;
    
  if (isNight) 
  {
    if ((hour()>=3) && (hour()<=4)) {
      // Some complete darkness
      ReefAngel.PWM.SetDaylight(0);
      ReefAngel.PWM.SetActinic(0);
    } else {
      // Set moonlights to the MoonPhase
      ReefAngel.PWM.SetDaylight(MoonPhase());
      ReefAngel.PWM.SetActinic(MoonPhase());
    }  
      
    // Vortech's to night mode.
    if (vtOverride==false && isFeeding==false) {
      setRFmode(Night,vtNightSpeed,vtNightDuration);
    }
    
    // Turn on refugium light opposite normal lights
    ReefAngel.Relay.On(Refugium);
  
  } else { // It's Daytime!
    // Regular lights are controlled by Memory variables set in SunLocation class
    ReefAngel.PWM.SetDaylight(0);
    ReefAngel.PWM.SetActinic(0);
    ReefAngel.Relay.Off(Refugium);
      
    // Go back to our regularly scheduled program.
    if (vtOverride==false && vtMode==Night) {
      setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
    }
  }   
    
  // Enable Feeding Mode flag
  if (ReefAngel.DisplayedMenu==FEEDING_MODE) isFeeding=true;
  // Turn on Refugium light during water change mode
  if (ReefAngel.DisplayedMenu==WATERCHANGE_MODE) ReefAngel.Relay.On(Refugium);
  // Enable ATOHigh flag on purpose during feed/water change mode so we don't get alerts.
  if (ReefAngel.DisplayedMenu==FEEDING_MODE || ReefAngel.DisplayedMenu==WATERCHANGE_MODE) floatHigh=true;
    
  // Here's what we do if we're just out of feeding mode...
  if (ReefAngel.DisplayedMenu==DEFAULT_MENU && isFeeding) {
    isFeeding=false; 
    feedDelay=true; // This will let us know we want some extra time before Smart_NTM
    setRFtimer(30); // Start Smart_NTM in 30 minutes...
  } else if (vtOverride && ReefAngel.Timer[1].IsTriggered()) { // Our RF timer is over. 
    vtOverride=false; // Stop overriding the default RF mode

    // First let's deal with that extra 30 minutes
    if(feedDelay) {
      feedDelay=false; // Reset the feedDelay flag
      setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration); // Smart_NTM time!
    } else {
      // Otherwise go to Previous settings
      setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration); 
    }
  } else   {
    setRFmode(); // Update the mode if we change it remotely
  }
  // A little extra Smart_NTM never hurt anyone
  if ( ((hour() == 15) && (minute() == 00) && (second() == 00) ) ) {
    setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration);
  }
    
  // Turn off return pump if we run out of water!
  if (ReefAngel.LowATO.IsActive()) {
    bitClear(ReefAngel.Relay.RelayMaskOff,Return-1);
  } 
 
  // Turn off return if we are somehow overflowing the sump
  if (ReefAngel.HighATO.IsActive()) {
    if (!floatHigh) {
      floatHigh=true;
      ReefAngel.CustomVar[Var_HighATO]=1;
      bitClear(ReefAngel.Relay.RelayMaskOff,Return-1);
    }  
  } else {
    ReefAngel.CustomVar[Var_HighATO]=0;
    floatHigh=false;
  }  
      
  // Turn off Skimmer if Return pump is shutoff.   
  if (bitRead(ReefAngel.Relay.RelayMaskOff,Return-1)==0) {
    bitClear(ReefAngel.Relay.RelayMaskOff,Skimmer-1);
  }
    
  // Power Outage - Only Return Pump should be active
  if (!ReefAngel.Relay.IsRelayPresent(EXP1_RELAY)) // Expansion Relay NOT present
  {
    powerOutage=true;
    ReefAngel.Relay.Off (Skimmer); 
    ReefAngel.Relay.Off (WhiteLEDs); 
    ReefAngel.Relay.Off (BlueLEDs); 
    ReefAngel.Relay.Off (Extension);
    ReefAngel.Relay.Off (Heater);
    ReefAngel.Relay.Off (Refugium); 
    ReefAngel.Relay.Off (Reactor); 
    ReefAngel.CustomVar[Var_Power]=1;
  }
    
  ////// Place your custom code above here

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

// Vortech Helper functions
void setRFmode(int mode, int speed, int duration) {

  // Check if mode has changed
  if (mode!=vtMode) {  
    vtPrevMode=vtMode;
    vtMode=mode; 
  
    if (mode!=InternalMemory.RFMode_read()) { 
      InternalMemory.RFMode_write(mode); 
    }
    
    // Fix for coming out of night mode
    if (vtPrevMode==Night) {
      ReefAngel.RF.UseMemory=false;
      ReefAngel.RF.SetMode(Feeding_Stop,0,0);
      ReefAngel.RF.UseMemory=true;
    }
    
    // If it's at night or we are setting NTM, do this only temporarily
    if ( (isNight && vtMode != Night) || vtMode==Smart_NTM) {
      setRFtimer(60);
    }
  } 

  // Check if speed has changed
  if (speed!=vtSpeed) {  
    vtPrevSpeed=vtSpeed;
    vtSpeed=speed;
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    } 
  }

  // Check if duration has changed
  if (duration!=vtDuration) {  
    vtPrevDuration=vtDuration;
    vtDuration=duration; 
    
    if (speed!=InternalMemory.RFSpeed_read()) {
      InternalMemory.RFSpeed_write(speed);
    }
  }
}
void setRFmode() {
  setRFmode(InternalMemory.RFMode_read(), InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
}
void setRFtimer(int minutes) {
  ReefAngel.Timer[1].SetInterval(minutes*60);
  ReefAngel.Timer[1].Start();
  vtOverride=true;
}

// Menu Code
void MenuEntry1() {
  ReefAngel.FeedingModeStart();
}
void MenuEntry2() {
  ReefAngel.WaterChangeModeStart();
}
void MenuEntry3() {
  byte mode,speed,duration;
  byte prev_mode,prev_speed,prev_dur;
  
  mode=vtMode;
  mode++;
  
  prev_mode=vtPrevMode; prev_speed=vtPrevSpeed; prev_dur=vtPrevDuration;
  
  if (mode > 9) { 
    mode=0; 
    speed=50; duration=0; // Constant
  } else if (mode == 1) { 
    speed=40; duration=0; // Lagoon
  } else if (mode == 2) { 
    speed=45; duration=0; // Reef Crest
  } else if (mode == 3) {  
    speed=55; duration=10; // Short Pulse
  } else if (mode == 4) {
    speed=55; duration=20; // Long Pulse
  } else if (mode == 6) {
    speed=50; duration=10; // Smart_TSM
  } else if (mode == 5) {
    speed=vtNTMSpeed; duration=vtNTMDuration; // Smart_NTM
  } else if (mode == 7) {
    speed=vtNightSpeed; duration=vtNightDuration; // Night
    mode=9; 
  }  

  // Backup the previous modes. We don't want Night to become default...
  prev_mode=vtPrevMode; prev_speed=vtPrevSpeed; prev_dur=vtPrevDuration;
  setRFmode(mode,speed,duration);
  
  // If it's night time, don't overwrite the default daytime mode when using the menu
  if (!isNight) {
    vtPrevMode=prev_mode; vtPrevSpeed=prev_speed; vtPrevDuration=prev_dur;
  }
  
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;   
}
void MenuEntry4() {
  // Toggle the refugium light if we choose this menu entry.
  // Behavior is opposite for night vs day.
  
  if (isNight) { // Turn off the Refugium light
    if (bitRead(ReefAngel.Relay.RelayMaskOff,Refugium-1)==1) {
      bitClear(ReefAngel.Relay.RelayMaskOff,Refugium-1);
    } else {
      bitSet(ReefAngel.Relay.RelayMaskOff,Refugium-1);
    }
  } else { // Turn on the Refugium light
    if (bitRead(ReefAngel.Relay.RelayMaskOn,Refugium-1)==1) {
      bitClear(ReefAngel.Relay.RelayMaskOn,Refugium-1);
    } else {
      bitSet(ReefAngel.Relay.RelayMaskOn,Refugium-1);
    }
  }
  ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
}
void MenuEntry5() {
  ReefAngel.ATOClear();
  ReefAngel.DisplayMenuEntry("Clear ATO Timeout");
}
void MenuEntry6() {
  ReefAngel.OverheatClear();
  ReefAngel.DisplayMenuEntry("Clear Overheat");
}
void MenuEntry7() {
  ReefAngel.SetupCalibratePH();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry8() {
  ReefAngel.SetupCalibrateWaterLevel();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry9() {
  ReefAngel.SetupDateTime();
  ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}

// Custom Main Screen
void DrawCustomMain() {
  char buf[16];
  byte x = 5;
  byte y = 2;
  byte t;

  // Main Header
  // ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 35, y,"Lee's Reef");
  // Had no room for this anymore :(
  
  // Date+Time
  ReefAngel.LCD.DrawDate(x+1, y);
  ReefAngel.LCD.Clear(COLOR_BLACK, 1, y+9, 128, y+9);
  
  // Param Header
  y+=12; 
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x+5,y,"Temp:");
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x+80, y, "PH:");
  // Temp and PH
  y+=2;
  ConvertNumToString(buf, ReefAngel.Params.Temp[T2_PROBE], 10);
  ReefAngel.LCD.DrawText(T2TempColor, DefaultBGColor, x+45, y, buf);
  y+=6; 
  ConvertNumToString(buf, ReefAngel.Params.Temp[T1_PROBE], 10);
  ReefAngel.LCD.DrawLargeText(T1TempColor, DefaultBGColor, x+5, y, buf, Num8x16);
  ConvertNumToString(buf, ReefAngel.Params.PH, 100);
  ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+80, y, buf, Num8x16);
  y+=5;
  ConvertNumToString(buf, ReefAngel.Params.Temp[T3_PROBE], 10);
  ReefAngel.LCD.DrawText(T3TempColor, DefaultBGColor, x+45, y, buf);
  pingSerial();
    
  /// Display Sunrise / Sunset (to be calculated later...)
  y+=12; t=x;
  sprintf(buf, "%02d:%02d", sl.GetRiseHour(), sl.GetRiseMinute());
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Rise:"); t+=31;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf); 
  sprintf(buf, "%02d:%02d", sl.GetSetHour(), sl.GetSetMinute()); t+=36;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,t,y,"Set:"); t+=25;
  ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,t,y,buf);
  pingSerial();

  // MoonPhase
  y+=10; 
  ReefAngel.LCD.DrawText(0,255,x,y,"Moon:");
  ReefAngel.LCD.Clear(DefaultBGColor,x+32,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_MAGENTA,255,x+32,y,MoonPhaseLabel());
  pingSerial();
  
  // MoonLight %
  y+=10;
  t = intlength(ReefAngel.PWM.GetDaylightValue()) + 1;  t *= 5;
  ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MoonLights:"); 
  ReefAngel.LCD.DrawSingleMonitor(ReefAngel.PWM.GetDaylightValue(), DPColor, x+68, y, 1);
  ReefAngel.LCD.DrawText(DPColor, DefaultBGColor, x+68+t, y, "%");
  pingSerial();

  // Display Water level
  y+=10; t=x;
  ConvertNumToString(buf, ReefAngel.WaterLevel.GetLevel(), 1);
  strcat(buf,"  ");
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"AT0 Level:"); t+=60;
  ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,t,y,buf);

  // Vortech Mode
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF:"); t+=20;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  if (vtMode == 0) ReefAngel.LCD.DrawLargeText(COLOR_GREEN,255,t,y,"Constant");
  else if(vtMode == 1) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Lagoon");
  else if (vtMode == 2) ReefAngel.LCD.DrawLargeText(COLOR_GOLD,255,t,y,"Reef Crest");
  else if (vtMode == 3) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Short Pulse");
  else if (vtMode == 4) ReefAngel.LCD.DrawLargeText(COLOR_RED,255,t,y,"Long Pulse");
  else if (vtMode == 5) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Smart NTM");
  else if (vtMode == 6) ReefAngel.LCD.DrawLargeText(COLOR_MAGENTA,255,t,y,"Tidal Swell");
  else if (vtMode == 9) ReefAngel.LCD.DrawLargeText(COLOR_WHITE,0,t,y,"Night");
  y+=10; t=x;
  ReefAngel.LCD.DrawText(0,255,x,y,"RF Speed:"); t+=60;
  ReefAngel.LCD.Clear(DefaultBGColor,t,y,x+(128-x),y+8);
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFSpeed_read()); t+=15;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,"/"); t+=10;
  ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor,t,y,InternalMemory.RFDuration_read());
  pingSerial();
  
  // Display Water level
  y+=10; t=x;
  if (acclDay > 0) {
    ConvertNumToString(buf, acclDay, 1);
    strcat(buf,"  ");
    ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,x,y,"Acclimation Day:"); t+=100;
    ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,t,y,buf);
  } else {
    ReefAngel.LCD.Clear(DefaultBGColor,x,y,x+(128-x),y+8);
  }
  
  // Relays
  y+=10; t=x+7;
  byte TempRelay = ReefAngel.Relay.RelayData;
  TempRelay &= ReefAngel.Relay.RelayMaskOff;
  TempRelay |= ReefAngel.Relay.RelayMaskOn;
  ReefAngel.LCD.DrawOutletBox(t, y, TempRelay);
  pingSerial();
  y+=12;
  TempRelay = ReefAngel.Relay.RelayDataE[0];
  TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
  TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
  ReefAngel.LCD.DrawOutletBox(t, y, TempRelay);
  pingSerial();
}

void DrawCustomGraph() {
}
Post Reply