monkeecreate / jquery.simpleWeather

A simple jQuery plugin to display current weather data for any location and doesn't get in your way. Now supports HTML5 GeoLocation!
https://monkeecreate.github.io/jquery.simpleWeather/
MIT License
772 stars 147 forks source link

Please Read - simpleWeather is currently not working. #221

Closed ahmedhammad closed 7 years ago

ahmedhammad commented 8 years ago

Simple Weather Gives me the following error: THERE WAS A PROBLEM RETRIEVING THE LATEST WEATHER INFORMATION. Also, I tried the plugin in the website http://simpleweatherjs.com/ and the same result is happen. Please help me to find a solution for it

fleeting commented 8 years ago

Yahoo has made some changes to their API including requiring oAuth. As simpleWeather is pure JavaScript using oAuth isn't an easy option as I don't want people publishing their consumer and secret keys. I'm looking into other API options but honestly not sure when I'll have a replacement.

It has also been up and down a few times today so it's possible it could start working again.

canomi commented 8 years ago

I need use it like temporary module, please show me how to fix it with secret keys!

X-Ryl669 commented 8 years ago

You can still use the rss feed, like this: http://weather.yahooapis.com/forecastrss?w=WOEID_HERE. Since it's XML, you can parse it as well with jQuery automatically (or use Yahoo to digest their own dog food)

Example code:

var woeid = "26355493";

var $url = "http://query.yahooapis.com/v1/public/yql?callback=?";

$.getJSON($url, {
    q: "select * from xml where url=" +
       "\"http://weather.yahooapis.com/forecastrss?w=" + woeid + "\"",
    format: "json"
  }, function (data) {
    console.log(data.query.results.rss.channel);
  }
);
X-Ryl669 commented 8 years ago

Just a side node, it's possible to do something better so it'll be futureproof, using OAuth. This requires modifying a bit the code so it first fetch the access token from Yahoo's server, but it'll also imply having to modify simpleWeather instantiation so it includes the Yahoo's developer API as a mandatory parameter. For example about how to do it, see this: https://gist.github.com/hannestyden/563893

I'm not 100% sure Yahoo allow OAuth2 for its api. In all case, it's not very sexy to give the secret keys & token in the JS code from the final user, and Yahoo as some tricks that allows you to avoid this (see this post): http://derek.io/blog/2010/how-to-secure-oauth-in-javascript/

fleeting commented 8 years ago

It's unlikely I'll update simpleWeather to work with OAuth. It is not recommended to have secret keys or tokens in client side code as it's not really secret anymore. The initial option would be to provide a PHP proxy but that complicates simpleWeather more than I would like at the moment.

The XML feed is also limited by woeid only so location names and geolocation wouldn't work which I believe is the majority of the simpleWeather use cases.

I have been looking at other options for the data. One might be to use weather.gov but it will be a complete change in data returned and how location works; http://forecast.weather.gov/MapClick.php?lat=38.4247341&lon=-86.9624086&FcstType=json is an option but uses coordinates vs location name. forecast.io API would also require a proxy due to OAuth but it also only gives 1,000 free API calls a day before charging. I'm not sure when I'll have the time to really work on it or whether the weather.gov data will be the best option.

If anybody has recommendations for those wanting an alternate solution to simpleWeather please share. Thanks!

quartsZzz commented 8 years ago

fleeting, can use http://openweathermap.org/ ?

webdevbrian commented 8 years ago

Broke 13 of my apps. Dammit!

rwebler commented 8 years ago

The XML RSS looks promising. We can still make it work with geolocation by retrieving woeid from geo.places in a separate call.

githubthom commented 8 years ago

The XML solution is working in my case. Thanks for that.

fleeting commented 8 years ago

I'm glad the XML feed is a workable solution for some. The geo.places call will continue to work for getting the woeid until Yahoo rolls out OAuth to it as well.

X-Ryl669 commented 8 years ago

@fleeting Please read my second comment and the derek's blog, as it's a method to avoid distributing your Yahoo's API key. Basically you'll store the keys/token on Yahoo's servers directly, only referencing them in your request.

trex888 commented 8 years ago

Sorry guys, I've tried the XML feed option but can't quite make it work. Can anyone advise as to where exactly the above XML code should go? This is what I'm currently using in my header.php file of my Wordpress install and up until yesterday it worked perfectly:

