Arduino (ESP8266) Http funktioniert nicht mehr

berto

Lt. Junior Grade
Registriert
Juni 2011
Beiträge
428
Hi Leute,

ich komme aus der Web-Development-Ecke und bin gerade dabei mich ein bisschen in die Raspi/Arduino-Welt einzuarbeiten mit verschiedenen kleinen Projekten.
Vor einiger Zeit habe ich mir einen Wettersensor gebastelt mit einem BME280. Dazu habe ich 2-3 Tutorials aus dem Web genommen und zusammen gebastelt, damit das Ding per HTTP POST die Daten an einen Kafka-Server schickt und das hat auch funktioniert.
Jetzt wollte ich allerdings ein bisschen mehr machen damit und somit die Daten nicht mehr an Kafka, sondern an eine API schicken.

Ich habe dazu den Code ein wenig umgebaut und es hat soweit auch alles funktioniert, bis auf einmal der httpClient nur noch "-1" returned hat. Und jetzt bringe ich gar nichts mehr zum Laufen, nicht einmal mehr die alte Version, die an Kafka schickt (nochmal aus git ausgecheckt). Ich finde leider auch keine Doku dazu was der -1 genau für ein return code ist.

Hier wäre mein (gekürzter) Code mit Debug output:
C++:
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <NTPClient.h>

#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10


#define NTP_OFFSET   0      // In seconds
#define NTP_INTERVAL 5 * 1000    // In miliseconds
#define NTP_ADDRESS  "at.pool.ntp.org"

#define SEALEVELPRESSURE_HPA (1013.25)
#define ALTITUDE 728 //Altitude of your location (m above sea level)

const int sensorId = 1;
const String sensorLocation = "Carport";

const float cToKOffset = 273.15;
float absoluteHumidity(float temperature, float humidity);
float dewPoint(float temperature, float humidity);

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);

// WiFi Configuration
WiFiClientSecure espClient;
const char* cfg_wifi_ssid = "<WifiName>";
const char* cfg_wifi_password = "<WifiPass>";

//Web/Server address to read/write from
//const char* http_target = "<APIUrl>";
const char* http_target = "<LocalAPIUrl>";

Adafruit_BME280 bme; // I2C

unsigned long interval = 60000; // every minute


void setup() {
  delay(1000);
  Serial.begin(115200);
  WiFi.mode(WIFI_OFF);        //Prevents reconnection issue (taking too long to connect)
  delay(1000);
  WiFi.mode(WIFI_STA);        //This line hides the viewing of ESP as wifi hotspot

  WiFi.begin(cfg_wifi_ssid, cfg_wifi_password);     //Connect to your WiFi router
  Serial.println("");
  Serial.println("1");
  Serial.print("Connecting");
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("2");


  //If connection successful show IP address in serial monitor
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(cfg_wifi_ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());  //IP address assigned to your ESP

  Serial.println("3");
  timeClient.begin();

  // default settings
  // (you can also pass in a Wire library object like &Wire2)
  bool status;
  status = bme.begin(0x76);
  if (!status) {
    Serial.println(F("Could not find a valid BME280 sensor, check wiring!"));
    while (1);
  }
    Serial.println("4");
}

void loop() {
  Serial.println("L0");
  timeClient.update();
  Serial.println("L1");

  unsigned long timestamp =  timeClient.getEpochTime();

  HTTPClient http;    //Declare object of class HTTPClient
  Serial.println("L2");

  String postData;

  float temperature = bme.readTemperature();
  float relHumidity = bme.readHumidity();
  float pressure = bme.readPressure() / 100.0F;
  float dewpoint = dewPoint(temperature, relHumidity);
  float absHumidity = absoluteHumidity(temperature, relHumidity);

  Serial.println("L3");

  //Post Data
  postData = "{";
  postData += jsonTupel("timestamp", String(timestamp)) + ",";
  postData += jsonTupel("sensor_id", String(sensorId)) + ",";
  postData += jsonTupel("sensor_location", sensorLocation) + ",";
  postData += jsonTupel("temperature", String(temperature)) + ",";
  postData += jsonTupel("relative_humidity", String(relHumidity)) + ",";
  postData += jsonTupel("pressure", String(pressure)) + ",";
  postData += jsonTupel("dewpoint", String(dewpoint)) + ",";
  postData += jsonTupel("absolute_humidity", String(absHumidity));
  postData += "}";

  Serial.println("L4");

  http.begin(http_target);              //Specify request destination
  http.addHeader("Content-Type", "application/json");    //Specify content-type header
  http.addHeader("Accept", "application/json");    //Specify content-type header

    Serial.println("L5");

  int httpCode = http.POST(postData);   //Send the request
    Serial.println("L6");

  String payload = http.getString();    //Get the response payload
  Serial.println("L7");

  Serial.println(httpCode);   //Print HTTP return code
  Serial.println("L7,5");

  Serial.println(payload);    //Print request response payload

  Serial.println("L8");

  http.end();  //Close connection

  Serial.println("L9");

  delay(interval);
   Serial.println("L10");

}

