mirror of
https://github.com/esphome/esphome.git
synced 2026-05-23 03:06:05 +08:00
[sendspin] Add a metadata text sensor component (#15969)
This commit is contained in:
@@ -443,6 +443,7 @@ esphome/components/sen6x/* @martgras @mebner86 @mikelawrence @tuct
|
||||
esphome/components/sendspin/* @kahrendt
|
||||
esphome/components/sendspin/media_player/* @kahrendt
|
||||
esphome/components/sendspin/media_source/* @kahrendt
|
||||
esphome/components/sendspin/text_sensor/* @kahrendt
|
||||
esphome/components/sensirion_common/* @martgras
|
||||
esphome/components/sensor/* @esphome/core
|
||||
esphome/components/serial_proxy/* @kbx81
|
||||
|
||||
@@ -39,6 +39,10 @@ void SendspinHub::setup() {
|
||||
this->controller_role_->set_listener(this);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_METADATA
|
||||
this->client_->add_metadata().set_listener(this);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_PLAYER
|
||||
this->client_->add_player(this->player_config_).set_listener(this->player_listener_);
|
||||
#endif
|
||||
@@ -167,6 +171,13 @@ void SendspinHub::on_controller_state(const sendspin::ServerStateControllerObjec
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_METADATA
|
||||
// THREAD CONTEXT: Main loop (MetadataRoleListener override, fired from client_->loop())
|
||||
void SendspinHub::on_metadata(const sendspin::ServerMetadataStateObject &metadata) {
|
||||
this->metadata_update_callbacks_.call(metadata);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_PLAYER
|
||||
// THREAD CONTEXT: Main loop, called from child component setup() after player role is created and configured
|
||||
sendspin::PlayerRole *SendspinHub::get_player_role() {
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#ifdef USE_SENDSPIN_CONTROLLER
|
||||
#include <sendspin/controller_role.h>
|
||||
#endif
|
||||
#ifdef USE_SENDSPIN_METADATA
|
||||
#include <sendspin/metadata_role.h>
|
||||
#endif
|
||||
#ifdef USE_SENDSPIN_PLAYER
|
||||
#include <sendspin/player_role.h>
|
||||
#endif
|
||||
@@ -66,6 +69,9 @@ struct StaticDelayPref {
|
||||
class SendspinHub final : public Component,
|
||||
#ifdef USE_SENDSPIN_CONTROLLER
|
||||
public sendspin::ControllerRoleListener,
|
||||
#endif
|
||||
#ifdef USE_SENDSPIN_METADATA
|
||||
public sendspin::MetadataRoleListener,
|
||||
#endif
|
||||
public sendspin::SendspinClientListener,
|
||||
public sendspin::SendspinNetworkProvider,
|
||||
@@ -122,6 +128,12 @@ class SendspinHub final : public Component,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_METADATA
|
||||
template<typename F> void add_metadata_update_callback(F &&callback) {
|
||||
this->metadata_update_callbacks_.add(std::forward<F>(callback));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_PLAYER
|
||||
void set_listener(sendspin::PlayerRoleListener *listener) { this->player_listener_ = listener; }
|
||||
void set_player_config(const sendspin::PlayerRoleConfig &config) { this->player_config_ = config; }
|
||||
@@ -159,6 +171,13 @@ class SendspinHub final : public Component,
|
||||
CallbackManager<void(const sendspin::ServerStateControllerObject &)> controller_state_callbacks_{};
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_METADATA
|
||||
void on_metadata(const sendspin::ServerMetadataStateObject &metadata) override;
|
||||
|
||||
// Callback fan-out to child components; they filter as needed
|
||||
CallbackManager<void(const sendspin::ServerMetadataStateObject &)> metadata_update_callbacks_{};
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN_PLAYER
|
||||
sendspin::PlayerRoleListener *player_listener_{nullptr};
|
||||
sendspin::PlayerRoleConfig player_config_{};
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import text_sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_TYPE
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .. import CONF_SENDSPIN_ID, SendspinHub, request_metadata_support, sendspin_ns
|
||||
|
||||
CODEOWNERS = ["@kahrendt"]
|
||||
DEPENDENCIES = ["sendspin"]
|
||||
|
||||
SendspinTextSensor = sendspin_ns.class_(
|
||||
"SendspinTextSensor",
|
||||
text_sensor.TextSensor,
|
||||
cg.Component,
|
||||
)
|
||||
|
||||
SendspinTextMetadataTypes = sendspin_ns.enum("SendspinTextMetadataTypes", is_class=True)
|
||||
SENDSPIN_TEXT_METADATA_TYPES = {
|
||||
"title": SendspinTextMetadataTypes.TITLE,
|
||||
"artist": SendspinTextMetadataTypes.ARTIST,
|
||||
"album": SendspinTextMetadataTypes.ALBUM,
|
||||
"album_artist": SendspinTextMetadataTypes.ALBUM_ARTIST,
|
||||
"year": SendspinTextMetadataTypes.YEAR,
|
||||
"track": SendspinTextMetadataTypes.TRACK,
|
||||
}
|
||||
|
||||
|
||||
def _request_roles(config: ConfigType) -> ConfigType:
|
||||
"""Request the necessary Sendspin roles for the text sensor."""
|
||||
request_metadata_support()
|
||||
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
text_sensor.text_sensor_schema().extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(SendspinTextSensor),
|
||||
cv.GenerateID(CONF_SENDSPIN_ID): cv.use_id(SendspinHub),
|
||||
cv.Required(CONF_TYPE): cv.enum(SENDSPIN_TEXT_METADATA_TYPES),
|
||||
}
|
||||
),
|
||||
cv.only_on_esp32,
|
||||
_request_roles,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await cg.register_parented(var, config[CONF_SENDSPIN_ID])
|
||||
await text_sensor.register_text_sensor(var, config)
|
||||
|
||||
cg.add(var.set_metadata_type(config[CONF_TYPE]))
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "sendspin_text_sensor.h"
|
||||
|
||||
#if defined(USE_ESP32) && defined(USE_SENDSPIN_METADATA) && defined(USE_TEXT_SENSOR)
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
#include <sendspin/metadata_role.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace esphome::sendspin_ {
|
||||
|
||||
static const char *const TAG = "sendspin.text_sensor";
|
||||
|
||||
void SendspinTextSensor::dump_config() { LOG_TEXT_SENSOR("", "Sendspin", this); }
|
||||
|
||||
// THREAD CONTEXT: Main loop. The registered metadata callback also fires on the main loop
|
||||
// (SendspinHub dispatches metadata from client_->loop()).
|
||||
void SendspinTextSensor::setup() {
|
||||
switch (this->metadata_type_) {
|
||||
case SendspinTextMetadataTypes::TITLE: {
|
||||
this->parent_->add_metadata_update_callback([this](const sendspin::ServerMetadataStateObject &metadata) {
|
||||
if (metadata.title.has_value()) {
|
||||
this->publish_if_changed_(metadata.title.value().c_str());
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case SendspinTextMetadataTypes::ARTIST: {
|
||||
this->parent_->add_metadata_update_callback([this](const sendspin::ServerMetadataStateObject &metadata) {
|
||||
if (metadata.artist.has_value()) {
|
||||
this->publish_if_changed_(metadata.artist.value().c_str());
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case SendspinTextMetadataTypes::ALBUM: {
|
||||
this->parent_->add_metadata_update_callback([this](const sendspin::ServerMetadataStateObject &metadata) {
|
||||
if (metadata.album.has_value()) {
|
||||
this->publish_if_changed_(metadata.album.value().c_str());
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case SendspinTextMetadataTypes::ALBUM_ARTIST: {
|
||||
this->parent_->add_metadata_update_callback([this](const sendspin::ServerMetadataStateObject &metadata) {
|
||||
if (metadata.album_artist.has_value()) {
|
||||
this->publish_if_changed_(metadata.album_artist.value().c_str());
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case SendspinTextMetadataTypes::YEAR: {
|
||||
this->parent_->add_metadata_update_callback([this](const sendspin::ServerMetadataStateObject &metadata) {
|
||||
if (metadata.year.has_value() && metadata.year.value() <= 9999) {
|
||||
char buf[UINT32_MAX_STR_SIZE];
|
||||
uint32_to_str(buf, metadata.year.value());
|
||||
this->publish_if_changed_(buf);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case SendspinTextMetadataTypes::TRACK: {
|
||||
this->parent_->add_metadata_update_callback([this](const sendspin::ServerMetadataStateObject &metadata) {
|
||||
if (metadata.track.has_value() && metadata.track.value() <= 9999) {
|
||||
char buf[UINT32_MAX_STR_SIZE];
|
||||
uint32_to_str(buf, metadata.track.value());
|
||||
this->publish_if_changed_(buf);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dedup to avoid frontend churn; TextSensor::publish_state already dedups the string assign but still notifies.
|
||||
void SendspinTextSensor::publish_if_changed_(const char *value) {
|
||||
if (this->get_raw_state() != value) {
|
||||
this->publish_state(value);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::sendspin_
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#if defined(USE_ESP32) && defined(USE_SENDSPIN_METADATA) && defined(USE_TEXT_SENSOR)
|
||||
|
||||
#include "esphome/components/sendspin/sendspin_hub.h"
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
|
||||
namespace esphome::sendspin_ {
|
||||
|
||||
enum class SendspinTextMetadataTypes {
|
||||
TITLE,
|
||||
ARTIST,
|
||||
ALBUM,
|
||||
ALBUM_ARTIST,
|
||||
YEAR,
|
||||
TRACK,
|
||||
};
|
||||
|
||||
class SendspinTextSensor : public SendspinChild, public text_sensor::TextSensor {
|
||||
public:
|
||||
void dump_config() override;
|
||||
void setup() override;
|
||||
|
||||
void set_metadata_type(SendspinTextMetadataTypes metadata_type) { this->metadata_type_ = metadata_type; }
|
||||
|
||||
protected:
|
||||
void publish_if_changed_(const char *value);
|
||||
|
||||
SendspinTextMetadataTypes metadata_type_;
|
||||
};
|
||||
|
||||
} // namespace esphome::sendspin_
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
<<: !include common.yaml
|
||||
|
||||
text_sensor:
|
||||
- platform: sendspin
|
||||
name: "Title"
|
||||
type: title
|
||||
- platform: sendspin
|
||||
name: "Artist"
|
||||
type: artist
|
||||
- platform: sendspin
|
||||
name: "Album"
|
||||
type: album
|
||||
- platform: sendspin
|
||||
name: "Album Artist"
|
||||
type: album_artist
|
||||
- platform: sendspin
|
||||
name: "Year"
|
||||
type: year
|
||||
- platform: sendspin
|
||||
name: "Track Number"
|
||||
type: track
|
||||
@@ -0,0 +1 @@
|
||||
<<: !include common-text_sensor.yaml
|
||||
Reference in New Issue
Block a user