Imported from archive.

* Release 1.5.

* (all): Updated copyright notices for 2010.

* FAQ, INSTALL, LICENSE, README: Reformatted as ReStructuredText.

* FAQ: Updated to mention alternative sources for NOAA's stations
list, in case the recommended one is unavailable (thanks Celejar!).

* NEWS: Renamed to ChangeLog and refactored into GNU format.

* weather: Added some comment padding between the shebang line and
the copyright, so that distributions wishing to carry patches which
modify the interpreter path don't have to refresh them every year
when the copyright line changes in their context.

* weather, weather.1, weatherrc.5, weather.py: Added experimental
alert, atypes, aurl and zones options to support retrieval,
filtering and formatting of unexpired NWS severe weather advisories.

* weather.1, weatherrc.5: Minor cosmetic fixes to option
descriptions.

* weather.1, weatherrc.5, weather.py: Added imperial and metric
options to filter/convert display units (thanks to Andrew Carter for
this suggestion!).

* weather.py: Fixed a METAR parsing error which would trigger an
IndexError exception if the NWS didn't have a station description on
file (thanks to Celejar for reporting the bug!). Fixed METAR title
line parsing to look for human-readable city and state in the first
line--previous code stopped showing the city name after NWS made
slight format mods. Upped the version to 1.5.

* weatherrc: Additional PIE (Saint Petersburg, FL), PNC (Ponca City,
OK), and PNS (Pensacola, FL) aliases.
This commit is contained in:
Jeremy Stanley
2010-03-19 13:30:22 +00:00
parent 8349654b7c
commit 4d25a49d5a
9 changed files with 522 additions and 197 deletions

111
FAQ
View File

