Tide function (proper use quesiton)

Related to the development libraries, released by Curt Binder
User avatar
Posts: 5347
Joined: Fri Jul 20, 2012 9:42 am
PostPosted: Fri Feb 05, 2016 3:45 pm
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
Posts: 11
Joined: Fri Mar 18, 2016 7:49 am
PostPosted: Sun Apr 17, 2016 3:57 pm
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
Posts: 5347
Joined: Fri Jul 20, 2012 9:42 am
PostPosted: Sun Apr 17, 2016 9:22 pm
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
Posts: 11
Joined: Fri Mar 18, 2016 7:49 am
PostPosted: Tue Apr 19, 2016 9:07 am
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
Posts: 5347
Joined: Fri Jul 20, 2012 9:42 am
PostPosted: Tue Apr 19, 2016 10:08 am
I really only change that depending on the mode. If you look at my function RFCustom you'll see where I set it.
Previous

Return to Development Libraries

Who is online

Users browsing this forum: No registered users and 1 guest

cron