Let the weather panel be pinned to a chosen location

The weather widgets asked wttr.in to geolocate by IP, which lands on
whatever city the ISP registers its address block under -- Downey when
you're in Malibu. Now the location can be set explicitly:

* Click the location in the weather panel to search via open-meteo
  geocoding, pick a suggestion (disambiguated by region), and it sticks.
  The X next to the field returns to IP auto-detect, as does committing
  an empty search.

* State lives in ~/.local/state/omarchy/settings/weather.json as
  {name, latitude, longitude}, owned by the new omarchy-weather-location
  command (bare call prints the current location, --set/--clear write).
  The panel watches the file, so hand edits apply live.

* Stored coordinates make wttr.in and open-meteo exact. Open-meteo also
  now supplies current conditions alongside the daily forecast it
  already served, which fills the panel within a second of a location
  change instead of waiting out wttr.in's multi-second responses; wttr
  results still win once they land. Failed wttr fetches retry instead
  of sitting stale until the next refresh cycle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
David Heinemeier Hansson
2026-07-16 14:46:56 -07:00
co-authored by Claude Fable 5
parent 95c1ff0901
commit 5044e711a0
6 changed files with 514 additions and 17 deletions
+10 -1
View File
@@ -2,7 +2,16 @@
# omarchy:summary=Returns a weather condition icon, adjusted for live sunrise and sunset.
weather_data=$(curl -fsS --max-time 3 "https://wttr.in?format=j1" 2>/dev/null | jq -er '[.current_condition[0].weatherCode, .weather[0].astronomy[0].sunrise, .weather[0].astronomy[0].sunset] | select(all(. != null and . != "")) | @tsv' 2>/dev/null) || exit 1
# Only consult the helper when a location is stored: this runs every minute,
# and the helper's dynamic fallback would cost an extra wttr.in request when
# nothing is set — the bare j1 fetch already auto-detects by IP.
query=""
if [[ -s "$HOME/.local/state/omarchy/settings/weather.json" ]]; then
location=$(omarchy-weather-location 2>/dev/null)
[[ -n $location ]] && query=$(jq -rn --arg location "$location" '$location | @uri')
fi
weather_data=$(curl -fsS --max-time 3 "https://wttr.in/${query}?format=j1" 2>/dev/null | jq -er '[.current_condition[0].weatherCode, .weather[0].astronomy[0].sunrise, .weather[0].astronomy[0].sunset] | select(all(. != null and . != "")) | @tsv' 2>/dev/null) || exit 1
IFS=$'\t' read -r weather_code sunrise sunset <<< "$weather_data"
if [[ ! $weather_code =~ ^[0-9]+$ || ! $sunrise =~ ^[0-9]{1,2}:[0-9]{2}\ [AP]M$ || ! $sunset =~ ^[0-9]{1,2}:[0-9]{2}\ [AP]M$ ]]; then
+46
View File
@@ -0,0 +1,46 @@
#!/bin/bash
# omarchy:summary=Show or set the location used for weather reports
#
# State lives in ~/.local/state/omarchy/settings/weather.json as
# {"name": ..., "latitude": ..., "longitude": ...}. A missing file means the
# location is auto-detected from the IP address. Coordinates make the weather
# panel exact; a hand-written {"name": "Malibu"} alone works too.
#
# (no args) the current location: the stored name, or the
# IP-detected city when nothing is set
# --set <name> [lat,lon] store a location
# --clear return to IP auto-detect
LOC_FILE="$HOME/.local/state/omarchy/settings/weather.json"
COORDS_PATTERN='^(-?[0-9]+(\.[0-9]+)?),(-?[0-9]+(\.[0-9]+)?)$'
case "${1:-}" in
"")
name=""
[[ -f $LOC_FILE ]] && name=$(jq -r '.name // "" | if type == "string" then . else "" end' "$LOC_FILE" 2>/dev/null)
if [[ -z $name ]]; then
name=$(curl -fsS --max-time 4 "https://wttr.in/?format=%l" 2>/dev/null)
name=${name%%,*}
fi
[[ -n $name ]] && echo "$name"
;;
--set)
[[ -n ${2:-} ]] || { echo "Usage: omarchy-weather-location --set <name> [lat,lon]" >&2; exit 1; }
if [[ -n ${3:-} ]]; then
[[ ${3} =~ $COORDS_PATTERN ]] || { echo "Invalid coordinates: $3 (expected lat,lon)" >&2; exit 1; }
location=$(jq -n --arg name "$2" --argjson latitude "${3%,*}" --argjson longitude "${3#*,}" '{$name, $latitude, $longitude}')
else
location=$(jq -n --arg name "$2" '{$name}')
fi
mkdir -p "$(dirname "$LOC_FILE")"
echo "$location" >"$LOC_FILE"
;;
--clear)
rm -f "$LOC_FILE"
;;
*)
echo "Usage: omarchy-weather-location [--set <name> [lat,lon]|--clear]" >&2
exit 1
;;
esac
+10 -3
View File
@@ -2,15 +2,22 @@
# omarchy:summary=Returns a formatted weather status string with temperature and wind speed.
weather=$(curl -fsS --max-time 4 "https://wttr.in?format=%l|%t|%w" 2>/dev/null | tr -d '\n')
place=$(omarchy-weather-location 2>/dev/null)
if [[ -z $place ]]; then
echo "Weather unavailable"
exit 1
fi
query=$(jq -rn --arg place "$place" '$place | @uri')
weather=$(curl -fsS --max-time 4 "https://wttr.in/${query}?format=%t|%w" 2>/dev/null | tr -d '\n')
if [[ -z $weather ]]; then
echo "Weather unavailable"
exit 1
fi
IFS='|' read -r place temperature wind <<< "$weather"
place=${place%%,*}
IFS='|' read -r temperature wind <<< "$weather"
place=${place^}
temperature=${temperature#+}