From 66e72cebccfaae6d990294a76cab61624771bec2 Mon Sep 17 00:00:00 2001 From: Ben Nicholson Date: Fri, 2 Oct 2026 19:59:40 +1000 Subject: [PATCH] status: spotify_error, the last Spotify session error and when it happened Co-Authored-By: Claude Opus 5.5 --- components/spotify/include/spotify.h | 2 ++ components/spotify/spotify.cpp | 12 ++++++++++++ docs/hardware-and-design-notes.md | 2 +- main/player.c | 4 ++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/components/spotify/include/spotify.h b/components/spotify/include/spotify.h index fa17dd0..70e6269 100644 --- a/components/spotify/include/spotify.h +++ b/components/spotify/include/spotify.h @@ -58,6 +58,8 @@ typedef struct { bool spotify_now_playing(spotify_track_t *t); // Current state for status.spotify_state. const char *spotify_state(void); +// Last session error (exception text and uptime) for status.spotify_error. False if none yet. +bool spotify_last_error(char *out, size_t len); #ifdef __cplusplus } diff --git a/components/spotify/spotify.cpp b/components/spotify/spotify.cpp index ea0e96b..a5c0956 100644 --- a/components/spotify/spotify.cpp +++ b/components/spotify/spotify.cpp @@ -16,6 +16,7 @@ #include "SpircHandler.h" #include "TrackPlayer.h" #include "esp_log.h" +#include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "mdns.h" @@ -39,6 +40,8 @@ static std::atomic s_got_blob{false}; static std::atomic s_in_session{false}; // session() running (its tasks may exist) static std::atomic s_volume{65535}; // player volume in Spotify units (0..65535) static std::atomic s_state{"disabled"}; +static std::mutex s_error_mutex; +static std::string s_error; // last session error, kept for the status static std::atomic s_pcm_bytes{0}; static std::shared_ptr s_handler; // running session, else null static spotify_pcm_cb_t s_pcm_cb; @@ -230,6 +233,13 @@ const char *spotify_state(void) return s_state.load(); } +bool spotify_last_error(char *out, size_t len) +{ + std::lock_guard lock(s_error_mutex); + snprintf(out, len, "%s", s_error.c_str()); + return !s_error.empty(); +} + /* ----- cspot/bell logging -> esp_log (UART + syslog) ----- */ // cspot logs through bell::bellGlobalLogger; without one, CSPOT_LOG dereferences NULL. @@ -494,6 +504,8 @@ static void spotify_task(void *arg) } catch (const std::exception &e) { s_state = "error"; ESP_LOGE(TAG, "session ended: %s", e.what()); + std::lock_guard lock(s_error_mutex); + s_error = std::string(e.what()) + " (at " + std::to_string(esp_timer_get_time() / 1000000) + " s)"; } s_handler.reset(); s_in_session = false; diff --git a/docs/hardware-and-design-notes.md b/docs/hardware-and-design-notes.md index e40231c..16e90f6 100644 --- a/docs/hardware-and-design-notes.md +++ b/docs/hardware-and-design-notes.md @@ -33,7 +33,7 @@ source (cspot Spotify Connect | HLS player) -> decode (Vorbis/AAC/MP3) -> SRC 44 ## Project config group - source: {mode: spotify|hls|auto|tone|pink|off, spotify_name, spotify_bitrate, hls_url, autoplay, gain_db, failover_delay_s, failover_on_pause, spotify_client_id, spotify_client_secret} - spotify_client_id / spotify_client_secret: each user's own Spotify developer app (developer.spotify.com, Premium account), needed by the maintained cspot fork (philippe44/cspot) since Spotify's 2025 API restrictions. The secret is write-only (never returned by GET /api/config). spotify_state reports "no client credentials" while either is missing. -- Project status fields: active_source, source_state, spotify_state, buffer_ms +- Project status fields: active_source, source_state, spotify_state, buffer_ms; spotify_error (last session error with the uptime it happened at, e.g. "Can't connect to spotify servers (at 412 s)"; only present after one) - mode "tone": the core's 1 kHz / -18 dBFS test tone, phase-locked to PTP (commissioning, e.g. Riedel import tests). "pink": the core's pink noise, -18 dBFS RMS (peaks about -6 dBFS), same on L and R (level/EQ checks). Neither is affected by volume or gain. "off": silence. ## Player control API (project routes) diff --git a/main/player.c b/main/player.c index 90358ae..904a143 100644 --- a/main/player.c +++ b/main/player.c @@ -390,6 +390,10 @@ static void player_status(cJSON *st) cJSON_AddStringToObject(st, "active_source", SRC_NAME[src]); cJSON_AddStringToObject(st, "source_state", state); cJSON_AddStringToObject(st, "spotify_state", spotify_state()); + char err[96]; + if (spotify_last_error(err, sizeof(err))) { + cJSON_AddStringToObject(st, "spotify_error", err); + } cJSON_AddNumberToObject(st, "buffer_ms", (double)(audio_ring_level() * 1000 / RATE)); }