help with interfacing esp8266 SPIFFS

Hi. I’m trying to make a animated Covid-19 LED Mask. I’ve already written image conversion code to turn color values from animations to FastLED values. The python code I’ve written, dumps values to a text file, then it’s transferred to an sd card, then the values are supposed to be read and then dumped to a WS2812B Matrix. Also there is supposed to be a button that changes the current animation (that’s what I’m testing right now). The problem I’m having is that I can’t read one file at a time (via button press) and I’m not sure how to convert the buffer to variable values.

Here’s the current code:

#include <SPI.h>
#include <SD.h>

File root;
String buffer;

const int buttonPin = 2;
int buttonState = 0;
bool ButtonPressBool;

void setup() {
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
  while (!Serial) {}

  Serial.print("Initializing SD card...\n");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  root = SD.open("files/");
  selectFile(root);
}

void loop() {

}

void selectFile(File dir) {
  while (ButtonPressBool = true) {

    File entry =  dir.openNextFile();
    Serial.print('\n');
    if(entry) {
      while (entry.available()) {
      buffer = entry.readStringUntil('\n');
      Serial.println(buffer);  
      }
    }
    
    if (! entry) {
      // no more files
      break;
    }

    Serial.print(entry.name());
    entry.close();
  }
}

void buttonPress(){
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    ButtonPressBool = true;
  } else {
    ButtonPressBool = false;
  }
}

If anyone can help me out, it would be appreciated.

I can't read one file at a time

Your code should go through all the files in the root folder of the the card, and do that one at a time. It won't open them all at the same time, so not sure what you are saying?

how to convert the buffer to variable values.

We need to know how your files are formatted to help with that. Please post an example into your next post, between code tags.

PaulRB:
Your code should go through all the files in the root folder of the the card, and do that one at a time. It won't open them all at the same time, so not sure what you are saying?
We need to know how your files are formatted to help with that. Please post an example into your next post, between code tags.

At the moment the code just reads all the files. Yes it does open them one at a time but nothing stop it from reading all the files. Not even that I have a bool in place. "how your files are formatted"? I didn't mention it cause the formatting can change. At the moment the formatting looks like this: "led[0] = CRGB(0, 0, 0)".

I would change that format. You have a machine reading it, not a human. It could just be something like "0,0,0,0"

aarg:
I would change that format. You have a machine reading it, not a human. It could just be something like "0,0,0,0"

Ok, done. I changed the format.

while (ButtonPressBool = true)

This line sets the bool to true, so it loops forever. You meant to write "==", not "=".

Or simply write

while (ButtonPressBool)

(I would rename the bool to "buttonPressed")

while (entry.available()) {
  int ledNumber = entry.parseInt();
  byte red = entry.parseInt();
  byte green = entry.parseInt();
  byte blue = entry.parseInt();
  //Do something with ledNumber, red, green, blue here...
}

PaulRB:

while (entry.available()) {

int ledNumber = entry.parseInt();
  byte red = entry.parseInt();
  byte green = entry.parseInt();
  byte blue = entry.parseInt();
  //Do something with ledNumber, red, green, blue here…
}

Thanks for the help. I didn’t know I could parse values like this. I do have one problem. When I Serial.print() this it outputs an extra line with all values set to “0”. (Please note: I’m just testing with Serial.print(). )

Here’s the current code:

#include <SPI.h>
#include <SD.h>

File root;
String buffer;

const int buttonPin = 2;
int buttonState = 0;
bool ButtonPressed;

void setup() {
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
  while (!Serial) {}

  Serial.print("Initializing SD card...\n");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  root = SD.open("files/");
  selectFile(root);
}

void loop() {
}

void selectFile(File dir) {
  while (true){

    File entry =  dir.openNextFile();
    Serial.print('\n');
    if(entry) {
      while (entry.available()) {
        int frame = entry.parseInt();
        int ledNumber = entry.parseInt();
        byte red = entry.parseInt();
        byte green = entry.parseInt();
        byte blue = entry.parseInt();
        Serial.print("frame:");
        Serial.print(frame);
        Serial.print(" ledNumber:");
        Serial.print(ledNumber);
        Serial.print(" red:");
        Serial.print(red);
        Serial.print(" green:");
        Serial.print(green);
        Serial.print(" blue:");
        Serial.println(blue);
      }
    }
    
    if (! entry) {
      // no more files
      break;
    }

    Serial.print(entry.name());
    entry.close();
  }
}

