1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
#!/bin/bash
# desktop-assistant tool: weather from OpenWeatherMap.
# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# weather.sh [PLACE] [WHEN]: PLACE empty = home, WHEN now (default), today
# or tomorrow. WEATHER_ENV names an env file with KEY, CITY, COUNTRY and
# UNITS (the conky-theme-udt format). Home "now" reuses that project's
# cache when it is under 30 minutes old, so it costs no request.
# ponytail: wind is converted as metric (m/s to km/h); UNITS=imperial
# would need mph instead.
set -uo pipefail
env_file="${WEATHER_ENV:-$HOME/.config/udt/weather.env}"
[ -r "$env_file" ] || { echo "no weather env file at $env_file" >&2; exit 1; }
# shellcheck source=/dev/null
. "$env_file"
[ -n "${KEY:-}" ] || { echo "KEY is empty in $env_file" >&2; exit 1; }
place="${1:-}"
when="${2:-}"
q="${place:-$CITY,$COUNTRY}"
get() {
curl -fsS --max-time 8 --get "https://api.openweathermap.org/data/2.5/$1" \
--data-urlencode "appid=$KEY" --data-urlencode "units=${UNITS:-metric}" \
--data-urlencode "q=$q" \
|| { echo "weather request failed for $q" >&2; exit 1; }
}
case "${when:-now}" in
now)
cache="${XDG_CACHE_HOME:-$HOME/.cache}/udt/weather.json"
if [ -z "$place" ] && [ -n "$(find "$cache" -mmin -30 2>/dev/null)" ]; then
json=$(cat "$cache")
else
json=$(get weather) || exit 1
fi
jq -r '"\(.name), \(.sys.country): \(.weather[0].description), \(.main.temp|round) degrees, feels like \(.main.feels_like|round), humidity \(.main.humidity)%, wind \(.wind.speed*3.6|round) km/h"' <<<"$json"
;;
today|tomorrow)
day=$(date -d "$when" +%F)
json=$(get forecast) || exit 1
jq -r --arg day "$day" '
"\(.city.name), \(.city.country)" as $c
| [.list[] | select((.dt | localtime | strftime("%Y-%m-%d")) == $day)]
| if length == 0 then "no forecast for \($c) on \($day)"
else "\($c) \($day): " + (map("\(.dt | localtime | strftime("%H:%M")) \(.weather[0].description) \(.main.temp|round) degrees") | join(", "))
end' <<<"$json"
;;
*)
echo "when must be now, today or tomorrow" >&2
exit 1
;;
esac
|