I can't seem to figure out how to use the flexible pH calibration in my custom menu. I click the option in my menu and the screen just flashes and nothing happens. I want to be able to calibrate it for monitoring my calcium reactor and for occasionally testing the pH of my tank itself, so I want the easy option of calibrating it for 5 - 7 or 7 - 10. Here's my 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 <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, both WP-25s, Refugium Flow, QT flow, QT filter, and QT heater - need 8 outlets
#define returnPump Port8
//Port9 (Box1_Port1) - Eventually will be used to control RODI solenoid to fill the RODI barrel when it is close to empty
#define RODI Box1_Port1
//Port10 (Box1_Port2) - Eventually will be used for automatic dry food feeder control - "http://wamas.org/forums/blog/13/entry-46-diy-automatic-feeder-for-aquacontroller/"
#define feeder 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) - Temporary control of QT lights.
#define QTFixture Box1_Port5
//Port14 (Box1_Port6) -
//Port15 (Box1_Port7) - AWC fill pump and QT overflow reservoir drain pump - need 2 outlets
#define AWCFillPump Box1_Port7
//Port16 (Box1_Port8) - AWC drain pump
#define AWCDrainPump Box1_Port8
//Change these values as needed. They are the threshold values for the low and high temperatures, respectively.
int lowTempValue = 730;
int highTempValue = 740;
//defnie dimming channels 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;
//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 = 600;
//The following variables control when automatic water changes occur.
int AWCHour = 21;
int AWCMinute = 0;
//These variables will be used to keep track of the progress of an AWC.
int AWCCheck = 0;
boolean AWCDrainCheck = false;
boolean AWCFail = false;
//This variable will trigger an AWC().
boolean AWC = false;
//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 starting the skimmer pump 5 minutes after the return pump is started in order to preven the skimmer cup from overflowing.
static unsigned long returnTimer = 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 = 180;
int AWCFillSecs = 180;
//This variable will control whether ATO is working.
boolean ATOOn = true;
//These variables will control automatic feeding.
boolean canFeed = false; //Controls when feeding is allowed.
const int feedsPerDay = 4; //Controls number of feedings per 24 hours; must be an even number.
const int feedDelay = 30; //Delay in minutes after lights come on and before lights go out when feeding is allowed.
int feedsToday = 0; //Keeps track of the number of feedings today.
static unsigned long feedTimer = 0; //Compared with feedTime to determine when to feed.
//This function will control automatic feeding.
void feed()
{
if (hour() == 0 && minute() == 0)
feedsToday = 0;
if (canFeed && feedsToday < feedsPerDay)
{
switch (now() - feedTimer)
{
case (feedDelay * 60):
feedsToday += 1;
ReefAngel.FeedingModeStart();
while (true)
{
if ((now() - feedTimer) == (120 + (feedDelay * 60)))
ReefAngel.Relay.On(feeder);
if ((now() - feedTimer) == (121 + (feedDelay * 60)))
{
ReefAngel.Relay.Off(feeder);
break;
}
}
break;
case (21600 - (feedDelay * 60)):
feedsToday += 1;
ReefAngel.FeedingModeStart();
while (true)
{
if ((now() - feedTimer) == (21720 - (feedDelay * 60)))
ReefAngel.Relay.On(feeder);
if ((now() - feedTimer) == (21721 - (feedDelay * 60)))
{
ReefAngel.Relay.Off(feeder);
break;
}
}
break;
}
}
}
//This function will check to make sure the water level in the sump is at the high float before initiating an AWC.
int AWCATOCheck()
{
if (!ReefAngel.Relay.Status(returnPump)) //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.
return 2;
}
else
return 1;
}
//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);
}
}
//Custom Menu Code
prog_char menu0_label[] PROGMEM = "Manual Feed";
prog_char menu1_label[] PROGMEM = "Start AWC";
prog_char menu2_label[] PROGMEM = "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()
{
feedsToday += 1;
unsigned long manualTimer = now();
ReefAngel.FeedingModeStart();
while (true)
{
if ((now() - manualTimer) == 120)
ReefAngel.Relay.On(feeder);
if ((now() - manualTimer) >= 121)
{
ReefAngel.Relay.Off(feeder);
break;
}
}
}
void MenuEntry2()
{
AWCToday = false;
AWC = true;
}
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 = 600;
}
}
void MenuEntry4()
{
if (toggleMainLights)
toggleMainLights = false;
else
toggleMainLights = true;
if (mainLightsOn)
{
mainLightsOn = false;
ReefAngel.Relay.Off(daylightFixture);
ReefAngel.Relay.Off(actinicFixture);
}
else
{
mainLightsOn = true;
ReefAngel.Relay.On(daylightFixture);
ReefAngel.Relay.On(actinicFixture);
}
}
void MenuEntry5()
{
if (toggleFugeLights)
toggleFugeLights = false;
else
toggleFugeLights = true;
if (fugeLightsOn)
{
fugeLightsOn = false;
ReefAngel.Relay.Off(fugeFixture);
}
else
{
fugeLightsOn = true;
ReefAngel.Relay.On(fugeFixture);
}
}
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();
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_MAGENTA; }
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.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));
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.UseFlexiblePhCalibration();
ReefAngel.Relay.On(CaRXPump); //Turn on Port 6
ReefAngel.Relay.On(manifoldPump); //Turn on Port 7
ReefAngel.Relay.On(returnPump); //Turn on Port 8
returnTimer = now(); //Start the return timer
}
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)
}
//Start an AWC once per day at 12 noon if an AWC hasn't happened since midnight and there hasn't been an ATO timeout.
if (!AWCFail && (now() % 86400) == ((AWCHour * 3600) + (AWCMinute * 60)) && !AWCToday && !ReefAngel.isATOTimeOut())
AWC = true; //Sets the AWC control variable to true.
//Reset the automatic water change variable every day at midnight.
if (hour() == 0 && minute() == 0)
AWCToday = false;
//Start the chain of AWC functions.
if(AWC && !AWCToday)
{
AWC = false;
AWCToday = true;
AWCCheck = AWCATOCheck();
}
if (AWCCheck == 2)
{
if (ReefAngel.HighATO.IsActive())
{
ReefAngel.Relay.Off(ATOPump);
AWCCheck = 1;
}
else if ((now() - AWCTimer) >= ATOTimeOut)
{
ReefAngel.Relay.Off(ATOPump);
bitSet(ReefAngel.AlertFlags,ATOTimeOutFlag); //Trigger ATO timeout flag.
AWCFail = true;
AWCCheck = 0;
}
}
else if (AWCCheck == 1)
{
ATOOn = false;
AWCTimer = now();
ReefAngel.Relay.On(AWCDrainPump);
if (ReefAngel.LowATO.IsActive())
{
ReefAngel.Relay.Off(AWCDrainPump);
AWCCheck = 0;
AWCDrainCheck = 1;
}
else if ((now() - AWCTimer) >= AWCDrainSecs)
{
ReefAngel.Relay.Off(AWCDrainPump);
bitSet(ReefAngel.AlertFlags,ATOTimeOutFlag); //Trigger ATO timeout flag.
AWCCheck = 0;
AWCDrainCheck = 0;
ATOOn = true;
AWCFail = true;
}
}
if (AWCDrainCheck == 1)
{
AWCTimer = now();
ReefAngel.Relay.On(AWCFillPump);
if (ReefAngel.HighATO.IsActive())
{
ReefAngel.Relay.Off(AWCFillPump);
ATOOn = true;
AWCDrainCheck = 0;
}
else if ((now() - AWCTimer) >= AWCFillSecs)
{
ReefAngel.Relay.Off(AWCFillPump);
bitSet(ReefAngel.AlertFlags,ATOTimeOutFlag); //Trigger ATO timeout flag.
ATOOn = true;
AWCDrainCheck = 0;
AWCFail = true;
}
}
//Light control
if (hour() < 12 && !toggleMainLights && !toggleFugeLights)
{
ReefAngel.StandardLights(daylightFixture, 6, 0, 12, 0);
ReefAngel.StandardLights(actinicFixture, 6, 0, 12, 0);
ReefAngel.StandardLights(QTFixture, 6, 0, 12, 0);
ReefAngel.StandardLights(fugeFixture, 0, 0, 6, 0);
}
else if (hour() >= 12 && !toggleMainLights && !toggleFugeLights)
{
ReefAngel.StandardLights(daylightFixture, 18, 0, 24, 0);
ReefAngel.StandardLights(actinicFixture, 18, 0, 24, 0);
ReefAngel.StandardLights(QTFixture, 18, 0, 24, 0);
ReefAngel.StandardLights(fugeFixture, 12, 0, 18, 0);
}
//Call the automatic feeding control function and monitor the light schedule to inform the feeding schedule.
feed();
if (ReefAngel.Relay.Status(daylightFixture))
canFeed == true;
else
canFeed == false;
if (hour() == lightsOnHour && minute() == 0)
feedTimer = now();
else if (hour() == (lightsOnHour + 12) && minute() == 0)
feedTimer = now();
ReefAngel.StandardHeater(heater,lowTempValue,highTempValue); // Heater on at 73.0F and off at 74.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();
}
if (returnTimer < 1 && ReefAngel.Relay.Status(returnPump))
returnTimer = now();
if (returnTimer >= 300 && !ReefAngel.Relay.Status(skimmerPump))
ReefAngel.Relay.On(skimmerPump);
ReefAngel.PWM.SetDaylight( GyreMode(20,80,10,true)); //Ramp from 10% to 70% with 10 min duration in sync mode
ReefAngel.PWM.SetActinic( GyreMode(20,80,10,false)); //Ramp from 10% to 70% with 10 min duration in Antisync mode
ReefAngel.Portal("gaberosenfield");
ReefAngel.ShowInterface();
}
Gabe