Skip to content

Commit 5cb0b8b

Browse files
fhirschmannclaude
andcommitted
feat: publish now-playing artist/album over MQTT + Home Assistant sensors
Roadmap item 7. Publishes the ID3 artist and album to new MQTT state topics (track_artist / track_album, next to the existing track title + cover_changed), reset per track and re-published on (re)connect, plus Home-Assistant discovery sensors (Artist, Album) mirroring the existing Track sensor. Compile-verified; MQTT runtime not exercised on the test device (no broker / MQTT disabled there) - the publish calls are guarded by MQTT_ENABLE and follow the existing topicTrack/cover patterns. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent c2e7d44 commit 5cb0b8b

4 files changed

Lines changed: 15 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ neon logo that doubles as the SVG favicon ([`7be5254`](../../commit/7be5254)):
148148
| **Settings tabs de-cluttered**: the long "General" sub-tab was split — the **LED** settings (NeoPixel brightness + LED config) moved into a new **LEDs** sub-tab, and **Deep sleep + Battery** into a new **Power** sub-tab. Both new tabs are covered by the same auto-save. General now holds just volume/branding/options/playlist/rotary. i18n de/en/fr | [`settings-split`](../../releases/tag/settings-split) |
149149
| **Folder cover-art fallback**: when a track has no embedded ID3 cover, `/cover` now serves a sidecar image from the track's folder (`cover.jpg`/`.jpeg`/`.png` or `folder.jpg`/`.png`) before falling back to the placeholder icon — so audiobooks/albums with a folder image show art in the Control tab | [`cover-fallback`](../../releases/tag/cover-fallback) |
150150
| **Most-played cards (listening stats)**: a per-card play counter (incremented when a music card starts a playlist) drives a **most-played** list — the top 3 cards (path + play count) appear in the info dialog next to the daily totals; full top-10 via a new `GET /topcards`. A card's counter is cleared when the card is deleted (no ghost stats). Stored in NVS (`rfidPlayCnt`) | [`stats-topcards`](../../releases/tag/stats-topcards) |
151+
| **MQTT now-playing metadata**: the ID3 **artist** and **album** are published to MQTT state topics (`track_artist`/`track_album`, alongside the existing `track` title and `cover_changed`) and registered as Home-Assistant discovery sensors, so a broker/Home Assistant sees the current artist & album. Reset per track. | — |
151152
| **OpenAPI/Swagger spec updated**: the bundled `REST_API.yaml` (served at `/swagger.html`) now documents all fork-added endpoints (`/sync`, `/syncstop`, `/playlist`, `/githubupdate`, `/version`, `/login`, `/logout`, `/security`, `/eqrule(s)`, `/activeequalizer`, `/bluetooth*`, `/sdclean`) and declares the security schemes (`X-API-Key` header / `apikey` query param, or the `ESPUINO_SESSION` login cookie) so the Swagger "Authorize" button works. The web-interface footer links to the Swagger UI (`/swagger.html`) | [`f8298d9`](../../commit/f8298d9) |
152153

153154
#### Feature highlights

‎src/AudioPlayer.cpp‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,14 @@ void Audio_InfoCallback(Audio::msg_t m) {
194194
// get artist / album (ID3 "Artist:"/"Album:" + VORBISCOMMENT "ARTIST="/"ALBUM=")
195195
else if (startsWith((char *) m.msg, "Artist") || startsWith((char *) m.msg, "ARTIST=") || startsWith((char *) m.msg, "artist=")) {
196196
Audio_SetMeta(gPlayProperties.artist, sizeof(gPlayProperties.artist), (const char *) m.msg);
197+
#ifdef MQTT_ENABLE
198+
publishMqtt(topicTrackArtist, gPlayProperties.artist, false);
199+
#endif
197200
} else if (startsWith((char *) m.msg, "Album") || startsWith((char *) m.msg, "ALBUM=") || startsWith((char *) m.msg, "album=")) {
198201
Audio_SetMeta(gPlayProperties.album, sizeof(gPlayProperties.album), (const char *) m.msg);
202+
#ifdef MQTT_ENABLE
203+
publishMqtt(topicTrackAlbum, gPlayProperties.album, false);
204+
#endif
199205
}
200206
break;
201207
}
@@ -1773,6 +1779,8 @@ void AudioPlayer_ClearCover(void) {
17731779
Web_SendWebsocketData(0, WebsocketCodeType::CoverImg);
17741780
#ifdef MQTT_ENABLE
17751781
publishMqtt(topicCoverChanged, "", false);
1782+
publishMqtt(topicTrackArtist, "", false); // reset now-playing metadata for the next track
1783+
publishMqtt(topicTrackAlbum, "", false);
17761784
#endif
17771785
}
17781786

