#!/bin/bash # Current weather for xmobar, e.g. " 7°C": NOAA's decoded METAR (the source of xmobar's Weather plugin) # Icon from the weather, else the sky conditions; clear/partly/mostly cloudy get moon icons when the sun is down. # Temperature colors match the plugin's -L 0 -H 30: low up to 0, high above 30. # With "notify": show the description (e.g. "Light drizzle, mist") and temperature in a notification instead. STATION=LZIB LAT=48.2 LON=17.2 declare -A ICON=( [thermometer]=$'\xef\x8b\x89' [day_sunny]=$'\xee\x8c\x8d' [night_clear]=$'\xee\x8c\xab' [day_cloudy]=$'\xee\x8c\x82' [night_partly_cloudy]=$'\xee\x8d\xb9' [day_sunny_overcast]=$'\xee\x8c\x8c' [night_cloudy]=$'\xee\x8d\xbe' [cloudy]=$'\xee\x8c\x92' [cloud]=$'\xee\x8c\xbd' [thunderstorm]=$'\xee\x8c\x9d' [rain_mix]=$'\xee\x8c\x96' [snow]=$'\xee\x8c\x9a' [showers]=$'\xee\x8c\x99' [rain]=$'\xee\x8c\x98' [sprinkle]=$'\xee\x8c\x9b' [fog]=$'\xee\x8c\x93' [smoke]=$'\xee\x8d\x9c' [dust]=$'\xee\x8d\x9d' ) report=$(curl -sf --max-time 20 https://tgftp.nws.noaa.gov/data/observations/metar/decoded/"$STATION".TXT) temp=$(sed -n 's/^Temperature: .*(\([-0-9.]*\) C).*/\1/p' <<< "$report") if [[ -z $temp ]]; then if [[ $1 == notify ]]; then notify-send "Weather" "No report from $STATION"; else echo "${ICON[thermometer]} N/A"; fi exit 0 fi # Phenomena "in the vicinity" aren't at the station; the rest are e.g. "light drizzle; mist" wx=$(sed -n 's/^Weather: //p' <<< "$report" | tr ';' '\n' | sed 's/^ *//' | grep -v vicinity) wx=${wx,,} sky=$(sed -n 's/^Sky conditions: //p' <<< "$report") # CAVOK/NSC (no cloud below 5000 ft) have no sky line in the decoded report [[ -z $sky ]] && grep -qE '^ob: .* (CAVOK|NSC) ' <<< "$report" && sky=clear sky=${sky,,} # Sun above the horizon (elevation > -0.833°, as for sunrise/sunset) right now, from the low-precision solar position sun_up() { awk -v t="$(date +%s)" -v lat="$LAT" -v lon="$LON" 'BEGIN { r = atan2(0, -1) / 180; d = t / 86400 - 10957.5 g = (357.529 + 0.98560028 * d) * r l = (280.459 + 0.98564736 * d + 1.915 * sin(g) + 0.020 * sin(2 * g)) * r e = (23.439 - 0.00000036 * d) * r ra = atan2(cos(e) * sin(l), cos(l)); s = sin(e) * sin(l); dec = atan2(s, sqrt(1 - s * s)) h = (280.46061837 + 360.98564736629 * d + lon) * r - ra exit !(sin(lat * r) * sin(dec) + cos(lat * r) * cos(dec) * cos(h) > sin(-0.833 * r)) }' } case $wx in *thunder*) icon=thunderstorm ;; *freezing*|*sleet*|*ice\ pellets*|*hail*) icon=rain_mix ;; *snow*rain*|*rain*snow*|*snow*drizzle*|*drizzle*snow*) icon=rain_mix ;; *snow*) icon=snow ;; *showers*) icon=showers ;; *rain*) icon=rain ;; *drizzle*) icon=sprinkle ;; *fog*|*mist*) icon=fog ;; *haze*|*smoke*) icon=smoke ;; *dust*|*sand*) icon=dust ;; *) case $sky in clear*) if sun_up; then icon=day_sunny; else icon=night_clear; fi ;; "mostly clear"*|"partly cloudy"*) if sun_up; then icon=day_cloudy; else icon=night_partly_cloudy; fi ;; "mostly cloudy"*) if sun_up; then icon=day_sunny_overcast; else icon=night_cloudy; fi ;; overcast*|obscured*) icon=cloudy ;; *) icon=cloud ;; esac ;; esac if awk -v t="$temp" 'BEGIN { exit !(t > 30) }'; then color="#ffb86c" elif awk -v t="$temp" 'BEGIN { exit !(t > 0) }'; then color="#50fa7b" else color="#8be9fd" fi if [[ $1 == notify ]]; then if [[ -n $wx ]]; then desc=$(paste -sd, <<< "$wx" | sed 's/,/, /g') elif [[ $icon == day_sunny ]]; then desc=sunny else desc=${sky:-unknown} fi notify-send "${ICON[$icon]} Weather" "${desc^}, $temp°C" exit 0 fi echo "${ICON[$icon]} $temp°C"