Kodi Community Forum
Broken Yahoo! Weather - Printable Version

Kodi Community Forum (https://forum.kodi.tv)
+-- Forum: Support (https://forum.kodi.tv/forumdisplay.php?fid=33)
+--- Forum: Add-on Support (https://forum.kodi.tv/forumdisplay.php?fid=27)
+---- Forum: Weather Add-ons (https://forum.kodi.tv/forumdisplay.php?fid=155)
---- Thread: Broken Yahoo! Weather (/showthread.php?tid=169410)

Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34


RE: [RELEASE] Yahoo! Weather - mentat - 2016-03-26

(2016-03-26, 17:30)UncleBrian Wrote: The Weather Underground add-on isn't in the repository anymore - how were you able to install to use the dev key? I will likely do this as well; none of the US weather providers in the repository (including Open Weathermap) appear to be working at all now.

http://forum.kodi.tv/showthread.php?tid=116668

For Kodi 16.0 Jarvis (and up...)

This addon requires a personal API Key!


RE: [RELEASE] Yahoo! Weather - pagali - 2016-03-26

(2016-03-26, 17:30)UncleBrian Wrote: The Weather Underground add-on isn't in the repository anymore - how were you able to install to use the dev key? I will likely do this as well.

I also installed the WU addon yesterday, it was right there in the Kodi repository.

(Kodi 16, Windows 7)

Getting the API key only took about 5 minutes, was free, and easy.


Yahoo! Weather API Changes and Fix - haxobel - 2016-03-27

Yahoo! made a change to their weather API authentication rules on 15/03/2016 (See https://developer.yahoo.com/weather/) which broke many applications using their weather service including my Kodi installations. I have changed the KODI Yahoo! Weather add-on (default.py) to use YQL over SSL to fetch the weather instead of the RSS feed API which is used in version 3.0.9. The code is actually much neater using JSON instead of XML. This fixed my issue.

Here is the working default.py code. It would be nice if ronie could update the addon in the KODI repository if the code is deemed to work. In the meantime, you can backup your current default.py and replace it with this code (be careful with Python indenting). Hope it's nice weather where you live Smile

Code:
import os, sys, socket, urllib2
from xml.dom import minidom
import xbmc, xbmcgui, xbmcaddon
if sys.version_info < (2, 7):
    import simplejson
else:
    import json as simplejson

ADDON        = xbmcaddon.Addon()
ADDONNAME    = ADDON.getAddonInfo('name')
ADDONID      = ADDON.getAddonInfo('id')
ADDONVERSION = ADDON.getAddonInfo('version')
CWD          = ADDON.getAddonInfo('path').decode("utf-8")
RESOURCE     = xbmc.translatePath( os.path.join( CWD, 'resources', 'lib' ).encode("utf-8") ).decode("utf-8")

sys.path.append(RESOURCE)

from utilities import *

YQL_URL          = 'https://query.yahooapis.com/v1/public/yql?q=%s&format=json'
LOC_QUERY        = 'select * from geo.places where text="%s"'
FORECAST_QUERY   = 'select * from weather.forecast where woeid=%s and u="c"'
WEATHER_ICON     = xbmc.translatePath('special://temp/weather/%s.png').decode("utf-8")
WEATHER_WINDOW   = xbmcgui.Window(12600)

socket.setdefaulttimeout(10)

def log(txt):
    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():
    locations = 0
    for count in range(1, 6):
        loc_name = ADDON.getSetting('Location%s' % count)
        if loc_name != '':
            locations += 1
        set_property('Location%s' % count, loc_name)
    set_property('Locations', str(locations))
    log('available locations: %s' % str(locations))

def location(loc):
    items  = []
    locs   = []
    locids = []
    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('query') and data['query'].has_key('results') and data['query']['results'].has_key('place'):
        if isinstance (data['query']['results']['place'],list):
            for item in data['query']['results']['place']:
                listitem = item['name'] + ' (' + (item['admin1']['content'] + ' - ' if item['admin1'] is not None else '') + item['country']['code'] + ')'
                location   = item['name'] + ' (' + item['country']['code'] + ')'
                locationid = item['woeid']
                items.append(listitem)
                locs.append(location)
                locids.append(locationid)
        else:
            listitem   = data['query']['results']['place']['name'] + ' (' + data['query']['results']['place']['admin1']['content'] + ' - ' + data['query']['results']['place']['country']['code'] + ')'
            location   = data['query']['results']['place']['name'] + ' (' + data['query']['results']['place']['country']['code'] + ')'
            locationid = data['query']['results']['place']['woeid']
            items.append(listitem)
            locs.append(location)
            locids.append(locationid)
    return items, locs, locids

def find_location(loc):
    query = urllib2.quote(LOC_QUERY % loc)
    url = YQL_URL % query
    try:
        req = urllib2.urlopen(url)
        response = req.read()
        req.close()
    except:
        response = ''
    return response

def parse_data(reply):
    try:
        data = simplejson.loads(reply)
    except:
        log('failed to parse weather data')
        data = ''
    return data

def forecast(loc,locid):
    log('weather location: %s' % locid)
    retry = 0
    while (retry < 6) and (not MONITOR.abortRequested()):
        query = get_weather(locid)
        if query != '':
            retry = 6
        else:
            retry += 1
            xbmc.sleep(10000)
            log('weather download failed')
    log('forecast data: %s' % query)
    if query != '':
        properties(query,loc)
    else:
        clear()

def get_weather(locid):
    query = urllib2.quote(FORECAST_QUERY % locid)
    url = YQL_URL % query
    try:
        req = urllib2.urlopen(url)
        response = req.read()
        req.close()
    except:
        response = ''
    return response
    
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, 5):
        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 properties(data,loc):
    json = parse_data(data)
    wind = json['query']['results']['channel']['wind']
    atmosphere = json['query']['results']['channel']['atmosphere']
    astronomy = json['query']['results']['channel']['astronomy']
    condition = json['query']['results']['channel']['item']['condition']
    forecast = json['query']['results']['channel']['item']['forecast']
    set_property('Current.Location'      , loc)
    set_property('Current.Condition'     , condition['text'].replace('/', ' / '))
    set_property('Current.Temperature'   , condition['temp'])
    set_property('Current.Wind'          , wind['speed'])
    if (wind['direction'] != ''):
        set_property('Current.WindDirection' , winddir(int(wind['direction'])))
    else:
        set_property('Current.WindDirection' , '')
    set_property('Current.WindChill'     , wind['chill'])
    set_property('Current.Humidity'      , atmosphere['humidity'])
    set_property('Current.Visibility'    , atmosphere['visibility'])
    set_property('Current.Pressure'      , atmosphere['pressure'])
    if (wind['speed'] != ''):
        set_property('Current.FeelsLike'     , feelslike(int(condition['temp']), int(round(float(wind['speed']) + 0.5))))
    else:
        set_property('Current.FeelsLike' , '')
    if (condition['temp'] != '') and (atmosphere['humidity'] != ''):
        set_property('Current.DewPoint'      , dewpoint(int(condition['temp']), int(atmosphere['humidity'])))
    else:
        set_property('Current.DewPoint' , '')
    set_property('Current.UVIndex'       , '')
    set_property('Current.OutlookIcon'   , '%s.png' % condition['code']) # Kodi translates it to Current.ConditionIcon
    set_property('Current.FanartCode'    , condition['code'])
    set_property('Today.Sunrise'         , astronomy['sunrise'])
    set_property('Today.Sunset'          , astronomy['sunset'])
    for count, item in enumerate(forecast):
        set_property('Day%i.Title'       % count, DAYS[item['day']])
        set_property('Day%i.HighTemp'    % count, item['high'])
        set_property('Day%i.LowTemp'     % count, item['low'])
        set_property('Day%i.Outlook'     % count, item['text'].replace('/', ' / '))
        set_property('Day%i.OutlookIcon' % count, '%s.png' % item['code'])
        set_property('Day%i.FanartCode'  % count, item['code'])

class MyMonitor(xbmc.Monitor):
    def __init__(self, *args, **kwargs):
        xbmc.Monitor.__init__(self)

log('version %s started: %s' % (ADDONVERSION, sys.argv))

MONITOR = MyMonitor()
set_property('Forecast.IsFetched' , '')
set_property('Current.IsFetched'  , '')
set_property('Today.IsFetched'    , '')
set_property('Daily.IsFetched'    , '')
set_property('Weekend.IsFetched'  , '')
set_property('36Hour.IsFetched'   , '')
set_property('Hourly.IsFetched'   , '')
set_property('Alerts.IsFetched'   , '')
set_property('Map.IsFetched'      , '')
set_property('WeatherProvider'    , ADDONNAME)
set_property('WeatherProviderLogo', xbmc.translatePath(os.path.join(CWD, 'resources', 'banner.png')))

if sys.argv[1].startswith('Location'):
    keyboard = xbmc.Keyboard('', xbmc.getLocalizedString(14024), False)
    keyboard.doModal()
    if (keyboard.isConfirmed() and keyboard.getText() != ''):
        text = keyboard.getText()
        items, locs, locids = location(text)
        dialog = xbmcgui.Dialog()
        if locs != []:
            selected = dialog.select(xbmc.getLocalizedString(396), items)
            if selected != -1:
                ADDON.setSetting(sys.argv[1], locs[selected])
                ADDON.setSetting(sys.argv[1] + 'id', locids[selected])
                log('selected location: %s' % locs[selected])
        else:
            log('no locations found')
            dialog.ok(ADDONNAME, xbmc.getLocalizedString(284))
else:
    location = ADDON.getSetting('Location%s' % sys.argv[1])
    locationid = ADDON.getSetting('Location%sid' % sys.argv[1])
    if (locationid == '') and (sys.argv[1] != '1'):
        location = ADDON.getSetting('Location1')
        locationid = ADDON.getSetting('Location1id')
        log('trying location 1 instead')
    if not locationid == '':
        forecast(location, locationid)
    else:
        log('empty location id')
        clear()
    refresh_locations()

log('finished')



RE: [RELEASE] Yahoo! Weather - NicCo - 2016-03-27

I've tried and it seems to work very well, thank you !


RE: [RELEASE] Yahoo! Weather - OTinley - 2016-03-27

DISREGARD- CAN NO LONGER REPRODUCE ERROR-

Thank you Haxobel.
I am using version 3.09 by Roni which allowed up to 5 different locations.
I can switch to 3 then it errors out on the 4th & 5th with the following error.

Code:
ERROR: EXCEPTION Thrown (PythonToCppException) : -->Python callback/script returned the following error<--
                                             - NOTE: IGNORING THIS CAN LEAD TO MEMORY LEAKS!
                                            Error Type: <type 'exceptions.TypeError'>
                                            Error Contents: 'NoneType' object has no attribute '__getitem__'
                                            Traceback (most recent call last):
                                              File "C:\Users\DumbUser\AppData\Roaming\Kodi\addons\weather.yahoo\default.py", line 222, in <module>
                                                forecast(location, locationid)
                                              File "C:\Users\DumbUser\AppData\Roaming\Kodi\addons\weather.yahoo\default.py", line 105, in forecast
                                                properties(query,loc)
                                              File "C:\Users\DumbUser\AppData\Roaming\Kodi\addons\weather.yahoo\default.py", line 141, in properties
                                                wind = json['query']['results']['channel']['wind']
                                            TypeError: 'NoneType' object has no attribute '__getitem__'
                                            -->End of Python script error report<--
12:56:26 T:5208   ERROR: Previous line repeats 2 times.
12:56:26 T:5208   ERROR: XFILE::CDirectory::GetDirectory - Error getting Weather
[/code]



RE: [RELEASE] Yahoo! Weather - OTinley - 2016-03-27

Haxobel,
Disregard previous post as I can no longer reproduce the error.
All 5 locations cycle just fine now.
Thanks again.


RE: [RELEASE] Yahoo! Weather - alphaomega16 - 2016-03-27

(2016-03-27, 00:12)haxobel Wrote: Yahoo! made a change to their weather API authentication rules on 15/03/2016 (See https://developer.yahoo.com/weather/) which broke many applications using their weather service including my Kodi installations. I have changed the KODI Yahoo! Weather add-on (default.py) to use YQL over SSL to fetch the weather instead of the RSS feed API which is used in version 3.0.9. The code is actually much neater using JSON instead of XML. This fixed my issue.

Here is the working default.py code. It would be nice if ronie could update the addon in the KODI repository if the code is deemed to work. In the meantime, you can backup your current default.py and replace it with this code (be careful with Python indenting). Hope it's nice weather where you live Smile

Code:
import os, sys, socket, urllib2
from xml.dom import minidom
import xbmc, xbmcgui, xbmcaddon
if sys.version_info < (2, 7):
    import simplejson
else:
    import json as simplejson

ADDON        = xbmcaddon.Addon()
ADDONNAME    = ADDON.getAddonInfo('name')
ADDONID      = ADDON.getAddonInfo('id')
ADDONVERSION = ADDON.getAddonInfo('version')
CWD          = ADDON.getAddonInfo('path').decode("utf-8")
RESOURCE     = xbmc.translatePath( os.path.join( CWD, 'resources', 'lib' ).encode("utf-8") ).decode("utf-8")

sys.path.append(RESOURCE)

from utilities import *

YQL_URL          = 'https://query.yahooapis.com/v1/public/yql?q=%s&format=json'
LOC_QUERY        = 'select * from geo.places where text="%s"'
FORECAST_QUERY   = 'select * from weather.forecast where woeid=%s and u="c"'
WEATHER_ICON     = xbmc.translatePath('special://temp/weather/%s.png').decode("utf-8")
WEATHER_WINDOW   = xbmcgui.Window(12600)

socket.setdefaulttimeout(10)

def log(txt):
    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():
    locations = 0
    for count in range(1, 6):
        loc_name = ADDON.getSetting('Location%s' % count)
        if loc_name != '':
            locations += 1
        set_property('Location%s' % count, loc_name)
    set_property('Locations', str(locations))
    log('available locations: %s' % str(locations))

def location(loc):
    items  = []
    locs   = []
    locids = []
    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('query') and data['query'].has_key('results') and data['query']['results'].has_key('place'):
        if isinstance (data['query']['results']['place'],list):
            for item in data['query']['results']['place']:
                listitem = item['name'] + ' (' + (item['admin1']['content'] + ' - ' if item['admin1'] is not None else '') + item['country']['code'] + ')'
                location   = item['name'] + ' (' + item['country']['code'] + ')'
                locationid = item['woeid']
                items.append(listitem)
                locs.append(location)
                locids.append(locationid)
        else:
            listitem   = data['query']['results']['place']['name'] + ' (' + data['query']['results']['place']['admin1']['content'] + ' - ' + data['query']['results']['place']['country']['code'] + ')'
            location   = data['query']['results']['place']['name'] + ' (' + data['query']['results']['place']['country']['code'] + ')'
            locationid = data['query']['results']['place']['woeid']
            items.append(listitem)
            locs.append(location)
            locids.append(locationid)
    return items, locs, locids

def find_location(loc):
    query = urllib2.quote(LOC_QUERY % loc)
    url = YQL_URL % query
    try:
        req = urllib2.urlopen(url)
        response = req.read()
        req.close()
    except:
        response = ''
    return response

def parse_data(reply):
    try:
        data = simplejson.loads(reply)
    except:
        log('failed to parse weather data')
        data = ''
    return data

def forecast(loc,locid):
    log('weather location: %s' % locid)
    retry = 0
    while (retry < 6) and (not MONITOR.abortRequested()):
        query = get_weather(locid)
        if query != '':
            retry = 6
        else:
            retry += 1
            xbmc.sleep(10000)
            log('weather download failed')
    log('forecast data: %s' % query)
    if query != '':
        properties(query,loc)
    else:
        clear()

def get_weather(locid):
    query = urllib2.quote(FORECAST_QUERY % locid)
    url = YQL_URL % query
    try:
        req = urllib2.urlopen(url)
        response = req.read()
        req.close()
    except:
        response = ''
    return response
    
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, 5):
        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 properties(data,loc):
    json = parse_data(data)
    wind = json['query']['results']['channel']['wind']
    atmosphere = json['query']['results']['channel']['atmosphere']
    astronomy = json['query']['results']['channel']['astronomy']
    condition = json['query']['results']['channel']['item']['condition']
    forecast = json['query']['results']['channel']['item']['forecast']
    set_property('Current.Location'      , loc)
    set_property('Current.Condition'     , condition['text'].replace('/', ' / '))
    set_property('Current.Temperature'   , condition['temp'])
    set_property('Current.Wind'          , wind['speed'])
    if (wind['direction'] != ''):
        set_property('Current.WindDirection' , winddir(int(wind['direction'])))
    else:
        set_property('Current.WindDirection' , '')
    set_property('Current.WindChill'     , wind['chill'])
    set_property('Current.Humidity'      , atmosphere['humidity'])
    set_property('Current.Visibility'    , atmosphere['visibility'])
    set_property('Current.Pressure'      , atmosphere['pressure'])
    if (wind['speed'] != ''):
        set_property('Current.FeelsLike'     , feelslike(int(condition['temp']), int(round(float(wind['speed']) + 0.5))))
    else:
        set_property('Current.FeelsLike' , '')
    if (condition['temp'] != '') and (atmosphere['humidity'] != ''):
        set_property('Current.DewPoint'      , dewpoint(int(condition['temp']), int(atmosphere['humidity'])))
    else:
        set_property('Current.DewPoint' , '')
    set_property('Current.UVIndex'       , '')
    set_property('Current.OutlookIcon'   , '%s.png' % condition['code']) # Kodi translates it to Current.ConditionIcon
    set_property('Current.FanartCode'    , condition['code'])
    set_property('Today.Sunrise'         , astronomy['sunrise'])
    set_property('Today.Sunset'          , astronomy['sunset'])
    for count, item in enumerate(forecast):
        set_property('Day%i.Title'       % count, DAYS[item['day']])
        set_property('Day%i.HighTemp'    % count, item['high'])
        set_property('Day%i.LowTemp'     % count, item['low'])
        set_property('Day%i.Outlook'     % count, item['text'].replace('/', ' / '))
        set_property('Day%i.OutlookIcon' % count, '%s.png' % item['code'])
        set_property('Day%i.FanartCode'  % count, item['code'])

class MyMonitor(xbmc.Monitor):
    def __init__(self, *args, **kwargs):
        xbmc.Monitor.__init__(self)

log('version %s started: %s' % (ADDONVERSION, sys.argv))

MONITOR = MyMonitor()
set_property('Forecast.IsFetched' , '')
set_property('Current.IsFetched'  , '')
set_property('Today.IsFetched'    , '')
set_property('Daily.IsFetched'    , '')
set_property('Weekend.IsFetched'  , '')
set_property('36Hour.IsFetched'   , '')
set_property('Hourly.IsFetched'   , '')
set_property('Alerts.IsFetched'   , '')
set_property('Map.IsFetched'      , '')
set_property('WeatherProvider'    , ADDONNAME)
set_property('WeatherProviderLogo', xbmc.translatePath(os.path.join(CWD, 'resources', 'banner.png')))

if sys.argv[1].startswith('Location'):
    keyboard = xbmc.Keyboard('', xbmc.getLocalizedString(14024), False)
    keyboard.doModal()
    if (keyboard.isConfirmed() and keyboard.getText() != ''):
        text = keyboard.getText()
        items, locs, locids = location(text)
        dialog = xbmcgui.Dialog()
        if locs != []:
            selected = dialog.select(xbmc.getLocalizedString(396), items)
            if selected != -1:
                ADDON.setSetting(sys.argv[1], locs[selected])
                ADDON.setSetting(sys.argv[1] + 'id', locids[selected])
                log('selected location: %s' % locs[selected])
        else:
            log('no locations found')
            dialog.ok(ADDONNAME, xbmc.getLocalizedString(284))
else:
    location = ADDON.getSetting('Location%s' % sys.argv[1])
    locationid = ADDON.getSetting('Location%sid' % sys.argv[1])
    if (locationid == '') and (sys.argv[1] != '1'):
        location = ADDON.getSetting('Location1')
        locationid = ADDON.getSetting('Location1id')
        log('trying location 1 instead')
    if not locationid == '':
        forecast(location, locationid)
    else:
        log('empty location id')
        clear()
    refresh_locations()

log('finished')

Oh you diamond, working again.


RE: [RELEASE] Yahoo! Weather - haxobel - 2016-03-27

(2016-03-27, 00:53)OTinley Wrote: DISREGARD- CAN NO LONGER REPRODUCE ERROR-
...
I can switch to 3 then it errors out on the 4th & 5th with the following error.
....

I also received the error that you posted. Only once, and it hasn't happened since. I didn't change the error handling in the code, but it hides the real problem. The problem is most likely the connection, timeout or response from Yahoo! which should be easy enough to get around (unless Yahoo decides to change the security in the YQL calls). I will alter the error handling after work tonight so that people can post any issues and the log will represent the root cause of the problem.


RE: [RELEASE] Yahoo! Weather - ronie - 2016-03-27

[quote='haxobel' pid='2293225' dateline='1459030327

Here is the working default.py code. It would be nice if ronie could update the addon in the KODI repository if the code is deemed to work. In the meantime, you can backup your current default.py and replace it with this code (be careful with Python indenting). Hope it's nice weather where you live :)
[/quote]

thanx for the code haxobel!

i haven't had the time to look into it myself yet.
i'll review your changes sometime next week and update the addon in the repo accordingly.


RE: [RELEASE] Yahoo! Weather - ShlomiD - 2016-03-27

(2016-03-27, 00:12)haxobel Wrote: Yahoo! made a change to their weather API authentication rules on 15/03/2016 (See https://developer.yahoo.com/weather/) which broke many applications using their weather service including my Kodi installations. I have changed the KODI Yahoo! Weather add-on (default.py) to use YQL over SSL to fetch the weather instead of the RSS feed API which is used in version 3.0.9. The code is actually much neater using JSON instead of XML. This fixed my issue.

Here is the working default.py code. It would be nice if ronie could update the addon in the KODI repository if the code is deemed to work. In the meantime, you can backup your current default.py and replace it with this code (be careful with Python indenting). Hope it's nice weather where you live Smile

Code:
import os, sys, socket, urllib2
from xml.dom import minidom
import xbmc, xbmcgui, xbmcaddon
if sys.version_info < (2, 7):
    import simplejson
else:
    import json as simplejson

ADDON        = xbmcaddon.Addon()
ADDONNAME    = ADDON.getAddonInfo('name')
ADDONID      = ADDON.getAddonInfo('id')
ADDONVERSION = ADDON.getAddonInfo('version')
CWD          = ADDON.getAddonInfo('path').decode("utf-8")
RESOURCE     = xbmc.translatePath( os.path.join( CWD, 'resources', 'lib' ).encode("utf-8") ).decode("utf-8")

sys.path.append(RESOURCE)

from utilities import *

YQL_URL          = 'https://query.yahooapis.com/v1/public/yql?q=%s&format=json'
LOC_QUERY        = 'select * from geo.places where text="%s"'
FORECAST_QUERY   = 'select * from weather.forecast where woeid=%s and u="c"'
WEATHER_ICON     = xbmc.translatePath('special://temp/weather/%s.png').decode("utf-8")
WEATHER_WINDOW   = xbmcgui.Window(12600)

socket.setdefaulttimeout(10)

def log(txt):
    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():
    locations = 0
    for count in range(1, 6):
        loc_name = ADDON.getSetting('Location%s' % count)
        if loc_name != '':
            locations += 1
        set_property('Location%s' % count, loc_name)
    set_property('Locations', str(locations))
    log('available locations: %s' % str(locations))

def location(loc):
    items  = []
    locs   = []
    locids = []
    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('query') and data['query'].has_key('results') and data['query']['results'].has_key('place'):
        if isinstance (data['query']['results']['place'],list):
            for item in data['query']['results']['place']:
                listitem = item['name'] + ' (' + (item['admin1']['content'] + ' - ' if item['admin1'] is not None else '') + item['country']['code'] + ')'
                location   = item['name'] + ' (' + item['country']['code'] + ')'
                locationid = item['woeid']
                items.append(listitem)
                locs.append(location)
                locids.append(locationid)
        else:
            listitem   = data['query']['results']['place']['name'] + ' (' + data['query']['results']['place']['admin1']['content'] + ' - ' + data['query']['results']['place']['country']['code'] + ')'
            location   = data['query']['results']['place']['name'] + ' (' + data['query']['results']['place']['country']['code'] + ')'
            locationid = data['query']['results']['place']['woeid']
            items.append(listitem)
            locs.append(location)
            locids.append(locationid)
    return items, locs, locids

def find_location(loc):
    query = urllib2.quote(LOC_QUERY % loc)
    url = YQL_URL % query
    try:
        req = urllib2.urlopen(url)
        response = req.read()
        req.close()
    except:
        response = ''
    return response

def parse_data(reply):
    try:
        data = simplejson.loads(reply)
    except:
        log('failed to parse weather data')
        data = ''
    return data

def forecast(loc,locid):
    log('weather location: %s' % locid)
    retry = 0
    while (retry < 6) and (not MONITOR.abortRequested()):
        query = get_weather(locid)
        if query != '':
            retry = 6
        else:
            retry += 1
            xbmc.sleep(10000)
            log('weather download failed')
    log('forecast data: %s' % query)
    if query != '':
        properties(query,loc)
    else:
        clear()

def get_weather(locid):
    query = urllib2.quote(FORECAST_QUERY % locid)
    url = YQL_URL % query
    try:
        req = urllib2.urlopen(url)
        response = req.read()
        req.close()
    except:
        response = ''
    return response
    
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, 5):
        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 properties(data,loc):
    json = parse_data(data)
    wind = json['query']['results']['channel']['wind']
    atmosphere = json['query']['results']['channel']['atmosphere']
    astronomy = json['query']['results']['channel']['astronomy']
    condition = json['query']['results']['channel']['item']['condition']
    forecast = json['query']['results']['channel']['item']['forecast']
    set_property('Current.Location'      , loc)
    set_property('Current.Condition'     , condition['text'].replace('/', ' / '))
    set_property('Current.Temperature'   , condition['temp'])
    set_property('Current.Wind'          , wind['speed'])
    if (wind['direction'] != ''):
        set_property('Current.WindDirection' , winddir(int(wind['direction'])))
    else:
        set_property('Current.WindDirection' , '')
    set_property('Current.WindChill'     , wind['chill'])
    set_property('Current.Humidity'      , atmosphere['humidity'])
    set_property('Current.Visibility'    , atmosphere['visibility'])
    set_property('Current.Pressure'      , atmosphere['pressure'])
    if (wind['speed'] != ''):
        set_property('Current.FeelsLike'     , feelslike(int(condition['temp']), int(round(float(wind['speed']) + 0.5))))
    else:
        set_property('Current.FeelsLike' , '')
    if (condition['temp'] != '') and (atmosphere['humidity'] != ''):
        set_property('Current.DewPoint'      , dewpoint(int(condition['temp']), int(atmosphere['humidity'])))
    else:
        set_property('Current.DewPoint' , '')
    set_property('Current.UVIndex'       , '')
    set_property('Current.OutlookIcon'   , '%s.png' % condition['code']) # Kodi translates it to Current.ConditionIcon
    set_property('Current.FanartCode'    , condition['code'])
    set_property('Today.Sunrise'         , astronomy['sunrise'])
    set_property('Today.Sunset'          , astronomy['sunset'])
    for count, item in enumerate(forecast):
        set_property('Day%i.Title'       % count, DAYS[item['day']])
        set_property('Day%i.HighTemp'    % count, item['high'])
        set_property('Day%i.LowTemp'     % count, item['low'])
        set_property('Day%i.Outlook'     % count, item['text'].replace('/', ' / '))
        set_property('Day%i.OutlookIcon' % count, '%s.png' % item['code'])
        set_property('Day%i.FanartCode'  % count, item['code'])

class MyMonitor(xbmc.Monitor):
    def __init__(self, *args, **kwargs):
        xbmc.Monitor.__init__(self)

log('version %s started: %s' % (ADDONVERSION, sys.argv))

MONITOR = MyMonitor()
set_property('Forecast.IsFetched' , '')
set_property('Current.IsFetched'  , '')
set_property('Today.IsFetched'    , '')
set_property('Daily.IsFetched'    , '')
set_property('Weekend.IsFetched'  , '')
set_property('36Hour.IsFetched'   , '')
set_property('Hourly.IsFetched'   , '')
set_property('Alerts.IsFetched'   , '')
set_property('Map.IsFetched'      , '')
set_property('WeatherProvider'    , ADDONNAME)
set_property('WeatherProviderLogo', xbmc.translatePath(os.path.join(CWD, 'resources', 'banner.png')))

if sys.argv[1].startswith('Location'):
    keyboard = xbmc.Keyboard('', xbmc.getLocalizedString(14024), False)
    keyboard.doModal()
    if (keyboard.isConfirmed() and keyboard.getText() != ''):
        text = keyboard.getText()
        items, locs, locids = location(text)
        dialog = xbmcgui.Dialog()
        if locs != []:
            selected = dialog.select(xbmc.getLocalizedString(396), items)
            if selected != -1:
                ADDON.setSetting(sys.argv[1], locs[selected])
                ADDON.setSetting(sys.argv[1] + 'id', locids[selected])
                log('selected location: %s' % locs[selected])
        else:
            log('no locations found')
            dialog.ok(ADDONNAME, xbmc.getLocalizedString(284))
else:
    location = ADDON.getSetting('Location%s' % sys.argv[1])
    locationid = ADDON.getSetting('Location%sid' % sys.argv[1])
    if (locationid == '') and (sys.argv[1] != '1'):
        location = ADDON.getSetting('Location1')
        locationid = ADDON.getSetting('Location1id')
        log('trying location 1 instead')
    if not locationid == '':
        forecast(location, locationid)
    else:
        log('empty location id')
        clear()
    refresh_locations()

log('finished')

thank you, working great again.


RE: [RELEASE] Yahoo! Weather - great_vc - 2016-03-27

(2016-03-27, 00:12)haxobel Wrote: Yahoo! made a change to their weather API authentication rules on 15/03/2016 (See https://developer.yahoo.com/weather/) which broke many applications using their weather service including my Kodi installations. I have changed the KODI Yahoo! Weather add-on (default.py) to use YQL over SSL to fetch the weather instead of the RSS feed API which is used in version 3.0.9. The code is actually much neater using JSON instead of XML. This fixed my issue.

Here is the working default.py code. It would be nice if ronie could update the addon in the KODI repository if the code is deemed to work. In the meantime, you can backup your current default.py and replace it with this code (be careful with Python indenting). Hope it's nice weather where you live Smile

Code:
import os, sys, socket, urllib2
from xml.dom import minidom
import xbmc, xbmcgui, xbmcaddon
if sys.version_info < (2, 7):
    import simplejson
else:
    import json as simplejson

ADDON        = xbmcaddon.Addon()
ADDONNAME    = ADDON.getAddonInfo('name')
ADDONID      = ADDON.getAddonInfo('id')
ADDONVERSION = ADDON.getAddonInfo('version')
CWD          = ADDON.getAddonInfo('path').decode("utf-8")
RESOURCE     = xbmc.translatePath( os.path.join( CWD, 'resources', 'lib' ).encode("utf-8") ).decode("utf-8")

sys.path.append(RESOURCE)

from utilities import *

YQL_URL          = 'https://query.yahooapis.com/v1/public/yql?q=%s&format=json'
LOC_QUERY        = 'select * from geo.places where text="%s"'
FORECAST_QUERY   = 'select * from weather.forecast where woeid=%s and u="c"'
WEATHER_ICON     = xbmc.translatePath('special://temp/weather/%s.png').decode("utf-8")
WEATHER_WINDOW   = xbmcgui.Window(12600)

socket.setdefaulttimeout(10)

def log(txt):
    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():
    locations = 0
    for count in range(1, 6):
        loc_name = ADDON.getSetting('Location%s' % count)
        if loc_name != '':
            locations += 1
        set_property('Location%s' % count, loc_name)
    set_property('Locations', str(locations))
    log('available locations: %s' % str(locations))

def location(loc):
    items  = []
    locs   = []
    locids = []
    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('query') and data['query'].has_key('results') and data['query']['results'].has_key('place'):
        if isinstance (data['query']['results']['place'],list):
            for item in data['query']['results']['place']:
                listitem = item['name'] + ' (' + (item['admin1']['content'] + ' - ' if item['admin1'] is not None else '') + item['country']['code'] + ')'
                location   = item['name'] + ' (' + item['country']['code'] + ')'
                locationid = item['woeid']
                items.append(listitem)
                locs.append(location)
                locids.append(locationid)
        else:
            listitem   = data['query']['results']['place']['name'] + ' (' + data['query']['results']['place']['admin1']['content'] + ' - ' + data['query']['results']['place']['country']['code'] + ')'
            location   = data['query']['results']['place']['name'] + ' (' + data['query']['results']['place']['country']['code'] + ')'
            locationid = data['query']['results']['place']['woeid']
            items.append(listitem)
            locs.append(location)
            locids.append(locationid)
    return items, locs, locids

def find_location(loc):
    query = urllib2.quote(LOC_QUERY % loc)
    url = YQL_URL % query
    try:
        req = urllib2.urlopen(url)
        response = req.read()
        req.close()
    except:
        response = ''
    return response

def parse_data(reply):
    try:
        data = simplejson.loads(reply)
    except:
        log('failed to parse weather data')
        data = ''
    return data

def forecast(loc,locid):
    log('weather location: %s' % locid)
    retry = 0
    while (retry < 6) and (not MONITOR.abortRequested()):
        query = get_weather(locid)
        if query != '':
            retry = 6
        else:
            retry += 1
            xbmc.sleep(10000)
            log('weather download failed')
    log('forecast data: %s' % query)
    if query != '':
        properties(query,loc)
    else:
        clear()

def get_weather(locid):
    query = urllib2.quote(FORECAST_QUERY % locid)
    url = YQL_URL % query
    try:
        req = urllib2.urlopen(url)
        response = req.read()
        req.close()
    except:
        response = ''
    return response
    
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, 5):
        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 properties(data,loc):
    json = parse_data(data)
    wind = json['query']['results']['channel']['wind']
    atmosphere = json['query']['results']['channel']['atmosphere']
    astronomy = json['query']['results']['channel']['astronomy']
    condition = json['query']['results']['channel']['item']['condition']
    forecast = json['query']['results']['channel']['item']['forecast']
    set_property('Current.Location'      , loc)
    set_property('Current.Condition'     , condition['text'].replace('/', ' / '))
    set_property('Current.Temperature'   , condition['temp'])
    set_property('Current.Wind'          , wind['speed'])
    if (wind['direction'] != ''):
        set_property('Current.WindDirection' , winddir(int(wind['direction'])))
    else:
        set_property('Current.WindDirection' , '')
    set_property('Current.WindChill'     , wind['chill'])
    set_property('Current.Humidity'      , atmosphere['humidity'])
    set_property('Current.Visibility'    , atmosphere['visibility'])
    set_property('Current.Pressure'      , atmosphere['pressure'])
    if (wind['speed'] != ''):
        set_property('Current.FeelsLike'     , feelslike(int(condition['temp']), int(round(float(wind['speed']) + 0.5))))
    else:
        set_property('Current.FeelsLike' , '')
    if (condition['temp'] != '') and (atmosphere['humidity'] != ''):
        set_property('Current.DewPoint'      , dewpoint(int(condition['temp']), int(atmosphere['humidity'])))
    else:
        set_property('Current.DewPoint' , '')
    set_property('Current.UVIndex'       , '')
    set_property('Current.OutlookIcon'   , '%s.png' % condition['code']) # Kodi translates it to Current.ConditionIcon
    set_property('Current.FanartCode'    , condition['code'])
    set_property('Today.Sunrise'         , astronomy['sunrise'])
    set_property('Today.Sunset'          , astronomy['sunset'])
    for count, item in enumerate(forecast):
        set_property('Day%i.Title'       % count, DAYS[item['day']])
        set_property('Day%i.HighTemp'    % count, item['high'])
        set_property('Day%i.LowTemp'     % count, item['low'])
        set_property('Day%i.Outlook'     % count, item['text'].replace('/', ' / '))
        set_property('Day%i.OutlookIcon' % count, '%s.png' % item['code'])
        set_property('Day%i.FanartCode'  % count, item['code'])

class MyMonitor(xbmc.Monitor):
    def __init__(self, *args, **kwargs):
        xbmc.Monitor.__init__(self)

log('version %s started: %s' % (ADDONVERSION, sys.argv))

MONITOR = MyMonitor()
set_property('Forecast.IsFetched' , '')
set_property('Current.IsFetched'  , '')
set_property('Today.IsFetched'    , '')
set_property('Daily.IsFetched'    , '')
set_property('Weekend.IsFetched'  , '')
set_property('36Hour.IsFetched'   , '')
set_property('Hourly.IsFetched'   , '')
set_property('Alerts.IsFetched'   , '')
set_property('Map.IsFetched'      , '')
set_property('WeatherProvider'    , ADDONNAME)
set_property('WeatherProviderLogo', xbmc.translatePath(os.path.join(CWD, 'resources', 'banner.png')))

if sys.argv[1].startswith('Location'):
    keyboard = xbmc.Keyboard('', xbmc.getLocalizedString(14024), False)
    keyboard.doModal()
    if (keyboard.isConfirmed() and keyboard.getText() != ''):
        text = keyboard.getText()
        items, locs, locids = location(text)
        dialog = xbmcgui.Dialog()
        if locs != []:
            selected = dialog.select(xbmc.getLocalizedString(396), items)
            if selected != -1:
                ADDON.setSetting(sys.argv[1], locs[selected])
                ADDON.setSetting(sys.argv[1] + 'id', locids[selected])
                log('selected location: %s' % locs[selected])
        else:
            log('no locations found')
            dialog.ok(ADDONNAME, xbmc.getLocalizedString(284))
else:
    location = ADDON.getSetting('Location%s' % sys.argv[1])
    locationid = ADDON.getSetting('Location%sid' % sys.argv[1])
    if (locationid == '') and (sys.argv[1] != '1'):
        location = ADDON.getSetting('Location1')
        locationid = ADDON.getSetting('Location1id')
        log('trying location 1 instead')
    if not locationid == '':
        forecast(location, locationid)
    else:
        log('empty location id')
        clear()
    refresh_locations()

log('finished')

THANK YOU haxobel! working great again without even restarting KODI


[RELEASE] Yahoo! Weather - diedrichg - 2016-03-27

Does any of this info help?
https://forum.rainmeter.net/viewtopic.php?f=13&t=23010

example: http://xml.weather.yahoo.com/forecastrss?w=2436453&u=f


RE: [RELEASE] Yahoo! Weather - haxobel - 2016-03-27

(2016-03-27, 18:10)diedrichg Wrote: Does any of this info help?
https://forum.rainmeter.net/viewtopic.php?f=13&t=23010 ex: http://xml.weather.yahoo.com/forecastrss?w=2436453&u=f

Thanks for finding this. The Yahoo API is not so well documented so it is difficult to get this information. The XML link works in my browser so I it will probably also work in Kodi. This would allow a quicker change to the Yahoo! Weather addon with just a minor addition to the URL. Based on the oauth report on Yahoo's site I don't know how long it will be open, but then again, they wrote the same about the YQL which I used in my fix. The response for the XML seems to be faster (which is what I think is causing the sporadic errors with the YQL version. The JSON parser is much cleaner, but who cares as long as it works!


[RELEASE] Yahoo! Weather - diedrichg - 2016-03-27

(2016-03-27, 20:15)haxobel Wrote: Thanks for finding this.

Yeah, I run Rainmeter on my HTPC and its weather widget stopped working the same time Kodi's weather did so I knew it had to do with the the links. This then took me to the Rainmeter forums and they had this info posted a few days ago. I understand the issue, I just don't have the knowledge on how to implement it into our Yahoo! Weather addon in Kodi.


RE: [RELEASE] Yahoo! Weather - haxobel - 2016-03-27

Quote:... I just don't have the knowledge on how to implement it into our Yahoo! Weather addon in Kodi.

You should just have to change the following line in default.py
Code:
API_URL          = 'http://weather.yahooapis.com/forecastrss?w=%s&u=c'
to
Code:
API_URL          = 'http://xml.weather.yahoo.com/forecastrss?w=%s&u=c'



This forum uses Lukasz Tkacz MyBB addons.