Your new topic does not fit any of the above??? Check first. Then post here. Thanks.

Moderator: igrr

User avatar
By Th3On3Fr33man
#49922 Alright so I am currently using a modified version of the SPIFFS library that is asynchronous: https://github.com/me-no-dev/ESPAsyncWebServer, I was referred to this by @Me-no-dev and on a general basis it works great, but every once in a while it will either fail to load a css/js file or one of the images that I'm using on the webpage with the following error:

Image

I need a way to ensure that the css/images will never fail to load if possible. I can't just have the page randomly loading without the styles, that's ridiculous.

Another thing that's been happening is the first load of the page will occur pretty quickly, but then when I refresh, it takes forever for the page to load again.

Here's a list of the files I currently have on the server:

Image

Here's the current version of my code:

Relevant Code from Primary ino File
Code: Select all// WEB HANDLER IMPLEMENTATION (Modified Server Library Code)
class SPIFFSEditor: public AsyncWebHandler {
  private:
    String _username;
    String _password;
    bool _uploadAuthenticated;
  public:
    SPIFFSEditor(String username=String(), String password=String()):_username(username),_password(password),_uploadAuthenticated(false){}
    bool canHandle(AsyncWebServerRequest *request){
      if(request->method() == HTTP_GET && request->url() == "/edit" && (SPIFFS.exists("/edit.htm") || SPIFFS.exists("/edit.htm.gz")))
        return true;
      else if(request->method() == HTTP_GET && request->url() == "/list")
        return true;
      else if(request->method() == HTTP_GET && (request->url().endsWith("/") || SPIFFS.exists(request->url()) || (!request->hasParam("download") && SPIFFS.exists(request->url()+".gz"))))
        return true;
      else if(request->method() == HTTP_POST && request->url() == "/edit")
        return true;
      else if(request->method() == HTTP_DELETE && request->url() == "/edit")
        return true;
      else if(request->method() == HTTP_PUT && request->url() == "/edit")
        return true;
      return false;
    }

    //Function used to serve webpage to user (Modified Server Library Code)
    void handleRequest(AsyncWebServerRequest *request){
      if(_username.length() && (request->method() != HTTP_GET || request->url() == "/edit" || request->url() == "/list") && !request->authenticate(_username.c_str(),_password.c_str()))
        return request->requestAuthentication();

      if(request->method() == HTTP_GET && request->url() == "/edit"){
        request->send(SPIFFS, "/edit.htm");
      } else if(request->method() == HTTP_GET && request->url() == "/list"){
        if(request->hasParam("dir")){
          String path = request->getParam("dir")->value();
          Dir dir = SPIFFS.openDir(path);
          path = String();
          String output = "[";
          while(dir.next()){
            File entry = dir.openFile("r");
            if (output != "[") output += ',';
            bool isDir = false;
            output += "{\"type\":\"";
            output += (isDir)?"dir":"file";
            output += "\",\"name\":\"";
            output += String(entry.name()).substring(1);
            output += "\"}";
            entry.close();
          }
          output += "]";
          request->send(200, "text/json", output);
          output = String();
        }
        else
          request->send(400);
      } else if(request->method() == HTTP_GET){
        String path = request->url();
        if(path.endsWith("/"))
          path += "index.htm";
        request->send(SPIFFS, path, String(), request->hasParam("download"));
      } else if(request->method() == HTTP_DELETE){
        if(request->hasParam("path", true)){
          ESP.wdtDisable(); SPIFFS.remove(request->getParam("path", true)->value()); ESP.wdtEnable(10);
          request->send(200, "", "DELETE: "+request->getParam("path", true)->value());
        } else
          request->send(404);
      } else if(request->method() == HTTP_POST){
        if(request->hasParam("data", true, true) && SPIFFS.exists(request->getParam("data", true, true)->value()))
          request->send(200, "", "UPLOADED: "+request->getParam("data", true, true)->value());
        else
          request->send(500);
      } else if(request->method() == HTTP_PUT){
        if(request->hasParam("path", true)){
          String filename = request->getParam("path", true)->value();
          if(SPIFFS.exists(filename)){
            request->send(200);
          } else {
            File f = SPIFFS.open(filename, "w");
            if(f){
              f.write(0x00);
              f.close();
              request->send(200, "", "CREATE: "+filename);
            } else {
              request->send(500);
            }
          }
        } else
          request->send(400);
      }
    }