Und der Serial Output schaut dann so aus:
Code:
1
Connecting...........2

Connected to Simon
IP address: 192.168.1.155
3
4
L0
L1
L2
L3
L4
L5
L6
L7
-1
L7,5

L8
L9
L10

Dann Fängt er wieder bei L0 an. Also gibt http.POST(postData) "-1" zurück und http.getString() ist leer.

Hat jemand eine Idee wie ich das Werk wieder zum Laufen bekomme? Ich vermute, dass evtl etwas mit den Libraries nicht mehr stimmt, da ja auch die alte Version nicht mehr geht, aber da kenne ich mich leider noch viel zu wenig aus.

Vielen Dank im Voraus und lg!
 
  • Gefällt mir
Reaktionen: blöderidiot
  • Gefällt mir
Reaktionen: 0-8-15 User
-1 ist kein Http Status code sondern deutet darauf hin dass nie eine Verbindung zustande kam
In Zeile 41 sollte eine gültig Url stehen
 
  • Gefällt mir
Reaktionen: berto
cloudman schrieb:
-1 ist kein Http Status code sondern deutet darauf hin dass nie eine Verbindung zustande kam
In Zeile 41 sollte eine gültig Url stehen

Da steht eine gültige url, ich hab sie nur hier entfernt, wie auch wlan passwort etc. Ich habe schon verschiedene Varianten ausprobiert:
  • IP+Port vom lokalen Rechner: zb. http://192.168.1.106:8000/data)
  • Lokaler DNS name (da hatte ich am ehesten noch Bedenken, dass der nicht aufgelöst werden kann, obwohl es auf anderen DHCP Geräten im Wlan funktioniert): zb. http://weather.local/data
  • IP+Port vom Kafka host/jetzt Docker container
 
cloudman schrieb:
Hast du schon mal versucht ob der Post einen Pc funktioniert. Z. B mit Postman (https://www.postman.com/downloads/) oder curl
curl -d '{"key1":"value1", "key2":"value2"}' -H "Content-Type: application/json" -X POST http://192.168.1.106:8000/data

Sorry das hab ich vergessen zu erwähnen:
jap postman funktioniert mit zb
Code:
curl --location --request POST 'http://localhost:8000/data' \
--header 'Content-Type: application/json' \
--data-raw '{ "timestamp": "1588428361",
  "sensor_id": "1",
  "sensor_location": "Carport",
  "temperature": "-26.44",
  "relative_humidity": "75.63",
  "pressure": "927.57",
  "dewpoint": "22.34",
  "absolute_humidity": "18.88" }'

Funktioniert auch gegen den weather.local und xxx.106
 
wenn es früher mal funktioniert hat und jetzt nicht, dann würde ich ja mal gucken, was sich geändert hat...
wenn es nicht dein Code ist, die ESP8266HTTPClient Library hat sich auf Github vor 8 Tagen geändert. Hat deine Entwicklungsumgebung die aktualisiert?
vielleicht muss das jetzt anders initialisiert werden?
 
Mickey Mouse schrieb:
Hat deine Entwicklungsumgebung die aktualisiert?
vielleicht muss das jetzt anders initialisiert werden?

Das ist eine gute Frage, die ich leider nicht auf die schnelle Beantworten kann, da das ziemliches Neuland für mich ist. Ich verwende Arduino 1.8.9 und finde die ESP8266HTTPClient nicht in den Libraries, also weiß ich nicht welche Version verwendet wird. Auch finde ich keinen "changelog" dazu. die Examples sehen ziemlich ähnlich aus, aber 2 Sachen fallen mir auf:
1. in dem example wird der http.begin() noch ein WifiClient mitgegeben, das funktioniert bei mir aber nicht, weil er sagt, dass WifiClient nirgendwo im Scope definiert ist. Im example wird dieser client aber nicht extra importiert.
2. Es gibt noch einen error output Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str()); Den hab ich einmal eingebaut und der output ist: "[HTTP] POST... failed, error: connection refused"
 
