ESPHome
2026.8.0b4
Loading...
Searching...
No Matches
esphome
components
sendspin
sensor
sendspin_sensor.cpp
Go to the documentation of this file.
1
#include "
sendspin_sensor.h
"
2
3
#if defined(USE_ESP32) && defined(USE_SENDSPIN_METADATA) && defined(USE_SENSOR)
4
5
#include <sendspin/metadata_role.h>
6
7
#include <cmath>
8
9
namespace
esphome::sendspin_
{
10
11
static
const
char
*
const
TAG =
"sendspin.sensor"
;
12
13
// --- SendspinTrackProgressSensor ---
14
15
void
SendspinTrackProgressSensor::dump_config
() {
16
LOG_SENSOR(
""
,
"Track Progress"
,
this
);
17
LOG_UPDATE_INTERVAL(
this
);
18
}
19
20
// THREAD CONTEXT: Main loop. The registered metadata callback also fires on the main loop
21
// (SendspinHub dispatches metadata from client_->loop()).
22
void
SendspinTrackProgressSensor::setup
() {
23
this->
parent_
->add_metadata_update_callback([
this
](
const
sendspin::ServerMetadataStateObject &metadata) {
24
if
(!metadata.progress.has_value()) {
25
// Progress is unknown: the server has not reported it, or it was cleared (e.g. on disconnect). Stop polling and
26
// report unknown rather than leaving the last position frozen on the frontend. Only the transition is published;
27
// NAN never compares equal to itself, so an unguarded publish would repeat on every metadata update.
28
this->
stop_poller
();
29
if
(!std::isnan(this->
get_raw_state
())) {
30
this->
publish_state
(NAN);
31
}
32
return
;
33
}
34
const
auto
&progress = metadata.progress.value();
35
if
(progress.playback_speed == 0) {
36
// Paused: freeze progress at the reported position and stop polling to save cycles.
37
this->
stop_poller
();
38
this->
publish_state
(progress.track_progress);
39
}
else
{
40
// Resumed: publish the fresh interpolated position immediately so the frontend doesn't show a stale
41
// paused value until the next poll tick.
42
this->
publish_state
(this->
parent_
->get_track_progress_ms());
43
this->
start_poller
();
44
}
45
});
46
47
// PollingComponent starts the poller before setup(), but there is nothing to interpolate yet:
48
// get_track_progress_ms() returns 0 until the server reports a position, so polling now would publish 0 every tick
49
// from boot until the first metadata arrives. The callback above starts it once playback is running.
50
this->
stop_poller
();
51
}
52
53
// THREAD CONTEXT: Main loop.
54
// Sendspin only pushes progress on state changes (play/pause/seek/speed change), not continuously during
55
// playback. The hub helper interpolates the current position from the last server update and the playback
56
// speed, giving us a fresh value on every poll.
57
void
SendspinTrackProgressSensor::update
() { this->
publish_state
(this->
parent_
->get_track_progress_ms()); }
58
59
// --- SendspinMetadataSensor ---
60
61
void
SendspinMetadataSensor::dump_config
() {
62
switch
(this->
metadata_type_
) {
63
case
SendspinNumericMetadataTypes::TRACK_DURATION
:
64
LOG_SENSOR(
""
,
"Track Duration"
,
this
);
65
break
;
66
case
SendspinNumericMetadataTypes::YEAR
:
67
LOG_SENSOR(
""
,
"Year"
,
this
);
68
break
;
69
case
SendspinNumericMetadataTypes::TRACK
:
70
LOG_SENSOR(
""
,
"Track"
,
this
);
71
break
;
72
}
73
}
74
75
std::optional<float>
SendspinMetadataSensor::extract_value_
(
const
sendspin::ServerMetadataStateObject &metadata)
const
{
76
switch
(this->
metadata_type_
) {
77
case
SendspinNumericMetadataTypes::TRACK_DURATION
:
78
if
(metadata.progress.has_value())
79
return
metadata.progress.value().track_duration;
80
return
std::nullopt;
81
case
SendspinNumericMetadataTypes::YEAR
:
82
if
(metadata.year.has_value())
83
return
metadata.year.value();
84
return
std::nullopt;
85
case
SendspinNumericMetadataTypes::TRACK
:
86
if
(metadata.track.has_value())
87
return
metadata.track.value();
88
return
std::nullopt;
89
}
90
return
std::nullopt;
91
}
92
93
// THREAD CONTEXT: Main loop. The registered metadata callback also fires on the main loop
94
// (SendspinHub dispatches metadata from client_->loop()).
95
void
SendspinMetadataSensor::setup
() {
96
this->
parent_
->add_metadata_update_callback([
this
](
const
sendspin::ServerMetadataStateObject &metadata) {
97
// A field the server has not provided, or has explicitly cleared, is published as NAN (the sensor convention for
98
// unknown) rather than skipped, so a value that goes away does not linger from the previous track.
99
this->
publish_if_changed_
(this->
extract_value_
(metadata).value_or(NAN));
100
});
101
}
102
103
// Dedup to avoid frontend churn; Sensor::publish_state always notifies without checking for changes.
104
void
SendspinMetadataSensor::publish_if_changed_
(
float
value) {
105
const
float
current = this->
get_raw_state
();
106
// The raw state starts as NAN, so a field that is already cleared when the first update arrives is suppressed here
107
// as well: the frontend still shows the sensor as unknown, which is what a clear means. NAN never compares equal to
108
// itself, so a field that stays cleared would republish on every metadata update without the second check.
109
if
(current != value && !(std::isnan(current) && std::isnan(value))) {
110
this->
publish_state
(value);
111
}
112
}
113
114
}
// namespace esphome::sendspin_
115
116
#endif
esphome::Parented< SendspinHub >::parent_
SendspinHub * parent_
Definition
helpers.h:1918
esphome::PollingComponent::start_poller
void start_poller()
Definition
component.cpp:388
esphome::PollingComponent::stop_poller
void stop_poller()
Definition
component.cpp:393
esphome::sendspin_::SendspinMetadataSensor::metadata_type_
SendspinNumericMetadataTypes metadata_type_
Definition
sendspin_sensor.h:38
esphome::sendspin_::SendspinMetadataSensor::setup
void setup() override
Definition
sendspin_sensor.cpp:95
esphome::sendspin_::SendspinMetadataSensor::publish_if_changed_
void publish_if_changed_(float value)
Definition
sendspin_sensor.cpp:104
esphome::sendspin_::SendspinMetadataSensor::extract_value_
std::optional< float > extract_value_(const sendspin::ServerMetadataStateObject &metadata) const
Definition
sendspin_sensor.cpp:75
esphome::sendspin_::SendspinMetadataSensor::dump_config
void dump_config() override
Definition
sendspin_sensor.cpp:61
esphome::sendspin_::SendspinTrackProgressSensor::setup
void setup() override
Definition
sendspin_sensor.cpp:22
esphome::sendspin_::SendspinTrackProgressSensor::dump_config
void dump_config() override
Definition
sendspin_sensor.cpp:15
esphome::sendspin_::SendspinTrackProgressSensor::update
void update() override
Definition
sendspin_sensor.cpp:57
esphome::sensor::Sensor::publish_state
void publish_state(float state)
Publish a new state to the front-end.
Definition
sensor.cpp:68
esphome::sensor::Sensor::get_raw_state
float get_raw_state() const
Getter-syntax for .raw_state.
Definition
sensor.h:100
esphome::sendspin_
Definition
automation.h:10
esphome::sendspin_::SendspinNumericMetadataTypes::TRACK_DURATION
@ TRACK_DURATION
esphome::sendspin_::SendspinNumericMetadataTypes::TRACK
@ TRACK
esphome::sendspin_::SendspinNumericMetadataTypes::YEAR
@ YEAR
sendspin_sensor.h
Generated by
1.12.0