ESPHome 2026.2.3
Loading...
Searching...
No Matches
entity_base.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <span>
5#include <string>
6#include "string_ref.h"
7#include "helpers.h"
8#include "log.h"
9#include "preferences.h"
10
11#ifdef USE_DEVICES
12#include "device.h"
13#endif
14
15namespace esphome {
16
17// Maximum device name length - keep in sync with validate_hostname() in esphome/core/config.py
18static constexpr size_t ESPHOME_DEVICE_NAME_MAX_LEN = 31;
19
20// Maximum friendly name length for entities and sub-devices - keep in sync with FRIENDLY_NAME_MAX_LEN in
21// esphome/core/config.py
22static constexpr size_t ESPHOME_FRIENDLY_NAME_MAX_LEN = 120;
23
24// Maximum domain length (longest: "alarm_control_panel" = 19)
25static constexpr size_t ESPHOME_DOMAIN_MAX_LEN = 20;
26
27// Maximum size for object_id buffer (friendly_name + null + margin)
28static constexpr size_t OBJECT_ID_MAX_LEN = 128;
29
30// Maximum state length that Home Assistant will accept without raising ValueError
31static constexpr size_t MAX_STATE_LEN = 255;
32
38
39// The generic Entity base class that provides an interface common to all Entities.
41 public:
42 // Get/set the name of this Entity
43 const StringRef &get_name() const;
44 void set_name(const char *name);
47 void set_name(const char *name, uint32_t object_id_hash);
48
49 // Get whether this Entity has its own name or it should use the device friendly_name.
50 bool has_own_name() const { return this->flags_.has_own_name; }
51
52 // Get the sanitized name of this Entity as an ID.
53 // Deprecated: object_id mangles names and all object_id methods are planned for removal.
54 // See https://github.com/esphome/backlog/issues/76
55 // Now is the time to stop using object_id entirely. If you still need it temporarily,
56 // use get_object_id_to() which will remain available longer but will also eventually be removed.
57 ESPDEPRECATED("object_id mangles names and all object_id methods are planned for removal "
58 "(see https://github.com/esphome/backlog/issues/76). "
59 "Now is the time to stop using object_id. If still needed, use get_object_id_to() "
60 "which will remain available longer. get_object_id() will be removed in 2026.7.0",
61 "2025.12.0")
62 std::string get_object_id() const;
63
64 // Get the unique Object ID of this Entity
65 uint32_t get_object_id_hash();
66
70 StringRef get_object_id_to(std::span<char, OBJECT_ID_MAX_LEN> buf) const;
71
74 size_t write_object_id_to(char *buf, size_t buf_size) const;
75
76 // Get/set whether this Entity should be hidden outside ESPHome
77 bool is_internal() const { return this->flags_.internal; }
78 void set_internal(bool internal) { this->flags_.internal = internal; }
79
80 // Check if this object is declared to be disabled by default.
81 // That means that when the device gets added to Home Assistant (or other clients) it should
82 // not be added to the default view by default, and a user action is necessary to manually add it.
83 bool is_disabled_by_default() const { return this->flags_.disabled_by_default; }
84 void set_disabled_by_default(bool disabled_by_default) { this->flags_.disabled_by_default = disabled_by_default; }
85
86 // Get/set the entity category.
88 void set_entity_category(EntityCategory entity_category) {
89 this->flags_.entity_category = static_cast<uint8_t>(entity_category);
90 }
91
92 // Get/set this entity's icon
94 "Use get_icon_ref() instead for better performance (avoids string copy). Will be removed in ESPHome 2026.5.0",
95 "2025.11.0")
96 std::string get_icon() const;
97 void set_icon(const char *icon);
99 static constexpr auto EMPTY_STRING = StringRef::from_lit("");
100#ifdef USE_ENTITY_ICON
101 return this->icon_c_str_ == nullptr ? EMPTY_STRING : StringRef(this->icon_c_str_);
102#else
103 return EMPTY_STRING;
104#endif
105 }
106
107#ifdef USE_DEVICES
108 // Get/set this entity's device id
109 uint32_t get_device_id() const {
110 if (this->device_ == nullptr) {
111 return 0; // No device set, return 0
112 }
113 return this->device_->get_device_id();
114 }
115 void set_device(Device *device) { this->device_ = device; }
116 // Get the device this entity belongs to (nullptr if main device)
117 Device *get_device() const { return this->device_; }
118#endif
119
120 // Check if this entity has state
121 bool has_state() const { return this->flags_.has_state; }
122
123 // Set has_state - for components that need to manually set this
124 void set_has_state(bool state) { this->flags_.has_state = state; }
125
145 ESPDEPRECATED("Use make_entity_preference<T>() instead, or preferences won't be migrated. "
146 "See https://github.com/esphome/backlog/issues/85. Will be removed in 2027.1.0.",
147 "2026.7.0")
148 uint32_t get_preference_hash() {
149#ifdef USE_DEVICES
150 // Combine object_id_hash with device_id to ensure uniqueness across devices
151 // Note: device_id is 0 for the main device, so XORing with 0 preserves the original hash
152 // This ensures backward compatibility for existing single-device configurations
153 return this->get_object_id_hash() ^ this->get_device_id();
154#else
155 // Without devices, just use object_id_hash as before
156 return this->get_object_id_hash();
157#endif
158 }
159
163 template<typename T> ESPPreferenceObject make_entity_preference(uint32_t version = 0) {
164 static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable");
165 return this->make_entity_preference_(sizeof(T), version);
166 }
167
168 protected:
171 ESPPreferenceObject make_entity_preference_(size_t size, uint32_t version);
172
173 void calc_object_id_();
174
176#ifdef USE_ENTITY_ICON
177 const char *icon_c_str_{nullptr};
178#endif
179 uint32_t object_id_hash_{};
180#ifdef USE_DEVICES
182#endif
183
184 // Bit-packed flags to save memory (1 byte instead of 5)
185 struct EntityFlags {
186 uint8_t has_own_name : 1;
187 uint8_t internal : 1;
189 uint8_t has_state : 1;
190 uint8_t entity_category : 2; // Supports up to 4 categories
191 uint8_t reserved : 2; // Reserved for future use
193};
194
195class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming)
196 public:
198 ESPDEPRECATED("Use get_device_class_ref() instead for better performance (avoids string copy). Will be removed in "
199 "ESPHome 2026.5.0",
200 "2025.11.0")
201 std::string get_device_class();
203 void set_device_class(const char *device_class);
206 static constexpr auto EMPTY_STRING = StringRef::from_lit("");
207 return this->device_class_ == nullptr ? EMPTY_STRING : StringRef(this->device_class_);
208 }
209
210 protected:
211 const char *device_class_{nullptr};
212};
213
214class EntityBase_UnitOfMeasurement { // NOLINT(readability-identifier-naming)
215 public:
217 ESPDEPRECATED("Use get_unit_of_measurement_ref() instead for better performance (avoids string copy). Will be "
218 "removed in ESPHome 2026.5.0",
219 "2025.11.0")
220 std::string get_unit_of_measurement();
222 void set_unit_of_measurement(const char *unit_of_measurement);
225 static constexpr auto EMPTY_STRING = StringRef::from_lit("");
226 return this->unit_of_measurement_ == nullptr ? EMPTY_STRING : StringRef(this->unit_of_measurement_);
227 }
228
229 protected:
230 const char *unit_of_measurement_{nullptr};
231};
232
234#define LOG_ENTITY_ICON(tag, prefix, obj) log_entity_icon(tag, prefix, obj)
235void log_entity_icon(const char *tag, const char *prefix, const EntityBase &obj);
237#define LOG_ENTITY_DEVICE_CLASS(tag, prefix, obj) log_entity_device_class(tag, prefix, obj)
238void log_entity_device_class(const char *tag, const char *prefix, const EntityBase_DeviceClass &obj);
240#define LOG_ENTITY_UNIT_OF_MEASUREMENT(tag, prefix, obj) log_entity_unit_of_measurement(tag, prefix, obj)
241void log_entity_unit_of_measurement(const char *tag, const char *prefix, const EntityBase_UnitOfMeasurement &obj);
242
247template<typename T> class StatefulEntityBase : public EntityBase {
248 public:
249 virtual bool has_state() const { return this->state_.has_value(); }
250 virtual const T &get_state() const { return this->state_.value(); }
251 virtual T get_state_default(T default_value) const { return this->state_.value_or(default_value); }
252 void invalidate_state() { this->set_new_state({}); }
253
254 void add_full_state_callback(std::function<void(optional<T> previous, optional<T> current)> &&callback) {
255 if (this->full_state_callbacks_ == nullptr)
256 this->full_state_callbacks_ = new CallbackManager<void(optional<T> previous, optional<T> current)>(); // NOLINT
257 this->full_state_callbacks_->add(std::move(callback));
258 }
259 void add_on_state_callback(std::function<void(T)> &&callback) {
260 if (this->state_callbacks_ == nullptr)
261 this->state_callbacks_ = new CallbackManager<void(T)>(); // NOLINT
262 this->state_callbacks_->add(std::move(callback));
263 }
264
265 void set_trigger_on_initial_state(bool trigger_on_initial_state) {
266 this->trigger_on_initial_state_ = trigger_on_initial_state;
267 }
268
269 protected:
277 virtual bool set_new_state(const optional<T> &new_state) {
278 if (this->state_ != new_state) {
279 // call the full state callbacks with the previous and new state
280 if (this->full_state_callbacks_ != nullptr)
281 this->full_state_callbacks_->call(this->state_, new_state);
282 // trigger legacy callbacks only if the new state is valid and either the trigger on initial state is enabled or
283 // the previous state was valid
284 auto had_state = this->has_state();
285 this->state_ = new_state;
286 if (this->state_callbacks_ != nullptr && new_state.has_value() && (this->trigger_on_initial_state_ || had_state))
287 this->state_callbacks_->call(new_state.value());
288 return true;
289 }
290 return false;
291 }
293 // callbacks with full state and previous state
296};
297} // namespace esphome
uint32_t get_device_id()
Definition device.h:8
StringRef get_device_class_ref() const
Get the device class as StringRef.
ESPDEPRECATED("Use get_device_class_ref() instead for better performance (avoids string copy). Will be removed in " "ESPHome 2026.5.0", "2025.11.0") std void set_device_class(const char *device_class)
Get the device class, using the manual override if set.
const char * device_class_
Device class override.
const char * unit_of_measurement_
Unit of measurement override.
ESPDEPRECATED("Use get_unit_of_measurement_ref() instead for better performance (avoids string copy). Will be " "removed in ESPHome 2026.5.0", "2025.11.0") std void set_unit_of_measurement(const char *unit_of_measurement)
Get the unit of measurement, using the manual override if set.
StringRef get_unit_of_measurement_ref() const
Get the unit of measurement as StringRef.
struct esphome::EntityBase::EntityFlags flags_
void set_device(Device *device)
ESPPreferenceObject make_entity_preference_(size_t size, uint32_t version)
Non-template helper for make_entity_preference() to avoid code bloat.
bool has_own_name() const
Definition entity_base.h:50
bool is_internal() const
Definition entity_base.h:77
ESPDEPRECATED("object_id mangles names and all object_id methods are planned for removal " "(see https://github.com/esphome/backlog/issues/76). " "Now is the time to stop using object_id. If still needed, use get_object_id_to() " "which will remain available longer. get_object_id() will be removed in 2026.7.0", "2025.12.0") std uint32_t get_object_id_hash()
const StringRef & get_name() const
void set_entity_category(EntityCategory entity_category)
Definition entity_base.h:88
StringRef get_icon_ref() const
Definition entity_base.h:98
size_t write_object_id_to(char *buf, size_t buf_size) const
Write object_id directly to buffer, returns length written (excluding null) Useful for building compo...
ESPDEPRECATED("Use make_entity_preference<T>() instead, or preferences won't be migrated. " "See https://github.com/esphome/backlog/issues/85. Will be removed in 2027.1.0.", "2026.7.0") uint32_t get_preference_hash()
Get a unique hash for storing preferences/settings for this entity.
uint32_t get_device_id() const
bool is_disabled_by_default() const
Definition entity_base.h:83
void set_name(const char *name)
ESPPreferenceObject make_entity_preference(uint32_t version=0)
Create a preference object for storing this entity's state/settings.
ESPDEPRECATED("Use get_icon_ref() instead for better performance (avoids string copy). Will be removed in ESPHome 2026.5.0", "2025.11.0") std void set_icon(const char *icon)
Device * get_device() const
void set_disabled_by_default(bool disabled_by_default)
Definition entity_base.h:84
void set_has_state(bool state)
const char * icon_c_str_
bool has_state() const
EntityCategory get_entity_category() const
Definition entity_base.h:87
StringRef get_object_id_to(std::span< char, OBJECT_ID_MAX_LEN > buf) const
Get object_id with zero heap allocation For static case: returns StringRef to internal storage (buffe...
void set_internal(bool internal)
Definition entity_base.h:78
An entity that has a state.
virtual const T & get_state() const
virtual bool set_new_state(const optional< T > &new_state)
Set a new state for this entity.
void add_full_state_callback(std::function< void(optional< T > previous, optional< T > current)> &&callback)
CallbackManager< void(T)> * state_callbacks_
void add_on_state_callback(std::function< void(T)> &&callback)
void set_trigger_on_initial_state(bool trigger_on_initial_state)
virtual bool has_state() const
virtual T get_state_default(T default_value) const
CallbackManager< void(optional< T > previous, optional< T > current)> * full_state_callbacks_
StringRef is a reference to a string owned by something else.
Definition string_ref.h:26
static constexpr StringRef from_lit(const CharT(&s)[N])
Definition string_ref.h:50
bool has_value() const
Definition optional.h:92
value_type const & value() const
Definition optional.h:94
bool state
Definition fan.h:2
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void log_entity_icon(const char *tag, const char *prefix, const EntityBase &obj)
void log_entity_device_class(const char *tag, const char *prefix, const EntityBase_DeviceClass &obj)
void log_entity_unit_of_measurement(const char *tag, const char *prefix, const EntityBase_UnitOfMeasurement &obj)
size_t size
Definition helpers.h:729
@ ENTITY_CATEGORY_NONE
Definition entity_base.h:34
@ ENTITY_CATEGORY_CONFIG
Definition entity_base.h:35
@ ENTITY_CATEGORY_DIAGNOSTIC
Definition entity_base.h:36
struct ESPDEPRECATED("Use std::index_sequence instead. Removed in 2026.6.0", "2025.12.0") seq
Definition automation.h:25