The system includes...
RA +
Relay(original included)'
PH Probe
Standard ATO High and Low
Expansion Hub
Dimming Expansion
RANet and Relay
Water Level Expansion
Multi Water Level Expansion
Salinity Expansion
ATO Pump
WiFi module
Bluetooth module
3 Jebao Cables (WP-25, WP-40, DC-12000pump)
3 Temp Sensors
Dimmable Lunar Hub & 2 Moonlights
Basic control of the following.
Daylight
Actinic
Moonlight
Pumps
2 Jebao pumps (WP40 & WP25)
Control of my NatuReef DeNitrification chamber.
(Thanks to lnevo for help with this coding)
Random Jebao modes that lnevo did for PaulTurner911.
12/21/13
Changed the Speed for the Jebao pumps from 30% to 0% during feeding.
3/22/14
Added AutoFeeder triggered by Reef Angel.
How to modify the Eheim 3581 are here. http://wamas.org/forums/blog/13/entry-4 ... ontroller/
Added Dimmable Lunar Hub. Right now I'm just using the MoonPhase with an on and off time that coincide with my lighting. I added a slope to it so it seems like a moonrise and set
4/8/14 Added some code to turn a pump on every 8 hours for 15 min to stir my Kalkwasser.
5/26/14 Removed code to mix Kalkwasser.
8/1/14 Modified the Denitrification code to use variables instead of hard times. (Thanks to lnevo again for this)
8/4/14 Added Kalk Mixing Code. When the ATO reservoir is at 100% or above the pump in the reservoir turns on for 1 hr to mix the Kalkwasser in the reservoir and then turns off to let the unsaturated Kalk settle to bottom before use as ATO water.
9/11 Updated code for 1.1.1 Libraries. Added DNS server name and Server Authentication. Removed the Else Mode wave function code since it is now incorporated in to the libraries and added the Gyre Wave mode to the choice of Random Waves. Made some slight changes to the ATO code that had to be done because of the new libraries.
1/26/15 Added RA Net and Relay.
2/27/15 Added code to auto flush my RO/DI unit Monday, Wednesday and Friday using a 12V DC 1/2" Normally Closed Pneumatic Plastic Air Water Electric Solenoid Valve.
7/05/15 Added 2 Evergreen D120 LED lights. Modded for RA Dimming control and set up and East to West Sunrise/Sunet 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 <Humidity.h>
#include <DCPump.h>
#include <ReefAngel.h>
#include <SoftwareSerial.h>
// Define Relay Ports by Name
#define Actinic_Lights 1
#define Day_Lights 2
#define Kalkwasser 3
#define Pumps 4
#define Unused 5
#define DeNit_Doser 6
#define DeNit_Pump 7
#define ATO_Pump 8
#define Unused Box1_Port1
#define Feeder Box1_Port2
#define Unused Box1_Port3
#define Unused Box1_Port4
#define Unused Box1_Port5
#define Flush_Bypass Box1_Port6
#define Main_RODI Box1_Port7
#define Dummy Box1_Port8
////// Place global variable code below here
// Does not need to be global.
// unsigned long ATOUpdate=0;
static time_t LastATO=millis(); // For de-bounced ATO
////// Place global variable code above here
void setup()
{
// This must be the first line
ReefAngel.Init(); //Initialize controller
// Ports toggled in Feeding Mode
ReefAngel.FeedingModePorts = 0;
// Ports toggled in Water Change Mode
ReefAngel.WaterChangePorts = Port4Bit;
ReefAngel.WaterChangePortsE[0] = Port1Bit;
// Ports toggled when Lights On / Off menu entry selected
ReefAngel.LightsOnPorts = 0;
// Ports turned off when Overheat temperature exceeded
ReefAngel.OverheatShutoffPorts = 0;
// Use T1 probe as temperature and overheat functions
ReefAngel.TempProbe = T1_PROBE;
ReefAngel.OverheatProbe = T1_PROBE;
// Set the Overheat temperature setting
InternalMemory.OverheatTemp_write( 825 );
//Set Standard Menu
ReefAngel.AddStandardMenu();
//Water Level
ReefAngel.AddMultiChannelWaterLevelExpansion();
//Webserver Authentication
ReefAngel.Network.WifiAuthentication("Sacohen:xxxxxxxx");
//DDNS Server
ReefAngel.DDNS("myreeftank");
ReefAngel.AddRANet();
// Feeeding and Water Change mode speed
ReefAngel.DCPump.FeedingSpeed=0;
ReefAngel.DCPump.WaterChangeSpeed=0;
ReefAngel.DCPump.ActinicChannel=Sync; // Now you're pump will be affected by the portal settings.
//ReefAngel.DCPump.DaylightChannel=AntiSync; // Now you're pump will be affected by the portal settings.
//ReefAngel.DCPump.AntiSyncOffset=85;
// Ports that are always on
ReefAngel.Relay.On( Pumps );
ReefAngel.Relay.On( Dummy );
////// Place additional initialization code below here
////// Place additional initialization code above here
}
void loop()
{
ReefAngel.StandardLights( Actinic_Lights,12,0,22,0 );
ReefAngel.StandardLights( Day_Lights,12,30,21,0 );
//East to West Sunrise/Sunset Dimming
ReefAngel.PWM.SetChannel( 0, PWMSlope(12,30,20,30,0,100,60,0) );
ReefAngel.PWM.SetChannel( 1, PWMSlope(12,0,21,30,0,100,60,0) );
ReefAngel.PWM.SetChannel( 2, PWMSlope(13,0,21,0,0,100,60,0) );
ReefAngel.PWM.SetChannel( 3, PWMSlope(12,30,22,0,0,100,60,0) );
// ******************* Debounced ATO code. Activate ATO no more than every 30 seconds. *******************
//if (ReefAngel.WaterLevel.GetLevel(0) < 34) LastATO=millis(); // Start a timer
//if (millis()-LastATO<30000 && millis()-LastATO>10) // Has it been less than 30,000 ms? (30 secs)
// ReefAngel.Relay.Off(ATO_Pump); // If so, make sure the topoff pump is off
// else
ReefAngel.WaterLevelATO(0,ATO_Pump,720,34,36); // Otherwise, use the normal topoff routine.
if ( hour()>=13 && hour()<21 )
ReefAngel.PWM.SetChannel( 5, 0 );
else
ReefAngel.PWM.SetChannel( 5, PWMSlope(21,0,13,0,0,MoonPhase() ,60,0) );
////// Place your custom code below here
//Flush RO/DI Membrane Monday, Wednseday and Friday times a week @ 9pm.
ReefAngel.Relay.Off(Main_RODI);
if (weekday()==dowMonday && hour()==21 && minute()<5)
ReefAngel.Relay.On(Main_RODI);
if (weekday()==dowWednesday && hour()==21 && minute()<5)
ReefAngel.Relay.On(Main_RODI);
if (weekday()==dowFriday && hour()==21 && minute()<10)
ReefAngel.Relay.On(Main_RODI);
ReefAngel.Relay.Off(Flush_Bypass);
if (weekday()==dowFriday && hour()==21 && minute()>=05 && minute()<10)
ReefAngel.Relay.On(Flush_Bypass);
//Mix Kalkwasser
static unsigned long Kalk_Mixing = 0;
static unsigned long stopTime = 0;
static byte prevWL=0;
if (ReefAngel.WaterLevel.GetLevel(1)==100 && prevWL<100) {
stopTime=now()+7200; // Get time one hour from now.
}
prevWL = ReefAngel.WaterLevel.GetLevel(1); // Store the water level
if (now() < stopTime) { ReefAngel.Relay.On(Kalkwasser); } else { ReefAngel.Relay.Off(Kalkwasser); }
//AutoFeeder
static unsigned long autofeeding = 0;
if ((now()%SECS_PER_DAY==64800)) //if it is 6 pm
{
ReefAngel.FeedingModeStart(); //START FEEDING MODE
}
if (ReefAngel.DisplayedMenu==FEEDING_MODE)
{
if ( autofeeding == 0 ) {
autofeeding = now(); //set the time of the start of feeding to variable feeding
}
if ((now()-autofeeding>=60) && (now()-autofeeding<=61)) //if between 60 and 61 seconds has past
{
ReefAngel.Relay.On(Feeder); //TURN FEEDER RELAY ON
}
else
{
ReefAngel.Relay.Off(Feeder); //TURN FEEDER RELAY OFF
}
} else {
if ( autofeeding > 0 ) {
autofeeding = 0;
}
}
// DeNitrate Routine
int DeNit_Offset=3600;
int DeNit_Repeat=21600;
int DeNit_Doser_Offset=1200;
int DeNit_Doser_Runtime=600;
int DeNit_Pump_Runtime=1200;
int DeNit_ATO_Offtime=1500;
// Pump comes on first
ReefAngel.Relay.Set(DeNit_Pump,(now()-DeNit_Offset)%DeNit_Repeat<DeNit_Pump_Runtime); // Runs denitrator pump
// Doser comes on second
ReefAngel.Relay.Set(DeNit_Doser,((now()-DeNit_Offset)-DeNit_Doser_Offset)%DeNit_Repeat<DeNit_Doser_Runtime); // Runs denitrator doser
// Disable ATO
if ( (now()-3600)%21600<DeNit_ATO_Offtime) ReefAngel.WaterLevelATO(0,ATO_Pump,720,0,1);
// Delay WL ATO after water change and DeNit_Dosing
static time_t wcTimer=0;
if (ReefAngel.DisplayedMenu == WATERCHANGE_MODE) wcTimer=now();
// First 10 minutes after WC disable ATO
if (now()-wcTimer >= 0 && now()-wcTimer < 600)
ReefAngel.WaterLevelATO(0,ATO_Pump,720,0,1);
// Track Salinity low duration
static unsigned long lastGoodSal;
static boolean lowSalFlag;
// Salinity is good, update counter
if (ReefAngel.Params.Salinity>=335) lastGoodSal=now();
// Counter hasn't been updating in 300 seconds..
if (now()-lastGoodSal>300) {
lowSalFlag=true; // Salinity is definitely below 33.5
} else {
lowSalFlag=false; // Salinity back to normal
}
// Disable ATO if lowSalFlag is true
//if (lowSalFlag) ReefAngel.WaterLevelATO(0,ATO_Pump,720,0,1);
// Disable ATO if ATO High IsActive()
if (ReefAngel.HighATO.IsActive())
ReefAngel.WaterLevelATO(0,ATO_Pump,720,0,1);
// Add random mode if we set to Mode to Custom in portal
static int rmode;
static boolean changeMode=true;
// These are the modes we can cycle through. You can add more and even repeat...
byte modes[] = { ReefCrest, Gyre, Lagoon, Constant, TidalSwell, ShortPulse, LongPulse, Else, };
if (now()%SECS_PER_DAY==0 || changeMode==true) { // Change at midnight or if controller rebooted
rmode=random(100)%sizeof(modes); // Change the mode once per day to pick from our array
changeMode=false;
}
// Set timer when in feeding mode
static unsigned long feeding;
if (ReefAngel.DisplayedMenu==FEEDING_MODE) feeding=now();
if (now()-feeding<3600) {
// Continue NTM for the 60 minutes
ReefAngel.DCPump.UseMemory=false;
ReefAngel.DCPump.Duration=InternalMemory.DCPumpDuration_read();
ReefAngel.DCPump.Mode=NutrientTransport;
} else if (now()%SECS_PER_DAY<43200 || now()%SECS_PER_DAY>=79200) { // 12pm / 10pm
// Night mode (go to 30%)
ReefAngel.DCPump.UseMemory=false;
ReefAngel.DCPump.Duration=InternalMemory.DCPumpDuration_read();
ReefAngel.DCPump.Mode=Constant;
ReefAngel.DCPump.Speed=30;
} else if (InternalMemory.DCPumpMode_read()==11) {
// Custom Mode and nothing else going on
ReefAngel.DCPump.UseMemory=false;
ReefAngel.DCPump.Duration=InternalMemory.DCPumpDuration_read();
ReefAngel.DCPump.Mode=modes[rmode]; // Put the mode to the random mode :)
ReefAngel.DCPump.Speed=InternalMemory.DCPumpSpeed_read(); // Set speed from portal
} else {
ReefAngel.DCPump.UseMemory=true; // Will reset all values from memory
}
////// Place your custom code above here
// This should always be the last line
ReefAngel.Portal( "Sacohen","xxxxxxxx" );
ReefAngel.ShowInterface();
}
void DrawCustomMain()
{
int x,y;
char text[10];
// Parameters
#if defined DisplayLEDPWM && ! defined RemoveAllLights
ReefAngel.LCD.DrawMonitor( 15, 20, ReefAngel.Params,
ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue() );
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
ReefAngel.LCD.DrawMonitor( 15, 20, ReefAngel.Params );
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
pingSerial();
// Water Level
ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,75,57, "WL:" );
ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,99,57, ReefAngel.WaterLevel.GetLevel() );
ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,66,66, "WL 1:" );
ReefAngel.LCD.DrawText( COLOR_DARKGOLDENROD,DefaultBGColor,99,66, ReefAngel.WaterLevel.GetLevel(1) );
//Salinity
ConvertNumToString(text, ReefAngel.Params.Salinity, 10);
strcat(text," ");
ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,39,75,"Salinity:");
ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,99,75,text);
pingSerial();
// Main Relay Box
byte TempRelay = ReefAngel.Relay.RelayData;
TempRelay &= ReefAngel.Relay.RelayMaskOff;
TempRelay |= ReefAngel.Relay.RelayMaskOn;
ReefAngel.LCD.DrawOutletBox( 12, 92, TempRelay );
pingSerial();
TempRelay = ReefAngel.Relay.RelayDataE[0];
TempRelay &= ReefAngel.Relay.RelayMaskOffE[0];
TempRelay |= ReefAngel.Relay.RelayMaskOnE[0];
ReefAngel.LCD.DrawOutletBox(12, 104, TempRelay);
// Date and Time
ReefAngel.LCD.DrawDate( 6, 122 );
pingSerial();
}
void DrawCustomGraph()
{
}