diff --git a/Images.md b/Images.md index a9ae86d..36c634f 100644 --- a/Images.md +++ b/Images.md @@ -47,5 +47,14 @@ \ ![ёRadio](images/img22.jpg)\ \ -![ёRadio](images/img23.jpg) - +![ёRadio](images/img23.jpg)\ +\ +![ёRadio](images/img24.jpg)\ +\ +![ёRadio](images/img25.jpg)\ +\ +![ёRadio](images/img26.jpg)\ +\ +![ёRadio](images/img27.jpg)\ +\ +![ёRadio](images/img28.jpg) diff --git a/README.md b/README.md index b743641..7bb8d7e 100644 --- a/README.md +++ b/README.md @@ -269,26 +269,7 @@ download _http://\/data/playlist.csv_ and _http://\/data ## More features - Сan add up to 65535 stations to a playlist. Supports and imports [KaRadio](https://github.com/karawin/Ka-Radio32) playlists (WebStations.txt) - Telnet with KaRadio format output \ - **Commands**: \ - **cli.prev** (_or simply_ **prev**) - previous station \ - **cli.next** _or_ **next** - next station \ - **cli.toggle** _or_ **toggle** - start/stop \ - **cli.stop** _or_ **stop** - stop \ - **cli.start** _or_ **start** _or_ **cli.play** _or_ **play** - start playing \ - **cli.play("x")** _or_ **play(x)** _or_ **play x** - play station x \ - **cli.vol** _or_ **vol** - display the current value of volume (0-254) \ - **cli.vol("x")** _or_ **vol(x)** _or_ **vol x** - set volume (0-254) \ - **cli.audioinfo** _or_ **audioinfo** - display the current value of debug (0-1) \ - **cli.audioinfo("x")** _or_ **audioinfo(x)** _or_ **audioinfo x** - debug on/off (0-1) \ - **cli.smartstart** _or_ **smartstart** - display the current value of smart start \ - **cli.smartstart("x")** _or_ **smartstart(x)** _or_ **smartstart x** - smart start: 2-off, 0-1 - start playing on boot, if the radio was playing before the reboot \ - **cli.list** _or_ **list** - display playlist \ - **cli.info** _or_ **info** - display current state \ - **sys.boot** _or_ **boot** _or_ **reboot** - reboot \ - **sys.date** - sync date/time and display it \ - **sys.tzo** _or_ **tzo** - display the timezone offset \ - **sys.tzo("h:m")** _or_ **tzo(h:m)** _or_ **tzo h:m** - set timezone offset \ - **sys.tzo("h")** _or_ **tzo(h)** _or_ **tzo h** - set timezone offset in hours only + **see [list of available commands](https://github.com/e2002/yoradio/wiki/List-of-available-commands-(UART-telnet-GET-POST))** - MQTT support \ **Topics**: \ @@ -317,6 +298,16 @@ Work is in progress... --- ## Version history +#### v0.7.534 +- added control via uart (see [list of commands](https://github.com/e2002/yoradio/wiki/List-of-available-commands-(UART-telnet-GET-POST))). The uart and telnet commands are the same. +- added additional commands +- added control via GET/POST (see [list of commands](https://github.com/e2002/yoradio/wiki/List-of-available-commands-(UART-telnet-GET-POST))) +- fixed clock operation when configured with DSP_DUMMY +- fixed RSSI display in web interface when configured with DSP_DUMMY +- added brightness control/on/off nextion displays from the web interface +- new parameter WAKE_PIN (to wake up esp after sleep command earlier than given time (see exsamples/myoptions.h and list of commands) +- minor memory optimization + #### v0.7.490 **!!! a [full update](#update-over-web-interface) with Sketch data upload is required. After updating please press CTRL+F5 in browser !!!** \ **Please backup playlist.csv and wifi.csv before updating.** diff --git a/exsamples/myoptions.h b/exsamples/myoptions.h index 43aae4e..dc5bb8b 100644 --- a/exsamples/myoptions.h +++ b/exsamples/myoptions.h @@ -115,7 +115,8 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti //#define PLAYER_FORCE_MONO false /* mono option on boot - false stereo, true mono */ //#define I2S_INTERNAL false /* If true - use esp32 internal DAC */ //#define ROTATE_90 false /* Optional 90 degree rotation for square displays */ - +//#define WAKE_PIN 255 /* Wake Pin (for manual wakeup from sleep mode. can match with BTN_XXXX, ENC_BTNB, ENC2_BTNB. must be one of: 0,2,4,12,13,14,15,25,26,27,32,33,34,35,36,39) */ + /* For sample #define ENC_BTNB 36 - next line - #define WAKE_PIN ENC_BTNB */ /* VU settings. See the default settings for your display in file yoRadio/display_vu.h */ /************************************************************************************************************************************************************************************/ /* vu left | vu top | band width | band height | band space | num of bands | fade speed | horisontal | Max Bands Color | Min Bands Color */ diff --git a/images/img24.jpg b/images/img24.jpg new file mode 100644 index 0000000..fc71346 Binary files /dev/null and b/images/img24.jpg differ diff --git a/images/img25.jpg b/images/img25.jpg new file mode 100644 index 0000000..90b15a0 Binary files /dev/null and b/images/img25.jpg differ diff --git a/images/img26.jpg b/images/img26.jpg new file mode 100644 index 0000000..a7f00f1 Binary files /dev/null and b/images/img26.jpg differ diff --git a/images/img27.jpg b/images/img27.jpg new file mode 100644 index 0000000..2e12e30 Binary files /dev/null and b/images/img27.jpg differ diff --git a/images/img28.jpg b/images/img28.jpg new file mode 100644 index 0000000..a4c9f3b Binary files /dev/null and b/images/img28.jpg differ diff --git a/yoRadio/audiohandlers.ino b/yoRadio/audiohandlers.ino index 74bff8e..54a7d11 100644 --- a/yoRadio/audiohandlers.ino +++ b/yoRadio/audiohandlers.ino @@ -47,7 +47,6 @@ bool printable(const char *info) { } void audio_showstation(const char *info) { - DBGVB("[%s] info = %s", __func__, info); if (strlen(info) > 0) { bool p = printable(info); config.setTitle(p?info:config.station.name); @@ -56,7 +55,7 @@ void audio_showstation(const char *info) { } void audio_showstreamtitle(const char *info) { - DBGVB("[%s] info = %s", __func__, info); + DBGH(); if (strstr(info, "Account already in use") != NULL){ config.setTitle(info); netserver.requestOnChange(TITLE, 0); diff --git a/yoRadio/config.cpp b/yoRadio/config.cpp index 74c8d60..77e1226 100644 --- a/yoRadio/config.cpp +++ b/yoRadio/config.cpp @@ -3,19 +3,8 @@ #include #include "display.h" #include "player.h" -Config config; -void DBGVB(const char *format, ...) { -#ifdef DEBUG_V - char buf[200]; - va_list args; - va_start (args, format ); - vsnprintf(buf, 200, format, args); - Serial.print("[DEBUG] "); - Serial.print(buf); - Serial.println(); -#endif -} +Config config; void u8fix(char *src){ char last = src[strlen(src)-1]; @@ -492,11 +481,25 @@ void Config::setBrightness(bool dosave){ if(!store.dspon) store.dspon = true; if(dosave) save(); #endif +#ifdef USE_NEXTION +// if(!store.dspon && dosave) { + nextion.wake(); +// } + char cmd[15]; + snprintf(cmd, 15, "dims=%d", store.brightness); + nextion.putcmd(cmd); + if(!store.dspon) store.dspon = true; + if(dosave) save(); +#endif } void Config::setDspOn(bool dspon){ store.dspon = dspon; save(); +#ifdef USE_NEXTION + if(!dspon) nextion.sleep(); + else nextion.wake(); +#endif if(!dspon){ #if BRIGHTNESS_PIN!=255 analogWrite(BRIGHTNESS_PIN, 0); @@ -509,3 +512,20 @@ void Config::setDspOn(bool dspon){ #endif } } + +void Config::doSleep(){ + if(BRIGHTNESS_PIN!=255) analogWrite(BRIGHTNESS_PIN, 0); + display.deepsleep(); +#ifdef USE_NEXTION + nextion.sleep(); +#endif + if(WAKE_PIN!=255) esp_sleep_enable_ext0_wakeup((gpio_num_t)WAKE_PIN, LOW); + esp_sleep_enable_timer_wakeup(config.sleepfor * 60 * 1000000ULL); + esp_deep_sleep_start(); +} + +void Config::sleepForAfter(uint16_t sf, uint16_t sa){ + sleepfor = sf; + if(sa > 0) _sleepTimer.attach(sa * 60, doSleep); + else doSleep(); +} diff --git a/yoRadio/config.h b/yoRadio/config.h index b046946..d762ffb 100644 --- a/yoRadio/config.h +++ b/yoRadio/config.h @@ -1,6 +1,7 @@ #ifndef config_h #define config_h #include "Arduino.h" +#include #include "options.h" #define EEPROM_SIZE 768 @@ -13,7 +14,14 @@ #define TMP_PATH "/data/tmpfile.txt" #define INDEX_PATH "/data/index.dat" -void DBGVB(const char *format, ...); +#ifdef DEBUG_V +#define DBGH() { Serial.printf("[%s:%s:%d] Heap: %d\n", __PRETTY_FUNCTION__, __FILE__, __LINE__, xPortGetFreeHeapSize()); } +#define DBGVB( ... ) { char buf[200]; sprintf( buf, __VA_ARGS__ ) ; Serial.print("[DEBUG]\t"); Serial.println(buf); } +#else +#define DBGVB( ... ) +#define DBGH() +#endif +#define EVERY_MS(x) static uint32_t tmr; bool flag = millis() - tmr >= (x); if (flag) tmr += (x); if (flag) void u8fix(char *src); struct theme_t { @@ -124,6 +132,7 @@ class Config { #endif neworkItem ssids[5]; byte ssidsCount; + uint16_t sleepfor; public: Config() {}; void save(); @@ -158,10 +167,13 @@ class Config { uint16_t getTimezoneOffset(); void setBrightness(bool dosave=false); void setDspOn(bool dspon); + void sleepForAfter(uint16_t sleepfor, uint16_t sleepafter=0); private: template int eepromWrite(int ee, const T& value); template int eepromRead(int ee, T& value); void setDefaults(); + Ticker _sleepTimer; + static void doSleep(); uint16_t color565(uint8_t r, uint8_t g, uint8_t b); }; diff --git a/yoRadio/display.cpp b/yoRadio/display.cpp index 5b0f940..3744742 100644 --- a/yoRadio/display.cpp +++ b/yoRadio/display.cpp @@ -70,7 +70,9 @@ void ticks() { #ifndef CORE_STACK_SIZE #define CORE_STACK_SIZE 1024*3 #endif - +#ifndef DSP_TASK_DELAY +#define DSP_TASK_DELAY 5 +#endif byte currentScrollId = 0; /* one scroll on one time */ #if WEATHER_READY==1 @@ -225,7 +227,7 @@ void loopCore0( void * pvParameters ){ while(!display.busy){ if(displayQueue==NULL) break; display.loop(); - vTaskDelay(10); + vTaskDelay(DSP_TASK_DELAY); } vTaskDelete( NULL ); TaskCore0=NULL; @@ -254,6 +256,9 @@ void Display::init() { } else { weatherScroll.init(5, " * ", 2, TFT_LINEHGHT * 9 + 5, 0, config.theme.weather, config.theme.background); } +#endif +#ifdef USE_NEXTION + nextion.wake(); #endif if (dsp_on_init) dsp_on_init(); } @@ -580,7 +585,6 @@ char *split(char *str, const char *delim) { } void Display::title() { - DBGVB("[%s] config.station.title = %s", __func__, config.station.title); if (strlen(config.station.title) > 0) { char tmpbuf[strlen(config.station.title)+1]; strlcpy(tmpbuf, config.station.title, strlen(config.station.title)+1); @@ -683,6 +687,18 @@ void Display::wakeup(){ #ifdef DUMMYDISPLAY /******************************************************************************************************************/ +void ticks() { + static bool divrssi; + network.timeinfo.tm_sec ++; + mktime(&network.timeinfo); + if(divrssi) { + netserver.setRSSI(WiFi.RSSI()); + divrssi=false; + }else{ + divrssi=true; + } +} + void Display::bootString(const char* text, byte y) { #ifdef USE_NEXTION if(y==2) nextion.bootString(text); @@ -697,6 +713,7 @@ void Display::start(bool reboot){ #ifdef USE_NEXTION nextion.start(); #endif + timer.attach_ms(1000, ticks); } void Display::putRequest(requestParams_t request){ #ifdef USE_NEXTION diff --git a/yoRadio/display.h b/yoRadio/display.h index 5de28fd..896127f 100644 --- a/yoRadio/display.h +++ b/yoRadio/display.h @@ -183,6 +183,8 @@ class Display { void drawNextStationNum(uint16_t num); void returnTile(); void createCore0Task(); +#else + Ticker timer; #endif }; diff --git a/yoRadio/netserver.cpp b/yoRadio/netserver.cpp index 8b38b18..d27f3a4 100644 --- a/yoRadio/netserver.cpp +++ b/yoRadio/netserver.cpp @@ -564,28 +564,29 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) { case PLAYLIST: getPlaylist(clientId); break; case PLAYLISTSAVED: config.indexPlaylist(); config.initPlaylist(); getPlaylist(clientId); break; case GETACTIVE: { - bool dbgact = false; - String act = "\"group_wifi\","; + bool dbgact = false, nxtn=false; + String act = F("\"group_wifi\","); if (network.status == CONNECTED) { - act += "\"group_system\","; - if (BRIGHTNESS_PIN != 255 || DSP_FLIPPED == 1 || DSP_MODEL == DSP_NOKIA5110 || dbgact) act += "\"group_display\","; + act += F("\"group_system\","); + if (BRIGHTNESS_PIN != 255 || DSP_FLIPPED == 1 || DSP_MODEL == DSP_NOKIA5110 || dbgact) act += F("\"group_display\","); #ifdef USE_NEXTION - act += "\"group_nextion\","; - if (WEATHER_READY == 0 || dbgact) act += "\"group_weather\","; + act += F("\"group_nextion\","); + if (WEATHER_READY == 0 || dbgact) act += F("\"group_weather\","); + nxtn=true; #endif #if defined(LCD_I2C) || DSP_OLED - act += "\"group_oled\","; + act += F("\"group_oled\","); #endif - if (VU_READY == 1 || dbgact) act += "\"group_vu\","; - if (BRIGHTNESS_PIN != 255 || dbgact) act += "\"group_brightness\","; - if (DSP_FLIPPED == 1 || dbgact) act += "\"group_tft\","; - if (TS_CS != 255 || dbgact) act += "\"group_touch\","; - if (DSP_MODEL == DSP_NOKIA5110) act += "\"group_nokia\","; - if (DSP_MODEL != DSP_DUMMY || dbgact) act += "\"group_timezone\","; - if (WEATHER_READY == 1 || dbgact) act += "\"group_weather\","; - act += "\"group_controls\","; - if (ENC_BTNL != 255 || ENC2_BTNL != 255 || dbgact) act += "\"group_encoder\","; - if (IR_PIN != 255 || dbgact) act += "\"group_ir\","; + if (VU_READY == 1 || dbgact) act += F("\"group_vu\","); + if (BRIGHTNESS_PIN != 255 || nxtn || dbgact) act += F("\"group_brightness\","); + if (DSP_FLIPPED == 1 || dbgact) act += F("\"group_tft\","); + if (TS_CS != 255 || dbgact) act += F("\"group_touch\","); + if (DSP_MODEL == DSP_NOKIA5110) act += F("\"group_nokia\","); + act += F("\"group_timezone\","); + if (WEATHER_READY == 1 || dbgact) act += F("\"group_weather\","); + act += F("\"group_controls\","); + if (ENC_BTNL != 255 || ENC2_BTNL != 255 || dbgact) act += F("\"group_encoder\","); + if (IR_PIN != 255 || dbgact) act += F("\"group_ir\","); } act = act.substring(0, act.length() - 1); sprintf (buf, "{\"act\":[%s]}", act.c_str()); @@ -606,7 +607,7 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) { case NRSSI: sprintf (buf, "{\"rssi\": %d}", rssi); rssi = 255; break; case BITRATE: sprintf (buf, "{\"bitrate\": %d}", config.station.bitrate); break; case MODE: sprintf (buf, "{\"mode\": \"%s\"}", player.mode == PLAYING ? "playing" : "stopped"); break; - case EQUALIZER: sprintf (buf, "{\"bass\": %d, \"middle\": %d, \"trebble\": %d}", config.store.bass, config.store.middle, config.store.trebble); DBGVB("[%s] %s", __func__, buf); break; + case EQUALIZER: sprintf (buf, "{\"bass\": %d, \"middle\": %d, \"trebble\": %d}", config.store.bass, config.store.middle, config.store.trebble); break; case BALANCE: sprintf (buf, "{\"balance\": %d}", config.store.balance); break; } if (strlen(buf) > 0) { @@ -671,15 +672,14 @@ void handleHTTPArgs(AsyncWebServerRequest * request) { } } if (network.status == CONNECTED) { - if (request->hasArg("start")) player.request.station = config.store.lastStation; - if (request->hasArg("stop")) { - player.mode = STOPPED; - config.setTitle("[stopped]"); - } - if (request->hasArg("prev")) player.prev(); - if (request->hasArg("next")) player.next(); - if (request->hasArg("volm")) player.stepVol(false); - if (request->hasArg("volp")) player.stepVol(true); + bool commandFound=false; + if (request->hasArg("start")) { player.request.station = config.store.lastStation; commandFound=true; } + if (request->hasArg("stop")) { player.mode = STOPPED; config.setTitle("[stopped]"); 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; } if (request->hasArg("trebble") && request->hasArg("middle") && request->hasArg("bass")) { AsyncWebParameter* pt = request->getParam("trebble", request->method() == HTTP_POST); @@ -691,6 +691,7 @@ void handleHTTPArgs(AsyncWebServerRequest * request) { 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); @@ -698,6 +699,7 @@ void handleHTTPArgs(AsyncWebServerRequest * request) { 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); @@ -706,6 +708,7 @@ void handleHTTPArgs(AsyncWebServerRequest * request) { if (id > config.store.countStation) id = config.store.countStation; player.request.station = id; player.request.doSave = true; + commandFound=true; DBGVB("[%s] play=%d", __func__, id); } if (request->hasArg("vol")) { @@ -715,10 +718,40 @@ void handleHTTPArgs(AsyncWebServerRequest * request) { if (v > 254) v = 254; config.store.volume = v; player.setVol(v, false); + 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; + } + 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->params() > 0) { - request->send(200); + request->send(commandFound?200:404); return; } } else { diff --git a/yoRadio/network.cpp b/yoRadio/network.cpp index 63f11d7..7551f10 100644 --- a/yoRadio/network.cpp +++ b/yoRadio/network.cpp @@ -62,13 +62,11 @@ void Network::begin() { digitalWrite(LED_BUILTIN, LOW); status = CONNECTED; WiFi.setSleep(false); - //configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), SNTP_SERVER); if(strlen(config.store.sntp1)>0 && strlen(config.store.sntp2)>0){ configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1, config.store.sntp2); }else if(strlen(config.store.sntp1)>0){ configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1); } - ////getLocalTime(&timeinfo); stimer.once_ms(200,getFirstTime); ntimer.attach_ms(TSYNC_DELAY, syncTime); #ifdef USE_NEXTION @@ -78,16 +76,15 @@ void Network::begin() { if (network_on_connect) network_on_connect(); } -void Network::requestTimeSync(bool withTelnetOutput) { - //configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), "pool.ntp.org", "ru.pool.ntp.org"); +void Network::requestTimeSync(bool withTelnetOutput, uint8_t clientId) { if (withTelnetOutput) { getLocalTime(&timeinfo); char timeStringBuff[50]; strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S", &timeinfo); if (config.store.tzHour < 0) { - telnet.printf(0, "##SYS.DATE#: %s%03d:%02d\n> ", timeStringBuff, config.store.tzHour, config.store.tzMin); + telnet.printf(clientId, "##SYS.DATE#: %s%03d:%02d\n> ", timeStringBuff, config.store.tzHour, config.store.tzMin); } else { - telnet.printf(0, "##SYS.DATE#: %s+%02d:%02d\n> ", timeStringBuff, config.store.tzHour, config.store.tzMin); + telnet.printf(clientId, "##SYS.DATE#: %s+%02d:%02d\n> ", timeStringBuff, config.store.tzHour, config.store.tzMin); } } } diff --git a/yoRadio/network.h b/yoRadio/network.h index 0a97ce1..1522b7e 100644 --- a/yoRadio/network.h +++ b/yoRadio/network.h @@ -17,7 +17,7 @@ class Network { public: Network() {}; void begin(); - void requestTimeSync(bool withTelnetOutput=false); + void requestTimeSync(bool withTelnetOutput=false, uint8_t clientId=0); private: Ticker ntimer, stimer, rtimer; void raiseSoftAP(); diff --git a/yoRadio/options.h b/yoRadio/options.h index 63d0fc6..4f97ef4 100644 --- a/yoRadio/options.h +++ b/yoRadio/options.h @@ -1,7 +1,7 @@ #ifndef options_h #define options_h -#define VERSION "0.7.490" +#define VERSION "0.7.534" /******************************************************* DO NOT EDIT THIS FILE. @@ -214,6 +214,9 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti #ifndef ROTATE_90 #define ROTATE_90 false // Optional 90 degree rotation for square displays #endif +#ifndef WAKE_PIN + #define WAKE_PIN 255 // Wake Pin (for manual wakeup from sleep mode. can match with BTN_XXXX, ENC_BTNB, ENC2_BTNB. must be one of: 0,2,4,12,13,14,15,25,26,27,32,33,34,35,36,39) +#endif /* *** ST7735 display submodel *** INITR_BLACKTAB // 1.8' https://aliexpress.ru/item/1005002822797745.html diff --git a/yoRadio/player.cpp b/yoRadio/player.cpp index 40810b8..3ccece8 100644 --- a/yoRadio/player.cpp +++ b/yoRadio/player.cpp @@ -64,7 +64,7 @@ void Player::loop() { xSemaphoreTake(playmutex, portMAX_DELAY); Audio::loop(); xSemaphoreGive(playmutex); - vTaskDelay(2); + //vTaskDelay(2); } else { if (isRunning()) { //digitalWrite(LED_BUILTIN, LOW); diff --git a/yoRadio/src/audioI2S/Audio.cpp b/yoRadio/src/audioI2S/Audio.cpp index 57df7c1..518ecbc 100644 --- a/yoRadio/src/audioI2S/Audio.cpp +++ b/yoRadio/src/audioI2S/Audio.cpp @@ -18,7 +18,9 @@ #ifdef SDFATFS_USED fs::SDFATFS SD_SDFAT; #endif - +#ifndef DMA_BUFCOUNT +#define DMA_BUFCOUNT 4 +#endif //--------------------------------------------------------------------------------------------------------------------- AudioBuffer::AudioBuffer(size_t maxBlockSize) { // if maxBlockSize isn't set use defaultspace (1600 bytes) is enough for aac and mp3 player @@ -174,7 +176,11 @@ Audio::Audio(bool internalDAC /* = false */, uint8_t channelEnabled /* = I2S_DAC m_i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT; m_i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; m_i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1; // interrupt priority - m_i2s_config.dma_buf_count = 16; +#ifdef OLD_DMABUF_PARAMS + m_i2s_config.dma_buf_count = 16; // 4×512×16=32768 +#else + m_i2s_config.dma_buf_count = psramInit()?16:DMA_BUFCOUNT; +#endif m_i2s_config.dma_buf_len = 512; m_i2s_config.use_apll = APLL_DISABLE; // must be disabled in V2.0.1-RC1 m_i2s_config.tx_desc_auto_clear = true; // new in V1.0.1 diff --git a/yoRadio/src/displays/nextion.cpp b/yoRadio/src/displays/nextion.cpp index e4beb6c..2d8b0ce 100644 --- a/yoRadio/src/displays/nextion.cpp +++ b/yoRadio/src/displays/nextion.cpp @@ -712,6 +712,12 @@ void Nextion::startWeather(){ updateWeather(); } +void Nextion::sleep(void) { + putcmd("sleep=1"); +} +void Nextion::wake(void) { + putcmd("sleep=0"); +} /* По мотивам https://forum.amperka.ru/threads/%D0%94%D0%B8%D1%81%D0%BF%D0%BB%D0%B5%D0%B9-nextion-%D0%B0%D0%B7%D1%8B-arduino-esp8266.9204/page-18#post-173442 */ diff --git a/yoRadio/src/displays/nextion.h b/yoRadio/src/displays/nextion.h index 844722b..af22cdf 100644 --- a/yoRadio/src/displays/nextion.h +++ b/yoRadio/src/displays/nextion.h @@ -71,6 +71,8 @@ class Nextion { bool getForecast(); static void updateWeather(); static void getWeather(void * pvParameters); + void sleep(); + void wake(); }; extern Nextion nextion; diff --git a/yoRadio/telnet.cpp b/yoRadio/telnet.cpp index 99533da..f78ef64 100644 --- a/yoRadio/telnet.cpp +++ b/yoRadio/telnet.cpp @@ -2,9 +2,9 @@ #include "WiFi.h" #include "config.h" -#include "telnet.h" #include "player.h" #include "network.h" +#include "telnet.h" Telnet telnet; @@ -46,6 +46,13 @@ void Telnet::cleanupClients() { } } +void Telnet::handleSerial(){ + if(Serial.available()){ + String request = Serial.readStringUntil('\n'); request.trim(); + on_input(request.c_str(), 100); + } +} + void Telnet::loop() { uint8_t i; if (WiFi.status() == WL_CONNECTED) { @@ -82,6 +89,7 @@ void Telnet::loop() { } delay(1000); } + handleSerial(); yield(); } @@ -114,20 +122,40 @@ void Telnet::printf(const char *format, ...) { Serial.print(buf); } -void Telnet::printf(byte id, const char *format, ...) { +/*void Telnet::printf(byte id, const char *format, ...) { + va_list argptr; + va_start(argptr, format); + char *szBuffer = 0; + const size_t nBufferLength = vsnprintf(szBuffer, 0, format, argptr) + 1; + if (nBufferLength == 1) return; + szBuffer = (char *) malloc(nBufferLength); + if (! szBuffer) return; + vsnprintf(szBuffer, nBufferLength, format, argptr); + va_end(argptr); + if(id>MAX_TLN_CLIENTS){ + Serial.print(szBuffer); + free(szBuffer); + return; + } if (clients[id] && clients[id].connected()) { - va_list argptr; - va_start(argptr, format); - char *szBuffer = 0; - const size_t nBufferLength = vsnprintf(szBuffer, 0, format, argptr) + 1; - if (nBufferLength == 1) return; - szBuffer = (char *) malloc(nBufferLength); - if (! szBuffer) return; - vsnprintf(szBuffer, nBufferLength, format, argptr); - va_end(argptr); clients[id].print(szBuffer); free(szBuffer); } +}*/ + +void Telnet::printf(byte id, const char *format, ...) { + char buf[MAX_PRINTF_LEN]; + va_list argptr; + va_start(argptr, format); + vsnprintf(buf, MAX_PRINTF_LEN, format, argptr); + va_end(argptr); + if(id>MAX_TLN_CLIENTS){ + Serial.print(buf); + return; + } + if (clients[id] && clients[id].connected()) { + clients[id].print(buf); + } } void Telnet::on_connect(const char* str, byte clientId) { @@ -155,149 +183,278 @@ void Telnet::info() { void Telnet::on_input(const char* str, byte clientId) { if (strlen(str) == 0) return; - if (strcmp(str, "cli.prev") == 0 || strcmp(str, "prev") == 0) { - player.prev(); - return; + if(network.status == CONNECTED){ + if (strcmp(str, "cli.prev") == 0 || strcmp(str, "prev") == 0) { + player.prev(); + return; + } + if (strcmp(str, "cli.next") == 0 || strcmp(str, "next") == 0) { + player.next(); + return; + } + if (strcmp(str, "cli.toggle") == 0 || strcmp(str, "toggle") == 0) { + player.toggle(); + return; + } + if (strcmp(str, "cli.stop") == 0 || strcmp(str, "stop") == 0) { + player.mode = STOPPED; + //display.title("[stopped]"); + info(); + return; + } + if (strcmp(str, "cli.start") == 0 || strcmp(str, "start") == 0 || strcmp(str, "cli.play") == 0 || strcmp(str, "play") == 0) { + player.play(config.store.lastStation); + return; + } + if (strcmp(str, "cli.vol") == 0 || strcmp(str, "vol") == 0) { + printf(clientId, "##CLI.VOL#: %d\n> ", config.store.volume); + return; + } + if (strcmp(str, "cli.vol-") == 0 || strcmp(str, "vol-") == 0) { + player.stepVol(false); + return; + } + if (strcmp(str, "cli.vol+") == 0 || strcmp(str, "vol+") == 0) { + player.stepVol(true); + return; + } + if (strcmp(str, "sys.date") == 0 || strcmp(str, "date") == 0 || strcmp(str, "time") == 0) { + network.requestTimeSync(true, clientId > MAX_TLN_CLIENTS?clientId:0); + return; + } + int volume; + if (sscanf(str, "vol(%d)", &volume) == 1 || sscanf(str, "cli.vol(\"%d\")", &volume) == 1 || sscanf(str, "vol %d", &volume) == 1) { + if (volume < 0) volume = 0; + if (volume > 254) volume = 254; + player.setVol(volume, false); + return; + } + if (strcmp(str, "cli.audioinfo") == 0 || strcmp(str, "audioinfo") == 0) { + printf(clientId, "##CLI.AUDIOINFO#: %d\n> ", config.store.audioinfo > 0); + return; + } + int ainfo; + if (sscanf(str, "audioinfo(%d)", &ainfo) == 1 || sscanf(str, "cli.audioinfo(\"%d\")", &ainfo) == 1 || sscanf(str, "audioinfo %d", &ainfo) == 1) { + config.store.audioinfo = ainfo > 0; + printf(clientId, "new audioinfo value is: %d\n> ", config.store.audioinfo); + config.save(); + return; + } + if (strcmp(str, "cli.smartstart") == 0 || strcmp(str, "smartstart") == 0) { + printf(clientId, "##CLI.SMARTSTART#: %d\n> ", config.store.smartstart); + return; + } + int sstart; + if (sscanf(str, "smartstart(%d)", &sstart) == 1 || sscanf(str, "cli.smartstart(\"%d\")", &sstart) == 1 || sscanf(str, "smartstart %d", &sstart) == 1) { + config.store.smartstart = (byte)sstart; + printf(clientId, "new smartstart value is: %d\n> ", config.store.smartstart); + config.save(); + return; + } + if (strcmp(str, "cli.list") == 0 || strcmp(str, "list") == 0) { + printf(clientId, "#CLI.LIST#\n"); + File file = SPIFFS.open(PLAYLIST_PATH, "r"); + if (!file || file.isDirectory()) { + return; + } + char sName[BUFLEN], sUrl[BUFLEN]; + int sOvol; + byte c = 1; + while (file.available()) { + if (config.parseCSV(file.readStringUntil('\n').c_str(), sName, sUrl, sOvol)) { + printf(clientId, "#CLI.LISTNUM#: %*d: %s, %s\n", 3, c, sName, sUrl); + c++; + } + } + printf(clientId, "##CLI.LIST#\n"); + printf(clientId, "> "); + return; + } + if (strcmp(str, "cli.info") == 0 || strcmp(str, "info") == 0) { + printf(clientId, "##CLI.INFO#\n"); + char timeStringBuff[50]; + strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S", &network.timeinfo); + if (config.store.tzHour < 0) { + printf(clientId, "##SYS.DATE#: %s%03d:%02d\n", timeStringBuff, config.store.tzHour, config.store.tzMin); + } else { + printf(clientId, "##SYS.DATE#: %s+%02d:%02d\n", timeStringBuff, config.store.tzHour, config.store.tzMin); + } + printf(clientId, "##CLI.NAMESET#: %d %s\n", config.store.lastStation, config.station.name); + if (player.mode == PLAYING) { + printf(clientId, "##CLI.META#: %s\n", config.station.title); + } + printf(clientId, "##CLI.VOL#: %d\n", config.store.volume); + if (player.mode == PLAYING) { + printf(clientId, "##CLI.PLAYING#\n"); + } else { + printf(clientId, "##CLI.STOPPED#\n"); + } + printf(clientId, "> "); + return; + } + int sb; + if (sscanf(str, "play(%d)", &sb) == 1 || sscanf(str, "cli.play(\"%d\")", &sb) == 1 || sscanf(str, "play %d", &sb) == 1 ) { + if (sb < 1) sb = 1; + if (sb >= config.store.countStation) sb = config.store.countStation; + player.play((uint16_t)sb); + return; + } + if (strcmp(str, "sys.tzo") == 0 || strcmp(str, "tzo") == 0) { + printf(clientId, "##SYS.TZO#: %d:%d\n> ", config.store.tzHour, config.store.tzMin); + return; + } + //int16_t tzh, tzm; + int tzh, tzm; + if (sscanf(str, "tzo(%d:%d)", &tzh, &tzm) == 2 || sscanf(str, "sys.tzo(\"%d:%d\")", &tzh, &tzm) == 2 || sscanf(str, "tzo %d:%d", &tzh, &tzm) == 2) { + if (tzh < -12) tzh = -12; + if (tzh > 14) tzh = 14; + if (tzm < 0) tzm = 0; + if (tzm > 59) tzm = 59; + config.setTimezone((int8_t)tzh, (int8_t)tzm); + if(tzh<0){ + printf(clientId, "new timezone offset: %03d:%02d\n", config.store.tzHour, config.store.tzMin); + }else{ + printf(clientId, "new timezone offset: %02d:%02d\n", config.store.tzHour, config.store.tzMin); + } + network.requestTimeSync(true); + return; + } + if (sscanf(str, "tzo(%d)", &tzh) == 1 || sscanf(str, "sys.tzo(\"%d\")", &tzh) == 1 || sscanf(str, "tzo %d", &tzh) == 1) { + if (tzh < -12) tzh = -12; + if (tzh > 14) tzh = 14; + config.setTimezone((int8_t)tzh, 0); + if(tzh<0){ + printf(clientId, "new timezone offset: %03d:%02d\n", config.store.tzHour, config.store.tzMin); + }else{ + printf(clientId, "new timezone offset: %02d:%02d\n", config.store.tzHour, config.store.tzMin); + } + network.requestTimeSync(true); + return; + } + if (sscanf(str, "dspon(%d)", &tzh) == 1 || sscanf(str, "cli.dspon(\"%d\")", &tzh) == 1 || sscanf(str, "dspon %d", &tzh) == 1) { + config.setDspOn(tzh!=0); + return; + } + if (sscanf(str, "dim(%d)", &tzh) == 1 || sscanf(str, "cli.dim(\"%d\")", &tzh) == 1 || sscanf(str, "dim %d", &tzh) == 1) { + if (tzh < 0) tzh = 0; + if (tzh > 100) tzh = 100; + config.store.brightness = (uint8_t)tzh; + config.setBrightness(true); + return; + } + if (sscanf(str, "sleep(%d,%d)", &tzh, &tzm) == 2 || sscanf(str, "cli.sleep(\"%d\",\"%d\")", &tzh, &tzm) == 2 || sscanf(str, "sleep %d %d", &tzh, &tzm) == 2) { + if(tzh>0 && tzm>0) { + printf(clientId, "sleep for %d minutes after %d minutes ...\n> ", tzh, tzm); + config.sleepForAfter(tzh, tzm); + }else{ + printf(clientId, "##CMD_ERROR#\tunknown command <%s>\n> ", str); + } + return; + } + if (sscanf(str, "sleep(%d)", &tzh) == 1 || sscanf(str, "cli.sleep(\"%d\")", &tzh) == 1 || sscanf(str, "sleep %d", &tzh) == 1) { + if(tzh>0) { + printf(clientId, "sleep for %d minutes ...\n> ", tzh); + config.sleepForAfter(tzh); + }else{ + printf(clientId, "##CMD_ERROR#\tunknown command <%s>\n> ", str); + } + return; + } } - if (strcmp(str, "cli.next") == 0 || strcmp(str, "next") == 0) { - player.next(); - return; - } - if (strcmp(str, "cli.toggle") == 0 || strcmp(str, "toggle") == 0) { - player.toggle(); - return; - } - if (strcmp(str, "cli.stop") == 0 || strcmp(str, "stop") == 0) { - player.mode = STOPPED; - //display.title("[stopped]"); - info(); - return; - } - if (strcmp(str, "cli.start") == 0 || strcmp(str, "start") == 0 || strcmp(str, "cli.play") == 0 || strcmp(str, "play") == 0) { - player.play(config.store.lastStation); + if (strcmp(str, "sys.version") == 0 || strcmp(str, "version") == 0) { + printf(clientId, "##SYS.VERSION#: %s\n> ", VERSION); return; } if (strcmp(str, "sys.boot") == 0 || strcmp(str, "boot") == 0 || strcmp(str, "reboot") == 0) { ESP.restart(); return; } - if (strcmp(str, "cli.vol") == 0 || strcmp(str, "vol") == 0) { - printf(clientId, "##CLI.VOL#: %d\n> ", config.store.volume); - return; - } - if (strcmp(str, "sys.date") == 0) { - network.requestTimeSync(true); - return; - } - int volume; - if (sscanf(str, "vol(%d)", &volume) == 1 || sscanf(str, "cli.vol(\"%d\")", &volume) == 1 || sscanf(str, "vol %d", &volume) == 1) { - if (volume < 0) volume = 0; - if (volume > 254) volume = 254; - player.setVol(volume, false); - return; - } - if (strcmp(str, "cli.audioinfo") == 0 || strcmp(str, "audioinfo") == 0) { - printf(clientId, "##CLI.AUDIOINFO#: %d\n> ", config.store.audioinfo > 0); - return; - } - int ainfo; - if (sscanf(str, "audioinfo(%d)", &ainfo) == 1 || sscanf(str, "cli.audioinfo(\"%d\")", &ainfo) == 1 || sscanf(str, "audioinfo %d", &ainfo) == 1) { - config.store.audioinfo = ainfo > 0; - printf(clientId, "new audioinfo value is: %d\n> ", config.store.audioinfo); - config.save(); - return; - } - if (strcmp(str, "cli.smartstart") == 0 || strcmp(str, "smartstart") == 0) { - printf(clientId, "##CLI.SMARTSTART#: %d\n> ", config.store.smartstart); - return; - } - int sstart; - if (sscanf(str, "smartstart(%d)", &sstart) == 1 || sscanf(str, "cli.smartstart(\"%d\")", &sstart) == 1 || sscanf(str, "smartstart %d", &sstart) == 1) { - config.store.smartstart = (byte)sstart; - printf(clientId, "new smartstart value is: %d\n> ", config.store.smartstart); - config.save(); - return; - } - if (strcmp(str, "cli.list") == 0 || strcmp(str, "list") == 0) { - printf(clientId, "#CLI.LIST#\n"); - File file = SPIFFS.open(PLAYLIST_PATH, "r"); - if (!file || file.isDirectory()) { - return; - } - char sName[BUFLEN], sUrl[BUFLEN]; - int sOvol; - byte c = 1; - while (file.available()) { - if (config.parseCSV(file.readStringUntil('\n').c_str(), sName, sUrl, sOvol)) { - printf(clientId, "#CLI.LISTNUM#: %*d: %s, %s\n", 3, c, sName, sUrl); - c++; + if (strcmp(str, "wifi.list") == 0 || strcmp(str, "wifi") == 0) { + printf(clientId, "#WIFI.SCAN#\n"); + int n = WiFi.scanNetworks(); + if (n == 0) { + printf(clientId, "no networks found\n"); + } else { + for (int i = 0; i < n; ++i) { + printf(clientId, "%d", i + 1); + printf(clientId, ": "); + printf(clientId, "%s", WiFi.SSID(i)); + printf(clientId, " ("); + printf(clientId, "%d", WiFi.RSSI(i)); + printf(clientId, ")"); + printf(clientId, (WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*"); + printf(clientId, "\n"); + delay(10); } } - printf(clientId, "##CLI.LIST#\n"); - printf(clientId, "> "); + printf(clientId, "#WIFI.SCAN#\n> "); return; } - if (strcmp(str, "cli.info") == 0 || strcmp(str, "info") == 0) { - printf(clientId, "##CLI.INFO#\n"); - char timeStringBuff[50]; - strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S", &network.timeinfo); - if (config.store.tzHour < 0) { - printf(clientId, "##SYS.DATE#: %s%03d:%02d\n", timeStringBuff, config.store.tzHour, config.store.tzMin); - } else { - printf(clientId, "##SYS.DATE#: %s+%02d:%02d\n", timeStringBuff, config.store.tzHour, config.store.tzMin); + if (strcmp(str, "wifi.con") == 0 || strcmp(str, "conn") == 0) { + printf(clientId, "#WIFI.CON#\n"); + File file = SPIFFS.open(SSIDS_PATH, "r"); + if (file && !file.isDirectory()) { + char sSid[BUFLEN], sPas[BUFLEN]; + byte c = 1; + while (file.available()) { + if (config.parseSsid(file.readStringUntil('\n').c_str(), sSid, sPas)) { + printf(clientId, "%d: %s, %s\n", c, sSid, sPas); + c++; + } + } } - printf(clientId, "##CLI.NAMESET#: %d %s\n", config.store.lastStation, config.station.name); - if (player.mode == PLAYING) { - printf(clientId, "##CLI.META#: %s\n", config.station.title); + printf(clientId, "##WIFI.CON#\n> "); + return; + } + if (strcmp(str, "wifi.station") == 0 || strcmp(str, "station") == 0 || strcmp(str, "ssid") == 0) { + printf(clientId, "#WIFI.STATION#\n"); + File file = SPIFFS.open(SSIDS_PATH, "r"); + if (file && !file.isDirectory()) { + char sSid[BUFLEN], sPas[BUFLEN]; + byte c = 1; + while (file.available()) { + if (config.parseSsid(file.readStringUntil('\n').c_str(), sSid, sPas)) { + if(c==config.store.lastSSID) printf(clientId, "%d: %s, %s\n", c, sSid, sPas); + c++; + } + } } - printf(clientId, "##CLI.VOL#: %d\n", config.store.volume); - if (player.mode == PLAYING) { - printf(clientId, "##CLI.PLAYING#\n"); - } else { - printf(clientId, "##CLI.STOPPED#\n"); - } - printf(clientId, "> "); + printf(clientId, "##WIFI.STATION#\n> "); return; } - int sb; - if (sscanf(str, "play(%d)", &sb) == 1 || sscanf(str, "cli.play(\"%d\")", &sb) == 1 || sscanf(str, "play %d", &sb) == 1 ) { - if (sb < 1) sb = 1; - if (sb >= config.store.countStation) sb = config.store.countStation; - player.play((uint16_t)sb); + char newssid[20], newpass[40]; + if (sscanf(str, "wifi.con(\"%[^\"]\",\"%[^\"]\")", newssid, newpass) == 2 || sscanf(str, "wifi.con(%[^,],%[^)])", newssid, newpass) == 2 || sscanf(str, "wifi.con(%[^ ] %[^)])", newssid, newpass) == 2 || sscanf(str, "wifi %[^ ] %s", newssid, newpass) == 2) { + char buf[BUFLEN]; + snprintf(buf, BUFLEN, "New SSID: \"%s\" with PASS: \"%s\" for next boot\n> ", newssid, newpass); + printf(clientId, buf); + printf(clientId, "...REBOOTING...\n> "); + memset(buf, 0, BUFLEN); + snprintf(buf, BUFLEN, "%s\t%s", newssid, newpass); + config.saveWifiFromNextion(buf); return; } - if (strcmp(str, "sys.tzo") == 0 || strcmp(str, "tzo") == 0) { - printf(clientId, "##SYS.TZO#: %d:%d\n> ", config.store.tzHour, config.store.tzMin); + if (strcmp(str, "wifi.status") == 0 || strcmp(str, "status") == 0) { + printf(clientId, "#WIFI.STATUS#\nStatus:\t\t%d\nMode:\t\t%s\nIP:\t\t%s\nMask:\t\t%s\nGateway:\t%s\nRSSI:\t\t%d dBm\n##WIFI.STATUS#\n> ", + WiFi.status(), WiFi.getMode()==WIFI_STA?"WIFI_STA":"WIFI_AP", + WiFi.getMode()==WIFI_STA?WiFi.localIP().toString():WiFi.softAPIP().toString(), + WiFi.getMode()==WIFI_STA?WiFi.subnetMask().toString():"255.255.255.0", + WiFi.getMode()==WIFI_STA?WiFi.gatewayIP().toString():WiFi.softAPIP().toString(), + WiFi.RSSI() + ); return; } - //int16_t tzh, tzm; - int tzh, tzm; - if (sscanf(str, "tzo(%d:%d)", &tzh, &tzm) == 2 || sscanf(str, "sys.tzo(\"%d:%d\")", &tzh, &tzm) == 2 || sscanf(str, "tzo %d:%d", &tzh, &tzm) == 2) { - if (tzh < -12) tzh = -12; - if (tzh > 14) tzh = 14; - if (tzm < 0) tzm = 0; - if (tzm > 59) tzm = 59; - config.setTimezone((int8_t)tzh, (int8_t)tzm); - if(tzh<0){ - printf(clientId, "new timezone offset: %03d:%02d\n", config.store.tzHour, config.store.tzMin); - }else{ - printf(clientId, "new timezone offset: %02d:%02d\n", config.store.tzHour, config.store.tzMin); - } - network.requestTimeSync(true); + if (strcmp(str, "wifi.rssi") == 0 || strcmp(str, "rssi") == 0) { + printf(clientId, "#WIFI.RSSI#\t%d dBm\n> ", WiFi.RSSI()); return; } - if (sscanf(str, "tzo(%d)", &tzh) == 1 || sscanf(str, "sys.tzo(\"%d\")", &tzh) == 1 || sscanf(str, "tzo %d", &tzh) == 1) { - if (tzh < -12) tzh = -12; - if (tzh > 14) tzh = 14; - config.setTimezone((int8_t)tzh, 0); - if(tzh<0){ - printf(clientId, "new timezone offset: %03d:%02d\n", config.store.tzHour, config.store.tzMin); - }else{ - printf(clientId, "new timezone offset: %02d:%02d\n", config.store.tzHour, config.store.tzMin); - } - network.requestTimeSync(true); + if (strcmp(str, "sys.heap") == 0 || strcmp(str, "heap") == 0) { + printf(clientId, "Free heap:\t%d bytes\n> ", xPortGetFreeHeapSize()); return; } - - telnet.printf(clientId, "unknown command: %s\n> ", str); + if (strcmp(str, "wifi.discon") == 0 || strcmp(str, "discon") == 0 || strcmp(str, "disconnect") == 0) { + printf(clientId, "#WIFI.DISCON#\tdisconnected...\n> "); + WiFi.disconnect(); + return; + } + telnet.printf(clientId, "##CMD_ERROR#\tunknown command <%s>\n> ", str); } diff --git a/yoRadio/telnet.h b/yoRadio/telnet.h index 5e3cb4e..5c0ef7b 100644 --- a/yoRadio/telnet.h +++ b/yoRadio/telnet.h @@ -26,6 +26,7 @@ class Telnet { void on_input(const char* str, byte clientId); private: bool _isIPSet(IPAddress ip); + void handleSerial(); }; extern Telnet telnet; diff --git a/yoRadio/yoRadio.ino b/yoRadio/yoRadio.ino index 90f7460..7c0183a 100644 --- a/yoRadio/yoRadio.ino +++ b/yoRadio/yoRadio.ino @@ -48,8 +48,8 @@ void setup() { } void loop() { + telnet.loop(); if (network.status == CONNECTED) { - telnet.loop(); player.loop(); loopControls(); checkConnection();