getting weather forecasts from yahoo

hello everybody !

I was successfully using my arduino (UNO and Wi-Fi shield) to read weather forecasts from yahoo weather … but since the 15th of march, they have changed “something” … and I can’t get data anymore …

Has someone the same problem and find a solution ??

Thanks

the old code (which connects to yahoo, but the received datas are not “correct”)

#include <SPI.h>
#include <WiFi.h>
#include <TextFinder.h>
#include <HttpClient.h>

byte mac[] = { 0x78, 0xC4, 0x0E, 0x01, 0x9B, 0x43 };

char ssid[]  = "*************";
char pass[] = "************";
int status = WL_IDLE_STATUS;
char server[] = "weather.yahooapis.com";

WiFiClient client;

void setup() {
  Serial.begin(9600);
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while(true);
  }
 
  // connexion au wifi
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(5000);
  }
}

void loop() {
  get_meteo();
  delay(30000);
}

int get_meteo() {
  if (client.connect(server, 80)) {
    Serial.println("Connect to Yahoo Weather...");
    client.print("GET /forecastrss?w=628879&u=c HTTP/1.0\n"); //toulon, France
    client.print("HOST:weather.yahooapis.com\n\n");
    Serial.println("Connected...");
  } else {
    Serial.println(" connection failed");
    return(-1);
  }
 
  if (client.connected())   {
    //print all the response
    while(client.connected()) {
     while(client.available()) Serial.write(client.read());
    }
    return(0);
  }
  else Serial.println("Disconnected");
  client.stop();
  client.flush();
}

and the XML response I get since few days

Connect to Yahoo Weather…
Connected…
HTTP/1.0 401 Unauthorized
WWW-Authenticate: OAuth oauth_problem=“OST_OAUTH_PARAMETER_ABSENT_ERROR”, realm=“yahooapis.com
Content-Type: application/xml;charset=UTF-8
Date: Fri, 25 Mar 2016 20:06:53 GMT
Age: 0
Server: ATS

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>Please provide valid credentials. OAuth oauth_problem="OST_OAUTH_PARAMETER_ABSENT_ERROR", realm="yahooapis.com"Please provide valid credentials. OAuth oauth_problem="OST_OAUTH_PARAMETER_ABSENT_ERROR", realm="yahooapis.com"

the explanation is right there in your error response. you need to supply the oauth token.

In other words, the data is no longer free.

yahoo maybe just increased security.

did you have to register with yahoo before you can use their api?
if not, maybe you should now.

google, facebook, etc requires you to register to get an oauth token before you can use their api.

Thanks for your help

yahoo weather data are still free. And I'am registered .. (but my arduino is also ??)

In a web browser, I can get xml forecasts from yahoo if I write this sentence

http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D"toulon%2C%20france")&format=xml&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys

How can I do the same in my arduino programm

I tried
char server = "query.yahooapis.com"

and in the function

client.print("GET /v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20%28select%20woeid%20from%20geo.places%281%29%20where%20text%3D%22toulon%2C%20france%22%29&format=xml\n"); //toulon
client.print("HOST:query.yahooapis.com\n\n");

but nothing is forwarded, even with error messages

yahoo weather data are still free. And I'am registered

If you had to register, it is not free. They may not (yet) charge for the data, but it is not free.

but nothing is forwarded, even with error messages

What do you mean by "even with error messages"? If you are getting error messages, it is incredible that you expect things to work anyway.

PaulS ... Thanks.

with the old API link in my arduino program, I actually get an XML response but with Error messages (Oath error...) instead of weather forecasts.

If you click on the link in the #4 message, in your webrowser you should get some weather forecasts in XML format ...

If I try to put this link in my Arduino program, it says "connected" (to yahoo) but nothing is received, even messages like Oath error ...

Look at the GET statement in your original code. Look at the GET statement snippet. Pay particular to the end of each statement.

OK Paul, I've forget something

but with the HTTP/1.0\n at the end, I get nothing from yahoo ..

char server[] = "query.yahooapis.com";
...
client.print("GET /v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20%28select%20woeid%20from%20geo.places%281%29%20where%20text%3D%22toulon%2C%20france%22%29&format=xml&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys HTTP/1.0\n"); 
client.print("HOST:query.yahooapis.com\n\n");

I tried with "...%20HTTP/1.0\n" or "... HTTP/1.0\n" or ".../nHTTP/1.0\n" ...but nothing is returned by yahoo

Have you tried and managed to get xml datas from yahoo weather these days ??

Try " HTTP/1.1" on the end, using client.println() to send the GET request,

