From bb5dfcd19312932113b678d78d2d1d34c70db3c1 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Thu, 27 Mar 2014 23:26:06 +0100 Subject: doc + make it possible to select download command for weather MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/weather.py | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) (limited to 'src') 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 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)? 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) -- cgit v1.2.3-70-g09d2