Page 1 of 2

Moon rise/set implementation

Posted: Wed Mar 20, 2013 8:44 pm
by lnevo
Hey guys,

So, I found this other aquarium controller code at http://code.google.com/p/stilo/ that had ported a javascript implementation of a Moonrise/set calculator into Arduino. I have adapted it to the RA libraries and it looks like it's working great.

Anyway if you want to have your moonlights follow an actual rise/set calculated based on GPS location, then here's what you have to do..

Code: Select all

#include Moon.h
And then in your loop() function, add this

Code: Select all

moon_init(21,-73); // pass it lat / lon - it uses ints for the caclulation...
You will then have access to the Moon struct which has the following definition:

Code: Select all

struct moon_t
{
  boolean isRise;
  boolean isSet;
  byte riseH;
  byte riseM;
  byte setH;
  byte setM;
  float riseAZ;
  float setAZ;
}
So you'll be able to do something like this:

Code: Select all

  if (Moon.isRise) {
    ReefAngel.PWM.SetDaylight(MoonPhase());
    ReefAngel.PWM.SetActinic(MoonPhase());
  } else {
    ReefAngel.PWM.SetDaylight(0);
    ReefAngel.PWM.SetActinic(0);
  }
or add this to your display

Code: Select all

    sprintf(buf, "%02d:%02d", Moon.riseH, Moon.riseM);
    ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MR:"); x+=21;
    ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,x,y,buf);
    sprintf(buf, "%02d:%02d", Moon.setH, Moon.setM); x+=36;
    ReefAngel.LCD.DrawText(COLOR_BLACK,DefaultBGColor,x,y,"MS:"); x+=21;
    ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,x,y,buf); x+=36;
    if(Moon.isRise) ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,x,y,"@");
    else ReefAngel.LCD.DrawText(COLOR_RED,DefaultBGColor,x,y,"_");

Re: Moon rise/set implementation

Posted: Wed Mar 20, 2013 9:10 pm
by rimai
Cool :)
Just as curiosity, without having to open the h file, did you change it to use our Time.h library??
What is the time that we had moonrise today? :)

Moon rise/set implementation

Posted: Thu Mar 21, 2013 2:48 am
by lnevo
Yeah i changed it to use out time library.

Rise and set on my screen:
15:32 4:24

There may be some logic in this i still dont understand because my lights are still on lol.. But the times look ok.

They dont match the page that the source came from, but the times change each day properly...

So maybe not exact but Im not an astronomer :) it does take latitude and longitude..

I'll need to look further why the boolean is keeping my light on right now :)

Moon rise/set implementation

Posted: Thu Mar 21, 2013 3:49 am
by lnevo
Alright, I have a fix in, so lights are off at the moment...we'll see if they go on tonight.

There may also be some logic issues when calculating that I may have to review..I may be getting the next days set time while still in the previous days cycle...maybe...

Moon rise/set implementation

Posted: Thu Mar 21, 2013 1:56 pm
by lnevo
Ok, the moon did rise :) Next I want to see if it calculated set time for tomorrow or if I'll need to wait till after midnight. I'll know when I get home :)

Will also test the new PWMSlope function.

Moon rise/set implementation

Posted: Fri Mar 22, 2013 5:18 am
by lnevo
And the moon did set...did not get to see what today's calculation was...I'll have to just wait and see...

The PWMSlope function worked for overnight still :) needs to be checked for standard use now too.

Re: Moon rise/set implementation

Posted: Fri Mar 22, 2013 7:40 am
by Piper
This is very cool, Lee! Are you using the same lat/lon you use for your lighting? I haven't looked too deep into the sunrise/sunset code so not terribly familiar with how that works at the moment.

~Charlie

Re: Moon rise/set implementation

Posted: Fri Mar 22, 2013 11:06 am
by lnevo
Yeah, I'm using the same lat / long right now that I'm using for my SunLocation, but they are not tied to each other. So I'm just setting the same variables. I wanted to keep these seperate so they can stand alone...

