Giter VIP home page Giter VIP logo

esp-fs-webserver's Introduction

If you like this work, please consider sponsoring this project!

esp-fs-webserver

From FSBrowser.ino example to esp-fs-webserver Arduino library

When you need a webserver running on ESP32 or ESP8266 device, FSBrowser.ino - ESP8266 or FSBrowser.ino - ESP32 are the best examples as start point because you can simply put your webserver HTML/CSS/JavaScript source files in the flash memory of device (for example with filesystem-type dedicated plugins like Arduino ESP8266 LittleFS Filesystem Uploader or Arduino ESP32 filesystem uploader) or in an external SD.

Unfortunately are a little complex examples for a novice due to a lot of handling functions "under the cover". This library makes it easier by incorporating this functions into a specific class and more, it adds some convenience functionality like WiFi / Custom Options manager.

Note: Starting from version 2.0.0 ESP32 core for Aruino introduced the LittlsFS library like ESP8266. The examples in this library is written to work with this for both platform by default. Change according to your needs if you prefer other filesystems.

WiFi, OTA firmware update and Options manager

Thanks to the built-in page /setup (about 8Kb of program space) it is possible to scan and set the WiFi credentials and other freely configurable parameters.

With /setup webpage it is also possible to perform remote firmware update (OTA-update).

image

This web page can be injected also with custom HTML and Javascript code in order to create very smart and powerful web application.

In the image below, for example, the HTML and Javascript code to provision the devices in the well-known ThingsBoard IoT platform has been added at runtime starting from the Arduino sketch (check example customHTML.ino).

image

Web server file upload

In addition to built-in firmware update functionality, you can also upload your web server content all at once (typically the files are placed inside the folder data of your sketch).

image

ACE web file editor/browser

Thanks to the built-in /edit page, it is possible to upload, delete and edit the HTML/CSS/JavaScript source files directly from browser and immediately display the changes introduced at runtime without having to recompile the device firmware. The page can be enabled at runtime using the method enableFsCodeEditor() and it occupies about 6.7Kb of program space.

image

esp-fs-webserver's People

Contributors

cotestatnt avatar github-actions[bot] avatar sjmf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

esp-fs-webserver's Issues

customOptions error

Hello,

I can not run the customOptions example on wemos d1 mini.

This error is in serial monitor:

02:54:25.747 ->
02:54:25.747 -> AP mode.
02:54:25.747 -> Server IP address: 192.168.4.1
02:54:25.747 ->
02:54:25.794 ->
02:54:25.794 -> This are the current values stored:
02:54:25.794 ->
02:54:25.794 -> LED pin value: 2
02:54:25.794 -> Bool value: true
02:54:25.794 -> Long value: 1234567890
02:54:25.794 -> Float value: 15.500
02:54:25.794 -> String value: Test option String
02:54:25.794 -> Dropdown selected value: Monday
02:54:25.794 ->
02:54:25.794 -> Application option loaded
02:54:25.837 ->
02:54:25.837 -> --------------- CUT HERE FOR EXCEPTION DECODER ---------------
02:54:25.837 ->
02:54:25.837 -> Exception (3):
02:54:25.837 -> epc1=0x4020a743 epc2=0x00000000 epc3=0x00000000 excvaddr=0x4025145e depc=0x00000000
02:54:25.837 ->
02:54:25.837 -> >>>stack>>>
02:54:25.837 ->
02:54:25.837 -> ctx: cont
02:54:25.837 -> sp: 3ffffc90 end: 3fffffd0 offset: 0190
02:54:25.837 -> 3ffffe20: 00000000 000003e8 4021241c 00000000
02:54:25.837 -> 3ffffe30: 00000000 00000000 3fff10cc 00000007
02:54:25.837 -> 3ffffe40: 3ffffe80 00000009 00000020 40100b50
02:54:25.837 -> 3ffffe50: 00000010 00000020 3ffffee0 3ffffed0
02:54:25.837 -> 3ffffe60: 3ffeef40 c7efffff e54daff8 40209ce4
02:54:25.837 -> 3ffffe70: 00000000 00000000 00000000 00000007
02:54:25.883 -> 3ffffe80: 00000010 00000001 3ffffee0 40216133
02:54:25.883 -> 3ffffe90: e54daff8 00000001 3ffffee0 4021645c
02:54:25.883 -> 3ffffea0: 3fff005c 3ffe8a45 3fff005c 40100b1c
02:54:25.883 -> 3ffffeb0: 3ffe8a45 00000009 3ffffee0 3ffffed0
02:54:25.883 -> 3ffffec0: 3ffeef40 c7efffff e54daff8 40209cd1
02:54:25.883 -> 3ffffed0: e54daff8 47efffff 00000000 3ff00000
02:54:25.883 -> 3ffffee0: 3fff005c 0010001f 8900002d 3fff11ba
02:54:25.883 -> 3ffffef0: 3fff178c 3fff18cc feefef00 feefeffe
02:54:25.883 -> 3fffff00: 3fff18bc 3fff181c feefef20 feefeffe
02:54:25.883 -> 3fffff10: 4021a4ac 00000000 0064616f 00000000
02:54:25.930 -> 3fffff20: feefeffe feefeffe feefeffe feefeffe
02:54:25.930 -> 3fffff30: feefeffe feefeffe feefeffe 4021a8b0
02:54:25.930 -> 3fffff40: 00000000 000003e8 00000000 00000000
02:54:25.930 -> 3fffff50: 00000000 00000000 402126f4 00000000
02:54:25.930 -> 3fffff60: 00000000 3ffef16c 00000000 0010001f
02:54:25.930 -> 3fffff70: 00000000 00000000 00000000 feefeffe
02:54:25.930 -> 3fffff80: feefeffe 4021a97c 0104a8c0 feefeffe
02:54:25.930 -> 3fffff90: 3ffffed0 3ffffe80 feefeffe feefeffe
02:54:25.930 -> 3fffffa0: feefeffe feefeffe feefeffe 3ffef374
02:54:25.930 -> 3fffffb0: 3fffdad0 00000000 3ffef348 40217790
02:54:25.978 -> 3fffffc0: feefeffe feefeffe 3fffdab0 40100df5
02:54:25.978 -> <<<stack<<<
02:54:25.978 ->
02:54:25.978 -> --------------- CUT HERE FOR EXCEPTION DECODER ---------------
02:54:25.978 ->
02:54:25.978 -> ets Jan 8 2013,rst cause:2, boot mode:(3,4)
02:54:25.978 ->
02:54:25.978 -> load 0x4010f000, len 3424, room 16
02:54:25.978 -> tail 0
02:54:25.978 -> chksum 0x2e
02:54:25.978 -> load 0x3fff20b8, len 40, room 8
02:54:25.978 -> tail 0
02:54:25.978 -> chksum 0x2b
02:54:25.978 -> csum 0x2b
02:54:25.978 -> v000607e0
02:54:25.978 -> ~ld

Thx for the help.

Disable Captive Portal??

How on earth do I disable the captive portal with this library? I'm using it in AP mode only, but it still presents the captive portal popup when I connect to it (which defaults to /setup) - but I want to disable this, I don't need it at all.

many thanks in advance

add multiple OptionBox

Hello,

i created a with addOptionBox like in the optionsExample.
is it possible to add multiple option sites with different settings?

Won't Store Wifi Credentials when Password is empty.

I figured I will open up a new issue with this. I was able to alter the code with your help so that the esp32 would connect to WIFI SSID that doesn't require a password. It worked perfectly. The issue now is it won't save that SSID or connect to it when I reset the esp32. Instead it sets up an AP right away after reset, as if there is no WIFI SSID stored that it can connect to.