@@ -1,71 +1,68 @@
FREQUENTLY ASKED QUESTIONS ABOUT THE WEATHER UTILITY
======================================================
Frequently Asked Questions About the Weather Utility
======================================================
Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
Permission to use, copy, modify, and distribute this software is
granted under terms provided in the LICENSE file distributed with
this software.
:Copyright: (c) 2006-2010 Jeremy Stanley <fungi@yuggoth.org>. Permission to
use, copy, modify, and distribute this software is granted under
terms provided in the LICENSE file distributed with this software.
Table of Contents:
.. contents::
1. Can I help?
2. How do I figure out my local METAR station ID?
3. How do I figure out my local city name and state abbreviation?
4. I live outside the USA--can this be made to work for me
anyway?
5. Why do I get the wrong forecast when specifying -i or --id?
1. Can I help?
Sure! Bug reports and feature suggestions are always welcome, but
fixes and patches are of course preferred. Contact
fungi@yuggoth.org if desired, but please read this FAQ and the
included manuals for weather(1) and weatherrc(5) before asking
questions that might be answered therein. One big way anyone can
help is to provide me with some additional mappings of METAR
station ID, city name and state abbreviation for inclusion in the
default /etc/weatherrc file.
--------------
Sure! Bug reports and feature suggestions are always welcome, but fixes and
patches are of course preferred. Contact fungi@yuggoth.org if desired, but
please read this FAQ and the included manuals for weather(1) and weatherrc(5)
before asking questions that might be answered therein. One big way anyone can
help is to provide me with some additional mappings of METAR station ID, city
name and state abbreviation for inclusion in the default /etc/weatherrc file.
2. How do I figure out my local METAR station ID?
-------------------------------------------------
The list of stations is found at http://weather.noaa.gov/data/nsd_cccc.gz (it's
thousands of lines long, so I recommend keyword searching in your browser or
using grep(1) to find what you're looking for). From time to time, the
compression on their site seems to be failing, resulting in zero-byte files. If
you run into this issue, you can get uncompressed and zip-compressed versions
by replacing the "gz" suffix in the URL with "txt" or "zip" respectively. The
list can also be obtained from the following URLs in a pinch, though they are
not guaranteed to be up to date (thanks Celejar!):
The list of stations is found at
http://weather.noaa.gov/data/nsd_cccc.gz (it's thousands of lines
long, so I recommend keyword searching in your browser or using
grep(1) to find what you're looking for).
* http://www.rap.ucar.edu/weather/surface/stations.txt
* http://aviationweather.gov/adds/metars/stations.txt
3. How do I figure out my local city name and state abbreviation?
-----------------------------------------------------------------
The forecasts can be located starting from
http://weather.noaa.gov/pub/data/forecasts/city/ (choose the
state abbreviation to get to a list of cities in that state).
4. I live outside the USA--can this be made to work for me
anyway?
METAR station IDs can be found for cities and airports worldwide,
but forecast data is harder to come by. If you have any
recommendations of forecast data for other countries available in a
format like NOAA's, I will be happy to try and find a way to
integrate it into the weather utility, but I suspect that some
serious modification would be necessary given that the data is
likely to be published in a non-English language, requiring some
additional input from speakers of that language for how to handle
filtering and formatting of the text.
http://weather.noaa.gov/pub/data/forecasts/city/ (choose the state abbreviation
to get to a list of cities in that state).
4. I live outside the USA--can this be made to work for me anyway?
------------------------------------------------------------------
METAR station IDs can be found for cities and airports worldwide, but forecast
data is harder to come by. If you have any recommendations of forecast data for
other countries available in a format like NOAA's, I will be happy to try and
find a way to integrate it into the weather utility, but I suspect that some
serious modification would be necessary given that the data is likely to be
published in a non-English language, requiring some additional input from
speakers of that language for how to handle filtering and formatting of the
text.
5. Why do I get the wrong forecast when specifying -i or --id?
--------------------------------------------------------------
The -i or --id switch (or the id parameter in an alias definition), only tells
weather(1) what current conditions to retrieve. If you specify -f or --forecast
on the command line (or forecast=True in an alias) without providing a city
name and state abbreviation (-c/--city and -s/--st, or city and st in an alias)
and are seeing an actual forecast, then you probably have a default city and
state abbreviation set in your config. See question 3 above for information on
figuring out what city name and state abbreviation to use, and the manual for
weatherrc(5) for information on defining aliases.
The -i or --id switch (or the id parameter in an alias definition),
only tells weather(1) what current conditions to retrieve. If you
specify -f or --forecast on the command line (or forecast=True in
an alias) without providing a city name and state abbreviation
(-c/--city and -s/--st, or city and st in an alias) and are seeing
an actual forecast, then you probably have a default city and state
abbreviation set in your config. See question 3 above for
information on figuring out what city name and state abbreviation
to use, and the manual for weatherrc(5) for information on defining
aliases.
6. Where can I get a list of the NWS advisory zones for alerts?
---------------------------------------------------------------
The lists of advisory zones by region are found aggregated at
http://weather.noaa.gov/pub/data/zonecatalog.curr.tar (it's several thousand
files totalling well over a hundred thousand lines of text, so I recommend
downloading, unpacking and using a recursive grep(1) to find what you're
looking for).

79
INSTALL
View File

