This commit is contained in:
e2002
2022-02-13 11:12:33 +03:00
parent e20bcd953c
commit 287bc69bef
13 changed files with 163 additions and 61 deletions

View File

@@ -42,6 +42,16 @@ Three tact buttons or Encoder or all together
| RSTL | 15* | TFT_RST |
| DCL | 4* | TFT_DC |
| NOKIA5110 | ESP-32 | options.h |
| ------ | ------ | ------ |
| RST | 15* | TFT_RST |
| CE | 5* | TFT_CS |
| DC | 4* | TFT_DC |
| DIN | 23 | - |
| CLK | 18 | - |
| VCC | +3v3 | - |
| GND | GND | - |
| I2C Display | ESP-32 | options.h |
| ------ | ------ | ------ |
| GND | GND | - |
@@ -76,7 +86,7 @@ Adafruit_GFX, Adafruit_ST7735\*, Adafruit_SSD1306\*, Adafruit_PCD8544\*, (\* dep
## Hardware setup
Hardware is connected in the **[options.h](yoRadio/options.h)** file. \
_so that the settings are not overwritten when updating git, you need to put the file **myoptions.h** ([exsample](exsamples/myoptions.h)) in the root of the project and make settings in it_
````
````c++
/* DISPLAY MODEL
* 0 - DUMMY
* 1 - ST7735
@@ -86,16 +96,16 @@ _so that the settings are not overwritten when updating git, you need to put the
#define DSP_MODEL 1
````
The ST7735 display model is configured in the file [src/displays/displayST7735.cpp](yoRadio/src/displays/displayST7735.cpp)
````
````c++
#define DTYPE INITR_BLACKTAB // 1.8' https://aliexpress.ru/item/1005002822797745.html
//#define DTYPE INITR_144GREENTAB // 1.44' https://aliexpress.ru/item/1005002822797745.html
````
Rotation of the ST7735 display is configured in the file [src/displays/displayST7735.h](yoRadio/src/displays/displayST7735.h)
````
````c++
#define TFT_ROTATE 3 // 180 degress
````
If there is a noisy line on one side of the screen, then in Adafruit_ST7735.cpp:
````
````c++
// Black tab, change MADCTL color filter
if ((options == INITR_BLACKTAB) || (options == INITR_MINI160x80)) {
uint8_t data = 0xC0;
@@ -107,14 +117,14 @@ If there is a noisy line on one side of the screen, then in Adafruit_ST7735.cpp:
---
## Quick start
1. In ArduinoIDE - upload sketch data (Tools→ESP32 Sketch Data Upload)
2. Upload the sketch to the board ([example of the board connection](images/board.jpg))
1. In ArduinoIDE - upload sketch data via Tools→ESP32 Sketch Data Upload ([it's here](images/board2.jpg))
2. Upload the sketch to the board ([example of the board settings](images/board.jpg))
3. Connect to yoRadioAP acces point with password 12345987, go to http://192.168.4.1/ configure and wifi connections. \
_\*this step can be skipped if you add WiFiSSID WiFiPassword pairs to the [yoRadio/data/data/wifi.csv](yoRadio/data/data/wifi.csv) file (tab-separated values, one line per access point) before uploading the sketch data in step 1_
4. After successful connection go to http://\<ipaddress\>/ , add stations to playlist (or import WebStations.txt from KaRadio)
4. After successful connection go to http://\<yoipaddress\>/ , add stations to playlist (or import WebStations.txt from KaRadio)
5. Well done!
**localization:**
**Localization:**
Если Adafruit_GFX ещё не русифицирована, русифицировать её, заменив файл Arduino/libraries/Adafruit_GFX_Library/glcdfont.c файлом [yoRadio/fonts/glcdfont.c](yoRadio/fonts/glcdfont.c)
---
@@ -122,27 +132,35 @@ _\*this step can be skipped if you add WiFiSSID WiFiPassword pairs to the [yoRad
- С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, next - next station \
cli.toggle, toggle - start/stop \
cli.stop, stop - stop \
cli.start, start, cli.play, play - start playing \
cli.play("x"), play(x), play x - play station x \
cli.vol, vol - the current value of volume (0-254) \
cli.vol("x"), vol(x), vol x - set volume (0-254) \
cli.audioinfo, audioinfo - the current value of debug (0-1) \
cli.audioinfo("x"), audioinfo(x), audioinfo x - debug on/off (0-1) \
cli.smartstart, smartstart - the current value of smart start \
cli.smartstart("x"), smartstart(x), smartstart x - smart start: 2-off, 0-1 - start playing on boot, if the radio was playing before the reboot \
cli.list, list - get playlist \
cli.info, info - get current state \
sys.boot, boot, reboot - reboot \
sys.date - date/time
**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
---
## Version history
#### v0.4.210
- added timezone config by telnet
- fix telnet output
- some separation apples and oranges
#### v0.4.199
- excluded required installation of all libraries for displays.
- excluded required installation of all libraries for displays
#### v0.4.197
- added support for Nokia 5110 SPI displays

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 107 KiB

BIN
images/board2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@@ -33,7 +33,7 @@ void audio_showstreamtitle(const char *info) {
telnet.info();
player.requesToStart = false;
} else {
telnet.printf("##CLI.META#: %s\n", info);
telnet.printf("##CLI.META#: %s\n> ", info);
}
}
}

View File

@@ -6,6 +6,12 @@ Config config;
void Config::init() {
eepromRead(EEPROM_START, store);
if (store.tz_set!=57){ // update to v0.4.200
store.tz_set = 57;
store.tzHour = 3;
store.tzMin = 0;
store.timezoneOffset = 0;
}
if (store.config_set != 4256) setDefaults();
//if (!SPIFFS.begin(false, "/spiffs", 30)) {
if (!SPIFFS.begin(false)) {
@@ -54,6 +60,25 @@ void Config::setDefaults() {
store.lastSSID = 0;
store.audioinfo = false;
store.smartstart = 2;
store.tz_set = 57;
store.tzHour = 3;
store.tzMin = 0;
store.timezoneOffset = 0;
}
void Config::setTimezone(int8_t tzh, int8_t tzm) {
store.tzHour=tzh;
store.tzMin=tzm;
save();
}
void Config::setTimezoneOffset(uint16_t tzo) {
store.timezoneOffset=tzo;
save();
}
uint16_t Config::getTimezoneOffset() {
return 0; // TODO
}
void Config::save() {

View File

@@ -23,6 +23,10 @@ struct config_t
byte lastSSID;
bool audioinfo;
byte smartstart;
byte tz_set; // must be 57
int8_t tzHour;
int8_t tzMin;
uint16_t timezoneOffset;
};
struct station_t
@@ -67,6 +71,9 @@ class Config {
void initPlaylist();
void indexPlaylist();
void fillPlMenu(char plmenu[][40], int from, byte count);
void setTimezone(int8_t tzh, int8_t tzm);
void setTimezoneOffset(uint16_t tzo);
uint16_t getTimezoneOffset();
private:
template <class T> int eepromWrite(int ee, const T& value);
template <class T> int eepromRead(int ee, T& value);

View File

@@ -1,10 +1,11 @@
#include "options.h"
#include "WiFi.h"
#include "time.h"
#include "display.h"
#include "player.h"
#include "netserver.h"
#include "options.h"
#include "network.h"
#if DSP_MODEL==0
@@ -85,7 +86,7 @@ void Scroll::clearscrolls() {
void Scroll::loop() {
if (checkdelay(x == TFT_FRAMEWDT ? delayStartScroll : SCROLLTIME, scrolldelay)) {
scroll();
ticks();
sticks();
}
yield();
}
@@ -103,7 +104,7 @@ void Scroll::drawFrame() {
dsp.drawScrollFrame(texttop, textheight, bg);
}
void Scroll::ticks() {
void Scroll::sticks() {
if (!doscroll || locked) return;
setTextParams();
dsp.set_Cursor(x, texttop);
@@ -170,7 +171,6 @@ void Display::start() {
station();
rssi();
time();
configTime(TIMEZONE, OFFSET, "pool.ntp.org", "ru.pool.ntp.org");
timer.attach_ms(1000, ticks);
// Экстреминатус секвестирован
}
@@ -213,14 +213,8 @@ void Display::swichMode(displayMode_e newmode) {
void Display::drawPlayer() {
if (clockRequest) {
if (syncTicks % 21600 == 0) { //6hours
configTime(TIMEZONE, OFFSET, "pool.ntp.org", "ru.pool.ntp.org");
yield();
syncTicks = 0;
}
getLocalTime(&timeinfo);
getLocalTime(&network.timeinfo);
time();
syncTicks++;
clockRequest = false;
}
meta.loop();
@@ -322,9 +316,9 @@ void Display::time() {
if (!dt) {
heap();
rssi();
strftime(timeStringBuff, sizeof(timeStringBuff), "%H:%M", &timeinfo);
strftime(timeStringBuff, sizeof(timeStringBuff), "%H:%M", &network.timeinfo);
} else {
strftime(timeStringBuff, sizeof(timeStringBuff), "%H %M", &timeinfo);
strftime(timeStringBuff, sizeof(timeStringBuff), "%H %M", &network.timeinfo);
}
dsp.printClock(timeStringBuff);
dt = !dt;

View File

@@ -7,9 +7,6 @@
enum displayMode_e { PLAYER, VOL, STATIONS };
#define TIMEZONE 10800 // 3600*3=10800 (UTC+3)
#define OFFSET 0 // Daylight Offset (sec.)
class Scroll {
public:
Scroll() { };
@@ -33,7 +30,7 @@ class Scroll {
void getbounds(uint16_t &tWidth, uint16_t &tHeight, uint16_t &sWidth);
boolean checkdelay(int m, unsigned long &tstamp);
void scroll();
void ticks();
void sticks();
void clear();
void setTextParams();
void drawFrame();
@@ -41,8 +38,6 @@ class Scroll {
class Display {
public:
struct tm timeinfo;
uint16_t syncTicks;
bool clockRequest;
uint16_t screenwidth, screenheight;
displayMode_e mode;

View File

@@ -2,9 +2,15 @@
#include "WiFi.h"
#include "display.h"
#include "options.h"
#include "config.h"
#include "telnet.h"
Network network;
void syncTime() {
network.requestTimeSync(true);
}
void Network::begin() {
config.initNetwork();
if (config.ssidsCount == 0) {
@@ -35,7 +41,7 @@ void Network::begin() {
break;
}
}
if(WiFi.status() != WL_CONNECTED && ls==startedls){
if (WiFi.status() != WL_CONNECTED && ls == startedls) {
raiseSoftAP();
return;
}
@@ -46,6 +52,22 @@ void Network::begin() {
}
digitalWrite(LED_BUILTIN, LOW);
status = CONNECTED;
requestTimeSync();
ntimer.attach_ms(TSYNC_DELAY, syncTime);
}
void Network::requestTimeSync(bool withTelnetOutput) {
configTime(config.store.tzHour * 3600 + config.store.tzMin * 60, config.getTimezoneOffset(), "pool.ntp.org", "ru.pool.ntp.org");
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);
} else {
telnet.printf(0, "##SYS.DATE#: %s+%02d:%02d\n> ", timeStringBuff, config.store.tzHour, config.store.tzMin);
}
}
}
void Network::raiseSoftAP() {

View File

@@ -1,18 +1,24 @@
#ifndef network_h
#define network_h
#include <Ticker.h>
#include "time.h"
#define apSsid "yoRadioAP"
#define apPassword "12345987"
#define TSYNC_DELAY 10800000 // 1000*60*60*3 = 3 hours
enum n_Status_e { CONNECTED, SOFT_AP, FAILED };
class Network {
public:
n_Status_e status;
struct tm timeinfo;
public:
Network() {};
void begin();
void requestTimeSync(bool withTelnetOutput=false);
private:
Ticker ntimer;
void raiseSoftAP();
};

View File

@@ -1,7 +1,7 @@
#ifndef options_h
#define options_h
#define VERSION "0.4.199"
#define VERSION "0.4.210"
/* DISPLAY MODEL
* 0 - DUMMY

View File

@@ -30,6 +30,7 @@ void Player::loop() {
} else {
if (isRunning()) {
digitalWrite(LED_BUILTIN, LOW);
display.title("[stopped]");
stopSong();
stopInfo();
}

View File

@@ -4,7 +4,7 @@
#include "config.h"
#include "telnet.h"
#include "player.h"
#include "display.h"
#include "network.h"
Telnet telnet;
@@ -139,7 +139,7 @@ void Telnet::info() {
byte volume;
telnet.printf("##CLI.INFO#\n");
char timeStringBuff[50];
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S+03:00", &display.timeinfo);
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S+03:00", &network.timeinfo);
telnet.printf("##SYS.DATE#: %s\n", timeStringBuff); //TODO timezone offset
telnet.printf("##CLI.NAMESET#: %d %s\n", config.store.lastStation, config.station.name);
if (player.mode == PLAYING) {
@@ -170,7 +170,7 @@ void Telnet::on_input(const char* str, byte clientId) {
}
if (strcmp(str, "cli.stop") == 0 || strcmp(str, "stop") == 0) {
player.mode = STOPPED;
display.title("[stopped]");
//display.title("[stopped]");
info();
return;
}
@@ -183,13 +183,11 @@ void Telnet::on_input(const char* str, byte clientId) {
return;
}
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;
}
if (strcmp(str, "sys.date") == 0) {
char timeStringBuff[50];
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%S+03:00", &display.timeinfo);
telnet.printf("##SYS.DATE#: %s\n", timeStringBuff); //TODO timezone offset
network.requestTimeSync(true);
return;
}
int volume;
@@ -199,24 +197,25 @@ void Telnet::on_input(const char* str, byte clientId) {
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);
printf(clientId, "##CLI.AUDIOINFO#: %d\n> ", config.store.audioinfo > 0);
return;
}
byte 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;
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);
printf(clientId, "##CLI.SMARTSTART#: %d\n> ", config.store.smartstart);
return;
}
byte sstart;
if (sscanf(str, "smartstart(%d)", &sstart) == 1 || sscanf(str, "cli.smartstart(\"%d\")", &sstart) == 1 || sscanf(str, "smartstart %d", &sstart) == 1) {
config.store.smartstart = sstart;
printf(clientId, "new smartstart value is: %d\n> ", config.store.audioinfo);
config.save();
return;
}
@@ -242,8 +241,12 @@ void Telnet::on_input(const char* str, byte clientId) {
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+03:00", &display.timeinfo);
printf(clientId, "##SYS.DATE#: %s\n", timeStringBuff); //TODO timezone offset
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);
@@ -257,7 +260,6 @@ void Telnet::on_input(const char* str, byte clientId) {
printf(clientId, "> ");
return;
}
uint8_t 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;
@@ -265,5 +267,37 @@ void Telnet::on_input(const char* str, byte clientId) {
player.play(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;
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(tzh, 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(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;
}
telnet.printf(clientId, "unknown command: %s\n> ", str);
}