HTTP POST issue, especially when using deep sleep

I bought a Spark Core and connected it with a DS18B20 temperature sensor to monitor the temperature inside my beehive. Every 30 minutes, it reads the temperature, sends it to my webserver with a HTTP POST (using HttpClient) and returns to deep sleep.

I see it returning properly every 30 minutes, blinking green while connecting to the Wifi and then breathing cyan while the code is running. This takes a few seconds and then it returns to sleep.

What is going wrong is that the HTTP POST isn’t executed always. With the deep sleep, roughly 20% of the requests reach my server. Without the deep sleep (a simple delay instead), most requests reach the server (around 90%). The failures are irregular, I don’t see a pattern.

I tried sniffing the Wifi to see the TCP packets, but failed to do so (my Wifi driver doesn’t support this mode).

Has anyone experienced this problem?

This is my code:

// This #include statement was automatically added by the Spark IDE.
#include "HttpClient/HttpClient.h" 

// This #include statement was automatically added by the Spark IDE.
#include "OneWire/OneWire.h"

HttpClient http; 
OneWire one = OneWire(D2);
uint8_t rom[8];
uint8_t resp[9];
int counter = 0;
char szInfo[64];
unsigned long startT;

// Headers currently need to be set at init, useful for API keys etc.
http_header_t headers[] = {
{ NULL, NULL } // NOTE: Always terminate headers will NULL
};
 
http_request_t request;
http_response_t response; 

/* This function is called once at start up ----------------------------------*/
void setup()
{
    request.hostname = "www.netb.be";
    request.port = 80;
    startT = millis();
}

/* This function loops forever --------------------------------------------*/
void loop()
{
    //This will run in a loop
    if (millis()-startT > 30*1000){ 
        Spark.sleep(SLEEP_MODE_DEEP, 30);
    } 
    
    // Get the ROM address
    one.reset();
    one.write(0x33);
    one.read_bytes(rom, 8);
    // Get the temp
    one.reset();
    one.write(0x55);
    one.write_bytes(rom,8);
    one.write(0x44);
    delay(10);
    one.reset();
    one.write(0x55);
    one.write_bytes(rom, 8);
    one.write(0xBE);
    one.read_bytes(resp, 9);

    byte MSB = resp[1];
    byte LSB = resp[0];

    int16_t intTemp = ((MSB << 8) | LSB); //using two's compliment 16-bit
    float celsius =   ((double)intTemp)/16.0;
    
    request.path = "/bees/save.php?temp=" + String(celsius);
    request.body = "";
    http.post(request, response, headers);
    startT = millis();
    
    // normal delay improves things, but eats the battery much faster
    //delay(10000);
    
    // 30 minute deep sleep
    Spark.sleep(SLEEP_MODE_DEEP, 1800);
}

@bennygiesbers
First of all when your core returns from a deep sleep it will behave as if it was just turned on again. So you don’t need to put the Spark.sleep() at the end of your loop, the first test is sufficient.

With the way you have it currently entering sleep at the end of loop you are not letting the Spark complete sending the data to your server before you go to sleep. I suggest that you remove the sleep at the end of your loop and let your loop continue for the 30 seconds and then enter sleep.

BTW - I put together a bee hive sensor package that monitors temp in 4 places and humidity in two. You can find the info here

First of all, thanks for your help.

That first test with the sleep was added after reading this thread, hoping it fixes things when the Spark gets stuck. Not sure if it actually ever ran once, as I haven’t seen the Spark get stuck.

You’re saying the Spark might not be able to complete the sending of the data to my server. So that means the HttpClient request isn’t blocking execution. Not what I expected, since all code I’ve seen with the HttpClient just continues after the request without doing any checks. I don’t want to wait a very high number of seconds just to be sure that the request went through, because efficient battery usage is important to me. Waiting 30 seconds would seriously lower battery life. I’ll add a while loop after the request that loops until there’s a response. Will post it this thread when I have some results…

I like your project as well, nice job! Will try it if I can’t get mine to work. Or maybe in the next phase of my “beehive monitoring project”.

@bennygiesbers
I just looked at the code for the HttpClient library and it waits for a response code from the server. However you are not checking the response from the call to http.post(request, response, headers); for errors. The response code from the HttpServer will be in response.status. I can’t remember what code indicates success.

If you are getting an error, or not a success code you can try again until you get a success response code.

You may want to try to send the data, if that fails let your loop continue and try again next time thru. Then once you get a success from your http.post(request, response, headers); you can enter sleep mode.

1 Like

I did a test on the response.status code. If it’s still empty or zero, I wait for half a second and check it again. It seems it never fails with a status code that is zero or empty. When it goes wrong, the connection just fails.

HttpClient>    Connection failed.

That’s all I see in the Serial Monitor when it fails. My server isn’t experiencing any issues, but it looks like it’s hitting a timeout. The request often takes 1 to 2 seconds, but sometimes it’s more. If it goes over 5 seconds, there’s a timeout which results in the failed connection. I guess this could be the problem, but I don’t understand why it’s happening a lot more when using a deep sleep instead of a delay.

When I test it on my desktop, the request to the server usually takes 200 to 300 milliseconds, but sometime it goes up to 1 to 2 seconds. I’ll try another server, see if I can improve things this way.

Another thing to keep in mind is that the HttpClient library only supports HTTP 1.0, so if your destination site/server requires host headers, it will not work. In some of my other testing, I had to put a delay(5000); before making an HTTP call after waking up from a deep sleep.

