From 1d7f85f462e26cc38f84eaa113a5fdfa4b127a98 Mon Sep 17 00:00:00 2001 From: Yurii Date: Thu, 6 Nov 2025 13:29:59 +0300 Subject: [PATCH] refactor: migrating from Telnet to WebSerial for remote logging --- platformio.ini | 9 +++++---- secrets.default.ini | 3 +-- src/MainTask.h | 35 +++++------------------------------ src/MqttTask.h | 2 +- src/PortalTask.h | 6 ++++++ src/Settings.h | 5 ++--- src/defines.h | 10 +++------- src/main.cpp | 26 +++++++++++++------------- src/strings.h | 2 +- src/utils.h | 24 +++++++----------------- src_data/locales/cn.json | 8 ++------ src_data/locales/en.json | 8 ++------ src_data/locales/it.json | 8 ++------ src_data/locales/nl.json | 8 ++------ src_data/locales/ru.json | 8 ++------ src_data/pages/settings.html | 13 +++---------- src_data/scripts/utils.js | 30 ++++++++++++++++++------------ 17 files changed, 75 insertions(+), 130 deletions(-) diff --git a/platformio.ini b/platformio.ini index 79b2ee1..e48fd26 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,16 +20,17 @@ lib_deps = ESP32Async/AsyncTCP ;ESP32Async/ESPAsyncWebServer https://github.com/ESP32Async/ESPAsyncWebServer#main + mathieucarbou/MycilaWebSerial@^8.2.0 bblanchon/ArduinoJson@^7.4.2 ;ihormelnyk/OpenTherm Library@^1.1.5 https://github.com/Laxilef/opentherm_library#esp32_timer arduino-libraries/ArduinoMqttClient@^0.1.8 - lennarthennigs/ESP Telnet@^2.2.3 gyverlibs/FileData@^1.0.3 gyverlibs/GyverPID@^3.3.2 gyverlibs/GyverBlinker@^1.1.1 https://github.com/pstolarz/Arduino-Temperature-Control-Library.git#OneWireNg - laxilef/TinyLogger@^1.1.1 + ;laxilef/TinyLogger@^1.1.1 + https://github.com/Laxilef/TinyLogger#custom_handlers build_type = ${secrets.build_type} build_flags = -mtext-section-literals @@ -40,10 +41,10 @@ build_flags = -D CONFIG_ASYNC_TCP_STACK_SIZE=4096 -D ARDUINOJSON_USE_DOUBLE=0 -D ARDUINOJSON_USE_LONG_LONG=0 + -D TINYLOGGER_GLOBAL -D DEFAULT_SERIAL_ENABLED=${secrets.serial_enabled} -D DEFAULT_SERIAL_BAUD=${secrets.serial_baud} - -D DEFAULT_TELNET_ENABLED=${secrets.telnet_enabled} - -D DEFAULT_TELNET_PORT=${secrets.telnet_port} + -D DEFAULT_WEBSERIAL_ENABLED=${secrets.webserial_enabled} -D DEFAULT_LOG_LEVEL=${secrets.log_level} -D DEFAULT_HOSTNAME='"${secrets.hostname}"' -D DEFAULT_AP_SSID='"${secrets.ap_ssid}"' diff --git a/secrets.default.ini b/secrets.default.ini index f478977..2aaa9f2 100644 --- a/secrets.default.ini +++ b/secrets.default.ini @@ -3,8 +3,7 @@ build_type = release serial_enabled = true serial_baud = 115200 -telnet_enabled = true -telnet_port = 23 +webserial_enabled = true log_level = 5 hostname = opentherm diff --git a/src/MainTask.h b/src/MainTask.h index 8d746e0..5c6bcbc 100644 --- a/src/MainTask.h +++ b/src/MainTask.h @@ -6,7 +6,6 @@ extern NetworkMgr* network; extern MqttTask* tMqtt; extern OpenThermTask* tOt; extern FileData fsNetworkSettings, fsSettings, fsSensorsSettings; -extern ESPTelnetStream* telnetStream; class MainTask : public Task { @@ -40,7 +39,6 @@ protected: PumpStartReason extPumpStartReason = PumpStartReason::NONE; unsigned long externalPumpStartTime = 0; bool ntpStarted = false; - bool telnetStarted = false; bool emergencyDetected = false; unsigned long emergencyFlipTime = 0; bool freezeDetected = false; @@ -106,9 +104,9 @@ protected: vars.network.connected = network->isConnected(); vars.network.rssi = network->isConnected() ? WiFi.RSSI() : 0; - if (settings.system.logLevel >= TinyLogger::Level::SILENT && settings.system.logLevel <= TinyLogger::Level::VERBOSE) { + if (settings.system.logLevel >= TinyLoggerLevel::SILENT && settings.system.logLevel <= TinyLoggerLevel::VERBOSE) { if (Log.getLevel() != settings.system.logLevel) { - Log.setLevel(static_cast(settings.system.logLevel)); + Log.setLevel(static_cast(settings.system.logLevel)); } } @@ -123,11 +121,6 @@ protected: } } - if (!this->telnetStarted && telnetStream != nullptr) { - telnetStream->begin(23, false); - this->telnetStarted = true; - } - if (settings.mqtt.enabled && !tMqtt->isEnabled()) { tMqtt->enable(); @@ -142,11 +135,6 @@ protected: this->ntpStarted = false; } - if (this->telnetStarted) { - telnetStream->stop(); - this->telnetStarted = false; - } - if (tMqtt->isEnabled()) { tMqtt->disable(); } @@ -160,23 +148,10 @@ protected: } this->ledStatus(); - // telnet - if (this->telnetStarted) { - this->yield(); - telnetStream->loop(); - this->yield(); - } - // anti memory leak - for (Stream* stream : Log.getStreams()) { - while (stream->available() > 0) { - stream->read(); - - #ifdef ARDUINO_ARCH_ESP8266 - ::optimistic_yield(1000); - #endif - } + while (Serial.available() > 0) { + Serial.read(); } // heap info @@ -215,7 +190,7 @@ protected: vars.states.restarting = true; } - if (settings.system.logLevel < TinyLogger::Level::VERBOSE) { + if (settings.system.logLevel < TinyLoggerLevel::VERBOSE) { return; } diff --git a/src/MqttTask.h b/src/MqttTask.h index 7578f72..bc170e0 100644 --- a/src/MqttTask.h +++ b/src/MqttTask.h @@ -416,7 +416,7 @@ protected: return; } - if (settings.system.logLevel >= TinyLogger::Level::TRACE) { + if (settings.system.logLevel >= TinyLoggerLevel::TRACE) { Log.strace(FPSTR(L_MQTT_MSG), F("Topic: %s\r\n> "), topic.c_str()); if (Log.lock()) { for (size_t i = 0; i < length; i++) { diff --git a/src/PortalTask.h b/src/PortalTask.h index d97cece..fd5469e 100644 --- a/src/PortalTask.h +++ b/src/PortalTask.h @@ -13,6 +13,7 @@ using namespace NetworkUtils; extern NetworkMgr* network; extern FileData fsNetworkSettings, fsSettings, fsSensorsSettings; extern MqttTask* tMqtt; +extern WebSerial* webSerial; class PortalTask : public LeanTask { @@ -76,6 +77,11 @@ protected: return request->requestAuthentication(AsyncAuthType::AUTH_BASIC, PROJECT_NAME, "Authentication failed"); }); + // web serial + if (webSerial != nullptr) { + webSerial->begin(this->webServer); + } + // index page this->webServer->on("/", HTTP_GET, [](AsyncWebServerRequest *request) { request->redirect("/index.html"); diff --git a/src/Settings.h b/src/Settings.h index ecb4d15..0d4a548 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -32,9 +32,8 @@ struct Settings { } serial; struct { - bool enabled = DEFAULT_TELNET_ENABLED; - unsigned short port = DEFAULT_TELNET_PORT; - } telnet; + bool enabled = DEFAULT_WEBSERIAL_ENABLED; + } webSerial; struct { char server[49] = "pool.ntp.org"; diff --git a/src/defines.h b/src/defines.h index f5e0de9..f97f54f 100644 --- a/src/defines.h +++ b/src/defines.h @@ -42,12 +42,8 @@ #define DEFAULT_SERIAL_BAUD 115200 #endif -#ifndef DEFAULT_TELNET_ENABLED - #define DEFAULT_TELNET_ENABLED true -#endif - -#ifndef DEFAULT_TELNET_PORT - #define DEFAULT_TELNET_PORT 23 +#ifndef DEFAULT_WEBSERIAL_ENABLED + #define DEFAULT_WEBSERIAL_ENABLED true #endif #ifndef USE_BLE @@ -75,7 +71,7 @@ #endif #ifndef DEFAULT_LOG_LEVEL - #define DEFAULT_LOG_LEVEL TinyLogger::Level::VERBOSE + #define DEFAULT_LOG_LEVEL TinyLoggerLevel::VERBOSE #endif #ifndef DEFAULT_STATUS_LED_GPIO diff --git a/src/main.cpp b/src/main.cpp index ff50fa5..97996a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include "defines.h" #include "strings.h" @@ -34,7 +34,7 @@ using namespace NetworkUtils; // Vars -ESPTelnetStream* telnetStream = nullptr; +WebSerial* webSerial = nullptr; NetworkMgr* network = nullptr; Sensors::Result sensorsResults[SENSORS_AMOUNT]; @@ -58,7 +58,7 @@ void setup() { Sensors::results = sensorsResults; LittleFS.begin(); - Log.setLevel(TinyLogger::Level::VERBOSE); + Log.setLevel(TinyLoggerLevel::VERBOSE); Log.setServiceTemplate("\033[1m[%s]\033[22m"); Log.setLevelTemplate("\033[1m[%s]\033[22m"); Log.setMsgPrefix("\033[m "); @@ -76,7 +76,7 @@ void setup() { #if ARDUINO_USB_MODE Serial.setTxBufferSize(512); #endif - Log.addStream(&Serial); + Log.addHandler(&Serial); Log.print("\n\n\r"); // @@ -160,24 +160,24 @@ void setup() { // Logs settings if (!settings.system.serial.enabled) { Serial.end(); - Log.clearStreams(); + Log.clearHandlers(); } else if (settings.system.serial.baudrate != 115200) { Serial.end(); - Log.clearStreams(); + Log.clearHandlers(); Serial.begin(settings.system.serial.baudrate); - Log.addStream(&Serial); + Log.addHandler(&Serial); } - if (settings.system.telnet.enabled) { - telnetStream = new ESPTelnetStream; - telnetStream->setKeepAliveInterval(500); - Log.addStream(telnetStream); + if (settings.system.webSerial.enabled) { + webSerial = new WebSerial(); + webSerial->setBuffer(100); + Log.addHandler(webSerial); } - if (settings.system.logLevel >= TinyLogger::Level::SILENT && settings.system.logLevel <= TinyLogger::Level::VERBOSE) { - Log.setLevel(static_cast(settings.system.logLevel)); + if (settings.system.logLevel >= TinyLoggerLevel::SILENT && settings.system.logLevel <= TinyLoggerLevel::VERBOSE) { + Log.setLevel(static_cast(settings.system.logLevel)); } // diff --git a/src/strings.h b/src/strings.h index ca85f6a..24fe593 100644 --- a/src/strings.h +++ b/src/strings.h @@ -198,7 +198,6 @@ const char S_SUMMER_WINTER_MODE[] PROGMEM = "summerWinterMode" const char S_SYSTEM[] PROGMEM = "system"; const char S_TARGET[] PROGMEM = "target"; const char S_TARGET_TEMP[] PROGMEM = "targetTemp"; -const char S_TELNET[] PROGMEM = "telnet"; const char S_TEMPERATURE[] PROGMEM = "temperature"; const char S_THRESHOLD_HIGH[] PROGMEM = "thresholdHigh"; const char S_THRESHOLD_LOW[] PROGMEM = "thresholdLow"; @@ -217,3 +216,4 @@ const char S_USE_DHCP[] PROGMEM = "useDhcp"; const char S_USER[] PROGMEM = "user"; const char S_VALUE[] PROGMEM = "value"; const char S_VERSION[] PROGMEM = "version"; +const char S_WEBSERIAL[] PROGMEM = "webSerial"; \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index 8442dbf..7836844 100644 --- a/src/utils.h +++ b/src/utils.h @@ -425,9 +425,8 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) { serial[FPSTR(S_ENABLED)] = src.system.serial.enabled; serial[FPSTR(S_BAUDRATE)] = src.system.serial.baudrate; - auto telnet = system[FPSTR(S_TELNET)].to(); - telnet[FPSTR(S_ENABLED)] = src.system.telnet.enabled; - telnet[FPSTR(S_PORT)] = src.system.telnet.port; + auto webSerial = system[FPSTR(S_WEBSERIAL)].to(); + webSerial[FPSTR(S_ENABLED)] = src.system.webSerial.enabled; auto ntp = system[FPSTR(S_NTP)].to(); ntp[FPSTR(S_SERVER)] = src.system.ntp.server; @@ -576,7 +575,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false if (!src[FPSTR(S_SYSTEM)][FPSTR(S_LOG_LEVEL)].isNull()) { uint8_t value = src[FPSTR(S_SYSTEM)][FPSTR(S_LOG_LEVEL)].as(); - if (value != dst.system.logLevel && value >= TinyLogger::Level::SILENT && value <= TinyLogger::Level::VERBOSE) { + if (value != dst.system.logLevel && value >= TinyLoggerLevel::SILENT && value <= TinyLoggerLevel::VERBOSE) { dst.system.logLevel = value; changed = true; } @@ -602,20 +601,11 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false } } - if (src[FPSTR(S_SYSTEM)][FPSTR(S_TELNET)][FPSTR(S_ENABLED)].is()) { - bool value = src[FPSTR(S_SYSTEM)][FPSTR(S_TELNET)][FPSTR(S_ENABLED)].as(); + if (src[FPSTR(S_SYSTEM)][FPSTR(S_WEBSERIAL)][FPSTR(S_ENABLED)].is()) { + bool value = src[FPSTR(S_SYSTEM)][FPSTR(S_WEBSERIAL)][FPSTR(S_ENABLED)].as(); - if (value != dst.system.telnet.enabled) { - dst.system.telnet.enabled = value; - changed = true; - } - } - - if (!src[FPSTR(S_SYSTEM)][FPSTR(S_TELNET)][FPSTR(S_PORT)].isNull()) { - unsigned short value = src[FPSTR(S_SYSTEM)][FPSTR(S_TELNET)][FPSTR(S_PORT)].as(); - - if (value > 0 && value <= 65535 && value != dst.system.telnet.port) { - dst.system.telnet.port = value; + if (value != dst.system.webSerial.enabled) { + dst.system.webSerial.enabled = value; changed = true; } } diff --git a/src_data/locales/cn.json b/src_data/locales/cn.json index 10a3a6b..d0f4358 100644 --- a/src_data/locales/cn.json +++ b/src_data/locales/cn.json @@ -341,12 +341,8 @@ "enable": "启用串口", "baud": "串口波特率" }, - "telnet": { - "enable": "启用 Telnet", - "port": { - "title": "Telnet 端口", - "note": "默认值:23" - } + "webSerial": { + "enable": "启用 WebSerial" }, "ntp": { "server": "NTP服务器", diff --git a/src_data/locales/en.json b/src_data/locales/en.json index 24ac153..2724c6b 100644 --- a/src_data/locales/en.json +++ b/src_data/locales/en.json @@ -341,12 +341,8 @@ "enable": "Enabled Serial port", "baud": "Serial port baud rate" }, - "telnet": { - "enable": "Enabled Telnet", - "port": { - "title": "Telnet port", - "note": "Default: 23" - } + "webSerial": { + "enable": "Enabled WebSerial" }, "ntp": { "server": "NTP server", diff --git a/src_data/locales/it.json b/src_data/locales/it.json index 2e4f15c..cde255a 100644 --- a/src_data/locales/it.json +++ b/src_data/locales/it.json @@ -341,12 +341,8 @@ "enable": "Porta seriale attivata", "baud": "Porta seriale baud rate" }, - "telnet": { - "enable": "Telnet attivato", - "port": { - "title": "Porta Telnet", - "note": "Default: 23" - } + "webSerial": { + "enable": "WebSerial attivato" }, "ntp": { "server": "NTP server", diff --git a/src_data/locales/nl.json b/src_data/locales/nl.json index 65ff5a3..3fa3623 100644 --- a/src_data/locales/nl.json +++ b/src_data/locales/nl.json @@ -313,12 +313,8 @@ "enable": "Seriële poort ingeschakeld", "baud": "Baudrate seriële poort" }, - "telnet": { - "enable": "Telnet ingeschakeld", - "port": { - "title": "Telnet-poort", - "note": "Standaard: 23" - } + "webSerial": { + "enable": "WebSerial ingeschakeld" }, "ntp": { "server": "NTP-server", diff --git a/src_data/locales/ru.json b/src_data/locales/ru.json index 7a6e627..b26662f 100644 --- a/src_data/locales/ru.json +++ b/src_data/locales/ru.json @@ -341,12 +341,8 @@ "enable": "Вкл. Serial порт", "baud": "Скорость Serial порта" }, - "telnet": { - "enable": "Вкл. Telnet", - "port": { - "title": "Telnet порт", - "note": "По умолчанию: 23" - } + "webSerial": { + "enable": "Вкл. WebSerial" }, "ntp": { "server": "NTP сервер", diff --git a/src_data/pages/settings.html b/src_data/pages/settings.html index f5c4494..2f49c57 100644 --- a/src_data/pages/settings.html +++ b/src_data/pages/settings.html @@ -126,8 +126,8 @@ - - settings.note.restart @@ -876,8 +870,7 @@ setSelectValue("[name='system[logLevel]']", data.system.logLevel); setCheckboxValue("[name='system[serial][enabled]']", data.system.serial.enabled); setSelectValue("[name='system[serial][baudrate]']", data.system.serial.baudrate); - setCheckboxValue("[name='system[telnet][enabled]']", data.system.telnet.enabled); - setInputValue("[name='system[telnet][port]']", data.system.telnet.port); + setCheckboxValue("[name='system[webSerial][enabled]']", data.system.webSerial.enabled); setInputValue("[name='system[ntp][server]']", data.system.ntp.server); setInputValue("[name='system[ntp][timezone]']", data.system.ntp.timezone); setRadioValue("[name='system[unitSystem]']", data.system.unitSystem); diff --git a/src_data/scripts/utils.js b/src_data/scripts/utils.js index 836bcb9..8cf9ef5 100644 --- a/src_data/scripts/utils.js +++ b/src_data/scripts/utils.js @@ -313,19 +313,25 @@ const setupRestoreBackupForm = (formSelector) => { console.log("Backup: ", data); if (data.settings != undefined) { - let response = await fetch(url, { - method: "POST", - cache: "no-cache", - credentials: "include", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({"settings": data.settings}) - }); + for (var key in data.settings) { + let response = await fetch(url, { + method: "POST", + cache: "no-cache", + credentials: "include", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + "settings": { + [key]: data.settings[key] + } + }) + }); - if (!response.ok) { - onFailed(); - return; + if (!response.ok) { + onFailed(); + return; + } } }