ESP8266 + little fs web page not fully loaded

Hello all,
I'm programming a countdown timmer, I founded a old tuto that I modified to include a pedal with buttons. I also changed SPIFFS to littleFS because i read that SPIFFS were not longer supported.

I'm done with the hardware but i still have a situation with the wifi http server.

It works, i can uploading data, and viewing them but when I connect the webpages are not fully loaded.
The webpage helps me to trigger and start a countdown without pedal.

Here is my ESP8266 configuration :

  • NODE MCU ESP 12E
  • Upload speed : 921600
  • CPU: 80Mhz
  • FS: 2MB OTA 1019
  • IwIP : V2ipv6
  • Vtables : Flash
  • C++ disabled
  • stack protect : disabled
  • Erase Flash : Sketch
  • MMU : 32kb cache + 32 Kb Iram
  • non 32bit : Use PGM_read macros for Iram_PROGMEM

Ino code (full page) :

#include <Wire.h>
#include <RtcDS3231.h>                        // Include RTC library by Makuna: https://github.com/Makuna/Rtc
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
#include <FastLED.h>
#include <LittleFS.h>
#include <FS.h>                               // Please read the instructions on http://arduino.esp8266.com/Arduino/versions/2.3.0/doc/filesystem.html#uploading-files-to-file-system
#include <ezButton.h>
#define countof(a) (sizeof(a) / sizeof(a[0]))
#define NUM_LEDS 86                           // Total of 86 LED's     
#define DATA_PIN D6                           // Change this if you are using another type of ESP board than a WeMos D1 Mini
#define MILLI_AMPS 2400 
#define COUNTDOWN_OUTPUT D5
#define WIFIMODE 0                           // 0 = Only Soft Access Point, 1 = Only connect to local WiFi network with UN/PW, 2 = Both

#include <ezButton.h>

ezButton button(D7);  // create ezButton object that attach to ESP8266 pin D7

#if defined(WIFIMODE) && (WIFIMODE == 0 || WIFIMODE == 2)
  const char* APssid = "*****";        
  const char* APpassword = "*****";  
#endif
  
#if defined(WIFIMODE) && (WIFIMODE == 1 || WIFIMODE == 2)
  #include "Credentials.h"                    // Create this file in the same directory as the .ino file and add your credentials (#define SID YOURSSID and on the second line #define PW YOURPASSWORD)
  const char *ssid = SID;
  const char *password = PW;
#endif

RtcDS3231<TwoWire> Rtc(Wire);
ESP8266WebServer server(80);
ESP8266HTTPUpdateServer httpUpdateServer;
CRGB LEDs[NUM_LEDS];

// Settings
unsigned long prevTime = 0;
byte r_val = 255;
byte g_val = 255;
byte b_val = 255;
bool dotsOn = true;
byte brightness = 255;
float temperatureCorrection = -3.0;
byte temperatureSymbol = 12;              // 12=Celcius, 13=Fahrenheit check 'numbers'
byte clockMode = 1;                           // Clock modes: 0=Clock, 1=Countdown, 2=Temperature, 3=Scoreboard
unsigned long countdownMilliSeconds;
unsigned long endCountDownMillis;
byte hourFormat = 24;                         // Change this to 12 if you want default 12 hours format instead of 24               
CRGB countdownColor = CRGB(255, 255, 255);
byte scoreboardLeft = 0;
byte scoreboardRight = 0;
CRGB scoreboardColorLeft = CRGB::Green;
CRGB scoreboardColorRight = CRGB::Red;
CRGB alternateColor = CRGB::Black;
long numbers[] = {
  0b000111111111111111111,  // [0] 0
  0b000111000000000000111,  // [1] 1
  0b111111111000111111000,  // [2] 2
  0b111111111000000111111,  // [3] 3
  0b111111000111000000111,  // [4] 4
  0b111000111111000111111,  // [5] 5
  0b111000111111111111111,  // [6] 6
  0b000111111000000000111,  // [7] 7
  0b111111111111111111111,  // [8] 8
  0b111111111111000111111,  // [9] 9
  0b000000000000000000000,  // [10] off
  0b111111111111000000000,  // [11] degrees symbol
  0b000000111111111111000,  // [12] C(elsius)
  0b111000111111111000000,  // [13] F(ahrenheit)
};