Struggle in compiling your project

Hello cotestant.

thank you for this published project. Unfortunatly my knowledge is somehow to less to compile this project. I tested Arduino IDE and PlatformIO and goolged a lot. Found no workaround which worked.
Do you have a workaround for rookies?
Thanks
Ole

ESP32 could not convert '{"input", "INPUT 2", 2, 0}' from '<brace-enclosed initializer list>' to 'gpio_type'

I tried to compile the gpio_list-example for ESP32
and got this error
exit status 1
could not convert '{"input", "INPUT 2", 2, 0}' from '' to 'gpio_type'

first I thought this might be because the declaring of the array

gpio_type gpios[NUM_GPIOS] = {
  {"input", "INPUT 2", 2 },
  {"input", "INPUT 4", 4},
  {"input", "INPUT 5", 5},
  {"output", "OUTPUT 6", 6},
  {"output", "OUTPUT 7", 7},
  {"output", "LED BUILTIN", 3} // Led ON with signal HIGH (ESP32-C3)
};

is missing the fourth parameter
bool level = LOW;

// Define a struct for store all info about each gpio
struct gpio_type {
  const char* type;
  const char* label;
  int pin;
  bool level = LOW;
};

but this was mot the problem
I got the same compiler-error-message after adding the fourth parameter

gpio_type gpios[NUM_GPIOS] = {
  {"input", "INPUT 2", 2, LOW},
  {"input", "INPUT 4", 4, LOW},
  {"input", "INPUT 5", 5, LOW},
  {"output", "OUTPUT 6", 6, LOW},
  {"output", "OUTPUT 7", 7, LOW},
  {"output", "LED BUILTIN", 3, LOW} // Led ON with signal HIGH (ESP32-C3)
};

the astonishing thing is if I compile for an ESP8266 it does compile and the serial monitor shows how the ESP8266 connects to my WiFi but then the IP-adress is unavailable

Here is the compilerlog

gpio_list-ESP32-004:49:1: error: could not convert '{"input", "INPUT 2", 2, 0}' from '<brace-enclosed initializer list>' to 'gpio_type' }; ^ gpio_list-ESP32-004:49:1: error: could not convert '{"input", "INPUT 4", 4, 0}' from '<brace-enclosed initializer list>' to 'gpio_type' gpio_list-ESP32-004:49:1: error: could not convert '{"input", "INPUT 5", 5, 0}' from '<brace-enclosed initializer list>' to 'gpio_type' gpio_list-ESP32-004:49:1: error: could not convert '{"output", "OUTPUT 6", 6, 0}' from '<brace-enclosed initializer list>' to 'gpio_type' gpio_list-ESP32-004:49:1: error: could not convert '{"output", "OUTPUT 7", 7, 0}' from '<brace-enclosed initializer list>' to 'gpio_type' gpio_list-ESP32-004:49:1: error: could not convert '{"output", "LED BUILTIN", 3, 0}' from '<brace-enclosed initializer list>' to 'gpio_type' Mehrere Bibliotheken wurden für "WiFi.h" gefunden Benutzt: C:\Users\dipl-\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi Nicht benutzt: E:\Arduino-funktioniert\arduino-1.8.19-windows-2022-01-30\arduino-1.8.19\libraries\WiFi Mehrere Bibliotheken wurden für "ArduinoJson.h" gefunden Benutzt: F:\myData\Arduino\libraries\ArduinoJson Nicht benutzt: E:\Arduino-funktioniert\arduino-1.8.19-windows-2022-01-30\arduino-1.8.19\libraries\ArduinoJson Mehrere Bibliotheken wurden für "WebSocketsServer.h" gefunden Benutzt: F:\myData\Arduino\libraries\WebSockets Nicht benutzt: E:\Arduino-funktioniert\arduino-1.8.19-windows-2022-01-30\arduino-1.8.19\libraries\WebSockets Bibliothek WebSockets in Version 2.3.6 im Ordner: F:\myData\Arduino\libraries\WebSockets wird verwendet Bibliothek WiFi in Version 1.0 im Ordner: C:\Users\dipl-\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi wird verwendet Bibliothek WiFiClientSecure in Version 1.0 im Ordner: C:\Users\dipl-\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFiClientSecure wird verwendet Bibliothek esp-fs-webserver in Version 1.1.3 im Ordner: F:\myData\Arduino\libraries\esp-fs-webserver wird verwendet Bibliothek FS in Version 1.0 im Ordner: C:\Users\dipl-\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\FS wird verwendet Bibliothek ArduinoJson in Version 6.19.4 im Ordner: F:\myData\Arduino\libraries\ArduinoJson wird verwendet Bibliothek WebServer in Version 1.0 im Ordner: C:\Users\dipl-\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WebServer wird verwendet Bibliothek ESPmDNS in Version 1.0 im Ordner: C:\Users\dipl-\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\ESPmDNS wird verwendet Bibliothek HTTPUpdateServer in Version 1.0 im Ordner: C:\Users\dipl-\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\HTTPUpdateServer wird verwendet Bibliothek SPIFFS in Version 1.0 im Ordner: C:\Users\dipl-\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\SPIFFS wird verwendet Bibliothek Update in Version 1.0 im Ordner: C:\Users\dipl-\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\Update wird verwendet Bibliothek DNSServer in Version 1.1.0 im Ordner: C:\Users\dipl-\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\DNSServer wird verwendet Bibliothek LittleFS_esp32 in Version 1.0.6 im Ordner: F:\myData\Arduino\libraries\LittleFS_esp32 wird verwendet exit status 1 could not convert '{"input", "INPUT 2", 2, 0}' from '<brace-enclosed initializer list>' to 'gpio_type'

best regards Stefan

Crash loading examples

I've tried several of the examples and they all seem to crash and reboot... I've tried with and without config.json files, empty file, just an empty json object... all result in the same failure.

Hard resetting via RTS pin...
--- Terminal on /dev/cu.wchusbserial10 | 115200 8-N-1
--- Available filters and text transformations: colorize, debug, default, direct, esp32_exception_decoder, hexlify, log2file, nocontrol, printable, send_on_enter, time
--- More details at https://bit.ly/pio-monitor-filters
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H

/
|__ favicon.ico         (1150 bytes)
|__ index.htm   (2004 bytes)

/css
|__ pico.fluid.classless.css.gz         (5387 bytes)

/img
|__ espressif.jpg       (34305 bytes)

/setup
|__ config.json         (0 bytes)

[E][.pio/libdeps/esp32dev/esp-fs-webserver/src/esp-fs-webserver.cpp:228] startWiFi():   Failed to deserialize file, may be corrupted
 EmptyInput

[I][.pio/libdeps/esp32dev/esp-fs-webserver/src/esp-fs-webserver.cpp:208] startAP():     AP mode.
Server IP address: 8.8.8.8Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.

Core  1 register dump:
PC      : 0x400dad5b  PS      : 0x00060130  A0      : 0x800dc2d5  A1      : 0x3ffb2110  
A2      : 0x00000038  A3      : 0x3ffb2148  A4      : 0x3f4012b1  A5      : 0x3f41161f  
A6      : 0x00000000  A7      : 0x3f400317  A8      : 0x80167520  A9      : 0x3ffb2100  
A10     : 0x00000001  A11     : 0x00000000  A12     : 0x00000000  A13     : 0x00000000  
A14     : 0xffffbfff  A15     : 0x3f4012b1  SAR     : 0x00000013  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000040  LBEG    : 0x400e8ccc  LEND    : 0x400e8d12  LCOUNT  : 0x0000003c  


