March 30, 2018

Weather report

Using OpenWeatherMap’s API it is possible to get JSON-encoded forecasts for my local area. I use jq and gnuplot to format the forecast into something that looks good in my terminal:

Here’s the script that pulls it all together:

#!/bin/sh

set -e

# Fill in location and api_key here
location=''
api_key=''
units=metric

[ ! -d "$HOME"/dl ] && mkdir "$HOME"/dl

fcast=$HOME/dl/forecast

get_weather() {
    curl -sfL -G 'http://api.openweathermap.org/data/2.5/forecast' \
        --data id="${location}" \
        --data units="${units}" \
        --data appid="${api_key}" \
        -o "${fcast}"
}

[ ! -f "${fcast}" ] && get_weather

time_now=$(date +"%s")

case $(uname) in
    Darwin | *BSD) mtime=$(stat -f "%m" "${fcast}") ;;
    Linux) mtime=$(stat -c "%Y" "${fcast}") ;;
esac

[ $((time_now - mtime)) -gt 3600 ] && get_weather

len=$(jq '.list | length' "${fcast}")

printf '\n'

for n in $(jot "$len" 0); do
    day=$(date -j -r "$(jq ".list | .[$n] | .dt" "${fcast}")" +"%A")
    hour=$(date -j -r "$(jq ".list | .[$n] | .dt" "${fcast}")" +"%H:%M")
    temp=$(jq -r ".list | .[$n] | .main | .temp" "${fcast}")
    press=$(jq -r ".list | .[$n] | .main | .pressure" "${fcast}")
    wspeed=$(jq -r ".list | .[$n] | .wind | .speed" "${fcast}")
    wdir=$(jq -r ".list | .[$n] | .wind | .deg" "${fcast}")
    rainfall=$(jq -r ".list | .[$n] | .rain | .\"3h\"" "${fcast}")
    {
        printf '\t%-11s' "${day}"
        printf '%5s' "${hour}"
        printf '%4.0f°C' "${temp}"
        printf '%6.0f hPa ' "${press}"
        # units returns an error if given a wind speed of zero
        if [ "${wspeed}" = 0 ]; then
            printf '%d Kn ' "0"
        else
            printf '%3.0f Kn ' "$(units "${wspeed} m/s" knots |
                sed q | sed 's/^\t\* //')"
        fi
        printf '%3.0f° ' "${wdir}"
        [ "${rainfall}" != null ] && printf '%4.2f mm/3h' "${rainfall}"
        printf '\n'
    }
done

jq -r '.list | .[] | .main | .pressure' "${fcast}" |
    sed 's/\.[0-9]\+$//' >"$HOME"/dl/pressure

gnuplot <<EOF
    set terminal dumb
    set ytics add ('' 0) scale 0
    unset xtics
    set title "5 day pressure forecast"
    plot "$HOME/dl/pressure" t "" pt "*"
EOF

The script is set up for metric data, so you’ll have to edit it if you’re using the imperial system. And you’ll need an API key (available free), along with a location code.