From f173dad9b57dcae4f261c38da913c8c37bd2bf91 Mon Sep 17 00:00:00 2001 From: e2002 Date: Thu, 17 Jul 2025 15:33:24 +0300 Subject: [PATCH] v0.9.530 --- README.md | 13 + yoRadio/src/audioI2S/Audio.cpp | 3 +- yoRadio/src/audioI2S/AudioEx.h | 4 - yoRadio/src/audioVS1053/audioVS1053Ex.cpp | 19 +- yoRadio/src/core/commandhandler.cpp | 117 +++ yoRadio/src/core/commandhandler.h | 18 + yoRadio/src/core/config.cpp | 164 ++++- yoRadio/src/core/config.h | 19 +- yoRadio/src/core/netserver.cpp | 849 ++++++---------------- yoRadio/src/core/netserver.h | 17 +- yoRadio/src/core/options.h | 16 +- yoRadio/src/core/telnet.cpp | 6 +- yoRadio/src/displays/nextion.cpp | 8 - yoRadio/src/main.cpp | 5 +- 14 files changed, 606 insertions(+), 652 deletions(-) create mode 100644 yoRadio/src/core/commandhandler.cpp create mode 100644 yoRadio/src/core/commandhandler.h diff --git a/README.md b/README.md index 546b924..94bb273 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,19 @@ Work is in progress... --- ## Version history +### 0.9.530 +- optimization of webserver/socket code in netserver.cpp, part#1 +- added support for ArduinoOTA (OTA update from Arduino IDE) (disabled by default)\ + to enable you need to add to myoptions.h: `#define USE_OTA true`\ + set password: in myoptions.h `#define OTA_PASS "myotapassword12345"` +- in web interface added basic HTTP authentication capability (disabled by default)\ + to enable you need to add to myoptions.h:\ + `#define HTTP_USER "user"`\ + `#define HTTP_PASS "password"` +- added "emergency firmware uploader" form (for unforeseen cases) http://ipaddress/emergency +- added config (sys.config) telnet command that displays the same information usually shown over serial at boot. +- bug fixes 🪲 + ### 0.9.515 - fixed a bug with resetting all parameters when resetting only one section of parameters diff --git a/yoRadio/src/audioI2S/Audio.cpp b/yoRadio/src/audioI2S/Audio.cpp index f98fdf1..e444487 100644 --- a/yoRadio/src/audioI2S/Audio.cpp +++ b/yoRadio/src/audioI2S/Audio.cpp @@ -3613,7 +3613,7 @@ bool Audio::parseHttpResponseHeader() { // this is the response to a GET / reque if(audio_showstation) audio_showstation(""); if(audio_icydescription) audio_icydescription(""); if(audio_icyurl) audio_icyurl(""); - AUDIO_ERROR("Host %s not available", m_lastHost); + AUDIO_ERROR("Host not available"); m_lastHost[0] = '\0'; setDatamode(AUDIO_NONE); stopSong(); @@ -3883,6 +3883,7 @@ bool Audio:: initializeDecoder(){ return true; exit: + AUDIO_ERROR("Not enough free memory to initialize the decoder: %u bytes free", ESP.getFreeHeap()); stopSong(); return false; } diff --git a/yoRadio/src/audioI2S/AudioEx.h b/yoRadio/src/audioI2S/AudioEx.h index 448d23e..c25184c 100644 --- a/yoRadio/src/audioI2S/AudioEx.h +++ b/yoRadio/src/audioI2S/AudioEx.h @@ -36,10 +36,6 @@ #define AUDIOBUFFER_MULTIPLIER2 8 #endif -#ifndef HEADER_TIMEOUT -#define HEADER_TIMEOUT 5000 -#endif - #if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0) #include "hal/gpio_ll.h" #endif diff --git a/yoRadio/src/audioVS1053/audioVS1053Ex.cpp b/yoRadio/src/audioVS1053/audioVS1053Ex.cpp index 464ac5f..199dd7e 100644 --- a/yoRadio/src/audioVS1053/audioVS1053Ex.cpp +++ b/yoRadio/src/audioVS1053/audioVS1053Ex.cpp @@ -1203,10 +1203,23 @@ bool Audio::latinToUTF8(char* buff, size_t bufflen){ //--------------------------------------------------------------------------------------------------------------------- bool Audio::parseHttpResponseHeader() { // this is the response to a GET / request - + static uint32_t notavailablefor = 0; if(getDatamode() != HTTP_RESPONSE_HEADER) return false; - if(_client->available() == 0) return false; - + if(_client->available() == 0) { + if (notavailablefor == 0) notavailablefor = millis(); + if (millis() - notavailablefor > HEADER_TIMEOUT) { + notavailablefor = 0; + if(audio_showstation) audio_showstation(""); + if(audio_icydescription) audio_icydescription(""); + if(audio_icyurl) audio_icyurl(""); + AUDIO_ERROR("Host not available"); + m_lastHost[0] = '\0'; + setDatamode(AUDIO_NONE); + stopSong(); + } + return false; + } + notavailablefor = 0; char rhl[512]; // responseHeaderline bool ct_seen = false; uint32_t ctime = millis(); diff --git a/yoRadio/src/core/commandhandler.cpp b/yoRadio/src/core/commandhandler.cpp new file mode 100644 index 0000000..9e880b2 --- /dev/null +++ b/yoRadio/src/core/commandhandler.cpp @@ -0,0 +1,117 @@ +#include "commandhandler.h" +#include "player.h" +#include "display.h" +#include "netserver.h" +#include "config.h" +#include "controls.h" +#include "options.h" + +CommandHandler cmd; + +bool CommandHandler::exec(const char *command, const char *value, uint8_t cid) { + if (strEquals(command, "start")) { player.sendCommand({PR_PLAY, config.lastStation()}); return true; } + if (strEquals(command, "stop")) { player.sendCommand({PR_STOP, 0}); return true; } + if (strEquals(command, "toggle")) { player.toggle(); return true; } + if (strEquals(command, "prev")) { player.prev(); return true; } + if (strEquals(command, "next")) { player.next(); return true; } + if (strEquals(command, "volm")) { player.stepVol(false); return true; } + if (strEquals(command, "volp")) { player.stepVol(true); return true; } +#ifdef USE_SD + if (strEquals(command, "mode")) { config.changeMode(atoi(value)); return true; } +#endif + if (strEquals(command, "reset") && cid==0) { config.reset(); return true; } + if (strEquals(command, "ballance")) { config.setBalance(atoi(value)); return true; } + if (strEquals(command, "playstation") || strEquals(command, "play")){ + int id = atoi(value); + if (id < 1) id = 1; + uint16_t cs = config.playlistLength(); + if (id > cs) id = cs; + player.sendCommand({PR_PLAY, id}); + return true; + } + if (strEquals(command, "vol")){ + int v = atoi(value); + config.store.volume = v < 0 ? 0 : (v > 254 ? 254 : v); + player.setVol(v); + return true; + } + if (strEquals(command, "dspon")) { config.setDspOn(atoi(value)!=0); return true; } + if (strEquals(command, "dim")) { int d=atoi(value); config.store.brightness = (uint8_t)(d < 0 ? 0 : (d > 100 ? 100 : d)); config.setBrightness(true); return true; } + if (strEquals(command, "clearspiffs")){ config.spiffsCleanup(); config.saveValue(&config.store.play_mode, static_cast(PM_WEB)); return true; } + /*********************************************/ + /****************** WEBSOCKET ****************/ + /*********************************************/ + if (strEquals(command, "getindex")) { netserver.requestOnChange(GETINDEX, cid); return true; } + + if (strEquals(command, "getsystem")) { netserver.requestOnChange(GETSYSTEM, cid); return true; } + if (strEquals(command, "getscreen")) { netserver.requestOnChange(GETSCREEN, cid); return true; } + if (strEquals(command, "gettimezone")){ netserver.requestOnChange(GETTIMEZONE, cid); return true; } + if (strEquals(command, "getcontrols")){ netserver.requestOnChange(GETCONTROLS, cid); return true; } + if (strEquals(command, "getweather")) { netserver.requestOnChange(GETWEATHER, cid); return true; } + if (strEquals(command, "getactive")) { netserver.requestOnChange(GETACTIVE, cid); return true; } + if (strEquals(command, "newmode")) { config.newConfigMode = atoi(value); netserver.requestOnChange(CHANGEMODE, cid); return true; } + + if (strEquals(command, "invertdisplay")){ config.saveValue(&config.store.invertdisplay, static_cast(atoi(value))); display.invert(); return true; } + if (strEquals(command, "numplaylist")) { config.saveValue(&config.store.numplaylist, static_cast(atoi(value))); display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); return true; } + if (strEquals(command, "fliptouch")) { config.saveValue(&config.store.fliptouch, static_cast(atoi(value))); flipTS(); return true; } + if (strEquals(command, "dbgtouch")) { config.saveValue(&config.store.dbgtouch, static_cast(atoi(value))); return true; } + if (strEquals(command, "flipscreen")) { config.saveValue(&config.store.flipscreen, static_cast(atoi(value))); display.flip(); display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); return true; } + if (strEquals(command, "brightness")) { if (!config.store.dspon) netserver.requestOnChange(DSPON, 0); config.store.brightness = static_cast(atoi(value)); config.setBrightness(true); return true; } + if (strEquals(command, "screenon")) { config.setDspOn(static_cast(atoi(value))); return true; } + if (strEquals(command, "contrast")) { config.saveValue(&config.store.contrast, static_cast(atoi(value))); display.setContrast(); return true; } + if (strEquals(command, "screensaverenabled")){ config.enableScreensaver(static_cast(atoi(value))); return true; } + if (strEquals(command, "screensavertimeout")){ config.setScreensaverTimeout(static_cast(atoi(value))); return true; } + if (strEquals(command, "screensaverblank")) { config.setScreensaverBlank(static_cast(atoi(value))); return true; } + if (strEquals(command, "screensaverplayingenabled")){ config.setScreensaverPlayingEnabled(static_cast(atoi(value))); return true; } + if (strEquals(command, "screensaverplayingtimeout")){ config.setScreensaverPlayingTimeout(static_cast(atoi(value))); return true; } + if (strEquals(command, "screensaverplayingblank")) { config.setScreensaverPlayingBlank(static_cast(atoi(value))); return true; } + + if (strEquals(command, "tzh")) { config.saveValue(&config.store.tzHour, static_cast(atoi(value))); return true; } + if (strEquals(command, "tzm")) { config.saveValue(&config.store.tzMin, static_cast(atoi(value))); return true; } + if (strEquals(command, "sntp2")) { config.saveValue(config.store.sntp2, value, 35, false); return true; } + if (strEquals(command, "sntp1")) { config.setSntpOne(value); return true; } + + if (strEquals(command, "volsteps")) { config.saveValue(&config.store.volsteps, static_cast(atoi(value))); return true; } + if (strEquals(command, "encacc")) { setEncAcceleration(static_cast(atoi(value))); return true; } + if (strEquals(command, "irtlp")) { setIRTolerance(static_cast(atoi(value))); return true; } + if (strEquals(command, "oneclickswitching")){ config.saveValue(&config.store.skipPlaylistUpDown, static_cast(atoi(value))); return true; } + if (strEquals(command, "showweather")) { config.setShowweather(static_cast(atoi(value))); return true; } + if (strEquals(command, "lat")) { config.saveValue(config.store.weatherlat, value, 10, false); return true; } + if (strEquals(command, "lon")) { config.saveValue(config.store.weatherlon, value, 10, false); return true; } + if (strEquals(command, "key")) { config.setWeatherKey(value); return true; } + //<-----TODO + if (strEquals(command, "volume")) { player.setVol(static_cast(atoi(value))); return true; } + if (strEquals(command, "sdpos")) { config.setSDpos(static_cast(atoi(value))); return true; } + if (strEquals(command, "snuffle")) { config.setSnuffle(strcmp(value, "true") == 0); return true; } + if (strEquals(command, "balance")) { config.setBalance(static_cast(atoi(value))); return true; } + if (strEquals(command, "reboot")) { ESP.restart(); return true; } + if (strEquals(command, "format")) { SPIFFS.format(); ESP.restart(); return true; } + if (strEquals(command, "submitplaylist")) { return true; } + +#if IR_PIN!=255 + if (strEquals(command, "irbtn")) { config.setIrBtn(atoi(value)); return true; } + if (strEquals(command, "chkid")) { config.irchck = static_cast(atoi(value)); return true; } + if (strEquals(command, "irclr")) { config.ircodes.irVals[config.irindex][static_cast(atoi(value))] = 0; return true; } +#endif + if (strEquals(command, "reset")) { config.resetSystem(value, cid); return true; } + + if (strEquals(command, "smartstart")){ uint8_t ss = atoi(value) == 1 ? 1 : 2; if (!player.isRunning() && ss == 1) ss = 0; config.setSmartStart(ss); return true; } + if (strEquals(command, "audioinfo")) { config.saveValue(&config.store.audioinfo, static_cast(atoi(value))); display.putRequest(AUDIOINFO); return true; } + if (strEquals(command, "vumeter")) { config.saveValue(&config.store.vumeter, static_cast(atoi(value))); display.putRequest(SHOWVUMETER); return true; } + if (strEquals(command, "softap")) { config.saveValue(&config.store.softapdelay, static_cast(atoi(value))); return true; } + if (strEquals(command, "mdnsname")) { config.saveValue(config.store.mdnsname, value, MDNS_LENGTH); return true; } + if (strEquals(command, "rebootmdns")){ + char buf[MDNS_LENGTH*2]; + if(strlen(config.store.mdnsname)>0) snprintf(buf, MDNS_LENGTH*2, "{\"redirect\": \"http://%s.local\"}", config.store.mdnsname); + else snprintf(buf, MDNS_LENGTH*2, "{\"redirect\": \"http://%s/\"}", WiFi.localIP().toString().c_str()); + websocket.text(cid, buf); delay(500); ESP.restart(); + return true; + } + + return false; +} + + + + + diff --git a/yoRadio/src/core/commandhandler.h b/yoRadio/src/core/commandhandler.h new file mode 100644 index 0000000..c835426 --- /dev/null +++ b/yoRadio/src/core/commandhandler.h @@ -0,0 +1,18 @@ +#ifndef commandhandler_h +#define commandhandler_h + +#include + +class CommandHandler { +public: + bool exec(const char *command, const char *value, uint8_t cid=0); + +private: + static bool strEquals(const char *a, const char *b) { + return strcmp(a, b) == 0; + } +}; + +extern CommandHandler cmd; + +#endif diff --git a/yoRadio/src/core/config.cpp b/yoRadio/src/core/config.cpp index f478000..d3c520b 100644 --- a/yoRadio/src/core/config.cpp +++ b/yoRadio/src/core/config.cpp @@ -5,6 +5,7 @@ #include "player.h" #include "network.h" #include "netserver.h" +#include "controls.h" #ifdef USE_SD #include "sdmanager.h" #endif @@ -43,6 +44,7 @@ void Config::init() { sdResumePos = 0; screensaverTicks = 0; screensaverPlayingTicks = 0; + newConfigMode = 0; isScreensaver = false; bootInfo(); #if RTCSUPPORTED @@ -140,7 +142,7 @@ void Config::changeMode(int newmode){ return; } } - if(newmode<0){ + if(newmode<0||newmode>MAX_PLAY_MODE){ store.play_mode++; if(getMode() > MAX_PLAY_MODE) store.play_mode=0; }else{ @@ -319,6 +321,160 @@ void Config::reset(){ delay(500); ESP.restart(); } +void Config::enableScreensaver(bool val){ + saveValue(&store.screensaverEnabled, val); +#ifndef DSP_LCD + display.putRequest(NEWMODE, PLAYER); +#endif +} +void Config::setScreensaverTimeout(uint16_t val){ + val=constrain(val,5,65520); + saveValue(&store.screensaverTimeout, val); +#ifndef DSP_LCD + display.putRequest(NEWMODE, PLAYER); +#endif +} +void Config::setScreensaverBlank(bool val){ + saveValue(&store.screensaverBlank, val); +#ifndef DSP_LCD + display.putRequest(NEWMODE, PLAYER); +#endif +} +void Config::setScreensaverPlayingEnabled(bool val){ + saveValue(&store.screensaverPlayingEnabled, val); +#ifndef DSP_LCD + display.putRequest(NEWMODE, PLAYER); +#endif +} +void Config::setScreensaverPlayingTimeout(uint16_t val){ + val=constrain(val,1,1080); + config.saveValue(&config.store.screensaverPlayingTimeout, val); +#ifndef DSP_LCD + display.putRequest(NEWMODE, PLAYER); +#endif +} +void Config::setScreensaverPlayingBlank(bool val){ + saveValue(&store.screensaverPlayingBlank, val); +#ifndef DSP_LCD + display.putRequest(NEWMODE, PLAYER); +#endif +} +void Config::setSntpOne(const char *val){ + bool tzdone = false; + if (strlen(val) > 0 && strlen(store.sntp2) > 0) { + configTime(store.tzHour * 3600 + store.tzMin * 60, getTimezoneOffset(), val, store.sntp2); + tzdone = true; + } else if (strlen(val) > 0) { + configTime(store.tzHour * 3600 + store.tzMin * 60, getTimezoneOffset(), val); + tzdone = true; + } + if (tzdone) { + network.forceTimeSync = true; + saveValue(config.store.sntp1, val, 35); + } +} +void Config::setShowweather(bool val){ + config.saveValue(&config.store.showweather, val); + network.trueWeather=false; + network.forceWeather = true; + display.putRequest(SHOWWEATHER); +} +void Config::setWeatherKey(const char *val){ + saveValue(store.weatherkey, val, WEATHERKEY_LENGTH); + network.trueWeather=false; + display.putRequest(NEWMODE, CLEAR); + display.putRequest(NEWMODE, PLAYER); +} +void Config::setSDpos(uint32_t val){ + if (getMode()==PM_SDCARD){ + sdResumePos = 0; + if(!player.isRunning()){ + player.setResumeFilePos(val-player.sd_min); + player.sendCommand({PR_PLAY, config.store.lastSdStation}); + }else{ + player.setFilePos(val-player.sd_min); + } + } +} +#if IR_PIN!=255 +void Config::setIrBtn(int val){ + irindex = val; + netserver.irRecordEnable = (irindex >= 0); + irchck = 0; + netserver.irValsToWs(); + if (irindex < 0) saveIR(); +} +#endif +void Config::resetSystem(const char *val, uint8_t clientId){ + if (strcmp(val, "system") == 0) { + saveValue(&store.smartstart, (uint8_t)2, false); + saveValue(&store.audioinfo, false, false); + saveValue(&store.vumeter, false, false); + saveValue(&store.softapdelay, (uint8_t)0, false); + snprintf(store.mdnsname, MDNS_LENGTH, "yoradio-%x", getChipId()); + saveValue(store.mdnsname, store.mdnsname, MDNS_LENGTH, true, true); + display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); + netserver.requestOnChange(GETSYSTEM, clientId); + return; + } + if (strcmp(val, "screen") == 0) { + saveValue(&store.flipscreen, false, false); + display.flip(); + saveValue(&store.invertdisplay, false, false); + display.invert(); + saveValue(&store.dspon, true, false); + store.brightness = 100; + setBrightness(false); + saveValue(&store.contrast, (uint8_t)55, false); + display.setContrast(); + saveValue(&store.numplaylist, false); + saveValue(&store.screensaverEnabled, false); + saveValue(&store.screensaverTimeout, (uint16_t)20); + saveValue(&store.screensaverBlank, false); + saveValue(&store.screensaverPlayingEnabled, false); + saveValue(&store.screensaverPlayingTimeout, (uint16_t)5); + saveValue(&store.screensaverPlayingBlank, false); + display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); + netserver.requestOnChange(GETSCREEN, clientId); + return; + } + if (strcmp(val, "timezone") == 0) { + saveValue(&store.tzHour, (int8_t)3, false); + saveValue(&store.tzMin, (int8_t)0, false); + saveValue(store.sntp1, "pool.ntp.org", 35, false); + saveValue(store.sntp2, "0.ru.pool.ntp.org", 35); + configTime(store.tzHour * 3600 + store.tzMin * 60, getTimezoneOffset(), store.sntp1, store.sntp2); + network.forceTimeSync = true; + netserver.requestOnChange(GETTIMEZONE, clientId); + return; + } + if (strcmp(val, "weather") == 0) { + saveValue(&store.showweather, false, false); + saveValue(store.weatherlat, "55.7512", 10, false); + saveValue(store.weatherlon, "37.6184", 10, false); + saveValue(store.weatherkey, "", WEATHERKEY_LENGTH); + network.trueWeather=false; + display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); + netserver.requestOnChange(GETWEATHER, clientId); + return; + } + if (strcmp(val, "controls") == 0) { + saveValue(&store.volsteps, (uint8_t)1, false); + saveValue(&store.fliptouch, false, false); + saveValue(&store.dbgtouch, false, false); + saveValue(&store.skipPlaylistUpDown, false); + setEncAcceleration(200); + setIRTolerance(40); + netserver.requestOnChange(GETCONTROLS, clientId); + return; + } + if (strcmp(val, "1") == 0) { + config.reset(); + return; + } +} + + void Config::setDefaults() { store.config_set = 4262; @@ -373,10 +529,12 @@ void Config::setDefaults() { store.rotate90 = false; store.screensaverEnabled = false; store.screensaverTimeout = 20; + store.screensaverBlank = false; snprintf(store.mdnsname, MDNS_LENGTH, "yoradio-%x", getChipId()); store.skipPlaylistUpDown = false; store.screensaverPlayingEnabled = false; store.screensaverPlayingTimeout = 5; + store.screensaverPlayingBlank = false; eepromWrite(EEPROM_START, store); } @@ -419,6 +577,8 @@ void Config::setTone(int8_t bass, int8_t middle, int8_t trebble) { saveValue(&store.bass, bass, false); saveValue(&store.middle, middle, false); saveValue(&store.trebble, trebble); + player.setTone(store.bass, store.middle, store.trebble); + netserver.requestOnChange(EQUALIZER, 0); } void Config::setSmartStart(uint8_t ss) { @@ -427,6 +587,8 @@ void Config::setSmartStart(uint8_t ss) { void Config::setBalance(int8_t balance) { saveValue(&store.balance, balance); + player.setBalance(store.balance); + netserver.requestOnChange(BALANCE, 0); } uint8_t Config::setLastStation(uint16_t val) { diff --git a/yoRadio/src/core/config.h b/yoRadio/src/core/config.h index 6c564ff..819e659 100644 --- a/yoRadio/src/core/config.h +++ b/yoRadio/src/core/config.h @@ -7,6 +7,7 @@ #include //#include "SD.h" #include "options.h" +#include "telnet.h" #include "rtcsupport.h" #include "../pluginsManager/pluginsManager.h" @@ -32,7 +33,7 @@ #define DBGVB( ... ) #define DBGH() #endif -#define BOOTLOG( ... ) { char buf[120]; sprintf( buf, __VA_ARGS__ ) ; Serial.print("##[BOOT]#\t"); Serial.println(buf); } +#define BOOTLOG( ... ) { char buf[120]; sprintf( buf, __VA_ARGS__ ) ; telnet.print("##[BOOT]#\t"); telnet.printf("%s\n",buf); } #define EVERY_MS(x) static uint32_t tmr; bool flag = millis() - tmr >= (x); if (flag) tmr += (x); if (flag) #define REAL_PLAYL getMode()==PM_WEB?PLAYLIST_PATH:PLAYLIST_SD_PATH #define REAL_INDEX getMode()==PM_WEB?INDEX_PATH:INDEX_SD_PATH @@ -187,6 +188,7 @@ class Config { uint16_t screensaverTicks; uint16_t screensaverPlayingTicks; bool isScreensaver; + int newConfigMode; public: Config() {}; //void save(); @@ -243,6 +245,21 @@ class Config { uint8_t getMode() { return store.play_mode/* & 0b11*/; } void initPlaylistMode(); void reset(); + void enableScreensaver(bool val); + void setScreensaverTimeout(uint16_t val); + void setScreensaverBlank(bool val); + void setScreensaverPlayingEnabled(bool val); + void setScreensaverPlayingTimeout(uint16_t val); + void setScreensaverPlayingBlank(bool val); + void setSntpOne(const char *val); + void setShowweather(bool val); + void setWeatherKey(const char *val); + void setSDpos(uint32_t val); +#if IR_PIN!=255 + void setIrBtn(int val); +#endif + void resetSystem(const char *val, uint8_t clientId); + bool spiffsCleanup(); FS* SDPLFS(){ return _SDplaylistFS; } #if RTCSUPPORTED diff --git a/yoRadio/src/core/netserver.cpp b/yoRadio/src/core/netserver.cpp index 8462940..d98a815 100644 --- a/yoRadio/src/core/netserver.cpp +++ b/yoRadio/src/core/netserver.cpp @@ -9,8 +9,15 @@ #include "network.h" #include "mqtt.h" #include "controls.h" +#include "commandhandler.h" #include #include + +#if USE_OTA +#include +#include +#endif + #ifdef USE_SD #include "sdmanager.h" #endif @@ -27,13 +34,10 @@ NetServer netserver; AsyncWebServer webserver(80); AsyncWebSocket websocket("/ws"); -AsyncUDP udp; -String processor(const String& var); void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); -void handleUploadWeb(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); -void handleUpdate(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); -void handleHTTPArgs(AsyncWebServerRequest * request); +void handleIndex(AsyncWebServerRequest * request); +void handleNotFound(AsyncWebServerRequest * request); void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len); bool shouldReboot = false; @@ -62,45 +66,9 @@ bool NetServer::begin(bool quiet) { nsQueue = xQueueCreate( 20, sizeof( nsRequestParams_t ) ); while(nsQueue==NULL){;} - if(config.emptyFS){ - webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/html", emptyfs_html); }); - webserver.on("/webboard", HTTP_POST, [](AsyncWebServerRequest *request) { request->redirect("/"); ESP.restart(); }, handleUploadWeb); - webserver.on("/", HTTP_POST, [](AsyncWebServerRequest *request) { - if(request->arg("ssid")!="" && request->arg("pass")!=""){ - char buf[BUFLEN]; - memset(buf, 0, BUFLEN); - snprintf(buf, BUFLEN, "%s\t%s", request->arg("ssid").c_str(), request->arg("pass").c_str()); - request->redirect("/"); - config.saveWifiFromNextion(buf); - return; - } - request->redirect("/"); - ESP.restart(); - }, handleUploadWeb); - }else{ - webserver.on("/", HTTP_ANY, handleHTTPArgs); - webserver.on("/settings.html", HTTP_GET, handleHTTPArgs); - webserver.on("/update.html", HTTP_GET, handleHTTPArgs); - webserver.on("/ir.html", HTTP_GET, handleHTTPArgs); - webserver.on("/webboard", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/html", emptyfs_html); }); - webserver.on("/webboard", HTTP_POST, [](AsyncWebServerRequest *request) { request->redirect("/"); }, handleUploadWeb); - } - - webserver.on(PLAYLIST_PATH, HTTP_GET, handleHTTPArgs); - webserver.on(INDEX_PATH, HTTP_GET, handleHTTPArgs); - webserver.on(PLAYLIST_SD_PATH, HTTP_GET, handleHTTPArgs); - webserver.on(INDEX_SD_PATH, HTTP_GET, handleHTTPArgs); - webserver.on(SSIDS_PATH, HTTP_GET, handleHTTPArgs); - - webserver.on("/upload", HTTP_POST, beginUpload, handleUpload); - webserver.on("/update", HTTP_GET, handleHTTPArgs); - webserver.on("/update", HTTP_POST, beginUpdate, handleUpdate); - - webserver.on("/variables.js", HTTP_GET, [](AsyncWebServerRequest * request) { - char varjsbuf[BUFLEN]; - sprintf (varjsbuf, "var yoVersion='%s';\nvar formAction='%s';\nvar playMode='%s';\n", YOVERSION, (network.status == CONNECTED && !config.emptyFS)?"webboard":"", (network.status == CONNECTED)?"player":"ap"); - request->send(200, "text/html", varjsbuf); - }); + webserver.on("/", HTTP_ANY, handleIndex); + webserver.onNotFound(handleNotFound); + webserver.onFileUpload(handleUpload); webserver.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=31536000"); #ifdef CORS_DEBUG @@ -110,66 +78,47 @@ bool NetServer::begin(bool quiet) { webserver.begin(); if(strlen(config.store.mdnsname)>0) MDNS.begin(config.store.mdnsname); + websocket.onEvent(onWsEvent); webserver.addHandler(&websocket); - - //echo -n "helle?" | socat - udp-datagram:255.255.255.255:44490,broadcast - if (udp.listen(44490)) { - udp.onPacket([](AsyncUDPPacket packet) { - if (strcmp((char*)packet.data(), "helle?") == 0) - packet.println(WiFi.localIP()); +#if USE_OTA + if(strlen(config.store.mdnsname)>0) + ArduinoOTA.setHostname(config.store.mdnsname); +#ifdef OTA_PASS + ArduinoOTA.setPassword(OTA_PASS); +#endif + ArduinoOTA + .onStart([]() { + display.putRequest(NEWMODE, UPDATING); + telnet.printf("Start OTA updating %s\n", ArduinoOTA.getCommand() == U_FLASH?"firmware":"filesystem"); + }) + .onEnd([]() { + telnet.printf("\nEnd OTA update, Rebooting...\n"); + }) + .onProgress([](unsigned int progress, unsigned int total) { + telnet.printf("Progress OTA: %u%%\r", (progress / (total / 100))); + }) + .onError([](ota_error_t error) { + telnet.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) { + telnet.printf("Auth Failed\n"); + } else if (error == OTA_BEGIN_ERROR) { + telnet.printf("Begin Failed\n"); + } else if (error == OTA_CONNECT_ERROR) { + telnet.printf("Connect Failed\n"); + } else if (error == OTA_RECEIVE_ERROR) { + telnet.printf("Receive Failed\n"); + } else if (error == OTA_END_ERROR) { + telnet.printf("End Failed\n"); + } }); - } + ArduinoOTA.begin(); +#endif + if(!quiet) Serial.println("done"); return true; } -void NetServer::beginUpdate(AsyncWebServerRequest *request) { - shouldReboot = !Update.hasError(); - AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", shouldReboot ? "OK" : updateError()); - response->addHeader("Connection", "close"); - request->send(response); -} - -void handleUpdate(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { - if (!index) { - int target = (request->getParam("updatetarget", true)->value() == "spiffs") ? U_SPIFFS : U_FLASH; - Serial.printf("Update Start: %s\n", filename.c_str()); - player.sendCommand({PR_STOP, 0}); - display.putRequest(NEWMODE, UPDATING); - if (!Update.begin(UPDATE_SIZE_UNKNOWN, target)) { - Update.printError(Serial); - request->send(200, "text/html", updateError()); - } - } - if (!Update.hasError()) { - if (Update.write(data, len) != len) { - Update.printError(Serial); - request->send(200, "text/html", updateError()); - } - } - if (final) { - if (Update.end(true)) { - Serial.printf("Update Success: %uB\n", index + len); - } else { - Update.printError(Serial); - request->send(200, "text/html", updateError()); - } - } -} - -void NetServer::beginUpload(AsyncWebServerRequest *request) { - if (request->hasParam("plfile", true, true)) { - netserver.importRequest = IMPL; - request->send(200); - } else if (request->hasParam("wifile", true, true)) { - netserver.importRequest = IMWIFI; - request->send(200); - } else { - request->send(404); - } -} - size_t NetServer::chunkedHtmlPageCallback(uint8_t* buffer, size_t maxLen, size_t index){ File requiredfile; bool sdpl = strcmp(netserver.chunkedPathBuffer, PLAYLIST_SD_PATH) == 0; @@ -188,21 +137,17 @@ size_t NetServer::chunkedHtmlPageCallback(uint8_t* buffer, size_t maxLen, size_t size_t canread = (needread > maxLen) ? maxLen : needread; DBGVB("[%s] seek to %d in %s and read %d bytes with maxLen=%d", __func__, index, netserver.chunkedPathBuffer, canread, maxLen); requiredfile.seek(index, SeekSet); - //vTaskDelay(1); requiredfile.read(buffer, canread); index += canread; if (requiredfile) requiredfile.close(); return canread; } -void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest *request, const char * path, bool doproc) { +void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest *request, const char * path) { memset(chunkedPathBuffer, 0, sizeof(chunkedPathBuffer)); strlcpy(chunkedPathBuffer, path, sizeof(chunkedPathBuffer)-1); AsyncWebServerResponse *response; - if(doproc) - response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback, processor); - else - response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback); + response = request->beginChunkedResponse(contentType, chunkedHtmlPageCallback); request->send(response); } @@ -364,7 +309,7 @@ void NetServer::processQueue(){ case SDINIT: sprintf (wsbuf, "{\"sdinit\": %d}", SDC_CS!=255); break; case GETPLAYERMODE: sprintf (wsbuf, "{\"playermode\": \"%s\"}", config.getMode()==PM_SDCARD?"modesd":"modeweb"); break; #ifdef USE_SD - case CHANGEMODE: config.changeMode(newConfigMode); return; break; + case CHANGEMODE: config.changeMode(config.newConfigMode); return; break; #endif default: break; } @@ -391,8 +336,10 @@ void NetServer::loop() { case IMWIFI: config.saveWifi(); importRequest = IMDONE; break; default: break; } - //if (rssi < 255) requestOnChange(NRSSI, 0); processQueue(); +#if USE_OTA + ArduinoOTA.handle(); +#endif } #if IR_PIN!=255 @@ -413,389 +360,34 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client AwsFrameInfo *info = (AwsFrameInfo*)arg; if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) { data[len] = 0; - char cmd[65], val[65]; - if (config.parseWsCommand((const char*)data, cmd, val, 65)) { - //if (strcmp(cmd, "getmode") == 0 ) { requestOnChange(GETMODE, clientId); return; } - if (strcmp(cmd, "getindex") == 0 ) { requestOnChange(GETINDEX, clientId); return; } - if (strcmp(cmd, "getsystem") == 0 ) { requestOnChange(GETSYSTEM, clientId); return; } - if (strcmp(cmd, "getscreen") == 0 ) { requestOnChange(GETSCREEN, clientId); return; } - if (strcmp(cmd, "gettimezone") == 0 ) { requestOnChange(GETTIMEZONE, clientId); return; } - if (strcmp(cmd, "getcontrols") == 0 ) { requestOnChange(GETCONTROLS, clientId); return; } - if (strcmp(cmd, "getweather") == 0 ) { requestOnChange(GETWEATHER, clientId); return; } - if (strcmp(cmd, "getactive") == 0 ) { requestOnChange(GETACTIVE, clientId); return; } - if (strcmp(cmd, "newmode") == 0 ) { newConfigMode = atoi(val); requestOnChange(CHANGEMODE, 0); return; } - if (strcmp(cmd, "smartstart") == 0) { - uint8_t valb = atoi(val); - uint8_t ss = valb == 1 ? 1 : 2; - if (!player.isRunning() && ss == 1) ss = 0; - config.setSmartStart(ss); - return; - } - if (strcmp(cmd, "audioinfo") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.audioinfo, valb); - display.putRequest(AUDIOINFO); - return; - } - if (strcmp(cmd, "vumeter") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.vumeter, valb); - display.putRequest(SHOWVUMETER); - return; - } - if (strcmp(cmd, "prev") == 0) { player.prev(); return; } - if (strcmp(cmd, "toggle") == 0) { player.toggle(); return; } - if (strcmp(cmd, "next") == 0) { player.next(); return; } - if (strcmp(cmd, "volm") == 0) { player.stepVol(false); return; } - if (strcmp(cmd, "volp") == 0) { player.stepVol(true); return; } - if (strcmp(cmd, "play") == 0) { uint16_t valb = atoi(val); player.sendCommand({PR_PLAY, valb}); return; } - if (strcmp(cmd, "softap") == 0) { - uint8_t valb = atoi(val); - config.saveValue(&config.store.softapdelay, valb); - return; - } - if (strcmp(cmd, "mdnsname") == 0) { - config.saveValue(config.store.mdnsname, val, MDNS_LENGTH); - return; - } - if (strcmp(cmd, "rebootmdns") == 0) { - char buf[MDNS_LENGTH*2]; - if(strlen(config.store.mdnsname)>0) - snprintf(buf, MDNS_LENGTH*2, "{\"redirect\": \"http://%s.local\"}", config.store.mdnsname); - else - snprintf(buf, MDNS_LENGTH*2, "{\"redirect\": \"http://%s/\"}", WiFi.localIP().toString().c_str()); - websocket.text(clientId, buf); - delay(500); - ESP.restart(); - return; - } - if (strcmp(cmd, "invertdisplay") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.invertdisplay, valb); - display.invert(); - return; - } - if (strcmp(cmd, "numplaylist") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.numplaylist, valb); - display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); - return; - } - if (strcmp(cmd, "fliptouch") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.fliptouch, valb); - flipTS(); - return; - } - if (strcmp(cmd, "dbgtouch") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.dbgtouch, valb); - return; - } - if (strcmp(cmd, "flipscreen") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.flipscreen, valb); - display.flip(); - display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); - return; - } - if (strcmp(cmd, "brightness") == 0) { - uint8_t valb = atoi(val); - if (!config.store.dspon) requestOnChange(DSPON, 0); - config.store.brightness = valb; - config.setBrightness(true); - return; - } - if (strcmp(cmd, "screenon") == 0) { - bool valb = static_cast(atoi(val)); - config.setDspOn(valb); - return; - } - if (strcmp(cmd, "contrast") == 0) { - uint8_t valb = atoi(val); - config.saveValue(&config.store.contrast, valb); - display.setContrast(); - return; - } - if (strcmp(cmd, "screensaverenabled") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.screensaverEnabled, valb); - #ifndef DSP_LCD - display.putRequest(NEWMODE, PLAYER); - #endif - return; - } - if (strcmp(cmd, "screensavertimeout") == 0) { - uint16_t valb = atoi(val); - valb = constrain(valb,5,65520); - config.saveValue(&config.store.screensaverTimeout, valb); - #ifndef DSP_LCD - display.putRequest(NEWMODE, PLAYER); - #endif - return; - } - if (strcmp(cmd, "screensaverblank") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.screensaverBlank, valb); - #ifndef DSP_LCD - display.putRequest(NEWMODE, PLAYER); - #endif - return; - } - if (strcmp(cmd, "screensaverplayingenabled") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.screensaverPlayingEnabled, valb); - #ifndef DSP_LCD - display.putRequest(NEWMODE, PLAYER); - #endif - return; - } - if (strcmp(cmd, "screensaverplayingtimeout") == 0) { - uint16_t valb = atoi(val); - valb = constrain(valb,1,1080); - config.saveValue(&config.store.screensaverPlayingTimeout, valb); - #ifndef DSP_LCD - display.putRequest(NEWMODE, PLAYER); - #endif - return; - } - if (strcmp(cmd, "screensaverplayingblank") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.screensaverPlayingBlank, valb); - #ifndef DSP_LCD - display.putRequest(NEWMODE, PLAYER); - #endif - return; - } - if (strcmp(cmd, "tzh") == 0) { - int8_t vali = atoi(val); - config.saveValue(&config.store.tzHour, vali); - return; - } - if (strcmp(cmd, "tzm") == 0) { - int8_t vali = atoi(val); - config.saveValue(&config.store.tzMin, vali); - return; - } - if (strcmp(cmd, "sntp2") == 0) { - config.saveValue(config.store.sntp2, val, 35, false); - return; - } - if (strcmp(cmd, "sntp1") == 0) { - //strlcpy(config.store.sntp1, val, 35); - bool tzdone = false; - if (strlen(val) > 0 && strlen(config.store.sntp2) > 0) { - configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), val, config.store.sntp2); - tzdone = true; - } else if (strlen(val) > 0) { - configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), val); - tzdone = true; - } - if (tzdone) { - network.forceTimeSync = true; - config.saveValue(config.store.sntp1, val, 35); - } - return; - } - if (strcmp(cmd, "volsteps") == 0) { - uint8_t valb = atoi(val); - config.saveValue(&config.store.volsteps, valb); - return; - } - if (strcmp(cmd, "encacceleration") == 0) { - uint16_t valb = atoi(val); - setEncAcceleration(valb); - config.saveValue(&config.store.encacc, valb); - return; - } - if (strcmp(cmd, "irtlp") == 0) { - uint8_t valb = atoi(val); - setIRTolerance(valb); - return; - } - if (strcmp(cmd, "oneclickswitching") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.skipPlaylistUpDown, valb); - return; - } - if (strcmp(cmd, "showweather") == 0) { - bool valb = static_cast(atoi(val)); - config.saveValue(&config.store.showweather, valb); - network.trueWeather=false; - network.forceWeather = true; - display.putRequest(SHOWWEATHER); - return; - } - if (strcmp(cmd, "lat") == 0) { - config.saveValue(config.store.weatherlat, val, 10, false); - return; - } - if (strcmp(cmd, "lon") == 0) { - config.saveValue(config.store.weatherlon, val, 10, false); - return; - } - if (strcmp(cmd, "key") == 0) { - config.saveValue(config.store.weatherkey, val, WEATHERKEY_LENGTH); - network.trueWeather=false; - display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); - return; - } - /* RESETS */ - if (strcmp(cmd, "reset") == 0) { - if (strcmp(val, "system") == 0) { - config.saveValue(&config.store.smartstart, (uint8_t)2, false); - config.saveValue(&config.store.audioinfo, false, false); - config.saveValue(&config.store.vumeter, false, false); - config.saveValue(&config.store.softapdelay, (uint8_t)0, false); - snprintf(config.store.mdnsname, MDNS_LENGTH, "yoradio-%x", config.getChipId()); - config.saveValue(config.store.mdnsname, config.store.mdnsname, MDNS_LENGTH, true, true); - display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); - requestOnChange(GETSYSTEM, clientId); - return; - } - if (strcmp(val, "screen") == 0) { - config.saveValue(&config.store.flipscreen, false, false); - display.flip(); - config.saveValue(&config.store.invertdisplay, false, false); - display.invert(); - config.saveValue(&config.store.dspon, true, false); - config.store.brightness = 100; - config.setBrightness(false); - config.saveValue(&config.store.contrast, (uint8_t)55, false); - display.setContrast(); - config.saveValue(&config.store.numplaylist, false); - config.saveValue(&config.store.screensaverEnabled, false); - config.saveValue(&config.store.screensaverTimeout, (uint16_t)20); - config.saveValue(&config.store.screensaverBlank, false); - config.saveValue(&config.store.screensaverPlayingEnabled, false); - config.saveValue(&config.store.screensaverPlayingTimeout, (uint16_t)5); - config.saveValue(&config.store.screensaverPlayingBlank, false); - display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); - requestOnChange(GETSCREEN, clientId); - return; - } - if (strcmp(val, "timezone") == 0) { - config.saveValue(&config.store.tzHour, (int8_t)3, false); - config.saveValue(&config.store.tzMin, (int8_t)0, false); - config.saveValue(config.store.sntp1, "pool.ntp.org", 35, false); - config.saveValue(config.store.sntp2, "0.ru.pool.ntp.org", 35); - configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1, config.store.sntp2); - network.forceTimeSync = true; - requestOnChange(GETTIMEZONE, clientId); - return; - } - if (strcmp(val, "weather") == 0) { - config.saveValue(&config.store.showweather, false, false); - config.saveValue(config.store.weatherlat, "55.7512", 10, false); - config.saveValue(config.store.weatherlon, "37.6184", 10, false); - config.saveValue(config.store.weatherkey, "", WEATHERKEY_LENGTH); - network.trueWeather=false; - display.putRequest(NEWMODE, CLEAR); display.putRequest(NEWMODE, PLAYER); - requestOnChange(GETWEATHER, clientId); - return; - } - if (strcmp(val, "controls") == 0) { - config.saveValue(&config.store.volsteps, (uint8_t)1, false); - config.saveValue(&config.store.fliptouch, false, false); - config.saveValue(&config.store.dbgtouch, false, false); - config.saveValue(&config.store.skipPlaylistUpDown, false); - setEncAcceleration(200); - setIRTolerance(40); - requestOnChange(GETCONTROLS, clientId); - return; - } - if (strcmp(val, "1") == 0) { - config.reset(); - return; - } - } /* EOF RESETS */ - if (strcmp(cmd, "volume") == 0) { - uint8_t v = atoi(val); - player.setVol(v); - } - if (strcmp(cmd, "sdpos") == 0) { - //return; - if (config.getMode()==PM_SDCARD){ - config.sdResumePos = 0; - if(!player.isRunning()){ - player.setResumeFilePos(atoi(val)-player.sd_min); - player.sendCommand({PR_PLAY, config.store.lastSdStation}); - }else{ - player.setFilePos(atoi(val)-player.sd_min); - } - } - return; - } - if (strcmp(cmd, "snuffle") == 0) { - config.setSnuffle(strcmp(val, "true") == 0); - return; - } - if (strcmp(cmd, "balance") == 0) { + char comnd[65], val[65]; + if (config.parseWsCommand((const char*)data, comnd, val, 65)) { + if (strcmp(comnd, "trebble") == 0) { int8_t valb = atoi(val); - player.setBalance(valb); - config.setBalance(valb); - netserver.requestOnChange(BALANCE, 0); - return; - } - if (strcmp(cmd, "trebble") == 0) { - int8_t valb = atoi(val); - player.setTone(config.store.bass, config.store.middle, valb); config.setTone(config.store.bass, config.store.middle, valb); - netserver.requestOnChange(EQUALIZER, 0); return; } - if (strcmp(cmd, "middle") == 0) { + if (strcmp(comnd, "middle") == 0) { int8_t valb = atoi(val); - player.setTone(config.store.bass, valb, config.store.trebble); config.setTone(config.store.bass, valb, config.store.trebble); - netserver.requestOnChange(EQUALIZER, 0); return; } - if (strcmp(cmd, "bass") == 0) { + if (strcmp(comnd, "bass") == 0) { int8_t valb = atoi(val); - player.setTone(valb, config.store.middle, config.store.trebble); config.setTone(valb, config.store.middle, config.store.trebble); - netserver.requestOnChange(EQUALIZER, 0); return; } - if (strcmp(cmd, "reboot") == 0) { - ESP.restart(); - return; - } - if (strcmp(cmd, "format") == 0) { - SPIFFS.format(); - ESP.restart(); - return; - } - if (strcmp(cmd, "submitplaylist") == 0) { - return; - } - if (strcmp(cmd, "submitplaylistdone") == 0) { + if (strcmp(comnd, "submitplaylistdone") == 0) { #ifdef MQTT_ROOT_TOPIC - //mqttPublishPlaylist(); mqttplaylistticker.attach(5, mqttplaylistSend); #endif - if (player.isRunning()) { - player.sendCommand({PR_PLAY, -config.lastStation()}); - } + if (player.isRunning()) player.sendCommand({PR_PLAY, -config.lastStation()}); return; } -#if IR_PIN!=255 - if (strcmp(cmd, "irbtn") == 0) { - config.irindex = atoi(val); - irRecordEnable = (config.irindex >= 0); - config.irchck = 0; - irValsToWs(); - if (config.irindex < 0) config.saveIR(); + + if(cmd.exec(comnd, val, clientId)){ + return; } - if (strcmp(cmd, "chkid") == 0) { - config.irchck = atoi(val); - } - if (strcmp(cmd, "irclr") == 0) { - uint8_t cl = atoi(val); - config.ircodes.irVals[config.irindex][cl] = 0; - } -#endif } } } @@ -865,48 +457,66 @@ void NetServer::resetQueue(){ if(nsQueue!=NULL) xQueueReset(nsQueue); } -String processor(const String& var) { // %Templates% - if (var == "ACTION") return (network.status == CONNECTED && !config.emptyFS)?"webboard":""; - if (var == "UPLOADWIFI") return (network.status == CONNECTED)?" hidden":""; - if (var == "VERSION") return YOVERSION; - return String(); -} - int freeSpace; void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { - if (!index) { - if(filename!="tempwifi.csv"){ - if(SPIFFS.exists(PLAYLIST_PATH)) SPIFFS.remove(PLAYLIST_PATH); - if(SPIFFS.exists(INDEX_PATH)) SPIFFS.remove(INDEX_PATH); - if(SPIFFS.exists(PLAYLIST_SD_PATH)) SPIFFS.remove(PLAYLIST_SD_PATH); - if(SPIFFS.exists(INDEX_SD_PATH)) SPIFFS.remove(INDEX_SD_PATH); + if(request->url()=="/upload"){ + if (!index) { + if(filename!="tempwifi.csv"){ + if(SPIFFS.exists(PLAYLIST_PATH)) SPIFFS.remove(PLAYLIST_PATH); + if(SPIFFS.exists(INDEX_PATH)) SPIFFS.remove(INDEX_PATH); + if(SPIFFS.exists(PLAYLIST_SD_PATH)) SPIFFS.remove(PLAYLIST_SD_PATH); + if(SPIFFS.exists(INDEX_SD_PATH)) SPIFFS.remove(INDEX_SD_PATH); + } + freeSpace = (float)SPIFFS.totalBytes()/100*68-SPIFFS.usedBytes(); + request->_tempFile = SPIFFS.open(TMP_PATH , "w"); } - freeSpace = (float)SPIFFS.totalBytes()/100*68-SPIFFS.usedBytes(); - request->_tempFile = SPIFFS.open(TMP_PATH , "w"); - } - if (len) { - if(freeSpace>index+len){ + if (len) { + if(freeSpace>index+len){ + request->_tempFile.write(data, len); + } + } + if (final) { + request->_tempFile.close(); + } + }else if(request->url()=="/update"){ + if (!index) { + int target = (request->getParam("updatetarget", true)->value() == "spiffs") ? U_SPIFFS : U_FLASH; + Serial.printf("Update Start: %s\n", filename.c_str()); + player.sendCommand({PR_STOP, 0}); + display.putRequest(NEWMODE, UPDATING); + if (!Update.begin(UPDATE_SIZE_UNKNOWN, target)) { + Update.printError(Serial); + request->send(200, "text/html", updateError()); + } + } + if (!Update.hasError()) { + if (Update.write(data, len) != len) { + Update.printError(Serial); + request->send(200, "text/html", updateError()); + } + } + if (final) { + if (Update.end(true)) { + Serial.printf("Update Success: %uB\n", index + len); + } else { + Update.printError(Serial); + request->send(200, "text/html", updateError()); + } + } + }else{ // "/webboard" + DBGVB("File: %s, size:%u bytes, index: %u, final: %s\n", filename.c_str(), len, index, final?"true":"false"); + if (!index) { + String spath = "/www/"; + if(filename=="playlist.csv" || filename=="wifi.csv") spath = "/data/"; + request->_tempFile = SPIFFS.open(spath + filename , "w"); + } + if (len) { request->_tempFile.write(data, len); } - } - if (final) { - request->_tempFile.close(); - } -} - -void handleUploadWeb(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { - DBGVB("File: %s, size:%u bytes, index: %u, final: %s\n", filename.c_str(), len, index, final?"true":"false"); - if (!index) { - String spath = "/www/"; - if(filename=="playlist.csv" || filename=="wifi.csv") spath = "/data/"; - request->_tempFile = SPIFFS.open(spath + filename , "w"); - } - if (len) { - request->_tempFile.write(data, len); - } - if (final) { - request->_tempFile.close(); - if(filename=="playlist.csv") config.indexPlaylist(); + if (final) { + request->_tempFile.close(); + if(filename=="playlist.csv") config.indexPlaylist(); + } } } @@ -920,8 +530,19 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp break; } } - -void handleHTTPArgs(AsyncWebServerRequest * request) { +void handleNotFound(AsyncWebServerRequest * request) { +#if defined(HTTP_USER) && defined(HTTP_PASS) + if(network.status == CONNECTED) + if (request->url() == "/logout") { + request->send(401); + return; + } + if (!request->authenticate(HTTP_USER, HTTP_PASS)) { + return request->requestAuthentication(); + } +#endif + if(request->url()=="/emergency") { request->send_P(200, "text/html", emergency_form); return; } + if(request->method() == HTTP_POST && request->url()=="/webboard" && config.emptyFS) { request->redirect("/"); ESP.restart(); return; } if (request->method() == HTTP_GET) { DBGVB("[%s] client ip=%s request of %s", __func__, request->client()->remoteIP().toString().c_str(), request->url().c_str()); if (strcmp(request->url().c_str(), PLAYLIST_PATH) == 0 || @@ -934,137 +555,115 @@ void handleHTTPArgs(AsyncWebServerRequest * request) { if (strcmp(request->url().c_str(), PLAYLIST_PATH) == 0) while (mqttplaylistblock) vTaskDelay(5); #endif if(strcmp(request->url().c_str(), PLAYLIST_PATH) == 0 && config.getMode()==PM_SDCARD){ - netserver.chunkedHtmlPage("application/octet-stream", request, PLAYLIST_SD_PATH, false); + netserver.chunkedHtmlPage("application/octet-stream", request, PLAYLIST_SD_PATH); }else{ - netserver.chunkedHtmlPage("application/octet-stream", request, request->url().c_str(), false); + netserver.chunkedHtmlPage("application/octet-stream", request, request->url().c_str()); + } + return; + }// if (strcmp(request->url().c_str(), PLAYLIST_PATH) == 0 || + }// if (request->method() == HTTP_GET) + + if (request->method() == HTTP_POST) { + if(request->url()=="/webboard"){ request->redirect("/"); return; } // <--post files from /data/www + if(request->url()=="/upload"){ // <--upload playlist.csv or wifi.csv + if (request->hasParam("plfile", true, true)) { + netserver.importRequest = IMPL; + request->send(200); + } else if (request->hasParam("wifile", true, true)) { + netserver.importRequest = IMWIFI; + request->send(200); + } else { + request->send(404); } return; } - Serial.println(request->url()); - if (strcmp(request->url().c_str(), "/") == 0 && request->params() == 0) { - if(network.status == CONNECTED){ - request->send_P(200, "text/html", index_html); - }else{ - request->redirect("/settings.html"); - } - //netserver.chunkedHtmlPage(String(), request, network.status == CONNECTED ? "/www/index.html" : "/www/settings.html", false); + if(request->url()=="/update"){ // <--upload firmware + shouldReboot = !Update.hasError(); + AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", shouldReboot ? "OK" : updateError()); + response->addHeader("Connection", "close"); + request->send(response); return; } + }// if (request->method() == HTTP_POST) + + if (request->url() == "/favicon.ico") { + request->send(200, "image/x-icon", "data:,"); + return; + } + if (request->url() == "/variables.js") { + char varjsbuf[BUFLEN]; + sprintf (varjsbuf, "var yoVersion='%s';\nvar formAction='%s';\nvar playMode='%s';\n", YOVERSION, (network.status == CONNECTED && !config.emptyFS)?"webboard":"", (network.status == CONNECTED)?"player":"ap"); + request->send(200, "text/html", varjsbuf); + return; } if (strcmp(request->url().c_str(), "/settings.html") == 0 || strcmp(request->url().c_str(), "/update.html") == 0 || strcmp(request->url().c_str(), "/ir.html") == 0){ request->send_P(200, "text/html", index_html); return; } - if (network.status == CONNECTED) { - bool commandFound=false; - if (request->hasArg("start")) { player.sendCommand({PR_PLAY, config.lastStation()}); commandFound=true; } - if (request->hasArg("stop")) { player.sendCommand({PR_STOP, 0}); commandFound=true; } - if (request->hasArg("toggle")) { player.toggle(); commandFound=true; } - if (request->hasArg("prev")) { player.prev(); commandFound=true; } - if (request->hasArg("next")) { player.next(); commandFound=true; } - if (request->hasArg("volm")) { player.stepVol(false); commandFound=true; } - if (request->hasArg("volp")) { player.stepVol(true); commandFound=true; } - #ifdef USE_SD - if (request->hasArg("mode")) { - AsyncWebParameter* p = request->getParam("mode"); - int mm = atoi(p->value().c_str()); - if(mm>2) mm=0; - if(mm==2) - config.changeMode(); - else - config.changeMode(mm); - commandFound=true; + if (request->method() == HTTP_GET && request->url() == "/webboard") { + request->send_P(200, "text/html", emptyfs_html); + return; + } + Serial.print("Not Found: "); + Serial.println(request->url()); + request->send(404, "text/plain", "Not found"); +} + +void handleIndex(AsyncWebServerRequest * request) { + if(config.emptyFS){ + if(request->url()=="/" && request->method() == HTTP_GET ) { request->send_P(200, "text/html", emptyfs_html); return; } + if(request->url()=="/" && request->method() == HTTP_POST) { + if(request->arg("ssid")!="" && request->arg("pass")!=""){ + char buf[BUFLEN]; + memset(buf, 0, BUFLEN); + snprintf(buf, BUFLEN, "%s\t%s", request->arg("ssid").c_str(), request->arg("pass").c_str()); + request->redirect("/"); + config.saveWifiFromNextion(buf); + return; + } + request->redirect("/"); + ESP.restart(); + return; + } + Serial.print("Not Found: "); + Serial.println(request->url()); + request->send(404, "text/plain", "Not found"); + return; + } // end if(config.emptyFS) +#if defined(HTTP_USER) && defined(HTTP_PASS) + if(network.status == CONNECTED) + if (!request->authenticate(HTTP_USER, HTTP_PASS)) { + return request->requestAuthentication(); + } +#endif + if (strcmp(request->url().c_str(), "/") == 0 && request->params() == 0) { + if(network.status == CONNECTED) request->send_P(200, "text/html", index_html); else request->redirect("/settings.html"); + return; + } + if(network.status == CONNECTED){ + int paramsNr = request->params(); + if(paramsNr==1){ + AsyncWebParameter* p = request->getParam(0); + if(cmd.exec(p->name().c_str(),p->value().c_str())) { + if(p->name()=="reset" || p->name()=="clearspiffs") request->redirect("/"); + if(p->name()=="clearspiffs") { delay(100); ESP.restart(); } + request->send(200, "text/plain", ""); + return; + } } - #endif - if (request->hasArg("reset")) { request->redirect("/"); request->send(200); config.reset(); return; } if (request->hasArg("trebble") && request->hasArg("middle") && request->hasArg("bass")) { - AsyncWebParameter* pt = request->getParam("trebble", request->method() == HTTP_POST); - AsyncWebParameter* pm = request->getParam("middle", request->method() == HTTP_POST); - AsyncWebParameter* pb = request->getParam("bass", request->method() == HTTP_POST); - int t = atoi(pt->value().c_str()); - int m = atoi(pm->value().c_str()); - int b = atoi(pb->value().c_str()); - player.setTone(b, m, t); - config.setTone(b, m, t); - netserver.requestOnChange(EQUALIZER, 0); - commandFound=true; - } - if (request->hasArg("ballance")) { - AsyncWebParameter* p = request->getParam("ballance", request->method() == HTTP_POST); - int b = atoi(p->value().c_str()); - player.setBalance(b); - config.setBalance(b); - netserver.requestOnChange(BALANCE, 0); - commandFound=true; - } - if (request->hasArg("playstation") || request->hasArg("play")) { - AsyncWebParameter* p = request->getParam(request->hasArg("playstation") ? "playstation" : "play", request->method() == HTTP_POST); - int id = atoi(p->value().c_str()); - if (id < 1) id = 1; - uint16_t cs = config.playlistLength(); - if (id > cs) id = cs; - //config.sdResumePos = 0; - player.sendCommand({PR_PLAY, id}); - commandFound=true; - DBGVB("[%s] play=%d", __func__, id); - } - if (request->hasArg("vol")) { - AsyncWebParameter* p = request->getParam("vol", request->method() == HTTP_POST); - int v = atoi(p->value().c_str()); - if (v < 0) v = 0; - if (v > 254) v = 254; - config.store.volume = v; - player.setVol(v); - commandFound=true; - DBGVB("[%s] vol=%d", __func__, v); - } - if (request->hasArg("dspon")) { - AsyncWebParameter* p = request->getParam("dspon", request->method() == HTTP_POST); - int d = atoi(p->value().c_str()); - config.setDspOn(d!=0); - commandFound=true; - } - if (request->hasArg("dim")) { - AsyncWebParameter* p = request->getParam("dim", request->method() == HTTP_POST); - int d = atoi(p->value().c_str()); - if (d < 0) d = 0; - if (d > 100) d = 100; - config.store.brightness = (uint8_t)d; - config.setBrightness(true); - commandFound=true; + config.setTone(request->getParam("bass")->value().toInt(), request->getParam("middle")->value().toInt(), request->getParam("trebble")->value().toInt()); + request->send(200, "text/plain", ""); + return; } if (request->hasArg("sleep")) { - AsyncWebParameter* sfor = request->getParam("sleep", request->method() == HTTP_POST); - int sford = atoi(sfor->value().c_str()); - int safterd = 0; - if(request->hasArg("after")){ - AsyncWebParameter* safter = request->getParam("after", request->method() == HTTP_POST); - safterd = atoi(safter->value().c_str()); - } - if(sford > 0 && safterd >= 0){ - request->send(200); - config.sleepForAfter(sford, safterd); - commandFound=true; - } - } - if (request->hasArg("clearspiffs")) { - if(config.spiffsCleanup()){ - config.saveValue(&config.store.play_mode, static_cast(PM_WEB)); - request->redirect("/"); - ESP.restart(); - }else{ - request->send(200); - } - return; - } - if (request->params() > 0) { - request->send(commandFound?200:404); - return; - } - } else { - if (request->params() > 0) { - request->send(404); - return; + int sford = request->getParam("sleep")->value().toInt(); + int safterd = request->hasArg("after")?request->getParam("after")->value().toInt():0; + if(sford > 0 && safterd >= 0){ request->send(200, "text/plain", ""); config.sleepForAfter(sford, safterd); return; } } + request->send(404, "text/plain", "Not found"); + + }else{ + request->send(404, "text/plain", "Not found"); } } diff --git a/yoRadio/src/core/netserver.h b/yoRadio/src/core/netserver.h index 2584aa7..a6bbba0 100644 --- a/yoRadio/src/core/netserver.h +++ b/yoRadio/src/core/netserver.h @@ -3,7 +3,6 @@ #include "Arduino.h" #include "../AsyncWebServer/ESPAsyncWebServer.h" -#include "AsyncUDP.h" enum requestType_e : uint8_t { PLAYLIST=1, STATION=2, STATIONNAME=3, ITEM=4, TITLE=5, VOLUME=6, NRSSI=7, BITRATE=8, MODE=9, EQUALIZER=10, BALANCE=11, PLAYLISTSAVED=12, STARTUP=13, GETINDEX=14, GETACTIVE=15, GETSYSTEM=16, GETSCREEN=17, GETTIMEZONE=18, GETWEATHER=19, GETCONTROLS=20, DSPON=21, SDPOS=22, SDLEN=23, SDSNUFFLE=24, SDINIT=25, GETPLAYERMODE=26, CHANGEMODE=27 }; enum import_e : uint8_t { IMDONE=0, IMPL=1, IMWIFI=2 }; @@ -45,6 +44,7 @@ input[type=text],input[type=password]{width:170px;background:#272727;color:#e3d2 +

emergency firmware uploader

powered by ёRadio