Backtrace: 0x400dad58:0x3ffb2110 0x400dc2d2:0x3ffb2140 0x400dc3a3:0x3ffb2190 0x400d23e6:0x3ffb2230 0x400df0de:0x3ffb2290




ELF file SHA256: 89734c2ea7361308

Rebooting...

Difficult to load web-based configuration when the Wifi AP disappears for a long time after connected

Hi @cotestatnt

  1. I tried examples/customHTML on esp8266
    after scanning and connecting to one of the detected Wifi networks, esp8226 gets an IP address

I tried turning off the wifi network router for a long time, so esp8266 would be WiFi.status() != WL_CONNECTED

I noticed if the esp8266 doesn't connect then it will try to reconnect, and if it fails then it will go into WIFI_AP mode
so wifi network 'ESP_AP' will reappear

but when my laptop is connected to the 'ESP_AP' of esp8266, I'm having trouble opening the web-based configuration on 192.168.4.1
but when i turn on wifi network router, web based configuration can open

is there a blocking function that makes the web based configuration unopenable??

  1. Is it possible if WIFI_AP_STA mode is always active in all conditions, so we won't depend on the serial terminal to know the IP address if esp8266 is connected to Wifi Network

Thanks

Reducing filesystem access

[FEATURE REQUEST]

I love your lib, and i implement much options with it.
But due the ammount of options the access to the filesystem is horrible.
With all addOption and getOptionValue i get a total of 85 times opening the config.json file. Wich cause in a boottime of arround 25 seconds only for these operations on a ESP32 with maximum clock of 240mhz.

is it possible to open the file and create the JsonDocument once?

default site

Hi,
is there a way to set the default website to something else than /edit? For example to /index.html?

Bool options are not saved

bool options, wich will be displayed as switches
image

are not saved into the config.json. after i hit "save configuration" i check the config.json and the value is always false

simpleServer - invalid conversion from...

Hi,

I wanna try the simpleServer example with an ESP32 and I get the compile error:

invalid conversion from 'const char*' to 'int' [-fpermissive]

at the line
myWebServer.addHandler("/led", HTTP_GET, handleLed);

Where is my mistake?

ESP8266 / ESP32 webserver ace js tryit alike live preview

hello

i am using ace on ESP8266 / ESP32 webserver
for wifi relais switches
i would like to ad live html preview to the ace code text editor (tryit codepen jsfiddle alike)

like https://github.com/geard-dev/web-based-live-code-editor
demo https://live-editor.js.org/html.html

but i do not now how to implement it in my editor code

is there anyone that can help me?

Greet Luberth
https://github.com/ldijkman/randomnerd_esp32_wifi_manager/tree/main/LAB_Experiments

<!DOCTYPE html>
<html lang="en">
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Electra's ESP Editor</title>
<link rel="apple-touch-icon" href="/ace.ico" type="image/x-icon">
<link rel="shortcut icon" href="/ace.ico" type="image/x-icon">
<link rel="icon" href="/ace.ico" type="image/x-icon">
<style type="text/css" media="screen">
  label {
    font-size: 12px;
    font-family: sans-serif
  }

  .cm {
    z-index: 300;
    position: absolute;
    left: 5px;
    border: 1px solid #444;
    background-color: #f5f5f5;
    display: none;
    box-shadow: 0 0 10px rgba(0, 0, 0, .4);
    font-size: 12px;
    font-family: sans-serif;
    font-weight: 700
  }

  .cm ul {
    list-style: none;
    top: 0;
    left: 0;
    margin: 0;
    padding: 0
  }

  .cm li {
    position: relative;
    min-width: 60px;
    cursor: pointer
  }

  .cm span {
    color: #444;
    display: inline-block;
    padding: 6px
  }

  .cm li:hover {
    background: #444
  }

  .cm li:hover span {
    color: #eee
  }

  .tvu li,
  .tvu ul {
    padding: 0;
    margin: 0;
    list-style: none
  }

  .tvu input {
    position: absolute;
    opacity: 0
  }

  .tvu {
    font: 400 12px Verdana, Arial, Sans-serif;
    -moz-user-select: none;
    -webkit-user-select: none;
    user-select: none;
    color: #444;
    line-height: 16px
  }

  .tvu span {
    margin-bottom: 5px;
    padding: 0 0 0 18px;
    cursor: pointer;
    display: inline-block;
    height: 16px;
    vertical-align: middle;
    background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAADoSURBVBgZBcExblNBGAbA2ceegTRBuIKOgiihSZNTcC5LUHAihNJR0kGKCDcYJY6D3/77MdOinTvzAgCw8ysThIvn/VojIyMjIyPP+bS1sUQIV2s95pBDDvmbP/mdkft83tpYguZq5Jh/OeaYh+yzy8hTHvNlaxNNczm+la9OTlar1UdA/+C2A4trRCnD3jS8BB1obq2Gk6GU6QbQAS4BUaYSQAf4bhhKKTFdAzrAOwAxEUAH+KEM01SY3gM6wBsEAQB0gJ+maZoC3gI6iPYaAIBJsiRmHU0AALOeFC3aK2cWAACUXe7+AwO0lc9eTHYTAAAAAElFTkSuQmCC) no-repeat;
    background-position: 0 0
  }

  .tvu span:hover {
    text-decoration: underline
  }

  @media screen and (-webkit-min-device-pixel-ratio:0) {
    .tvu {
      -webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s
    }

    @-webkit-keyframes webkit-adjacent-element-selector-bugfix {
      from {
        padding: 0
      }

      to {
        padding: 0
      }
    }
  }

  #uploader {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    height: 28px;
    line-height: 24px;
    padding-left: 10px;
    background-color: #444;
    color: #eee
  }

  #tree {
    position: absolute;
    top: 28px;
    bottom: 0;
    left: 0;
    width: 160px;
    padding: 8px
  }

  #editor,
  #preview {
    position: absolute;
    top: 28px;
    right: 0;
    bottom: 0;
    left: 160px;
    border-left: 1px solid #eee
  }

  #preview {
    background-color: #eee;
    padding: 5px
  }

  #loader {
    position: absolute;
    top: 36%;
    right: 40%
  }

  .loader {
    z-index: 10000;
    border: 8px solid #b5b5b5;
    border-top: 8px solid #3498db;
    border-bottom: 8px solid #3498db;
    border-radius: 50%;
    width: 240px;
    height: 240px;
    animation: spin 2s linear infinite;
    display: none
  }

  @keyframes spin {
    0% {
      transform: rotate(0)
    }

    100% {
      transform: rotate(360deg)
    }
  }