    //Function used to handle uploading web files (Modified Server Library Code)
    void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
      if(!index){
        if(!_username.length() || request->authenticate(_username.c_str(),_password.c_str()))
          _uploadAuthenticated = true;
        request->_tempFile = SPIFFS.open(filename, "w");
      }
      if(_uploadAuthenticated && request->_tempFile && len){
        ESP.wdtDisable(); request->_tempFile.write(data,len); ESP.wdtEnable(10);
      }
      if(_uploadAuthenticated && final)
        if(request->_tempFile) request->_tempFile.close();
    }
};

void setup(){
 
  IPAddress ip(192, 168, 1, 16);
  IPAddress subnet(255, 255, 255, 0);
  IPAddress gt(192, 168, 1, 1);
   
  //Initialize Serial Connections
  initSerial();
 
  //Initialize File System
  SPIFFS.begin();
   
  //Initialize WiFi Connection (Modified Server Library Code)
  WiFi.mode(WIFI_STA);
  //WiFi.config(ip, gt, subnet);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
   
    Serial.printf("STA: Failed!\n");
    WiFi.disconnect(false);
   
    //Seems to work without this, not sure if necessary
    //delay(1000);
   
    WiFi.begin(ssid, password);
  }
  ArduinoOTA.begin();
  //Serial.printf("format start\n"); SPIFFS.format();  Serial.printf("format end\n");
 
  //NEW
  ws.onEvent(onEvent);
  server.addHandler(&ws);
   
  server.serveStatic("/fs", SPIFFS, "/");

  server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", String(ESP.getFreeHeap()));
  });
  server.addHandler(new SPIFFSEditor(http_username,http_password));

  server.onNotFound([](AsyncWebServerRequest *request){
   
    if(mySerial)
    {
        mySerial.printf("NOT_FOUND: ");
    } //end if
     
    if(request->method() == HTTP_GET)
    {
        if(mySerial)
        {
            mySerial.printf("GET");
        } //end if
    } //end if
     
    else if(request->method() == HTTP_POST)
    {
        if(mySerial)
        {
            mySerial.printf("POST");
        } //end if
    } //end else if
     
    else if(request->method() == HTTP_DELETE)
    {
        if(mySerial)
        {
            mySerial.printf("DELETE");
        } //end if
    } //end else if
     
    else if(request->method() == HTTP_PUT)
    {
        if(mySerial)
        {
            mySerial.printf("PUT");
        } //end if
    } //end else if
     
    else if(request->method() == HTTP_PATCH)
    {
        if(mySerial)
        {
            mySerial.printf("PATCH");
        } //end if
    } //end else if
     
    else if(request->method() == HTTP_HEAD)
    {
        if(mySerial)
        {
            mySerial.printf("HEAD");
        } //end if
    } //end else if
     
    else if(request->method() == HTTP_OPTIONS)
    {
        if(mySerial)
        {
            mySerial.printf("OPTIONS");
        } //end if
    } //end else if
     
    else
    {
        if(mySerial)
        {
            mySerial.printf("UNKNOWN");
        } //end if
    } //end else
     
    //Continued Server Initialization (Modified Server Library Code)
    if(mySerial)
    {
        mySerial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str());
    } //end if

    if(request->contentLength()){
        if(mySerial)
        {
            mySerial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str());
            mySerial.printf("_CONTENT_LENGTH: %u\n", request->contentLength());
        } //end if
    } //end if

    int headers = request->headers();
    int i;
    for(i=0;i<headers;i++){
      AsyncWebHeader* h = request->getHeader(i);
      if(mySerial)
      {
          mySerial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str());
      } //end if
    }

    int params = request->params();
    for(i=0;i<params;i++){
      AsyncWebParameter* p = request->getParam(i);
      if(p->isFile()){
        if(mySerial)
        {
            mySerial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size());
        } //end if
      } else if(p->isPost()){
        if(mySerial)
        {
            mySerial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
        } //end if
      } else {
        if(mySerial)
        {
            mySerial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
        } //end if
      }
    }

    request->send(404);
  });
  server.onFileUpload([](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
    if(!index)
    {
        if(mySerial)
        {
            mySerial.printf("UploadStart: %s\n", filename.c_str());
        } //end if
    } //end if
   
    if(mySerial)
    {
        mySerial.printf("%s", (const char*)data);
    } //end if
     
    if(final)
    {
        if(mySerial)
        {
            mySerial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len);
        } //end if
    } //end if
     
  });
  server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
    if(!index)
    {
        if(mySerial)
        {
            mySerial.printf("BodyStart: %u\n", total);
        } //end if
    } //end if
   
    if(mySerial)
    {
        mySerial.printf("%s", (const char*)data);
    } //end if
     
    if(index + len == total)
    {
        if(mySerial)
        {
            mySerial.printf("BodyEnd: %u\n", total);
        } //end if
    } //end if
     
  });
  server.begin();

  //Setup a timer for all WiFi status updates
  updateTimerId = timer.setInterval(5000, sendInfoWifi);
}

