ESPHome 2026.10.0-dev
Loading...
Searching...
No Matches
text_sensor.cpp
Go to the documentation of this file.
1#include "text_sensor.h"
4#include "esphome/core/log.h"
5#include <cstring>
6
7namespace esphome::text_sensor {
8
9static const char *const TAG = "text_sensor";
10
11void log_text_sensor(const char *tag, const char *prefix, const char *type, TextSensor *obj) {
12 if (obj == nullptr) {
13 return;
14 }
15
16 ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
17 LOG_ENTITY_DEVICE_CLASS(tag, prefix, *obj);
18 LOG_ENTITY_ICON(tag, prefix, *obj);
19}
20
21void TextSensor::publish_state(const char *state, size_t len) {
22#ifdef USE_TEXT_SENSOR_FILTER
23 if (this->filter_list_ == nullptr) {
24#endif
25 // No filters: raw_state == state, store once and use for both callbacks
26 // Only assign if changed to avoid heap allocation
27 if (len != this->state.size() || memcmp(state, this->state.data(), len) != 0) {
28 this->state.assign(state, len);
29 }
30#ifdef USE_TEXT_SENSOR_FILTER
31 this->raw_callback_.call(this->state);
32#endif
33 ESP_LOGV(TAG, "'%s': Received new state %s", this->name_.c_str(), this->state.c_str());
34 this->notify_frontend_();
35#ifdef USE_TEXT_SENSOR_FILTER
36 } else {
37 // Has filters: need separate raw storage
38 // Only assign if changed to avoid heap allocation
39 if (len != this->raw_state_.size() || memcmp(state, this->raw_state_.data(), len) != 0) {
40 this->raw_state_.assign(state, len);
41 }
42 this->raw_callback_.call(this->raw_state_);
43 ESP_LOGV(TAG, "'%s': Received new state %s", this->name_.c_str(), this->raw_state_.c_str());
44 this->filter_list_->input(this->raw_state_);
45 }
46#endif
47}
48
49#ifdef USE_TEXT_SENSOR_FILTER
51 // inefficient, but only happens once on every sensor setup and nobody's going to have massive amounts of
52 // filters
53 ESP_LOGVV(TAG, "TextSensor(%p)::add_filter(%p)", this, filter);
54 if (this->filter_list_ == nullptr) {
55 this->filter_list_ = filter;
56 } else {
57 Filter *last_filter = this->filter_list_;
58 while (last_filter->next_ != nullptr)
59 last_filter = last_filter->next_;
60 last_filter->initialize(this, filter);
61 }
62 filter->initialize(this, nullptr);
63}
64void TextSensor::add_filters(std::initializer_list<Filter *> filters) {
65 for (Filter *filter : filters) {
66 this->add_filter(filter);
67 }
68}
69void TextSensor::set_filters(std::initializer_list<Filter *> filters) {
70 this->clear_filters();
71 this->add_filters(filters);
72}
74 if (this->filter_list_ != nullptr) {
75 ESP_LOGVV(TAG, "TextSensor(%p)::clear_filters()", this);
76 }
77 this->filter_list_ = nullptr;
78}
79#endif // USE_TEXT_SENSOR_FILTER
80
81const std::string &TextSensor::get_state() const { return this->state; }
82const std::string &TextSensor::get_raw_state() const {
83#ifdef USE_TEXT_SENSOR_FILTER
84 if (this->filter_list_ != nullptr) {
85 return this->raw_state_;
86 }
87#endif
88 return this->state; // No filters, raw == filtered
89}
91 // Only assign if changed to avoid heap allocation
92 if (len != this->state.size() || memcmp(state, this->state.data(), len) != 0) {
93 this->state.assign(state, len);
94 }
95 this->notify_frontend_();
96}
97
99 this->set_has_state(true);
100 ESP_LOGV(TAG, "'%s' >> '%s'", this->name_.c_str(), this->state.c_str());
101 this->callback_.call(this->state);
102#if defined(USE_TEXT_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
103 ControllerRegistry::notify_text_sensor_update(this);
104#endif
105}
106
107} // namespace esphome::text_sensor
const StringRef & get_name() const
Definition entity_base.h:71
void set_has_state(bool state)
constexpr const char * c_str() const
Definition string_ref.h:73
Apply a filter to text sensor values such as to_upper.
Definition filter.h:20
void input(std::string value)
Definition filter.cpp:14
virtual void initialize(TextSensor *parent, Filter *next)
Initialize this filter, please note this can be called more than once.
Definition filter.cpp:28
void internal_send_state_to_frontend(const std::string &state)
Definition text_sensor.h:73
void add_filter(Filter *filter)
Add a filter to the filter chain. Will be appended to the back.
const std::string & get_raw_state() const
Returns the raw (pre-filter) state.
void clear_filters()
Clear the entire filter chain.
void set_filters(std::initializer_list< Filter * > filters)
Clear the filters and replace them by filters.
Filter * filter_list_
Store all active filters.
Definition text_sensor.h:88
LazyCallbackManager< void(const std::string &)> raw_callback_
Storage for raw state callbacks.
Definition text_sensor.h:83
LazyCallbackManager< void(const std::string &)> callback_
Storage for filtered state callbacks.
Definition text_sensor.h:85
const std::string & get_state() const
Getter-syntax for .state.
std::string raw_state_
Backing storage for the raw (pre-filter) value. Only used when a filter is attached.
Definition text_sensor.h:82
void add_filters(std::initializer_list< Filter * > filters)
Add a list of vectors to the back of the filter chain.
void notify_frontend_()
Notify frontend that state has changed (assumes this->state is already set)
void publish_state(const std::string &state)
Definition text_sensor.h:40
uint16_t type
bool state
Definition fan.h:2
const char *const TAG
Definition spi.cpp:7
void log_text_sensor(const char *tag, const char *prefix, const char *type, TextSensor *obj)
const void size_t len
Definition hal.h:64