ESP8266 загрузка данных методом PUT в Grovestreams - PullRequest
0 голосов
/ 05 мая 2018

У меня проблема с загрузкой данных с ESP8266 (подключен к STM32L0) в Grovestreams (с ThingSpeak он работает отлично, но на GS нет). Я не использую Arduino HW или SW (и никогда не буду), но моя собственная библиотека (но это, вероятно, не проблема).

В веб-браузере эта команда работает

http://grovestreams.com/api/feed?api_key=secretKEY&compId=bath&data=29&data=66&asPut

&asPut есть, потому что веб-браузер использует GET по умолчанию. Но когда я делаю это с ESP8266, как

ESP8266_SendCmd("AT+CIPSTART="TCP","grovestreams.com",80");
ESP8266_SendData("PUT /api/feed?api_key=secretKEY&compId=bath&data=29&data=66 HTTP/1.1");

ESP отправляет данные в потоковые потоки

AT+CIPSTART="TCP","grovestreams.com",80
CONNECT
OK
AT+CIPSEND=95
OK
> 
busy s...
Recv 95 bytes
SEND OK

но ничего не происходит (значения не будут отображаться на сервере). Я тоже попробовал это

ESP8266_SendCmd("AT+CIPSTART="TCP","grovestreams.com",80");
ESP8266_SendData("PUT /api/feed?api_key=secretKEY&compId=bath&data=29&data=66 HTTP/1.1\r\nHost: \r\nConnection: close\r\nContent-Type: application/json");

тогда я получаю ответ от сервера

+IPD,487:HTTP/1.1 408 Request Time-out
Date: Sat, 05 May 2018 00:48:23 GMT
Server: Apache
Vary: Accept-Encoding
Content-Length: 293
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head><title>408 
Request Time-out</title></head><body><h1>Request Time-out</h1><p>Server 
timeout waiting for the HTTP request from the client.</p><hr><address>Apache 
Server at www.grovestreams.com Port 80</address></body></html>CLOSED

Функции для отправки данных и команд выглядят как

void ESP8266_SendData(char* data)
{
    char str[50] = "";
    sprintf(str, "AT+CIPSEND=%d", strlen(data));
    ESP8266_SendCmd(str);
    HAL_Delay(100);

    char str2[2048] = "";
    sprintf(str2, "%s\r\n", data);
    HAL_UART_Transmit(&ESPUartHandle, str2,(uint16_t) strlen(str2), 20);
    HAL_Delay(200);
}

void ESP8266_SendCmd(char* cmd)
{
    char str[50] = "";
    sprintf(str, "%s\r\n", cmd);
    HAL_UART_Transmit(&ESPUartHandle, str,(uint16_t) strlen(str), 20);
    HAL_Delay(100);
}

Как я писал ранее, с Thingspeak он отлично работает (метод GET) как

ESP8266_SendCmd("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80");
HAL_Delay(2000);
ESP8266_SendData("GET /update?api_key=secretKEY&field1=36");

Пожалуйста, что я делаю не так с методом PUT на ESP8266?

РЕДАКТИРОВАТЬ 6.5.2018: после детального изучения библиотеки arduino grovestreams этот формат команды работает:

ESP8266_SendData("PUT /api/feed?api_key=secretKEY&compId=bath&data=20.7&data=66.8 HTTP/1.1\nHost: grovestreams.com\nConnection: close\nContent-Type: application/json\n\n");

Очень важны последние два \n\n, без которых данные не будут загружаться.

1 Ответ

0 голосов
/ 07 мая 2018

Это различие между Grovestreams и ThingSpeak, скорее всего, связано с разным способом анализа HTTP-запросов (в ThingSpeak используется более надежная реализация).

RFC2616 - Раздел 4. HTTP-сообщение говорит следующее:

В сообщениях «Запрос» (раздел 5) и «Ответ» (раздел 6) используется общий формат сообщения RFC 822 [9] для передающих объектов (полезная нагрузка сообщения). Оба типа сообщений состоят из стартовой строки, ноль или более полей заголовка (также известных как «заголовки»), пустая строка (т.е. строка, не предшествующая CRLF), указывающая конец поля заголовка и, возможно, тело сообщения.

Поэтому вы не отправляете маркер «конца заголовков» \r\n\r\n может привести к тому, что сервер продолжит ожидать больше заголовков, которые могут быть отправлены в отдельных кадрах TCP (или PDU TLS). Это также подтверждается полученным ответом:

<html><head><title>408 
Request Time-out</title></head><body><h1>Request Time-out</h1><p>Server 
timeout waiting for the HTTP request from the client.</p><hr><address>Apache 
Server at www.grovestreams.com Port 80</address></body></html>

Поэтому в целом, похоже, есть две проблемы с вашим кодом:

  1. Используйте CRLF (\r\n), а не только LF \n, чтобы соответствовать RFC2616. В разделе 10.3 «Допустимые приложения» упоминается следующее: :

Терминатором строки для полей заголовка сообщения является последовательность CRLF. Тем не менее, мы рекомендуем приложениям при разборе таких заголовков распознавать один LF в качестве ограничителя строки и игнорировать ведущий CR.

Отправка \n вместо \r\n для разделения заголовков работает только потому, что данная реализация допускает это, а не потому, что это следует RFC.

  1. Отправьте пустой заголовок для обозначения конца раздела заголовков, поместив CRLF сразу после последнего CRLF, следующего за последним содержимым заголовка. Это говорит серверу, что он больше не должен ждать больше заголовков, и теперь он может приступить к получению / анализу тела HTTP (если оно есть в данном случае) или отправке ответа.

После применения этих исправлений правильный запрос должен выглядеть следующим образом:

ESP8266_SendData("PUT /api/feed?api_key=secretKEY&compId=bath&data=20.7&data=66.8 HTTP/1.1\r\nHost: grovestreams.com\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n");
...