improve eww

This commit is contained in:
2026-09-10 19:54:50 +02:00
parent e551d36e1c
commit 7bb27f9373
46 changed files with 1296 additions and 1092 deletions
@@ -1,100 +1,106 @@
#!/usr/bin/env bash
# Weather from met.no for the IP-geolocated position. The last result is
# cached on disk, so re-opening the panel is instant and offline-safe; the
# network is hit at most every 10 minutes.
FALLBACK='{"temp":0,"feelslike":0,"humidity":0,"wind":0,"desc":"Unavailable","icon":"󰖐","city":""}'
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/eww"
LOC_CACHE="$CACHE_DIR/weather-location"
UA="eww-bar/1.0 cedric.hoelzl@gmail.com"
fallback='{"temp":0,"feelslike":0,"humidity":0,"wind":0,"desc":"Unavailable","icon":"󰖐","city":""}'
cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}/eww
loc_cache=$cache_dir/weather-location.json
wx_cache=$cache_dir/weather.json
interval=600
ua="eww-bar/1.0 cedric.hoelzl@gmail.com"
mkdir -p "$cache_dir"
mkdir -p "$CACHE_DIR"
fresh() { [[ -s $1 ]] && [[ -n $(find "$1" -mmin "-$2" 2>/dev/null) ]]; } # FILE MINUTES
get_location() {
# Cache location for 1 hour; IP rarely changes
if [ -f "$LOC_CACHE" ] && [ -n "$(find "$LOC_CACHE" -mmin -60 2>/dev/null)" ]; then
cat "$LOC_CACHE"
return 0
location() {
fresh "$loc_cache" 60 && { cat "$loc_cache"; return; }
local data
if data=$(curl -sf --max-time 5 "http://ip-api.com/json?fields=lat,lon,city"); then
printf '%s' "$data" | tee "$loc_cache"
elif [[ -s $loc_cache ]]; then
cat "$loc_cache"
else
return 1
fi
data=$(curl -sf --max-time 5 "http://ip-api.com/json?fields=lat,lon,city") || return 1
echo "$data" | tee "$LOC_CACHE"
}
icon_for() {
case "$1" in
*thunder*) echo "󰖔" ;;
*snow*|*sleet*) echo "󰖘" ;;
heavyrain*|*heavyrainshowers*) echo "󰖖" ;;
*rain*|*shower*) echo "󰖗" ;;
fog*) echo "󰖑" ;;
cloudy*) echo "󰖐" ;;
partlycloudy*) echo "󰖕" ;;
fair*|clearsky*) echo "󰖙" ;;
*) echo "󰖐" ;;
case $1 in
*thunder*) echo "󰖔" ;;
*snow* | *sleet*) echo "󰖘" ;;
heavyrain*) echo "󰖖" ;;
*rain* | *shower*) echo "󰖗" ;;
fog*) echo "󰖑" ;;
cloudy*) echo "󰖐" ;;
partlycloudy*) echo "󰖕" ;;
fair* | clearsky*) echo "󰖙" ;;
*) echo "󰖐" ;;
esac
}
desc_for() {
case "$(echo "$1" | sed 's/_day//;s/_night//;s/_polartwilight//')" in
clearsky) echo "Clear sky" ;;
fair) echo "Fair" ;;
partlycloudy) echo "Partly cloudy" ;;
cloudy) echo "Cloudy" ;;
fog) echo "Foggy" ;;
lightrain) echo "Light rain" ;;
rain) echo "Rain" ;;
heavyrain) echo "Heavy rain" ;;
lightrainshowers) echo "Light showers" ;;
rainshowers) echo "Rain showers" ;;
heavyrainshowers) echo "Heavy showers" ;;
lightrainandthunder) echo "Light rain & thunder" ;;
rainandthunder) echo "Rain & thunder" ;;
heavyrainandthunder) echo "Heavy rain & thunder" ;;
*showersandthunder) echo "Showers & thunder" ;;
lightsleet|lightsleetshowers) echo "Light sleet" ;;
sleet|sleetshowers) echo "Sleet" ;;
heavysleet|heavysleetshowers) echo "Heavy sleet" ;;
*sleetandthunder) echo "Sleet & thunder" ;;
lightsnow|lightsnowshowers) echo "Light snow" ;;
snow|snowshowers) echo "Snow" ;;
heavysnow|heavysnowshowers) echo "Heavy snow" ;;
*snowandthunder) echo "Snow & thunder" ;;
*) echo "$1" ;;
local c=$1
c=${c%_day}; c=${c%_night}; c=${c%_polartwilight}
case $c in
clearsky) echo "Clear sky" ;;
fair) echo "Fair" ;;
partlycloudy) echo "Partly cloudy" ;;
cloudy) echo "Cloudy" ;;
fog) echo "Foggy" ;;
lightrain) echo "Light rain" ;;
rain) echo "Rain" ;;
heavyrain) echo "Heavy rain" ;;
lightrainshowers) echo "Light showers" ;;
rainshowers) echo "Rain showers" ;;
heavyrainshowers) echo "Heavy showers" ;;
lightrainandthunder) echo "Light rain & thunder" ;;
rainandthunder) echo "Rain & thunder" ;;
heavyrainandthunder) echo "Heavy rain & thunder" ;;
*showersandthunder) echo "Showers & thunder" ;;
lightsleet | lightsleetshowers) echo "Light sleet" ;;
sleet | sleetshowers) echo "Sleet" ;;
heavysleet | heavysleetshowers) echo "Heavy sleet" ;;
*sleetandthunder) echo "Sleet & thunder" ;;
lightsnow | lightsnowshowers) echo "Light snow" ;;
snow | snowshowers) echo "Snow" ;;
heavysnow | heavysnowshowers) echo "Heavy snow" ;;
*snowandthunder) echo "Snow & thunder" ;;
*) echo "$c" ;;
esac
}
fetch() {
loc=$(get_location) || { echo "$FALLBACK"; return; }
lat=$(echo "$loc" | jq -r '.lat')
lon=$(echo "$loc" | jq -r '.lon')
city=$(echo "$loc" | jq -r '.city')
data=$(curl -sf --max-time 8 \
-H "User-Agent: $UA" \
-H "Accept: application/json" \
"https://api.met.no/weatherapi/locationforecast/2.0/compact?lat=$lat&lon=$lon") \
|| { echo "$FALLBACK"; return; }
d='.properties.timeseries[0].data'
temp=$( echo "$data" | jq -r "${d}.instant.details.air_temperature | round")
humidity=$(echo "$data" | jq -r "${d}.instant.details.relative_humidity | round")
wind_ms=$( echo "$data" | jq -r "${d}.instant.details.wind_speed")
wind=$( echo "$wind_ms" | awk '{printf "%d", $1 * 3.6}')
code=$( echo "$data" | jq -r \
"(${d}.next_1_hours.summary.symbol_code) // (${d}.next_6_hours.summary.symbol_code) // \"cloudy\"")
# Simplified apparent temperature: wind chill below 10°C, else = temp
feelslike=$(echo "$temp $wind" | awk '{
t=$1; v=$2
if (v > 4.8 && t < 10)
printf "%d", 13.12 + 0.6215*t - 11.37*(v^0.16) + 0.3965*t*(v^0.16)
else
printf "%d", t
}')
icon=$(icon_for "$code")
desc=$(desc_for "$code")
printf '{"temp":%s,"feelslike":%s,"humidity":%s,"wind":%s,"desc":"%s","icon":"%s","city":"%s"}\n' \
"$temp" "$feelslike" "$humidity" "$wind" "$desc" "$icon" "$city"
local loc lat lon city data temp humidity wind code feelslike
loc=$(location) || return 1
read -r lat lon city < <(jq -r '"\(.lat) \(.lon) \(.city)"' <<<"$loc")
data=$(curl -sf --max-time 8 -H "User-Agent: $ua" -H "Accept: application/json" \
"https://api.met.no/weatherapi/locationforecast/2.0/compact?lat=$lat&lon=$lon") || return 1
read -r temp humidity wind code < <(jq -r '
.properties.timeseries[0].data
| "\(.instant.details.air_temperature | round) \(.instant.details.relative_humidity | round) \(.instant.details.wind_speed * 3.6 | floor) \(.next_1_hours.summary.symbol_code // .next_6_hours.summary.symbol_code // "cloudy")"' <<<"$data")
[[ -n $temp ]] || return 1
# Apparent temperature: wind chill below 10 °C, otherwise the air temperature.
feelslike=$(awk -v t="$temp" -v v="$wind" 'BEGIN {
if (v > 4.8 && t < 10) printf "%d", 13.12 + 0.6215 * t - 11.37 * (v ^ 0.16) + 0.3965 * t * (v ^ 0.16)
else printf "%d", t }')
printf '{"temp":%s,"feelslike":%s,"humidity":%s,"wind":%s,"desc":"%s","icon":"%s","city":"%s"}' \
"$temp" "$feelslike" "$humidity" "$wind" "$(desc_for "$code")" "$(icon_for "$code")" "$(jstr "$city")"
}
fetch
while true; do sleep 600; fetch; done
refresh() {
local out
if fresh "$wx_cache" $((interval / 60)); then
emit "$(cat "$wx_cache")"
elif out=$(fetch); then
printf '%s\n' "$out" >"$wx_cache"
emit "$out"
elif [[ -s $wx_cache ]]; then
emit "$(cat "$wx_cache")"
else
emit "$fallback"
fi
}
refresh
while sleep "$interval"; do refresh; done