Repeat http requests to server help

I am trying to port the WiFi shield example from Arduino to the Spark.

Here is their example: http://arduino.cc/en/Tutorial/WiFiWebClientRepeating

So far I am entirely unable to get this to work on the Spark Core. Any example code out there yet for this?

Thanks in advance for help.

Yeah, that’s not going to work at all. That’s designed for a specific hardware shield that’s entirely incompatible with the CC2000 on the Spark Core.

However, the Core does have commands for connecting to and receiving data over TCP. Can you explain exactly what you’re trying to accomplish? Perhaps we can write something up (or help you write it). :smile:

Thanks for the quick reply. Here is a simple example of the workflow I need:

  1. Spark pings a script at www.examplesite.com/ping.php

  2. Ping.php returns a simple numerical response of 0,1,2,3,4, or 5

  3. Spark then runs something like:

    if(response == 0){do something;} and so on for each possible return.

Is something like that possible?

Very much so! You can use the TCPClient functionality to do it: http://docs.spark.io/#/firmware/communication-tcpclient

TCPClient client;
byte server[] = { 74, 125, 224, 72 }; // Google

This is the start of the (above) example TCPClient code. The four numbers separated by commas are where you’ll put the IP (dotted quad) of the server you’re trying to connect to.

void setup()
{
  Serial.begin(9600);
  delay(1000);
  Serial.println("connecting...");

  if (client.connect(server, 80)) 
  {
    Serial.println("connected");
    client.println("GET /search?q=unicorn HTTP/1.0");
    client.println();
  } 
  else 
  {
    Serial.println("connection failed");
  }
}

In this example, the client.println acts in a very similar manner to your standard serial.println function. Essentially, it’s just “printing” whatever is in the quotes to the IP you entered at the start. In your case, you’d want to use something like GET /ping.php HTTP/1.0 to get the desired response. Note the client.connect(server, 80) beforehand, which tells the function to connect over the standard HTTP port, 80.

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

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

Here, the char c = client.read(); reads the response from your ping.php script into a char called c. Note that all the setup is done in void setup, however you could move the entire * if (client.connect(server, 80))* section into void loop if you wanted it to poll the PHP script on each iteration. Be sure to put a delay in there so it’s not slamming the server.

(As you can see from the example script, it’s designed to search Google and print the RAW HTML response over the serial port. You don’t actually need any of the serial stuff for TCPClient, it’s just handy to have for debugging!)

Let me know if this gets you pointed in the right direction. If you need any specific advice or help, don’t hesitate to ask and we’ll do what we can to get you going! :smile:

Thanks very much for your detailed example!
I will try this on my Core and let you know how it goes.

I may also be going about this backwards. I can also have the server/browser call functions via the API.

This is why I should have purchased 2 cores… :smile:

Oh, if you can have the server run the PHP script on a cronjob, or you only need it to contact the Spark Core when the user goes to the ping.php URL, then I’d say just use the Cloud API Functions Call.

This statement will never finish. So when the client is disconnected, the core has to be reset before another run can be done.
Right now, this will also prevent the core to be flashed over wifi. (fix is impending).
If you want it repeated, the connection has to be made in the loop itself. so some reordering is required.

The other way to do it (barring resetting the core manually every so often) is by resetting the core in code.
There is no official call to restart the core, but in arduino forums the alternative approach is to make a call to a null reference.

it's rather ugly though.

void setup(){
}

void (*pseudoReset)(void)=0;

void loop(){
    delay(10000);
    pseudoReset ();
}

edit: and it works only once.

imho this would be port of the example. The “print wifi status” part is not applicable here so I left it out.
If anyone tries this out, let us know how it goes. Some of us are currently seeing behaviour that the tcp client cannot stabily make a connection twice.

    /*
   Repeating Wifi Web client
  
  This sketch connects to a a web server and makes a request
  over wifi using a spark core
  
  created 23 April 2012
  modifide 31 May 2012 by Tom Igoe
  ported to spark core 24 December 2013
  
  http://arduino.cc/en/Tutorial/WifiWebClientRepeating
  This code is in the public domain.
  */

// server address:
char server[] = "www.arduino.cc";
//IPAddress server(64,131,82,241);
TCPClient client;

unsigned long lastConnectionTime = 0;           // last time you connected to the server, in milliseconds
bool lastConnected = false;                  // state of the connection last time through the main loop
const unsigned long postingInterval = 10*1000;  // delay between updates, in milliseconds

void setup() {
   //Initialize serial and wait for port to open:
   Serial.begin(9600); 
   delay(1000);
}

