Cannot adapt lnevo's custom feed mode to delay Port6 start.
Posted: Sun Jan 27, 2013 8:31 pm
I am attempting to use lnevo's custom feeding mode code to delay the start of my skimmer and reactor (both are plugged into relay port 6) for 2 minutes after the 1 minute feed mode timer expires. Some of the code is working correctly but the delayed start of the skimmer and reactor is not working. The skimmer and reactor starts as soon as the feeding timer expires. I have not been able to adapt lnevo's code to work for me. Any suggestions?
See the **** CUSTOM FEEDING MODE **** section of my current code.
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
}