From bb752f08a2d91c3bef8e11916bd9967550d58540 Mon Sep 17 00:00:00 2001 From: e2002 Date: Thu, 3 Mar 2022 12:34:19 +0300 Subject: [PATCH] v0.4.320 --- README.md | 34 +++++++++++- exsamples/mqttoptions.h | 24 +++++++++ images/mqtt.jpg | Bin 0 -> 15166 bytes yoRadio/mqtt.cpp | 112 ++++++++++++++++++++++++++++++++++++++++ yoRadio/mqtt.h | 21 ++++++++ yoRadio/netserver.cpp | 10 ++++ yoRadio/options.h | 2 +- yoRadio/yoRadio.ino | 4 ++ 8 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 exsamples/mqttoptions.h create mode 100644 images/mqtt.jpg create mode 100644 yoRadio/mqtt.cpp create mode 100644 yoRadio/mqtt.h diff --git a/README.md b/README.md index fdf0f4a..b8d3e35 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ - [Hardware setup](#hardware-setup) - [Quick start](#quick-start) - [Update](#update) +- [MQTT](#mqtt) - [More features](#more-features) - [Version history](#version-history) --- @@ -101,7 +102,9 @@ _\** GPIOs 34-39 don't have software pullup/down functions. For encoder/buttons ## Dependencies #### Libraries: **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: [ESP32 Filesystem Uploader](https://randomnerdtutorials.com/install-esp32-filesystem-uploader-arduino-ide/) @@ -171,6 +174,12 @@ download _http://\/data/playlist.csv_ and _http://\/data 4. Go to page _http://\/_ in the browser and press Ctrl+F5 to update the scripts. 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 - С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://\/data/playlist.csv_ and _http://\/data **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 \ + **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 +#### v0.4.320 +- MQTT support + + + #### v0.4.315 - added support for digital buttons for the IR control \ (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 - fixed js/html bugs (a [full update](#update) is required) diff --git a/exsamples/mqttoptions.h b/exsamples/mqttoptions.h new file mode 100644 index 0000000..926eb1a --- /dev/null +++ b/exsamples/mqttoptions.h @@ -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 +*/ diff --git a/images/mqtt.jpg b/images/mqtt.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8876d998fff8b8e1a92adf83c8fd5dab19d9f7bd GIT binary patch literal 15166 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 literal 0 HcmV?d00001 diff --git a/yoRadio/mqtt.cpp b/yoRadio/mqtt.cpp new file mode 100644 index 0000000..432d932 --- /dev/null +++ b/yoRadio/mqtt.cpp @@ -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(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 diff --git a/yoRadio/mqtt.h b/yoRadio/mqtt.h new file mode 100644 index 0000000..224870c --- /dev/null +++ b/yoRadio/mqtt.h @@ -0,0 +1,21 @@ +#ifndef mqtt_h +#define mqtt_h + +#if __has_include("mqttoptions.h") +#include "mqttoptions.h" +#include + + +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 diff --git a/yoRadio/netserver.cpp b/yoRadio/netserver.cpp index 1c5391d..ced44fa 100644 --- a/yoRadio/netserver.cpp +++ b/yoRadio/netserver.cpp @@ -6,6 +6,7 @@ #include "display.h" #include "options.h" #include "network.h" +#include "mqtt.h" NetServer netserver; @@ -183,6 +184,9 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) { config.indexPlaylist(); config.initPlaylist(); getPlaylist(clientId); +#ifdef MQTT_HOST + mqttPublishPlaylist(); +#endif break; } case STATION: { @@ -200,6 +204,9 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) { } case VOLUME: { sprintf (buf, "{\"vol\": %d}", config.store.volume); +#ifdef MQTT_HOST + if (clientId == 0) mqttPublishVolume(); +#endif break; } case NRSSI: { @@ -226,6 +233,9 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) { if (strlen(buf) > 0) { if (clientId == 0) { websocket.textAll(buf); +#ifdef MQTT_HOST + if(request==STATION || request==ITEM || request==TITLE || request==MODE) mqttPublishStatus(); +#endif } else { websocket.text(clientId, buf); } diff --git a/yoRadio/options.h b/yoRadio/options.h index 5f0db5b..12bd0aa 100644 --- a/yoRadio/options.h +++ b/yoRadio/options.h @@ -1,7 +1,7 @@ #ifndef options_h #define options_h -#define VERSION "0.4.315" +#define VERSION "0.4.320" #if __has_include("myoptions.h") #include "myoptions.h" // <- write your variable values here diff --git a/yoRadio/yoRadio.ino b/yoRadio/yoRadio.ino index 358738b..a408b22 100644 --- a/yoRadio/yoRadio.ino +++ b/yoRadio/yoRadio.ino @@ -9,6 +9,7 @@ #include "network.h" #include "netserver.h" #include "controls.h" +#include "mqtt.h" void setup() { Serial.begin(115200); @@ -30,6 +31,9 @@ void setup() { player.setVol(config.store.volume, true); display.start(); if(config.store.smartstart==1) player.play(config.store.lastStation); +#ifdef MQTT_HOST + mqttInit(); +#endif } void loop() {