` $(function() {

        $.simpleWeather({
             location: '43.623432, -79.386583',
            unit: 'c',
            success: function(weather) {
                html = '<div align="center">' + weather.temp + '&deg;' + weather.units.temp + '<br />' + weather.wind.direction + ' ' + Math.round(weather.wind.speed * 0.540) + 'kts</div>';

                $("#weather2").html(html);
            },
            error: function(error) {
                $("#weather2").html('<p>'+error+'</p>');
            }
        });
    });`

Thanks for any help with this,

T

aric87 commented 8 years ago

This broke ~150 sites. I really hate that Yahoo isn't more proactive with warnings.

githubthom commented 8 years ago

If somebody is interested, this is how I my code looks like now after change to XML/RSS. I'm not using geo.places, so it was a quick fix.

`function getWeatherData() {

var woeid = '2375129';
var weatherURL = 'http://weather.yahooapis.com/forecastrss?w=' + woeid;
$.ajax({
    url: "http://query.yahooapis.com/v1/public/yql",
    async: true,
    data: {
        q: "select * from xml where url='" + weatherURL + "'",
        format: "json"
    },
    success: function (data) {

        var weather = data.query.results.rss.channel.item;

        // Today
        $('#condition').find('.weather').addClass('icon-' + weather.condition.code);
        $('#conditionText').text(weather.condition.text);
        $('#todayHighText').find('span').html(weather.forecast[0].high + '<i class="degree">&deg;</i>');
        $('#todayLowText').find('span').html(weather.forecast[0].low + '<i class="degree">&deg;</i>');
        $('#todayCurrentText').find('.value').html(weather.condition.temp + '<i class="degree">&deg;</i>');
        $('#todayCurrentText').find('.unit').text('F');

        // Forecast
        $('#day1 .weather').addClass('icon-' + weather.forecast[1].code);
        $('#day1 .weekdayHigh').html(weather.forecast[1].high + '<i class="degree">&deg;</i>');
        $('#day1 .weekdayLow').html(weather.forecast[1].low + '<i class="degree">&deg;</i>');
        $('#day2 .weather').addClass('icon-' + weather.forecast[2].code);
        $('#day2 .weekdayHigh').html(weather.forecast[2].high + '<i class="degree">&deg;</i>');
        $('#day2 .weekdayLow').html(weather.forecast[2].low + '<i class="degree">&deg;</i>');
        $('#day3 .weather').addClass('icon-' + weather.forecast[3].code);
        $('#day3 .weekdayHigh').html(weather.forecast[3].high + '<i class="degree">&deg;</i>');
        $('#day3 .weekdayLow').html(weather.forecast[3].low + '<i class="degree">&deg;</i>');

        $('#weatherContainer').addClass('fadeInDown');

    },
    error: function () {
        $('#weatherContainer').html('No weather data available').addClass('fadeInDown');
    }
});

}`

webdevbrian commented 8 years ago

For my needs I'm switching to the weather underground API

mattferderer commented 8 years ago

Using the XML method proposed by @X-Ryl669 this is a simplified version of the code I used just in case it helps anyone: http://plnkr.co/edit/dClPDtnToMhHqvKpfCzj?p=preview

var zipCode = 90210;

$.ajax({
    dataType: "json",
    headers:  { "Accept": "application/json; odata=verbose" },
    url: "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.places%20where%20text%3D"+zipCode+"%20limit%201&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys",
    beforeSend: function(xhr){xhr.setRequestHeader('Accept', 'application/json; odata=verbose');},
    success: function(data){
        $.getJSON("https://query.yahooapis.com/v1/public/yql?callback=?", {
            q: "select * from xml where url=\"https://weather.yahooapis.com/forecastrss?w="+data.query.results.place.locality1.woeid+"\"",
            format: "json"
        },function (data) {
          var weather = data.query.results.rss.channel;
          var html = '<div><span class="temperature">'+weather.item.condition.temp+'<span class="degree">&deg;</span><sup>'+weather.units.temperature+'</sup></span><br><span class="wind-chill">Feels like: '+weather.wind.chill+'<span class="degree">&deg;</span></span></div></a>';
          $("#weather").html(html);
        });
    },
});
alexranc commented 8 years ago

Was also able to work with XML using code below (thanks X-Ryl669). You will now have a weather object with all the data you need.

My only concern is how often these XML/RSS get updated. Anyone know this?

var woeid = "12772140";
var $url = "http://query.yahooapis.com/v1/public/yql?callback=?";

