Sunrise / sunset code based on location
Re: Sunrise / sunset code based on location
I looked at the code...
One thing thats probably causing you issues currently...
In your setup()
You do not declare
dow=0;
Nor do I see you declaring what dow actually ever is... so I think its running assuming that whatever time its currently at is midnight and never correcting for that... which will cause errors
You need to do this somewhere in the loop
dow=day();
which sets dow to 1-31 as the output of day() in arduino scales from 1-31...
Then... the loops asking if dow=0 which should check for a restart and trigger a correction of current time of day to midnight will work. Else, if you never define dow its going to always be a zero and every calculation will simply use current elapsed Unix Epoch time in CalcSun... but that could be off by 23:59:59 maximally, depending on the time of day. I am unsure what the exact magnitude of the introduced error might be but it would be but the rise and set times will NOT be the same as if you actually had used midnight.
Code seems ok otherwise... so far as I can tell. I also note that you switched to decimal latitude and longitude but enabled the correct conversion in the code so thats looking ok. As for your offset, I think its looking correct as the time library functions hour() and minute() will do what your trying to do... I think. But do you really need the library functions? You could just grab the current time in hours and minutes using time_t=now() as I did... I am not sure if there is a functional difference, but I because I have not called the hour function as you are I cannot say if its working.
One thing thats probably causing you issues currently...
In your setup()
You do not declare
dow=0;
Nor do I see you declaring what dow actually ever is... so I think its running assuming that whatever time its currently at is midnight and never correcting for that... which will cause errors
You need to do this somewhere in the loop
dow=day();
which sets dow to 1-31 as the output of day() in arduino scales from 1-31...
Then... the loops asking if dow=0 which should check for a restart and trigger a correction of current time of day to midnight will work. Else, if you never define dow its going to always be a zero and every calculation will simply use current elapsed Unix Epoch time in CalcSun... but that could be off by 23:59:59 maximally, depending on the time of day. I am unsure what the exact magnitude of the introduced error might be but it would be but the rise and set times will NOT be the same as if you actually had used midnight.
Code seems ok otherwise... so far as I can tell. I also note that you switched to decimal latitude and longitude but enabled the correct conversion in the code so thats looking ok. As for your offset, I think its looking correct as the time library functions hour() and minute() will do what your trying to do... I think. But do you really need the library functions? You could just grab the current time in hours and minutes using time_t=now() as I did... I am not sure if there is a functional difference, but I because I have not called the hour function as you are I cannot say if its working.
Sunrise / sunset code based on location
Im declaring byte dow=0; right after i declare lat/longitude.
Ill take a look at the rest of your feedback soon!
Thanks so much for reviewing.
Lee
Ill take a look at the rest of your feedback soon!
Thanks so much for reviewing.
Lee
Re: Sunrise / sunset code based on location
Sorry... missed that. I think it looks correct (the dow=day()) command is before you call CalSun() in the loop). So... looks like it should start with a global declaration of dow=0
Then... if its still zero run cal sun and trigger a time correction to midnight.
Then set dow=day() so it does not run again until the day changes...
then dow!=0 so no time correction needed....
unsure why its not working... let us know what happens when you get a chance to look it all the way through, I easily could be missing something important. Tough to read and trouble shoot. Good luck.
Then... if its still zero run cal sun and trigger a time correction to midnight.
Then set dow=day() so it does not run again until the day changes...
then dow!=0 so no time correction needed....
unsure why its not working... let us know what happens when you get a chance to look it all the way through, I easily could be missing something important. Tough to read and trouble shoot. Good luck.
Sunrise / sunset code based on location
Thanks. Been dealing with a pinched nerve in my leg the past few days, so all activities have been on pause
Re: Sunrise / sunset code based on location
Ouch! Sorry to hear that, I bet sitting to program would be delightful.
One thing- I am typically up fairly late so I know that I have not experienced the weird lights on late behavior that you saw but the other day I did have one weird thing at about 1 am... one side of the tank had very very dim lighting. It seems to be good now, but I wonder... more now than ever before. The library I grabbed and basically use unmodified is where the calculation results are coming from, and it has always worked when I test it. But- because were on arduino its exceedingly painful to extensively test this. As you have detailed- For me this is the only time I have ever seen lights on when they should not be... and I will be checking more regularly but I would guess I am up after midnight more often than not so its not common. I have not earthly idea whats up, to me the most likely thing is not in the code- per see... but certainly because of the code.. but I wonder if memory is being corrupted. I ran into this REPEATEDLY during my writing the code, but it was *ALL* because of my extensive use of arrays in the weather features and doing stupid stuff like writing to locations past their allocated memory. But, I NEVER looked into the library code so it may be possible that somewhere somehow the memory location for either the input midnight seconds is occasionally getting corrupted from somewhere or equally possibly, the location of the values for rise and set. I just don't see an algorithm working the vast majority of the time and then suddenly outputting garbage... its just not making sense from that perspective as I have seen that even when people feed it times that are DECADES in the future, they get the right values back so the algorithim seems solid.
Your NOT using any of my arrays for lighting effects so its not there either. Unsure how the heck to get at this, but my money is now kinda drifting to the memory side of things... which is like chasing a ghost. I would need help to look at this, its beyond my ability and understanding- very very far beyond. But- if you know anything or have ideas... I would be looking here. The other possibility is that the system time memory is getting corrupted... I think I remember that I did this accidentally once... so if there is a memory leak ANYWHERE on the code loaded- all bets are off as to what might take the hit. But seriously- this sounds like that kinda problem. No way you can write a algorithm that works when tested and then suddenly its giving garbage results, its JUST math. That is a fixed predictable process that I feel works. Memory- well, I did it- its easy to corrupt and its RANDOM what happens- possibly predictably so but this really really sounds like that kinda issue.
Any thoughts from the big guns who know this platform?
One thing- I am typically up fairly late so I know that I have not experienced the weird lights on late behavior that you saw but the other day I did have one weird thing at about 1 am... one side of the tank had very very dim lighting. It seems to be good now, but I wonder... more now than ever before. The library I grabbed and basically use unmodified is where the calculation results are coming from, and it has always worked when I test it. But- because were on arduino its exceedingly painful to extensively test this. As you have detailed- For me this is the only time I have ever seen lights on when they should not be... and I will be checking more regularly but I would guess I am up after midnight more often than not so its not common. I have not earthly idea whats up, to me the most likely thing is not in the code- per see... but certainly because of the code.. but I wonder if memory is being corrupted. I ran into this REPEATEDLY during my writing the code, but it was *ALL* because of my extensive use of arrays in the weather features and doing stupid stuff like writing to locations past their allocated memory. But, I NEVER looked into the library code so it may be possible that somewhere somehow the memory location for either the input midnight seconds is occasionally getting corrupted from somewhere or equally possibly, the location of the values for rise and set. I just don't see an algorithm working the vast majority of the time and then suddenly outputting garbage... its just not making sense from that perspective as I have seen that even when people feed it times that are DECADES in the future, they get the right values back so the algorithim seems solid.
Your NOT using any of my arrays for lighting effects so its not there either. Unsure how the heck to get at this, but my money is now kinda drifting to the memory side of things... which is like chasing a ghost. I would need help to look at this, its beyond my ability and understanding- very very far beyond. But- if you know anything or have ideas... I would be looking here. The other possibility is that the system time memory is getting corrupted... I think I remember that I did this accidentally once... so if there is a memory leak ANYWHERE on the code loaded- all bets are off as to what might take the hit. But seriously- this sounds like that kinda problem. No way you can write a algorithm that works when tested and then suddenly its giving garbage results, its JUST math. That is a fixed predictable process that I feel works. Memory- well, I did it- its easy to corrupt and its RANDOM what happens- possibly predictably so but this really really sounds like that kinda issue.
Any thoughts from the big guns who know this platform?
Re: Sunrise / sunset code based on location
So, after turning the calculations into a standalone binary, I found the cause of my concerns...
The issue was that by declaring latitude and longitude as global variables... and then keeping this code in CalSun()
I was continually re-calculating lat/long and it was completely screwing up after midnight. Reset controller and it would calc properly... only the first time... so those functions have to move out to setup().
Also, now that I had a standalone binary... I played with the following function...
With that commented, I was able to get the best accuracy with the following offset added..
Keep in mind this is only ~17 minute offset for each, but one thing is that the time is assuming the local time is set to the lat/long that you are calculating for...
With that code uncommented, I get the rise/set time calculated at -14 hours from the current time which is actually what I should see as the aruduino assumes we are at GMT (and we are currently +4 and GBR, AU is at -10), so total is -14. I still had to add an offset to get the most accurate times, but now it's around ~8 minutes.
Since I really want the RA to actually offset -9 hours, I will change the 14*3600 to 9*3600 in my final code to get the hours I want. I did not compare any other GPS coordinates to the output of the function to see if the accuracy holds or is different for different parts of the world. I'm sure it wouldn't be. But this is what I came up with... Feel free to experiment.
The issue was that by declaring latitude and longitude as global variables... and then keeping this code in CalSun()
Code: Select all
latitude=ddToSeconds(latitude);
longitude=ddToSeconds(longitude);
Also, now that I had a standalone binary... I played with the following function...
[/quote]rufessor wrote:Code: Select all
//*dt -= longitude / 15.0; // rotate to our own meridian
With that commented, I was able to get the best accuracy with the following offset added..
Code: Select all
int userRiseOffset=1025;
int userSetOffset=1058;
// You could just call it at 1020 (17 minutes) for the average...
With that code uncommented, I get the rise/set time calculated at -14 hours from the current time which is actually what I should see as the aruduino assumes we are at GMT (and we are currently +4 and GBR, AU is at -10), so total is -14. I still had to add an offset to get the most accurate times, but now it's around ~8 minutes.
Code: Select all
int userRiseOffset=-(14*3600)+472;
int userSetOffset=-(14*3600)+506;
// You could just call it at 480 for the average...
Re: Sunrise / sunset code based on location
OK, This should be the bug free working code.
Code: Select all
//By Matthew Hockin 2012.
//SWFLTEK library functions, #includes, and #define were copied directly from the Epherma library
//Epherma (SWFLTEK.com) was written by Michael Rice- thanks Michael it works great.
//If you copy from this (its all open source) please
//acknowledge Michael for SWFLTEK library code (obviously labeled) or Matthew Hockin (for the rest).
#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 <ReefAngel.h>
////// Place global variable code below here
//includes for SWFLTEK functions
#include <stdlib.h>
#include <math.h>
//defines for SWFLTEK functions
#define _sec_rad 206264.806247096370813 // arc-seconds per radian
#define _tilt 0.409092804222329 // axial tilt of earth at epoch, in radians
#define _tropical_year 31556925 // tropical year in seconds... rounding error accumulates to 26 seconds by the year 2136
#define _zenith 3.11250383272322 // 'zenith' of rising (setting) sun in radians (360 - 2 * 90.833 degrees)
//*******************GLOBAL VARIABLE DECLERATIONS FOR MHOCKIN Weather package*************************************
long latitude=-18.285833; // Great Barrier Reef, Australia
long longitude=147.699722; // Great Barrier Reef, Australia
byte dom=0;//day of month
//*******************END HEADER FOR MHOCKIN Weather package*******************************************************
// Additional variables added for Sunrise/Sunset calculation
int SunriseHour, SunriseMin, SunsetHour, SunsetMin;
// Most accurate...(for GBR at least...)
int userRiseOffset=-(14*3600)+472;
int userSetOffset=-(14*3600)+506;
////// Place global variable code above here
void setup()
{
// Adjust lat/long to seconds here. Only need to do this once!
latitude=ddToSeconds(latitude);
longitude=ddToSeconds(longitude);
// This must be the first line
ReefAngel.Init(); //Initialize controller
// Ports that are always on
////// Place additional initialization code below here
////// Place additional initialization code above here
}
void loop()
{
////// Place your custom code below here
// Set Sunrise and Sunset from MHOCKIN Weather package functions.
if (dom!=day()) // used to see that were in a new day and need to recalculate sunrise and sunset
{
CalSun();
dom=day();
// And let's reset the light schedule
}
////// Place your custom code above here
// This should always be the last line
ReefAngel.ShowInterface();
}
//Start of sunrise, sunset and cloud calculations- runs on reset and once a day thereafter.
void CalSun(){
long newDay;
unsigned long rise;//time in seconds from the year 2000 (GMT) for sunrise
unsigned long set;//time in seconds from the year 2000 (GMT) for sunrise
//Serial.println("CalSun Run Now");
long hours, minutes, seconds;//store current elapsed local hours as total seconds from midnight
time_t t=now();//store current clock time to parse
hours=hour(t);
hours=(hours*3600);//current hour number 0-23 as seconds
minutes=minute(t);
minutes=(minutes*60);//minutes of current hour as seconds
seconds=second(t);
newDay=now();
newDay-=(hours+minutes+seconds);//Convert current local unix epoch time to local unix epoch time of midnight
//#define SECS_YR_2000 (946684800) the time at the start of y2k (need to subtract from unix epoch time to bring to Y2K origin
newDay-=946684800;//convert GMT unix Epoch to seconds elasped since 2000 for GMT midnight of today
rise=newDay;
set=newDay;
//Calculate rise time and set time using Epherma Library functions (see end of code)
SunRise(&rise);//call to Epherma function
SunSet(&set);//Call to Epherma functionunsigned long newDay;
/*
Serial.print("rise and set= ");
Serial.println(rise);
Serial.println(set);
Serial.print("newDay as seconds since 2000 to todays midnight= ");
Serial.println(newDay);
*/
rise+= 946684800;
set += 946684800;
newDay+=946684800;
// Convert rise/set to normal hours/minutes before we make it an offset from midnight.
// Currently correcting for a 56 minute correction to Sunrise and -19 minute correction to Sunset (8/14/2012@GBR)
SunriseHour=hour(rise+userRiseOffset);
SunriseMin=minute(rise+userRiseOffset);
SunsetHour=hour(set+userSetOffset);
SunsetMin=minute(set+userSetOffset);
}//END SunCalc FUNCTION
//********************** DO NOT MESS WITH THIS UNLESS YOU KNOW WHAT YOUR DOING****************************
//THE CODE BELOW THIS copied directly from the SWFLTEK Epherma library constructed by Michael Rice.
//this code is being used freely with attribution to Micahel Rice in accord with his request
// A big thank you for these library functions. Its great!
// decimal degrees
long ddToSeconds(float dd){
return dd * 3600.0;
}
//Degrees, minutes, seconds
long dmsToSeconds(int d, unsigned char m, unsigned char s){
long ret;
ret = labs((long)d);
ret = ret * 3600L + 60L * m + s;
ret = (d<0L) ? -ret : ret;
return ret;
}
/* ------------------------------------------------------------------------------------------------
'Equation of Time'
We use the 'short form equation, which has a theoretical accuracy of about 40 seconds.
The returned value is in seconds.
*/
int equation_of_time(unsigned long dt){
double t;
dt -= 192540UL; // refer to Jan 3 2000 05:29 (first periapsis)
dt %= _tropical_year;
t = dt;
t /= _tropical_year;
t *= 6.283185307179586;
t = -459.27672 * sin(t) + 575.333472 * sin(2.0 * t + 3.588414);
return t;
}
/* -----------------------------------------------------------------------------------------------
'Solar Declination'
Returns declination in radians
Accurate to within 50 arc-seconds
*/
double SolarDeclination(unsigned long dt){
double y;
dt %= _tropical_year;
y = dt;
y /= _tropical_year; // fractional year
y *= 6.283185307179586;
y=0.006918-0.399912*cos(y)+0.070257*sin(y)-0.006758*cos(y*2)+0.000907*sin(y*2)-0.002697*cos(y*3)+0.00148*sin(y*3);
return y;
}
/* ------------------------------------------------------------------------------------------------
Return the period between sunrise and sunset, in seconds.
At high latitudes around the time of the solstices, this could be zero, or all day.
*/
unsigned long daylightseconds(unsigned long dt){
float l, d, e;
long n;
d = -SolarDeclination(dt); // will be positive in Northern winter
l = latitude / _sec_rad; // latitude in radians
e += 60.0 * l * tan(l + d); // latitudinal error
d = tan(l) * tan(d); //
if(d>1.0) return 86400UL;
if(d < -1.0) return 0UL;
d = acos(d);
d /= _zenith;
n = 86400UL * d;
n += e;
return n;
}
/* ------------------------------------------------------------------------------------------------
Modify the passed time stamp to the time of sunrise (or sunset if 'set' is non-zero).
Returns 0 to signal 'normal' completion. If the position is in a polar circle, 1 will be
returned if the sun is above the horizon all day, and -1 if the sun is below the horizon
all day.
*/
char SunRiseSet(unsigned long * dt, char set){
unsigned long daylen;
daylen = daylightseconds(*dt);
if(daylen == 86400UL) return 1; // there is no 'night' today (midnight sun)
if(daylen == 0UL) return -1; // there is no 'day' today
*dt /= 86400UL;
*dt *= 86400UL;
*dt += 43200UL; // set the time stamp to 12:00:00 GMT
*dt -= daylen / 2; // sunrise at the prime meridian
if(set) *dt += daylen; // sunset at the prime meridian
*dt -= equation_of_time(*dt);
*dt -= longitude / 15.0; // rotate to our own meridian
return 0;
}
// 'short' forms of SunRiseSet
char SunRise(unsigned long* when){
return SunRiseSet(when, 0);
}
char SunSet(unsigned long* when){
return SunRiseSet(when, 1);
}
Re: Sunrise / sunset code based on location
Here's the code I changed in order to compile it as a standalone binary... this is not in real diff format, so you'll have to patch it manually... It is based on the code listed in post http://forum.reefangel.com/viewtopic.php?p=13419#p13419
Here's the header file I had to create...
and also for Time.cpp I had to modify the now() function to return the system time...
The rest of the now() function should be commented out. You'll also have to copy Time.h and Time.cpp to the working folder. Here's the command I used to compile.
Code: Select all
> #include <test.h>
> #include <stdio.h>
> #include <unistd.h>
---
< long latitude=-18.285833; // Great Barrier Reef, Australia
< long longitude=147.699722; // Great Barrier Reef, Australia
---
> double latitude=-18.285833; // Great Barrier Reef, Australia
> double longitude=147.699722; // Great Barrier Reef, Australia
---
< int userOffset=-(9*3600); // -9 hours
>
> // Most accurate...
> int userRiseOffset=-(14*3600)+472;
> int userSetOffset=-(14*3600)+506;
>
> int os=0;
--
< Remove setup() and loop() functions
-- // Add main() function
> int main() {
> latitude=ddToSeconds(latitude);
> longitude=ddToSeconds(longitude);
> int i=0;
>
> // Set Sunrise and Sunset from MHOCKIN Weather package functions.
> for (i=0;i<=(483+3650);i++) {
> CalSun();
> os+=(24*3600);
> }
> }
--- // The next few changes go into CalSun()
> newDay+=os;
---
< SunriseHour=hour(rise+userOffset);
< SunriseMin=minute(rise+userOffset);
< SunsetHour=hour(set+userOffset);
< SunsetMin=minute(set+userOffset);
---
> SunriseHour=hour(rise+userRiseOffset);
> SunriseMin=minute(rise+userRiseOffset);
> SunsetHour=hour(set+userSetOffset);
> SunsetMin=minute(set+userSetOffset);
>
> printf("%02d/%02d/%d %d:%02d %d:%02d\n", month(newDay), day(newDay), year(newDay),SunriseHour, SunriseMin, SunsetHour, SunsetMin);
>
>
-- // Cast changes that had to happen to compile...
< return dd * 3600.0;
> return (long) (dd * 3600.0);
---
< int equation_of_time(unsigned long dt){
> double equation_of_time(int dt){
---
< double SolarDeclination(unsigned long dt){
> double SolarDeclination(long dt){
---
< n = 86400UL * d;
< n += e;
---
> n = (unsigned long) (86400UL * d);
> n += (unsigned long) e;
>
---
< if(set) *dt += daylen; // sunset at the prime meridian
> if(set) *dt += (long) daylen; // sunset at the prime meridian
---
< *dt -= equation_of_time(*dt);
> *dt -= (long) equation_of_time((int) *dt);
---
< *dt -= longitude / 15.0; // rotate to our own meridian
> *dt -= (long) (longitude / 15.0); // rotate to our own meridian
Code: Select all
void CalSun();
long ddToSeconds(float);
long dmsToSeconds(int, unsigned char, unsigned char);
double equation_of_time(long);
double SolarDeclination(long);
unsigned long daylightseconds(unsigned long);
char SunRiseSet(unsigned long*, char);
char SunRise(unsigned long*);
char SunSet(unsigned long*);
Code: Select all
> time_t t;
> return time(&t);
Code: Select all
g++ -o test test.cpp Time.cpp -I .
Re: Sunrise / sunset code based on location
So great! Thanks for going through all the trouble and verifying the code is stable and outputs correctly. I am still a little confused as to how the global declaration of Latitude and Longitude is screwing up with CalSun- my read of your post is that somehow that was calculating continuously? Was it somehow getting stuck and left as a process or was CalSun never exiting? Cause it should only run on restart or midnight?
Just trying to figure out exactly what you mean.
Very very excellent. This was much needed as there seems to be a LOT of confusion going around this piece of code. I feel a little bit responsible
Now that we have this bit of data... When I hear back from you I will change anything in the Dimming expansion module that might need changing, re post to that thread and we should have this working on the main as well as on the dimming modules. I need hear back from you before I can fully understand what's up with the lat/lon declarations. But will be testing this on my dimming module and know a few people running this I can ask them to help test as well. But- Congrats most excellent.
Just trying to figure out exactly what you mean.
Very very excellent. This was much needed as there seems to be a LOT of confusion going around this piece of code. I feel a little bit responsible
Now that we have this bit of data... When I hear back from you I will change anything in the Dimming expansion module that might need changing, re post to that thread and we should have this working on the main as well as on the dimming modules. I need hear back from you before I can fully understand what's up with the lat/lon declarations. But will be testing this on my dimming module and know a few people running this I can ask them to help test as well. But- Congrats most excellent.
Re: Sunrise / sunset code based on location
So the issue with latitude and longtitude was a bug that *I* introduced...
In the original CalSun() function...
Which I modified to use a globally declared latitude and longitude as single variables (instead of hour,min,sec..)
So, the problem was that every time CalSun was executed, it would re-calculate lat/long from Coordinates to seconds. So it would work the first time, but then after midnight, it would re-calc and then it would re-calculate the lat/long and get screwed up...
So, unless you copied my lat/long changes, you probably experienced something else. But running the standalone test over a few years (I ran it to 10 years and the date/times looked good, but I only verified in full 2013...), so the actual calculations look good....
In the original CalSun() function...
Code: Select all
latitude=dmsToSeconds(40,44,00); //United States of America- Salt Lake City, local time is -7 hours GMT
longitude=dmsToSeconds(-111,47,00);
Code: Select all
// In global declaration...
long latitude=-18.2861; // Great Barrier Reef, Australia
long longitude=147.7000; // Great Barrier Reef, Australia
// and then within CalSun() function
latitude=ddToSeconds(latitude);
longitude=ddToSeconds(longitude);
So, unless you copied my lat/long changes, you probably experienced something else. But running the standalone test over a few years (I ran it to 10 years and the date/times looked good, but I only verified in full 2013...), so the actual calculations look good....
Re: Sunrise / sunset code based on location
Ok. Thanks
That makes more sense. I will look again at the original code, I think its ok but I dont remember for sure
That makes more sense. I will look again at the original code, I think its ok but I dont remember for sure
Re: Sunrise / sunset code based on location
how hard is this to make into a paste and go function? That's what I'm going to try to work on redeveloping.
Sunrise / sunset code based on location
I pasted the minimum code needed already some posts back...theres no way to make it one function but its pretty close. Im no sure if binder is working on turning it into a class still...he's a pretty busy guy
But it's pretty straightforward at this point. If you have questions setting it up let me know.
But it's pretty straightforward at this point. If you have questions setting it up let me know.
Re: Sunrise / sunset code based on location
I haven't converted it into a class yet. You are correct...I am a pretty busy guy. I'll see what I can come up with though.lnevo wrote:I pasted the minimum code needed already some posts back...theres no way to make it one function but its pretty close. Im no sure if binder is working on turning it into a class still...he's a pretty busy guy
But it's pretty straightforward at this point. If you have questions setting it up let me know.
Re: Sunrise / sunset code based on location
Ok. I've got it all merged into a class. However, I'm a little confused on some of the specifics of the functions with all the back and forth going on.
I have a couple questions that I need answered before I post my code for you guys to test out.
1. How / What would be the "best" way to initialize the location you want to calculate the sunrise / sunset off of? I've seen the Degrees, Minutes, Seconds route and the actual Lat and Long route. I currently have it configured to only use the Lat / Long route. Is this acceptable or do I need both options or only D,M,S?
2. User Sunrise / Sunset offset? I figured it out that it's the hours offset but I'm a little confused as to how to compute the minutes. I don't need an explanation on how it's computed or why (I figured out why it would be and it makes sense). I just don't know how you came up with the corrections. I have a function that allows for setting an offset and I allow for a sunrise offset hour and seconds along with sunset offset hour and seconds. Should that be changed to minutes? If so, what equation should I use to convert it properly?
I'm referring to this line:
I figured out the hours is 14 but I don't know how you computed the minutes to be 472 for a 56 minute offset. Anyways, should we use seconds or minutes? and if minutes what formula to compute it?
3. What values are needed to be used from this class? I'm guessing it's simply Sunrise Hour, Sunrise Minute, Sunset Hour, Sunset Minute. Is this all?
Ok, that's all the questions that I have for now.
The way I have it set to be used is as follows:
This was a very crude example of how it could be used. It can be this way if it's not a part of the libraries. If it was included with the libraries, it could be simplified even more than this. In fact, you could have separate functions that handle all the "heavy lifting" and you could just have a simple StandardLightsComputed() function (or whatever) that would use the proper values for the sunrise and sunset for you.
Anyways, I just need some more feedback so I can finalize a few things with it before I post the code.
I have a couple questions that I need answered before I post my code for you guys to test out.
1. How / What would be the "best" way to initialize the location you want to calculate the sunrise / sunset off of? I've seen the Degrees, Minutes, Seconds route and the actual Lat and Long route. I currently have it configured to only use the Lat / Long route. Is this acceptable or do I need both options or only D,M,S?
2. User Sunrise / Sunset offset? I figured it out that it's the hours offset but I'm a little confused as to how to compute the minutes. I don't need an explanation on how it's computed or why (I figured out why it would be and it makes sense). I just don't know how you came up with the corrections. I have a function that allows for setting an offset and I allow for a sunrise offset hour and seconds along with sunset offset hour and seconds. Should that be changed to minutes? If so, what equation should I use to convert it properly?
I'm referring to this line:
Code: Select all
int userRiseOffset=-(14*3600)+472;
3. What values are needed to be used from this class? I'm guessing it's simply Sunrise Hour, Sunrise Minute, Sunset Hour, Sunset Minute. Is this all?
Ok, that's all the questions that I have for now.
The way I have it set to be used is as follows:
Code: Select all
// standard code headers
#include <SunLocation.h>
// Globals
SunLocation sl;
void setup()
{
ReefAngel.Init();
// init to different location other than default
sl.Init(-18.285833,147.699722); // Lat, Long. If not initialized, it's set to GBR
// set offset if needed
sl.SetOffset(14,472,14,506); // If not set, defaults to the values listed
}
void loop()
{
// handles all the additional checks for updating
sl.CheckAndUpdate();
// get the values and use them
ReefAngel.StandardLights( Port1, sl.GetRiseHour(), sl.GetRiseMinute(), sl.GetSetHour(), sl.GetSetMinute());
ReefAngel.ShowInterface();
}
Anyways, I just need some more feedback so I can finalize a few things with it before I post the code.
Sunrise / sunset code based on location
Here's my take,,
1) I prefer the lat/long single variables as its easier to set the variables...for a class I think it's the easier way to go...I'm not sure why you'd need both, it's easy enough to find the coords you need online in whatever format is required. I say whatever format is easiest to support...
2) the offset aside from the hours was calculated to give me the best margin of error for 2013 based on a year of calculations and comparing to GBR (I think I got the data from timeanddate.com?) it's 472 seconds in that example which is under 10 minutes, not sure where you got 56 minutes? The whole variable is seconds since 2000. So 14*3600 is 14 hours and i added an extra 472 or 506 seconds to get it more accurate. I believe this may be just margin of error in the functions used to calc...not 100% sure...I would leave it out and let user adjust...but I think best adjust would be in either seconds or minutes. Definitely not necessarily hours...for me to maintain the offset I figured out I'd need to maintain seconds...maybe make the offset take hours,min,sec as the args? Overload if too much of a pain?
3) yes...unless anyone can think of any other variables, but I think that's basically all that's calculated, unless you want the seconds...but none of the light functions need that so...
Great job..the use looks great! Will be even better if integrated into the library!
Lee
1) I prefer the lat/long single variables as its easier to set the variables...for a class I think it's the easier way to go...I'm not sure why you'd need both, it's easy enough to find the coords you need online in whatever format is required. I say whatever format is easiest to support...
2) the offset aside from the hours was calculated to give me the best margin of error for 2013 based on a year of calculations and comparing to GBR (I think I got the data from timeanddate.com?) it's 472 seconds in that example which is under 10 minutes, not sure where you got 56 minutes? The whole variable is seconds since 2000. So 14*3600 is 14 hours and i added an extra 472 or 506 seconds to get it more accurate. I believe this may be just margin of error in the functions used to calc...not 100% sure...I would leave it out and let user adjust...but I think best adjust would be in either seconds or minutes. Definitely not necessarily hours...for me to maintain the offset I figured out I'd need to maintain seconds...maybe make the offset take hours,min,sec as the args? Overload if too much of a pain?
3) yes...unless anyone can think of any other variables, but I think that's basically all that's calculated, unless you want the seconds...but none of the light functions need that so...
Great job..the use looks great! Will be even better if integrated into the library!
Lee
Sunrise / sunset code based on location
Just an Addon to #2...I'm subtracting 14 hours...so the example you had in I it would need to be -14 and again the 472 and 506 were seconds added to improve the accuracy...this took compiling a separate binary and comparing to data on the web...don't know if this would be standard or dependent on gps coords or not...Ymmv.. In the end, I think either just make the offset in seconds, or h,m,s to make it easier to calculate. Not sure the easiest for others. Would love some other input from ppl.
Sunrise / sunset code based on location
And as far as StandardLightsComputed() type of function...you'd still want a way to modify the times like of you want to turn blues on the. Whites the. Whites off then blues off which is what I'm doing now...just saying...
Awesome job though! Can't wait to integrate it this way and simplify my RA code
Awesome job though! Can't wait to integrate it this way and simplify my RA code
Re: Sunrise / sunset code based on location
well this new function will make things easier I suppose. How will the new library function be used in main ino code?
Re: Sunrise / sunset code based on location
There's not a new library function right now. You would use it like I posted previously.alexwbush wrote:well this new function will make things easier I suppose. How will the new library function be used in main ino code?
If it were included into the libraries, you would need to enable support for it. Then we would probably have several functions to reference it.
lnevo -
I'm going to keep it be as Lat and Long initializing. It will be simpler having 2 variables vs 6 (d,m,s to compute the lat & long).
I got the 56 minutes from comment in the file next to the offset: (I changed the offset variable names).
Code: Select all
// Currently correcting for a 56 minute correction to Sunrise and -19 minute correction to Sunset (8/14/2012@GBR)
m_UserRiseOffset = -(14*3600)+472;
m_userSetOffset = -(14*3600)+506;
I'm also attaching my code to this post.
Here's how you use it:
- Download SunLocation.zip file.
- Extract this file to Documents/Aruduino/libraries. This will create a new folder inside the libraries folder called SunLocation
- Now the library is ready to use, see below for sample code
Code: Select all
#include <Salinity.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 <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <ReefAngel.h>
#include <SunLocation.h>
SunLocation sl;
void DrawCustomMain()
{
char buf[16];
ReefAngel.LCD.Clear(DefaultBGColor,0,0,132,132);
sprintf(buf, "%02d:%02d", sl.GetRiseHour(), sl.GetRiseMinute());
ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,10,10,"Sunrise: ");
ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,58,10,buf);
sprintf(buf, "%02d:%02d", sl.GetSetHour(), sl.GetSetHour());
ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,10,30,"Sunset: ");
ReefAngel.LCD.DrawText(DefaultFGColor,DefaultBGColor,58,30,buf);
}
void DrawCustomGraph()
{
}
void setup()
{
ReefAngel.Init();
// initialize the sunrise / sunset location
// Latitude , Longitude values set
sl.Init(-18.285833, 147.699722);
}
void loop()
{
// handle updating sunrise and sunset values
sl.CheckAndUpdate();
ReefAngel.ShowInterface();
}
- Attachments
-
- SunLocation.zip
- Sunrise and Sunset Location library
- (3.6 KiB) Downloaded 424 times
Re: Sunrise / sunset code based on location
So what's the current syntax to set the offset? I'm going to be updating my code soon and I'll swap out for the object you created! Awesome!
The 56 minutes was just a non updated comment...it's not in my code anymore
The 56 minutes was just a non updated comment...it's not in my code anymore
Last edited by lnevo on Thu Sep 20, 2012 6:40 pm, edited 1 time in total.
Re: Sunrise / sunset code based on location
Ok two issues...I answered my own question reviewing the code...so I know how to set the offset...
The first issue is here:
You kept my default of subtracting hours... You should assume positive for the offset and then I would use -14 as the arg...
Not so much an issue but unneeded code in CalSun()? These don't do anything after this point...
And just a question...since you default to GBR...if I want to use the default then do I still need to call init? Looking at the code, I think not...
The first issue is here:
Code: Select all
void SunLocation::SetOffset(int risehour, int risesec, int sethour, int setsec)
{
m_UserRiseOffset = -(risehour*3600)+risesec;
m_UserSetOffset = -(sethour*3600)+setsec;
}
Not so much an issue but unneeded code in CalSun()? These don't do anything after this point...
Code: Select all
rise+= 946684800;
set += 946684800;
newDay+=946684800;
Re: Sunrise / sunset code based on location
good points. i will correct the offset values to be positive and then you can input your offset as needed. right now you would have to enter a negative value for a positive offset.lnevo wrote:Ok two issues...I answered my own question reviewing the code...so I know how to set the offset...
The first issue is here:
You kept my default of subtracting hours... You should assume positive for the offset and then I would use -14 as the arg...Code: Select all
void SunLocation::SetOffset(int risehour, int risesec, int sethour, int setsec) { m_UserRiseOffset = -(risehour*3600)+risesec; m_UserSetOffset = -(sethour*3600)+setsec; }
Not so much an issue but unneeded code in CalSun()? These don't do anything after this point...
And just a question...since you default to GBR...if I want to use the default then do I still need to call init? Looking at the code, I think not...Code: Select all
rise+= 946684800; set += 946684800; newDay+=946684800;
i will remove those lines of code too. i wasn't paying attention and just converting what was there.
you are correct, you don't really need to call Init if you are gonna use GBR. i would for completeness and if the default ever changes but that may not happen.
Re: Sunrise / sunset code based on location
Ok, I implemented the class and I did find a big bug!
The Init function is required, otherwise you never convert the lat/long in coordinates to seconds...
I modified the SunLocation() constructor so it could be optional again
Second, here is where the MAJOR issue is...
In the header file, in the private: section, you are declaring latitude and longitude as int. They MUST be long.
Otherwise we do not get the right value after doing ddToSeconds which definitely screws up the time calculations. Subtle if you weren't already using it and expecting certain values
Also, while I thought this was unnecessary, rise and set will be from 1970 instead of from 2000 if we don't leave these in. I don't think it matters, because it's only years... but best to leave it if we ever want full date info out of the class. newDay is local, but again never know what we may use it for later.
Anyway, the rest of it looks good. Took me a bit to debug, but I'm glad I found it. I only would have known it wasn't working because the offset was not where I had expected it and it was pushing the time to where I was before I enabled the longitude rotation part during my debugging. Let me know if any questions on the fixes.
I'll attach the file for those that don't want to wait for the fix (I also changed the offset to not be negative...)
The Init function is required, otherwise you never convert the lat/long in coordinates to seconds...
I modified the SunLocation() constructor so it could be optional again
Code: Select all
SunLocation::SunLocation()
{
m_Latitude = ddToSeconds(-18.285833); // Great Barrier Reef, Australia
m_Longitude = ddToSeconds(147.699722); // Great Barrier Reef, Australia
m_UserRiseOffset = 0;
m_UserSetOffset = 0;
m_DayOfMonth = 0;
}
In the header file, in the private: section, you are declaring latitude and longitude as int. They MUST be long.
Code: Select all
// lat & long for the location
long m_Latitude;
long m_Longitude;
Also, while I thought this was unnecessary, rise and set will be from 1970 instead of from 2000 if we don't leave these in. I don't think it matters, because it's only years... but best to leave it if we ever want full date info out of the class. newDay is local, but again never know what we may use it for later.
Code: Select all
rise+= 946684800;
set += 946684800;
newDay+=946684800;
Anyway, the rest of it looks good. Took me a bit to debug, but I'm glad I found it. I only would have known it wasn't working because the offset was not where I had expected it and it was pushing the time to where I was before I enabled the longitude rotation part during my debugging. Let me know if any questions on the fixes.
I'll attach the file for those that don't want to wait for the fix (I also changed the offset to not be negative...)
- Attachments
-
- SunLocation.zip
- (3.81 KiB) Downloaded 419 times
Re: Sunrise / sunset code based on location
Just want to add that having it as a class has made my code so much simpler in my main INO. Love it! Great work on putting it together this way curt! Thanks a million.
Re: Sunrise / sunset code based on location
It only LOOKs simple!
You do need to correct years to 2000 from 1970 or your julian date conversion (which is implicit in the calculation) is going to be WAY off.. leap year etc....
So those conversions need to be left in, no question.
One comment, I would be somewhat apprehensive about utilizing an offset- it its going to be seasonally changing and dependent upon the position (very dependent) you use (lat/long), so if its hard coded in and its used world wide its going to cause more problems than it will ever solve.
To bad the head does not have enough room for the cloud effects... but its nice to have a port of the basic calculations to the main for rise and set, those are fairly light duty. Especially in terms of memory its only a couple variables that are global.
I would bet the Plus might be able to handle the whole thing. ANy interest in moving the whole thing? You could have two classes- weather, and rise_set or whatever, they could basically be completely independent and if you simply reframe the variables such that they are generic lights on and lights off times, the weather class could run independently of the rise_set class and be used by anyone with a plus- since it just needs to know day length... thats it. It then creates all the clouds/storms etc to fit into the given day.
You do need to correct years to 2000 from 1970 or your julian date conversion (which is implicit in the calculation) is going to be WAY off.. leap year etc....
So those conversions need to be left in, no question.
One comment, I would be somewhat apprehensive about utilizing an offset- it its going to be seasonally changing and dependent upon the position (very dependent) you use (lat/long), so if its hard coded in and its used world wide its going to cause more problems than it will ever solve.
To bad the head does not have enough room for the cloud effects... but its nice to have a port of the basic calculations to the main for rise and set, those are fairly light duty. Especially in terms of memory its only a couple variables that are global.
I would bet the Plus might be able to handle the whole thing. ANy interest in moving the whole thing? You could have two classes- weather, and rise_set or whatever, they could basically be completely independent and if you simply reframe the variables such that they are generic lights on and lights off times, the weather class could run independently of the rise_set class and be used by anyone with a plus- since it just needs to know day length... thats it. It then creates all the clouds/storms etc to fit into the given day.
Sunrise / sunset code based on location
Rufessor as far as the rise set needing the += it is in the code *after* the calculations which is why i said it may or may not be needed.
I did want to add back the solar noon function to this class and see what would be needed to get back the dimming that you do...i have no dimming LEDs so hard to play with but definitely useful for those that just need 2 channel control.
As far as the weather...could certainly be doable and my + controller has plenty of mem...i just have no way to test on my own.
I really want to do a diy set of fixtures at some point, but really intimidated by the project and costs...so may be a while...
As fas as the offset, it doesn't really change much seasonally..at least with the GBR time zone you get mostly 12 hours of daylight with +/- 30 minutes as the year goes on...when i made the standalone binary the rise/set times varied very nicely over the course of the year...
I highly recommend using an equatorial time zone and setting the offset for your viewing pleasure...will be much more consistent than a US or other higher latitude area..
On another note, who wants to help wrote a coral acclimation function
Something like the new radions have where we can set number of days for the program to run and either start dim/ end dim or time based for those like me without dimming lights...
Lee
I did want to add back the solar noon function to this class and see what would be needed to get back the dimming that you do...i have no dimming LEDs so hard to play with but definitely useful for those that just need 2 channel control.
As far as the weather...could certainly be doable and my + controller has plenty of mem...i just have no way to test on my own.
I really want to do a diy set of fixtures at some point, but really intimidated by the project and costs...so may be a while...
As fas as the offset, it doesn't really change much seasonally..at least with the GBR time zone you get mostly 12 hours of daylight with +/- 30 minutes as the year goes on...when i made the standalone binary the rise/set times varied very nicely over the course of the year...
I highly recommend using an equatorial time zone and setting the offset for your viewing pleasure...will be much more consistent than a US or other higher latitude area..
On another note, who wants to help wrote a coral acclimation function
Something like the new radions have where we can set number of days for the program to run and either start dim/ end dim or time based for those like me without dimming lights...
Lee
Re: Sunrise / sunset code based on location
I'm taking down my DIY LED this weekend, time permitting.
I got 2x ELN-60-48P and 24 LEDS (12 Cool White and 12 Royal Blue).
I think they are XP-E LEDs.
If you are interested on a used set to get your feet wet, PM me
I got 2x ELN-60-48P and 24 LEDS (12 Cool White and 12 Royal Blue).
I think they are XP-E LEDs.
If you are interested on a used set to get your feet wet, PM me
Roberto.
Re: Sunrise / sunset code based on location
I could help with the conversion of the weather functionality to a class like with the sunrise / sunset.... or at least get it started for you guys to tweak.
just let me know
just let me know
Sunrise / sunset code based on location
Just to put it out there, we'll need to add daylen and solar noon to the SunLocation class for the weather to have what it needs.