1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-18 15:55:46 +00:00

[mqtt] Use StringRef to avoid string copies in discovery (#11731)

This commit is contained in:
J. Nick Koston
2025-11-05 12:30:45 -06:00
committed by GitHub
parent d36ef050a9
commit b08419fa47
15 changed files with 81 additions and 52 deletions

View File

@@ -36,7 +36,7 @@ void MQTTAlarmControlPanelComponent::setup() {
} else if (strcasecmp(payload.c_str(), "TRIGGERED") == 0) { } else if (strcasecmp(payload.c_str(), "TRIGGERED") == 0) {
call.triggered(); call.triggered();
} else { } else {
ESP_LOGW(TAG, "'%s': Received unknown command payload %s", this->friendly_name().c_str(), payload.c_str()); ESP_LOGW(TAG, "'%s': Received unknown command payload %s", this->friendly_name_().c_str(), payload.c_str());
} }
call.perform(); call.perform();
}); });

View File

@@ -30,9 +30,12 @@ MQTTBinarySensorComponent::MQTTBinarySensorComponent(binary_sensor::BinarySensor
} }
void MQTTBinarySensorComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { void MQTTBinarySensorComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
if (!this->binary_sensor_->get_device_class().empty()) const auto device_class = this->binary_sensor_->get_device_class_ref();
root[MQTT_DEVICE_CLASS] = this->binary_sensor_->get_device_class(); if (!device_class.empty()) {
root[MQTT_DEVICE_CLASS] = device_class;
}
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
if (this->binary_sensor_->is_status_binary_sensor()) if (this->binary_sensor_->is_status_binary_sensor())
root[MQTT_PAYLOAD_ON] = mqtt::global_mqtt_client->get_availability().payload_available; root[MQTT_PAYLOAD_ON] = mqtt::global_mqtt_client->get_availability().payload_available;
if (this->binary_sensor_->is_status_binary_sensor()) if (this->binary_sensor_->is_status_binary_sensor())

View File

@@ -20,7 +20,7 @@ void MQTTButtonComponent::setup() {
if (payload == "PRESS") { if (payload == "PRESS") {
this->button_->press(); this->button_->press();
} else { } else {
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name().c_str(), payload.c_str()); ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name_().c_str(), payload.c_str());
this->status_momentary_warning("state", 5000); this->status_momentary_warning("state", 5000);
} }
}); });
@@ -33,8 +33,9 @@ void MQTTButtonComponent::dump_config() {
void MQTTButtonComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { void MQTTButtonComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
config.state_topic = false; config.state_topic = false;
if (!this->button_->get_device_class().empty()) { const auto device_class = this->button_->get_device_class_ref();
root[MQTT_DEVICE_CLASS] = this->button_->get_device_class(); if (!device_class.empty()) {
root[MQTT_DEVICE_CLASS] = device_class;
} }
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks) // NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
} }

View File

