aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DEPENDENCIES6
-rw-r--r--README40
-rwxr-xr-xmetar97
3 files changed, 128 insertions, 15 deletions
diff --git a/DEPENDENCIES b/DEPENDENCIES
new file mode 100644
index 0000000..845ac8b
--- /dev/null
+++ b/DEPENDENCIES
@@ -0,0 +1,6 @@
+sh
+sed
+curl
+coreutils
+python3
+
diff --git a/README b/README
index 9427d94..a7d5e3f 100644
--- a/README
+++ b/README
@@ -10,47 +10,57 @@ SYNOPSIS
DESCRIPTION
metar is a simple utility for find whether stations (hence referred to
- as METAR stations,) get and raw METAR reports. Most METAR stations are
+ as METAR stations,) and get METAR reports. Most METAR stations are
airports.
ACTIONS
get
Gets the most recent weather report from the selected METAR
station. The first line in the report will contain the station's
- name, country, code, and location.
+ name, country, ICAO station identifier, and location. There are
+ however some station there this information is missing.
print
- Print the code of the selected METAR station, the station
- from which weather reports are retrieved. This is equivalent
- to running
+ Print the ICAO station identifier of the selected METAR station,
+ the station from which weather reports are retrieved. This is
+ equivalent to running
(cat ~/.config/metar || cat /etc/metar) 2> /dev/null | head -n 1
set STATION
Stores the STATION as the METAR station from which weather
reports shall be retrieved. STATION shall be the stations's
- code. This is equivalent to running
+ ICAO station identifier. This is equivalent to running
echo STATION > ~/.config/metar
- list
+ list [PREFIX]
Print all METAR stations. This can take a very long time. You
- are strongly encouraged to store the output to a file.
+ are strongly encouraged to store the output to a file. For a,
+ not as good, list you can look at
+ http://www.aviationweather.gov/static/adds/metars/stations.txt
+
+ To speed up the listing process, you can filter the output
+ by select the PREFIX of the ICAO station identifiers. If you
+ look at the page with the URL above, you will find the prefix
+ for your country. PREFIX may be a regular expression.
Each station is will be printed on a line, containing the its
- name, country, code, and location. The code is in parenthesis.
+ name, country, ICAO station identifier, and location. The
+ ICAO station identifier is in parenthesis.
closest LATITUDE LONGITUDE [LIST]
Given a LATITUDE and LONGITUDE in decimal format, print the
- code of the closest METAR station. If you have already created
- a list of all stations using the action list, specify the
- filename of that list as the LIST argument.
+ ICAO station identifier of the closest METAR station. If you
+ have already created a list of all stations using the action
+ list, specify the filename of that list as the LIST argument.
FILES
~/.config/metar
- Contains a the code for the selected weather station, and
- nothing else, except an LF at the end. This will never change.
- Other programs are encouraged to use this file too.
+ Contains the ICAO station identifier for the selected weather
+ station, and nothing else, except an LF at the end. This will
+ never change. Other programs are encouraged to use this file
+ too.
If the file contains more than one line, only the first line,
even if it is empty, is used.
diff --git a/metar b/metar
new file mode 100755
index 0000000..ed3527d
--- /dev/null
+++ b/metar
@@ -0,0 +1,97 @@
+#!/bin/sh
+
+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"
+}
+
+list_stations ()
+{
+ file="$(mktemp)"
+ if test -z "$file"; then
+ exit 1
+ fi
+ if ! curl -s "http://weather.noaa.gov/pub/data/observations/metar/decoded/" > "$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 "http://weather.noaa.gov/pub/data/observations/metar/decoded/${icao}.TXT" | 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="$(echo "$latitude" | grep 'S' > /dev/null; echo $?)"
+ east="$(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 "http://weather.noaa.gov/pub/data/observations/metar/decoded/$(get_station).TXT" || 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 $# = 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
+