ESP8266 SPIFFS не сохраняется правильно?

Привет всем, у меня возникли проблемы с SPIFFS для этого мини-контроллера ESP8266 Wemos D1.

Это мой эскиз Arduino:

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

struct RGBLA {
  uint8_t R;
  uint8_t G;
  uint8_t B;
  uint8_t L;
  uint8_t A;
};

void setup() {
  if (!SPIFFS.begin()) {
    Serial.println("error while mounting filesystem!");
  } else {    
    // поместите сюда свой код установки для однократного запуска:
    RGBLA returnedVars = readSPIFFS();

    Serial.begin(115200);
    Serial.println();
    Serial.println("Starting...");

    Serial.println("readSPIFFS 1");
    Serial.print("R: ");
    Serial.println(returnedVars.R);
    Serial.print("G: ");
    Serial.println(returnedVars.G);
    Serial.print("B: ");
    Serial.println(returnedVars.B);
    Serial.print("L: ");
    Serial.println(returnedVars.L);
    Serial.print("AmbientLight: ");
    Serial.println(returnedVars.A);

    Serial.println("==================================");

    returnedVars = saveToSPIFFS(25,77, 107, 250, 155, false);  
    Serial.println("saveToSPIFFS #1");
    Serial.print("R: ");
    Serial.println(returnedVars.R);
    Serial.print("G: ");
    Serial.println(returnedVars.G);
    Serial.print("B: ");
    Serial.println(returnedVars.B);
    Serial.print("L: ");
    Serial.println(returnedVars.L);
    Serial.print("AmbientLight: ");
    Serial.println(returnedVars.A);

    Serial.println("==================================");

    returnedVars = saveToSPIFFS(205,17, 68, 50, 15, true);
    Serial.println("saveToSPIFFS #2");
    Serial.print("R: ");
    Serial.println(returnedVars.R);
    Serial.print("G: ");
    Serial.println(returnedVars.G);
    Serial.print("B: ");
    Serial.println(returnedVars.B);
    Serial.print("L: ");
    Serial.println(returnedVars.L);
    Serial.print("AmbientLight: ");
    Serial.println(returnedVars.A);

    returnedVars = readSPIFFS();
    Serial.println("readSPIFFS 2");
    Serial.print("R: ");
    Serial.println(returnedVars.R);
    Serial.print("G: ");
    Serial.println(returnedVars.G);
    Serial.print("B: ");
    Serial.println(returnedVars.B);
    Serial.print("L: ");
    Serial.println(returnedVars.L);
    Serial.print("AmbientLight: ");
    Serial.println(returnedVars.A);

    Serial.println();
    Serial.println("END!");
  }
}

void loop() {
  // поместите сюда свой основной код для повторного запуска:
}

RGBLA saveToSPIFFS(uint8_t R, uint8_t G, uint8_t B, uint8_t L, uint8_t A, bool saveA) {
  File configFile = SPIFFS.open("/config.json", "w+");

  if (configFile.size() > 3072) {
    Serial.println("Config file size is too large.");
  } else {
    Serial.print("Writing json to Config file...");

    StaticJsonBuffer<200> jsonBuffer;
    JsonObject& json = jsonBuffer.createObject();

    //Получаем старое значение и сохраняем его
    RGBLA returnedVars = readSPIFFS();

    Serial.println("Old Values?");
    Serial.print("R: ");
    Serial.println(returnedVars.R);
    Serial.print("G: ");
    Serial.println(returnedVars.G);
    Serial.print("B: ");
    Serial.println(returnedVars.B);
    Serial.print("L: ");
    Serial.println(returnedVars.L);
    Serial.print("AmbientLight: ");
    Serial.println(returnedVars.A);

    if (saveA) {
      //Сохраняем данные рассеянного света
      json["R"] = returnedVars.R;
      json["G"] = returnedVars.G;
      json["B"] = returnedVars.B;
      json["L"] = returnedVars.L;
      json["A"] = A;

      //Теперь сохраняем новые данные
      returnedVars.A = A;
    } else {
      //Сохраняем данные RGBL
      json["R"] = R;
      json["G"] = G;
      json["B"] = B;
      json["L"] = L;   
      json["A"] = returnedVars.A;

      //Теперь сохраняем новые данные
      returnedVars.R = R;
      returnedVars.G = G;
      returnedVars.B = B;
      returnedVars.L = L;
    }

    json.printTo(configFile);
    configFile.close();

    //Читаем новые сохраненные значения в структуру
    //returnedVars = readSPIFFS();
    return returnedVars;
  }
}