void loop(){
   
 
  if(wifiInit == 0)
  { 
     initConnWifi();
  } //end if
 
  //Updates whatever timers have been defined
  timer.run();
 
  recInfoWifi();
   
  ArduinoOTA.handle();
}


Relevant code from Header ino File
Code: Select all#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <FS.h>
#include <Hash.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <WebSocketsServer.h>

// SKETCH BEGIN
AsyncWebServer server(80);

//NEW
AsyncWebSocket ws("/ws");

//Websocket
WebSocketsServer webSocket = WebSocketsServer(81);


index.html
Code: Select all<!DOCTYPE html>
<html>

<head>
    <meta name="viewport" content="width=device-width initial-scale=1.0">
    <title>FITS</title>

    <!--CSS-->
    <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body style='background-color:#4a4a4c;' onload="drawGauges(); startSocket();"> <!--start()-->
<div class="centerPiece">
   
    <h1 class="pageHdr">Fluid Infusion Training System</h1>
   
    <div class="adminLoginButtonDiv">
        <a id="adminLoginButton" class="styled-button-11 elementWrapper" onclick="admin_login_init()">Admin Login</a>

        <a id="adminLoginCancel" class="styled-button-11RED deactiveSect elementWrapper" onclick="admin_login_cancel()">Cancel Login</a>

        <a id="adminLogout" class="styled-button-11RED deactiveSect elementWrapper" onclick="admin_logout()">Admin Logout</a>
    </div>

    <div id="adminLoginCreds" class="adminLoginCreds deactiveSect">
        <div class="elementWrapper">
            <label id="adminLoginUserCredLabel" for="adminLoginNameCred">User: </label>
            <input type="text" id="adminLoginUserCred">
        </div>

        <div class="elementWrapper">
            <label id="adminLoginPassCredLabel" for="adminLoginPassCred">Password: </label>
            <input type="password" id="adminLoginPassCred">
        </div>

        <div class="elementWrapper">
            <a id="adminLoginSubmit" class="submit" onclick="admin_login_submit()">Submit</a>
        </div>
    </div>

   

    <div style="clear:both;"></div>

    <div class='counterContainer'>
        <span id="counterText" style="color:white;"></span>
    </div>

    <div id='adminControls' class='adminControlsRow deactiveSect'>

        <h2>Administrator Controls</h2>

        <div id='Newbtn' class='powerSwitchContainer'>
            <h2>HHIO PTT Power</h2>

            <!--HHIO PTT Power Switch-->
            <span class="switch">
