summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2014-03-27 23:26:06 +0100
committerMattias Andrée <maandree@operamail.com>2014-03-27 23:26:06 +0100
commitbb5dfcd19312932113b678d78d2d1d34c70db3c1 (patch)
tree27356e10adeb4fee0795af6a491bd2c4416bb9cd
parentupdate todo (diff)
downloadblueshift-bb5dfcd19312932113b678d78d2d1d34c70db3c1.tar.gz
blueshift-bb5dfcd19312932113b678d78d2d1d34c70db3c1.tar.bz2
blueshift-bb5dfcd19312932113b678d78d2d1d34c70db3c1.tar.xz
doc + make it possible to select download command for weather
Signed-off-by: Mattias Andrée <maandree@operamail.com>
-rw-r--r--DEPENDENCIES2
-rw-r--r--TODO1
-rw-r--r--dist/archlinux/stable/PKGBUILD2
-rw-r--r--examples/comprehensive9
-rw-r--r--examples/weather7
-rw-r--r--info/blueshift.texinfo21
-rw-r--r--src/weather.py43
7 files changed, 72 insertions, 13 deletions
diff --git a/DEPENDENCIES b/DEPENDENCIES
index 7469f77..8585b54 100644
--- a/DEPENDENCIES
+++ b/DEPENDENCIES
@@ -20,7 +20,7 @@ RUNTIME DEPENDENCIES:
For permission-hasslefree backlight adjustments via sysfs
wget (optional)
- For weather conditions
+ For weather conditions, default command
MAKE DEPENDENCIES:
diff --git a/TODO b/TODO
index cb8277e..c440bf0 100644
--- a/TODO
+++ b/TODO
@@ -8,7 +8,6 @@ Medium priority:
Low priority:
Raw ramp applying functions with precalcuated interpolation, polynomial
- Add support for proxies such as Tor in weather
Add support for temporarily closing DRM connection so that multiple users can run in DRM
Add multi-display support (for example operating on two X display)
diff --git a/dist/archlinux/stable/PKGBUILD b/dist/archlinux/stable/PKGBUILD
index bd1f3f7..39d6fe2 100644
--- a/dist/archlinux/stable/PKGBUILD
+++ b/dist/archlinux/stable/PKGBUILD
@@ -10,7 +10,7 @@ license=('AGPL3' 'GPL3' 'custom:GFDL1.3')
depends=(python3 argparser libxcb libxxf86vm libx11 libdrm)
optdepends=('adjbacklight: for backlight adjustments without root requirements'
'linux: for backlight support'
- 'wget: for weather support')
+ 'wget: for weather support, default command')
makedepends=(cython gcc python3 libxcb libxxf86vm libx11 libdrm make coreutils sed zip texinfo auto-auto-complete)
install=blueshift.install
source=($url/archive/$pkgver.tar.gz)
diff --git a/examples/comprehensive b/examples/comprehensive
index b164212..96e3d96 100644
--- a/examples/comprehensive
+++ b/examples/comprehensive
@@ -82,6 +82,13 @@ def by_time():
return 1 # Error in `time_alpha` (probably)
+
+# Command used to download a file at an HTTP URL
+download_command = None
+# This is what if used if `None` is selected:
+# download_command = lambda url : ['wget', url, '-O', '-']
+
+
# Method for applying colour curves.
apply_curves = randr
#apply_curves = vidmode
@@ -318,7 +325,7 @@ def periodically(year, month, day, hour, minute, second, weekday, fade):
(metar, last_time) = (None, None) if last_metar is None else last_metar
now_time = minute
if (metar is None) or (now_time < last_time) or (last_time < now_time + 5):
- metar = weather(airport)
+ metar = weather(airport, download_command)
last_metar = (metar, now_time)
# Account for weather.
diff --git a/examples/weather b/examples/weather
index 78b826e..3fac3e4 100644
--- a/examples/weather
+++ b/examples/weather
@@ -26,6 +26,11 @@ latitude, longitude = 59.3326, 18.0652
# (Stockholm Bromma Airport in this example.)
airport = 'ESSB'
+# Command used to download a file at an HTTP URL
+download_command = None
+# This is what if used if `None` is selected:
+# download_command = lambda url : ['wget', url, '-O', '-']
+
# The colour temperature at day and at night.
temperature_day, temperature_night = 6500, 3700
@@ -47,7 +52,7 @@ visibility_max = 4
dayness = sun(latitude, longitude)
# Get weather report.
-metar = weather(airport)
+metar = weather(airport, download_command)
# Account for weather.
if metar is not None:
diff --git a/info/blueshift.texinfo b/info/blueshift.texinfo
index 7984afc..27c9dd8 100644
--- a/info/blueshift.texinfo
+++ b/info/blueshift.texinfo
@@ -1332,9 +1332,16 @@ astronomical twilight, measured in degrees.
Blueshift includes the function @code{whether}
which gives a brief weather report. @code{whether}
-takes one argument: the International Civil Aviation
-Organization (ICAO) code of your closest airport.
-If Blueshift is unable to download the latest METAR
+takes one manditory argument: the International
+Civil Aviation Organization (ICAO) code of your
+closest airport. It also takes one optional argument,
+@code{downloader}: an function that takes an URL
+to download as its only parameter and returns a
+command, as a list of arguments, that downloads
+the file at the given URL to standard output.
+The default @code{downloader} is
+@code{lambda url : ['wget', url, '-O', '-']}. If
+Blueshift is unable to download the latest METAR
(Meteorological Aerodrome Report) @code{whether}
will return @code{None}. If successful it will
return the sky conditions (assumed clear if not
@@ -1363,6 +1370,14 @@ approximate.
The weather is reported as an string list, that
can and often is empty.
+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.
+
@node Running without X
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)