Compare commits

...
Author SHA1 Message Date
J. Nick Koston 66d855f25d [improv_serial] Take the auth word length from the copied text 2026-11-15 03:51:47 -06:00
J. Nick Koston 68b5e6bdea [core] Define the log words once in log.h as inline variables
One set of YESNO/ONOFF/TRUEFALSE/ONOFFMAYBE macros for all platforms; the
words are inline constexpr PROGMEM arrays, so no log.cpp definitions are
needed. improv_serial passes the word length to add_string.
2026-11-15 03:36:22 -06:00
J. Nick Koston 693732434c [core] Keep YESNO/ONOFF/TRUEFALSE words and two core literals in flash on ESP8266
YESNO, ONOFF, TRUEFALSE and ONOFFMAYBE now return one shared PROGMEM copy
of each word on ESP8266 (LOG_STR_ARG semantics), so the plain literals no
longer sit in RAM. The two non-log users (API message dump, improv_serial
Wi-Fi scan reply) read them with flash-safe helpers.

value_accuracy_to_buf's "%.*f" fallback format and strftime_to's "ERROR"
string also move to flash.
2026-11-15 03:26:30 -06:00
6 changed files with 35 additions and 15 deletions

No files matched your search

+1 -1
View File
@@ -86,7 +86,7 @@ static void dump_field(DumpBuffer &out, const char *field_name, uint64_t value,
static void dump_field(DumpBuffer &out, const char *field_name, bool value, int indent = 2) {
append_field_prefix(out, field_name, indent);
out.append(YESNO(value));
out.append_p(YESNO(value));
out.append("\n");
}
@@ -4,6 +4,7 @@
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include "esphome/core/progmem.h"
#include "esphome/core/version.h"
#include "esphome/components/logger/logger.h"
@@ -13,6 +14,7 @@
#endif
#include <array>
#include <cstring>
namespace esphome::improv_serial {
@@ -349,7 +351,10 @@ bool ImprovSerialComponent::parse_improv_payload_(improv::ImprovCommand &command
const auto &ssid = scan.get_ssid();
builder.add_string(ssid.c_str(), ssid.size());
builder.add_string(rssi_buf, rssi_end - rssi_buf);
builder.add_string(YESNO(with_auth));
// YESNO points to flash on ESP8266
char auth[4];
ESPHOME_strncpy_P(auth, YESNO(with_auth), sizeof(auth));
builder.add_string(auth, strlen(auth));
this->send_response_(builder.finish(false));
}
#endif // USE_WIFI
+2 -1
View File
@@ -656,7 +656,8 @@ size_t value_accuracy_to_buf(std::span<char, VALUE_ACCURACY_MAX_LEN> buf, float
}
// Fallback for NaN/Inf/high accuracy/out-of-range
int len = snprintf(buf.data(), buf.size(), "%.*f", accuracy_decimals, static_cast<double>(value));
int len =
ESPHOME_snprintf_P(buf.data(), buf.size(), ESPHOME_PSTR("%.*f"), accuracy_decimals, static_cast<double>(value));
if (len < 0)
return 0;
return static_cast<size_t>(len) >= buf.size() ? buf.size() - 1 : static_cast<size_t>(len);
+20 -6
View File
@@ -197,12 +197,6 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT
((byte) & 0x80 ? '1' : '0'), ((byte) & 0x40 ? '1' : '0'), ((byte) & 0x20 ? '1' : '0'), ((byte) & 0x10 ? '1' : '0'), \
((byte) & 0x08 ? '1' : '0'), ((byte) & 0x04 ? '1' : '0'), ((byte) & 0x02 ? '1' : '0'), \
((byte) & 0x01 ? '1' : '0')
#define YESNO(b) ((b) ? "YES" : "NO")
#define ONOFF(b) ((b) ? "ON" : "OFF")
#define TRUEFALSE(b) ((b) ? "TRUE" : "FALSE")
// for use with optional values
#define ONOFFMAYBE(b) (((b).has_value()) ? ONOFF((b).value()) : "UNKNOWN")
// Helper class that identifies strings that may be stored in flash storage (similar to Arduino's __FlashStringHelper)
struct LogString;
@@ -223,6 +217,26 @@ struct LogString;
#endif
// Empty off ESP8266, as in each platform's hal.h, which log.h cannot include (hal.h -> gpio_pin.h -> log.h)
#ifndef PROGMEM
#define PROGMEM
#endif
// Words for %s log arguments. On ESP8266 one shared copy of each lives in flash, so the result must only be
// passed where a LOG_STR_ARG is accepted (ESP_LOG* %s arguments, the *_P functions).
inline constexpr char LOG_STR_YES[] PROGMEM = "YES";
inline constexpr char LOG_STR_NO[] PROGMEM = "NO";
inline constexpr char LOG_STR_ON[] PROGMEM = "ON";
inline constexpr char LOG_STR_OFF[] PROGMEM = "OFF";
inline constexpr char LOG_STR_TRUE[] PROGMEM = "TRUE";
inline constexpr char LOG_STR_FALSE[] PROGMEM = "FALSE";
inline constexpr char LOG_STR_UNKNOWN[] PROGMEM = "UNKNOWN";
#define YESNO(b) LOG_STR_ARG((b) ? ::esphome::LOG_STR_YES : ::esphome::LOG_STR_NO)
#define ONOFF(b) LOG_STR_ARG((b) ? ::esphome::LOG_STR_ON : ::esphome::LOG_STR_OFF)
#define TRUEFALSE(b) LOG_STR_ARG((b) ? ::esphome::LOG_STR_TRUE : ::esphome::LOG_STR_FALSE)
// for use with optional values
#define ONOFFMAYBE(b) (((b).has_value()) ? ONOFF((b).value()) : LOG_STR_ARG(::esphome::LOG_STR_UNKNOWN))
// Declares a static log tag at namespace scope, in a source file or a header; on ESP8266 it lives in flash, so
// read it with the _P functions, never strcmp/strlen. Not usable for a class member: the ESP8266 form is a
// PROGMEM array, which cannot be initialized in a class.
+4 -4
View File
@@ -1,7 +1,7 @@
#include "time.h" // NOLINT
#include "hal.h"
#include "helpers.h"
#include <algorithm>
#ifdef USE_TIME_TIMEZONE
#include "esphome/components/time/posix_tz.h"
#endif
@@ -76,9 +76,9 @@ size_t ESPTime::strftime_to(std::span<char, STRFTIME_BUFFER_SIZE> buffer, const
return len;
}
// Write "ERROR" to buffer on failure for consistent behavior
constexpr char error_str[] = "ERROR";
std::copy_n(error_str, sizeof(error_str), buffer.data());
return sizeof(error_str) - 1; // Length excluding null terminator
static constexpr char ERROR_STR[] PROGMEM = "ERROR";
progmem_memcpy(buffer.data(), ERROR_STR, sizeof(ERROR_STR));
return sizeof(ERROR_STR) - 1; // Length excluding null terminator
}
ESPTime ESPTime::from_c_tm(struct tm *c_tm, time_t c_time) {
+2 -2
View File
@@ -834,7 +834,7 @@ class BoolType(VarintTypeMixin, TypeInfo):
wire_type = WireType.VARINT # Uses wire type 0
def dump(self, name: str) -> str:
return f"out.append(YESNO({name}));"
return f"out.append_p(YESNO({name}));"
def get_size_calculation(self, name: str, force: bool = False) -> str:
return self._get_simple_size_calculation(name, force, "bool")
@@ -3353,7 +3353,7 @@ static void dump_field(DumpBuffer &out, const char *field_name, uint64_t value,
static void dump_field(DumpBuffer &out, const char *field_name, bool value, int indent = 2) {
append_field_prefix(out, field_name, indent);
out.append(YESNO(value));
out.append_p(YESNO(value));
out.append("\\n");
}