Page 1 of 1

New Buzzer is not working correctly.

Posted: Sun Jan 20, 2013 3:24 pm
by mudcat1
I recently added the buzzer accessory to my generation 1 Reef Angel. I would like the buzzer to sound when my ATO reservior is empty or when the sump is going to overflow. I use both float switches to detect both of these conditions and the code seems to be working correctly but the buzzer will not sound. The buzzer is connected to the Actinic channel on my generation 1 relay box. The only time the buzzer does sound is when I manually turn on my Refugium Light which is connect to port 8 on my relay box. The Actinic channel displays 20% when the light is switched on using the controller or the RA Android application. I have intentionally temporarily commented out the buzzer code in my code sample below because it affects the ATO functionality (i.e. relay port 1 for the ATO is turned off). I would normally uncomment the section that starts with "/* added buzzer 1-19-13".

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 <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>

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

// define what each relay port is used for.
#define ATO_pump Port1       // Auto Top Off
#define Dose_Alk Port2       // Dosing Pump Alk
#define Dose_Ca Port3        // Dosing Pump Ca
#define Dose_Mg Port4        // Dosing Pump Mg
#define Powerhead Port5      // Tunze 6105 Powerhead
// #define Unused Port6      // Unused
#define Heater Port7         // Heater
#define Refugium_Light Port8 // Refugium LED Light

// define Internal Memory variables for the 3 dosing pumps
#define Dose_Alk_Seconds 100 // Number of seconds to dose Alk (byte value=90)
#define Dose_Ca_Seconds  101 // Number of seconds to dose Ca (byte value=90)
#define Dose_Mg_Seconds  102 // Number of seconds to dose Mg (byte value=60)

// define Internal Memory variables for Tunze 6105 Powerhead
#define DTime_MinSpeed  103 // Tunze Powerhead Day time Minimum Speed (byte value=30)
#define DTime_MaxSpeed  104 // Tunze Powerhead Day time Minimum Speed (byte value=90)
#define DTime_Duration  105 // Tunze Powerhead Day time Minimum Speed (byte value=3)
#define NTime_MinSpeed  106 // Tunze Powerhead Night time Minimum Speed (byte value=30)
#define NTime_MaxSpeed  107 // Tunze Powerhead Night time Minimum Speed (byte value=50)
#define NTime_Duration  108 // Tunze Powerhead Night time Minimum Speed (byte value=3)
#define NTime_StartTime 109 // Tunze Powerhead Night Start time 10:00 pm (byte value=22) 
#define NTime_EndTime   110 // Tunze Powerhead Night End time 8:00 am (byte value=8)
#define Tunze_ShortPulse 111 // TunzeShortPulse=1 or TunzeLongPulse=0 (byte value=1)

// added buzzer 1-19-13
// Initialize Buzzer variables
byte buzzer=0;
byte overheatflag=0;
byte atoflag=0;

/* added 1-19-13
byte iochannel0flag=0;
byte iochannel1flag=0;
byte iochannel2flag=0;
byte iochannel3flag=0;
byte iochannel4flag=0;
byte iochannel5flag=0;
*/

// define the custom menu descriptions.
#include <avr/pgmspace.h>
prog_char menu0_label[] PROGMEM = "Feeding";
prog_char menu1_label[] PROGMEM = "Water Change";
prog_char menu2_label[] PROGMEM = "ATO Clear";
prog_char menu3_label[] PROGMEM = "Overheat Clear";
prog_char menu4_label[] PROGMEM = "PH Calibration";
prog_char menu5_label[] PROGMEM = "Sump Light On/Off";
prog_char menu6_label[] PROGMEM = "Powerhead On/Off";
prog_char menu7_label[] PROGMEM = "Version";
PROGMEM const char *menu_items[] = {
menu0_label, menu1_label, menu2_label, menu3_label, menu4_label, menu5_label, menu6_label, menu7_label  };

void MenuEntry1()
{
//ReefAngel.DisplayMenuEntry("Feeding");
ReefAngel.FeedingModeStart();

}
void MenuEntry2()
{
//ReefAngel.DisplayMenuEntry("Water Change");
ReefAngel.WaterChangeModeStart();

}
void MenuEntry3()
{
ReefAngel.ATOClear();
ReefAngel.DisplayMenuEntry("Clear ATO Timeout");

}
void MenuEntry4()
{
ReefAngel.OverheatClear();
ReefAngel.DisplayMenuEntry("Clear Overheat");

}
void MenuEntry5()
{
//ReefAngel.DisplayMenuEntry("PH Calibration");
ReefAngel.SetupCalibratePH();
ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;

}
void MenuEntry6()
{
// Clear the screen
ReefAngel.ClearScreen(DefaultBGColor);
// Display some text on the screen.
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 5, 10, "Sump Light On/Off");
// Determine whether the Sump Light is already on.
if (bitRead(ReefAngel.Relay.RelayData, Refugium_Light-1)) { // If relay is on.
  // Toggle MaskOff for the light
  bitWrite(ReefAngel.Relay.RelayMaskOff, Refugium_Light-1, 1-bitRead(ReefAngel.Relay.RelayMaskOff, Refugium_Light-1));
} else { 
  // Toggle the MaskOn for the light
  bitWrite(ReefAngel.Relay.RelayMaskOn, Refugium_Light-1, 1-bitRead(ReefAngel.Relay.RelayMaskOn, Refugium_Light-1));
}
ReefAngel.Relay.Write();
// Tell the controller to cleanup and return to the main screen
ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
// To return to the menu instead, comment out the above line and use
// this line instead
//ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}

