mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[mqtt] Use stack buffer for discovery topic to avoid heap allocation
This commit is contained in:
@@ -34,10 +34,7 @@ inline char *append_char(char *p, char c) {
|
|||||||
// MQTT_COMPONENT_TYPE_MAX_LEN, MQTT_SUFFIX_MAX_LEN, and MQTT_DEFAULT_TOPIC_MAX_LEN are in mqtt_component.h.
|
// MQTT_COMPONENT_TYPE_MAX_LEN, MQTT_SUFFIX_MAX_LEN, and MQTT_DEFAULT_TOPIC_MAX_LEN are in mqtt_component.h.
|
||||||
// ESPHOME_DEVICE_NAME_MAX_LEN and OBJECT_ID_MAX_LEN are defined in entity_base.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.
|
// This ensures the stack buffers below are always large enough.
|
||||||
static constexpr size_t DISCOVERY_PREFIX_MAX_LEN = 64; // Validated in Python: cv.Length(max=64)
|
// MQTT_DISCOVERY_PREFIX_MAX_LEN and MQTT_DISCOVERY_TOPIC_MAX_LEN are defined in mqtt_component.h
|
||||||
// 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;
|
|
||||||
|
|
||||||
// Function implementation of LOG_MQTT_COMPONENT macro to reduce code size
|
// Function implementation of LOG_MQTT_COMPONENT macro to reduce code size
|
||||||
void log_mqtt_component(const char *tag, MQTTComponent *obj, bool state_topic, bool command_topic) {
|
void log_mqtt_component(const char *tag, MQTTComponent *obj, bool state_topic, bool command_topic) {
|
||||||
@@ -54,15 +51,15 @@ void MQTTComponent::set_subscribe_qos(uint8_t qos) { this->subscribe_qos_ = qos;
|
|||||||
|
|
||||||
void MQTTComponent::set_retain(bool retain) { this->retain_ = retain; }
|
void MQTTComponent::set_retain(bool retain) { this->retain_ = retain; }
|
||||||
|
|
||||||
std::string MQTTComponent::get_discovery_topic_(const MQTTDiscoveryInfo &discovery_info) const {
|
StringRef MQTTComponent::get_discovery_topic_to_(std::span<char, MQTT_DISCOVERY_TOPIC_MAX_LEN> buf,
|
||||||
|
const MQTTDiscoveryInfo &discovery_info) const {
|
||||||
char sanitized_name[ESPHOME_DEVICE_NAME_MAX_LEN + 1];
|
char sanitized_name[ESPHOME_DEVICE_NAME_MAX_LEN + 1];
|
||||||
str_sanitize_to(sanitized_name, App.get_name().c_str());
|
str_sanitize_to(sanitized_name, App.get_name().c_str());
|
||||||
const char *comp_type = this->component_type();
|
const char *comp_type = this->component_type();
|
||||||
char object_id_buf[OBJECT_ID_MAX_LEN];
|
char object_id_buf[OBJECT_ID_MAX_LEN];
|
||||||
StringRef object_id = this->get_default_object_id_to_(object_id_buf);
|
StringRef object_id = this->get_default_object_id_to_(object_id_buf);
|
||||||
|
|
||||||
char buf[DISCOVERY_TOPIC_MAX_LEN];
|
char *p = buf.data();
|
||||||
char *p = buf;
|
|
||||||
|
|
||||||
p = append_str(p, discovery_info.prefix.data(), discovery_info.prefix.size());
|
p = append_str(p, discovery_info.prefix.data(), discovery_info.prefix.size());
|
||||||
p = append_char(p, '/');
|
p = append_char(p, '/');
|
||||||
@@ -72,8 +69,9 @@ std::string MQTTComponent::get_discovery_topic_(const MQTTDiscoveryInfo &discove
|
|||||||
p = append_char(p, '/');
|
p = append_char(p, '/');
|
||||||
p = append_str(p, object_id.c_str(), object_id.size());
|
p = append_str(p, object_id.c_str(), object_id.size());
|
||||||
p = append_str(p, "/config", 7);
|
p = append_str(p, "/config", 7);
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
return std::string(buf, p - buf);
|
return StringRef(buf.data(), p - buf.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef MQTTComponent::get_default_topic_for_to_(std::span<char, MQTT_DEFAULT_TOPIC_MAX_LEN> buf, const char *suffix,
|
StringRef MQTTComponent::get_default_topic_for_to_(std::span<char, MQTT_DEFAULT_TOPIC_MAX_LEN> buf, const char *suffix,
|
||||||
@@ -182,16 +180,19 @@ bool MQTTComponent::publish_json(const char *topic, const json::json_build_t &f)
|
|||||||
bool MQTTComponent::send_discovery_() {
|
bool MQTTComponent::send_discovery_() {
|
||||||
const MQTTDiscoveryInfo &discovery_info = global_mqtt_client->get_discovery_info();
|
const MQTTDiscoveryInfo &discovery_info = global_mqtt_client->get_discovery_info();
|
||||||
|
|
||||||
|
char discovery_topic_buf[MQTT_DISCOVERY_TOPIC_MAX_LEN];
|
||||||
|
StringRef discovery_topic = this->get_discovery_topic_to_(discovery_topic_buf, discovery_info);
|
||||||
|
|
||||||
if (discovery_info.clean) {
|
if (discovery_info.clean) {
|
||||||
ESP_LOGV(TAG, "'%s': Cleaning discovery", this->friendly_name_().c_str());
|
ESP_LOGV(TAG, "'%s': Cleaning discovery", this->friendly_name_().c_str());
|
||||||
return global_mqtt_client->publish(this->get_discovery_topic_(discovery_info), "", 0, this->qos_, true);
|
return global_mqtt_client->publish(discovery_topic.c_str(), "", 0, this->qos_, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGV(TAG, "'%s': Sending discovery", this->friendly_name_().c_str());
|
ESP_LOGV(TAG, "'%s': Sending discovery", this->friendly_name_().c_str());
|
||||||
|
|
||||||
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||||
return global_mqtt_client->publish_json(
|
return global_mqtt_client->publish_json(
|
||||||
this->get_discovery_topic_(discovery_info),
|
discovery_topic.c_str(),
|
||||||
[this](JsonObject root) {
|
[this](JsonObject root) {
|
||||||
SendDiscoveryConfig config;
|
SendDiscoveryConfig config;
|
||||||
config.state_topic = true;
|
config.state_topic = true;
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ static constexpr size_t MQTT_TOPIC_PREFIX_MAX_LEN = 64; // Validated in Python:
|
|||||||
// Format: prefix + "/" + type + "/" + object_id + "/" + suffix + null
|
// Format: prefix + "/" + type + "/" + object_id + "/" + suffix + null
|
||||||
static constexpr size_t MQTT_DEFAULT_TOPIC_MAX_LEN =
|
static constexpr size_t MQTT_DEFAULT_TOPIC_MAX_LEN =
|
||||||
MQTT_TOPIC_PREFIX_MAX_LEN + 1 + MQTT_COMPONENT_TYPE_MAX_LEN + 1 + OBJECT_ID_MAX_LEN + 1 + MQTT_SUFFIX_MAX_LEN + 1;
|
MQTT_TOPIC_PREFIX_MAX_LEN + 1 + MQTT_COMPONENT_TYPE_MAX_LEN + 1 + OBJECT_ID_MAX_LEN + 1 + MQTT_SUFFIX_MAX_LEN + 1;
|
||||||
|
static constexpr size_t MQTT_DISCOVERY_PREFIX_MAX_LEN = 64; // Validated in Python: cv.Length(max=64)
|
||||||
|
// Format: prefix + "/" + type + "/" + name + "/" + object_id + "/config" + null
|
||||||
|
static constexpr size_t MQTT_DISCOVERY_TOPIC_MAX_LEN = MQTT_DISCOVERY_PREFIX_MAX_LEN + 1 + MQTT_COMPONENT_TYPE_MAX_LEN +
|
||||||
|
1 + ESPHOME_DEVICE_NAME_MAX_LEN + 1 + OBJECT_ID_MAX_LEN + 7 + 1;
|
||||||
|
|
||||||
class MQTTComponent; // Forward declaration
|
class MQTTComponent; // Forward declaration
|
||||||
void log_mqtt_component(const char *tag, MQTTComponent *obj, bool state_topic, bool command_topic);
|
void log_mqtt_component(const char *tag, MQTTComponent *obj, bool state_topic, bool command_topic);
|
||||||
@@ -263,8 +267,9 @@ class MQTTComponent : public Component {
|
|||||||
void subscribe_json(const std::string &topic, const mqtt_json_callback_t &callback, uint8_t qos = 0);
|
void subscribe_json(const std::string &topic, const mqtt_json_callback_t &callback, uint8_t qos = 0);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Helper method to get the discovery topic for this component.
|
/// Helper method to get the discovery topic for this component into a buffer.
|
||||||
std::string get_discovery_topic_(const MQTTDiscoveryInfo &discovery_info) const;
|
StringRef get_discovery_topic_to_(std::span<char, MQTT_DISCOVERY_TOPIC_MAX_LEN> buf,
|
||||||
|
const MQTTDiscoveryInfo &discovery_info) const;
|
||||||
|
|
||||||
/** Get this components state/command/... topic into a buffer.
|
/** Get this components state/command/... topic into a buffer.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user