@@ -1,28 +1,28 @@
BASIC UNIX INSTALLATION INSTRUCTIONS FOR THE WEATHER UTILITY
==============================================================
Basic Unix Installation Instructions for the Weather Utility
==============================================================
Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
Permission to use, copy, modify, and distribute this software is
granted under terms provided in the LICENSE file distributed with
this software.
:Copyright: (c) 2006-2010 Jeremy Stanley <fungi@yuggoth.org>. Permission to
use, copy, modify, and distribute this software is granted under
terms provided in the LICENSE file distributed with this software.
.. contents::
PREREQUISITES
Prerequisites
-------------
You need the Python interpreter installed somewhere in your path (most modern
UNIX derivatives come with one already). If you need to get Python, it can be
obtained from http://www.python.org/ (but chances are your operating system at
least provides some sort of native package for it, which you should probably
install in whatever means is recommended by your OS vendor/distributor).
You need the Python interpreter installed somewhere in your path
(most modern UNIX derivatives come with one already). If you need to
get Python, it can be obtained from http://www.python.org/ (but
chances are your operating system at least provides some sort of
native package for it, which you should probably install in whatever
means is recommended by your OS vendor/distributor).
RUNNING IN PLACE
An easy way to try it out is to unpack the tarball and change to the
resulting directory:
Running in Place
----------------
An easy way to try it out is to unpack the tarball and change to the resulting
directory::
tar xzf weather-*.tar.gz
cd weather
cd weather-*
./weather --version
./weather --help
man ./weather.1
@@ -30,30 +30,27 @@ resulting directory:
./weather --forecast --no-conditions --city=charlotte --st=nc
./weather ord sea
...and so on. The weather utility, included Python module and
documentation are all fully functional when kept together in one
directory, if somewhat inconvenient.
...and so on. The weather utility, included Python module and documentation are
all fully functional when kept together in one directory, if somewhat
inconvenient.
INSTALLING THE UTILITY
The file named weather should be made executable and put somewhere
in your path (/usr/local/bin/ or ~/bin/ for example). Similarly,
weather.py needs to be somewhere in Python's include path. You can
see your Python interpreter's default include path by running:
Installing the Utility
----------------------
The file named weather should be made executable and put somewhere in your path
(/usr/local/bin/ or ~/bin/ for example). Similarly, weather.py needs to be
somewhere in Python's include path. You can see your Python interpreter's
default include path by running::
python -c "import sys ; print sys.path"
Configuration
-------------
The weatherrc file should go in /etc/ or you can save it in your home directory
as a dotfile (~/.weatherrc) to support user-specific alias configuration and
overrides of the global /etc/weatherrc file.
CONFIGURATION
The weatherrc file should go in /etc/ or you can save it in your
home directory as a dotfile (~/.weatherrc) to support user-specific
alias configuration and overrides of the global /etc/weatherrc file.
MANUALS
Optionally, the weather.1 and weatherrc.5 files can be placed in
sane locations for TROFF/NROFF manual files on your system (for
example, /usr/local/share/man/ or ~/man/).
Manuals
-------
Optionally, the weather.1 and weatherrc.5 files can be placed in sane locations
for TROFF/NROFF manual files on your system (for example, /usr/local/share/man/
or ~/man/).

37
LICENSE
View File

@@ -1,13 +1,28 @@
Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>
=================
Weather License
=================
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
The weather project employs the ISC license, a permissive free software license
written by the Internet Systems Consortium and functionally equivalent to the
2-clause BSD license. Initially used for the ISC's own software releases, it
has since become the preferred license of many projects (OpenBSD, for example).
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Copyright Notice
----------------
Copyright (c) 2006-2010 Jeremy Stanley <fungi@yuggoth.org>
Permission Notice
-----------------
Permission to use, copy, modify, and distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
Disclaimer
----------
The software is provided "as is" and the author disclaims all warranties with
regard to this software including all implied warranties of merchantability and
fitness. In no event shall the author be liable for any special, direct,
indirect, or consequential damages or any damages whatsoever resulting from
loss of use, data or profits, whether in an action of contract, negligence or
other tortious action, arising out of or in connection with the use or
performance of this software.

83
README
View File