void MenuEntry7()
{
// Clear the screen
ReefAngel.ClearScreen(DefaultBGColor);
// Display some text on the screen
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 5, 10, "Powerhead On/Off");
// Determine whether the Powerhead is already on.
if (bitRead(ReefAngel.Relay.RelayData, Powerhead-1)) { // If relay is on.
  // Toggle MaskOff for the powerhead
  bitWrite(ReefAngel.Relay.RelayMaskOff, Powerhead-1, 1-bitRead(ReefAngel.Relay.RelayMaskOff, Powerhead-1));
} else { 
  // Toggle the MaskOn for the powerhead
  bitWrite(ReefAngel.Relay.RelayMaskOn, Powerhead-1, 1-bitRead(ReefAngel.Relay.RelayMaskOn, Powerhead-1));
}
ReefAngel.Relay.Write();
// Tell the controller to cleanup and return to the main screen
ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
// To return to the menu instead, comment out the above line and use
// this line instead
//ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}

void MenuEntry8()
{
//ReefAngel.DisplayMenuEntry("Display Version");
ReefAngel.DisplayVersion();

}

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

void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Initialize the menu - Added 1-7-13
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port5Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit;
    // Ports toggled when Lights On / Off menu entry selected
    ReefAngel.LightsOnPorts = Port8Bit;
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port7Bit;
    // 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( Powerhead ); // Tunze 6105 powerhead 
}

////// Place additional initialization code below here

// Setup SMS alerts
void WifiSendAlert(byte id, boolean IsAlert)
{
  static byte alert_status;
  if (IsAlert) {
    if ((alert_status & 1<<(id-1))==0) {
      alert_status|=1<<(id-1);
      Serial.print("GET /status/alert.asp?e=3141234567@vtext.com&id=");
      Serial.println(alert_status,DEC);
      Serial.println("\n\n"); 
    }
  }
  else {
    if (id==0) {
      alert_status=0;
      delay(900);
    }
    else {
      alert_status&=~(1<<(id-1)); 
    }
  }
}

// Tunze short pulse functions
  byte TunzeShortPulse(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
  byte tspeed=0;
  PulseMinSpeed=constrain(PulseMinSpeed,0,100);
  PulseMaxSpeed=constrain(PulseMaxSpeed,0,100);
  tspeed=(millis()%(PulseDuration*2)<PulseDuration?PulseMinSpeed:PulseMaxSpeed);
  if (PulseSync) 
    return tspeed;
  else 
    return (tspeed==PulseMinSpeed)?PulseMaxSpeed:PulseMinSpeed;
}

// Tunze long pulse functions
byte TunzeLongPulse(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
  byte tspeed=0;
  PulseMinSpeed=constrain(PulseMinSpeed,0,100);
  PulseMaxSpeed=constrain(PulseMaxSpeed,0,100);
  tspeed=(now()%(PulseDuration*2)<PulseDuration?PulseMinSpeed:PulseMaxSpeed);
  if (PulseSync)
    return tspeed;
  else
    return (tspeed==PulseMinSpeed)?PulseMaxSpeed:PulseMinSpeed;
}
////// Place additional initialization code above here

