How to use flexible pH calibration in custom menu?

Do you have a question on how to do something.
Ask in here.
Post Reply
gaberosenfield
Posts: 89
Joined: Thu Mar 08, 2012 5:11 pm
Location: Redwood City, California

How to use flexible pH calibration in custom menu?

Post by gaberosenfield »

Hello wise masters of the RA Libraries,

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();
}
Thanks in advance!
Gabe
Ademster
Posts: 144
Joined: Tue Aug 14, 2012 1:11 pm

Re: How to use flexible pH calibration in custom menu?

Post by Ademster »

use the joy stick to move the cursor to the calibration fluid number 10.1 is default and 7.1 is default you can change them
Adam
58 Gal
Image
gaberosenfield
Posts: 89
Joined: Thu Mar 08, 2012 5:11 pm
Location: Redwood City, California

Re: How to use flexible pH calibration in custom menu?

Post by gaberosenfield »

Sorry, I must have been unclear. When I use the joy stick to click the "Calibrate pH" option on my custom menu, nothing happens. There are no numbers for me to click... I'm trying to figure out how to even have the option to calibrate my pH probe.
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: How to use flexible pH calibration in custom menu?

Post by rimai »

Try removing this:

Code: Select all

ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
Roberto.
gaberosenfield
Posts: 89
Joined: Thu Mar 08, 2012 5:11 pm
Location: Redwood City, California

Re: How to use flexible pH calibration in custom menu?

Post by gaberosenfield »

Sorry for the late reply! Removing the line you suggested, Roberto, allows me to access the regular pH calibration menu. It doesn't give me access to any pH calibration options except 7 and 10. Any ideas on how I can get the option to use 4 and 7 without changing the values in the library?
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: How to use flexible pH calibration in custom menu?

Post by rimai »

Are you sure?
You can navigate to the 7 or 10 and use the joystick up/down to change it.
Roberto.
gaberosenfield
Posts: 89
Joined: Thu Mar 08, 2012 5:11 pm
Location: Redwood City, California

Re: How to use flexible pH calibration in custom menu?

Post by gaberosenfield »

As usual, you are right Roberto; I'm just an idiot and couldn't figure out how to change the number until now... It all works splendidly! Thanks for helping me and being patient!

Best,
Gabe
Post Reply