| 1 |
raymond |
1 |
|
|
|
2 |
|
|
|
3 |
#include <FS.h>
|
|
|
4 |
#include <LittleFS.h>
|
|
|
5 |
#include <AsyncFsWebServer.h> //https://github.com/cotestatnt/async-esp-fs-webserver
|
|
|
6 |
|
|
|
7 |
#define FILESYSTEM LittleFS
|
|
|
8 |
bool captiveRun = false;
|
|
|
9 |
|
|
|
10 |
// AsyncFsWebServer server(80, FILESYSTEM, "esphost");
|
|
|
11 |
AsyncFsWebServer server(80, FILESYSTEM);
|
|
|
12 |
|
| 2 |
raymond |
13 |
#ifndef Default_MQTT_Port
|
|
|
14 |
#define Default_MQTT_Port 1883
|
| 1 |
raymond |
15 |
#endif
|
|
|
16 |
|
|
|
17 |
#define BTN_SAVE 5
|
|
|
18 |
|
|
|
19 |
// Test "options" values
|
| 2 |
raymond |
20 |
uint16_t MQTT_Port = Default_MQTT_Port;
|
|
|
21 |
bool MQTT_Enabled = false;
|
|
|
22 |
String MQTT_Server = "";
|
|
|
23 |
String MQTT_User = "";
|
|
|
24 |
String MQTT_Password = "";
|
|
|
25 |
String MQTT_Prefix = "";
|
| 1 |
raymond |
26 |
|
|
|
27 |
// Var labels (in /setup webpage)
|
| 2 |
raymond |
28 |
#define MQTT_ENABLED_LABEL "MQTT Enabled"
|
|
|
29 |
#define MQTT_SERVER_LABEL "MQTT Server"
|
|
|
30 |
#define MQTT_PORT_LABEL "MQTT Server Port"
|
|
|
31 |
#define MQTT_USER_LABEL "MQTT User"
|
|
|
32 |
#define MQTT_PASSWORD_LABEL "MQTT Password"
|
|
|
33 |
#define MQTT_PREFIX_LABEL "MQTT Prefix"
|
| 1 |
raymond |
34 |
|
|
|
35 |
// Timezone definition to get properly time from NTP server
|
|
|
36 |
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"
|
|
|
37 |
struct tm Time;
|
|
|
38 |
|
|
|
39 |
static const char save_btn_htm[] PROGMEM = R"EOF(
|
|
|
40 |
<div class="btn-bar">
|
|
|
41 |
<a class="btn" id="reload-btn">Reload options</a>
|
|
|
42 |
</div>
|
|
|
43 |
)EOF";
|
|
|
44 |
|
|
|
45 |
static const char button_script[] PROGMEM = R"EOF(
|
|
|
46 |
/* Add click listener to button */
|
|
|
47 |
document.getElementById('reload-btn').addEventListener('click', reload);
|
|
|
48 |
function reload() {
|
|
|
49 |
console.log('Reload configuration options');
|
|
|
50 |
fetch('/reload')
|
|
|
51 |
.then((response) => {
|
|
|
52 |
if (response.ok) {
|
|
|
53 |
openModalMessage('Options loaded', 'Options was reloaded from configuration file');
|
|
|
54 |
return;
|
|
|
55 |
}
|
|
|
56 |
throw new Error('Something goes wrong with fetch');
|
|
|
57 |
})
|
|
|
58 |
.catch((error) => {
|
|
|
59 |
openModalMessage('Error', 'Something goes wrong with your request');
|
|
|
60 |
});
|
|
|
61 |
}
|
|
|
62 |
)EOF";
|
|
|
63 |
|
|
|
64 |
|
|
|
65 |
//////////////////////////////// Filesystem /////////////////////////////////////////
|
|
|
66 |
bool startFilesystem() {
|
|
|
67 |
if (FILESYSTEM.begin()){
|
|
|
68 |
server.printFileList(FILESYSTEM, "/", 2);
|
|
|
69 |
return true;
|
|
|
70 |
}
|
|
|
71 |
else {
|
|
|
72 |
Serial.println("ERROR on mounting filesystem. It will be reformatted!");
|
|
|
73 |
FILESYSTEM.format();
|
|
|
74 |
ESP.restart();
|
|
|
75 |
}
|
|
|
76 |
return false;
|
|
|
77 |
}
|
|
|
78 |
|
|
|
79 |
/*
|
|
|
80 |
* Getting FS info (total and free bytes) is strictly related to
|
|
|
81 |
* filesystem library used (LittleFS, FFat, SPIFFS etc etc) and ESP framework
|
|
|
82 |
*/
|
|
|
83 |
#ifdef ESP32
|
|
|
84 |
void getFsInfo(fsInfo_t* fsInfo) {
|
|
|
85 |
fsInfo->fsName = "LittleFS";
|
|
|
86 |
fsInfo->totalBytes = LittleFS.totalBytes();
|
|
|
87 |
fsInfo->usedBytes = LittleFS.usedBytes();
|
|
|
88 |
}
|
|
|
89 |
#endif
|
|
|
90 |
|
|
|
91 |
//////////////////// Load application options from filesystem ////////////////////
|
|
|
92 |
bool loadOptions() {
|
|
|
93 |
if (FILESYSTEM.exists(server.getConfiFileName())) {
|
| 2 |
raymond |
94 |
server.getOptionValue(MQTT_ENABLED_LABEL, MQTT_Enabled);
|
|
|
95 |
server.getOptionValue(MQTT_SERVER_LABEL, MQTT_Server);
|
|
|
96 |
server.getOptionValue(MQTT_PORT_LABEL, MQTT_Port);
|
|
|
97 |
server.getOptionValue(MQTT_USER_LABEL, MQTT_User);
|
|
|
98 |
server.getOptionValue(MQTT_PASSWORD_LABEL, MQTT_Password);
|
|
|
99 |
server.getOptionValue(MQTT_PREFIX_LABEL, MQTT_Prefix);
|
| 1 |
raymond |
100 |
|
|
|
101 |
Serial.println("\nThis are the current values stored: \n");
|
| 2 |
raymond |
102 |
Serial.printf("MQTT Enabled: %s\n", MQTT_Enabled ? "true" : "false");
|
|
|
103 |
Serial.printf("MQTT Server: %s\n", MQTT_Server.c_str());
|
|
|
104 |
Serial.printf("MQTT Server Port: %d\n", MQTT_Port);
|
|
|
105 |
Serial.printf("MQTT User: %s\n", MQTT_User.c_str());
|
|
|
106 |
Serial.printf("MQTT password: %s\n", MQTT_Password.c_str());
|
|
|
107 |
Serial.printf("MQTT Prefix: %s\n", MQTT_Prefix.c_str());
|
| 1 |
raymond |
108 |
return true;
|
|
|
109 |
}
|
|
|
110 |
else
|
|
|
111 |
Serial.println(F("Config file not exist"));
|
|
|
112 |
return false;
|
|
|
113 |
}
|
|
|
114 |
|
|
|
115 |
void saveOptions() {
|
|
|
116 |
// server.saveOptionValue(LED_LABEL, ledPin);
|
|
|
117 |
// server.saveOptionValue(BOOL_LABEL, boolVar);
|
|
|
118 |
// server.saveOptionValue(LONG_LABEL, longVar);
|
|
|
119 |
// server.saveOptionValue(FLOAT_LABEL, floatVar);
|
|
|
120 |
// server.saveOptionValue(STRING_LABEL, stringVar);
|
|
|
121 |
// server.saveOptionValue(DROPDOWN_LABEL, dropdownSelected);
|
|
|
122 |
Serial.println(F("Application options saved."));
|
|
|
123 |
}
|
|
|
124 |
|
|
|
125 |
//////////////////////////// HTTP Request Handlers ////////////////////////////////////
|
|
|
126 |
void handleLoadOptions(AsyncWebServerRequest *request) {
|
|
|
127 |
request->send(200, "text/plain", "Options loaded");
|
|
|
128 |
loadOptions();
|
|
|
129 |
Serial.println("Application option loaded after web request");
|
|
|
130 |
}
|
|
|
131 |
|
|
|
132 |
|
|
|
133 |
void setup() {
|
|
|
134 |
Serial.begin(115200);
|
|
|
135 |
pinMode(BTN_SAVE, INPUT_PULLUP);
|
|
|
136 |
|
|
|
137 |
// FILESYSTEM INIT
|
|
|
138 |
if (startFilesystem()){
|
|
|
139 |
// Load configuration (if not present, default will be created when webserver will start)
|
|
|
140 |
if (loadOptions())
|
|
|
141 |
Serial.println(F("Application option loaded"));
|
|
|
142 |
else
|
|
|
143 |
Serial.println(F("Application options NOT loaded!"));
|
|
|
144 |
}
|
|
|
145 |
|
|
|
146 |
// Try to connect to stored SSID, start AP with captive portal if fails after timeout
|
|
|
147 |
IPAddress myIP = server.startWiFi(15000);
|
|
|
148 |
if (!myIP) {
|
|
|
149 |
Serial.println("\n\nNo WiFi connection, start AP and Captive Portal\n");
|
|
|
150 |
server.startCaptivePortal("ESP_AP", "123456789", "/setup");
|
|
|
151 |
myIP = WiFi.softAPIP();
|
|
|
152 |
captiveRun = true;
|
|
|
153 |
}
|
|
|
154 |
|
|
|
155 |
// Add custom page handlers to webserver
|
|
|
156 |
server.on("/reload", HTTP_GET, handleLoadOptions);
|
|
|
157 |
|
|
|
158 |
// Configure /setup page and start Web Server
|
| 2 |
raymond |
159 |
server.addOptionBox("MQTT");
|
| 1 |
raymond |
160 |
|
| 2 |
raymond |
161 |
server.addOption(MQTT_ENABLED_LABEL, MQTT_Enabled);
|
|
|
162 |
server.addOption(MQTT_SERVER_LABEL, MQTT_Server);
|
|
|
163 |
server.addOption(MQTT_PORT_LABEL, MQTT_Port);
|
|
|
164 |
server.addOption(MQTT_USER_LABEL, MQTT_User);
|
|
|
165 |
server.addOption(MQTT_PASSWORD_LABEL, MQTT_Password);
|
|
|
166 |
server.addOption(MQTT_PREFIX_LABEL, MQTT_Prefix);
|
|
|
167 |
server.addOptionBox(const char *title);
|
| 1 |
raymond |
168 |
|
|
|
169 |
server.addHTML(save_btn_htm, "buttons", /*overwrite*/ false);
|
|
|
170 |
server.addJavascript(button_script, "js", /*overwrite*/ false);
|
|
|
171 |
|
|
|
172 |
// Enable ACE FS file web editor and add FS info callback function
|
|
|
173 |
server.enableFsCodeEditor();
|
|
|
174 |
#ifdef ESP32
|
|
|
175 |
server.setFsInfoCallback(getFsInfo);
|
|
|
176 |
#endif
|
|
|
177 |
|
|
|
178 |
// set /setup and /edit page authentication
|
|
|
179 |
server.setAuthentication("admin", "admin");
|
|
|
180 |
|
|
|
181 |
// Start server
|
|
|
182 |
server.init();
|
|
|
183 |
Serial.print(F("ESP Web Server started on IP Address: "));
|
|
|
184 |
Serial.println(myIP);
|
|
|
185 |
Serial.println(F(
|
|
|
186 |
"This is \"customOptions.ino\" example.\n"
|
|
|
187 |
"Open /setup page to configure optional parameters.\n"
|
|
|
188 |
"Open /edit page to view, edit or upload example or your custom webserver source files."
|
|
|
189 |
));
|
|
|
190 |
}
|
|
|
191 |
|
|
|
192 |
void loop() {
|
|
|
193 |
if (captiveRun)
|
|
|
194 |
server.updateDNS();
|
|
|
195 |
|
|
|
196 |
// Savew options also on button click
|
|
|
197 |
if (! digitalRead(BTN_SAVE)) {
|
|
|
198 |
saveOptions();
|
|
|
199 |
delay(1000);
|
|
|
200 |
}
|
|
|
201 |
}
|