This commit is contained in:
e2002
2022-09-05 11:10:54 +03:00
parent b574b4ab8d
commit da238ea42a
24 changed files with 470 additions and 214 deletions

View File

@@ -47,5 +47,14 @@
\ \
![ёRadio](images/img22.jpg)\ ![ё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)

View File

@@ -269,26 +269,7 @@ download _http://\<yoradioip\>/data/playlist.csv_ and _http://\<yoradioip\>/data
## More features ## More features
- Сan add up to 65535 stations to a playlist. Supports and imports [KaRadio](https://github.com/karawin/Ka-Radio32) playlists (WebStations.txt) - С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 \ - Telnet with KaRadio format output \
**Commands**: \ **see [list of available commands](https://github.com/e2002/yoradio/wiki/List-of-available-commands-(UART-telnet-GET-POST))**
**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
- MQTT support \ - MQTT support \
**Topics**: \ **Topics**: \
@@ -317,6 +298,16 @@ Work is in progress...
--- ---
## Version history ## 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 #### v0.7.490
**!!! a [full update](#update-over-web-interface) with Sketch data upload is required. After updating please press CTRL+F5 in browser !!!** \ **!!! 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.** **Please backup playlist.csv and wifi.csv before updating.**

View File

@@ -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 PLAYER_FORCE_MONO false /* mono option on boot - false stereo, true mono */
//#define I2S_INTERNAL false /* If true - use esp32 internal DAC */ //#define I2S_INTERNAL false /* If true - use esp32 internal DAC */
//#define ROTATE_90 false /* Optional 90 degree rotation for square displays */ //#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 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 */ /* vu left | vu top | band width | band height | band space | num of bands | fade speed | horisontal | Max Bands Color | Min Bands Color */

BIN
images/img24.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

BIN
images/img25.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

BIN
images/img26.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

BIN
images/img27.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
images/img28.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

View File

@@ -47,7 +47,6 @@ bool printable(const char *info) {
} }
void audio_showstation(const char *info) { void audio_showstation(const char *info) {
DBGVB("[%s] info = %s", __func__, info);
if (strlen(info) > 0) { if (strlen(info) > 0) {
bool p = printable(info); bool p = printable(info);
config.setTitle(p?info:config.station.name); config.setTitle(p?info:config.station.name);
@@ -56,7 +55,7 @@ void audio_showstation(const char *info) {
} }
void audio_showstreamtitle(const char *info) { void audio_showstreamtitle(const char *info) {
DBGVB("[%s] info = %s", __func__, info); DBGH();
if (strstr(info, "Account already in use") != NULL){ if (strstr(info, "Account already in use") != NULL){
config.setTitle(info); config.setTitle(info);
netserver.requestOnChange(TITLE, 0); netserver.requestOnChange(TITLE, 0);

View File

@@ -3,19 +3,8 @@
#include <SPIFFS.h> #include <SPIFFS.h>
#include "display.h" #include "display.h"
#include "player.h" #include "player.h"
Config config;
void DBGVB(const char *format, ...) { Config config;
#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
}
void u8fix(char *src){ void u8fix(char *src){
char last = src[strlen(src)-1]; char last = src[strlen(src)-1];
@@ -492,11 +481,25 @@ void Config::setBrightness(bool dosave){
if(!store.dspon) store.dspon = true; if(!store.dspon) store.dspon = true;
if(dosave) save(); if(dosave) save();
#endif #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){ void Config::setDspOn(bool dspon){
store.dspon = dspon; store.dspon = dspon;
save(); save();
#ifdef USE_NEXTION
if(!dspon) nextion.sleep();
else nextion.wake();
#endif
if(!dspon){ if(!dspon){
#if BRIGHTNESS_PIN!=255 #if BRIGHTNESS_PIN!=255
analogWrite(BRIGHTNESS_PIN, 0); analogWrite(BRIGHTNESS_PIN, 0);
@@ -509,3 +512,20 @@ void Config::setDspOn(bool dspon){
#endif #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();
}

View File

@@ -1,6 +1,7 @@
#ifndef config_h #ifndef config_h
#define config_h #define config_h
#include "Arduino.h" #include "Arduino.h"
#include <Ticker.h>
#include "options.h" #include "options.h"
#define EEPROM_SIZE 768 #define EEPROM_SIZE 768
@@ -13,7 +14,14 @@
#define TMP_PATH "/data/tmpfile.txt" #define TMP_PATH "/data/tmpfile.txt"
#define INDEX_PATH "/data/index.dat" #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); void u8fix(char *src);
struct theme_t { struct theme_t {
@@ -124,6 +132,7 @@ class Config {
#endif #endif
neworkItem ssids[5]; neworkItem ssids[5];
byte ssidsCount; byte ssidsCount;
uint16_t sleepfor;
public: public:
Config() {}; Config() {};
void save(); void save();
@@ -158,10 +167,13 @@ class Config {
uint16_t getTimezoneOffset(); uint16_t getTimezoneOffset();
void setBrightness(bool dosave=false); void setBrightness(bool dosave=false);
void setDspOn(bool dspon); void setDspOn(bool dspon);
void sleepForAfter(uint16_t sleepfor, uint16_t sleepafter=0);
private: private:
template <class T> int eepromWrite(int ee, const T& value); template <class T> int eepromWrite(int ee, const T& value);
template <class T> int eepromRead(int ee, T& value); template <class T> int eepromRead(int ee, T& value);
void setDefaults(); void setDefaults();
Ticker _sleepTimer;
static void doSleep();
uint16_t color565(uint8_t r, uint8_t g, uint8_t b); uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
}; };

View File

@@ -70,7 +70,9 @@ void ticks() {
#ifndef CORE_STACK_SIZE #ifndef CORE_STACK_SIZE
#define CORE_STACK_SIZE 1024*3 #define CORE_STACK_SIZE 1024*3
#endif #endif
#ifndef DSP_TASK_DELAY
#define DSP_TASK_DELAY 5
#endif
byte currentScrollId = 0; /* one scroll on one time */ byte currentScrollId = 0; /* one scroll on one time */
#if WEATHER_READY==1 #if WEATHER_READY==1
@@ -225,7 +227,7 @@ void loopCore0( void * pvParameters ){
while(!display.busy){ while(!display.busy){
if(displayQueue==NULL) break; if(displayQueue==NULL) break;
display.loop(); display.loop();
vTaskDelay(10); vTaskDelay(DSP_TASK_DELAY);
} }
vTaskDelete( NULL ); vTaskDelete( NULL );
TaskCore0=NULL; TaskCore0=NULL;
@@ -254,6 +256,9 @@ void Display::init() {
} else { } else {
weatherScroll.init(5, " * ", 2, TFT_LINEHGHT * 9 + 5, 0, config.theme.weather, config.theme.background); weatherScroll.init(5, " * ", 2, TFT_LINEHGHT * 9 + 5, 0, config.theme.weather, config.theme.background);
} }
#endif
#ifdef USE_NEXTION
nextion.wake();
#endif #endif
if (dsp_on_init) dsp_on_init(); if (dsp_on_init) dsp_on_init();
} }
@@ -580,7 +585,6 @@ char *split(char *str, const char *delim) {
} }
void Display::title() { void Display::title() {
DBGVB("[%s] config.station.title = %s", __func__, config.station.title);
if (strlen(config.station.title) > 0) { if (strlen(config.station.title) > 0) {
char tmpbuf[strlen(config.station.title)+1]; char tmpbuf[strlen(config.station.title)+1];
strlcpy(tmpbuf, config.station.title, strlen(config.station.title)+1); strlcpy(tmpbuf, config.station.title, strlen(config.station.title)+1);
@@ -683,6 +687,18 @@ void Display::wakeup(){
#ifdef DUMMYDISPLAY #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) { void Display::bootString(const char* text, byte y) {
#ifdef USE_NEXTION #ifdef USE_NEXTION
if(y==2) nextion.bootString(text); if(y==2) nextion.bootString(text);
@@ -697,6 +713,7 @@ void Display::start(bool reboot){
#ifdef USE_NEXTION #ifdef USE_NEXTION
nextion.start(); nextion.start();
#endif #endif
timer.attach_ms(1000, ticks);
} }
void Display::putRequest(requestParams_t request){ void Display::putRequest(requestParams_t request){
#ifdef USE_NEXTION #ifdef USE_NEXTION

View File

@@ -183,6 +183,8 @@ class Display {
void drawNextStationNum(uint16_t num); void drawNextStationNum(uint16_t num);
void returnTile(); void returnTile();
void createCore0Task(); void createCore0Task();
#else
Ticker timer;
#endif #endif
}; };

View File

@@ -564,28 +564,29 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) {
case PLAYLIST: getPlaylist(clientId); break; case PLAYLIST: getPlaylist(clientId); break;
case PLAYLISTSAVED: config.indexPlaylist(); config.initPlaylist(); getPlaylist(clientId); break; case PLAYLISTSAVED: config.indexPlaylist(); config.initPlaylist(); getPlaylist(clientId); break;
case GETACTIVE: { case GETACTIVE: {
bool dbgact = false; bool dbgact = false, nxtn=false;
String act = "\"group_wifi\","; String act = F("\"group_wifi\",");
if (network.status == CONNECTED) { if (network.status == CONNECTED) {
act += "\"group_system\","; act += F("\"group_system\",");
if (BRIGHTNESS_PIN != 255 || DSP_FLIPPED == 1 || DSP_MODEL == DSP_NOKIA5110 || dbgact) act += "\"group_display\","; if (BRIGHTNESS_PIN != 255 || DSP_FLIPPED == 1 || DSP_MODEL == DSP_NOKIA5110 || dbgact) act += F("\"group_display\",");
#ifdef USE_NEXTION #ifdef USE_NEXTION
act += "\"group_nextion\","; act += F("\"group_nextion\",");
if (WEATHER_READY == 0 || dbgact) act += "\"group_weather\","; if (WEATHER_READY == 0 || dbgact) act += F("\"group_weather\",");
nxtn=true;
#endif #endif
#if defined(LCD_I2C) || DSP_OLED #if defined(LCD_I2C) || DSP_OLED
act += "\"group_oled\","; act += F("\"group_oled\",");
#endif #endif
if (VU_READY == 1 || dbgact) act += "\"group_vu\","; if (VU_READY == 1 || dbgact) act += F("\"group_vu\",");
if (BRIGHTNESS_PIN != 255 || dbgact) act += "\"group_brightness\","; if (BRIGHTNESS_PIN != 255 || nxtn || dbgact) act += F("\"group_brightness\",");
if (DSP_FLIPPED == 1 || dbgact) act += "\"group_tft\","; if (DSP_FLIPPED == 1 || dbgact) act += F("\"group_tft\",");
if (TS_CS != 255 || dbgact) act += "\"group_touch\","; if (TS_CS != 255 || dbgact) act += F("\"group_touch\",");
if (DSP_MODEL == DSP_NOKIA5110) act += "\"group_nokia\","; if (DSP_MODEL == DSP_NOKIA5110) act += F("\"group_nokia\",");
if (DSP_MODEL != DSP_DUMMY || dbgact) act += "\"group_timezone\","; act += F("\"group_timezone\",");
if (WEATHER_READY == 1 || dbgact) act += "\"group_weather\","; if (WEATHER_READY == 1 || dbgact) act += F("\"group_weather\",");
act += "\"group_controls\","; act += F("\"group_controls\",");
if (ENC_BTNL != 255 || ENC2_BTNL != 255 || dbgact) act += "\"group_encoder\","; if (ENC_BTNL != 255 || ENC2_BTNL != 255 || dbgact) act += F("\"group_encoder\",");
if (IR_PIN != 255 || dbgact) act += "\"group_ir\","; if (IR_PIN != 255 || dbgact) act += F("\"group_ir\",");
} }
act = act.substring(0, act.length() - 1); act = act.substring(0, act.length() - 1);
sprintf (buf, "{\"act\":[%s]}", act.c_str()); 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 NRSSI: sprintf (buf, "{\"rssi\": %d}", rssi); rssi = 255; break;
case BITRATE: sprintf (buf, "{\"bitrate\": %d}", config.station.bitrate); break; case BITRATE: sprintf (buf, "{\"bitrate\": %d}", config.station.bitrate); break;
case MODE: sprintf (buf, "{\"mode\": \"%s\"}", player.mode == PLAYING ? "playing" : "stopped"); 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; case BALANCE: sprintf (buf, "{\"balance\": %d}", config.store.balance); break;
} }
if (strlen(buf) > 0) { if (strlen(buf) > 0) {
@@ -671,15 +672,14 @@ void handleHTTPArgs(AsyncWebServerRequest * request) {
} }
} }
if (network.status == CONNECTED) { if (network.status == CONNECTED) {
if (request->hasArg("start")) player.request.station = config.store.lastStation; bool commandFound=false;
if (request->hasArg("stop")) { if (request->hasArg("start")) { player.request.station = config.store.lastStation; commandFound=true; }
player.mode = STOPPED; if (request->hasArg("stop")) { player.mode = STOPPED; config.setTitle("[stopped]"); commandFound=true; }
config.setTitle("[stopped]"); if (request->hasArg("toggle")) { player.toggle(); commandFound=true; }
} if (request->hasArg("prev")) { player.prev(); commandFound=true; }
if (request->hasArg("prev")) player.prev(); if (request->hasArg("next")) { player.next(); commandFound=true; }
if (request->hasArg("next")) player.next(); if (request->hasArg("volm")) { player.stepVol(false); commandFound=true; }
if (request->hasArg("volm")) player.stepVol(false); if (request->hasArg("volp")) { player.stepVol(true); commandFound=true; }
if (request->hasArg("volp")) player.stepVol(true);
if (request->hasArg("trebble") && request->hasArg("middle") && request->hasArg("bass")) { if (request->hasArg("trebble") && request->hasArg("middle") && request->hasArg("bass")) {
AsyncWebParameter* pt = request->getParam("trebble", request->method() == HTTP_POST); AsyncWebParameter* pt = request->getParam("trebble", request->method() == HTTP_POST);
@@ -691,6 +691,7 @@ void handleHTTPArgs(AsyncWebServerRequest * request) {
player.setTone(b, m, t); player.setTone(b, m, t);
config.setTone(b, m, t); config.setTone(b, m, t);
netserver.requestOnChange(EQUALIZER, 0); netserver.requestOnChange(EQUALIZER, 0);
commandFound=true;
} }
if (request->hasArg("ballance")) { if (request->hasArg("ballance")) {
AsyncWebParameter* p = request->getParam("ballance", request->method() == HTTP_POST); AsyncWebParameter* p = request->getParam("ballance", request->method() == HTTP_POST);
@@ -698,6 +699,7 @@ void handleHTTPArgs(AsyncWebServerRequest * request) {
player.setBalance(b); player.setBalance(b);
config.setBalance(b); config.setBalance(b);
netserver.requestOnChange(BALANCE, 0); netserver.requestOnChange(BALANCE, 0);
commandFound=true;
} }
if (request->hasArg("playstation") || request->hasArg("play")) { if (request->hasArg("playstation") || request->hasArg("play")) {
AsyncWebParameter* p = request->getParam(request->hasArg("playstation") ? "playstation" : "play", request->method() == HTTP_POST); 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; if (id > config.store.countStation) id = config.store.countStation;
player.request.station = id; player.request.station = id;
player.request.doSave = true; player.request.doSave = true;
commandFound=true;
DBGVB("[%s] play=%d", __func__, id); DBGVB("[%s] play=%d", __func__, id);
} }
if (request->hasArg("vol")) { if (request->hasArg("vol")) {
@@ -715,10 +718,40 @@ void handleHTTPArgs(AsyncWebServerRequest * request) {
if (v > 254) v = 254; if (v > 254) v = 254;
config.store.volume = v; config.store.volume = v;
player.setVol(v, false); player.setVol(v, false);
commandFound=true;
DBGVB("[%s] vol=%d", __func__, v); DBGVB("[%s] vol=%d", __func__, v);
} }
if (request->params() > 0) { 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); request->send(200);
config.sleepForAfter(sford, safterd);
commandFound=true;
}
}
if (request->params() > 0) {
request->send(commandFound?200:404);
return; return;
} }
} else { } else {

View File

@@ -62,13 +62,11 @@ void Network::begin() {
digitalWrite(LED_BUILTIN, LOW); digitalWrite(LED_BUILTIN, LOW);
status = CONNECTED; status = CONNECTED;
WiFi.setSleep(false); 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){ 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); configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1, config.store.sntp2);
}else if(strlen(config.store.sntp1)>0){ }else if(strlen(config.store.sntp1)>0){
configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1); configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), config.store.sntp1);
} }
////getLocalTime(&timeinfo);
stimer.once_ms(200,getFirstTime); stimer.once_ms(200,getFirstTime);
ntimer.attach_ms(TSYNC_DELAY, syncTime); ntimer.attach_ms(TSYNC_DELAY, syncTime);
#ifdef USE_NEXTION #ifdef USE_NEXTION
@@ -78,16 +76,15 @@ void Network::begin() {
if (network_on_connect) network_on_connect(); if (network_on_connect) network_on_connect();
} }
void Network::requestTimeSync(bool withTelnetOutput) { void Network::requestTimeSync(bool withTelnetOutput, uint8_t clientId) {
//configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), "pool.ntp.org", "ru.pool.ntp.org");
if (withTelnetOutput) { if (withTelnetOutput) {
getLocalTime(&timeinfo); getLocalTime(&timeinfo);
char timeStringBuff[50]; char timeStringBuff[50];
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S", &timeinfo); strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S", &timeinfo);
if (config.store.tzHour < 0) { 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 { } 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);
} }
} }
} }

View File

@@ -17,7 +17,7 @@ class Network {
public: public:
Network() {}; Network() {};
void begin(); void begin();
void requestTimeSync(bool withTelnetOutput=false); void requestTimeSync(bool withTelnetOutput=false, uint8_t clientId=0);
private: private:
Ticker ntimer, stimer, rtimer; Ticker ntimer, stimer, rtimer;
void raiseSoftAP(); void raiseSoftAP();

View File

@@ -1,7 +1,7 @@
#ifndef options_h #ifndef options_h
#define options_h #define options_h
#define VERSION "0.7.490" #define VERSION "0.7.534"
/******************************************************* /*******************************************************
DO NOT EDIT THIS FILE. DO NOT EDIT THIS FILE.
@@ -214,6 +214,9 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti
#ifndef ROTATE_90 #ifndef ROTATE_90
#define ROTATE_90 false // Optional 90 degree rotation for square displays #define ROTATE_90 false // Optional 90 degree rotation for square displays
#endif #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 *** *** ST7735 display submodel ***
INITR_BLACKTAB // 1.8' https://aliexpress.ru/item/1005002822797745.html INITR_BLACKTAB // 1.8' https://aliexpress.ru/item/1005002822797745.html

View File

@@ -64,7 +64,7 @@ void Player::loop() {
xSemaphoreTake(playmutex, portMAX_DELAY); xSemaphoreTake(playmutex, portMAX_DELAY);
Audio::loop(); Audio::loop();
xSemaphoreGive(playmutex); xSemaphoreGive(playmutex);
vTaskDelay(2); //vTaskDelay(2);
} else { } else {
if (isRunning()) { if (isRunning()) {
//digitalWrite(LED_BUILTIN, LOW); //digitalWrite(LED_BUILTIN, LOW);

View File

@@ -18,7 +18,9 @@
#ifdef SDFATFS_USED #ifdef SDFATFS_USED
fs::SDFATFS SD_SDFAT; fs::SDFATFS SD_SDFAT;
#endif #endif
#ifndef DMA_BUFCOUNT
#define DMA_BUFCOUNT 4
#endif
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
AudioBuffer::AudioBuffer(size_t maxBlockSize) { AudioBuffer::AudioBuffer(size_t maxBlockSize) {
// if maxBlockSize isn't set use defaultspace (1600 bytes) is enough for aac and mp3 player // 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.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
m_i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; 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.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.dma_buf_len = 512;
m_i2s_config.use_apll = APLL_DISABLE; // must be disabled in V2.0.1-RC1 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 m_i2s_config.tx_desc_auto_clear = true; // new in V1.0.1

View File

@@ -712,6 +712,12 @@ void Nextion::startWeather(){
updateWeather(); 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 По мотивам 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
*/ */

View File

@@ -71,6 +71,8 @@ class Nextion {
bool getForecast(); bool getForecast();
static void updateWeather(); static void updateWeather();
static void getWeather(void * pvParameters); static void getWeather(void * pvParameters);
void sleep();
void wake();
}; };
extern Nextion nextion; extern Nextion nextion;

View File

@@ -2,9 +2,9 @@
#include "WiFi.h" #include "WiFi.h"
#include "config.h" #include "config.h"
#include "telnet.h"
#include "player.h" #include "player.h"
#include "network.h" #include "network.h"
#include "telnet.h"
Telnet telnet; 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() { void Telnet::loop() {
uint8_t i; uint8_t i;
if (WiFi.status() == WL_CONNECTED) { if (WiFi.status() == WL_CONNECTED) {
@@ -82,6 +89,7 @@ void Telnet::loop() {
} }
delay(1000); delay(1000);
} }
handleSerial();
yield(); yield();
} }
@@ -114,8 +122,7 @@ void Telnet::printf(const char *format, ...) {
Serial.print(buf); Serial.print(buf);
} }
void Telnet::printf(byte id, const char *format, ...) { /*void Telnet::printf(byte id, const char *format, ...) {
if (clients[id] && clients[id].connected()) {
va_list argptr; va_list argptr;
va_start(argptr, format); va_start(argptr, format);
char *szBuffer = 0; char *szBuffer = 0;
@@ -125,9 +132,30 @@ void Telnet::printf(byte id, const char *format, ...) {
if (! szBuffer) return; if (! szBuffer) return;
vsnprintf(szBuffer, nBufferLength, format, argptr); vsnprintf(szBuffer, nBufferLength, format, argptr);
va_end(argptr); va_end(argptr);
if(id>MAX_TLN_CLIENTS){
Serial.print(szBuffer);
free(szBuffer);
return;
}
if (clients[id] && clients[id].connected()) {
clients[id].print(szBuffer); clients[id].print(szBuffer);
free(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) { void Telnet::on_connect(const char* str, byte clientId) {
@@ -155,6 +183,7 @@ void Telnet::info() {
void Telnet::on_input(const char* str, byte clientId) { void Telnet::on_input(const char* str, byte clientId) {
if (strlen(str) == 0) return; if (strlen(str) == 0) return;
if(network.status == CONNECTED){
if (strcmp(str, "cli.prev") == 0 || strcmp(str, "prev") == 0) { if (strcmp(str, "cli.prev") == 0 || strcmp(str, "prev") == 0) {
player.prev(); player.prev();
return; return;
@@ -177,16 +206,20 @@ void Telnet::on_input(const char* str, byte clientId) {
player.play(config.store.lastStation); player.play(config.store.lastStation);
return; 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) { if (strcmp(str, "cli.vol") == 0 || strcmp(str, "vol") == 0) {
printf(clientId, "##CLI.VOL#: %d\n> ", config.store.volume); printf(clientId, "##CLI.VOL#: %d\n> ", config.store.volume);
return; return;
} }
if (strcmp(str, "sys.date") == 0) { if (strcmp(str, "cli.vol-") == 0 || strcmp(str, "vol-") == 0) {
network.requestTimeSync(true); 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; return;
} }
int volume; int volume;
@@ -298,6 +331,130 @@ void Telnet::on_input(const char* str, byte clientId) {
network.requestTimeSync(true); network.requestTimeSync(true);
return; return;
} }
if (sscanf(str, "dspon(%d)", &tzh) == 1 || sscanf(str, "cli.dspon(\"%d\")", &tzh) == 1 || sscanf(str, "dspon %d", &tzh) == 1) {
telnet.printf(clientId, "unknown command: %s\n> ", str); 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, "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, "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, "#WIFI.SCAN#\n> ");
return;
}
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, "##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, "##WIFI.STATION#\n> ");
return;
}
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, "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;
}
if (strcmp(str, "wifi.rssi") == 0 || strcmp(str, "rssi") == 0) {
printf(clientId, "#WIFI.RSSI#\t%d dBm\n> ", WiFi.RSSI());
return;
}
if (strcmp(str, "sys.heap") == 0 || strcmp(str, "heap") == 0) {
printf(clientId, "Free heap:\t%d bytes\n> ", xPortGetFreeHeapSize());
return;
}
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);
} }

View File

@@ -26,6 +26,7 @@ class Telnet {
void on_input(const char* str, byte clientId); void on_input(const char* str, byte clientId);
private: private:
bool _isIPSet(IPAddress ip); bool _isIPSet(IPAddress ip);
void handleSerial();
}; };
extern Telnet telnet; extern Telnet telnet;

View File

@@ -48,8 +48,8 @@ void setup() {
} }
void loop() { void loop() {
if (network.status == CONNECTED) {
telnet.loop(); telnet.loop();
if (network.status == CONNECTED) {
player.loop(); player.loop();
loopControls(); loopControls();
checkConnection(); checkConnection();