You are not logged in.

#1 2016-03-06 18:46:23

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,743

Weather Underground

I have been displeased with the state of CLI weather programs of late (since weatherman broke when the underlying API changed).  As there are clearly not enough of these darn tings, I bring you another.

This program, written in Python, will fetch weather from the Weather Underground ( http://www.wunderground.com/ )  Disclaimer. I have no affiliation with Weather Underground.   
EDIT:  See post #4 for an improved version of this code

#! /usr/bin/python
"""
Obtain cuurent weather from Weather Underground

    Copyright 2015 Eric Waller

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""


from urllib.request import urlopen
import json
import time
import shelve
import os

logger = None

class Weather:

    # Define the fields of interest.  Each field is a tuple of four items -- (1) a tuple that defines a path to the field, (2) an string prefix
    # that is printed before the field value,  (3) a string that is printed after the field value and (4) a flag that, if not None,
    # is a string that defines whether the field is valid for imperial or metric units. .

    # The tuple that defines the key path (first item in the field)
    # defines the path (tree) of keys for the field of interest.  The size of the tuples  for the keys
    # are variable in length as this json scheme uses multiple layers of hierarchical dictionaries.
    # All of the entries are keys that point to dictionaries with the
    # exception of the last, which is a key to a string, int, float, in the second to last dictionary.
    
    fields=[ ( ('current_observation','display_location','full') ,'Location : '   ,'\n'      ,None),
             ( ('current_observation','local_time_rfc822')       ,''              ,'\n'      ,None),
             ( ('current_observation','weather')                 ,'Condition : '  ,'\n'      ,None),
             ( ('current_observation','temperature_string')      ,'Temperature :' ,'\n'      ,None), 
             ( ('current_observation','relative_humidity')       ,'Humidity :'    ,' / '     ,None),
             ( ('current_observation','dewpoint_string')         ,'Dewpoint :'    ,'\n'      ,None), 
             ( ('current_observation','pressure_in')             ,'Pressure :'    ,' in hg. ','imperial'),
             ( ('current_observation','pressure_mb')             ,'Pressure :'    ,' mb '    ,'metric'),
             ( ('current_observation','pressure_trend')          ,'Trend '        ,'\n'      ,None),
             ( ('current_observation','visibility_mi')           ,'Visibility :'  ,'mi\n'    ,'imperial'),
             ( ('current_observation','visibility_km')           ,'Visibility :'  ,'km\n'    ,'metric'),
             ( ('current_observation','wind_dir')                ,'Wind: '        , ''       ,None),
             ( ('current_observation','wind_mph')                ,' @ '           ,' mph\n'  ,'imperial'),
             ( ('current_observation','wind_kph')                ,' @ '           ,' kph\n'  ,'metric'),
             ( ('current_observation','precip_today_string')     ,'precip :'      ,'\n'      ,None),
             ( ('moon_phase','phaseofMoon')                      ,'Moon : '       ,''        ,None), 
             ( ('moon_phase','percentIlluminated')               ,' '             ,'%\n'     ,None),
             ( ('sun_phase','sunrise','hour')                    ,'Sunrise : '    ,''        ,None), 
             ( ('sun_phase','sunrise','minute')                  ,':'             ,' ; '     ,None),
             ( ('sun_phase','sunset','hour')                     ,'Sunset : '     ,''        ,None),
             ( ('sun_phase','sunset','minute')                   ,':'             ,'\n'      ,None)
           ]

    def __init__(self,theLocation,theKey,imperial):
        self.location=theLocation
        self.key=theKey
        self.imperial = imperial
        logger.print("location set to "+self.location)
        logger.print("Units are "+( "imperial" if self.imperial else "metric"))
        logger.print("Fetching weather data using API key "+self.key)
      
    def GetWeather(self):
        """ Get the json information for the current location 

        returns:  A dictionary of items in the json file
        """
        url='http://api.wunderground.com/api/'+self.key+'/conditions/astronomy/q/'+self.location+'.json'
        logger.print("Retrieving weather report from "+url)
        response =urlopen(url)
        theString = response.read().decode('utf-8')
        theDict= json.loads(theString)
        logger.print("json response received:"+theString)
        return (theDict)

    def PrintReport(self,theWeather):
        """Generate  a report of the current weather using 'interesting' json fields """

        logger.print("Generating report")
        for x in self.fields:
            theThing=theWeather
            for y in x[0]:
                theThing=theThing[y]
            if not type(theThing) is str:
                theThing=theThing.__str__()
            if not x[3] or (self.imperial and (x[3] == 'imperial')) or ((not self.imperial) and (x[3]=='metric')):
                print (x[1]+theThing,end=x[2])
        print("Weather data by Weather Underground\n(http://www.wunderground.com)")

class log:
    """ Tools for optionally logging data

        The rather than using 'print' for debugging, debug output are processed here
        where they may turned on or off by a parameter passed in at the time the class is
        instantiated. Messages sent here are time tied to the time the instance was created"""
    
    def __init__(self,enabled):
        self.enabled=enabled
        self.initialtime=time.time()
    def print(self,theData):
        if self.enabled:
            print ("{:0>9.7f} : ".format(time.time()-self.initialtime)+theData)

def main():
    global logger
    from argparse import ArgumentParser

    # the variable theParameters defines the command line options, where and how their data are stored, and define the relation
    # of the command line parameters to things that are stored in persistent storage. Element 0 is the member name in the ArgumentPaser object,
    # element 1 is the action, element 2 is the short option name, element 3 is the long option name,
    # element 4 is the key name for storage in theShelve (None implies the value is not stored) 
    # element 5 is the help string, and element 6 is the error message if the element is not set (None implies it is not required)
    theParameters=[
          ('verbose'  ,'store_true'  ,'-v','--verbose'  , None        ,"Generate debugging information"         ,None),
          ('api_key'  ,'store'       ,'-k','--key'      , 'APIkey'    ,"Set and store the API key"              ,"API key not set"),
          ('location' ,'store'       ,'-l','--location' , 'location'  ,"Set and store the location"             ,"Location not set"),
          ('units'    ,'store_true'  ,'-i','--imperial' , 'units'     ,"Set and store choice of Imperial units" ,"Units not set (Imperial/Metric)"),
          ('units'    ,'store_false' ,'-m','--metric'   , 'units'     ,"Set and store choice of Metric units"   ,"Units not set (Imperial/Metric)"),
        ]
    # open the persistent storage and create any missing keys
    
    theShelve = shelve.open(os.environ['HOME'] + '/.wunderground')
    for x in theParameters:
        if x[4]:
            if not x[4] in theShelve:
                theShelve[x[4]]=None

    # Handle all the command line nonsense. 
    # There are five options -- one is to set the location, one is to set the API key, two to set the
    # unit system that is desired, and one to enable verbose reporting.
    # Defaults come from persistent storage
    
    description = "Fetch weather from Weather Underground"
    parser = ArgumentParser(description=description)
    for x in theParameters:
        parser.add_argument(x[2],x[3], action=x[1], dest=x[0], help=x[5] , default = theShelve[x[4]] if x[4] else False)
    args = parser.parse_args()

    # Set up the log function and enable the output if the user wants it
    
    logger=log(args.verbose)

    # If anything needs to be updated in persistent storage, then do so.
    for x in theParameters:
        if x[4] != None:
            if theShelve[x[4]] != getattr(args,x[0]):
                theShelve[x[4]] = getattr(args,x[0])
                result = theShelve[x[4]]
                if type(result) != str:
                    result = result.__str__()
                logger.print('Persistent storage updated: '+x[4]+" set to "+ result)
                
    # If we have all the data we need, then proceed, die otherwise

    for x in theParameters:
        if x[4] != None:
            if  theShelve[x[4]] == None:
                parser.error(x[6])


    # Here is where the magic happens.
    
    weather = Weather(theShelve['location'],theShelve['APIkey'],theShelve['units'])
    theWeather = weather.GetWeather()
    weather.PrintReport(theWeather)

    logger.print("Done")
    theShelve.close()

if __name__ == "__main__":
    main()

Examples:

ewaller@turing ~/devel/python 1188 %./wunderground.py  -h
usage: wunderground.py [-h] [-v] [-k API_KEY] [-l LOCATION] [-i] [-m]

Fetch weather from Weather Underground

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose         Generate debugging information
  -k API_KEY, --key API_KEY
                        Set and store the API key
  -l LOCATION, --location LOCATION
                        Set and store the location
  -i, --imperial        Set and store choice of Imperial units
  -m, --metric          Set and store choice of Metric units
ewaller@turing ~/devel/python 1189 %./wunderground.py    
Location : Pasadena, CA
Sun, 06 Mar 2016 10:21:57 -0800
Condition : Mostly Cloudy
Temperature :57.0 F (13.9 C)
Humidity :77% / Dewpoint :50 F (10 C)
Pressure :29.98 in hg. Trend +
Visibility :10.0mi
Wind: East @ 0.0 mph
precip :1.52 in (39 mm)
Moon : Waning Crescent 7%
Sunrise : 6:14 ; Sunset : 17:53
Weather data by Weather Underground
(http://www.wunderground.com)
ewaller@turing ~/devel/python 1190 %./wunderground.py  -m
Location : Pasadena, CA
Sun, 06 Mar 2016 10:23:10 -0800
Condition : Mostly Cloudy
Temperature :57.2 F (14.0 C)
Humidity :79% / Dewpoint :51 F (10 C)
Pressure :1015 mb Trend +
Visibility :16.1km
Wind: SE @ 1.4 kph
precip :1.52 in (39 mm)
Moon : Waning Crescent 7%
Sunrise : 6:14 ; Sunset : 17:53
Weather data by Weather Underground
(http://www.wunderground.com)
ewaller@turing ~/devel/python 1191 %./wunderground.py  -l 91324
Location : Northridge, CA
Sun, 06 Mar 2016 10:23:21 -0800
Condition : Clear
Temperature :61.7 F (16.5 C)
Humidity :61% / Dewpoint :48 F (9 C)
Pressure :1015 mb Trend +
Visibility :16.1km
Wind: NNW @ 10.8 kph
precip :0.83 in (21 mm)
Moon : Waning Crescent 7%
Sunrise : 6:15 ; Sunset : 17:55
Weather data by Weather Underground
(http://www.wunderground.com)
ewaller@turing ~/devel/python 1192 %./wunderground.py  -m -v   
0.0000501 : location set to 91324
0.0000763 : Units are metric
0.0000925 : Fetching weather data using API key <REDACTED>
0.0001001 : Retrieving weather report from http://api.wunderground.com/api/<REDACTED>/conditions/astronomy/q/91324.json
0.3449099 : json response received:
{
  "response": {
  "version":"0.1",
  "termsofService":"http://www.wunderground.com/weather/api/d/terms.html",
  "features": {
  "conditions": 1
  ,
  "astronomy": 1
  }
	}
  ,	"current_observation": {
		"image": {
		"url":"http://icons.wxug.com/graphics/wu2/logo_130x80.png",
		"title":"Weather Underground",
		"link":"http://www.wunderground.com"
		},
		"display_location": {
		"full":"Northridge, CA",
		"city":"Northridge",
		"state":"CA",
		"state_name":"California",
		"country":"US",
		"country_iso3166":"US",
		"zip":"91324",
		"magic":"1",
		"wmo":"99999",
		"latitude":"34.24044037",
		"longitude":"-118.54892731",
		"elevation":"261.00000000"
		},
		"observation_location": {
		"full":"Northridge Center, Los Angeles, California",
		"city":"Northridge Center, Los Angeles",
		"state":"California",
		"country":"US",
		"country_iso3166":"US",
		"latitude":"34.232887",
		"longitude":"-118.539673",
		"elevation":"833 ft"
		},
		"estimated": {
		},
		"station_id":"KCALOSAN160",
		"observation_time":"Last Updated on March 6, 10:23 AM PST",
		"observation_time_rfc822":"Sun, 06 Mar 2016 10:23:22 -0800",
		"observation_epoch":"1457288602",
		"local_time_rfc822":"Sun, 06 Mar 2016 10:23:37 -0800",
		"local_epoch":"1457288617",
		"local_tz_short":"PST",
		"local_tz_long":"America/Los_Angeles",
		"local_tz_offset":"-0800",
		"weather":"Clear",
		"temperature_string":"61.7 F (16.5 C)",
		"temp_f":61.7,
		"temp_c":16.5,
		"relative_humidity":"60%",
		"wind_string":"From the WNW at 4.5 MPH Gusting to 7.4 MPH",
		"wind_dir":"WNW",
		"wind_degrees":286,
		"wind_mph":4.5,
		"wind_gust_mph":"7.4",
		"wind_kph":7.2,
		"wind_gust_kph":"11.9",
		"pressure_mb":"1015",
		"pressure_in":"29.99",
		"pressure_trend":"+",
		"dewpoint_string":"48 F (9 C)",
		"dewpoint_f":48,
		"dewpoint_c":9,
		"heat_index_string":"NA",
		"heat_index_f":"NA",
		"heat_index_c":"NA",
		"windchill_string":"NA",
		"windchill_f":"NA",
		"windchill_c":"NA",
		"feelslike_string":"61.7 F (16.5 C)",
		"feelslike_f":"61.7",
		"feelslike_c":"16.5",
		"visibility_mi":"10.0",
		"visibility_km":"16.1",
		"solarradiation":"149",
		"UV":"0.0","precip_1hr_string":"0.00 in ( 0 mm)",
		"precip_1hr_in":"0.00",
		"precip_1hr_metric":" 0",
		"precip_today_string":"0.83 in (21 mm)",
		"precip_today_in":"0.83",
		"precip_today_metric":"21",
		"icon":"clear",
		"icon_url":"http://icons.wxug.com/i/c/k/clear.gif",
		"forecast_url":"http://www.wunderground.com/US/CA/Northridge.html",
		"history_url":"http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=KCALOSAN160",
		"ob_url":"http://www.wunderground.com/cgi-bin/findweather/getForecast?query=34.232887,-118.539673",
		"nowcast":""
	}
		,	"moon_phase": {
		"percentIlluminated":"7",
		"ageOfMoon":"27",
		"phaseofMoon":"Waning Crescent",
		"hemisphere":"North",
		"current_time": {
		"hour":"10",
		"minute":"23"
		},
		"sunrise": {
		"hour":"6",
		"minute":"15"
		},
		"sunset": {
		"hour":"17",
		"minute":"55"
		},
		"moonrise": {
		"hour":"4",
		"minute":"28"
		},
		"moonset": {
		"hour":"15",
		"minute":"37"
		}
	},
	"sun_phase": {
		"sunrise": {
		"hour":"6",
		"minute":"15"
		},
		"sunset": {
		"hour":"17",
		"minute":"55"
		}
	}
}

0.3451507 : Generating report
Location : Northridge, CA
Sun, 06 Mar 2016 10:23:37 -0800
Condition : Clear
Temperature :61.7 F (16.5 C)
Humidity :60% / Dewpoint :48 F (9 C)
Pressure :1015 mb Trend +
Visibility :16.1km
Wind: WNW @ 7.2 kph
precip :0.83 in (21 mm)
Moon : Waning Crescent 7%
Sunrise : 6:15 ; Sunset : 17:55
Weather data by Weather Underground
(http://www.wunderground.com)
0.3453128 : Done
ewaller@turing ~/devel/python 1193 %
ewaller@turing ~/devel/python 1193 %./wunderground.py  -i -l 91104
Location : Pasadena, CA
Sun, 06 Mar 2016 10:23:10 -0800
Condition : Mostly Cloudy
Temperature :57.2 F (14.0 C)
Humidity :79% / Dewpoint :51 F (10 C)
Pressure :29.98 in hg. Trend +
Visibility :10.0mi
Wind: SE @ 0.9 mph
precip :1.52 in (39 mm)
Moon : Waning Crescent 7%
Sunrise : 6:14 ; Sunset : 17:53
Weather data by Weather Underground
(http://www.wunderground.com)
ewaller@turing

To use this program, you must obtain an API key from Weather Underground http://www.wunderground.com/weather/api/
The geolocation, choice of units, and api key are stored in persistent storage.  After they are entered once, they need not be entered from the CLI each time.
Note that the verbose option does expose the API key.  I have redacted mine in the sample outputs

To use this from conky, I use a helper script called getweather:

ewaller@turing ~/devel/python 1195 %cat ~/.weatherdata/getWeather 
#!/bin/bash 
~/devel/python/wunderground.py   > ~/.weatherdata/theWeather

ewaller@turing ~/devel/python 1196 %

and the following in my conkyrc

${color black}Weather :${execi 300 ~/.weatherdata/getWeather}
${exec cat ~/.weatherdata/theWeather}

This serves a static file most of the time.  That static file is updated every 5 minutes.

Look like this: http://i.imgur.com/QzU3XBr.jpg

Southern California finally got some rain big_smile
Enjoy

Edit:  Oh yeah, comments on the program or programming style are welcome

Last edited by ewaller (2016-03-09 16:09:18)


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Online

#2 2016-03-06 23:31:10

TheChickenMan
Member
From: United States
Registered: 2015-07-25
Posts: 354

Re: Weather Underground

Oh that looks really interesting. I bet it would also work really well if you wanted to put something together that could keep logs of your past weather conditions. I'll have to save that and give it a try when I have some time. Thanks. The code looks good and readable to me but I'm not a python professional or anything.


If quantum mechanics hasn't profoundly shocked you, you haven't understood it yet.
Niels Bohr

Offline

#3 2016-03-07 16:03:37

karol
Archivist
Registered: 2009-05-06
Posts: 25,440

Re: Weather Underground

I'm using https://github.com/HalosGhost/shaman
I've cobbled together a script that prints a one-line summary of the forecast. I can prepend it with time and date and pipe it to 'tee' which in turn appends it to a file.

Offline

#4 2016-03-09 16:07:58

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,743

Re: Weather Underground

Here is an updated version I like better smile
Changed it to use native logging and refactor to use list comprehensions when rational

#! /usr/bin/python
"""
Obtain cuurent weather from Weather Underground

    Copyright 2015 Eric Waller

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""


from urllib.request import urlopen
import json
import time
import shelve
import os
import logging

class Weather:

    """
    Class for retrieving weather data from wunderground.com and printing those data
    """

    # Definition of the fields of interest.  Each field is a tuple of four items --
    #  (1) a tuple that defines a path to the field,
    #  (2) an string prefix that is printed before the field value,
    #  (3) a string that is printed after the field value and
    #  (4) a flag that, if not None, is a string that defines whether the
    #      field is valid for imperial or metric units. .

    # The tuple that defines the key path (first item in the field)
    # defines the path (tree) of keys for the field of interest.
    # The size of the tuples  for the keys are variable in length as
    # this json scheme uses multiple layers of hierarchical dictionaries.
    # All of the entries are keys that point to dictionaries with the
    # exception of the last, which is a key for something that is not a
    # dictionary (string, int, float,etc)


    fields=[ ( ('current_observation','display_location','full') ,'Location : '   ,'\n'      ,None),
             ( ('current_observation','local_time_rfc822')       ,''              ,'\n'      ,None),
             ( ('current_observation','weather')                 ,'Condition : '  ,'\n'      ,None),
             ( ('current_observation','temperature_string')      ,'Temperature :' ,'\n'      ,None),
             ( ('current_observation','relative_humidity')       ,'Humidity :'    ,' / '     ,None),
             ( ('current_observation','dewpoint_string')         ,'Dewpoint :'    ,'\n'      ,None),
             ( ('current_observation','pressure_in')             ,'Pressure :'    ,' in hg. ','imperial'),
             ( ('current_observation','pressure_mb')             ,'Pressure :'    ,' mb '    ,'metric'),
             ( ('current_observation','pressure_trend')          ,'Trend '        ,'\n'      ,None),
             ( ('current_observation','visibility_mi')           ,'Visibility :'  ,'mi\n'    ,'imperial'),
             ( ('current_observation','visibility_km')           ,'Visibility :'  ,'km\n'    ,'metric'),
             ( ('current_observation','wind_dir')                ,'Wind: '        , ''       ,None),
             ( ('current_observation','wind_mph')                ,' @ '           ,' mph\n'  ,'imperial'),
             ( ('current_observation','wind_kph')                ,' @ '           ,' kph\n'  ,'metric'),
             ( ('current_observation','precip_today_string')     ,'precip :'      ,'\n'      ,None),
             ( ('moon_phase','phaseofMoon')                      ,'Moon : '       ,''        ,None),
             ( ('moon_phase','percentIlluminated')               ,' '             ,'%\n'     ,None),
             ( ('sun_phase','sunrise','hour')                    ,'Sunrise : '    ,''        ,None),
             ( ('sun_phase','sunrise','minute')                  ,':'             ,' ; '     ,None),
             ( ('sun_phase','sunset','hour')                     ,'Sunset : '     ,''        ,None),
             ( ('sun_phase','sunset','minute')                   ,':'             ,'\n'      ,None)
           ]

    def __init__(self,theLocation,theKey,imperial):
        """
        Instanciate a weather object

        theLocation : a string representing the geolocation
        theKey      : a string representing the Weather Underground API key

        """

        self.location=theLocation
        self.key=theKey
        self.imperial = imperial
        logging.info("location set to "+self.location)
        logging.info("Units are "+( "imperial" if self.imperial else "metric"))
        logging.info("Fetching weather data using API key "+self.key)

    def GetWeather(self):
        """ Get the json information for the current location

        returns:  A dictionary of items in the json file
        """
        url='http://api.wunderground.com/api/'+self.key+'/conditions/astronomy/q/'+self.location+'.json'
        logging.info("Retrieving weather report from "+url)
        response =urlopen(url)
        theString = response.read().decode('utf-8')
        theDict= json.loads(theString)
        logging.debug("json response received:"+theString)
        return (theDict)

    def PrintReport(self,theWeather):
        """Generate  a report of the current weather using 'interesting' json fields

        theWeather : a dictionary of weather items (derived from the json report)
        Returns: None
        """

        logging.info("Generating report")
        for x in self.fields:
            theThing=theWeather
            for y in x[0]:
                theThing=theThing[y]
            if not type(theThing) is str:
                theThing=theThing.__str__()
            if not x[3] or (self.imperial and (x[3] == 'imperial')) or ((not self.imperial) and (x[3]=='metric')):
                print (x[1]+theThing,end=x[2])
        print("Weather data by Weather Underground\n(http://www.wunderground.com)")

def main():
    from argparse import ArgumentParser
    logFormat='%(relativeCreated)6dmS (%(threadName)s) %(levelname)s : %(message)s'

    # variable theParameters defines the command line options, where
    # and how their data are stored, and define the relation
    # of the command line parameters to things that are stored in
    # persistent storage.
    #
    #    Element 0 is the member name in the ArgumentPaser object,
    #    element 1 is the action,
    #    element 2 is the short option name,
    #    element 3 is the long option name,
    #    element 4 is the key name for storage in theShelve (None implies the value is not stored)
    #    element 5 is the help string, and
    #    element 6 is the error message if the element is not set (None implies it is not required)

    theParameters=[
          ('verbose'  ,'store_true'  ,'-v' ,'--verbose'  , None        ,"Generate information"                   ,None),
          ('debug'    ,'store_true'  ,'-d' ,'--debug'    , None        ,"Generate debugging information"         ,None),
          ('api_key'  ,'store'       ,'-k' ,'--key'      , 'APIkey'    ,"Set and store the API key"              ,"API key not set"),
          ('location' ,'store'       ,'-l' ,'--location' , 'location'  ,"Set and store the location"             ,"Location not set"),
          ('units'    ,'store_true'  ,'-i' ,'--imperial' , 'units'     ,"Set and store choice of Imperial units" ,"Units not set (Imperial/Metric)"),
          ('units'    ,'store_false' ,'-m' ,'--metric'   , 'units'     ,"Set and store choice of Metric units"   ,"Units not set (Imperial/Metric)"),
        ]

    # open the persistent storage and create any missing keys

    theShelve = shelve.open(os.environ['HOME'] + '/.wunderground')

    for x in  theParameters:
        if x[4] and  not x[4] in theShelve:
            theShelve[x[4]]=None

    # Handle all the command line nonsense.
    # There are six options -- one is to set the location, one is to set the API key, two to set the
    # unit system that is desired, and two to set verbose and debug level reporting.
    # Defaults come from persistent storage

    description = "Fetch weather from Weather Underground"
    parser = ArgumentParser(description=description)

    [ parser.add_argument(x[2],x[3],action=x[1],dest=x[0],help=x[5] ,
                          default = theShelve[x[4]] if x[4] else False )
                          for x in theParameters ]

    args = parser.parse_args()

    # Set up the log function and enable the output if the user wants it

    if (args.verbose):
        logging.basicConfig(level=logging.INFO, format=logFormat)
    if (args.debug):
        logging.basicConfig(level=logging.DEBUG, format=logFormat)

    # If anything needs to be updated in persistent storage, then do so.

    for x in theParameters:
        if x[4] != None and ( theShelve[x[4]] != getattr(args,x[0]) ):
            theShelve[x[4]] = getattr(args,x[0])
            result = theShelve[x[4]]
            if type(result) != str:
                result = result.__str__()
            logging.info('Persistent storage updated: '+x[4]+" set to "+ result)

    # If we have all the data we need, then proceed, die otherwise

    [parser.error(x[6]) for x in theParameters if x[4] != None  if  theShelve[x[4]] == None]

    # Here is where the magic happens.

    weather = Weather(theShelve['location'],theShelve['APIkey'],theShelve['units'])
    theWeather = weather.GetWeather()
    weather.PrintReport(theWeather)

    logging.info("Done")
    theShelve.close()

if __name__ == "__main__":
    main()

Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Online

#5 2016-05-15 22:44:28

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,743

Re: Weather Underground

I finally got around to making a package.

https://aur.archlinux.org/packages/wunderground/


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Online

Board footer

Powered by FluxBB