void loop()
{
        
//*** Heater *** added 12-27-12
   ReefAngel.StandardHeater( Heater,755,765 );

//*** Refugium Light *** added 12-27-12 - turn light on at 8:00 pm and off at 8:00 am.
   ReefAngel.StandardLights( Refugium_Light,20,0,8,0 );
    
////// Place your custom code below here
   ReefAngel.CustomVar[0]=InternalMemory.read(Dose_Alk_Seconds);
   ReefAngel.CustomVar[1]=InternalMemory.read(Dose_Ca_Seconds);
   ReefAngel.CustomVar[2]=InternalMemory.read(Dose_Mg_Seconds);
   ReefAngel.CustomVar[3]=ReefAngel.LowATO.IsActive();
   ReefAngel.CustomVar[4]=ReefAngel.HighATO.IsActive();
   ReefAngel.CustomVar[5]=InternalMemory.read(Tunze_ShortPulse);
   ReefAngel.CustomVar[6]=InternalMemory.read(DTime_MaxSpeed);   
   ReefAngel.CustomVar[7]=InternalMemory.read(NTime_MaxSpeed);

// added buzzer 1-19-13    
   // Sound buzzer if any flag is set.
//   buzzer = overheatflag + atoflag + iochannel0flag + iochannel1flag + iochannel2flag + iochannel3flag + iochannel4flag + iochannel5flag;
   buzzer = overheatflag + atoflag;
   if ( buzzer >= 1 ) buzzer = 100;
   ReefAngel.PWM.SetActinic( buzzer );
/*
// Night mode for Tunze powerheads starts at 10:00 pm and stops at 8:00 am. ShortPulse creates more random length pulses.
   if ( (hour() >= 22) || (hour() <= 8) ){
     if ( Tunze_ShortPulse == 1 ){ // Determine which TunzePulse type has been selected. 
       ReefAngel.PWM.SetDaylight( TunzeShortPulse(30,50,3,false) );} 
     else {
       ReefAngel.PWM.SetDaylight( TunzeLongPulse(30,50,3,false) );} 
   }  
   else {
   // Day mode for Tunze powerheads
     if (Tunze_ShortPulse == 1){ // Determine which TunzePulse type has been selected. 
       ReefAngel.PWM.SetDaylight( TunzeShortPulse(30,90,3,false) );} 
     else {
       ReefAngel.PWM.SetDaylight( TunzeLongPulse(30,90,3,false) );} 
   }
*/ 
/*  
// Night mode for Tunze powerheads LongPulse starts at 10:00 pm and stops at 8:00 am. LongPulse completely stops the pump between pulses.
   if ( (hour() >= 22) || (hour() <= 8) ){
     ReefAngel.PWM.SetDaylight( TunzeLongPulse(30,50,3,false) ); 
   } 
   else {
   // Day mode for Tunze powerheads
     ReefAngel.PWM.SetDaylight( TunzeLongPulse(30,90,3,false) ); 
   }
*/
// added 1-19-13
// Night mode for Tunze powerheads starts at 10:00 pm and stops at 8:00 am. ShortPulse creates more random length pulses.
// LongPulse completely stops the pump between pulses.
   if ( (hour() >= InternalMemory.read(NTime_StartTime)) || (hour() <= InternalMemory.read(NTime_EndTime)) ){
     if ( Tunze_ShortPulse == 1 ){ // Determine which Tunze Pulse type (Short or Long) has been selected. 
       ReefAngel.PWM.SetDaylight( TunzeShortPulse(InternalMemory.read(NTime_MinSpeed),InternalMemory.read(NTime_MaxSpeed),InternalMemory.read(NTime_Duration),false) );} 
     else {
       ReefAngel.PWM.SetDaylight( TunzeLongPulse(InternalMemory.read(NTime_MinSpeed),InternalMemory.read(NTime_MaxSpeed),InternalMemory.read(NTime_Duration),false) );} 
   } 
   else {
   // Day mode for Tunze powerheads
     if ( Tunze_ShortPulse == 1 ){ // Determine which Tunze Pulse (Short or Long) type has been selected. 
       ReefAngel.PWM.SetDaylight( TunzeShortPulse(InternalMemory.read(DTime_MinSpeed),InternalMemory.read(DTime_MaxSpeed),InternalMemory.read(DTime_Duration),false) );} 
     else {
       ReefAngel.PWM.SetDaylight( TunzeLongPulse(InternalMemory.read(DTime_MinSpeed),InternalMemory.read(DTime_MaxSpeed),InternalMemory.read(DTime_Duration),false) );} 
   }

/* **** DOSING ****
   Future enhancement: Add code to set the dosing time from a variable in the web portal or android application, so I don't have to 
   upload code everytime I want to make slight adjustments to the amount I dose.
*/

// Dose Alk one time per hour between 8:00 pm and 5:00 am.
// Note: Because this dosing occurs for less than 5 minutes it will not be recorded in the Relay activity view in the web portal
   if ( hour() >=20 || hour() <5) {
     ReefAngel.DosingPumpRepeat( Dose_Alk,0,60,InternalMemory.read(Dose_Alk_Seconds)); } // Dose Alk for x number of seconds at the top of the hour.
   else {
     ReefAngel.Relay.Off( Dose_Alk );
   }  

// Dose Ca and Mg one time per hour between 9:00 am and 6:00 pm.
// Note: Because this dosing occurs for less than 5 minutes it will not be recorded in the Relay activity view in the web portal.
   if ( hour() >=9 && hour() <18) {
     ReefAngel.DosingPumpRepeat( Dose_Ca,0,60,InternalMemory.read(Dose_Ca_Seconds)); // Dose Ca for x number of seconds at the top of the hour.
     ReefAngel.DosingPumpRepeat( Dose_Mg,10,60,InternalMemory.read(Dose_Mg_Seconds)); } // Dose Mg for x number of seconds 10 minutes after the top of the hour.
   else {
     ReefAngel.Relay.Off( Dose_Ca );
     ReefAngel.Relay.Off( Dose_Mg );
   }

/* **** SMS TEXT ALERTS ****
Future enhancement: Allow us to add custom text for SMS alerts.

 List of the possible alert codes.
   WifiSendAlert(0)="Nothing"
   WifiSendAlert(1)="Auto top-off timeout"
   WifiSendAlert(2)="Water temperature too high"
   WifiSendAlert(3)="Water temperature too low"
   WifiSendAlert(4)="Lights temperature too high"
   WifiSendAlert(5)="PH too high"
   WifiSendAlert(6)="PH too low Alert"

   Let's say you would like to receive a high water temperature alert.
   The line you have to add is:
   if (ReefAngel.Params.Temp1>820) WifiSendAlert(2);
*/
// Send SMS text message alert if temp1 is less than 74.5 degrees.    
   if (ReefAngel.Params.Temp[1]<745 && ReefAngel.Params.Temp[1]>0) WifiSendAlert(3,true); 
// Send SMS text message alert if temp1 is greater than 82 degrees.
   if (ReefAngel.Params.Temp[1]>820 && ReefAngel.Params.Temp[1]<1850) WifiSendAlert(2,false);

//*** ATO *** added 12-29-12
// Shutoff ATO pump if the ATO reservoir is empty or if the sump is going to overflow.        
   if (!ReefAngel.LowATO.IsActive() || !ReefAngel.HighATO.IsActive()){
      ReefAngel.Relay.Off (ATO_pump);} 
/*  added buzzer 1-19-13 
//    Determine which channel the buzzer is attached to (i.e. daylight or actinic) and uncomment the appropriate code below.
//    Do not sound the buzzer for empty ATO reservior between 7:00 am and 10:00 pm.
      if ( hour() >= 7 && hour() < 22) {
        // Sound the buzzer on the actinic channel for 100ms every 30 seconds. 
        ReefAngel.PWM.SetActinic( buzzer );
        // Sound the buzzer on the actinic channel for 1/2 second every 2 minutes. 
//        ReefAngel.PWM.SetActinic(millis()%120000<500?buzzer:0);
      }
*/      
   else {
      ReefAngel.Relay.On (ATO_pump);
   }
  
  ////// Place your custom code above here

// This should always be the last line
   ReefAngel.Portal( "mudcat1" );
   ReefAngel.ShowInterface();
   }