void setup() {
  
  button.setDebounceTime(50); // set debounce time to 50 milliseconds
  pinMode(COUNTDOWN_OUTPUT, OUTPUT);
  Serial.begin(115200); 
  delay(200);

  // RTC DS3231 Setup
  Rtc.Begin();    
  RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);

  if (!Rtc.IsDateTimeValid()) {
      if (Rtc.LastError() != 0) {
          // we have a communications error see https://www.arduino.cc/en/Reference/WireEndTransmission for what the number means
          Serial.print("RTC communications error = ");
          Serial.println(Rtc.LastError());
      } else {
          // Common Causes:
          //    1) first time you ran and the device wasn't running yet
          //    2) the battery on the device is low or even missing
          Serial.println("RTC lost confidence in the DateTime!");
          // following line sets the RTC to the date & time this sketch was compiled
          // it will also reset the valid flag internally unless the Rtc device is
          // having an issue
          Rtc.SetDateTime(compiled);
      }
  }

  WiFi.setSleepMode(WIFI_NONE_SLEEP);  

  delay(200);
  //Serial.setDebugOutput(true);

  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(LEDs, NUM_LEDS);  
  FastLED.setDither(false);
  FastLED.setCorrection(TypicalLEDStrip);
  FastLED.setMaxPowerInVoltsAndMilliamps(5, MILLI_AMPS);
  fill_solid(LEDs, NUM_LEDS, CRGB::Black);
  FastLED.show();

  // WiFi - AP Mode or both
#if defined(WIFIMODE) && (WIFIMODE == 0 || WIFIMODE == 2) 
  WiFi.mode(WIFI_AP_STA);
  WiFi.softAP(APssid, APpassword);    // IP is usually 192.168.4.1
  Serial.println();
  Serial.print("SoftAP IP: ");
  Serial.println(WiFi.softAPIP());
#endif

  // WiFi - Local network Mode or both
#if defined(WIFIMODE) && (WIFIMODE == 1 || WIFIMODE == 2) 
  byte count = 0;
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    // Stop if cannot connect
    if (count >= 60) {
      Serial.println("Could not connect to local WiFi.");      
      return;
    }
       
    delay(500);
    Serial.print(".");
    LEDs[count] = CRGB::Green;
    FastLED.show();
    count++;
  }
  Serial.print("Local IP: ");
  Serial.println(WiFi.localIP());

  IPAddress ip = WiFi.localIP();
  Serial.println(ip[3]);
