[Solved] Trying to make an API call

This is part of some code that I wrote in c# and works well. I am trying to port over. I tried to use the HttpClient lib but cant get it to work, and don’t really understand web stuff.

Can anyone help me with this issue, Thanks

       xmlConditions.Load(string.Format("http://api.wunderground.com/api/key_value/conditions/q/CA/Newhall.xml"));

        if (xmlConditions.SelectSingleNode("xml_api_reply/weather/problem_cause") != null)
        {
            conditions = null;
        }
        else
        {
            conditions.City = xmlConditions.SelectSingleNode("/response/current_observation/display_location/full").InnerText;
            conditions.Condition = xmlConditions.SelectSingleNode("/response/current_observation/weather").InnerText;
            conditions.TempC = xmlConditions.SelectSingleNode("/response/current_observation/temp_c").InnerText;
            conditions.TempF = xmlConditions.SelectSingleNode("/response/current_observation/temp_f").InnerText;
            conditions.TempF = xmlConditions.SelectSingleNode("/response/current_observation/temp_f").InnerText;
            conditions.TempF = xmlConditions.SelectSingleNode("/response/current_observation/temp_f").InnerText;
            conditions.Humidity = xmlConditions.SelectSingleNode("/response/current_observation/relative_humidity").InnerText;
            conditions.Wind = xmlConditions.SelectSingleNode("/response/current_observation/wind_string").InnerText;
            conditions.Icon = xmlConditions.SelectSingleNode("/response/current_observation/icon").InnerText;
        }

If I wasn’t writting this on a phone I’d be happy to whip up some quick code for you.

What have you tried so far? Do you have any testing code on the core yet?

I think you’ve essentially got two parts of this problem:

  1. Download the data @ http://api/wunderground.com/api/key_value/conditions/q/CA/Newhall.xml
  2. Parse the XML data

It sounds like you are tackling part 1 right now. Let’s see what you come up with and we can help from there.

I’d start with the TCPClient example code but the HttpClient library might be better suited in the long run.

Here’s the TCPClient example. You will need to modify both the ip and the host/url to get it to work for your applicaiton.

// SYNTAX
TCPClient client;
// EXAMPLE USAGE

TCPClient client;
byte server[] = { 74, 125, 224, 72 }; // Google
void setup()
{
  // Make sure your Serial Terminal app is closed before powering your Core
  Serial.begin(9600);
  // Now open your Serial Terminal, and hit any key to continue!
  while(!Serial.available()) SPARK_WLAN_Loop();

  Serial.println("connecting...");

  if (client.connect(server, 80))
  {
    Serial.println("connected");
    client.println("GET /search?q=unicorn HTTP/1.0");
    client.println("Host: www.google.com");
    client.println("Content-Length: 0");
    client.println();
  }
  else
  {
    Serial.println("connection failed");
  }
}

void loop()
{
  if (client.available())
  {
    char c = client.read();
    Serial.print(c);
  }

  if (!client.connected())
  {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    for(;;);
  }
}

Thanks for the feed back, I put the code in and ran it. I did not get anything back and ‘locks up the connection’ so I cant make changes to the core.

The code is waiting for a keypress before continuing so after connecting via a Terminal program, simply hit any key and it should work :slight_smile:

Hey thanks, I did hit any key to continue and waiting…
So not sure where to go from here.

Still hopefull

You should see some output on the terminal.

What does it say?

Well I get the print lines “connecting…” and “Connected” followed by nothing.
Also not sure if this will ever time out.

I got my spark core working again…

Got the sample code working via google. I started changing it to call the api I am trying to get data from, and this is what I get back (YEA sort of)

byte server[] = { 23, 193, 151, 76 }; // api.wunderground.com

don’t know what this line does.
client.println(“GET /search?q=unicorn HTTP/1.0”);
or
client.println(“Content-Length: 0”);
but this is the call I am trying to make:
-api.wunderground.com/api/key_value/conditions/q/CA/Newhall.xml-

connecting…
connected
HTTP/1.0 400 Bad Request
Server: AkamaiGHost
Mime-Version: 1.0
Content-Type: text/html
Content-Length: 216
Expires: Thu, 20 Nov 2014 19:06:38 GMT
Date: Thu, 20 Nov 2014 19:06:38 GMT
Connection: close

Bad Request

Bad Request

Your browser sent a request that this server could not understand.

Reference #7.c42c0e6b.1416510398.0 any thoughts?

@mgcurtis: The following code with do part 1 for you:

TCPClient client;
byte server[] = { 184, 29, 184, 182 }; // api.wunderground.com

SYSTEM_MODE(SEMI_AUTOMATIC);

/* This function is called once at start up ----------------------------------*/
void setup()
{
    // Make sure your Serial Terminal app is closed before powering your Core
    Serial.begin(9600);
    // Now open your Serial Terminal, and hit any key to continue!
    while(!Serial.available());
    Serial.println("Turning on WiFi");
    WiFi.on();
    Serial.println("Connecting to WiFi");
    WiFi.connect();
    Serial.println("Waiting for connection to be established");
    while(!WiFi.ready());
    Serial.println("WiFi Connected!");
    
    Serial.println("Connecting to the API...");
    
    // URL: http://api.wunderground.com/api/API_KEY/conditions/q/CA/Newhall.json
    if (client.connect(server, 80))
    {
      Serial.println("connected");
      client.println("GET /api/5db4c89c7b8b7624/conditions/q/CA/Newhall.json HTTP/1.0");
      client.println("Host: api.wunderground.com");
      client.println("Content-Length: 0");
      client.println();
    }
    else
    {
      Serial.println("connection failed");
    }

}

/* This function loops forever --------------------------------------------*/
void loop()
{
    if (client.available())
    {
        char c = client.read();
        Serial.print(c);
    }

    if (!client.connected())
    {
        Serial.println();
        Serial.println("disconnecting. Connecting to the SparkCloud for re-programming");
        client.stop();
        Spark.connect();
        for(;;) SPARK_WLAN_Loop();
    }
}

You need to put your API key in.
Here’s what this code is doing:

  • SYSTEM_MODE(SEMI_AUTOMATIC) disconnects you from the cloud. Useful if you are downloading and printing a lot of data out to the Serial console
  • Wifi.on(), WiFI.connect(), etc connects you to the internet without connecting you to the cloud
  • “GET /api/5db4c89c7b8b7624/conditions/q/CA/Newhall.json HTTP/1.0” and “Content-Length: 0” are required HTTP headers so you can talk to the HTTP server which serves the API.
  • Spark.connect() reconnects the core to the SparkCloud in case you aren’t developing locally.

I know that’s a lot to take it. Let me know if you have any questions and I’ll be happy to answer them.

You next step is to strip off all the http header stuff that gets returned and then to parse the JSON using one of the JSON parsing libraries that have been ported.

I copied the code that you provided (using my own key) and it worked great!!
After parsing the results my output is as follows:

Turning on WiFi
Connecting to WiFi
Waiting for connection to be established
WiFi Connected!
Connecting to the API…
connected

Outside Temp F = 69.9
Outside Temp C = 21.1
Relative Humidity = 41%
Wind = 2.6
icon = partlycloudy

disconnecting. Connecting to the SparkCloud for re-programming
your help was great.

Thanks and best regards,
Michael

1 Like