Moon rise/set implementation

Posted: Fri Mar 22, 2013 2:20 pm
by lnevo
Well at 4:29pm i have a status of moonlights coming on for today. So thats ~hour diff then yesterday.

I think the offset from real moonrise / set may be from the fact that we do not use any timezone in our clock. I need to test with some other locations and see what the result is.

But it looks like its working. I'll try and test pwmslope with the normal condition and if it works we should be good to go...

Re: Moon rise/set implementation

Posted: Fri Mar 22, 2013 3:17 pm
by lnevo
New times were 16:24 to 04:58

Re: Moon rise/set implementation

Posted: Sat Mar 23, 2013 8:01 am
by lnevo
17:13 to 5:29 for today's schedule...

looks good so far :)

Re: Moon rise/set implementation

Posted: Sun Mar 31, 2013 1:26 am
by thekameleon
Not sure if you had updated the code attached. The isRise was true outside the rise to set time range. I tried to figure out what is going on, but I got lost quickly with the code as I could not figure out the meaning of the variables. So I went ahead and use a PMWParabola function with the rise and set times, which is working so far... Do you have an updated code file?

Re: Moon rise/set implementation

Posted: Mon Apr 01, 2013 7:01 am
by lnevo
The isRise variable I believe is only used during the test_moon() function. This is why I stopped using it also and did the same thing as you. The issue though, I don't know if the parabola works properly when spanning over midnight. I used a previously published PWMSlopeOvernight which I have modified to work either overnight or not overnight. It should end up in the libraries next update I believe. Is the parabola working properly for you?

Re: Moon rise/set implementation

Posted: Mon Apr 01, 2013 7:05 am
by lnevo
Btw, the last code I posted has been updated to the latest and is complete. I haven't done any work on it and it looks like it's working properly. The time is 3 hours off from the coordinates that I am testing with but it could be because we do not really do any time zone on the RA. and the place I have is -3 from GMT... anyway, please test and if you have improvements, I'm all for it. I don't know enough of what's going on and spent like 3 days reading the code to really start tinkering and changing it around. I now have a variable rise/set that matches a moon cylce so I'm happy :)

Re: Moon rise/set implementation

Posted: Mon Apr 01, 2013 11:26 am
by thekameleon
I'd just like to understand the variable names and what it all means. I haven't seen the PWMSlopeOvernight function, but I wrote this to drive my moon lights.

Code: Select all

      byte moonPhase = MoonPhase();
      byte moonPWM = 0;
      if(moonPhase > 0)
        moonPWM = PWMParabola(Moon.riseH, Moon.riseM, Moon.setH, Moon.setM, 10, ((moonPhase / 10) + 11), 0);
My question is around MoonPhase and if I am using it right. It appears the value is an index or in this case 0 - 100, so when it returns 1, I should have the lowest value (dimmest light). Knowing that my MeanWell drivers don't turn on until a value of 11 is sent to them. I adjusted the index according (hence the adding of 11).

Re: Moon rise/set implementation

Posted: Mon Apr 01, 2013 11:30 am
by lnevo
Yeah. I just don't know that the PWMParabola function will work properly when PM -> AM versus AM->PM. There was an issue with this in the PWMSlope and so a PWMSlopeOVernight was written. Moving forward there will be one PWMSlope function, but again, not sure on the parabola.

You have the moonphase and params correct it looks like.

Re: Moon rise/set implementation

Posted: Mon Apr 01, 2013 12:50 pm
by thekameleon
I think this should do it:

Code: Select all

