Forum: Mikrocontroller und Digitale Elektronik ESP8266 - Datenübermittlung aus FRAM und als Download über Webserver zur verfügung stellen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Johannes R. (johannes_r981)


Lesenswert?

Grüß euch!

Ich möchte gerne mit einen ESP8266-01S Sensor Daten aus einen FRAM Chip 
auslesen und über Webserver zum Download zur Verfügung stellen. Ich habe 
mich explizit für eine FRAM Variante entschieden und auf einen 
Schreiben/Lesen über SPIFFS verzichtet aufgrund der Häufigkeit der 
Schreibzyklen.

Daher war mein Zugang der, dass ich die Daten zur Laufzeit hin über aus 
dem FRAM Auslese und über die ESPAsyncWebServer events.send an den 
Webserver Client übetrage und anschließend die Daten mit JavaScript 
auslese und zu einer .csv File zusammenbaue.

Das ganze funktioniert nur leider nicht mit den Übertragen der Daten 
zwischen den Webserver und den ESP8266. Ca. 10 Messwerte werden 
erfolgreich übertragen - anschließend kommt immer die Meldung "Event 
Disconnected".

Die Funktion zum Übertragen der daten an den Client ist:
1
 
2
 void SensorJSONReadup(unsigned long intervall, bool _DownloadRequest){
3
  unsigned long currentMillis = millis();
4
  if((currentMillis - lastTime >= intervall) && !_DownloadRequest){
5
    events.send("ping",NULL,currentMillis);
6
    events.send(getSensorReadings().c_str(),"new_readings", currentMillis);
7
    lastTime = currentMillis;
8
  }
9
  //Read Sensor Data for Download by Webserver!
10
  if(_DownloadRequest){
11
    // Json Variable to hold sensor readings 4 Download
12
    JSONVar downloadData;
13
    //Serial.println(_DownloadRequest);
14
    //Serial.println("Enter READING Sensor Data from FRAM");
15
        if (!DataRecived) { //Confirm 
16
          PowerValues get_data = ConvertSensorDataFromFRam(_i_down);
17
          PowerValues_print(get_data);
18
        
19
          downloadData["cur"] = String(get_data.current);
20
          downloadData["pow"] = String(get_data.power);
21
          downloadData["loadvol"] = String(get_data.loadvoltage);
22
          downloadData["time"] = String(get_data.timestamp);
23
        
24
          String jsonStringforDownload = JSON.stringify(downloadData);
25
          events.send(jsonStringforDownload.c_str(),"download_Data_csv", millis());
26
          
27
          DataRecived = 1;
28
          
29
          _i_down=_i_down+16;         
30
        }
31
        if(_i_down >= j){
32
          Serial.println("Download Data DONE");
33
          DownloadTriggerd = 0;
34
          _i_down = 0;
35
        };
36
      };
37
    };

Anschließend warte ich bis über die Websocket bestätigt wird, dass Daten 
empfangen wurden:
1
  //Confirm Data Recived
2
  server.on("/download_Data_done", HTTP_GET, [](AsyncWebServerRequest *request){
3
    if(DataRecived){
4
      DataRecived = 0;
5
    }    
6
    request->send(200, "text/plain", "OK!");
7
  });

Im JavaScript code habe ich einen EventListener wie folgt angelegt der 
mir dann die Daten empfängt und in der Konsole plottet bzw. bestätigt:
1
source.addEventListener('download_Data_csv', function(e) {
2
  var xhr = new XMLHttpRequest();
3
  console.log("download_Data_csv, e.data");
4
  var myObj = JSON.parse(e.data);
5
  console.log(myObj);
6
  xhr.open("GET", "/download_Data_done", true);
7
  xhr.send();
8
}, false);

Ich glaube ja das mein Hauptproblem noch darin liegt wie ich den 
Datenempfang an den ESP8266 erfolgreich/nicht erfolgreich zurück 
"checke" um den Event erfolgreich/nicht erfolgreich zu schließen bevor 
der nächste Datensatz übermittelt wird?!?

Vielleicht hat ja jemand schon mal so was ähnliches realisiert...

mfg

von Stefan F. (Gast)


Lesenswert?

Johannes R. schrieb:
> Daher war mein Zugang der, dass ich die Daten zur Laufzeit hin über aus
> dem FRAM Auslese und über die ESPAsyncWebServer events.send an den
> Webserver Client übetrage und anschließend die Daten mit JavaScript
> auslese und zu einer .csv File zusammenbaue.

Bist du sicher, dass das Konzept so sinnvoll ist? Events und der ganze 
asynchrone Kram sind hier meiner Meinung nach gar nicht nötig. Hat dein 
ESP für diese komplexe Sache genug RAM (ich frage, weil genau das hier 
in den letzten Monaten mehrfach der Knackpunkt war)? Funktioniert dein 
Konzept mit mehreren zeitgleichen Anfragen?