‎src/Mqtt.cpp‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ static void Mqtt_PublishHassDiscovery(void) {
341341

342342
// sensors
343343
mqttHassPublish("sensor", "track", "\"name\":\"Track\",\"icon\":\"mdi:music-note\",\"state_topic\":\"" + String(Mqtt_GetStateTopic(topicTrack)) + "\"");
344+
mqttHassPublish("sensor", "track_artist", "\"name\":\"Artist\",\"icon\":\"mdi:account-music\",\"state_topic\":\"" + String(Mqtt_GetStateTopic(topicTrackArtist)) + "\"");
345+
mqttHassPublish("sensor", "track_album", "\"name\":\"Album\",\"icon\":\"mdi:album\",\"state_topic\":\"" + String(Mqtt_GetStateTopic(topicTrackAlbum)) + "\"");
344346
mqttHassPublish("sensor", "status", "\"name\":\"Status\",\"icon\":\"mdi:play-pause\",\"state_topic\":\"" + String(Mqtt_GetStateTopic(topicPausePlay)) + "\"");
345347
mqttHassPublish("sensor", "wifi", "\"name\":\"WiFi signal\",\"device_class\":\"signal_strength\",\"unit_of_measurement\":\"dBm\",\"entity_category\":\"diagnostic\",\"state_topic\":\"" + String(Mqtt_GetStateTopic(topicWiFiRssi)) + "\"");
346348
mqttHassPublish("sensor", "firmware", "\"name\":\"Firmware update\",\"icon\":\"mdi:package-up\",\"entity_category\":\"diagnostic\",\"state_topic\":\"" + String(Mqtt_GetStateTopic(topicFirmwareUpdate)) + "\"");
@@ -439,6 +441,8 @@ void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event
439441
// Publish current state
440442
publishMqtt(topicState, "Online", false);
441443
publishMqtt(topicTrack, gPlayProperties.title, false);
444+
publishMqtt(topicTrackArtist, gPlayProperties.artist, false);
445+
publishMqtt(topicTrackAlbum, gPlayProperties.album, false);
442446
publishMqtt(topicCoverChanged, "", false);
443447
publishMqtt(topicLoudness, static_cast<uint32_t>(AudioPlayer_GetCurrentVolume()), false);
444448
publishMqtt(topicSleepTimer, System_GetSleepTimerTimeStamp(), false);

‎src/settings.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@
301301

302302
// Topics (state only)
303303
constexpr const char topicTrack[] = "track"; // State: current track info (e.g. "(2/10) /mp3/.../file.mp3")
304+
constexpr const char topicTrackArtist[] = "track_artist"; // State: current ID3 artist (empty if none)
305+
constexpr const char topicTrackAlbum[] = "track_album"; // State: current ID3 album (empty if none)
304306
constexpr const char topicCoverChanged[] = "cover_changed"; // State: indicates cover image may have changed
305307
constexpr const char topicState[] = "state"; // State: 'Online' when powering on, 'Offline' when powering off
306308
constexpr const char topicCurrentIPv4IP[] = "ipv4"; // State: sends current IPv4 address

0 commit comments

Comments
 (0)