<span class="switch-border1">
<span class="switch-border2">
<input id="switch1" type="checkbox" onclick='POWERswitch()' checked />
<label for="switch1"></label>
<span class="switch-top"></span>
            <span class="switch-shadow"></span>
            <span class="switch-handle"></span>
            <span class="switch-handle-left"></span>
            <span class="switch-handle-right"></span>
            <span class="switch-handle-top"></span>
            <span class="switch-handle-bottom"></span>
            <span class="switch-handle-base"></span>
            <span class="switch-led switch-led-green">
<span class="switch-led-border">
<span class="switch-led-light">
<span class="switch-led-glow"></span>
            </span>
            </span>
            </span>
            <span class="switch-led switch-led-red">
<span class="switch-led-border">
<span class="switch-led-light">
<span class="switch-led-glow"></span>
            </span>
            </span>
            </span>
            </span>
            </span>
            </span>
        </div>

        <!--Flushing Button-->
        <div class='flushBtnContainer'>
            <h2>Fluid Reservoir</h2>
            <button id='flushBtn' onmousedown="FLUSHbegin();" onmouseup="FLUSHend();">Flush</button>
        </div>
    </div>

    <div id="mainControls" class="mainControlsRow deactiveSect">
        <h2 class="mainHdr">Maintenance Controls</h2>
    </div>

   
    <div class="battFluid">
       
        <!--COLUMN HEADERS-->
        <div class='headerRow'>
            <div class="topHeader">
                <h3 class="headerStyle under">Battery</h3>
            </div>

            <div class="topHeader">
                <h3 class="headerStyle under">Marrow</h3>
            </div>
        </div>
           
            <div id="battery0" class="battery">
            <div id="battery100" class="juice"></div>
        </div>
   
        <svg width="50px" height="50px" viewBox="0 0 100 150" class="battChgContainer">
            <polygon id="battChgContainer" stroke="gray" fill="grey" points="100,0 67,50 90,45 47,100 70,95 0,150 27,110 12,113 50,70 30,73 100,0" />
        </svg>
   
        <svg id="battLowContainer" width="120px" height="120px" viewBox="0 0 100 190" class="battLowContainer deactiveSect">
            <polygon stroke="gray" fill="#1A1A1C" points="85,151 85,110 100,110 105,105 110,100 115,95 115,50 100,50 100,20 85,20 85,50 65,50 65,20 50,20 50,50 35,50 35,95 40,100 45,105 50,110 65,110 65,151"></polygon>
        </svg>
       
        <h1 id="hdr100" class="hdr100">100%</h1>
       
        <!--FLUID GAUGE-->
        <table class="fluidGauge">
            <tr>
                <td>
                    <div style="width: 140px; height: 225px;" class="fluidReservoir blood">
                        <div class="tube">
                        </div>
                        <div class="liquid">
                            <div class="head">
                            </div>
                            <div id="fluidReservoirHeight" class="body">
                                <div class="drop large">
                                </div>
                                <div class="drop medium">
                                </div>
                                <div class="drop small">
                                </div>
                            </div>
                            <div class="tail">
                            </div>
                        </div>
                        <div class="glitter">
                        </div>
                    </div>
                </td>
            </tr>
        </table>
    </div>
   
    <!--COLUMN HEADERS-->
    <div class='headerRow'>
        <div class="header">
            <h3 class="headerStyle under">Left</h3>
        </div>

        <div class="header">
            <h3 class="headerStyle under">Sternum</h3>
        </div>

        <div class="header">
            <h3 class="headerStyle under">Right</h3>
        </div>
    </div>

    <!--MICROSWITCHES-->
    <div class='microswitchRow'>
        <div class="microswitchContainer">
            <div id="microC" class="microswitch white">
                <input type="radio" name="switchC" class="microswitchRadio" id="switchOffC" checked>
                <input type="radio" name="switchC" class="microswitchRadio" id="switchOnC">

                <label id="switchOffLabelC" for="switchOffC" class="headerStyle">Detached</label>
                <label id="switchOnLabelC" for="switchOnC" class="headerStyle deactiveSect">Attached</label>

                <span class="toggle"></span>
            </div>
        </div>
        <div class="microswitchContainer">
            <div id="microD" class="microswitch white">
                <input type="radio" name="switchD" class="microswitchRadio" id="switchOffD" checked>
                <input type="radio" name="switchD" class="microswitchRadio" id="switchOnD">

                <label id="switchOffLabelD" for="switchOffD" class="headerStyle">Detached</label>
                <label id="switchOnLabelD" for="switchOnD" class="headerStyle deactiveSect">Attached</label>

                <span class="toggle"></span>
            </div>
        </div>
        <div class="microswitchContainer">
            <div id="microE" class="microswitch white">
                <input type="radio" name="switchE" class="microswitchRadio" id="switchOffE" checked>
                <input type="radio" name="switchE" class="microswitchRadio" id="switchOnE">

                <label id="switchOffLabelE" for="switchOffE" class="headerStyle">Detached</label>
                <label id="switchOnLabelE" for="switchOnE" class="headerStyle deactiveSect">Attached</label>

                <span class="toggle"></span>
            </div>
        </div>
    </div>

    <!--VALVES-->
    <div class='valveRow'>
        <div class='valveContainer'>
            <img id="openValveC" src="openvalve.png" alt="open valve C" class="openValvePic">
            <img id="closedValveC" src="closedvalve.png" alt="closed valve C" class="deactiveSect closedValvePic">
        </div>
        <div class='valveContainer'>
            <img id="openValveD" src="openvalve.png" alt="open valve D" class="openValvePic deactiveSect">
            <img id="closedValveD" src="closedvalve.png" alt="closed valve D" class="closedValvePic">
        </div>
        <div class='valveContainer'>
            <img id="openValveE" src="openvalve.png" alt="open valve E" class="openValvePic">
            <img id="closedValveE" src="closedvalve.png" alt="closed valve E" class="deactiveSect closedValvePic">
        </div>
    </div>
   
    <!--PRESSURE GAUGES-->
    <div id="pGauges" class="pressureRow">
        <div class="pressureContainer pContainC">
            <div id="pGaugeC">
                <canvas id="pressureGaugeC" class="gauge"></canvas>
            </div>
           
            <div class="pGaugeText">
                <div class="bubble">
                    <div class="num"></div>
                    <div id="pgcValue" class="rotating">
                        0.00
                    </div>
                </div>
                <span class="psi">PSI</span>
            </div>
        </div>
        <div class="pressureContainer pContainD">
            <div id="pGaugeD">
                <canvas id="pressureGaugeD" class="gauge"></canvas>
            </div>
            <div class="pGaugeText">
                <div class="bubble">
                    <div class="num"></div>
                    <div id="pgdValue" class="rotating">
                        0.00
                    </div>
                </div>
                <span class="psi">PSI</span>
            </div>
        </div>
        <div class="pressureContainer pContainE">
            <div id="pGaugeE">
                <canvas id="pressureGaugeE" class="gauge"></canvas>
            </div>
            <div class="pGaugeText">
                <div class="bubble">
                    <div class="num"></div>
                    <div id="pgeValue" class="rotating">
                        0.00
                    </div>
                </div>
                <span class="psi">PSI</span>
            </div>
        </div>
    </div>
</div>
    <!--LED BUTTON-->
    <div style='background-color:#1E1E20; clear:both;'>
        <h3 class="headerStyle under">LED Controls</h3>
        <div id='LEDbtn' class='onoffswitch'>
            <input type='checkbox' name='onoffswitch' class='onoffswitch-checkbox' id='myonoffswitch' onclick='LEDswitch()'>
            <label class='onoffswitch-label' for='myonoffswitch'>
                <span class='onoffswitch-inner'></span>
                <span class='onoffswitch-switch'></span>
            </label>
        </div>
    </div>
   
    <script src="general.js"></script>
   
</body>

</html>
User avatar
By Th3On3Fr33man
#51481 Alright so I think I've solved most, if not all of my issues by updating the libraries, including using the git version of the esp8266 library found here: https://github.com/esp8266/Arduino

I also had to update my functions to match the example found in the new libraries.