Keep get_name() working on ESP8266 with a RAM copy made on first use

This commit is contained in:
J. Nick Koston committed 2026-10-08 22:00:40 -10:00
1 parent e3d33df379
commit 096921cddb
6 files changed
+44 -23

No files matched your search

+4 -3
View File
@@ -413,9 +413,10 @@ void MQTTComponent::schedule_resend_state() { this->resend_state_ = true; }
bool MQTTComponent::is_connected_() const { return global_mqtt_client->is_connected(); }
// Pull these properties from EntityBase if not overridden
#ifndef USE_ESP8266
const StringRef &MQTTComponent::friendly_name_() const { return this->get_entity()->get_name_progmem().ram_ref(); }
#endif
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
const StringRef &MQTTComponent::friendly_name_() const { return this->get_entity()->get_name(); }
#pragma GCC diagnostic pop
const LogString *MQTTComponent::log_name_() const { return this->get_entity()->get_log_name(); }
StringRef MQTTComponent::get_default_object_id_to_(std::span<char, OBJECT_ID_MAX_LEN> buf) const {
return this->get_entity()->get_object_id_to(buf);
-2
View File
@@ -300,10 +300,8 @@ class MQTTComponent : public Component {
/// Entity name for a "%s" log argument.
const LogString *log_name_() const;
#ifndef USE_ESP8266
ESPDEPRECATED("Use log_name_() for logging. Removed in 2027.5.0", "2026.11.0")
const StringRef &friendly_name_() const;
#endif
/// Get the icon field of this component into a stack buffer
const char *get_icon_to_(std::span<char, MAX_ICON_LENGTH> buf) const { return this->get_entity()->get_icon_to(buf); }
+4 -3
View File
@@ -870,14 +870,15 @@ void Sprinkler::reset_resume() {
this->resume_duration_.reset();
}
#ifndef USE_ESP8266
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
const char *Sprinkler::valve_name(const size_t valve_number) {
if (this->is_a_valid_valve(valve_number)) {
return this->valve_[valve_number].controller_switch->get_name_progmem().ram_ref().c_str();
return this->valve_[valve_number].controller_switch->get_name().c_str();
}
return nullptr;
}
#endif
#pragma GCC diagnostic pop
const LogString *Sprinkler::valve_log_name(const size_t valve_number) {
if (this->is_a_valid_valve(valve_number)) {
-8
View File
@@ -335,17 +335,9 @@ class Sprinkler final : public Component {
/// resets resume state
void reset_resume();
#ifdef USE_ESP8266
template<typename T = int> const char *valve_name(size_t /*valve_number*/) {
static_assert(sizeof(T) == 0, "valve_name() unavailable on ESP8266 (name is in flash). Use valve_log_name() "
"for logging, or valve_switch()->get_name_to() for a copy.");
return nullptr;
}
#else
/// returns a pointer to a valve's name string object; returns nullptr if valve_number is invalid
ESPDEPRECATED("Use valve_log_name() or valve_switch()->get_name_to() instead. Removed in 2027.5.0", "2026.11.0")
const char *valve_name(size_t valve_number);
#endif
/// returns a valve's name for a "%s" log argument; returns nullptr if valve_number is invalid
const LogString *valve_log_name(size_t valve_number);
+32
View File
@@ -9,6 +9,38 @@ namespace esphome {
ESPHOME_LOG_TAG(TAG, "entity_base");
#ifdef USE_ESP8266
namespace {
// RAM copies made by the deprecated get_name(), only for entities whose name is asked for. Remove before 2027.5.0
struct NameCopy {
NameCopy *next;
const char *key;
StringRef ref;
};
NameCopy *name_copies = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
const StringRef EMPTY_NAME;
} // namespace
const StringRef &EntityBase::get_name() const {
const char *key = this->name_.progmem_ptr();
for (NameCopy *copy = name_copies; copy != nullptr; copy = copy->next) {
if (copy->key == key)
return copy->ref;
}
size_t len = this->name_.size();
auto *copy = static_cast<NameCopy *>(malloc(sizeof(NameCopy) + len + 1)); // NOLINT(cppcoreguidelines-no-malloc)
if (copy == nullptr)
return EMPTY_NAME;
char *buf = reinterpret_cast<char *>(copy + 1);
this->name_.write_to(buf, len + 1);
copy->next = name_copies;
copy->key = key;
copy->ref = StringRef(buf, len);
name_copies = copy;
return copy->ref;
}
#endif
void EntityBase::configure_entity_(const char *name, uint32_t object_id_hash, uint32_t entity_fields) {
this->name_ = ProgmemStringRef(name, ESPHOME_strlen_P(name));
if (this->name_.empty()) {
+4 -7
View File
@@ -73,19 +73,16 @@ static constexpr uint8_t ENTITY_FIELD_ENTITY_CATEGORY_SHIFT = 26;
// The generic Entity base class that provides an interface common to all Entities.
class EntityBase {
public:
// Remove before 2027.5.0
ESPDEPRECATED("Use get_name_to() or get_log_name() instead. Will be removed in ESPHome 2027.5.0", "2026.11.0")
#ifdef USE_ESP8266
// On ESP8266 the name is in flash and cannot be read as a plain string.
template<typename T = int> StringRef get_name() const {
static_assert(sizeof(T) == 0, "get_name() unavailable on ESP8266 (name is in flash). "
"Use get_name_to() with a stack buffer, or get_log_name() for logging.");
return {};
}
/// The name is in flash here; the first call makes a RAM copy that is kept for the life of the device.
const StringRef &get_name() const;
/// Get the name of this Entity, copied out of flash into buffer.
StringRef get_name_to(std::span<char, ENTITY_NAME_BUF_SIZE> buffer) const {
return StringRef(buffer.data(), this->write_name_to(buffer.data(), buffer.size()));
}
#else
ESPDEPRECATED("Use get_name_to() or get_log_name() instead. Will be removed in ESPHome 2027.5.0", "2026.11.0")
const StringRef &get_name() const { return this->name_.ram_ref(); }
const StringRef &get_name_to(std::span<char, ENTITY_NAME_BUF_SIZE> /*buffer*/) const { return this->name_.ram_ref(); }
#endif