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();
}
if ( Tunze_ShortPulse == 1 ){ // Determine which TunzePulse type has been selected.
I would appreciate any assistance you can provide to me.
Thanks,
John