From 7b496ef7fde61ada939e9c20af9af33b76f2fd2a Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sun, 18 Oct 2026 14:55:41 +0200 Subject: docs: the Open-Meteo weather cards and their Conky-Mirage origin Co-Authored-By: Claude Sonnet 5.5 --- README.md | 65 ++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index c5b261b..fa2451b 100644 --- a/README.md +++ b/README.md @@ -29,37 +29,41 @@ config. Both are deliberately left as your choice rather than done for you. ## Weather -The weather card needs an [OpenWeatherMap](https://openweathermap.org/api) API -key. Copy the example and fill it in: +Five cards cover the weather: `now` (current conditions), `hourly` (the next +24 hours), `week` (seven days), `details` (wind, humidity, UV, air quality) and +`sky` (sun, moon and the daylight arc). The forecast cards are adapted from +[Conky-Mirage](https://github.com/alexsson-xexpanderx/Conky-themes/tree/master/Conky-Mirage) +by alexsson-xexpanderx, redrawn in this dashboard's palette, glyphs and fonts. + +Data comes from [Open-Meteo](https://open-meteo.com), which needs no key. Set +the location: cp weather.env.example ~/.config/udt/weather.env chmod 600 ~/.config/udt/weather.env -That path is outside the repo because it holds a key, and anything committed is -potentially public. `weather.env` is gitignored here as a second line of -defence. - -**A new key returns `401 Invalid API key` for anywhere from a few minutes to a -few hours after you create it.** That is the API activating it, not a mistake in -the file. Until it works, and whenever the cache is missing, the card draws its -own chrome with `no weather data` and the thing to fix, rather than vanishing. +The file is sourced by bash, so a value with spaces needs quotes, as in +`CITY="Example City"`. That path is outside the repo because a location is +personal data, and anything committed is potentially public. `weather.env` is +gitignored here as a second line of defence. `CITY` is geocoded once through +Open-Meteo and the result cached in `~/.cache/udt/weather-loc`; changing `CITY` +or `COUNTRY` re-geocodes on the next fetch. -Fetching is scheduled by conky itself: `conky.text` carries a single +Fetching is scheduled by conky itself: `conky.text` carries `${texeci 900 ~/.config/conky/bin/weather-fetch.sh}`, so the cache refreshes every 15 minutes while the dashboard runs and never while it does not. The -widget only ever reads `~/.cache/udt/weather.json`; it makes no network call and -cannot block the draw. +cards only ever read `~/.cache/udt/weather.txt`; they make no network call and +cannot block the draw. Until the first fetch lands, each card draws its own +chrome with `no weather data` rather than vanishing. A leftover +`~/.cache/udt/weather.json` from the old OpenWeatherMap version is no longer +read and can be deleted. To check the fetch by hand: ./bin/weather-fetch.sh; echo "exit: $?" It prints nothing and exits 0 on success. On failure it says why on stderr and -leaves any existing cache alone, so a transient error never replaces good data -with an error body. - -Location and units live in `weather.env` too (`CITY`, `COUNTRY`, `UNITS`), not -in the source, so no real location appears in committed files. +leaves any existing cache alone. A failed air-quality call is not a failure: +the AQI row reads `--` and everything else updates. ## System widgets @@ -160,7 +164,7 @@ dropping photos that are no longer in it. It needs `immich.env.example`. The key wants `memory.read` and `asset.view`; with `asset.read` too, the card shows the place, and without it the row reads `--`. -The key sits in a plain file, like the weather key, because the fetch runs +The key sits in a plain file because the fetch runs unattended from conky: reading it from a GPG-backed store would raise a pinentry whenever the agent's cache has expired. @@ -181,7 +185,7 @@ table works on differently shaped monitors. local layout = { { widget = 'clock', col = 1, row = 1, w = 1, h = 1 }, - { widget = 'weather', col = 1, row = 2, w = 1, h = 1 }, + { widget = 'now', col = 1, row = 2, w = 1, h = 1 }, } Reordering widgets is an edit to that table and nothing else: a widget is handed @@ -237,17 +241,16 @@ the largest base size at which every row still fits the width, and the widget takes the smaller of that and its height budget. Larger cell, larger type; a row that would collide pulls the size back down. The breaktimer and immich cards do this. A card that cannot afford the measuring pass can still key off width with -a clamp, `math.max(lo, math.min(hi, inner.w * k))`; the clock and weather -cards do. +a clamp, `math.max(lo, math.min(hi, inner.w * k))`; the clock does. **Decide where the slack goes, and let one element absorb it.** The clock pins its date block to the bottom and gives the numerals everything above. The -weather card stacks from the top and lets the arc take the remainder. Either is +sky card stacks its rows from the top and pins the arc to the bottom. Either is fine; what fails is leaving the slack wherever it lands. An element that cannot shrink below some size should drop out rather than -overlap. The weather arc does this: below 70px it is not drawn at all, because a -curve crossing the stat rows is worse than no curve. Check a widget at several +overlap. The sky arc does this: below 50px it is not drawn at all, because a +curve crossing the rows is worse than no curve. Check a widget at several spans before believing it is fluid, which the offscreen renderer above makes cheap. @@ -337,7 +340,7 @@ for bold. **Fonts are per-widget when a widget wants one.** `lib/card.lua` holds the shared `FONT_*` families, but `card.font()` takes any family string, so a widget passes its own. The clock uses `FONT_CLOCK` (Oswald, OFL-1.1, under -`~/.fonts/o/Oswald`) for squared numerals while the weather card keeps +`~/.fonts/o/Oswald`) for squared numerals while the other cards keep `FONT_HEAVY`. Check a new family with `fc-match` first: fontconfig silently substitutes a default for a name it does not know, which looks exactly like the font "not applying". @@ -352,11 +355,9 @@ on the 2-second draw cadence, entirely unrelated to the 15-minute fetch, so a fetch killed mid-write would otherwise hand the parser half a response. Rename is only atomic within a filesystem, so the temp file sits in the same directory. -**A bad OWM key returns 401 and an unknown city returns 404**, so `curl -f` -catches both. The fetch script also checks `.cod` is 200 before replacing the -cache, which covers the remaining case of a 200 whose body is not usable -weather. The polybar script this was ported from needed that check as its only -defence, because it ran curl without `-f`. +**A 200 is not proof of a forecast.** `curl -f` rejects HTTP errors, and the +fetch script also checks the flattened cache has a current temperature before +replacing the old one, so an unusable body never reaches the cards. **Nothing in `lib/weather.lua` raises.** Every function returns nil, or a sentinel, on input it cannot use, and that is verified against every function @@ -365,7 +366,7 @@ the parser's input is a file written by a network fetch, and a raise here is a blank dashboard rather than a message. **Type keyed on one dimension alone leaves the card broken or sparse.** The -weather text once shrank to a whisper beside the clock when its cell got shorter +old weather card's text once shrank to a whisper beside the clock when its cell got shorter because the size keyed on height; a card keyed only on width leaves a tall cell half empty. Fill the cell instead: `card.fit_unit()` measures the rows and returns the largest size that fits the width, the widget takes the smaller of -- cgit v1.2.3