ESP8266 - JSON File aus dem Web in SPIFFS downloaden [MIT LÖSUNG]

LÖSUNG in #6

Hallo Zusammen,
ich habe mir eine ein paar Zeilen Quellcode zusammengeschrieben um persönliche Einstellungen auf einem ESP8266 abzuspeichern. Zum Speichern verwende ich das SPIFFS Dateisystem und als Format habe ich mich für JSON entschieden. Mein Quellcode sieht wie folgt aus:

#include <ArduinoJson.h>
#include "FS.h"

bool loadConfig() {
  File configFile = SPIFFS.open("/config.json", "r");
  if (!configFile) {
    Serial.println("Failed to open config file");
    return false;
  }
  
  size_t size = configFile.size();
  if (size > 1024) {
    Serial.println("Config file size is too large");
    return false;
  }

  // Allocate a buffer to store contents of the file.
  std::unique_ptr<char[]> buf(new char[size]);

  configFile.readBytes(buf.get(), size);

  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& json = jsonBuffer.parseObject(buf.get());

  if (!json.success()) {
    Serial.println("Failed to parse config file");
    return false;
  }

  const char* serverName = json["SSID"];
  const char* accessToken = json["Passwort"];

  Serial.print("SSID: ");
  Serial.println(serverName);
  Serial.print("PW: ");
  Serial.println(accessToken);
  return true;
}

bool saveConfig() {
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& json = jsonBuffer.createObject();
  json["SSID"] = "DEMO_SSID";
  json["Passwort"] = "123456789";

  File configFile = SPIFFS.open("/config.json", "w");
  if (!configFile) {
    Serial.println("Failed to open config file for writing");
    return false;
  }

  json.printTo(configFile);
  return true;
}

void setup() {
  delay(10);
  Serial.begin(115200);
  delay(1000);
  Serial.println("Dateisystem einbinden...");

  if (!SPIFFS.begin()) {
    Serial.println("Failed to mount file system");
    return;
  }

  if (!saveConfig()) {
    Serial.println("Failed to save config");
  } else {
    Serial.println("Config saved");
  }

  if (!loadConfig()) {
    Serial.println("Failed to load config");
  } else {
    Serial.println("Config loaded");
  }

  Serial.println("Ausgabe JSON File...............");
  Serial.println("");
  
  File f = SPIFFS.open("/config.json", "r");
  Serial.println(f.readStringUntil('\n'));
}

void loop() {
}

Dieser Test-Sketch tut genau was er soll und ich bin zufrieden. Eine zweite Routine stellt die Verbindung zum Internet her:

#include <ESP8266WiFi.h>

const char* ssid = "Airport Extreme";
const char* password = "********";

void CONNECT_WLAN() {

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WLAN: Verbindungsversuch fehlgeschlagen! ESP wird neu gestartet...");
    delay(5000);
    ESP.restart();
  }
  
}

void setup() {
  delay(10);
  Serial.begin(115200);
  Serial.println("ESP wurde gestartet. Verbinde mit WLAN...");
  
  CONNECT_WLAN();

  Serial.println("SETUP ABGESCHLOSSEN...");
}


void loop() {
}

Frage ist nun:
Wie kann ich eine Datei “config.json” von meinem FTP Server “www.server.de/folder/config.json” herunterladen und direkt im SPIFFS wie im ersten Sketch abspeichern?

Ich habs nicht durchstudiert aber evtl. wäre das was für Dich?

Gruß Tommy

magie004:
Wie kann ich eine Datei “config.json” von meinem FTP Server “www.server.de/folder/config.json” herunterladen …

Meinst Du wirklich einen FTP Server, oder geht es um einen Zugriff per HTTP? Das sind zwei komplett verschiedene Protokolle. HTTP ist dabei das deutlich einfachere Protokoll.

HTTP ist dabei das deutlich einfachere Protokoll.

? ? ? ?

mkl0815:
Meinst Du wirklich einen FTP Server, oder geht es um einen Zugriff per HTTP? Das sind zwei komplett verschiedene Protokolle. HTTP ist dabei das deutlich einfachere Protokoll.

Verstehe ich zwar nicht ganz, aber wenn du eine "simple" Lösung kennst, immer gern.
Der FTP Server ist eigentlich nur der Host meiner privaten Daten. Läge meine Datei auf dem Google Server, würde sich in der Methode nur der Link ändern. Im Prinzip müsste ich nur per HTTP Get die Datei abgreifen und am besten direkt ans Filesystem übergeben.

Optimaler Weise gäbe es eine fertige Funktion (mit oder ohne Library), welche wie folgt arbeitet:

downloadFile('http://meineurl.de/config.json');

Serial.println("Datei wurde erfolgreich heruntergeladen");

void downloadFile(String URL) {
  
  String ausgabe;
  .....
  ausgabe = http_get_content(URL);

  File f = SPIFFS.open("/config.json", "w");
  if (!f) {Serial.println("Kritischer Fehler! config.json konnten nicht gelesen werden");}
  f.print(ausgabe);
  f.close();
  
}

