NodeMCU mit WifiManager -> zusätzliche Daten wo/wie speichern?

Guten Morgen,

ich habe einen NodeMCU mittels WifiManager in mein Netzwerk eingebunden, funktioniert wunderbar.
Der NodeMCU soll mir bei der Gartenbewässerung helfen, dazu würde ich auf dem NodeMCU einen Webserver laufen lassen, der a) Daten anzeigt und b) Einstellungen ändern lässt (nicht viele Werte, nur z.B. Uhrzeit der Bewässerung, Dauer...).
Das Ganze läuft sogar schon, allerdings verliere ich alle eingestellten Werte, wenn der NodeMCU neu gestartet wird (nur die Wifi-Verbindungsdaten bleiben erhalten).
Wie würdet ihr das lösen? Webserver im Haus mit der Möglichkeit, die Einstellungen in einer Textdatei zu speichern, wäre vorhanden (obwohl mir auch dafür das Know-How noch fehlt), allerdings würde ich eine Speicherung auf dem NodeMCU selbst bevorzugen. SD-Karte kommt leider nicht in Frage, alle GPIOs sind bereits belegt.
Die WifiManager-Lib habe ich extra erwähnt, da diese ja schon Daten dauerhaft im Flash (oder EEPROM?) ablegt.

Vielen Dank!!!

Andreas

Ja, ich nehme auch SPIFFS. Im Weihnachtsstern habe ich ein Array von Structs als Config dort abgelegt. Man kann die Werte im Webserver ändern und auf Wunsch neu ins SPIFFS schreiben. Evtl. kannst Du Dir da Anregungen holen.

Gruß Tommy

Moin,

das Thema ist interessant.
Stell doch mal bitte den Code hier rein!

Lieben Gruß,
Chris

themanfrommoon:
Moin,

das Thema ist interessant.
Stell doch mal bitte den Code hier rein!

Lieben Gruß,
Chris

Du meinst die Bewässerung?

Mir hat bisher immer der EEPROM-Emulator/Übersetzer/Verknüpfer ausgereicht.
Der ist aber nur auf dem ESP8266 vorhanden, der ESP32 schmiert ab, wenn man versucht die EEPROM Library zu verwenden!

Dort liegt die URL meines Servers, ein Intervall, ein paar Indentifizierungsmerkmale und die WiFi Zugriffsdaten.

Übermittel ich dem Server ein Json, checkt dieser ob die Einrichtung aktuell ist und liefert ggf. ein Json mit den neuen Einstellungen zurück.
Das lese ich (zugegebener Maßen dreckig selbstgebastelt) manuell wieder aus und überschreibe die config.

Ein paar Helferlein erlauben auch Integer, Long und String abzulegen:

#include <EEPROM.h>

#define EEPROM_MIN_ADDR 0
#define EEPROM_MAX_ADDR 130
// Returns true if the address is between the
// minimum and maximum allowed values, false otherwise.
//
// This function is used by the other, higher-level functions
// to prevent bugs and runtime errors due to invalid addresses.
boolean eeprom_is_addr_ok(int addr) {
  return ((addr >= EEPROM_MIN_ADDR) && (addr <= EEPROM_MAX_ADDR));
}

// Writes a sequence of bytes to eeprom starting at the specified address.
// Returns true if the whole array is successfully written.
// Returns false if the start or end addresses aren't between
// the minimum and maximum allowed values.
// When returning false, nothing gets written to eeprom.
boolean eeprom_write_bytes(int startAddr, const byte* array, int numBytes) {
  // counter
  int i;

  // both first byte and last byte addresses must fall within
  // the allowed range
  if (!eeprom_is_addr_ok(startAddr) || !eeprom_is_addr_ok(startAddr + numBytes)) {
    return false;
  }

  for (i = 0; i < numBytes; i++) {
    EEPROM.write(startAddr + i, array[i]);
  }
  return true;
}

// Writes a string starting at the specified address.
// Returns true if the whole string is successfully written.
// Returns false if the address of one or more bytes fall outside the allowed range.
// If false is returned, nothing gets written to the eeprom.
boolean eeprom_write_string(int addr, const char* string) {
  int numBytes; // actual number of bytes to be written
  //write the string contents plus the string terminator byte (0x00)
  numBytes = strlen(string) + 1;
  return eeprom_write_bytes(addr, (const byte*)string, numBytes);
}

