Dendroboard banner

Arduino Moon Program

12K views 20 replies 6 participants last post by  Daniel.mcnaughtan  
#1 ·
When I start looking for a relatively simple program to simulate the moon over my vivarium I noticed two things:

1) The moons cycle is not simple and

2) The aquarium/vivarium community has not yet paid enough attention to simulating the moon over their enclosures.

I have read discussions on how moon cycle and coral spawning events are linked but there is little discussion as to why they are linked. That complex problem cannot be solved here but I hope that the following program has enough complexity to inspire a better discussion on that topic and others. I am honestly not sure that the frogs will care, but who knows!

I have done a little homework, made a few observations and now written a program to light a single LED over the inhabitants of our glass cages. Having taken on this project, I am amazed when I look out of the window at the lunar patterns I see over my own backyard. In the past year I have had to set aside and come back to this problem a few different times. Now I think I am very, very close to having a program anyone can use!

For those of you who are curious please follow along. For those who are mildly math and/or Arduino savvy I think you may enjoy helping me solve this one. Please remember to keep things as SIMPLE as is reasonable. The following posts are hopefully going to build on each other logically and also a little in complexity so feel free to stop at whatever stage meets your needs.

If you are interested in accessing real time data from your computer, comparing actual moon position and eclipse times, utilizing “Ultra-High-Def-Full-Color-Display/ utilizing extensive and processing heavy LookUP Tables… this may not be the thread for you.

I have a standalone (under cabinet) Arduino build utilizing the humble 20x4 Green and Black Character LCD. Without the extra equipment cost I am limited to programming with simpler equations then the algorithm heavy packages you can buy off the shelf, but I think this will get the job done.

I am posting the entire code here for convenience but I will be referencing small parts of it as we go so that you can follow what I am doing each step of the way:
(I did “cut and paste” this from my larger lighting code so if I dropped anything let me know)
Code:
#include "Arduino.h"
#include <Wire.h>
#include "Chronodot.h"

Chronodot RTC;

#define pinMin 0                          // PWM min
#define pinMax 255                        // PWM max
#define minutesInDay 1440
#define cycleLengthBase 2551442.98          //29.53059 days
#define lengthVarMltplA 13.7                 // ~ 400 Days
#define lengthVarMltplB 8.2                 // ~ 3317 Days (9 Years)
#define lastWaxQtr 1432555000               //Adjusted to K-Zoo, MI
#define cycleLongStart 1427063716           //Adjusted to K-Zoo, MI

/*||||||||||||||||||||  General Light  ||||||||||||||||||||||||*/

unsigned long unixTimeNow;
int dayNow;
float yearPercent;
float yearPercentVal;

/*||||||||||||||||||||  Moon Light  ||||||||||||||||||||||||||||*/

float cycleLength;
float moonPercent;
float moonTimePercent;
int moonOnTime;
float moonDegreePercent;
float wholeNumberR ;
float wholeNumberZ;
float fractionalPartR;
float fractionalPartZ;
int moonPhase;   
float moonIntPercentVal;
unsigned long cycleLengthLong = (lengthVarMltplA * lengthVarMltplB * cycleLengthBase);        // ~ 3317 Days (9 Years)
unsigned long moonLength = (( 12.13 ) * 3600);           // This is Moon PhotoPeriod Base
int logDayOn;
int dayCountOn;
unsigned long moonStartTime;
int moonON;
double moonPercentPow;  
int moon = 8;         // Light Connected to digital pin (pwm)