$.getJSON($url, {
    q: "select * from xml where url=" +
       "\"http://weather.yahooapis.com/forecastrss?w=" + woeid + "\"",
    format: "json"
  }, function (data) {

    var weather = {
      code: data.query.results.rss.channel.item.condition.code, 
      temp: data.query.results.rss.channel.item.condition.temp,
      phrase: data.query.results.rss.channel.item.condition.text
    };

    weather.temp_alt = Math.round( (weather.temp - 32) * 5 / 9 );

  }
);
rhyshalsey commented 8 years ago

I have modified Simple Weather to use the new rss and xml solution provided by @X-Ryl669 and @mattferderer. It should work as before, just swap the old script for this one.

EDIT : This no longer works!

(function($) {
  "use strict";

  function getAltTemp(unit, temp) {
    if(unit === 'f') {
      return Math.round((5.0/9.0)*(temp-32.0));
    } else {
      return Math.round((9.0/5.0)*temp+32.0);
    }
  }

  $.extend({
    simpleWeather: function(options){
      options = $.extend({
        location: '',
        woeid: '',
        unit: 'f',
        success: function(weather){},
        error: function(message){}
      }, options);

      if(options.location !== '') {
        $.ajax({
          dataType: "json",
          headers: {"Accept": "application/json; odata=verbose"},
          url: "https://query.yahooapis.com/v1/public/yql?format=json&q=select%20woeid%20from%20geo.places(1)%20where%20text%3D%22" + options.location + "%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=",
          beforeSend: function (xhr) {
            xhr.setRequestHeader('Accept', 'application/json; odata=verbose');
          },
          success: function (data) {
            if (data !== null && data.query !== null && data.query.results !== null && data.query.results.place !== null && data.query.results.place.woeid !== null) {
              var woeid = data.query.results.place.woeid;
              getWeatherData(woeid);
            } else {
              options.error({message: "There was an error retrieving the latest weather information. Please try again.", error: null});
            }
          }
        });
      } else if(options.woeid !== '') {
        getWeatherData(options.woeid);
      } else {
        options.error({message: "Could not retrieve weather due to an invalid location."});
        return false;
      }

      function getWeatherData (woeid) {
        var now = new Date();
        $.getJSON('https://query.yahooapis.com/v1/public/yql?callback=?&rnd='+now.getFullYear()+now.getMonth()+now.getDay()+now.getHours(), {
          q: 'select * from xml where url="https://weather.yahooapis.com/forecastrss?w='+woeid+'&u='+options.unit+'"',
          format: "json"
        },function (data) {
          if(data !== null && data.query !== null && data.query.results !== null && data.query.results.rss !== null && data.query.results.rss.channel.description !== 'Yahoo! Weather Error') {
            var result = data.query.results.rss.channel,
                weather = {},
                forecast,
                compass = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'],
                image404 = "https://s.yimg.com/os/mit/media/m/weather/images/icons/l/44d-100567.png";

            weather.title = result.item.title;
            weather.temp = result.item.condition.temp;
            weather.code = result.item.condition.code;
            weather.todayCode = result.item.forecast[0].code;
            weather.currently = result.item.condition.text;
            weather.high = result.item.forecast[0].high;
            weather.low = result.item.forecast[0].low;
            weather.text = result.item.forecast[0].text;
            weather.humidity = result.atmosphere.humidity;
            weather.pressure = result.atmosphere.pressure;
            weather.rising = result.atmosphere.rising;
            weather.visibility = result.atmosphere.visibility;
            weather.sunrise = result.astronomy.sunrise;
            weather.sunset = result.astronomy.sunset;
            weather.description = result.item.description;
            weather.city = result.location.city;
            weather.country = result.location.country;
            weather.region = result.location.region;
            weather.updated = result.item.pubDate;
            weather.link = result.item.link;
            weather.units = {temp: result.units.temperature, distance: result.units.distance, pressure: result.units.pressure, speed: result.units.speed};
            weather.wind = {chill: result.wind.chill, direction: compass[Math.round(result.wind.direction / 22.5)], speed: result.wind.speed};

            if(result.item.condition.temp < 80 && result.atmosphere.humidity < 40) {
              weather.heatindex = -42.379+2.04901523*result.item.condition.temp+10.14333127*result.atmosphere.humidity-0.22475541*result.item.condition.temp*result.atmosphere.humidity-6.83783*(Math.pow(10, -3))*(Math.pow(result.item.condition.temp, 2))-5.481717*(Math.pow(10, -2))*(Math.pow(result.atmosphere.humidity, 2))+1.22874*(Math.pow(10, -3))*(Math.pow(result.item.condition.temp, 2))*result.atmosphere.humidity+8.5282*(Math.pow(10, -4))*result.item.condition.temp*(Math.pow(result.atmosphere.humidity, 2))-1.99*(Math.pow(10, -6))*(Math.pow(result.item.condition.temp, 2))*(Math.pow(result.atmosphere.humidity,2));
            } else {
              weather.heatindex = result.item.condition.temp;
            }

            if(result.item.condition.code == "3200") {
              weather.thumbnail = image404;
              weather.image = image404;
            } else {
              weather.thumbnail = "https://s.yimg.com/zz/combo?a/i/us/nws/weather/gr/"+result.item.condition.code+"ds.png";
              weather.image = "https://s.yimg.com/zz/combo?a/i/us/nws/weather/gr/"+result.item.condition.code+"d.png";
            }

            weather.alt = {temp: getAltTemp(options.unit, result.item.condition.temp), high: getAltTemp(options.unit, result.item.forecast[0].high), low: getAltTemp(options.unit, result.item.forecast[0].low)};
            if(options.unit === 'f') {
              weather.alt.unit = 'c';
            } else {
              weather.alt.unit = 'f';
            }

            weather.forecast = [];
            for(var i=0;i<result.item.forecast.length;i++) {
              forecast = result.item.forecast[i];
              forecast.alt = {high: getAltTemp(options.unit, result.item.forecast[i].high), low: getAltTemp(options.unit, result.item.forecast[i].low)};

              if(result.item.forecast[i].code == "3200") {
                forecast.thumbnail = image404;
                forecast.image = image404;
              } else {
                forecast.thumbnail = "https://s.yimg.com/zz/combo?a/i/us/nws/weather/gr/"+result.item.forecast[i].code+"ds.png";
                forecast.image = "https://s.yimg.com/zz/combo?a/i/us/nws/weather/gr/"+result.item.forecast[i].code+"d.png";
              }

              weather.forecast.push(forecast);
            }

            options.success(weather);
          } else {
            options.error({message: "There was an error retrieving the latest weather information. Please try again.", error: data.query.results.rss.channel.item.title});
          }
        });
      }
      return this;
    }
  });
})(jQuery);
kgiszewski commented 8 years ago

