weather/client_weather.sh
KeeganForelight b0e8c10f0e bug fixes
2023-01-13 22:12:30 -05:00

326 lines
8.9 KiB
Bash
Executable File

#!/bin/bash
# client version, calls server for actual API info
usage() {
cat <<EOF
usage: $0 [-p][-s QUERY | -z ZIPCODE][-u <c|f>][-i][-h]
Queries OpenWeatherMapAPI for weather or lat/long
options:
-p, --pretty enables nerdfont symbols
-z, --zipcode returns the weather for ZIPCODE
-s, --search returns the weather for QUERY
-u, --units sets the temperature units
-i, --icon_test tests the icons used
-h, --help displays this message
ZIPCODE sets the location to the given zipcode
to narrow results, include the ISO country code
ex) -z "02139,US"
QUERY sets the location to the search
QUERY format is "CITY,REGION,COUNTRY" where
CITY is any city
REGION is Region or State
COUNTRY is ISO Country Code
to narrow results, try more specific searches
ex) -s "Cambridge" will return places in the UK
ex) -s "Cambridge,US" will return Cambridge, MA
EOF
exit $1
}
WORKING_DIR="$HOME/.local/share/weather"
WEATHER_FILE="$WORKING_DIR/.env"
WEATHER_CALL="ssh spinach@git.keegandeppe.com weather"
TIMEOUT=60 # timeout for info
TIME=$(date +%s)
if [[ ! -d "$WORKING_DIR" ]] ; then
mkdir -p "$WORKING_DIR"
fi
print_weather() {
# prints the weather
# check to see if it is expired
check_expiration
# trimming state
if [[ "$PRETTY" = true ]] ; then
# print with NF icons
icon=$(get_icon "$WEATHER_ICON")
# checking units
if [[ "$UNIT" == "C" ]] ; then
temp_icon=$(echo -e '\ufa03')
else
temp_icon=$(echo -e '\ufa04')
fi
# printing
printf '%s %.1f%s%d\ue373 in %s, %s\n' $icon $TEMPERATURE "$temp_icon" "$HUMIDITY" "$CITY" "$STATE"
else
# default printing
printf "%.1f *$UNIT %d%% Humidity in %s, %s\n" $TEMPERATURE $HUMIDITY "$CITY" "$STATE"
fi
# save before exiting
save_info
}
check_expiration() {
# checks if the info is expired
if [[ $TIME -gt $EXPIRATION ]] ; then
# expired
get_weather
fi
}
get_location() {
# searching for user location
if [[ -n "$QUERY" ]] ; then
# search
RESULTS=$($WEATHER_CALL $QUERY | gojq "del(.[].local_names)")
NUM_RESULTS=$(echo "$RESULTS" | gojq '. | length')
SELECTION=0
if [[ $NUM_RESULTS -gt 1 ]] ; then
# create menu for user
for ((i=0; i < $NUM_RESULTS; i++)); do
# adding options
res=$(echo "$RESULTS" | gojq ".[$i]")
name=$(echo "$res" | gojq '.name' | tr -d '"')
state=$(echo "$res" | gojq '.state' | tr -d '"')
country=$(echo "$res" | gojq '.country' | tr -d '"')
opt=$(printf '%s %s, %s' "$name" "$state" "$country")
OPTIONS+=($(($i+1)) "$opt")
done
# executing dialog menu
exec 3>&1
SELECTION=$(dialog \
--title 'Multiple Locations Found!' \
--clear \
--cancel-label 'Exit' \
--ok-label 'Select' \
--menu 'Please select the desired location. If none of the options look correct, try making refining your search by including a country code and/or region' 0 0 4 \
"${OPTIONS[@]}" \
2>&1 1>&3)
exit_status=$?
exec 3>&-
clear
if [[ $exit_status -eq 1 || $exit_satus -eq 255 ]] ; then
# canceled or escaped
echo "Try again: $0 -s 'CITY,REGION,COUNTRY'"
exit 0
fi
# fix index
SELECTION=$(($SELECTION - 1))
fi
# Update info
LAT=$(echo "$RESULTS" | gojq ".[$SELECTION].lat")
LON=$(echo "$RESULTS" | gojq ".[$SELECTION].lon")
CITY=$(echo "$RESULTS" | gojq ".[$SELECTION].name" | tr -d '"')
STATE=$(echo "$RESULTS" | gojq ".[$SELECTION].state" | tr -d '"')
else
# no search, default to user IP
url="http://ip-api.com/csv/?fields=252"
res=$(curl --silent -fL "$url")
LAT=$(awk -F , '{print $5}' <<<"$res")
LON=$(awk -F , '{print $6}' <<<"$res")
CITY=$(awk -F , '{print $3}' <<<"$res")
STATE=$(awk -F , '{print $1}' <<<"$res")
fi
# check
if [[ -z "$LAT" || -z "$LON" ]] ; then
echo "No location found!"
exit 1
fi
# force refresh
EXPIRED=0
}
get_weather() {
# calls server for weather based on $LAT, $LONG
if [[ -z "$LAT" || -z "$LON" ]] ; then
# no lat or lon
get_location
fi
# only update weather every 30 seconds
if [[ "$UNIT" =~ ^[Cc]$ ]] ; then
# units set to celsius
UNIT="C"
UNITS="metric"
else
# imperial
UNIT="F"
UNITS="imperial"
fi
WEATHER=$($WEATHER_CALL "-c $LAT,$LON -u $UNITS")
TEMPERATURE=$(echo $WEATHER | gojq -r '.main.temp')
HUMIDITY=$(echo $WEATHER | gojq -r '.main.humidity')
WEATHER_ICON=$(echo $WEATHER | gojq -r '.weather[0].icon')
EXPIRATION=$(($TIME+$TIMEOUT))
}
save_info() {
# saves set env vars to files
printf '%s\n' \
"LAT=$LAT" \
"LON=$LON" \
"CITY=$CITY" \
"STATE=$STATE" \
"TEMPERATURE=$TEMPERATURE" \
"HUMIDITY=$HUMIDITY" \
"WEATHER_ICON=$WEATHER_ICON" \
"EXPIRATION=$EXPIRATION" > "$WEATHER_FILE"
}
load_info() {
# loads env vars
if [[ ! -e "$WEATHER_FILE" ]] ; then
# generates blank info
save_info
fi
source $WEATHER_FILE
}
get_icon() {
# sets NF symbols
tod=$(echo "$1" | sed --expression='s/[0-9]//g')
conditions=$(echo "$1" | sed --expression='s/[^0-9]//g')
# getting icon
if [[ "$tod" == "d" ]] ; then
# day icons
case "$conditions" in
"01") echo -e '\ue30d' ;; # clear
"02") echo -e '\ue30c' ;; # scattered clouds
"03") echo -e '\ue302' ;; # broken clouds
"04") echo -e '\ue312' ;; # cloudy
"09") echo -e '\ue309' ;; # showers
"10") echo -e '\ue308' ;; # rain
"11") echo -e '\ue30f' ;; # thunderstorm
"13") echo -e '\uf2dc' ;; # snow
"50") echo -e '\ue303' ;; # mist
* ) echo -e '\ue374' ;; # unknown
esac
elif [[ "$tod" == "n" ]] ; then
# night icons
case "$conditions" in
"01") echo -e '\ue32b' ;; # clear
"02") echo -e '\ue379' ;; # scattered clouds
"03") echo -e '\ue37e' ;; # broken clouds
"04") echo -e '\ue312' ;; # cloudy
"09") echo -e '\ue326' ;; # showers
"10") echo -e '\ue325' ;; # rain
"11") echo -e '\ue32a' ;; # thunderstorm
"13") echo -e '\uf2dc' ;; # snow
"50") echo -e '\ue346' ;; # mist
* ) echo -e '\ue374' ;; # unknown
esac
else
echo "TOD not recognized"
exit 1
fi
}
icon_test() {
#tests icons
printf 'Testing weather icons\nIf any look broken, check that NerdFont is installed\n'
printf '\nDay:\n'
printf 'Clear: \ue30d\n'
printf 'Partly Cloudy: \ue30c\n'
printf 'Cloudy: \ue302\n'
printf 'Very Cloudy: \ue312\n'
printf 'Showers: \ue309\n'
printf 'Rain: \ue308\n'
printf 'Thunderstorm: \ue30f\n'
printf 'Snow: \uf2dc\n'
printf 'Fog: \ue303\n'
# night icons
printf '\nNight:\n'
printf 'Clear: \ue32b\n'
printf 'Partly Cloudy: \ue379\n'
printf 'Cloudy: \ue37e\n'
printf 'Very Cloudy: \ue312\n'
printf 'Showers: \uf2dc\n'
printf 'Rain: \ue325\n'
printf 'Thunderstorm: \ue32a\n'
printf 'Snow: \uf2dc\n'
printf 'Fog: \ue346\n'
printf '\nAssorted:\n'
printf 'Degrees (F) \ufa04\n'
printf 'Degrees (C) \ufa03\n'
printf '%% Humidity \ue373\n'
}
# shifting longform
for arg in "$@"; do
shift
case "$arg" in
'--zipcode') set -- "$@" "-z" ;;
'--coords') set -- "$@" "-c" ;;
'--search') set -- "$@" "-s" ;;
'--units') set -- "$@" "-u" ;;
'--pretty') set -- "$@" "-p" ;;
'--icon_test') set -- "$@" "-i" ;;
'--help') set -- "$@" "-h" ;;
*) set -- "$@" "$arg" ;;
esac
done
while getopts "chpiz:s:u:" opt; do
case "$opt" in
'u' )
UNIT="$OPTARG"
;;
'z' )
[ -n "$QUERY" ] && usage 1 || QUERY="-z $OPTARG"
;;
's' )
[ -n "$QUERY" ] && usage 1 || QUERY="-s $OPTARG"
;;
'p' )
PRETTY=true
;;
'i' )
icon_test
exit 0
;;
'h' )
usage 0
;;
'?' )
usage 1
;;
esac
done
load_info
if [[ -n "$QUERY" ]] ; then
# perform search
get_location
fi
# print the weather
print_weather