/*||||||||||||||||||||  VOID SET-UP  ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/

void setup() {

    Serial.begin(9600);
    Wire.begin();
    RTC.begin();

{
analogWrite(moon, pinMin);
dayCountOn = 0;
logDayOn = 0;
moonON = 0;
}
    
}

/*||||||||||||||||||||  VOID LOOP  |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/

void loop() {

DateTime now = RTC.now();

float yearSolsticeNow = (((now.month() - 1) * 30.39) + now.day() - 10);
if (yearSolsticeNow <= 0) yearPercentVal = (365.29 - yearSolsticeNow);
else yearPercentVal = (yearSolsticeNow);
yearPercent = (yearPercentVal / 365.29);

float dayByMinute = ((now.hour() * 60.0) + now.minute());       //converts time of day to a single value in minutes

/*||||||||||||||||||||  Moon Operation  |||||||||||||||||||||||||||||||||||*/

 {

unixTimeNow = now.unixtime();

unsigned long cycleDif = (unixTimeNow - cycleLongStart);
wholeNumberR  = (float) cycleDif / cycleLengthLong;
int integerPartR = wholeNumberR;
fractionalPartR = wholeNumberR - integerPartR;      // % of 9 year cycle
float cycleLengthVar = ((0.00282 + ((0.01376 + 0.01199 * sin(fractionalPartR *2 * PI  - PI/2)) * sin(8.2 * fractionalPartR *2 * PI)))/0.92514);
cycleLength = (cycleLengthBase + cycleLengthVar);

unsigned long moonDif = (unixTimeNow - lastWaxQtr);
wholeNumberZ  = (float) moonDif / cycleLength;
int integerPartZ = wholeNumberZ;
fractionalPartZ = wholeNumberZ - integerPartZ;                 // This should be used to determine Waxing vs. Waning and time of day rise/set
    
    {
/*lcd.setCursor(6, 2);
    if ((fractionalPartZ >= (0.78)) || (fractionalPartZ <= (0.22)))
    lcd.print("Waxing");
    else if ((fractionalPartZ > (0.22)) && (fractionalPartZ < (.28)))
    lcd.print("Full");
    else if ((fractionalPartZ >= (0.28)) && (fractionalPartZ <= (.72)))
    lcd.print("Waning");
    else  lcd.print("New");
    }*/

moonPercent = ((1+ sin(fractionalPartZ * 2.0 * PI)) / 2); // This is the Moon Phase Intencity ONLY (without accounting position in sky)
int moonLight = (100 * moonPercent);

float moonTimeVal = (fractionalPartZ + 0.50);

if (moonTimeVal >= 1)                          
    moonTimePercent = (moonTimeVal - 1);
else
    moonTimePercent = (moonTimeVal);

float moonDegreeVal = ((moonPercent * 360) + (yearPercent *360));

if (moonDegreeVal >= 360)
    moonDegreePercent = ((moonDegreeVal - 360) / 360);
else
    moonDegreePercent = ((moonDegreeVal) / 360);

float moonRiseVar = (9 * ((2*cos(moonDegreePercent * 2 * PI)) + (sin(2*moonDegreePercent * 2 * PI))));   // “9” here is for latitude 10°. N (For Northern Hemisphere use N row for rise/S for set on Table), Use “30” for Latitude 42°.
float moonSetVar = (9 * ((2*cos((moonDegreePercent * 2 * PI) + PI)) + (sin(2*moonDegreePercent * 2 * PI))));


/*||||||||||||||||||||  MOON LED  |||||||||||||||||||||||||||||||||*/

dayNow = now.day();

int moonOnVal = ((moonTimePercent * minutesInDay) - 8 + moonRiseVar);    // If moonRiseVar positive, then shorter photoperiod , “8” (see moonLength… accounting for light refraction over the horizon) 
if (moonOnVal < 0) moonOnTime = (minutesInDay + moonOnVal); //if negative ‘int’ than add
else moonOnTime = moonOnVal;
if ((moonOnVal > minutesInDay) && (dayByMinute >= (minutesInDay - 1)) && (dayCountOn != 1))               // If the Moon Rise time occurs the following day...
        {
        logDayOn = dayNow;
        dayCountOn = 1;     //Prevents this being called more than once until reset
        }
if ((dayCountOn == 1) && ((dayNow > logDayOn) || ((dayNow == 1) && (dayNow != logDayOn))))
        moonOnTime = (moonOnVal - minutesInDay);

if ((dayByMinute = moonOnTime) && (moonON != 1))
        {
        moonStartTime = unixTimeNow;
        moonON = 1;
        }
unsigned long moonPhotoPeriod = (moonStartTime + moonLength + (moonSetVar * 60));
      
if ((unixTimeNow >= moonStartTime) && (unixTimeNow <= moonPhotoPeriod))
        {
        moonIntPercentVal = (sin((moonPhotoPeriod - unixTimeNow) / moonPhotoPeriod * PI));
        double moonPercentPowA = pow (moonPercent , 3);
        double moonPercentPowB = pow (moonPercent , 16);
        moonPercentPow = ((moonPercentPowA + moonPercentPowB) / 2);
        float moonIntPercent = (moonIntPercentVal * moonPercentPow);
        int moonIntencity = (pinMax * moonIntPercent);
//    if (moonIntencity < 2.55) analogWrite(moon, 0);          //MOSFET has no lower limit, 1% lower limit applies to LDD.
        
analogWrite(moon, moonIntencity);
        }

if ((unixTimeNow  >= moonPhotoPeriod) && (moonON != 0))
        {
        dayCountOn = 0;
        moonON = 0;
        }
// int moonLight = (180 * moonIntPercentVal); //For LCD
   }
}
 delay (1000);
}
 
