#!/bin/bash # client version, calls server for actual API info usage() { cat <][-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 ST="$STATE" if [[ $(wc -c <<<"$STATE") -gt 4 ]] ; then ST=$(printf '%s.' $(head -c 4 <<<"$STATE")) fi # 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" "$ST" else # default printing printf "%.1f *$UNIT %d%% Humidity in %s, %s\n" $TEMPERATURE $HUMIDITY "$CITY" "$ST" 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