RGBLA readSPIFFS() {
  bool exist = SPIFFS.exists("/config.json");

  if (exist) {
    Serial.println("YAY!");
  } else {
    Serial.println("Boo!");
  }

  File configFile = SPIFFS.open("/config.json", "r");
  std::unique_ptr<char[]> buf(new char[configFile.size()]);
  configFile.readBytes(buf.get(), configFile.size());
  DynamicJsonBuffer jsonBuffer;
  JsonObject& json = jsonBuffer.parseObject(buf.get());  
  RGBLA returnedVars;

  String debugLogData;
  json.printTo(debugLogData);

  Serial.println("===============");
  Serial.println(debugLogData);
  Serial.println("===============");
  returnedVars.R = json["R"];
  returnedVars.G = json["G"];
  returnedVars.B = json["B"];
  returnedVars.L = json["L"];
  returnedVars.A = json["A"];

  configFile.close();

  return returnedVars;
}

А это вывод консоли:

Starting...
readSPIFFS 1
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25
==================================
Writing json to Config file...YAY!
===============
{}
===============
Old Values?
R: 0
G: 0
B: 0
L: 0
AmbientLight: 0
saveToSPIFFS #1
R: 25
G: 77
B: 107
L: 250
AmbientLight: 0
==================================
Writing json to Config file...YAY!
===============
{}
===============
Old Values?
R: 0
G: 0
B: 0
L: 0
AmbientLight: 0
saveToSPIFFS #2
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25
YAY!
===============
{"R":0,"G":0,"B":0,"L":0,"A":25}
===============
readSPIFFS 2
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25

END!

Как видите, первые старые значения содержат все 0, что неверно. В этот момент AmbientLight должно быть 25, поскольку readSPIFFS 1 имеет 25. Итак, это должно читаться так:

Old Values?
R: 0
G: 0
B: 0
L: 0
AmbientLight: 25

saveToSPIFFS #1 отправляет значения 25, 77, 107, 250, 155 и false, которые затем корректно выводятся как:

R: 25
G: 77
B: 107
L: 250
AmbientLight: 0

Но на этот раз AmbientLight все равно должно быть 25, поскольку было отправлено false. Он должен был взять старое значение (25) и поместить его в новое сохранение.

R: 25
G: 77
B: 107
L: 250
AmbientLight: 25

При переходе к saveToSPIFFS #2 значения снова неверны. Однако AmbientLight здесь правильный. Вместо этого вывода:

R: 0
G: 0
B: 0
L: 0
AmbientLight: 25

он должен собрать 4 предыдущих старых значений:

R: 25
G: 77
B: 107
L: 250
AmbientLight: 25

Json после этого не должен быть таким:

{"R":0,"G":0,"B":0,"L":0,"A":25}

Это должно быть так:

{"R":250,"G":77,"B":107,"L":250,"A":25}

И, наконец, вывод readSPIFFS 2:

R: 0
G: 0
B: 0
L: 0
AmbientLight: 25

Неверно. Должно быть выведено:

R: 25
G: 77
B: 107
L: 250
AmbientLight: 25

Тогда после перезагрузки должно быть именно это, а не то, что показано ниже для readSPIFFS 1:

R: 0
G: 0
B: 0
L: 0
AmbientLight: 25

Итак, где я здесь накосячил?

ОБНОВЛЕНИЕ

struct RGBLA {
  uint8_t R;
  uint8_t G;
  uint8_t B;
  uint8_t L;
  uint8_t A;
};

void setup() {
   RGBLA returnedValues = readSPIFFS();

   Serial.println("readSPIFFS 1");
   Serial.print("R: ");
   Serial.println(returnedVars.R);
   Serial.print("G: ");
   Serial.println(returnedVars.G);
   Serial.print("B: ");
   Serial.println(returnedVars.B);
   Serial.print("L: ");
   Serial.println(returnedVars.L);
   Serial.print("AmbientLight: ");
   Serial.println(returnedVars.A);

   returnedValues = saveToSPIFFS(205, 17, 68, 50, 15, false);

   Serial.println("saveToSPIFFS 1");
   Serial.print("R: ");
   Serial.println(returnedVars.R);
   Serial.print("G: ");
   Serial.println(returnedVars.G);
   Serial.print("B: ");
   Serial.println(returnedVars.B);
   Serial.print("L: ");
   Serial.println(returnedVars.L);
   Serial.print("AmbientLight: ");
   Serial.println(returnedVars.A);
}

RGBLA readSPIFFS() {    
   RGBLA returnedVars;
   File configFile = SPIFFS.open("/config.json", "r");

   if (configFile ) {
     Serial.println("YAY!");
     configFile.readBytes((byte*) &returnedValues, sizeof(RGBLA));
     configFile.close();
   } else {
     Serial.println("Boo!");
   }

   return returnedValues;
}