#endif   

  httpUpdateServer.setup(&server);

  // Handlers
  server.on("/color", HTTP_POST, []() {    
    r_val = server.arg("r").toInt();
    g_val = server.arg("g").toInt();
    b_val = server.arg("b").toInt();
    server.send(200, "text/json", "{\"result\":\"ok\"}");
  });

  server.on("/setdate", HTTP_POST, []() { 
    // Sample input: date = "Dec 06 2009", time = "12:34:56"
    // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    String datearg = server.arg("date");
    String timearg = server.arg("time");
    Serial.println(datearg);
    Serial.println(timearg);    
    char d[12];
    char t[9];
    datearg.toCharArray(d, 12);
    timearg.toCharArray(t, 9);
    RtcDateTime compiled = RtcDateTime(d, t);
    Rtc.SetDateTime(compiled);   
    clockMode = 0;     
    server.send(200, "text/json", "{\"result\":\"ok\"}");
  });

  server.on("/brightness", HTTP_POST, []() {    
    brightness = server.arg("brightness").toInt();    
    server.send(200, "text/json", "{\"result\":\"ok\"}");
  });
  
  server.on("/countdown", HTTP_POST, []() {    
    //countdownMilliSeconds = server.arg("ms").toInt(); 
    countdownMilliSeconds = server.arg("ms").toInt();     
    digitalWrite(COUNTDOWN_OUTPUT, LOW);
    countdownColor = CRGB(255, 255, 0); 
    endCountDownMillis = millis() + countdownMilliSeconds;
    allBlank(); 
    clockMode = 1;
    server.send(5, "text/json", "{\"result\":\"ok\"}");
  });

  server.on("/temperature", HTTP_POST, []() {   
    temperatureCorrection = server.arg("correction").toInt();
    temperatureSymbol = server.arg("symbol").toInt();
    clockMode = 2;     
    server.send(200, "text/json", "{\"result\":\"ok\"}");
  });  

  server.on("/scoreboard", HTTP_POST, []() {   
    scoreboardLeft = server.arg("left").toInt();
    scoreboardRight = server.arg("right").toInt();
    scoreboardColorLeft = CRGB(server.arg("rl").toInt(),server.arg("gl").toInt(),server.arg("bl").toInt());
    scoreboardColorRight = CRGB(server.arg("rr").toInt(),server.arg("gr").toInt(),server.arg("br").toInt());
    clockMode = 3;     
    server.send(200, "text/json", "{\"result\":\"ok\"}");
  });  

  server.on("/hourformat", HTTP_POST, []() {   
    hourFormat = server.arg("hourformat").toInt();
    clockMode = 0;     
    server.send(200, "text/json", "{\"result\":\"ok\"}");
  }); 

  server.on("/clock", HTTP_POST, []() {       
    clockMode = 0;     
    server.send(200, "text/json", "{\"result\":\"ok\"}");
  });  
  
  // Before uploading the files with the "ESP8266 Sketch Data Upload" tool, zip the files with the command "gzip -r ./data/" (on Windows I do this with a Git Bash)
  // *.gz files are automatically unpacked and served from your ESP (so you don't need to create a handler for each file).
  server.serveStatic("/", LittleFS, "/");
  server.begin();     

/*
  SPIFFS.begin();
  Serial.println("SPIFFS contents:");
  Dir dir = SPIFFS.openDir("/");
  while (dir.next()) {
    String fileName = dir.fileName();
    size_t fileSize = dir.fileSize();
    Serial.printf("FS File: %s, size: %s\n", fileName.c_str(), String(fileSize).c_str());
  }
  Serial.println(); 
  */ 
  LittleFS.begin();
  Serial.begin(115200);
  Serial.println("LittleFS contents:");
  Dir dir = LittleFS.openDir("/");
  while (dir.next()) {
    String fileName = dir.fileName();
    size_t fileSize = dir.fileSize();
    Serial.printf("FS File: %s, size: %s\n", fileName.c_str(), String(fileSize).c_str());
  }
 
  Serial.println();
  
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

 
  digitalWrite(COUNTDOWN_OUTPUT, LOW);
}

void loop(){

   button.loop(); // MUST call the loop() function first

  if (button.isPressed()) {
    Serial.println("The switch: OFF -> ON");
    Serial.println("Countdown timer ended.");
    countdownMilliSeconds = 32000;     
    digitalWrite(COUNTDOWN_OUTPUT, HIGH);
    countdownColor = CRGB(255, 255, 255); 
    endCountDownMillis = millis() + countdownMilliSeconds;
    allBlank(); 
    clockMode = 1;
  }

  if (button.isReleased())
    Serial.println("The switch: ON -> OFF");

  int state = button.getState();
  if (state == HIGH)
  {
    //Serial.println("The switch: OFF");
  }
  else
  {
    //Serial.println("The switch: ON");
  }
    

  server.handleClient(); 
  
  unsigned long currentMillis = millis();  
  if (currentMillis - prevTime >= 1000) {
    prevTime = currentMillis;

    if (clockMode == 1) {
      updateCountdown();
    }

    FastLED.setBrightness(brightness);
    FastLED.show();
  }   
}