@@ -1,53 +1,48 @@
GENERAL INFORMATION ABOUT THE WEATHER UTILITY
===============================================
General Information About the Weather Utility
===============================================
Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
Permission to use, copy, modify, and distribute this software is
granted under terms provided in the LICENSE file distributed with
this software.
:Copyright: (c) 2006-2010 Jeremy Stanley <fungi@yuggoth.org>. Permission to
use, copy, modify, and distribute this software is granted under
terms provided in the LICENSE file distributed with this software.
.. contents::
WHAT?
What?
-----
This command-line utility is intended to provide quick access to current
weather conditions and forecasts. Presently, it is capable of returning data
for localities throughout the USA by retrieving and formatting decoded METARs
(Meteorological Aerodrome Reports) from NOAA (the USA National Oceanic and
Atmospheric Administration) and forecasts from NWS (the USA National Weather
Service). The tool is written to function in the same spirit as other
command-line informational utilities like cal(1), calendar(1) and dict(1). It
can retrieve arbitrary weather data via specific command-line switches (station
ID, city, state), or aliases can be configured system wide and on a per-user
basis. It can be freely used and redistributed under the terms of a BSD-like
License.
This command-line utility is intended to provide quick access to
current weather conditions and forecasts. Presently, it is
capable of returning data for localities throughout the USA by
retrieving and formatting decoded METARs (Meteorological
Aerodrome Reports) from NOAA (the USA National Oceanic and
Atmospheric Administration) and forecasts from NWS (the USA
National Weather Service). The tool is written to function in the
same spirit as other command-line informational utilities like
cal(1), calendar(1) and dict(1). It can retrieve arbitrary weather
data via specific command-line switches (station ID, city, state),
or aliases can be configured system wide and on a per-user basis.
It can be freely used and redistributed under the terms of a
BSD-like License.
Why?
----
My girlfriend had a long commute to/from work and school, and often wanted to
check the weather both for home and her office. Unfortunately, starting a Web
browser, pulling up a weather site, entering multiple ZIP codes and waiting for
them to load is time-consuming for the marginally-impatient. Since she tended
to stay logged into a shell server most of the time, I figured I'd install a
quick command-line tool to retrieve weather info for her commute, but to my
surprise, a quick search turned up little that met my basic requirements:
* retrieve current data on-demand
* provide both current conditions and short-term forecasts
* simple, human-readable output
* easy to configure and use
* flexible command-line switches and options
WHY?
Where?
------
A tarball for the most recent version of the weather utility can be had here:
My girlfriend had a long commute to/from work and school, and
often wanted to check the weather both for home and her office.
Unfortunately, starting a Web browser, pulling up a weather site,
entering multiple ZIP codes and waiting for them to load is
time-consuming for the marginally-impatient. Since she tended to
stay logged into a shell server most of the time, I figured I'd
install a quick command-line tool to retrieve weather info for
her commute, but to my surprise, a quick search turned up little
that met my basic requirements:
* http://fungi.yuggoth.org/weather/src/
* retrieve current data on-demand
* provide both current conditions and short-term forecasts
* simple, human-readable output
* easy to configure and use
* flexible command-line switches and options
WHERE?
A tarball for the most recent version of the weather utility can
be had here:
http://fungi.yuggoth.org/weather/src/
Alternatively, Debian users can install the weather-util package
Alternatively, Debian and Ubuntu users can install the weather-util package
from any mirror.

58
weather
View File

@@ -1,10 +1,10 @@
#!/usr/bin/env python
# distributions may wish to edit the above to refer to a specific interpreter
# path, such as #!/usr/bin/python
# weather version 1.4, http://fungi.yuggoth.org/weather/
# Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
# Permission to use, copy, modify, and distribute this software is
# granted under terms provided in the LICENSE file distributed with
# this software.
# Copyright (c) 2006-2010 Jeremy Stanley <fungi@yuggoth.org>. Permission to
# use, copy, modify, and distribute this software is granted under terms
# provided in the LICENSE file distributed with this software.
"""Wrapper utility using the weather.py module."""
@@ -26,22 +26,52 @@ if get_bool("list"): print weather.list_aliases(selections.config)
# normal operation
else:
output = ""
for argument in selections.arguments:
if get_bool("conditions", argument):
print weather.get_metar(
if get_bool("conditions", argument) or not (
get_bool("alert", argument) or get_bool("forecast", argument)
):
partial = weather.get_metar(
id=get("id", argument),
verbose=get_bool("verbose", argument),
quiet=get_bool("quiet", argument),
headers=get("headers", argument),
murl=get("murl", argument)
)
if not get_bool("conditions", argument) \
or get_bool("forecast", argument):
print weather.get_forecast(
murl=get("murl", argument),
imperial=get_bool("imperial", argument),
metric=get_bool("metric", argument)
)
if partial: output += partial + "\n"
if get_bool("forecast", argument) or not (
get_bool("alert", argument) or get_bool("conditions", argument)
):
partial = weather.get_forecast(
city=get("city", argument),
st=get("st", argument),
verbose=get_bool("verbose", argument),
quiet=get_bool("quiet", argument),
flines=get("flines", argument),
furl=get("furl", argument)
)
furl=get("furl", argument),
imperial=get_bool("imperial", argument),
metric=get_bool("metric", argument)
)
if partial: output += partial + "\n"
if get_bool("alert", argument) or not (
get_bool("conditions", argument) or get_bool("forecast", argument)
):
alert_text = ""
for atype in get("atypes", argument).split(","):
for zone in get("zones", argument).split(","):
partial = weather.get_alert(
zone=zone,
verbose=get_bool("verbose", argument),
quiet=get_bool("quiet", argument),
atype=atype,
aurl=get("aurl", argument),
imperial=get_bool("imperial", argument),
metric=get_bool("metric", argument)
)
if partial: alert_text += partial + "\n"
if not alert_text: alert_text = "(no current alerts for your zones)\n"
output += alert_text
output = output.strip()
if output: print( output )

