v0.4.320
This commit is contained in:
34
README.md
34
README.md
@@ -9,6 +9,7 @@
|
|||||||
- [Hardware setup](#hardware-setup)
|
- [Hardware setup](#hardware-setup)
|
||||||
- [Quick start](#quick-start)
|
- [Quick start](#quick-start)
|
||||||
- [Update](#update)
|
- [Update](#update)
|
||||||
|
- [MQTT](#mqtt)
|
||||||
- [More features](#more-features)
|
- [More features](#more-features)
|
||||||
- [Version history](#version-history)
|
- [Version history](#version-history)
|
||||||
---
|
---
|
||||||
@@ -101,7 +102,9 @@ _\** GPIOs 34-39 don't have software pullup/down functions. For encoder/buttons
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
#### Libraries:
|
#### Libraries:
|
||||||
**Library Manager**: Adafruit_GFX, Adafruit_ST7735\*, Adafruit_SSD1306\*, Adafruit_PCD8544\*, (\* depending on display model), ESP32Encoder, OneButton, IRremoteESP8266 \
|
**Library Manager**: Adafruit_GFX, Adafruit_ST7735\*, Adafruit_SSD1306\*, Adafruit_PCD8544\*, (\* depending on display model), ESP32Encoder, OneButton, IRremoteESP8266 \
|
||||||
**Github**: [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer), [AsyncTCP](https://github.com/me-no-dev/AsyncTCP)
|
**Github**: [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer), [AsyncTCP](https://github.com/me-no-dev/AsyncTCP), [async-mqtt-client](https://github.com/marvinroger/async-mqtt-client)* \
|
||||||
|
\* _if you need MQTT support_
|
||||||
|
|
||||||
#### Tool:
|
#### Tool:
|
||||||
[ESP32 Filesystem Uploader](https://randomnerdtutorials.com/install-esp32-filesystem-uploader-arduino-ide/)
|
[ESP32 Filesystem Uploader](https://randomnerdtutorials.com/install-esp32-filesystem-uploader-arduino-ide/)
|
||||||
|
|
||||||
@@ -171,6 +174,12 @@ download _http://\<yoradioip\>/data/playlist.csv_ and _http://\<yoradioip\>/data
|
|||||||
4. Go to page _http://\<yoradioip\>/_ in the browser and press Ctrl+F5 to update the scripts.
|
4. Go to page _http://\<yoradioip\>/_ in the browser and press Ctrl+F5 to update the scripts.
|
||||||
5. Well done!
|
5. Well done!
|
||||||
|
|
||||||
|
---
|
||||||
|
## MQTT
|
||||||
|
1. Copy file exsamples/mqttoptions.h to yoRadio/ directory
|
||||||
|
2. In the mqtoptions.h file, change the options to the ones you need
|
||||||
|
3. Well done!
|
||||||
|
|
||||||
---
|
---
|
||||||
## 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)
|
||||||
@@ -196,12 +205,33 @@ download _http://\<yoradioip\>/data/playlist.csv_ and _http://\<yoradioip\>/data
|
|||||||
**sys.tzo("h:m")** _or_ **tzo(h:m)** _or_ **tzo h:m** - set 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
|
**sys.tzo("h")** _or_ **tzo(h)** _or_ **tzo h** - set timezone offset in hours only
|
||||||
|
|
||||||
|
- MQTT support \
|
||||||
|
**Topics**: \
|
||||||
|
**MQTT_ROOT_TOPIC/command** - Commands \
|
||||||
|
**MQTT_ROOT_TOPIC/status** - Player status \
|
||||||
|
**MQTT_ROOT_TOPIC/playlist** - Playlist URL \
|
||||||
|
**MQTT_ROOT_TOPIC/volume** - Current volume
|
||||||
|
|
||||||
|
**Commands**: \
|
||||||
|
**prev** - prev station \
|
||||||
|
**next** - next station \
|
||||||
|
**toggle** - start/stop playing \
|
||||||
|
**stop** - stop playing \
|
||||||
|
**start, play** - start playing \
|
||||||
|
**boot, reboot** - reboot \
|
||||||
|
**vol x** - set volume \
|
||||||
|
**play x** - play station x
|
||||||
---
|
---
|
||||||
## Version history
|
## Version history
|
||||||
|
#### v0.4.320
|
||||||
|
- MQTT support
|
||||||
|
|
||||||
|
<img src="images/mqtt.jpg" width="680" height="110">
|
||||||
|
|
||||||
#### v0.4.315
|
#### v0.4.315
|
||||||
- added support for digital buttons for the IR control \
|
- added support for digital buttons for the IR control \
|
||||||
(num keys - enter number of station, ok - play, hash - cancel)
|
(num keys - enter number of station, ok - play, hash - cancel)
|
||||||
- added buttons for exporting settings from the web interface
|
- added buttons for exporting settings from the web interface
|
||||||
- added MUTE_PIN to be able to control the audio output
|
- added MUTE_PIN to be able to control the audio output
|
||||||
- fixed js/html bugs (a [full update](#update) is required)
|
- fixed js/html bugs (a [full update](#update) is required)
|
||||||
|
|
||||||
|
|||||||
24
exsamples/mqttoptions.h
Normal file
24
exsamples/mqttoptions.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#define MQTT_HOST "192.168.3.100"
|
||||||
|
#define MQTT_PORT 1883
|
||||||
|
#define MQTT_USER ""
|
||||||
|
#define MQTT_PASS ""
|
||||||
|
|
||||||
|
#define MQTT_ROOT_TOPIC "yoradio/100/"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Topics:
|
||||||
|
MQTT_ROOT_TOPIC/command // Commands
|
||||||
|
MQTT_ROOT_TOPIC/status // Player status
|
||||||
|
MQTT_ROOT_TOPIC/playlist // Playlist URL
|
||||||
|
MQTT_ROOT_TOPIC/volume // Current volume
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
prev // prev station
|
||||||
|
next // next station
|
||||||
|
toggle // start/stop playing
|
||||||
|
stop // stop playing
|
||||||
|
start, play // start playing
|
||||||
|
boot, reboot // reboot
|
||||||
|
vol x // set volume
|
||||||
|
play x // play station x
|
||||||
|
*/
|
||||||
BIN
images/mqtt.jpg
Normal file
BIN
images/mqtt.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
112
yoRadio/mqtt.cpp
Normal file
112
yoRadio/mqtt.cpp
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#include "mqtt.h"
|
||||||
|
|
||||||
|
#ifdef MQTT_HOST
|
||||||
|
#include "WiFi.h"
|
||||||
|
|
||||||
|
#include "telnet.h"
|
||||||
|
#include "player.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
AsyncMqttClient mqttClient;
|
||||||
|
TimerHandle_t mqttReconnectTimer;
|
||||||
|
|
||||||
|
void connectToMqtt() {
|
||||||
|
mqttClient.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mqttInit() {
|
||||||
|
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
|
||||||
|
mqttClient.onConnect(onMqttConnect);
|
||||||
|
mqttClient.onDisconnect(onMqttDisconnect);
|
||||||
|
mqttClient.onMessage(onMqttMessage);
|
||||||
|
if(MQTT_USER!="") mqttClient.setCredentials(MQTT_USER, MQTT_PASS);
|
||||||
|
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
|
||||||
|
connectToMqtt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onMqttConnect(bool sessionPresent) {
|
||||||
|
char buf[140];
|
||||||
|
sprintf(buf, "%s%s", MQTT_ROOT_TOPIC, "command");
|
||||||
|
mqttClient.subscribe(buf, 2);
|
||||||
|
mqttPublishStatus();
|
||||||
|
mqttPublishVolume();
|
||||||
|
mqttPublishPlaylist();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mqttPublishStatus() {
|
||||||
|
if(mqttClient.connected()){
|
||||||
|
char topic[140], status[255];
|
||||||
|
sprintf(topic, "%s%s", MQTT_ROOT_TOPIC, "status");
|
||||||
|
sprintf(status, "{\"status\": %d, \"station\": %d, \"name\": \"%s\", \"title\": \"%s\"}", player.mode==PLAYING?1:0, config.store.lastStation, config.station.name, config.station.title);
|
||||||
|
mqttClient.publish(topic, 0, true, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mqttPublishPlaylist() {
|
||||||
|
if(mqttClient.connected()){
|
||||||
|
char topic[140], playlist[140];
|
||||||
|
sprintf(topic, "%s%s", MQTT_ROOT_TOPIC, "playlist");
|
||||||
|
sprintf(playlist, "http://%s%s", WiFi.localIP().toString().c_str(), PLAYLIST_PATH);
|
||||||
|
mqttClient.publish(topic, 0, true, playlist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mqttPublishVolume(){
|
||||||
|
if(mqttClient.connected()){
|
||||||
|
char topic[140], vol[5];
|
||||||
|
sprintf(topic, "%s%s", MQTT_ROOT_TOPIC, "volume");
|
||||||
|
sprintf(vol, "%d", config.store.volume);
|
||||||
|
mqttClient.publish(topic, 0, true, vol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
|
||||||
|
if (WiFi.isConnected()) {
|
||||||
|
xTimerStart(mqttReconnectTimer, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||||
|
if (strlen(payload) == 0) return;
|
||||||
|
if (strcmp(payload, "prev") == 0) {
|
||||||
|
player.prev();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strcmp(payload, "next") == 0) {
|
||||||
|
player.next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strcmp(payload, "toggle") == 0) {
|
||||||
|
player.toggle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strcmp(payload, "stop") == 0) {
|
||||||
|
player.mode = STOPPED;
|
||||||
|
telnet.info();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strcmp(payload, "start") == 0 || strcmp(payload, "play") == 0) {
|
||||||
|
player.play(config.store.lastStation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strcmp(payload, "boot") == 0 || strcmp(payload, "reboot") == 0) {
|
||||||
|
ESP.restart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int volume;
|
||||||
|
if ( sscanf(payload, "vol %d", &volume) == 1) {
|
||||||
|
if (volume < 0) volume = 0;
|
||||||
|
if (volume > 254) volume = 254;
|
||||||
|
player.setVol(volume, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint16_t sb;
|
||||||
|
if (sscanf(payload, "play %d", &sb) == 1 ) {
|
||||||
|
if (sb < 1) sb = 1;
|
||||||
|
if (sb >= config.store.countStation) sb = config.store.countStation;
|
||||||
|
player.play(sb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ifdef MQTT_HOST
|
||||||
21
yoRadio/mqtt.h
Normal file
21
yoRadio/mqtt.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef mqtt_h
|
||||||
|
#define mqtt_h
|
||||||
|
|
||||||
|
#if __has_include("mqttoptions.h")
|
||||||
|
#include "mqttoptions.h"
|
||||||
|
#include <AsyncMqttClient.h>
|
||||||
|
|
||||||
|
|
||||||
|
void mqttInit();
|
||||||
|
void connectToMqtt();
|
||||||
|
void onMqttConnect(bool sessionPresent);
|
||||||
|
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
|
||||||
|
void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total);
|
||||||
|
void mqttPublishStatus();
|
||||||
|
void mqttPublishPlaylist();
|
||||||
|
void mqttPublishVolume();
|
||||||
|
|
||||||
|
#endif // if __has_include("mqttoptions.h")
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
#include "mqtt.h"
|
||||||
|
|
||||||
NetServer netserver;
|
NetServer netserver;
|
||||||
|
|
||||||
@@ -183,6 +184,9 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) {
|
|||||||
config.indexPlaylist();
|
config.indexPlaylist();
|
||||||
config.initPlaylist();
|
config.initPlaylist();
|
||||||
getPlaylist(clientId);
|
getPlaylist(clientId);
|
||||||
|
#ifdef MQTT_HOST
|
||||||
|
mqttPublishPlaylist();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case STATION: {
|
case STATION: {
|
||||||
@@ -200,6 +204,9 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) {
|
|||||||
}
|
}
|
||||||
case VOLUME: {
|
case VOLUME: {
|
||||||
sprintf (buf, "{\"vol\": %d}", config.store.volume);
|
sprintf (buf, "{\"vol\": %d}", config.store.volume);
|
||||||
|
#ifdef MQTT_HOST
|
||||||
|
if (clientId == 0) mqttPublishVolume();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NRSSI: {
|
case NRSSI: {
|
||||||
@@ -226,6 +233,9 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) {
|
|||||||
if (strlen(buf) > 0) {
|
if (strlen(buf) > 0) {
|
||||||
if (clientId == 0) {
|
if (clientId == 0) {
|
||||||
websocket.textAll(buf);
|
websocket.textAll(buf);
|
||||||
|
#ifdef MQTT_HOST
|
||||||
|
if(request==STATION || request==ITEM || request==TITLE || request==MODE) mqttPublishStatus();
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
websocket.text(clientId, buf);
|
websocket.text(clientId, buf);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef options_h
|
#ifndef options_h
|
||||||
#define options_h
|
#define options_h
|
||||||
|
|
||||||
#define VERSION "0.4.315"
|
#define VERSION "0.4.320"
|
||||||
|
|
||||||
#if __has_include("myoptions.h")
|
#if __has_include("myoptions.h")
|
||||||
#include "myoptions.h" // <- write your variable values here
|
#include "myoptions.h" // <- write your variable values here
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "netserver.h"
|
#include "netserver.h"
|
||||||
#include "controls.h"
|
#include "controls.h"
|
||||||
|
#include "mqtt.h"
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
@@ -30,6 +31,9 @@ void setup() {
|
|||||||
player.setVol(config.store.volume, true);
|
player.setVol(config.store.volume, true);
|
||||||
display.start();
|
display.start();
|
||||||
if(config.store.smartstart==1) player.play(config.store.lastStation);
|
if(config.store.smartstart==1) player.play(config.store.lastStation);
|
||||||
|
#ifdef MQTT_HOST
|
||||||
|
mqttInit();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|||||||
Reference in New Issue
Block a user