void displayNumber(byte number, byte segment, CRGB color) {
  /*
   * 
      __ __ __        __ __ __          __ __ __        12 13 14  
    __        __    __        __      __        __    11        15
    __        __    __        __      __        __    10        16
    __        __    __        __  42  __        __    _9        17
      __ __ __        __ __ __          __ __ __        20 19 18  
    __        67    __        46  43  __        21    _8        _0
    __        __    __        __      __        __    _7        _1
    __        __    __        __      __        __    _6        _2
      __ __ __       __ __ __           __ __ __       _5 _4 _3   

   */
 
  // segment from left to right: 3, 2, 1, 0
  byte startindex = 0;
  switch (segment) {
    case 0:
      startindex = 0;
      break;
    case 1:
      startindex = 21;
      break;
    case 2:
      startindex = 46;
      break;
    case 3:
      startindex = 67;
      break;    
  }

  for (byte i=0; i<21; i++){
    yield();
    LEDs[i + startindex] = ((numbers[number] & 1 << i) == 1 << i) ? color : alternateColor;
  } 
}

void allBlank() {
  for (int i=0; i<NUM_LEDS; i++) {
    LEDs[i] = CRGB::Black;
  }
  FastLED.show();
}

void updateCountdown() {

  if (countdownMilliSeconds == 0 && endCountDownMillis == 0) 
    return;
    
  unsigned long restMillis = endCountDownMillis - millis();
  unsigned long hours   = ((restMillis / 1000) / 60) / 60;
  unsigned long minutes = (restMillis / 1000) / 60;
  unsigned long seconds = restMillis / 1000;
  int remSeconds = seconds - (minutes * 60);
  int remMinutes = minutes - (hours * 60); 
  
  Serial.print(restMillis);
  Serial.print(" ");
  Serial.print(hours);
  Serial.print(" ");
  Serial.print(minutes);
  Serial.print(" ");
  Serial.print(seconds);
  Serial.print(" | ");
  Serial.print(remMinutes);
  Serial.print(" ");
  Serial.println(remSeconds);

  byte h1 = hours / 10;
  byte h2 = hours % 10;
  byte m1 = remMinutes / 10;
  byte m2 = remMinutes % 10;  
  byte s1 = remSeconds / 10;
  byte s2 = remSeconds % 10;

  CRGB color = countdownColor;
  if (restMillis <= 30000) {
    color = CRGB::Red;
  }

  if (hours > 0) {
    // hh:mm
    displayNumber(h1,3,color); 
    displayNumber(h2,2,color);
    displayNumber(m1,1,color);
    displayNumber(m2,0,color);  
  } else {
    // mm:ss   
    displayNumber(m1,3,color);
    displayNumber(m2,2,color);
    displayNumber(s1,1,color);
    displayNumber(s2,0,color);  
  }

  displayDots(color);  

  if (hours <= 0 && remMinutes <= 0 && remSeconds <= 0) {
    Serial.println("Countdown timer ended.");
    //endCountdown();
    countdownMilliSeconds = 0;
    endCountDownMillis = 0;
    digitalWrite(COUNTDOWN_OUTPUT, HIGH);
    return;
  }  
}

void endCountdown() {
  allBlank();
  for (int i=0; i<NUM_LEDS; i++) {
    if (i>0)
      LEDs[i-1] = CRGB::Black;
    
    LEDs[i] = CRGB::Red;
    FastLED.show();
    delay(25);
  }  
}

void displayDots(CRGB color) {
  if (dotsOn) {
    LEDs[42] = color;
    LEDs[43] = color;
    LEDs[44] = CRGB::Black;
    LEDs[45] = CRGB::Black;
  } else {
    LEDs[42] = CRGB::Black;
    LEDs[43] = CRGB::Black;
    LEDs[44] = color;
    LEDs[45] = color;
  }

  dotsOn = !dotsOn;  
}

void hideDots() {
  LEDs[42] = CRGB::Black;
  LEDs[43] = CRGB::Black;
  LEDs[44] = CRGB::Black;
  LEDs[45] = CRGB::Black;
}