I am also trying to determine what the difference is between the TunzeShortPulse and TunzeLongPulse code so I have added an condition that will allow me to switch which Tunze code is in use while I have my hand in the tank so I can feel the changes in flow. I am not sure that I have coded the if statement correctly.

if ( Tunze_ShortPulse == 1 ){ // Determine which TunzePulse type has been selected.

I would appreciate any assistance you can provide to me.

Thanks,
John

Re: New Buzzer is not working correctly.

Posted: Sun Jan 20, 2013 7:26 pm
by Piper

Code: Select all

buzzer = overheatflag + atoflag;
if ( buzzer >= 1 ) buzzer = 100;
ReefAngel.PWM.SetActinic( buzzer )
I looked quickly but I don't see where you set overheatflag or atoflag to anything other than zero so you never pass your if test to set the buzzer. For ATO, check out ReefAngel.LowATO.IsActive() anf for overheat check out InternalMemory.read( Overheat_Exceed_Flag );. Use those to trip your flags.

~Charlie

Re: New Buzzer is not working correctly.

Posted: Sun Jan 20, 2013 7:32 pm
by rimai
What Charlie said :)
Change your ATO check to this:

Code: Select all

   if (!ReefAngel.LowATO.IsActive() || !ReefAngel.HighATO.IsActive()){
      atoflag=1;
      ReefAngel.Relay.Off (ATO_pump);} 
The short pulse is milliseconds duration and long pulse is seconds duration.

Re: New Buzzer is not working correctly.

Posted: Sun Jan 20, 2013 9:43 pm
by mudcat1
Charlie and Roberto,
Thanks for your help. I added the atoflag=1 code that you suggested and the buzzer is working correctly. I am still having one problem though. For some reason the Actinic channel is showing 20% so the buzzer comes on. I am not sure what is causing this. It may be because the Refugium light (on Port 8) is now on. Do you have any suggestions?

Thanks again,
John

Re: New Buzzer is not working correctly.

Posted: Sun Jan 20, 2013 9:58 pm
by Piper
Can you post the updated code? When you say you added atoflag=1, was that to the section that Roberto noted above?

And one more question. When you say:
I would like the buzzer to sound when my ATO reservior is empty or when the sump is going to overflow.
One of your float switches is in your ATO reservior?

Re: New Buzzer is not working correctly.

Posted: Sun Jan 20, 2013 10:00 pm
by rimai

Code: Select all

ReefAngel.LightsOnPorts = Port8Bit;
Just remove the port 8 from there.

Re: New Buzzer is not working correctly.

Posted: Mon Jan 21, 2013 8:54 am
by mudcat1
Piper wrote:Can you post the updated code? When you say you added atoflag=1, was that to the section that Roberto noted above?

Charlie, here is my latest 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 <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>

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

// define what each relay port is used for.
#define ATO_pump Port1       // Auto Top Off
#define Dose_Alk Port2       // Dosing Pump Alk
#define Dose_Ca Port3        // Dosing Pump Ca
#define Dose_Mg Port4        // Dosing Pump Mg
#define Powerhead Port5      // Tunze 6105 Powerhead
// #define Unused Port6      // Unused
#define Heater Port7         // Heater
#define Refugium_Light Port8 // Refugium LED Light

// define Internal Memory variables for the 3 dosing pumps
#define Dose_Alk_Seconds 100 // Number of seconds to dose Alk (byte value=90)
#define Dose_Ca_Seconds  101 // Number of seconds to dose Ca (byte value=90)
#define Dose_Mg_Seconds  102 // Number of seconds to dose Mg (byte value=60)

