mirror of
https://github.com/esphome/esphome.git
synced 2026-01-20 18:09:10 -07:00
Compare commits
8 Commits
ard_debug_
...
no_new_to_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11fb46ad11 | ||
|
|
9245c691d0 | ||
|
|
c213de4861 | ||
|
|
6cf320fd60 | ||
|
|
aeea340bc6 | ||
|
|
d0e50ed030 | ||
|
|
280d460025 | ||
|
|
971a1a3e00 |
@@ -25,7 +25,9 @@ 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)); }
|
||||
template<typename T> static std::string value_to_string(T &&val) {
|
||||
return to_string(std::forward<T>(val)); // NOLINT
|
||||
}
|
||||
|
||||
// Overloads for string types - needed because std::to_string doesn't support them
|
||||
static std::string value_to_string(char *val) {
|
||||
|
||||
@@ -76,7 +76,6 @@ class CS5460AComponent : public Component,
|
||||
void restart() { restart_(); }
|
||||
|
||||
void setup() override;
|
||||
void loop() override {}
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -48,7 +48,7 @@ class ESPBTUUID {
|
||||
|
||||
// Remove before 2026.8.0
|
||||
ESPDEPRECATED("Use to_str() instead. Removed in 2026.8.0", "2026.2.0")
|
||||
std::string to_string() const;
|
||||
std::string to_string() const; // NOLINT
|
||||
const char *to_str(std::span<char, UUID_STR_LEN> output) const;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -28,16 +28,14 @@ const LogString *lock_state_to_string(LockState state) {
|
||||
Lock::Lock() : state(LOCK_STATE_NONE) {}
|
||||
LockCall Lock::make_call() { return LockCall(this); }
|
||||
|
||||
void Lock::lock() {
|
||||
void Lock::set_state_(LockState state) {
|
||||
auto call = this->make_call();
|
||||
call.set_state(LOCK_STATE_LOCKED);
|
||||
this->control(call);
|
||||
}
|
||||
void Lock::unlock() {
|
||||
auto call = this->make_call();
|
||||
call.set_state(LOCK_STATE_UNLOCKED);
|
||||
call.set_state(state);
|
||||
this->control(call);
|
||||
}
|
||||
|
||||
void Lock::lock() { this->set_state_(LOCK_STATE_LOCKED); }
|
||||
void Lock::unlock() { this->set_state_(LOCK_STATE_UNLOCKED); }
|
||||
void Lock::open() {
|
||||
if (traits.get_supports_open()) {
|
||||
ESP_LOGD(TAG, "'%s' Opening.", this->get_name().c_str());
|
||||
|
||||
@@ -156,6 +156,9 @@ class Lock : public EntityBase {
|
||||
protected:
|
||||
friend LockCall;
|
||||
|
||||
/// Helper for lock/unlock convenience methods
|
||||
void set_state_(LockState state);
|
||||
|
||||
/** Perform the open latch action with hardware. This method is optional to implement
|
||||
* when creating a new lock.
|
||||
*
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <cinttypes>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
@@ -43,8 +44,17 @@ template<typename K, typename V> class Mapping {
|
||||
esph_log_e(TAG, "Key '%p' not found in mapping", key);
|
||||
} else if constexpr (std::is_same_v<K, std::string>) {
|
||||
esph_log_e(TAG, "Key '%s' not found in mapping", key.c_str());
|
||||
} else if constexpr (std::is_integral_v<K>) {
|
||||
char buf[24]; // enough for 64-bit integer
|
||||
if constexpr (std::is_unsigned_v<K>) {
|
||||
buf_append_printf(buf, sizeof(buf), 0, "%" PRIu64, static_cast<uint64_t>(key));
|
||||
} else {
|
||||
buf_append_printf(buf, sizeof(buf), 0, "%" PRId64, static_cast<int64_t>(key));
|
||||
}
|
||||
esph_log_e(TAG, "Key '%s' not found in mapping", buf);
|
||||
} else {
|
||||
esph_log_e(TAG, "Key '%s' not found in mapping", to_string(key).c_str());
|
||||
// All supported key types are handled above - this should never be reached
|
||||
static_assert(sizeof(K) == 0, "Unsupported key type for Mapping error logging");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -403,6 +403,12 @@ void MQTTClientComponent::loop() {
|
||||
|
||||
this->last_connected_ = now;
|
||||
this->resubscribe_subscriptions_();
|
||||
|
||||
// Process pending resends for all MQTT components centrally
|
||||
// This is more efficient than each component polling in its own loop
|
||||
for (MQTTComponent *component : this->children_) {
|
||||
component->process_resend();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -308,16 +308,12 @@ void MQTTComponent::call_setup() {
|
||||
}
|
||||
}
|
||||
|
||||
void MQTTComponent::call_loop() {
|
||||
if (this->is_internal())
|
||||
void MQTTComponent::process_resend() {
|
||||
// Called by MQTTClientComponent when connected to process pending resends
|
||||
// Note: is_internal() check not needed - internal components are never registered
|
||||
if (!this->resend_state_)
|
||||
return;
|
||||
|
||||
this->loop();
|
||||
|
||||
if (!this->resend_state_ || !this->is_connected_()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->resend_state_ = false;
|
||||
if (this->is_discovery_enabled()) {
|
||||
if (!this->send_discovery_()) {
|
||||
|
||||
@@ -81,8 +81,6 @@ class MQTTComponent : public Component {
|
||||
/// Override setup_ so that we can call send_discovery() when needed.
|
||||
void call_setup() override;
|
||||
|
||||
void call_loop() override;
|
||||
|
||||
void call_dump_config() override;
|
||||
|
||||
/// Send discovery info the Home Assistant, override this.
|
||||
@@ -133,6 +131,9 @@ class MQTTComponent : public Component {
|
||||
/// Internal method for the MQTT client base to schedule a resend of the state on reconnect.
|
||||
void schedule_resend_state();
|
||||
|
||||
/// Process pending resend if needed (called by MQTTClientComponent)
|
||||
void process_resend();
|
||||
|
||||
/** Send a MQTT message.
|
||||
*
|
||||
* @param topic The topic.
|
||||
|
||||
@@ -114,14 +114,22 @@ void StatsdComponent::update() {
|
||||
// This implies you can't explicitly set a gauge to a negative number without first setting it to zero.
|
||||
if (val < 0) {
|
||||
if (this->prefix_) {
|
||||
out.append(str_sprintf("%s.", this->prefix_));
|
||||
out.append(this->prefix_);
|
||||
out.append(".");
|
||||
}
|
||||
out.append(str_sprintf("%s:0|g\n", s.name));
|
||||
out.append(s.name);
|
||||
out.append(":0|g\n");
|
||||
}
|
||||
if (this->prefix_) {
|
||||
out.append(str_sprintf("%s.", this->prefix_));
|
||||
out.append(this->prefix_);
|
||||
out.append(".");
|
||||
}
|
||||
out.append(str_sprintf("%s:%f|g\n", s.name, val));
|
||||
out.append(s.name);
|
||||
// Buffer for ":" + value + "|g\n".
|
||||
// %f with -DBL_MAX can produce up to 321 chars, plus ":" and "|g\n" (4) + null = 326
|
||||
char val_buf[330];
|
||||
buf_append_printf(val_buf, sizeof(val_buf), 0, ":%f|g\n", val);
|
||||
out.append(val_buf);
|
||||
|
||||
if (out.length() > SEND_THRESHOLD) {
|
||||
this->send_(&out);
|
||||
|
||||
@@ -83,7 +83,7 @@ struct Timer {
|
||||
}
|
||||
// Remove before 2026.8.0
|
||||
ESPDEPRECATED("Use to_str() instead. Removed in 2026.8.0", "2026.2.0")
|
||||
std::string to_string() const {
|
||||
std::string to_string() const { // NOLINT
|
||||
char buffer[TO_STR_BUFFER_SIZE];
|
||||
return this->to_str(buffer);
|
||||
}
|
||||
|
||||
@@ -732,6 +732,47 @@ 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"],
|
||||
|
||||
Reference in New Issue
Block a user