// Reads a string starting from the specified address.
// Returns true if at least one byte (even only the string terminator one) is read.
// Returns false if the start address falls outside the allowed range or declare buffer size is zero.
//
// The reading might stop for several reasons:
// - no more space in the provided buffer
// - last eeprom address reached
// - string terminator byte (0x00) encountered.
boolean eeprom_read_string(int addr, char* buffer, int bufSize) {
  byte ch; // byte read from eeprom
  int bytesRead; // number of bytes read so far

  if (!eeprom_is_addr_ok(addr)) { // check start address
    return false;
  }

  if (bufSize == 0) { // how can we store bytes in an empty buffer ?
    return false;
  }

  // is there is room for the string terminator only, no reason to go further
  if (bufSize == 1) {
    buffer[0] = 0;
    return true;
  }

  bytesRead = 0; // initialize byte counter
  ch = EEPROM.read(addr + bytesRead); // read next byte from eeprom
  buffer[bytesRead] = ch; // store it into the user buffer
  bytesRead++; // increment byte counter

  // stop conditions:
  // - the character just read is the string terminator one (0x00)
  // - we have filled the user buffer
  // - we have reached the last eeprom address
  while ( (ch != 0x00) && (bytesRead < bufSize) && ((addr + bytesRead) <= EEPROM_MAX_ADDR) ) {
    // if no stop condition is met, read the next byte from eeprom
    ch = EEPROM.read(addr + bytesRead);
    buffer[bytesRead] = ch; // store it into the user buffer
    bytesRead++; // increment byte counter
  }

  // make sure the user buffer has a string terminator, (0x00) as its last byte
  if ((ch != 0x00) && (bytesRead >= 1)) {
    buffer[bytesRead - 1] = 0;
  }
  return true;
}

void eepromWriteInt(int adr, int value) {
  byte low, high;
  low=value&0xFF;
  high=(value>>8)&0xFF;
  EEPROM.write(adr, low);
  EEPROM.write(++adr, high);
  return;
}

int eepromReadInt(int adr) {
byte low, high;
  low=EEPROM.read(adr);
  high=EEPROM.read(++adr);
  return low + ((high << 8)&0xFF00);
}

//This function will write a 4 byte (32bit) long to the eeprom at
//the specified address to address + 3.
void EEPROMWritelong(int address, long value){
  //Decomposition from a long to 4 bytes by using bitshift.
  //One = Most significant -> Four = Least significant byte
  byte four = (value & 0xFF);
  byte three = ((value >> 8) & 0xFF);
  byte two = ((value >> 16) & 0xFF);
  byte one = ((value >> 24) & 0xFF);
  
  //Write the 4 bytes into the eeprom memory.
  EEPROM.write(address, four);
  EEPROM.write(address + 1, three);
  EEPROM.write(address + 2, two);
  EEPROM.write(address + 3, one);
}

long EEPROMReadlong(long address){
  //Read the 4 bytes from the eeprom memory.
  long four = EEPROM.read(address);
  long three = EEPROM.read(address + 1);
  long two = EEPROM.read(address + 2);
  long one = EEPROM.read(address + 3);
  
  //Return the recomposed long by using bitshift.
  return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}

Man muss nur zusätzlich die Länge der Strings speichern, damit man die korrekt wieder auslesen kann:

  ssidLength = EEPROM.read(5);
  passwordLength = EEPROM.read(6);
  eeprom_read_string(10, ssid, ssidLength);  
  eeprom_read_string(30, password, passwordLength);

Du meinst die Bewässerung?

Ja

@noiasca
Danke, ich meine aber mich zu erinnern, dass der ESP8266 rebootet hat, sobald man update() anstelle von write() verwendet hat. Was put() letztendlich intern verwendet.
Deshalb findest Du es auch in meinem o.g. Code nirgends.

Bin mir aber ehrlich gesagt nicht mehr 100%ig sicher :roll_eyes:

Also ich beschäftige mich gerade mit SPIFFS, ist ja im Grunde keine Hexerei, muss mir nur ausdenken, wie ich die Konfigurationsdaten in eine Datei bekomme und ordentlich auslesen/schreiben kann.
Danke für Eure Inputs!!!

@themanfrommoon: Kann ich gerne hier vorstellen, sobald das Projekt als Ganzes läuft