2 Likes

Most of the time (with the regular delay), it’s working fine, so I assume the failed connection isn’t related to HTTP 1.0. But it’s a good point that could help other people with similar issues.

About the delay(5000);, doesn’t that seriously decrease your battery life? And what would be the explanation for this fix? What exactly isn’t ready yet when the loop starts?

I added the delay(5000); after the HTTP post and before my deep sleep, but it doesn’t seem to be helping much. Nearly all of the HTTP posts are failing.

Does anyone have an idea why this is happening? Does someone have a working combination of a HTTP post/get and a deep sleep?

Hi @bennygiesbers

I would try to make sure that the network connection is working before you do any HTTP post requests when you wake up from deep sleep. You can check the local IP address for all zeros, or a variety of other tricks, like ping’ing your server etc. and see if that helps.

How can I make sure the network connection is working? The deep sleep comes so fast that it’s really hard to get anything out of the serial monitor.

But the issues also happen when I’m using a regular delay instead of a deep sleep and in those cases, I see that Wifi is working fine, signal strength is stable, but the HTTP/TCP connection to my server just fails. I could ping the device from my computer as well. At the same time, my server was perfectly reachable from my computer.

So lots of things can make it fail included but not limited to: DHCP lease problems, ARP problems, server busy, not reading all the returned data from the server on the last run, etc., etc.

Is the LED doing anything interesting when it fails in the delay() case? I would try to debug that first instead of the deep sleep case.

The LED isn’t behaving different when the post is failing.
I don’t know how I can diagnose these problems, as the device isn’t reachable with the serial monitor when using the deep sleep. It is reachable, but I just don’t have enough time. When I use the regular delay, I can monitor it and I see that the connection just fails.

I tried switching to a local WAMP server instead of my online server, but that makes things just worse. I tried several pieces of code and different libraries and none of these manages to connect to my local server. The connection just fails everytime. It fails when using the IP and it fails when using the hostname to connect. I’m also monitoring with Wireshark and don’t see any incoming connections. It’s not a firewall issue, as my iPhone can access the same webserver without problems.

I’m beginning to suspect that I just have a faulty Spark. Can someone post a piece of code that does HTTP calls and works 100% of the time for them?

If this is the only message you get, it looks exactly like our cores. Sometime they are not able to execute a DNS query so the library failes. A few hours later (or days) it will work (again) or not.

It seems to happen only in big WLAN Networks (with a lot of clients), and is very frustrating. Seems to be a Bug from the cc3000, handling the ARP Caches incorrectly (or simply overflows with too many clients)

If we change our Code to IP, everything works fine, even if we switch the CHIP on and off with Wifi.off();

PLEASE NOTE:
Do Not change “servername” to “192.168.0.1”.
You have to use the IP Structure :
request.ip = {192,168,0,1};
request.port = 80;

When I switch from domain to IP, it just stops working. It compiles just fine, but no contact is made to my local webserver.
Can you share your code please?

simply something like this (I’am posting data here to the Server)
(what happens in your log?)

request.ip = {87,106,...,....};
request.port = 80;
request.path = "/box.aspx";
   request.body = "<request><session ><box_deliver  t=\""+String(millis() / 1000)+"\" cfg=\""+cfg_server+"\" secret=\""+secret+"\" box=\""+Spark.deviceID()+"\">"+bufferlast+""+bufferframes+"</box_deliver></request>";
// Get request
Serial.println('Getting...');
http.post(request, response, headers);
Serial.println('Done');
Serial.println(response.body);
if (response.status == 200)``

@bennygiesbers
I have seen cases where my first connect fails after starting up the WiFi module. Do you have any code in place to test this condition and attempt a few retries before giving up? My DNSTest application tries 5 times before giving up. Look at line 526 for how I do the retries.

Please also ensure the following:
If you call an external Server using a name (like “www.google.com”) you must
specify this name inside the HTTP protokoll if you use plain IP, so the web server knows which name you want to use, if you directly call the server with IP!

So you must add the Host Header to HTTP

  { "Accept" , "*/*"},
  { "Host","softmeter.meinwebserver.de"},

It seems I have a breakthrough, yay! :slight_smile:
I tried all the things you guys suggested, thanks for the help!
Unfortunately it didn’t help. So I started disabling parts of my code, until I noticed that it started working flawlessly when I remove all the DS18B20 related code from my loop. Which was still the same code as in the first post in this thread. Even with the deep sleep, it’s working again.

So the code kept failing at the HTTP connection when I was reading the temperature sensor milliseconds earlier. If I just post a hardcoded temperature value and don’t touch my sensor, it just works.

Looking more closely at my temperature monitoring sensor, I also noticed that I had a 10 ohm resistor instead of a 4.7 ohm resistor. Again, I feel like such a newbie. I replaced it and it seems to be working better now, although not perfect. Since last night it’s posting indoor temperatures every half hour. Of the 19 posts it should be making, 14 were a success. This is with the 30 minutes deep sleep. Much better than before (with the 10 ohm resistor), when 80 to 90% of my posts failed.

My knowledge of electronics and Spark is too limited to explain that. Does anyone have an idea?

1 Like

I was a bit too optimistic yesterday after switching to the 4.7 ohm resistor. Seems it’s not making that much of a different, as earlier today around 12 consecutive posts failed (one every 30 minutes). I’ll look more in the direction of my temperature sensor code and try some alternative methods of reading the temperature. Suggestions are more than welcome.