Viel einfacher wäre doch ein ganz normales REST (HTTP GET Request). Der 
Browser fordert die Datei an, und bekommt sie dann in einem Rutsch als 
Response geliefert. Das ist so simpel, dafür muss man nicht mal einen 
vollwertigen HTTP Server verwenden.

von Stefan F. (Gast)


Lesenswert?

Hier mal ein einfaches Beispiel wie man so einen REST Request in 
Javascript implementiert:
1
/* Load navigation HTML fragment into the destination div
2
   id = id of the destination div
3
   url = url of the navigation HTML fragment
4
*/
5
function navi_load(id,url) {
6
  try {
7
    var request = new XMLHttpRequest();
8
    request.open("GET", url, true);
9
    request.onreadystatechange = function () {
10
      if (request.readyState == 4) {
11
12
         // response received
13
         document.getElementById(id).innerHTML = request.responseText;
14
15
      }
16
    };
17
    request.send(null);
18
  }
19
  catch (e) {
20
    console.error(e, e.stack);
21
  }
22
}

In diesem Fall wird ein Stück HTML Text vom Server geladen und in einen 
<div id="..."></div> eingefügt. Auf die gleiche Weise kannst du auch 
JSON Dokumente laden. Die Verarbeitung des Inhaltes überlasse ich dir.

Um dein Problem weiter zu untersuchen empfehle die Benutzung von 
Wireshark. Damit kannst du die HTTP Kommunikation aufzeichnen und 
(hoffentlich) erkennen, an welchen Schritt es scheitert.

von Johannes R. (johannes_r981)


Lesenswert?

Stefan F. schrieb:
> Events und der ganze
> asynchrone Kram sind hier meiner Meinung nach gar nicht nötig. Hat dein
> ESP für diese komplexe Sache genug RAM (ich frage, weil genau das hier
> in den letzten Monaten mehrfach der Knackpunkt war)? Funktioniert dein
> Konzept mit mehreren zeitgleichen Anfragen?

Danke dir Stefan für die rasche Rückmeldung!

Die Asynchronen Events sind Basis des gesamten Projektes, daher war mein 
Ansatz dieser, mit den events.... Um den Thema mit den Ram gleich vorweg 
entgegen zu wirken und nicht die ganze wurscht auf einmal zu übermitteln 
(im Worst-Case sind es nämlich der gesamte RAM Inhalt mit den 32KB an 
Daten....) habe ich eben diesen Ansatz entsprechend gewählt das ganze zu 
stückeln und mal Zeile für Zeile zu übertragen. Wenn dies funktioniert 
kann ich das ganze ja erweitern und z.B. immer 100 oder 1000 Datensätze 
auf einmal übermitteln...

Wenn ich auf dein Beispiel eingehe, sehe ich halt das Problem dass mir 
der RAM wsl ausgehen wird oder wie siehst du das wenn ich hier ein Array 
mit 32KB statisch definiere und dann in einem Übertrage?
Zudem der Halbe RAM bereits für OTA verwendet wird....
A Pro Pos OTA - spielt mir das gegen die Karten?

Wireshark installiere ich mal - eventuell kann ich hier Rückschluss 
ziehen woran die Übertragung scheitert.

mfg

von Stefan F. (Gast)


Lesenswert?

Johannes R. schrieb:
> Wenn ich auf dein Beispiel eingehe, sehe ich halt das Problem dass mir
> der RAM wsl ausgehen wird oder wie siehst du das wenn ich hier ein Array
> mit 32KB statisch definiere und dann in einem Übertrage?

Ich würde die Datei zeilenweise (oder in Blöcken von 1 kB) lesen und 
senden. Niemand sagt, dass die gesamte HTTP Response an einem Stück im 
RAM liegen muss.

> A Pro Pos OTA - spielt mir das gegen die Karten?

Damit habe ich keine Erfahrung. Bei meinen Projekten war das immer 
entweder unnötig oder zu unsicher. Ich bin auch nicht von der 
Mögloichkeit begeistert, das BIOS meines PC "einfach so" updaten zu 
können, ohne dafür wenigstens einen Jumper umstecken zu müssen.

> Wireshark installiere ich mal - eventuell kann ich hier Rückschluss
> ziehen woran die Übertragung scheitert.

Mache das. Ich habe einen Webserver für PC in C++ und einen für AVR 
Mikrocontroller in C implementiert. Bei beiden war mit Wireshark sehr 
nützlich. Viele Fehler markiert es sogar farblich.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.