ESPHome 2026.1.4
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
10#ifdef USE_DEVICES
11#include "device.h"
12#endif
13
14namespace esphome {
15
16// Maximum device name length - keep in sync with validate_hostname() in esphome/core/config.py
17static constexpr size_t ESPHOME_DEVICE_NAME_MAX_LEN = 31;
18
19// Maximum friendly name length for entities and sub-devices - keep in sync with FRIENDLY_NAME_MAX_LEN in
20// esphome/core/config.py
21static constexpr size_t ESPHOME_FRIENDLY_NAME_MAX_LEN = 120;
22
23// Maximum domain length (longest: "alarm_control_panel" = 19)
24static constexpr size_t ESPHOME_DOMAIN_MAX_LEN = 20;
25
26// Maximum size for object_id buffer (friendly_name + null + margin)
27static constexpr size_t OBJECT_ID_MAX_LEN = 128;
28
29// Maximum state length that Home Assistant will accept without raising ValueError
30static constexpr size_t MAX_STATE_LEN = 255;
31
37
38// The generic Entity base class that provides an interface common to all Entities.
40 public:
41 // Get/set the name of this Entity
42 const StringRef &get_name() const;
43 void set_name(const char *name);
46 void set_name(const char *name, uint32_t object_id_hash);
47
48 // Get whether this Entity has its own name or it should use the device friendly_name.
49 bool has_own_name() const { return this->flags_.has_own_name; }
50
51 // Get the sanitized name of this Entity as an ID.
52 // Deprecated: object_id mangles names and all object_id methods are planned for removal.
53 // See https://github.com/esphome/backlog/issues/76
54 // Now is the time to stop using object_id entirely. If you still need it temporarily,
55 // use get_object_id_to() which will remain available longer but will also eventually be removed.
56 ESPDEPRECATED("object_id mangles names and all object_id methods are planned for removal "
57 "(see https://github.com/esphome/backlog/issues/76). "
58 "Now is the time to stop using object_id. If still needed, use get_object_id_to() "
59 "which will remain available longer. get_object_id() will be removed in 2026.7.0",
60 "2025.12.0")
61 std::string get_object_id() const;
62
63 // Get the unique Object ID of this Entity
64 uint32_t get_object_id_hash();
65
69 StringRef get_object_id_to(std::span<char, OBJECT_ID_MAX_LEN> buf) const;
70
73 size_t write_object_id_to(char *buf, size_t buf_size) const;
74
75 // Get/set whether this Entity should be hidden outside ESPHome
76 bool is_internal() const { return this->flags_.internal; }
77 void set_internal(bool internal) { this->flags_.internal = internal; }
78
79 // Check if this object is declared to be disabled by default.
80 // That means that when the device gets added to Home Assistant (or other clients) it should
81 // not be added to the default view by default, and a user action is necessary to manually add it.
82 bool is_disabled_by_default() const { return this->flags_.disabled_by_default; }
83 void set_disabled_by_default(bool disabled_by_default) { this->flags_.disabled_by_default = disabled_by_default; }
84
85 // Get/set the entity category.
87 void set_entity_category(EntityCategory entity_category) {
88 this->flags_.entity_category = static_cast<uint8_t>(entity_category);
89 }
90
91 // Get/set this entity's icon
93 "Use get_icon_ref() instead for better performance (avoids string copy). Will be removed in ESPHome 2026.5.0",
94 "2025.11.0")
95 std::string get_icon() const;
96 void set_icon(const char *icon);
98 static constexpr auto EMPTY_STRING = StringRef::from_lit("");
99#ifdef USE_ENTITY_ICON
100 return this->icon_c_str_ == nullptr ? EMPTY_STRING : StringRef(this->icon_c_str_);
101#else
102 return EMPTY_STRING;
103#endif
104 }
105
106#ifdef USE_DEVICES
107 // Get/set this entity's device id
108 uint32_t get_device_id() const {
109 if (this->device_ == nullptr) {
110 return 0; // No device set, return 0
111 }
112 return this->device_->get_device_id();
113 }
114 void set_device(Device *device) { this->device_ = device; }
115 // Get the device this entity belongs to (nullptr if main device)
116 Device *get_device() const { return this->device_; }
117#endif
118
119 // Check if this entity has state
120 bool has_state() const { return this->flags_.has_state; }
121
122 // Set has_state - for components that need to manually set this
123 void set_has_state(bool state) { this->flags_.has_state = state; }
124
143#ifdef USE_DEVICES
144 // Combine object_id_hash with device_id to ensure uniqueness across devices
145 // Note: device_id is 0 for the main device, so XORing with 0 preserves the original hash
146 // This ensures backward compatibility for existing single-device configurations
147 return this->get_object_id_hash() ^ this->get_device_id();
148#else
149 // Without devices, just use object_id_hash as before
150 return this->get_object_id_hash();
151#endif
152 }
153
154 protected:
155 void calc_object_id_();
156
158#ifdef USE_ENTITY_ICON
159 const char *icon_c_str_{nullptr};
160#endif
161 uint32_t object_id_hash_{};
162#ifdef USE_DEVICES
164#endif
165
166 // Bit-packed flags to save memory (1 byte instead of 5)
167 struct EntityFlags {
168 uint8_t has_own_name : 1;
169 uint8_t internal : 1;
171 uint8_t has_state : 1;
172 uint8_t entity_category : 2; // Supports up to 4 categories
173 uint8_t reserved : 2; // Reserved for future use
175};
176
177class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming)
178 public:
180 ESPDEPRECATED("Use get_device_class_ref() instead for better performance (avoids string copy). Will be removed in "
181 "ESPHome 2026.5.0",
182 "2025.11.0")
183 std::string get_device_class();
185 void set_device_class(const char *device_class);
188 static constexpr auto EMPTY_STRING = StringRef::from_lit("");
189 return this->device_class_ == nullptr ? EMPTY_STRING : StringRef(this->device_class_);
190 }
191
192 protected:
193 const char *device_class_{nullptr};
194};
195
196class EntityBase_UnitOfMeasurement { // NOLINT(readability-identifier-naming)
197 public:
199 ESPDEPRECATED("Use get_unit_of_measurement_ref() instead for better performance (avoids string copy). Will be "
200 "removed in ESPHome 2026.5.0",
201 "2025.11.0")
202 std::string get_unit_of_measurement();
204 void set_unit_of_measurement(const char *unit_of_measurement);
207 static constexpr auto EMPTY_STRING = StringRef::from_lit("");
208 return this->unit_of_measurement_ == nullptr ? EMPTY_STRING : StringRef(this->unit_of_measurement_);
209 }
210
211 protected:
212 const char *unit_of_measurement_{nullptr};
213};
214
219template<typename T> class StatefulEntityBase : public EntityBase {
220 public:
221 virtual bool has_state() const { return this->state_.has_value(); }
222 virtual const T &get_state() const { return this->state_.value(); }
223 virtual T get_state_default(T default_value) const { return this->state_.value_or(default_value); }
224 void invalidate_state() { this->set_new_state({}); }
225
226 void add_full_state_callback(std::function<void(optional<T> previous, optional<T> current)> &&callback) {
227 if (this->full_state_callbacks_ == nullptr)
228 this->full_state_callbacks_ = new CallbackManager<void(optional<T> previous, optional<T> current)>(); // NOLINT
229 this->full_state_callbacks_->add(std::move(callback));
230 }
231 void add_on_state_callback(std::function<void(T)> &&callback) {
232 if (this->state_callbacks_ == nullptr)
233 this->state_callbacks_ = new CallbackManager<void(T)>(); // NOLINT
234 this->state_callbacks_->add(std::move(callback));
235 }
236
237 void set_trigger_on_initial_state(bool trigger_on_initial_state) {
238 this->trigger_on_initial_state_ = trigger_on_initial_state;
239 }
240
241 protected:
249 virtual bool set_new_state(const optional<T> &new_state) {
250 if (this->state_ != new_state) {
251 // call the full state callbacks with the previous and new state
252 if (this->full_state_callbacks_ != nullptr)
253 this->full_state_callbacks_->call(this->state_, new_state);
254 // trigger legacy callbacks only if the new state is valid and either the trigger on initial state is enabled or
255 // the previous state was valid
256 auto had_state = this->has_state();
257 this->state_ = new_state;
258 if (this->state_callbacks_ != nullptr && new_state.has_value() && (this->trigger_on_initial_state_ || had_state))
259 this->state_callbacks_->call(new_state.value());
260 return true;
261 }
262 return false;
263 }
265 // callbacks with full state and previous state
268};
269} // 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)
bool has_own_name() const
Definition entity_base.h:49
bool is_internal() const
Definition entity_base.h:76
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
uint32_t get_preference_hash()
Get a unique hash for storing preferences/settings for this entity.
void set_entity_category(EntityCategory entity_category)
Definition entity_base.h:87
StringRef get_icon_ref() const
Definition entity_base.h:97
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...
uint32_t get_device_id() const
bool is_disabled_by_default() const
Definition entity_base.h:82
void set_name(const char *name)
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:83
void set_has_state(bool state)
const char * icon_c_str_
bool has_state() const
EntityCategory get_entity_category() const
Definition entity_base.h:86
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:77
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:0
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
@ ENTITY_CATEGORY_NONE
Definition entity_base.h:33
@ ENTITY_CATEGORY_CONFIG
Definition entity_base.h:34
@ ENTITY_CATEGORY_DIAGNOSTIC
Definition entity_base.h:35
struct ESPDEPRECATED("Use std::index_sequence instead. Removed in 2026.6.0", "2025.12.0") seq
Definition automation.h:24