</style>
<script>
  function ge(e) {
    return document.getElementById(e)
  }

  function ce(e) {
    return document.createElement(e)
  }

  function sortByKey(e, t) {
    return e.sort((function(e, n) {
      var a = e[t],
        i = n[t];
      return i > a ? -1 : a > i ? 1 : 0
    }))
  }

  function createFileUploader(e, t, n) {
    var a = /(iPhone)*(OS ([7-9]|1[0-1])_)/i.test(navigator.userAgent);

    function i(e, n) {
      200 != e ? alert("ERROR[" + e + "]: " + n) : t.refreshPath(d.value)
    }
    var o = ce("button");
    o.innerHTML = "Root Dir", ge(e).appendChild(o);
    var c = ce("input");
    c.type = "file", c.multiple = !1, c.name = "data", c.id = "upload-select", ge(e).appendChild(c);
    var d = ce("input");
    d.id = "upload-path", d.type = "text", d.name = "path", d.defaultValue = "/", ge(e).appendChild(d);
    var s = ce("button");
    s.innerHTML = "Upload", ge(e).appendChild(s);
    var r = ce("button");
    r.innerHTML = "Create", ge(e).appendChild(r);
    var l = ce("input");
    l.id = "editor-filename", l.type = "text", l.disabled = !0, l.size = 20, ge(e).appendChild(l);
    var u = ce("input");
    u.id = "ipad-fix", u.name = "ipad-fix", u.type = "checkbox", u.checked = !!a;
    var p = ce("label");
    p.for = u.id, p.innerHTML = " Alt.";
    var m = ce("button");
    m.innerHTML = " Save ", ge(e).appendChild(m), ge(e).appendChild(p), ge(e).appendChild(u), r.onclick = function(e) {
      (function(e) {
        var t = new FormData;
        t.append("path", e), requests.add("PUT", "/edit", t, i)
      })(d.value), n.loadUrl(d.value), d.value = "/"
    }, m.onclick = function(e) {
      if (u.checked) {
        var t = ace.edit("editor").getValue(),
          a = new FormData;
        a.append("rawname", l.value);
        var o = 0;
        const e = 4096;
        for (var c = 0; c < t.length; c += e) {
          var d = t.substring(c, c + e);
          a.append("raw" + o, d), o++
        }
        requests.add("POST", "/edit", a, i)
      } else n.execCommand("saveCommand")
    }, o.onclick = function(e) {
      t.refreshPath(d.value)
    }, s.onclick = function(e) {
      if (0 !== c.files.length) {
        var t = new FormData;
        t.append("data", c.files[0], d.value), requests.add("POST", "/edit", t, i), ge("upload-path").value = "/", ge("upload-select").value = ""
      }
    }, c.onchange = function(e) {
      if (0 !== c.files.length) {
        var t = c.files[0].name,
          n = /(?:\.([^.]+))?$/.exec(t)[1],
          a = /(.*)\.[^.]+$/.exec(t)[1];
        void 0 !== typeof a && (t = a), d.value = "/" + t + "." + n
      }
    }
  }

  function createTree(e, t) {
    function n(e) {
      ge("editor-filename").value = e, ge("editor").style.display = "none", p.style.display = "block", p.innerHTML = '<img src="/edit?edit=' + e + "&_cb=" + Date.now() + '" style="max-width:100%; max-height:100%; margin:auto; display:block;" />'
    }

    function a(e, a) {
      var i = ce("ul");
      e.appendChild(i);
      var o = ce("li");
      i.appendChild(o), s(a) ? (o.innerHTML = "<span>Preview</span>", o.onclick = function(t) {
        n(a), document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(e)
      }) : d(a) && (o.innerHTML = "<span>Edit</span>", o.onclick = function(n) {
        t.loadUrl(a), document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(e)
      });
      var l = ce("li");
      i.appendChild(l), d(a) || s(a) || function(e) {
        var t = /(?:.([^.]+))?$/.exec(e)[1];
        if (void 0 !== typeof t) switch (t) {
          case "ico":
          case "gz":
          case "zip":
          case "wav":
          case "mp3":
          case "pdf":
            return !0
        }
        return !1
      }(a) ? (l.innerHTML = "<span>Download</span>", l.onclick = function(t) {
        (function(e) {
          ge("download-frame").src = "/edit?download=" + e
        })(a), document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(e)
      }) : c(a) && (i.appendChild(l), l.innerHTML = "<span>ChDir</span>", l.onclick = function(t) {
        m.removeChild(m.childNodes[0]), u(m, a), document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(e)
      });
      var p = ce("li");
      i.appendChild(p), p.innerHTML = "<span>Delete</span>", p.onclick = function(t) {
        r(a), document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(e)
      }
    }

    function i(e, t, n) {
      var i = ce("div"),
        o = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop,
        c = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft,
        d = e.clientX + c,
        s = e.clientY + o;
      i.className = "cm", i.style.display = "block", i.style.left = d + "px", i.style.top = s + "px", a(i, t), document.body.appendChild(i);
      var r = i.offsetWidth,
        l = i.offsetHeight;
      i.onmouseout = function(e) {
        (e.clientX < d || e.clientX > d + r || e.clientY < s || e.clientY > s + l) && document.body.getElementsByClassName("cm").length > 0 && document.body.removeChild(i)
      }
    }

    function o(e, a, o) {
      var r = ce("li");
      r.id = a;
      var l = ce("span");
      return l.innerHTML = a, r.appendChild(l), r.onclick = function(e) {
        d(r.id.toLowerCase()) ? t.loadUrl(r.id) : s(r.id.toLowerCase()) ? n(r.id) : c(r.id) && (m.removeChild(m.childNodes[0]) && u(m, r.id.toLowerCase()))
      }, r.oncontextmenu = function(e) {
        e.preventDefault(), e.stopPropagation(), i(e, r.id)
      }, r
    }

    function c(e) {
      return -1 == e.indexOf(".")
    }

    function d(e) {
      var t = /(?:.([^.]+))?$/.exec(e)[1];
      if (void 0 !== typeof t) switch (t) {
        case "txt":
        case "htm":
        case "html":
        case "js":
        case "css":
        case "xml":
        case "json":
        case "conf":
        case "ini":
        case "h":
        case "c":
        case "cpp":
        case "php":
        case "hex":
        case "ino":
        case "pde":
          return !0
      }
      return !1
    }

    function s(e) {
      var t = /(?:.([^.]+))?$/.exec(e)[1];
      if (void 0 !== typeof t) switch (t) {
        case "png":
        case "jpg":
        case "gif":
        case "bmp":
          return !0
      }
      return !1
    }

    function r(e) {
      var t = new FormData;
      t.append("path", e), requests.add("DELETE", "/edit", t, (function(e, t) {
        200 != e ? alert("ERROR[" + e + "]: " + t) : (m.removeChild(m.childNodes[0]), u(m, "/"))
      }))
    }

    function l(e, t) {
      return function(t, n) {
        200 == t && function(e, t, n) {
          sortByKey(n, "name");
          var a = ce("ul");
          e.appendChild(a);
          for (var i = n.length, c = 0; i > c; c++) "file" === n[c].type && a.appendChild(o(0, n[c].name, n[c].size))
        }(e, 0, JSON.parse(n))
      }
    }

    function u(e, t) {
      requests.add("GET", "/edit", {
        list: t
      }, l(e))
    }
    var p = ge("preview"),
      m = ce("div");
    return m.className = "tvu", ge(e).appendChild(m), this.refreshPath = function(e) {
      m.removeChild(m.childNodes[0]), u(m, "/")
    }, u(m, "/"), this
  }

  function createEditor(e, t, n, a, i) {
    function o(e) {
      var t = "plain",
        n = /(?:.([^.]+))?$/.exec(e)[1];
      if (void 0 !== typeof n) switch (n) {
        case "txt":
        case "hex":
        case "conf":
          t = "plain";
          break;
        case "htm":
          t = "html";
          break;
        case "js":
          t = "javascript";
          break;
        case "h":
        case "c":
        case "cpp":
          t = "c_cpp";
          break;
        case "css":
        case "scss":
        case "php":
        case "html":
        case "json":
        case "xml":
        case "ini":
          t = n
      }
      return t
    }

    function c(e, t) {
      200 != e && alert("ERROR[" + e + "]: " + t)
    }

    function d(e, t) {
      ge("preview").style.display = "none", ge("editor").style.display = "block", 200 == e ? s.setValue(t) : s.setValue(""), s.clearSelection()
    }
    void 0 === t && (t = "/my_edit.html"), void 0 === n && (n = o(t)), void 0 === a && (a = "monokai"), void 0 === i && (i = "text/" + n, "c_cpp" === n && (i = "text/plain"));
    var s = ace.edit(e);
    return "plain" !== n && s.getSession().setMode("ace/mode/" + n), s.setTheme("ace/theme/" + a), s.$blockScrolling = 1 / 0, s.getSession().setUseSoftTabs(!0), s.getSession().setTabSize(2), s.getSession().setUseWorker(!0), s.setHighlightActiveLine(!0), s.setShowPrintMargin(!1), s.commands.addCommand({
      name: "saveCommand",
      bindKey: {
        win: "Ctrl-S",
        mac: "Command-S"
      },
      exec: function(e) {
        ! function(e, t, n) {
          var a = new FormData;
          a.append("data", new Blob([t], {
            type: n
          }), e), requests.add("POST", "/edit", a, c)
        }(t, e.getValue() + "", i)
      },
      readOnly: !1
    }), s.commands.addCommand({
      name: "undoCommand",
      bindKey: {
        win: "Ctrl-Z",
        mac: "Command-Z"
      },
      exec: function(e) {
        e.getSession().getUndoManager().undo(!1)
      },
      readOnly: !1
    }), s.commands.addCommand({
      name: "redoCommand",
      bindKey: {
        win: "Ctrl-Shift-Z",
        mac: "Command-Shift-Z"
      },
      exec: function(e) {
        e.getSession().getUndoManager().redo(!1)
      },
      readOnly: !1
    }), s.loadUrl = function(e) {
      ge("editor-filename").value = e, n = o(t = e), i = "text/" + n, "plain" !== n && s.getSession().setMode("ace/mode/" + n),
        function(e) {
          requests.add("GET", "/edit", {
            edit: e
          }, d)
        }(t)
    }, s
  }

  function onBodyLoad() {
    var e = {},
      t = (window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, (function(t, n, a) {
        e[n] = a
      })), createEditor("editor", e.file, e.lang, e.theme)),
      n = createTree("tree", t);
    window.define = ace.define, window.require = ace.require, ace.config.set("basePath", "/"), ace.config.set("workerPath", "/"), createFileUploader("uploader", n, t), void 0 === e.file && (e.file = "/my_edit.html"), t.loadUrl(e.file)
  }
  "undefined" == typeof XMLHttpRequest && (XMLHttpRequest = function() {
    try {
      return new ActiveXObject("Msxml2.XMLHTTP.6.0")
    } catch (e) {}
    try {
      return new ActiveXObject("Msxml2.XMLHTTP.3.0")
    } catch (e) {}
    try {
      return new ActiveXObject("Microsoft.XMLHTTP")
    } catch (e) {}
    throw new Error("This browser does not support XMLHttpRequest.")
  });
  var QueuedRequester = function() {
    this.queue = [], this.running = !1, this.xmlhttp = null
  };
  QueuedRequester.prototype = {
    _request: function(e) {
      if (this.running = !0, !(!e instanceof Object)) {
        var t = this;
        ge("loader").style.display = "block";
        var n = "";
        if (e.params instanceof FormData) n = e.params;
        else if (e.params instanceof Object)
          for (var a in e.params) n += "" === n ? "GET" === e.method ? "?" : "" : "&", n += encodeURIComponent(a) + "=" + encodeURIComponent(e.params[a]);
        this.xmlhttp = new XMLHttpRequest, this.xmlhttp.onreadystatechange = function(e, n) {
          return function() {
            4 == e.readyState && (ge("loader").style.display = "none", n.callback(e.status, e.responseText), 0 === t.queue.length && (t.running = !1), t.running && t._request(t.queue.shift()))
          }
        }(this.xmlhttp, e), "GET" === e.method ? (this.xmlhttp.open(e.method, e.url + n, !0), this.xmlhttp.send()) : (this.xmlhttp.open(e.method, e.url, !0), n instanceof String && this.xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"), this.xmlhttp.send(n))
      }
    },
    stop: function() {
      this.running && (this.running = !1), this.xmlhttp && this.xmlhttp.readyState < 4 && this.xmlhttp.abort()
    },
    add: function(e, t, n, a) {
      this.queue.push({
        url: t,
        method: e,
        params: n,
        callback: a
      }), this.running || this._request(this.queue.shift())
    }
  };
  var requests = new QueuedRequester
</script>
<script id="ace" src="/acefull.js" charset="utf-8"></script>
<script>
  if (void 0 === ace.edit) {
    var script = document.createElement("script");
    script.src = "/ace.js", script.async = !1, document.head.appendChild(script)
  }
</script>

<body onload="onBodyLoad()">
  <div id="loader" class="loader"></div>
  <div id="uploader"></div>
  <div id="tree"></div>
  <div id="editor"></div>
  <div id="preview" style="display:none"></div><iframe id="download-frame" style="display:none"></iframe>

above code results in next screenshot (running on ESP32 webserver http://garage.local/edit)

2022-07-09-112711_1920x1080_scrot

would like to have a live html preview panel added
like demo on https://github.com/geard-dev/web-based-live-code-editor
demo https://live-editor.js.org/html.html

2022-07-09-114956_1920x1080_scrot

Feature Request : Add WiFi PEAP Auth

Just discovered this awesome lib, until there was using ESPAsync, but will migrate to this one.

Would it be complicated to add option to have PEAP WiFi option? (adding one field on WebServer WiFi option)

We're in a company building where wifi is not open but works with PEAP, on Arduino ESP32 we just do something like that and it's working fine, not sure how to achieve here.

  // we got PEAP Auth config?
  if (EAPname!="" && EAPuser!="" && EAPpass!="" ) {
    WiFi.begin(EAPname, WPA2_AUTH_PEAP, EAPuser, EAPuser, EAPpass);
    // wait 30s to connect
    if (!checkAPConnection(30)) {
      Serial.print("Failed to connect using PEAP Auth, fallback to classic");
    }
  }

  // in case PEAP failed or not configured, just use classic WiFi SSID/Pass
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin(APname, APpass);
    connected = checkAPConnection(45);
  }

Thanks

How to update variable value on custom html example?

Hi @cotestatnt

  1. I implement your sugestion on this and its work perfectly, so I try to other value like sensor DHT22. I want to show its value on custom_html, and the value update every 5 second without refresh webpage. I try to add some code to HTML
setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("label1").innerHTML = this.responseText;
      }
    };
    xhttp.open("GET", "/temperature", true);
    xhttp.send();
}, 5000 ) ;