Ok Update von meiner Seite:
nach einem Tag von Troubleshooting, habe ich herausgefunden, dass ich mehrere Probleme habe und nicht nur eines... :pcangry:
der HTTP client funktioniert (zb. post nach http://dummy.restapiexample.com/api/v1/create )
Mein lokales Setup ist von nicht lokal nicht mehr erreichbar (ich vermute einmal windoof, habe jetzt keine Lust das zu untersuchen und ein Grund mehr eher heute als morgen auf Linux zu wechseln)
Der local DNS-Lookup, der auf den anderen Geräten funktioniert, scheint am Arduino nicht zu funktionieren. Das muss ich mir jetzt genauer anschauen.
Ebenso keine Ahnung warum das alte setup nicht mehr funktioniert
 
ich habe in der Vorlesung "Betriebssystem und Rechnerverbund" gehört (bzw. sollte lernen), dass Computer deterministische Maschinen seien.
das ist für mich immer noch einer der Beweise dafür, wie weit die Universitäten und Praxis voneinander entfernt sind :rolleyes:
 
  • Gefällt mir
Reaktionen: berto
@Mickey Mouse Ja sowas gabs an der uni auch mal. Das gilt vielleicht für einfache Schaltungen und eben in der Theorie auch für programme aber sobald soviele Sachen auf Betriebsystemebene zusammen spielen wo die meisten dynamisch updaten, viel Spaß damit :D

naja jetzt muss ich schauen wie ich mein dns problem lösen kann. Interessanterweise funktioniert es vom Postman, wenn ich die IP als target nehme und den Host-header mitgebe, aber vom arduino auch wieder nicht
 
Namesauflösung könnte an mDns liegen : https://tttapa.github.io/ESP8266/Chap08 - mDNS.html

Http vielleicht an der Windows Firewall falls der Server dein Windows 10 Gerät ist

Oops hab deinen Post nicht richtig gelesen. Klingt eher so als würde der Server den host Header benötigen oder und/oder nur auf die lokale ip ein listen zu machen. Der Server läuft doch in Docker ist er überhaupt von einem anderen Rechner erreichbar?
 
  • Gefällt mir
Reaktionen: berto
cloudman schrieb:
Namesauflösung könnte an mDns liegen [...]
Http vielleicht an der Windows Firewall falls der Server dein Windows 10 Gerät ist
[...]
Der Server läuft doch in Docker ist er überhaupt von einem anderen Rechner erreichbar?
Sorry da haben wohl ein paar Infos gefehlt :rolleyes:
Danke für den Hinweis mit mDns, das muss ich mir durchlesen.

Die lokale Maschine ist ein Windows Host ja, und da vermute ich auch ein Firewall Problem, aber dem wollte ich eigentlich nicht mehr genauer nachgehen.

Das eigentliche Target ist ein Linux Server mit Docker. Als reverse proxy ist traefik im Einsatz.
Ich konnte bisher folgende Verhalten feststellen.
PC/handy -> weather-ingress.local -> OK
PC/handy -> IP Adresse + Host Header -> OK
PC/handy -> IP + random port vom Container (also direkt ohne Traefik) -> OK

Die gleichen Konstellationen vom Arduino:
ESP -> weather-ingress.local -> -1 "connection refused"
ESP -> IP Adresse + Host Header -> 404 page not found (Das dürfte von Traefik kommen, dass die routing rule nicht funktioniert, also der Header nicht passen dürfte.
ESP -> IP + random port vom Container (also direkt ohne Traefik) -> OK aber nicht praktikabel, da sich der port ja bei jedem neustart des containers ändert und ich genau deswegen einen reverse proxy habe, damit ich nicht die ports hardgecoded vergeben muss.

Das Ding macht mich noch wahnsinnig und hat jetzt schon fast 2 ganze Tage am Gewissen :freak:
 
Ich kenne mich mit Traefik leider nicht aus gibt es da keine logs die mehr Infos liefern?

Der random port könnte meiner Meinung nach vermieden werden wenn du den Container mit --publish published=8080,target=80
Oder - p 8080:80 startest

8080 wäre dann der Port den du von außen verwendest und 80 der Port im Container
 
cloudman schrieb:
[...]
Oder - p 8080:80 startest
[...]

Auf dem Server laufen aber mehrere (Web-)Services, dann hab ich den hier per 8080 freigegeben, der Port ist dann aber am host belegt und ich muss für den nächsten service dann 8081 zb verwenden usw. Dann muss ich wieder überall die Ports hardgecoded vergeben und im Browser ist das auch unschön, wenn man das Ganze auch über hostnames lösen kann.

Zu traefik: ja da bin ich auch erst beim Einlesen und bin schon auf der Suche nach den Logs.
 
Zurück
Oben