Entity Getters Now Return StringRef
Several entity component getters now return StringRef instead of const char* or std::string. This improves safety by eliminating null pointer crashes and provides a modern C++ API.
This is a breaking change for external components in ESPHome 2026.1.0 and later.
Background
Section titled “Background”These PRs modernize entity getters to return StringRef, a lightweight string reference class that signals static lifetime semantics:
PR #13092: Fan - get_preset_mode()
Returns StringRef instead of const char*. Adds has_preset_mode() helper.
PR #13095: Select - current_option()
Returns StringRef instead of const char*.
PR #13103: Climate - get_custom_fan_mode(), get_custom_preset()
Returns StringRef instead of const char*. Adds has_custom_fan_mode() and has_custom_preset() helpers.
PR #13104: Event - get_last_event_type()
Returns StringRef instead of const char*. Adds has_event() helper.
PR #13105: Light - LightEffect::get_name(), LightState::get_effect_name()
Returns StringRef instead of const char* and std::string respectively.
What’s Changing
Section titled “What’s Changing”Return type changes
Section titled “Return type changes”| Component | Method | Before | After |
|---|---|---|---|
| Fan | get_preset_mode() | const char* | StringRef |
| Select | current_option() | const char* | StringRef |
| Climate | get_custom_fan_mode() | const char* | StringRef |
| Climate | get_custom_preset() | const char* | StringRef |
| Event | get_last_event_type() | const char* | StringRef |
| Light | LightEffect::get_name() | const char* | StringRef |
| Light | LightState::get_effect_name() | std::string | StringRef |
Behavior changes
Section titled “Behavior changes”- Empty state: Returns empty
StringRefinstead ofnullptrwhen not set - Safety:
==comparisons are always safe (no null pointer crashes) - Implicit conversion:
StringRefconverts tostd::stringautomatically
Who This Affects
Section titled “Who This Affects”- External components that call these getter methods
- YAML lambdas that check for null or use
strcmp()
Standard YAML configurations are not affected.
Migration Guide
Section titled “Migration Guide”1. Null checks (Required)
Section titled “1. Null checks (Required)”The old pattern of checking for nullptr must be replaced:
// Before - checking for nullptrconst char *preset = fan->get_preset_mode();if (preset != nullptr) { // use preset}
// After - use empty() or has_*() helpersStringRef preset = fan->get_preset_mode();if (!preset.empty()) { // use preset}
// Or use the new helper methods where availableif (fan->has_preset_mode()) { StringRef preset = fan->get_preset_mode();}2. String comparisons (Simplified)
Section titled “2. String comparisons (Simplified)”The == operator now works directly and is safe even when empty:
// Before - strcmp required (crashes if nullptr!)const char *preset = fan->get_preset_mode();if (preset != nullptr && strcmp(preset, "auto") == 0) { // matched}
// After - direct comparison (always safe)if (fan->get_preset_mode() == "auto") { // matched}3. Logging (Updated format)
Section titled “3. Logging (Updated format)”Use %.*s format specifier for proper StringRef logging:
// BeforeESP_LOGD(TAG, "Preset: %s", fan->get_preset_mode());
// AfterStringRef preset = fan->get_preset_mode();ESP_LOGD(TAG, "Preset: %.*s", (int) preset.size(), preset.c_str());
// Or use c_str() directly (StringRef is null-terminated)ESP_LOGD(TAG, "Preset: %s", fan->get_preset_mode().c_str());4. Storing as std::string
Section titled “4. Storing as std::string”StringRef converts implicitly to std::string:
// Beforeconst char *preset = fan->get_preset_mode();std::string stored = preset ? preset : "";
// After - implicit conversionstd::string stored = fan->get_preset_mode();5. Passing to C functions
Section titled “5. Passing to C functions”Use .c_str() when passing to functions expecting const char*:
// StringRef is null-terminated, so c_str() is safesome_c_function(fan->get_preset_mode().c_str());6. YAML lambda updates
Section titled “6. YAML lambda updates”# Before - null check patternlambda: |- auto preset = id(my_fan).get_preset_mode(); if (preset != nullptr && strcmp(preset, "auto") == 0) { return true; } return false;
# After - direct comparisonlambda: |- return id(my_fan).get_preset_mode() == "auto";StringRef Quick Reference
Section titled “StringRef Quick Reference”StringRef is a lightweight reference to a string owned elsewhere:
StringRef ref = fan->get_preset_mode();
ref.empty() // true if empty (replaces nullptr check)ref.size() // string lengthref.c_str() // null-terminated C string pointerref.str() // convert to std::stringref == "value" // compare with string literalref == other_ref // compare with another StringRefSupporting Multiple ESPHome Versions
Section titled “Supporting Multiple ESPHome Versions”#if ESPHOME_VERSION_CODE >= VERSION_CODE(2026, 1, 0) // New API - StringRef if (!fan->get_preset_mode().empty()) { ESP_LOGD(TAG, "Preset: %s", fan->get_preset_mode().c_str()); }#else // Old API - const char* const char *preset = fan->get_preset_mode(); if (preset != nullptr) { ESP_LOGD(TAG, "Preset: %s", preset); }#endifTimeline
Section titled “Timeline”- ESPHome 2026.1.0 (January 2026): StringRef returns are active
- No deprecation period - this is a signature change
Finding Code That Needs Updates
Section titled “Finding Code That Needs Updates”# Find null pointer checks on these methodsgrep -rn "get_preset_mode().*nullptr" your_component/grep -rn "current_option().*nullptr" your_component/grep -rn "get_custom_fan_mode().*nullptr" your_component/grep -rn "get_custom_preset().*nullptr" your_component/grep -rn "get_last_event_type().*nullptr" your_component/grep -rn "get_effect_name().*nullptr" your_component/
# Find strcmp usagegrep -rn "strcmp.*get_preset_mode" your_component/grep -rn "strcmp.*current_option" your_component/Questions?
Section titled “Questions?”If you have questions about migrating your external component, please ask in:
- ESPHome Discord - #devs channel
- ESPHome GitHub Discussions
Related Documentation
Section titled “Related Documentation”Copyright © 2026 ESPHome - A project from the Open Home Foundation
Comments
Feel free to leave a comment here to discuss this post with others. You can ask questions, share your experience, or suggest improvements. If you have a question about a specific feature or issue, please consider using the ESPHome Discord. Stick to English and follow ESPHome's code of conduct. These comments exist on a discussion on GitHub, so you can also comment there directly if you prefer.