// define Internal Memory variables for Tunze 6105 Powerhead
#define DTime_MinSpeed  103 // Tunze Powerhead Day time Minimum Speed (byte value=30)
#define DTime_MaxSpeed  104 // Tunze Powerhead Day time Minimum Speed (byte value=90)
#define DTime_Duration  105 // Tunze Powerhead Day time Minimum Speed (byte value=3)
#define NTime_MinSpeed  106 // Tunze Powerhead Night time Minimum Speed (byte value=30)
#define NTime_MaxSpeed  107 // Tunze Powerhead Night time Minimum Speed (byte value=50)
#define NTime_Duration  108 // Tunze Powerhead Night time Minimum Speed (byte value=3)
#define NTime_StartTime 109 // Tunze Powerhead Night Start time 10:00 pm (byte value=22) 
#define NTime_EndTime   110 // Tunze Powerhead Night End time 8:00 am (byte value=8)
#define Tunze_ShortPulse 111 // TunzeShortPulse=1 or TunzeLongPulse=0 (byte value=1)

// added buzzer 1-19-13
// Initialize Buzzer variables
byte buzzer=0;
byte overheatflag=0;
byte atoflag=0;

/* added 1-19-13
byte iochannel0flag=0;
byte iochannel1flag=0;
byte iochannel2flag=0;
byte iochannel3flag=0;
byte iochannel4flag=0;
byte iochannel5flag=0;
*/

// define the custom menu descriptions.
#include <avr/pgmspace.h>
prog_char menu0_label[] PROGMEM = "Feeding";
prog_char menu1_label[] PROGMEM = "Water Change";
prog_char menu2_label[] PROGMEM = "ATO Clear";
prog_char menu3_label[] PROGMEM = "Overheat Clear";
prog_char menu4_label[] PROGMEM = "PH Calibration";
prog_char menu5_label[] PROGMEM = "Sump Light On/Off";
prog_char menu6_label[] PROGMEM = "Powerhead On/Off";
prog_char menu7_label[] PROGMEM = "Version";
PROGMEM const char *menu_items[] = {
menu0_label, menu1_label, menu2_label, menu3_label, menu4_label, menu5_label, menu6_label, menu7_label  };

void MenuEntry1()
{
//ReefAngel.DisplayMenuEntry("Feeding");
ReefAngel.FeedingModeStart();

}
void MenuEntry2()
{
//ReefAngel.DisplayMenuEntry("Water Change");
ReefAngel.WaterChangeModeStart();

}
void MenuEntry3()
{
ReefAngel.ATOClear();
ReefAngel.DisplayMenuEntry("Clear ATO Timeout");

}
void MenuEntry4()
{
ReefAngel.OverheatClear();
ReefAngel.DisplayMenuEntry("Clear Overheat");

}
void MenuEntry5()
{
//ReefAngel.DisplayMenuEntry("PH Calibration");
ReefAngel.SetupCalibratePH();
ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;

}
void MenuEntry6()
{
// Clear the screen
ReefAngel.ClearScreen(DefaultBGColor);
// Display some text on the screen.
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 5, 10, "Sump Light On/Off");
// Determine whether the Sump Light is already on.
if (bitRead(ReefAngel.Relay.RelayData, Refugium_Light-1)) { // If relay is on.
  // Toggle MaskOff for the light
  bitWrite(ReefAngel.Relay.RelayMaskOff, Refugium_Light-1, 1-bitRead(ReefAngel.Relay.RelayMaskOff, Refugium_Light-1));
} else { 
  // Toggle the MaskOn for the light
  bitWrite(ReefAngel.Relay.RelayMaskOn, Refugium_Light-1, 1-bitRead(ReefAngel.Relay.RelayMaskOn, Refugium_Light-1));
}
ReefAngel.Relay.Write();
// Tell the controller to cleanup and return to the main screen
ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
// To return to the menu instead, comment out the above line and use
// this line instead
//ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}

void MenuEntry7()
{
// Clear the screen
ReefAngel.ClearScreen(DefaultBGColor);
// Display some text on the screen
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 5, 10, "Powerhead On/Off");
// Determine whether the Powerhead is already on.
if (bitRead(ReefAngel.Relay.RelayData, Powerhead-1)) { // If relay is on.
  // Toggle MaskOff for the powerhead
  bitWrite(ReefAngel.Relay.RelayMaskOff, Powerhead-1, 1-bitRead(ReefAngel.Relay.RelayMaskOff, Powerhead-1));
} else { 
  // Toggle the MaskOn for the powerhead
  bitWrite(ReefAngel.Relay.RelayMaskOn, Powerhead-1, 1-bitRead(ReefAngel.Relay.RelayMaskOn, Powerhead-1));
}
ReefAngel.Relay.Write();
// Tell the controller to cleanup and return to the main screen
ReefAngel.DisplayedMenu = RETURN_MAIN_MODE;
// To return to the menu instead, comment out the above line and use
// this line instead
//ReefAngel.DisplayedMenu = ALT_SCREEN_MODE;
}

void MenuEntry8()
{
//ReefAngel.DisplayMenuEntry("Display Version");
ReefAngel.DisplayVersion();

}

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

void setup()
{
    // This must be the first line
    ReefAngel.Init();  //Initialize controller
    // Initialize the menu - Added 1-7-13
    ReefAngel.InitMenu(pgm_read_word(&(menu_items[0])),SIZE(menu_items));
    // Ports toggled in Feeding Mode
    ReefAngel.FeedingModePorts = Port5Bit;
    // Ports toggled in Water Change Mode
    ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit;
    // Ports toggled when Lights On / Off menu entry selected
//    ReefAngel.LightsOnPorts = Port8Bit;  // removed 1-21-13 to stop the buzzer alarm when sump light was turned on (i.e. 20% Actinic)
    // Ports turned off when Overheat temperature exceeded
    ReefAngel.OverheatShutoffPorts = Port7Bit;
    // 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( Powerhead ); // Tunze 6105 powerhead 
}