byte PWMParabolaOvernight(byte startHour, byte startMinute, byte endHour, byte endMinute, byte startPWM, byte endPWM, byte oldValue)
{
        unsigned long Start = previousMidnight(now())+((unsigned long)NumMins(startHour, startMinute)*60);
        unsigned long End = nextMidnight(now())+((unsigned long)NumMins(endHour, endMinute)*60);
        boolean isOvernight=NumMins(startHour,startMinute)>NumMins(endHour,endMinute);
        
        int Now = NumMins(hour(), minute());
        if (hour()<startHour && isOvernight) Start-=86400;
        if (hour()<startHour || !isOvernight) End-=86400;
        
        byte PWMDelta = endPWM-startPWM;
        byte ParabolaPhase=constrain(map(Now,Start,End,0,180),0,180);

        if ( Now <= Start || Now >= End)
               return oldValue;
        else
        {
               return startPWM+(PWMDelta*sin(radians(ParabolaPhase)));
        }
}
I'll let you know in a few days.

Re: Moon rise/set implementation

Posted: Mon Apr 01, 2013 12:58 pm
by lnevo
Let me find you the thread that I posted the overnight/non-overnight code. You should test with that because moonrise could be within the same day or be an overnight event...

Re: Moon rise/set implementation

Posted: Mon Apr 01, 2013 1:01 pm
by lnevo
Original PWMSlopeOvernight
http://forum.reefangel.com/viewtopic.php?p=11781#p11781

My Modification to make it universal
http://forum.reefangel.com/viewtopic.php?p=22384#p22384


Lol nevermind... just read your code... looks like you got my changes :)

Roberto.. if this works, both fixes should go in together :)

Re: Moon rise/set implementation

Posted: Mon Apr 01, 2013 1:24 pm
by rimai
The slope one is already merged in the dev branch :)
I'll check out the parabola.

Re: Moon rise/set implementation

Posted: Wed Apr 03, 2013 10:57 am
by thekameleon
So the function did not work. So I tweaked it to this:

Code: Select all

byte PWMParabolaOvernight(byte startHour, byte startMinute, byte endHour, byte endMinute, byte startPWM, byte endPWM, byte oldValue)
{
        int start = NumMins(startHour, startMinute);
        int end = NumMins(endHour, endMinute);
        if (start < end)
        {
          //Example: 2300hrs to 0200hrs
          if (hour() < endHour) start -= 1440; //past midnight
          if (hour() > startHour) end += 1440; //before midnight
        }
        
        int current = NumMins(hour(), minute());
        
        byte pwmDelta = endPWM - startPWM;
        byte parabolaPhase = constrain(map(current, start, end, 0, 180), 0, 180);

        if ( current <= start || current >= end)
          return oldValue;
        else
        {
          return startPWM + (pwmDelta * sin(radians(parabolaPhase)));
        }
}
This is outputting during a normal non-over midnight. I wish there was a good way to Unit Test Arduino to validate over midnight.

Re: Moon rise/set implementation

Posted: Wed Apr 03, 2013 11:40 am
by rimai
You can, but you will need to modify the libraries.
Would you like to do that?

Re: Moon rise/set implementation

Posted: Wed Apr 03, 2013 11:44 am
by thekameleon
I was thinking of using Visual Studio for Unit Testing and even building sketches. Visual Micro for Visual Studio actually allows for step through debugging via the serial port. I am not sure how tweaking the libraries would help here, I just want to run the code out side of the controller

Re: Moon rise/set implementation

Posted: Wed Apr 03, 2013 11:47 am
by rimai
I used VS with RA just fine :)

Re: Moon rise/set implementation

Posted: Wed Apr 03, 2013 12:29 pm
by thekameleon
Wow... That was easy.

Re: Moon rise/set implementation

Posted: Mon Apr 15, 2013 12:07 am
by thekameleon
Here is the function PWMParabolaOvernight. I have been testing it for over a week and it seems to be behaving properly.

Code: Select all

