ESPHome 2026.6.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 std::string &state) { this->publish_state(state.data(), state.size()); }
22
23void TextSensor::publish_state(const char *state) { this->publish_state(state, strlen(state)); }
24
25void TextSensor::publish_state(const char *state, size_t len) {
26#ifdef USE_TEXT_SENSOR_FILTER
27 if (this->filter_list_ == nullptr) {
28#endif
29 // No filters: raw_state == state, store once and use for both callbacks
30 // Only assign if changed to avoid heap allocation
31 if (len != this->state.size() || memcmp(state, this->state.data(), len) != 0) {
32 this->state.assign(state, len);
33 }
34#ifdef USE_TEXT_SENSOR_FILTER
35 this->raw_callback_.call(this->state);
36#endif
37 ESP_LOGV(TAG, "'%s': Received new state %s", this->name_.c_str(), this->state.c_str());
38 this->notify_frontend_();
39#ifdef USE_TEXT_SENSOR_FILTER
40 } else {
41 // Has filters: need separate raw storage
42 // Only assign if changed to avoid heap allocation
43 if (len != this->raw_state_.size() || memcmp(state, this->raw_state_.data(), len) != 0) {
44 this->raw_state_.assign(state, len);
45 }
46 this->raw_callback_.call(this->raw_state_);
47 ESP_LOGV(TAG, "'%s': Received new state %s", this->name_.c_str(), this->raw_state_.c_str());
48 this->filter_list_->input(this->raw_state_);
49 }
50#endif
51}
52
53#ifdef USE_TEXT_SENSOR_FILTER
55 // inefficient, but only happens once on every sensor setup and nobody's going to have massive amounts of
56 // filters
57 ESP_LOGVV(TAG, "TextSensor(%p)::add_filter(%p)", this, filter);
58 if (this->filter_list_ == nullptr) {
59 this->filter_list_ = filter;
60 } else {
61 Filter *last_filter = this->filter_list_;
62 while (last_filter->next_ != nullptr)
63 last_filter = last_filter->next_;
64 last_filter->initialize(this, filter);
65 }
66 filter->initialize(this, nullptr);
67}
68void TextSensor::add_filters(std::initializer_list<Filter *> filters) {
69 for (Filter *filter : filters) {
70 this->add_filter(filter);
71 }
72}
73void TextSensor::set_filters(std::initializer_list<Filter *> filters) {
74 this->clear_filters();
75 this->add_filters(filters);
76}
78 if (this->filter_list_ != nullptr) {
79 ESP_LOGVV(TAG, "TextSensor(%p)::clear_filters()", this);
80 }
81 this->filter_list_ = nullptr;
82}
83#endif // USE_TEXT_SENSOR_FILTER
84
85const std::string &TextSensor::get_state() const { return this->state; }
86const std::string &TextSensor::get_raw_state() const {
87#ifdef USE_TEXT_SENSOR_FILTER
88 if (this->filter_list_ != nullptr) {
89 return this->raw_state_;
90 }
91#endif
92 return this->state; // No filters, raw == filtered
93}
95 this->internal_send_state_to_frontend(state.data(), state.size());
96}
97
99 // Only assign if changed to avoid heap allocation
100 if (len != this->state.size() || memcmp(state, this->state.data(), len) != 0) {
101 this->state.assign(state, len);
102 }
103 this->notify_frontend_();
104}
105
107 this->set_has_state(true);
108 ESP_LOGV(TAG, "'%s' >> '%s'", this->name_.c_str(), this->state.c_str());
109 this->callback_.call(this->state);
110#if defined(USE_TEXT_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
111 ControllerRegistry::notify_text_sensor_update(this);
112#endif
113}
114
115} // 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)
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:86
LazyCallbackManager< void(const std::string &)> raw_callback_
Storage for raw state callbacks.
Definition text_sensor.h:81
LazyCallbackManager< void(const std::string &)> callback_
Storage for filtered state callbacks.
Definition text_sensor.h:83
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:80
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)
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 char * tag
Definition log.h:74
const void size_t len
Definition hal.h:64