ESPHome 2026.8.0b4
Loading...
Searching...
No Matches
sendspin_hub.h
Go to the documentation of this file.
1#pragma once
2
4
5#ifdef USE_ESP32
6
11
12#include <sendspin/client.h>
13#include <sendspin/config.h>
14#include <sendspin/types.h>
15
16#ifdef USE_SENDSPIN_ARTWORK
17#include <sendspin/artwork_role.h>
18#endif
19#ifdef USE_SENDSPIN_CONTROLLER
20#include <sendspin/controller_role.h>
21#endif
22#ifdef USE_SENDSPIN_METADATA
23#include <sendspin/metadata_role.h>
24#endif
25#ifdef USE_SENDSPIN_PLAYER
26#include <sendspin/player_role.h>
27#endif
28
29#include <functional>
30#include <memory>
31#include <optional>
32
33namespace esphome::sendspin_ {
34
40namespace sendspin_priority {
41// AFTER_WIFI so the hub runs after the wifi/ethernet drivers are up and we can read the active
42// interface's MAC for client_id.
44inline constexpr float CHILD = HUB - 1.0f;
45} // namespace sendspin_priority
46
51
52#ifdef USE_SENDSPIN_PLAYER
55 uint16_t delay_ms;
56};
57#endif
58
74class SendspinHub final : public Component,
75#ifdef USE_SENDSPIN_ARTWORK
76 public sendspin::ArtworkRoleListener,
77#endif
78#ifdef USE_SENDSPIN_CONTROLLER
79 public sendspin::ControllerRoleListener,
80#endif
81#ifdef USE_SENDSPIN_METADATA
82 public sendspin::MetadataRoleListener,
83#endif
84 public sendspin::SendspinClientListener,
85 public sendspin::SendspinNetworkProvider,
86 public sendspin::SendspinPersistenceProvider {
87 public:
88 float get_setup_priority() const override { return sendspin_priority::HUB; }
89 void setup() override;
90 void loop() override;
91 void dump_config() override;
92
98 void connect_to_server(const std::string &url);
99
109 void disconnect_from_server(sendspin::SendspinGoodbyeReason reason);
110
118 void update_state(sendspin::SendspinClientState state);
119
120 // --- Configuration setters (called from codegen) ---
121
122 template<typename F> void add_group_update_callback(F &&callback) {
123 this->group_update_callbacks_.add(std::forward<F>(callback));
124 }
125
126 void set_task_stack_in_psram(bool task_stack_in_psram) { this->task_stack_in_psram_ = task_stack_in_psram; }
127
128 // --- Sendspin role specific methods ---
129
130#ifdef USE_SENDSPIN_ARTWORK
131 void set_artwork_config(const sendspin::ArtworkRoleConfig &config) { this->artwork_config_ = config; }
132
138 void artwork_frame_done(uint8_t slot);
139
140 template<typename F> void add_image_decode_callback(F &&callback) {
141 this->artwork_image_decode_callbacks_.add(std::forward<F>(callback));
142 }
143 template<typename F> void add_image_display_callback(F &&callback) {
144 this->artwork_image_display_callbacks_.add(std::forward<F>(callback));
145 }
146 template<typename F> void add_image_clear_callback(F &&callback) {
147 this->artwork_image_clear_callbacks_.add(std::forward<F>(callback));
148 }
149#endif
150
151#ifdef USE_SENDSPIN_CONTROLLER
152 void send_client_command(sendspin::SendspinControllerCommand command, std::optional<uint8_t> volume = std::nullopt,
153 std::optional<bool> mute = std::nullopt);
154
155 template<typename F> void add_controller_state_callback(F &&callback) {
156 this->controller_state_callbacks_.add(std::forward<F>(callback));
157 }
158
160 template<typename F> void add_controller_state_clear_callback(F &&callback) {
161 this->controller_state_clear_callbacks_.add(std::forward<F>(callback));
162 }
163#endif
164
165#ifdef USE_SENDSPIN_METADATA
170 template<typename F> void add_metadata_update_callback(F &&callback) {
171 this->metadata_update_callbacks_.add(std::forward<F>(callback));
172 }
173
176#endif
177
178#ifdef USE_SENDSPIN_PLAYER
179 void set_listener(sendspin::PlayerRoleListener *listener) { this->player_listener_ = listener; }
180 void set_player_config(const sendspin::PlayerRoleConfig &config) { this->player_config_ = config; }
181
183 sendspin::PlayerRole *get_player_role();
184#endif
185
186 protected:
188 sendspin::SendspinClientConfig build_client_config_();
189
192 static const char *get_client_id_into_buffer(std::span<char, MAC_ADDRESS_PRETTY_BUFFER_SIZE> buf);
193
194 // --- SendspinClientListener overrides ---
195 void on_group_update(const sendspin::GroupUpdateObject &group) override;
196
197 void on_request_high_performance() override;
198
199 void on_release_high_performance() override;
200
201 // --- SendspinNetworkProvider override ---
202 bool is_network_ready() override;
203
204 // --- SendspinPersistenceProvider overrides ---
205 bool save_last_server_hash(uint32_t hash) override;
206 std::optional<uint32_t> load_last_server_hash() override;
207
208 // --- Sendspin role specific methods/overrides/member variables ---
209
210#ifdef USE_SENDSPIN_ARTWORK
211 void on_image_decode(uint8_t slot, const uint8_t *data, size_t length, sendspin::SendspinImageFormat format) override;
212
213 void on_image_display(uint8_t slot, uint32_t lateness_ms) override;
214
215 void on_image_clear(uint8_t slot) override;
216
217 sendspin::ArtworkRoleConfig artwork_config_{};
218 sendspin::ArtworkRole *artwork_role_{nullptr};
219
220 // Callback fan-out to child components; they filter by slot as needed.
221 CallbackManager<void(uint8_t, const uint8_t *, size_t, sendspin::SendspinImageFormat)>
225#endif
226
227#ifdef USE_SENDSPIN_CONTROLLER
228 sendspin::ControllerRole *controller_role_{nullptr};
229
230 void on_controller_state(const sendspin::ServerStateControllerObject &state) override;
231
232 void on_controller_state_clear() override;
233
234 // Callback fan-out to child components; they filter as needed. Only a media_player subscribes, while the switch
235 // action and the media source enable the controller role without one, so keep the idle cost to a single pointer.
236 LazyCallbackManager<void(const sendspin::ServerStateControllerObject &)> controller_state_callbacks_{};
238#endif
239
240#ifdef USE_SENDSPIN_METADATA
241 sendspin::MetadataRole *metadata_role_{nullptr};
242
243 void on_metadata(const sendspin::ServerMetadataStateObject &metadata) override;
244
245 void on_metadata_clear() override;
246
247 // Callback fan-out to child components; they filter as needed
248 CallbackManager<void(const sendspin::ServerMetadataStateObject &)> metadata_update_callbacks_{};
249#endif
250
251#ifdef USE_SENDSPIN_PLAYER
252 sendspin::PlayerRoleListener *player_listener_{nullptr};
253 sendspin::PlayerRoleConfig player_config_{};
254
255 // Part of SendspinPersistenceProvider overrides
257 std::optional<uint16_t> load_static_delay() override;
258 bool save_static_delay(uint16_t delay_ms) override;
259#endif
260
261 // --- Core member variables ---
262
264
265 std::unique_ptr<sendspin::SendspinClient> client_;
266
267 // Callback fan-out to child components
268 CallbackManager<void(const sendspin::GroupUpdateObject &)> group_update_callbacks_{};
269
271};
272
279class SendspinChild : public Component, public Parented<SendspinHub> {
280 public:
281 float get_setup_priority() const override { return sendspin_priority::CHILD; }
282};
283
289class SendspinPollingChild : public PollingComponent, public Parented<SendspinHub> {
290 public:
291 float get_setup_priority() const override { return sendspin_priority::CHILD; }
292};
293
294} // namespace esphome::sendspin_
295
296#endif // USE_ESP32
Helper class to easily give an object a parent of type T.
Definition helpers.h:1907
This class simplifies creating components that periodically check a state.
Definition component.h:510
Base class for all sendspin subcomponents.
float get_setup_priority() const override
Thin adapter over sendspin::SendspinClient.
CallbackManager< void(uint8_t, const uint8_t *, size_t, sendspin::SendspinImageFormat)> artwork_image_decode_callbacks_
void add_image_clear_callback(F &&callback)
CallbackManager< void(uint8_t, uint32_t)> artwork_image_display_callbacks_
sendspin::PlayerRoleListener * player_listener_
void update_state(sendspin::SendspinClientState state)
Updates the client's reported playback state on the server.
bool save_last_server_hash(uint32_t hash) override
bool save_static_delay(uint16_t delay_ms) override
void on_controller_state_clear() override
void set_artwork_config(const sendspin::ArtworkRoleConfig &config)
CallbackManager< void(const sendspin::ServerMetadataStateObject &)> metadata_update_callbacks_
void add_image_decode_callback(F &&callback)
LazyCallbackManager< void(const sendspin::ServerStateControllerObject &)> controller_state_callbacks_
static const char * get_client_id_into_buffer(std::span< char, MAC_ADDRESS_PRETTY_BUFFER_SIZE > buf)
Writes the active network interface's MAC into buf and returns its data pointer.
void add_group_update_callback(F &&callback)
void on_release_high_performance() override
sendspin::MetadataRole * metadata_role_
CallbackManager< void(const sendspin::GroupUpdateObject &)> group_update_callbacks_
sendspin::PlayerRoleConfig player_config_
void on_metadata(const sendspin::ServerMetadataStateObject &metadata) override
void set_player_config(const sendspin::PlayerRoleConfig &config)
sendspin::PlayerRole * get_player_role()
Child components call this to get the PlayerRole instance after setup, so they can push updates to it...
void set_listener(sendspin::PlayerRoleListener *listener)
void on_image_clear(uint8_t slot) override
void add_controller_state_clear_callback(F &&callback)
Registers a callback that fires when the connection is lost and the cached controller state is droppe...
void disconnect_from_server(sendspin::SendspinGoodbyeReason reason)
Disconnects the underlying client from the current server.
std::optional< uint16_t > load_static_delay() override
std::unique_ptr< sendspin::SendspinClient > client_
sendspin::ArtworkRoleConfig artwork_config_
sendspin::SendspinClientConfig build_client_config_()
Builds the SendspinClientConfig from ESPHome configuration and platform info.
sendspin::ControllerRole * controller_role_
ESPPreferenceObject last_played_server_pref_
uint32_t get_track_progress_ms() const
Returns the interpolated track progress in milliseconds, or 0 if the hub is not yet ready.
void add_controller_state_callback(F &&callback)
void send_client_command(sendspin::SendspinControllerCommand command, std::optional< uint8_t > volume=std::nullopt, std::optional< bool > mute=std::nullopt)
LazyCallbackManager< void()> controller_state_clear_callbacks_
ESPPreferenceObject static_delay_pref_
CallbackManager< void(uint8_t)> artwork_image_clear_callbacks_
void set_task_stack_in_psram(bool task_stack_in_psram)
sendspin::ArtworkRole * artwork_role_
void on_request_high_performance() override
float get_setup_priority() const override
void on_image_display(uint8_t slot, uint32_t lateness_ms) override
void on_image_decode(uint8_t slot, const uint8_t *data, size_t length, sendspin::SendspinImageFormat format) override
std::optional< uint32_t > load_last_server_hash() override
void on_controller_state(const sendspin::ServerStateControllerObject &state) override
void connect_to_server(const std::string &url)
Connects the underlying client to the given Sendspin server.
void add_image_display_callback(F &&callback)
void on_group_update(const sendspin::GroupUpdateObject &group) override
void add_metadata_update_callback(F &&callback)
Registers a callback that fires when the server sends metadata.
void artwork_frame_done(uint8_t slot)
Acknowledges the most recent artwork delivery (display or clear) for a slot.
Base class for sendspin subcomponents that need polling behavior.
float get_setup_priority() const override
bool state
Definition fan.h:2
constexpr float AFTER_WIFI
For components that should be initialized after WiFi is connected.
Definition component.h:55
const char int const __FlashStringHelper * format
Definition log.h:74
static void uint32_t
Persistent storage structure for last played server hash.
Persistent storage structure for player static delay.
uint16_t length
Definition tt21100.cpp:0