107 lines
3.8 KiB
Bash
Executable File
107 lines
3.8 KiB
Bash
Executable File
#!/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.json
|
|
wx_cache=$cache_dir/weather.json
|
|
interval=600
|
|
ua="eww-bar/1.0 cedric.hoelzl@gmail.com"
|
|
mkdir -p "$cache_dir"
|
|
|
|
fresh() { [[ -s $1 ]] && [[ -n $(find "$1" -mmin "-$2" 2>/dev/null) ]]; } # FILE MINUTES
|
|
|
|
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
|
|
}
|
|
|
|
icon_for() {
|
|
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() {
|
|
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() {
|
|
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")"
|
|
}
|
|
|
|
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
|