View File

@@ -1,5 +1,5 @@
.TH WEATHER 1 "July 13, 2008" "" \" -*- nroff -*-
\" Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
.TH WEATHER 1 "March 15, 2010" "" \" -*- nroff -*-
\" Copyright (c) 2006-2010 Jeremy Stanley <fungi@yuggoth.org>.
\" Permission to use, copy, modify, and distribute this software is
\" granted under terms provided in the LICENSE file distributed with
\" this software.
@@ -29,7 +29,16 @@ show program's version number and exit
.B \-h, \-\-help
show a help message and exit
.TP
.B \-cCITY, \-\-city=CITY
.B \-a, \-\-alert
include local alert notices
.TP
.B \-\-atypes=ATYPES
alert notification types to display
.TP
.B \-\-aurl=AURL
alert URL (including %atype% and %zone%)
.TP
.B \-c CITY, \-\-city=CITY
the city name (ex: "Raleigh Durham")
.TP
.B \-\-flines=FLINES
@@ -44,12 +53,18 @@ forecast URL (including %city% and %st%)
.B \-\-headers=HEADERS
the conditions headers to display
.TP
.B \-iID, \-\-id=ID
.B \-i ID, \-\-id=ID
the METAR station ID (ex: KRDU)
.TP
.B \-\-imperial
filter/convert for US/UK units
.TP
.B \-l, \-\-list
print a list of configured aliases
.TP
.B \-m, \-\-metric
filter/convert for metric units
.TP
.B \-\-murl=MURL
METAR URL (including %id%)
.TP
@@ -62,11 +77,14 @@ omit the local forecast (cancels \-f)
.B \-\-quiet
skip preambles and don't indent
.TP
.B \-sST, \-\-st=ST
.B \-s ST, \-\-st=ST
the state abbreviation (ex: NC)
.TP
.B \-v, \-\-verbose
show full decoded feeds (cancels \-q)
.TP
.B \-z ZONES, \-\-zones=ZONES
alert zones (ex: nc/ncc183,nc/ncz041)
.SH FILES
.B weather
may additionally obtain configuration data from a system\-wide

View File

