I am having trouble with the tide speed call. My speed stays fixed on 50 no matter what time of day. Is this how the code is supposed to operate? I thought this would vary.
Code: Select all
#include <SunLocation.h>
#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 <PAR.h>
#include <ReefAngel.h>
#include <Tide.h>
void DrawCustomMain()
{
// the graph is drawn/updated when we exit the main menu &
// when the parameters are saved
ReefAngel.LCD.DrawDate(6, 122);
pingSerial();
#if defined DisplayLEDPWM && ! defined RemoveAllLights
ReefAngel.LCD.DrawMonitor(15, 60, ReefAngel.Params,
ReefAngel.PWM.GetDaylightValue(), ReefAngel.PWM.GetActinicValue());
#else // defined DisplayLEDPWM && ! defined RemoveAllLights
ReefAngel.LCD.DrawMonitor(15, 60, ReefAngel.Params);
#endif // defined DisplayLEDPWM && ! defined RemoveAllLights
pingSerial();
char text[10];
ConvertNumToString(text, ReefAngel.Params.Salinity, 10);
strcat(text, " ");
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 15, 93, "Salinity:");
ReefAngel.LCD.DrawText(DefaultFGColor, DefaultBGColor, 75, 93, text);
pingSerial();
byte TempRelay = ReefAngel.Relay.RelayData;
TempRelay &= ReefAngel.Relay.RelayMaskOff;
TempRelay |= ReefAngel.Relay.RelayMaskOn;
ReefAngel.LCD.DrawOutletBox(12, 103, TempRelay);
}
void DrawCustomGraph()
{
ReefAngel.LCD.DrawGraph(5, 5);
}
////// Place global variable code below here
Tide tide;
byte tideSpeed = tide.CalcTide();
SunLocation sun;
int DaylightPWMValue = 0; // For cloud code
////// Place global variable code above here
// Define Relay Ports by Name
#define MoonLights 1
#define ATOPump 2
#define Unused 3
#define ATOCirculation 4
#define Skimmer 5
#define MainPump 6
#define WhiteLED 7
#define BlueLED 8
void setup()
{
// This must be the first line
ReefAngel.Init(); //Initialize controller
ReefAngel.Use2014Screen(); // Let's use 2014 Screen
ReefAngel.AddSalinityExpansion(); // Salinity Expansion Module
ReefAngel.FeedingModePorts = Port5Bit | Port4Bit | Port6Bit; // Ports toggled in Feeding Mode
ReefAngel.WaterChangePorts = Port5Bit | Port4Bit | Port6Bit; // Ports toggled in Water Change Mode
// Feeeding and Water Change mode speed
ReefAngel.DCPump.FeedingSpeed = 0;
ReefAngel.DCPump.WaterChangeSpeed = 0;
// Ports toggled when Lights On / Off menu entry selected
ReefAngel.LightsOnPorts = Port1Bit | Port7Bit | Port8Bit;
// Ports turned off when Overheat temperature exceeded
ReefAngel.OverheatShutoffPorts = Port7Bit | Port8Bit;
// Use T1 probe as temperature and overheat functions
ReefAngel.TempProbe = T1_PROBE;
ReefAngel.OverheatProbe = T1_PROBE;
// Set the Overheat temperature setting
InternalMemory.OverheatTemp_write(869);
// Feeeding and Water Change mode speed
ReefAngel.DCPump.FeedingSpeed = 0;
ReefAngel.DCPump.WaterChangeSpeed = 0;
// Ports that are always on
ReefAngel.Relay.On(Port2);
ReefAngel.Relay.On(Port4);
ReefAngel.Relay.On(Port5);
ReefAngel.Relay.On(Port6);
////// Place additional initialization code below here
tide.Init(45, 10, 30);
tide.SetWaveLength(12 + SECS_PER_HOUR);
sun.Init(25.6839518, -80.4713138); // Miami, FL
sun.SetOffset(-4, 0, -4, 0); //Offset to get Eastern Time Zone
////// Place additional initialization code above here
}
void loop()
{
CheckCloud();
ReefAngel.PWM.SetChannelRaw(0, DaylightPWMValue);
sun.CheckAndUpdate();
byte w_risehour = sun.GetRiseHour();
byte b_risehour = sun.GetRiseHour(); //Starting Blues an hour before
byte riseminute = sun.GetRiseMinute();
byte w_sethour = sun.GetSetHour();
byte b_sethour = (sun.GetSetHour()) + 1;
byte setminute = sun.GetSetMinute();
char label_rise_hr = sun.GetRiseHour();
char label_rise_min = sun.GetRiseMinute();
char label_set_hr = sun.GetSetHour();
char label_set_min = sun.GetSetMinute();
byte vtDuration = InternalMemory.RFDuration_read();
ReefAngel.StandardLights(Port7, w_risehour, riseminute, w_sethour, setminute);
ReefAngel.StandardLights(Port8, b_risehour, riseminute, b_sethour, setminute);
DaylightPWMValue = PWMSlopeHighRes(w_risehour, riseminute, w_sethour, setminute, 0, 50, 60, 0); //White SunLocation
ReefAngel.PWM.SetChannelRaw(1, PWMSlopeHighRes(b_risehour, riseminute, b_sethour, setminute, 0, 85, 30, 0)); // Blues SunLocation
ReefAngel.StandardLights(Port1, w_sethour, setminute, w_risehour, riseminute); //Moon Lights
ReefAngel.CustomVar[0] = label_rise_hr; //Sunrise time label
ReefAngel.CustomVar[1] = label_rise_min; //Sunrise time label
ReefAngel.CustomVar[2] = label_set_hr; //Sunset time label
ReefAngel.CustomVar[3] = label_set_min; //Sunset time label
ReefAngel.CustomVar[4] = tideSpeed; //Tide speed
ReefAngel.CustomVar[5] = vtDuration; //Tide duration
ReefAngel.DCPump.UseMemory = false;
ReefAngel.DCPump.DaylightChannel = Sync;
ReefAngel.DCPump.ActinicChannel = AntiSync;
ReefAngel.DCPump.Threshold = 20;
////// Place your custom code below here
if (hour() >= 0 && hour() < w_risehour) {
ReefAngel.DCPump.SetMode(Lagoon, tideSpeed, vtDuration);
}
else if (hour() >= w_sethour && hour() <= 24) {
ReefAngel.DCPump.SetMode(Lagoon, tideSpeed, vtDuration);
}
else if (hour() >= w_risehour && hour() <= w_sethour)
{
ReefAngel.DCPump.SetMode(LongPulse, tideSpeed, vtDuration);
}
////// Place your custom code above here
// This should always be the last line
ReefAngel.Portal("CaliFSU");
ReefAngel.ShowInterface();
}
void CheckCloud()
{
// ------------------------------------------------------------
// Change the values below to customize your cloud/storm effect
// Frequency in days based on the day of the month - number 2 means every 2 days, for example (day 2,4,6 etc)
// For testing purposes, you can use 1 and cause the cloud to occur everyday
#define Clouds_Every_X_Days 1
// Percentage chance of a cloud happening today
// For testing purposes, you can use 100 and cause the cloud to have 100% chance of happening
#define Cloud_Chance_per_Day 100
// 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 10
// Minimum number of clouds that can happen per day
#define Min_Clouds_per_Day 3
// Maximum number of clouds that can happen per day
#define Max_Clouds_per_Day 5
// Only start the cloud effect after this setting
// In this example, start cloud after noon
#define Start_Cloud_After NumMins(9,00)
// Always end the cloud effect before this setting
// In this example, end cloud before 9:00pm
#define End_Cloud_Before NumMins(21,00)
// Percentage chance of a lightning happen for every cloud
// For testing purposes, you can use 100 and cause the lightning to have 100% chance of happening
#define Lightning_Change_per_Cloud 100
// Note: Make sure to choose correct values that will work within your PWMSLope settings.
// For example, in our case, we could have a max of 5 clouds per day and they could last for 50 minutes.
// Which could mean 250 minutes of clouds. We need to make sure the PWMSlope can accomodate 250 minutes
// of effects or unforseen result could happen.
// Also, make sure that you can fit double those minutes between Start_Cloud_After and End_Cloud_Before.
// In our example, we have 510 minutes between Start_Cloud_After and End_Cloud_Before, so double the
// 250 minutes (or 500 minutes) can fit in that 510 minutes window.
// It's a tight fit, but it did.
//#define printdebug // Uncomment this for debug print on Serial Monitor window
#define forcecloudcalculation // Uncomment this to force the cloud calculation to happen in the boot process.
// Add Random Lightning modes
#define Calm 0 // No lightning
#define Slow 1 // 5 seconds of slow lightning in the middle of a cloud for ELN style (slow response) drivers
#define Fast 2 // 5 seconds of fast lightning in the middle of a cloud for LDD style (fast response) drivers
#define Mega 3 // Lightning throughout the cloud, higher chance as it gets darker
#define Mega2 4 // Like Mega, but with more lightning
// Set which modes you want to use
// Example: { Calm, Fast, Mega, Mega2 } to randomize all four modes.
// { Mega2 } for just Mega2. { Mega, Mega, Fast} for Mega and Fast, with twice the chance of Mega.
byte LightningModes[] = { Mega2,Mega,Mega };
// Change the values above to customize your cloud/storm effect
// ------------------------------------------------------------
// Do not change anything below here
static byte cloudchance = 255;
static byte cloudduration = 0;
static int cloudstart = 0;
static byte numclouds = 0;
static byte lightningchance = 0;
static byte cloudindex = 0;
static byte lightningstatus = 0;
static int LastNumMins = 0;
static byte lightningMode = 0;
static boolean chooseLightning = true;
static time_t DelayCounter = millis(); // Variable for lightning timing.
static int DelayTime = random(1000); // Variable for lightning timimg.
// Every day at midnight, we check for chance of cloud happening today
if (hour() == 0 && minute() == 0 && second() == 0) cloudchance = 255;
#ifdef forcecloudcalculation
if (cloudchance == 255)
#else
if (hour() == 0 && minute() == 0 && second() == 1 && cloudchance == 255)
#endif
{
randomSeed(millis()); // Seed the random number generator
//Pick a random number between 0 and 99
cloudchance = random(100);
// if picked number is greater than Cloud_Chance_per_Day, we will not have clouds today
if (cloudchance>Cloud_Chance_per_Day) cloudchance = 0;
// Check if today is day for clouds.
if ((day() % Clouds_Every_X_Days) != 0) cloudchance = 0;
// If we have cloud today
if (cloudchance)
{
// pick a random number for number of clouds between Min_Clouds_per_Day and Max_Clouds_per_Day
numclouds = random(Min_Clouds_per_Day, Max_Clouds_per_Day);
// pick the time that the first cloud will start
// the range is calculated between Start_Cloud_After and the even distribuition of clouds on this day.
cloudstart = random(Start_Cloud_After, Start_Cloud_After + ((End_Cloud_Before - Start_Cloud_After) / (numclouds * 2)));
// pick a random number for the cloud duration of first cloud.
cloudduration = random(Min_Cloud_Duration, Max_Cloud_Duration);
//Pick a random number between 0 and 99
lightningchance = random(100);
// if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
if (lightningchance>Lightning_Change_per_Cloud) lightningchance = 0;
}
}
// Now that we have all the parameters for the cloud, let's create the effect
if (cloudchance)
{
//is it time for cloud yet?
if (NumMins(hour(), minute()) >= cloudstart && NumMins(hour(), minute())<(cloudstart + cloudduration))
{
DaylightPWMValue = ReversePWMSlope(cloudstart, cloudstart + cloudduration, DaylightPWMValue / 40.95, 0, 180)*40.95;
if (chooseLightning)
{
lightningMode = LightningModes[random(100) % sizeof(LightningModes)];
chooseLightning = false;
}
switch (lightningMode)
{
case Calm:
break;
case Mega:
// Lightning chance from beginning of cloud through the end. Chance increases with darkness of cloud.
if (lightningchance && random(ReversePWMSlope(cloudstart, cloudstart + cloudduration, 100, 0, 180))<1 && (millis() - DelayCounter)>DelayTime)
{
// Send the trigger
Strike();
DelayCounter = millis(); // If we just had a round of flashes, then lets put in a longer delay
DelayTime = random(1000); // of up to a second for dramatic effect before we do another round.
}
break;
case Mega2:
// Higher lightning chance from beginning of cloud through the end. Chance increases with darkness of cloud.
if (lightningchance && random(ReversePWMSlope(cloudstart, cloudstart + cloudduration, 100, 0, 180))<2)
{
Strike();
}
break;
case Fast:
// 5 seconds of lightning in the middle of the cloud
if (lightningchance && (NumMins(hour(), minute()) == (cloudstart + (cloudduration / 2))) && second()<5 && (millis() - DelayCounter)>DelayTime)
{
Strike();
DelayCounter = millis(); // If we just had a round of flashes, then lets put in a longer delay
DelayTime = random(1000); // of up to a second for dramatic effect before we do another round.
}
break;
case Slow:
// Slow lightning for 5 seconds in the middle of the cloud. Suitable for slower ELN style drivers
if (lightningchance && (NumMins(hour(), minute()) == (cloudstart + (cloudduration / 2))) && second()<5)
{
if (random(100)<20) lightningstatus = 1;
else lightningstatus = 0;
if (lightningstatus)
{
DaylightPWMValue = 4095;
}
else
{
DaylightPWMValue = 0;
}
delay(1);
}
break;
default:
break;
}
}
else
{
chooseLightning = true; // Reset the flag to choose a new lightning type
}
if (NumMins(hour(), minute())>(cloudstart + cloudduration))
{
cloudindex++;
if (cloudindex < numclouds)
{
cloudstart = random(Start_Cloud_After + (((End_Cloud_Before - Start_Cloud_After) / (numclouds * 2))*cloudindex * 2), (Start_Cloud_After + (((End_Cloud_Before - Start_Cloud_After) / (numclouds * 2))*cloudindex * 2)) + ((End_Cloud_Before - Start_Cloud_After) / (numclouds * 2)));
// pick a random number for the cloud duration of first cloud.
cloudduration = random(Min_Cloud_Duration, Max_Cloud_Duration);
//Pick a random number between 0 and 99
lightningchance = random(100);
// if picked number is greater than Lightning_Change_per_Cloud, we will not have lightning today
if (lightningchance>Lightning_Change_per_Cloud) lightningchance = 0;
}
}
}
// Write the times of the next cloud, next lightning, and cloud duration to the screen and into some customvars for the Portal.
if (LastNumMins != NumMins(hour(), minute()))
{
LastNumMins = NumMins(hour(), minute());
/*ReefAngel.LCD.Clear(255,0,120,132,132);
ReefAngel.LCD.DrawText(0,255,5,120,"C");
ReefAngel.LCD.DrawText(0,255,11,120,"00:00");
ReefAngel.LCD.DrawText(0,255,45,120,"L");
ReefAngel.LCD.DrawText(0,255,51,120,"00:00"); */
if (cloudchance && (NumMins(hour(), minute())<cloudstart))
{
int x = 0;
if ((cloudstart / 60) >= 10) x = 11;
else x = 17;
//ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart/60));
//ReefAngel.CustomVar[3] = cloudstart / 60; // Write the hour of the next cloud to custom variable for Portal reporting
if ((cloudstart % 60) >= 10) x = 29;
else x = 35;
//ReefAngel.LCD.DrawText(0,255,x,120,(cloudstart%60));
//ReefAngel.CustomVar[4] = cloudstart % 60; // Write the minute of the next cloud to custom variable for Portal reporting
}
//ReefAngel.LCD.DrawText(0,255,90,120,cloudduration);
//ReefAngel.CustomVar[7] = (cloudduration); // Put the duration of the next cloud in a custom var for the portal
if (lightningchance)
{
int x = 0;
if (((cloudstart + (cloudduration / 2)) / 60) >= 10) x = 51;
else x = 57;
//ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))/60));
//ReefAngel.CustomVar[5] = (cloudstart + (cloudduration / 2)) / 60; // Write the hour of the next lightning to a custom variable for the Portal
if (((cloudstart + (cloudduration / 2)) % 60) >= 10) x = 69;
else x = 75;
//ReefAngel.LCD.DrawText(0,255,x,120,((cloudstart+(cloudduration/2))%60)); // Write the minute of the next lightning to a custom variable for the Portal
//ReefAngel.CustomVar[6] = (cloudstart + (cloudduration / 2)) % 60;
}
}
}
void Strike()
{
int a = random(1, 5); // Pick a number of consecutive flashes from 1 to 4.
for (int i = 0; i<a; i++)
{
// Flash on
int newdata = 4095;
Wire.beginTransmission(0x40); // Address of the dimming expansion module
Wire.write(0x8 + (4 * 1)); // 0x8 is channel 0, 0x12 is channel 1, etc. I'm using channel 1.
Wire.write(newdata & 0xff); // Send the data 8 bits at a time. This sends the LSB
Wire.write(newdata >> 8); // This sends the MSB
Wire.endTransmission();
int randy = random(20, 80); // Random number for a delay
if (randy>71) randy = ((randy - 70) / 2) * 100; // Small chance of a longer delay
delay(randy); // Wait from 20 to 69 ms, or 100-400 ms
// Flash off. Return to baseline.
newdata = ReefAngel.PWM.GetChannelValueRaw(1); // Use the channel number you're flashing here
Wire.beginTransmission(0x40); // Same as above
Wire.write(0x8 + (4 * 1));
Wire.write(newdata & 0xff);
Wire.write(newdata >> 8);
Wire.endTransmission();
delay(random(30, 50)); // Wait from 30 to 49 ms
wdt_reset(); // Reset watchdog timer to avoid re-boots
}
}
byte ReversePWMSlope(long cstart, long cend, byte PWMStart, byte PWMEnd, byte clength)
{
long n = elapsedSecsToday(now());
cstart *= 60;
cend *= 60;
if (n<cstart) return PWMStart;
if (n >= cstart && n <= (cstart + clength)) return map(n, cstart, cstart + clength, PWMStart, PWMEnd);
if (n>(cstart + clength) && n<(cend - clength)) return PWMEnd;
if (n >= (cend - clength) && n <= cend) return map(n, cend - clength, cend, PWMEnd, PWMStart);
if (n>cend) return (int)PWMStart;
}