JSON Array Größe --> Was passiert, wenn unterdimensioniert?

Hi zusammen,

kurze & knappe Frage:

Ich hab hier ne Funktion, die nach Netzwerken scannt und diese in einen Array (bzw. ein JSON-Dokument) schreibt.

Theoretisch könnten nun ja eine Zilliarde Netzwerke in der Umgebung sein.
Somit weiß ich nicht, wie groß ich "networks_arr" (siehe unten) dimensionieren muss.

Daher die Frage:
Was würde denn schlimmstenfalls passieren, wenn die gefundenen Netzwerke nicht alle "reinpassen"? Läuft dann der Speicher voll und der ESP sagt goodbye?
Oder sind dann einfach nicht alle gefundenen drin?

void scan_networks() {
  StaticJsonDocument<1536> networks_arr; // Hier kann ich die Grüße nur schätzen
  int n = WiFi.scanNetworks();
  if (n == 0) {
      Serial.println("Keine Netzwerke gefunden");
  } else {
    for (int i = 0; i < n; ++i) {
        networks_arr[i]["net_ssid"] = WiFi.SSID(i);
        networks_arr[i]["net_rssi"] = WiFi.RSSI(i);
    }
    serializeJson(networks_arr, networksString);
  }
}

Danke für eure Hilfe :wink:

LG Daniel

bau Dir einen sketch und las Dir ausgeben, was pasiert:

void scan_networks()
{
  StaticJsonDocument<1536> networks_arr; // Hier kann ich die Grüße nur schätzen
  int n = 1024;
  if (n == 0)
  {
    Serial.println("Keine Netzwerke gefunden");
  }
  else
  {
    for (int i = 0; i < n; ++i)
    {
      networks_arr[i]["net_ssid"] = "meinwifitestwifissid";
      networks_arr[i]["net_rssi"] = n;
    }
    serializeJson(networks_arr, networksString);
  }
}

vermutlich wird das irgendwohin überlaufen und Speicher überschreiben.
Im einfachsten Fall wird das Json keine EndeKennung jaben.

Kannst Du nicht zwei mal scannen? Das erste mal zum zählen, anschließend den Speicher anlegen und beim zweiten Scannen mit Daten füllen?

Hilft nicht, da sich zwischendurch was geändert haben könnte!
Denn die Welt ist nicht so deterministisch, wie man sich das wünscht.

Wenn von WLAN die Rede ist, dann höre ich automatisch ESP!
Was hält dich davon ab, vector oder list zu benutzen?

Sagt mir leider im ersten Moment garnichts.
Muss ich mal googeln (oder du bist so lieb und schreibst kurz was dazu :wink:

Gebe ich dir recht. Es ist aber recht unwahrscheinlich, dass an einem Standort ganz plötzlich 10 Wlans dazukommen, von daher könnte man ja den Speicher etwas größer machen. Wenn man beim ESP tatsächlich vector oder list einsetzen kann (was ich nicht wusste), dann ist das natürlich besser.

Ja!
Tipp: "C++ vector"

Aber eines noch vorab:
Ich will das Ergebnis des Netzwerk-Scans an einen Webserver senden.
Daher habe ich JSON gewählt.

Geht das mit C++ Vector auch?
Falls ja, les ich mich da natürlich ein.
Evtl. hast du ja einen Link zu einem Beispiel-Sketch.

LG
Daniel

Edit: Was ich natürlich auch machen könnte, wäre das ganze hier zu begrenzen (z.B. auf 50)

und mein JSON Document auf maximal 50 zu dimensionieren:

Bedenke, das Du die Länge der Einträge nicht kennst.
Der ESP hat doch ein Dateisystem? Da einfach was reinschreiben und wenn fertig weiter verwenden?

1 Like

Hi zusammen,

ich hab wegen der Sache mal direkt den Entwickler der Arduino JSON library gefragt.
Hier seine Antwort:

Hi Daniel,

When the JsonDocument overflows:

Somit kann man zumindest sagen, dass der ESP nicht abgeschossen wird, wenn das JSON Document überquillt.

Somit wäre ein Weg, einfach eine maximale Anzahl an WiFi-Hotspots "anzunehmen" und das JSON Document entsprechend zu dimensionieren. Sollte das dann nicht ausreichen, wird im schlimmsten Fall nichts angezeigt. Mir war aber extrem wichtig, dass der ESP online bleibt und nicht Tschüss sagt (weil der Speicher voll läuft).

und warum willst du so früh schon ein JSON generieren?
Behalte deine Daten im Array, und mache das JSON erst dann wenn du es übertragen willst.
Wenn es eh nur zwet Wertpaare SSID und RSSI sind - braucht es dazu auch keine Library.
Beim Array befüllen achte darauf dass du deine Index-Größe einhältst.
Brauchst du mehr als Indexe vorhanden sind, überträgst du die bisherigen Daten an den Server mit einem Flag ... "da kommt noch was".
und beginne von vorne.

Dann könnte ich aber auch folgendes machen (Angenommen es gäbe 32 Einträge):

  1. (Ajax-)Anfrage von Server starten für (z.B.) max. 16 Einträge (mit Abbruch falls Rückantwort 0)
  2. 16 Einträge als JSON verpacken und senden.
  3. Erneute (Ajax-)Anfrage von Server starten für (z.B.) max. 16 Einträge (mit Abbruch falls Rückantwort 0)
  4. 16 Einträge als JSON verpacken und senden.
  5. Erneute (Ajax-)Anfrage von Server starten für (z.B.) max. 16 Einträge (mit Abbruch falls Rückantwort 0)
  6. 0 Senden
  7. Abbruch der Ajax-Anfrage und Anzeige der gesammelten Einträge

Ich habe noch nicht ganz begriffen, was mir das Sammeln im Array bringt, wenn ich es am Ende ja dann doch stücklesweise als JSON zum Server schaufeln muss. Dann kann ich doch das JSON Document gleich für max. 16 Einträge dimensionieren (oder bissl mehr, dass Puffer da ist, falls die Einträge recht lang sind) und direkt senden.

Soll jetzt nicht heißen, dass deine Antwort nicht stimmen würde bzw. die Lösung besser ist sondern nur, dass ichs nioch nicht ganz begriffen hab :slight_smile:

würdest du einen compilierbaren Sketch zeigen mit Speicherung im JSON, dann könnte man das vergleichen wie das in einem einfachen Struct array aussehen könnte.
Mit welchen maximal Größen für die SSID und RSSI rechnest du?

Den Vorteil beim Array sehe ich darin, dass ich dabei exakt weis wie viele Einträge reinpassen und somit exakt bei Erreichen der Arraygröße Maßnahmen ergreifen kann (eben z.B. zu senden).

Mit der JSON lib könntest/solltest halt Absicherungen mit isOverflow oder noMemory vorsehen.

1 Like

Schwer zu sagen. Ich würde mal maximal 20 tippen.

Ich mach heute Abend mal was, wie ich mir das OHNE Array vorstellen würde (also mit direktem Senden des JSON obwohl das

natürlich auch stimmt...

Wenn schon, dann doch gleich für nur 1 Element, oder ?

Drum auch der vector Vorschlag!
Da muss man nicht auf einen Index achten.
Und nicht wirklich auf die Größe.

Und dann folgt:

Nur dann eben vector und nicht Array.

Das hat (hoffentlich irre ich mich nicht) den Vorteil/Nachteil, dass der Bereich auf dem Stack angelegt wird. Was dann z.B. unter FreeRTOS schon zu dolle sein kann.

Meiner bescheidenen Meinung/Erfahrung nach, muss man sich bei den ESP deutlicher weniger Sorgen bei der dynamischen Speicherverwaltung machen, als auf den kleinen Arduinos.

Wenn man das nur in einem Schritt erledigen möchte:
StaticJsonDocument würde ich dort nur verwenden, wenn unumgänglich.

Die 2 Schritt Lösung hat den Vorteil, dass man zwischendurch noch filtern und sortieren kann.

Wieso? Dann muss ich bei angenommenen 32 Einträgen ja 32 mal JSON zum Server schaufeln und 32 mal neu anfordern. Die 16 war ja nur mal ein Beispiel. Evtl. kann man auch 32 auf einmal schaufeln.

Aber am Ende, wenn ich die Daten dann zum Server schicken will, muss ich auch aus dem Vector wieder einen JSON basteln und stücklesweise zum Server schicken, oder? Ich muss aber zu meiner Schande gestehen, dass ich mich noch nicht mit dem Thema Vector beschäftigt habe. Muss ich nachholen, sorry.

DynamicJsonDocument wäre wohl die bessere Variante

Wenn du sowieso "stücklesweis" im Server einbaust, kannst du es ja auch konsequent verwenden.
Aber da die eigentlichen Daten ja schon bei einem einzigen Aufruf von
WiFi.scanNetworks();
geholt werden, solltest du auch ein dazu passendes DynamicJsonDocument verwenden.

Nur für euch auch noch zur Info:
Ich hatte mich auch mal mit der Sache direkt an den Entwickler der ArduinoJSON-Lib gewendet und ihn gefragt, wie sich das verhält, wenn das JSONDocument "überlaufen" würde (weil zu klein dimensioniert). Außerdem hab ich das Verhalten auch mal noch selber getestet:

#include <ArduinoJson.h>

String networksString="";

void setup() {
  Serial.begin(115200);
  delay(2000);
  // put your setup code here, to run once:
  scan_networks();
  Serial.println(networksString);
}

void loop() {
  // put your main code here, to run repeatedly:

}


void scan_networks() {
  Serial.println("Netzwerk-Scan wird gestartet");
  int n=1000;
  
  StaticJsonDocument<1536> networks_arr;
  //DynamicJsonDocument networks_arr(4096);
  
    for (int i = 0; i < n; ++i) {
        networks_arr[i]["net_ssid"] = "Meine SSID 12345678910111213";
        networks_arr[i]["net_rssi"] = "Netzwerkstärke 123456789101112";
        networks_arr[i]["nr"] = i;
    }
    serializeJson(networks_arr, networksString);
}

Wenn es zum Überlauf kommt, bleiben alle Inhalte, die reingepasst haben auch drin, d.h. man hat in jedem Fall ein gültiges JSON Document. Er war sogar so nett und hat einen neuen Absatz dafür in seine Dokumentation mit aufgenommen:

Hier ist der Absatz:

LG Daniel

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.