#pragma once #include #include #include "string_ref.h" #include "helpers.h" #include "log.h" namespace esphome { enum EntityCategory : uint8_t { ENTITY_CATEGORY_NONE = 0, ENTITY_CATEGORY_CONFIG = 1, ENTITY_CATEGORY_DIAGNOSTIC = 2, }; // The generic Entity base class that provides an interface common to all Entities. class EntityBase { public: // Get/set the name of this Entity const StringRef &get_name() const; void set_name(const char *name); // Get whether this Entity has its own name or it should use the device friendly_name. bool has_own_name() const { return this->has_own_name_; } // Get the sanitized name of this Entity as an ID. std::string get_object_id() const; void set_object_id(const char *object_id); // Get the unique Object ID of this Entity uint32_t get_object_id_hash(); // Get/set whether this Entity should be hidden outside ESPHome bool is_internal() const; void set_internal(bool internal); // Check if this object is declared to be disabled by default. // That means that when the device gets added to Home Assistant (or other clients) it should // not be added to the default view by default, and a user action is necessary to manually add it. bool is_disabled_by_default() const; void set_disabled_by_default(bool disabled_by_default); // Get/set the entity category. EntityCategory get_entity_category() const; void set_entity_category(EntityCategory entity_category); // Get/set this entity's icon std::string get_icon() const; void set_icon(const char *icon); protected: /// The hash_base() function has been deprecated. It is kept in this /// class for now, to prevent external components from not compiling. virtual uint32_t hash_base() { return 0L; } void calc_object_id_(); StringRef name_; const char *object_id_c_str_{nullptr}; const char *icon_c_str_{nullptr}; uint32_t object_id_hash_{}; bool has_own_name_{false}; bool internal_{false}; bool disabled_by_default_{false}; EntityCategory entity_category_{ENTITY_CATEGORY_NONE}; bool has_state_{}; }; class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming) public: /// Get the device class, using the manual override if set. std::string get_device_class(); /// Manually set the device class. void set_device_class(const char *device_class); protected: const char *device_class_{nullptr}; ///< Device class override }; class EntityBase_UnitOfMeasurement { // NOLINT(readability-identifier-naming) public: /// Get the unit of measurement, using the manual override if set. std::string get_unit_of_measurement(); /// Manually set the unit of measurement. void set_unit_of_measurement(const char *unit_of_measurement); protected: const char *unit_of_measurement_{nullptr}; ///< Unit of measurement override }; /** * An entity that has a state. * @tparam T The type of the state */ template class StatefulEntityBase : public EntityBase { public: virtual bool has_state() const { return this->state_.has_value(); } virtual const T &get_state() const { return this->state_.value(); } virtual T get_state_default(T default_value) const { return this->state_.value_or(default_value); } void invalidate_state() { this->set_state_({}); } void add_full_state_callback(std::function previous, optional current)> &&callback) { if (this->full_state_callbacks_ == nullptr) this->full_state_callbacks_ = new CallbackManager previous, optional current)>(); // NOLINT this->full_state_callbacks_->add(std::move(callback)); } void add_on_state_callback(std::function &&callback) { if (this->state_callbacks_ == nullptr) this->state_callbacks_ = new CallbackManager(); // NOLINT this->state_callbacks_->add(std::move(callback)); } void set_trigger_on_initial_state(bool trigger_on_initial_state) { this->trigger_on_initial_state_ = trigger_on_initial_state; } protected: optional state_{}; /** * Set a new state for this entity. This will trigger callbacks only if the new state is different from the previous. * * @param state The new state. * @return True if the state was changed, false if it was the same as before. */ bool set_state_(const optional &state) { if (this->state_ != state) { // call the full state callbacks with the previous and new state if (this->full_state_callbacks_ != nullptr) this->full_state_callbacks_->call(this->state_, state); // trigger legacy callbacks only if the new state is valid and either the trigger on initial state is enabled or // the previous state was valid auto had_state = this->has_state(); this->state_ = state; if (this->state_callbacks_ != nullptr && state.has_value() && (this->trigger_on_initial_state_ || had_state)) this->state_callbacks_->call(state.value()); return true; } return false; } bool trigger_on_initial_state_{true}; // callbacks with full state and previous state CallbackManager previous, optional current)> *full_state_callbacks_{}; CallbackManager *state_callbacks_{}; }; } // namespace esphome