@@ -64,11 +64,11 @@ bool MQTTComponent::send_discovery_() {
const MQTTDiscoveryInfo &discovery_info = global_mqtt_client->get_discovery_info(); const MQTTDiscoveryInfo &discovery_info = global_mqtt_client->get_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(this->get_discovery_topic_(discovery_info), "", 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(
@@ -85,12 +85,16 @@ bool MQTTComponent::send_discovery_() {
} }
// Fields from EntityBase // Fields from EntityBase
root[MQTT_NAME] = this->get_entity()->has_own_name() ? this->friendly_name() : ""; root[MQTT_NAME] = this->get_entity()->has_own_name() ? this->friendly_name_() : "";
if (this->is_disabled_by_default()) if (this->is_disabled_by_default_())
root[MQTT_ENABLED_BY_DEFAULT] = false; root[MQTT_ENABLED_BY_DEFAULT] = false;
if (!this->get_icon().empty()) // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
root[MQTT_ICON] = this->get_icon(); const auto icon_ref = this->get_icon_ref_();
if (!icon_ref.empty()) {
root[MQTT_ICON] = icon_ref;
}
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
const auto entity_category = this->get_entity()->get_entity_category(); const auto entity_category = this->get_entity()->get_entity_category();
switch (entity_category) { switch (entity_category) {
@@ -122,7 +126,7 @@ bool MQTTComponent::send_discovery_() {
const MQTTDiscoveryInfo &discovery_info = global_mqtt_client->get_discovery_info(); const MQTTDiscoveryInfo &discovery_info = global_mqtt_client->get_discovery_info();
if (discovery_info.unique_id_generator == MQTT_MAC_ADDRESS_UNIQUE_ID_GENERATOR) { if (discovery_info.unique_id_generator == MQTT_MAC_ADDRESS_UNIQUE_ID_GENERATOR) {
char friendly_name_hash[9]; char friendly_name_hash[9];
sprintf(friendly_name_hash, "%08" PRIx32, fnv1_hash(this->friendly_name())); sprintf(friendly_name_hash, "%08" PRIx32, fnv1_hash(this->friendly_name_()));
friendly_name_hash[8] = 0; // ensure the hash-string ends with null friendly_name_hash[8] = 0; // ensure the hash-string ends with null
root[MQTT_UNIQUE_ID] = get_mac_address() + "-" + this->component_type() + "-" + friendly_name_hash; root[MQTT_UNIQUE_ID] = get_mac_address() + "-" + this->component_type() + "-" + friendly_name_hash;
} else { } else {
@@ -184,7 +188,7 @@ bool MQTTComponent::is_discovery_enabled() const {
} }
std::string MQTTComponent::get_default_object_id_() const { std::string MQTTComponent::get_default_object_id_() const {
return str_sanitize(str_snake_case(this->friendly_name())); return str_sanitize(str_snake_case(this->friendly_name_()));
} }
void MQTTComponent::subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos) { void MQTTComponent::subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos) {
@@ -268,9 +272,9 @@ void MQTTComponent::schedule_resend_state() { this->resend_state_ = true; }
bool MQTTComponent::is_connected_() const { return global_mqtt_client->is_connected(); } bool MQTTComponent::is_connected_() const { return global_mqtt_client->is_connected(); }
// Pull these properties from EntityBase if not overridden // Pull these properties from EntityBase if not overridden
std::string MQTTComponent::friendly_name() const { return this->get_entity()->get_name(); } std::string MQTTComponent::friendly_name_() const { return this->get_entity()->get_name(); }
std::string MQTTComponent::get_icon() const { return this->get_entity()->get_icon(); } 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_disabled_by_default_() const { return this->get_entity()->is_disabled_by_default(); }
bool MQTTComponent::is_internal() { bool MQTTComponent::is_internal() {
if (this->has_custom_state_topic_) { if (this->has_custom_state_topic_) {
// If the custom state_topic is null, return true as it is internal and should not publish // If the custom state_topic is null, return true as it is internal and should not publish

View File

@@ -165,13 +165,13 @@ class MQTTComponent : public Component {
virtual const EntityBase *get_entity() const = 0; virtual const EntityBase *get_entity() const = 0;
/// Get the friendly name of this MQTT component. /// Get the friendly name of this MQTT component.
virtual std::string friendly_name() const; std::string friendly_name_() const;
/// Get the icon field of this component /// Get the icon field of this component as StringRef
virtual std::string get_icon() const; StringRef get_icon_ref_() const;
/// Get whether the underlying Entity is disabled by default /// Get whether the underlying Entity is disabled by default
virtual bool is_disabled_by_default() const; bool is_disabled_by_default_() const;
/// Get the MQTT topic that new states will be shared to. /// Get the MQTT topic that new states will be shared to.
std::string get_state_topic_() const; std::string get_state_topic_() const;

View File

@@ -67,9 +67,12 @@ void MQTTCoverComponent::dump_config() {
} }
} }
void MQTTCoverComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { void MQTTCoverComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
if (!this->cover_->get_device_class().empty()) const auto device_class = this->cover_->get_device_class_ref();
root[MQTT_DEVICE_CLASS] = this->cover_->get_device_class(); if (!device_class.empty()) {
root[MQTT_DEVICE_CLASS] = device_class;
}
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
auto traits = this->cover_->get_traits(); auto traits = this->cover_->get_traits();
if (traits.get_is_assumed_state()) { if (traits.get_is_assumed_state()) {

View File

@@ -21,8 +21,12 @@ void MQTTEventComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConf
for (const auto &event_type : this->event_->get_event_types()) for (const auto &event_type : this->event_->get_event_types())
event_types.add(event_type); event_types.add(event_type);
if (!this->event_->get_device_class().empty()) // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
root[MQTT_DEVICE_CLASS] = this->event_->get_device_class(); const auto device_class = this->event_->get_device_class_ref();
if (!device_class.empty()) {
root[MQTT_DEVICE_CLASS] = device_class;
}
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
config.command_topic = false; config.command_topic = false;
} }

View File

@@ -24,15 +24,15 @@ void MQTTFanComponent::setup() {
auto val = parse_on_off(payload.c_str()); auto val = parse_on_off(payload.c_str());
switch (val) { switch (val) {
case PARSE_ON: case PARSE_ON:
ESP_LOGD(TAG, "'%s' Turning Fan ON.", this->friendly_name().c_str()); ESP_LOGD(TAG, "'%s' Turning Fan ON.", this->friendly_name_().c_str());
this->state_->turn_on().perform(); this->state_->turn_on().perform();
break; break;
case PARSE_OFF: case PARSE_OFF:
ESP_LOGD(TAG, "'%s' Turning Fan OFF.", this->friendly_name().c_str()); ESP_LOGD(TAG, "'%s' Turning Fan OFF.", this->friendly_name_().c_str());
this->state_->turn_off().perform(); this->state_->turn_off().perform();
break; break;
case PARSE_TOGGLE: case PARSE_TOGGLE:
ESP_LOGD(TAG, "'%s' Toggling Fan.", this->friendly_name().c_str()); ESP_LOGD(TAG, "'%s' Toggling Fan.", this->friendly_name_().c_str());
this->state_->toggle().perform(); this->state_->toggle().perform();
break; break;
case PARSE_NONE: case PARSE_NONE:
@@ -48,11 +48,11 @@ void MQTTFanComponent::setup() {
auto val = parse_on_off(payload.c_str(), "forward", "reverse"); auto val = parse_on_off(payload.c_str(), "forward", "reverse");
switch (val) { switch (val) {
case PARSE_ON: case PARSE_ON:
ESP_LOGD(TAG, "'%s': Setting direction FORWARD", this->friendly_name().c_str()); ESP_LOGD(TAG, "'%s': Setting direction FORWARD", this->friendly_name_().c_str());
this->state_->make_call().set_direction(fan::FanDirection::FORWARD).perform(); this->state_->make_call().set_direction(fan::FanDirection::FORWARD).perform();
break; break;
case PARSE_OFF: case PARSE_OFF:
ESP_LOGD(TAG, "'%s': Setting direction REVERSE", this->friendly_name().c_str()); ESP_LOGD(TAG, "'%s': Setting direction REVERSE", this->friendly_name_().c_str());
this->state_->make_call().set_direction(fan::FanDirection::REVERSE).perform(); this->state_->make_call().set_direction(fan::FanDirection::REVERSE).perform();
break; break;
case PARSE_TOGGLE: case PARSE_TOGGLE:
@@ -75,11 +75,11 @@ void MQTTFanComponent::setup() {
auto val = parse_on_off(payload.c_str(), "oscillate_on", "oscillate_off"); auto val = parse_on_off(payload.c_str(), "oscillate_on", "oscillate_off");
switch (val) { switch (val) {
case PARSE_ON: case PARSE_ON:
ESP_LOGD(TAG, "'%s': Setting oscillating ON", this->friendly_name().c_str()); ESP_LOGD(TAG, "'%s': Setting oscillating ON", this->friendly_name_().c_str());
this->state_->make_call().set_oscillating(true).perform(); this->state_->make_call().set_oscillating(true).perform();
break; break;
case PARSE_OFF: case PARSE_OFF:
ESP_LOGD(TAG, "'%s': Setting oscillating OFF", this->friendly_name().c_str()); ESP_LOGD(TAG, "'%s': Setting oscillating OFF", this->friendly_name_().c_str());
this->state_->make_call().set_oscillating(false).perform(); this->state_->make_call().set_oscillating(false).perform();
break; break;
case PARSE_TOGGLE: case PARSE_TOGGLE:

View File

@@ -24,7 +24,7 @@ void MQTTLockComponent::setup() {
} else if (strcasecmp(payload.c_str(), "OPEN") == 0) { } else if (strcasecmp(payload.c_str(), "OPEN") == 0) {
this->lock_->open(); this->lock_->open();
} else { } else {
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name().c_str(), payload.c_str()); ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name_().c_str(), payload.c_str());
this->status_momentary_warning("state", 5000); this->status_momentary_warning("state", 5000);
} }
}); });

View File

@@ -44,8 +44,11 @@ void MQTTNumberComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCon
root[MQTT_MIN] = traits.get_min_value(); root[MQTT_MIN] = traits.get_min_value();
root[MQTT_MAX] = traits.get_max_value(); root[MQTT_MAX] = traits.get_max_value();
root[MQTT_STEP] = traits.get_step(); root[MQTT_STEP] = traits.get_step();
if (!this->number_->traits.get_unit_of_measurement().empty()) // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
root[MQTT_UNIT_OF_MEASUREMENT] = this->number_->traits.get_unit_of_measurement(); const auto unit_of_measurement = this->number_->traits.get_unit_of_measurement_ref();
if (!unit_of_measurement.empty()) {
root[MQTT_UNIT_OF_MEASUREMENT] = unit_of_measurement;
}
switch (this->number_->traits.get_mode()) { switch (this->number_->traits.get_mode()) {
case NUMBER_MODE_AUTO: case NUMBER_MODE_AUTO:
break; break;
@@ -56,8 +59,11 @@ void MQTTNumberComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCon
root[MQTT_MODE] = "slider"; root[MQTT_MODE] = "slider";
break; break;
} }
if (!this->number_->traits.get_device_class().empty()) const auto device_class = this->number_->traits.get_device_class_ref();
root[MQTT_DEVICE_CLASS] = this->number_->traits.get_device_class(); if (!device_class.empty()) {
root[MQTT_DEVICE_CLASS] = device_class;
}
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
config.command_topic = true; config.command_topic = true;
} }

View File

@@ -44,13 +44,17 @@ void MQTTSensorComponent::set_expire_after(uint32_t expire_after) { this->expire
void MQTTSensorComponent::disable_expire_after() { this->expire_after_ = 0; } void MQTTSensorComponent::disable_expire_after() { this->expire_after_ = 0; }
void MQTTSensorComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { void MQTTSensorComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
if (!this->sensor_->get_device_class().empty()) { const auto device_class = this->sensor_->get_device_class_ref();
root[MQTT_DEVICE_CLASS] = this->sensor_->get_device_class(); if (!device_class.empty()) {
root[MQTT_DEVICE_CLASS] = device_class;
} }
if (!this->sensor_->get_unit_of_measurement().empty()) const auto unit_of_measurement = this->sensor_->get_unit_of_measurement_ref();
root[MQTT_UNIT_OF_MEASUREMENT] = this->sensor_->get_unit_of_measurement(); if (!unit_of_measurement.empty()) {
root[MQTT_UNIT_OF_MEASUREMENT] = unit_of_measurement;
}
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
if (this->get_expire_after() > 0) if (this->get_expire_after() > 0)
root[MQTT_EXPIRE_AFTER] = this->get_expire_after() / 1000; root[MQTT_EXPIRE_AFTER] = this->get_expire_after() / 1000;

View File

@@ -29,7 +29,7 @@ void MQTTSwitchComponent::setup() {
break; break;
case PARSE_NONE: case PARSE_NONE:
default: default:
ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name().c_str(), payload.c_str()); ESP_LOGW(TAG, "'%s': Received unknown status payload: %s", this->friendly_name_().c_str(), payload.c_str());
this->status_momentary_warning("state", 5000); this->status_momentary_warning("state", 5000);
break; break;
} }

View File

@@ -15,10 +15,12 @@ using namespace esphome::text_sensor;
MQTTTextSensor::MQTTTextSensor(TextSensor *sensor) : sensor_(sensor) {} MQTTTextSensor::MQTTTextSensor(TextSensor *sensor) : sensor_(sensor) {}
void MQTTTextSensor::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { void MQTTTextSensor::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
if (!this->sensor_->get_device_class().empty()) { const auto device_class = this->sensor_->get_device_class_ref();
root[MQTT_DEVICE_CLASS] = this->sensor_->get_device_class(); if (!device_class.empty()) {
root[MQTT_DEVICE_CLASS] = device_class;
} }
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
config.command_topic = false; config.command_topic = false;
} }
void MQTTTextSensor::setup() { void MQTTTextSensor::setup() {

View File

@@ -20,7 +20,7 @@ void MQTTUpdateComponent::setup() {
if (payload == "INSTALL") { if (payload == "INSTALL") {
this->update_->perform(); this->update_->perform();
} else { } else {
ESP_LOGW(TAG, "'%s': Received unknown update payload: %s", this->friendly_name().c_str(), payload.c_str()); ESP_LOGW(TAG, "'%s': Received unknown update payload: %s", this->friendly_name_().c_str(), payload.c_str());
this->status_momentary_warning("state", 5000); this->status_momentary_warning("state", 5000);
} }
}); });

View File

@@ -49,10 +49,12 @@ void MQTTValveComponent::dump_config() {
} }
} }
void MQTTValveComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) { void MQTTValveComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson // NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
if (!this->valve_->get_device_class().empty()) { const auto device_class = this->valve_->get_device_class_ref();
root[MQTT_DEVICE_CLASS] = this->valve_->get_device_class(); if (!device_class.empty()) {
root[MQTT_DEVICE_CLASS] = device_class;
} }
// NOLINTEND(clang-analyzer-cplusplus.NewDeleteLeaks)
auto traits = this->valve_->get_traits(); auto traits = this->valve_->get_traits();
if (traits.get_is_assumed_state()) { if (traits.get_is_assumed_state()) {