добавил асинхронный веб сервер и веб сокеты, проверенный код

This commit is contained in:
Dmitry Borisenko
2021-12-23 00:33:45 +01:00
parent f20486517b
commit 7147e041b4
15 changed files with 201 additions and 249 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -11,3 +11,6 @@ extern FS* filesystem;
extern bool fileSystemInit();
extern void globalVarsSync();
void saveSettingsFlashJson();
void saveParamsFlashJson();

View File

@@ -4,6 +4,7 @@
#include <Arduino.h>
#include <ArduinoJson.h>
#include <ESP8266httpUpdate.h>
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include <TickerScheduler.h>
@@ -15,6 +16,7 @@
//глобальные объекты классов
extern TickerScheduler ts;
extern AsyncWebServer server;
//глобальные переменные
extern String settingsFlashJson;

View File

@@ -1,8 +1,10 @@
//#pragma once
//
//#include "Global.h"
//
//
//
// void initWS();
// void init();
#pragma once
#include "Global.h"
extern AsyncWebSocket ws;
extern AsyncEventSource events;
void webServerInit();
void webSocketsInit();
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len);

View File

@@ -3,3 +3,4 @@
#include "Global.h"
#include "Utils/Pretty.h"
#include "Utils/WiFiUtils.h"
#include "WebServer.h"

View File

@@ -19,6 +19,3 @@ bool jsonWriteStr_(String& json, String name, String value);
bool jsonWriteBool_(String& json, String name, bool value);
bool jsonWriteInt_(String& json, String name, int value);
bool jsonWriteFloat_(String& json, String name, float value);
void saveConfig();
void saveStore();

View File

@@ -16,6 +16,7 @@ data_dir = data_svelte
[common_env_data]
lib_deps_external =
bblanchon/ArduinoJson @6.18.0
me-no-dev/ESP Async WebServer
[env:esp8266_4mb]
build_flags = -Desp8266_4mb="esp8266_4mb"

View File