@rhyshalsey +1, worked immediately for me

kgiszewski commented 8 years ago

One note, it appears to be reporting the wrong weather status. It's 54 degrees and raining here, but shows snowing. Could be an issue with the icons I'm using.

screen shot 2016-03-24 at 1 36 53 pm
equatebrand commented 8 years ago

@rhyshalsey, thank you!

whistletutor commented 8 years ago

@rhyshalsey Thanks from me as well, I was neck deep in other options for my applications. Glad you got this figured out!

nfishertbc commented 8 years ago

@rhyshalsey thanks!! This worked for me as well. I just made the code change and its now working.

X-Ryl669 commented 8 years ago

@rhyshalsey, you should move the line var now = new Date(); into the function just below, else it's undefined in the function itself where you're using it.

X-Ryl669 commented 8 years ago

Just a comment, guys: This is only a temporary workaround. As soon as more people will use this, Yahoo is going to protect with oAuth either their RSS feed, either their XML to JSON converter. I still think we need to figure out how to use their weather api with oAuth in pure JS without having to give our reader our own dev API tokens.

rhyshalsey commented 8 years ago

Good catch @X-Ryl669, updated the code. I also agree that this should not be considered a long term solution.

I have been trying to get a consumer key for the YDN all day, but I'm being been hit with a "An internal error occurred" when trying to access the YDN apps section. Anyone else getting this error?

kgiszewski commented 8 years ago

@X-Ryl669 Send me a link and I'll try.

mattferderer commented 8 years ago

I've been getting a "Server Connection Closed" error all day when trying to go to https://developer.yahoo.com/apps/

Trying to create an app gives me some server connection error on submit.

kgiszewski commented 8 years ago

Same error here.

X-Ryl669 commented 8 years ago

Same for me. I guess their weather API change is currently overloading their "processing" buffers.

mattferderer commented 8 years ago

