blob: 5d66e7b3e3bc17c47b88e53cf451b9367b0b7a82 (
plain) (
tree)
|
|
#!/bin/sh
set -e
metar_url ()
{
url="http://tgftp.nws.noaa.gov/data/observations/metar/decoded"
if test $# = 1; then
echo "${url}/${1}.TXT"
else
echo "${url}/"
fi
}
usage ()
{
echo "usage: $0 (get | print | set STATION | list [PREFIX] | closest [LATITUDE LONGITUDE] [LIST])"
}
get_station ()
{
icao=""
if test -f ~/.config/metar; then
icao="$(cat ~/.config/metar | head -n 1)"
elif test -f /etc/metar; then
icao="$(cat /etc/metar | head -n 1)"
fi
if test -z "$icao"; then
echo 'No METAR station has been selected.' >&2
exit 1
fi
echo "$icao"
}
get_location ()
{
geo=""
if test -f ~/.config/geolocation; then
geo="$(cat ~/.config/geolocation | head -n 1)"
geof=~/.config/geolocation
elif test -f /etc/geolocation; then
geo="$(cat /etc/geolocation | head -n 1)"
geof=/etc/geolocation
fi
if test -z "$geo"; then
echo 'No location has been specificed or configured.' >&2
exit 1
fi
if ! test $(printf '%s\n' $geo | wc -l) = 2; then
echo "Invalid geolocation configuration (${geof})." >&2
exit 1
fi
echo "$geo"
}
list_stations ()
{
file="$(mktemp)"
if test -z "$file"; then
exit 1
fi
if ! curl -s "$(metar_url)" > "$file"; then
unlink "$file"
exit 1
fi
list="$(sed -n 's/^.*<a href="\('"$1"'[A-Za-z0-9]*\)\.TXT">.*$/\1/p' "$file")"
unlink "$file"
for icao in $list; do
curl -s "$(metar_url "${icao}")" | head -n 1
done
}
get_closest ()
{
best=
grep ')' | while read line; do
icao="$(echo "$line" | cut -d ')' -f 1 | cut -d '(' -f 2)"
location="$(echo "$line" | cut -d ')' -f 2 | cut -d ' ' -f 2,3)"
latitude="$(echo "$location" | cut -d ' ' -f 1)"
longitude="$(echo "$location" | cut -d ' ' -f 2)"
north="$(set +e; echo "$latitude" | grep 'S' > /dev/null; echo $?)"
east="$(set +e; echo "$longitude" | grep 'W' > /dev/null; echo $?)"
latitude="$(echo "$latitude" | tr -d NSEW | sed 's/-/ /g')"
longitude="$(echo "$longitude" | tr -d NSEW | sed 's/-/ /g')"
best="$(python3 - $north "$latitude" $east "$longitude" "$1" "$2" "$icao" $best <<EOF
import sys, math
ploc = lambda ps : sum(float(p) / (60 ** i) for i, p in enumerate(ps))
haversin = lambda a : 0.5 - math.cos(a) / 2
lat = (+1 if sys.argv[1] == '1' else -1) * ploc(sys.argv[2].split(' '))
lon = (+1 if sys.argv[3] == '1' else -1) * ploc(sys.argv[4].split(' '))
rlat = float(sys.argv[5])
rlon = float(sys.argv[6])
icao = sys.argv[7]
best = None if len(sys.argv) == 8 else float(sys.argv[9])
ϕ1, λ1 = [c * math.pi / 180 for c in (lat, lon)]
ϕ2, λ2 = [c * math.pi / 180 for c in (rlat, rlon)]
h = haversin(ϕ2 - ϕ1) + math.cos(ϕ1) * math.cos(ϕ2) * haversin(λ2 - λ1)
d = 2 * 6367.5 * math.asin(h ** 0.5)
if best is None or d < best:
print('%s %f' % (icao, d))
else:
print(sys.argv[8] + ' ' + sys.argv[9])
EOF
)"
echo "$best"
done | tail -n 1 | cut -d ' ' -f 1
}
if test $# = 1 && test "$1" = "get"; then
curl -s "$(metar_url "$(get_station)")" || exit 1
elif test $# = 1 && test "$1" = "print"; then
get_station
elif test $# = 2 && test "$1" = "set"; then
echo "$2" > ~/.config/metar
elif test $# = 1 && test "$1" = "list"; then
list_stations ""
elif test $# = 2 && test "$1" = "list"; then
list_stations "$(echo "$2" | tr '[a-z]' '[A-Z]')"
elif test $# = 1 && test "$1" = "closest"; then
location="$(get_location)"
list_stations "" | get_closest $location
elif test $# = 2 && test "$1" = "closest"; then
location="$(get_location)"
get_closest $location < "$2"
elif test $# = 3 && test "$1" = "closest"; then
list_stations "" | get_closest "$2" "$3"
elif test $# = 4 && test "$1" = "closest"; then
get_closest "$2" "$3" < "$4"
else
usage
fi
|