Ich glaube ich habe was simples gefunden :slight_smile: Muss ich dann zu Hause nur noch anpassen und sollte klappen. Wenn es klappt, stelle ich dann später noch die Lösung online.

Danke für die Hilfe!

Link zur Lösung

LÖSUNG

So, für alle die ähnliches realisieren möchten hier mal mein Quellcode. Gerne Verbesserungsvorschläge hinterlassen :slight_smile:

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include "FS.h"

const char* ssid = "Airport Extreme";
const char* password = "**********";

//================================================================================================
//=========================================== SETUP ==============================================
//================================================================================================

void setup () {
  delay(10);
  Serial.begin(115200);

  SPIFFS.begin();
  WiFi.begin(ssid, password);
  
  Serial.println("Verbinde mit: " + String(ssid));
 
  while (WiFi.status() != WL_CONNECTED) {
 
    delay(1000);
    Serial.print(".");
 
  }

  Serial.println("");
 
}

//================================================================================================
//========================================== HTTP GET ============================================
//================================================================================================

void handleHTTP_Error(int httpCode) {

  switch (httpCode) {
    case -1:
      Serial.println("HTTPC_ERROR_CONNECTION_REFUSED");
      break;
    case -2:
      Serial.println("HTTPC_ERROR_SEND_HEADER_FAILED");
      break;
    case -3:
      Serial.println("HTTPC_ERROR_SEND_PAYLOAD_FAILED");
      break;
    case -4:
      Serial.println("HTTPC_ERROR_NOT_CONNECTED");
      break;
    case -5:
      Serial.println("HTTPC_ERROR_CONNECTION_LOST");
      break;
    case -6:
      Serial.println("HTTPC_ERROR_NO_STREAM");
      break;
    case -7:
      Serial.println("HTTPC_ERROR_NO_HTTP_SERVER");
      break;
    case -8:
      Serial.println("HTTPC_ERROR_TOO_LESS_RAM");
      break;
    case -9:
      Serial.println("HTTPC_ERROR_ENCODING");
      break;
    case -10:
      Serial.println("HTTPC_ERROR_STREAM_WRITE");
      break;
    case -11:
      Serial.println("HTTPC_ERROR_READ_TIMEOUT");
      break;
  }
  
}

String http_GET_DATA(String URL) {

    String result;
    
    HTTPClient http;  //Declare an object of class HTTPClient
 
    http.begin(URL);  //Specify request destination
    int httpCode = http.GET(); //Send the request
 
    if (httpCode > 0) { //Check the returning code
 
      result = http.getString();   //Get the request response result
      Serial.println("Datei von " + URL + " heruntergeladen.");    
      Serial.println("");           
 
    } else {
      handleHTTP_Error(httpCode); //Fehler Code ausgeben
    }
 
    http.end();   //Close connection

    return result;
}

//================================================================================================
//=========================================== SPIFFS =============================================
//================================================================================================

void saveToSPIFFS(String param) {
  
  File f = SPIFFS.open("/config.json", "w");
  if (!f) {
    Serial.println("Kritischer Fehler. config.json konnte nicht geöffnet werden");
  } else {
    f.print(param);
    Serial.println("Erfolgreich gespeichert!");
    Serial.println("");
  }
  
  f.close();
 
}


//================================================================================================
//============================================ LOOP ==============================================
//================================================================================================

boolean a;

void loop() {

if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status
  
  if (!a) { //Aktion wird nur einmal ausgeführt 
    
    // http_GET_DATA("http://deineURL.com/deineDatei.json"); - Gibt als String den Inhalt des HTTP Requests wieder
    //saveToSPIFFS("TEST"); - Speichert String in SPIFFS

    saveToSPIFFS(http_GET_DATA("http://deineURL.com/deineDatei.json"));


    //SPIFFS in Serial Monitor ausgeben

    Serial.println("Ausgabe SPIFFS");
    Serial.println("==================================================================");
    Serial.println("");
    
    File f = SPIFFS.open("/config.json", "r");
    
    while (f.available()){
      Serial.write(f.read());
    }
    
    f.close();
    
    a = true;
  }
  
}
 
}

//Aktion wird nur einmal ausgeführt

Warum packst du den Teil nicht an das Ende der setup() damit es 1x ausgeführt wird?
Spart die Variable a und die if-Abfrage.

if (httpCode > 0) ist kein Kriterium für eine erfolgreiche Abfrage.

200 ist ok, z.B 404 Not found. 500 Server Error.

Alle HTTP-Statuscodes sind > 0.

Gruß Tommy

Tommy56:
if (httpCode > 0) ist kein Kriterium für eine erfolgreiche Abfrage.

Danke für die Info, aber ich wollte mit der Abfrage nach negativen Werten, nur Fehler abfangen, welche ein Crash der Library hervorrufen würden. Die HTTP-Codes werte ich nicht einzeln aus.. Aber wer mag, darf gern erweitern:

@xbow42
Das wäre natürlich auch gegangen :slight_smile: