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);
}
}
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.
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.
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):
(Ajax-)Anfrage von Server starten für (z.B.) max. 16 Einträge (mit Abbruch falls Rückantwort 0)
16 Einträge als JSON verpacken und senden.
Erneute (Ajax-)Anfrage von Server starten für (z.B.) max. 16 Einträge (mit Abbruch falls Rückantwort 0)
16 Einträge als JSON verpacken und senden.
Erneute (Ajax-)Anfrage von Server starten für (z.B.) max. 16 Einträge (mit Abbruch falls Rückantwort 0)
0 Senden
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
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.
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: