mirror of
https://github.com/esphome/esphome.git
synced 2026-02-18 15:35:59 -07:00
[mqtt] Reduce heap allocations in topic string building (#13072)
This commit is contained in:
@@ -77,6 +77,13 @@ CONF_DISCOVER_IP = "discover_ip"
|
||||
CONF_IDF_SEND_ASYNC = "idf_send_async"
|
||||
CONF_WAIT_FOR_CONNECTION = "wait_for_connection"
|
||||
|
||||
# Max lengths for stack-based topic building.
|
||||
# These values are used in cv.Length() validators below to ensure the C++ code
|
||||
# in mqtt_component.cpp can safely use fixed-size stack buffers without overflow.
|
||||
# If you change these, update the corresponding constants in mqtt_component.cpp.
|
||||
TOPIC_PREFIX_MAX_LEN = 64 # Default is device name, typically short
|
||||
DISCOVERY_PREFIX_MAX_LEN = 64 # Default is "homeassistant" (13 chars)
|
||||
|
||||
|
||||
def validate_message_just_topic(value):
|
||||
value = cv.publish_topic(value)
|
||||
@@ -253,9 +260,9 @@ CONFIG_SCHEMA = cv.All(
|
||||
),
|
||||
cv.Optional(CONF_DISCOVERY_RETAIN, default=True): cv.boolean,
|
||||
cv.Optional(CONF_DISCOVER_IP, default=True): cv.boolean,
|
||||
cv.Optional(
|
||||
CONF_DISCOVERY_PREFIX, default="homeassistant"
|
||||
): cv.publish_topic,
|
||||
cv.Optional(CONF_DISCOVERY_PREFIX, default="homeassistant"): cv.All(
|
||||
cv.publish_topic, cv.Length(max=DISCOVERY_PREFIX_MAX_LEN)
|
||||
),
|
||||
cv.Optional(CONF_DISCOVERY_UNIQUE_ID_GENERATOR, default="legacy"): cv.enum(
|
||||
MQTT_DISCOVERY_UNIQUE_ID_GENERATOR_OPTIONS
|
||||
),
|
||||
@@ -266,7 +273,9 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_BIRTH_MESSAGE): MQTT_MESSAGE_SCHEMA,
|
||||
cv.Optional(CONF_WILL_MESSAGE): MQTT_MESSAGE_SCHEMA,
|
||||
cv.Optional(CONF_SHUTDOWN_MESSAGE): MQTT_MESSAGE_SCHEMA,
|
||||
cv.Optional(CONF_TOPIC_PREFIX, default=lambda: CORE.name): cv.publish_topic,
|
||||
cv.Optional(CONF_TOPIC_PREFIX, default=lambda: CORE.name): cv.All(
|
||||
cv.publish_topic, cv.Length(max=TOPIC_PREFIX_MAX_LEN)
|
||||
),
|
||||
cv.Optional(CONF_LOG_TOPIC): cv.Any(
|
||||
None,
|
||||
MQTT_MESSAGE_BASE.extend(
|
||||
|
||||
@@ -79,7 +79,7 @@ void MQTTAlarmControlPanelComponent::send_discovery(JsonObject root, mqtt::SendD
|
||||
root[MQTT_CODE_ARM_REQUIRED] = this->alarm_control_panel_->get_requires_code_to_arm();
|
||||
}
|
||||
|
||||
std::string MQTTAlarmControlPanelComponent::component_type() const { return "alarm_control_panel"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTAlarmControlPanelComponent, "alarm_control_panel")
|
||||
const EntityBase *MQTTAlarmControlPanelComponent::get_entity() const { return this->alarm_control_panel_; }
|
||||
|
||||
bool MQTTAlarmControlPanelComponent::send_initial_state() { return this->publish_state(); }
|
||||
|
||||
@@ -25,7 +25,7 @@ class MQTTAlarmControlPanelComponent : public mqtt::MQTTComponent {
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
alarm_control_panel::AlarmControlPanel *alarm_control_panel_;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace esphome::mqtt {
|
||||
|
||||
static const char *const TAG = "mqtt.binary_sensor";
|
||||
|
||||
std::string MQTTBinarySensorComponent::component_type() const { return "binary_sensor"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTBinarySensorComponent, "binary_sensor")
|
||||
const EntityBase *MQTTBinarySensorComponent::get_entity() const { return this->binary_sensor_; }
|
||||
|
||||
void MQTTBinarySensorComponent::setup() {
|
||||
|
||||
@@ -29,7 +29,7 @@ class MQTTBinarySensorComponent : public mqtt::MQTTComponent {
|
||||
bool publish_state(bool state);
|
||||
|
||||
protected:
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
binary_sensor::BinarySensor *binary_sensor_;
|
||||
|
||||
@@ -39,7 +39,7 @@ void MQTTButtonComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCon
|
||||
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
|
||||
}
|
||||
|
||||
std::string MQTTButtonComponent::component_type() const { return "button"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTButtonComponent, "button")
|
||||
const EntityBase *MQTTButtonComponent::get_entity() const { return this->button_; }
|
||||
|
||||
} // namespace esphome::mqtt
|
||||
|
||||
@@ -26,7 +26,7 @@ class MQTTButtonComponent : public mqtt::MQTTComponent {
|
||||
|
||||
protected:
|
||||
/// "button" component type.
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
button::Button *button_;
|
||||
|
||||
@@ -254,7 +254,7 @@ void MQTTClimateComponent::setup() {
|
||||
}
|
||||
MQTTClimateComponent::MQTTClimateComponent(Climate *device) : device_(device) {}
|
||||
bool MQTTClimateComponent::send_initial_state() { return this->publish_state_(); }
|
||||
std::string MQTTClimateComponent::component_type() const { return "climate"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTClimateComponent, "climate")
|
||||
const EntityBase *MQTTClimateComponent::get_entity() const { return this->device_; }
|
||||
|
||||
bool MQTTClimateComponent::publish_state_() {
|
||||
|
||||
@@ -15,7 +15,7 @@ class MQTTClimateComponent : public mqtt::MQTTComponent {
|
||||
MQTTClimateComponent(climate::Climate *device);
|
||||
void send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) override;
|
||||
bool send_initial_state() override;
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
void setup() override;
|
||||
|
||||
MQTT_COMPONENT_CUSTOM_TOPIC(current_temperature, state)
|
||||
|
||||
@@ -13,6 +13,34 @@ namespace esphome::mqtt {
|
||||
|
||||
static const char *const TAG = "mqtt.component";
|
||||
|
||||
// Helper functions for building topic strings on stack
|
||||
inline char *append_str(char *p, const char *s, size_t len) {
|
||||
memcpy(p, s, len);
|
||||
return p + len;
|
||||
}
|
||||
|
||||
inline char *append_char(char *p, char c) {
|
||||
*p = c;
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
// Max lengths for stack-based topic building.
|
||||
// These limits are enforced at Python config validation time in mqtt/__init__.py
|
||||
// using cv.Length() validators for topic_prefix and discovery_prefix.
|
||||
// MQTT_COMPONENT_TYPE_MAX_LEN and MQTT_SUFFIX_MAX_LEN are defined in mqtt_component.h.
|
||||
// ESPHOME_DEVICE_NAME_MAX_LEN and OBJECT_ID_MAX_LEN are defined in entity_base.h.
|
||||
// This ensures the stack buffers below are always large enough.
|
||||
static constexpr size_t TOPIC_PREFIX_MAX_LEN = 64; // Validated in Python: cv.Length(max=64)
|
||||
static constexpr size_t DISCOVERY_PREFIX_MAX_LEN = 64; // Validated in Python: cv.Length(max=64)
|
||||
|
||||
// Stack buffer sizes - safe because all inputs are length-validated at config time
|
||||
// Format: prefix + "/" + type + "/" + object_id + "/" + suffix + null
|
||||
static constexpr size_t DEFAULT_TOPIC_MAX_LEN =
|
||||
TOPIC_PREFIX_MAX_LEN + 1 + MQTT_COMPONENT_TYPE_MAX_LEN + 1 + OBJECT_ID_MAX_LEN + 1 + MQTT_SUFFIX_MAX_LEN + 1;
|
||||
// Format: prefix + "/" + type + "/" + name + "/" + object_id + "/config" + null
|
||||
static constexpr size_t DISCOVERY_TOPIC_MAX_LEN = DISCOVERY_PREFIX_MAX_LEN + 1 + MQTT_COMPONENT_TYPE_MAX_LEN + 1 +
|
||||
ESPHOME_DEVICE_NAME_MAX_LEN + 1 + OBJECT_ID_MAX_LEN + 7 + 1;
|
||||
|
||||
void MQTTComponent::set_qos(uint8_t qos) { this->qos_ = qos; }
|
||||
|
||||
void MQTTComponent::set_subscribe_qos(uint8_t qos) { this->subscribe_qos_ = qos; }
|
||||
@@ -21,8 +49,23 @@ void MQTTComponent::set_retain(bool retain) { this->retain_ = retain; }
|
||||
|
||||
std::string MQTTComponent::get_discovery_topic_(const MQTTDiscoveryInfo &discovery_info) const {
|
||||
std::string sanitized_name = str_sanitize(App.get_name());
|
||||
return discovery_info.prefix + "/" + this->component_type() + "/" + sanitized_name + "/" +
|
||||
this->get_default_object_id_() + "/config";
|
||||
const char *comp_type = this->component_type();
|
||||
char object_id_buf[OBJECT_ID_MAX_LEN];
|
||||
StringRef object_id = this->get_default_object_id_to_(object_id_buf);
|
||||
|
||||
char buf[DISCOVERY_TOPIC_MAX_LEN];
|
||||
char *p = buf;
|
||||
|
||||
p = append_str(p, discovery_info.prefix.data(), discovery_info.prefix.size());
|
||||
p = append_char(p, '/');
|
||||
p = append_str(p, comp_type, strlen(comp_type));
|
||||
p = append_char(p, '/');
|
||||
p = append_str(p, sanitized_name.data(), sanitized_name.size());
|
||||
p = append_char(p, '/');
|
||||
p = append_str(p, object_id.c_str(), object_id.size());
|
||||
p = append_str(p, "/config", 7);
|
||||
|
||||
return std::string(buf, p - buf);
|
||||
}
|
||||
|
||||
std::string MQTTComponent::get_default_topic_for_(const std::string &suffix) const {
|
||||
@@ -32,7 +75,22 @@ std::string MQTTComponent::get_default_topic_for_(const std::string &suffix) con
|
||||
return "";
|
||||
}
|
||||
|
||||
return topic_prefix + "/" + this->component_type() + "/" + this->get_default_object_id_() + "/" + suffix;
|
||||
const char *comp_type = this->component_type();
|
||||
char object_id_buf[OBJECT_ID_MAX_LEN];
|
||||
StringRef object_id = this->get_default_object_id_to_(object_id_buf);
|
||||
|
||||
char buf[DEFAULT_TOPIC_MAX_LEN];
|
||||
char *p = buf;
|
||||
|
||||
p = append_str(p, topic_prefix.data(), topic_prefix.size());
|
||||
p = append_char(p, '/');
|
||||
p = append_str(p, comp_type, strlen(comp_type));
|
||||
p = append_char(p, '/');
|
||||
p = append_str(p, object_id.c_str(), object_id.size());
|
||||
p = append_char(p, '/');
|
||||
p = append_str(p, suffix.data(), suffix.size());
|
||||
|
||||
return std::string(buf, p - buf);
|
||||
}
|
||||
|
||||
std::string MQTTComponent::get_state_topic_() const {
|
||||
@@ -123,6 +181,8 @@ bool MQTTComponent::send_discovery_() {
|
||||
}
|
||||
|
||||
const MQTTDiscoveryInfo &discovery_info = global_mqtt_client->get_discovery_info();
|
||||
char object_id_buf[OBJECT_ID_MAX_LEN];
|
||||
StringRef object_id = this->get_default_object_id_to_(object_id_buf);
|
||||
if (discovery_info.unique_id_generator == MQTT_MAC_ADDRESS_UNIQUE_ID_GENERATOR) {
|
||||
char friendly_name_hash[9];
|
||||
sprintf(friendly_name_hash, "%08" PRIx32, fnv1_hash(this->friendly_name_()));
|
||||
@@ -131,12 +191,12 @@ bool MQTTComponent::send_discovery_() {
|
||||
} else {
|
||||
// default to almost-unique ID. It's a hack but the only way to get that
|
||||
// gorgeous device registry view.
|
||||
root[MQTT_UNIQUE_ID] = "ESP" + this->component_type() + this->get_default_object_id_();
|
||||
root[MQTT_UNIQUE_ID] = "ESP" + std::string(this->component_type()) + object_id.c_str();
|
||||
}
|
||||
|
||||
const std::string &node_name = App.get_name();
|
||||
if (discovery_info.object_id_generator == MQTT_DEVICE_NAME_OBJECT_ID_GENERATOR)
|
||||
root[MQTT_OBJECT_ID] = node_name + "_" + this->get_default_object_id_();
|
||||
root[MQTT_OBJECT_ID] = node_name + "_" + object_id.c_str();
|
||||
|
||||
const std::string &friendly_name_ref = App.get_friendly_name();
|
||||
const std::string &node_friendly_name = friendly_name_ref.empty() ? node_name : friendly_name_ref;
|
||||
@@ -194,10 +254,6 @@ bool MQTTComponent::is_discovery_enabled() const {
|
||||
return this->discovery_enabled_ && global_mqtt_client->is_discovery_enabled();
|
||||
}
|
||||
|
||||
std::string MQTTComponent::get_default_object_id_() const {
|
||||
return str_sanitize(str_snake_case(this->friendly_name_()));
|
||||
}
|
||||
|
||||
void MQTTComponent::subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos) {
|
||||
global_mqtt_client->subscribe(topic, std::move(callback), qos);
|
||||
}
|
||||
@@ -280,6 +336,9 @@ bool MQTTComponent::is_connected_() const { return global_mqtt_client->is_connec
|
||||
|
||||
// Pull these properties from EntityBase if not overridden
|
||||
std::string MQTTComponent::friendly_name_() const { return this->get_entity()->get_name(); }
|
||||
StringRef MQTTComponent::get_default_object_id_to_(std::span<char, OBJECT_ID_MAX_LEN> buf) const {
|
||||
return this->get_entity()->get_object_id_to(buf);
|
||||
}
|
||||
StringRef MQTTComponent::get_icon_ref_() const { return this->get_entity()->get_icon_ref(); }
|
||||
bool MQTTComponent::is_disabled_by_default_() const { return this->get_entity()->is_disabled_by_default(); }
|
||||
bool MQTTComponent::is_internal() {
|
||||
|
||||
@@ -19,6 +19,10 @@ struct SendDiscoveryConfig {
|
||||
bool command_topic{true}; ///< If the command topic should be included. Default to true.
|
||||
};
|
||||
|
||||
// Max lengths for stack-based topic building (must match mqtt_component.cpp)
|
||||
static constexpr size_t MQTT_COMPONENT_TYPE_MAX_LEN = 20;
|
||||
static constexpr size_t MQTT_SUFFIX_MAX_LEN = 32;
|
||||
|
||||
#define LOG_MQTT_COMPONENT(state_topic, command_topic) \
|
||||
if (state_topic) { \
|
||||
ESP_LOGCONFIG(TAG, " State Topic: '%s'", this->get_state_topic_().c_str()); \
|
||||
@@ -27,7 +31,18 @@ struct SendDiscoveryConfig {
|
||||
ESP_LOGCONFIG(TAG, " Command Topic: '%s'", this->get_command_topic_().c_str()); \
|
||||
}
|
||||
|
||||
// Macro to define component_type() with compile-time length verification
|
||||
// Usage: MQTT_COMPONENT_TYPE(MQTTSensorComponent, "sensor")
|
||||
#define MQTT_COMPONENT_TYPE(class_name, type_str) \
|
||||
const char *class_name::component_type() const { return type_str; } \
|
||||
static_assert(sizeof(type_str) - 1 <= MQTT_COMPONENT_TYPE_MAX_LEN, \
|
||||
#class_name "::component_type() exceeds MQTT_COMPONENT_TYPE_MAX_LEN");
|
||||
|
||||
// Macro to define custom topic getter/setter with compile-time suffix length verification
|
||||
#define MQTT_COMPONENT_CUSTOM_TOPIC_(name, type) \
|
||||
static_assert(sizeof(#name "/" #type) - 1 <= MQTT_SUFFIX_MAX_LEN, \
|
||||
"topic suffix " #name "/" #type " exceeds MQTT_SUFFIX_MAX_LEN"); \
|
||||
\
|
||||
protected: \
|
||||
std::string custom_##name##_##type##_topic_{}; \
|
||||
\
|
||||
@@ -92,7 +107,7 @@ class MQTTComponent : public Component {
|
||||
void set_subscribe_qos(uint8_t qos);
|
||||
|
||||
/// Override this method to return the component type (e.g. "light", "sensor", ...)
|
||||
virtual std::string component_type() const = 0;
|
||||
virtual const char *component_type() const = 0;
|
||||
|
||||
/// Set a custom state topic. Set to "" for default behavior.
|
||||
void set_custom_state_topic(const char *custom_state_topic);
|
||||
@@ -185,8 +200,8 @@ class MQTTComponent : public Component {
|
||||
|
||||
// ========== INTERNAL METHODS ==========
|
||||
// (In most use cases you won't need these)
|
||||
/// Generate the Home Assistant MQTT discovery object id by automatically transforming the friendly name.
|
||||
std::string get_default_object_id_() const;
|
||||
/// Get the object ID for this MQTT component, writing to the provided buffer.
|
||||
StringRef get_default_object_id_to_(std::span<char, OBJECT_ID_MAX_LEN> buf) const;
|
||||
|
||||
StringRef custom_state_topic_{};
|
||||
StringRef custom_command_topic_{};
|
||||
|
||||
@@ -90,7 +90,7 @@ void MQTTCoverComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConf
|
||||
}
|
||||
}
|
||||
|
||||
std::string MQTTCoverComponent::component_type() const { return "cover"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTCoverComponent, "cover")
|
||||
const EntityBase *MQTTCoverComponent::get_entity() const { return this->cover_; }
|
||||
|
||||
bool MQTTCoverComponent::send_initial_state() { return this->publish_state(); }
|
||||
|
||||
@@ -29,7 +29,7 @@ class MQTTCoverComponent : public mqtt::MQTTComponent {
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
cover::Cover *cover_;
|
||||
|
||||
@@ -39,7 +39,7 @@ void MQTTDateComponent::dump_config() {
|
||||
LOG_MQTT_COMPONENT(true, true)
|
||||
}
|
||||
|
||||
std::string MQTTDateComponent::component_type() const { return "date"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTDateComponent, "date")
|
||||
const EntityBase *MQTTDateComponent::get_entity() const { return this->date_; }
|
||||
|
||||
void MQTTDateComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
|
||||
@@ -31,7 +31,7 @@ class MQTTDateComponent : public mqtt::MQTTComponent {
|
||||
bool publish_state(uint16_t year, uint8_t month, uint8_t day);
|
||||
|
||||
protected:
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
datetime::DateEntity *date_;
|
||||
|
||||
@@ -50,7 +50,7 @@ void MQTTDateTimeComponent::dump_config() {
|
||||
LOG_MQTT_COMPONENT(true, true)
|
||||
}
|
||||
|
||||
std::string MQTTDateTimeComponent::component_type() const { return "datetime"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTDateTimeComponent, "datetime")
|
||||
const EntityBase *MQTTDateTimeComponent::get_entity() const { return this->datetime_; }
|
||||
|
||||
void MQTTDateTimeComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
|
||||
@@ -31,7 +31,7 @@ class MQTTDateTimeComponent : public mqtt::MQTTComponent {
|
||||
bool publish_state(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second);
|
||||
|
||||
protected:
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
datetime::DateTimeEntity *datetime_;
|
||||
|
||||
@@ -50,7 +50,7 @@ bool MQTTEventComponent::publish_event_(const std::string &event_type) {
|
||||
});
|
||||
}
|
||||
|
||||
std::string MQTTEventComponent::component_type() const { return "event"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTEventComponent, "event")
|
||||
const EntityBase *MQTTEventComponent::get_entity() const { return this->event_; }
|
||||
|
||||
} // namespace esphome::mqtt
|
||||
|
||||
@@ -25,7 +25,7 @@ class MQTTEventComponent : public mqtt::MQTTComponent {
|
||||
|
||||
protected:
|
||||
bool publish_event_(const std::string &event_type);
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
event::Event *event_;
|
||||
|
||||
@@ -15,7 +15,7 @@ using namespace esphome::fan;
|
||||
MQTTFanComponent::MQTTFanComponent(Fan *state) : state_(state) {}
|
||||
|
||||
Fan *MQTTFanComponent::get_state() const { return this->state_; }
|
||||
std::string MQTTFanComponent::component_type() const { return "fan"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTFanComponent, "fan")
|
||||
const EntityBase *MQTTFanComponent::get_entity() const { return this->state_; }
|
||||
|
||||
void MQTTFanComponent::setup() {
|
||||
|
||||
@@ -36,7 +36,7 @@ class MQTTFanComponent : public mqtt::MQTTComponent {
|
||||
bool send_initial_state() override;
|
||||
bool publish_state();
|
||||
/// 'fan' component type for discovery.
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
|
||||
fan::Fan *get_state() const;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ static const char *const TAG = "mqtt.light";
|
||||
|
||||
using namespace esphome::light;
|
||||
|
||||
std::string MQTTJSONLightComponent::component_type() const { return "light"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTJSONLightComponent, "light")
|
||||
const EntityBase *MQTTJSONLightComponent::get_entity() const { return this->state_; }
|
||||
|
||||
void MQTTJSONLightComponent::setup() {
|
||||
|
||||
@@ -28,7 +28,7 @@ class MQTTJSONLightComponent : public mqtt::MQTTComponent, public light::LightRe
|
||||
void on_light_remote_values_update() override;
|
||||
|
||||
protected:
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
bool publish_state_();
|
||||
|
||||
@@ -34,7 +34,7 @@ void MQTTLockComponent::dump_config() {
|
||||
LOG_MQTT_COMPONENT(true, true);
|
||||
}
|
||||
|
||||
std::string MQTTLockComponent::component_type() const { return "lock"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTLockComponent, "lock")
|
||||
const EntityBase *MQTTLockComponent::get_entity() const { return this->lock_; }
|
||||
void MQTTLockComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
|
||||
@@ -27,7 +27,7 @@ class MQTTLockComponent : public mqtt::MQTTComponent {
|
||||
|
||||
protected:
|
||||
/// "lock" component type.
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
lock::Lock *lock_;
|
||||
|
||||
@@ -33,7 +33,7 @@ void MQTTNumberComponent::dump_config() {
|
||||
LOG_MQTT_COMPONENT(true, false)
|
||||
}
|
||||
|
||||
std::string MQTTNumberComponent::component_type() const { return "number"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTNumberComponent, "number")
|
||||
const EntityBase *MQTTNumberComponent::get_entity() const { return this->number_; }
|
||||
|
||||
void MQTTNumberComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
|
||||
@@ -32,7 +32,7 @@ class MQTTNumberComponent : public mqtt::MQTTComponent {
|
||||
|
||||
protected:
|
||||
/// Override for MQTTComponent, returns "number".
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
number::Number *number_;
|
||||
|
||||
@@ -28,7 +28,7 @@ void MQTTSelectComponent::dump_config() {
|
||||
LOG_MQTT_COMPONENT(true, false)
|
||||
}
|
||||
|
||||
std::string MQTTSelectComponent::component_type() const { return "select"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTSelectComponent, "select")
|
||||
const EntityBase *MQTTSelectComponent::get_entity() const { return this->select_; }
|
||||
|
||||
void MQTTSelectComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
|
||||
@@ -32,7 +32,7 @@ class MQTTSelectComponent : public mqtt::MQTTComponent {
|
||||
|
||||
protected:
|
||||
/// Override for MQTTComponent, returns "select".
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
select::Select *select_;
|
||||
|
||||
@@ -31,7 +31,7 @@ void MQTTSensorComponent::dump_config() {
|
||||
LOG_MQTT_COMPONENT(true, false)
|
||||
}
|
||||
|
||||
std::string MQTTSensorComponent::component_type() const { return "sensor"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTSensorComponent, "sensor")
|
||||
const EntityBase *MQTTSensorComponent::get_entity() const { return this->sensor_; }
|
||||
|
||||
uint32_t MQTTSensorComponent::get_expire_after() const {
|
||||
|
||||
@@ -43,7 +43,7 @@ class MQTTSensorComponent : public mqtt::MQTTComponent {
|
||||
|
||||
protected:
|
||||
/// Override for MQTTComponent, returns "sensor".
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
sensor::Sensor *sensor_;
|
||||
|
||||
@@ -41,7 +41,7 @@ void MQTTSwitchComponent::dump_config() {
|
||||
LOG_MQTT_COMPONENT(true, true);
|
||||
}
|
||||
|
||||
std::string MQTTSwitchComponent::component_type() const { return "switch"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTSwitchComponent, "switch")
|
||||
const EntityBase *MQTTSwitchComponent::get_entity() const { return this->switch_; }
|
||||
void MQTTSwitchComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
|
||||
@@ -27,7 +27,7 @@ class MQTTSwitchComponent : public mqtt::MQTTComponent {
|
||||
|
||||
protected:
|
||||
/// "switch" component type.
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
switch_::Switch *switch_;
|
||||
|
||||
@@ -29,7 +29,7 @@ void MQTTTextComponent::dump_config() {
|
||||
LOG_MQTT_COMPONENT(true, true)
|
||||
}
|
||||
|
||||
std::string MQTTTextComponent::component_type() const { return "text"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTTextComponent, "text")
|
||||
const EntityBase *MQTTTextComponent::get_entity() const { return this->text_; }
|
||||
|
||||
void MQTTTextComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
|
||||
@@ -32,7 +32,7 @@ class MQTTTextComponent : public mqtt::MQTTComponent {
|
||||
|
||||
protected:
|
||||
/// Override for MQTTComponent, returns "text".
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
text::Text *text_;
|
||||
|
||||
@@ -39,7 +39,7 @@ bool MQTTTextSensor::send_initial_state() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
std::string MQTTTextSensor::component_type() const { return "sensor"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTTextSensor, "sensor")
|
||||
const EntityBase *MQTTTextSensor::get_entity() const { return this->sensor_; }
|
||||
|
||||
} // namespace esphome::mqtt
|
||||
|
||||
@@ -25,7 +25,7 @@ class MQTTTextSensor : public mqtt::MQTTComponent {
|
||||
bool send_initial_state() override;
|
||||
|
||||
protected:
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
text_sensor::TextSensor *sensor_;
|
||||
|
||||
@@ -39,7 +39,7 @@ void MQTTTimeComponent::dump_config() {
|
||||
LOG_MQTT_COMPONENT(true, true)
|
||||
}
|
||||
|
||||
std::string MQTTTimeComponent::component_type() const { return "time"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTTimeComponent, "time")
|
||||
const EntityBase *MQTTTimeComponent::get_entity() const { return this->time_; }
|
||||
|
||||
void MQTTTimeComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
||||
|
||||
@@ -31,7 +31,7 @@ class MQTTTimeComponent : public mqtt::MQTTComponent {
|
||||
bool publish_state(uint8_t hour, uint8_t minute, uint8_t second);
|
||||
|
||||
protected:
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
datetime::TimeEntity *time_;
|
||||
|
||||
@@ -52,7 +52,7 @@ void MQTTUpdateComponent::dump_config() {
|
||||
LOG_MQTT_COMPONENT(true, true);
|
||||
}
|
||||
|
||||
std::string MQTTUpdateComponent::component_type() const { return "update"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTUpdateComponent, "update")
|
||||
const EntityBase *MQTTUpdateComponent::get_entity() const { return this->update_; }
|
||||
|
||||
} // namespace esphome::mqtt
|
||||
|
||||
@@ -27,7 +27,7 @@ class MQTTUpdateComponent : public mqtt::MQTTComponent {
|
||||
|
||||
protected:
|
||||
/// "update" component type.
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
update::UpdateEntity *update_;
|
||||
|
||||
@@ -65,7 +65,7 @@ void MQTTValveComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConf
|
||||
}
|
||||
}
|
||||
|
||||
std::string MQTTValveComponent::component_type() const { return "valve"; }
|
||||
MQTT_COMPONENT_TYPE(MQTTValveComponent, "valve")
|
||||
const EntityBase *MQTTValveComponent::get_entity() const { return this->valve_; }
|
||||
|
||||
bool MQTTValveComponent::send_initial_state() { return this->publish_state(); }
|
||||
|
||||
@@ -27,7 +27,7 @@ class MQTTValveComponent : public mqtt::MQTTComponent {
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
std::string component_type() const override;
|
||||
const char *component_type() const override;
|
||||
const EntityBase *get_entity() const override;
|
||||
|
||||
valve::Valve *valve_;
|
||||
|
||||
@@ -76,6 +76,7 @@ VALID_INCLUDE_EXTS = {".h", ".hpp", ".tcc", ".ino", ".cpp", ".c"}
|
||||
|
||||
|
||||
def validate_hostname(config):
|
||||
# Keep in sync with ESPHOME_DEVICE_NAME_MAX_LEN in esphome/core/entity_base.h
|
||||
max_length = 31
|
||||
if config[CONF_NAME_ADD_MAC_SUFFIX]:
|
||||
max_length -= 7 # "-AABBCC" is appended when add mac suffix option is used
|
||||
@@ -207,6 +208,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_NAME): cv.valid_name,
|
||||
# Keep max=120 in sync with OBJECT_ID_MAX_LEN in esphome/core/entity_base.h
|
||||
cv.Optional(CONF_FRIENDLY_NAME, ""): cv.All(
|
||||
cv.string_no_slash, cv.Length(max=120)
|
||||
),
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
// Maximum size for object_id buffer (friendly_name max ~120 + margin)
|
||||
// Maximum device name length - keep in sync with validate_hostname() in esphome/core/config.py
|
||||
static constexpr size_t ESPHOME_DEVICE_NAME_MAX_LEN = 31;
|
||||
|
||||
// Maximum size for object_id buffer - keep in sync with friendly_name cv.Length(max=120) in esphome/core/config.py
|
||||
static constexpr size_t OBJECT_ID_MAX_LEN = 128;
|
||||
|
||||
enum EntityCategory : uint8_t {
|
||||
|
||||
Reference in New Issue
Block a user