ansiweather

Weather in terminal, with ANSI colors and Unicode symbols
Log | Files | Refs | README | LICENSE

ansiweather (11020B)


      1 #!/bin/sh
      2 
      3 #
      4 # AnsiWeather 1.18.0
      5 # Copyright (c) 2013-2021, Frederic Cambus
      6 # https://github.com/fcambus/ansiweather
      7 #
      8 # Created: 2013-08-29
      9 # Last Updated: 2021-09-14
     10 #
     11 # AnsiWeather is released under the BSD 2-Clause license.
     12 # See LICENSE file for details.
     13 #
     14 # SPDX-License-Identifier: BSD-2-Clause
     15 #
     16 
     17 ###[ Configuration options ]###################################################
     18 
     19 LC_ALL=C; export LC_ALL
     20 
     21 if [ -n "$ANSIWEATHERRC" ] ; then
     22 	config_file="$ANSIWEATHERRC"
     23 elif [ -s "$XDG_CONFIG_HOME"/ansiweather/config ] ; then
     24 	config_file="$XDG_CONFIG_HOME"/ansiweather/config
     25 elif [ -s "$HOME"/.config/ansiweather/config ] ; then
     26 	config_file="$HOME"/.config/ansiweather/config
     27 else
     28 	config_file=~/.ansiweatherrc
     29 fi
     30 
     31 get_config() {
     32 	ret=""
     33 	if [ -f "$config_file" ]
     34 	then
     35 		ret=$(grep "^$1:" "$config_file" | cut -d: -f2-)
     36 	fi
     37 
     38 	if [ "X$ret" = "X" ]
     39 	then
     40 		return 1
     41 	else
     42 		echo "$ret"
     43 	fi
     44 }
     45 
     46 fetch_cmd=$(get_config "fetch_cmd" || echo "curl -sf")
     47 
     48 
     49 
     50 ###[ Parse the command line ]##################################################
     51 
     52 # Get config options from command line flags
     53 while getopts l:u:f:FH:a:s:k:i:w:h:p:d:v option
     54 do
     55 	case "${option}"
     56 	in
     57 		l) location=${OPTARG};;
     58 		u) units=${OPTARG};;
     59 		f) forecast=${OPTARG};;
     60 		F) forecast="5";;
     61 		H) show_feels_like=${OPTARG};;
     62 		a) ansi=${OPTARG};;
     63 		s) symbols=${OPTARG};;
     64 		k) api_key=${OPTARG};;
     65 		i) show_uvi=${OPTARG};;
     66 		w) show_wind=${OPTARG};;
     67 		h) show_humidity=${OPTARG};;
     68 		p) show_pressure=${OPTARG};;
     69 		d) show_daylight=${OPTARG};;
     70 		v) echo "AnsiWeather 1.18.0" && exit 0;;
     71 		\?) exit 64;; # EX_USAGE
     72 	esac
     73 done
     74 
     75 
     76 
     77 ###[ Check if bc and jq are installed ]########################################
     78 
     79 jqpath=$(command -v jq)
     80 if [ "$jqpath" = "" ]
     81 then
     82 	echo "ERROR: Cannot find jq binary"
     83 	exit 69 # EX_UNAVAILABLE
     84 fi
     85 
     86 bcpath=$(command -v bc)
     87 if [ "$bcpath" = "" ]
     88 then
     89 	echo "ERROR: Cannot find bc binary"
     90 	exit 69 # EX_UNAVAILABLE
     91 fi
     92 
     93 
     94 
     95 ###[ Set options that are not set from command line ]##########################
     96 
     97 # OpenWeatherMap API key
     98 [ -z "$api_key" ] && api_key=$(get_config "api_key" || echo "85a4e3c55b73909f42c6a23ec35b7147")
     99 
    100 # Location: example "Rzeszow,PL"
    101 [ -z "$location" ] && location=$(get_config "location" || echo "Rzeszow,PL")
    102 
    103 # System of Units: "metric" or "imperial"
    104 [ -z "$units" ] && units=$(get_config "units" || echo "metric")
    105 
    106 # Show forecast: How many days, example "5". "0" is standard output
    107 [ -z "$forecast" ] && forecast=$(get_config "forecast" || echo 0)
    108 
    109 # Display ANSI colors: "true" or "false"
    110 [ -z "$ansi" ] && ansi=$(get_config "ansi" || echo true)
    111 
    112 # Display symbols: "true" or "false" (requires a Unicode capable display)
    113 [ -z "$symbols" ] && symbols=$(get_config "symbols" || echo false)
    114 
    115 # Show feels-like: "true" or "false"
    116 [ -z "$show_feels_like" ] && show_feels_like=$(get_config "show_feels_like" || echo false)
    117 
    118 # Show UVI: "true" or "false"
    119 [ -z "$show_uvi" ] && show_uvi=$(get_config "show_uvi" || echo true)
    120 
    121 # Show wind: "true" or "false"
    122 [ -z "$show_wind" ] && show_wind=$(get_config "show_wind" || echo true)
    123 
    124 # Show humidity: "true" or "false"
    125 [ -z "$show_humidity" ] && show_humidity=$(get_config "show_humidity" || echo true)
    126 
    127 # Show pressure: "true" or "false"
    128 [ -z "$show_pressure" ] && show_pressure=$(get_config "show_pressure" || echo true)
    129 
    130 # Show daylight: "true" or "false"
    131 [ -z "$show_daylight" ] && show_daylight=$(get_config "show_daylight" || echo false)
    132 
    133 dateformat=$(get_config "dateformat" || echo "%a %b %d")
    134 timeformat=$(get_config "timeformat" || echo "%b %d %r")
    135 
    136 
    137 
    138 ###[ Colors and characters ]###################################################
    139 
    140 background=$(get_config "background" || echo "\033[44m")
    141 text=$(get_config "text" || echo "\033[36;1m")
    142 data=$(get_config "data" || echo "\033[33;1m")
    143 delimiter=$(get_config "delimiter" || echo "\033[35m:")
    144 dashes=$(get_config "dashes" || echo "\033[34m-")
    145 
    146 
    147 
    148 ###[ Text Labels ]#############################################################
    149 
    150 greeting_text=$(get_config "greeting_text" || echo "Weather in")
    151 wind_text=$(get_config "wind_text" || echo "Wind")
    152 feels_like_text=$(get_config "feels_like_text" || echo "Feels like")
    153 humidity_text=$(get_config "humidity_text" || echo "Humidity")
    154 pressure_text=$(get_config "pressure_text" || echo "Pressure")
    155 sunrise_text=$(get_config "sunrise_text" || echo "Sunrise")
    156 sunset_text=$(get_config "sunset_text" || echo "Sunset")
    157 forecast_text=$(get_config "forecast_text" || echo "forecast")
    158 
    159 
    160 
    161 ###[ Unicode Symbols for icons ]###############################################
    162 
    163 sun=$(get_config "sun" || echo "\033[33;1m\xe2\x98\x80")
    164 moon=$(get_config "moon" || echo "\033[36m\xe2\x98\xbd")
    165 clouds=$(get_config "clouds" || echo "\033[37;1m\xe2\x98\x81")
    166 rain=$(get_config "rain" || echo "\033[37;1m\xe2\x98\x94")
    167 fog=$(get_config "fog" || echo "\033[37;1m\xe2\x96\x92")
    168 mist=$(get_config "mist" || echo "\033[34m\xe2\x96\x91")
    169 haze=$(get_config "haze" || echo "\033[33m\xe2\x96\x91")
    170 snow=$(get_config "snow" || echo "\033[37;1m\xe2\x9d\x84")
    171 thunderstorm=$(get_config "thunderstorm" || echo "\033[33;1m\xe2\x9a\xa1")
    172 
    173 
    174 
    175 ###[ Fetch Weather data ]######################################################
    176 
    177 api_cmd=$([ "$forecast" != 0 ] && echo "forecast/daily" || echo "weather")
    178 
    179 if [ "$location" -gt 0 ] 2> /dev/null
    180 then
    181 	# Location is all numeric
    182 	weather=$($fetch_cmd "https://api.openweathermap.org/data/2.5/$api_cmd?id=$location&units=$units&appid=$api_key")
    183 else
    184 	# Location is a string
    185 	location=$(echo "$location" | sed "s/ /%20/g")
    186 	weather=$($fetch_cmd "https://api.openweathermap.org/data/2.5/$api_cmd?q=$location&units=$units&appid=$api_key")
    187 fi
    188 
    189 if [ -z "$weather" ]
    190 then
    191 	echo "ERROR: Cannot fetch weather data"
    192 	exit 75 # EX_TEMPFAIL
    193 fi
    194 
    195 status_code=$(echo "$weather" | jq -r '.cod' 2>/dev/null)
    196 
    197 if [ "$status_code" != 200 ]
    198 then
    199 	echo "ERROR: Cannot fetch weather data for the given location"
    200 	exit 69 # EX_UNAVAILABLE
    201 fi
    202 
    203 
    204 
    205 ###[ Fetch UV data ]###########################################################
    206 
    207 if [ "$show_uvi" = true ] && [ "$forecast" = 0 ]
    208 then
    209 	lat=$(echo "$weather" | jq -r '.coord.lat')
    210 	lon=$(echo "$weather" | jq -r '.coord.lon')
    211 
    212 	uvdata=$($fetch_cmd "https://api.openweathermap.org/data/2.5/uvi?lat=$lat&lon=$lon&appid=$api_key")
    213 	uvi=$(echo "$uvdata" | jq -r '.value')
    214 fi
    215 
    216 
    217 
    218 ###[ Process Weather data ]####################################################
    219 
    220 epoch_to_date() {
    221 	if date -j -r "$1" +"%a %b %d" > /dev/null 2>&1; then
    222 		# BSD
    223 		ret=$(date -j -r "$1" +"$dateformat")
    224 	else
    225 		# GNU
    226 		ret=$(date -d "@$1" +"$dateformat")
    227 	fi
    228 	echo "$ret"
    229 }
    230 
    231 if [ "$forecast" != 0 ]
    232 then
    233 	city=$(echo "$weather" | jq -r '.city.name')
    234 	flength=$(echo "$weather" | jq '.list | length')
    235 	forecast=$([ "$forecast" -gt "$flength" ] && echo "$flength" || echo "$forecast")
    236 else
    237 	city=$(echo "$weather" | jq -r '.name')
    238 	temperature=$(echo "$weather" | jq '.main.temp' | xargs printf "%.0f")
    239 	humidity=$(echo "$weather" | jq '.main.humidity')
    240 	feels_like=$(echo "$weather" | jq '.main.feels_like' | xargs printf "%.0f")
    241 	pressure=$(echo "$weather" | jq '.main.pressure')
    242 	sky=$(echo "$weather" | jq -r '.weather[0].main')
    243 	sunrise=$(echo "$weather" | jq '.sys.sunrise')
    244 	sunset=$(echo "$weather" | jq '.sys.sunset')
    245 	wind=$(echo "$weather" | jq '.wind.speed')
    246 	azimuth=$(echo "$weather" | jq '.wind.deg')
    247 fi
    248 
    249 
    250 
    251 ###[ Process Wind data ]#######################################################
    252 
    253 set -- $(get_config "wind_directions" || echo "N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW")
    254 
    255 if [ "$forecast" = 0 ]
    256 then
    257 	shift "$(echo "scale=0; ($azimuth + 11.25)/22.5 % 16" | bc)"
    258 	direction=$1
    259 fi
    260 
    261 
    262 
    263 ###[ Process Sunrise and Sunset data ]#########################################
    264 
    265 epoch_to_time() {
    266 	if date -j -r "$1" +"%r" > /dev/null 2>&1; then
    267 		# BSD
    268 		ret=$(date -j -r "$1" +"$timeformat")
    269 	else
    270 		# GNU
    271 		ret=$(date -d "@$1" +"$timeformat")
    272 	fi
    273 	echo "$ret"
    274 }
    275 
    276 if [ "$forecast" = 0 ]
    277 then
    278 	if [ -n "$sunrise" ]
    279 	then
    280 		sunrise_time=$(epoch_to_time "$sunrise")
    281 	fi
    282 
    283 	if [ -n "$sunset" ]
    284 	then
    285 		sunset_time=$(epoch_to_time "$sunset")
    286 	fi
    287 fi
    288 
    289 
    290 
    291 ###[ Set the period ]##########################################################
    292 
    293 now=$(date +%s)
    294 
    295 if [ "$forecast" != 0 ]
    296 then
    297 	period="none"
    298 else
    299 	if [ -z "$sunset" ] || [ -z "$sunrise" ]
    300 	then
    301 		period="day"
    302 	elif [ "$now" -ge "$sunset" ] || [ "$now" -le "$sunrise" ]
    303 	then
    304 		period="night"
    305 	else
    306 		period="day"
    307 	fi
    308 fi
    309 
    310 
    311 
    312 ###[ Set the scale ]###########################################################
    313 
    314 case $units in
    315 	metric)
    316 		scale="°C"
    317 		speed_unit="m/s"
    318 		pressure_unit="hPa"
    319 		pressure=$(echo "$pressure" | xargs printf "%.0f")
    320 		;;
    321 	imperial)
    322 		scale="°F"
    323 		speed_unit="mph"
    324 		pressure_unit="inHg"
    325 		if [ "$forecast" = 0 ]
    326 		then
    327 			pressure=$(echo "$pressure*0.0295" | bc | xargs printf "%.2f")
    328 		fi
    329 		;;
    330 esac
    331 
    332 
    333 
    334 ###[ Set icons ]###############################################################
    335 
    336 get_icon() {
    337 	case $1 in
    338 		Clear)
    339 			if [ $period = "night" ]
    340 			then
    341 				echo "$moon "
    342 			else
    343 				echo "$sun "
    344 			fi
    345 			;;
    346 		Clouds)
    347 			echo "$clouds "
    348 			;;
    349 		Rain)
    350 			echo "$rain "
    351 			;;
    352 		Fog)
    353 			echo "$fog "
    354 			;;
    355 		Mist)
    356 			echo "$mist "
    357 			;;
    358 		Haze)
    359 			echo "$haze "
    360 			;;
    361 		Snow)
    362 			echo "$snow "
    363 			;;
    364 		Thunderstorm)
    365 			echo "$thunderstorm "
    366 			;;
    367 	esac
    368 }
    369 
    370 
    371 
    372 ###[ Display current Weather ]#################################################
    373 
    374 if [ "$forecast" != 0 ]
    375 then
    376 	output="$background$text $city $forecast_text$text$delimiter "
    377 
    378 	i=0
    379 	while [ $i -lt "$forecast" ]
    380 	do
    381 		day=$(echo "$weather" | jq ".list[$i]")
    382 		date=$(epoch_to_date "$(echo "$day" | jq -r '.dt')")
    383 		low=$(echo "$day" | jq -r '.temp.min' | xargs printf "%.0f")
    384 		high=$(echo "$day" | jq -r '.temp.max' | xargs printf "%.0f")
    385 
    386 		icon=""
    387 		if [ "$symbols" = true ]
    388 		then
    389 			sky=$(echo "$day" | jq -r '.weather[0].main')
    390 			icon=$(get_icon "$sky")
    391 		fi
    392 
    393 		output="$output$text$date$delimiter $data$high$text/$data$low $scale $icon"
    394 		if [ $i -lt $((forecast-1)) ]
    395 		then
    396 			output="$output$dashes "
    397 		fi
    398 
    399 		i=$((i + 1))
    400 	done
    401 else
    402 	if [ "$symbols" = true ]
    403 	then
    404 		icon="$(get_icon "$sky")"
    405 	fi
    406 	output="$background$text $greeting_text $city$delimiter$data $temperature $scale $icon"
    407 
    408         if [ "$show_feels_like" = true ]
    409         then
    410                 output="$output$dashes$text $feels_like_text$delimiter$data $feels_like $scale "
    411         fi
    412 
    413 	if [ "$show_uvi" = true ]
    414 	then
    415 		output="$output$dashes$text UVI$delimiter$data $uvi "
    416 	fi
    417 
    418 	if [ "$show_wind" = true ]
    419 	then
    420 		output="$output$dashes$text $wind_text$delimiter$data $wind $speed_unit $direction "
    421 	fi
    422 
    423 	if [ "$show_humidity" = true ]
    424 	then
    425 		output="$output$dashes$text $humidity_text$delimiter$data $humidity%% "
    426 	fi
    427 
    428 	if [ "$show_pressure" = true ]
    429 	then
    430 		output="$output$dashes$text $pressure_text$delimiter$data $pressure $pressure_unit "
    431 	fi
    432 
    433 	if [ "$show_daylight" = true ]
    434 	then
    435 		output="$output$dashes$text $sunrise_text$delimiter$data $sunrise_time $dashes$text $sunset_text$delimiter$data $sunset_time "
    436 	fi
    437 fi
    438 
    439 if [ "$ansi" = true ]
    440 then
    441 	env printf "$output\033[0m\n"
    442 else
    443 	env printf "$output\n" | sed "s/$(printf '\033')\[[0-9;]*m//g"
    444 fi