#2 ·
So let’s get started!

The Moon goes around the Earth and has a cycle just under 30 days. It starts at a 1st Quarter Moon and then cycles up or Waxes to FULL (LED fully on) and then cycles or Wanes to NEW (LED off) and returns to 1st Qtr. This occurs in a sin wave pattern. I simulate this by programming my Arduino to vary the intensity of one LED from 0 through 255 and back to 0 with a PWM (pulse width modulation) pin. This is not an Arduino/ DIY LED tutorial as there are plenty of other threads that cover that topic, but if this is your first introduction to that topic I hope this thread helps inspire you to take the leap!

Start with the moon cycle time: 29.5 days

Convert Days to Seconds so we can use Unix Time: 2551442 (Note: any units that make the programming simple could be used here and another option such as “now.secondstime()” or use of Julian Date could improve the program). I used an RTC (real time clock) to keep time and provide the unix time input.

Next determine the beginning of the cycle (for me this was time of the 1st Qtr. Moon (waxing) May 25, 2015 [Mon. 01:20 PM in Kalamazoo, MI], or 1432555000.

Now subtract the starting time from the current time, divide by our 29 day constant to determine the # of cycles from the start. Finally, drop the whole # and keeping the fraction part only.

Example: 1500000000 – 1432555000 = 67445000

67445000 / 2551442 = 26.43 (or 26.43 cycles [months] from the start of our program)

(keep the 0.43 only)

This returns a result of 43% though the current cycle or waning moon (past Full, almost 3rd Qtr.). Throughout my program I call the use of this important fraction “Z” in various ways to keep track of it.

Applying this fraction to a sin wave (0 – 2π) will give an intensity of a moon with that brightness.

((1+ sin(0.43 * 2.0 * PI)) / 2)

I add 1 and divide by 2 so that I always have a POSITIVE response between 0 and 1.

This result multiplied by 255 (or whatever you decide to make your max LED brightness).

Step One complete! We now know how bright to make our LED.

Code:
#define cycleLength 2551442.98          //29.53059 days
#define lastWaxQtr 1432555000               //Adjusted to K-Zoo, MI

unixTimeNow = now.unixtime();

unsigned long moonDif = (unixTimeNow - lastWaxQtr);
z = (float) moonDif / cycleLength;
float wholeNumberZ = z;		// http://forum.arduino.cc/index.php?topic=48337.0 for discussion and crediting code
int integerPartZ = wholeNumberZ;
fractionalPartZ = wholeNumberZ - integerPartZ;                 // This should be used to determine Waxing vs. Waning and time of day rise/set

moonPercent = ((1+ sin(fractionalPartZ * 2.0 * PI)) / 2); // This is the Moon Phase Intencity ONLY (without accounting position in sky)
 
#3 ·
The next thing to observe is that the moon rises and sets (an observation many available aquarium programs don’t even address!). If you haven’t figured it out yet, this will make you smile at how obvious it is… The Moon is out during the day AND night. So when does it rise? Well if you think about it, the moon appears Full when the Earth is between the Moon and Sun (and appears New when the Moon is between the Earth and Sun). It phases in between on its transit around the Earth.

predicting moonrise and moonset - Moonstick Information Site


Image


Code:
float moonTimeVal = (fractionalPartZ + 0.50);  //Note: Full moon is “0.25” and rises at 6:00pm (75% through the day)

if (moonTimeVal >= 1)                          
    moonTimePercent = (moonTimeVal - 1);
else
    moonTimePercent = (moonTimeVal);
If this is where you quit your simulated Moon will be within an hour (depending on where on Earth that you are simulating) of actual rise and set times. Not bad! But let’s take it one EASY step further.

Image


Image


The Earth’s axis is tilted so we enjoy the seasons (especially in Michigan). It also changes how we observe the moon rise and set in a very predictable order. Just like there are times of the year that the Sun never sets in the summer in Alaska, the observation of the moon is the same. The first table asks you pick a degree 0-360 based on phase of Moon and time of the year.

The second table then uses that number to adjust moonrise and then moonset times.

Example: If we are in the northern hemisphere (i.e. Panama) than: MoonRise (10°N) / Moonset (10°S) and if the year and phase returned 225° then moon rise is 8:58AM and moon set is 9:22PM.

Programming the first table is easy and looks like the following:

Code:
float moonDegreeVal = ((moonPercent * 360) + (yearPercent *360));    // Year starts Dec. 21 (winter solstice) in this case.

if (moonDegreeVal >= 360)
    moonDegreePercent = ((moonDegreeVal - 360) / 360);
else
    moonDegreePercent = ((moonDegreeVal) / 360);
Now if you graph the results of a North and South row in the second table it will look like this:

Image

Red is N, Blue is S.

Code:
float moonRiseVar = (9 * ((2*cos(moonDegreePercent * 2 * PI)) + (sin(2*moonDegreePercent * 2 * PI))));  			 // “9” here is for latitude 10°. N (For Northern Hemisphere use N row for rise/S for set on Table), Use “30” for Latitude 42°.
float moonSetVar = (9 * ((2*cos((moonDegreePercent * 2 * PI) + PI)) + (sin(2*moonDegreePercent * 2 * PI))));
Now we are within 30 minutes of actual Moon Rise/Set times!
 
#4 ·
This step is a little in the weeds but is interesting and will get us much closer to actual moon variations because as you can see, over the course of 14 months the 29 day cycle shifts as much as 28 hours!

Moon and the Molad of the Hebrew Calendar

Image


Image


I developed an Excel spreadsheet and tracked only 1st Qtr Moon for 5 years starting in 2015 and found this pattern! Historical moon times vs. theoretical time varied quite a bit but it follows it reasonably.

Code:
#define cycleLengthBase 2551442.98          //29.53059 days
#define lengthVarMltplA 13.7                 // ~ 400 Days
#define lengthVarMltplB 8.2                 // ~ 3317 Days (9 Years)
#define lastWaxQtr 1432555000               //Adjusted to K-Zoo, MI
#define cycleLongStart 1427063716           //Adjusted to K-Zoo, MI

unsigned long cycleLengthLong = (lengthVarMltplA * lengthVarMltplB * cycleLengthBase);        // ~ 3317 Days (9 Years)

unsigned long cycleDif = (unixTimeNow - cycleLongStart);
wholeNumberR  = (float) cycleDif / cycleLengthLong;
int integerPartR = wholeNumberR;
fractionalPartR = wholeNumberR - integerPartR;      // % of 9 year cycle
float cycleLengthVar = ((0.00282 + ((0.01376 + 0.01199 * sin(fractionalPartR *2 * PI  - PI/2)) * sin(8.2 * fractionalPartR *2 * PI)))/0.92514);
cycleLength = (cycleLengthBase + cycleLengthVar);
This took me FOREVER and I am still not sure it is right. But there it is…
 
#5 ·
Describing light intensity is last concept I am going to discuss before we light the LED. As you can see by the following chart Light increases both due to phase of the moon and position in the sky:

The Brightness of Moonlight

Image


As you can see a Full Moon just above the horizon is twice as bright as a Quarter Moon at the high point in the sky. And a Full moon at its zenith is 6 times brighter still!

Code:
double moonPercentPowA = pow (moonPercent , 3);
double moonPercentPowB = pow (moonPercent , 16);
moonPercentPow = ((moonPercentPowA + moonPercentPowB) / 2);

float moonIntPercent = (moonIntPercentVal * moonPercentPow);
int moonIntencity = (pinMax * moonIntPercent);
I think this line of code should approximately match the above curve account for the change in intensity.
 
#6 ·
Finally let’s tell the LED to light!

The most difficult part about this section is the programming. So far we are using the 24 hour clock for our inputs. Unfortunately, by simplifying these commands, we are bound by midnight (where 1440 minutes switches to 0 minutes). There are times though that the variables return a number that is yesterday or tomorrow. When Moon rise/set is confined to one 24 hour period the programming is easy. But as soon as the variable becomes negative (or greater than 1440 minutes) the “daybyMinutes” call no longer really works. We still need to rely on it for our Base input though.
This made my head hurt a little.

So I figured out that by using a series of “switches”, and converting from 24 hour time to Unix and back again, that I could eliminate most logic errors (I think… maybe… or…). Anyways, here it is:

Code:
dayNow = now.day();

int moonOnVal = ((moonTimePercent * minutesInDay) - 8 + moonRiseVar);    // If moonRiseVar positive, then shorter photoperiod , “8” (see moonLength… accounting for light refraction over the horizon) 
if (moonOnVal < 0) moonOnTime = (minutesInDay + moonOnVal);	//if negative ‘int’ than add
else moonOnTime = moonOnVal;
if ((moonOnVal > minutesInDay) && (dayByMinute >= (minutesInDay - 1)) && (dayCountOn != 1))               // If the Moon Rise time occurs the following day...
        {
        logDayOn = dayNow;
        dayCountOn = 1;			//Prevents this being called more than once until reset
        }
if ((dayCount On == 1) && ((dayNow > logDayOn) || ((dayNow == 1) && (dayNow != logDayOn))))
        moonOnTime = (moonOnVal - minutesInDay);

if (dayByMinute = moonOnTime) && (moonON != 1)
        {
        moonStartTime = unixTimeNow;
        moonON = 1;
        }
unsigned long moonPhotoPeriod = (moonStartTime + moonLength + (moonSetVar * 60));
      
if ((unixTimeNow >= moonStartTime) && (unixTimeNow <= moonPhotoPeriod))
        {
        moonIntPercentVal = (sin((moonPhotoPeriod - unixTimeNow) / moonPhotoPeriod * PI));
        float moonIntPercent = (moonIntPercentVal * moonPercentPow);
        int moonIntencity = (pinMax * moonIntPercent);
//    if (moonIntencity < 2.55) analogWrite(moon, 0);          //MOSFET has no lower limit, 1% lower limit applies to Meanwell LDD, Driver could be limited to 10%.
        
analogWrite(moon, moonIntencity);
        }

if ((unixTimeNow  >= moonPhotoPeriod) && (moonON != 0))
        {
        dayCountOn = 0;
        moonON = 0;
        }
 
#7 ·
That’s it! Feel free to recommend changes.

In full disclosure, I have yet to light a single LED using this program. Also, I have not taken a month to just to sit and watch a “serial.print” output to see if the program even works (honestly, I don’t know if I would know what I was looking at if I did). I suppose I could write a TEST program to run a “fast” cycle, but I ‘m not sure how to begin to test it (i.e. if ON and OFF times are even close to accurate).

Which is why if any of you “Arduino-Heads” or “Math-Bunnies” out there look at this stuff and get an insight I’d love to hear your advice.

Please Help!
 
#8 ·
This is really cool. I think it would simulate a real jungle a lot more because, well, as far as I know, jungles don't just go completely black like our vivariums. I might try this with my arduino, or maybe with another microprocessor.(raspberry pi, or wireless like a photon)
 
#9 · (Edited)
All you need is timelord arduino library, I am using it to calculate moon phases, sunrise, sunset and seasons in any location on earth by passing Lat. and long. You can also use firmware for storm x light controller available for download on coralux website, and build your own controller with arduino uno with Rtc, 16x2 lcd, pwm driver, and rotary encoder total cost ~$50 or less. Storm x has all the options for fancy vivarium lights, sunrise, sunset, moon, cloud simulation and lightning.
Those are my thoughts.
Peter
Sorry for grammar and spelling errors, English is not my first language :)
 