With talks of Yahoo trying to sell the majority of their internet business & staff, plus large shareholders trying to remove their entire board, the best path forward may be to find a different weather api. Unfortunately I can't find any that are free, utilize zip codes or city/state/country, and have a high request per hour/day limit.

webdevbrian commented 8 years ago

@mattferderer I'm probably going to fork this and hook this up with weatherunderground's API. 500 calls a day @ 10 a minute max suits my needs. edited, I said "an hour" previously, not by minute.

kgiszewski commented 8 years ago

@webdevbrian +1

mattferderer commented 8 years ago

@webdevbrian Are you going to cache the response from Weather Underground or do you get less than 10 visitors per hour on your site or am I mistaken in how I read that?

X-Ryl669 commented 8 years ago

@webdevbrian Where I live, there's only 24 hours a day. So the best I could expect with only 10 call per hour would be 240 calls per day. Did I miss something ?

webdevbrian commented 8 years ago

@X-Ryl669 Whoops, meant to say minute. Here are their limits for their free account. Feel free to dig into it if it'll work for you (and their other packages if you need more and what you'll be paying) See here

screen shot 2016-03-24 at 3 41 00 pm

Just started my fork, I'm out on vacation next week but I need this working again so probably expect it to be done in a few weeks. I'll ping @fleeting to see what he wants to do? Holler at me buddy. Also, I might be in Boston soon, we should meet up for some :beers: .

@mattferderer I'll probably set a rate limit. I'll need more than 500 a day for my needs, but at least people will be able to throttle it so it doesn't get canned. I'll have to think it over a few margaritas on the beach next week :)

:boat: :sunrise: :sunny: :sunglasses:

kgiszewski commented 8 years ago

I think the difference is the application. I only use it for a digital signage (updates every 5 mins) whereas someone else may use it on a website and may load it 1000's of times a day.

webdevbrian commented 8 years ago

@kgiszewski Correct -- I'll probably just rate limit it which people can define whatever they'd like in the options depending how crazy they want to get, haven't thought to that point yet. Currently mapping the response from wunderground to what @fleeting has, there are a bunch of things to change.

dmcrock commented 8 years ago

@rhyshalsey Looks like we are starting to get an error on your work around. Was working great until 2 minutes ago. "Unhandled exception at line 53, column 21, 0x800a138f - JavaScript runtime error: Unable to get property 'channel' of undefined or null reference" anyone else seeing this? Doug

romulosnascimento commented 8 years ago

@dmcrock, same here

mattferderer commented 8 years ago

Looks like they're requiring OAuth on the XML feed now. Glad to see Yahoo took the time to implement that fix but still haven't fixed their Developer App section so you can login & create an app to connect through OAuth.

koccan commented 8 years ago

So what? When hundreds of people enter my website, I can not show the weather? This is so absurd. Is there another weather app I can use?

lostcook commented 8 years ago

Long time SimpleWeather user, first time commentor. Not sure if others are experiencing this, but it seems like it is only displaying Fahrenheit. Sorry to be a pain, but in Canada we use Celsius.

Otherwise, thanks for all the updating you have been doing to this plugin.

grandoompa commented 8 years ago

@dmcrock, same here. The workaround provided by @rhyshalsey (by the way, thanks for trying) worked for a few hours until around 5pm'ish EST today (3/24/16).

I am now getting the following console error: Uncaught TypeError: Cannot read property 'channel' of undefined

mattferderer commented 8 years ago

Yahoo claims the site to create an app works now. I can't verify though. 

whistletutor commented 8 years ago

Yes, it is working now - but their example code doesn't reference the API keys so I'm not sure where we're supposed to pass them.

biapar commented 8 years ago

@rhyshalsey don't work

chimit commented 8 years ago

I think openweathermap.org is only one replacement for the Yahoo API, because it has the best limits (Calls per minute 60). I don't see any other way to make this plugin work again, because as I know there are no public weather APIs without limitations. Even in this way we have to expose keys.

X-Ryl669 commented 8 years ago

