Esp8266 Sonnenlauf als Arduino Tab.
Sonnenlauf.ino
// ****************************************************************
// Sketch Esp8266 Sonnen Auf/Untergang Modular(Tab)
// created: Jens Fleischer, 2019-01-05
// last mod: Jens Fleischer, 2021-04-24
// For more information visit: https://fipsok.de
// ****************************************************************
// Hardware: Esp8266
// Software: Esp8266 Arduino Core 2.4.2 / 2.5.2 / 2.6.3 / 2.7.4
// Getestet auf: Nodemcu, Wemos D1 Mini Pro
/******************************************************************
Copyright (c) 2018 Jens Fleischer. All rights reserved.
This file is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
*******************************************************************/
// Diese Version von Sonnenlauf sollte als Tab eingebunden werden.
// Der Lokalzeit Tab (bzw. "struct tm") ist zum ausführen erforderlich.
// Gib beim Aufrufen der Funktion "twilight(Länge, Breite)"
// den Längen- und Breitengrad deines Ortes an.
// "twilight(12.348283, 51.345751);" https://www.laengengrad-breitengrad.de/
/**************************************************************************************/
struct SunTime {
char sunrise[6];
char sunset[6];
};
void twilight(const double longitude, const double latitude) {
SunTime sun;
localTime(); // Sollte die Lokalzeit schon im loop eingebunden sein, auskommentieren!
static byte lastday, lastdst;
if (tm.tm_mday != lastday || tm.tm_isdst != lastdst) { // Sonnenlauf für Tage mit Zeitumstellung zweimal Täglich berechnen.
lastday = tm.tm_mday;
lastdst = tm.tm_isdst;
const double h = -0.833333333333333 * DEG_TO_RAD;
const double w = latitude * DEG_TO_RAD;
double JD = julianDate(1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday);
double T = (JD - 2451545.0) / 36525.0;
double DK;
double EOT = calculateEOT(DK, T);
double differenceTime = 12.0 * acos((sin(h) - sin(w) * sin(DK)) / (cos(w) * cos(DK))) / PI;
strcpy(sun.sunrise, outputFormat((12.0 - differenceTime - EOT) - longitude / 15.0 + (_timezone* -1) / 3600 + tm.tm_isdst));
strcpy(sun.sunset, outputFormat((12.0 + differenceTime - EOT) - longitude / 15.0 + (_timezone* -1) / 3600 + tm.tm_isdst));
Serial.printf("Sonnenaufgang: %s\nSonnenuntergang: %s\n", sun.sunrise, sun.sunset);
server.on("/sun", [=]() {
char buf[18];
snprintf(buf, sizeof(buf), "[\"%s\",\"%s\"]", sun.sunrise, sun.sunset);
server.send(200, "application/json", buf);
});
}
}
double julianDate (int y, int m, int d) { // Gregorianischer Kalender
if (m <= 2) {
m = m + 12;
y = y - 1;
}
int gregorian = (y / 400) - (y / 100) + (y / 4); // Gregorianischer Kalender
return 2400000.5 + 365.0 * y - 679004.0 + gregorian + (30.6001 * (m + 1)) + d + 12.0 / 24.0;
}
double InPi(double x) {
int n = x / TWO_PI;
x = x - n * TWO_PI;
if (x < 0) x += TWO_PI;
return x;
}
double calculateEOT(double &DK, double T) {
double RAm = 18.71506921 + 2400.0513369 * T + (2.5862e-5 - 1.72e-9 * T) * T * T;
double M = InPi(TWO_PI * (0.993133 + 99.997361 * T));
double L = InPi(TWO_PI * ( 0.7859453 + M / TWO_PI + (6893.0 * sin(M) + 72.0 * sin(2.0 * M) + 6191.2 * T) / 1296.0e3));
double e = DEG_TO_RAD * (23.43929111 + (-46.8150 * T - 0.00059 * T * T + 0.001813 * T * T * T) / 3600.0); // Neigung der Erdachse
double RA = atan(tan(L) * cos(e));
if (RA < 0.0) RA += PI;
if (L > PI) RA += PI;
RA = 24.0 * RA / TWO_PI;
DK = asin(sin(e) * sin(L));
RAm = 24.0 * InPi(TWO_PI * RAm / 24.0) / TWO_PI;
double dRA = RAm - RA;
if (dRA < -12.0) dRA += 24.0;
if (dRA > 12.0) dRA -= 24.0;
dRA = dRA * 1.0027379;
return dRA ;
}
char* outputFormat(double sunTime) {
if (sunTime < 0) sunTime += 24;
else if (sunTime >= 24) sunTime -= 24;
int8_t decimal = 60 * (sunTime - static_cast<int>(sunTime)) + 0.5;
int8_t predecimal = sunTime;
if (decimal >= 60) {
decimal -= 60;
predecimal++;
}
else if (decimal < 0) {
decimal += 60;
predecimal--;
if (predecimal < 0) predecimal += 24;
}
static char buf[6];
snprintf(buf, sizeof(buf), "%.2d:%.2d", predecimal, decimal);
return buf;
}
Der Aufruf der Funktion "twilight(Länge, Breite)" ist nach ausführen von "setupTime();" möglich.
Die Berechnung des Sonnenaufgang und Sonnenuntergang durch "twilight(Länge, Breite)" wird nur einmal am Tag durchgeführt.
Die Funktion "localTime();" muss entweder im "void loop" oder am Anfang der Funktion "twilight()" aufgerufen werden.
*************** Aufruf localTime() aus void loop() ******************
Bsp.: Melbourne Australien
void loop() {
......
localTime();
twilight(144.97, -37.75); // geographische Länge und Breite
......
}
Im Lokalzeit Tab die korrekte POSIX Zeitzone für Melbourne Australien einfügen.
void setupTime() {
.....
setenv("TZ", "AEST-10AEDT,M10.1.0,M4.1.0/3", 1);
....
}
Es ist unbedingt erforderlich die richtige POSIX Zeitzone zu setzen da diese die Information zur möglichen Sommerzeit enthält.
Beispiel:
************* Aufruf localTime() aus void twilight() ****************
Bsp.: Leipzig Deutschland
void loop() {
......
twilight(12.348283, 51.345751); // geographische Länge und Breite
......
}
void twilight(const double longitude, const double latitude) {
localTime();
static byte lastday = 0;
......
}
Im Lokalzeit Tab die korrekte POSIX Zeitzone für Leipzig Deutschland einfügen.
void setupTime() {
.....
setenv("TZ", "CET-1CEST,M3.5.0/02,M10.5.0/03", 1);
....
}
suntime.html
<!DOCTYPE HTML> <!-- For more information visit: https://fipsok.de -->
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Uhrzeit</title>
<script>
function suntime() {
fetch('/sun').then(response => {
return response.json();
}).then(array => {
document.querySelector('#sunrise').innerHTML = array[0];
document.querySelector('#sunset').innerHTML = array[1];
});
}
function renew() {
fetch('/time').then(response => {
return response.json();
}).then(array => {
document.querySelector('#time').innerHTML = array[0];
document.querySelector('#date').innerHTML = array[1];
});
}
document.addEventListener('DOMContentLoaded', suntime(), renew(), setInterval(renew, 1000));
</script>
<style>
body {
padding: 10px;
font-size: 3.2em;
}
main {
display: flex;
flex-direction: column;
align-items: center;
background-color: black;
width: 280px;
padding: .2em;
border: .15em solid #aeaeab;
box-shadow: 5px 10px 5px rgba(0, 0, 0, 0.7);
border-radius: .2em;
}
span {
color: #00ff05;
position: relative;
top: .3em;
left: .1em;
letter-spacing: .1em;
font-weight: bold
}
#date {
font-size: .7em;
margin-top: .5em;
}
div {
display: flex;
justify-content: space-evenly;
width: 100%;
font-size: .5em;
margin-top: .7em;
}
</style>
</head>
<body>
<main>
<span id="time"></span>
<span id="date"></span>
<div>
<span id="sunrise"></span>
☀️
<span id="sunset"></span>
</div>
</main>
</body>
</html>