////// Place additional initialization code below here

// Setup SMS alerts
void WifiSendAlert(byte id, boolean IsAlert)
{
  static byte alert_status;
  if (IsAlert) {
    if ((alert_status & 1<<(id-1))==0) {
      alert_status|=1<<(id-1);
      Serial.print("GET /status/alert.asp?e=3141234567@vtext.com&id=");
      Serial.println(alert_status,DEC);
      Serial.println("\n\n"); 
    }
  }
  else {
    if (id==0) {
      alert_status=0;
      delay(900);
    }
    else {
      alert_status&=~(1<<(id-1)); 
    }
  }
}

// Tunze short pulse functions
  byte TunzeShortPulse(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
  byte tspeed=0;
  PulseMinSpeed=constrain(PulseMinSpeed,0,100);
  PulseMaxSpeed=constrain(PulseMaxSpeed,0,100);
  tspeed=(millis()%(PulseDuration*2)<PulseDuration?PulseMinSpeed:PulseMaxSpeed);
  if (PulseSync) 
    return tspeed;
  else 
    return (tspeed==PulseMinSpeed)?PulseMaxSpeed:PulseMinSpeed;
}

// Tunze long pulse functions
byte TunzeLongPulse(byte PulseMinSpeed, byte PulseMaxSpeed, int PulseDuration, boolean PulseSync)
{
  byte tspeed=0;
  PulseMinSpeed=constrain(PulseMinSpeed,0,100);
  PulseMaxSpeed=constrain(PulseMaxSpeed,0,100);
  tspeed=(now()%(PulseDuration*2)<PulseDuration?PulseMinSpeed:PulseMaxSpeed);
  if (PulseSync)
    return tspeed;
  else
    return (tspeed==PulseMinSpeed)?PulseMaxSpeed:PulseMinSpeed;
}
////// Place additional initialization code above here

