Thanks! The code for it should be in the other how do I area if you wanted just that how to bit.
I've edited a bit more and fixed some issues with the clouds not processing correctly. Also added in the ATO bit. I have a bucket on the side of my stand with RODI water in it and a pump. The pump has a float switch on it so I know if I'm about to suck air or not (LowATO). There is also an emergency float in the sump to act as a redundant check to the water sensor kit (HighATO). Other than that cleaned it up a bit and added better comments here and there.
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>
#include <SunLocation.h>
////// Place global variable code below here
#define FONT_8x16
SunLocation sl;
time_t nextEvent = 0, timeSunRise, timeSunSet, nextCloud = 0;
String nextEventName;
boolean isCloudy = false;
boolean isATOAvail = false;
byte atoPort = 0;;
//Cloud Defines:
// Frequency in days based on the day of the month - number 2 means every 2 days, for example (day 2,4,6 etc)
#define Clouds_Every_X_Days 1
// Percentage chance of a cloud happening today
#define Cloud_Chance_per_Day 25
// Minimum number of minutes for cloud duration. Don't use max duration of less than 6
#define Min_Cloud_Duration 7
// Maximum number of minutes for the cloud duration. Don't use max duration of more than 255
#define Max_Cloud_Duration 30
// Minimum number of clouds that can happen per day
#define Min_Clouds_per_Day 2
// Maximum number of clouds that can happen per day
#define Max_Clouds_per_Day 5
// Time in minutes for the fade of a cloud to take affect
#define Cloud_Fade_Duration 3
// Minimum fade of cloud
#define Min_Cloud_Fade 20
// Maximum fade of cloud
#define Max_Cloud_Fade 70
byte cloudChance=0;
byte cloudDuration=0;
byte numClouds=0;
byte cloudIndex=0;
byte cloudFade = 0;
////// Place global variable code above here
void setup()
{
//This must be the first line
ReefAngel.Init(); //Initialize controller
ReefAngel.AddStandardMenu(); // Add Standard Menu
//Ports toggled in Feeding Mode
ReefAngel.FeedingModePorts = Port7Bit;
//Ports toggled in Water Change Mode
ReefAngel.WaterChangePorts = Port8Bit;
//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(800);
//Set the port ATO is on numerically
atoPort = 6;
//Enable LED driver board fan
ReefAngel.Relay.On( Port2 );
//Enable heater port - Currently not used
ReefAngel.Relay.On( Port5 );
//Enable skimmer
ReefAngel.Relay.On( Port7 );
//Enable return pump
ReefAngel.Relay.On( Port8 );
//Get an event at startup
if (nextEvent == 0) {GetNextEvent();}
}
void loop()
{
//Moonlights
ReefAngel.StandardLights(Port1, hour(timeSunSet - 90), minute(timeSunSet - 90), hour(timeSunRise + 90), minute(timeSunRise + 90));
//Sump Lights
ReefAngel.StandardLights(Port3, hour(timeSunSet - 60), minute(timeSunSet - 60), hour(timeSunRise + 60), minute(timeSunRise + 60));
//Display Lights
ReefAngel.StandardLights(Port4, hour(timeSunRise - 1860), minute(timeSunRise - 1860), hour(timeSunSet + 1860), minute(timeSunSet + 1860));
//Sun Pattern for Sump
ReefAngel.PWM.SetActinic(PWMSlope(hour(timeSunSet), minute(timeSunSet), hour(timeSunRise), minute(timeSunRise), 15, 100, 30, 0));
//Sun Pattern for Display
if (isCloudy)
{
ReefAngel.PWM.SetDaylight(PWMSlope(hour(nextCloud), minute(nextCloud), hour(nextCloud + cloudDuration), minute(nextCloud + cloudDuration), 100, cloudFade, 3, 100));
}
else
{
ReefAngel.PWM.SetDaylight(PWMSlope(hour(timeSunRise - 1800), minute(timeSunRise - 1800), hour(timeSunSet + 1800), minute(timeSunSet + 1800), 15, 100, 30, 0));
}
//ATO code
//check emergency float switch detector in sump for overfilling
if (ReefAngel.HighATO.IsActive())
{
ReefAngel.Relay.Off(Port6);
}
//else check status of top off bucket
//check if bucket level is too low to pump from or if water in sump is getting too high
else if ((ReefAngel.LowATO.IsActive() == false) || (ReefAngel.WaterLevel.GetLevel() > 90))
{
ReefAngel.Relay.Off(Port6);
}
//check if pump should be enabled
else if ((ReefAngel.LowATO.IsActive()) && (ReefAngel.WaterLevel.GetLevel() <= 80))
{
ReefAngel.Relay.On(Port6);
}
//Event logic
//if we just past the current event, go get another
if (now() >= nextEvent) { GetNextEvent(); }
// This should always be the last line
ReefAngel.ShowInterface();
}
void GetNextEvent()
{
//check if called from setup and if so establish current day's params
if (nextEvent == 0)
{
sl.CalSun();
timeSunRise = sl.GetSunRise();
timeSunSet = sl.GetSunSet();
}
//WHEN IS IT?!?!?
//Before the sun starts peeking over the horizon?
if (now() < timeSunRise - 1800)
{
nextEventName = "Dawn";
nextEvent = timeSunRise - 1800;
}
//Is the sun rising?
//Use this time to figure out if today will be cloudy since we can kind of see the sky now
else if (now() < timeSunRise)
{
sl.CalSun();
cloudChance = 255;
GetNextCloud();
timeSunRise = sl.GetSunRise();
timeSunSet = sl.GetSunSet();
nextEventName = "Sunrise";
nextEvent = timeSunRise;
}
//Is it after the sun has fully set?
else if (now() >= timeSunSet + 1800)
{
nextEventName = "Dawn";
sl.GetTomorrowSunRise(&timeSunRise);
nextEvent = timeSunRise - 1800;
}
//Is the sun starting to descend?
else if (now() >= timeSunSet)
{
nextEventName = "Dusk";
nextEvent = timeSunSet + 1800;
}
//Sun is up. What now? Clouds perhaps?
else
{
//If clouds today, are we before a cloud?
if ((now() < nextCloud) && (nextCloud > 0))
{
nextEventName = "Cloud";
nextEvent = nextCloud;
}
//We have just entered a cloud zone
else if ((now() >= nextCloud) && (nextCloud > 0))
{
isCloudy = true;
cloudFade = random(Min_Cloud_Fade, Max_Cloud_Fade);
nextEventName = "Sun";
nextEvent = nextCloud + cloudDuration;
}
//We are leaving a cloud zone, but are there more? Find out.
else if (isCloudy)
{
isCloudy = false;
cloudIndex++;
GetNextCloud();
if (nextCloud > 0)
{
nextEvent = nextCloud;
nextEventName = "Cloud";
}
else
{
nextEventName = "Sunset";
nextEvent = timeSunSet;
}
}
//Nope, no clouds today. Get ready for sunset.
else
{
nextEventName = "Sunset";
nextEvent = timeSunSet;
}
}
}
void GetNextCloud()
{
//Init - Ran by GetNextEvent() at Dawn once per day by setting cloudChance to 255
if (cloudChance == 255)
{
//Is today cloudy?
cloudChance = random(100);
if (cloudChance <= Cloud_Chance_per_Day)
{
time_t t = now();
int minSunRise = 0, minSunSet = 0;
minSunRise = (hour(timeSunRise) * 60) + minute(timeSunRise);
minSunSet = (hour(timeSunSet) * 60) + minute(timeSunSet);
numClouds = random(Min_Clouds_per_Day, Max_Clouds_per_Day);
nextCloud = t - ((hour(t) * 3600) + (minute(t) * 60) + second(t));
nextCloud += (random(minSunRise, minSunRise + ((minSunSet - minSunRise) / (numClouds * 2)))) * 60;
cloudDuration = (random(Min_Cloud_Duration, Max_Cloud_Duration)) * 60;
}
}
//We must have picked a cloudy day, but are there more?
else
{
if (cloudIndex < numClouds)
{
time_t t = now();
int minSunRise = 0, minSunSet = 0;
minSunRise = (hour(timeSunRise) * 60) + minute(timeSunRise);
minSunSet = (hour(timeSunSet) * 60) + minute(timeSunSet);
nextCloud = t - ((hour(t) * 3600) + (minute(t) * 60) + second(t));
nextCloud += (random(minSunRise + (((minSunSet - minSunRise) / (numClouds * 2)) * cloudIndex * 2), (minSunRise + (((minSunSet - minSunRise) / (numClouds * 2)) * cloudIndex * 2)) + ((minSunSet - minSunRise) / (numClouds * 2)))) * 60;
cloudDuration = (random(Min_Cloud_Duration, Max_Cloud_Duration)) * 60;
}
//Nope, out of clouds for today
else
{
nextCloud = 0;
cloudDuration = 0;
cloudIndex = 0;
}
}
}
void DrawCustomMain()
{
byte offset = 3; //Display offset vertically
byte waterLevel = ReefAngel.WaterLevel.GetLevel(); //Percentage of water height based off sensor (aprox 3-5 inches off top of sump height)
byte dispLights = ReefAngel.PWM.GetDaylightValue(); //Percentage of lights on display
byte sumpLights = ReefAngel.PWM.GetActinicValue(); //Percentage of lights on sump
byte TempRelay = ReefAngel.Relay.RelayData; //--------------------
TempRelay &= ReefAngel.Relay.RelayMaskOff; //Setup for relay info
TempRelay |= ReefAngel.Relay.RelayMaskOn; //--------------------
char text[10];
//Header Section - Title + Date and Time
ReefAngel.LCD.DrawText(COLOR_GREEN, DefaultBGColor, 15, offset, "JerkyJunky's Reef");
ReefAngel.LCD.DrawDate(6, offset + 10);
ReefAngel.LCD.Clear(COLOR_GREEN, 1, offset + 20, 128, offset + 20);
offset = 26;
pingSerial();
//Main Relay Box & Main Parameters
ReefAngel.LCD.Clear(DefaultBGColor, 1, offset, 45, offset + 21);
ReefAngel.LCD.DrawCircleOutletBoxHorizontal(2, offset, TempRelay);
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 50, offset, "Temp:");
ConvertNumToString(text, ReefAngel.Params.Temp[T1_PROBE], 10);
ReefAngel.LCD.DrawLargeText(COLOR_PURPLE, 255, 49, offset + 9, text, Font8x16);
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 101, offset, "pH:");
ConvertNumToString(text, ReefAngel.Params.PH, 100);
ReefAngel.LCD.DrawLargeText(COLOR_ORANGE, 255, 93, offset + 9, text, Font8x16);
offset = offset + 23;
pingSerial();
//Water Level
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 5, offset, "Tank Level");
ConvertNumToString(text, waterLevel, 1);
strcat(text, "%");
if (waterLevel >= 100)
{
ReefAngel.LCD.DrawLargeText(COLOR_BLUE, DefaultBGColor, 19, offset + 9, "Full", Font8x16);
}
else if (waterLevel >= 90)
{
ReefAngel.LCD.Clear(DefaultBGColor, 1, offset + 9, 60, offset + 22);
ReefAngel.LCD.DrawLargeText(COLOR_BLUE, DefaultBGColor, 23, offset + 9, text, Font8x16);
}
else if ((waterLevel < 90) && (waterlevel >=80))
{
ReefAngel.LCD.Clear(DefaultBGColor, 1, offset + 9, 60, offset + 22);
ReefAngel.LCD.DrawLargeText(COLOR_ORANGE, DefaultBGColor, 23, offset + 9, text, Font8x16);
}
else
{
ReefAngel.LCD.Clear(DefaultBGColor, 1, offset + 9, 60, offset + 22);
ReefAngel.LCD.DrawLargeText(COLOR_RED, DefaultBGColor, 23, offset + 9, text, Font8x16);
}
//ATO - Avail?
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 70, offset + 2, "ATO:");
if (ReefAngel.LowATO.IsActive())
ReefAngel.LCD.DrawText(COLOR_GREEN, DefaultBGColor, 95, offset + 2, "Avail");
else
ReefAngel.LCD.DrawText(COLOR_RED, DefaultBGColor, 95, offset + 2, "Empty");
//ATO - Pump?
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 72, offset + 12, "Pump:");
if ((TempRelay&(1<<(atoPort - 1)))==1<<(atoPort - 1))
{
ReefAngel.LCD.Clear(DefaultBGColor, 102, offset + 12, 128, offset + 21);
ReefAngel.LCD.DrawText(COLOR_GREEN, DefaultBGColor, 102, offset + 12, "On");
}
else
ReefAngel.LCD.DrawText(COLOR_RED, DefaultBGColor, 102, offset + 12, "Off");
ReefAngel.LCD.Clear(COLOR_GREEN, 1, offset + 24, 128, offset + 24);
offset = offset + 27;
pingSerial();
//Lights
if (dispLights > 0)
ReefAngel.LCD.DrawText(COLOR_GREEN, DefaultBGColor, 10, offset, "Display");
else
ReefAngel.LCD.DrawText(COLOR_RED, DefaultBGColor, 10, offset, "Display");
if (sumpLights > 0)
ReefAngel.LCD.DrawText(COLOR_GREEN, DefaultBGColor, 72, offset, "Refugium");
else
ReefAngel.LCD.DrawText(COLOR_RED, DefaultBGColor, 72, offset, "Refugium");
ReefAngel.LCD.Clear(DefaultBGColor, 1, offset + 9, 128, offset + 22);
ConvertNumToString(text, dispLights, 1);
strcat(text, "%");
if (strlen(text) == 5)
ReefAngel.LCD.DrawLargeText(COLOR_BLUE, DefaultBGColor, 10, offset + 9, text, Font8x16);
else if (strlen(text) == 4)
ReefAngel.LCD.DrawLargeText(COLOR_BLUE, DefaultBGColor, 14, offset + 9, text, Font8x16);
else if (strlen(text) == 3)
ReefAngel.LCD.DrawLargeText(COLOR_BLUE, DefaultBGColor, 18, offset + 9, text, Font8x16);
else
ReefAngel.LCD.DrawLargeText(COLOR_BLUE, DefaultBGColor, 22, offset + 9, text, Font8x16);
ConvertNumToString(text, sumpLights, 1);
strcat(text, "%");
if (strlen(text) == 5)
ReefAngel.LCD.DrawLargeText(COLOR_BLUE, DefaultBGColor, 80, offset + 9, text, Font8x16);
else if (strlen(text) == 4)
ReefAngel.LCD.DrawLargeText(COLOR_BLUE, DefaultBGColor, 84, offset + 9, text, Font8x16);
else if (strlen(text) == 3)
ReefAngel.LCD.DrawLargeText(COLOR_BLUE, DefaultBGColor, 88, offset + 9, text, Font8x16);
else
ReefAngel.LCD.DrawLargeText(COLOR_BLUE, DefaultBGColor, 92, offset + 9, text, Font8x16);
offset = offset + 25;
pingSerial();
//Events Viewer
ReefAngel.LCD.Clear(DefaultBGColor, 1, offset, 128, offset + 17);
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 2, offset, "Next Event:");
nextEventName.toCharArray(text, 10);
ReefAngel.LCD.DrawText(COLOR_BLUE, DefaultBGColor, 70, offset, text);
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 2, offset + 9, "Time Until:");
if (nextEvent > now())
{
ConvertNumToString(text, hour(nextEvent - now()), 1);
strcat(text, ":");
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 75, offset + 9, text);
ConvertNumToString(text, minute(nextEvent - now()), 1);
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 95, offset + 9, text);
}
else
{
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 75, offset + 9, "NOW!");
}
pingSerial();
//Diag
ConvertNumToString(text, hour(nextCloud) , 1);
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 2, offset + 18, text);
ConvertNumToString(text, cloudChance , 1);
ReefAngel.LCD.DrawText(COLOR_BLACK, DefaultBGColor, 70, offset + 18, text);
}
void DrawCustomGraph()
{
}