RGBLA saveToSPIFFS() {    
   File configFile = SPIFFS.open("/config.json", "w+");

   if (configFile.size() > 3072) {
     Serial.println("Config file size is too large.");
   } else {
     Serial.print("Writing to Config file...");

     //Get the old value and save it
     RGBLA returnedVars = readSPIFFS();

     Serial.println("Old Values:");
     Serial.print("R: ");
     Serial.println(returnedVars.R);
     Serial.print("G: ");
     Serial.println(returnedVars.G);
     Serial.print("B: ");
     Serial.println(returnedVars.B);
     Serial.print("L: ");
     Serial.println(returnedVars.L);
     Serial.print("AmbientLight: ");
     Serial.println(returnedVars.A);

     if (saveA) {
       //Save Ambient Light data
       returnedVars.A = A;
     } else {
       //Save RGBL data
       returnedVars.R = R;
       returnedVars.G = G;
       returnedVars.B = B;
       returnedVars.L = L;
     }

     configFile.write((byte*) &returnedVars, sizeof(RGBLA));
     configFile.close();

     return returnedVars;
}

, 👍0

Обсуждение

почему вы сохраняете его как JSON? простые file.write((byte*) rgbla, sizeof (RGBLA)) и file.read((byte*) rgbla, sizeof (RGBLA)) будут работать, @Juraj

@Юрай, можешь ли ты назвать это потенциальным ответом и привести пример?, @StealthRT

если это будет только один экземпляр структуры RGBLA и один файл для ее сохранения, тогда создайте один глобальный экземпляр структуры и скорее верните успешное состояние из функций, @Juraj


1 ответ


2

Вы можете записать структуру в файл в виде двоичных данных. Этот пример из моего проекта.

глобальные данные:

struct Stats {
  int heatingTime; // минуты
  int consumedPower; // Вт
};

Stats statsData;

фрагмент из setup():

  File file = SPIFFS.open(STATS_FILENAME, "r");
  if (file) {
    file.readBytes((byte*) &statsData, sizeof(statsData));
    file.close();
  }

фрагмент из функции statsSave():

  File file = SPIFFS.open(STATS_FILENAME, "w");
  if (file) {
    file.write((byte*) &statsData, sizeof(statsData));
    file.close();
  }

Ваш обновленный readSPIFFS должен быть:

RGBLA readSPIFFS() {

  RGBLA returnedVars;
  File configFile = SPIFFS.open("/config.json", "r");
  if (configFile ) {
    Serial.println("YAY!");
    configFile.readBytes((byte*) &returnedValues, sizeof(RGBLA));
    configFile.close();
  } else {
    Serial.println("Boo!");
  }
  return returnedValues;
}
,

Значит, я все еще могу вернуть **RGBLA**, например **RGBLA returnVars = readSPIFFS();**?, @StealthRT

Посмотрите мой обновленный ОП., @StealthRT

configFile.readBytes((byte*) &returnedValues, sizeof(returnedValues)); или configFile.readBytes((byte*) &returnedValues, sizeof(RGBLA));, @Juraj

Хорошо, исправил это в обновлении. Нужно ли мне еще использовать **return returnVars;** или он уже заполняет стойку?, @StealthRT

что такое configFile["R"]?, @Juraj

Получение значения **R** в **RGBLA.**, @StealthRT

вы читаете его в структуру с помощью readbytes. он находится в returnValues после readBytes, @Juraj

Хорошо, я снова обновил ОП, чтобы отразить изменения. Правильно ли это сейчас?, @StealthRT

вы читаете локальную переменную returnValues, а return копирует значения структуры в returnValues в переменной в настройке., @Juraj

Хорошо, я снова обновил ОП, чтобы отразить эти изменения. Я также добавил **saveToSPIFFS**, но не знаю, как его сохранить, поскольку в нем есть старые данные, которые необходимо сохранить вместе с новыми данными (пример: RGBL — это новые данные, а A — старые данные), все, что необходимо сохранить. в этот файл конфигурации., @StealthRT

Хорошо, я думаю, что теперь оно у меня есть. Обновил обновление ОП., @StealthRT

После того, как я наконец смог это проверить, я получаю сообщение об ошибке **недопустимого преобразования из 'byte* {aka unsigned char*}' в 'char*' [-fpermissive]**, @StealthRT

**недопустимое преобразование из 'char*' в 'const uint8_t* {aka const unsigned char*}' [-fpermissive]**, @StealthRT

измените приведение на необходимый тип. это всего лишь разные названия байтов., @Juraj