Arthur
Arthur

Reputation: 97

Arduino with WiFi Shield make weird post request

I am working on small weather station based on Arduino Uno. In fact I am already create prototype which measure humidity, temperature, pressure and level of CO2 and send data trough POST request to server. For the whole week it works perfectly sending data to server on hourly basis. But yesterday I find out that no new data coming. My first thought was that something wrong with WiFi, I restart router, check connectivity, everything work perfect. I think if something wrong with Arduino and restart it, it works. So I check what I get after connection and answer was:

   HTTP/1.1 405 METHOD NOT ALLOWED
   Date: Fri, 02 Sep 2016 13:27:02 GMT
   Server: Apache/2.4.10 (Debian)
   Allow: GET, OPTIONS, POST, HEAD
   Content-Length: 178
   Connection: close
   Content-Type: text/html

   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
   <title>405 Method Not Allowed</title>
   <h1>Method Not Allowed</h1>
   <p>The method is not allowed for the requested URL.</p>
   *CLOS*

Ok then I send POST request to server manually (trough Postman) and it is works. So I go to server and start read logs, there is no errors but in access.log I find out something interesting:

Working post request coming from Postman look like:

15.15.119.103 - - [02/Sep/2016:13:54:03 +0300] "POST /api/meteo HTTP/1.1" 200 319 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"

But when it comes from Arduino it look in strange way

15.15.119.103 - - [02/Sep/2016:13:53:54 +0300] "*HELLO*POST /api/meteo HTTP/1.1" 405 380 "-" "-"

So as you can see it comes to server not like POST but LIKE "HELLOPOST" and it is ruined everything. The problem is that I change nothing in my code and it is working somehow during the week. You can see peace of my Arduino code bellow:

#include <WiFly.h>
#include "HTTPClient.h"

#define SSID      "bbbbbbb"
#define KEY       "ccccccc"

#define AUTH      WIFLY_AUTH_WPA2_PSK

#define HTTP_POST_URL "15.15.25.67/api/meteo"

SoftwareSerial uart(2, 3);
WiFly wifly(uart);
HTTPClient http;

String PostData;
char PostBuf[90];

        uart.begin(9600);
//      check if WiFly is associated with AP(SSID)
        if (!wifly.isAssociated(SSID)) {
          while (!wifly.join(SSID, KEY, AUTH)) {
            Serial.println("Failed to join " SSID);
            Serial.println("Wait 0.1 second and try again...");
            delay(100);
          }

          wifly.save();    // save configuration, 
        }  
        PostData.toCharArray(PostBuf, 90);
        while (http.post(HTTP_POST_URL, PostBuf, 10000) < 0) {
        }
        while (wifly.receive((uint8_t *)&get, 1, 1000) == 1) {
        Serial.print(get);
        }
        uart.end();

So it connect to WiFI and send request, but type of request is quite strange. I try to find any key which can help with no results maybe somebody can give me advise?

In case if needed I put here HTTPClient.h:

#ifndef __HTTP_CLIENT_H__
#define __HTTP_CLIENT_H__

#define HTTP_CLIENT_DEFAULT_TIMEOUT         30000  // 3s

#define HTTP_MAX_HOST_LEN                   20
#define HTTP_MAX_PATH_LEN                   64
#define HTTP_MAX_BUF_LEN                    100

#define HTTP_DEFAULT_PORT                   80

#include <Arduino.h>
#include <WiFly.h>

class HTTPClient {
  public:
    HTTPClient();

    int get(const char *url, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);
    int get(const char *url, const char *header, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);
    int post(const char *url, const char *data, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);
    int post(const char *url, const char *headers, const char *data, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);

  private:
    int parseURL(const char *url, char *host, int max_host_len, uint16_t *port, char *path, int max_path_len);
    int connect(const char *url, const char *method, const char *data, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);
    int connect(const char *url, const char *method, const char *header, const char *data, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);

    WiFly* wifly;
};

#endif // __HTTP_CLIENT_H__

As for HTTPClient.cpp it looks like this:

#include <string.h>
#include "HTTPClient.h"
#include "Debug.h"

HTTPClient::HTTPClient()
{
  wifly = WiFly::getInstance();
}