Ok, for those interested, I've started my port with weatherunderground and it's working for my need. You'll need to register an api key from the Weatherunderground website, and add a apiKey member to the options of simpleWeather. The woeid does not exist in weather underground, but I've used the "id" they are using. Either you use the location member of options to specify the location (but it'll make 2 request to WU, one to figure out the id, and the second for the forecast), either you capture the output of the former request on the console, and use that as woeid. If location is set to auto then it takes the IP address of the client for the weather query.

Not everything is ported (feel free to adjust to your need), but for those using metrics system, it works quite well.

(function($) {
  "use strict";

  function getAltTemp(unit, temp) {
    if(unit === 'f') {
      return Math.round((5.0/9.0)*(temp-32.0));
    } else {
      return Math.round((9.0/5.0)*temp+32.0);
    }
  }

  $.extend({
    simpleWeather: function(options){
      options = $.extend({
        location: '',
        woeid: '',
        unit: 'f',
        apiKey: '',
        success: function(weather){},
        error: function(message){}
      }, options);

      if(options.location !== '') {
        if (options.location == 'auto')
        {
            $.ajax({
              dataType: "json",
              headers: {"Accept": "application/json; odata=verbose"},
              url: "http://api.wunderground.com/api/"+options.apiKey+"/geolookup/q/autoip.json",
              beforeSend: function (xhr) {
                xhr.setRequestHeader('Accept', 'application/json; odata=verbose');
              },
              success: function (data) {
                 if (data !== null && data.location !== null && data.location.l !== null) {
                    var query = data.location.l;
                    console.log("Fetching weather forecast for :" + query);
                    getWeatherData(query);
                 } else {
                    options.error({message: "There was an error retrieving the latest weather information. Please try again.", error: null});
                 }
              }
            });
        }
        else
        {
            $.ajax({
              dataType: "json",
              headers: {"Accept": "application/json; odata=verbose"},
              url: "http://api.wunderground.com/api/"+options.apiKey+"/geolookup/q/" + options.location + ".json",
              beforeSend: function (xhr) {
                xhr.setRequestHeader('Accept', 'application/json; odata=verbose');
              },
              success: function (data) {
                 if (data !== null && data.location !== null && data.location.l !== null) {
                    var query = data.location.l;
                    console.log("Fetching weather forecast for :" + query);
                    getWeatherData(query);
                 } else {
                    options.error({message: "There was an error retrieving the latest weather information. Please try again.", error: null});
                 }
              }
            });
        }
      } else if(options.woeid !== '') {
        getWeatherData(options.woeid);
      } else {
        options.error({message: "Could not retrieve weather due to an invalid location."});
        return false;
      }

      function iconToCode(icon) {
         var night = /^nt_/.test(icon);
         var i = icon.replace("nt_", "");
         switch(i) {
            case "chanceflurries": // Chance of Flurries
                return 13;
            case "chancerain": // Chance of Rain
                return 40;
            case "chancesleet": // Chance of Freezing Rain
                return 10;
            case "chancesnow": // Chance of Snow
                return 42;
            case "chancetstorms": // Chance of Thunderstorms
                return 38;
            case "clear": // Clear
                 return night ? 31 : 32;
            case "flurries": // Flurries
                 return 13;
            case "fog": // Fog
                 return 20;
            case "hazy": // Haze
                 return 21;
            case "mostlycloudy": // Mostly Cloudy
                 return night ? 27 : 28;
            case "mostlysunny": // Mostly Sunny
                 return night ? 33 : 34;
            case "partlycloudy": // Partly Cloudy
                 return night ? 29 : 30;
            case "partlysunny": // Partly Sunny
                 return night ? 33 : 34;
            case "rain": // Rain
                 return 11;
            case "sleet": // Sleet
                 return 18;
            case "snow": // Snow
                 return 16;
            case "sunny": // Sunny
                 return 32;
            case "tstorms": // Thunderstorms
                 return 4;
            case "cloudy": // Overcast
                 return 26;
            default:
            case "unknown": // Unknown
                 return 3200;
         }
      }

      function padToTwo(number) {
         if (number<=99) { number = ("0"+number).slice(-2); }
         return number;
      }

      function getWeatherData (woeid) {
        $.getJSON('http://api.wunderground.com/api/' + options.apiKey + '/conditions/astronomy/forecast10day' + woeid + '.json', { format: 'json' }, function(data) {
          if(data !== null && data.current_observation !== null && data.sun_phase !== null && data.forecast !== null && data.forecast.simpleforecast !== null && data.forecast.simpleforecast.forecastday !== null) {
            var current = data.current_observation,
                weather = {},
                forecast,
                compass = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'],
                image404 = "https://s.yimg.com/os/mit/media/m/weather/images/icons/l/44d-100567.png";
                weather.title = 'Conditions for ' + current.display_location.city;
                weather.city = current.display_location.city;
                weather.temp = options.unit == 'f' ? current.temp_f : current.temp_c;
                weather.humidity = current.relative_humidity.replace("%", "");
                weather.pressure = current.pressure_mb;
                weather.currently = current.weather;
                weather.code = iconToCode(current.icon);

                weather.sunrise = data.sun_phase.sunrise.hour + ':' + padToTwo(data.sun_phase.sunrise.minute);
                weather.sunset = data.sun_phase.sunset.hour + ':' + padToTwo(data.sun_phase.sunset.minute);

           var result = data.forecast.simpleforecast.forecastday;
                weather.forecast = [];

                     for(var i=0;i<Math.min(result.length, 5);i++) {
                        var forecast = {};
                        forecast.day = result[i].date.weekday;
                        forecast.low = result[i].low[options.unit == 'c' ? "celsius" : "fahrenheit"];
                        forecast.high = result[i].high[options.unit == 'c' ? "celsius" : "fahrenheit"];
                        forecast.code = iconToCode(result[i].icon);
                        forecast.text = result[i].conditions;
                        weather.forecast.push(forecast);
                     }

                     weather.todayCode = weather.code;
                     weather.high = weather.forecast[0].high;
                     weather.low = weather.forecast[0].low;
                     weather.text = weather.forecast[0].text;

/* Everything below should be adapted to WU format, but I'm not interested into them.
   Refer to https://www.wunderground.com/weather/api/d/docs?d=data/forecast10day for documentation
            weather.rising = result.atmosphere.rising;
            weather.visibility = result.atmosphere.visibility;
            weather.description = result.item.description;
            weather.country = result.location.country;
            weather.region = result.location.region;
            weather.updated = result.item.pubDate;
            weather.link = result.item.link;
            weather.units = {temp: result.units.temperature, distance: result.units.distance, pressure: result.units.pressure, speed: result.units.speed};
            weather.wind = {chill: result.wind.chill, direction: compass[Math.round(result.wind.direction / 22.5)], speed: result.wind.speed};

            if(result.item.condition.temp < 80 && result.atmosphere.humidity < 40) {
              weather.heatindex = -42.379+2.04901523*result.item.condition.temp+10.14333127*result.atmosphere.humidity-0.22475541*result.item.condition.temp*result.atmosphere.humidity-6.83783*(Math.pow(10, -3))*(Math.pow(result.item.condition.temp, 2))-5.481717*(Math.pow(10, -2))*(Math.pow(result.atmosphere.humidity, 2))+1.22874*(Math.pow(10, -3))*(Math.pow(result.item.condition.temp, 2))*result.atmosphere.humidity+8.5282*(Math.pow(10, -4))*result.item.condition.temp*(Math.pow(result.atmosphere.humidity, 2))-1.99*(Math.pow(10, -6))*(Math.pow(result.item.condition.temp, 2))*(Math.pow(result.atmosphere.humidity,2));
            } else {
              weather.heatindex = result.item.condition.temp;
            }

            if(result.item.condition.code == "3200") {
              weather.thumbnail = image404;
              weather.image = image404;
            } else {
              weather.thumbnail = "https://s.yimg.com/zz/combo?a/i/us/nws/weather/gr/"+result.item.condition.code+"ds.png";
              weather.image = "https://s.yimg.com/zz/combo?a/i/us/nws/weather/gr/"+result.item.condition.code+"d.png";
            }

            weather.alt = {temp: getAltTemp(options.unit, result.item.condition.temp), high: getAltTemp(options.unit, result.item.forecast[0].high), low: getAltTemp(options.unit, result.item.forecast[0].low)};
            if(options.unit === 'f') {
              weather.alt.unit = 'c';
            } else {
              weather.alt.unit = 'f';
            }
*/

                       options.success(weather);
            } else {
               options.error({message: "There was an error retrieving the latest weather information. Please try again.", error: data.query.results.rss.channel.item.title});
            }
        });
      }
      return this;
    }
  });
})(jQuery);
larsinsd commented 8 years ago

X-Ryl669 Thank you for posting this! I went to WeatherUnderground and got an API key, but I'm getting this in the console:

XMLHttpRequest cannot load http://api.wunderground.com/api//geolookup/q/Solana%20Beach,%20CA,%20United%20States.json. The 'Access-Control-Allow-Origin' header has a value 'http://www.wunderground.com' that is not equal to the supplied origin. Origin 'http://mydomain.com' is therefore not allowed access.

Am I missing something obvious here?