From f390872d6af3aa5ca8d87e1ae5d2da00e84a7a7d Mon Sep 17 00:00:00 2001 From: e2002 Date: Tue, 21 Feb 2023 17:06:39 +0300 Subject: [PATCH] v0.8.950 --- HA/custom_components/yoradio/media_player.py | 45 ++++++++++++++++++-- README.md | 3 ++ yoRadio/src/core/mqtt.cpp | 10 ++++- yoRadio/src/core/netserver.cpp | 8 ++-- yoRadio/src/core/options.h | 2 +- yoRadio/src/core/player.cpp | 32 ++++++++++++++ yoRadio/src/core/player.h | 7 +++ yoRadio/yoRadio.ino | 19 ++++++++- 8 files changed, 114 insertions(+), 12 deletions(-) diff --git a/HA/custom_components/yoradio/media_player.py b/HA/custom_components/yoradio/media_player.py index 3c82266..e999c64 100644 --- a/HA/custom_components/yoradio/media_player.py +++ b/HA/custom_components/yoradio/media_player.py @@ -4,28 +4,35 @@ import logging import voluptuous as vol import json +from homeassistant.components import media_source from homeassistant.helpers.aiohttp_client import async_get_clientsession _LOGGER = logging.getLogger(__name__) -VERSION = '0.8.933' +VERSION = '0.8.950' DOMAIN = "yoradio" from homeassistant.helpers import config_validation as cv +from homeassistant.components.media_player.browse_media import ( + async_process_play_media_url, +) from homeassistant.components.media_player import ( MediaPlayerEntity, + MediaPlayerEnqueue, + BrowseMedia, PLATFORM_SCHEMA ) from homeassistant.components.media_player.const import ( MEDIA_TYPE_MUSIC, + MEDIA_TYPE_URL, SUPPORT_TURN_ON, SUPPORT_TURN_OFF, SUPPORT_VOLUME_STEP, SUPPORT_VOLUME_SET, SUPPORT_PAUSE, SUPPORT_PLAY, SUPPORT_STOP, SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK, - SUPPORT_SELECT_SOURCE + SUPPORT_SELECT_SOURCE, SUPPORT_BROWSE_MEDIA, SUPPORT_PLAY_MEDIA ) from homeassistant.const import ( @@ -38,7 +45,7 @@ from homeassistant.const import ( SUPPORT_YORADIO = SUPPORT_PAUSE | SUPPORT_PLAY | SUPPORT_STOP |\ SUPPORT_VOLUME_SET | SUPPORT_VOLUME_STEP | \ SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | \ - SUPPORT_SELECT_SOURCE + SUPPORT_SELECT_SOURCE | SUPPORT_BROWSE_MEDIA | SUPPORT_PLAY_MEDIA DEFAULT_NAME = 'yoRadio' CONF_MAX_VOLUME = 'max_volume' @@ -88,6 +95,12 @@ class yoradioApi(): except: await self.mqtt.async_publish(self.hass, self.root_topic + '/command', command) + async def set_browse_media(self, media_content_id): + try: + self.mqtt.async_publish(self.root_topic + '/command', media_content_id) + except: + await self.mqtt.async_publish(self.hass, self.root_topic + '/command', media_content_id) + async def load_playlist(self, msg): try: async with aiohttp.ClientSession() as session: @@ -186,6 +199,32 @@ class yoradioDevice(MediaPlayerEntity): def source_list(self): return self.api.playlist + async def async_browse_media( + self, media_content_type: str | None = None, media_content_id: str | None = None + ) -> BrowseMedia: + #await self.api.set_browse_media(media_content_id) + """Implement the websocket media browsing helper.""" + return await media_source.async_browse_media( + self.hass, + media_content_id, + ) + + async def async_play_media( + self, + media_type: str, + media_id: str, + enqueue: MediaPlayerEnqueue | None = None, + announce: bool | None = None, **kwargs + ) -> None: + """Play a piece of media.""" + if media_source.is_media_source_id(media_id): + media_type = MEDIA_TYPE_URL + play_item = await media_source.async_resolve_media(self.hass, media_id, self.entity_id) + media_id = async_process_play_media_url(self.hass, play_item.url) + if media_type in (MEDIA_TYPE_URL): + media_id = async_process_play_media_url(self.hass, media_id) + await self.api.set_browse_media(media_id) + async def async_select_source(self, source): await self.api.set_source(source) self._current_source = source diff --git a/README.md b/README.md index 6685e8e..06e4350 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,9 @@ Work is in progress... --- ## Version history +#### v0.8.950 +- added support for remote media playback from Home Assistant (Local Media, Radio Browser, TTS) + #### v0.8.933 (homeassistant component) - HA component >> fixed bugs of getting and generating a playlist diff --git a/yoRadio/src/core/mqtt.cpp b/yoRadio/src/core/mqtt.cpp index 382f94b..e172576 100644 --- a/yoRadio/src/core/mqtt.cpp +++ b/yoRadio/src/core/mqtt.cpp @@ -1,6 +1,6 @@ #include "mqtt.h" -#ifdef MQTT_HOST +#ifdef MQTT_ROOT_TOPIC #include "WiFi.h" #include "telnet.h" @@ -122,6 +122,12 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties player.request.doSave = true; return; } + if (strstr(buf, "http")==buf){ + Serial.println(payload); + if(len+1>sizeof(player.burl)) return; + strlcpy(player.burl, payload, len+1); + return; + } } -#endif // ifdef MQTT_HOST +#endif // #ifdef MQTT_ROOT_TOPIC diff --git a/yoRadio/src/core/netserver.cpp b/yoRadio/src/core/netserver.cpp index 5619b66..706e0dc 100644 --- a/yoRadio/src/core/netserver.cpp +++ b/yoRadio/src/core/netserver.cpp @@ -30,7 +30,7 @@ void handleHTTPArgs(AsyncWebServerRequest * request); void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len); bool shouldReboot = false; -#ifdef MQTT_HOST +#ifdef MQTT_ROOT_TOPIC Ticker mqttplaylistticker; bool mqttplaylistblock = false; void mqttplaylistSend() { @@ -231,7 +231,7 @@ void NetServer::processQueue(){ } if (strlen(wsbuf) > 0) { if (clientId == 0) { websocket.textAll(wsbuf); }else{ websocket.text(clientId, wsbuf); } - #ifdef MQTT_HOST + #ifdef MQTT_ROOT_TOPIC if (clientId == 0 && (request.type == STATION || request.type == ITEM || request.type == TITLE || request.type == MODE)) mqttPublishStatus(); if (clientId == 0 && request.type == VOLUME) mqttPublishVolume(); #endif @@ -548,7 +548,7 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client return; } if (strcmp(cmd, "submitplaylistdone") == 0) { -#ifdef MQTT_HOST +#ifdef MQTT_ROOT_TOPIC //mqttPublishPlaylist(); mqttplaylistticker.attach(5, mqttplaylistSend); #endif @@ -679,7 +679,7 @@ void handleHTTPArgs(AsyncWebServerRequest * request) { if (request->method() == HTTP_GET) { DBGVB("[%s] client ip=%s request of %s", __func__, request->client()->remoteIP().toString().c_str(), request->url().c_str()); if (strcmp(request->url().c_str(), PLAYLIST_PATH) == 0 || strcmp(request->url().c_str(), SSIDS_PATH) == 0 || strcmp(request->url().c_str(), INDEX_PATH) == 0 || strcmp(request->url().c_str(), TMP_PATH) == 0 || strcmp(request->url().c_str(), PLAYLIST_SD_PATH) == 0 || strcmp(request->url().c_str(), INDEX_SD_PATH) == 0) { -#ifdef MQTT_HOST +#ifdef MQTT_ROOT_TOPIC if (strcmp(request->url().c_str(), PLAYLIST_PATH) == 0) while (mqttplaylistblock) vTaskDelay(5); #endif if(strcmp(request->url().c_str(), PLAYLIST_PATH) == 0 && config.store.play_mode==PM_SDCARD){ diff --git a/yoRadio/src/core/options.h b/yoRadio/src/core/options.h index 26f8060..e10d377 100644 --- a/yoRadio/src/core/options.h +++ b/yoRadio/src/core/options.h @@ -1,7 +1,7 @@ #ifndef options_h #define options_h -#define YOVERSION "0.8.933" +#define YOVERSION "0.8.950" /******************************************************* DO NOT EDIT THIS FILE. diff --git a/yoRadio/src/core/player.cpp b/yoRadio/src/core/player.cpp index 7ef5710..a0fed0e 100644 --- a/yoRadio/src/core/player.cpp +++ b/yoRadio/src/core/player.cpp @@ -34,6 +34,9 @@ Player player; void Player::init() { Serial.print("##[BOOT]#\tplayer.init\t"); +#ifdef MQTT_ROOT_TOPIC + memset(burl, 0, 400); +#endif if(MUTE_PIN!=255) pinMode(MUTE_PIN, OUTPUT); #if I2S_DOUT!=255 #if !I2S_INTERNAL @@ -124,6 +127,11 @@ void Player::loop() { volTimer=false; } } +#ifdef MQTT_ROOT_TOPIC + if(strlen(burl)>0){ + browseUrl(); + } +#endif } void Player::zeroRequest() { @@ -165,6 +173,30 @@ void Player::play(uint16_t stationId, uint32_t filePos) { }; } +#ifdef MQTT_ROOT_TOPIC +void Player::browseUrl(){ + resumeAfterUrl = mode==PLAYING; + display.putRequest(PSTOP); + setDefaults(); + setOutputPins(false); + config.setTitle(const_PlConnect); + netserver.requestOnChange(TITLE, 0); + if (connecttohost(burl)){ + mode = PLAYING; + config.setTitle(""); + netserver.requestOnChange(TITLE, 0); + netserver.requestOnChange(MODE, 0); + setOutputPins(true); + requestToStart = true; + display.putRequest(PSTART); + if (player_on_start_play) player_on_start_play(); + }else{ + telnet.printf("##ERROR#:\tError connecting to %s\n", burl); + } + memset(burl, 0, 400); +} +#endif + void Player::prev() { if(config.store.play_mode==PM_WEB || !config.sdSnuffle){ if (config.store.lastStation == 1) config.store.lastStation = config.store.countStation; else config.store.lastStation--; diff --git a/yoRadio/src/core/player.h b/yoRadio/src/core/player.h index d0cac6a..c43a836 100644 --- a/yoRadio/src/core/player.h +++ b/yoRadio/src/core/player.h @@ -27,13 +27,20 @@ class Player: public Audio { void zeroRequest(); SemaphoreHandle_t playmutex=NULL; bool lockOutput = true; + bool resumeAfterUrl = false; uint32_t sd_min, sd_max; + #ifdef MQTT_ROOT_TOPIC + char burl[400]; /* buffer for browseUrl */ + #endif public: Player(); void init(); void loop(); void initHeaders(const char *file); void play(uint16_t stationId, uint32_t filePos=0); + #ifdef MQTT_ROOT_TOPIC + void browseUrl(); + #endif void stop(const char *nttl = NULL); void prev(); void next(); diff --git a/yoRadio/yoRadio.ino b/yoRadio/yoRadio.ino index 80bc08c..540856b 100644 --- a/yoRadio/yoRadio.ino +++ b/yoRadio/yoRadio.ino @@ -52,7 +52,7 @@ void setup() { initControls(); display.putRequest(DSP_START); while(!display.ready()) delay(10); - #ifdef MQTT_HOST + #ifdef MQTT_ROOT_TOPIC mqttInit(); #endif if (config.store.play_mode==PM_SDCARD) player.initHeaders(config.station.url); @@ -87,7 +87,7 @@ void checkConnection(){ display.putRequest(NEWMODE, PLAYER); if (playing) player.request.station = config.store.lastStation; checkMillis = millis(); - #ifdef MQTT_HOST + #ifdef MQTT_ROOT_TOPIC connectToMqtt(); #endif } @@ -142,6 +142,9 @@ void audio_showstation(const char *info) { bool p = printable(info); config.setTitle(p?info:config.station.name); netserver.requestOnChange(TITLE, 0); + config.setStation(p?info:config.station.name); + display.putRequest(NEWSTATION); + netserver.requestOnChange(STATION, 0); } } @@ -198,6 +201,7 @@ void audio_id3data(const char *info){ //id3 metadata if(player.lockOutput) return; telnet.printf("##AUDIO.ID3#: %s\n", info); } + void audio_eof_mp3(const char *info){ //end of file config.sdResumePos = 0; if(config.sdSnuffle){ @@ -206,6 +210,17 @@ void audio_eof_mp3(const char *info){ //end of file player.next(); } } + +void audio_eof_stream(const char *info){ + player.stop(); + if(!player.resumeAfterUrl) return; + if (config.store.play_mode==PM_WEB){ + player.play(config.store.lastStation); + }else{ + player.play(config.store.lastStation, config.sdResumePos==0?0:config.sdResumePos-player.sd_min); + } +} + void audio_progress(uint32_t startpos, uint32_t endpos){ player.sd_min = startpos; player.sd_max = endpos;