Here’s the output:

loads of similar lines before this
frame:3 ledNumber:383 red:0 green:0 blue:254
frame:0 ledNumber:0 red:0 green:0 blue:0 // this line isn't supposed to be here
TEST.TXT

Try putting

entry.read(); //discard end-of-line character

after the last parseInt(). You may need to repeat it twice because Windows ends each line with line-feed and carriage-return characters (Linux doesn't, suspect Mac OS doesn't either, they only put one line-end character).

I can’t get the code running on a Nano (memory limitations can’t use the SD card library and FastLED at the same time) so I’m investigating using the Wemos D1 mini. I have an issue where I’m trying to get the code to pause after every “frame” and then loop around and re-read the file. I’m currently testing this with “CompareFrame”. “CompareFrame” is supposed to count from 0 to “numberOfFrames” and then reset to 0. Currently it goes “0,1,2,3,” a huge pause and then “4,5,6…” all the way to infinity. Can anyone point out my mistake? I swear I’m losing patience with this project

#include <SPI.h>
#include <SD.h>

File root;
String buffer;
int x = 32;
int y = 12;
int numOfLeds = x * y;
int CompareFrame = 0;
int batterySaver = 3;
int delayBetweenFrames = 1000;
const int buttonPin = 2;
int buttonState = 0;
bool boolButtonPressed = false;

/*******************/
//#define NUM_LEDS 384
//#include <FastLED.h>
//#define DATA_PIN 3
//CRGB leds[NUM_LEDS];
/******************/

void setup() {
  /*****************/
  //  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  /*****************/
  pinMode(buttonPin, INPUT);

  Serial.begin(9600);
  while (!Serial) {}

  Serial.print("Initializing SD card...\n");

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");
  //  root = SD.open("files/");
}

void loop() {
  buttonPress();
}

void selectFile() {
  while (true) {
    root = SD.open("files/");
    File entry =  root.openNextFile();
    setLEDs(entry);

    while (!entry) {
      root.rewindDirectory();
      entry.close();
      entry = root.openNextFile();
    }

    entry.close();
  }
}

void setLEDs(File entry) {
  if (entry) {
    while (entry.available()) {
      int numberOfFrames = entry.parseInt();
      int frame = entry.parseInt();
      int ledNumber = entry.parseInt();
      byte red = entry.parseInt();
      byte green = entry.parseInt();
      byte blue = entry.parseInt();

      red = red / batterySaver;
      green = green / batterySaver;
      blue = blue / batterySaver;
//      Serial.print("numberOfFrames:");
//      Serial.print(numberOfFrames);
//      Serial.print("frame:");
//      Serial.print(frame);
//      Serial.print(" ledNumber:");
//      Serial.print(ledNumber);
//      Serial.print(" red:");
//      Serial.print(red);
//      Serial.print(" green:");
//      Serial.print(green);
//      Serial.print(" blue:");
//      Serial.println(blue);
//      Serial.print(entry.name());
        Serial.println(CompareFrame);

       if(CompareFrame > numberOfFrames - 1) {
         CompareFrame == 0;
       }

      if (CompareFrame == frame) {
        //      leds[ledNumber] = CRGB(red, green, blue);
      }
      else {
        delay(delayBetweenFrames);
        CompareFrame = CompareFrame + 1;

      }
    }
  }
}

void buttonPress() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    boolButtonPressed == true;
    delay(10);
    selectFile();
  }
  else {
    boolButtonPressed == false;
  }
}

void clearLEDs() {
  for (int i = 0; i < numOfLeds; i++)
  {
    //    leds[i] = CRGB(0, 0, 0);
  }
}

I'm investigating using the Wemos D1 mini.

Before I read your code, some thoughts on this change.

