Troubleshooting my INO file

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

Troubleshooting my INO file

Post by gaberosenfield »

Hi everyone,

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();
}
rimai
Posts: 12881
Joined: Fri Mar 18, 2011 6:47 pm

Re: Troubleshooting my INO file

Post by rimai »

You need to initialize your menu system.
Add this to your setup() anywhere after ReefAngel.Init()

Code: Select all

  ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));
Roberto.
User avatar
cosmith71
Posts: 1437
Joined: Fri Mar 29, 2013 3:51 pm
Location: Oklahoma City

Re: Troubleshooting my INO file

Post by cosmith71 »

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?
Yes.

--Colin
gaberosenfield
Posts: 89
Joined: Thu Mar 08, 2012 5:11 pm
Location: Redwood City, California

Re: Troubleshooting my INO file

Post by gaberosenfield »

Thanks Roberto and Colin!

I'm not sure how I missed that I needed to initialize my custom menu... But that fixed all the issues.

BTW, in case you didn't know already and just so that other users might find this info when they search the forum later, custom menus do not display properly if you make the menu entry/label too long to fit on a single line of the screen. I'm not sure exactly how many pixels these labels can be, but if your custom menu isn't showing up properly you should try shortening the menu entries/labels. That worked for me.

Best,
Gabe
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Troubleshooting my INO file

Post by binder »

gaberosenfield wrote:Thanks Roberto and Colin!

I'm not sure how I missed that I needed to initialize my custom menu... But that fixed all the issues.

BTW, in case you didn't know already and just so that other users might find this info when they search the forum later, custom menus do not display properly if you make the menu entry/label too long to fit on a single line of the screen. I'm not sure exactly how many pixels these labels can be, but if your custom menu isn't showing up properly you should try shortening the menu entries/labels. That worked for me.

Best,
Gabe
just a fyi....
I think I wrote a guide on the custom menus (or maybe it was just for custom main screens). regardless, it tells you how many characters will fit with each font size. also, I wrote a Java based app that creates a custom menu for you and I believe it checks the menu text lengths as well.

Sent from my Moto X
binder
Posts: 2871
Joined: Fri Mar 18, 2011 6:20 pm
Location: Illinois
Contact:

Re: Troubleshooting my INO file

Post by binder »

yeah, here's the post...
http://forum.reefangel.com/viewtopic.php?t=1773

Sent from my Moto X
Post Reply