#10 ·
I have looked at Timelord before. I'm a total Code Nub... Maybe you can point out the lines in their code that address the same aspects of Moon light that I have outlined above. It seems to me that it has addressed phasing ONLY and quit there, which is a shortcoming that drove me down this rabbit whole in the first place! I see Sunrise/set but not Moonrise and Moonset. Their Lat and Longitude is nice... sure beats guess and check on a scientific calculator.:) But no tie to moon for seasonal change. And intensity?

Timelord is a great start, maybe you could share some ways to tie its inputs into some of these other aspects. Suggestions?
 
#13 ·
Thank you for the link.
I have to look at it again but I don't think I will not be using Timelord for moon phase. It looks like I may be able to use "moon.h" though.

I don't think it matters which Time file you use if you #include "moon.h".

Note: Page 5 of the above link has the most updated version of Moon.Zip.

This program returns moon.phase/.rise/.set.() based on lat/long that you input which is nice.

I would still include (at least) the "Intensity" line from my code above, even if you are including one of the other libraries. One thing I would also recommend to anyone starting a new build is to dedicate a single LED (or channel to moon light if your enclosure is wide) that way you are not trying to tell a Daylight channel to also be a Moonlight channel. The light output of my moon LED is so low I am able to drive it off a MOSFET circuit. This is far more dim than a LDD @ 1% minimum will output.
 
