Skip to content

Socket and ClientInfo std::string Removal

The Socket class virtual methods getpeername() and getsockname() that returned std::string have been removed. The ClientInfo struct no longer contains std::string fields.

This is a breaking change for external components in ESPHome 2026.1.0 and later.

Background

PR #12566: Eliminate std::string from ClientInfo struct

This PR removes heap-allocated strings from socket and API connection code: - Saves ~38 bytes of RAM per active API connection - Reduces flash by 516 bytes on ESP32-IDF - Eliminates heap fragmentation from connection handling

What's Changing

Socket class methods removed

// Removed - heap-allocating virtual methods
virtual std::string getpeername();
virtual std::string getsockname();

New buffer-based API

// New - write to provided buffer
// Returns bytes written (can be ignored for simple logging)
size_t getpeername_to(std::span<char, SOCKADDR_STR_LEN> buf);
size_t getsockname_to(std::span<char, SOCKADDR_STR_LEN> buf);

// Buffer size constant (compile-time, based on IPv6 support)
socket::SOCKADDR_STR_LEN  // 16 bytes (IPv4-only) or 46 bytes (IPv6-enabled)

APIFrameHelper buffer changes

// Before - heap-allocated strings in APIFrameHelper
class APIFrameHelper {
  std::string client_info_;
  // ...
};

// After - fixed buffers in APIFrameHelper
class APIFrameHelper {
  char client_name_[CLIENT_INFO_NAME_MAX_LEN];     // 32 bytes for client name
  char client_peername_[socket::SOCKADDR_STR_LEN]; // 16/46 bytes for IP address
  // ...
};

APIConnection getters

// Before - returned std::string
const std::string &get_name() const;
const std::string &get_peername() const;

// After - returns const char*
const char *get_name() const;
const char *get_peername() const;

Who This Affects

External components that: - Call getpeername() or getsockname() on socket objects - Access APIFrameHelper client name/peername fields - Call get_name() or get_peername() on APIConnection

Standard YAML configurations are not affected.

Migration Guide

1. Socket getpeername/getsockname

// Before - heap allocation
std::string peer = socket->getpeername();
ESP_LOGD(TAG, "Connected from: %s", peer.c_str());

// After - stack buffer
char peer[socket::SOCKADDR_STR_LEN];
socket->getpeername_to(peer);
ESP_LOGD(TAG, "Connected from: %s", peer);

2. Buffer size constant

SOCKADDR_STR_LEN is a compile-time constant sized for your build configuration:

// Works for both IPv4 and IPv6 - size determined at compile time
char buffer[socket::SOCKADDR_STR_LEN];

// IPv4-only builds: 16 bytes (fits "255.255.255.255")
// IPv6-enabled builds: 46 bytes (fits full IPv6 addresses)

3. APIConnection name access

// Before
const std::string &name = connection->get_name();
const std::string &peer = connection->get_peername();

// After - returns const char*
const char *name = connection->get_name();
const char *peer = connection->get_peername();

// Direct logging (no .c_str() needed)
ESP_LOGD(TAG, "Client: %s from %s", name, peer);

4. Storing the address

If you need to store the address, copy it to your own buffer:

// Stack buffer for temporary use
char peer[socket::SOCKADDR_STR_LEN];
socket->getpeername_to(peer);

// If you need to store it (snprintf ensures null-termination)
char stored_peer[socket::SOCKADDR_STR_LEN];
snprintf(stored_peer, sizeof(stored_peer), "%s", peer);

Supporting Multiple ESPHome Versions

#if ESPHOME_VERSION_CODE >= VERSION_CODE(2026, 1, 0)
  // New API - buffer-based
  char peer[socket::SOCKADDR_STR_LEN];
  socket->getpeername_to(peer);
  ESP_LOGD(TAG, "Peer: %s", peer);
#else
  // Old API - heap-allocating
  std::string peer = socket->getpeername();
  ESP_LOGD(TAG, "Peer: %s", peer.c_str());
#endif

Timeline

  • ESPHome 2026.1.0 (January 2026): Old methods removed, new buffer-based API required
  • No deprecation period - methods removed directly

Finding Code That Needs Updates

# Find getpeername/getsockname calls
grep -rn "getpeername()" your_component/
grep -rn "getsockname()" your_component/

# Find APIFrameHelper usage
grep -rn "APIFrameHelper" your_component/

# Find APIConnection name access
grep -rn "get_name()" your_component/
grep -rn "get_peername()" your_component/

Questions?

If you have questions about migrating your external component, please ask in:

Comments

Feel free to leave a comment here to discuss this post wth 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.