diff --git a/include/sendspin/config.h b/include/sendspin/config.h index bd90f15..bf8af29 100644 --- a/include/sendspin/config.h +++ b/include/sendspin/config.h @@ -34,8 +34,10 @@ namespace sendspin { /// @brief Configuration for a SendspinClient instance /// Filled in by the platform (e.g., ESPHome) before calling start_server() struct SendspinClientConfig { - std::string client_id; ///< Unique client identifier (e.g., MAC address) - std::string name; ///< Friendly display name + /// Unique client identifier. When left empty, the library falls back to the detected local + /// network interface MAC address (the same value used for device_info.mac_address). + std::string client_id; + std::string name; ///< Friendly display name std::optional product_name{}; ///< Device product name (optional) std::optional manufacturer{}; ///< Manufacturer name, e.g., "ESPHome" (optional) diff --git a/src/client.cpp b/src/client.cpp index 674c03b..a1b6815 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -438,17 +438,26 @@ void SendspinClient::cleanup_connection_state() { std::string SendspinClient::build_hello_message() { ClientHelloMessage msg; - msg.client_id = this->config_.client_id; msg.name = this->config_.name; + // Use the explicitly configured MAC when provided; otherwise fall back to platform detection + // (reliable on ESP, best-effort on host). Leaves the field absent if neither is available. + const std::optional interface_mac = + this->config_.mac_address ? this->config_.mac_address : platform_get_interface_mac(); + + // Some integrations use the network MAC as the Sendspin client_id. If they leave it empty, + // default to the same active-interface MAC advertised in device_info instead of forcing them + // to duplicate platform-specific MAC detection. + msg.client_id = this->config_.client_id; + if (msg.client_id.empty() && interface_mac.has_value()) { + msg.client_id = interface_mac.value(); + } + DeviceInfoObject device_info{}; device_info.product_name = this->config_.product_name; device_info.manufacturer = this->config_.manufacturer; device_info.software_version = this->config_.software_version; - // Use the explicitly configured MAC when provided; otherwise fall back to platform detection - // (reliable on ESP, best-effort on host). Leaves the field absent if neither is available. - device_info.mac_address = - this->config_.mac_address ? this->config_.mac_address : platform_get_interface_mac(); + device_info.mac_address = interface_mac; msg.device_info = device_info; msg.version = 1; diff --git a/src/connection_manager.cpp b/src/connection_manager.cpp index 94c1d4f..5b24a08 100644 --- a/src/connection_manager.cpp +++ b/src/connection_manager.cpp @@ -337,9 +337,11 @@ void ConnectionManager::on_new_connection(std::shared_ptr lock(this->conn_ptr_mutex_); + SendspinConnection* accepted_conn = nullptr; if (this->current_connection_ == nullptr) { SS_LOGD(TAG, "No existing connection, accepting as current"); this->current_connection_ = std::move(conn); + accepted_conn = this->current_connection_.get(); } else { SS_LOGD(TAG, "Existing connection present, setting as pending for handoff"); if (this->pending_connection_ != nullptr) { @@ -348,6 +350,15 @@ void ConnectionManager::on_new_connection(std::shared_ptrpending_connection_ = std::move(conn); + accepted_conn = this->pending_connection_.get(); + } + + // Some ESP-IDF/httpd versions complete the WebSocket upgrade without dispatching the initial + // HTTP_GET request to websocket_handler(). Arm the hello retry from the accept path as well so + // server-initiated connections always receive client/hello. If the GET callback arrives later, + // initiate_hello() only re-arms the existing per-connection retry entry. + if (accepted_conn != nullptr) { + this->initiate_hello(accepted_conn); } }