I think I have my code pretty much written. I uploaded it to my RA+ and everything seems to work except for two little problems. First, after every reboot of the RA+, the screen is just white until I push on the joystick. Then it looks the way it should. Second, my custom menus don't show up. When I click the joystick from the main screen, a new screen pops up that just says:
"Main:
Exit"
If I click "Exit" it goes into feeding mode...
I also have one more question: when using one of the DC pump modes (e.g. gyre), does dimming to zero actually turn the pump off even if the relay the pump is plugged into is still on?
Here's my code. I'm using the latest development libraries BTW.
Code: Select all
#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DCPump.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>
#include <ReefAngel_Colors.h>
#include <ReefAngel_CustomColors.h>
#include <avr/pgmspace.h>
//Ports assignment:
//Port1 - Daylight fixture and QT light - need 2 outlets
#define daylightFixture Port1
//Port2 - Actinic fixture
#define actinicFixture Port2
//Port3 - Refugium fixture
#define fugeFixture Port3
//Port4 - DT heaters - "http://www.reefangel.com/Support.Relay-function-StandardHeater.ashx" - need 2 outlets
#define heater Port4
//Port5 - Skimmer Recirculation Pump
#define skimmerPump Port5
//Port6 - Calcium Reactor Recirculation Pump
#define CaRXPump Port6
//Port7 - Manifold Pump
#define manifoldPump Port7
//Port8 - Return Pump, wavebox, Refugium Flow, QT flow, QT filter, and QT heater - need 6 outlets
#define returnPump Port8
//Port9 (Box1_Port1) - AWC drain pump
#define AWCDrainPump Box1_Port1
//Port10 (Box1_Port2) - AWC fill pump and QT overflow reservoir drain pump - need 2 outlets
#define AWCFillPump Box1_Port2
//Port11 (Box1_Port3) - Standard ATO - "http://forum.reefangel.com/viewtopic.php?f=7&t=240"
#define ATOPump Box1_Port3
//Port12 (Box1_Port4) - CO2 Solenoid
#define solenoid Box1_Port4
//Port13 (Box1_Port5) - WP-25 left
#define wp25L Box1_Port5
//Port14 (Box1_Port6) - WP-25 right
#define wp25R Box1_Port6
//Port15 (Box1_Port7) - Eventually will be used to control RODI solenoid to fill the RODI barrel when it is close to empty
//Port16 (Box1_Port8) - Eventually will be used for automatic dry food feeder control - "http://wamas.org/forums/blog/13/entry-46-diy-automatic-feeder-for-aquacontroller/"
//defnie daylight dimming channel to control the left wp-25 and actinic dimming channel to control the right wp-25
#define leftWp25 SetDaylight
#define rightWp25 SetActinic
////// Place global variable code below here
//The following variables control when the lights first come on during a 24 hour period starting at midnight.
//After that, lights stay on for 6 hours, turn off for 6 hours, come on for 6 hours, and turn off for 6 hours.
int lightsOnHour = 6;
int lightsOnMin = 0;
boolean mainLightsOn = false;
boolean fugeLightsOn = false;
//The following variables will toggle the state of the relays controling the main and fuge lights, respectively.
boolean toggleMainLights = false;
boolean toggleFugeLights = false;
boolean toggleChanged = false;
//The following variable controls acclimation mode, in which the return section is topped off, then the ATO switches
//to use salt water instead of RODI to replace water lost to acclimation of new arrivals.
boolean acclimationMode = false;
//The following variables control the ReefAngel.StandardATO() function to work with either RODI or saltwater and to have a timeout of either 300 or 60 seconds.
byte fillPump = ATOPump;
int ATOTimeOut = 300;
//The following variables control when automatic water changes occur.
int AWCHour = 21;
int AWCMin = 0;
//This variable will be set to true if a water change has been done since the last midnight and will be set to false at midnight.
boolean AWCToday = false;
//This variable will be a backup timer for AWC.
static unsigned long AWCTimer = 0;
//This variable will be a timer for calcium reactor pH checks
static unsigned long pHTimer = 0;
//This variable will be a timer for the gyre function
static unsigned long gyreTimer = 0;
//These variables will control how long the AWC drain and fill pumps should be on (in seconds) in case of float switch failure.
int AWCDrainSecs = 60;
int AWCFillSecs = 60;
//This variable will control whether ATO is working.
boolean ATOOn = true;
//This function will carry out an automatic water change.
boolean AWC()
{
if (!ReefAngel.Relay.Status(Port8)) //If the return pump is not on, don't run an AWC and return 0 (false).
{
return 0;
}
if (!ReefAngel.HighATO.IsActive())
{
AWCTimer = now();
ReefAngel.Relay.On(ATOPump); //Fill the return section to the high float with RODI.
while (true)
{
if (ReefAngel.HighATO.IsActive())
{
ReefAngel.Relay.Off(ATOPump); //Turn off the RODI pump once the high float is triggered.
break;
}
else if ((now() - AWCTimer) >= ATOTimeOut)
{
ReefAngel.Relay.Off(ATOPump); //Turn off the RODI pump.
bitSet(ReefAngel.AlertFlags,ATOTimeOutFlag); //Trigger ATO timeout flag.
return 0; //Return 0 (false) if the ATO times out.
}
}
}
ATOOn = false;
AWCTimer = now();
ReefAngel.Relay.On(AWCDrainPump); //Turn on the AWC drain pump.
while (true)
{
if (ReefAngel.LowATO.IsActive())
{
ReefAngel.Relay.Off(AWCDrainPump); //Turn off the AWC drain pump.
break;
}
else if ((now() - AWCTimer) >= AWCDrainSecs)
{
ReefAngel.Relay.Off(AWCDrainPump); //Turn off the AWC drain pump.
bitSet(ReefAngel.AlertFlags,ATOTimeOutFlag); //Trigger ATO timeout flag.
return 0; //Return 0 (false) if the AWC times out.
}
}
AWCTimer = now();
ReefAngel.Relay.On(AWCFillPump); //Turn on the AWC fill pump.
while (true)
{
if (ReefAngel.HighATO.IsActive())
{
ReefAngel.Relay.Off(AWCFillPump); //Turn off the AWC fill pump.
break;
}
else if ((now() - AWCTimer) >= AWCFillSecs)
{
ReefAngel.Relay.Off(AWCFillPump); //Turn off the AWC fill pump.
bitSet(ReefAngel.AlertFlags,ATOTimeOutFlag); //Trigger ATO timeout flag.
return 0; //Return 0 (false) if the AWC times out.
}
}
ATOOn = true;
return 1; //If the AWC ran successfully, return 1 (true).
}
//This function will be called once a minute and will check the pH in the calcium reactor and turn off or on the solenoid accordingly
void pHControl()
{
if (!ReefAngel.Relay.Status(solenoid) && ReefAngel.Params.PH > 670)
{
ReefAngel.Relay.On(solenoid);
}
if (ReefAngel.Relay.Status(solenoid) && ReefAngel.Params.PH < 660)
{
ReefAngel.Relay.Off(solenoid);
}
}
//This function will control the DT and Fuge lights, including allowing them to be toggled from the custom menu; it also triggers an automatic water change once per day if one is not manually started.
void lightControl()
{
if ((hour() || ((hour() + 12) % 24)) == lightsOnHour && minute() == lightsOnMin) //Main lights on and fuge lights off when the time = lightsOnHour & lightsOnMin or lightsOnHour + 12 & lightsOnMin.
{
toggleMainLights = toggleFugeLights = toggleChanged = fugeLightsOn = false; //Reset all light toggle control variables.
mainLightsOn = true;
ReefAngel.Relay.On(Port1);
ReefAngel.Relay.On(Port2);
ReefAngel.Relay.Off(Port3);
}
if ((hour() || ((hour() + 12) % 24)) == (lightsOnHour + 6) && minute() == lightsOnMin) //Main lights off and fuge lights on when the time = lightsOnHour + 6 & lightsOnMin or lightsOnHour + 18 & lightsOnMin.
{
toggleMainLights = toggleFugeLights = toggleChanged = mainLightsOn = false; //Reset all light toggle control variables.
fugeLightsOn = true;
ReefAngel.Relay.Off(Port1);
ReefAngel.Relay.Off(Port2);
ReefAngel.Relay.On(Port3);
//If an AWC hasn't been manually triggered since midnight today, trigger one
if (AWCToday == false && !ReefAngel.isATOTimeOut())
{
AWCToday = AWC(); //AWC() returns 0 (false) if the AWC failed and 1 (true) if the AWC succeeded
}
}
if (toggleMainLights == true && toggleChanged == false) //Turn off main lights when they are on and toggled.
{
toggleChanged = true;
if (mainLightsOn == true)
{
mainLightsOn = false;
ReefAngel.Relay.Off(Port1);
ReefAngel.Relay.Off(Port2);
}
else
{
mainLightsOn = true;
ReefAngel.Relay.On(Port1);
ReefAngel.Relay.On(Port2);
}
}
if (toggleMainLights == false && toggleChanged == true) //Turn on main lights when they are off and toggled.
{
toggleChanged = false;
if (mainLightsOn == false)
{
mainLightsOn = true;
ReefAngel.Relay.On(Port1);
ReefAngel.Relay.On(Port2);
}
else
{
mainLightsOn = false;
ReefAngel.Relay.Off(Port1);
ReefAngel.Relay.Off(Port2);
}
}
if (toggleFugeLights == true && toggleChanged == false) //Turn off fuge lights when they are on and toggled.
{
toggleChanged = true;
if (fugeLightsOn == true)
{
fugeLightsOn = false;
ReefAngel.Relay.Off(Port3);
}
else
{
fugeLightsOn = true;
ReefAngel.Relay.On(Port3);
}
}
if (toggleFugeLights == false && toggleChanged == true) //Turn on fuge lights when they are off and toggled.
{
toggleChanged = false;
if (fugeLightsOn == false)
{
fugeLightsOn = true;
ReefAngel.Relay.On(Port3);
}
else
{
fugeLightsOn = false;
ReefAngel.Relay.Off(Port3);
}
}
//Reset the automatic water change variable every day at midnight
if (hour() == 0 && minute() == 0)
{
AWCToday == false;
}
}
//Custom Menu Code
prog_char menu0_label[] PROGMEM = "Feeding Mode";
prog_char menu1_label[] PROGMEM = "Start Auto Water Change";
prog_char menu2_label[] PROGMEM = "Toggle Acclimation Mode";
prog_char menu3_label[] PROGMEM = "Toggle DT Lights";
prog_char menu4_label[] PROGMEM = "Toggle Fuge Lights";
prog_char menu5_label[] PROGMEM = "ATO Clear";
prog_char menu6_label[] PROGMEM = "pH Calibration";
prog_char menu7_label[] PROGMEM = "Toggle All Pumps";
PROGMEM const char *menu_items[] = {
menu0_label, menu1_label, menu2_label, menu3_label, menu4_label,
menu5_label, menu6_label, menu7_label
};
void MenuEntry1()
{
ReefAngel.FeedingModeStart();
}
void MenuEntry2()
{
AWCToday = true;
AWC();
}
void MenuEntry3()
{
if (acclimationMode == false)
{
if (!ReefAngel.HighATO.IsActive())
{
AWCTimer = now();
ReefAngel.Relay.On(ATOPump); //Fill the return section to the high float with RODI.
while (true)
{
if (ReefAngel.HighATO.IsActive())
{
ReefAngel.Relay.Off(ATOPump); //Turn off the RODI pump once the high float is triggered.
break;
}
else if ((now() - AWCTimer) >= ATOTimeOut)
{
ReefAngel.Relay.Off(ATOPump); //Turn off the RODI pump.
bitSet(ReefAngel.AlertFlags,ATOTimeOutFlag); //Trigger ATO timeout flag.
break;
}
}
}
if (!ReefAngel.isATOTimeOut())
{
acclimationMode = true;
fillPump = AWCFillPump;
ATOTimeOut = AWCFillSecs;
}
}
else
{
acclimationMode = false;
fillPump = ATOPump;
ATOTimeOut = 300;
}
}
void MenuEntry4()
{
if (toggleMainLights == false)
{
toggleMainLights = true;
}
else
{
toggleMainLights = false;
}
}
void MenuEntry5()
{
if (toggleFugeLights == false)
{
toggleFugeLights = true;
}
else
{
toggleFugeLights = false;
}
}
void MenuEntry6()
{
ReefAngel.ATOClear();
ReefAngel.DisplayMenuEntry("Clear ATO Timeout");
}
void MenuEntry7()
{
ReefAngel.StartSetupCalibrateChoicePH();
ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}
void MenuEntry8()
{
ReefAngel.WaterChangeModeStart();
}
void DrawCustomMain()
{
// the graph is drawn/updated when we exit the main menu & when the parameters are saved
ReefAngel.LCD.DrawDate(6, 112);
pingSerial();
//Change these values as needed. They are the threshold values for the low and high temperatures, respectively.
int lowTempValue = 760;
int highTempValue = 770;
byte tempColor;
//To make changes for each temp sensor, change the value of tempColor to be the appropriate color
if ( ReefAngel.Params.Temp[T1_PROBE] < lowTempValue ) { tempColor = COLOR_BLUE; }
else if ( ReefAngel.Params.Temp[T1_PROBE] > highTempValue ) { tempColor = COLOR_RED; }
else { tempColor = COLOR_SEAGREEN; }
//Display the T1 temperature starting at 8, 67
ReefAngel.LCD.DrawText(tempColor, DefaultBGColor, 8, 67, "Temp:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.Temp[T1_PROBE], tempColor, 38, 67, 10);
//Change these values as needed. They are the threshold values for the low and high pH, respectively.
int lowpHValue = 660;
int highpHValue = 670;
byte pHColor;
//Depending upon the temperature, change the value of pHColor to be the appropriate color
if ( ReefAngel.Params.PH < lowpHValue ) { pHColor = COLOR_YELLOW; }
else if ( ReefAngel.Params.PH > highpHValue ) { pHColor = COLOR_RED; }
else { pHColor = COLOR_SEAGREEN; }
//Display the pH starting at 83, 67
ReefAngel.LCD.DrawText(pHColor, DefaultBGColor, 83, 67, "pH:");
ReefAngel.LCD.DrawSingleMonitor(ReefAngel.Params.PH, pHColor, 100, 67, 100);
pingSerial();
//Display relay box 1 ports with status at 12,81
byte TempRelay = ReefAngel.Relay.RelayData;
TempRelay &= ReefAngel.Relay.RelayMaskOff;
TempRelay |= ReefAngel.Relay.RelayMaskOn;
ReefAngel.LCD.DrawOutletBox(12, 81, TempRelay);
//Display relay box 2 ports with status at 12,93
TempRelay = ReefAngel.Relay.RelayDataE[0];
TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
ReefAngel.LCD.DrawOutletBox(12, 93, TempRelay);
}
void DrawCustomGraph()
{
//Print "Gabe's Grad Reef" at the top of the screen
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 18, 2, "Gabe's Grad Reef");
ReefAngel.LCD.DrawGraph(5,11);
}
////// Place global variable code above here
void setup()
{
ReefAngel.Init();
ReefAngel.FeedingModePorts = Port5Bit | Port7Bit | Port8Bit; //Turn off ports 5, 7, & 8 when feeding mode is activated
ReefAngel.FeedingModePortsE[0] = Port4Bit | Port5Bit | Port6Bit; // Turn off box1_ports 4-6 when feeding mode is activated
ReefAngel.WaterChangePorts = Port4Bit | Port5Bit | Port6Bit | Port7Bit | Port8Bit; // Turn off ports 4-8 when water change mode is activated
ReefAngel.WaterChangePortsE[0] = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit; // Turn off box1_ports 1-6 when water change mode is activated
ReefAngel.Relay.On(Port5); //Turn on Port 5
ReefAngel.Relay.On(Port6); //Turn on Port 6
ReefAngel.Relay.On(Port7); //Turn on Port 7
ReefAngel.Relay.On(Port8); //Turn on Port 8
}
void loop()
{
if (ATOOn == true) //If ATO is allowed, run the standard reef angel ATO function
{
ReefAngel.StandardATO(fillPump, ATOTimeOut); // Controls ATO with either RODI (normal operation) or new saltwater (acclimation mode only)
}
//Call the light control function (also calls AWC() once per day)
lightControl();
ReefAngel.StandardHeater(Port5,760,770); // Heater on at 76.0F and off at 77.0F
if ((now() - pHTimer) >= 60) //Every 60 seconds, check the pH in the calcium reactor and turn on or off the solenoid
{
pHControl();
pHTimer = now();
}
ReefAngel.PWM.SetDaylight( GyreMode(10,70,10,true)); //Ramp from 10% to 70% with 10 min duration in sync mode
ReefAngel.PWM.SetActinic( GyreMode(10,70,10,false)); //Ramp from 10% to 70% with 10 min duration in Antisync mode
ReefAngel.ShowInterface();
}