Compare commits

..

4 Commits

11 changed files with 37 additions and 78 deletions

View File

@@ -1,6 +1,6 @@
#include "am43_base.h"
#include "esphome/core/helpers.h"
#include <cstring>
#include <cstdio>
namespace esphome {
namespace am43 {
@@ -8,12 +8,9 @@ namespace am43 {
const uint8_t START_PACKET[5] = {0x00, 0xff, 0x00, 0x00, 0x9a};
std::string pkt_to_hex(const uint8_t *data, uint16_t len) {
char buf[64];
memset(buf, 0, 64);
for (int i = 0; i < len; i++)
sprintf(&buf[i * 2], "%02x", data[i]);
std::string ret = buf;
return ret;
char buf[64]; // format_hex_size(31) = 63, fits 31 bytes of hex data
format_hex_to(buf, sizeof(buf), data, len);
return buf;
}
Am43Packet *Am43Encoder::get_battery_level_request() {

View File

@@ -18,31 +18,31 @@ AnovaPacket *AnovaCodec::clean_packet_() {
AnovaPacket *AnovaCodec::get_read_device_status_request() {
this->current_query_ = READ_DEVICE_STATUS;
snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_READ_DEVICE_STATUS);
sprintf((char *) this->packet_.data, "%s", CMD_READ_DEVICE_STATUS);
return this->clean_packet_();
}
AnovaPacket *AnovaCodec::get_read_target_temp_request() {
this->current_query_ = READ_TARGET_TEMPERATURE;
snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_READ_TARGET_TEMP);
sprintf((char *) this->packet_.data, "%s", CMD_READ_TARGET_TEMP);
return this->clean_packet_();
}
AnovaPacket *AnovaCodec::get_read_current_temp_request() {
this->current_query_ = READ_CURRENT_TEMPERATURE;
snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_READ_CURRENT_TEMP);
sprintf((char *) this->packet_.data, "%s", CMD_READ_CURRENT_TEMP);
return this->clean_packet_();
}
AnovaPacket *AnovaCodec::get_read_unit_request() {
this->current_query_ = READ_UNIT;
snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_READ_UNIT);
sprintf((char *) this->packet_.data, "%s", CMD_READ_UNIT);
return this->clean_packet_();
}
AnovaPacket *AnovaCodec::get_read_data_request() {
this->current_query_ = READ_DATA;
snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_READ_DATA);
sprintf((char *) this->packet_.data, "%s", CMD_READ_DATA);
return this->clean_packet_();
}
@@ -50,25 +50,25 @@ AnovaPacket *AnovaCodec::get_set_target_temp_request(float temperature) {
this->current_query_ = SET_TARGET_TEMPERATURE;
if (this->fahrenheit_)
temperature = ctof(temperature);
snprintf((char *) this->packet_.data, sizeof(this->packet_.data), CMD_SET_TARGET_TEMP, temperature);
sprintf((char *) this->packet_.data, CMD_SET_TARGET_TEMP, temperature);
return this->clean_packet_();
}
AnovaPacket *AnovaCodec::get_set_unit_request(char unit) {
this->current_query_ = SET_UNIT;
snprintf((char *) this->packet_.data, sizeof(this->packet_.data), CMD_SET_TEMP_UNIT, unit);
sprintf((char *) this->packet_.data, CMD_SET_TEMP_UNIT, unit);
return this->clean_packet_();
}
AnovaPacket *AnovaCodec::get_start_request() {
this->current_query_ = START;
snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_START);
sprintf((char *) this->packet_.data, CMD_START);
return this->clean_packet_();
}
AnovaPacket *AnovaCodec::get_stop_request() {
this->current_query_ = STOP;
snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_STOP);
sprintf((char *) this->packet_.data, CMD_STOP);
return this->clean_packet_();
}

View File

