[weather] sync wunderground with repo
authorMartijn Kaijser <mcm.kaijser@gmail.com>
Wed, 14 Nov 2012 21:56:35 +0000 (22:56 +0100)
committerMartijn Kaijser <mcm.kaijser@gmail.com>
Wed, 14 Nov 2012 21:56:35 +0000 (22:56 +0100)
12 files changed:
addons/weather.wunderground/README.txt [new file with mode: 0644]
addons/weather.wunderground/addon.xml
addons/weather.wunderground/changelog.txt
addons/weather.wunderground/default.py
addons/weather.wunderground/resources/language/Belarusian/strings.po
addons/weather.wunderground/resources/language/English/strings.po
addons/weather.wunderground/resources/language/Spanish (Argentina)/strings.po [new file with mode: 0644]
addons/weather.wunderground/resources/lib/utilities.py
addons/weather.wunderground/resources/lib/wunderground/__init__.py [new file with mode: 0644]
addons/weather.wunderground/resources/lib/wunderground/wunderground.py [new file with mode: 0644]
addons/weather.wunderground/resources/logo/logo.jpg [new file with mode: 0644]
addons/weather.wunderground/resources/settings.xml

diff --git a/addons/weather.wunderground/README.txt b/addons/weather.wunderground/README.txt
new file mode 100644 (file)
index 0000000..39834e5
--- /dev/null
@@ -0,0 +1,187 @@
+---------------------------
+DEFAULT XBMC WEATHER LABELS
+---------------------------
+
+
+CURRENT
+-------
+Current.Location
+Current.Condition
+Current.Temperature
+Current.Wind
+Current.WindDirection
+Current.Humidity
+Current.FeelsLike
+Current.UVIndex
+Current.DewPoint
+Current.OutlookIcon
+Current.FanartCode
+
+
+DAY [0-6]
+---------
+Day%i.Title
+Day%i.HighTemp
+Day%i.LowTemp
+Day%i.Outlook
+Day%i.OutlookIcon
+Day%i.FanartCode
+
+
+WEATHERPROVIDER
+----------------
+WeatherProvider
+
+
+
+
+-------------------------
+ADDITIONAL WEATHER LABELS
+-------------------------
+
+
+FORECAST
+--------
+Forecast.IsFetched
+Forecast.City
+Forecast.State
+Forecast.Country
+Forecast.Updated
+
+
+CURRENT
+-------
+Current.IsFetched
+Current.WindDegree
+Current.SolarRadiation
+Current.Pressure
+Current.Precipitation
+Current.HeatIndex
+Current.WindChill
+Current.Visibility
+Current.WindGust
+
+
+TODAY
+-----
+Today.IsFetched
+Today.Sunrise
+Today.Sunset
+Today.MoonPhase
+Today.AvgHighTemperature
+Today.AvgLowTemperature
+Today.RecordHighTemperature
+Today.RecordLowTemperature
+Today.RecordHighYear
+Today.RecordLowYear
+
+
+DAILY [1-10]
+------------
+Daily.IsFetched
+Daily.%i.LongDay
+Daily.%i.ShortDay
+Daily.%i.LongDate
+Daily.%i.ShortDate
+Daily.%i.Outlook
+Daily.%i.OutlookIcon
+Daily.%i.FanartCode
+Daily.%i.WindSpeed
+Daily.%i.MaxWind
+Daily.%i.WindDirection
+Daily.%i.ShortWindDirection
+Daily.%i.WindDegree
+Daily.%i.Humidity
+Daily.%i.MinHumidity
+Daily.%i.MaxHumidity
+Daily.%i.HighTemperature
+Daily.%i.LowTemperature
+Daily.%i.LongOutlookDay
+Daily.%i.LongOutlookNight
+Daily.%i.Precipitation
+Daily.%i.Snow
+Daily.%i.ChancePrecipitation
+
+
+WEEKEND [1-3]
+-------------
+Weekend.IsFetched
+Weekend.%i.LongDay
+Weekend.%i.ShortDay
+Weekend.%i.LongDate
+Weekend.%i.ShortDate
+Weekend.%i.Outlook
+Weekend.%i.OutlookIcon
+Weekend.%i.FanartCode
+Weekend.%i.WindSpeed
+Weekend.%i.MaxWind
+Weekend.%i.WindDirection
+Weekend.%i.ShortWindDirection
+Weekend.%i.WindDegree
+Weekend.%i.Humidity
+Weekend.%i.MinHumidity
+Weekend.%i.MaxHumidity
+Weekend.%i.HighTemperature
+Weekend.%i.LowTemperature
+Weekend.%i.LongOutlookDay
+Weekend.%i.LongOutlookNight
+Weekend.%i.Precipitation
+Weekend.%i.Snow
+Weekend.%i.ChancePrecipitation
+
+
+36HOUR [1-3]
+------------
+36Hour.IsFetched
+36Hour.%i.Forecast
+36Hour.%i.TemperatureHeading
+36Hour.%i.Temperature
+36Hour.%i.Heading
+36Hour.%i.ChancePrecipitation
+36Hour.%i.OutlookIcon
+36Hour.%i.FanartCode
+
+
+HOURLY [1-36]
+-------------
+Hourly.IsFetched
+Hourly.%i.Time
+Hourly.%i.ShortDate
+Hourly.%i.LongDate
+Hourly.%i.Temperature
+Hourly.%i.DewPoint
+Hourly.%i.FeelsLike
+Hourly.%i.Precipitation
+Hourly.%i.Snow
+Hourly.%i.HeatIndex
+Hourly.%i.WindChill
+Hourly.%i.Mslp
+Hourly.%i.WindSpeed
+Hourly.%i.WindDirection
+Hourly.%i.ShortWindDirection
+Hourly.%i.WindDegree
+Hourly.%i.Humidity
+Hourly.%i.UVIndex
+Hourly.%i.ChancePrecipitation
+Hourly.%i.Outlook
+Hourly.%i.OutlookIcon
+Hourly.%i.FanartCode
+
+
+ALERTS [1-<number of alerts>]
+-----------------------------
+Alerts.IsFetched
+Alerts.%i.Description
+Alerts.%i.Message
+Alerts.%i.StartDate
+Alerts.%i.EndDate
+Alerts.%i.Significance
+Alerts.RSS
+Alerts
+Alerts.Count
+
+
+[MAP]
+Map.IsFetched
+MapPath
+
index 8adb2cc..61e2bd9 100644 (file)
@@ -1,10 +1,11 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="weather.wunderground" name="Weather Underground" version="0.0.9" provider-name="Team XBMC">
+<addon id="weather.wunderground" name="Weather Underground" version="1.0.1" provider-name="Team XBMC">
        <requires>
                <import addon="xbmc.python" version="2.0"/>
                <import addon="script.module.simplejson" version="2.0.10"/>
        </requires>
        <extension point="xbmc.python.weather" library="default.py"/>
+       <extension point="xbmc.python.module" library="resources/lib/wunderground"/>
        <extension point="xbmc.addon.metadata">
                <summary lang="af">Weer voorspelling vanaf wonderground.com</summary>
                <summary lang="ar">توقعات الطقس من wunderground.com</summary>
@@ -17,6 +18,7 @@
                <summary lang="el">Πρόγνωση καιρού από το wunderground.com</summary>
                <summary lang="en">Weather forecast from wunderground.com</summary>
                <summary lang="es">Predicción meteorológica de wunderground.com</summary>
+               <summary lang="es_AR">Predicción meteorológica de wunderground.com</summary>
                <summary lang="es_MX">Pronóstico de wunderground.com</summary>
                <summary lang="et">Ilmaennustus portaalist wunderground.com</summary>
                <summary lang="fi">Sääennusteet wunderground.com-sivustolta</summary>
