Compare commits

..

14 Commits

Author SHA1 Message Date
J. Nick Koston
d95ef154aa Merge branch 'dev' into mqtt_stack_part_2 2026-01-25 22:37:19 -10:00
sebcaps
1c9a9c7536 [mhz19] Fix Uninitialized var warning message (#13526) 2026-01-25 20:07:29 -10:00
J. Nick Koston
e006216ad3 Merge branch 'dev' into mqtt_stack_part_2 2026-01-21 18:37:55 -10:00
J. Nick Koston
d66d05dbfc [mqtt] Use stack buffers for publish_state() topic building 2026-01-21 11:08:06 -10:00
J. Nick Koston
bba447e656 Merge branch 'dev' into mqtt_formatting 2026-01-21 11:06:26 -10:00
J. Nick Koston
77b6720a25 Merge branch 'dev' into mqtt_formatting 2026-01-19 17:40:37 -10:00
J. Nick Koston
2f8f052f43 Merge branch 'dev' into mqtt_formatting 2026-01-18 18:44:11 -10:00
J. Nick Koston
86e70c7e76 more 2026-01-17 07:38:51 -10:00
J. Nick Koston
40025bb277 tweaks to reduce RAM 2026-01-17 07:34:22 -10:00
J. Nick Koston
438bb96687 tweaks to reduce RAM 2026-01-17 07:28:44 -10:00
J. Nick Koston
c1e1325af2 Merge branch 'dev' into mqtt_formatting 2026-01-17 07:24:11 -10:00
pre-commit-ci-lite[bot]
944194e04e [pre-commit.ci lite] apply automatic fixes 2026-01-15 00:02:35 +00:00
J. Nick Koston
d27d6d64da Update esphome/components/mqtt/mqtt_component.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 14:00:57 -10:00
J. Nick Koston
2182d1e9f0 [mqtt] Use stack buffers for discovery message formatting 2026-01-14 13:57:45 -10:00
29 changed files with 140 additions and 97 deletions

View File

@@ -133,8 +133,8 @@ void APIConnection::start() {
return;
}
// Initialize client name with peername (IP address) until Hello message provides actual name
char peername[socket::SOCKADDR_STR_LEN];
this->helper_->set_client_name(this->helper_->get_peername_to(peername), strlen(peername));
const char *peername = this->helper_->get_client_peername();
this->helper_->set_client_name(peername, strlen(peername));
}
APIConnection::~APIConnection() {
@@ -179,8 +179,8 @@ void APIConnection::begin_iterator_(ActiveIterator type) {
void APIConnection::loop() {
if (this->flags_.next_close) {
// requested a disconnect - don't close socket here, let APIServer::loop() do it
// so getpeername() still works for the disconnect trigger
// requested a disconnect
this->helper_->close();
this->flags_.remove = true;
return;
}
@@ -293,8 +293,7 @@ bool APIConnection::send_disconnect_response(const DisconnectRequest &msg) {
return this->send_message(resp, DisconnectResponse::MESSAGE_TYPE);
}
void APIConnection::on_disconnect_response(const DisconnectResponse &value) {
// Don't close socket here, let APIServer::loop() do it
// so getpeername() still works for the disconnect trigger
this->helper_->close();
this->flags_.remove = true;
}
@@ -1525,11 +1524,8 @@ void APIConnection::complete_authentication_() {
this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::AUTHENTICATED);
this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("connected"));
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
{
char peername[socket::SOCKADDR_STR_LEN];
this->parent_->get_client_connected_trigger()->trigger(std::string(this->helper_->get_client_name()),
std::string(this->helper_->get_peername_to(peername)));
}
this->parent_->get_client_connected_trigger()->trigger(std::string(this->helper_->get_client_name()),
std::string(this->helper_->get_client_peername()));
#endif
#ifdef USE_HOMEASSISTANT_TIME
if (homeassistant::global_homeassistant_time != nullptr) {
@@ -1548,9 +1544,8 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) {
this->helper_->set_client_name(msg.client_info.c_str(), msg.client_info.size());
this->client_api_version_major_ = msg.api_version_major;
this->client_api_version_minor_ = msg.api_version_minor;
char peername[socket::SOCKADDR_STR_LEN];
ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->helper_->get_client_name(),
this->helper_->get_peername_to(peername), this->client_api_version_major_, this->client_api_version_minor_);
this->helper_->get_client_peername(), this->client_api_version_major_, this->client_api_version_minor_);
HelloResponse resp;
resp.api_version_major = 1;
@@ -1867,8 +1862,7 @@ void APIConnection::on_no_setup_connection() {
this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("no connection setup"));
}
void APIConnection::on_fatal_error() {
// Don't close socket here - keep it open so getpeername() works for logging
// Socket will be closed when client is removed from the list in APIServer::loop()
this->helper_->close();
this->flags_.remove = true;
}
@@ -2224,14 +2218,12 @@ void APIConnection::process_state_subscriptions_() {
#endif // USE_API_HOMEASSISTANT_STATES
void APIConnection::log_client_(int level, const LogString *message) {
char peername[socket::SOCKADDR_STR_LEN];
esp_log_printf_(level, TAG, __LINE__, ESPHOME_LOG_FORMAT("%s (%s): %s"), this->helper_->get_client_name(),
this->helper_->get_peername_to(peername), LOG_STR_ARG(message));
this->helper_->get_client_peername(), LOG_STR_ARG(message));
}
void APIConnection::log_warning_(const LogString *message, APIError err) {
char peername[socket::SOCKADDR_STR_LEN];
ESP_LOGW(TAG, "%s (%s): %s %s errno=%d", this->helper_->get_client_name(), this->helper_->get_peername_to(peername),
ESP_LOGW(TAG, "%s (%s): %s %s errno=%d", this->helper_->get_client_name(), this->helper_->get_client_peername(),
LOG_STR_ARG(message), LOG_STR_ARG(api_error_to_logstr(err)), errno);
}

View File

@@ -281,10 +281,8 @@ class APIConnection final : public APIServerConnection {
bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override;
const char *get_name() const { return this->helper_->get_client_name(); }
/// Get peer name (IP address) into caller-provided buffer, returns buf for convenience
const char *get_peername_to(std::span<char, socket::SOCKADDR_STR_LEN> buf) const {
return this->helper_->get_peername_to(buf);
}
/// Get peer name (IP address) - cached at connection init time
const char *get_peername() const { return this->helper_->get_client_peername(); }
protected:
// Helper function to handle authentication completion

View File

@@ -16,12 +16,7 @@ static const char *const TAG = "api.frame_helper";
static constexpr size_t API_MAX_LOG_BYTES = 168;
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
#define HELPER_LOG(msg, ...) \
do { \
char peername_buf[socket::SOCKADDR_STR_LEN]; \
this->get_peername_to(peername_buf); \
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername_buf, ##__VA_ARGS__); \
} while (0)
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif
@@ -245,20 +240,13 @@ APIError APIFrameHelper::try_send_tx_buf_() {
return APIError::OK; // All buffers sent successfully
}
const char *APIFrameHelper::get_peername_to(std::span<char, socket::SOCKADDR_STR_LEN> buf) const {
if (this->socket_) {
this->socket_->getpeername_to(buf);
} else {
buf[0] = '\0';
}
return buf.data();
}
APIError APIFrameHelper::init_common_() {
if (state_ != State::INITIALIZE || this->socket_ == nullptr) {
HELPER_LOG("Bad state for init %d", (int) state_);
return APIError::BAD_STATE;
}
// Cache peername now while socket is valid - needed for error logging after socket failure
this->socket_->getpeername_to(this->client_peername_);
int err = this->socket_->setblocking(false);
if (err != 0) {
state_ = State::FAILED;

View File

@@ -90,9 +90,8 @@ class APIFrameHelper {
// Get client name (null-terminated)
const char *get_client_name() const { return this->client_name_; }
// Get client peername/IP into caller-provided buffer (fetches on-demand from socket)
// Returns pointer to buf for convenience in printf-style calls
const char *get_peername_to(std::span<char, socket::SOCKADDR_STR_LEN> buf) const;
// Get client peername/IP (null-terminated, cached at init time for availability after socket failure)
const char *get_client_peername() const { return this->client_peername_; }
// Set client name from buffer with length (truncates if needed)
void set_client_name(const char *name, size_t len) {
size_t copy_len = std::min(len, sizeof(this->client_name_) - 1);
@@ -106,8 +105,6 @@ class APIFrameHelper {
bool can_write_without_blocking() { return this->state_ == State::DATA && this->tx_buf_count_ == 0; }
int getpeername(struct sockaddr *addr, socklen_t *addrlen) { return socket_->getpeername(addr, addrlen); }
APIError close() {
if (state_ == State::CLOSED)
return APIError::OK; // Already closed
state_ = State::CLOSED;
int err = this->socket_->close();
if (err == -1)
@@ -234,6 +231,8 @@ class APIFrameHelper {
// Client name buffer - stores name from Hello message or initial peername
char client_name_[CLIENT_INFO_NAME_MAX_LEN]{};
// Cached peername/IP address - captured at init time for availability after socket failure
char client_peername_[socket::SOCKADDR_STR_LEN]{};
// Group smaller types together
uint16_t rx_buf_len_ = 0;

View File

@@ -29,12 +29,7 @@ static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit")
static constexpr size_t API_MAX_LOG_BYTES = 168;
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
#define HELPER_LOG(msg, ...) \
do { \
char peername_buf[socket::SOCKADDR_STR_LEN]; \
this->get_peername_to(peername_buf); \
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername_buf, ##__VA_ARGS__); \
} while (0)
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif

View File

@@ -21,12 +21,7 @@ static const char *const TAG = "api.plaintext";
static constexpr size_t API_MAX_LOG_BYTES = 168;
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
#define HELPER_LOG(msg, ...) \
do { \
char peername_buf[socket::SOCKADDR_STR_LEN]; \
this->get_peername_to(peername_buf); \
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername_buf, ##__VA_ARGS__); \
} while (0)
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif

View File

@@ -192,15 +192,11 @@ void APIServer::loop() {
ESP_LOGV(TAG, "Remove connection %s", client->get_name());
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
// Save client info before closing socket and removal for the trigger
char peername_buf[socket::SOCKADDR_STR_LEN];
// Save client info before removal for the trigger
std::string client_name(client->get_name());
std::string client_peername(client->get_peername_to(peername_buf));
std::string client_peername(client->get_peername());
#endif
// Close socket now (was deferred from on_fatal_error to allow getpeername)
client->helper_->close();
// Swap with the last element and pop (avoids expensive vector shifts)
if (client_index < this->clients_.size() - 1) {
std::swap(this->clients_[client_index], this->clients_.back());

View File

@@ -155,6 +155,9 @@ void MHZ19Component::dump_config() {
case MHZ19_DETECTION_RANGE_0_10000PPM:
range_str = "0 to 10000ppm";
break;
default:
range_str = "default";
break;
}
ESP_LOGCONFIG(TAG, " Detection range: %s", range_str);
}

View File

@@ -119,7 +119,8 @@ bool MQTTAlarmControlPanelComponent::publish_state() {
default:
state_s = "unknown";
}
return this->publish(this->get_state_topic_(), state_s);
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
return this->publish(this->get_state_topic_to_(topic_buf), state_s);
}
} // namespace esphome::mqtt

View File

@@ -52,8 +52,9 @@ bool MQTTBinarySensorComponent::publish_state(bool state) {
if (this->binary_sensor_->is_status_binary_sensor())
return true;
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
const char *state_s = state ? "ON" : "OFF";
return this->publish(this->get_state_topic_(), state_s);
return this->publish(this->get_state_topic_to_(topic_buf), state_s);
}
} // namespace esphome::mqtt

View File

@@ -132,17 +132,29 @@ std::string MQTTComponent::get_command_topic_() const {
}
bool MQTTComponent::publish(const std::string &topic, const std::string &payload) {
return this->publish(topic, payload.data(), payload.size());
return this->publish(topic.c_str(), payload.data(), payload.size());
}
bool MQTTComponent::publish(const std::string &topic, const char *payload, size_t payload_length) {
if (topic.empty())
return this->publish(topic.c_str(), payload, payload_length);
}
bool MQTTComponent::publish(const char *topic, const char *payload, size_t payload_length) {
if (topic[0] == '\0')
return false;
return global_mqtt_client->publish(topic, payload, payload_length, this->qos_, this->retain_);
}
bool MQTTComponent::publish(const char *topic, const char *payload) {
return this->publish(topic, payload, strlen(payload));
}
bool MQTTComponent::publish_json(const std::string &topic, const json::json_build_t &f) {
if (topic.empty())
return this->publish_json(topic.c_str(), f);
}
bool MQTTComponent::publish_json(const char *topic, const json::json_build_t &f) {
if (topic[0] == '\0')
return false;
return global_mqtt_client->publish_json(topic, f, this->qos_, this->retain_);
}

View File

@@ -157,6 +157,38 @@ class MQTTComponent : public Component {
*/
bool publish(const std::string &topic, const char *payload, size_t payload_length);
/** Send a MQTT message (no heap allocation for topic).
*
* @param topic The topic as C string.
* @param payload The payload buffer.
* @param payload_length The length of the payload.
*/
bool publish(const char *topic, const char *payload, size_t payload_length);
/** Send a MQTT message (no heap allocation for topic).
*
* @param topic The topic as StringRef (for use with get_state_topic_to_()).
* @param payload The payload buffer.
* @param payload_length The length of the payload.
*/
bool publish(StringRef topic, const char *payload, size_t payload_length) {
return this->publish(topic.c_str(), payload, payload_length);
}
/** Send a MQTT message (no heap allocation for topic).
*
* @param topic The topic as C string.
* @param payload The null-terminated payload.
*/
bool publish(const char *topic, const char *payload);
/** Send a MQTT message (no heap allocation for topic).
*
* @param topic The topic as StringRef (for use with get_state_topic_to_()).
* @param payload The null-terminated payload.
*/
bool publish(StringRef topic, const char *payload) { return this->publish(topic.c_str(), payload); }
/** Construct and send a JSON MQTT message.
*
* @param topic The topic.
@@ -164,6 +196,20 @@ class MQTTComponent : public Component {
*/
bool publish_json(const std::string &topic, const json::json_build_t &f);
/** Construct and send a JSON MQTT message (no heap allocation for topic).
*
* @param topic The topic as C string.
* @param f The Json Message builder.
*/
bool publish_json(const char *topic, const json::json_build_t &f);
/** Construct and send a JSON MQTT message (no heap allocation for topic).
*
* @param topic The topic as StringRef (for use with get_state_topic_to_()).
* @param f The Json Message builder.
*/
bool publish_json(StringRef topic, const json::json_build_t &f) { return this->publish_json(topic.c_str(), f); }
/** Subscribe to a MQTT topic.
*
* @param topic The topic. Wildcards are currently not supported.

View File

@@ -115,7 +115,8 @@ bool MQTTCoverComponent::publish_state() {
: this->cover_->position == COVER_OPEN ? "open"
: traits.get_supports_position() ? "open"
: "unknown";
if (!this->publish(this->get_state_topic_(), state_s))
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
if (!this->publish(this->get_state_topic_to_(topic_buf), state_s))
success = false;
return success;
}

View File

@@ -53,7 +53,8 @@ bool MQTTDateComponent::send_initial_state() {
}
}
bool MQTTDateComponent::publish_state(uint16_t year, uint8_t month, uint8_t day) {
return this->publish_json(this->get_state_topic_(), [year, month, day](JsonObject root) {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
return this->publish_json(this->get_state_topic_to_(topic_buf), [year, month, day](JsonObject root) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
root[ESPHOME_F("year")] = year;
root[ESPHOME_F("month")] = month;

View File

@@ -66,15 +66,17 @@ bool MQTTDateTimeComponent::send_initial_state() {
}
bool MQTTDateTimeComponent::publish_state(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute,
uint8_t second) {
return this->publish_json(this->get_state_topic_(), [year, month, day, hour, minute, second](JsonObject root) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
root[ESPHOME_F("year")] = year;
root[ESPHOME_F("month")] = month;
root[ESPHOME_F("day")] = day;
root[ESPHOME_F("hour")] = hour;
root[ESPHOME_F("minute")] = minute;
root[ESPHOME_F("second")] = second;
});
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
return this->publish_json(this->get_state_topic_to_(topic_buf),
[year, month, day, hour, minute, second](JsonObject root) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
root[ESPHOME_F("year")] = year;
root[ESPHOME_F("month")] = month;
root[ESPHOME_F("day")] = day;
root[ESPHOME_F("hour")] = hour;
root[ESPHOME_F("minute")] = minute;
root[ESPHOME_F("second")] = second;
});
}
} // namespace esphome::mqtt

View File

@@ -44,7 +44,8 @@ void MQTTEventComponent::dump_config() {
}
bool MQTTEventComponent::publish_event_(const std::string &event_type) {
return this->publish_json(this->get_state_topic_(), [event_type](JsonObject root) {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
return this->publish_json(this->get_state_topic_to_(topic_buf), [event_type](JsonObject root) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
root[MQTT_EVENT_TYPE] = event_type;
});

View File

@@ -158,9 +158,10 @@ void MQTTFanComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig
}
}
bool MQTTFanComponent::publish_state() {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
const char *state_s = this->state_->state ? "ON" : "OFF";
ESP_LOGD(TAG, "'%s' Sending state %s.", this->state_->get_name().c_str(), state_s);
this->publish(this->get_state_topic_(), state_s);
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(),

View File

@@ -34,7 +34,8 @@ void MQTTJSONLightComponent::on_light_remote_values_update() {
MQTTJSONLightComponent::MQTTJSONLightComponent(LightState *state) : state_(state) {}
bool MQTTJSONLightComponent::publish_state_() {
return this->publish_json(this->get_state_topic_(), [this](JsonObject root) {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
return this->publish_json(this->get_state_topic_to_(topic_buf), [this](JsonObject root) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
LightJSONSchema::dump_json(*this->state_, root);
});

View File

@@ -47,13 +47,14 @@ void MQTTLockComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfi
bool MQTTLockComponent::send_initial_state() { return this->publish_state(); }
bool MQTTLockComponent::publish_state() {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
#ifdef USE_STORE_LOG_STR_IN_FLASH
char buf[LOCK_STATE_STR_SIZE];
strncpy_P(buf, (PGM_P) lock_state_to_string(this->lock_->state), sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
return this->publish(this->get_state_topic_(), buf);
return this->publish(this->get_state_topic_to_(topic_buf), buf);
#else
return this->publish(this->get_state_topic_(), LOG_STR_ARG(lock_state_to_string(this->lock_->state)));
return this->publish(this->get_state_topic_to_(topic_buf), LOG_STR_ARG(lock_state_to_string(this->lock_->state)));
#endif
}

View File

@@ -74,9 +74,10 @@ bool MQTTNumberComponent::send_initial_state() {
}
}
bool MQTTNumberComponent::publish_state(float value) {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
char buffer[64];
buf_append_printf(buffer, sizeof(buffer), 0, "%f", value);
return this->publish(this->get_state_topic_(), buffer);
size_t len = buf_append_printf(buffer, sizeof(buffer), 0, "%f", value);
return this->publish(this->get_state_topic_to_(topic_buf), buffer, len);
}
} // namespace esphome::mqtt

View File

@@ -50,7 +50,8 @@ bool MQTTSelectComponent::send_initial_state() {
}
}
bool MQTTSelectComponent::publish_state(const std::string &value) {
return this->publish(this->get_state_topic_(), value);
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
return this->publish(this->get_state_topic_to_(topic_buf), value.data(), value.size());
}
} // namespace esphome::mqtt

View File

@@ -79,12 +79,13 @@ bool MQTTSensorComponent::send_initial_state() {
}
}
bool MQTTSensorComponent::publish_state(float value) {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
if (mqtt::global_mqtt_client->is_publish_nan_as_none() && std::isnan(value))
return this->publish(this->get_state_topic_(), "None", 4);
return this->publish(this->get_state_topic_to_(topic_buf), "None", 4);
int8_t accuracy = this->sensor_->get_accuracy_decimals();
char buf[VALUE_ACCURACY_MAX_LEN];
size_t len = value_accuracy_to_buf(buf, value, accuracy);
return this->publish(this->get_state_topic_(), buf, len);
return this->publish(this->get_state_topic_to_(topic_buf), buf, len);
}
} // namespace esphome::mqtt

View File

@@ -52,8 +52,9 @@ void MQTTSwitchComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCon
bool MQTTSwitchComponent::send_initial_state() { return this->publish_state(this->switch_->state); }
bool MQTTSwitchComponent::publish_state(bool state) {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
const char *state_s = state ? "ON" : "OFF";
return this->publish(this->get_state_topic_(), state_s);
return this->publish(this->get_state_topic_to_(topic_buf), state_s);
}
} // namespace esphome::mqtt

View File

@@ -53,7 +53,8 @@ bool MQTTTextComponent::send_initial_state() {
}
}
bool MQTTTextComponent::publish_state(const std::string &value) {
return this->publish(this->get_state_topic_(), value);
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
return this->publish(this->get_state_topic_to_(topic_buf), value.data(), value.size());
}
} // namespace esphome::mqtt

View File

@@ -31,7 +31,10 @@ void MQTTTextSensor::dump_config() {
LOG_MQTT_COMPONENT(true, false);
}
bool MQTTTextSensor::publish_state(const std::string &value) { return this->publish(this->get_state_topic_(), value); }
bool MQTTTextSensor::publish_state(const std::string &value) {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
return this->publish(this->get_state_topic_to_(topic_buf), value.data(), value.size());
}
bool MQTTTextSensor::send_initial_state() {
if (this->sensor_->has_state()) {
return this->publish_state(this->sensor_->state);

View File

@@ -53,7 +53,8 @@ bool MQTTTimeComponent::send_initial_state() {
}
}
bool MQTTTimeComponent::publish_state(uint8_t hour, uint8_t minute, uint8_t second) {
return this->publish_json(this->get_state_topic_(), [hour, minute, second](JsonObject root) {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
return this->publish_json(this->get_state_topic_to_(topic_buf), [hour, minute, second](JsonObject root) {
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
root[ESPHOME_F("hour")] = hour;
root[ESPHOME_F("minute")] = minute;

View File

@@ -28,7 +28,8 @@ void MQTTUpdateComponent::setup() {
}
bool MQTTUpdateComponent::publish_state() {
return this->publish_json(this->get_state_topic_(), [this](JsonObject root) {
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
return this->publish_json(this->get_state_topic_to_(topic_buf), [this](JsonObject root) {
root[ESPHOME_F("installed_version")] = this->update_->update_info.current_version;
root[ESPHOME_F("latest_version")] = this->update_->update_info.latest_version;
root[ESPHOME_F("title")] = this->update_->update_info.title;

View File

@@ -84,7 +84,8 @@ bool MQTTValveComponent::publish_state() {
: this->valve_->position == VALVE_OPEN ? "open"
: traits.get_supports_position() ? "open"
: "unknown";
if (!this->publish(this->get_state_topic_(), state_s))
char topic_buf[MQTT_DEFAULT_TOPIC_MAX_LEN];
if (!this->publish(this->get_state_topic_to_(topic_buf), state_s))
success = false;
return success;
}

View File

@@ -430,14 +430,12 @@ void VoiceAssistant::client_subscription(api::APIConnection *client, bool subscr
}
if (this->api_client_ != nullptr) {
char current_peername[socket::SOCKADDR_STR_LEN];
char new_peername[socket::SOCKADDR_STR_LEN];
ESP_LOGE(TAG,
"Multiple API Clients attempting to connect to Voice Assistant\n"
"Current client: %s (%s)\n"
"New client: %s (%s)",
this->api_client_->get_name(), this->api_client_->get_peername_to(current_peername), client->get_name(),
client->get_peername_to(new_peername));
this->api_client_->get_name(), this->api_client_->get_peername(), client->get_name(),
client->get_peername());
return;
}