but fail. Can you give me a hint to do that??

  1. How to erase input previous settings every time I upload sketch?
  2. When I try examples/simpleServer >> upload littleFS data, and then I try examples/customHTML, the previous HTML simpleServer still exist. How to reset it?

Thanks

Is possible to add more than one custom_html?

hi @cotestatnt

I want to add 2 custom addOptionBox,

I try this on sketch,

  myWebServer.addOptionBox("Summary Result");
  myWebServer.addHTML(custom_html1, "fetch-test", /*overwite*/ true);
  myWebServer.addCSS(custom_css, /*overwite*/ false);
  myWebServer.addJavascript(custom_script, /*overwite*/ false);
  
  myWebServer.addOptionBox("About Me");
  myWebServer.addHTML(custom_html2, "fetch-test", /*overwite*/ true);
  myWebServer.addCSS(custom_css, /*overwite*/ false);
  myWebServer.addJavascript(custom_script, /*overwite*/ false);

and this on customelement.h

static const char custom_html1[] PROGMEM = R"EOF(
    <main class="container">
      <article class="grid">
        <div>
          <p id="esp1">T E S T 1</p>
        </div>
      </article>
    </main>
)EOF";

static const char custom_html2[] PROGMEM = R"EOF(
    <main class="container">
      <article class="grid">
        <div>
          <p id="esp2">T E S T 2</p>
        </div>
      </article>
    </main>
)EOF";

