hedrickms code
Posted: Wed Sep 17, 2014 7:49 pm
Ok I am finally giving this a try and posting for all to review/use as necessary. I want to thank everyone on this awesome forum for all the great threads and code samples etc... that hopefully will work (in my code) and that have helped me get this done. I have to admit I was a little scared about attempting this (not a serious coder ... just a fooled around for fun) but after doing some reading/research and studying what has been posted by some very talented folks everything worked out fine and I understand more about this controller. BTW... This is the best purchase I have ever made.
My code: It does all the basic controls...heating/cooling pumping, turn relays, and feeding modes. What is unique is how I am trying to utilize some of these items (nothing fancy). Heating and cooling is based on a seasonal temps (I created my own to try). I set it up so I can adjust every month. The other unique thing is my control of pumps and since my lighting is a reef breeder and not controllable I thought it would be fun to see if I can get a random pump mode (daily) and an occasional storm mode (we'll see if it works).
Please look over and provide any comments/feedback to fix or make better.
Enjoy:
My code: It does all the basic controls...heating/cooling pumping, turn relays, and feeding modes. What is unique is how I am trying to utilize some of these items (nothing fancy). Heating and cooling is based on a seasonal temps (I created my own to try). I set it up so I can adjust every month. The other unique thing is my control of pumps and since my lighting is a reef breeder and not controllable I thought it would be fun to see if I can get a random pump mode (daily) and an occasional storm mode (we'll see if it works).
Please look over and provide any comments/feedback to fix or make better.
Enjoy:
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 <Humidity.h>
#include <DCPump.h>
#include <ReefAngel.h>
#include <WiFiAlert.h>
//******************************************
//define ports
#define Skimmer 1
#define ReturnPump 2
#define FugeLight 3
#define WCPump 4
#define Heater 5
#define Jebao_MP10 6
#define Cooling 7
#define ATOpump 8
//******************************************
////// Place global variable code below here
int avgph[10];
unsigned long totalavgph=0;
byte avgindex=0;
void DrawCustomMain()
{
byte x;
byte y = 2;
char text[7];
// *********** CHANGE TEMP READOUT COLOR DEPENDENT ON FAN AND HEATER STATUS ***********
int TempColor; // Color for drawing temperature
boolean FanOn = ReefAngel.Relay.Status(Cooling); // Get the status of the fan relay
boolean HeatOn = ReefAngel.Relay.Status(Heater); // Get the status of the heater relay
if (HeatOn)
{
TempColor = COLOR_NAVY; // Blue text, too cold, heater is on
}
if (FanOn)
{
TempColor = COLOR_RED; // Red text, too warm, fan is on
}
if (!HeatOn && !FanOn)
{
TempColor = COLOR_GREEN; // Green text, no fan or heater on
}
// ***********************************************************************************
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 30, 2, "Hedrick's REEF"); // Put a banner at the top
ReefAngel.LCD.DrawDate(6, 119); // Put the date and time at the bottom
ReefAngel.LCD.Clear(COLOR_BLACK, 1, 11, 132, 11); // Draw a black line under the banner
x = 6;
y += MENU_START_ROW*1.0; // MENU_START_ROW is 10, according to globals.h, so y=2+10+1=13
ReefAngel.LCD.DrawText(COLOR_BLUE, COLOR_WHITE, x, y+1, "Tank Temp PH");
x = 6;
y = MENU_START_ROW*0.8;
ConvertNumToString(text, ReefAngel.Params.PH, 100); // Get pH reading and convert
ReefAngel.LCD.DrawLargeText(PHColor, DefaultBGColor, x+73, y+12, text, Font8x16); // Put pH on the screen
ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10); // Get T1 temp and convert
x = 6;
y += MENU_START_ROW*1.3;
ReefAngel.LCD.DrawHugeNumbers(COLOR_WHITE, TempColor, x, y, text); // Draw the temperature, white numbers on a colored background
x += 6;
y += MENU_START_ROW*1.2;
ReefAngel.LCD.DrawText(COLOR_BLUE, COLOR_WHITE, x-6, y+5, "Stand Temp");
ConvertNumToString(text, ReefAngel.Params.Temp[T2_PROBE], 10); // Get T2 temp and convert
y += MENU_START_ROW*1.2;
x = 6;
ReefAngel.LCD.DrawHugeNumbers(COLOR_WHITE, TempColor, x, y, text); // Draw the temperature, white numbers on a colored background
x += 6;
y += MENU_START_ROW*2.2;
ReefAngel.LCD.DrawLargeText(COLOR_INDIGO,DefaultBGColor,25,y,"ATO",Font8x8); // Draw the Float switch status
if (ReefAngel.HighATO.IsActive()) {
ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_RED);
} else {
ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_GREEN);
}
x += 6;
y += MENU_START_ROW*1.6;
ReefAngel.LCD.DrawLargeText(COLOR_INDIGO,DefaultBGColor,25,y,"Skimmate",Font8x8);
if (!ReefAngel.LowATO.IsActive()) {
ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_RED);
} else {
ReefAngel.LCD.FillCircle(15,y+3,7,COLOR_GREEN);
}
byte TempRelay = ReefAngel.Relay.RelayData; // Code for drawing the relay box
TempRelay &= ReefAngel.Relay.RelayMaskOff;
TempRelay |= ReefAngel.Relay.RelayMaskOn;
ReefAngel.LCD.DrawOutletBox(12, 100, TempRelay);
}
void DrawCustomGraph()
{
}
////// Place global variable code above here
void setup()
{
// This must be the first line
ReefAngel.Init(); //Initialize controller
ReefAngel.Use2014Screen(); // Let's use 2014 Screen
// Ports toggled in Feeding Mode
ReefAngel.FeedingModePorts = Port1Bit | Port2Bit | Port8Bit;
// Ports toggled in Water Change Mode
ReefAngel.WaterChangePorts = Port1Bit | Port2Bit | Port8Bit;
// Ports toggled when Lights On / Off menu entry selected
ReefAngel.LightsOnPorts = Port3Bit;
// Ports turned off when Overheat temperature exceeded
ReefAngel.OverheatShutoffPorts = Port1Bit | Port3Bit | Port5Bit | Port6Bit;
// Use T1 probe as temperature and overheat functions
ReefAngel.TempProbe = T1_PROBE;
ReefAngel.OverheatProbe = T1_PROBE;
// Set the Overheat temperature setting
InternalMemory.OverheatTemp_write( 840 );
// Feeding and Water Change mode speed
ReefAngel.DCPump.FeedingSpeed=25;
ReefAngel.DCPump.WaterChangeSpeed=0;
// Ports that are always on/off
ReefAngel.Relay.On( ReturnPump );
ReefAngel.Relay.Off( WCPump );
ReefAngel.Relay.On( Jebao_MP10 );
////// Place additional initialization code below here
randomSeed(now()%SECS_PER_DAY);
//Custom Variable [0] = Month/Season
//Custom Variable [1] = NTM Feeding mode time remaining
//Custom Variable [2] = Storm Mode (24/17)
//Custom Variable [3] = Pump Mode
////// Place additional initialization code above here
}//End Setup
void loop()
{
ReefAngel.StandardLights( FugeLight,21,0,9,0 );
// seasonal temperatures
SeasonalTemps();
// skimmer on with delay
ReefAngel.Relay.DelayedOn(Skimmer);
ReefAngel.DCPump.UseMemory = true; //use Portal Settings
ReefAngel.DCPump.ActinicChannel=Sync; // portal settings
ReefAngel.DCPump.DaylightChannel=AntiSync; // portal setting
////// Place your custom code below here
//Set DCPump (Jebao_MP10)
JebaoMode();
// Monitor for float switch for sump level (too low) and turn off return
CheckFloatSwitches();
//check and set Jebao for Feeding mode and Turn Skimmer Off if ReturnPump off
SkimmerOffMode(Skimmer);
//ATO High Switch
ReefAngel.SingleATOHigh(ATOpump);
////// Place your custom code above here
// This should always be the last line
ReefAngel.Portal( "hedrickms", "xxxxxx" );
ReefAngel.ShowInterface();
} //End Loop
void CheckFloatSwitches()
{
static boolean atocheck = false;
static boolean atoalertsent = false;
static boolean switchalertsent = false;
static boolean skimmeralertsent = false;
static unsigned long atotimeout;
static unsigned long timeout;
static WiFiAlert atoAlert, switchAlert, skimmerAlert;
if (ReefAngel.DisplayedMenu==FEEDING_MODE || ReefAngel.DisplayedMenu==WATERCHANGE_MODE)
return;
else
{
//if ato is on set flag and timer
if (ReefAngel.HighATO.IsActive() && ReefAngel.Relay.Status(ATOpump))
{
atocheck = true;
atotimeout = now();
}
if (bitRead(ReefAngel.AlertFlags,ATOTimeOutFlag))
{
if (!atoalertsent)
{
atoAlert.Send("ATO+pump+disabled.");
atoalertsent = true;
}
ReefAngel.Relay.Override(ATOpump,0);
// Turn off return if sump level is low
if (ReefAngel.HighATO.IsActive() && now()-timeout>3600) //if the ato float is active for 1 hours turn off return skimmer and ato
{
if (!switchalertsent)
{
switchAlert.Send("Sump+level_low+alarm!+Return+pump+Skimmer+disabled.");
ReefAngel.Relay.Override(ReturnPump,0);
switchalertsent = true;
}
}
else switchalertsent = false; //reset switchalert flag so alert can be sent if needed
}
else
{
timeout = now();
atoalertsent = false; //reset atoalert flag so alert can be sent if needed
//run ato for additional 10secs after ato triggered to avoid float bouncing activation
if (atocheck && now()-atotimeout<10)
{
ReefAngel.Relay.On(ATOpump);
}
else
{
atocheck = false;
ReefAngel.Relay.Off(ATOpump);
}
}
// turn off skimmer if skimmate overflows
if (!ReefAngel.LowATO.IsActive()) //active by default
{
if (!skimmeralertsent)
{
skimmerAlert.Send("Skimmer+Overflow+alarm!+Skimmer+disabled.");
skimmeralertsent = true;
}
ReefAngel.Relay.Override(Skimmer,0);
}
else skimmeralertsent = false; //reset skimmer flag so alert can be sent if needed
}
}// End CheckFloatSwitches
void SkimmerOffMode (byte relayport)
{
// Turn off relay if Return pump has been shut off
if (!ReefAngel.Relay.Status(ReturnPump) && ReefAngel.Relay.Status(relayport))
{
ReefAngel.Relay.Override(relayport,0);
}
} //End SkimmerOffModes
void JebaoMode()
{
static boolean feedingalert = false;
static boolean pumpstormalert = false;
static unsigned long isfeeding;
static byte ranMode = random (30);
static byte ranPumpMode = ranMode%9;
static WiFiAlert pumpAlert;
if (ReefAngel.DCPump.Mode == Custom)
{
if (ReefAngel.DisplayedMenu==FEEDING_MODE)
{
isfeeding = now();
feedingalert = false; //reset feeding flag so alert can be sent if needed
}
if (now()-isfeeding<3600) // Continue for the 60 minutes
{
if (!feedingalert)
{
pumpAlert.Send("Pump+Mode+NTM+Feeding!+Activated.");
feedingalert = true;
}
ReefAngel.PWM.SetDaylight( NutrientTransportMode(30,70,140,true));
ReefAngel.PWM.SetActinic( NutrientTransportMode(30,70,140,false));
ReefAngel.CustomVar[1]=((now()-isfeeding)/60);
}
else
{
if (ReefAngel.CustomVar[1]>0) ReefAngel.CustomVar[1]=0;//reset feed timer portal variable if was in feeding mode;
if ((now()%SECS_PER_DAY >= 75600) || (now()%SECS_PER_DAY < 28800)) // night mode 9pm -> 8am
{
if (now()%SECS_PER_DAY == 75600) pumpstormalert = false; //reset pump flag at 9pm so alert can be sent if needed
if (!pumpstormalert)
{
pumpAlert.Send("Pump+Mode+Sine+NightMode!+Activated.");
pumpstormalert = true;
}
ReefAngel.PWM.SetDaylight(SineMode(25,35,20, true));
ReefAngel.PWM.SetActinic(SineMode(25,35,20, false));
ReefAngel.CustomVar[3]=99;//night mode = 99
}// end night mode 8am
else // choose a random pump mode (ReefCrest, TidalSwell, ShortPulse, LongPulse, Else) between 0 and 8
{
if (now()%SECS_PER_DAY == 28800)//at 8am set pump mode and determine if storm
{
pumpstormalert = false; //reset pump flag so alert can be sent if needed
//set random pump mode at start of each day (midnight) and determine if storm will occur
ranMode = random(30);
ranPumpMode = ranMode%9;
}
else if (ranMode==27 || ranMode==11)//storm mode only after 8am
{
if (!pumpstormalert)
{
//enter storm mode for pumps (random)
pumpAlert.Send("Pump+Mode+STORM!+Activated.");
pumpstormalert = true; //reset pump flag so alert can be sent if needed
}
StormMode();
ReefAngel.CustomVar[2]=ranMode;
ReefAngel.CustomVar[3]=0;
}
else
{
switch (ranPumpMode)
{
case 0:
if (!pumpstormalert)
{
//enter storm mode for pumps (random)
pumpAlert.Send("Pump+Mode+ShortPule+case0!+Activated.");
pumpstormalert = true; //reset pump flag so alert can be sent if needed
}
ReefAngel.PWM.SetActinic( ShortPulseMode(10,70,600,true) );
ReefAngel.PWM.SetDaylight( ShortPulseMode(10,70,600,false) );
break;
case 1:
if (!pumpstormalert)
{
//enter storm mode for pumps (random)
pumpAlert.Send("Pump+Mode+ReefCrest+case1!+Activated.");
pumpstormalert = true; //reset pump flag so alert can be sent if needed
}
ReefAngel.PWM.SetDaylight( ReefCrestMode(50,20,true) );
ReefAngel.PWM.SetActinic( ReefCrestMode(50,20,false) );
break;
case 2:
if (!pumpstormalert)
{
//enter storm mode for pumps (random)
pumpAlert.Send("Pump+Mode+TideMode+case2!+Activated.");
pumpstormalert = true; //reset pump flag so alert can be sent if needed
}
ReefAngel.PWM.SetActinic( ShortPulseMode(0,75,800,true) );
ReefAngel.PWM.SetDaylight( ShortPulseMode(0,75,800,false) );
break;
case 3:
if (!pumpstormalert)
{
//enter storm mode for pumps (random)
pumpAlert.Send("Pump+Mode+ElseMode+case3!+Activated.");
pumpstormalert = true; //reset pump flag so alert can be sent if needed
}
ReefAngel.PWM.SetDaylight( ElseMode(55,25,true) );
ReefAngel.PWM.SetActinic( ElseMode(55,25,false) );
break;
case 4:
if (!pumpstormalert)
{
//enter storm mode for pumps (random)
pumpAlert.Send("Pump+Mode+TideMode+case4!+Activated.");
pumpstormalert = true; //reset pump flag so alert can be sent if needed
}
ReefAngel.PWM.SetDaylight( ReefCrestMode(55,25,true) );
ReefAngel.PWM.SetActinic( ReefCrestMode(55,25,false) );
break;
case 5:
if (!pumpstormalert)
{
//enter storm mode for pumps (random)
pumpAlert.Send("Pump+Mode+LongPulse+case5!+Activated.");
pumpstormalert = true; //reset pump flag so alert can be sent if needed
}
ReefAngel.PWM.SetDaylight( LongPulseMode(20,70,10,true) );
ReefAngel.PWM.SetActinic( LongPulseMode(20,70,10,false) );
break;
case 6:
if (!pumpstormalert)
{
//enter storm mode for pumps (random)
pumpAlert.Send("Pump+Mode+ElseMode+case6!+Activated.");
pumpstormalert = true; //reset pump flag so alert can be sent if needed
}
ReefAngel.PWM.SetDaylight( ElseMode(50,15,true) );
ReefAngel.PWM.SetActinic( ElseMode(50,15,false) );
break;
case 7:
if (!pumpstormalert)
{
//enter storm mode for pumps (random)
pumpAlert.Send("Pump+Mode+SineWave+case7!+Activated.");
pumpstormalert = true; //reset pump flag so alert can be sent if needed
}
ReefAngel.PWM.SetDaylight(SineMode(25,50,20, true));
ReefAngel.PWM.SetActinic(SineMode(25,50,20, false));
break;
case 8:
if (!pumpstormalert)
{
//enter storm mode for pumps (random)
pumpAlert.Send("Pump+Mode+ShortPule+case8!+Activated.");
pumpstormalert = true; //reset pump flag so alert can be sent if needed
}
ReefAngel.PWM.SetActinic( ShortPulseMode(20,65,300,true) );
ReefAngel.PWM.SetDaylight( ShortPulseMode(20,65,300,false) );
break;
}//end of random pump mode
ReefAngel.CustomVar[2]=ranMode;
ReefAngel.CustomVar[3]=ranPumpMode;
}//end else switch
}//end else pump mode
}//end else
} //end of DCPump custom
} // End Void JebaoRandomMode()
void StormMode ()
{
if ((now()%SECS_PER_DAY >= 28800) && (now()%SECS_PER_DAY < 43200)) // 8am - 12 pm
{
ReefAngel.PWM.SetDaylight( NutrientTransportMode(40,85,140,true));
ReefAngel.PWM.SetActinic( NutrientTransportMode(40,85,140,false));
}
else if ((now()%SECS_PER_DAY >= 43200) && (now()%SECS_PER_DAY < 64800)) // 12pm - 6pm
{
ReefAngel.PWM.SetDaylight( LongPulseMode(30,55,10,true) );
ReefAngel.PWM.SetActinic( LongPulseMode(30,55,10,false) );
}
else if ((now()%SECS_PER_DAY >= 64800) && (now()%SECS_PER_DAY < 72000)) // 6pm - 8pm
{
ReefAngel.PWM.SetDaylight( NutrientTransportMode(35,75,260,true));
ReefAngel.PWM.SetActinic( NutrientTransportMode(35,75,260,false));
}
else if ((now()%SECS_PER_DAY >= 72000) && (now()%SECS_PER_DAY < 75600)) // 8pm - 9pm
{
ReefAngel.PWM.SetDaylight( ElseMode(65,25,true) );
ReefAngel.PWM.SetActinic( ElseMode(65,25,false) );
}
}//end StormMode
void SeasonalTemps ()
{
ReefAngel.CustomVar[0]=month();
static int heatArray[][2] = { {792,796},// default in case of error in month=0 (June)
{770,774},//January (winter)
{774,778},//February (winter)
{775,779},//March (early spring)
{779,783},//April (spring)
{785,789},//May (spring)
{792,796},//June (early summer)
{799,803},//July (summer)
{806,810},//August (summer)
{796,801},//September (early fall)
{787,791},//October (fall)
{780,784},//November (fall)
{775,779} };//December (early winter)
static int coolArray[][2] = { {794,799},// default in case of error in month=0 (June)
{772,776},//January (winter)
{776,780},//February (winter)
{777,781},//March (early spring)
{781,785},//April (spring)
{787,791},//May (spring)
{794,798},//June (early summer)
{801,805},//July (summer)
{808,812},//August (summer)
{798,803},//September (early fall)
{789,793},//October (fall)
{782,786},//November (fall)
{777,781} };//December (early winter)
ReefAngel.StandardHeater( Heater,heatArray[month()][0],heatArray[month()][1]);
ReefAngel.StandardFan(Cooling,coolArray[month()][0],coolArray[month()][1]);
}//end seasonalTemps
byte ElseMode( byte MidPoint, byte Offset, boolean WaveSync )
{
// Static's only initialize the first time they are called
static unsigned long LastChange=millis(); // Set the inital time that the last change occurred
static int Delay = random( 500, 3000); // Set the initial delay
static int NewSpeed = MidPoint; // Set the initial speed
static int AntiSpeed = MidPoint; // Set the initial anti sync speed
if ((millis()-LastChange) > Delay) // Check if the delay has elapsed
{
Delay=random(500,5000); // If so, come up with a new delay
int ChangeUp = random(Offset); // Amount to go up or down
if (random(100)<50) // 50/50 chance of speed going up or going down
{
NewSpeed = MidPoint - ChangeUp;
AntiSpeed = MidPoint + ChangeUp;
}
else
{
NewSpeed = MidPoint + ChangeUp;
AntiSpeed = MidPoint - ChangeUp;
}
LastChange=millis(); // Reset the time of the last change
}
if (WaveSync)
{
return NewSpeed;
}
else
{
return AntiSpeed;
}
}//end Elsemode()