#15 ·
#16 ·
Good links Jimmy. As tempting as it is to use "Silvery" light... Keep any LED you choose to mid-day color ~5700K. I also found it helpful to limit the LED to about a single watt (for me) so that the light output is MAX of 0.01% of the output of the rest of my array.

I am using this pwm driver witch give me 12 bit resolution 0-4095 comparing to arduino 0-255 is a big improvement and have 16 channels over I2C. It works great with mean well
LDD drivers
I was looking at that board. Is the 0-4095 resolution really necessary? Whats the benefit of the board (I haven't run out of PWM pins just yet :) ...i think I have one left on my Mega). What else is improved?

Also, If you guys can help me out I'm trying to integrate moon.h into my current build... I've been at it 7 days now and can't make heads or tails of it... I like their algorithm adaptation for the detail but?!?!?! I've downloaded their entire ZIP file and copied out single lines from file after file but they are so spread out and interconnected that I keep missing critical lines (and every line seems to need another arduino library). The more I look the more I may just stick with my original code (as manually reliant as it is;)).

Still, I'll try to write up a good question here but it will take a little work just to pose the question...
 
#17 ·
This is how I chose to integrate the RA program but I have some questions:

Code:
#include "Arduino.h"
#include <TimeLib.h>                    // https://github.com/PaulStoffregen/Time 
#include <Wire.h>
#include <DS1307RTC.h>
#include "Moon.h"
#include <LiquidCrystal.h>
#include "General.h"                    //See Post below for explination

