~tomterl/public-inbox

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH thp] New module: +sun.ha

Carlos Une <une@fastmail.fm>
Details
Message ID
<20230618144543.17798-1-une@fastmail.fm>
DKIM signature
missing
Download raw message
Patch: +186 -4
---
 README.org     |   8 +--
 man/thp.1.scd  |   3 +
 man/thpd.5.scd |  31 +++++++++++
 mods/+sun.ha   | 148 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 186 insertions(+), 4 deletions(-)
 create mode 100644 mods/+sun.ha

diff --git a/README.org b/README.org
index 6c8e372..69a7dfc 100644
--- a/README.org
+++ b/README.org
@@ -32,16 +32,16 @@ one patche applied (as of now):
To build thp with all modules included, you need libgit2 and your platforms libgit2-dev equivalent installed, then issued

#+BEGIN_SRC sh :exports code
make EXTRA_MODS="project git clock timer shind uptime moon"
make EXTRA_MODS="project git clock timer shind uptime moon" test
make EXTRA_MODS="project git clock timer shind uptime moon sun"
make EXTRA_MODS="project git clock timer shind uptime moon sun" test
make PREFIX="${HOME}" install
#+END_SRC

To build with just the modules you use in your spec, use ~MODS~:

#+BEGIN_SRC sh :exports code
make MODS="path host project timer uptime moon"
make MODS="path host project timer uptime moon" test
make MODS="path host project timer uptime moon sun"
make MODS="path host project timer uptime moon sun" test
make PREFIX="${HOME}" install
#+END_SRC

diff --git a/man/thp.1.scd b/man/thp.1.scd
index dcdf50c..cd6a11f 100644
--- a/man/thp.1.scd
+++ b/man/thp.1.scd
@@ -107,6 +107,9 @@ All modules are optionally compiled into the server executable.

*moon* displays an icon representing the current moon phase.

*sunrise* and *sunset* display the time of sunrise and sunset, respectively.
	The location and time format can be configured. See thpd(5).

# STYLES