int HTTPClient::get(const char *url, int timeout)
{
  return connect(url, "GET", NULL, NULL, timeout);
}

int HTTPClient::get(const char *url, const char *headers, int timeout)
{
  return connect(url, "GET", headers, NULL, timeout);
}

int HTTPClient::post(const char *url, const char *data, int timeout)
{
  return connect(url, "POST", NULL, data, timeout);
}

int HTTPClient::post(const char *url, const char *headers, const char *data, int timeout)
{
  return connect(url, "POST", headers, data, timeout);
}

int HTTPClient::connect(const char *url, const char *method, const char *data, int timeout)
{
  return connect(url, method, NULL, data, timeout);
}

int HTTPClient::connect(const char *url, const char *method, const char *headers, const char *data, int timeout)
{
  char host[HTTP_MAX_HOST_LEN];
  uint16_t port;
  char path[HTTP_MAX_PATH_LEN];

  if (parseURL(url, host, sizeof(host), &port, path, sizeof(path)) != 0) {
    DBG("Failed to parse URL.\r\n");
    return -1;
  }

  if (!wifly->connect(host, port, timeout)) {
    DBG("Failed to connect.\r\n");
    return -2;
  }

  // Send request
  char buf[HTTP_MAX_BUF_LEN];
  snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\n", method, path);
  wifly->send(buf);

  // Send all headers
  snprintf(buf, sizeof(buf), "Host: %s\r\nConnection: close\r\n", host);
  wifly->send(buf);

  if (data != NULL) {
    snprintf(buf, sizeof(buf), "Content-Length: %d\r\nContent-Type: text/plain\r\n", strlen(data));
    wifly->send(buf);
  }

  if (headers != NULL) {
    wifly->send(headers);
  }

  // Close headers
  wifly->send("\r\n");

  // Send body
  if (data != NULL) {
    wifly->send(data);
  }

  return 0;
}

int HTTPClient::parseURL(const char *url, char *host, int max_host_len, uint16_t *port, char *path, int max_path_len)
{
  char *scheme_ptr = (char *)url;
  char *host_ptr = (char *)strstr(url, "://");
  if (host_ptr != NULL) {
    if (strncmp(scheme_ptr, "http://", 7)) {
      DBG("Bad scheme\r\n");
      return -1;
    }
    host_ptr += 3;
  } else {
    host_ptr = (char *)url;
  }

  int host_len = 0;
  char *port_ptr = strchr(host_ptr, ':');
  if (port_ptr != NULL) {
    host_len = port_ptr - host_ptr;
    port_ptr++;
    if (sscanf(port_ptr, "%hu", port) != 1) {
      DBG("Could not find port.\r\n");
      return -3;
    }
  } else {
    *port = HTTP_DEFAULT_PORT;
  }

  char *path_ptr = strchr(host_ptr, '/');
  if (host_len == 0) {
    host_len = path_ptr - host_ptr;
  }

  if (max_host_len < (host_len + 1)) {
    DBG("Host buffer is too small.\r\n");
    return -4;
  }
  memcpy(host, host_ptr, host_len);
  host[host_len] = '\0';

  int path_len;
  char *fragment_ptr = strchr(host_ptr, '#');
  if (fragment_ptr != NULL) {
    path_len = fragment_ptr - path_ptr;
  } else {
    path_len = strlen(path_ptr);
  }

  if (max_path_len < (path_len + 1)) {
    DBG("Path buffer is too small.\r\n");
    return -5;
  }
  memcpy(path, path_ptr, path_len);
  path[path_len] = '\0';

  return 0;
}

Upvotes: 0

Views: 244

Answers (1)

Arthur
Arthur

Reputation: 97

I find out a root of problem, by default WiFiShield v.1.0 say "HELLO" when TCP connection opened. In fact it written deep into the manual.

My connection was not so fast, so it is manage to say "HELLO" before connectivity, but I upgrade router firmware and it start working faster, that is why "HELLO" connected to next request which was POST in this case. Solution is simple just add:

wifly.sendCommand("set comm remote 0\r");

and this command disable welcome message on WiFiShield. Hope it helps somebody.

Upvotes: 1

Related Questions