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