Update: 2024-03-06

Die Zeiten für den Sonnenaufgang und Sonnenuntergang werden einmal am Tag berechnet und im "struct sun" gespeichert.

Der Lokalzeit Tab ist für die Berechnung erforderlich

Esp32 Sonnenaufgang als Arduino Tab.

Sonnenaufgang.ino

// ****************************************************************
// Arduino IDE Tab Esp32 Sonnen Auf/Untergang Modular
// source: https://lexikon.astronomie.info/zeitgleichung/neu.html
// created: Jens Fleischer, 2018-12-29
// last mod: Jens Fleischer, 2024-03-06
// For more information visit: https://fipsok.de
// ****************************************************************
// Hardware: Esp32
// Software: Esp32 Arduino Core 1.0.0 - 2.0.14
// Getestet auf: ESP32 NodeMCU-32s
/******************************************************************
  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 Sonnenaufgang 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, UTC +/-)"
// den Längen- und Breitengrad sowie die Zeitzone deines Ortes an.
// "twilight(12.348283, 51.345751, 1);" https://www.laengengrad-breitengrad.de/
/**************************************************************************************/

struct sun {
  char sunrise[6];
  char sunset[6];
} sun;

const double PIx2 = PI * 2;
const double RAD = 0.017453292519943;

void twilight(const double longitude, const double latitude, double timeZone) {
  static byte lastday = 0;
  if (tm.tm_mday != lastday) {           // Sonnenaufgang Sonnenuntergang nur einmal Täglich berechnen
    lastday = tm.tm_mday;
    const double h = -0.833333333333333 * RAD;
    const double w = latitude * 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 + tm.tm_isdst));
    strcpy(sun.sunset, outputFormat((12.0 + differenceTime - EOT) - longitude / 15.0 + timeZone + tm.tm_isdst));
    DEBUG_F("Sonnenaufgang: %s\nSonnenuntergang: %s\n", sun.sunrise, sun.sunset);
  }
}

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 + int(30.6001 * (m + 1)) + d + 12.0 / 24.0;
}

double InPi(double x) {
  int n = (int)(x / PIx2);
  x = x - n * PIx2;
  if (x < 0) x += PIx2;
  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(PIx2 * (0.993133 + 99.997361 * T));
  double L  = InPi(PIx2 * (  0.7859453 + M / PIx2 + (6893.0 * sin(M) + 72.0 * sin(2.0 * M) + 6191.2 * T) / 1296.0e3));
  double e = 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 / PIx2;
  DK = asin(sin(e) * sin(L));
  RAm = 24.0 * InPi(PIx2 * RAm / 24.0) / PIx2;
  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 - (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[9];
  snprintf(buf, sizeof(buf), "%.2d:%.2d", predecimal, decimal);
  return buf;
}

Der Aufruf der Funktion "twilight(Länge, Breite, Zeitzone)" ist nach ausführen von "setupTime();" möglich.
Die Berechnung des Sonnenaufgang und Sonnenuntergang durch "twilight(Länge, Breite, UTC +/-)" 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() ******************

Example Melbourne Australien

void loop() {
 ......
  localTime();
  twilight(144.97, -37.75, 10);  // geographische Länge, Breite und Zeitzone setzen UTC +/-
 ......
}

Im Lokalzeit Tab die korrekte POSIX Zeitzone für Melbourne Australien einfügen.

bool getTime() {
  .....
  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.


************* Aufruf localTime() aus void twilight() ****************

Example: Leipzig Deutschland

void loop() {
 ......
  twilight(12.348283, 51.345751, 1);  // geographische Länge, Breite und Zeitzone setzen UTC +/-
 ......
}

void twilight(const double longitude, const double latitude, double timeZone) {
  localTime(); 
  static byte lastday = 0;
  ......
}

Im Lokalzeit Tab die korrekte POSIX Zeitzone für Leipzig Deutschland einfügen.

bool getTime() {
  .....
  setenv("TZ", "CET-1CEST,M3.5.0/02,M10.5.0/03", 1);
  ....
}