void loop()
{
        
//*** Heater *** added 12-27-12
   ReefAngel.StandardHeater( Heater,755,765 );

//*** Refugium Light *** added 12-27-12 - turn light on at 8:00 pm and off at 8:00 am.
   ReefAngel.StandardLights( Refugium_Light,20,0,8,0 );
    
////// Place your custom code below here
   ReefAngel.CustomVar[0]=InternalMemory.read(Dose_Alk_Seconds);
   ReefAngel.CustomVar[1]=InternalMemory.read(Dose_Ca_Seconds);
   ReefAngel.CustomVar[2]=InternalMemory.read(Dose_Mg_Seconds);
   ReefAngel.CustomVar[3]=ReefAngel.LowATO.IsActive();
   ReefAngel.CustomVar[4]=ReefAngel.HighATO.IsActive();
   ReefAngel.CustomVar[5]=InternalMemory.read(Tunze_ShortPulse);
   ReefAngel.CustomVar[6]=InternalMemory.read(DTime_MaxSpeed);   
   ReefAngel.CustomVar[7]=InternalMemory.read(NTime_MaxSpeed);

// added buzzer 1-19-13    
// Sound buzzer if any flag is set.
//   buzzer = overheatflag + atoflag + iochannel0flag + iochannel1flag + iochannel2flag + iochannel3flag + iochannel4flag + iochannel5flag;
   buzzer = overheatflag + atoflag;
   if ( buzzer >= 1 ) buzzer = 100; // Change value of buzzer to 100 for full volume.
//   Do not sound the buzzer for empty ATO reservior between 7:00 am and 10:00 pm.
   if (!ReefAngel.LowATO.IsActive() && ( hour() >= 7 && hour() < 22)){
      ReefAngel.PWM.SetActinic( buzzer );}
//      // Sound the buzzer on the actinic channel for 1/2 second every 2 minutes. 
//      ReefAngel.PWM.SetActinic(millis()%120000<500?buzzer:0);}

/*
// Night mode for Tunze powerheads starts at 10:00 pm and stops at 8:00 am. ShortPulse creates more random length pulses.
   if ( (hour() >= 22) || (hour() <= 8) ){
     if ( Tunze_ShortPulse == 1 ){ // Determine which TunzePulse type has been selected. 
       ReefAngel.PWM.SetDaylight( TunzeShortPulse(30,50,3,false) );} 
     else {
       ReefAngel.PWM.SetDaylight( TunzeLongPulse(30,50,3,false) );} 
   }  
   else {
   // Day mode for Tunze powerheads
     if (Tunze_ShortPulse == 1){ // Determine which TunzePulse type has been selected. 
       ReefAngel.PWM.SetDaylight( TunzeShortPulse(30,90,3,false) );} 
     else {
       ReefAngel.PWM.SetDaylight( TunzeLongPulse(30,90,3,false) );} 
   }
*/ 
/*  
// Night mode for Tunze powerheads LongPulse starts at 10:00 pm and stops at 8:00 am. LongPulse completely stops the pump between pulses.
   if ( (hour() >= 22) || (hour() <= 8) ){
     ReefAngel.PWM.SetDaylight( TunzeLongPulse(30,50,3,false) ); 
   } 
   else {
   // Day mode for Tunze powerheads
     ReefAngel.PWM.SetDaylight( TunzeLongPulse(30,90,3,false) ); 
   }
*/
// added 1-19-13
// Night mode for Tunze powerheads starts at 10:00 pm and stops at 8:00 am. ShortPulse creates more random length pulses.
// LongPulse completely stops the pump between pulses.
   if ( (hour() >= InternalMemory.read(NTime_StartTime)) || (hour() <= InternalMemory.read(NTime_EndTime)) ){
     if ( Tunze_ShortPulse == 1 ){ // Determine which Tunze Pulse type (Short or Long) has been selected. 
       ReefAngel.PWM.SetDaylight( TunzeShortPulse(InternalMemory.read(NTime_MinSpeed),InternalMemory.read(NTime_MaxSpeed),InternalMemory.read(NTime_Duration),false) );} 
     else {
       ReefAngel.PWM.SetDaylight( TunzeLongPulse(InternalMemory.read(NTime_MinSpeed),InternalMemory.read(NTime_MaxSpeed),InternalMemory.read(NTime_Duration),false) );} 
   } 
   else {
   // Day mode for Tunze powerheads
     if ( Tunze_ShortPulse == 1 ){ // Determine which Tunze Pulse (Short or Long) type has been selected. 
       ReefAngel.PWM.SetDaylight( TunzeShortPulse(InternalMemory.read(DTime_MinSpeed),InternalMemory.read(DTime_MaxSpeed),InternalMemory.read(DTime_Duration),false) );} 
     else {
       ReefAngel.PWM.SetDaylight( TunzeLongPulse(InternalMemory.read(DTime_MinSpeed),InternalMemory.read(DTime_MaxSpeed),InternalMemory.read(DTime_Duration),false) );} 
   }

/* **** DOSING ****
   Future enhancement: Add code to set the dosing time from a variable in the web portal or android application, so I don't have to 
   upload code everytime I want to make slight adjustments to the amount I dose.
*/

// Dose Alk one time per hour between 8:00 pm and 5:00 am.
// Note: Because this dosing occurs for less than 5 minutes it will not be recorded in the Relay activity view in the web portal
   if ( hour() >=20 || hour() <5) {
     ReefAngel.DosingPumpRepeat( Dose_Alk,0,60,InternalMemory.read(Dose_Alk_Seconds)); } // Dose Alk for x number of seconds at the top of the hour.
   else {
     ReefAngel.Relay.Off( Dose_Alk );
   }  

// Dose Ca and Mg one time per hour between 9:00 am and 6:00 pm.
// Note: Because this dosing occurs for less than 5 minutes it will not be recorded in the Relay activity view in the web portal.
   if ( hour() >=9 && hour() <18) {
     ReefAngel.DosingPumpRepeat( Dose_Ca,0,60,InternalMemory.read(Dose_Ca_Seconds)); // Dose Ca for x number of seconds at the top of the hour.
     ReefAngel.DosingPumpRepeat( Dose_Mg,10,60,InternalMemory.read(Dose_Mg_Seconds)); } // Dose Mg for x number of seconds 10 minutes after the top of the hour.
   else {
     ReefAngel.Relay.Off( Dose_Ca );
     ReefAngel.Relay.Off( Dose_Mg );
   }

/* **** SMS TEXT ALERTS ****
Future enhancement: Allow us to add custom text for SMS alerts.

 List of the possible alert codes.
   WifiSendAlert(0)="Nothing"
   WifiSendAlert(1)="Auto top-off timeout"
   WifiSendAlert(2)="Water temperature too high"
   WifiSendAlert(3)="Water temperature too low"
   WifiSendAlert(4)="Lights temperature too high"
   WifiSendAlert(5)="PH too high"
   WifiSendAlert(6)="PH too low Alert"

   Let's say you would like to receive a high water temperature alert.
   The line you have to add is:
   if (ReefAngel.Params.Temp1>820) WifiSendAlert(2);
*/
// Send SMS text message alert if temp1 is less than 74.5 degrees.    
   if (ReefAngel.Params.Temp[1]<745 && ReefAngel.Params.Temp[1]>0) WifiSendAlert(3,true); 
// Send SMS text message alert if temp1 is greater than 82 degrees.
   if (ReefAngel.Params.Temp[1]>820 && ReefAngel.Params.Temp[1]<1850) WifiSendAlert(2,false);

//*** ATO *** added 12-29-12
// Shutoff ATO pump if the ATO reservoir is empty or if the sump is going to overflow.        
   if (!ReefAngel.LowATO.IsActive() || !ReefAngel.HighATO.IsActive()){
     atoflag=1;  // added 1-20-13 to start buzzer alarm.
     ReefAngel.Relay.Off (ATO_pump);} 
   else {
     atoflag=0; // added 1-21-13 to reset buzzer.
     ReefAngel.Relay.On (ATO_pump);}
   
  ////// Place your custom code above here

// This should always be the last line
   ReefAngel.Portal( "mudcat1" );
   ReefAngel.ShowInterface();
   }