LiquidCrystal lcd(22, 24, 26, 28, 30, 32);

#define pinMin 0                            // PWM min
#define pinMax 255                          // PWM max

/*||||||||||||||||||||  General Light  ||||||||||||||||||||||||*/

unsigned long unixTimeNow;

/*||||||||||||||||||||  Moon Light  ||||||||||||||||||||||||||||*/

float moonPhase;
float aa;

const int moonLED = 8;         // Light Connected to digital pin (pwm)


/*||||||||||||||||||||  VOID SET-UP  ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/

void setup() {

    Serial.begin(9600);
    Wire.begin();
    setSyncProvider(RTC.get);
    lcd.begin(20, 4);

analogWrite(moonLED, pinMin);   
}

/*||||||||||||||||||||  VOID LOOP  |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/

void loop() {

/*||||||||||||||||||||  Moon Operation  |||||||||||||||||||||||||||||||||||*/

unixTimeNow = now();
  {
moon_init(10,-86); // pass it lat / lon - it uses ints for the caclulation in moon.h

/*||||||||||||||||||||  MOON LED  |||||||||||||||||||||||||||||||||*/

unsigned long moonPhotoPeriod = (set_time - rise_time);

if (Moon.isRise) {
    moonPhase = (MoonPhase());
    } 
  else {
    moonPhase = (0);
    }
        aa = (sin((moonPhotoPeriod - unixTimeNow) / moonPhotoPeriod * PI));
        double bb= pow (moonPhase , 3);
        double cc = pow (moonPhase , 16);
        bb = ((bb + cc) / 2);
        float dd = (aa * bb);
        
        int moonIntencity = (pinMax * dd);
        
analogWrite(moonLED, moonIntencity);
  }
 delay (1000);
}
General.h (copied from RA Global):
Code:
/*
 * Copyright 2010 Reef Angel / Roberto Imai */

 /*
  * Updated by:  Curt Binder
  * Updates Released under Apache License, Version 2.0
  */

#ifndef __GENERAL_H__
#define __GENERAL_H__
#include "Arduino.h"
#include <TimeLib.h>
#include <avr/pgmspace.h>
int MoonPhase();

#ifdef MOONPHASELABEL
char* MoonPhaseLabel();
#endif // MOONPHASELABEL

#endif
General.cpp (copied from RA Global):
Code:
/*
 * Copyright 2010 Reef Angel / Roberto Imai */

 /*
  * Updated by:  Curt Binder
  * Updates Released under Apache License, Version 2.0
  */

