ESP8266 http POST kérés nem megy...

Sziasztok!

Csináltam egy ESP8266 alapon egy 5 csatornás hőmérsékletmérő eszközt, ami WiFi-n HTTP POST-al tolná
föl az adatokat egy szerverre. (Arduino framework, Platform.IO)
Nem értem, a válasz a POST kérésnek:
"HTTP Response code: 400" - tehát valami szintaktikai hiba lehet?! Már a szemem kifolyik, nem találom
a hibám.
Ez a programrész:

bool puthttp() {
    bool result = false;
    long rssi = WiFi.RSSI();
    String localip = WiFi.localIP().toString();
    WiFiClient client;
    HTTPClient http;

    char jsonstr[400];
    char jsonstr2[100];
    char jsonstr3[30];

    Serial.println(serverstr);

    snprintf(jsonstr, sizeof(jsonstr), "{\"device_id\":%d, \"ip_address\":\"%s\", \"ssid\":\"%s\", \"rssi\":%d, ",didx,localip.c_str(),ssidstr,rssi);
    snprintf(jsonstr2, sizeof(jsonstr2), "\"value_1\":%.1f, \"value_2\":%.1f, \"value_3\":%.1f, \"value_4\":%.1f, \"value_5\":%.1f, ",hom1,hom2,hom3,hom4,hom5);
    snprintf(jsonstr3, sizeof(jsonstr3), "\"timestamp\":%ld}", helyiUTC);
    strncat(jsonstr, jsonstr2, sizeof(jsonstr2));
    strncat(jsonstr, jsonstr3, sizeof(jsonstr3));

    Serial.println(jsonstr);

    // Your Domain name with URL path or IP address with path
    Serial.print("http.begin:");
    bool mi = http.begin(client, serverstr);
    
    Serial.println(mi);
    http.addHeader("Content-Type", "application/json");

    int httpResponseCode = http.POST(jsonstr);
    //int httpResponseCode = http.POST("{\"value\": 20 }");
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    http.end();
    if (httpResponseCode == 200) result = true;
    return result;
}

És ez a készített "jsonstr":
{"device_id":10170, "ip_address":"192.168.3.162", "ssid":"gentoom", "rssi":-62, "value_1":22.8, "value_2":-100.0,
"value_3":-100.0, "value_4":-100.0, "value_5":-100.0, "timestamp":1709045163}

Köszönöm!
Roland

Hozzászólások

Szerkesztve: 2024. 02. 27., k – 18:13

Maga amit küldesz, az valid JSON. A kérdés az, hogy a szerveroldal ugyanilyen struktúrájú JSON-t vár-e el, vagy esetleg valamelyik mező neve vagy típusa eltérő, esetleg van hiányzó kötelező mező stb. A szerver logjában mi látszik? Azt is el tudom képzelni, hogy a value az egy tömb, azaz nem value_1, value_2, value_3, value_4, value_5 mező kéne neki külön-külön, hanem egy ilyen json:
 

{
    "device_id": 10170,
    "ip_address": "192.168.3.162",
    "ssid": "gentoom",
    "rssi": -62,
    "value": [22.8, -100.0, -100.0, -100.0, -100.0],
    "timestamp": 1709045163
}

De ezt csak a fogadóoldali kód ismeretében tudjuk eldönteni, hiszen ő mondja azt, hogy nem megfelelő a kérés.

A szerverig el sem jut.
Egyébként a szervert nem én használom/csináltam.

Ennyit kaptam az ottani gazditól (így várja az adatokat):

> A végpont:
> https://xxxxx.xx:8080
>
> A kérés:
> POST
> headers: {
>     'Content-Type': 'application/json'
> }
>
> Body data:
>
> {
>     "device_id": 1,
>     "ip_address": "192.168.1.123",
>     "ssid": "Sample_SSID",
>     "rssi": -41,
>     "value_1": 18.1,
>     "value_2": 18.2,
>     "value_3": 18.3,
>     "value_4": 18.4,
>     "value_5": 18.5,
>     "timestamp": 1708478505
> }

