mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 09:01:49 +00:00 
			
		
		
		
	EntityBase Refactor (#2418)
* Renamed Nameable to EntityBase (cpp) * Renamed NAMEABLE_SCHEMA to ENTITY_BASE_SCHEMA (Python) * Renamed cg.Nameable to cg.EntityBase (Python) * Remove redundant use of CONF_NAME from esp32_touch * Remove redundant use of CONF_NAME from mcp3008 * Updated test * Moved EntityBase from Component.h and Component.cpp * Added icon property to EntityBase * Added CONF_ICON to ENTITY_BASE_SCHEMA and added setup_entity function to cpp_helpers * Added MQTT component getters for icon and disabled_by_default * Lint * Removed icon field from MQTT components * Code generation now uses setup_entity to setENTITY_BASE_SCHEMA fields * Removed unused import * Added cstdint include * Optimisation: don't set icon if it is empty * Remove icon from NumberTraits and SelectTraits * Removed unused import * Integration and Total Daily Energy sensors now inherit icons from their parents during code generation * Minor comment correction * Removed redundant icon-handling code from sensor, switch, and text_sensor * Update esphome/components/tsl2591/tsl2591.h Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl> * Added icon property to binary sensor, climate, cover, and fan component tests * Added icons for Binary Sensor, Climate, Cover, Fan, and Light to API * Consolidated EntityBase fields in MQTT components Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
This commit is contained in:
		@@ -67,7 +67,7 @@ from esphome.cpp_types import (  # noqa
 | 
			
		||||
    NAN,
 | 
			
		||||
    esphome_ns,
 | 
			
		||||
    App,
 | 
			
		||||
    Nameable,
 | 
			
		||||
    EntityBase,
 | 
			
		||||
    Component,
 | 
			
		||||
    ComponentPtr,
 | 
			
		||||
    PollingComponent,
 | 
			
		||||
 
 | 
			
		||||
@@ -215,6 +215,7 @@ message ListEntitiesBinarySensorResponse {
 | 
			
		||||
  string device_class = 5;
 | 
			
		||||
  bool is_status_binary_sensor = 6;
 | 
			
		||||
  bool disabled_by_default = 7;
 | 
			
		||||
  string icon = 8;
 | 
			
		||||
}
 | 
			
		||||
message BinarySensorStateResponse {
 | 
			
		||||
  option (id) = 21;
 | 
			
		||||
@@ -245,6 +246,7 @@ message ListEntitiesCoverResponse {
 | 
			
		||||
  bool supports_tilt = 7;
 | 
			
		||||
  string device_class = 8;
 | 
			
		||||
  bool disabled_by_default = 9;
 | 
			
		||||
  string icon = 10;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum LegacyCoverState {
 | 
			
		||||
@@ -313,6 +315,7 @@ message ListEntitiesFanResponse {
 | 
			
		||||
  bool supports_direction = 7;
 | 
			
		||||
  int32 supported_speed_count = 8;
 | 
			
		||||
  bool disabled_by_default = 9;
 | 
			
		||||
  string icon = 10;
 | 
			
		||||
}
 | 
			
		||||
enum FanSpeed {
 | 
			
		||||
  FAN_SPEED_LOW = 0;
 | 
			
		||||
@@ -388,6 +391,7 @@ message ListEntitiesLightResponse {
 | 
			
		||||
  float max_mireds = 10;
 | 
			
		||||
  repeated string effects = 11;
 | 
			
		||||
  bool disabled_by_default = 13;
 | 
			
		||||
  string icon = 14;
 | 
			
		||||
}
 | 
			
		||||
message LightStateResponse {
 | 
			
		||||
  option (id) = 24;
 | 
			
		||||
@@ -790,6 +794,7 @@ message ListEntitiesClimateResponse {
 | 
			
		||||
  repeated ClimatePreset supported_presets = 16;
 | 
			
		||||
  repeated string supported_custom_presets = 17;
 | 
			
		||||
  bool disabled_by_default = 18;
 | 
			
		||||
  string icon = 19;
 | 
			
		||||
}
 | 
			
		||||
message ClimateStateResponse {
 | 
			
		||||
  option (id) = 47;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
#include "api_connection.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/components/network/util.h"
 | 
			
		||||
#include "esphome/core/version.h"
 | 
			
		||||
@@ -143,8 +144,8 @@ void APIConnection::loop() {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string get_default_unique_id(const std::string &component_type, Nameable *nameable) {
 | 
			
		||||
  return App.get_name() + component_type + nameable->get_object_id();
 | 
			
		||||
std::string get_default_unique_id(const std::string &component_type, EntityBase *entity) {
 | 
			
		||||
  return App.get_name() + component_type + entity->get_object_id();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) {
 | 
			
		||||
@@ -180,6 +181,7 @@ bool APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_
 | 
			
		||||
  msg.device_class = binary_sensor->get_device_class();
 | 
			
		||||
  msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor();
 | 
			
		||||
  msg.disabled_by_default = binary_sensor->is_disabled_by_default();
 | 
			
		||||
  msg.icon = binary_sensor->get_icon();
 | 
			
		||||
  return this->send_list_entities_binary_sensor_response(msg);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -212,6 +214,7 @@ bool APIConnection::send_cover_info(cover::Cover *cover) {
 | 
			
		||||
  msg.supports_tilt = traits.get_supports_tilt();
 | 
			
		||||
  msg.device_class = cover->get_device_class();
 | 
			
		||||
  msg.disabled_by_default = cover->is_disabled_by_default();
 | 
			
		||||
  msg.icon = cover->get_icon();
 | 
			
		||||
  return this->send_list_entities_cover_response(msg);
 | 
			
		||||
}
 | 
			
		||||
void APIConnection::cover_command(const CoverCommandRequest &msg) {
 | 
			
		||||
@@ -277,6 +280,7 @@ bool APIConnection::send_fan_info(fan::FanState *fan) {
 | 
			
		||||
  msg.supports_direction = traits.supports_direction();
 | 
			
		||||
  msg.supported_speed_count = traits.supported_speed_count();
 | 
			
		||||
  msg.disabled_by_default = fan->is_disabled_by_default();
 | 
			
		||||
  msg.icon = fan->get_icon();
 | 
			
		||||
  return this->send_list_entities_fan_response(msg);
 | 
			
		||||
}
 | 
			
		||||
void APIConnection::fan_command(const FanCommandRequest &msg) {
 | 
			
		||||
@@ -339,6 +343,7 @@ bool APIConnection::send_light_info(light::LightState *light) {
 | 
			
		||||
  msg.unique_id = get_default_unique_id("light", light);
 | 
			
		||||
 | 
			
		||||
  msg.disabled_by_default = light->is_disabled_by_default();
 | 
			
		||||
  msg.icon = light->get_icon();
 | 
			
		||||
 | 
			
		||||
  for (auto mode : traits.get_supported_color_modes())
 | 
			
		||||
    msg.supported_color_modes.push_back(static_cast<enums::ColorMode>(mode));
 | 
			
		||||
@@ -529,6 +534,7 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
 | 
			
		||||
  msg.unique_id = get_default_unique_id("climate", climate);
 | 
			
		||||
 | 
			
		||||
  msg.disabled_by_default = climate->is_disabled_by_default();
 | 
			
		||||
  msg.icon = climate->get_icon();
 | 
			
		||||
 | 
			
		||||
  msg.supports_current_temperature = traits.get_supports_current_temperature();
 | 
			
		||||
  msg.supports_two_point_target_temperature = traits.get_supports_two_point_target_temperature();
 | 
			
		||||
@@ -601,7 +607,7 @@ bool APIConnection::send_number_info(number::Number *number) {
 | 
			
		||||
  msg.object_id = number->get_object_id();
 | 
			
		||||
  msg.name = number->get_name();
 | 
			
		||||
  msg.unique_id = get_default_unique_id("number", number);
 | 
			
		||||
  msg.icon = number->traits.get_icon();
 | 
			
		||||
  msg.icon = number->get_icon();
 | 
			
		||||
  msg.disabled_by_default = number->is_disabled_by_default();
 | 
			
		||||
 | 
			
		||||
  msg.min_value = number->traits.get_min_value();
 | 
			
		||||
@@ -638,7 +644,7 @@ bool APIConnection::send_select_info(select::Select *select) {
 | 
			
		||||
  msg.object_id = select->get_object_id();
 | 
			
		||||
  msg.name = select->get_name();
 | 
			
		||||
  msg.unique_id = get_default_unique_id("select", select);
 | 
			
		||||
  msg.icon = select->traits.get_icon();
 | 
			
		||||
  msg.icon = select->get_icon();
 | 
			
		||||
  msg.disabled_by_default = select->is_disabled_by_default();
 | 
			
		||||
 | 
			
		||||
  for (const auto &option : select->traits.get_options())
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
// See scripts/api_protobuf/api_protobuf.py
 | 
			
		||||
#include "api_pb2.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace api {
 | 
			
		||||
@@ -532,6 +531,10 @@ bool ListEntitiesBinarySensorResponse::decode_length(uint32_t field_id, ProtoLen
 | 
			
		||||
      this->device_class = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    case 8: {
 | 
			
		||||
      this->icon = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
@@ -554,6 +557,7 @@ void ListEntitiesBinarySensorResponse::encode(ProtoWriteBuffer buffer) const {
 | 
			
		||||
  buffer.encode_string(5, this->device_class);
 | 
			
		||||
  buffer.encode_bool(6, this->is_status_binary_sensor);
 | 
			
		||||
  buffer.encode_bool(7, this->disabled_by_default);
 | 
			
		||||
  buffer.encode_string(8, this->icon);
 | 
			
		||||
}
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const {
 | 
			
		||||
@@ -587,6 +591,10 @@ void ListEntitiesBinarySensorResponse::dump_to(std::string &out) const {
 | 
			
		||||
  out.append("  disabled_by_default: ");
 | 
			
		||||
  out.append(YESNO(this->disabled_by_default));
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
 | 
			
		||||
  out.append("  icon: ");
 | 
			
		||||
  out.append("'").append(this->icon).append("'");
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
  out.append("}");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -678,6 +686,10 @@ bool ListEntitiesCoverResponse::decode_length(uint32_t field_id, ProtoLengthDeli
 | 
			
		||||
      this->device_class = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    case 10: {
 | 
			
		||||
      this->icon = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
@@ -702,6 +714,7 @@ void ListEntitiesCoverResponse::encode(ProtoWriteBuffer buffer) const {
 | 
			
		||||
  buffer.encode_bool(7, this->supports_tilt);
 | 
			
		||||
  buffer.encode_string(8, this->device_class);
 | 
			
		||||
  buffer.encode_bool(9, this->disabled_by_default);
 | 
			
		||||
  buffer.encode_string(10, this->icon);
 | 
			
		||||
}
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
void ListEntitiesCoverResponse::dump_to(std::string &out) const {
 | 
			
		||||
@@ -743,6 +756,10 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const {
 | 
			
		||||
  out.append("  disabled_by_default: ");
 | 
			
		||||
  out.append(YESNO(this->disabled_by_default));
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
 | 
			
		||||
  out.append("  icon: ");
 | 
			
		||||
  out.append("'").append(this->icon).append("'");
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
  out.append("}");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -949,6 +966,10 @@ bool ListEntitiesFanResponse::decode_length(uint32_t field_id, ProtoLengthDelimi
 | 
			
		||||
      this->unique_id = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    case 10: {
 | 
			
		||||
      this->icon = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
@@ -973,6 +994,7 @@ void ListEntitiesFanResponse::encode(ProtoWriteBuffer buffer) const {
 | 
			
		||||
  buffer.encode_bool(7, this->supports_direction);
 | 
			
		||||
  buffer.encode_int32(8, this->supported_speed_count);
 | 
			
		||||
  buffer.encode_bool(9, this->disabled_by_default);
 | 
			
		||||
  buffer.encode_string(10, this->icon);
 | 
			
		||||
}
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
void ListEntitiesFanResponse::dump_to(std::string &out) const {
 | 
			
		||||
@@ -1015,6 +1037,10 @@ void ListEntitiesFanResponse::dump_to(std::string &out) const {
 | 
			
		||||
  out.append("  disabled_by_default: ");
 | 
			
		||||
  out.append(YESNO(this->disabled_by_default));
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
 | 
			
		||||
  out.append("  icon: ");
 | 
			
		||||
  out.append("'").append(this->icon).append("'");
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
  out.append("}");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1263,6 +1289,10 @@ bool ListEntitiesLightResponse::decode_length(uint32_t field_id, ProtoLengthDeli
 | 
			
		||||
      this->effects.push_back(value.as_string());
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    case 14: {
 | 
			
		||||
      this->icon = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
@@ -1303,6 +1333,7 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer buffer) const {
 | 
			
		||||
    buffer.encode_string(11, it, true);
 | 
			
		||||
  }
 | 
			
		||||
  buffer.encode_bool(13, this->disabled_by_default);
 | 
			
		||||
  buffer.encode_string(14, this->icon);
 | 
			
		||||
}
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
void ListEntitiesLightResponse::dump_to(std::string &out) const {
 | 
			
		||||
@@ -1366,6 +1397,10 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const {
 | 
			
		||||
  out.append("  disabled_by_default: ");
 | 
			
		||||
  out.append(YESNO(this->disabled_by_default));
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
 | 
			
		||||
  out.append("  icon: ");
 | 
			
		||||
  out.append("'").append(this->icon).append("'");
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
  out.append("}");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@@ -3073,6 +3108,10 @@ bool ListEntitiesClimateResponse::decode_length(uint32_t field_id, ProtoLengthDe
 | 
			
		||||
      this->supported_custom_presets.push_back(value.as_string());
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    case 19: {
 | 
			
		||||
      this->icon = value.as_string();
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
@@ -3130,6 +3169,7 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
 | 
			
		||||
    buffer.encode_string(17, it, true);
 | 
			
		||||
  }
 | 
			
		||||
  buffer.encode_bool(18, this->disabled_by_default);
 | 
			
		||||
  buffer.encode_string(19, this->icon);
 | 
			
		||||
}
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
void ListEntitiesClimateResponse::dump_to(std::string &out) const {
 | 
			
		||||
@@ -3222,6 +3262,10 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
 | 
			
		||||
  out.append("  disabled_by_default: ");
 | 
			
		||||
  out.append(YESNO(this->disabled_by_default));
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
 | 
			
		||||
  out.append("  icon: ");
 | 
			
		||||
  out.append("'").append(this->icon).append("'");
 | 
			
		||||
  out.append("\n");
 | 
			
		||||
  out.append("}");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -269,6 +269,7 @@ class ListEntitiesBinarySensorResponse : public ProtoMessage {
 | 
			
		||||
  std::string device_class{};
 | 
			
		||||
  bool is_status_binary_sensor{false};
 | 
			
		||||
  bool disabled_by_default{false};
 | 
			
		||||
  std::string icon{};
 | 
			
		||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
  void dump_to(std::string &out) const override;
 | 
			
		||||
@@ -304,6 +305,7 @@ class ListEntitiesCoverResponse : public ProtoMessage {
 | 
			
		||||
  bool supports_tilt{false};
 | 
			
		||||
  std::string device_class{};
 | 
			
		||||
  bool disabled_by_default{false};
 | 
			
		||||
  std::string icon{};
 | 
			
		||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
  void dump_to(std::string &out) const override;
 | 
			
		||||
@@ -360,6 +362,7 @@ class ListEntitiesFanResponse : public ProtoMessage {
 | 
			
		||||
  bool supports_direction{false};
 | 
			
		||||
  int32_t supported_speed_count{0};
 | 
			
		||||
  bool disabled_by_default{false};
 | 
			
		||||
  std::string icon{};
 | 
			
		||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
  void dump_to(std::string &out) const override;
 | 
			
		||||
@@ -424,6 +427,7 @@ class ListEntitiesLightResponse : public ProtoMessage {
 | 
			
		||||
  float max_mireds{0.0f};
 | 
			
		||||
  std::vector<std::string> effects{};
 | 
			
		||||
  bool disabled_by_default{false};
 | 
			
		||||
  std::string icon{};
 | 
			
		||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
  void dump_to(std::string &out) const override;
 | 
			
		||||
@@ -856,6 +860,7 @@ class ListEntitiesClimateResponse : public ProtoMessage {
 | 
			
		||||
  std::vector<enums::ClimatePreset> supported_presets{};
 | 
			
		||||
  std::vector<std::string> supported_custom_presets{};
 | 
			
		||||
  bool disabled_by_default{false};
 | 
			
		||||
  std::string icon{};
 | 
			
		||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
			
		||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
			
		||||
  void dump_to(std::string &out) const override;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,14 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.cpp_helpers import setup_entity
 | 
			
		||||
from esphome import automation, core
 | 
			
		||||
from esphome.automation import Condition, maybe_simple_id
 | 
			
		||||
from esphome.components import mqtt
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_DELAY,
 | 
			
		||||
    CONF_DEVICE_CLASS,
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_FILTERS,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_INVALID_COOLDOWN,
 | 
			
		||||
    CONF_INVERTED,
 | 
			
		||||
    CONF_MAX_LENGTH,
 | 
			
		||||
@@ -88,7 +87,7 @@ DEVICE_CLASSES = [
 | 
			
		||||
IS_PLATFORM_COMPONENT = True
 | 
			
		||||
 | 
			
		||||
binary_sensor_ns = cg.esphome_ns.namespace("binary_sensor")
 | 
			
		||||
BinarySensor = binary_sensor_ns.class_("BinarySensor", cg.Nameable)
 | 
			
		||||
BinarySensor = binary_sensor_ns.class_("BinarySensor", cg.EntityBase)
 | 
			
		||||
BinarySensorInitiallyOff = binary_sensor_ns.class_(
 | 
			
		||||
    "BinarySensorInitiallyOff", BinarySensor
 | 
			
		||||
)
 | 
			
		||||
@@ -314,7 +313,7 @@ def validate_multi_click_timing(value):
 | 
			
		||||
 | 
			
		||||
device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
 | 
			
		||||
 | 
			
		||||
BINARY_SENSOR_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(BinarySensor),
 | 
			
		||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
 | 
			
		||||
@@ -375,10 +374,8 @@ BINARY_SENSOR_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).exten
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup_binary_sensor_core_(var, config):
 | 
			
		||||
    cg.add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        cg.add(var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
    await setup_entity(var, config)
 | 
			
		||||
 | 
			
		||||
    if CONF_DEVICE_CLASS in config:
 | 
			
		||||
        cg.add(var.set_device_class(config[CONF_DEVICE_CLASS]))
 | 
			
		||||
    if CONF_INVERTED in config:
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ void BinarySensor::send_state_internal(bool state, bool is_initial) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
std::string BinarySensor::device_class() { return ""; }
 | 
			
		||||
BinarySensor::BinarySensor(const std::string &name) : Nameable(name), state(false) {}
 | 
			
		||||
BinarySensor::BinarySensor(const std::string &name) : EntityBase(name), state(false) {}
 | 
			
		||||
BinarySensor::BinarySensor() : BinarySensor("") {}
 | 
			
		||||
void BinarySensor::set_device_class(const std::string &device_class) { this->device_class_ = device_class; }
 | 
			
		||||
std::string BinarySensor::get_device_class() {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/components/binary_sensor/filter.h"
 | 
			
		||||
 | 
			
		||||
@@ -22,7 +23,7 @@ namespace binary_sensor {
 | 
			
		||||
 * The sub classes should notify the front-end of new states via the publish_state() method which
 | 
			
		||||
 * handles inverted inputs for you.
 | 
			
		||||
 */
 | 
			
		||||
class BinarySensor : public Nameable {
 | 
			
		||||
class BinarySensor : public EntityBase {
 | 
			
		||||
 public:
 | 
			
		||||
  explicit BinarySensor();
 | 
			
		||||
  /** Construct a binary sensor with the specified name
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,13 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.cpp_helpers import setup_entity
 | 
			
		||||
from esphome import automation
 | 
			
		||||
from esphome.components import mqtt
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_AWAY,
 | 
			
		||||
    CONF_CUSTOM_FAN_MODE,
 | 
			
		||||
    CONF_CUSTOM_PRESET,
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_MAX_TEMPERATURE,
 | 
			
		||||
    CONF_MIN_TEMPERATURE,
 | 
			
		||||
    CONF_MODE,
 | 
			
		||||
@@ -19,7 +18,6 @@ from esphome.const import (
 | 
			
		||||
    CONF_TEMPERATURE_STEP,
 | 
			
		||||
    CONF_VISUAL,
 | 
			
		||||
    CONF_MQTT_ID,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_FAN_MODE,
 | 
			
		||||
    CONF_SWING_MODE,
 | 
			
		||||
)
 | 
			
		||||
@@ -30,7 +28,7 @@ IS_PLATFORM_COMPONENT = True
 | 
			
		||||
CODEOWNERS = ["@esphome/core"]
 | 
			
		||||
climate_ns = cg.esphome_ns.namespace("climate")
 | 
			
		||||
 | 
			
		||||
Climate = climate_ns.class_("Climate", cg.Nameable)
 | 
			
		||||
Climate = climate_ns.class_("Climate", cg.EntityBase)
 | 
			
		||||
ClimateCall = climate_ns.class_("ClimateCall")
 | 
			
		||||
ClimateTraits = climate_ns.class_("ClimateTraits")
 | 
			
		||||
 | 
			
		||||
@@ -88,7 +86,7 @@ validate_climate_swing_mode = cv.enum(CLIMATE_SWING_MODES, upper=True)
 | 
			
		||||
# Actions
 | 
			
		||||
ControlAction = climate_ns.class_("ControlAction", automation.Action)
 | 
			
		||||
 | 
			
		||||
CLIMATE_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(Climate),
 | 
			
		||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTClimateComponent),
 | 
			
		||||
@@ -105,10 +103,8 @@ CLIMATE_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).ext
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup_climate_core_(var, config):
 | 
			
		||||
    cg.add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        cg.add(var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
    await setup_entity(var, config)
 | 
			
		||||
 | 
			
		||||
    visual = config[CONF_VISUAL]
 | 
			
		||||
    if CONF_MIN_TEMPERATURE in visual:
 | 
			
		||||
        cg.add(var.set_visual_min_temperature_override(visual[CONF_MIN_TEMPERATURE]))
 | 
			
		||||
 
 | 
			
		||||
@@ -440,7 +440,7 @@ void Climate::set_visual_max_temperature_override(float visual_max_temperature_o
 | 
			
		||||
void Climate::set_visual_temperature_step_override(float visual_temperature_step_override) {
 | 
			
		||||
  this->visual_temperature_step_override_ = visual_temperature_step_override;
 | 
			
		||||
}
 | 
			
		||||
Climate::Climate(const std::string &name) : Nameable(name) {}
 | 
			
		||||
Climate::Climate(const std::string &name) : EntityBase(name) {}
 | 
			
		||||
Climate::Climate() : Climate("") {}
 | 
			
		||||
ClimateCall Climate::make_call() { return ClimateCall(this); }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/preferences.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
@@ -163,7 +164,7 @@ struct ClimateDeviceRestoreState {
 | 
			
		||||
 * mode etc). These are read-only for the user and rw for integrations. The reason these are public
 | 
			
		||||
 * is for simple access to them from lambdas `if (id(my_climate).mode == climate::CLIMATE_MODE_HEAT_COOL) ...`
 | 
			
		||||
 */
 | 
			
		||||
class Climate : public Nameable {
 | 
			
		||||
class Climate : public EntityBase {
 | 
			
		||||
 public:
 | 
			
		||||
  /// Construct a climate device with empty name (will be set later).
 | 
			
		||||
  Climate();
 | 
			
		||||
 
 | 
			
		||||
@@ -4,18 +4,16 @@ from esphome import automation
 | 
			
		||||
from esphome.automation import maybe_simple_id, Condition
 | 
			
		||||
from esphome.components import mqtt
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_DEVICE_CLASS,
 | 
			
		||||
    CONF_STATE,
 | 
			
		||||
    CONF_POSITION,
 | 
			
		||||
    CONF_TILT,
 | 
			
		||||
    CONF_STOP,
 | 
			
		||||
    CONF_MQTT_ID,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE, coroutine_with_priority
 | 
			
		||||
from esphome.cpp_helpers import setup_entity
 | 
			
		||||
 | 
			
		||||
IS_PLATFORM_COMPONENT = True
 | 
			
		||||
 | 
			
		||||
@@ -36,7 +34,7 @@ DEVICE_CLASSES = [
 | 
			
		||||
 | 
			
		||||
cover_ns = cg.esphome_ns.namespace("cover")
 | 
			
		||||
 | 
			
		||||
Cover = cover_ns.class_("Cover", cg.Nameable)
 | 
			
		||||
Cover = cover_ns.class_("Cover", cg.EntityBase)
 | 
			
		||||
 | 
			
		||||
COVER_OPEN = cover_ns.COVER_OPEN
 | 
			
		||||
COVER_CLOSED = cover_ns.COVER_CLOSED
 | 
			
		||||
@@ -65,7 +63,7 @@ CoverPublishAction = cover_ns.class_("CoverPublishAction", automation.Action)
 | 
			
		||||
CoverIsOpenCondition = cover_ns.class_("CoverIsOpenCondition", Condition)
 | 
			
		||||
CoverIsClosedCondition = cover_ns.class_("CoverIsClosedCondition", Condition)
 | 
			
		||||
 | 
			
		||||
COVER_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
COVER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(Cover),
 | 
			
		||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTCoverComponent),
 | 
			
		||||
@@ -76,10 +74,8 @@ COVER_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).exten
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup_cover_core_(var, config):
 | 
			
		||||
    cg.add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        cg.add(var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
    await setup_entity(var, config)
 | 
			
		||||
 | 
			
		||||
    if CONF_DEVICE_CLASS in config:
 | 
			
		||||
        cg.add(var.set_device_class(config[CONF_DEVICE_CLASS]))
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ const char *cover_operation_to_str(CoverOperation op) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Cover::Cover(const std::string &name) : Nameable(name), position{COVER_OPEN} {}
 | 
			
		||||
Cover::Cover(const std::string &name) : EntityBase(name), position{COVER_OPEN} {}
 | 
			
		||||
 | 
			
		||||
uint32_t Cover::hash_base() { return 1727367479UL; }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/preferences.h"
 | 
			
		||||
#include "cover_traits.h"
 | 
			
		||||
@@ -107,7 +108,7 @@ const char *cover_operation_to_str(CoverOperation op);
 | 
			
		||||
 * to control all values of the cover. Also implement get_traits() to return what operations
 | 
			
		||||
 * the cover supports.
 | 
			
		||||
 */
 | 
			
		||||
class Cover : public Nameable {
 | 
			
		||||
class Cover : public EntityBase {
 | 
			
		||||
 public:
 | 
			
		||||
  explicit Cover();
 | 
			
		||||
  explicit Cover(const std::string &name);
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ from esphome.components.esp32 import add_idf_sdkconfig_option
 | 
			
		||||
DEPENDENCIES = ["esp32", "api"]
 | 
			
		||||
 | 
			
		||||
esp32_camera_ns = cg.esphome_ns.namespace("esp32_camera")
 | 
			
		||||
ESP32Camera = esp32_camera_ns.class_("ESP32Camera", cg.PollingComponent, cg.Nameable)
 | 
			
		||||
ESP32Camera = esp32_camera_ns.class_("ESP32Camera", cg.PollingComponent, cg.EntityBase)
 | 
			
		||||
ESP32CameraFrameSize = esp32_camera_ns.enum("ESP32CameraFrameSize")
 | 
			
		||||
FRAME_SIZES = {
 | 
			
		||||
    "160X120": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_160X120,
 | 
			
		||||
 
 | 
			
		||||
@@ -172,7 +172,7 @@ void ESP32Camera::framebuffer_task(void *pv) {
 | 
			
		||||
    esp_camera_fb_return(framebuffer);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
ESP32Camera::ESP32Camera(const std::string &name) : Nameable(name) {
 | 
			
		||||
ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) {
 | 
			
		||||
  this->config_.pin_pwdn = -1;
 | 
			
		||||
  this->config_.pin_reset = -1;
 | 
			
		||||
  this->config_.pin_xclk = -1;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include <esp_camera.h>
 | 
			
		||||
#include <freertos/FreeRTOS.h>
 | 
			
		||||
@@ -50,7 +51,7 @@ enum ESP32CameraFrameSize {
 | 
			
		||||
  ESP32_CAMERA_SIZE_1600X1200,  // UXGA
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ESP32Camera : public Component, public Nameable {
 | 
			
		||||
class ESP32Camera : public Component, public EntityBase {
 | 
			
		||||
 public:
 | 
			
		||||
  ESP32Camera(const std::string &name);
 | 
			
		||||
  void set_data_pins(std::array<uint8_t, 8> pins);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.components import binary_sensor
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_PIN,
 | 
			
		||||
    CONF_THRESHOLD,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
@@ -55,7 +54,6 @@ async def to_code(config):
 | 
			
		||||
    hub = await cg.get_variable(config[CONF_ESP32_TOUCH_ID])
 | 
			
		||||
    var = cg.new_Pvariable(
 | 
			
		||||
        config[CONF_ID],
 | 
			
		||||
        config[CONF_NAME],
 | 
			
		||||
        TOUCH_PADS[config[CONF_PIN]],
 | 
			
		||||
        config[CONF_THRESHOLD],
 | 
			
		||||
        config[CONF_WAKEUP_THRESHOLD],
 | 
			
		||||
 
 | 
			
		||||
@@ -159,9 +159,8 @@ void ESP32TouchComponent::on_shutdown() {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ESP32TouchBinarySensor::ESP32TouchBinarySensor(const std::string &name, touch_pad_t touch_pad, uint16_t threshold,
 | 
			
		||||
                                               uint16_t wakeup_threshold)
 | 
			
		||||
    : BinarySensor(name), touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {}
 | 
			
		||||
ESP32TouchBinarySensor::ESP32TouchBinarySensor(touch_pad_t touch_pad, uint16_t threshold, uint16_t wakeup_threshold)
 | 
			
		||||
    : BinarySensor(), touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {}
 | 
			
		||||
 | 
			
		||||
}  // namespace esp32_touch
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ class ESP32TouchComponent : public Component {
 | 
			
		||||
/// Simple helper class to expose a touch pad value as a binary sensor.
 | 
			
		||||
class ESP32TouchBinarySensor : public binary_sensor::BinarySensor {
 | 
			
		||||
 public:
 | 
			
		||||
  ESP32TouchBinarySensor(const std::string &name, touch_pad_t touch_pad, uint16_t threshold, uint16_t wakeup_threshold);
 | 
			
		||||
  ESP32TouchBinarySensor(touch_pad_t touch_pad, uint16_t threshold, uint16_t wakeup_threshold);
 | 
			
		||||
 | 
			
		||||
  touch_pad_t get_touch_pad() const { return touch_pad_; }
 | 
			
		||||
  uint16_t get_threshold() const { return threshold_; }
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,7 @@ from esphome import automation
 | 
			
		||||
from esphome.automation import maybe_simple_id
 | 
			
		||||
from esphome.components import mqtt
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_MQTT_ID,
 | 
			
		||||
    CONF_OSCILLATING,
 | 
			
		||||
    CONF_OSCILLATION_COMMAND_TOPIC,
 | 
			
		||||
@@ -16,7 +14,6 @@ from esphome.const import (
 | 
			
		||||
    CONF_SPEED_LEVEL_STATE_TOPIC,
 | 
			
		||||
    CONF_SPEED_COMMAND_TOPIC,
 | 
			
		||||
    CONF_SPEED_STATE_TOPIC,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_ON_SPEED_SET,
 | 
			
		||||
    CONF_ON_TURN_OFF,
 | 
			
		||||
    CONF_ON_TURN_ON,
 | 
			
		||||
@@ -24,11 +21,12 @@ from esphome.const import (
 | 
			
		||||
    CONF_DIRECTION,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE, coroutine_with_priority
 | 
			
		||||
from esphome.cpp_helpers import setup_entity
 | 
			
		||||
 | 
			
		||||
IS_PLATFORM_COMPONENT = True
 | 
			
		||||
 | 
			
		||||
fan_ns = cg.esphome_ns.namespace("fan")
 | 
			
		||||
FanState = fan_ns.class_("FanState", cg.Nameable, cg.Component)
 | 
			
		||||
FanState = fan_ns.class_("FanState", cg.EntityBase, cg.Component)
 | 
			
		||||
MakeFan = cg.Application.struct("MakeFan")
 | 
			
		||||
 | 
			
		||||
FanDirection = fan_ns.enum("FanDirection")
 | 
			
		||||
@@ -50,7 +48,7 @@ FanSpeedSetTrigger = fan_ns.class_("FanSpeedSetTrigger", automation.Trigger.temp
 | 
			
		||||
FanIsOnCondition = fan_ns.class_("FanIsOnCondition", automation.Condition.template())
 | 
			
		||||
FanIsOffCondition = fan_ns.class_("FanIsOffCondition", automation.Condition.template())
 | 
			
		||||
 | 
			
		||||
FAN_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
FAN_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(FanState),
 | 
			
		||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTFanComponent),
 | 
			
		||||
@@ -92,10 +90,7 @@ FAN_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup_fan_core_(var, config):
 | 
			
		||||
    cg.add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        cg.add(var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
    await setup_entity(var, config)
 | 
			
		||||
 | 
			
		||||
    if CONF_MQTT_ID in config:
 | 
			
		||||
        mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var)
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ void FanState::set_traits(const FanTraits &traits) { this->traits_ = traits; }
 | 
			
		||||
void FanState::add_on_state_callback(std::function<void()> &&callback) {
 | 
			
		||||
  this->state_callback_.add(std::move(callback));
 | 
			
		||||
}
 | 
			
		||||
FanState::FanState(const std::string &name) : Nameable(name) {}
 | 
			
		||||
FanState::FanState(const std::string &name) : EntityBase(name) {}
 | 
			
		||||
 | 
			
		||||
FanStateCall FanState::turn_on() { return this->make_call().set_state(true); }
 | 
			
		||||
FanStateCall FanState::turn_off() { return this->make_call().set_state(false); }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/preferences.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
@@ -66,7 +67,7 @@ class FanStateCall {
 | 
			
		||||
  optional<FanDirection> direction_{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FanState : public Nameable, public Component {
 | 
			
		||||
class FanState : public EntityBase, public Component {
 | 
			
		||||
 public:
 | 
			
		||||
  FanState() = default;
 | 
			
		||||
  /// Construct the fan state with name.
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,6 @@ class IntegrationSensor : public sensor::Sensor, public Component {
 | 
			
		||||
    this->rtc_.save(&result_f);
 | 
			
		||||
  }
 | 
			
		||||
  std::string unit_of_measurement() override;
 | 
			
		||||
  std::string icon() override { return this->sensor_->get_icon(); }
 | 
			
		||||
  int8_t accuracy_decimals() override { return this->sensor_->get_accuracy_decimals() + 2; }
 | 
			
		||||
 | 
			
		||||
  sensor::Sensor *sensor_;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,8 @@ import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome import automation
 | 
			
		||||
from esphome.components import sensor
 | 
			
		||||
from esphome.const import CONF_ID, CONF_SENSOR, CONF_RESTORE
 | 
			
		||||
from esphome.const import CONF_ICON, CONF_ID, CONF_SENSOR, CONF_RESTORE
 | 
			
		||||
from esphome.core.entity_helpers import inherit_property_from
 | 
			
		||||
 | 
			
		||||
integration_ns = cg.esphome_ns.namespace("integration")
 | 
			
		||||
IntegrationSensor = integration_ns.class_(
 | 
			
		||||
@@ -29,7 +30,6 @@ CONF_TIME_UNIT = "time_unit"
 | 
			
		||||
CONF_INTEGRATION_METHOD = "integration_method"
 | 
			
		||||
CONF_MIN_SAVE_INTERVAL = "min_save_interval"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(IntegrationSensor),
 | 
			
		||||
@@ -46,6 +46,19 @@ CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend(
 | 
			
		||||
).extend(cv.COMPONENT_SCHEMA)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
FINAL_VALIDATE_SCHEMA = cv.All(
 | 
			
		||||
    cv.Schema(
 | 
			
		||||
        {
 | 
			
		||||
            cv.Required(CONF_ID): cv.use_id(IntegrationSensor),
 | 
			
		||||
            cv.Optional(CONF_ICON): cv.icon,
 | 
			
		||||
            cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
 | 
			
		||||
        },
 | 
			
		||||
        extra=cv.ALLOW_EXTRA,
 | 
			
		||||
    ),
 | 
			
		||||
    inherit_property_from(CONF_ICON, CONF_SENSOR),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,13 +5,10 @@ from esphome.components import mqtt, power_supply
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_COLOR_CORRECT,
 | 
			
		||||
    CONF_DEFAULT_TRANSITION_LENGTH,
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_EFFECTS,
 | 
			
		||||
    CONF_FLASH_TRANSITION_LENGTH,
 | 
			
		||||
    CONF_GAMMA_CORRECT,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_MQTT_ID,
 | 
			
		||||
    CONF_POWER_SUPPLY,
 | 
			
		||||
    CONF_RESTORE_MODE,
 | 
			
		||||
@@ -22,6 +19,7 @@ from esphome.const import (
 | 
			
		||||
    CONF_WARM_WHITE_COLOR_TEMPERATURE,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import coroutine_with_priority
 | 
			
		||||
from esphome.cpp_helpers import setup_entity
 | 
			
		||||
from .automation import light_control_to_code  # noqa
 | 
			
		||||
from .effects import (
 | 
			
		||||
    validate_effects,
 | 
			
		||||
@@ -54,7 +52,7 @@ RESTORE_MODES = {
 | 
			
		||||
    "RESTORE_INVERTED_DEFAULT_ON": LightRestoreMode.LIGHT_RESTORE_INVERTED_DEFAULT_ON,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LIGHT_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
LIGHT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(LightState),
 | 
			
		||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTJSONLightComponent),
 | 
			
		||||
@@ -126,10 +124,10 @@ def validate_color_temperature_channels(value):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup_light_core_(light_var, output_var, config):
 | 
			
		||||
    cg.add(light_var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    await setup_entity(light_var, config)
 | 
			
		||||
 | 
			
		||||
    cg.add(light_var.set_restore_mode(config[CONF_RESTORE_MODE]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        cg.add(light_var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
 | 
			
		||||
    if CONF_DEFAULT_TRANSITION_LENGTH in config:
 | 
			
		||||
        cg.add(
 | 
			
		||||
            light_var.set_default_transition_length(
 | 
			
		||||
@@ -167,7 +165,7 @@ async def setup_light_core_(light_var, output_var, config):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def register_light(output_var, config):
 | 
			
		||||
    light_var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME], output_var)
 | 
			
		||||
    light_var = cg.new_Pvariable(config[CONF_ID], output_var)
 | 
			
		||||
    cg.add(cg.App.register_light(light_var))
 | 
			
		||||
    await cg.register_component(light_var, config)
 | 
			
		||||
    await setup_light_core_(light_var, output_var, config)
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,8 @@ namespace light {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "light";
 | 
			
		||||
 | 
			
		||||
LightState::LightState(const std::string &name, LightOutput *output) : Nameable(name), output_(output) {}
 | 
			
		||||
LightState::LightState(const std::string &name, LightOutput *output) : EntityBase(name), output_(output) {}
 | 
			
		||||
LightState::LightState(LightOutput *output) : output_(output) {}
 | 
			
		||||
 | 
			
		||||
LightTraits LightState::get_traits() { return this->output_->get_traits(); }
 | 
			
		||||
LightCall LightState::turn_on() { return this->make_call().set_state(true); }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/optional.h"
 | 
			
		||||
#include "esphome/core/preferences.h"
 | 
			
		||||
#include "light_call.h"
 | 
			
		||||
@@ -26,11 +27,13 @@ enum LightRestoreMode {
 | 
			
		||||
/** This class represents the communication layer between the front-end MQTT layer and the
 | 
			
		||||
 * hardware output layer.
 | 
			
		||||
 */
 | 
			
		||||
class LightState : public Nameable, public Component {
 | 
			
		||||
class LightState : public EntityBase, public Component {
 | 
			
		||||
 public:
 | 
			
		||||
  /// Construct this LightState using the provided traits and name.
 | 
			
		||||
  LightState(const std::string &name, LightOutput *output);
 | 
			
		||||
 | 
			
		||||
  LightState(LightOutput *output);
 | 
			
		||||
 | 
			
		||||
  LightTraits get_traits();
 | 
			
		||||
 | 
			
		||||
  /// Make a light state call
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ from esphome import automation
 | 
			
		||||
 | 
			
		||||
# Base
 | 
			
		||||
light_ns = cg.esphome_ns.namespace("light")
 | 
			
		||||
LightState = light_ns.class_("LightState", cg.Nameable, cg.Component)
 | 
			
		||||
LightState = light_ns.class_("LightState", cg.EntityBase, cg.Component)
 | 
			
		||||
# Fake class for addressable lights
 | 
			
		||||
AddressableLightState = light_ns.class_("LightState", LightState)
 | 
			
		||||
LightOutput = light_ns.class_("LightOutput")
 | 
			
		||||
 
 | 
			
		||||
@@ -37,10 +37,8 @@ float MCP3008::read_data(uint8_t pin) {
 | 
			
		||||
  return data / 1023.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MCP3008Sensor::MCP3008Sensor(MCP3008 *parent, const std::string &name, uint8_t pin, float reference_voltage)
 | 
			
		||||
    : PollingComponent(1000), parent_(parent), pin_(pin), reference_voltage_(reference_voltage) {
 | 
			
		||||
  this->set_name(name);
 | 
			
		||||
}
 | 
			
		||||
MCP3008Sensor::MCP3008Sensor(MCP3008 *parent, uint8_t pin, float reference_voltage)
 | 
			
		||||
    : PollingComponent(1000), parent_(parent), pin_(pin), reference_voltage_(reference_voltage) {}
 | 
			
		||||
 | 
			
		||||
float MCP3008Sensor::get_setup_priority() const { return setup_priority::DATA; }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ class MCP3008 : public Component,
 | 
			
		||||
 | 
			
		||||
class MCP3008Sensor : public PollingComponent, public sensor::Sensor, public voltage_sampler::VoltageSampler {
 | 
			
		||||
 public:
 | 
			
		||||
  MCP3008Sensor(MCP3008 *parent, const std::string &name, uint8_t pin, float reference_voltage);
 | 
			
		||||
  MCP3008Sensor(MCP3008 *parent, uint8_t pin, float reference_voltage);
 | 
			
		||||
 | 
			
		||||
  void set_reference_voltage(float reference_voltage) { reference_voltage_ = reference_voltage; }
 | 
			
		||||
  void setup() override;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.components import sensor, voltage_sampler
 | 
			
		||||
from esphome.const import CONF_ID, CONF_NUMBER, CONF_NAME
 | 
			
		||||
from esphome.const import CONF_ID, CONF_NUMBER
 | 
			
		||||
from . import mcp3008_ns, MCP3008
 | 
			
		||||
 | 
			
		||||
AUTO_LOAD = ["voltage_sampler"]
 | 
			
		||||
@@ -29,7 +29,6 @@ async def to_code(config):
 | 
			
		||||
    var = cg.new_Pvariable(
 | 
			
		||||
        config[CONF_ID],
 | 
			
		||||
        parent,
 | 
			
		||||
        config[CONF_NAME],
 | 
			
		||||
        config[CONF_NUMBER],
 | 
			
		||||
        config[CONF_REFERENCE_VOLTAGE],
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ namespace mqtt {
 | 
			
		||||
static const char *const TAG = "mqtt.binary_sensor";
 | 
			
		||||
 | 
			
		||||
std::string MQTTBinarySensorComponent::component_type() const { return "binary_sensor"; }
 | 
			
		||||
const EntityBase *MQTTBinarySensorComponent::get_entity() const { return this->binary_sensor_; }
 | 
			
		||||
 | 
			
		||||
void MQTTBinarySensorComponent::setup() {
 | 
			
		||||
  this->binary_sensor_->add_on_state_callback([this](bool state) { this->publish_state(state); });
 | 
			
		||||
@@ -25,7 +26,6 @@ MQTTBinarySensorComponent::MQTTBinarySensorComponent(binary_sensor::BinarySensor
 | 
			
		||||
    this->set_custom_state_topic(mqtt::global_mqtt_client->get_availability().topic);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
std::string MQTTBinarySensorComponent::friendly_name() const { return this->binary_sensor_->get_name(); }
 | 
			
		||||
 | 
			
		||||
void MQTTBinarySensorComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) {
 | 
			
		||||
  if (!this->binary_sensor_->get_device_class().empty())
 | 
			
		||||
@@ -43,7 +43,6 @@ bool MQTTBinarySensorComponent::send_initial_state() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
bool MQTTBinarySensorComponent::is_internal() { return this->binary_sensor_->is_internal(); }
 | 
			
		||||
bool MQTTBinarySensorComponent::publish_state(bool state) {
 | 
			
		||||
  if (this->binary_sensor_->is_status_binary_sensor())
 | 
			
		||||
    return true;
 | 
			
		||||
 
 | 
			
		||||
@@ -28,11 +28,10 @@ class MQTTBinarySensorComponent : public mqtt::MQTTComponent {
 | 
			
		||||
 | 
			
		||||
  bool send_initial_state() override;
 | 
			
		||||
  bool publish_state(bool state);
 | 
			
		||||
  bool is_internal() override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  std::string friendly_name() const override;
 | 
			
		||||
  std::string component_type() const override;
 | 
			
		||||
  const EntityBase *get_entity() const override;
 | 
			
		||||
 | 
			
		||||
  binary_sensor::BinarySensor *binary_sensor_;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -212,9 +212,9 @@ void MQTTClimateComponent::setup() {
 | 
			
		||||
}
 | 
			
		||||
MQTTClimateComponent::MQTTClimateComponent(Climate *device) : device_(device) {}
 | 
			
		||||
bool MQTTClimateComponent::send_initial_state() { return this->publish_state_(); }
 | 
			
		||||
bool MQTTClimateComponent::is_internal() { return this->device_->is_internal(); }
 | 
			
		||||
std::string MQTTClimateComponent::component_type() const { return "climate"; }
 | 
			
		||||
std::string MQTTClimateComponent::friendly_name() const { return this->device_->get_name(); }
 | 
			
		||||
const EntityBase *MQTTClimateComponent::get_entity() const { return this->device_; }
 | 
			
		||||
 | 
			
		||||
bool MQTTClimateComponent::publish_state_() {
 | 
			
		||||
  auto traits = this->device_->get_traits();
 | 
			
		||||
  // mode
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@ class MQTTClimateComponent : public mqtt::MQTTComponent {
 | 
			
		||||
  MQTTClimateComponent(climate::Climate *device);
 | 
			
		||||
  void send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) override;
 | 
			
		||||
  bool send_initial_state() override;
 | 
			
		||||
  bool is_internal() override;
 | 
			
		||||
  std::string component_type() const override;
 | 
			
		||||
  void setup() override;
 | 
			
		||||
 | 
			
		||||
@@ -38,7 +37,7 @@ class MQTTClimateComponent : public mqtt::MQTTComponent {
 | 
			
		||||
  MQTT_COMPONENT_CUSTOM_TOPIC(swing_mode, command)
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  std::string friendly_name() const override;
 | 
			
		||||
  const EntityBase *get_entity() const override;
 | 
			
		||||
 | 
			
		||||
  bool publish_state_();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -68,8 +68,13 @@ bool MQTTComponent::send_discovery_() {
 | 
			
		||||
 | 
			
		||||
        this->send_discovery(root, config);
 | 
			
		||||
 | 
			
		||||
        std::string name = this->friendly_name();
 | 
			
		||||
        root["name"] = name;
 | 
			
		||||
        // Fields from EntityBase
 | 
			
		||||
        root["name"] = this->friendly_name();
 | 
			
		||||
        if (this->is_disabled_by_default())
 | 
			
		||||
          root["enabled_by_default"] = false;
 | 
			
		||||
        if (!this->get_icon().empty())
 | 
			
		||||
          root["icon"] = this->get_icon();
 | 
			
		||||
 | 
			
		||||
        if (config.state_topic)
 | 
			
		||||
          root["state_topic"] = this->get_state_topic_();
 | 
			
		||||
        if (config.command_topic)
 | 
			
		||||
@@ -199,6 +204,12 @@ void MQTTComponent::schedule_resend_state() { this->resend_state_ = true; }
 | 
			
		||||
std::string MQTTComponent::unique_id() { return ""; }
 | 
			
		||||
bool MQTTComponent::is_connected_() const { return global_mqtt_client->is_connected(); }
 | 
			
		||||
 | 
			
		||||
// Pull these properties from EntityBase if not overridden
 | 
			
		||||
std::string MQTTComponent::friendly_name() const { return this->get_entity()->get_name(); }
 | 
			
		||||
std::string MQTTComponent::get_icon() const { return this->get_entity()->get_icon(); }
 | 
			
		||||
bool MQTTComponent::is_disabled_by_default() const { return this->get_entity()->is_disabled_by_default(); }
 | 
			
		||||
bool MQTTComponent::is_internal() { return this->get_entity()->is_internal(); }
 | 
			
		||||
 | 
			
		||||
}  // namespace mqtt
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "mqtt_client.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
@@ -73,7 +74,7 @@ class MQTTComponent : public Component {
 | 
			
		||||
 | 
			
		||||
  virtual bool send_initial_state() = 0;
 | 
			
		||||
 | 
			
		||||
  virtual bool is_internal() = 0;
 | 
			
		||||
  virtual bool is_internal();
 | 
			
		||||
 | 
			
		||||
  /// Set whether state message should be retained.
 | 
			
		||||
  void set_retain(bool retain);
 | 
			
		||||
@@ -148,8 +149,10 @@ class MQTTComponent : public Component {
 | 
			
		||||
   */
 | 
			
		||||
  std::string get_default_topic_for_(const std::string &suffix) const;
 | 
			
		||||
 | 
			
		||||
  /// Get the friendly name of this MQTT component.
 | 
			
		||||
  virtual std::string friendly_name() const = 0;
 | 
			
		||||
  /**
 | 
			
		||||
   * Gets the Entity served by this MQTT component.
 | 
			
		||||
   */
 | 
			
		||||
  virtual const EntityBase *get_entity() const = 0;
 | 
			
		||||
 | 
			
		||||
  /** A unique ID for this MQTT component, empty for no unique id. See unique ID requirements:
 | 
			
		||||
   * https://developers.home-assistant.io/docs/en/entity_registry_index.html#unique-id-requirements
 | 
			
		||||
@@ -158,6 +161,15 @@ class MQTTComponent : public Component {
 | 
			
		||||
   */
 | 
			
		||||
  virtual std::string unique_id();
 | 
			
		||||
 | 
			
		||||
  /// Get the friendly name of this MQTT component.
 | 
			
		||||
  virtual std::string friendly_name() const;
 | 
			
		||||
 | 
			
		||||
  /// Get the icon field of this component
 | 
			
		||||
  virtual std::string get_icon() const;
 | 
			
		||||
 | 
			
		||||
  /// Get whether the underlying Entity is disabled by default
 | 
			
		||||
  virtual bool is_disabled_by_default() const;
 | 
			
		||||
 | 
			
		||||
  /// Get the MQTT topic that new states will be shared to.
 | 
			
		||||
  const std::string get_state_topic_() const;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -84,9 +84,9 @@ void MQTTCoverComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryCon
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string MQTTCoverComponent::component_type() const { return "cover"; }
 | 
			
		||||
std::string MQTTCoverComponent::friendly_name() const { return this->cover_->get_name(); }
 | 
			
		||||
const EntityBase *MQTTCoverComponent::get_entity() const { return this->cover_; }
 | 
			
		||||
 | 
			
		||||
bool MQTTCoverComponent::send_initial_state() { return this->publish_state(); }
 | 
			
		||||
bool MQTTCoverComponent::is_internal() { return this->cover_->is_internal(); }
 | 
			
		||||
bool MQTTCoverComponent::publish_state() {
 | 
			
		||||
  auto traits = this->cover_->get_traits();
 | 
			
		||||
  bool success = true;
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,6 @@ class MQTTCoverComponent : public mqtt::MQTTComponent {
 | 
			
		||||
  MQTT_COMPONENT_CUSTOM_TOPIC(tilt, state)
 | 
			
		||||
 | 
			
		||||
  bool send_initial_state() override;
 | 
			
		||||
  bool is_internal() override;
 | 
			
		||||
 | 
			
		||||
  bool publish_state();
 | 
			
		||||
 | 
			
		||||
@@ -32,7 +31,7 @@ class MQTTCoverComponent : public mqtt::MQTTComponent {
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  std::string component_type() const override;
 | 
			
		||||
  std::string friendly_name() const override;
 | 
			
		||||
  const EntityBase *get_entity() const override;
 | 
			
		||||
 | 
			
		||||
  cover::Cover *cover_;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ MQTTFanComponent::MQTTFanComponent(FanState *state) : MQTTComponent(), state_(st
 | 
			
		||||
 | 
			
		||||
FanState *MQTTFanComponent::get_state() const { return this->state_; }
 | 
			
		||||
std::string MQTTFanComponent::component_type() const { return "fan"; }
 | 
			
		||||
const EntityBase *MQTTFanComponent::get_entity() const { return this->state_; }
 | 
			
		||||
 | 
			
		||||
void MQTTFanComponent::setup() {
 | 
			
		||||
  this->subscribe(this->get_command_topic_(), [this](const std::string &topic, const std::string &payload) {
 | 
			
		||||
@@ -113,7 +114,7 @@ void MQTTFanComponent::dump_config() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MQTTFanComponent::send_initial_state() { return this->publish_state(); }
 | 
			
		||||
std::string MQTTFanComponent::friendly_name() const { return this->state_->get_name(); }
 | 
			
		||||
 | 
			
		||||
void MQTTFanComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) {
 | 
			
		||||
  if (this->state_->get_traits().supports_oscillation()) {
 | 
			
		||||
    root["oscillation_command_topic"] = this->get_oscillation_command_topic();
 | 
			
		||||
@@ -126,7 +127,6 @@ void MQTTFanComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfi
 | 
			
		||||
    root["speed_state_topic"] = this->get_speed_state_topic();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
bool MQTTFanComponent::is_internal() { return this->state_->is_internal(); }
 | 
			
		||||
bool MQTTFanComponent::publish_state() {
 | 
			
		||||
  const char *state_s = this->state_->state ? "ON" : "OFF";
 | 
			
		||||
  ESP_LOGD(TAG, "'%s' Sending state %s.", this->state_->get_name().c_str(), state_s);
 | 
			
		||||
 
 | 
			
		||||
@@ -39,10 +39,8 @@ class MQTTFanComponent : public mqtt::MQTTComponent {
 | 
			
		||||
 | 
			
		||||
  fan::FanState *get_state() const;
 | 
			
		||||
 | 
			
		||||
  bool is_internal() override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  std::string friendly_name() const override;
 | 
			
		||||
  const EntityBase *get_entity() const override;
 | 
			
		||||
 | 
			
		||||
  fan::FanState *state_;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ static const char *const TAG = "mqtt.light";
 | 
			
		||||
using namespace esphome::light;
 | 
			
		||||
 | 
			
		||||
std::string MQTTJSONLightComponent::component_type() const { return "light"; }
 | 
			
		||||
const EntityBase *MQTTJSONLightComponent::get_entity() const { return this->state_; }
 | 
			
		||||
 | 
			
		||||
void MQTTJSONLightComponent::setup() {
 | 
			
		||||
  this->subscribe_json(this->get_command_topic_(), [this](const std::string &topic, JsonObject &root) {
 | 
			
		||||
@@ -32,7 +33,7 @@ bool MQTTJSONLightComponent::publish_state_() {
 | 
			
		||||
                            [this](JsonObject &root) { LightJSONSchema::dump_json(*this->state_, root); });
 | 
			
		||||
}
 | 
			
		||||
LightState *MQTTJSONLightComponent::get_state() const { return this->state_; }
 | 
			
		||||
std::string MQTTJSONLightComponent::friendly_name() const { return this->state_->get_name(); }
 | 
			
		||||
 | 
			
		||||
void MQTTJSONLightComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) {
 | 
			
		||||
  root["schema"] = "json";
 | 
			
		||||
  auto traits = this->state_->get_traits();
 | 
			
		||||
@@ -70,7 +71,6 @@ void MQTTJSONLightComponent::send_discovery(JsonObject &root, mqtt::SendDiscover
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
bool MQTTJSONLightComponent::send_initial_state() { return this->publish_state_(); }
 | 
			
		||||
bool MQTTJSONLightComponent::is_internal() { return this->state_->is_internal(); }
 | 
			
		||||
void MQTTJSONLightComponent::dump_config() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "MQTT Light '%s':", this->state_->get_name().c_str());
 | 
			
		||||
  LOG_MQTT_COMPONENT(true, true)
 | 
			
		||||
 
 | 
			
		||||
@@ -25,11 +25,9 @@ class MQTTJSONLightComponent : public mqtt::MQTTComponent {
 | 
			
		||||
 | 
			
		||||
  bool send_initial_state() override;
 | 
			
		||||
 | 
			
		||||
  bool is_internal() override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  std::string friendly_name() const override;
 | 
			
		||||
  std::string component_type() const override;
 | 
			
		||||
  const EntityBase *get_entity() const override;
 | 
			
		||||
 | 
			
		||||
  bool publish_state_();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -33,13 +33,11 @@ void MQTTNumberComponent::dump_config() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string MQTTNumberComponent::component_type() const { return "number"; }
 | 
			
		||||
const EntityBase *MQTTNumberComponent::get_entity() const { return this->number_; }
 | 
			
		||||
 | 
			
		||||
std::string MQTTNumberComponent::friendly_name() const { return this->number_->get_name(); }
 | 
			
		||||
void MQTTNumberComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) {
 | 
			
		||||
  const auto &traits = number_->traits;
 | 
			
		||||
  // https://www.home-assistant.io/integrations/number.mqtt/
 | 
			
		||||
  if (!traits.get_icon().empty())
 | 
			
		||||
    root["icon"] = traits.get_icon();
 | 
			
		||||
  root["min"] = traits.get_min_value();
 | 
			
		||||
  root["max"] = traits.get_max_value();
 | 
			
		||||
  root["step"] = traits.get_step();
 | 
			
		||||
@@ -53,7 +51,6 @@ bool MQTTNumberComponent::send_initial_state() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
bool MQTTNumberComponent::is_internal() { return this->number_->is_internal(); }
 | 
			
		||||
bool MQTTNumberComponent::publish_state(float value) {
 | 
			
		||||
  char buffer[64];
 | 
			
		||||
  snprintf(buffer, sizeof(buffer), "%f", value);
 | 
			
		||||
 
 | 
			
		||||
@@ -28,15 +28,13 @@ class MQTTNumberComponent : public mqtt::MQTTComponent {
 | 
			
		||||
  void send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) override;
 | 
			
		||||
 | 
			
		||||
  bool send_initial_state() override;
 | 
			
		||||
  bool is_internal() override;
 | 
			
		||||
 | 
			
		||||
  bool publish_state(float value);
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  /// Override for MQTTComponent, returns "number".
 | 
			
		||||
  std::string component_type() const override;
 | 
			
		||||
 | 
			
		||||
  std::string friendly_name() const override;
 | 
			
		||||
  const EntityBase *get_entity() const override;
 | 
			
		||||
 | 
			
		||||
  number::Number *number_;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -28,13 +28,11 @@ void MQTTSelectComponent::dump_config() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string MQTTSelectComponent::component_type() const { return "select"; }
 | 
			
		||||
const EntityBase *MQTTSelectComponent::get_entity() const { return this->select_; }
 | 
			
		||||
 | 
			
		||||
std::string MQTTSelectComponent::friendly_name() const { return this->select_->get_name(); }
 | 
			
		||||
void MQTTSelectComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) {
 | 
			
		||||
  const auto &traits = select_->traits;
 | 
			
		||||
  // https://www.home-assistant.io/integrations/select.mqtt/
 | 
			
		||||
  if (!traits.get_icon().empty())
 | 
			
		||||
    root["icon"] = traits.get_icon();
 | 
			
		||||
  JsonArray &options = root.createNestedArray("options");
 | 
			
		||||
  for (const auto &option : traits.get_options())
 | 
			
		||||
    options.add(option);
 | 
			
		||||
@@ -48,7 +46,6 @@ bool MQTTSelectComponent::send_initial_state() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
bool MQTTSelectComponent::is_internal() { return this->select_->is_internal(); }
 | 
			
		||||
bool MQTTSelectComponent::publish_state(const std::string &value) {
 | 
			
		||||
  return this->publish(this->get_state_topic_(), value);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,15 +28,13 @@ class MQTTSelectComponent : public mqtt::MQTTComponent {
 | 
			
		||||
  void send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) override;
 | 
			
		||||
 | 
			
		||||
  bool send_initial_state() override;
 | 
			
		||||
  bool is_internal() override;
 | 
			
		||||
 | 
			
		||||
  bool publish_state(const std::string &value);
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  /// Override for MQTTComponent, returns "select".
 | 
			
		||||
  std::string component_type() const override;
 | 
			
		||||
 | 
			
		||||
  std::string friendly_name() const override;
 | 
			
		||||
  const EntityBase *get_entity() const override;
 | 
			
		||||
 | 
			
		||||
  select::Select *select_;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ void MQTTSensorComponent::dump_config() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string MQTTSensorComponent::component_type() const { return "sensor"; }
 | 
			
		||||
const EntityBase *MQTTSensorComponent::get_entity() const { return this->sensor_; }
 | 
			
		||||
 | 
			
		||||
uint32_t MQTTSensorComponent::get_expire_after() const {
 | 
			
		||||
  if (this->expire_after_.has_value())
 | 
			
		||||
@@ -38,7 +39,7 @@ uint32_t MQTTSensorComponent::get_expire_after() const {
 | 
			
		||||
}
 | 
			
		||||
void MQTTSensorComponent::set_expire_after(uint32_t expire_after) { this->expire_after_ = expire_after; }
 | 
			
		||||
void MQTTSensorComponent::disable_expire_after() { this->expire_after_ = 0; }
 | 
			
		||||
std::string MQTTSensorComponent::friendly_name() const { return this->sensor_->get_name(); }
 | 
			
		||||
 | 
			
		||||
void MQTTSensorComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) {
 | 
			
		||||
  if (!this->sensor_->get_device_class().empty())
 | 
			
		||||
    root["device_class"] = this->sensor_->get_device_class();
 | 
			
		||||
@@ -49,9 +50,6 @@ void MQTTSensorComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryCo
 | 
			
		||||
  if (this->get_expire_after() > 0)
 | 
			
		||||
    root["expire_after"] = this->get_expire_after() / 1000;
 | 
			
		||||
 | 
			
		||||
  if (!this->sensor_->get_icon().empty())
 | 
			
		||||
    root["icon"] = this->sensor_->get_icon();
 | 
			
		||||
 | 
			
		||||
  if (this->sensor_->get_force_update())
 | 
			
		||||
    root["force_update"] = true;
 | 
			
		||||
 | 
			
		||||
@@ -67,7 +65,6 @@ bool MQTTSensorComponent::send_initial_state() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
bool MQTTSensorComponent::is_internal() { return this->sensor_->is_internal(); }
 | 
			
		||||
bool MQTTSensorComponent::publish_state(float value) {
 | 
			
		||||
  int8_t accuracy = this->sensor_->get_accuracy_decimals();
 | 
			
		||||
  return this->publish(this->get_state_topic_(), value_accuracy_to_string(value, accuracy));
 | 
			
		||||
 
 | 
			
		||||
@@ -41,14 +41,11 @@ class MQTTSensorComponent : public mqtt::MQTTComponent {
 | 
			
		||||
 | 
			
		||||
  bool publish_state(float value);
 | 
			
		||||
  bool send_initial_state() override;
 | 
			
		||||
  bool is_internal() override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  /// Override for MQTTComponent, returns "sensor".
 | 
			
		||||
  std::string component_type() const override;
 | 
			
		||||
 | 
			
		||||
  std::string friendly_name() const override;
 | 
			
		||||
 | 
			
		||||
  const EntityBase *get_entity() const override;
 | 
			
		||||
  std::string unique_id() override;
 | 
			
		||||
 | 
			
		||||
  sensor::Sensor *sensor_;
 | 
			
		||||
 
 | 
			
		||||
@@ -41,15 +41,13 @@ void MQTTSwitchComponent::dump_config() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string MQTTSwitchComponent::component_type() const { return "switch"; }
 | 
			
		||||
const EntityBase *MQTTSwitchComponent::get_entity() const { return this->switch_; }
 | 
			
		||||
void MQTTSwitchComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) {
 | 
			
		||||
  if (!this->switch_->get_icon().empty())
 | 
			
		||||
    root["icon"] = this->switch_->get_icon();
 | 
			
		||||
  if (this->switch_->assumed_state())
 | 
			
		||||
    root["optimistic"] = true;
 | 
			
		||||
}
 | 
			
		||||
bool MQTTSwitchComponent::send_initial_state() { return this->publish_state(this->switch_->state); }
 | 
			
		||||
bool MQTTSwitchComponent::is_internal() { return this->switch_->is_internal(); }
 | 
			
		||||
std::string MQTTSwitchComponent::friendly_name() const { return this->switch_->get_name(); }
 | 
			
		||||
 | 
			
		||||
bool MQTTSwitchComponent::publish_state(bool state) {
 | 
			
		||||
  const char *state_s = state ? "ON" : "OFF";
 | 
			
		||||
  return this->publish(this->get_state_topic_(), state_s);
 | 
			
		||||
 
 | 
			
		||||
@@ -23,15 +23,13 @@ class MQTTSwitchComponent : public mqtt::MQTTComponent {
 | 
			
		||||
  void send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) override;
 | 
			
		||||
 | 
			
		||||
  bool send_initial_state() override;
 | 
			
		||||
  bool is_internal() override;
 | 
			
		||||
 | 
			
		||||
  bool publish_state(bool state);
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  std::string friendly_name() const override;
 | 
			
		||||
 | 
			
		||||
  /// "switch" component type.
 | 
			
		||||
  std::string component_type() const override;
 | 
			
		||||
  const EntityBase *get_entity() const override;
 | 
			
		||||
 | 
			
		||||
  switch_::Switch *switch_;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -13,9 +13,6 @@ using namespace esphome::text_sensor;
 | 
			
		||||
 | 
			
		||||
MQTTTextSensor::MQTTTextSensor(TextSensor *sensor) : MQTTComponent(), sensor_(sensor) {}
 | 
			
		||||
void MQTTTextSensor::send_discovery(JsonObject &root, mqtt::SendDiscoveryConfig &config) {
 | 
			
		||||
  if (!this->sensor_->get_icon().empty())
 | 
			
		||||
    root["icon"] = this->sensor_->get_icon();
 | 
			
		||||
 | 
			
		||||
  config.command_topic = false;
 | 
			
		||||
}
 | 
			
		||||
void MQTTTextSensor::setup() {
 | 
			
		||||
@@ -35,9 +32,8 @@ bool MQTTTextSensor::send_initial_state() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
bool MQTTTextSensor::is_internal() { return this->sensor_->is_internal(); }
 | 
			
		||||
std::string MQTTTextSensor::component_type() const { return "sensor"; }
 | 
			
		||||
std::string MQTTTextSensor::friendly_name() const { return this->sensor_->get_name(); }
 | 
			
		||||
const EntityBase *MQTTTextSensor::get_entity() const { return this->sensor_; }
 | 
			
		||||
std::string MQTTTextSensor::unique_id() { return this->sensor_->unique_id(); }
 | 
			
		||||
 | 
			
		||||
}  // namespace mqtt
 | 
			
		||||
 
 | 
			
		||||
@@ -25,13 +25,9 @@ class MQTTTextSensor : public mqtt::MQTTComponent {
 | 
			
		||||
 | 
			
		||||
  bool send_initial_state() override;
 | 
			
		||||
 | 
			
		||||
  bool is_internal() override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  std::string component_type() const override;
 | 
			
		||||
 | 
			
		||||
  std::string friendly_name() const override;
 | 
			
		||||
 | 
			
		||||
  const EntityBase *get_entity() const override;
 | 
			
		||||
  std::string unique_id() override;
 | 
			
		||||
 | 
			
		||||
  text_sensor::TextSensor *sensor_;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,25 +6,21 @@ from esphome.components import mqtt
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_ABOVE,
 | 
			
		||||
    CONF_BELOW,
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_ICON,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_ON_VALUE,
 | 
			
		||||
    CONF_ON_VALUE_RANGE,
 | 
			
		||||
    CONF_TRIGGER_ID,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_MQTT_ID,
 | 
			
		||||
    CONF_VALUE,
 | 
			
		||||
    ICON_EMPTY,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE, coroutine_with_priority
 | 
			
		||||
from esphome.cpp_helpers import setup_entity
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@esphome/core"]
 | 
			
		||||
IS_PLATFORM_COMPONENT = True
 | 
			
		||||
 | 
			
		||||
number_ns = cg.esphome_ns.namespace("number")
 | 
			
		||||
Number = number_ns.class_("Number", cg.Nameable)
 | 
			
		||||
Number = number_ns.class_("Number", cg.EntityBase)
 | 
			
		||||
NumberPtr = Number.operator("ptr")
 | 
			
		||||
 | 
			
		||||
# Triggers
 | 
			
		||||
@@ -46,11 +42,10 @@ NumberInRangeCondition = number_ns.class_(
 | 
			
		||||
icon = cv.icon
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
NUMBER_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
NUMBER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTNumberComponent),
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(Number),
 | 
			
		||||
        cv.Optional(CONF_ICON, default=ICON_EMPTY): icon,
 | 
			
		||||
        cv.Optional(CONF_ON_VALUE): automation.validate_automation(
 | 
			
		||||
            {
 | 
			
		||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(NumberStateTrigger),
 | 
			
		||||
@@ -71,12 +66,8 @@ NUMBER_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
async def setup_number_core_(
 | 
			
		||||
    var, config, *, min_value: float, max_value: float, step: Optional[float]
 | 
			
		||||
):
 | 
			
		||||
    cg.add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        cg.add(var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
    await setup_entity(var, config)
 | 
			
		||||
 | 
			
		||||
    cg.add(var.traits.set_icon(config[CONF_ICON]))
 | 
			
		||||
    cg.add(var.traits.set_min_value(min_value))
 | 
			
		||||
    cg.add(var.traits.set_max_value(max_value))
 | 
			
		||||
    if step is not None:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
@@ -9,8 +10,8 @@ namespace number {
 | 
			
		||||
#define LOG_NUMBER(prefix, type, obj) \
 | 
			
		||||
  if ((obj) != nullptr) { \
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
 | 
			
		||||
    if (!(obj)->traits.get_icon().empty()) { \
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->traits.get_icon().c_str()); \
 | 
			
		||||
    if (!(obj)->get_icon().empty()) { \
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
 | 
			
		||||
    } \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -40,21 +41,18 @@ class NumberTraits {
 | 
			
		||||
  float get_max_value() const { return max_value_; }
 | 
			
		||||
  void set_step(float step) { step_ = step; }
 | 
			
		||||
  float get_step() const { return step_; }
 | 
			
		||||
  void set_icon(std::string icon) { icon_ = std::move(icon); }
 | 
			
		||||
  const std::string &get_icon() const { return icon_; }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  float min_value_ = NAN;
 | 
			
		||||
  float max_value_ = NAN;
 | 
			
		||||
  float step_ = NAN;
 | 
			
		||||
  std::string icon_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Base-class for all numbers.
 | 
			
		||||
 *
 | 
			
		||||
 * A number can use publish_state to send out a new value.
 | 
			
		||||
 */
 | 
			
		||||
class Number : public Nameable {
 | 
			
		||||
class Number : public EntityBase {
 | 
			
		||||
 public:
 | 
			
		||||
  float state;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,4 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
from esphome.components import binary_sensor, remote_base
 | 
			
		||||
from esphome.const import CONF_NAME
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES = ["remote_receiver"]
 | 
			
		||||
 | 
			
		||||
@@ -9,5 +7,4 @@ CONFIG_SCHEMA = remote_base.validate_binary_sensor
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    var = await remote_base.build_binary_sensor(config)
 | 
			
		||||
    cg.add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    await binary_sensor.register_binary_sensor(var, config)
 | 
			
		||||
 
 | 
			
		||||
@@ -4,24 +4,20 @@ import esphome.config_validation as cv
 | 
			
		||||
from esphome import automation
 | 
			
		||||
from esphome.components import mqtt
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_ICON,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_ON_VALUE,
 | 
			
		||||
    CONF_OPTION,
 | 
			
		||||
    CONF_TRIGGER_ID,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_MQTT_ID,
 | 
			
		||||
    ICON_EMPTY,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE, coroutine_with_priority
 | 
			
		||||
from esphome.cpp_helpers import setup_entity
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@esphome/core"]
 | 
			
		||||
IS_PLATFORM_COMPONENT = True
 | 
			
		||||
 | 
			
		||||
select_ns = cg.esphome_ns.namespace("select")
 | 
			
		||||
Select = select_ns.class_("Select", cg.Nameable)
 | 
			
		||||
Select = select_ns.class_("Select", cg.EntityBase)
 | 
			
		||||
SelectPtr = Select.operator("ptr")
 | 
			
		||||
 | 
			
		||||
# Triggers
 | 
			
		||||
@@ -35,11 +31,10 @@ SelectSetAction = select_ns.class_("SelectSetAction", automation.Action)
 | 
			
		||||
icon = cv.icon
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SELECT_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
SELECT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTSelectComponent),
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(Select),
 | 
			
		||||
        cv.Optional(CONF_ICON, default=ICON_EMPTY): icon,
 | 
			
		||||
        cv.Optional(CONF_ON_VALUE): automation.validate_automation(
 | 
			
		||||
            {
 | 
			
		||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SelectStateTrigger),
 | 
			
		||||
@@ -50,12 +45,8 @@ SELECT_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup_select_core_(var, config, *, options: List[str]):
 | 
			
		||||
    cg.add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        cg.add(var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
    await setup_entity(var, config)
 | 
			
		||||
 | 
			
		||||
    cg.add(var.traits.set_icon(config[CONF_ICON]))
 | 
			
		||||
    cg.add(var.traits.set_options(options))
 | 
			
		||||
 | 
			
		||||
    for conf in config.get(CONF_ON_VALUE, []):
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
@@ -11,8 +12,8 @@ namespace select {
 | 
			
		||||
#define LOG_SELECT(prefix, type, obj) \
 | 
			
		||||
  if ((obj) != nullptr) { \
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
 | 
			
		||||
    if (!(obj)->traits.get_icon().empty()) { \
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->traits.get_icon().c_str()); \
 | 
			
		||||
    if (!(obj)->get_icon().empty()) { \
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "%s  Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
 | 
			
		||||
    } \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -38,19 +39,16 @@ class SelectTraits {
 | 
			
		||||
 public:
 | 
			
		||||
  void set_options(std::vector<std::string> options) { this->options_ = std::move(options); }
 | 
			
		||||
  const std::vector<std::string> get_options() const { return this->options_; }
 | 
			
		||||
  void set_icon(std::string icon) { icon_ = std::move(icon); }
 | 
			
		||||
  const std::string &get_icon() const { return icon_; }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  std::vector<std::string> options_;
 | 
			
		||||
  std::string icon_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Base-class for all selects.
 | 
			
		||||
 *
 | 
			
		||||
 * A select can use publish_state to send out a new value.
 | 
			
		||||
 */
 | 
			
		||||
class Select : public Nameable {
 | 
			
		||||
class Select : public EntityBase {
 | 
			
		||||
 public:
 | 
			
		||||
  std::string state;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,13 +10,11 @@ from esphome.const import (
 | 
			
		||||
    CONF_ACCURACY_DECIMALS,
 | 
			
		||||
    CONF_ALPHA,
 | 
			
		||||
    CONF_BELOW,
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_EXPIRE_AFTER,
 | 
			
		||||
    CONF_FILTERS,
 | 
			
		||||
    CONF_FROM,
 | 
			
		||||
    CONF_ICON,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_ON_RAW_VALUE,
 | 
			
		||||
    CONF_ON_VALUE,
 | 
			
		||||
    CONF_ON_VALUE_RANGE,
 | 
			
		||||
@@ -27,7 +25,6 @@ from esphome.const import (
 | 
			
		||||
    CONF_TRIGGER_ID,
 | 
			
		||||
    CONF_UNIT_OF_MEASUREMENT,
 | 
			
		||||
    CONF_WINDOW_SIZE,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_MQTT_ID,
 | 
			
		||||
    CONF_FORCE_UPDATE,
 | 
			
		||||
    DEVICE_CLASS_EMPTY,
 | 
			
		||||
@@ -59,6 +56,7 @@ from esphome.const import (
 | 
			
		||||
    DEVICE_CLASS_VOLTAGE,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE, coroutine_with_priority
 | 
			
		||||
from esphome.cpp_helpers import setup_entity
 | 
			
		||||
from esphome.util import Registry
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@esphome/core"]
 | 
			
		||||
@@ -136,7 +134,7 @@ def validate_datapoint(value):
 | 
			
		||||
 | 
			
		||||
# Base
 | 
			
		||||
sensor_ns = cg.esphome_ns.namespace("sensor")
 | 
			
		||||
Sensor = sensor_ns.class_("Sensor", cg.Nameable)
 | 
			
		||||
Sensor = sensor_ns.class_("Sensor", cg.EntityBase)
 | 
			
		||||
SensorPtr = Sensor.operator("ptr")
 | 
			
		||||
 | 
			
		||||
# Triggers
 | 
			
		||||
@@ -180,12 +178,11 @@ validate_accuracy_decimals = cv.int_
 | 
			
		||||
validate_icon = cv.icon
 | 
			
		||||
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
 | 
			
		||||
 | 
			
		||||
SENSOR_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTSensorComponent),
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(Sensor),
 | 
			
		||||
        cv.Optional(CONF_UNIT_OF_MEASUREMENT): validate_unit_of_measurement,
 | 
			
		||||
        cv.Optional(CONF_ICON): validate_icon,
 | 
			
		||||
        cv.Optional(CONF_ACCURACY_DECIMALS): validate_accuracy_decimals,
 | 
			
		||||
        cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
 | 
			
		||||
        cv.Optional(CONF_STATE_CLASS): validate_state_class,
 | 
			
		||||
@@ -495,18 +492,14 @@ async def build_filters(config):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup_sensor_core_(var, config):
 | 
			
		||||
    cg.add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        cg.add(var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
    await setup_entity(var, config)
 | 
			
		||||
 | 
			
		||||
    if CONF_DEVICE_CLASS in config:
 | 
			
		||||
        cg.add(var.set_device_class(config[CONF_DEVICE_CLASS]))
 | 
			
		||||
    if CONF_STATE_CLASS in config:
 | 
			
		||||
        cg.add(var.set_state_class(config[CONF_STATE_CLASS]))
 | 
			
		||||
    if CONF_UNIT_OF_MEASUREMENT in config:
 | 
			
		||||
        cg.add(var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT]))
 | 
			
		||||
    if CONF_ICON in config:
 | 
			
		||||
        cg.add(var.set_icon(config[CONF_ICON]))
 | 
			
		||||
    if CONF_ACCURACY_DECIMALS in config:
 | 
			
		||||
        cg.add(var.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS]))
 | 
			
		||||
    cg.add(var.set_force_update(config[CONF_FORCE_UPDATE]))
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ std::string state_class_to_string(StateClass state_class) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Sensor::Sensor(const std::string &name) : Nameable(name), state(NAN), raw_state(NAN) {}
 | 
			
		||||
Sensor::Sensor(const std::string &name) : EntityBase(name), state(NAN), raw_state(NAN) {}
 | 
			
		||||
Sensor::Sensor() : Sensor("") {}
 | 
			
		||||
 | 
			
		||||
std::string Sensor::get_unit_of_measurement() {
 | 
			
		||||
@@ -31,14 +31,6 @@ void Sensor::set_unit_of_measurement(const std::string &unit_of_measurement) {
 | 
			
		||||
}
 | 
			
		||||
std::string Sensor::unit_of_measurement() { return ""; }
 | 
			
		||||
 | 
			
		||||
std::string Sensor::get_icon() {
 | 
			
		||||
  if (this->icon_.has_value())
 | 
			
		||||
    return *this->icon_;
 | 
			
		||||
  return this->icon();
 | 
			
		||||
}
 | 
			
		||||
void Sensor::set_icon(const std::string &icon) { this->icon_ = icon; }
 | 
			
		||||
std::string Sensor::icon() { return ""; }
 | 
			
		||||
 | 
			
		||||
int8_t Sensor::get_accuracy_decimals() {
 | 
			
		||||
  if (this->accuracy_decimals_.has_value())
 | 
			
		||||
    return *this->accuracy_decimals_;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/components/sensor/filter.h"
 | 
			
		||||
 | 
			
		||||
@@ -43,7 +44,7 @@ std::string state_class_to_string(StateClass state_class);
 | 
			
		||||
 *
 | 
			
		||||
 * A sensor has unit of measurement and can use publish_state to send out a new value with the specified accuracy.
 | 
			
		||||
 */
 | 
			
		||||
class Sensor : public Nameable {
 | 
			
		||||
class Sensor : public EntityBase {
 | 
			
		||||
 public:
 | 
			
		||||
  explicit Sensor();
 | 
			
		||||
  explicit Sensor(const std::string &name);
 | 
			
		||||
@@ -53,11 +54,6 @@ class Sensor : public Nameable {
 | 
			
		||||
  /// Manually set the unit of measurement.
 | 
			
		||||
  void set_unit_of_measurement(const std::string &unit_of_measurement);
 | 
			
		||||
 | 
			
		||||
  /// Get the icon. Uses the manual override if specified or the default value instead.
 | 
			
		||||
  std::string get_icon();
 | 
			
		||||
  /// Manually set the icon, for example "mdi:flash".
 | 
			
		||||
  void set_icon(const std::string &icon);
 | 
			
		||||
 | 
			
		||||
  /// Get the accuracy in decimals, using the manual override if set.
 | 
			
		||||
  int8_t get_accuracy_decimals();
 | 
			
		||||
  /// Manually set the accuracy in decimals.
 | 
			
		||||
@@ -157,9 +153,6 @@ class Sensor : public Nameable {
 | 
			
		||||
  /// Override this to set the default unit of measurement.
 | 
			
		||||
  virtual std::string unit_of_measurement();  // NOLINT
 | 
			
		||||
 | 
			
		||||
  /// Override this to set the default icon.
 | 
			
		||||
  virtual std::string icon();  // NOLINT
 | 
			
		||||
 | 
			
		||||
  /// Override this to set the default accuracy in decimals.
 | 
			
		||||
  virtual int8_t accuracy_decimals();  // NOLINT
 | 
			
		||||
 | 
			
		||||
@@ -178,7 +171,6 @@ class Sensor : public Nameable {
 | 
			
		||||
  Filter *filter_list_{nullptr};  ///< Store all active filters.
 | 
			
		||||
 | 
			
		||||
  optional<std::string> unit_of_measurement_;           ///< Unit of measurement override
 | 
			
		||||
  optional<std::string> icon_;                          ///< Icon override
 | 
			
		||||
  optional<int8_t> accuracy_decimals_;                  ///< Accuracy in decimals override
 | 
			
		||||
  optional<std::string> device_class_;                  ///< Device class override
 | 
			
		||||
  optional<StateClass> state_class_{STATE_CLASS_NONE};  ///< State class override
 | 
			
		||||
 
 | 
			
		||||
@@ -4,24 +4,21 @@ from esphome import automation
 | 
			
		||||
from esphome.automation import Condition, maybe_simple_id
 | 
			
		||||
from esphome.components import mqtt
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_ICON,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_INVERTED,
 | 
			
		||||
    CONF_ON_TURN_OFF,
 | 
			
		||||
    CONF_ON_TURN_ON,
 | 
			
		||||
    CONF_TRIGGER_ID,
 | 
			
		||||
    CONF_MQTT_ID,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE, coroutine_with_priority
 | 
			
		||||
from esphome.cpp_helpers import setup_entity
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@esphome/core"]
 | 
			
		||||
IS_PLATFORM_COMPONENT = True
 | 
			
		||||
 | 
			
		||||
switch_ns = cg.esphome_ns.namespace("switch_")
 | 
			
		||||
Switch = switch_ns.class_("Switch", cg.Nameable)
 | 
			
		||||
Switch = switch_ns.class_("Switch", cg.EntityBase)
 | 
			
		||||
SwitchPtr = Switch.operator("ptr")
 | 
			
		||||
 | 
			
		||||
ToggleAction = switch_ns.class_("ToggleAction", automation.Action)
 | 
			
		||||
@@ -39,10 +36,9 @@ SwitchTurnOffTrigger = switch_ns.class_(
 | 
			
		||||
 | 
			
		||||
icon = cv.icon
 | 
			
		||||
 | 
			
		||||
SWITCH_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
SWITCH_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTSwitchComponent),
 | 
			
		||||
        cv.Optional(CONF_ICON): icon,
 | 
			
		||||
        cv.Optional(CONF_INVERTED): cv.boolean,
 | 
			
		||||
        cv.Optional(CONF_ON_TURN_ON): automation.validate_automation(
 | 
			
		||||
            {
 | 
			
		||||
@@ -59,12 +55,8 @@ SWITCH_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).exte
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup_switch_core_(var, config):
 | 
			
		||||
    cg.add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        cg.add(var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
    if CONF_ICON in config:
 | 
			
		||||
        cg.add(var.set_icon(config[CONF_ICON]))
 | 
			
		||||
    await setup_entity(var, config)
 | 
			
		||||
 | 
			
		||||
    if CONF_INVERTED in config:
 | 
			
		||||
        cg.add(var.set_inverted(config[CONF_INVERTED]))
 | 
			
		||||
    for conf in config.get(CONF_ON_TURN_ON, []):
 | 
			
		||||
 
 | 
			
		||||
@@ -6,17 +6,9 @@ namespace switch_ {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "switch";
 | 
			
		||||
 | 
			
		||||
std::string Switch::icon() { return ""; }
 | 
			
		||||
Switch::Switch(const std::string &name) : Nameable(name), state(false) {}
 | 
			
		||||
Switch::Switch(const std::string &name) : EntityBase(name), state(false) {}
 | 
			
		||||
Switch::Switch() : Switch("") {}
 | 
			
		||||
 | 
			
		||||
std::string Switch::get_icon() {
 | 
			
		||||
  if (this->icon_.has_value())
 | 
			
		||||
    return *this->icon_;
 | 
			
		||||
  return this->icon();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Switch::set_icon(const std::string &icon) { this->icon_ = icon; }
 | 
			
		||||
void Switch::turn_on() {
 | 
			
		||||
  ESP_LOGD(TAG, "'%s' Turning ON.", this->get_name().c_str());
 | 
			
		||||
  this->write_state(!this->inverted_);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/preferences.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
 | 
			
		||||
@@ -26,7 +27,7 @@ namespace switch_ {
 | 
			
		||||
 * A switch is basically just a combination of a binary sensor (for reporting switch values)
 | 
			
		||||
 * and a write_state method that writes a state to the hardware.
 | 
			
		||||
 */
 | 
			
		||||
class Switch : public Nameable {
 | 
			
		||||
class Switch : public EntityBase {
 | 
			
		||||
 public:
 | 
			
		||||
  explicit Switch();
 | 
			
		||||
  explicit Switch(const std::string &name);
 | 
			
		||||
@@ -70,12 +71,6 @@ class Switch : public Nameable {
 | 
			
		||||
   */
 | 
			
		||||
  void set_inverted(bool inverted);
 | 
			
		||||
 | 
			
		||||
  /// Set the icon for this switch. "" for no icon.
 | 
			
		||||
  void set_icon(const std::string &icon);
 | 
			
		||||
 | 
			
		||||
  /// Get the icon for this switch. Using icon() if not manually set
 | 
			
		||||
  std::string get_icon();
 | 
			
		||||
 | 
			
		||||
  /** Set callback for state changes.
 | 
			
		||||
   *
 | 
			
		||||
   * @param callback The void(bool) callback.
 | 
			
		||||
@@ -104,18 +99,8 @@ class Switch : public Nameable {
 | 
			
		||||
   */
 | 
			
		||||
  virtual void write_state(bool state) = 0;
 | 
			
		||||
 | 
			
		||||
  /** Override this to set the Home Assistant icon for this switch.
 | 
			
		||||
   *
 | 
			
		||||
   * Return "" to disable this feature.
 | 
			
		||||
   *
 | 
			
		||||
   * @return The icon of this switch, for example "mdi:fan".
 | 
			
		||||
   */
 | 
			
		||||
  virtual std::string icon();  // NOLINT
 | 
			
		||||
 | 
			
		||||
  uint32_t hash_base() override;
 | 
			
		||||
 | 
			
		||||
  optional<std::string> icon_{};  ///< The icon shown here. Not set means use default from switch. Empty means no icon.
 | 
			
		||||
 | 
			
		||||
  CallbackManager<void(bool)> state_callback_{};
 | 
			
		||||
  bool inverted_{false};
 | 
			
		||||
  Deduplicator<bool> publish_dedup_;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,21 +3,18 @@ import esphome.config_validation as cv
 | 
			
		||||
from esphome import automation
 | 
			
		||||
from esphome.components import mqtt
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_FILTERS,
 | 
			
		||||
    CONF_ICON,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_ON_VALUE,
 | 
			
		||||
    CONF_ON_RAW_VALUE,
 | 
			
		||||
    CONF_TRIGGER_ID,
 | 
			
		||||
    CONF_MQTT_ID,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_STATE,
 | 
			
		||||
    CONF_FROM,
 | 
			
		||||
    CONF_TO,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE, coroutine_with_priority
 | 
			
		||||
from esphome.cpp_helpers import setup_entity
 | 
			
		||||
from esphome.util import Registry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -25,7 +22,7 @@ IS_PLATFORM_COMPONENT = True
 | 
			
		||||
 | 
			
		||||
# pylint: disable=invalid-name
 | 
			
		||||
text_sensor_ns = cg.esphome_ns.namespace("text_sensor")
 | 
			
		||||
TextSensor = text_sensor_ns.class_("TextSensor", cg.Nameable)
 | 
			
		||||
TextSensor = text_sensor_ns.class_("TextSensor", cg.EntityBase)
 | 
			
		||||
TextSensorPtr = TextSensor.operator("ptr")
 | 
			
		||||
 | 
			
		||||
TextSensorStateTrigger = text_sensor_ns.class_(
 | 
			
		||||
@@ -111,10 +108,9 @@ async def substitute_filter_to_code(config, filter_id):
 | 
			
		||||
 | 
			
		||||
icon = cv.icon
 | 
			
		||||
 | 
			
		||||
TEXT_SENSOR_SCHEMA = cv.NAMEABLE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
TEXT_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTTextSensor),
 | 
			
		||||
        cv.Optional(CONF_ICON): icon,
 | 
			
		||||
        cv.Optional(CONF_FILTERS): validate_filters,
 | 
			
		||||
        cv.Optional(CONF_ON_VALUE): automation.validate_automation(
 | 
			
		||||
            {
 | 
			
		||||
@@ -137,12 +133,7 @@ async def build_filters(config):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup_text_sensor_core_(var, config):
 | 
			
		||||
    cg.add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    cg.add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        cg.add(var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
    if CONF_ICON in config:
 | 
			
		||||
        cg.add(var.set_icon(config[CONF_ICON]))
 | 
			
		||||
    await setup_entity(var, config)
 | 
			
		||||
 | 
			
		||||
    if config.get(CONF_FILTERS):  # must exist and not be empty
 | 
			
		||||
        filters = await build_filters(config[CONF_FILTERS])
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ namespace text_sensor {
 | 
			
		||||
static const char *const TAG = "text_sensor";
 | 
			
		||||
 | 
			
		||||
TextSensor::TextSensor() : TextSensor("") {}
 | 
			
		||||
TextSensor::TextSensor(const std::string &name) : Nameable(name) {}
 | 
			
		||||
TextSensor::TextSensor(const std::string &name) : EntityBase(name) {}
 | 
			
		||||
 | 
			
		||||
void TextSensor::publish_state(const std::string &state) {
 | 
			
		||||
  this->raw_state = state;
 | 
			
		||||
@@ -68,14 +68,6 @@ void TextSensor::internal_send_state_to_frontend(const std::string &state) {
 | 
			
		||||
  this->callback_.call(state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TextSensor::set_icon(const std::string &icon) { this->icon_ = icon; }
 | 
			
		||||
std::string TextSensor::get_icon() {
 | 
			
		||||
  if (this->icon_.has_value())
 | 
			
		||||
    return *this->icon_;
 | 
			
		||||
  return this->icon();
 | 
			
		||||
}
 | 
			
		||||
std::string TextSensor::icon() { return ""; }
 | 
			
		||||
 | 
			
		||||
std::string TextSensor::unique_id() { return ""; }
 | 
			
		||||
bool TextSensor::has_state() { return this->has_state_; }
 | 
			
		||||
uint32_t TextSensor::hash_base() { return 334300109UL; }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/components/text_sensor/filter.h"
 | 
			
		||||
 | 
			
		||||
@@ -18,7 +19,7 @@ namespace text_sensor {
 | 
			
		||||
    } \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
class TextSensor : public Nameable {
 | 
			
		||||
class TextSensor : public EntityBase {
 | 
			
		||||
 public:
 | 
			
		||||
  explicit TextSensor();
 | 
			
		||||
  explicit TextSensor(const std::string &name);
 | 
			
		||||
@@ -30,8 +31,6 @@ class TextSensor : public Nameable {
 | 
			
		||||
 | 
			
		||||
  void publish_state(const std::string &state);
 | 
			
		||||
 | 
			
		||||
  void set_icon(const std::string &icon);
 | 
			
		||||
 | 
			
		||||
  /// Add a filter to the filter chain. Will be appended to the back.
 | 
			
		||||
  void add_filter(Filter *filter);
 | 
			
		||||
 | 
			
		||||
@@ -53,10 +52,6 @@ class TextSensor : public Nameable {
 | 
			
		||||
 | 
			
		||||
  // ========== INTERNAL METHODS ==========
 | 
			
		||||
  // (In most use cases you won't need these)
 | 
			
		||||
  std::string get_icon();
 | 
			
		||||
 | 
			
		||||
  virtual std::string icon();
 | 
			
		||||
 | 
			
		||||
  virtual std::string unique_id();
 | 
			
		||||
 | 
			
		||||
  bool has_state();
 | 
			
		||||
@@ -71,7 +66,6 @@ class TextSensor : public Nameable {
 | 
			
		||||
 | 
			
		||||
  Filter *filter_list_{nullptr};  ///< Store all active filters.
 | 
			
		||||
 | 
			
		||||
  optional<std::string> icon_;
 | 
			
		||||
  bool has_state_{false};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,14 @@ import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.components import sensor, time
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_ICON,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_TIME_ID,
 | 
			
		||||
    DEVICE_CLASS_ENERGY,
 | 
			
		||||
    CONF_METHOD,
 | 
			
		||||
    STATE_CLASS_TOTAL_INCREASING,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core.entity_helpers import inherit_property_from
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES = ["time"]
 | 
			
		||||
 | 
			
		||||
@@ -45,6 +47,18 @@ CONFIG_SCHEMA = (
 | 
			
		||||
    .extend(cv.COMPONENT_SCHEMA)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
FINAL_VALIDATE_SCHEMA = cv.All(
 | 
			
		||||
    cv.Schema(
 | 
			
		||||
        {
 | 
			
		||||
            cv.Required(CONF_ID): cv.use_id(TotalDailyEnergy),
 | 
			
		||||
            cv.Optional(CONF_ICON): cv.icon,
 | 
			
		||||
            cv.Required(CONF_POWER_ID): cv.use_id(sensor.Sensor),
 | 
			
		||||
        },
 | 
			
		||||
        extra=cv.ALLOW_EXTRA,
 | 
			
		||||
    ),
 | 
			
		||||
    inherit_property_from(CONF_ICON, CONF_POWER_ID),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,6 @@ class TotalDailyEnergy : public sensor::Sensor, public Component {
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
  float get_setup_priority() const override { return setup_priority::DATA; }
 | 
			
		||||
  std::string unit_of_measurement() override { return this->parent_->get_unit_of_measurement() + "h"; }
 | 
			
		||||
  std::string icon() override { return this->parent_->get_icon(); }
 | 
			
		||||
  int8_t accuracy_decimals() override { return this->parent_->get_accuracy_decimals() + 2; }
 | 
			
		||||
  void loop() override;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -224,7 +224,7 @@ class TSL2591Component : public PollingComponent, public i2c::I2CDevice {
 | 
			
		||||
  float get_setup_priority() const override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  const char *name_;  // TODO: extend esphome::Nameable
 | 
			
		||||
  const char *name_;
 | 
			
		||||
  sensor::Sensor *full_spectrum_sensor_;
 | 
			
		||||
  sensor::Sensor *infrared_sensor_;
 | 
			
		||||
  sensor::Sensor *visible_sensor_;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
#include "web_server.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/util.h"
 | 
			
		||||
#include "esphome/components/json/json_util.h"
 | 
			
		||||
#include "esphome/components/network/util.h"
 | 
			
		||||
@@ -28,8 +29,8 @@ namespace web_server {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "web_server";
 | 
			
		||||
 | 
			
		||||
void write_row(AsyncResponseStream *stream, Nameable *obj, const std::string &klass, const std::string &action,
 | 
			
		||||
               const std::function<void(AsyncResponseStream &stream, Nameable *obj)> &action_func = nullptr) {
 | 
			
		||||
void write_row(AsyncResponseStream *stream, EntityBase *obj, const std::string &klass, const std::string &action,
 | 
			
		||||
               const std::function<void(AsyncResponseStream &stream, EntityBase *obj)> &action_func = nullptr) {
 | 
			
		||||
  if (obj->is_internal())
 | 
			
		||||
    return;
 | 
			
		||||
  stream->print("<tr class=\"");
 | 
			
		||||
@@ -225,7 +226,7 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) {
 | 
			
		||||
 | 
			
		||||
#ifdef USE_SELECT
 | 
			
		||||
  for (auto *obj : App.get_selects())
 | 
			
		||||
    write_row(stream, obj, "select", "", [](AsyncResponseStream &stream, Nameable *obj) {
 | 
			
		||||
    write_row(stream, obj, "select", "", [](AsyncResponseStream &stream, EntityBase *obj) {
 | 
			
		||||
      select::Select *select = (select::Select *) obj;
 | 
			
		||||
      stream.print("<select>");
 | 
			
		||||
      stream.print("<option></option>");
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ from esphome.const import (
 | 
			
		||||
    CONF_COMMAND_TOPIC,
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_DISCOVERY,
 | 
			
		||||
    CONF_ICON,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
@@ -1476,7 +1477,7 @@ class OnlyWith(Optional):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _nameable_validator(config):
 | 
			
		||||
def _entity_base_validator(config):
 | 
			
		||||
    if CONF_NAME not in config and CONF_ID not in config:
 | 
			
		||||
        raise Invalid("At least one of 'id:' or 'name:' is required!")
 | 
			
		||||
    if CONF_NAME not in config:
 | 
			
		||||
@@ -1587,15 +1588,16 @@ MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend(
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
NAMEABLE_SCHEMA = Schema(
 | 
			
		||||
ENTITY_BASE_SCHEMA = Schema(
 | 
			
		||||
    {
 | 
			
		||||
        Optional(CONF_NAME): string,
 | 
			
		||||
        Optional(CONF_INTERNAL): boolean,
 | 
			
		||||
        Optional(CONF_DISABLED_BY_DEFAULT, default=False): boolean,
 | 
			
		||||
        Optional(CONF_ICON): icon,
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
NAMEABLE_SCHEMA.add_extra(_nameable_validator)
 | 
			
		||||
ENTITY_BASE_SCHEMA.add_extra(_entity_base_validator)
 | 
			
		||||
 | 
			
		||||
COMPONENT_SCHEMA = Schema({Optional(CONF_SETUP_PRIORITY): float_})
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -177,26 +177,6 @@ void PollingComponent::call_setup() {
 | 
			
		||||
uint32_t PollingComponent::get_update_interval() const { return this->update_interval_; }
 | 
			
		||||
void PollingComponent::set_update_interval(uint32_t update_interval) { this->update_interval_ = update_interval; }
 | 
			
		||||
 | 
			
		||||
const std::string &Nameable::get_name() const { return this->name_; }
 | 
			
		||||
void Nameable::set_name(const std::string &name) {
 | 
			
		||||
  this->name_ = name;
 | 
			
		||||
  this->calc_object_id_();
 | 
			
		||||
}
 | 
			
		||||
Nameable::Nameable(std::string name) : name_(std::move(name)) { this->calc_object_id_(); }
 | 
			
		||||
 | 
			
		||||
const std::string &Nameable::get_object_id() { return this->object_id_; }
 | 
			
		||||
bool Nameable::is_internal() const { return this->internal_; }
 | 
			
		||||
void Nameable::set_internal(bool internal) { this->internal_ = internal; }
 | 
			
		||||
void Nameable::calc_object_id_() {
 | 
			
		||||
  this->object_id_ = sanitize_string_allowlist(to_lowercase_underscore(this->name_), HOSTNAME_CHARACTER_ALLOWLIST);
 | 
			
		||||
  // FNV-1 hash
 | 
			
		||||
  this->object_id_hash_ = fnv1_hash(this->object_id_);
 | 
			
		||||
}
 | 
			
		||||
uint32_t Nameable::get_object_id_hash() { return this->object_id_hash_; }
 | 
			
		||||
 | 
			
		||||
bool Nameable::is_disabled_by_default() const { return this->disabled_by_default_; }
 | 
			
		||||
void Nameable::set_disabled_by_default(bool disabled_by_default) { this->disabled_by_default_ = disabled_by_default; }
 | 
			
		||||
 | 
			
		||||
WarnIfComponentBlockingGuard::WarnIfComponentBlockingGuard(Component *component)
 | 
			
		||||
    : started_(millis()), component_(component) {}
 | 
			
		||||
WarnIfComponentBlockingGuard::~WarnIfComponentBlockingGuard() {
 | 
			
		||||
 
 | 
			
		||||
@@ -264,40 +264,6 @@ class PollingComponent : public Component {
 | 
			
		||||
  uint32_t update_interval_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Helper class that enables naming of objects so that it doesn't have to be re-implement every time.
 | 
			
		||||
class Nameable {
 | 
			
		||||
 public:
 | 
			
		||||
  Nameable() : Nameable("") {}
 | 
			
		||||
  explicit Nameable(std::string name);
 | 
			
		||||
  const std::string &get_name() const;
 | 
			
		||||
  void set_name(const std::string &name);
 | 
			
		||||
  /// Get the sanitized name of this nameable as an ID. Caching it internally.
 | 
			
		||||
  const std::string &get_object_id();
 | 
			
		||||
  uint32_t get_object_id_hash();
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  virtual uint32_t hash_base() = 0;
 | 
			
		||||
 | 
			
		||||
  void calc_object_id_();
 | 
			
		||||
 | 
			
		||||
  std::string name_;
 | 
			
		||||
  std::string object_id_;
 | 
			
		||||
  uint32_t object_id_hash_;
 | 
			
		||||
  bool internal_{false};
 | 
			
		||||
  bool disabled_by_default_{false};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class WarnIfComponentBlockingGuard {
 | 
			
		||||
 public:
 | 
			
		||||
  WarnIfComponentBlockingGuard(Component *component);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								esphome/core/entity_base.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								esphome/core/entity_base.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
#include "esphome/core/entity_base.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "entity_base";
 | 
			
		||||
 | 
			
		||||
EntityBase::EntityBase(std::string name) : name_(std::move(name)) { this->calc_object_id_(); }
 | 
			
		||||
 | 
			
		||||
// Entity Name
 | 
			
		||||
const std::string &EntityBase::get_name() const { return this->name_; }
 | 
			
		||||
void EntityBase::set_name(const std::string &name) {
 | 
			
		||||
  this->name_ = name;
 | 
			
		||||
  this->calc_object_id_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Entity Internal
 | 
			
		||||
bool EntityBase::is_internal() const { return this->internal_; }
 | 
			
		||||
void EntityBase::set_internal(bool internal) { this->internal_ = internal; }
 | 
			
		||||
 | 
			
		||||
// Entity Disabled by Default
 | 
			
		||||
bool EntityBase::is_disabled_by_default() const { return this->disabled_by_default_; }
 | 
			
		||||
void EntityBase::set_disabled_by_default(bool disabled_by_default) { this->disabled_by_default_ = disabled_by_default; }
 | 
			
		||||
 | 
			
		||||
// Entity Icon
 | 
			
		||||
const std::string &EntityBase::get_icon() const { return this->icon_; }
 | 
			
		||||
void EntityBase::set_icon(const std::string &name) { this->icon_ = name; }
 | 
			
		||||
 | 
			
		||||
// Entity Object ID
 | 
			
		||||
const std::string &EntityBase::get_object_id() { return this->object_id_; }
 | 
			
		||||
 | 
			
		||||
// Calculate Object ID Hash from Entity Name
 | 
			
		||||
void EntityBase::calc_object_id_() {
 | 
			
		||||
  this->object_id_ = sanitize_string_allowlist(to_lowercase_underscore(this->name_), HOSTNAME_CHARACTER_ALLOWLIST);
 | 
			
		||||
  // FNV-1 hash
 | 
			
		||||
  this->object_id_hash_ = fnv1_hash(this->object_id_);
 | 
			
		||||
}
 | 
			
		||||
uint32_t EntityBase::get_object_id_hash() { return this->object_id_hash_; }
 | 
			
		||||
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
							
								
								
									
										50
									
								
								esphome/core/entity_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								esphome/core/entity_base.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
 | 
			
		||||
// The generic Entity base class that provides an interface common to all Entities.
 | 
			
		||||
class EntityBase {
 | 
			
		||||
 public:
 | 
			
		||||
  EntityBase() : EntityBase("") {}
 | 
			
		||||
  explicit EntityBase(std::string name);
 | 
			
		||||
 | 
			
		||||
  // Get/set the name of this Entity
 | 
			
		||||
  const std::string &get_name() const;
 | 
			
		||||
  void set_name(const std::string &name);
 | 
			
		||||
 | 
			
		||||
  // Get the sanitized name of this Entity as an ID. Caching it internally.
 | 
			
		||||
  const std::string &get_object_id();
 | 
			
		||||
 | 
			
		||||
  // Get the unique Object ID of this Entity
 | 
			
		||||
  uint32_t get_object_id_hash();
 | 
			
		||||
 | 
			
		||||
  // Get/set whether this Entity should be hidden from outside of 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 this entity's icon
 | 
			
		||||
  const std::string &get_icon() const;
 | 
			
		||||
  void set_icon(const std::string &name);
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  virtual uint32_t hash_base() = 0;
 | 
			
		||||
  void calc_object_id_();
 | 
			
		||||
 | 
			
		||||
  std::string name_;
 | 
			
		||||
  std::string object_id_;
 | 
			
		||||
  std::string icon_;
 | 
			
		||||
  uint32_t object_id_hash_;
 | 
			
		||||
  bool internal_{false};
 | 
			
		||||
  bool disabled_by_default_{false};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
							
								
								
									
										32
									
								
								esphome/core/entity_helpers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								esphome/core/entity_helpers.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
import esphome.final_validate as fv
 | 
			
		||||
 | 
			
		||||
from esphome.const import CONF_ID
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def inherit_property_from(property_to_inherit, parent_id_property):
 | 
			
		||||
    """Validator that inherits a configuration property from another entity, for use with FINAL_VALIDATE_SCHEMA.
 | 
			
		||||
 | 
			
		||||
    If a property is already set, it will not be inherited.
 | 
			
		||||
 | 
			
		||||
    Keyword arguments:
 | 
			
		||||
    property_to_inherit -- the name of the property to inherit, e.g. CONF_ICON
 | 
			
		||||
    parent_id_property -- the name of the property that holds the ID of the parent, e.g. CONF_POWER_ID
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def inherit_property(config):
 | 
			
		||||
        if property_to_inherit not in config:
 | 
			
		||||
            fconf = fv.full_config.get()
 | 
			
		||||
 | 
			
		||||
            # Get config for the parent entity
 | 
			
		||||
            path = fconf.get_path_for_id(config[parent_id_property])[:-1]
 | 
			
		||||
            parent_config = fconf.get_config_for_path(path)
 | 
			
		||||
 | 
			
		||||
            # If parent sensor has the property set, inherit it
 | 
			
		||||
            if property_to_inherit in parent_config:
 | 
			
		||||
                path = fconf.get_path_for_id(config[CONF_ID])[:-1]
 | 
			
		||||
                this_config = fconf.get_config_for_path(path)
 | 
			
		||||
                this_config[property_to_inherit] = parent_config[property_to_inherit]
 | 
			
		||||
 | 
			
		||||
        return config
 | 
			
		||||
 | 
			
		||||
    return inherit_property
 | 
			
		||||
@@ -1,6 +1,10 @@
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_DISABLED_BY_DEFAULT,
 | 
			
		||||
    CONF_ICON,
 | 
			
		||||
    CONF_INTERNAL,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_SETUP_PRIORITY,
 | 
			
		||||
    CONF_UPDATE_INTERVAL,
 | 
			
		||||
    CONF_TYPE_ID,
 | 
			
		||||
@@ -90,6 +94,16 @@ async def register_parented(var, value):
 | 
			
		||||
    add(var.set_parent(paren))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup_entity(var, config):
 | 
			
		||||
    """Set up generic properties of an Entity"""
 | 
			
		||||
    add(var.set_name(config[CONF_NAME]))
 | 
			
		||||
    add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
 | 
			
		||||
    if CONF_INTERNAL in config:
 | 
			
		||||
        add(var.set_internal(config[CONF_INTERNAL]))
 | 
			
		||||
    if CONF_ICON in config:
 | 
			
		||||
        add(var.set_icon(config[CONF_ICON]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def extract_registry_entry_config(registry, full_config):
 | 
			
		||||
    # type: (Registry, ConfigType) -> RegistryEntry
 | 
			
		||||
    key, config = next((k, v) for k, v in full_config.items() if k in registry)
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ const_char_ptr = global_ns.namespace("const char *")
 | 
			
		||||
NAN = global_ns.namespace("NAN")
 | 
			
		||||
esphome_ns = global_ns  # using namespace esphome;
 | 
			
		||||
App = esphome_ns.App
 | 
			
		||||
Nameable = esphome_ns.class_("Nameable")
 | 
			
		||||
EntityBase = esphome_ns.class_("EntityBase")
 | 
			
		||||
Component = esphome_ns.class_("Component")
 | 
			
		||||
ComponentPtr = Component.operator("ptr")
 | 
			
		||||
PollingComponent = esphome_ns.class_("PollingComponent", Component)
 | 
			
		||||
 
 | 
			
		||||
@@ -1708,6 +1708,7 @@ climate:
 | 
			
		||||
    name: Anova cooker
 | 
			
		||||
    ble_client_id: ble_blah
 | 
			
		||||
    unit_of_measurement: c
 | 
			
		||||
    icon: mdi:stove
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - id: climate_custom
 | 
			
		||||
@@ -1986,6 +1987,7 @@ fan:
 | 
			
		||||
    direction_output: gpio_26
 | 
			
		||||
  - platform: speed
 | 
			
		||||
    id: fan_speed
 | 
			
		||||
    icon: mdi:weather-windy
 | 
			
		||||
    output: pca_6
 | 
			
		||||
    speed_count: 10
 | 
			
		||||
    name: 'Living Room Fan 2'
 | 
			
		||||
@@ -2287,6 +2289,7 @@ cover:
 | 
			
		||||
    name: 'Test AM43'
 | 
			
		||||
    id: am43_test
 | 
			
		||||
    ble_client_id: ble_foo
 | 
			
		||||
    icon: mdi:blinds
 | 
			
		||||
 | 
			
		||||
debug:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,7 @@ binary_sensor:
 | 
			
		||||
  - platform: gpio
 | 
			
		||||
    pin: GPIO0
 | 
			
		||||
    id: io0_button
 | 
			
		||||
    icon: mdi:gesture-tap-button
 | 
			
		||||
 | 
			
		||||
tlc5947:
 | 
			
		||||
  data_pin: GPIO12
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ from esphome import codegen as cg
 | 
			
		||||
        "NAN",
 | 
			
		||||
        "esphome_ns",
 | 
			
		||||
        "App",
 | 
			
		||||
        "Nameable",
 | 
			
		||||
        "EntityBase",
 | 
			
		||||
        "Component",
 | 
			
		||||
        "ComponentPtr",
 | 
			
		||||
        # from cpp_types
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user