mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 08:41:59 +00:00
[mqtt] Add zero-allocation topic getters to MQTT_COMPONENT_CUSTOM_TOPIC macro
Add _to() variants that write into a stack buffer and return StringRef, avoiding heap allocation on every publish. Update publish_state() in climate (11 allocations eliminated), fan (3), cover (2), and valve (1) to use the new stack-based getters. The allocating getters are retained for setup-time paths (subscribe, send_discovery, dump_config) where the allocation is one-time.
This commit is contained in:
@@ -300,9 +300,11 @@ const EntityBase *MQTTClimateComponent::get_entity() const { return this->device
|
||||
|
||||
bool MQTTClimateComponent::publish_state_() {
|
||||
auto traits = this->device_->get_traits();
|
||||
// Reusable stack buffer for topic construction (avoids heap allocation per publish)
|
||||
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
|
||||
// mode
|
||||
bool success = true;
|
||||
if (!this->publish(this->get_mode_state_topic(), climate_mode_to_mqtt_str(this->device_->mode)))
|
||||
if (!this->publish(this->get_mode_state_topic_to(topic_buf), climate_mode_to_mqtt_str(this->device_->mode)))
|
||||
success = false;
|
||||
int8_t target_accuracy = traits.get_target_temperature_accuracy_decimals();
|
||||
int8_t current_accuracy = traits.get_current_temperature_accuracy_decimals();
|
||||
@@ -311,68 +313,70 @@ bool MQTTClimateComponent::publish_state_() {
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE) &&
|
||||
!std::isnan(this->device_->current_temperature)) {
|
||||
len = value_accuracy_to_buf(payload, this->device_->current_temperature, current_accuracy);
|
||||
if (!this->publish(this->get_current_temperature_state_topic(), payload, len))
|
||||
if (!this->publish(this->get_current_temperature_state_topic_to(topic_buf), payload, len))
|
||||
success = false;
|
||||
}
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE |
|
||||
climate::CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE)) {
|
||||
len = value_accuracy_to_buf(payload, this->device_->target_temperature_low, target_accuracy);
|
||||
if (!this->publish(this->get_target_temperature_low_state_topic(), payload, len))
|
||||
if (!this->publish(this->get_target_temperature_low_state_topic_to(topic_buf), payload, len))
|
||||
success = false;
|
||||
len = value_accuracy_to_buf(payload, this->device_->target_temperature_high, target_accuracy);
|
||||
if (!this->publish(this->get_target_temperature_high_state_topic(), payload, len))
|
||||
if (!this->publish(this->get_target_temperature_high_state_topic_to(topic_buf), payload, len))
|
||||
success = false;
|
||||
} else {
|
||||
len = value_accuracy_to_buf(payload, this->device_->target_temperature, target_accuracy);
|
||||
if (!this->publish(this->get_target_temperature_state_topic(), payload, len))
|
||||
if (!this->publish(this->get_target_temperature_state_topic_to(topic_buf), payload, len))
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_HUMIDITY) &&
|
||||
!std::isnan(this->device_->current_humidity)) {
|
||||
len = value_accuracy_to_buf(payload, this->device_->current_humidity, 0);
|
||||
if (!this->publish(this->get_current_humidity_state_topic(), payload, len))
|
||||
if (!this->publish(this->get_current_humidity_state_topic_to(topic_buf), payload, len))
|
||||
success = false;
|
||||
}
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TARGET_HUMIDITY) &&
|
||||
!std::isnan(this->device_->target_humidity)) {
|
||||
len = value_accuracy_to_buf(payload, this->device_->target_humidity, 0);
|
||||
if (!this->publish(this->get_target_humidity_state_topic(), payload, len))
|
||||
if (!this->publish(this->get_target_humidity_state_topic_to(topic_buf), payload, len))
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (traits.get_supports_presets() || !traits.get_supported_custom_presets().empty()) {
|
||||
if (this->device_->has_custom_preset()) {
|
||||
if (!this->publish(this->get_preset_state_topic(), this->device_->get_custom_preset()))
|
||||
if (!this->publish(this->get_preset_state_topic_to(topic_buf), this->device_->get_custom_preset()))
|
||||
success = false;
|
||||
} else if (this->device_->preset.has_value()) {
|
||||
if (!this->publish(this->get_preset_state_topic(), climate_preset_to_mqtt_str(this->device_->preset.value())))
|
||||
if (!this->publish(this->get_preset_state_topic_to(topic_buf),
|
||||
climate_preset_to_mqtt_str(this->device_->preset.value())))
|
||||
success = false;
|
||||
} else if (!this->publish(this->get_preset_state_topic(), "")) {
|
||||
} else if (!this->publish(this->get_preset_state_topic_to(topic_buf), "")) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_ACTION)) {
|
||||
if (!this->publish(this->get_action_state_topic(), climate_action_to_mqtt_str(this->device_->action)))
|
||||
if (!this->publish(this->get_action_state_topic_to(topic_buf), climate_action_to_mqtt_str(this->device_->action)))
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (traits.get_supports_fan_modes()) {
|
||||
if (this->device_->has_custom_fan_mode()) {
|
||||
if (!this->publish(this->get_fan_mode_state_topic(), this->device_->get_custom_fan_mode()))
|
||||
if (!this->publish(this->get_fan_mode_state_topic_to(topic_buf), this->device_->get_custom_fan_mode()))
|
||||
success = false;
|
||||
} else if (this->device_->fan_mode.has_value()) {
|
||||
if (!this->publish(this->get_fan_mode_state_topic(),
|
||||
if (!this->publish(this->get_fan_mode_state_topic_to(topic_buf),
|
||||
climate_fan_mode_to_mqtt_str(this->device_->fan_mode.value())))
|
||||
success = false;
|
||||
} else if (!this->publish(this->get_fan_mode_state_topic(), "")) {
|
||||
} else if (!this->publish(this->get_fan_mode_state_topic_to(topic_buf), "")) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
if (!this->publish(this->get_swing_mode_state_topic(), climate_swing_mode_to_mqtt_str(this->device_->swing_mode)))
|
||||
if (!this->publish(this->get_swing_mode_state_topic_to(topic_buf),
|
||||
climate_swing_mode_to_mqtt_str(this->device_->swing_mode)))
|
||||
success = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,11 @@ void log_mqtt_component(const char *tag, MQTTComponent *obj, bool state_topic, b
|
||||
\
|
||||
public: \
|
||||
void set_custom_##name##_##type##_topic(const std::string &topic) { this->custom_##name##_##type##_topic_ = topic; } \
|
||||
StringRef get_##name##_##type##_topic_to(std::span<char, MQTT_DEFAULT_TOPIC_MAX_LEN> buf) const { \
|
||||
if (!this->custom_##name##_##type##_topic_.empty()) \
|
||||
return StringRef(this->custom_##name##_##type##_topic_.data(), this->custom_##name##_##type##_topic_.size()); \
|
||||
return this->get_default_topic_for_to_(buf, #name "/" #type, sizeof(#name "/" #type) - 1); \
|
||||
} \
|
||||
std::string get_##name##_##type##_topic() const { \
|
||||
if (this->custom_##name##_##type##_topic_.empty()) \
|
||||
return this->get_default_topic_for_(#name "/" #type); \
|
||||
|
||||
@@ -112,19 +112,19 @@ bool MQTTCoverComponent::send_initial_state() { return this->publish_state(); }
|
||||
bool MQTTCoverComponent::publish_state() {
|
||||
auto traits = this->cover_->get_traits();
|
||||
bool success = true;
|
||||
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
|
||||
if (traits.get_supports_position()) {
|
||||
char pos[VALUE_ACCURACY_MAX_LEN];
|
||||
size_t len = value_accuracy_to_buf(pos, roundf(this->cover_->position * 100), 0);
|
||||
if (!this->publish(this->get_position_state_topic(), pos, len))
|
||||
if (!this->publish(this->get_position_state_topic_to(topic_buf), pos, len))
|
||||
success = false;
|
||||
}
|
||||
if (traits.get_supports_tilt()) {
|
||||
char pos[VALUE_ACCURACY_MAX_LEN];
|
||||
size_t len = value_accuracy_to_buf(pos, roundf(this->cover_->tilt * 100), 0);
|
||||
if (!this->publish(this->get_tilt_state_topic(), pos, len))
|
||||
if (!this->publish(this->get_tilt_state_topic_to(topic_buf), pos, len))
|
||||
success = false;
|
||||
}
|
||||
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
|
||||
if (!this->publish(this->get_state_topic_to_(topic_buf),
|
||||
cover_state_to_mqtt_str(this->cover_->current_operation, this->cover_->position,
|
||||
traits.get_supports_position())))
|
||||
|
||||
@@ -173,19 +173,20 @@ bool MQTTFanComponent::publish_state() {
|
||||
this->publish(this->get_state_topic_to_(topic_buf), state_s);
|
||||
bool failed = false;
|
||||
if (this->state_->get_traits().supports_direction()) {
|
||||
bool success = this->publish(this->get_direction_state_topic(), fan_direction_to_mqtt_str(this->state_->direction));
|
||||
bool success = this->publish(this->get_direction_state_topic_to(topic_buf),
|
||||
fan_direction_to_mqtt_str(this->state_->direction));
|
||||
failed = failed || !success;
|
||||
}
|
||||
if (this->state_->get_traits().supports_oscillation()) {
|
||||
bool success =
|
||||
this->publish(this->get_oscillation_state_topic(), fan_oscillation_to_mqtt_str(this->state_->oscillating));
|
||||
bool success = this->publish(this->get_oscillation_state_topic_to(topic_buf),
|
||||
fan_oscillation_to_mqtt_str(this->state_->oscillating));
|
||||
failed = failed || !success;
|
||||
}
|
||||
auto traits = this->state_->get_traits();
|
||||
if (traits.supports_speed()) {
|
||||
char buf[12];
|
||||
size_t len = buf_append_printf(buf, sizeof(buf), 0, "%d", this->state_->speed);
|
||||
bool success = this->publish(this->get_speed_level_state_topic(), buf, len);
|
||||
bool success = this->publish(this->get_speed_level_state_topic_to(topic_buf), buf, len);
|
||||
failed = failed || !success;
|
||||
}
|
||||
return !failed;
|
||||
|
||||
@@ -87,13 +87,13 @@ bool MQTTValveComponent::send_initial_state() { return this->publish_state(); }
|
||||
bool MQTTValveComponent::publish_state() {
|
||||
auto traits = this->valve_->get_traits();
|
||||
bool success = true;
|
||||
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
|
||||
if (traits.get_supports_position()) {
|
||||
char pos[VALUE_ACCURACY_MAX_LEN];
|
||||
size_t len = value_accuracy_to_buf(pos, roundf(this->valve_->position * 100), 0);
|
||||
if (!this->publish(this->get_position_state_topic(), pos, len))
|
||||
if (!this->publish(this->get_position_state_topic_to(topic_buf), pos, len))
|
||||
success = false;
|
||||
}
|
||||
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
|
||||
if (!this->publish(this->get_state_topic_to_(topic_buf),
|
||||
valve_state_to_mqtt_str(this->valve_->current_operation, this->valve_->position,
|
||||
traits.get_supports_position())))
|
||||
|
||||
Reference in New Issue
Block a user