| 2 |
raymond |
1 |
#include <FS.h>
|
|
|
2 |
#include <LittleFS.h>
|
|
|
3 |
#include <AsyncFsWebServer.h> //https://github.com/cotestatnt/async-esp-fs-webserver
|
|
|
4 |
|
|
|
5 |
// Timezone definition to get properly time from NTP server
|
|
|
6 |
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"
|
|
|
7 |
struct tm Time;
|
|
|
8 |
|
|
|
9 |
#define FILESYSTEM LittleFS
|
|
|
10 |
AsyncFsWebServer server(FILESYSTEM, 80, "myserver");
|
|
|
11 |
|
|
|
12 |
// Define built-in LED if not defined by board (eg. generic dev boards)
|
|
|
13 |
#ifndef LED_BUILTIN
|
|
|
14 |
#define LED_BUILTIN 2
|
|
|
15 |
#endif
|
|
|
16 |
#define BOOT_PIN 0
|
|
|
17 |
|
|
|
18 |
// Labels used in /setup webpage for options
|
|
|
19 |
#define LED_LABEL "The LED pin number"
|
|
|
20 |
#define BOOL_LABEL "A bool variable"
|
|
|
21 |
#define BOOL_LABEL2 "A second bool variable"
|
|
|
22 |
#define LONG_LABEL "A long variable"
|
|
|
23 |
#define FLOAT_LABEL "A float variable"
|
|
|
24 |
#define STRING_LABEL "A String variable"
|
|
|
25 |
#define DROPDOWN_LABEL "Days of week"
|
|
|
26 |
#define BRIGHTNESS_LABEL "Brightness"
|
|
|
27 |
|
|
|
28 |
// Test "options" values
|
|
|
29 |
uint8_t ledPin = LED_BUILTIN;
|
|
|
30 |
bool boolVar = true;
|
|
|
31 |
bool boolVar2 = false;
|
|
|
32 |
uint32_t longVar = 1234567890;
|
|
|
33 |
float floatVar = 15.51F;
|
|
|
34 |
String stringVar = "Test option String";
|
|
|
35 |
|
|
|
36 |
// Add a dropdown list box in /setup page
|
|
|
37 |
const char* days[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
|
|
|
38 |
uint8_t daySelected = 2;// Default to "Wednesday"
|
|
|
39 |
AsyncFsWebServer::DropdownList dayOfWeek{ DROPDOWN_LABEL, days, 7, daySelected};
|
|
|
40 |
|
|
|
41 |
// Add a slider in /setup page
|
|
|
42 |
AsyncFsWebServer::Slider brightness{ BRIGHTNESS_LABEL, 0.0, 100.0, 1.0, 50.0 };
|
|
|
43 |
|
|
|
44 |
static const char reload_btn_htm[] PROGMEM = R"EOF(
|
|
|
45 |
<div class="bar">
|
|
|
46 |
<a class="btn" id="reload-btn">Reload options</a>
|
|
|
47 |
</div>
|
|
|
48 |
)EOF";
|
|
|
49 |
|
|
|
50 |
static const char reload_btn_script[] PROGMEM = R"EOF(
|
|
|
51 |
/* Add click listener to button */
|
|
|
52 |
const reloadCfg = () => {
|
|
|
53 |
console.log('Reload configuration options');
|
|
|
54 |
fetch('/reload')
|
|
|
55 |
.then((response) => {
|
|
|
56 |
if (response.ok) {
|
|
|
57 |
openModal('Options loaded', 'Options was reloaded from configuration file');
|
|
|
58 |
return;
|
|
|
59 |
}
|
|
|
60 |
throw new Error('Something goes wrong with fetch');
|
|
|
61 |
})
|
|
|
62 |
.catch((error) => {
|
|
|
63 |
openModal('Error', 'Something goes wrong with your request');
|
|
|
64 |
});
|
|
|
65 |
};
|
|
|
66 |
document.getElementById('reload-btn').addEventListener('click', reloadCfg);
|
|
|
67 |
)EOF";
|
|
|
68 |
|
|
|
69 |
|
|
|
70 |
/////////// Callback: notify user when the configuration file is saved /////////////
|
|
|
71 |
void onConfigSaved(const char* path) {
|
|
|
72 |
Serial.printf("\n[Config] File salvato: %s\n", path);
|
|
|
73 |
}
|
|
|
74 |
|
|
|
75 |
//////////////////////////////// Filesystem /////////////////////////////////////////
|
|
|
76 |
bool startFilesystem() {
|
|
|
77 |
if (FILESYSTEM.begin()){
|
|
|
78 |
server.printFileList(FILESYSTEM, "/", 2);
|
|
|
79 |
return true;
|
|
|
80 |
}
|
|
|
81 |
else {
|
|
|
82 |
Serial.println("ERROR on mounting filesystem. It will be reformatted!");
|
|
|
83 |
FILESYSTEM.format();
|
|
|
84 |
ESP.restart();
|
|
|
85 |
}
|
|
|
86 |
return false;
|
|
|
87 |
}
|
|
|
88 |
|
|
|
89 |
//////////////////// Load application options from filesystem ////////////////////
|
|
|
90 |
bool loadOptions() {
|
|
|
91 |
if (FILESYSTEM.exists(server.getConfiFileName())) {
|
|
|
92 |
server.getOptionValue(LED_LABEL, ledPin);
|
|
|
93 |
server.getOptionValue(BOOL_LABEL, boolVar);
|
|
|
94 |
server.getOptionValue(BOOL_LABEL2, boolVar2);
|
|
|
95 |
server.getOptionValue(LONG_LABEL, longVar);
|
|
|
96 |
server.getOptionValue(FLOAT_LABEL, floatVar);
|
|
|
97 |
server.getOptionValue(STRING_LABEL, stringVar);
|
|
|
98 |
server.getDropdownSelection(dayOfWeek);
|
|
|
99 |
server.getSliderValue(brightness);
|
|
|
100 |
server.closeSetupConfiguration(); // Close configuration to free resources
|
|
|
101 |
|
|
|
102 |
Serial.println("\nThis are the current values stored: \n");
|
|
|
103 |
Serial.printf("LED pin value: %d\n", ledPin);
|
|
|
104 |
Serial.printf("Bool value: %s\n", boolVar ? "true" : "false");
|
|
|
105 |
Serial.printf("Bool value2: %s\n", boolVar2 ? "true" : "false");
|
|
|
106 |
Serial.printf("Long value: %u\n", longVar);
|
|
|
107 |
Serial.printf("Float value: %3.2f\n", floatVar);
|
|
|
108 |
Serial.printf("String value: %s\n", stringVar.c_str());
|
|
|
109 |
Serial.printf("Dropdown selected value: %s\n", days[dayOfWeek.selectedIndex]);
|
|
|
110 |
Serial.printf("Slider value: %3.2f\n\n", brightness.value);
|
|
|
111 |
return true;
|
|
|
112 |
}
|
|
|
113 |
else
|
|
|
114 |
Serial.println(F("Config file not exist"));
|
|
|
115 |
return false;
|
|
|
116 |
}
|
|
|
117 |
|
|
|
118 |
|
|
|
119 |
//////////////////////////// HTTP Request Handlers ////////////////////////////////////
|
|
|
120 |
void handleLoadOptions(AsyncWebServerRequest *request) {
|
|
|
121 |
request->send(200, "text/plain", "Options loaded");
|
|
|
122 |
loadOptions();
|
|
|
123 |
Serial.println("Application option loaded after web request");
|
|
|
124 |
}
|
|
|
125 |
|
|
|
126 |
|
|
|
127 |
void setup() {
|
|
|
128 |
pinMode(LED_BUILTIN, OUTPUT);
|
|
|
129 |
pinMode(BOOT_PIN, INPUT_PULLUP);
|
|
|
130 |
Serial.begin(115200);
|
|
|
131 |
|
|
|
132 |
// FILESYSTEM INIT
|
|
|
133 |
if (startFilesystem()){
|
|
|
134 |
// Load configuration (if not present, default will be created when webserver will start)
|
|
|
135 |
loadOptions();
|
|
|
136 |
}
|
|
|
137 |
|
|
|
138 |
// Default firmware version is set to compile time, but you can edit with a custom string
|
|
|
139 |
// Custom firmware version -> Major.Minor.Build (build is set to compile date YYYYMMDDHHMM)
|
|
|
140 |
String version = "1.0." + String(BUILD_TIMESTAMP);
|
|
|
141 |
server.setFirmwareVersion(version);
|
|
|
142 |
|
|
|
143 |
// Try to connect to WiFi (will start AP if not connected after timeout)
|
|
|
144 |
if (!server.startWiFi(10000)) {
|
|
|
145 |
Serial.println("\nWiFi not connected! Starting AP mode...");
|
|
|
146 |
server.startCaptivePortal("ESP_AP", "123456789", "/setup");
|
|
|
147 |
}
|
|
|
148 |
|
|
|
149 |
// Add custom page handler
|
|
|
150 |
server.on("/reload", HTTP_GET, handleLoadOptions);
|
|
|
151 |
|
|
|
152 |
// Configure /setup page and start Web Server
|
|
|
153 |
server.addOptionBox("My Options");
|
|
|
154 |
server.addOption(BOOL_LABEL, boolVar);
|
|
|
155 |
server.addOption(BOOL_LABEL2, boolVar2);
|
|
|
156 |
server.addOption(LED_LABEL, ledPin);
|
|
|
157 |
server.addOption(LONG_LABEL, longVar);
|
|
|
158 |
server.addOption(FLOAT_LABEL, floatVar, 1.0, 100.0, 0.01);
|
|
|
159 |
server.addOption(STRING_LABEL, stringVar);
|
|
|
160 |
server.addDropdownList(dayOfWeek);
|
|
|
161 |
server.addSlider(brightness);
|
|
|
162 |
server.addHTML(reload_btn_htm, "buttons", /*overwrite*/ false);
|
|
|
163 |
server.addJavascript(reload_btn_script, "js", /*overwrite*/ false);
|
|
|
164 |
|
|
|
165 |
// Enable ACE FS file web editor and add FS info callback function
|
|
|
166 |
server.enableFsCodeEditor();
|
|
|
167 |
|
|
|
168 |
// set /setup and /edit page authentication
|
|
|
169 |
server.setAuthentication("admin", "admin");
|
|
|
170 |
|
|
|
171 |
// Inform user when config.json is saved via /edit or /upload
|
|
|
172 |
server.setConfigSavedCallback(onConfigSaved);
|
|
|
173 |
|
|
|
174 |
// Start server
|
|
|
175 |
server.init();
|
|
|
176 |
Serial.print(F("\nESP Web Server started on IP Address: "));
|
|
|
177 |
Serial.println(server.getServerIP());
|
|
|
178 |
Serial.println(F(
|
|
|
179 |
"\nThis is \"customOptions.ino\" example.\n"
|
|
|
180 |
"Open /setup page to configure optional parameters.\n"
|
|
|
181 |
"Open /edit page to view, edit or upload example or your custom webserver source files."
|
|
|
182 |
));
|
|
|
183 |
}
|
|
|
184 |
|
|
|
185 |
void loop() {
|
|
|
186 |
if (server.isAccessPointMode())
|
|
|
187 |
server.updateDNS();
|
|
|
188 |
|
|
|
189 |
// Keep BOOT_PIN pressed 5 seconds to clear application options
|
|
|
190 |
static uint32_t buttonPressStart = 0;
|
|
|
191 |
static bool buttonPressed = false;
|
|
|
192 |
|
|
|
193 |
if (digitalRead(BOOT_PIN) == LOW) {
|
|
|
194 |
if (!buttonPressed) {
|
|
|
195 |
buttonPressed = true;
|
|
|
196 |
buttonPressStart = millis();
|
|
|
197 |
}
|
|
|
198 |
else if (millis() - buttonPressStart >= 5000) {
|
|
|
199 |
Serial.println("\nClearing application options...");
|
|
|
200 |
server.clearConfigFile();
|
|
|
201 |
delay(1000);
|
|
|
202 |
ESP.restart();
|
|
|
203 |
}
|
|
|
204 |
} else {
|
|
|
205 |
buttonPressed = false;
|
|
|
206 |
}
|
|
|
207 |
|
|
|
208 |
// Nothing to do here, just a small delay for task yield
|
|
|
209 |
delay(10);
|
|
|
210 |
}
|