@@ -12,4 +12,12 @@ bool fileSystemInit() {
void globalVarsSync() {
settingsFlashJson = readFile("settings.json", 4096);
settingsFlashJson.replace("\r\n", "");
}
void saveSettingsFlashJson() {
writeFile(String("config.json"), settingsFlashJson);
}
void saveParamsFlashJson() {
writeFile(String("store.json"), paramsFlashJson);
}

View File

@@ -2,6 +2,7 @@
//глобальные объекты классов
TickerScheduler ts(MYTEST + 1);
AsyncWebServer server(80);
//глобальные переменные
String settingsFlashJson = "{}"; //переменная в которой хранятся все настройки, находится в оперативной памяти только и синхронизированна с flash памятью

View File

@@ -1,213 +1,147 @@
//
//
//
// AsyncWebSocket ws("/ws");
// AsyncEventSource events("/events");
//
//
//
//
//
// void init() {
// String login = jsonReadStr(settingsFlashJson, "weblogin");
// String pass = jsonReadStr(settingsFlashJson, "webpass");
//#ifdef ESP32
// server.addHandler(new FSEditor(FileFS, login, pass));
//#else
// server.addHandler(new FSEditor(login, pass));
//#endif
//
// server.serveStatic("/css/", FileFS, "/css/").setCacheControl("max-age=600");
// server.serveStatic("/js/", FileFS, "/js/").setCacheControl("max-age=600");
// server.serveStatic("/favicon.ico", FileFS, "/favicon.ico").setCacheControl("max-age=600");
// server.serveStatic("/icon.jpeg", FileFS, "/icon.jpeg").setCacheControl("max-age=600");
// server.serveStatic("/edit", FileFS, "/edit").setCacheControl("max-age=600");
//
//#ifdef svelte
// server.serveStatic("/", FileFS, "/").setDefaultFile("index.html").setAuthentication(login.c_str(), pass.c_str());
//#else
// server.serveStatic("/", FileFS, "/").setDefaultFile("index.htm").setAuthentication(login.c_str(), pass.c_str());
//#endif
//
// server.onNotFound([](AsyncWebServerRequest *request) {
// SerialPrint("[E]", "WebServer", "not found:\n" + getRequestInfo(request));
// request->send(404);
// });
//
// server.onFileUpload([](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) {
// // TODO
// if (!index) {
// SerialPrint("I", "WebServer", "start upload " + filename);
// }
// if (final) {
// SerialPrint("I", "WebServer", "finish upload: " + prettyBytes(index + len));
// }
// });
//
// // динамические данные
// server.on("/config.live.json", HTTP_GET, [](AsyncWebServerRequest *request) {
// request->send(200, "application/json", configLiveJson);
// });
//
// server.on("/config.store.json", HTTP_GET, [](AsyncWebServerRequest *request) {
// request->send(200, "application/json", paramsFlashJson);
// });
//
// // данные не являющиеся событиями
// server.on("/config.option.json", HTTP_GET, [](AsyncWebServerRequest *request) {
// request->send(200, "application/json", paramsHeapJson);
// });
//
// // для хранения постоянных данных
// server.on("/config.setup.json", HTTP_GET, [](AsyncWebServerRequest *request) {
// request->send(200, "application/json", settingsFlashJson);
// });
//
// server.on("/cmd", HTTP_GET, [](AsyncWebServerRequest *request) {
// String cmdStr = request->getParam("command")->value();
// SerialPrint("I", "WebServer", "do: " + cmdStr);
// loopCmdAdd(cmdStr);
// request->send(200, "text/html", "OK");
// });
//
// server.begin();
//
// initOta();
// initMDNS();
// initWS();
//
// SerialPrint("I", F("HTTP"), F("HttpServer Init"));
//}
//
// void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
//#ifdef WEBSOCKET_ENABLED
// if (type == WS_EVT_CONNECT) {
// SerialPrint("I", F("WS"), F("CONNECTED"));
// Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
// // client->printf(json.c_str(), client->id());
// // client->ping();
// } else if (type == WS_EVT_DISCONNECT) {
// Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id());
// } else if (type == WS_EVT_ERROR) {
// Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data);
// } else if (type == WS_EVT_PONG) {
// Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len) ? (char *)data : "");
// } else if (type == WS_EVT_DATA) {
// AwsFrameInfo *info = (AwsFrameInfo *)arg;
// String msg = "";
// if (info->final && info->index == 0 && info->len == len) {
// // the whole message is in a single frame and we got all of it's data
// Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT) ? "text" : "binary", info->len);
//
// if (info->opcode == WS_TEXT) {
// for (size_t i = 0; i < info->len; i++) {
// msg += (char)data[i];
// }
// } else {
// char buff[3];
// for (size_t i = 0; i < info->len; i++) {
// sprintf(buff, "%02x ", (uint8_t)data[i]);
// msg += buff;
// }
// }
// Serial.printf("%s\n", msg.c_str());
//
// if (msg.startsWith("HELLO")) {
// SerialPrint("I", F("WS"), F("Full update"));
// // publishWidgetsWS();
// // publishStateWS();
// // choose_log_date_and_send(); // функцию выгрузки архива с графиком я не сделал. Забираю при выгрузке по MQTT
// }
//
// if (info->opcode == WS_TEXT)
// client->text("{}");
// else
// client->binary("{}");
// } else {
// // message is comprised of multiple frames or the frame is split into multiple packets
// if (info->index == 0) {
// if (info->num == 0)
// Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT) ? "text" : "binary");
// Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len);
// }
//
// Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT) ? "text" : "binary", info->index, info->index + len);
//
// if (info->opcode == WS_TEXT) {
// for (size_t i = 0; i < len; i++) {
// msg += (char)data[i];
// }
// } else {
// char buff[3];
// for (size_t i = 0; i < len; i++) {
// sprintf(buff, "%02x ", (uint8_t)data[i]);
// msg += buff;
// }
// }
// Serial.printf("%s\n", msg.c_str());
//
// if ((info->index + len) == info->len) {
// Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len);
// if (info->final) {
// Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT) ? "text" : "binary");
// if (info->message_opcode == WS_TEXT)
// client->text("I got your text message");
// else
// client->binary("I got your binary message");
// }
// }
// }
// }
//#endif
// ;
//}
//
// void initMDNS() {
//#ifdef MDNS_ENABLED
// MDNS.addService("http", "tcp", 80);
// // TODO Add Adduino OTA
//#endif
// ;
//}
//
// void initOta() {
//#ifdef OTA_UPDATES_ENABLED
// ArduinoOTA.onStart([]() {
// events.send("Update Start", "ota");
// });
// ArduinoOTA.onEnd([]() {
// events.send("Update End", "ota");
// });
// ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
// char p[32];
// sprintf(p, "Progress: %u%%\n", (progress / (total / 100)));
// events.send(p, "ota");
// });
// ArduinoOTA.onError([](ota_error_t error) {
// if (error == OTA_AUTH_ERROR)
// events.send("Auth Failed", "ota");
// else if (error == OTA_BEGIN_ERROR)
// events.send("Begin Failed", "ota");
// else if (error == OTA_CONNECT_ERROR)
// events.send("Connect Failed", "ota");
// else if (error == OTA_RECEIVE_ERROR)
// events.send("Recieve Failed", "ota");
// else if (error == OTA_END_ERROR)
// events.send("End Failed", "ota");
// });
// ArduinoOTA.setHostname(hostName);
// ArduinoOTA.begin();
//#endif
// ;
//}
//
// void initWS() {
//#ifdef WEBSOCKET_ENABLED
// ws.onEvent(onWsEvent);
// server.addHandler(&ws);
// events.onConnect([](AsyncEventSourceClient *client) {
// client->send("", NULL, millis(), 1000);
// });
// server.addHandler(&events);
//#endif
//}
#include "WebServer.h"
AsyncWebSocket ws("/ws");
AsyncEventSource events("/events");
void webServerInit() {
String login = jsonReadStr(settingsFlashJson, "weblogin");
String pass = jsonReadStr(settingsFlashJson, "webpass");
#ifdef ESP32
// server.addHandler(new FSEditor(FileFS, login, pass));
#else
// server.addHandler(new FSEditor(login, pass));
#endif
server.serveStatic("/css/", FileFS, "/css/").setCacheControl("max-age=600");
server.serveStatic("/js/", FileFS, "/js/").setCacheControl("max-age=600");
server.serveStatic("/favicon.ico", FileFS, "/favicon.ico").setCacheControl("max-age=600");
server.serveStatic("/icon.jpeg", FileFS, "/icon.jpeg").setCacheControl("max-age=600");
server.serveStatic("/edit", FileFS, "/edit").setCacheControl("max-age=600");
server.serveStatic("/", FileFS, "/").setDefaultFile("index.html").setAuthentication(login.c_str(), pass.c_str());
server.onNotFound([](AsyncWebServerRequest *request) {
// SerialPrint("[E]", "WebServer", "not found:\n" + getRequestInfo(request));
request->send(404);
});
server.onFileUpload([](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) {
// TODO
if (!index) {
// SerialPrint("i", "WebServer", "start upload " + filename);
}
if (final) {
// SerialPrint("i", "WebServer", "finish upload: " + prettyBytes(index + len));
}
});
// динамические данные
// server.on("/config.live.json", HTTP_GET, [](AsyncWebServerRequest *request) {
// request->send(200, "application/json", configLiveJson);
//});
//
// server.on("/config.store.json", HTTP_GET, [](AsyncWebServerRequest *request) {
// request->send(200, "application/json", paramsFlashJson);
//});
//
// server.on("/config.option.json", HTTP_GET, [](AsyncWebServerRequest *request) {
// request->send(200, "application/json", paramsHeapJson);
//});
//
// server.on("/config.setup.json", HTTP_GET, [](AsyncWebServerRequest *request) {
// request->send(200, "application/json", settingsFlashJson);
//});
//
// server.on("/cmd", HTTP_GET, [](AsyncWebServerRequest *request) {
// String cmdStr = request->getParam("command")->value();
// SerialPrint("i", "WebServer", "do: " + cmdStr);
// // loopCmdAdd(cmdStr);
// request->send(200, "text/html", "OK");
//});
server.begin();
SerialPrint("i", F("WEB"), F("WebServer Init"));
}
void webSocketsInit() {
ws.onEvent(onWsEvent);
server.addHandler(&ws);
events.onConnect([](AsyncEventSourceClient *client) {
client->send("", NULL, millis(), 1000);
});
server.addHandler(&events);
SerialPrint("i", F("WEB"), F("WebSockets Init"));
}
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
if (type == WS_EVT_CONNECT) {
Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
client->printf("Hello Client %u :)", client->id());
client->ping();
} else if (type == WS_EVT_DISCONNECT) {
Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id());
} else if (type == WS_EVT_ERROR) {
Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data);
} else if (type == WS_EVT_PONG) {
Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len) ? (char *)data : "");
} else if (type == WS_EVT_DATA) {
AwsFrameInfo *info = (AwsFrameInfo *)arg;
String msg = "";
if (info->final && info->index == 0 && info->len == len) {
// the whole message is in a single frame and we got all of it's data
Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT) ? "text" : "binary", info->len);
if (info->opcode == WS_TEXT) {
for (size_t i = 0; i < info->len; i++) {
msg += (char)data[i];
}
} else {
char buff[3];
for (size_t i = 0; i < info->len; i++) {
sprintf(buff, "%02x ", (uint8_t)data[i]);
msg += buff;
}
}
Serial.printf("%s\n", msg.c_str());
if (info->opcode == WS_TEXT)
client->text("I got your text message");
else
client->binary("I got your binary message");
} else {
// message is comprised of multiple frames or the frame is split into multiple packets
if (info->index == 0) {
if (info->num == 0)
Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT) ? "text" : "binary");
Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len);
}
Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT) ? "text" : "binary", info->index, info->index + len);
if (info->opcode == WS_TEXT) {
for (size_t i = 0; i < len; i++) {
msg += (char)data[i];
}
} else {
char buff[3];
for (size_t i = 0; i < len; i++) {
sprintf(buff, "%02x ", (uint8_t)data[i]);
msg += buff;
}
}
Serial.printf("%s\n", msg.c_str());
if ((info->index + len) == info->len) {
Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len);
if (info->final) {
Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT) ? "text" : "binary");
if (info->message_opcode == WS_TEXT)
client->text("I got your text message");
else
client->binary("I got your binary message");
}
}
}
}
}

