Thursday, November 12, 2009

Access Yahoo's Weather API via YQL and jQuery

Let me start off by saying that if you want a basic demo of YQL by grabbing an RSS feed check out my first blog post on YQL. In this post I am going to make a little weather widget that grabs the current temperature, weather condition, wind speed and direction, create a link to the full forecast and lastly drop a pretty weather condition graphic as the background of the widget. Then, once I have all that data I am going to display it via jQuery.

So let's get started! Pull up the YQL developer console: https://developer.yahoo.com/yql/console/ and type in:

select * from weather.forecast where location=29201

Select JSON and click test. This shows you the weather data for Columbia, SC in JSON format. The good stuff is located in the within data.query.results.channel. In there you have access to the current temperature, humidity, wind, wind direction and even sunrise and sunset times. So let's start off simple.

Notice the rest query url in YQL console? It reads:
http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20location%3D29201&format=json&callback=cbfunc

That is a little tough to work with if you ask me so I like to bring in a little jquery to make this JSON url a little easier to work with and read. Here is a little piece of jquery that does just that for you:

$.YQL = function(query, callback) {
    var encodedQuery = encodeURIComponent(query.toLowerCase()),
        url = 'http://query.yahooapis.com/v1/public/yql?q='
            + encodedQuery + '&format=json&callback=?';
    $.getJSON(url, callback);
};


I generally include this little snippet in a file called jquery.yql.js. After that we can place our YQL query just like in the console. Here is our sample query:

$.YQL("select * from weather.forecast where location=29201",function(data){
            var w=data.query.results.channel;
            $('#weatherTemp').html(w.item.condition.temp+"°");
            $('#weatherText').html(w.item.condition.text);
       });  

This call grabs the weather information for Columbia, SC and injects the temperature and condition text to their corresponding divs. So data.query.results.channel.item.condition.temp = current temperature. and data.query.results.channel.item.condition.text = current condition.

So that was easy, let's grab all the information we want for this demo!

$.YQL("select * from weather.forecast where location=29406",function(data){
            var w=data.query.results.channel;
            var weatherImage="url(http://l.yimg.com/a/i/us/nws/weather/gr/"+w.item.condition.code+"d.png)";
            var wd=w.wind.direction;
            if(wd>=348.75&&wd<=360){wd="N"};if(wd>=0&&wd<11.25){wd="N"};if(wd>=11.25&&wd<33.75){wd="NNE"};if(wd>=33.75&&wd<56.25){wd="NE"};if(wd>=56.25&&wd<78.75){wd="ENE"};if(wd>=78.75&&wd<101.25){wd="E"};if(wd>=101.25&&wd<123.75){wd="ESE"};if(wd>=123.75&&wd<146.25){wd="SE"};if(wd>=146.25&&wd<168.75){wd="SSE"};if(wd>=168.75&&wd<191.25){wd="S"};if(wd>=191.25 && wd<213.75){wd="SSW"};if(wd>=213.75&&wd<236.25){wd="SW"};if(wd>=236.25&&wd<258.75){wd="WSW"};if(wd>=258.75 && wd<281.25){wd="W"};if(wd>=281.25&&wd<303.75){wd="WNW"};if(wd>=303.75&&wd<326.25){wd="NW"};if(wd>=326.25&&wd<348.75){wd="NNW"};
            $('#weatherWidget').css("background-image",weatherImage);
            $('#weatherTemp').html(w.item.condition.temp+"&deg;");
            $('#weatherText').html(w.item.condition.text);
            $('#weatherWind').html(wd +" "+w.wind.speed+"mph");
            $('#weatherLink').html("<a href='"+w.item.link+"'>Full Forecast</a>");
        });

OK, let's go line by line. First off you wil notice that I created weatherImage variable. Yahoo does not give you the full url to the image. I have to build the url and insert the condition code to display the right image. So to make the weatherImage I take the string "http://l.yimg.com/a/i/us/nws/weather/gr/" and add the condition code "30" to it and append the string ".png" to that you get: http://l.yimg.com/a/i/us/nws/weather/gr/30d.png

Yahoo does not give you the text wind direction. It gives you the degree. So if w.wind.direction might equal "90" which equals East. But I actually want to display E or NE. etc... So I wrote a series of if statements to check the direction number and output a string. I know, I know. I could have written a regular expression, but hey, I am a designer. Cut me some slack!