void loop() {
   // if there's incoming data from the net connection.
   // send it out the serial port.  This is for debugging
   // purposes only:
   while (client.available()) {
     char c = client.read();
     Serial.write(c);
   }

   // if there's no net connection, but there was one last time
   // through the loop, then stop the client:
   if (!client.connected() && lastConnected) {
     Serial.println();
     Serial.println("disconnecting.");
     client.stop();
   }

   // if you're not connected, and ten seconds have passed since
   // your last connection, then connect again and send data:
   if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
     httpRequest();
   }
   // store the state of the connection for next time through
   // the loop:
   lastConnected = client.connected();
}

// this method makes a HTTP connection to the server:
void httpRequest() {
   // if there's a successful connection:
   if (client.connect(server, 80)) {
     Serial.println("connecting...");
     // send the HTTP PUT request:
     client.println("GET /latest.txt HTTP/1.1");
     client.println("Host: www.arduino.cc");
     client.println("User-Agent: spark.core-wifi");
     client.println("Connection: close");
     client.println();

     // note the time that the connection was made:
     lastConnectionTime = millis();
   } 
   else {
     // if you couldn't make a connection:
     Serial.println("connection failed");
     Serial.println("disconnecting.");
     client.stop();
   }
}

I flashed (using web IDE) the above code as is and got only the following response in a Putty serial session:

HTTP/1.1 200 OK
Server: nginx/1.4.2
Content-Type: text/plain
Last-Modified: Wed, 02 Oct 2013 13:46:55 GMT
ETag: "524c23cf-5"
Content-Length: 5
Accept-Ran

So it seems the program stopped part way through writing the first response before it got to writing the body (the body has the value 0105 as can be seen from www.arduino.cc/latest.txt). When I closed this putty session and opened a new one I got nothing at all.

When I re-flashed the program, and connected again with putty I got an identical result.

Has anybody got this to work?
Does anybody have any other working examples which retrieve a small HTTP GET response?

thanks,
Chris

There was recent update to TCPClient which caused problems. I made a fix that should to work:

1 Like

Ah, not true actually, though it's not in our docs anywhere. Since the Core uses an ARM Cortex-M3 microcontroller, we get the benefit of the CMSIS (Cortex Microcontroller Software Interface Standard) defined by ARM. The standard CMSIS reset call is NVIC_SystemReset. It's defined in the core-common-lib:

We call it, for example, to recover when we know an OTA update has failed:
https://github.com/spark/core-firmware/blob/master/src/main.cpp#L289

Also, I've glanced your pull request @weakset—I will test it in the next few days. Thank you!

Thanks weakset, that fixed my problem, I am now getting the full HTTP response (210 chars in my case).

Chris

1 Like

@weakset @zachary I was having these same read issues, and weakset’s code fixed it :smile: however I found the buffer can still be 512 and it works fine. The math done with _buffered and _remaining seem to be the real fix. I added a comment to the pull request with a link to my application.cpp test code: https://github.com/spark/core-firmware/pull/67

If I test that @roderikv’s code with 512, I get:

connecting...

Connection: close
X-Cache: MISS
X-URL: /latest.txt

0105

With 16 I get:

connecting...
HTTP/1.1 200 OK
Server: nginx/1.4.2
Content-Type: text/plain
Last-Modified: Wed, 02 Oct 2013 13:46:55 GMT
ETag: "524c23cf-5"
Content-Length: 5
Accept-Ranges: bytes
Date: Tue, 28 Jan 2014 16:16:58 GMT
X-Varnish: 1560461940 1560456490
Age: 146
Via: 1.1 varnish
Connection: close
X-Cache: HIT

0105

It depends a bit what your code is like, but 16 seems to me the value it works much more reliable than 32 or higher. With your code it works with 512 because of this trick in read loop, which gives the buffer time to fill up.:

 if(i++ > 100) {
     delay(100);
    i = 0;
  }

I did try injecting delays in tcpclient.cpp, but smaller buffer is the cleanest and best solution I found.

Uhg… that’s a bigger issue altogether then. We should not be relying upon delays to ensure we get all of the data. A buffer of 16 just masks the real problem. I’m not wrapping my head around how the buffer fills, vs. how fast we are reading it, vs. continuing to wait for the server to send data just yet… but I suspect there are more problems with it.

Btw, my delay was put in there more for a Serial bug I noticed where if I try to send too much data at once without a delay, it doesn’t get to the computer.

Is everything polled or what?

Just FYI all, I’ve pulled @weakset’s PR into master. We’ll get this deployed to the compile server this week.