Ha `curl` parancssorból meghívod ugyanezt, ugyanígy, akkor az mit ír? Egyszerűbb kitapasztalni a kommunikációs hibákat CLI-ben, mint ESP8266-on.

Ez lett:

domo@domo2:~$ curl -X POST https://xxxxxxx.hu:8080 -H "Content-Type: application/json" -d '{"device_id":10170, "ip_address":"192.168.3.162", "ssid":"gentoom", "rssi":-62, "value_1":22.8, "value_2":-100.0,
"value_3":-100.0, "value_4":-100.0, "value_5":-100.0, "timestamp":1709045163}'
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
domo@domo2:~$

Érdekes, mert ESPHome-ban így megy:

- http_request.post:
                url: https://xxxxxx.hu:8080
                headers:
                  Content-Type: application/json
                verify_ssl: false
                json: |-
                  //root["device_id"] = 10000 + id(vegeIP);
                  root["device_id"] = id(deviceid).state;
                  root["ip_address"] = WiFi.localIP().toString();
                  root["ssid"] = WiFi.SSID();
                  root["rssi"] = int(id(wifiero).state);
                  root["value_1"] = (!isnan(id(hom1).state) ? id(hom1).state : 0.0);
                  root["value_2"] = (!isnan(id(hom2).state) ? id(hom2).state : 0.0);
                  root["value_3"] = (!isnan(id(hom3).state) ? id(hom3).state : 0.0);
                  root["value_4"] = (!isnan(id(hom4).state) ? id(hom4).state : 0.0);
                  root["value_5"] = (!isnan(id(hom5).state) ? id(hom5).state : 0.0);
                  root["timestamp"] = id(idosntp).now().timestamp;

curl ... -k ... -ezzel megy!
 

curl -X POST https://xxxxxxxxx.hu:8080 -k -H "Content-Type: application/json" -d '{"device_id":10170, "ip_address":"192.168.3.162", "ssid":"gentoom", "rssi":-62, "value_1":22.8, "value_2":-100.0,
"value_3":-100.0, "value_4":-100.0, "value_5":-100.0, "timestamp":1709066827}'

Na, csak ezt kell az ESP8266-ra átírni ...-k...

Szerkesztve: 2024. 02. 27., k – 21:09

Mi a serverstr?

Lehetne egy http.getString() a történetben, hátha van valami hibaüzenet.

Érdekes jelenség - most látom.

A rutin első lefutásakor 200 a válasz (jó!), aztán utána x percre rá már -1! és így már nem megy. Nyomozom, hogy mitől lehet, ha ugyanazt hívom meg.

Nekem ez müxik:

void sendpost() {
  String purl = posts.substring(0, posts.indexOf(")"));
  String pdata = addvalstr(posts.substring(posts.indexOf("@") + 1, posts.length()));
  if (purl.substring(0, 4) != "http") { purl = F("http://") + purl; }
  HTTPClient httpClient;
  WiFiClient *client = nullptr;
  WiFiClientSecure *clients = nullptr;
  if (purl.substring(0, 5) == "https") { 
    clients = new WiFiClientSecure;
    clients->setInsecure();
    httpClient.begin(*clients, purl);
    } else {
    client = new WiFiClient;
    httpClient.begin(*client, purl);
    }
  httpClient.addHeader(F("Content-Type"), F("application/x-www-form-urlencoded"));
  poste = httpClient.POST(pdata);
  postg = httpClient.getString();
  httpClient.end();
  delete client;
  delete clients;
}

A szerver elejében van a "https://

úja ideteszem a kódot, ami kivételt okoz:

