20static const char *
const TAG =
"sun";
45 d += moment.
hour / 24.0;
46 d += moment.
minute / (24.0 * 60);
47 d += moment.
second / (24.0 * 60 * 60);
53 int b = 2 - a + a / 4;
54 return ((
int) (365.25 * (
y + 4716))) + ((int) (30.6001 * (
m + 1))) + d + b - 1524.5;
58 int t = moment.
year - 2000;
59 return 62.92 + t * (0.32217 + t * 0.005589);
74 return jd() +
delta_t(dt) / (60 * 60 * 24);
82 SunAtTime(
num_t jde) : jde(jde), t((jde - 2451545) / 36525.0) {}
84 num_t mean_obliquity()
const {
94 num_t omega = 125.05 - 1934.136 * t;
98 num_t true_obliquity()
const {
100 num_t delta_epsilon = 0.00256 * cos(radians(omega()));
101 num_t epsilon = mean_obliquity() + delta_epsilon;
105 num_t mean_longitude()
const {
107 num_t l0 = 280.46646 + 36000.76983 * t + 0.0003032 *
sq(t);
108 return wmod(l0, 360);
111 num_t eccentricity()
const {
113 num_t e = 0.016708634 - 0.000042037 * t - 0.0000001267 *
sq(t);
117 num_t mean_anomaly()
const {
119 num_t m = 357.52911 + 35999.05029 * t - 0.0001537 *
sq(t);
123 num_t equation_of_center()
const {
126 num_t c = ((1.914602 - 0.004817 * t - 0.000014 *
sq(t)) * sin(m_rad) + (0.019993 - 0.000101 * t) * sin(2 * m_rad) +
127 0.000289 * sin(3 * m_rad));
131 num_t true_longitude()
const {
133 num_t x = mean_longitude() + equation_of_center();
137 num_t true_anomaly()
const {
139 num_t x = mean_anomaly() + equation_of_center();
143 num_t apparent_longitude()
const {
145 num_t x = true_longitude() - 0.00569 - 0.00478 * sin(
radians(omega()));
153 num_t right_ascension_rad = atan2(cos(epsilon_rad) * sin(app_lon_rad), cos(app_lon_rad));
154 num_t declination_rad = asin(sin(epsilon_rad) * sin(app_lon_rad));
158 num_t equation_of_time()
const {
162 num_t l2 = 2 * mean_longitude();
164 num_t e = eccentricity();
167 num_t sin_m = sin(m_rad);
168 num_t eot = (
y * sin(l2_rad) - 2 * e * sin_m + 4 * e *
y * sin_m * cos(l2_rad) - 1 / 2.0 *
sq(
y) * sin(2 * l2_rad) -
169 5 / 4.0 *
sq(e) * sin(2 * m_rad));
175 ESP_LOGV(TAG,
"jde: %f", jde);
176 ESP_LOGV(TAG,
"T: %f", t);
177 ESP_LOGV(TAG,
"L_0: %f", mean_longitude());
178 ESP_LOGV(TAG,
"M: %f", mean_anomaly());
179 ESP_LOGV(TAG,
"e: %f", eccentricity());
180 ESP_LOGV(TAG,
"C: %f", equation_of_center());
181 ESP_LOGV(TAG,
"Odot: %f", true_longitude());
182 ESP_LOGV(TAG,
"Omega: %f", omega());
183 ESP_LOGV(TAG,
"lambda: %f", apparent_longitude());
184 ESP_LOGV(TAG,
"epsilon_0: %f", mean_obliquity());
185 ESP_LOGV(TAG,
"epsilon: %f", true_obliquity());
186 ESP_LOGV(TAG,
"v: %f", true_anomaly());
187 auto eq = equatorial_coordinate();
188 ESP_LOGV(TAG,
"right_ascension: %f", eq.right_ascension);
189 ESP_LOGV(TAG,
"declination: %f", eq.declination);
193struct SunAtLocation {
196 num_t greenwich_sidereal_time(
Moment moment)
const {
204 num_t t = (jd0 - 2451545) / 36525;
206 num_t gmst = (+280.46061837 + 360.98564736629 * (jd - 2451545) + 0.000387933 *
sq(t) - (1 / 38710000.0) *
cb(t));
207 return wmod(gmst, 360);
211 auto eq = SunAtTime(moment.
jde()).equatorial_coordinate();
212 num_t gmst = greenwich_sidereal_time(moment);
214 num_t nutation_corr = 0;
216 num_t ra = eq.right_ascension;
218 alpha =
wmod(alpha, 360);
223 num_t sin_elevation = (+sin_lat * sin(eq.declination_rad()) + cos_lat * cos(eq.declination_rad()) * cos(alpha_rad));
224 num_t elevation_rad = asin(sin_elevation);
225 num_t azimuth_rad = atan2(sin(alpha_rad), cos(alpha_rad) * sin_lat - tan(eq.declination_rad()) * cos_lat);
235 auto m = local_event_(date, 12);
237 num_t new_h = 0, old_h;
240 auto x = local_hour_angle_(jde + old_h / 86400, rise, zenith);
244 }
while (std::abs(new_h - old_h) >= 15);
245 time_t new_timestamp =
m.timestamp + (time_t) new_h;
246 return ESPTime::from_epoch_local(new_timestamp);
251 auto pos = SunAtTime(jde).equatorial_coordinate();
252 num_t dec_rad = pos.declination_rad();
254 num_t num = cos(
radians(zenith)) - (sin(dec_rad) * sin(lat_rad));
255 num_t denom = cos(dec_rad) * cos(lat_rad);
256 num_t cos_h = num / denom;
257 if (cos_h > 1 || cos_h < -1)
270 num_t eot = SunAtTime(jd).equation_of_time() * 240;
271 time_t new_timestamp = (time_t) (date.
timestamp + added_d * 86400 - eot);
272 return ESPTime::from_epoch_utc(new_timestamp);
277 SunAtLocation sun{location_};
279 if (!
m.dt.is_valid())
287 return sun.true_coordinate(
m);
290 SunAtLocation sun{location_};
295 today.
hour = today.minute = today.second = 0;
296 today.recalc_timestamp_utc();
298 auto it = sun.event(rising, today, zenith);
299 if (it.has_value() && it->timestamp < date.
timestamp) {
302 time_t new_timestamp = today.timestamp + 24 * 60 * 60;
304 it = sun.event(rising, today, zenith);
optional< ESPTime > calc_event_(bool rising, double zenith)
internal::HorizontalCoordinate calc_coords_()
optional< ESPTime > sunset(double elevation)
optional< ESPTime > sunrise(double elevation)
num_t delta_t(ESPTime moment)
num_t wmod(num_t x, num_t y)
num_t arcdeg(num_t deg, num_t minutes, num_t seconds)
num_t julian_day(ESPTime moment)
Providing packet encoding functions for exchanging data with a remote host.
A more user-friendly version of struct tm from time.h.
uint8_t minute
minutes after the hour [0-59]
uint8_t second
seconds after the minute [0-60]
uint8_t hour
hours since midnight [0-23]
time_t timestamp
unix epoch time (seconds since UTC Midnight January 1, 1970)
bool is_valid() const
Check if this ESPTime is valid (all fields in range and year is greater than 2018)
static ESPTime from_epoch_utc(time_t epoch)
Convert an UTC epoch timestamp to a UTC time ESPTime instance.
uint8_t day_of_month
day of the month [1-31]
uint8_t month
month; january=1 [1-12]
num_t declination_rad() const
num_t right_ascension_rad() const
num_t latitude_rad() const
num_t longitude_rad() const
num_t elevation_rad() const
num_t azimuth_rad() const