but the page is only show on last option box
Is possible to add more than one custom_html on different optionBox?

thanks

How to show json value to custom html page?

Hi @cotestatnt

I want to show json value to customElement.h every first time I open the page.
I found this from you and I follow the instruction

so I add handler and function to customHTML.ino like this

#include <esp-fs-webserver.h>   // https://github.com/cotestatnt/esp-fs-webserver

#include <FS.h>
#include <LittleFS.h>
#define FILESYSTEM LittleFS

#ifndef LED_BUILTIN
#define LED_BUILTIN 2
#endif

// Set this to 1 if you want clear the /config.json file at startup
#define CLEAR_OTIONS 0

struct tm sysTime;

// Test "options" values
uint8_t ledPin = LED_BUILTIN;
bool boolVar = true;
uint32_t longVar = 1234567890;
float floatVar = 15.5F;
String stringVar = "Test option String";

// ThingsBoard varaibles
String tb_deviceToken = "xxxxxxxxxxxxxxxxxxx";
String tb_device_key = "xxxxxxxxxxxxxxxxxxx";
String tb_secret_key = "xxxxxxxxxxxxxxxxxxx";
String tb_serverIP = "192.168.1.1";
uint16_t tb_port = 8181;

// Var labels (in /setup webpage)
#define LED_LABEL "The LED pin number"
#define BOOL_LABEL "A bool variable"
#define LONG_LABEL "A long variable"
#define FLOAT_LABEL "A float variable"
#define STRING_LABEL "A String variable"

#define TB_SERVER "ThingsBoard server address"
#define TB_PORT "ThingsBoard server port"
#define TB_DEVICE_TOKEN "ThingsBoard device token"
#define TB_DEVICE_KEY "Provisioning device key"
#define TB_SECRET_KEY "Provisioning secret key"

// Timezone definition to get properly time from NTP server
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"
struct tm Time;

#ifdef ESP8266
ESP8266WebServer server(80);
#elif defined(ESP32)
WebServer server(80);
#endif

FSWebServer myWebServer(FILESYSTEM, server);

#include "customElements.h"

////////////////////////////////  Filesystem  /////////////////////////////////////////
void startFilesystem() {
  // FILESYSTEM INIT
  if ( FILESYSTEM.begin()) {
    File root = FILESYSTEM.open("/", "r");
    File file = root.openNextFile();
    while (file) {
      const char* fileName = file.name();
      size_t fileSize = file.size();
      Serial.printf("FS File: %s, size: %lu\n", fileName, (long unsigned)fileSize);
      file = root.openNextFile();
    }
    Serial.println();
  }
  else {
    Serial.println(F("ERROR on mounting filesystem. It will be formmatted!"));
    FILESYSTEM.format();
    ESP.restart();
  }
}

bool loadOptions() {
  if (FILESYSTEM.exists(myWebServer.configFile())) {
    File file = FILESYSTEM.open(myWebServer.configFile(), "r");
    DynamicJsonDocument doc(file.size() * 1.33);
    if (!file)
      return false;

    DeserializationError error = deserializeJson(doc, file);
    if (error)
      return false;

    ledPin = doc[LED_LABEL];
    boolVar = doc[BOOL_LABEL];
    longVar = doc[LONG_LABEL];
    floatVar = doc[FLOAT_LABEL]["value"];
    stringVar = doc[STRING_LABEL].as<String>();

    tb_deviceToken = doc[TB_DEVICE_TOKEN].as<String>();
    tb_device_key = doc[TB_DEVICE_KEY].as<String>();
    tb_secret_key = doc[TB_SECRET_KEY].as<String>();
    tb_serverIP = doc[TB_SERVER].as<String>();
    tb_port = doc[TB_PORT];

    file.close();

    Serial.println();
    Serial.printf("LED pin value: %d\n", ledPin);
    Serial.printf("Bool value: %d\n", boolVar);
    Serial.printf("Long value: %ld\n",longVar);
    Serial.printf("Float value: %d.%d\n", (int)floatVar, (int)(floatVar*1000)%1000);
    Serial.println(stringVar);
    return true;
  }
  else
    Serial.println(F("Configuration file not exist"));
  return false;
}

void setup() {
  Serial.begin(115200);

  // FILESYSTEM INIT
  startFilesystem();

  // Load configuration (if not present, default will be created when webserver will start)
#if CLEAR_OPTIONS
  if (myWebServer.clearOptions())
    ESP.restart();
#endif
  if (loadOptions())
    Serial.println(F("Application option loaded\n\n"));
  else
    Serial.println(F("Application options NOT loaded!\n\n"));

  // Configure /setup page and start Web Server

  // Add a new options box
  myWebServer.addOptionBox("My Options");
  myWebServer.addOption(LED_LABEL, ledPin);
  myWebServer.addOption(LONG_LABEL, longVar);
  // Float fields can be configured with min, max and step properties
  myWebServer.addOption(FLOAT_LABEL, floatVar, 0.0, 100.0, 0.01);
  myWebServer.addOption(STRING_LABEL, stringVar);
  myWebServer.addOption(BOOL_LABEL, boolVar);

  // Add a new options box
  myWebServer.addOptionBox("ThingsBoard");
  myWebServer.addOption(TB_SERVER, tb_serverIP);
  myWebServer.addOption(TB_PORT, tb_port);
  myWebServer.addOption(TB_DEVICE_KEY, tb_device_key);
  myWebServer.addOption(TB_SECRET_KEY, tb_secret_key);
  myWebServer.addOption(TB_DEVICE_TOKEN, tb_deviceToken);

  // Add a new options box with custom code injected
  myWebServer.addOptionBox("Custom HTML");
  // How many times you need (for example one in different option box)
  myWebServer.addHTML(custom_html, "fetch-test", /*overwite*/ true);
  // Only once (CSS and Javascript will be appended to head and body)
  myWebServer.addCSS(custom_css, /*overwite*/ false);
  myWebServer.addJavascript(custom_script, /*overwite*/ false);

  // Try to connect to stored SSID, start AP if fails after timeout
  IPAddress myIP = myWebServer.startWiFi(15000, "ESP_AP", "123456789" );
  myWebServer.addHandler("/getValues", HTTP_GET, getActualValue);
  
  // Start webserver
  if (myWebServer.begin()) {
    Serial.print(F("\nESP Web Server started on IP Address: "));
    Serial.println(myIP);
    Serial.println(F("Open /setup page to configure optional parameters"));
    Serial.println(F("Open /edit page to view and edit files"));
    Serial.println(F("Open /update page to upload firmware and filesystem updates\n\n"));
  }
}


void loop() {
  myWebServer.run();
}

void getActualValue() {
  StaticJsonDocument<256> doc;
  String payload;
  doc["sunrise"] = "08:00";
  doc["sunset"] = "20:00";
  doc["automatic"] = true;
  serializeJsonPretty(doc, payload);
  // Send payoad to client
  myWebServer.webserver->send(200, "text/json", payload);
}

and add script to customElement.h like this

static const char custom_html[] PROGMEM = R"EOF(
<main onload="getActualValues()">
  <h3>Test Static Json Value</h3>
  <p id="sunrise-actual">xxxx</p> 
  <p id="sunset-actual">xxxx</p> 
</main>
)EOF";