@@ -55,6 +57,7 @@
                <description lang="el">Η πρόγνωση καιρού παρέχεται από το Weather Underground (http://www.wunderground.com/)</description>
                <description lang="en">Weather forecast provided by Weather Underground (http://www.wunderground.com/)</description>
                <description lang="es">Predicción meteorológica proporcionada por Weather Underground&#10;(http://www.wunderground.com/)</description>
+               <description lang="es_AR">Predicción meteorológica proporcionada por Weather Underground&#10;(http://www.wunderground.com/)</description>
                <description lang="es_MX">Pronóstico del tiempo por Weather Underground&#10;(http://www.wunderground.com/)</description>
                <description lang="et">Ilma ennustab Weather Underground (http://www.wunderground.com/)</description>
                <description lang="fi">Sääennusteet Weather Underground -sivuston tarjoamina (http://www.wunderground.com/)</description>
@@ -93,6 +96,7 @@
                <disclaimer lang="el">Χρήση αυτού του πρόσθετου συνεπάγεται την αποδοχή των Όρων Χρήσης της Υπηρεσίας (Terms of Service) οι οποίοι βρίσκονται στο http://www.wunderground.com/weather/api/d/terms.html</disclaimer>
                <disclaimer lang="en">Use of this add-on implies that you have agreed to the Terms of Service located at http://www.wunderground.com/weather/api/d/terms.html</disclaimer>
                <disclaimer lang="es">Al usar este complemento, aceptas los términos de uso de http://www.wunderground.com/weather/api/d/terms.html</disclaimer>
+               <disclaimer lang="es_AR">Al usar este complemento, aceptas los términos de uso de http://www.wunderground.com/weather/api/d/terms.html</disclaimer>
                <disclaimer lang="es_MX">El uso de este add-on implica que usted esta de acuerdo con los Términos de Servicio localizados en http://www.wunderground.com/weather/api/d/terms.html</disclaimer>
                <disclaimer lang="et">Selle lisamooduli kasutamine viitab sellele, et te olete nõustunud kasutajatingimustega aadressil http://www.wunderground.com/weather/api/d/terms.html</disclaimer>
                <disclaimer lang="fi">Tämän lisäosan käyttäminen tarkoittaa, että olet hyväksynyt osoitteessa http://www.wunderground.com/weather/api/d/terms.html sijaitsevat käyttöehdot</disclaimer>
                <platform>all</platform>
        </extension>
 </addon>
-
index f9c0fe0..0776546 100644 (file)
@@ -1,9 +1,76 @@
+v1.0.1
+- fix encoding issues
+
+v1.0.0
+- bump version for frodo
+- added .po language files
+
+v0.1.12
+- updated wunderground api module
+
+v0.1.11
+- added spanish translation
+- avoid crashes on api error responses
+- fix invalid humidity value
+
+v0.1.10
+- add 'L' weather alert severity
+- filter invalid response code
+- don't add beaufort unit to windspeeds
+- fix default zoom level
+- fixed windspeed for uk based locations in 36 hour and weekend forecast
+- localize AM/PM strings
+- made animated maps optional
+
+v0.1.9
+- fixed json error when no files are found
+- fix 36 hour heading and temp (again)
+- better detection of systems that use AM/PM time format
+- provide windspeeds in beaufort for systems that use it
+
+v0.1.8
+- fixed escape slashes in path
+
+v0.1.7
+- clear alert properties when there are no alerts
+- delete chached images when weather location is changed
+
+v0.1.6
+- fix 36 hour heading and temp for certain languages
+- provide 3 day weekend forecast
+- keep 4 hours worth of satellite images to create an animation
+
+v0.1.5
+- fixed weather icon location
+- fixed temp unit for hourly feels like
+
+v0.1.4
+- fetch satellite image instead of radar
+
+v0.1.3
+- disabled yesterdays weather and animated radar images (we don't have free access to that data)
+- added static radar image
+
+v0.1.2
+- bug fixes
+
+v0.1.1
+- beta release
+
+v0.1.0
+- wait for thread to finish before setting properties
+
 v0.0.9
-- clear 7 day labels not 6
-- save only the actual location code
+- implement threading
+- added wundermap support
 
 v0.0.8
-- fix error if no internet connection is available when searching for a location
+- use ascii strings for location search
+- added advanced configuration
+- added debug logging
+- added Current.Location window property
+- moved api code to a separate module (other weather addons can use it fetch wunderground data)
+- localize weather data
 
 v0.0.7
 - fix: import error on Windows with non/extended-ascii profile paths
index 3c36688..7b8f437 100644 (file)
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
 # *  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 2, or (at your option)
 # *  GNU General Public License for more details.
 # *
 # *  You should have received a copy of the GNU General Public License
-# *  along with XBMC; see the file COPYING.  If not, see
-# *  <http://www.gnu.org/licenses/>.
-# *
+# *  along with XBMC; see the file COPYING. If not, write to
+# *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+# *  http://www.gnu.org/copyleft/gpl.html
 
-import os, sys, urllib2, base64, socket, simplejson
-import xbmcgui, xbmcaddon
+
+import os, sys, socket, unicodedata, urllib2, time, base64
+from datetime import date
+import xbmc, xbmcgui, xbmcaddon, xbmcvfs
+if sys.version_info < (2, 7):
+    import simplejson
+else:
+    import json as simplejson
 
 __addon__      = xbmcaddon.Addon()
-__provider__   = __addon__.getAddonInfo('name')
-__cwd__        = __addon__.getAddonInfo('path')
-__resource__   = xbmc.translatePath(os.path.join(__cwd__, 'resources', 'lib')).decode("utf-8")
+__addonname__  = __addon__.getAddonInfo('name')
+__addonid__    = __addon__.getAddonInfo('id')
+__cwd__        = __addon__.getAddonInfo('path').decode("utf-8")
+__version__    = __addon__.getAddonInfo('version')
+__language__   = __addon__.getLocalizedString
+__resource__   = xbmc.translatePath(os.path.join(__cwd__, 'resources', 'lib'))
 
 sys.path.append (__resource__)
 
 from utilities import *
+from wunderground import wundergroundapi
 
-LOCATION_URL    = 'http://autocomplete.wunderground.com/aq?query=%s&format=JSON'
-WEATHER_URL     = 'http://api.wunderground.com/api/%s/conditions/forecast7day/hourly/q/%s.json'
-GEOIP_URL       = 'http://api.wunderground.com/api/%s/geolookup/q/autoip.json'
-A_I_K           = 'NDEzNjBkMjFkZjFhMzczNg=='
-WEATHER_WINDOW  = xbmcgui.Window(12600)
-MAXDAYS         = 6
+WUNDERGROUND_LOC = 'http://autocomplete.wunderground.com/aq?query=%s&format=JSON'
+WEATHER_FEATURES = 'hourly/conditions/forecast10day/astronomy/almanac/alerts/satellite'
+FORMAT           = 'json'
+DEBUG            = __addon__.getSetting('Debug')
+WEATHER_ICON     = xbmc.translatePath('special://temp/weather/%s.png').decode("utf-8")
+WEATHER_WINDOW   = xbmcgui.Window(12600)
+LANGUAGE         = xbmc.getLanguage().lower()
+SPEEDUNIT        = xbmc.getRegion('speedunit')
+TEMPUNIT         = unicode(xbmc.getRegion('tempunit'),encoding='utf-8')
+TIMEFORMAT       = xbmc.getRegion('meridiem')
+DATEFORMAT       = xbmc.getRegion('dateshort')
+MAXDAYS          = 6
 
 socket.setdefaulttimeout(10)
 
+def log(txt):
+    if DEBUG == 'true':
+        if isinstance (txt,str):
+            txt = txt.decode("utf-8")
+        message = u'%s: %s' % (__addonid__, txt)
+        xbmc.log(msg=message.encode("utf-8"), level=xbmc.LOGDEBUG)
+
 def set_property(name, value):
     WEATHER_WINDOW.setProperty(name, value)
 
 def refresh_locations():
-    location_set1 = __addon__.getSetting('Location1')
-    location_set2 = __addon__.getSetting('Location2')
-    location_set3 = __addon__.getSetting('Location3')
     locations = 0
-    if location_set1 != '':
-        locations += 1
-        set_property('Location1', location_set1)
-    else:
-        set_property('Location1', '')
-    if location_set2 != '':
-        locations += 1 
-        set_property('Location2', location_set2)
-    else:
-        set_property('Location2', '')
-    if location_set3 != '':
-        locations += 1
-        set_property('Location3', location_set3)
-    else:
-        set_property('Location3', '')
+    for count in range(1, 4):
+        loc_name = __addon__.getSetting('Location%s' % count)
+        if loc_name != '':
+            locations += 1
+        else:
+            __addon__.setSetting('Location%sid' % count, '')
+        set_property('Location%s' % count, loc_name)
     set_property('Locations', str(locations))
+    log('available locations: %s' % str(locations))
 
-def fetch(url):
+def find_location(loc):
+    url = WUNDERGROUND_LOC % urllib2.quote(loc)
     try:
         req = urllib2.urlopen(url)
-        json_string = req.read()
+        response = req.read()
         req.close()
     except:
-        json_string = ''
-    try:
-        json_clean = json_string.replace('"-9999.00"','""').replace('"-9998"','""').replace('"NA"','""')
-        parsed_json = simplejson.loads(json_clean)
-    except:
-        parsed_json = ''
-    return parsed_json
+        response = ''
+    return response
 
 def location(string):
-    loc   = []
-    locid = []
-    query = fetch(LOCATION_URL % (urllib2.quote(string)))
-    if query != '':
-        for item in query['RESULTS']:
+    locs   = []
+    locids = []
+    log('location: %s' % string)
+    loc = unicodedata.normalize('NFKD', unicode(string, 'utf-8')).encode('ascii','ignore')
+    log('searching for location: %s' % loc)
+    query = find_location(loc)
+    log('location data: %s' % query)
+    data = parse_data(query)
+    if data != '' and data.has_key('RESULTS'):
+        for item in data['RESULTS']:
             location   = item['name']
             locationid = item['l'][3:]
-            loc.append(location)
-            locid.append(locationid)
-    return loc, locid
+            locs.append(location)
+            locids.append(locationid)
+    return locs, locids
 
 def geoip():
-    data = fetch(GEOIP_URL % aik[::-1])
+    retry = 0
+    while (retry < 6) and (not xbmc.abortRequested):
+        query = wundergroundapi('geolookup', None, 'autoip', FORMAT)
+        if query != '':
+            retry = 6
+        else:
+            retry += 1
+            xbmc.sleep(10000)
+            log('geoip download failed')
+    log('geoip data: %s' % query)
+    data = parse_data(query)
     if data != '' and data.has_key('location'):
-        location = data['location']['l'][3:]
-        __addon__.setSetting('Location1', data['location']['city'])
-        __addon__.setSetting('Location1id', location)
+        location   = data['location']['city']
+        locationid = data['location']['l'][3:]
+        __addon__.setSetting('Location1', location)
+        __addon__.setSetting('Location1id', locationid)
+        log('geoip location: %s' % location)
+    else:
+        locationid = ''
+    return locationid
+
+def forecast(loc):
+    try:
+        lang = LANG[LANGUAGE]
+    except:
+        lang = 'EN'
+    opt = 'lang:' + lang
+    log('weather location: %s' % loc)
+    retry = 0
+    while (retry < 6) and (not xbmc.abortRequested):
+        query = wundergroundapi(WEATHER_FEATURES, opt, loc, FORMAT)
+        if query != '':
+            retry = 6
+        else:
+            retry += 1
+            xbmc.sleep(10000)
+            log('weather download failed')
+    log('forecast data: %s' % query)
+    data = parse_data(query)
+    if data != '' and not data.has_key('error'):
+        properties(data,loc)
     else:
-        location = ''
-    return location
-
-def forecast(city):
-    data = fetch(WEATHER_URL % (aik[::-1], city))
-    if data != '':
-        properties(data)
-
-def properties(query):
-    weathercode = WEATHER_CODES[query['current_observation']['icon_url'][31:-4]]
-    set_property('Current.Condition'     , query['current_observation']['weather'])
-    set_property('Current.Temperature'   , str(query['current_observation']['temp_c']))
-    set_property('Current.Wind'          , str(query['current_observation']['wind_kph']))
-    set_property('Current.WindDirection' , query['current_observation']['wind_dir'])
-    set_property('Current.Humidity'      , query['current_observation']['relative_humidity'].rstrip('%'))
-    set_property('Current.FeelsLike'     , str((int(query['hourly_forecast'][0]['feelslike']['english'])-32)*5/9))
-    set_property('Current.UVIndex'       , query['hourly_forecast'][0]['uvi'])
-    set_property('Current.DewPoint'      , str(query['current_observation']['dewpoint_c']))
+        clear()
+
+def clear():
+    set_property('Current.Condition'     , 'N/A')
+    set_property('Current.Temperature'   , '0')
+    set_property('Current.Wind'          , '0')
+    set_property('Current.WindDirection' , 'N/A')
+    set_property('Current.Humidity'      , '0')
+    set_property('Current.FeelsLike'     , '0')
+    set_property('Current.UVIndex'       , '0')
+    set_property('Current.DewPoint'      , '0')
+    set_property('Current.OutlookIcon'   , 'na.png')
+    set_property('Current.FanartCode'    , 'na')
+    for count in range (0, MAXDAYS+1):
+        set_property('Day%i.Title'       % count, 'N/A')
+        set_property('Day%i.HighTemp'    % count, '0')
+        set_property('Day%i.LowTemp'     % count, '0')
+        set_property('Day%i.Outlook'     % count, 'N/A')
+        set_property('Day%i.OutlookIcon' % count, 'na.png')
+        set_property('Day%i.FanartCode'  % count, 'na')
+
+def parse_data(json):
+    try:
+        reply = json.replace('"-999%"','""').replace('"-9999.00"','""').replace('"-9998"','""').replace('"NA"','""').replace(' <? END CHANCE OF PRECIP\n\n?>','') # wu api bug
+        data = simplejson.loads(reply)
+    except:
+        log('failed to parse weather data')
+        data = ''
+    return data
+
+def properties(data,loc):
+# standard properties
+    weathercode = WEATHER_CODES[data['current_observation']['icon_url'][31:-4]]
+    location = __addon__.getSetting('Location%s' % sys.argv[1])
+    if (location == '') and (sys.argv[1] != '1'):
+        location = __addon__.getSetting('Location1')
+    set_property('Current.Location'      , location)
+    set_property('Current.Condition'     , data['current_observation']['weather'])
+    set_property('Current.Temperature'   , str(data['current_observation']['temp_c']))
+    set_property('Current.Wind'          , str(data['current_observation']['wind_kph']))
+    set_property('Current.WindDirection' , data['current_observation']['wind_dir'])
+    set_property('Current.Humidity'      , data['current_observation']['relative_humidity'].rstrip('%'))
+    set_property('Current.FeelsLike'     , data['current_observation']['feelslike_c'])
+    set_property('Current.UVIndex'       , data['current_observation']['UV'])
+    set_property('Current.DewPoint'      , str(data['current_observation']['dewpoint_c']))
     set_property('Current.OutlookIcon'   , '%s.png' % weathercode)
     set_property('Current.FanartCode'    , weathercode)
-    for count, item in enumerate(query['forecast']['simpleforecast']['forecastday']):
+    for count, item in enumerate(data['forecast']['simpleforecast']['forecastday']):
         weathercode = WEATHER_CODES[item['icon_url'][31:-4]]
-        day = DAYS[item['date']['weekday_short']]
-        set_property('Day%i.Title'       % count, day)
+        set_property('Day%i.Title'       % count, item['date']['weekday'])
         set_property('Day%i.HighTemp'    % count, str(item['high']['celsius']))
         set_property('Day%i.LowTemp'     % count, str(item['low']['celsius']))
         set_property('Day%i.Outlook'     % count, item['conditions'])
@@ -123,6 +201,378 @@ def properties(query):
         set_property('Day%i.FanartCode'  % count, weathercode)
         if count == MAXDAYS:
             break
+# forecast properties
+    set_property('Forecast.IsFetched'        , 'true')
+    set_property('Forecast.City'             , data['current_observation']['display_location']['city'])
+    set_property('Forecast.State'            , data['current_observation']['display_location']['state_name'])
+    set_property('Forecast.Country'          , data['current_observation']['display_location']['country'])
+    update = time.localtime(float(data['current_observation']['observation_epoch']))
+    if DATEFORMAT[1] == 'm':
+        localdate = WEEKDAY[update[6]] + ' ' + MONTH[update[1]] + ' ' + str(update[2]) + ', ' + str(update[0])
+    else:
+        localdate = WEEKDAY[update[6]] + ' ' + str(update[2]) + ' ' + MONTH[update[1]] + ' ' + str(update[0])
+    if TIMEFORMAT != '/':
+        localtime = time.strftime('%I:%M%p', update)
+    else:
+        localtime = time.strftime('%H:%M', update)
+    set_property('Forecast.Updated'          , localdate + ' - ' + localtime)
+# current properties
+    set_property('Current.IsFetched'         , 'true')
+    set_property('Current.WindDegree'        , str(data['current_observation']['wind_degrees']) + u'°')
+    set_property('Current.SolarRadiation'    , str(data['current_observation']['solarradiation']))
+    if 'F' in TEMPUNIT:
+        set_property('Current.Pressure'      , data['current_observation']['pressure_in'] + ' inHg')
+        set_property('Current.Precipitation' , data['current_observation']['precip_1hr_in'] + ' in')
+        set_property('Current.HeatIndex'     , str(data['current_observation']['heat_index_f']) + TEMPUNIT)
+        set_property('Current.WindChill'     , str(data['current_observation']['windchill_f']) + TEMPUNIT)
+    else:
+        set_property('Current.Pressure'      , data['current_observation']['pressure_mb'] + ' mb')
+        set_property('Current.Precipitation' , data['current_observation']['precip_1hr_metric'] + ' mm')
+        set_property('Current.HeatIndex'     , str(data['current_observation']['heat_index_c']) + TEMPUNIT)
+        set_property('Current.WindChill'     , str(data['current_observation']['windchill_c']) + TEMPUNIT)
+    if SPEEDUNIT == 'mph':
+        set_property('Current.Visibility'    , data['current_observation']['visibility_mi'] + ' mi')
+        set_property('Current.WindGust'      , str(data['current_observation']['wind_gust_mph']) + ' ' + SPEEDUNIT)
+    elif SPEEDUNIT == 'Beaufort':
+        set_property('Current.Visibility'    , data['current_observation']['visibility_km'] + ' km')
+        set_property('Current.WindGust'      , KPHTOBFT(data['current_observation']['wind_gust_kph']))
+    else:
+        set_property('Current.Visibility'    , data['current_observation']['visibility_km'] + ' km')
+        set_property('Current.WindGust'      , str(data['current_observation']['wind_gust_kph']) + ' ' + SPEEDUNIT)
+# today properties
+    set_property('Today.IsFetched'                     , 'true')
+    if TIMEFORMAT != '/':
+        AM = unicode(TIMEFORMAT.split('/')[0],encoding='utf-8')
+        PM = unicode(TIMEFORMAT.split('/')[1],encoding='utf-8')
+        hour = int(data['moon_phase']['sunrise']['hour']) % 24
+        isam = (hour >= 0) and (hour < 12)
+        if isam:
+            hour = ('12' if (hour == 0) else '%02d' % (hour))
+            set_property('Today.Sunrise'               , hour.lstrip('0') + ':' + data['moon_phase']['sunrise']['minute'] + ' ' + AM)
+        else:
+            hour = ('12' if (hour == 12) else '%02d' % (hour-12))
+            set_property('Today.Sunrise'               , hour.lstrip('0') + ':' + data['moon_phase']['sunrise']['minute'] + ' ' + PM)
+        hour = int(data['moon_phase']['sunset']['hour']) % 24
+        isam = (hour >= 0) and (hour < 12)
+        if isam:
+            hour = ('12' if (hour == 0) else '%02d' % (hour))
+            set_property('Today.Sunset'               , hour.lstrip('0') + ':' + data['moon_phase']['sunset']['minute'] + ' ' + AM)
+        else:
+            hour = ('12' if (hour == 12) else '%02d' % (hour-12))
+            set_property('Today.Sunset'               , hour.lstrip('0') + ':' + data['moon_phase']['sunset']['minute'] + ' ' + PM)
+    else:
+        set_property('Today.Sunrise'                   , data['moon_phase']['sunrise']['hour'] + ':' + data['moon_phase']['sunrise']['minute'])
+        set_property('Today.Sunset'                    , data['moon_phase']['sunset']['hour'] + ':' + data['moon_phase']['sunset']['minute'])
+    set_property('Today.moonphase'                     , MOONPHASE(int(data['moon_phase']['ageOfMoon']), int(data['moon_phase']['percentIlluminated'])))
+    if 'F' in TEMPUNIT:
+        set_property('Today.AvgHighTemperature'        , data['almanac']['temp_high']['normal']['F'] + TEMPUNIT)
+        set_property('Today.AvgLowTemperature'         , data['almanac']['temp_low']['normal']['F'] + TEMPUNIT)
+        try:
+            set_property('Today.RecordHighTemperature' , data['almanac']['temp_high']['record']['F'] + TEMPUNIT)
+            set_property('Today.RecordLowTemperature'  , data['almanac']['temp_low']['record']['F'] + TEMPUNIT)
+        except:
+            set_property('Today.RecordHighTemperature' , '')
+            set_property('Today.RecordLowTemperature'  , '')
+    else:
+        set_property('Today.AvgHighTemperature'        , data['almanac']['temp_high']['normal']['C'] + TEMPUNIT)
+        set_property('Today.AvgLowTemperature'         , data['almanac']['temp_low']['normal']['C'] + TEMPUNIT)
+        try:
+            set_property('Today.RecordHighTemperature' , data['almanac']['temp_high']['record']['C'] + TEMPUNIT)
+            set_property('Today.RecordLowTemperature'  , data['almanac']['temp_low']['record']['C'] + TEMPUNIT)
+        except:
+            set_property('Today.RecordHighTemperature' , '')
+            set_property('Today.RecordLowTemperature'  , '')
+    try:
+        set_property('Today.RecordHighYear'            , data['almanac']['temp_high']['recordyear'])
+        set_property('Today.RecordLowYear'             , data['almanac']['temp_low']['recordyear'])
+    except:
+        set_property('Today.RecordHighYear'            , '')
+        set_property('Today.RecordLowYear'             , '')
+# daily properties
+    set_property('Daily.IsFetched', 'true')
+    for count, item in enumerate(data['forecast']['simpleforecast']['forecastday']):
+        weathercode = WEATHER_CODES[item['icon_url'][31:-4]]
+        set_property('Daily.%i.LongDay'              % (count+1), item['date']['weekday'])
+        set_property('Daily.%i.ShortDay'             % (count+1), item['date']['weekday_short'])
+        if DATEFORMAT[1] == 'm':
+            set_property('Daily.%i.LongDate'         % (count+1), item['date']['monthname'] + ' ' + str(item['date']['day']))
+            set_property('Daily.%i.ShortDate'        % (count+1), MONTH[item['date']['month']] + ' ' + str(item['date']['day']))
+        else:
+            set_property('Daily.%i.LongDate'         % (count+1), str(item['date']['day']) + ' ' + item['date']['monthname'])
+            set_property('Daily.%i.ShortDate'        % (count+1), str(item['date']['day']) + ' ' + MONTH[item['date']['month']])
+        set_property('Daily.%i.Outlook'              % (count+1), item['conditions'])
+        set_property('Daily.%i.OutlookIcon'          % (count+1), WEATHER_ICON % weathercode)
+        set_property('Daily.%i.FanartCode'           % (count+1), weathercode)
+        if SPEEDUNIT == 'mph':
+            set_property('Daily.%i.WindSpeed'        % (count+1), str(item['avewind']['mph']) + ' ' + SPEEDUNIT)
+            set_property('Daily.%i.MaxWind'          % (count+1), str(item['maxwind']['mph']) + ' ' + SPEEDUNIT)
+        elif SPEEDUNIT == 'Beaufort':
+            set_property('Daily.%i.WindSpeed'        % (count+1), KPHTOBFT(item['avewind']['kph']))
+            set_property('Daily.%i.MaxWind'          % (count+1), KPHTOBFT(item['maxwind']['kph']))
+        else:
+            set_property('Daily.%i.WindSpeed'        % (count+1), str(item['avewind']['kph']) + ' ' + SPEEDUNIT)
+            set_property('Daily.%i.MaxWind'          % (count+1), str(item['maxwind']['kph']) + ' ' + SPEEDUNIT)
+        set_property('Daily.%i.WindDirection'        % (count+1), item['avewind']['dir'])
+        set_property('Daily.%i.ShortWindDirection'   % (count+1), item['avewind']['dir'])
+        set_property('Daily.%i.WindDegree'           % (count+1), str(item['avewind']['degrees']) + u'°')
+        set_property('Daily.%i.Humidity'             % (count+1), str(item['avehumidity']) + '%')
+        set_property('Daily.%i.MinHumidity'          % (count+1), str(item['minhumidity']) + '%')
+        set_property('Daily.%i.MaxHumidity'          % (count+1), str(item['maxhumidity']) + '%')
+        if 'F' in TEMPUNIT:
+            set_property('Daily.%i.HighTemperature'  % (count+1), str(item['high']['fahrenheit']) + TEMPUNIT)
+            set_property('Daily.%i.LowTemperature'   % (count+1), str(item['low']['fahrenheit']) + TEMPUNIT)
+            set_property('Daily.%i.LongOutlookDay'   % (count+1), data['forecast']['txt_forecast']['forecastday'][2*count]['fcttext'])
+            set_property('Daily.%i.LongOutlookNight' % (count+1), data['forecast']['txt_forecast']['forecastday'][2*count+1]['fcttext'])
+            set_property('Daily.%i.Precipitation'    % (count+1), str(item['qpf_day']['in']) + ' in')
+            set_property('Daily.%i.Snow'             % (count+1), str(item['snow_day']['in']) + ' in')
+        else:
+            set_property('Daily.%i.HighTemperature'  % (count+1), str(item['high']['celsius']) + TEMPUNIT)
+            set_property('Daily.%i.LowTemperature'   % (count+1), str(item['low']['celsius']) + TEMPUNIT)
+            set_property('Daily.%i.LongOutlookDay'   % (count+1), data['forecast']['txt_forecast']['forecastday'][2*count]['fcttext_metric'])
+            set_property('Daily.%i.LongOutlookNight' % (count+1), data['forecast']['txt_forecast']['forecastday'][2*count+1]['fcttext_metric'])
+            set_property('Daily.%i.Precipitation'    % (count+1), str(item['qpf_day']['mm']) + ' mm')
+            set_property('Daily.%i.Snow'             % (count+1), str(item['snow_day']['cm']) + ' mm')
+        set_property('Daily.%i.ChancePrecipitation'  % (count+1), data['forecast']['txt_forecast']['forecastday'][2*count]['pop'] + '%')
+# weekend properties
+    set_property('Weekend.IsFetched', 'true')
+    if __addon__.getSetting('Weekend') == '2':
+        weekend = (3,4,5)
+    elif __addon__.getSetting('Weekend') == '1':
+        weekend = (4,5,6)
+    else:
+        weekend = (5,6,7)
+    count = 0
+    for item in data['forecast']['simpleforecast']['forecastday']:
+        if date(item['date']['year'], item['date']['month'], item['date']['day']).isoweekday() in weekend:
+            weathercode = WEATHER_CODES[item['icon_url'][31:-4]]
+            set_property('Weekend.%i.LongDay'                  % (count+1), item['date']['weekday'])
+            set_property('Weekend.%i.ShortDay'                 % (count+1), item['date']['weekday_short'])
+            if DATEFORMAT[1] == 'm':
+                set_property('Weekend.%i.LongDate'             % (count+1), item['date']['monthname'] + ' ' + str(item['date']['day']))
+                set_property('Weekend.%i.ShortDate'            % (count+1), MONTH[item['date']['month']] + ' ' + str(item['date']['day']))
+            else:
+                set_property('Weekend.%i.LongDate'             % (count+1), str(item['date']['day']) + ' ' + item['date']['monthname'])
+                set_property('Weekend.%i.ShortDate'            % (count+1), str(item['date']['day']) + ' ' + MONTH[item['date']['month']])
+            set_property('Weekend.%i.Outlook'                  % (count+1), item['conditions'])
+            set_property('Weekend.%i.OutlookIcon'              % (count+1), WEATHER_ICON % weathercode)
+            set_property('Weekend.%i.FanartCode'               % (count+1), weathercode)
+            if SPEEDUNIT == 'mph':
+                set_property('Weekend.%i.WindSpeed'            % (count+1), str(item['avewind']['mph']) + ' ' + SPEEDUNIT)
+                set_property('Weekend.%i.MaxWind'              % (count+1), str(item['maxwind']['mph']) + ' ' + SPEEDUNIT)
+            elif SPEEDUNIT == 'Beaufort':
+                set_property('Weekend.%i.WindSpeed'            % (count+1), KPHTOBFT(item['avewind']['kph']))
+                set_property('Weekend.%i.MaxWind'              % (count+1), KPHTOBFT(item['maxwind']['kph']))
+            else:
+                set_property('Weekend.%i.WindSpeed'            % (count+1), str(item['avewind']['kph']) + ' ' + SPEEDUNIT)
+                set_property('Weekend.%i.MaxWind'              % (count+1), str(item['maxwind']['kph']) + ' ' + SPEEDUNIT)
+            set_property('Weekend.%i.WindDirection'            % (count+1), item['avewind']['dir'])
+            set_property('Weekend.%i.ShortWindDirection'       % (count+1), item['avewind']['dir'])
+            set_property('Weekend.%i.WindDegree'               % (count+1), str(item['avewind']['degrees']) + u'°')
+            set_property('Weekend.%i.Humidity'                 % (count+1), str(item['avehumidity']) + '%')
+            set_property('Weekend.%i.MinHumidity'              % (count+1), str(item['minhumidity']) + '%')
+            set_property('Weekend.%i.MaxHumidity'              % (count+1), str(item['maxhumidity']) + '%')
+            set_property('Weekend.%i.ChancePrecipitation'      % (count+1), data['forecast']['txt_forecast']['forecastday'][2*count]['pop'] + '%')
+            if 'F' in TEMPUNIT:
+                set_property('Weekend.%i.HighTemperature'      % (count+1), str(item['high']['fahrenheit']) + TEMPUNIT)
+                set_property('Weekend.%i.LowTemperature'       % (count+1), str(item['low']['fahrenheit']) + TEMPUNIT)
+                set_property('Weekend.%i.Precipitation'        % (count+1), str(item['qpf_day']['in']) + ' in')
+                set_property('Weekend.%i.Snow'                 % (count+1), str(item['snow_day']['in']) + ' in')
+                set_property('Weekend.%i.LongOutlookDay'       % (count+1), data['forecast']['txt_forecast']['forecastday'][2*count]['fcttext'])
+                set_property('Weekend.%i.LongOutlookNight'     % (count+1), data['forecast']['txt_forecast']['forecastday'][2*count+1]['fcttext'])
+            else:
+                set_property('Weekend.%i.HighTemperature'      % (count+1), str(item['high']['celsius']) + TEMPUNIT)
+                set_property('Weekend.%i.LowTemperature'       % (count+1), str(item['low']['celsius']) + TEMPUNIT)
+                set_property('Weekend.%i.Precipitation'        % (count+1), str(item['qpf_day']['mm']) + ' mm')
+                set_property('Weekend.%i.Snow'                 % (count+1), str(item['snow_day']['cm']) + ' mm')
+                if data['current_observation']['display_location']['country'] == 'UK': # for the brits
+                    dfcast_e = data['forecast']['txt_forecast']['forecastday'][2*count]['fcttext'].split('.')
+                    dfcast_m = data['forecast']['txt_forecast']['forecastday'][2*count]['fcttext_metric'].split('.')
+                    nfcast_e = data['forecast']['txt_forecast']['forecastday'][2*count+1]['fcttext'].split('.')
+                    nfcast_m = data['forecast']['txt_forecast']['forecastday'][2*count+1]['fcttext_metric'].split('.')
+                    for field in dfcast_e:
+                        if field.endswith('mph'): # find windspeed in mph
+                            wind = field
+                            break
+                    for field in dfcast_m:
+                        if field.endswith('km/h'): # find windspeed in km/h
+                            dfcast_m[dfcast_m.index(field)] = wind # replace windspeed in km/h with windspeed in mph
+                            break
+                    for field in nfcast_e:
+                        if field.endswith('mph'): # find windspeed in mph
+                            wind = field
+                            break
+                    for field in nfcast_m:
+                        if field.endswith('km/h'): # find windspeed in km/h
+                            nfcast_m[nfcast_m.index(field)] = wind # replace windspeed in km/h with windspeed in mph
+                            break
+                    set_property('Weekend.%i.LongOutlookDay'   % (count+1), '. '.join(dfcast_m))
+                    set_property('Weekend.%i.LongOutlookNight' % (count+1), '. '.join(nfcast_m))
+                else:
+                    set_property('Weekend.%i.LongOutlookDay'   % (count+1), data['forecast']['txt_forecast']['forecastday'][2*count]['fcttext_metric'])
+                    set_property('Weekend.%i.LongOutlookNight' % (count+1), data['forecast']['txt_forecast']['forecastday'][2*count+1]['fcttext_metric'])
+            count += 1
+            if count == 3:
+                break
+# 36 hour properties
+    set_property('36Hour.IsFetched', 'true')
+    for count, item in enumerate(data['forecast']['txt_forecast']['forecastday']):
+        weathercode = WEATHER_CODES[item['icon_url'][31:-4]]
+        if 'F' in TEMPUNIT:
+            try:
+                fcast = item['fcttext'].split('.')
+                for line in fcast:
+                    if line.endswith('F'):
+                        set_property('36Hour.%i.TemperatureHeading' % (count+1), line.rsplit(' ',1)[0])
+                        set_property('36Hour.%i.Temperature'        % (count+1), line.rsplit(' ',1)[1].rstrip('F').strip() + TEMPUNIT)
+                        break
+            except:
+                set_property('36Hour.%i.TemperatureHeading'         % (count+1), '')
+                set_property('36Hour.%i.Temperature'                % (count+1), '')
+            set_property('36Hour.%i.Forecast'                       % (count+1), item['fcttext'])
+        else:
+            try:
+                fcast = item['fcttext_metric'].split('.')
+                for line in fcast:
+                    if line.endswith('C'):
+                        set_property('36Hour.%i.TemperatureHeading' % (count+1), line.rsplit(' ',1)[0])
+                        set_property('36Hour.%i.Temperature'        % (count+1), line.rsplit(' ',1)[1].rstrip('C').strip() + TEMPUNIT)
+                        break
+            except:
+                set_property('36Hour.%i.TemperatureHeading' % (count+1), '')
+                set_property('36Hour.%i.Temperature'        % (count+1), '')
+            if data['current_observation']['display_location']['country'] == 'UK': # for the brits
+                fcast_e = item['fcttext'].split('.')
+                for field in fcast_e:
+                    if field.endswith('mph'): # find windspeed in mph
+                        wind = field
+                        break
+                for field in fcast:
+                    if field.endswith('km/h'): # find windspeed in km/h
+                        fcast[fcast.index(field)] = wind # replace windspeed in km/h with windspeed in mph
+                        break
+                set_property('36Hour.%i.Forecast'                   % (count+1), '. '.join(fcast))
+            else:
+                set_property('36Hour.%i.Forecast'                   % (count+1), item['fcttext_metric'])
+        set_property('36Hour.%i.Heading'                    % (count+1), item['title'])
+        set_property('36Hour.%i.ChancePrecipitation'        % (count+1), item['pop']  + '%')
+        set_property('36Hour.%i.OutlookIcon'                % (count+1), WEATHER_ICON % weathercode)
+        set_property('36Hour.%i.FanartCode'                 % (count+1), weathercode)
+        if count == 2:
+            break
+# hourly properties
+    set_property('Hourly.IsFetched', 'true')
+    for count, item in enumerate(data['hourly_forecast']):
+        weathercode = WEATHER_CODES[item['icon_url'][31:-4]]
+        if TIMEFORMAT != '/':
+            set_property('Hourly.%i.Time'            % (count+1), item['FCTTIME']['civil'])
+        else:
+            set_property('Hourly.%i.Time'            % (count+1), item['FCTTIME']['hour_padded'] + ':' + item['FCTTIME']['min'])
+        if DATEFORMAT[1] == 'm':
+            set_property('Hourly.%i.ShortDate'       % (count+1), item['FCTTIME']['month_name_abbrev'] + ' ' + item['FCTTIME']['mday_padded'])
+            set_property('Hourly.%i.LongDate'        % (count+1), item['FCTTIME']['month_name'] + ' ' + item['FCTTIME']['mday_padded'])
+        else:
+            set_property('Hourly.%i.ShortDate'       % (count+1), item['FCTTIME']['mday_padded'] + ' ' + item['FCTTIME']['month_name_abbrev'])
+            set_property('Hourly.%i.LongDate'        % (count+1), item['FCTTIME']['mday_padded'] + ' ' + item['FCTTIME']['month_name'])
+        if 'F' in TEMPUNIT:
+            set_property('Hourly.%i.Temperature'     % (count+1), item['temp']['english'] + TEMPUNIT)
+            set_property('Hourly.%i.DewPoint'        % (count+1), item['dewpoint']['english'] + TEMPUNIT)
+            set_property('Hourly.%i.FeelsLike'       % (count+1), item['feelslike']['english'] + TEMPUNIT)
+            set_property('Hourly.%i.Precipitation'   % (count+1), item['qpf']['english'] + ' in')
+            set_property('Hourly.%i.Snow'            % (count+1), item['snow']['english'] + ' in')
+            set_property('Hourly.%i.HeatIndex'       % (count+1), item['heatindex']['english'] + TEMPUNIT)
+            set_property('Hourly.%i.WindChill'       % (count+1), item['windchill']['english'] + TEMPUNIT)
+            set_property('Hourly.%i.Mslp'            % (count+1), item['mslp']['english'] + ' inHg')
+        else:
+            set_property('Hourly.%i.Temperature'     % (count+1), item['temp']['metric'] + TEMPUNIT)
+            set_property('Hourly.%i.DewPoint'        % (count+1), item['dewpoint']['metric'] + TEMPUNIT)
+            set_property('Hourly.%i.FeelsLike'       % (count+1), item['feelslike']['metric'] + TEMPUNIT)
+            set_property('Hourly.%i.Precipitation'   % (count+1), item['qpf']['metric'] + ' mm')
+            set_property('Hourly.%i.Snow'            % (count+1), item['snow']['metric'] + ' mm')
+            set_property('Hourly.%i.HeatIndex'       % (count+1), item['heatindex']['metric'] + TEMPUNIT)
+            set_property('Hourly.%i.WindChill'       % (count+1), item['windchill']['metric'] + TEMPUNIT)
+            set_property('Hourly.%i.Mslp'            % (count+1), item['mslp']['metric'] + ' inHg')
+        if SPEEDUNIT == 'mph':
+            set_property('Hourly.%i.WindSpeed'       % (count+1), item['wspd']['english'] + ' ' + SPEEDUNIT)
+        elif SPEEDUNIT == 'Beaufort':
+            set_property('Hourly.%i.WindSpeed'       % (count+1), KPHTOBFT(int(item['wspd']['metric'])))
+        else:
+            set_property('Hourly.%i.WindSpeed'       % (count+1), item['wspd']['metric'] + ' ' + SPEEDUNIT)
+        set_property('Hourly.%i.WindDirection'       % (count+1), item['wdir']['dir'])
+        set_property('Hourly.%i.ShortWindDirection'  % (count+1), item['wdir']['dir'])
+        set_property('Hourly.%i.WindDegree'          % (count+1), item['wdir']['degrees'] + u'°')
+        set_property('Hourly.%i.Humidity'            % (count+1), item['humidity'] + '%')
+        set_property('Hourly.%i.UVIndex'             % (count+1), item['uvi'])
+        set_property('Hourly.%i.ChancePrecipitation' % (count+1), item['pop'] + '%')
+        set_property('Hourly.%i.Outlook'             % (count+1), item['condition'])
+        set_property('Hourly.%i.OutlookIcon'         % (count+1), WEATHER_ICON % weathercode)
+        set_property('Hourly.%i.FanartCode'          % (count+1), weathercode)
+        if count == 35: # workaround: wunderground provides a 10day hourly forecast
+            break
+# alert properties
+    set_property('Alerts.IsFetched', 'true')
+    if str(data['alerts']) != '[]':
+        rss = ''
+        alerts = ''
+        for count, item in enumerate(data['alerts']):
+            set_property('Alerts.%i.Description'     % (count+1), item['description'])
+            set_property('Alerts.%i.Message'         % (count+1), item['message'])
+            set_property('Alerts.%i.StartDate'       % (count+1), item['date'])
+            set_property('Alerts.%i.EndDate'         % (count+1), item['expires'])
+            set_property('Alerts.%i.Significance'    % (count+1), SEVERITY[item['significance']])
+            rss    = rss + item['description'] + ' - '
+            alerts = alerts + item['message']
+        set_property('Alerts.RSS'   , rss.rstrip(' - '))
+        set_property('Alerts'       , alerts)
+        set_property('Alerts.Count' , str(count+1))
+    else:
+        set_property('Alerts.RSS'   , '')
+        set_property('Alerts'       , '')
+        set_property('Alerts.Count' , '0')
+# map properties
+    set_property('Map.IsFetched', 'true')
+    filelist = []
+    locid = base64.b16encode(loc)
+    addondir = xbmc.translatePath(os.path.join(__cwd__, 'resources', 'logo'))
+    mapdir = xbmc.translatePath('special://profile/addon_data/%s/map' % __addonid__)
+    set_property('MapPath', addondir)
+    if not xbmcvfs.exists(mapdir):
+        xbmcvfs.mkdir(mapdir)
+    json_query = xbmc.executeJSONRPC('{ "jsonrpc" : "2.0" , "method" : "Files.GetDirectory" , "params" : { "directory" : "%s" , "sort" : { "method" : "file" } } , "id" : 1 }' % mapdir.replace('\\', '\\\\'))
+    json_query = unicode(json_query, 'utf-8', errors='ignore')
+    json_response = simplejson.loads(json_query)
+    if (json_response['result'] != None) and (json_response['result'].has_key('files')) and (json_response['result']['files'] != None):
+        for item in json_response['result']['files']:
+            if item['filetype'] == 'file':
+                filelist.append(item['file'])
+    animate = __addon__.getSetting('Animate')
+    for item in filelist:
+        if animate == 'true':
+            if (time.time() - os.path.getmtime(item) > 14400) or (not locid in item):
+                xbmcvfs.delete(item)
+        else:
+            xbmcvfs.delete(item)
+    zoom = __addon__.getSetting('Zoom')
+    if zoom == '10': # default setting does not return decimals, changed setting will
+        zoom = '10.0'
+    url = data['satellite']['image_url_ir4'].replace('width=300&height=300','width=640&height=360').replace('radius=75','radius=%i' % int(1000/int(zoom.rstrip('0').rstrip('.,'))))
+    log('map url: %s' % url)
+    req = urllib2.urlopen(url)
+    response = req.read()
+    req.close()
+    timestamp = time.strftime('%Y%m%d%H%M%S')
+    mapfile = xbmc.translatePath('special://profile/addon_data/%s/map/%s-%s.png' % (__addonid__,locid,timestamp))
+    tmpmap = open(mapfile, 'wb')
+    tmpmap.write(response)
+    tmpmap.close()
+    log('satellite image downloaded')
+    set_property('MapPath', mapdir)
+
+log('version %s started: %s' % (__version__, sys.argv))
+log('lang: %s'    % LANGUAGE)
+log('speed: %s'   % SPEEDUNIT)
+log('temp: %s'    % TEMPUNIT[1])
+log('time: %s'    % TIMEFORMAT)
+log('date: %s'    % DATEFORMAT)
 
 if sys.argv[1].startswith('Location'):
     keyboard = xbmc.Keyboard('', xbmc.getLocalizedString(14024), False)
@@ -133,41 +583,30 @@ if sys.argv[1].startswith('Location'):
         dialog = xbmcgui.Dialog()
         if locations != []:
             selected = dialog.select(xbmc.getLocalizedString(396), locations)
-            if selected != -1: 
+            if selected != -1:
                 __addon__.setSetting(sys.argv[1], locations[selected])
                 __addon__.setSetting(sys.argv[1] + 'id', locationids[selected])
+                log('selected location: %s' % locations[selected])
+                log('selected location id: %s' % locationids[selected])
         else:
-            dialog.ok(__provider__, xbmc.getLocalizedString(284))
+            dialog.ok(__addonname__, xbmc.getLocalizedString(284))
 
 else:
     location = __addon__.getSetting('Location%sid' % sys.argv[1])
-    aik = base64.b64decode(A_I_K)
     if (location == '') and (sys.argv[1] != '1'):
         location = __addon__.getSetting('Location1id')
+        log('trying location 1 instead')
     if location == '':
+        log('fallback to geoip')
         location = geoip()
     if not location == '':
         if location.startswith('/q/'): # backwards compatibility
             location = location[3:]
         forecast(location)
     else:
-        set_property('Current.Condition'     , 'N/A')
-        set_property('Current.Temperature'   , '0')
-        set_property('Current.Wind'          , '0')
-        set_property('Current.WindDirection' , 'N/A')
-        set_property('Current.Humidity'      , '0')
-        set_property('Current.FeelsLike'     , '0')
-        set_property('Current.UVIndex'       , '0')
-        set_property('Current.DewPoint'      , '0')
-        set_property('Current.OutlookIcon'   , 'na.png')
-        set_property('Current.FanartCode'    , 'na')
-        for count in range (0, MAXDAYS+1):
-            set_property('Day%i.Title'       % count, 'N/A')
-            set_property('Day%i.HighTemp'    % count, '0')
-            set_property('Day%i.LowTemp'     % count, '0')
-            set_property('Day%i.Outlook'     % count, 'N/A')
-            set_property('Day%i.OutlookIcon' % count, 'na.png')
-            set_property('Day%i.FanartCode'  % count, 'na')
-
-refresh_locations()
-set_property('WeatherProvider', 'Weather Underground')
+        log('no location found')
+        clear()
+    refresh_locations()
+
+set_property('WeatherProvider', __addonname__)
+log('finished')
index 13c82e1..671ffc3 100644 (file)
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: XBMC Main Translation Project (Frodo)\n"
 "Report-Msgid-Bugs-To: http://trac.xbmc.org/\n"
 "POT-Creation-Date: 2012-05-28 15:38+0000\n"
-"PO-Revision-Date: 2012-11-07 03:01+0000\n"
+"PO-Revision-Date: 2012-11-11 10:18+0000\n"
 "Last-Translator: XBMC Translation Team\n"
 "Language-Team: Belarusian (http://www.transifex.com/projects/p/XBMC-Main-Frodo/language/be/)\n"
 "MIME-Version: 1.0\n"
@@ -23,12 +23,12 @@ msgstr "Location Setup"
 
 msgctxt "#30111"
 msgid "Change location 1"
-msgstr "Change location 1"
+msgstr "Зьмяніць месца 1"
 
 msgctxt "#30112"
 msgid "Change location 2"
-msgstr "Change location 2"
+msgstr "Зьмяніць месца 2"
 
 msgctxt "#30113"
 msgid "Change location 3"
-msgstr "Change location 3"
+msgstr "Зьмяніць месца 3"
index b741f48..480791e 100644 (file)
@@ -1,15 +1,15 @@
 # XBMC Media Center language file
 # Addon Name: Weather Underground
 # Addon id: weather.wunderground
-# Addon version: 0.0.9
+# Addon version: 1.0.0
 # Addon Provider: Team XBMC
 msgid ""
 msgstr ""
 "Project-Id-Version: XBMC-Addons\n"
 "Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
-"POT-Creation-Date: 2012-05-28 15:38+0000\n"
+"POT-Creation-Date: 2012-09-23 21:15+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: XBMC Translation Team\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -17,20 +17,140 @@ msgstr ""
 "Language: en\n"
 "Plural-Forms: nplurals=2; plural=(n != 1)\n"
 
-msgctxt "#30101"
-msgid "Location Setup"
+msgctxt "#32101"
+msgid "Location setup"
 msgstr ""
 
-#empty strings from id 30102 to 30110
+msgctxt "#32102"
+msgid "Advanced options"
+msgstr ""
+
+#empty strings from id 32103 to 32110
+
+msgctxt "#32111"
+msgid "Location 1"
+msgstr ""
+
+msgctxt "#32112"
+msgid "Location 2"
+msgstr ""
+
+msgctxt "#32113"
+msgid "Location 3"
+msgstr ""
+
+msgctxt "#32114"
+msgid "Location 1 display name"
+msgstr ""
+
+msgctxt "#32115"
+msgid "Location 2 display name"
+msgstr ""
+
+msgctxt "#32116"
+msgid "Location 3 display name"
+msgstr ""
+
+msgctxt "#32117"
+msgid "Location 1 id"
+msgstr ""
+
+msgctxt "#32118"
+msgid "Location 2 id"
+msgstr ""
+
+msgctxt "#32119"
+msgid "Location 3 id"
+msgstr ""
+
+msgctxt "#32120"
+msgid "Enable logging"
+msgstr ""
+
+msgctxt "#32121"
+msgid "Weekend"
+msgstr ""
+
+msgctxt "#32122"
+msgid "Saturday/Sunday"
+msgstr ""
+
+msgctxt "#32123"
+msgid "Friday/Saturday"
+msgstr ""
+
+msgctxt "#32124"
+msgid "Thursday/Friday"
+msgstr ""
+
+msgctxt "#32125"
+msgid "Map zoom level"
+msgstr ""
+
+msgctxt "#32126"
+msgid "Animated map"
+msgstr ""
+
+#empty strings from id 32127 to 32500
+
+msgctxt "#32501"
+msgid "New Moon"
+msgstr ""
+
+msgctxt "#32502"
+msgid "Waxing Crescent"
+msgstr ""
+
+msgctxt "#32503"
+msgid "First Quarter"
+msgstr ""
+
+msgctxt "#32504"
+msgid "Waxing Gibbous"
+msgstr ""
+
+msgctxt "#32505"
+msgid "Full Moon"
+msgstr ""
+
+msgctxt "#32506"
+msgid "Waning Gibbous"
+msgstr ""
+
+msgctxt "#32507"
+msgid "Last Quarter"
+msgstr ""
+
+msgctxt "#32508"
+msgid "Waning Crescent"
+msgstr ""
+
+#empty string with id 32509
+
+msgctxt "#32510"
+msgid "Warning"
+msgstr ""
+
+msgctxt "#32511"
+msgid "Watch"
+msgstr ""
+
+msgctxt "#32512"
+msgid "Advisory"
+msgstr ""
+
+msgctxt "#32513"
+msgid "Statement"
+msgstr ""
 
-msgctxt "#30111"
-msgid "Change location 1"
+msgctxt "#32514"
+msgid "Outlook"
 msgstr ""
 
-msgctxt "#30112"
-msgid "Change location 2"
+msgctxt "#32515"
+msgid "Forecast"
 msgstr ""
 
-msgctxt "#30113"
-msgid "Change location 3"
+msgctxt "#32516"
+msgid "Synopsis"
 msgstr ""
diff --git a/addons/weather.wunderground/resources/language/Spanish (Argentina)/strings.po b/addons/weather.wunderground/resources/language/Spanish (Argentina)/strings.po
new file mode 100644 (file)
index 0000000..a25163a
--- /dev/null
@@ -0,0 +1,34 @@
+# XBMC Media Center language file
+# Addon Name: Weather Underground
+# Addon id: weather.wunderground
+# Addon version: 0.0.9
+# Addon Provider: Team XBMC
+msgid ""
+msgstr ""
+"Project-Id-Version: XBMC Main Translation Project (Frodo)\n"
+"Report-Msgid-Bugs-To: http://trac.xbmc.org/\n"
+"POT-Creation-Date: 2012-05-28 15:38+0000\n"
+"PO-Revision-Date: 2012-11-11 15:02+0000\n"
+"Last-Translator: XBMC Translation Team\n"
+"Language-Team: Spanish (Argentina) (http://www.transifex.com/projects/p/XBMC-Main-Frodo/language/es_AR/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: es_AR\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "#30101"
+msgid "Location Setup"
+msgstr "Configurar ubicación"
+
+msgctxt "#30111"
+msgid "Change location 1"
+msgstr "Cambiar ubicación 1"
+
+msgctxt "#30112"
+msgid "Change location 2"
+msgstr "Cambiar ubicación 2"
+
+msgctxt "#30113"
+msgid "Change location 3"
+msgstr "Cambiar ubicación 3"
index b31f732..ce9eed8 100644 (file)
@@ -1,13 +1,55 @@
-# -*- coding: utf-8 -*- 
+# -*- coding: utf-8 -*-
+
+import sys
 import xbmc
 
-DAYS = { "Mon": xbmc.getLocalizedString( 11 ),
-         "Tue": xbmc.getLocalizedString( 12 ),
-         "Wed": xbmc.getLocalizedString( 13 ),
-         "Thu": xbmc.getLocalizedString( 14 ),
-         "Fri": xbmc.getLocalizedString( 15 ),
-         "Sat": xbmc.getLocalizedString( 16 ),
-         "Sun": xbmc.getLocalizedString( 17 )}
+__language__ = sys.modules[ "__main__" ].__language__
+
+LANG = { 'afrikaans'             : 'AF',
+         'arabic'                : 'AR',
+         'basque'                : 'EU',
+         'bosnian'               : 'SR',  # n/a
+         'bulgarian'             : 'BU',
+         'catalan'               : 'CA',
+         'chinese (simple)'      : 'CN',
+         'chinese (traditional)' : 'TW',
+         'croatian'              : 'CR',
+         'czech'                 : 'CZ',
+         'danish'                : 'DK',
+         'dutch'                 : 'NL',
+         'english'               : 'LI',
+         'english (us)'          : 'EN',
+         'esperanto'             : 'EO',
+         'finnish'               : 'FI',
+         'french'                : 'FR',
+         'german'                : 'DL',
+         'greek'                 : 'GR',
+         'hebrew'                : 'IL',
+         'hindi (devanagiri)'    : 'HI',
+         'hungarian'             : 'HU',
+         'icelandic'             : 'IS',
+         'indonesian'            : 'ID',
+         'italian'               : 'IT',
+         'japanese'              : 'JP',
+         'korean'                : 'KR',
+         'lithuanian'            : 'LT',
+         'maltese'               : 'MT',
+         'norwegian'             : 'NO',
+         'polish'                : 'PL',
+         'portuguese'            : 'BR',
+         'portuguese (brazil)'   : 'BR',
+         'romanian'              : 'RO',
+         'russian'               : 'RU',
+         'serbian'               : 'SR',
+         'serbian (cyrillic)'    : 'SR',
+         'slovak'                : 'SK',
+         'slovenian'             : 'SL',
+         'spanish'               : 'SP',
+         'spanish (mexico)'      : 'SP',
+         'swedish'               : 'SW',
+         'thai'                  : 'TH',
+         'turkish'               : 'TU',
+         'ukrainian'             : 'UA'}
 
 WEATHER_CODES = { 'chanceflurries'    : '41',
                   'chancerain'        : '39',
@@ -29,6 +71,7 @@ WEATHER_CODES = { 'chanceflurries'    : '41',
                   'sunny'             : '32',
                   'tstorms'           : '35',
                   'unknown'           : 'na',
+                  ''                  : 'na',
                   'nt_chanceflurries' : '46',
                   'nt_chancerain'     : '45',
                   'nt_chancesleet'    : '45',
@@ -48,4 +91,88 @@ WEATHER_CODES = { 'chanceflurries'    : '41',
                   'nt_snow'           : '46',
                   'nt_sunny'          : '31',
                   'nt_tstorms'        : '47',
-                  'nt_unknown'        : 'na'}
+                  'nt_unknown'        : 'na',
+                  'nt_'               : 'na'}
+
+MONTH = { 1  : xbmc.getLocalizedString(51),
+          2  : xbmc.getLocalizedString(52),
+          3  : xbmc.getLocalizedString(53),
+          4  : xbmc.getLocalizedString(54),
+          5  : xbmc.getLocalizedString(55),
+          6  : xbmc.getLocalizedString(56),
+          7  : xbmc.getLocalizedString(57),
+          8  : xbmc.getLocalizedString(58),
+          9  : xbmc.getLocalizedString(59),
+          10 : xbmc.getLocalizedString(60),
+          11 : xbmc.getLocalizedString(61),
+          12 : xbmc.getLocalizedString(62)}
+
+WEEKDAY = { 0  : xbmc.getLocalizedString(41),
+            1  : xbmc.getLocalizedString(42),
+            2  : xbmc.getLocalizedString(43),
+            3  : xbmc.getLocalizedString(44),
+            4  : xbmc.getLocalizedString(45),
+            5  : xbmc.getLocalizedString(46),
+            6  : xbmc.getLocalizedString(47)}
+
+SEVERITY = { 'W' : __language__(32510),
+             'A' : __language__(32511),
+             'Y' : __language__(32512),
+             'S' : __language__(32513),
+             'O' : __language__(32514),
+             'F' : __language__(32515),
+             'N' : __language__(32516),
+             'L' :'', # no idea
+             ''  : ''}
+
+def MOONPHASE(age, percent):
+    if (percent == 0) and (age == 0):
+        phase = __language__(32501)
+    elif (age < 17) and (age > 0) and (percent > 0) and (percent < 50):
+        phase = __language__(32502)
+    elif (age < 17) and (age > 0) and (percent == 50):
+        phase = __language__(32503)
+    elif (age < 17) and (age > 0) and (percent > 50) and (percent < 100):
+        phase = __language__(32504)
+    elif (age > 0) and (percent == 100):
+        phase = __language__(32505)
+    elif (age > 15) and (percent < 100) and (percent > 50):
+        phase = __language__(32506)
+    elif (age > 15) and (percent == 50):
+        phase = __language__(32507)
+    elif (age > 15) and (percent < 50) and (percent > 0):
+        phase = __language__(32508)
+    else:
+        phase = ''
+    return phase
+
+def KPHTOBFT(spd):
+    if (spd < 1.0):
+        bft = '0'
+    elif (spd >= 1.0) and (spd < 5.6):
+        bft = '1'
+    elif (spd >= 5.6) and (spd < 12.0):
+        bft = '2'
+    elif (spd >= 12.0) and (spd < 20.0):
+        bft = '3'
+    elif (spd >= 20.0) and (spd < 29.0):
+        bft = '4'
+    elif (spd >= 29.0) and (spd < 39.0):
+        bft = '5'
+    elif (spd >= 39.0) and (spd < 50.0):
+        bft = '6'
+    elif (spd >= 50.0) and (spd < 62.0):
+        bft = '7'
+    elif (spd >= 62.0) and (spd < 75.0):
+        bft = '8'
+    elif (spd >= 75.0) and (spd < 89.0):
+        bft = '9'
+    elif (spd >= 89.0) and (spd < 103.0):
+        bft = '10'
+    elif (spd >= 103.0) and (spd < 118.0):
+        bft = '11'
+    elif (spd >= 118.0):
+        bft = '12'
+    else:
+        bft = ''
+    return bft
diff --git a/addons/weather.wunderground/resources/lib/wunderground/__init__.py b/addons/weather.wunderground/resources/lib/wunderground/__init__.py
new file mode 100644 (file)
index 0000000..b93054b
--- /dev/null
@@ -0,0 +1 @@
+# Dummy file to make this directory a package.
diff --git a/addons/weather.wunderground/resources/lib/wunderground/wunderground.py b/addons/weather.wunderground/resources/lib/wunderground/wunderground.py
new file mode 100644 (file)
index 0000000..809b583
--- /dev/null
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+
+import urllib2, base64
+
+WAIK             = 'NDEzNjBkMjFkZjFhMzczNg=='
+WUNDERGROUND_URL = 'http://api.wunderground.com/api/KEY/%s/%s/q/%s.%s'
+API_EXCLUDE      = ['hourly10day', 'yesterday', 'planner', 'webcams', 'animatedradar', 'animatedsatellite', 'currenthurricane']
+
+def wundergroundapi(features, settings, query, format):
+
+    """
+    wunderground api module
+    
+    How to use:
+    
+    1) import the wunderground addon in your addon.xml:
+            <requires>
+                <import addon="weather.wunderground" version="0.1.12"/>
+            </requires>
+    
+    2) import the wunderground api module in your script:
+            from wunderground import wundergroundapi
+    
+    3) to fetch weather data:
+            weatherdata = wundergroundapi(features, settings, query, format)
+    
+    see http://www.wunderground.com/weather/api/d/docs?d=data/index
+    for api features, optional settings, query examples and response formats.
+    """
+
+    for item in API_EXCLUDE:
+        if item in features:
+            return 'api access to %s restricted' % item
+    if not settings:
+        settings = 'lang:EN'
+    query = WUNDERGROUND_URL % (features, settings, query, format)
+    url = query.replace('KEY',(base64.b64decode(WAIK)[::-1]),1)
+    try:
+        req = urllib2.urlopen(url)
+        response = req.read()
+        req.close()
+    except:
+        response = ''
+    return response
diff --git a/addons/weather.wunderground/resources/logo/logo.jpg b/addons/weather.wunderground/resources/logo/logo.jpg
new file mode 100644 (file)
index 0000000..cc08b54
Binary files /dev/null and b/addons/weather.wunderground/resources/logo/logo.jpg differ
index 38fc86e..33dfdd5 100644 (file)
@@ -1,11 +1,27 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <settings>
-       <category label="30101">
-               <setting id="Location1" label="30111" type="action" action="RunScript($ID,Location1)" default=""/>
-               <setting id="Location2" label="30112" type="action" action="RunScript($ID,Location2)" enable="!eq( -1,)" default=""/>
-               <setting id="Location3" label="30113" type="action" action="RunScript($ID,Location3)" enable="!eq( -1,)" default=""/>
+       <category label="32101">
+               <setting id="Location1" label="32111" type="action" action="RunScript($ID,Location1)" default=""/>
+               <setting id="Location2" label="32112" type="action" action="RunScript($ID,Location2)" enable="!eq(-1,)" default=""/>
+               <setting id="Location3" label="32113" type="action" action="RunScript($ID,Location3)" enable="!eq(-1,)" default=""/>
                <setting id="Location1id" type="text" visible="false" default=""/>
                <setting id="Location2id" type="text" visible="false" default=""/>
                <setting id="Location3id" type="text" visible="false" default=""/>
        </category>
+       <category label="32102">
+               <setting id="Location1" label="32114" type="text" default=""/>
+               <setting id="Location1id" label="32117" type="text" subsetting="true" default=""/>
+               <setting type="sep"/>
+               <setting id="Location2" label="32115" type="text" enable="!eq(-3,)" default=""/>
+               <setting id="Location2id" label="32118" type="text" subsetting="true" enable="!eq(-3,)" default=""/>
+               <setting type="sep"/>
+               <setting id="Location3" label="32116" type="text" enable="!eq(-3,)" default=""/>
+               <setting id="Location3id" label="32119" type="text" subsetting="true" enable="!eq(-3,)" default=""/>
+               <setting type="sep"/>
+               <setting id="Zoom" label="32125" type="slider" option="int" range="1,100"  default="10"/>
+               <setting id="Animate" label="32126" type="bool" default="false"/>
+               <setting id="Weekend" label="32121" type="enum" lvalues="32122|32123|32124" default="0"/>
+               <setting type="sep"/>
+               <setting id="Debug" label="32120" type="bool" default="false"/>
+       </category>
 </settings>