bool puthttp() {
    bool result = false;
    long rssi = WiFi.RSSI();
    String localip = WiFi.localIP().toString();
    HTTPClient http;
    //WiFiClientSecure client;
    WiFiClientSecure *client = new WiFiClientSecure;

    char jsonstr[400];
    char jsonstr2[100];
    char jsonstr3[30];


    Serial.println(serverstr);


    snprintf(jsonstr, sizeof(jsonstr), "{\"device_id\":%d, \"ip_address\":\"%s\", \"ssid\":\"%s\", \"rssi\":%d, ",didx,localip.c_str(),ssidstr,rssi);
    snprintf(jsonstr2, sizeof(jsonstr2), "\"value_1\":%.1f, \"value_2\":%.1f, \"value_3\":%.1f, \"value_4\":%.1f, \"value_5\":%.1f, ",hom1,hom2,hom3,hom4,hom5);
    snprintf(jsonstr3, sizeof(jsonstr3), "\"timestamp\":%ld}", helyiUTC);
    strncat(jsonstr, jsonstr2, sizeof(jsonstr2));
    strncat(jsonstr, jsonstr3, sizeof(jsonstr3));

    Serial.println(jsonstr);


    // Your Domain name with URL path or IP address with path
    Serial.print("http.begin:");
    //client.setInsecure();
    client->setInsecure();
    bool mi = http.begin(*client, serverstr);
    
    Serial.println(mi);
    http.addHeader("Content-Type", "application/json");

    int httpResponseCode = http.POST(jsonstr);
    
    //int httpResponseCode = http.POST("{\"value\": 20 }");
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    http.end();
    delete client;
    if (httpResponseCode == 200) result = true;
    return result;
}

Ja, és a "new - delete" nélküli változat simán lefut - mondjuk, csak először, majd a második hívásra -1 a response

Hogy lehetne a http.POST(...)-ból http.print(...)-et csinálni?

Szerkesztve: 2024. 02. 28., sze – 22:26

Én nem értem. Ez a változat megy 1x meghívva a puthttp függvény. Többször meghívva -1 a "httpResponseCode".
Viszont, ha kívül - nem a függvény törzsében - van a "http" és "client" deklarálva, ismét nem fut, kivételt okoz.

#ifndef HTTPPOST
#define HTTPOST

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>

#include "config.h"

extern String serverstr, ssidstr;
extern long helyiUTC;
extern float hom1, hom2, hom3, hom4, hom5;
extern int didx;
//HTTPClient http;
//WiFiClientSecure client;

bool puthttp() {
    bool result = false;
    long rssi = WiFi.RSSI();
    String localip = WiFi.localIP().toString();
    HTTPClient http;
    WiFiClientSecure client;
    
    //WiFiClientSecure *client = new WiFiClientSecure;

    char jsonstr[400];
    char jsonstr2[100];
    char jsonstr3[30];

    Serial.println(serverstr);

    snprintf(jsonstr, sizeof(jsonstr), "{\"device_id\":%d, \"ip_address\":\"%s\", \"ssid\":\"%s\", \"rssi\":%d, ",didx,localip.c_str(),ssidstr,rssi);
    snprintf(jsonstr2, sizeof(jsonstr2), "\"value_1\":%.1f, \"value_2\":%.1f, \"value_3\":%.1f, \"value_4\":%.1f, \"value_5\":%.1f, ",hom1,hom2,hom3,hom4,hom5);
    snprintf(jsonstr3, sizeof(jsonstr3), "\"timestamp\":%ld}", helyiUTC);
    strncat(jsonstr, jsonstr2, sizeof(jsonstr2));
    strncat(jsonstr, jsonstr3, sizeof(jsonstr3));

    Serial.println(jsonstr);


    // Your Domain name with URL path or IP address with path
    Serial.print("http.begin:");
    client.setInsecure();
    //client->setInsecure();
    bool mi = http.begin(client, serverstr);
    
    Serial.println(mi);

    http.addHeader("Content-Type", "application/json");

    int httpResponseCode = http.POST(jsonstr);
    
    //int httpResponseCode = http.POST("{\"value\": 20 }");
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    http.end();
    //delete client;
    if (httpResponseCode == 200) result = true;
    return result;
}

#endif

Pedig https://github.com/lzsiga/untarArduino szép munka volt. Nem akarod befejezni? A debug üzeneteket F() formába kéne hozni, a végéről a

	if (source!=NULL && source->isOpen()) {
		source->close();
	}

sort kivenni. Mehetne a hivatalos Arduino könyvtárak közé, hiánypótlás. Köszönöm hogy nekem megcsináltad, de szerintem ezt közkinccsé kéne tenni.