static const char custom_css[] PROGMEM = R"EOF(
pre{
    font-family: Monaco,Menlo,Consolas,'Courier New',monospace;
    color: #333;
    line-height: 20px;
    background-color: #f5f5f5;
    border: 1px solid rgba(0,0,0,0.15);
    border-radius: 6px;
    overflow-y: scroll;
    min-height: 350px;
    font-size: 85%;
}
.select{
  width: 25%;
  height:40px;
  padding-top: 10px;
  padding-left: 20px;
  border:1px solid #ccc;
  border-radius: 6px;
  box-shadow: 0 1px 2px 0 rgba(220, 220, 230, 0.5);
}
.body{
  background-color: cadetblue;
}
)EOF";

static const char custom_script[] PROGMEM = R"EOF(
function fetchEndpoint() {
  var mt = $('httpmethod').options[$('httpmethod').selectedIndex].text;
  var url = $('url').value + mt.toLowerCase();
  var bd = (mt != 'GET') ? 'body: ""' : '';
  var options = {
    method: mt,
    bd
  };
  fetch(url, options)
  .then(response => response.text())
  .then(txt => {
    $('payload').innerHTML = txt;
  });
}

$('fetch').addEventListener('click', fetchEndpoint);

function getActualValues() {
      fetch("/getValues")

      .then(response => response.json())
      .then(data => {
        console.log(data);
        document.getElementById("sunrise-actual").innerHTML = data.sunrise;
        document.getElementById("sunset-actual").innerHTML = data.sunset;
      })
    }

)EOF";

but nothing happen. So Is it correct that the steps I have used?

ACE browser source

Is it possible to get the ACE file browser source?
I need to change something.

compilation error in platformio

flatform espressif 5.3.0 mcu esp32-s2
arduino framework

src/main.cpp: In function 'void handleLed()':
src/main.cpp:88:44: error: 'class FSWebServer' has no member named 'getRequest'; did you mean 'handleRequest'?
WebServerClass* webRequest = myWebServer.getRequest();

NO ISSUE, just question FILE DOWNLOAD ?

play with a ESP32-S3 N16R8
and setup FFAT 10MB partition.
and write dir and file (append 1 line / min )
/data/readings.csv

does THIS tool help me to DOWNLOAD that file via Browser?

the example FSBrowser i use, not even print that file (content)
my status : at GIT

THX for sharing your work

Problem with Options Box rename

I am using arduino-cli and ESP32-S3 D1 Mini
I was unable to change Options Box Label in your example CustomHTML.ino.
Even if I use the #define CLEAR_OTIONS 1 the label did not changed.
I have to get rid of the config.json (actually I rename it) in order to see my new labels.
In config.json I have noticed that options labels seems to be saved EX:"param-box1": "Mes Options".
Exception are "Setup" and "Update&FS"
This is confusing.

How to show variable value on Custom Html??

Hi @cotestatnt ,
I have some question,

  1. After connected to SSID, we dont know the giving IP Address from router, is possible to add status of ESP? connected or not connected and IP address? so we can go back to the page if we know the IP.

  2. Is possible to edit the Wifi Setup page? I read this but I fail, can you give hint more detail to generate setup_htm.h

  3. Give me hint how to print or show value of variable on customElement.h? for example, I have x variable, and i want to show value of x to customHTML page.

Thanks, you are great!!

Error compiling for board esp8266

hi @cotestatnt

I have updated lib to 1.2.4
an error appears when I compile the esp8266 board

D:\Documents\Arduino\libraries\esp-fs-webserver-master\src\esp-fs-webserver.cpp: In member function 'bool FSWebServer::begin(const char*)':
D:\Documents\Arduino\libraries\esp-fs-webserver-master\src\esp-fs-webserver.cpp:125:16: error: 'using WebServerClass = using ESP8266WebServer = class esp8266webserver::ESP8266WebServerTemplate<WiFiServer>' {aka 'class esp8266webserver::ESP8266WebServerTemplate<WiFiServer>'} has no member named 'enableDelay'
  125 |     webserver->enableDelay(false);
      |                ^~~~~~~~~~~

.
.
.
exit status 1
Error compiling for board LOLIN(WEMOS) D1 R2 & mini.

I have also updated the board manager for esp8266, but the error still appears
is there any solution?

on version 2.0.2 ,the saveOption function does not take effect when used in loop.

the function: myWebServer.addOption(LONG_LABEL, longVar); could save data to fs and could be loaded later, but when i use saveOptions();
it work as follow code : // Config file will be opened on the first time we call this method
..
myWebServer.saveOptionValue(LONG_LABEL, longVar);
..
Serial.println(F("Application options saved."));
It seem not take effectect, is there somthing wrong in code:?
my code is as follow:

void loop() {
  myWebServer.run();

  if (! digitalRead(BTN_SAVE)) {
// 
    loadOptions();
    Serial.printf("Application option loaded after web requestlongVar =%d\n",longVar);
    longVar++;
    Serial.printf("finished add n option loaded after web requestlongVar =%d\n",longVar);
// 
   saveOptions();
   Serial.printf("---------------------\n");
// 
    loadOptions();
    Serial.printf("Application option loaded after web requestlongVar =%d\n",longVar);
    longVar++;
    Serial.printf("finished add n option loaded after web requestlongVar =%d\n",longVar);

  //把longVar 保存的config文件中
  saveOptions();
     Serial.printf("========================\n");
    }
   delay(1000);
}

===========
Serial output:
This are the current values stored:

LED pin value: 2
Bool value: true
Long value: 1010
Float value: 15.500
String value: Test option String
Dropdown selected value: Monday

Application option loaded after web requestlongVar =1010
finished add n option loaded after web requestlongVar =1011
Application options saved.

This are the current values stored:

LED pin value: 2
Bool value: true
Long value: 1010
Float value: 15.500
String value: Test option String
Dropdown selected value: Monday

Application option loaded after web requestlongVar =1010
finished add n option loaded after web requestlongVar =1011
Application options saved.

switch to different wifi

when you setup a connection to wifi everithing is fine but if you need to switch to another wifi end the name of new wifi is shorter than the previous one there is a problem because the last part of previous name is attacced to new one
example:
first ssid name "abcdefghilmn"
sec. ssid name "123456"
the secon ssid name will be: "123456ghilmn"
so the result is no wifi found and go again on ap mode

WDT exception

I use Lolin wemos d1 mini pro v2.0.0 (esp8266)
arduino IDE 1.8.19
whit the same sketch using esp-fs-webserver version 1.1.7 I have no problem at all, everithing working well
but with the last version of esp-fs-webserver 2.0.7 just after loading the sketch on the micro it start to reset every minute

this is the output from serial monitor:


Deserializing JSON..

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Exception (28):
epc1=0x40218534 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

stack>>>

ctx: cont
sp: 3ffffd30 end: 3fffffd0 offset: 0150
3ffffe80: 40224800 0104a8c0 c28f5c28 00641888
3ffffe90: 40224800 00000000 00000001 3fff1df4
3ffffea0: 3fff1dd4 3fff1de4 3fff1e11 3fff29e0
3ffffeb0: 3fff25dc 3fff25dc 3fff25dc 402185d2
3ffffec0: 3fff25dc 3fff25dc 3fff4a50 40217034
3ffffed0: 3fff4104 3fffff00 3fff4a4c 40216430
3ffffee0: 3fff25dc 3fff25dc 00000001 402142b9
3ffffef0: 00000000 3fff4a4c 00000001 3f000000
3fffff00: 3fff0000 00000000 3fff2608 40215104
3fffff10: 0000562d 3fff2608 00000001 402154a4
3fffff20: 3fffdad0 00000000 3fff2284 4021049d
3fffff30: 402243f0 00000000 00001388 40222872
3fffff40: 3fffdad0 00000000 3fff42d4 3fff29e0
3fffff50: 3fffdad0 3fff25dc 3fff2280 402156fc
3fffff60: 3fffdad0 00000000 3fff2280 40210643
3fffff70: 3fff1dd4 3fff1dc0 3fff29b4 4020a333
3fffff80: 00000000 01040000 00005460 40224800
3fffff90: 0104a8c0 feefeffe feefeffe 3fff29e0
3fffffa0: 3fffdad0 00000000 3fff29b4 3fff29e0
3fffffb0: 3fffdad0 00000000 3fff29b4 402201c4
3fffffc0: feefeffe feefeffe 3fffdab0 401012e1
<<<stack<<<

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