Available colors are: black, red, green, yellow, blue, magenta, cyan, white,
diff --git a/man/thpd.5.scd b/man/thpd.5.scd
index e4d9dfd..1673a01 100644
--- a/man/thpd.5.scd
+++ b/man/thpd.5.scd
@@ -173,6 +173,37 @@ Valid values: "S" and "N".
hemisphere="N"
```

## sun

Display the time of sunrise and sunset.

- latitude[=-23.5898764]
	The latitude in decimal format.

- longitude[=-46.6589231]
	The longitude in decimal format.

- sunrise.layout[=🌅%H:%M]
- sunset.layout[=🌇%H:%M]
	Format string as understood by date::asformat from the hare standard library.

- midnight.sun.msg[=Midnight sun]
	Display message when the sun stays above the horizon all day.

- polar.night.msg[=Polar night]
	Display message when the sun stays below the horizon all day.

*example*:

```
[sun]
\# Buenos Aires/AR
latitude=-34.603333
longitude=-58.381667
sunrise.layout=%H:%M|
sunset.layout=%H:%M|
```

# SEE ALSO

*thpd*(1) *thp*(1) *thp*(5)
diff --git a/mods/+sun.ha b/mods/+sun.ha
new file mode 100644
index 0000000..ef9626e
--- /dev/null
+++ b/mods/+sun.ha
@@ -0,0 +1,148 @@
// Author: Carlos Une <une@fastmail.fm>
// Maintainer: Carlos Une <une@fastmail.fm>
//
// SPDX-FileCopyrightText:  2023 Carlos Une <une@fastmail.fm>
// SPDX-License-Identifier: GPL-3.0-or-later
// Reference: https://en.wikipedia.org/wiki/Sunrise_equation
use config;
use env;
use math;
use strconv;
use strings;
use time;
use time::chrono;
use time::date;

type midnightsun = !void; // Sun doesn't set
type polarnight = !void; // Sun doesn't rise

@init fn register_sun() void = {
	register("sunrise", &mod_sunrise);
	register("sunset", &mod_sunset);
};

fn readconfig() (f64, f64, str, str, str, str) = (
	strconv::stof64(config::setting("sun.latitude", "-23.5898764"))!,
	strconv::stof64(config::setting("sun.longitude", "-46.6589231"))!,
	config::setting("sun.sunrise.layout", "🌅%H:%M"),
	config::setting("sun.sunset.layout", "🌇%H:%M"),
	config::setting("sun.midnight.sun.msg", "Midnight sun"),
	config::setting("sun.polar.night.msg", "Polar night"));

export fn mod_sunrise(pe: *env::env) str = {
	const cfg = readconfig();
	match(sunrise_sunset(local_today_utc_noon(), cfg.0, cfg.1)) {
	case let r: (date::date, date::date) =>
		return strings::dup(date::asformat(cfg.2, &date::in(chrono::LOCAL, r.0)!)!);
	case midnightsun =>
		return strings::dup(cfg.4);
	case polarnight =>
		return strings::dup(cfg.5);
	};
};

export fn mod_sunset(pe: *env::env) str = {
	const cfg = readconfig();
	match(sunrise_sunset(local_today_utc_noon(), cfg.0, cfg.1)) {
	case let r: (date::date, date::date) =>
		return strings::dup(date::asformat(cfg.3, &date::in(chrono::LOCAL, r.1)!)!);
	case midnightsun =>
		return strings::dup(cfg.4);
	case polarnight =>
		return strings::dup(cfg.5);
	};
};

fn rad(a: f64) f64 = a * math::PI/180.0;
fn deg(a: f64) f64 = a * 180.0/math::PI;
fn sin(a: f64) f64 = math::sinf64(rad(a));
fn cos(a: f64) f64 = math::cosf64(rad(a));

// Get today's yyyy/mm/dd in LOCAL tzone, build yyyy/mm/dd 12:00:00 in UTC tzone
fn local_today_utc_noon() date::date = {
	const now = date::now();
	return date::new(chrono::UTC, 0, date::year(&now), date::month(&now), date::day(&now), 12, 0, 0, 0)!;
};

fn julian_day_n(dt: date::date) f64 = {
	const ref = date::new(chrono::UTC, 0, 2000, 1, 1, 12, 0, 0, 0)!;
	return chrono::diff(&ref, &dt)!: f64/(24*time::HOUR): f64;
};

// https://en.wikipedia.org/wiki/Julian_day#Julian_or_Gregorian_calendar_from_Julian_day_number
fn julian_to_gregorian(jday: f64) date::date = {
	const J: int = math::truncf64(jday): int;
	const y: int = 4716;
	const v: int = 3;
	const j: int = 1401;
	const u: int = 5;
	const m: int = 2;
	const s: int = 153;
	const n: int = 12;
	const w: int = 2;
	const r: int = 4;
	const B: int = 274277;
	const p: int = 1461;
	const C: int = -38;
	const f: int = J + j + (((4 * J + B) / 146097) * 3) / 4 + C;
	const e = r * f + v;
	const g = (e % p) / r;
	const h = u * g + w;
	const D = (h % s) / u + 1;
	const M = (h/s + m) % n + 1;
	const Y = (e / p) - y + (n + m - M) / n;
	const fday = jday - J: f64;
	const hour = (fday*24.0): int;
	const minute = (fday*24.0*60.0): int - (hour*60);
	const second = (fday*24.0*60.0*60.0): int - (hour*3600) - (minute*60);
	let date = date::new(chrono::UTC, 0, Y, M, D, 0, minute, second, 0)!;
	return date::add(date, (hour+12)*time::HOUR);
};

fn mean_solar_time(n: f64, lw: f64) f64 = {
	return n - lw/360.0;
};

fn solar_mean_anomaly(J: f64) f64 = {
	return math::modf64(357.5291 + 0.98560028 * J, 360.0);
};

fn equation_of_the_center(M: f64) f64 = {
	return 1.9148*sin(M) + 0.02*sin(2.0*M) + 0.0003*sin(3.0*M);
};

fn eclyptic_longitude(M: f64, C: f64) f64 = {
	return math::modf64(M + C + 180.0 + 102.9372, 360.0);
};

fn solar_transit(J: f64, M: f64, lambda: f64) f64 = {
	return 2451545.0 + J + 0.0053*sin(M) - 0.0069*sin(2.0*lambda);
};

fn declination_of_the_sun(lambda: f64) (f64, f64) = {
	let sindelta = sin(lambda)*sin(23.44);
	return (sindelta, deg(math::asinf64(sindelta)));
};

fn hour_angle(phi: f64, delta: f64) (f64, f64) = {
	let cosomega0 = (sin(-0.83) - sin(phi)*sin(delta))/(cos(phi)*cos(delta));
	return (cosomega0, deg(math::acosf64(cosomega0)));
};

fn sunrise_sunset(d: date::date, lat: f64, lon: f64) ((date::date, date::date) | midnightsun | polarnight) = {
	const J = mean_solar_time(math::ceilf64(julian_day_n(d)), lon);
	const M = solar_mean_anomaly(J);
	const C = equation_of_the_center(M);
	const lambda = eclyptic_longitude(M, C);
	const J_transit = solar_transit(J, M, lambda);
	const (sindelta, delta) = declination_of_the_sun(lambda);
	const (cosomega0, omega0) = hour_angle(lat, delta);
	if (cosomega0 < -1.0) {
		return midnightsun;
	} else if (cosomega0 > 1.0) {
		return polarnight;
	};
	const J_rise = J_transit - omega0/360.0;
	const J_set = J_transit + omega0/360.0;
	return (julian_to_gregorian(J_rise), julian_to_gregorian(J_set));
};
-- 
2.30.2
Details
Message ID
<87h6r3jvpv.fsf@tomsdiner.org>
In-Reply-To
<20230618144543.17798-1-une@fastmail.fm> (view parent)
DKIM signature
missing
Download raw message
Thanks a lot!
Reply to thread Export thread (mbox)