aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-17 09:22:59 +0200
committerDanilo M. <danix@danix.xyz>2026-09-17 09:22:59 +0200
commitb51d1efa913933cb272b7c1906340981f00010c8 (patch)
treed3df8647fbb295cb575142fd7125511a795c9646
parenta3bb9e2764b415901fb2475c03f6fdb8a736d4fa (diff)
downloadconky-theme-udt-b51d1efa913933cb272b7c1906340981f00010c8.tar.gz
conky-theme-udt-b51d1efa913933cb272b7c1906340981f00010c8.zip
docs: document the weather widget and fix the screenshot recipe
Adds a Weather section covering the API key, where it lives and why, the 401-while-activating behaviour a new key shows, the execi refresh, and the by-hand fetch check. Adds five gotchas: execi firing under empty text, the atomic cache write, what OWM actually returns for a bad key and city, the no-raise invariant in lib/weather.lua, and type scaling off width. Also corrects three things that had gone stale: the symlink list omitted bin/, the layout example still showed a single full-height clock, and the test line omitted test_weather.lua. The screenshot recipe was wrong in two ways, both of which bit during this work. It slept a fixed second and raced the compositor, which is how a capture came back showing a terminal instead of the dashboard; it now polls for the workspace switch. And it fed the window's geometry to grim -g, but a window on a hidden special workspace reports a negative Y, so that grabs the wrong region; it now captures the output. Every command in the file was run as written before committing this. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
-rw-r--r--README.md101
1 files changed, 92 insertions, 9 deletions
diff --git a/README.md b/README.md
index 195e62a..912aa18 100644
--- a/README.md
+++ b/README.md
@@ -15,8 +15,8 @@ Rendering and linking are automatic:
cd ../unified-desktop-theme && ./install.sh
That renders `conky.conf` from `conky.conf.in` and symlinks it, along with
-`dashboard.lua`, `lib/` and `widgets/`, into `~/.config/conky/`. Re-running it
-after a scheme change re-renders the colours.
+`dashboard.lua`, `lib/`, `widgets/` and `bin/`, into `~/.config/conky/`.
+Re-running it after a scheme change re-renders the colours.
The Hyprland side is **not** installed by that script and is still yours to do.
Until you do it, the dashboard opens as an ordinary floating window on whatever
@@ -27,6 +27,40 @@ are not loaded. Two things are needed, both described in
the bare `hl.exec_cmd("conky")` in `sections/autostart.lua` so it loads this
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:
+
+ 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.
+
+Fetching is scheduled by conky itself: `conky.text` carries a single
+`${execi 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.
+
+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.
+
## Changing the layout
Edit the `layout` table at the top of `dashboard.lua`. `col`/`row` are grid
@@ -34,7 +68,8 @@ cells and `w`/`h` span them; cell size is derived from the screen, so the same
table works on differently shaped monitors.
local layout = {
- { widget = 'clock', col = 1, row = 1, w = 1, h = 2 },
+ { widget = 'clock', col = 1, row = 1, w = 1, h = 1 },
+ { widget = 'weather', col = 1, row = 2, w = 1, h = 1 },
}
Reordering widgets is an edit to that table and nothing else: a widget is handed
@@ -76,21 +111,43 @@ rather than ending up with two.
Run the parser and layout checks:
- lua test/test_data.lua && lua test/test_layout.lua
+ lua test/test_data.lua && lua test/test_layout.lua && lua test/test_weather.lua
Screenshot it. `grim` captures screen coordinates, not a window, so the
dashboard's workspace has to be the active one first, and the toggle needs the
Lua dispatch form because this Hyprland config is Lua (the plain
-`togglespecialworkspace dash` form fails with `')' expected near 'dash'`):
+`togglespecialworkspace dash` form fails with `')' expected near 'dash'`).
+
+**Poll for the switch, do not sleep through it.** A fixed `sleep` races the
+compositor and captures whatever was on screen before; that is how a review
+screenshot here once came back showing a terminal. Capture the whole output
+instead of the window geometry, too: a window parked on a hidden special
+workspace reports a negative Y (`0,-540`), and feeding that to `grim -g` grabs
+the wrong region entirely.
hyprctl dispatch 'hl.dsp.workspace.toggle_special("dash")'
- sleep 1
- grim -g "$(hyprctl clients -j | jq -r '.[]|select(.class=="conky-dash")|"\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')" /tmp/dash.png
+ for i in $(seq 40); do
+ [ "$(hyprctl monitors -j | jq -r '.[0].specialWorkspace.name')" = "special:dash" ] && break
+ sleep 0.15
+ done
+ sleep 2.5 # conky redraws every 2s; make sure a frame has landed
+ grim -o DP-1 /tmp/dash.png
hyprctl dispatch 'hl.dsp.workspace.toggle_special("dash")'
+Then **look at the PNG**. `grim` exits 0 whether the card drew correctly, drew
+nothing, or drew an error, so the exit status says nothing about the thing you
+are checking.
+
+Faster, for iterating on a widget's layout: conky's Cairo bindings load in
+plain Lua, so a widget can be rendered to a PNG without conky at all. Point
+`package.cpath` at `/usr/lib64/conky/lib?.so`, `require 'cairo'`, build an
+image surface, and call the widget's `draw` with a hand-made rect and palette.
+That turns install-restart-toggle-screenshot into one command. Be aware it
+crops away the neighbouring cards, so check the real dashboard before believing
+anything about relative type size.
+
Before the Hyprland section is installed there is no `special:dash` to toggle,
-so the window is simply wherever it opened and the `grim` line alone captures
-it.
+so the window is simply wherever it opened and a bare `grim` captures it.
## Gotchas worth knowing
@@ -119,6 +176,32 @@ the heavy clock numerals ask for the family `Noto Sans Black` at normal weight.
**Sensors are globbed by hwmon `name`, never by index.** Indices drift across
kernel and hardware reorders, and a stale one silently reports a different chip.
+**`${execi}` fires even though `conky.text` renders nothing.** Cairo output
+covers the text stream, so the `execi` that refreshes the weather cache is
+invisible, but it still runs on schedule. This was checked with a probe config
+rather than assumed, because the whole refresh mechanism rests on it.
+
+**The weather cache is written to a temp file and renamed.** The widget reads it
+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`.
+
+**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
+for nil, string, table, boolean, NaN and negative arguments. It matters because
+the parser's input is a file written by a network fetch, and a raise here is a
+blank dashboard rather than a message.
+
+**Card type scales off the cell WIDTH, not its height.** Height changes with the
+grid, and scaling off it made the weather text shrink to a whisper beside the
+clock's numerals when its cell got shorter.
+
## License
GPLv2 only. See `LICENSE`.