Example of original webpage to read :

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>7 Segment Clock</title>
</head>
<body>
<body>
    <div class="row" style="margin: 10px 10px;">
        <div class="col-12">

            <div class="card">
                <div class="card-body">
                    <form method="POST">
                        <label>Time</label>
                        <div class="form-row">

                            <div class="col input-group mb-3">
                                <input type="text" class="form-control" value="00" id="hours">
                                <div class="input-group-append">
                                    <span class="input-group-text">h</span>
                                </div>
                            </div>

                            <div class="col input-group mb-3">
                                <input type="text" class="form-control" value="15" id="minutes">
                                <div class="input-group-append">
                                    <span class="input-group-text">m</span>
                                </div>
                            </div>

                            <div class="col input-group mb-3">
                                <input type="text" class="form-control" value="00" id="seconds">
                                <div class="input-group-append">
                                    <span class="input-group-text">s</span>
                                </div>
                            </div>
                        </div>

                        <div>
                            <div>
                                <button type="button" class="btn btn-primary" onclick="startCountdown()">Start Countdown
                                    Timer</button>
                            </div>
                        </div>
                        <script type="text/javascript" src="index.js"></script>
                        <script type="text/javascript" src="moment-with-locales.js"></script>
                    </form>
                </div>
            </div>
        </div>
    </div>
</body>

</html>

What the esp read :

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>7 Segment Clock</title>
</head>
<body>
<body>
    <div class="row" style="margin: 10px 10px;">
        <div class="col-12">

            <div class="card">
                <div class="card-body">
                    <form method="POST">
                        <label>Time</label>
                        <div class="form-row">


SPIFFS is deprecated for ESP8266 boards, so no longer developed and will be phased out.

With the 4MB flash size i suppose.

I suspect that it is a memory or buffer issue.

But it may be relevant to memory management.

It may be something else all together though.

Can you stream the webpages to the Serial monitor when you load them as well, or does the buffer gets overrun.

The website does not seem excessively big, but the webserver buffer may be limited. Still the serveStatic() function would be suited specifically for this, so it does not really make sense to start sending chunked_content.

Does the same thing happen when using SPIFFS ?

Hello Deva,
Thanks for your reply.

Noted for SPIFFS, that's why i checked the LittleFS.
Yes my 8266 is a 4MB.

Also for me, maybe a configuration, that's why i posted my 8266 conf...

I achieved to fully log index.html and index.js. The other js has a problem and turn back a general error causing the esp to reboot, but it is another situation. While working, without, i still have the situation.

Yes also with spiffs. And when i tested spiffs, pages were more loaded.
I'll try to explore chunked_content that are unknown for me.

Well personally i never store the webpage in the FS, but only in progmem.
Then the .send() function can just send it by using the pointer to the data (the function supports progmem)

??

Basically you would load a section of the file into the buffer, and then send it, load another section and send it etc. until you have no more to send and then you finish it off.

You start it with (where 's' is the buffer)

server.setContentLength(CONTENT_LENGTH_UNKNOWN);
server.send(200, "text/html", s);

you send the next section by using

server.sendContent(s);

and finish off with

server.sendContent(s);
server.sendContent("");

Basically the empty string tells the server object that you are done. (i think it actually comes down to a double '\r\n\r\n"

It is quite complex, and since you are doing only a small page, the progmem solution is probably easier & quicker to complete.

any particular reason you are returning a response code of 5 rather than the standard 200?

Hello Blh64, none, maybe avoiding overcharge ?The clock will run long time...
I saw other threads that the clock was raming overcharging during long time period using...

Should I turn back to 200 ?

Thanks ! I read some infos about wifi web server. I'll try to explore this way, but i'll have to modify all of my code... massive work in perspectives...

Oh i wouldn't use that method, to cumbersome.

Try and store your webpage like this so you can store the whole page (which is always the same) in a single progmem variable. Also keep in mind the it is the double quote markers that cause issues, but HTML is perfectly fine about using the single ' quote markers instead inside a webpage.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.