@@ -1715,7 +1715,7 @@ void APIConnection::on_home_assistant_state_response(const HomeAssistantStateRes
// HA state max length is 255 characters, but attributes can be much longer
// Use stack buffer for common case (states), heap fallback for large attributes
size_t state_len = msg.state.size();
SmallBufferWithHeapFallback<MAX_STATE_LEN + 1> state_buf_alloc(state_len + 1);
SmallBufferWithHeapFallback<256> state_buf_alloc(state_len + 1);
char *state_buf = reinterpret_cast<char *>(state_buf_alloc.get());
if (state_len > 0) {
memcpy(state_buf, msg.state.c_str(), state_len);

View File

@@ -25,9 +25,7 @@ template<typename... X> class TemplatableStringValue : public TemplatableValue<s
private:
// Helper to convert value to string - handles the case where value is already a string
template<typename T> static std::string value_to_string(T &&val) {
return to_string(std::forward<T>(val));
} // NOLINT
template<typename T> static std::string value_to_string(T &&val) { return to_string(std::forward<T>(val)); }
// Overloads for string types - needed because std::to_string doesn't support them
static std::string value_to_string(char *val) {

View File

@@ -46,7 +46,7 @@ class ESPBTUUID {
esp_bt_uuid_t get_uuid() const;
std::string to_string() const; // NOLINT
std::string to_string() const;
const char *to_str(std::span<char, UUID_STR_LEN> output) const;
protected:

View File

@@ -1,3 +1,4 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#ifdef USE_ESP8266
@@ -44,13 +45,16 @@ void LightWaveRF::send_rx(const std::vector<uint8_t> &msg, uint8_t repeats, bool
}
void LightWaveRF::print_msg_(uint8_t *msg, uint8_t len) {
char buffer[65];
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
char buffer[65]; // max 10 entries * 6 chars + null
ESP_LOGD(TAG, " Received code (len:%i): ", len);
size_t pos = 0;
for (int i = 0; i < len; i++) {
sprintf(&buffer[i * 6], "0x%02x, ", msg[i]);
pos = buf_append_printf(buffer, sizeof(buffer), pos, "0x%02x, ", msg[i]);
}
ESP_LOGD(TAG, "[%s]", buffer);
#endif
}
void LightWaveRF::dump_config() {

View File

@@ -1,6 +1,7 @@
#include "rf_bridge.h"
#include "esphome/core/log.h"
#include "esphome/core/application.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include <cinttypes>
#include <cstring>
@@ -72,9 +73,9 @@ bool RFBridgeComponent::parse_bridge_byte_(uint8_t byte) {
data.length = raw[2];
data.protocol = raw[3];
char next_byte[3];
char next_byte[3]; // 2 hex chars + null
for (uint8_t i = 0; i < data.length - 1; i++) {
sprintf(next_byte, "%02X", raw[4 + i]);
buf_append_printf(next_byte, sizeof(next_byte), 0, "%02X", raw[4 + i]);
data.code += next_byte;
}
@@ -90,10 +91,10 @@ bool RFBridgeComponent::parse_bridge_byte_(uint8_t byte) {
uint8_t buckets = raw[2] << 1;
std::string str;
char next_byte[3];
char next_byte[3]; // 2 hex chars + null
for (uint32_t i = 0; i <= at; i++) {
sprintf(next_byte, "%02X", raw[i]);
buf_append_printf(next_byte, sizeof(next_byte), 0, "%02X", raw[i]);
str += next_byte;
if ((i > 3) && buckets) {
buckets--;

View File

@@ -52,7 +52,7 @@ void SHTCXComponent::dump_config() {
ESP_LOGCONFIG(TAG,
"SHTCx:\n"
" Model: %s (%04x)",
to_string(this->type_), this->sensor_id_); // NOLINT
to_string(this->type_), this->sensor_id_);
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);

View File

@@ -1,4 +1,5 @@
#include "spi_led_strip.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace spi_led_strip {
@@ -47,15 +48,14 @@ void SpiLedStrip::dump_config() {
void SpiLedStrip::write_state(light::LightState *state) {
if (this->is_failed())
return;
if (ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE) {
char strbuf[49];
size_t len = std::min(this->buffer_size_, (size_t) (sizeof(strbuf) - 1) / 3);
memset(strbuf, 0, sizeof(strbuf));
for (size_t i = 0; i != len; i++) {
sprintf(strbuf + i * 3, "%02X ", this->buf_[i]);
}
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
{
char strbuf[49]; // format_hex_pretty_size(16) = 48, fits 16 bytes
size_t len = std::min(this->buffer_size_, (size_t) 16);
format_hex_pretty_to(strbuf, sizeof(strbuf), this->buf_, len, ' ');
esph_log_v(TAG, "write_state: buf = %s", strbuf);
}
#endif
this->enable();
this->write_array(this->buf_, this->buffer_size_);
this->disable();

View File

@@ -81,7 +81,7 @@ struct Timer {
this->id.c_str(), this->name.c_str(), this->total_seconds, this->seconds_left, YESNO(this->is_active));
return buffer.data();
}
std::string to_string() const { // NOLINT
std::string to_string() const {
char buffer[TO_STR_BUFFER_SIZE];
return this->to_str(buffer);
}

View File

@@ -732,47 +732,6 @@ def lint_no_heap_allocating_helpers(fname, match):
)
@lint_re_check(
# Match std::to_string() or unqualified to_string() calls
# The esphome namespace has "using std::to_string;" so unqualified calls resolve to std::to_string
# Use negative lookbehind to avoid matching:
# - Function definitions: "const char *to_string(" or "std::string to_string("
# - Method definitions: "Class::to_string("
# - Method calls: ".to_string(" or "->to_string("
# - Other identifiers: "_to_string("
r"(?<![*&.\w>:])to_string\s*\(" + CPP_RE_EOL,
include=cpp_include,
exclude=[
# Vendored library
"esphome/components/http_request/httplib.h",
# Deprecated helpers that return std::string
"esphome/core/helpers.cpp",
# The using declaration itself
"esphome/core/helpers.h",
# Test fixtures - not production embedded code
"tests/integration/fixtures/*",
],
)
def lint_no_std_to_string(fname, match):
return (
f"{highlight('std::to_string()')} allocates heap memory. On long-running embedded "
f"devices, repeated heap allocations fragment memory over time.\n"
f"Please use {highlight('snprintf()')} with a stack buffer instead.\n"
f"\n"
f"Buffer sizes and format specifiers:\n"
f" uint8_t/int8_t: 4 chars - %u / %d (or PRIu8/PRId8)\n"
f" uint16_t/int16_t: 6 chars - %u / %d (or PRIu16/PRId16)\n"
f" uint32_t/int32_t: 11 chars - %" + "PRIu32 / %" + "PRId32\n"
" uint64_t/int64_t: 21 chars - %" + "PRIu64 / %" + "PRId64\n"
f" float/double: 24 chars - %.8g (15 digits + sign + decimal + e+XXX)\n"
f" 317 chars - %f (for DBL_MAX: 309 int digits + decimal + 6 frac + sign)\n"
f"\n"
f"For sensor values, use value_accuracy_to_buf() from helpers.h.\n"
f'Example: char buf[11]; snprintf(buf, sizeof(buf), "%" PRIu32, value);\n'
f"(If strictly necessary, add `{highlight('// NOLINT')}` to the end of the line)"
)
@lint_content_find_check(
"ESP_LOG",
include=["*.h", "*.tcc"],