And one more question. When you say:
I would like the buzzer to sound when my ATO reservior is empty or when the sump is going to overflow.
One of your float switches is in your ATO reservior?
Yes, I have mounted a float switch (ATOLow) to the bottom of my ATO reservoir. I also flipped the float so that it would display a green indicator in the Reef Angel client (rather than the default red indicator).

I am also attempting to only sound the alarm, if the ATO reservoir is empty, between the hours of 7 am and 10 pm because I am sure my wife would kill me in my sleep if I didn't. She already hates the sound of the buzzer. ;)

Which reminds me is there an easy way to stop the buzzer? I thought the "Clear ATO" option on the simple menu might do it but I am unsure about what exactly it does.

Re: New Buzzer is not working correctly.

Posted: Mon Jan 21, 2013 8:57 am
by mudcat1
rimai wrote:

Code: Select all

ReefAngel.LightsOnPorts = Port8Bit;
Just remove the port 8 from there.
Thanks Roberto, that stopped the buzzer from sounding when I manually turn on the sump light from the menu. Are there any other setting that will cause the Actinic 20%? There is still something that causes it to occur occassionally. I have posted my latest code in the post above.

Re: New Buzzer is not working correctly.

Posted: Mon Jan 21, 2013 9:00 am
by mudcat1
My code is still not working correctly. The buzzer starts when it should not and the Actinic channel is displaying 100%.

Re: New Buzzer is not working correctly.

Posted: Mon Jan 21, 2013 9:33 am
by rimai
The buzzer is set to turn on anytime any of the floats is not active, in other words, when they are not floating if pointing down (away from C clip).

Re: New Buzzer is not working correctly.

Posted: Mon Jan 21, 2013 11:35 am
by mudcat1
rimai wrote:The buzzer is set to turn on anytime any of the floats is not active, in other words, when they are not floating if pointing down (away from C clip).
Roberto, is that true even if I have intentionally flipped the float on the ATOLow float switch? I did that so the green indicator would come on in the Reef Angel Client instead of the red indicator which was the default.

When I trigger the ATOHigh float (make it float away from the C clip) the buzzer will not sound, but the relay does shut off as it should though. I want the buzzer to sound when my sump is about to overflow and I use the ATOHigh float to detect it. This is the code I am currently using to stop the relay which is working correctly. I thought I should add the atoflag to start and stop the buzzer.

Code: Select all

// Shutoff ATO pump if the ATO reservoir is empty or if the sump is going to overflow.        
   if (!ReefAngel.LowATO.IsActive() || !ReefAngel.HighATO.IsActive()){
     atoflag=1;  // added 1-20-13 to start buzzer alarm.
     ReefAngel.Relay.Off (ATO_pump);} 
   else {
     atoflag=0; // added 1-21-13 to reset buzzer.
     ReefAngel.Relay.On (ATO_pump);}
This is the buzzer code

Code: Select all

  buzzer = overheatflag + atoflag;
   if ( buzzer >= 1 ) buzzer = 100; // Change value of buzzer to 100 for full volume.
//   Do not sound the buzzer for empty ATO reservior between 7:00 am and 10:00 pm.
   if (!ReefAngel.LowATO.IsActive() && ( hour() >= 7 && hour() < 22)){
      ReefAngel.PWM.SetActinic( buzzer );}


What am I missing?

Re: New Buzzer is not working correctly.

Posted: Mon Jan 21, 2013 11:45 am
by mudcat1
Roberto, after more testing I think the ATOLow switch is working correctly. It sounds the buzzer when the ATO reservoir is empty and I can turn off the buzzer by selecting the "Clear ATO" option from the simple menu. ATOHigh is still not working. I think I need to add a separate condition to trigger the buzzer for ATOHigh. I will try that next.

Re: New Buzzer is not working correctly.

Posted: Mon Jan 21, 2013 11:50 am
by Piper

Code: Select all

buzzer = overheatflag + atoflag;
if ( buzzer >= 1 ) {
  buzzer = 100; // Change value of buzzer to 100 for full volume.
  ReefAngel.PWM.SetActinic(100);
} else {
  ReefAngel.PWM.SetActinic(0);
}
//   Do not sound the buzzer for empty ATO reservior between 7:00 am and 10:00 pm.
if (!ReefAngel.LowATO.IsActive() && ( hour() >= 7 && hour() < 22)){
  ReefAngel.PWM.SetActinic(100);
} else {
  ReefAngel.PWM.SetActinic(0);
}
Does that help at all?

Re: New Buzzer is not working correctly.

Posted: Mon Jan 21, 2013 1:21 pm
by mudcat1
Piper wrote:

Code: Select all

buzzer = overheatflag + atoflag;
if ( buzzer >= 1 ) {
  buzzer = 100; // Change value of buzzer to 100 for full volume.
  ReefAngel.PWM.SetActinic(100);
} else {
  ReefAngel.PWM.SetActinic(0);
}
//   Do not sound the buzzer for empty ATO reservior between 7:00 am and 10:00 pm.
if (!ReefAngel.LowATO.IsActive() && ( hour() >= 7 && hour() < 22)){
  ReefAngel.PWM.SetActinic(100);
} else {
  ReefAngel.PWM.SetActinic(0);
}
Does that help at all?
Charlie, Yes that worked. Thank you for the help. :D