ESPHome 2026.11.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
9ESPHOME_LOG_TAG(TAG, "text_sensor");
10
11void log_text_sensor(const char *tag, const char *prefix, const char *type, TextSensor *obj) {
12 if (!log_entity_header(tag, prefix, type, obj)) {
13 return;
14 }
15 LOG_ENTITY_DEVICE_CLASS(tag, prefix, *obj);
16 LOG_ENTITY_ICON(tag, prefix, *obj);
17}
18
19void TextSensor::publish_state(const char *state, size_t len) {
20#ifdef USE_TEXT_SENSOR_FILTER
21 if (this->filter_list_ == nullptr) {
22#endif
23 // No filters: raw_state == state, store once and use for both callbacks
24 // Only assign if changed to avoid heap allocation
25 if (len != this->state.size() || memcmp(state, this->state.data(), len) != 0) {
26 this->state.assign(state, len);
27 }
28#ifdef USE_TEXT_SENSOR_FILTER
29 this->raw_callback_.call(this->state);
30#endif
31 ESP_LOGV(TAG, "'%s': Received new state %s", LOG_STR_ARG(this->get_log_name()), this->state.c_str());
32 this->notify_frontend_();
33#ifdef USE_TEXT_SENSOR_FILTER
34 } else {
35 // Has filters: need separate raw storage
36 // Only assign if changed to avoid heap allocation
37 if (len != this->raw_state_.size() || memcmp(state, this->raw_state_.data(), len) != 0) {
38 this->raw_state_.assign(state, len);
39 }
40 this->raw_callback_.call(this->raw_state_);
41 ESP_LOGV(TAG, "'%s': Received new state %s", LOG_STR_ARG(this->get_log_name()), this->raw_state_.c_str());
42 this->filter_list_->input(this->raw_state_);
43 }
44#endif
45}
46
47#ifdef USE_ESP8266
49 char buf[256];
50 strncpy_P(buf, reinterpret_cast<PGM_P>(state), sizeof(buf));
51 buf[sizeof(buf) - 1] = '\0';
52 this->publish_state(buf);
53}
54#endif
55
56#ifdef USE_TEXT_SENSOR_FILTER
58 // inefficient, but only happens once on every sensor setup and nobody's going to have massive amounts of
59 // filters
60 ESP_LOGVV(TAG, "TextSensor(%p)::add_filter(%p)", this, filter);
61 if (this->filter_list_ == nullptr) {
62 this->filter_list_ = filter;
63 } else {
64 Filter *last_filter = this->filter_list_;
65 while (last_filter->next_ != nullptr)
66 last_filter = last_filter->next_;
67 last_filter->initialize(this, filter);
68 }
69 filter->initialize(this, nullptr);
70}
71void TextSensor::add_filters(std::initializer_list<Filter *> filters) {
72 for (Filter *filter : filters) {
73 this->add_filter(filter);
74 }
75}
76void TextSensor::set_filters(std::initializer_list<Filter *> filters) {
77 this->clear_filters();
78 this->add_filters(filters);
79}
81 if (this->filter_list_ != nullptr) {
82 ESP_LOGVV(TAG, "TextSensor(%p)::clear_filters()", this);
83 }
84 this->filter_list_ = nullptr;
85}
86#endif // USE_TEXT_SENSOR_FILTER
87
88const std::string &TextSensor::get_state() const { return this->state; }
89const std::string &TextSensor::get_raw_state() const {
90#ifdef USE_TEXT_SENSOR_FILTER
91 if (this->filter_list_ != nullptr) {
92 return this->raw_state_;
93 }
94#endif
95 return this->state; // No filters, raw == filtered
96}
98 // Only assign if changed to avoid heap allocation
99 if (len != this->state.size() || memcmp(state, this->state.data(), len) != 0) {
100 this->state.assign(state, len);
101 }
102 this->notify_frontend_();
103}
104
106 this->set_has_state(true);
107 ESP_LOGV(TAG, "'%s' >> '%s'", LOG_STR_ARG(this->get_log_name()), this->state.c_str());
108 this->callback_.call(this->state);
109#if defined(USE_TEXT_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
110 ControllerRegistry::notify_text_sensor_update(this);
111#endif
112}
113
114} // namespace esphome::text_sensor
const LogString * get_log_name() const
Get the name for a "%s" log argument (LOG_STR_ARG).
void set_has_state(bool state)
Apply a filter to text sensor values such as to_upper.
Definition filter.h:18
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:80
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:95
LazyCallbackManager< void(const std::string &)> raw_callback_
Storage for raw state callbacks.
Definition text_sensor.h:90
LazyCallbackManager< void(const std::string &)> callback_
Storage for filtered state callbacks.
Definition text_sensor.h:92
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:89
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:42
uint8_t type
bool state
Definition fan.h:2
ESPHOME_LOG_TAG(TAG, "text_sensor.filter")
void log_text_sensor(const char *tag, const char *prefix, const char *type, TextSensor *obj)
bool log_entity_header(const char *tag, const char *prefix, const char *type, const EntityBase *obj)
Log "<prefix><type> '<name>'" for a dump_config header; returns false when obj is null.
const void size_t len
Definition hal.h:68
const __FlashStringHelper * ProgmemStr
Definition progmem.h:31