Tide function (proper use quesiton)

Related to the development libraries, released by Curt Binder
Post Reply
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Tide function (proper use quesiton)

Post by lnevo »

That was from reeftronics.net go check it out and sign up. You will get a 24 hour, 7 day history and 30 day graph of most parameters
User avatar
CaliFSU
Posts: 11
Joined: Fri Mar 18, 2016 7:49 am

Re: Tide function (proper use quesiton)

Post by CaliFSU »

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;
}

>>--Cali-->
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Tide function (proper use quesiton)

Post by lnevo »

Ok first off you copied the same mistake someone else made. If you set wavelength to 12 + SECS_PER_HOUR then it will be 72 minutes per high tide to low tide. Should be 12 * ... Unless you're troubleshooting maybe.

Also you only set tideSpeed once when you declare it so it isn't updating. Try setting it inside loop instead. Also you have w_sethour and label_rise_hr which are the same value. You could just consolidate them and reduce the number of variables you need.
User avatar
CaliFSU
Posts: 11
Joined: Fri Mar 18, 2016 7:49 am

Re: Tide function (proper use quesiton)

Post by CaliFSU »

Lee - thanks for your input. I got it working.

What are you doing to generate the vtDuration number? I wanted to see what I could tie this to in order for it to vary throughout the Tide cycle.
>>--Cali-->
User avatar
lnevo
Posts: 5430
Joined: Fri Jul 20, 2012 9:42 am

Re: Tide function (proper use quesiton)

Post by lnevo »

I really only change that depending on the mode. If you look at my function RFCustom you'll see where I set it.
Post Reply