#include "General.h"
#include "math.h"

int MoonPhase()
{
	int m,d,y;
	int yy,mm;
	long K1,K2,K3,J,V;
	m = month();
	d = day();
	y = year();
	yy = y-((12-m)/10);
	mm = m+9;
	if (mm>=12) mm -= 12;
	K1 = 365.25*(yy+4712);
	K2 = 30.6*mm+.5;
	K3 = int(int((yy/100)+49)*.75)-38;
	J = K1+K2+d+59-K3;
	V = (J-2451550.1)/0.29530588853;
	V -= int(V/100)*100;
	V = abs(V-50);
	return (byte)(2*abs(50-V));
}

#ifdef MOONPHASELABEL
char* MoonPhaseLabel()
{
  int m,d,y;
  int yy,mm;
  long K1,K2,K3,J;
  double V;
  byte PWMvalue;
  m = month();
  d = day();
  y = year();
  yy = y-((12-m)/10);
  mm = m+9;
  if (mm>=12) mm -= 12;
  K1 = 365.25*(yy+4712);
  K2 = 30.6*mm+.5;
  K3 = int(int((yy/100)+49)*.75)-38;
  J = K1+K2+d+59-K3;
  V = (J-2451550.1)/29.530588853;
  V -= floor(V);
  if (V<0) V++;
  if (V<0.0625) return "New Moon";
  else if (V<0.1875) return "Waxing Crescent";
  else if (V<0.3125) return "First Quarter";
  else if (V<0.4375) return "Waxing Gibbous";
  else if (V<0.5625) return "Full Moon";
  else if (V<0.6875) return "Waning Gibbous";
  else if (V<0.8125) return "Last Quarter";
  else if (V<0.9375) return "Waning Crescent";
  else return "New Moon";
}
#endif // MOONPHASELABEL
What is the best way to define:
Code:
unsigned long moonPhotoPeriod = (set_time - rise_time);
I want the "time_t" values from moon.h so that I can apply a sin() output like in "aa" above, but I get an error when I write it like this. Should I be defining "photoPeriod" differently?
The RA thread states:
Code:
ReefAngel.PWM.SetDaylight(PWMSlope(Moon.riseH,Moon.riseM,Moon.setH,Moon.setM, 0,MoonPhase(),30,0));
But I do not know what this means or how to use it. Is "Slope"( , , ) some kind of function I can define/use in my code without more RA libraries?
 
#18 ·
Hi Everyone

Just came across this thread and am hoping someone out there is still following it!

I work at a university and we have a new project starting up looking at the effects of moonlight on new hatched baby fish and we need to re-create up some moonlight simulations in the lab. After reading this thread, seems this is exactly what we are trying to do.

I have almost zero experience when it comes to programing / using Arduino but just wondering if someone out there would be happy to chat more and answer some questions I have? Mainly around hardware.

Cheers
 
#19 ·
I don't have any programming experience, but I can point out that much of what was done the old hard manual way five years ago is now baked in to off the shelf hardware.

AI LEDs now have a lunar sim feature that tracks the current actual lunar phase (not sure if it can be set out of sync with actual phases):


Neptune's Apex controllers have had this capability for over a decade, but they're a bit more pricey. They could run your whole lab, though:


There might be other even cheaper units that do this, but these are the ones I know of off hand.

If these suggestions are relevant to you, great. If not, sorry for the interruption. :)
 
#20 ·
I don't have any programming experience, but I can point out that much of what was done the old hard manual way five years ago is now baked in to off the shelf hardware.

AI LEDs now have a lunar sim feature that tracks the current actual lunar phase (not sure if it can be set out of sync with actual phases):


Neptune's Apex controllers have had this capability for over a decade, but they're a bit more pricey. They could run your whole lab, though:


There might be other even cheaper units that do this, but these are the ones I know of off hand.

If these suggestions are relevant to you, great. If not, sorry for the interruption. :)
 
#21 ·
Thanks for the reply. We have looked into them...problem is they are quite expensive for how many tanks we need to light up. The Neptune system only allows a max of 5 LED's per controller and we have approx. 20 tanks to illuminate so things are going to get pretty expensive quickly!

We aren't against buying an off the shelf system but also love a bit of DIY if its possible.

Cheers