@@ -1,12 +1,10 @@
# weather.py version 1.4, http://fungi.yuggoth.org/weather/
# Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
# Permission to use, copy, modify, and distribute this software is
# granted under terms provided in the LICENSE file distributed with
# this software.
# Copyright (c) 2006-2010 Jeremy Stanley <fungi@yuggoth.org>. Permission to
# use, copy, modify, and distribute this software is granted under terms
# provided in the LICENSE file distributed with this software.
"""Contains various object definitions needed by the weather utility."""
version = "1.4"
version = "1.5"
class Selections:
"""An object to contain selection data."""
@@ -46,24 +44,121 @@ def quote(words):
if words.find(" ") != -1: words = "\"" + words + "\""
return words
def titlecap(words):
"""Perform English-language title capitalization."""
words = words.lower().strip()
for separator in [" ", "-", "'"]:
newwords = []
wordlist = words.split(separator)
for word in wordlist:
if word:
newwords.append(word[0].upper() + word[1:])
words = separator.join(newwords)
end = len(words)
for prefix in ["Mac", "Mc"]:
position = 0
offset = len(prefix)
while position < end:
position = words.find(prefix, position)
if position == -1:
position = end
position += offset
import string
if position < end and words[position] in string.letters:
words = words[:position] \
+ words[position].upper() \
+ words[position+1:]
return words
def filter_units(line, units="imperial"):
"""Filter or convert units in a line of text between US/UK and metric."""
import re
# filter lines with both pressures in the form of "X inches (Y hPa)" or
# "X in. Hg (Y hPa)"
dual_p = re.match(
"(.* )(\d*(\.\d+)? (inches|in\. Hg)) \((\d*(\.\d+)? hPa)\)(.*)",
line
)
if dual_p:
preamble, in_hg, i_fr, i_un, hpa, h_fr, trailer = dual_p.groups()
if units == "imperial": line = preamble + in_hg + trailer
elif units == "metric": line = preamble + hpa + trailer
# filter lines with both temperatures in the form of "X F (Y C)"
dual_t = re.match(
"(.* )(\d*(\.\d+)? F) \((\d*(\.\d+)? C)\)(.*)",
line
)
if dual_t:
preamble, fahrenheit, f_fr, celsius, c_fr, trailer = dual_t.groups()
if units == "imperial": line = preamble + fahrenheit + trailer
elif units == "metric": line = preamble + celsius + trailer
# if metric is desired, convert distances in the form of "X mile(s)" to
# "Y kilometer(s)"
if units == "metric":
imperial_d = re.match(
"(.* )(\d+)( mile\(s\))(.*)",
line
)
if imperial_d:
preamble, mi, m_u, trailer = imperial_d.groups()
line = preamble + str(int(round(int(mi)*1.609344))) \
+ " kilometer(s)" + trailer
# filter speeds in the form of "X MPH (Y KT)" to just "X MPH"; if metric is
# desired, convert to "Z KPH"
imperial_s = re.match(
"(.* )(\d+)( MPH)( \(\d+ KT\))(.*)",
line
)
if imperial_s:
preamble, mph, m_u, kt, trailer = imperial_s.groups()
if units == "imperial": line = preamble + mph + m_u + trailer
elif units == "metric":
line = preamble + str(int(round(int(mph)*1.609344))) + " KPH" + \
trailer
# if imperial is desired, qualify given forcast temperatures like "X F"; if
# metric is desired, convert to "Y C"
imperial_t = re.match(
"(.* )(High |high |Low |low )(\d+)(\.|,)(.*)",
line
)
if imperial_t:
preamble, parameter, fahrenheit, sep, trailer = imperial_t.groups()
if units == "imperial":
line = preamble + parameter + fahrenheit + " F" + sep + trailer
elif units == "metric":
line = preamble + parameter \
+ str(int(round((int(fahrenheit)-32)*5/9))) + " C" + sep + trailer
# hand off the resulting line
return line
def sorted(data):
"""Return a sorted copy of a list."""
new_copy = data[:]
new_copy.sort()
return new_copy
def get_url(url):
def get_url(url, ignore_fail=False):
"""Return a string containing the results of a URL GET."""
import urllib2
try: return urllib2.urlopen(url).read()
except urllib2.URLError:
import sys, traceback
sys.stderr.write("weather: error: failed to retrieve\n " \
+ url + "\n " + \
traceback.format_exception_only(sys.exc_type, sys.exc_value)[0])
sys.exit(1)
if ignore_fail: return ""
else:
import sys, traceback
sys.stderr.write("weather: error: failed to retrieve\n " \
+ url + "\n " + \
traceback.format_exception_only(sys.exc_type, sys.exc_value)[0])
sys.exit(1)
def get_metar(id, verbose=False, quiet=False, headers=None, murl=None):
def get_metar(
id,
verbose=False,
quiet=False,
headers=None,
murl=None,
imperial=False,
metric=False
):
"""Return a summarized METAR for the specified station."""
if not id:
import sys
@@ -92,20 +187,92 @@ def get_metar(id, verbose=False, quiet=False, headers=None, murl=None):
headerlist = headers.lower().replace("_"," ").split(",")
output = []
if not quiet:
output.append("Current conditions at " \
+ lines[0].split(", ")[1] + " (" \
+ id.upper() +")")
title = "Current conditions at %s"
place = lines[0].split(", ")
if len(place) > 1:
place = "%s, %s (%s)" % (titlecap(place[0]), place[1], id.upper())
else: place = id.upper()
output.append(title%place)
output.append("Last updated " + lines[1])
for header in headerlist:
for line in lines:
if line.lower().startswith(header + ":"):
if line.endswith(":0"):
if line.endswith(":0") or line.endswith(":1"):
line = line[:-2]
if imperial: line = filter_units(line, units="imperial")
elif metric: line = filter_units(line, units="metric")
if quiet: output.append(line)
else: output.append(" " + line)
return "\n".join(output)
def get_forecast(city, st, verbose=False, quiet=False, flines="0", furl=None):
def get_alert(
zone,
verbose=False,
quiet=False,
atype=None,
aurl=None,
imperial=False,
metric=False
):
"""Return alert notice for the specified zone and type."""
if not zone:
import sys
sys.stderr.write("weather: error: zone required for alerts\n")
sys.exit(1)
if not atype: atype = "severe_weather_stmt"
if not aurl:
aurl = \
"http://weather.noaa.gov/pub/data/watches_warnings/%atype%/%zone%.txt"
aurl = aurl.replace("%ATYPE%", atype.upper())
aurl = aurl.replace("%Atype%", atype.capitalize())
aurl = aurl.replace("%atypE%", atype)
aurl = aurl.replace("%atype%", atype.lower())
aurl = aurl.replace("%ZONE%", zone.upper())
aurl = aurl.replace("%Zone%", zone.capitalize())
aurl = aurl.replace("%zonE%", zone)
aurl = aurl.replace("%zone%", zone.lower())
aurl = aurl.replace(" ", "_")
alert = get_url(aurl, ignore_fail=True).strip()
if alert:
if verbose: return alert
else:
lines = alert.split("\n")
muted = True
import calendar, re, time
valid_time = time.strftime("%Y%m%d%H%M")
#if not quiet: output = [ lines[3], lines[5] ]
#if not quiet: output = [ lines[8], lines[10] ]
#else: output = []
output = []
for line in lines:
if line.startswith("Expires:") and "Expires:"+valid_time > line:
return ""
if muted and line.find("...") != -1:
muted = False
if line == "$$" \
or line.startswith("LAT...LON") \
or line.startswith("TIME...MOT...LOC"):
muted = True
if line and not (
muted \
or line == "&&"
or re.match("^/.*/$", line) \
or re.match("^"+zone.split("/")[1][:3].upper()+".*", line)
):
if quiet: output.append(line)
else: output.append(" " + line)
return "\n".join(output)
def get_forecast(
city,
st,
verbose=False,
quiet=False,
flines="0",
furl=None,
imperial=False,
metric=False
):
"""Return the forecast for a specified city/st combination."""
if not city or not st:
import sys
@@ -131,6 +298,8 @@ def get_forecast(city, st, verbose=False, quiet=False, flines="0", furl=None):
flines = int(flines)
if not flines: flines = len(lines) - 5
for line in lines[5:flines+5]:
if imperial: line = filter_units(line, units="imperial")
elif metric: line = filter_units(line, units="metric")
if line.startswith("."):
if quiet: output.append(line.replace(".", "", 1))
else: output.append(line.replace(".", " ", 1))
@@ -149,6 +318,50 @@ def get_options(config):
import optparse
option_parser = optparse.OptionParser(usage=usage, version=verstring)
# the -a/--alert option
if config.has_option("default", "alert"):
default_alert = bool(config.get("default", "alert"))
else: default_alert = False
option_parser.add_option("-a", "--alert",
dest="alert",
action="store_true",
default=default_alert,
help="include local alert notices")
# the --atypes option
if config.has_option("default", "atypes"):
default_atypes = config.get("default", "atypes")
else:
default_atypes = \
"flash_flood/statement," \
+ "flash_flood/warning," \
+ "flash_flood/watch," \
+ "flood/coastal," \
+ "flood/statement," \
+ "flood/warning," \
+ "non_precip," \
+ "severe_weather_stmt," \
+ "special_weather_stmt," \
+ "thunderstorm," \
+ "tornado," \
+ "urgent_weather_message"
option_parser.add_option("--atypes",
dest="atypes",
default=default_atypes,
help="alert notification types to display")
# the --aurl option
if config.has_option("default", "aurl"):
default_aurl = config.get("default", "aurl")
else:
default_aurl = \
"http://weather.noaa.gov/pub/data/watches_warnings/%atype%/%zone%.txt"
option_parser.add_option("--aurl",
dest="aurl",
default=default_aurl,
help="alert URL (including %atype% and %zone%)")
# separate options object from list of arguments and return both
# the -c/--city option
if config.has_option("default", "city"):
default_city = config.get("default", "city")
@@ -213,6 +426,16 @@ def get_options(config):
default=default_id,
help="the METAR station ID (ex: KRDU)")
# the --imperial option
if config.has_option("default", "imperial"):
default_imperial = bool(config.get("default", "imperial"))
else: default_imperial = False
option_parser.add_option("--imperial",
dest="imperial",
action="store_true",
default=default_imperial,
help="filter/convert for US/UK units")
# the -l/--list option
option_parser.add_option("-l", "--list",
dest="list",
@@ -220,6 +443,16 @@ def get_options(config):
default=False,
help="print a list of configured aliases")
# the -m/--metric option
if config.has_option("default", "metric"):
default_metric = bool(config.get("default", "metric"))
else: default_metric = False
option_parser.add_option("-m", "--metric",
dest="metric",
action="store_true",
default=default_metric,
help="filter/convert for metric units")
# the --murl option
if config.has_option("default", "murl"):
default_murl = config.get("default", "murl")
@@ -277,7 +510,15 @@ def get_options(config):
default=default_verbose,
help="show full decoded feeds (cancels -q)")
# separate options object from list of arguments and return both
# the -z/--zones option
if config.has_option("default", "zones"):
default_zones = config.get("default", "zones")
else: default_zones = ""
option_parser.add_option("-z", "--zones",
dest="zones",
default=default_zones,
help="alert zones (ex: nc/ncc183,nc/ncz041)")
options, arguments = option_parser.parse_args()
return options, arguments

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
# Permission to use, copy, modify, and distribute this software is
# granted under terms provided in the LICENSE file distributed with
# this software.
# Copyright (c) 2006-2010 Jeremy Stanley <fungi@yuggoth.org>. Permission to
# use, copy, modify, and distribute this software is granted under terms
# provided in the LICENSE file distributed with this software.
[ABE]
City = Allentown
@@ -838,6 +837,11 @@ City = Peoria
ID = KPIA
St = IL
[PIE]
City = Saint Petersburg
ID = KPIE
St = FL
[PIH]
City = Pocatello
ID = KPIH
@@ -848,6 +852,16 @@ City = Pittsburgh
ID = KPIT
St = PA
[PNC]
City = Ponca City
ID = KPNC
St = OK
[PNS]
City = Pensacola
ID = KPNS
St = FL
[PQI]
City = Presque Isle
ID = KPQI