The rest of it just injects all the data into the corresponding divs. So here is a working example:


Please note there is NO server side coding going on. This is just javascript, HTML, and a little css. Speaking of which, here is the html as well:

<div id="weatherWidget" style="background: rgb(51, 51, 51) none no-repeat scroll 0% 0%; border: 10px solid rgb(17, 17, 17); height: 150px; position: relative;">
<div id="weatherDescription" style="left: 200px; position: absolute; top: 40px;">
<div id="weatherTemp" style="font-size: 200%; font-weight: bold;"></div>
<div id="weatherText"></div>
<div id="weatherWind"></div>
<div id="weatherLink"></div>
</div>
</div>

Pretty simple stuff if you ask me. I am going to post some flickr, youTube, upcoming.org, and twitter YQL widgets in the near future. So stay tuned!

26 comments:

  1. How do I query International locations? Any thoughts?

    ReplyDelete
  2. @Ram I'm not sure the weather api supports it. I tried using the yahoo location id and it says it's not supported. In the short term I would suggest using the international RSS feeds which I KNOW work.
    The query below will return weather for Paris, France.

    select * from rss where url='http://weather.yahooapis.com/forecastrss?p=FRXX0076&u=f'

    Navigate to your city via yahoo weather and grab the rss feed. Note: You might have to change some of the pathing for the variables. Hope this helps.

    ReplyDelete
  3. Wonderful! Much appreciated. Will investigate.

    ReplyDelete
  4. Here is the modified script, but it does not show any results. Any thoughts?


    $.YQL = function(query, callback) {
    if (!query || !callback) {
    throw new Error('$.YQL(): Parameters may be undefined');
    }
    var encodedQuery = encodeURIComponent(query.toLowerCase()),
    url = 'http://query.yahooapis.com/v1/public/yql?q='
    + encodedQuery + '&format=json&callback=?';
    $.getJSON(url, callback);
    };

    $(document).ready(function(){

    $.YQL("select * from rss where url='http://weather.yahooapis.com/forecastrss?p=SPXX0040&u=f'",function(data){
    var w=data.query.results.item;
    var weatherImage="url(http://l.yimg.com/a/i/us/nws/weather/gr/"+w.item.condition.code+"d.png)";
    var weatherIcon="url(http://l.yimg.com/a/i/us/nws/weather/gr/"+w.item.condition.code+"s.png)";
    $('#weatherWidget').css("background-image",weatherImage);
    $('#weatherIcon').css("background-image",weatherIcon);
    $('#weatherTemp').html(w.item.condition.temp+"°");
    $('#weatherText').html(w.item.condition.text);
    $('#weatherLink').html("Full Forecast");
    });
    });

    ReplyDelete
  5. There was an additional parameter "&u=f" on the end of the previous query. The query should just be:

    select * from rss where url='http://weather.yahooapis.com/forecastrss?p=FRXX0076'

    Or the full example request with callback function would be:
    $.YQL("select * from rss where url='http://weather.yahooapis.com/forecastrss?p=FRXX0076'",function(data){
    var w=data.query.results.item;
    var weatherImage="url(http://l.yimg.com/a/i/us/nws/weather/gr/"+w.item.condition.code+"d.png)";
    var weatherIcon="url(http://l.yimg.com/a/i/us/nws/weather/gr/"+w.item.condition.code+"s.png)";
    $('#weatherWidget').css("background-image",weatherImage);
    $('#weatherIcon').css("background-image",weatherIcon);
    $('#weatherTemp').html(w.item.condition.temp+"°");
    $('#weatherText').html(w.item.condition.text);
    $('#weatherLink').html("Full Forecast");
    });

    ReplyDelete
  6. Actually: I had "item" in there too many time in the callback function. Here you go:

    $.YQL("select * from rss where url='http://weather.yahooapis.com/forecastrss?p=FRXX0076'",function(data){
    var w=data.query.results.item;
    var weatherImage="url(http://l.yimg.com/a/i/us/nws/weather/gr/"+w.condition.code+"d.png)";
    var weatherIcon="url(http://l.yimg.com/a/i/us/nws/weather/gr/"+w.condition.code+"s.png)";
    $('#weatherWidget').css("background-image",weatherImage);
    $('#weatherIcon').css("background-image",weatherIcon);
    $('#weatherTemp').html(w.condition.temp+"°");
    $('#weatherText').html(w.condition.text);
    $('#weatherLink').html("Full Forecast");
    });

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. http://weather.yahooapis.com/forecastrss?p=FRXX0076&u=c

    ReplyDelete
  9. Celsius degrees & find location by name

    =============
    $(document).ready(function(){
    var q = "use 'http://github.com/yql/yql-tables/raw/master/weather/weather.bylocation.xml' as we; select * from we where location='Ufa, Russia' and unit='c'";

    $.YQL( q ,function(data){
    var w=data.query.results.weather.rss.channel.item;
    var dn = "d";
    var weatherImage="url(http://l.yimg.com/a/i/us/nws/weather/gr/" + w.condition.code + dn + ".png)";
    var weatherIcon="url(http://l.yimg.com/a/i/us/nws/weather/gr/" + w.condition.code + "s.png)";

    $('#weatherWidget').css("background-image",weatherImage);
    $('#weatherIcon').css("background-image",weatherIcon);
    $('#weatherTemp').html(w.condition.temp + "°C");
    });
    });

    ReplyDelete
  10. This is incredible. Thanks. I've been looking for something exactly like this.

    Is there anyway to control the size of the weather image? Can I have it display to 50% of its regular size?

    ReplyDelete
  11. This is wonderful!

    Is there a way to display other information such as the city, 3 day forecast?

    Thanks!

    ReplyDelete
  12. Hi Justin,
    I wanna be find the our location code but I m not able. Please tell me how can I know it?

    Like you are using "29201" for Columbia.

    I want to know about "Delhi, India". Please Help.


    http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20location%3D29201&format=json&callback=cbfunc

    ReplyDelete
  13. I use YQL in a similar way, with voice:

    http://weather-and-traffic-report.appspot.com/talk

    ReplyDelete
  14. @trish
    Check out the YQL developer console.
    http://developer.yahoo.com/yql/console/?q=select%20*%20from%20weather.forecast%20where%20location%3D90210
    Look at all the location information that is just associated with the weather api. I would check out some of the other tables that will have alot more location based information.

    ReplyDelete
  15. @Arshad you can use the RSS feed for local weather from yahoo in Delhi. I looked and the Delhi location code from yahoo is 20070458. Look above in the comments and use the code I put in there earlier. I hope that helps.

    ReplyDelete
  16. @sou;ohn You can use the code and create any image with any size you want and associate them. I just used the stock yahoo images. I have it set to a background image but I guess you could just load that image and absolutely position it at 50% height and width.

    ReplyDelete
  17. I have tested in all browsers and it doesn't show up in Mozilla or Opera. Is there something that I am missing? Thanks for your help!

    ReplyDelete
  18. That's interesting, Peter. Firefox is displaying it fine, but i get a syntax error in Safari.

    var class=w.condition.text;

    This line is the culprit according to safari :S

    ReplyDelete
  19. @KingScooty

    I had the same problem with Safari.

    I believe its because "class" is a reserved word in Safari.

    Once I changed it to a word Safari was happy with, all worked fine.

    eg:
    var weather=w.condition.text;

    ReplyDelete
  20. how i can show the temperature in Celsius and the min,max? thank you

    ReplyDelete
  21. how can u get the day or night image? i see thats it static to day images only...

    ReplyDelete
  22. Each of the weather conditions that are likely in the different parts of the country all require a slightly varied reaction from you, as a hauler. And each of these weather systems warrant a different set of tools and skills to get you safely to your destination.

    marine weather

    ReplyDelete
  23. I was actually looking for this resource a few weeks back. Thanks for sharing with us your wisdom.This will absolutely going to help me in my projects .
    Once again great post. You seem to have a good understanding of these themes.When I entering your blog,I felt this . Come on and keep writting your blog will be more attractive. To Your Success!
    Trumpet Wedding Dresses
    New Style Flower Girl Dresses
    Wedding Dresses with Sleeves
    Column Wedding Dresses
    New Style Wedding Dresses

    ReplyDelete