byte PWMParabolaOvernight(byte startHour, byte startMinute, byte endHour, byte endMinute, byte startPWM, byte endPWM, byte oldValue)
{
  int start = NumMins(startHour, startMinute);
  int end = NumMins(endHour, endMinute);
  if (start > end) //Start is greater than End so its over midnight
  {
    //Example: 2300hrs to 0200hrs
    if (hour() < endHour) start -= 1440; //past midnight
    if (hour() > startHour) end += 1440; //before midnight
  }

  int current = NumMins(hour(), minute());

  byte pwmDelta = endPWM - startPWM;
  byte parabolaPhase = constrain(map(current, start, end, 0, 180), 0, 180);

  if ( current <= start || current >= end)
    return oldValue;
  else
  {
    return startPWM + (pwmDelta * sin(radians(parabolaPhase)));
  }
}

Moon rise/set implementation

Posted: Mon Apr 15, 2013 6:29 am
by lnevo
Awesome!

Re: Moon rise/set implementation

Posted: Mon Apr 15, 2013 8:32 am
by rimai
Thanks!!!
But it is not working :(
I tested PWMParabolaOvernight(23,0,8,0,10,90,5) and got this:

Code: Select all

23	0	5
23	1	5
23	2	5
23	3	5
23	4	5
23	5	5
23	6	5
23	7	5
23	8	5
23	9	5
23	10	5
23	11	5
23	12	5
23	13	5
23	14	5
23	15	5
23	16	5
23	17	5
23	18	5
23	19	5
23	20	5
23	21	5
23	22	5
23	23	5
23	24	5
23	25	5
23	26	5
23	27	5
23	28	5
23	29	5
23	30	5
23	31	5
23	32	5
23	33	5
23	34	5
23	35	5
23	36	5
23	37	5
23	38	5
23	39	5
23	40	5
23	41	5
23	42	5
23	43	5
23	44	5
23	45	5
23	46	5
23	47	5
23	48	5
23	49	5
23	50	5
23	51	5
23	52	5
23	53	5
23	54	5
23	55	5
23	56	5
23	57	5
23	58	5
23	59	5
0	0	37
0	1	37
0	2	37
0	3	38
0	4	38
0	5	38
0	6	39
0	7	39
0	8	39
0	9	41
0	10	41
0	11	41
0	12	42
0	13	42
0	14	42
0	15	43
0	16	43
0	17	43
0	18	45
0	19	45
0	20	45
0	21	46
0	22	46
0	23	46
0	24	47
0	25	47
0	26	47
0	27	48
0	28	48
0	29	48
0	30	50
0	31	50
0	32	50
0	33	51
0	34	51
0	35	51
0	36	52
0	37	52
0	38	52
0	39	53
0	40	53
0	41	53
0	42	54
0	43	54
0	44	54
0	45	55
0	46	55
0	47	55
0	48	57
0	49	57
0	50	57
0	51	58
0	52	58
0	53	58
0	54	59
0	55	59
0	56	59
0	57	60
0	58	60
0	59	60
then I went and tested PWMParabolaOvernight(22,0,8,0,10,90,5) and got this:

Code: Select all

22	0	5
22	1	5
22	2	5
22	3	5
22	4	5
22	5	5
22	6	5
22	7	5
22	8	5
22	9	5
22	10	5
22	11	5
22	12	5
22	13	5
22	14	5
22	15	5
22	16	5
22	17	5
22	18	5
22	19	5
22	20	5
22	21	5
22	22	5
22	23	5
22	24	5
22	25	5
22	26	5
22	27	5
22	28	5
22	29	5
22	30	5
22	31	5
22	32	5
22	33	5
22	34	5
22	35	5
22	36	5
22	37	5
22	38	5
22	39	5
22	40	5
22	41	5
22	42	5
22	43	5
22	44	5
22	45	5
22	46	5
22	47	5
22	48	5
22	49	5
22	50	5
22	51	5
22	52	5
22	53	5
22	54	5
22	55	5
22	56	5
22	57	5
22	58	5
22	59	5
23	0	34
23	1	34
23	2	34
23	3	34
23	4	36
23	5	36
23	6	36
23	7	37
23	8	37
23	9	37
23	10	38
23	11	38
23	12	38
23	13	38
23	14	39
23	15	39
23	16	39
23	17	41
23	18	41
23	19	41
23	20	42
23	21	42
23	22	42
23	23	42
23	24	43
23	25	43
23	26	43
23	27	45
23	28	45
23	29	45
23	30	46
23	31	46
23	32	46
23	33	46
23	34	47
23	35	47
23	36	47
23	37	48
23	38	48
23	39	48
23	40	50
23	41	50
23	42	50
23	43	50
23	44	51
23	45	51
23	46	51
23	47	52
23	48	52
23	49	52
23	50	53
23	51	53
23	52	53
23	53	53
23	54	54
23	55	54
23	56	54
23	57	55
23	58	55
23	59	55
0	0	57
0	1	57
0	2	57
0	3	57
0	4	58
0	5	58
0	6	58
0	7	59
0	8	59
0	9	59
0	10	60
0	11	60
0	12	60
0	13	60
0	14	61
0	15	61
0	16	61
0	17	62
0	18	62
0	19	62
0	20	63
0	21	63
0	22	63
0	23	63
0	24	64
0	25	64
0	26	64
0	27	65
0	28	65
0	29	65
0	30	66
0	31	66
0	32	66
0	33	66
0	34	67
0	35	67
0	36	67
0	37	68
0	38	68
0	39	68
0	40	69
0	41	69
0	42	69
0	43	69
0	44	70
0	45	70
0	46	70
0	47	71
0	48	71
0	49	71
0	50	72
0	51	72
0	52	72
0	53	72
0	54	73
0	55	73
0	56	73
0	57	73
0	58	73
0	59	73
Looks like it is missing the starting hour completely.
Here is the test code I used:

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>

int test=0;
void setup()
{
  ReefAngel.Init();  
}

void loop()
{
  wdt_reset();
  adjustTime(60);
  Serial.print(hour());
  Serial.print("\t");
  Serial.print(minute());
  Serial.print("\t");
  Serial.println(PWMParabolaOvernight(22,0,8,0,10,90,5));
  delay(10);
  if (test++>2500)
  while(1) wdt_reset();
  
}

byte PWMParabolaOvernight(byte startHour, byte startMinute, byte endHour,
byte endMinute, byte startPWM, byte endPWM, byte oldValue)
{
  int start = NumMins(startHour, startMinute);
  int end = NumMins(endHour, endMinute);
  if (start > end) //Start is greater than End so its over midnight
  {
    //Example: 2300hrs to 0200hrs
    if (hour() < endHour) start -= 1440; //past midnight
    if (hour() > startHour) end += 1440; //before midnight
  }

  int current = NumMins(hour(), minute());

  byte pwmDelta = endPWM - startPWM;
  byte parabolaPhase = constrain(map(current, start, end, 0, 180), 0, 180);

  if ( current <= start || current >= end)
    return oldValue;
  else
  {
    return startPWM + (pwmDelta * sin(radians(parabolaPhase)));
  }
}
The only thing is that you will need to change the libraries to perform this test.... :(
You need to change ReefAngel.cpp
From

Code: Select all

	setSyncInterval(SECS_PER_HOUR*6);  // Changed to sync every 6 hours.
To

Code: Select all

	setSyncInterval(SECS_PER_HOUR*6000);  // Changed to sync every 6 hours.
Or the clock will keep syncing with the RTC.

Re: Moon rise/set implementation

Posted: Mon Apr 15, 2013 4:42 pm
by thekameleon
I was just testing if you were actually paying attention.... :D

I think my problem is this line:

Code: Select all

if (hour() > startHour) end += 1440; //before midnight
Change it to this

Code: Select all

if (hour() >= startHour) end += 1440; //before midnight

Re: Moon rise/set implementation

Posted: Tue Apr 16, 2013 8:33 am
by rimai
Awesome!!!
I'll include in the next update :)