View File

@@ -1,5 +1,5 @@
.TH WEATHERRC 5 "July 13, 2008" "" \" -*- nroff -*-
\" Copyright (c) 2006-2008 Jeremy Stanley <fungi@yuggoth.org>.
.TH WEATHERRC 5 "March 15, 2010" "" \" -*- nroff -*-
\" Copyright (c) 2006-2010 Jeremy Stanley <fungi@yuggoth.org>.
\" Permission to use, copy, modify, and distribute this software is
\" granted under terms provided in the LICENSE file distributed with
\" this software.
@@ -19,6 +19,15 @@ Multi-word values do not need quoting.
.SH PARAMETERS
These parameters are supported...
.TP
.B alert
include local alert notices
.TP
.B atypes
alert notification types to display
.TP
.B aurl
alert URL (including %atype% and %zone%)
.TP
.B city
the city name (ex: Raleigh Durham)
.TP
@@ -40,6 +49,12 @@ the conditions headers to display (ex: temperature,wind)
.B id
the METAR station ID (ex: KRDU)
.TP
.B imperial
filter/convert for US/UK units
.TP
.B metric
filter/convert for metric units
.TP
.B murl
METAR URL (ex: http://metar.org/%id%.txt)
.TP
@@ -51,6 +66,9 @@ the state abbreviation (ex: NC)
.TP
.B verbose
show full decoded feeds (possible values are False and True or 0 and 1)
.TP
.B zones
alert zones (ex: nc/ncc183,nc/ncz041)
.SH URL FORMAT
The placeholders %city% and %st% in the furl URL and %id% in the murl URL
will be replaced with the city, st and id definitions respectively. If the