ets Jan 8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 3424, room 16
tail 0
chksum 0x2e
load 0x3fff20b8, len 40, room 8
tail 0
chksum 0x2b
csum 0x2b
v0006bf80
~ld


I already tryed to use some espedient found on the net like reducing power of wifi or other stuffs but no one working

do you have any suggestion?

edit page shows FS INIT ERROR and not displaying Files

Hi cotestatnt , many thanks for this library very useful for every developer .
i Am developing with esp32 wroom dev my small project .

I did install your ESP-FS-webserver and it worked like a charm . on my first install
BUT suddenly something strange happened . ?

i have not change board ,partitions, on my arduino ide keeps the same as when it worked like a charm .
The code i am uploading is yours .inos from EXAMPLES .

When it opens /edit it shows everything but the files , and also indicates FS INIT ERROR .
i am using the handleformdata example .

So i did install simpleserver and also the same FS INIT ERROR
I did use other esp32 out of the package and the same FS INIT ERROR
I did replace all library with fresh download new ones and the same . FS INIT ERROR
I test it with mozzilla , safari , edge , many browsers just in case but FS INIT ERROR

So i decided to upload spiffs test and runs ok , even lists my files meaning data files of your library .

i also uploaded de FS library FSBROWSER that also use ACE and it does shows the files , but it hangs .

So i have being the last 3 days trying to solve this so i can continue with my development but i am stucked on this mysterious situation that i cant not understand .

If you could be kind , and at least tell me where to go , check, replace, look , or any idea about my situation i will much appreciate ,

Many thanks in advance in case you have the time for an answer to me ,

Denis Thornhill

changing the code to automatically inlcude the correct Little-filesystem library ESP8266 <LittleFS.h> / ESP32)<LITTLEFS.h>

Hi I made a small change to the code so that the correct littl-flsesystem-library is included on compiling
here is my modified version

I have tested it with an ESP32 and an ESP8266-board and it does compile and run as expected

the modification is here

#ifdef ESP8266
#include <LittleFS.h>
#define FILESYSTEM LittleFS
ESP8266WebServer server(80);

#elif defined(ESP32)
#include <LITTLEFS.h>
#define FILESYSTEM LITTLEFS
WebServer server(80);
#endif

full code is this

#include <esp-fs-webserver.h>   // https://github.com/cotestatnt/esp-fs-webserver

#include <FS.h>

#ifndef LED_BUILTIN
#define LED_BUILTIN 2
#endif

// Test "options" values
bool boolVar = true;
uint32_t longVar = 1234567890;
String stringVar = "Test option String";
uint8_t ledPin = LED_BUILTIN;

int myTestVar1;
int myTestVar2;
int myTestVar3;

// Timezone definition to get properly time from NTP server
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"
struct tm Time;

#ifdef ESP8266
#include <LittleFS.h>
#define FILESYSTEM LittleFS
ESP8266WebServer server(80);

#elif defined(ESP32)
#include <LITTLEFS.h>
#define FILESYSTEM LITTLEFS
WebServer server(80);
#endif

FSWebServer myWebServer(FILESYSTEM, server);


////////////////////////////////  Filesystem  /////////////////////////////////////////
void startFilesystem() {
  Serial.println( F("(try to start FileSystem") );
  // FILESYSTEM INIT
  if ( FILESYSTEM.begin()) {
    Serial.println( F("FILESYSTEM.begin() done") );
    File root = FILESYSTEM.open("/", "r");
    File file = root.openNextFile();
    while (file) {
      const char* fileName = file.name();
      size_t fileSize = file.size();
      Serial.printf("FS File: %s, size: %lu\n", fileName, (long unsigned)fileSize);
      file = root.openNextFile();
    }
    Serial.println();
  }
  else {
    Serial.println( F("ERROR on mounting filesystem. It will be formmatted!") );
    FILESYSTEM.format();
    Serial.println( F("formatting done ESP.restart()") );
    ESP.restart();
  }
}


////////////////////  Load application options from filesystem  ////////////////////
bool loadApplicationConfig() {
  StaticJsonDocument<1024> doc;
  File file = FILESYSTEM.open("/config.json", "r");
  if (file) {
    Serial.println( F("successfully opened file config.json for read") );
    DeserializationError error = deserializeJson(doc, file);
    file.close();
    if (!error) {
      Serial.println(F("Deserializing config JSON.. successful"));
      boolVar = doc["A bool var"];
      stringVar = doc["A String var"].as<String>();
      longVar = doc["A long var"];
      ledPin = doc["LED Pin"];
      serializeJsonPretty(doc, Serial);
      Serial.println();
      return true;
    }
    else {
      Serial.println( F("Failed to deserialize JSON. File could be corrupted"));
      Serial.println(error.c_str());
    }
  }
  return false;
}


void setup() {
  Serial.begin(115200);
  Serial.println( F("Setup-Start") );
  // FILESYSTEM INIT
  startFilesystem();

  // Try to connect to flash stored SSID, start AP if fails after timeout
  IPAddress myIP = myWebServer.startWiFi(15000, "ESP8266_AP", "123456789" );

  // Load configuration (if not present, default will be created when webserver will start)
  if (loadApplicationConfig()) {
    Serial.println( F("Application option loaded") );
  }
  else {
    Serial.println( F("Application NOT loaded!") );
    Serial.print( F("Open http://"));
    Serial.print(myIP);
    Serial.println( F("/setup to configure parameters") );
  }

  // Configure / setup page and start Web Server
  myWebServer.addOption(FILESYSTEM, "LED Pin", ledPin);
  myWebServer.addOption(FILESYSTEM, "A long var", longVar);
  myWebServer.addOption(FILESYSTEM, "A String var", stringVar.c_str());
  myWebServer.addOption(FILESYSTEM, "A bool var", boolVar);

  myWebServer.addOption(FILESYSTEM, "my number 1", myTestVar1);
  myWebServer.addOption(FILESYSTEM, "this testvar2", myTestVar2);
  myWebServer.addOption(FILESYSTEM, "3 my 33 myTestVar3", myTestVar3);

  if (myWebServer.begin()) {
    Serial.print( F("ESP Web Server started on IP Address: ") );
    Serial.println(myIP);
    Serial.println();

    Serial.println( F("Open ") );
    Serial.print( F("http://") );
    Serial.print(myIP);
    Serial.println( F("/setup") );
    Serial.println( F("to configure optional parameters") );
    Serial.println();

    Serial.println( F("Open ") );
    Serial.print( F("http://") );
    Serial.print(myIP);
    Serial.println( F("/edit") );
    Serial.println( F("to view and edit files") );
    Serial.println();

    Serial.println( F("Open ") );
    Serial.print( F("http://") );
    Serial.print(myIP);
    Serial.println( F("/update") );
    Serial.println( F("to upload firmware and filesystem updates"));
    Serial.println();
    Serial.println( F("start looping myWebServer.run()") );
  }
}

void loop() {
  myWebServer.run();
}

best regards Stefan

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.