summaryrefslogtreecommitdiffstats
path: root/src/weather.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/weather.py43
1 files changed, 38 insertions, 5 deletions
diff --git a/src/weather.py b/src/weather.py
index 33e58ac..f0f0de3 100644
--- a/src/weather.py
+++ b/src/weather.py
@@ -18,11 +18,19 @@
from subprocess import Popen, PIPE
-def weather(station):
+def weather(station, downloader = None):
'''
Get a brief weather report
- @param station:str The station's International Civil Aviation Organization airport code
+ Airports should publish METAR (Meteorological Aerodrome Report) reports at XX:20 and XX:50,
+ it can presumable take some time before the collection server we use (weather.noaa.gov) have
+ received it. Additionally some airports do not update while closed, and updates while closed
+ are less accurate.
+
+ @param station:str The station's International Civil Aviation
+ Organization airport code
+ @param downloader:(url:str)?→list<str> A function that, with an URL as input, returns
+ a command to download the file at the URL to stdout
@return :(sky:str, visiblity:(:int, :float)?, weather:list<str>)?
The sky condition, visiblity and weather. Sky condition values include
‘clear’, ‘mostly clear’, ‘partly cloudy’, ‘mostly cloudy’, ‘overcast’
@@ -33,42 +41,67 @@ def weather(station):
be `None`. The weather is a list that can, and often is, empty. `None`
is return if observation data cannot be downloaded.
'''
+ ## URI of METAR
url = 'http://weather.noaa.gov/pub/data/observations/metar/decoded/%s.TXT'
url %= station.upper()
- proc = Popen(['wget', url, '-O', '-'], stdout = PIPE, stderr = PIPE)
+ ## Download METAR
+ # Use wget if not specified
+ if downloader is None:
+ downloader = lambda u : ['wget', u, '-O', '-']
+ proc = Popen(downloader(url), stdout = PIPE, stderr = PIPE)
+ ## Wait for download to finish and fetch output
output = proc.communicate()[0]
+ # Ignore output if it was not successful
if not proc.returncode == 0:
return None
+ ## Create field table from
output = output.decode('utf-8', 'replace').split('\n')
output = [line.lower().split(': ') for line in output if ': ' in line]
output = dict([(line[0], ': '.join(line[1:])) for line in output])
+ ## Get sky condition, assume clear (although often not) if omitted
sky_conditions = 'clear' if 'sky conditions' not in output else output['sky conditions']
+ ## Get visibility range
visibility = None
try:
if 'visibility' in output:
+ # Remove tail digit
visibility = output['visibility'].split(':')[0]
+ # Remove unit, it is always miles the decoded part
visibility = visibility.replace(' mile(s)', '')
visibility = visibility.replace(' miles', '')
visibility = visibility.replace(' mile', '')
+ # Range is assumed approximate if not specified
visibility_eq = 0
if visibility.startswith('greater than '):
+ # Range is a lower bound
visibility_eq = 1
visibility = visibility[len('greater than '):]
if visibility.startswith('less than '):
+ # Range is an upper bound
visibility_eq = -1
visibility = visibility[len('less than '):]
- if len(list(filter(lambda c : not (('0' <= c <= '9') or (c in ' /')), visibility))) == 0:
+ if len(list(filter(lambda c : not (('0' <= c <= '9') or (c in ' /.')), visibility))) == 0:
+ # Parse mixed numeral or decimal form
visibility = sum([eval(v) for v in visibility.split(' ')])
+ # Pack boundary information and range (converted to kilometers)
visibility = (visibility_eq, visibility * 1.609)
else:
visibility = None
except:
+ ## `eval` failed (probably)
visibility = None
+ ## Get weather
weather = '' if 'weather' not in output else output['weather']
+ ## Unify conjnuctions
weather = weather.replace(',', ';').replace(' with ', ';')
+ ## Remove undesired details
+ # Not important as we are not pilots, we are probably far away
weather = weather.replace(' in the vicinity', '')
- weather = weather.replace(' observed', '')
+ # Duration is not important for use either
weather = weather.replace(' during the past hour', '')
+ # Unimportant detail
+ weather = weather.replace(' observed', '')
+ ## Split at conjunction
weather = [w.replace(';', '').strip() for w in weather.split(';') if not w == '']
return (sky_conditions, visibility, weather)