See the **** CUSTOM FEEDING MODE **** section of my current 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 Filtration Port6 // Reef Octopus skimmer and Reactor
#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=34)
#define DTime_MaxSpeed 104 // Tunze Powerhead Day time Maximum Speed (byte value=75 )
#define DTime_Duration 105 // Tunze Powerhead Day time Duration (byte value=3)
#define NTime_MinSpeed 106 // Tunze Powerhead Night time Minimum Speed (byte value=34)
#define NTime_MaxSpeed 107 // Tunze Powerhead Night time Maximum Speed (byte value=50)
#define NTime_Duration 108 // Tunze Powerhead Night time Duration (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)
#define Feedtime 112 // Set length of time for Feeding menu option (byte value=1)
// added buzzer 1-19-13
// Initialize Buzzer variables
byte buzzer=0;
byte overheatflag=0;
byte atoflag=0;
/* added 1-19-13 - Uncomment when I purchase the IO expansion module.
byte iochannel0flag=0;
byte iochannel1flag=0;
byte iochannel2flag=0;
byte iochannel3flag=0;
byte iochannel4flag=0;
byte iochannel5flag=0;
*/
// Added 1-22-13 to delay the start of the skimmer after feeding the corals.
boolean isFeeding=false;
boolean feedDelay=false;
boolean vtOverride=false;
boolean floatHigh=true;
// 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.Timer[FEEDING_TIMER].SetInterval(InternalMemory.read(Feedtime)); // Change feed time interval to ease testing of new code.
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)) { // The relay controlling the sump light 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 | Port6Bit;
// Ports toggled in Water Change Mode
ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port3Bit | Port4Bit | Port5Bit | Port6Bit;
// 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
ReefAngel.Relay.On( Filtration ); // Reef Octopus skimmer and reactor
}
// ************ 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. Uses milliseconds for duration.
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. Uses seconds for duration.
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]=isFeeding;
// ReefAngel.CustomVar[3]=ReefAngel.LowATO.IsActive();
ReefAngel.CustomVar[4]=feedDelay;
// 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.
// Added 1-19-13 - Uncomment when I purchase the IO expansion module.
// 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.
} 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( buzzer );
} else {
ReefAngel.PWM.SetActinic(0);
if (!ReefAngel.HighATO.IsActive()) {
ReefAngel.PWM.SetActinic( buzzer );
} else {
ReefAngel.PWM.SetActinic(0);
}
}
/* ***** TUNZE 6105 ******
Added 1-19-13 to control Tunze 6105 powerhead using internal variables.
Night mode for Tunze powerheads starts at 10:00 pm and stops at 8:00 am. ShortPulse appears to create more random length pulses.
LongPulse appears to completely stop the powerhead 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 ****
Added code to set the dosing time in secondes from a variable in the web portal or android application, so I don't have to
upload code every time I want to make slight adjustments to the amount I dose. BRS dosers dose 1.1 ml per minute.
*/
// 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);
}
/* ****** CUSTOM FEEDING MODE ******
Added 1-22-13 Delay filtration for 120 minutes.
*/
// Enable Feeding Mode flag
if (ReefAngel.DisplayedMenu==FEEDING_MODE) isFeeding=true;
// Turn on Refugium light during feeding and water change mode
if (ReefAngel.DisplayedMenu==FEEDING_MODE || ReefAngel.DisplayedMenu==WATERCHANGE_MODE) {
ReefAngel.Relay.On(Refugium_Light);
}
// Here's what we do if we're just out of feeding mode...
if (ReefAngel.DisplayedMenu==DEFAULT_MENU && isFeeding) {
isFeeding=false;
feedDelay=true; // This will let us know we want some extra time before starting filtration
setRFtimer(2); // Start Filtration in 120 minutes... Change from 2 to 120 minutes after testing
} else if (vtOverride && ReefAngel.Timer[1].IsTriggered()) { // Our RF timer is over.
vtOverride=false; // Stop overriding the default RF mode
// First let's deal with that extra 2 to 120 minutes
if(feedDelay) {
feedDelay=false; // Reset the feedDelay flag
// setRFmode(Smart_NTM,vtNTMSpeed,vtNTMDuration); // Smart_NTM time!
// added 1-27-13
setRFtimer(2); // Start Filtration in 120 minutes... Change from 2 to 120 minutes after testing
ReefAngel.Relay.RelayMaskOff==Port6Bit; // Turn off skimmer and reactor
} else {
// Otherwise go to Previous settings
// setRFmode(vtPrevMode,vtPrevSpeed,vtPrevDuration);
ReefAngel.Relay.RelayMaskOn==Port6Bit; // Turn on skimmer and reactor
}
} else {
// setRFmode(); // Update the mode if we change it remotely
ReefAngel.Relay.RelayMaskOn==Port6Bit; // Turn on skimmer and reactor
}
// I still need to determine how to turn the skimmer and reactor off.
// ************ PLACE YOUR CUSTOM CODE ABOVE HERE *******************
// This should always be the last line
ReefAngel.Portal( "mudcat1" );
ReefAngel.ShowInterface();
}
/*
void setRFmode() {
setRFmode(InternalMemory.RFMode_read(), InternalMemory.RFSpeed_read(), InternalMemory.RFDuration_read());
}
*/
void setRFtimer(int minutes) {
ReefAngel.Timer[1].SetInterval(minutes*60);
ReefAngel.Timer[1].Start();
vtOverride=true;
}
void setRFtimer() {
setRFtimer(2); // Change 5 to 120 minutes after testing
}