3 #include <ESPAsyncWebServer.h>
4 #include <StreamString.h>
7 bool isApEnabled = false;
8 bool isWebStarted = false;
10 bool pendingWiFi = false;
11 bool pendingAuth = false;
13 AsyncWebServer server(80);
14 AsyncEventSource events("/events");
21 void reportChange(const __FlashStringHelper* name) {
23 ConfigParameter* param = cfg.getParam(name);
25 switch (param->getType()) {
27 sprintf(buf,"{\"%s\":%s}", name, param->getBoolValue()?"true":"false");
30 sprintf(buf,"{\"%s\":%d}", name, param->getIntValue());
33 sprintf(buf,"{\"%s\":%f}", name, param->getFloatValue());
36 sprintf(buf,"{\"%s\":\"%s\"}", name, param->getCharValue());
39 events.send(buf,"update",millis());
43 void sendInitial(AsyncEventSourceClient *client) {
44 String mac = WiFi.macAddress();
46 sprintf(buf,"{\"_mac\":\"%s\",\"_weather\":\"%s\"}", mac.c_str(), weatherData);
47 client->send(buf,"keepalive",millis());
53 sprintf(buf,"{\"_weather\":\"%s\"}",weatherData);
54 events.send(buf,"keepalive",millis());
57 void sendKeepalive() {
58 static unsigned long lastMillis = 0;
59 static unsigned long uptimeCorrection = 0;
60 unsigned long currentMillis = millis();
61 unsigned long uptime = millis()/1000;
62 if (currentMillis < lastMillis) {
63 uptimeCorrection += lastMillis/1000;
65 lastMillis = millis();
66 uptime = uptime + uptimeCorrection;
67 int days = uptime / 86400;
68 uptime = uptime % 86400;
69 int hrs = uptime / 3600;
70 uptime = uptime % 3600;
71 int mins = uptime / 60;
73 int heap = ESP.getFreeHeap();
74 int rssi = WiFi.RSSI();
75 struct tm* timeinfo = localtime(&last_sync);
76 bool changed = cfg.getTimestamp() != 0;
77 char sync[16] = "--:--:--";
79 sprintf(sync, "%02d:%02d:%02d", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
83 sprintf(buf,"{\"_uptime\":\"%d д %d ч %d % м %d с\", \"_date\":\"%02d.%2d.%04d\", \"_time\":\"%02d:%02d\",\"_heap\":\"%d б\", \"_rssi\":\"%d\", \"_last_sync\":\"%s\", \"_changed\":%s}", days, hrs, mins, uptime, dd, mm, yy, hh, mi, heap, rssi, sync, changed?"true":"false");
85 sprintf(buf,"{\"_uptime\":\"%d ч %d % м %d с\", \"_date\":\"%02d.%2d.%04d\", \"_time\":\"%02d:%02d\",\"_heap\":\"%d б\", \"_rssi\":\"%d\", \"_last_sync\":\"%s\", \"_changed\":%s}", hrs, mins, uptime, dd, mm, yy, hh, mi, heap, rssi, sync, changed?"true":"false");
87 sprintf(buf,"{\"_uptime\":\"%d м %d с\", \"_date\":\"%02d.%2d.%04d\", \"_time\":\"%02d:%02d\",\"_heap\":\"%d б\", \"_rssi\":\"%d\", \"_last_sync\":\"%s\", \"_changed\":%s}", mins, uptime, dd, mm, yy, hh, mi, heap, rssi, sync, changed?"true":"false");
89 events.send(buf,"keepalive",millis());
92 void apply(const char* name) {
93 if (strcmp(name,"sta_ssid") == 0 || strcmp(name,"sta_psk") == 0) {
97 } else if (strcmp(name,"ap_ssid") == 0 || strcmp(name,"ap_psk") == 0) {
101 } else if (strcmp(name,"auth_user") == 0 || strcmp(name,"auth_pwd") == 0) {
103 } else if (strcmp(name,"ntp_server") == 0 || strcmp(name,"tz") == 0) {
105 } else if (strcmp(name,"pin_sda") == 0 || strcmp(name,"pin_scl") == 0 ||
106 strcmp(name,"i2c_speed") == 0 || strcmp(name,"enable_rtc") == 0 ||
107 strcmp(name,"enable_button") == 0 || strcmp(name,"button_pin") == 0 || strcmp(name,"button_inversed") == 0 ||
108 strcmp(name,"enable_buzzer") == 0 || strcmp(name,"buzzer_pin") == 0) {
110 } else if (strcmp(name,"pin_din") == 0 || strcmp(name,"pin_clk") == 0 ||
111 strcmp_P(name,"pin_cs") == 0 || strcmp(name,"led_modules") == 0){
113 } else if (strcmp(name,"panel_brightness_day") == 0 || strcmp_P(name,"panel_brightness_night") == 0 ||
114 strcmp_P(name,"day_from") == 0 || strcmp(name,"night_from") == 0){
115 setPanelBrightness();
119 char* actionScheduled = nullptr;
120 unsigned long millisScheduled = 0;
132 strncpy(auth_user,cfg.getCharValue(F("auth_user")),31);
133 strncpy(auth_pwd,cfg.getCharValue(F("auth_pwd")),31);
135 server.on("/action", HTTP_GET, [](AsyncWebServerRequest* request) {
136 if (auth_user && auth_pwd && auth_user[0] && auth_pwd[0] && !request->authenticate(auth_user, auth_pwd)) {
137 return request-> requestAuthentication();
139 if(request->hasParam("name")) {
140 const char* action = request->getParam("name")->value().c_str();
141 if (strcmp(action,"restart") == 0) {
143 request->send(200,"application/json", "{\"result\":\"FAILED\",\"message\":\"Не применены настройки WiFi\", \"page\":\"wifi\"}");
144 } else if (pendingAuth) {
145 request->send(200,"application/json", "{\"result\":\"FAILED\",\"message\":\"Не применены настройки авторизации\", \"page\":\"system\"}");
147 request->send(200,"application/json", "{\"result\":\"OK\",\"message\":\"Перезагружаюсь\"}");
148 millisScheduled = millis();
149 actionScheduled = "restart";
151 } else if (strcmp(action,"wifi") == 0) {
153 request->send(200,"application/json", "{\"result\":\"FAILED\",\"message\":\"Не применены настройки авторизации\", \"page\":\"system\"}");
155 request->send(200,"application/json", "{\"result\":\"OK\",\"message\":\"Применяю настройки\"}");
156 millisScheduled = millis();
157 actionScheduled = "wifi";
159 } else if (strcmp(action,"auth") == 0) {
160 request->send(200,"application/json", "{\"result\":\"OK\",\"message\":\"Применяю настройки\"}");
161 millisScheduled = millis();
162 actionScheduled = "auth";
163 } else if (strcmp(action,"save") == 0) {
165 request->send(200,"application/json", "{\"result\":\"FAILED\",\"message\":\"Не применены настройки WiFi\", \"page\":\"wifi\"}");
166 } else if (pendingAuth) {
167 request->send(200,"application/json", "{\"result\":\"FAILED\",\"message\":\"Не применены настройки авторизации\", \"page\":\"system\"}");
169 request->send(200,"application/json", "{\"result\":\"OK\",\"message\":\"Сохраняю настройки\"}");
170 millisScheduled = millis();
171 actionScheduled = "save";
177 server.on("/wifi/scan", HTTP_GET, [](AsyncWebServerRequest* request) {
178 if (auth_user && auth_pwd && auth_user[0] && auth_pwd[0] && !request->authenticate(auth_user, auth_pwd)) {
179 return request-> requestAuthentication();
182 int n = WiFi.scanComplete();
184 WiFi.scanNetworks(true);
186 for (int i = 0; i < n; ++i) {
189 json += "\"rssi\":" + String(WiFi.RSSI(i));
190 json += ",\"ssid\":\"" + WiFi.SSID(i) + "\"";
191 json += ",\"bssid\":\"" + WiFi.BSSIDstr(i) + "\"";
192 json += ",\"channel\":" + String(WiFi.channel(i));
193 json += ",\"secure\":" + String(WiFi.encryptionType(i));
194 json += ",\"hidden\":" + String(WiFi.isHidden(i) ? "true" : "false");
198 if (WiFi.scanComplete() == -2) {
199 WiFi.scanNetworks(true);
203 request->send(200, "application/json", json);
207 server.on("/config/get", HTTP_GET, [](AsyncWebServerRequest* request) {
208 if (auth_user && auth_pwd && auth_user[0] && auth_pwd[0] && !request->authenticate(auth_user, auth_pwd)) {
209 return request-> requestAuthentication();
211 AsyncResponseStream* s = request->beginResponseStream("application/json");
213 for (int i = 0; i < cfg.getParametersCount(); i++) {
214 ConfigParameter* param = cfg.getParameter(i);
215 if (i) s->print(",");
217 s->print(param->getID());
219 switch (param->getType()) {
221 s->print(param->getBoolValue() ? "true" : "false");
224 s->print(param->getIntValue());
227 s->print(param->getFloatValue());
231 s->print(param->getCharValue());
240 server.on("/config/set", HTTP_GET, [](AsyncWebServerRequest* request) {
241 if (auth_user && auth_pwd && auth_user[0] && auth_pwd[0] && !request->authenticate(auth_user, auth_pwd)) {
242 return request-> requestAuthentication();
244 if(request->hasParam("name") && (request->hasParam("value"))) {
245 const char* name = request->getParam("name")->value().c_str();
246 const char* value = request->getParam("value")->value().c_str();
247 Serial.print(name); Serial.print(" = "); Serial.println(value);
249 ConfigParameter* param = cfg.getParam(name);
251 switch (param->getType()) {
253 cfg.setValue(name, strcmp(value, "true")==0);
254 sprintf(buf,"{\"%s\":%s}", name, param->getBoolValue()?"true":"false");
257 cfg.setValue(name, atoi(value));
258 sprintf(buf,"{\"%s\":%d}", name, param->getIntValue());
261 cfg.setValue(name, atof(value));
262 sprintf(buf,"{\"%s\":%f}", name, param->getFloatValue());
265 cfg.setValue(name, value);
266 sprintf(buf,"{\"%s\":\"%s\"}", name, param->getCharValue());
271 request->send(500, "text/plain", "Unknown parameter name");
274 request->send(200,"application/json",buf);
276 request->send(500, "text/plain", "Not all parameters set");
280 server.serveStatic("ui", LittleFS, "/ui.json").setAuthentication(auth_user,auth_pwd);
282 server.serveStatic("/", LittleFS, "/web/").setDefaultFile("index.html").setAuthentication(auth_user,auth_pwd);
284 server.onNotFound([](AsyncWebServerRequest *request){
285 request->send(404,"text/plain","Not found");
288 events.onConnect([](AsyncEventSourceClient *client){
292 events.setAuthentication(auth_user,auth_pwd);
294 server.addHandler(&events);
298 tKeepalive.attach(2, sendKeepalive);
302 #define CFG_AUTOSAVE 15
305 static char storedSSID[64];
306 static char storedPSK[64];
307 static bool connectInProgress = false;
308 static unsigned long connectMillis = 0;
309 if (actionScheduled && millis()>millisScheduled+300) {
310 Serial.print(F("Запланированная операция ")); Serial.println(actionScheduled);
312 if (strcmp(actionScheduled,"restart") == 0) {
315 } else if (strcmp(actionScheduled,"auth") == 0) {
316 Serial.println("Логин/пароль изменены");
317 strncpy(auth_user,cfg.getCharValue(F("auth_user")),31);
318 strncpy(auth_pwd,cfg.getCharValue(F("auth_pwd")),31);
320 } else if (strcmp(actionScheduled,"wifi") == 0) {
321 Serial.println("Применяю настройки сети");
322 strcpy(storedSSID,WiFi.SSID().c_str());
323 strcpy(storedPSK,WiFi.psk().c_str());
325 WiFi.begin(cfg.getCharValue("sta_ssid"),cfg.getCharValue("sta_psk"));
326 connectInProgress = true;
327 connectMillis = millis();
328 } else if (strcmp(actionScheduled,"save") == 0 && !pendingWiFi && !pendingAuth) {
331 actionScheduled = nullptr;
333 if (connectInProgress && (millis() > connectMillis + 1000)) {
334 if (WiFi.status() == WL_CONNECTED) {
336 sprintf(buf,"Подключен к %s, IP=%s", WiFi.SSID(), WiFi.localIP().toString().c_str());
340 connectInProgress = false;
341 } else if (WiFi.status() == WL_CONNECT_FAILED || WiFi.status() == WL_NO_SSID_AVAIL || ((WiFi.status() == WL_CONNECTION_LOST || WiFi.status() == WL_DISCONNECTED) && (millis()>connectMillis+1000*cfg.getIntValue("sta_wait")))) {
342 Serial.println(F("Подключение не удалось, возвращаю прежние настройки"));
343 message(F("Подключение не удалось, возвращаю прежние настройки"),1);
344 WiFi.begin(storedSSID, storedPSK);
345 connectInProgress = false;
349 if (!pendingWiFi && !pendingAuth && cfg.getTimestamp() && cfg.getTimestamp() < now - CFG_AUTOSAVE) {
351 Serial.println(F("Настройки сохранены"));