Try " HTTP/1.1" on the end, using client.println() to send the GET request,

this doesn't solve anything ... (nothing is replied from yahoo)

I found weather underground (www.wunderground.com) which is free and arduino friendly :slight_smile:

Don't change your original code. Yahoo just changed the server name but didn't notify us. >:(

Just change the name

weather.yahooapis.com

to

xml.weather.yahoo.com

That should do.

I to returned to an application which was working prior to the yahoo weather shakeup.
After some effort I have a method of accessing data on the yahoo weather API.

I found this useful as a starting point;
https://www.igorkromin.net/

The new weather server is query.yahooapis.com
Essentually you need to send a get request.
This will return everything from the location in xml format and metric units:
String location ="/v1/public/yql?format=xml&q=select+*+from+weather.forecast+where+woeid=30079+and+u=‘c’";

You can also be selective, with a much smaller transfer overhead:
String location = “/v1/public/yql?format=xml&q=select+location,units.temperature,units.speed,wind.direction,wind.speed,item.condition+from+weather.forecast+where+woeid=30079+and+u=‘c’”;

This returns details on units, wind speed, wind direction and current conditions.
The woeid parameter is the location which can be looked up here:
http://woeid.rosselliot.co.nz/
.
David
.
The code uses the new wifi101 library.
I am sure interested parties will be able to adjust for other hardware.
Sample output is attached.

/*
 yifi101weather.ino
 
 Extracted from a larger application
 D.R.Patterson
 19/4/2016
 
 */

#include <SPI.h>
#include <SdFat.h>
#include <WiFi101.h>

char ssid[] = "DRP3";    // network name
int port = 8082;
WiFiServer server(port);
int wifistatus = WL_IDLE_STATUS;    // the Wifi radio's status
byte wifiSelect = 10;

SdFat sd; // file system object
Sd2Card card;
byte sdSelect = 53;

// ********************** yahoo weather data **************************
// old server ended 15/4/2016
//char wserver[] = "xml.weather.yahoo.com";
//String location = "/forecastrss?p=UKXX1695&u=c"; // newcastle upon tyne in degrees C (metric)

// new server
char wserver[] = "query.yahooapis.com";
String location = "/v1/public/yql?format=xml&q=select+location,units.temperature,units.speed,wind.direction,wind.speed,item.condition+from+weather.forecast+where+woeid=30079+and+u='c'";
// get all is slower!
//String location ="/v1/public/yql?format=xml&q=select+*+from+weather.forecast+where+woeid=30079+and+u='c'";

boolean showall = true; // show all from yahoo weather on monitor
// ********************************************************************

boolean useserial = true; // toggle serial output

void setup(){

pinMode(wifiSelect, OUTPUT);
pinMode(sdSelect, OUTPUT);

Serial.begin(115200);
  if(!sd.begin(sdSelect, SPI_FULL_SPEED)) Serial.println(F("sd.begin failed"));
  if (!card.init(SPI_FULL_SPEED, sdSelect)) Serial.println(F("card.init failed!"));
// connect to ssid
  if (!ssidConnect(ssid) ) while(1);
}

void loop(){
getweather(showall);
delay(300000);
}

void getweather(boolean fullprint){
float fspeed, ftemp, fdirection;
String synopsis, date, wlocation;
int icode;
icode = 3200; // in case weather code is not found
String timestring;

WiFiClient myclient;
String wunits, tunits, wdirection, wspeed, temp, thiscode;
unsigned long timenow;
  if (useserial){
  Serial.print(F("\nStarting connection to server.. "));
  Serial.println(wserver);
  //Serial.println(location);
  }
 
  if (myclient.connect(wserver, 80)) {
    if(useserial) Serial.println(F("Connected to server.."));
  // Make a HTTP request:
  myclient.println("GET " + location + " HTTP/1.1");
  myclient.println("Host: " + String(wserver));
  myclient.println(F("Connection: close"));
  myclient.println();
  timenow = millis();
  String recline = "";
    while(myclient.connected()) {
      while (myclient.available()) {
      char c = myclient.read();
        if(c==62) recline = recline + ">";
        if (c == 10 || c == 62) { // use ">" as a line terminator
          if(useserial && fullprint) Serial.println(recline);

          if (recline.indexOf(F("weather:location")) > 0 ) {
          wlocation =  par(recline, F("city"));
          }
          
          if (recline.indexOf(F("weather:units")) > 0 ) {
          wunits =  par(recline, F("speed"));
          tunits =  par(recline, F("temperature"));
          }
          
          if (recline.indexOf(F("weather:condition")) > 0 ) {
          date = par(recline, F("date"));
          synopsis =  par(recline, F("text"));
          thiscode =  par(recline, F("code"));
          icode = thiscode.toInt();          
          temp =  par(recline, F("temp"));
          ftemp = temp.toFloat();
          }
          
          if (recline.indexOf(F("weather:wind")) > 0 ) {
          wdirection = par(recline, F("direction"));
          fdirection = wdirection.toFloat();
          wspeed =  par(recline, F("speed"));
          fspeed = wspeed.toFloat();
          }
        recline = "";
        }else if (c>31 && c<127) recline = recline + String(c);
      }
      if (millis()-timenow > 30000) break; // get out if stuck
    }
    if(useserial)Serial.println(F("disconnecting from server."));
  myclient.stop();
    if(tunits != "C") ftemp = (ftemp - 32.0) * 5.0 / 9.0; // convert to Centigrade 
    if(wunits == "km/h") fspeed = fspeed * 0.621371; // mph
    if(useserial){
    Serial.println();
    Serial.print(wlocation + ", ");
    Serial.println(date);
    Serial.print(synopsis);
    Serial.print(". (" + thiscode + ")");
    Serial.print(F(".\nWind: Direction "));
    Serial.print(fdirection, 1);
    Serial.print(F(", Speed "));
    Serial.print(fspeed, 2);
    Serial.print(F(" m/h, Temp "));
    Serial.print(ftemp, 1);
    Serial.println(F(" C"));
    }
  }else if (useserial) Serial.println(F("Connection failed"));
}

String par(String thisline, String search){ // extract search parameter from xml thisline
byte e = search.length() + 2;
int p = thisline.indexOf(search);
int l = thisline.indexOf("\"", p + e);
return thisline.substring(p + e, l);
}

boolean ssidConnect(String thessid){
byte mytry = 0;
  // attempt to connect to Wifi network:
  do { // try 3 times
  mytry ++;
    if  (useserial){
    Serial.println(F("Connect attempt ")); Serial.print(mytry);
    Serial.print(F(" to SSID: ")); Serial.println(thessid);
    }
  // Connect to network.
  wifistatus = WiFi.begin(thessid);
  // wait 10 seconds for connection:
  unsigned long starttime = millis();
    do { // check status every 2 seconds
    delay(2000);
    wifistatus = WiFi.status();
    } while (wifistatus != WL_CONNECTED && millis() - starttime < 10000); 
  } while (wifistatus != WL_CONNECTED && mytry < 3); // 3 attempts

  if (wifistatus != WL_CONNECTED){
    if  (useserial){
    Serial.print(F("Unable to connect to ")); Serial.println(thessid);
    }
  return false;
  }
  if (useserial) {
  Serial.print(F("Connected, commencing server on port "));
  Serial.println(port);
  }
server.begin();
return true;
}

Thanks David !

It also works with the wifi.h library and these lines...

if (myclient.connect("query.yahooapis.com", 80)) {
    Serial.println(F("Connected to server.."));
    // Make a HTTP request:
    myclient.print(F("GET /v1/public/yql?format=xml&q=select+*+from+weather.forecast+where+woeid=628879+and+u='c' HTTP/1.1\n")); //toulon
    myclient.print(F("HOST:query.yahooapis.com\n"));
    myclient.println(F("Connection: close"));
    myclient.println();
    ...

As I previously said, I'm using weatherunderground now... but I will keep this in my pocket ...

De rien!

Hi, i'm try to use your code write in this forum, but they not work fine in my project with arduino mega and ethernet schield w5200.
i'm try to test, but non read data from xml and must important not understud istruction "recline"

It seems complaining to Yahoo worked. They have made the data accessible again by using a different GET phrase. What works for me is the following:

client.println("GET https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20
                    where%20woeid%3DXXXXXXXX%20and%20u%3D%27c%27
                    &format=xml&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys HTTP/1.1")

Substitute XXXXXXXX for your WOEID numbers. As you can see, some chars are escaped, otherwise it doesn't work. For clarity, the original string would be:

GET https://query.yahooapis.com/v1/public/yql?q=select * from weather.forecast
            where woeid=[i][b]XXXXXXXX[/b][/i] and u='c'
            &format=xml&env=store://datatables.org/Falltableswithkeys HTTP/1.1

I broke the line to make it more readable, but in the code it's in a single one.

Hope it helps!

Hello every body, i have try to replace a code for reading weather from yahoo.

this is my code … is completed form decode forecast, but is incomplete for my application (send weather data to PLC on UDP)

I try test for 2 week, at moment work fine.

YahooWeather_072017.txt (11 KB)