Skip to content

Instantly share code, notes, and snippets.

@buzztiaan
Created November 22, 2020 14:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save buzztiaan/b3cfd004218da75489142bd858823af3 to your computer and use it in GitHub Desktop.
Save buzztiaan/b3cfd004218da75489142bd858823af3 to your computer and use it in GitHub Desktop.
ESP8266 with relay, following sunset-sunrise times of a hardcoded month
#include <math.h>
#define PI 3.1415926
#define ZENITH -.83
#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <TimeLib.h>
const char *ssid = "xxx";
const char *password = "xxx";
int foreverthismonth = 6; // the sunrise-sunset will ALWAYS follow this month
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
float calculateSunrise(int year,int month,int day,float lat, float lng,int localOffset, int daylightSavings) {
/*
localOffset will be <0 for western hemisphere and >0 for eastern hemisphere
daylightSavings should be 1 if it is in effect during the summer otherwise it should be 0
*/
//1. first calculate the day of the year
float N1 = floor(275 * month / 9);
float N2 = floor((month + 9) / 12);
float N3 = (1 + floor((year - 4 * floor(year / 4) + 2) / 3));
float N = N1 - (N2 * N3) + day - 30;
//2. convert the longitude to hour value and calculate an approximate time
float lngHour = lng / 15.0;
float t = N + ((6 - lngHour) / 24); //if rising time is desired:
//float t = N + ((18 - lngHour) / 24) //if setting time is desired:
//3. calculate the Sun's mean anomaly
float M = (0.9856 * t) - 3.289;
//4. calculate the Sun's true longitude
float L = fmod(M + (1.916 * sin((PI/180)*M)) + (0.020 * sin(2 *(PI/180) * M)) + 282.634,360.0);
//5a. calculate the Sun's right ascension
float RA = fmod(180/PI*atan(0.91764 * tan((PI/180)*L)),360.0);
//5b. right ascension value needs to be in the same quadrant as L
float Lquadrant = floor( L/90) * 90;
float RAquadrant = floor(RA/90) * 90;
RA = RA + (Lquadrant - RAquadrant);
//5c. right ascension value needs to be converted into hours
RA = RA / 15;
//6. calculate the Sun's declination
float sinDec = 0.39782 * sin((PI/180)*L);
float cosDec = cos(asin(sinDec));
//7a. calculate the Sun's local hour angle
float cosH = (sin((PI/180)*ZENITH) - (sinDec * sin((PI/180)*lat))) / (cosDec * cos((PI/180)*lat));
/*
if (cosH > 1)
the sun never rises on this location (on the specified date)
if (cosH < -1)
the sun never sets on this location (on the specified date)
*/
//7b. finish calculating H and convert into hours
float H = 360 - (180/PI)*acos(cosH); // if if rising time is desired:
//float H = acos(cosH) // if setting time is desired:
H = H / 15;
//8. calculate local mean time of rising/setting
float T = H + RA - (0.06571 * t) - 6.622;
//9. adjust back to UTC
float UT = fmod(T - lngHour,24.0);
//10. convert UT value to local time zone of latitude/longitude
return UT + localOffset + daylightSavings;
}
float calculateSunset(int year,int month,int day,float lat, float lng,int localOffset, int daylightSavings) {
/*
localOffset will be <0 for western hemisphere and >0 for eastern hemisphere
daylightSavings should be 1 if it is in effect during the summer otherwise it should be 0
*/
//1. first calculate the day of the year
float N1 = floor(275 * month / 9);
float N2 = floor((month + 9) / 12);
float N3 = (1 + floor((year - 4 * floor(year / 4) + 2) / 3));
float N = N1 - (N2 * N3) + day - 30;
//2. convert the longitude to hour value and calculate an approximate time
float lngHour = lng / 15.0;
float t = N + ((6 - lngHour) / 24); //if rising time is desired:
//float t = N + ((18 - lngHour) / 24) //if setting time is desired:
//3. calculate the Sun's mean anomaly
float M = (0.9856 * t) - 3.289;
//4. calculate the Sun's true longitude
float L = fmod(M + (1.916 * sin((PI/180)*M)) + (0.020 * sin(2 *(PI/180) * M)) + 282.634,360.0);
//5a. calculate the Sun's right ascension
float RA = fmod(180/PI*atan(0.91764 * tan((PI/180)*L)),360.0);
//5b. right ascension value needs to be in the same quadrant as L
float Lquadrant = floor( L/90) * 90;
float RAquadrant = floor(RA/90) * 90;
RA = RA + (Lquadrant - RAquadrant);
//5c. right ascension value needs to be converted into hours
RA = RA / 15;
//6. calculate the Sun's declination
float sinDec = 0.39782 * sin((PI/180)*L);
float cosDec = cos(asin(sinDec));
//7a. calculate the Sun's local hour angle
float cosH = (sin((PI/180)*ZENITH) - (sinDec * sin((PI/180)*lat))) / (cosDec * cos((PI/180)*lat));
/*
if (cosH > 1)
the sun never rises on this location (on the specified date)
if (cosH < -1)
the sun never sets on this location (on the specified date)
*/
//7b. finish calculating H and convert into hours
//float H = 360 - (180/PI)*acos(cosH); // if if rising time is desired:
float H = (180/PI)*acos(cosH); // if setting time is desired:
H = H / 15;
//8. calculate local mean time of rising/setting
float T = H + RA - (0.06571 * t) - 6.622;
//9. adjust back to UTC
float UT = fmod(T - lngHour,24.0);
//10. convert UT value to local time zone of latitude/longitude
return UT + localOffset + daylightSavings;
}
int getSunrise() {
unsigned long t = timeClient.getEpochTime();
float localT = calculateSunrise(year(t),foreverthismonth,day(t),51.97,5.66,0,1);
double hours;
float minutes = modf(localT,&hours)*60;
return (((int)floor(hours)*60)+(int)floor(minutes));
}
int getSunset() {
unsigned long t = timeClient.getEpochTime();
float localT=fmod(24 + calculateSunset(year(t),foreverthismonth,day(t),51.97,5.66,0,1),24.0);
double hours;
float minutes = modf(localT,&hours)*60;
return (((int)floor(hours)*60)+(int)floor(minutes));
}
int sunsettoday;
int sunrisetoday;
void updatesuntimes() {
sunrisetoday = getSunrise();
sunsettoday = getSunset();
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while ( WiFi.status() != WL_CONNECTED ) {
delay ( 500 );
Serial.print ( "." );
}
timeClient.begin();
timeClient.setTimeOffset(3600);
pinMode(D1, OUTPUT);
digitalWrite(D1, HIGH);
updatesuntimes();
}
void loop() {
timeClient.update();
unsigned long t = timeClient.getEpochTime();
int dayminutes = (hour(t)*60)+minute(t);
if (dayminutes == 5) {
updatesuntimes();
}
Serial.print(dayminutes);
Serial.print(" ");
Serial.print(sunrisetoday);
Serial.print(" ");
Serial.print(sunsettoday);
Serial.println();
if ((dayminutes>sunrisetoday) && (dayminutes<sunsettoday)) {
// turn on relay
digitalWrite(D1, LOW);
} else {
// turn off relay
digitalWrite(D1, HIGH);
}
delay(1000);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment