- 12V Akku mit 280 Ah bauen         
Ergebnis 1 bis 9 von 9

Thema: Probleme bei der Kombination Firebase/HTTPS client

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    05.11.2020
    Beiträge
    7

    Probleme bei der Kombination Firebase/HTTPS client

    Anzeige

    Praxistest und DIY Projekte
    Ich habe einen Arduino-Sketch aufgesetzt, der über WiFi auf Firebase zugreifen soll und zusätzlich HTTPS-Requests starten soll. Ich nutze ein ESP8266-12F Modul (AZ Delivery D1 mini NodeMCU)

    ESP8266 Board Version 2.7.4
    FirebaseArduino Version 0.3 (von 2018, gibt es da etwas Neueres, das ich nicht finden konnte?) zusammen mit ArduinoJson Version 5.13.1
    ODER FirebaseESP8266 Version 3.0.2


    Für die Firebase-Zugriffe habe ich sowohl FirebaseArduino als auch FirebaseESP8266 ausprobiert, beide haben aber mit der Situation ihre Probleme:

    In setup() öffne ich die WiFi-Verbindung, und in loop() greife ich auf Firebase zu, um eine Liste von 10-Zeichen-Strings zu holen. Von diesen gibt es ca. 160 in der Datenbank, die genaue Anzahl kenne ich aber vorher nicht. Bis zu diesem Punkt funktionert auch alles prima. Ich kann mir sogar in einer Schleife die gesammelten String-Keys anschauen.

    Aber sobald ich dann eine HTTPS-Client-Verbindung aufbaue

    Code:
    WiFiClientSecure client;
    client.setInsecure();    // to avoid fingerprint stuff
    if(!client.connect()) {
      Serial.println("connection failed");
    } else {
      ... // hier steht dann client.print("GET ......")
    }
    kommt es entweder zu "connection failed" oder aber zu Soft WDT Resets.

    Wenn ich eine HTTPS-Client-Verbindung zu den gleichen URLs ohne vorherigen Firebase-Zugriff aufbaue, dann funktionieren diese prima!

    Was möchte ich eigentlich machen? Für jeden der 10-Zeichen-Strings aus Firebase möchte ich eine HTTPS-Verbindung zu einem Server aufbauen, wobei die URL diesen String enthält. Von diesem Server hole ich mir Infos (einen weiteren String), den ich dann in Firebase bei dem String-Key speichern möchte.

    Außerdem habe ich noch ein SSD1306 OLED an meinem ESP8266 angeschlossen.

    Codeaufbau:

    Code:
    #include <Arduino.h>
    
    #include <ESP8266WiFi.h>
    #include <ESP8266WiFiMulti.h>
    
    #include <WiFiClientSecureBearSSL.h>
    
    
    #include <WiFiClient.h>
    #include <Wire.h>
    #include <SSD1306.h>
    
    #include <FirebaseESP8266.h>
    
    #define FIREBASE_HOST "xxxxxxxxxxxxxxxxxxxxxxx"
    #define FIREBASE_AUTH "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
    
    #define OLED_ADDRESS                0x3C //you may need to change this, this is the OLED I2C address.  
    
    SSD1306 display(OLED_ADDRESS, D2, D1);
    
    ESP8266WiFiMulti WiFiMulti;
    
    FirebaseData firebaseData;
    ...
    
    void setup() {
      ...
      WiFi.mode(WIFI_STA);
      WiFiMulti.addAP("aaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbb");
    
      while(WiFiMulti.run() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      ...
    }
    
    void loop() {
      WiFiClientSecure client;
      client.setInsecure();
    
      Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
      Firebase.reconnectWiFi(true);
      firebaseData.setBSSLBufferSize(3072, 512);
      firebaseData.setResponseSize(3072);
      
      if(Firebase.get(firebaseData, "/my/path")){
        Serial.print("Read object of type ");
        Serial.println(firebaseData.dataType());
    
        FirebaseJson& json = firebaseData.jsonObject();
        size_t len = json.iteratorBegin();
        String key, value = "";
        int type = 0;
        String buffer[len];
        for (size_t i = 0; i < len; i++)
        {
            json.iteratorGet(i, type, key, value);
            buffer[i] = key;
        }
        json.iteratorEnd();
        delay(500);
    
        // check single IDs
        for(size_t i = 0; i < len; i++) {
    
          String url = "/" + buffer[i];
    
          if (!client.connect(host, httpsPort)) {  // the problems happen here
            Serial.println("connection failed");
          } else {
            ...
          }
          client.stop();
        }
        
      }
    }
    Gibt es in dem Code ein grundlegendes Problem, das zu dieser Situation führt? Ich weiß zum Beispiel, dass ich Strings vermeiden sollte ... habe aber zu wenig Erfahrung mit hardwarenaher Programmierung eines speicherlimitierten Systems in C++

    Vielleicht habt ihr Hinweise, wie ich beispielsweise die Liste der Keys nicht als String[] sondern speicherschonender ablegen und nutzen kann?

  2. #2
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    18.03.2018
    Beiträge
    2.650
    Hallo,

    ich gehe mal auf den Teil ein: "kommt es entweder zu "connection failed" oder ..."

    client.connect() sollte eine Rückmeldung geben, warum die Verbindung nicht zustande kam.
    Leider erfährst Du dies mit: if(!client.connect()) und dem anschließenden Serial.println("connection failed"); nicht.

    Um der Sache auf die Spur zu kommen, würde ich das mal so machen (Beispiel):
    Code:
    //https://www.arduino.cc/en/Reference/ClientConnect
    int s=client.connect();
    if(!s) {
      Serial.print("connection failed: ");
      Serial.println(s,DEC); 
    } else {
      ... // hier steht dann client.print("GET ......")
    }
    MfG

    PS: wenn Du also vorher einen Firebase-Zugriff hattest, sollte dann der Grund für die nicht erfolgte Verbindung dort stehen.
    Allerdings: wenn Du einen
    Firebase-Zugriff vorher hattest, was ist dann mit der Verbindung? Die muss zuvor doch hergestellt worden sein?
    Vielleicht steht die Verbindung schon, während Du versuchst eine Neue aufzubauen.
    Vielleicht musst Du nach einem
    Firebase-Zugriff erst die Verbindung schließen, bevor Du eine Neue mit client.connect(); aufbaust?
    Geändert von Moppi (05.11.2020 um 09:38 Uhr)

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    05.11.2020
    Beiträge
    7
    Hallo,

    danke für die schnelle Rückmeldung.

    Ich baue für die Firebase-Zugriffe keine Verbindung auf, das machen die Libraries wohl intern. Leider haben beide verwendeten Firebase-Libraries kein Firebase.close(), Firebase.end(), Firebase.stop() oder ähnliches. Daher habe ich keine Ahnung, ob und wie die Verbindung aufgebaut bzw. wieder beendet wird.

    Aber ich hatte wohl einen Fehler in meinem Code, der ab und zu falsche URLs produziert hat. Bei diesen kommt dann (natürlich) "connection failed". Bei korrekten URLs kommt es nun ausschließlich zu Soft WDT Resets.

    Die eigentliche Frage lautet also: Wie kann ich korrekt den WDT Reset verhindern (Stichwort: "Watchdog füttern"). delay() und/oder yield() haben nichts gebracht. ESP.wdtDisable() auch nicht, da dann der Hardware WDT zuschlägt.

    Dieser Code schaltet (angeblich) den HW WDT aus ...
    Code:
    void hw_wdt_disable(){
      *((volatile uint32_t*) 0x60000900) &= ~(1); // Hardware WDT OFF
    }
    das führt aber zu einem panic core dump (__yield), was mich auch nicht wundert.

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    18.03.2018
    Beiträge
    2.650
    Hier:

    Code:
        // check single IDs
        for(size_t i = 0; i < len; i++) {
    
          String url = "/" + buffer[i];
    Pack mal den String außerhalb Deiner Schleife. Als Globale Variable.

    Außerdem würde ich fragen;: muss das "String" sein?
    Vielleicht kannst Du auch ein Char-Array verwenden, dass im Code eine feste Länge hat. Das deklarierst Du dann global. Nicht innerhalb einer Schleife. I.R. funktionieren auch diese Char-Arrays, statt "String"s.

    Vielleicht kommst Du mit so etwas Ahnlichem, wie diesem, weiter:

    Code:
    char url[maxBufferLength];
    
    ...
    
    url[0] = "/"; 
    for(size_t i = 0; i < len; i++) {
    
       url[i+1] = buffer[i];
    
    }


    MfG
    Geändert von Moppi (05.11.2020 um 11:33 Uhr)

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    05.11.2020
    Beiträge
    7
    Ich bin noch nicht ganz sicher, wie ich das ohne String umsetzen soll.

    Die Firebase-Libraries liefern String keys zurück. Die lege ich in einem Array ab, das als Länge die Anzahl der Datenbank-Keys bekommt

    Code:
    size_t len = json.iteratorBegin();
    ...
    String buffer[len];
    In diesem Array lege ich dann in einer Schleife jeden Key ab. Ich wüsste also nicht einmal, wie ich das sinnvoll auf char[] oder meinetwegen char* umstellen könnte.

    Den String url könnte ich sicherlich umstellen ... doch bislang kommt mein Code nicht einmal bis zu der Stelle, wo diese url überhaupt verwendet werden soll.

  6. #6
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    18.03.2018
    Beiträge
    2.650
    Wie lang kann so ein String denn sein? Mehr als 2048 Byte bestimmt nicht. Weil mit der GET-Methode lassen sich normalerweise so lange Pfade nicht übertragen.
    Also würde ich einen Zeichen-Puffer mit 2048 Byte anlegen, in dem ich meinen Pfad zusammen bastele.

    In etwa so:

    Code:
    #define maxBufferLength 2048
    
    char meineUrl[maxBufferLength];
    
    // check single IDs
        int y=0;
    
        for(size_t i = 0; i < len && y<maxBufferLength; i++) {
          meineUrl[y] = "/"; y++;
          for(int x=0;x < buffer[i].length() && y<maxBufferLength; x++){
             meineUrl[y]=buffer[i].substring(x,x+1);
             y++;
          }
    
    
            ...
            ....
            ...
    Geändert von Moppi (05.11.2020 um 14:23 Uhr)

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    05.11.2020
    Beiträge
    7
    Der einzelne URL-Pfad ist exakt 11 Zeichen lang

    Es gibt aber ca. 160 davon ... in einer Schleife durchlaufe ich diese, erzeuge die URL und rufe sie auf. Ich habe also ein String buffer[160], in dem meine Keys stehen, und die URL ist dann "/" + buffer[i]

    - - - Aktualisiert - - -

    Noch ein interessanter Aspekt

    Wenn ich aus dem dynamisch erstellten String buffer[len] ein Array fester Länge mache und es statisch vorbelege (mit den gleichen Keys, die sonst aus der Datenbank kämen), dann funktioniert der anschließende HTTPS-Request jeweils einwandfrei, inklusive schreibendem Zugriff auf Firebase. Der ursprüngliche Lesezugriff bzw. das dynamische Befüllen des buffer-Arrays führt also irgendwie zu dem WDT-Problem ...

  8. #8
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    18.03.2018
    Beiträge
    2.650
    Zitat Zitat von Moppi Beitrag anzeigen
    Pack mal den String außerhalb Deiner Schleife. Als Globale Variable.
    siehe hier.

    Zur weitergehenden Erklärung:

    Du erzeugst in einer Schleife einen String unbekannter Länge (der vermutlich bis ca. 1600 Bytes anwächst).
    Wenn Du Pech hast, passt der String während der Schleife nicht in den Speicher, der ihm max. zur VErfügung steht, Stichworte: Stack und Heap:
    https://de.wikibooks.org/wiki/C%2B%2...Stack_und_Heap

    Wenn der Compiler weniger kByte für diesen Speicher vorsieht, als zur Programmausführung benötigt werden .... dann ... ?

    Oder Du löst das Problem über Char-Arrays.

    MfG

    PS: hast Du Dir mal die Fehlermeldung angeschaut, die bei WDT-Reset auf dem Schirm erscheint?
    Geändert von Moppi (05.11.2020 um 15:49 Uhr)

  9. #9
    Neuer Benutzer Öfters hier
    Registriert seit
    05.11.2020
    Beiträge
    7
    Ich hab's hinbekommen

    Das Kernthema: Akribische Trennung von Verbindungen

    - Das buffer-Array wird in fester Länge vorgegeben (aber nicht statisch belegt)
    - Firebase holt sich die Daten in setup(). Das Firebase-Objekt wird am Ende von Setup disposed
    - Die Keys aus den Daten werden in den buffer geschrieben (globales Array)
    - In loop wird jeweils nur EIN Key aus dem Buffer ausgelesen. Ein globaler Counter zählt mit, wo man sich im buffer befindet
    - Das Schreiben nach Firebase findet erst statt, wenn der HTTPS-Request beendet und der Client gestoppt wurde. Dafür wird jedesmal ein neues Firebase-Objekt erzeugt
    - Am Ende ein delay(500) vor dem nächsten Loop-Aufruf
    - Wenn der buffer abgearbeitet ist, dann deepSleep für 60 Minuten

    FERTIG

Ähnliche Themen

  1. Roboter mit Thin Client
    Von Johnny5 im Forum PC-, Pocket PC, Tablet PC, Smartphone oder Notebook
    Antworten: 2
    Letzter Beitrag: 20.11.2014, 16:58
  2. ASURO-Probleme bei Kombination von Tastern
    Von Barbara1 im Forum Asuro
    Antworten: 51
    Letzter Beitrag: 30.03.2011, 15:42
  3. OPC Server / Client
    Von fali im Forum C - Programmierung (GCC u.a.)
    Antworten: 0
    Letzter Beitrag: 22.10.2009, 13:25
  4. TCP/IP Client
    Von feitzi im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 9
    Letzter Beitrag: 23.03.2008, 11:45
  5. Thin Client Igel-208
    Von Eris im Forum PC-, Pocket PC, Tablet PC, Smartphone oder Notebook
    Antworten: 11
    Letzter Beitrag: 30.08.2006, 23:18

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test