Wemos have at least 4MB flash. You probably don't need the SD card. You can reserve 3MB of flash for SPIFFS file system, which acts just like an SD card. That leaves you with 1MB for sketch upload, which is still a lot. You can upload files to SPIFFS through the USB-serial interface or over WiFi using a utility sketch.

Wemos will add significantly to battery drain, so when used to run the led patterns, be sure to use MODEM_SLEEP mode which will reduce its own consumption down from around 80mA to 20mA.

Being a 3.3V device, you may well find out does not reliably drive the led matrix, which expects a 5V signal. If you power the led matrix direct from a Li-Ion battery for example, it might work because the difference between 3.3V and ~3.7V is not much. But you may find the blue LEDs stop working as the battery charge falls. If you use a 5V buck converter, the blue LEDs will keep going, but you may run into the problem I'm describing, because a 3.3V data signal may not be enough, causing data corruption. If this happens, don't bother trying one of those level shifter modules designed for i2c bus level conversions, they don't work well with ws2812's 800KHz signals. Instead, use a 74hc14 or 74hct14 chip as your level converter.

I suspect your code is trying to read past the end of the file. The parseInt() function has a 1 second timeout and your code calls it 6 times in a row, before it realises that it is at the end of the file. Could that be it?

I don't see my suggested fix from post #8 in there.

Hi PaulRB, you've been really helpful with these suggestions. About post #8 it was working sometimes without "entry.read();" since I'm on Linux. And frankly I've become hesitant to use SD cards with all the issues I'm having. Thanks for all the help but I think I'm going to try the "spiffs" idea. I think I'll start a new forum topic? I think that's how it works

No, continue with this topic. Starting a new topic would be "cross-posting" which is against forum rules. If you want to change the topic's title, amend the original post.

Well I'm glad I checked before making a new topic. So NOW I'm having issues with SPIFFS:

Here's the example code:

#include "FS.h"
 
void setup() {
  Serial.begin(115200);
  
  if(!SPIFFS.begin()){
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }
  
  File file = SPIFFS.open("/test_example.txt", "r");
  if(!file){
    Serial.println("Failed to open file for reading");
    return;
  }
  
  Serial.println();
  Serial.println("File Content:");
  while(file.available()){
    Serial.write(file.read());
  }
  file.close();
}
 
void loop() {

}

Here's what's in the text file:

test

Here's the Serial Monitor:

Failed to open file for reading

Never mind I was uploading the sketch correctly but not the SPIFFS data.

Try taking the "/" out of the file name.

PaulRB:
Try taking the "/" out of the file name.

I did more than once. I got it to dump out the file but I can't parse it like before

#include "FS.h"
#include "ESP8266WiFi.h"
 
void setup() {
  Serial.begin(115200);
  
  if(!SPIFFS.begin()){
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }
  
  File file = SPIFFS.open("/test.txt", "r");
  if(!file){
    Serial.println("Failed to open file for reading");
    return;
  }
  
  Serial.println("File Content:");
  while(file.available()){
    //Serial.write(file.read());
    int numberOfFrames = file.parseInt();
    int frame = file.parseInt();
    int ledNumber = file.parseInt();
    byte red = file.parseInt();
    byte green = file.parseInt();
    byte blue = file.parseInt();
    Serial.write(ledNumber);
    Serial.write(red);
    Serial.write(green);
    Serial.write(blue);
  }
  file.close();
}
 
void loop() {
}

This outputs a "Failed to open file for reading" error

johnscott:
got it to dump out the file but I can't parse it like before

  File file = SPIFFS.open("/test.txt", "r");

I don't understand. You still have the "/" there?[/code]

Sorry for being unclear. I can’t remove it, SPIFFS really wants to know the whole path of the file. It will happily print the whole file like this:

  File file = SPIFFS.open("/test.txt", "r");
  if(!file){
    Serial.println("Failed to open file for reading");
    return;
  }
  
  Serial.println("File Content:");
  while(file.available()){
    Serial.write(file.read());
  }

This only makes it give out an error:

  File file = SPIFFS.open("test.txt", "r");