View File

@@ -12,11 +12,20 @@ void setup() {
//синхронизация глобальных переменных с flash
globalVarsSync();
//инициализация асинхронного веб сервера
webServerInit();
//инициализация веб сокетов асинхронного веб сервера
webSocketsInit();
//подключаемся к роутеру
routerConnect();
//выводим остаток оперативной памяти после старта
// 22.12.21 пустой код без wifi остаток = 50.28 kB
// 22.12.21 пустой код без wifi остаток = 50.28 kB
// 22.12.21 запустил wifi остаток = 48.59 kB
// 22.12.21 добавил асинхронный веб сервер = 38.36 kB
// 22.12.21 добавил web sockets = 37.63 kB
SerialPrint(F("i"), F("HEAP"), prettyBytes(ESP.getFreeHeap()));
}

View File

@@ -166,11 +166,5 @@ bool jsonWriteFloat_(String& json, String key, float value) {
serializeJson(doc, json);
return ret;
}
//=================================================================================
void saveConfig() {
writeFile(String("config.json"), settingsFlashJson);
}
void saveStore() {
writeFile(String("store.json"), paramsFlashJson);
}
//=================================================================================

View File

@@ -124,9 +124,9 @@ void breakEpochToTime(unsigned long epoch, Time_t& tm) {
// prevTime = timenow;
// jsonWriteStr(configLiveJson, "timenow", timenow);
// eventGen2("timenow", timenow);
// SerialPrint("I", F("NTP"), timenow);
// SerialPrint("i", F("NTP"), timenow);
// }
// },
// nullptr, true);
// SerialPrint("I", F("NTP"), F("Handle time init"));
// SerialPrint("i", F("NTP"), F("Handle time init"));
//}

View File

@@ -19,8 +19,8 @@ void routerConnect() {
#else
WiFi.setOutputPower(20.5);
#endif
SerialPrint("I", "WIFI", "ssid: " + _ssid);
SerialPrint("I", "WIFI", "pass: " + _password);
SerialPrint("i", "WIFI", "ssid: " + _ssid);
SerialPrint("i", "WIFI", "pass: " + _password);
}
while (--tries && WiFi.status() != WL_CONNECTED) {
@@ -38,16 +38,16 @@ void routerConnect() {
startAPMode();
} else {
Serial.println("");
SerialPrint("I", "WIFI", "http://" + WiFi.localIP().toString());
SerialPrint("i", "WIFI", "http://" + WiFi.localIP().toString());
jsonWriteStr(settingsFlashJson, "ip", WiFi.localIP().toString());
//mqttInit();
}
SerialPrint("I", F("WIFI"), F("Network Init"));
SerialPrint("i", F("WIFI"), F("Network Init"));
}
bool startAPMode() {
SerialPrint("I", "WIFI", "AP Mode");
SerialPrint("i", "WIFI", "AP Mode");
WiFi.disconnect();
WiFi.mode(WIFI_AP);
@@ -58,7 +58,7 @@ bool startAPMode() {
WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str());
IPAddress myIP = WiFi.softAPIP();
SerialPrint("I", "WIFI", "AP IP: " + myIP.toString());
SerialPrint("i", "WIFI", "AP IP: " + myIP.toString());
jsonWriteStr(settingsFlashJson, "ip", myIP.toString());
// if (jsonReadInt(paramsHeapJson, "pass_status") != 1) {
@@ -66,7 +66,7 @@ bool startAPMode() {
WIFI_SCAN, 10 * 1000, [&](void*) {
String sta_ssid = jsonReadStr(settingsFlashJson, "routerssid");
SerialPrint("I", "WIFI", "scanning for " + sta_ssid);
SerialPrint("i", "WIFI", "scanning for " + sta_ssid);
if (RouterFind(sta_ssid)) {
ts.remove(WIFI_SCAN);
@@ -82,19 +82,19 @@ bool startAPMode() {
boolean RouterFind(String ssid) {
bool res = false;
int n = WiFi.scanComplete();
SerialPrint("I", "WIFI", "scan result: " + String(n, DEC));
SerialPrint("i", "WIFI", "scan result: " + String(n, DEC));
if (n == -2) { //Сканирование не было запущено, запускаем
SerialPrint("I", "WIFI", "start scanning");
SerialPrint("i", "WIFI", "start scanning");
WiFi.scanNetworks(true, false); // async, show_hidden
}
else if (n == -1) { //Сканирование все еще выполняется
SerialPrint("I", "WIFI", "scanning in progress");
SerialPrint("i", "WIFI", "scanning in progress");
}
else if (n == 0) { //ни одна сеть не найдена
SerialPrint("I", "WIFI", "no networks found");
SerialPrint("i", "WIFI", "no networks found");
WiFi.scanNetworks(true, false);
}
@@ -103,7 +103,7 @@ boolean RouterFind(String ssid) {
if (WiFi.SSID(i) == ssid) {
res = true;
}
SerialPrint("I", "WIFI", (res ? "*" : "") + String(i, DEC) + ") " + WiFi.SSID(i));
SerialPrint("i", "WIFI", (res ? "*" : "") + String(i, DEC) + ") " + WiFi.SSID(i));
}
}
WiFi.scanDelete();
@@ -138,7 +138,7 @@ uint8_t RSSIquality() {
void wifiSignalInit() {
ts.add(
SYGNAL, 1000 * 60, [&](void*) {
//SerialPrint("I", "System", printMemoryStatus());
//SerialPrint("i", "System", printMemoryStatus());
//getFSInfo();