[wifi] Replace optional with sentinel values to reduce RAM and clarify API (#12446)

This commit is contained in:
J. Nick Koston
2025-12-19 11:18:15 -10:00
committed by GitHub
parent 25cebedcfc
commit ebc3d28ade
6 changed files with 55 additions and 48 deletions

View File

@@ -2,6 +2,7 @@
#ifdef USE_WIFI #ifdef USE_WIFI
#include <cassert> #include <cassert>
#include <cinttypes> #include <cinttypes>
#include <cmath>
#ifdef USE_ESP32 #ifdef USE_ESP32
#if (ESP_IDF_VERSION_MAJOR >= 5 && ESP_IDF_VERSION_MINOR >= 1) #if (ESP_IDF_VERSION_MAJOR >= 5 && ESP_IDF_VERSION_MINOR >= 1)
@@ -394,7 +395,7 @@ void WiFiComponent::start() {
if (this->has_sta()) { if (this->has_sta()) {
this->wifi_sta_pre_setup_(); this->wifi_sta_pre_setup_();
if (this->output_power_.has_value() && !this->wifi_apply_output_power_(*this->output_power_)) { if (!std::isnan(this->output_power_) && !this->wifi_apply_output_power_(this->output_power_)) {
ESP_LOGV(TAG, "Setting Output Power Option failed"); ESP_LOGV(TAG, "Setting Output Power Option failed");
} }
@@ -441,7 +442,7 @@ void WiFiComponent::start() {
#ifdef USE_WIFI_AP #ifdef USE_WIFI_AP
} else if (this->has_ap()) { } else if (this->has_ap()) {
this->setup_ap_config_(); this->setup_ap_config_();
if (this->output_power_.has_value() && !this->wifi_apply_output_power_(*this->output_power_)) { if (!std::isnan(this->output_power_) && !this->wifi_apply_output_power_(this->output_power_)) {
ESP_LOGV(TAG, "Setting Output Power Option failed"); ESP_LOGV(TAG, "Setting Output Power Option failed");
} }
#ifdef USE_CAPTIVE_PORTAL #ifdef USE_CAPTIVE_PORTAL
@@ -713,8 +714,8 @@ WiFiAP WiFiComponent::build_params_for_current_phase_() {
case WiFiRetryPhase::RETRY_HIDDEN: case WiFiRetryPhase::RETRY_HIDDEN:
// Hidden network mode: clear BSSID/channel to trigger probe request // Hidden network mode: clear BSSID/channel to trigger probe request
// (both explicit hidden and retry hidden use same behavior) // (both explicit hidden and retry hidden use same behavior)
params.set_bssid(optional<bssid_t>{}); params.clear_bssid();
params.set_channel(optional<uint8_t>{}); params.clear_channel();
break; break;
case WiFiRetryPhase::SCAN_CONNECTING: case WiFiRetryPhase::SCAN_CONNECTING:
@@ -766,21 +767,20 @@ void WiFiComponent::start_connecting(const WiFiAP &ap) {
char bssid_s[18]; char bssid_s[18];
int8_t priority = 0; int8_t priority = 0;
if (ap.get_bssid().has_value()) { if (ap.has_bssid()) {
format_mac_addr_upper(ap.get_bssid().value().data(), bssid_s); format_mac_addr_upper(ap.get_bssid().data(), bssid_s);
priority = this->get_sta_priority(ap.get_bssid().value()); priority = this->get_sta_priority(ap.get_bssid());
} }
ESP_LOGI(TAG, ESP_LOGI(TAG,
"Connecting to " LOG_SECRET("'%s'") " " LOG_SECRET("(%s)") " (priority %d, attempt %u/%u in phase %s)...", "Connecting to " LOG_SECRET("'%s'") " " LOG_SECRET("(%s)") " (priority %d, attempt %u/%u in phase %s)...",
ap.get_ssid().c_str(), ap.get_bssid().has_value() ? bssid_s : LOG_STR_LITERAL("any"), priority, ap.get_ssid().c_str(), ap.has_bssid() ? bssid_s : LOG_STR_LITERAL("any"), priority, this->num_retried_ + 1,
this->num_retried_ + 1, get_max_retries_for_phase(this->retry_phase_), get_max_retries_for_phase(this->retry_phase_), LOG_STR_ARG(retry_phase_to_log_string(this->retry_phase_)));
LOG_STR_ARG(retry_phase_to_log_string(this->retry_phase_)));
#ifdef ESPHOME_LOG_HAS_VERBOSE #ifdef ESPHOME_LOG_HAS_VERBOSE
ESP_LOGV(TAG, "Connection Params:"); ESP_LOGV(TAG, "Connection Params:");
ESP_LOGV(TAG, " SSID: '%s'", ap.get_ssid().c_str()); ESP_LOGV(TAG, " SSID: '%s'", ap.get_ssid().c_str());
if (ap.get_bssid().has_value()) { if (ap.has_bssid()) {
ESP_LOGV(TAG, " BSSID: %s", bssid_s); ESP_LOGV(TAG, " BSSID: %s", bssid_s);
} else { } else {
ESP_LOGV(TAG, " BSSID: Not Set"); ESP_LOGV(TAG, " BSSID: Not Set");
@@ -808,8 +808,8 @@ void WiFiComponent::start_connecting(const WiFiAP &ap) {
#ifdef USE_WIFI_WPA2_EAP #ifdef USE_WIFI_WPA2_EAP
} }
#endif #endif
if (ap.get_channel().has_value()) { if (ap.has_channel()) {
ESP_LOGV(TAG, " Channel: %u", *ap.get_channel()); ESP_LOGV(TAG, " Channel: %u", ap.get_channel());
} else { } else {
ESP_LOGV(TAG, " Channel not set"); ESP_LOGV(TAG, " Channel not set");
} }
@@ -919,8 +919,8 @@ void WiFiComponent::print_connect_params_() {
get_wifi_channel(), wifi_subnet_mask_().str().c_str(), wifi_gateway_ip_().str().c_str(), get_wifi_channel(), wifi_subnet_mask_().str().c_str(), wifi_gateway_ip_().str().c_str(),
wifi_dns_ip_(0).str().c_str(), wifi_dns_ip_(1).str().c_str()); wifi_dns_ip_(0).str().c_str(), wifi_dns_ip_(1).str().c_str());
#ifdef ESPHOME_LOG_HAS_VERBOSE #ifdef ESPHOME_LOG_HAS_VERBOSE
if (const WiFiAP *config = this->get_selected_sta_(); config && config->get_bssid().has_value()) { if (const WiFiAP *config = this->get_selected_sta_(); config && config->has_bssid()) {
ESP_LOGV(TAG, " Priority: %d", this->get_sta_priority(*config->get_bssid())); ESP_LOGV(TAG, " Priority: %d", this->get_sta_priority(config->get_bssid()));
} }
#endif #endif
#ifdef USE_WIFI_11KV_SUPPORT #ifdef USE_WIFI_11KV_SUPPORT
@@ -1514,9 +1514,9 @@ void WiFiComponent::log_and_adjust_priority_for_failed_connect_() {
if (this->retry_phase_ == WiFiRetryPhase::SCAN_CONNECTING && !this->scan_result_.empty()) { if (this->retry_phase_ == WiFiRetryPhase::SCAN_CONNECTING && !this->scan_result_.empty()) {
// Scan-based phase: always use best result (index 0) // Scan-based phase: always use best result (index 0)
failed_bssid = this->scan_result_[0].get_bssid(); failed_bssid = this->scan_result_[0].get_bssid();
} else if (const WiFiAP *config = this->get_selected_sta_(); config && config->get_bssid()) { } else if (const WiFiAP *config = this->get_selected_sta_(); config && config->has_bssid()) {
// Config has specific BSSID (fast_connect or user-specified) // Config has specific BSSID (fast_connect or user-specified)
failed_bssid = *config->get_bssid(); failed_bssid = config->get_bssid();
} }
if (!failed_bssid.has_value()) { if (!failed_bssid.has_value()) {
@@ -1784,24 +1784,27 @@ void WiFiComponent::save_fast_connect_settings_() {
#endif #endif
void WiFiAP::set_ssid(const std::string &ssid) { this->ssid_ = ssid; } void WiFiAP::set_ssid(const std::string &ssid) { this->ssid_ = ssid; }
void WiFiAP::set_bssid(bssid_t bssid) { this->bssid_ = bssid; } void WiFiAP::set_bssid(const bssid_t &bssid) { this->bssid_ = bssid; }
void WiFiAP::set_bssid(optional<bssid_t> bssid) { this->bssid_ = bssid; } void WiFiAP::clear_bssid() { this->bssid_ = {}; }
void WiFiAP::set_password(const std::string &password) { this->password_ = password; } void WiFiAP::set_password(const std::string &password) { this->password_ = password; }
#ifdef USE_WIFI_WPA2_EAP #ifdef USE_WIFI_WPA2_EAP
void WiFiAP::set_eap(optional<EAPAuth> eap_auth) { this->eap_ = std::move(eap_auth); } void WiFiAP::set_eap(optional<EAPAuth> eap_auth) { this->eap_ = std::move(eap_auth); }
#endif #endif
void WiFiAP::set_channel(optional<uint8_t> channel) { this->channel_ = channel; } void WiFiAP::set_channel(uint8_t channel) { this->channel_ = channel; }
void WiFiAP::clear_channel() { this->channel_ = 0; }
#ifdef USE_WIFI_MANUAL_IP #ifdef USE_WIFI_MANUAL_IP
void WiFiAP::set_manual_ip(optional<ManualIP> manual_ip) { this->manual_ip_ = manual_ip; } void WiFiAP::set_manual_ip(optional<ManualIP> manual_ip) { this->manual_ip_ = manual_ip; }
#endif #endif
void WiFiAP::set_hidden(bool hidden) { this->hidden_ = hidden; } void WiFiAP::set_hidden(bool hidden) { this->hidden_ = hidden; }
const std::string &WiFiAP::get_ssid() const { return this->ssid_; } const std::string &WiFiAP::get_ssid() const { return this->ssid_; }
const optional<bssid_t> &WiFiAP::get_bssid() const { return this->bssid_; } const bssid_t &WiFiAP::get_bssid() const { return this->bssid_; }
bool WiFiAP::has_bssid() const { return this->bssid_ != bssid_t{}; }
const std::string &WiFiAP::get_password() const { return this->password_; } const std::string &WiFiAP::get_password() const { return this->password_; }
#ifdef USE_WIFI_WPA2_EAP #ifdef USE_WIFI_WPA2_EAP
const optional<EAPAuth> &WiFiAP::get_eap() const { return this->eap_; } const optional<EAPAuth> &WiFiAP::get_eap() const { return this->eap_; }
#endif #endif
const optional<uint8_t> &WiFiAP::get_channel() const { return this->channel_; } uint8_t WiFiAP::get_channel() const { return this->channel_; }
bool WiFiAP::has_channel() const { return this->channel_ != 0; }
#ifdef USE_WIFI_MANUAL_IP #ifdef USE_WIFI_MANUAL_IP
const optional<ManualIP> &WiFiAP::get_manual_ip() const { return this->manual_ip_; } const optional<ManualIP> &WiFiAP::get_manual_ip() const { return this->manual_ip_; }
#endif #endif
@@ -1829,7 +1832,7 @@ bool WiFiScanResult::matches(const WiFiAP &config) const {
// network is configured without SSID - match other settings // network is configured without SSID - match other settings
} }
// If BSSID configured, only match for correct BSSIDs // If BSSID configured, only match for correct BSSIDs
if (config.get_bssid().has_value() && *config.get_bssid() != this->bssid_) if (config.has_bssid() && config.get_bssid() != this->bssid_)
return false; return false;
#ifdef USE_WIFI_WPA2_EAP #ifdef USE_WIFI_WPA2_EAP
@@ -1847,7 +1850,7 @@ bool WiFiScanResult::matches(const WiFiAP &config) const {
#endif #endif
// If channel configured, only match networks on that channel. // If channel configured, only match networks on that channel.
if (config.get_channel().has_value() && *config.get_channel() != this->channel_) { if (config.has_channel() && config.get_channel() != this->channel_) {
return false; return false;
} }
return true; return true;

View File

@@ -151,25 +151,28 @@ template<typename T> using wifi_scan_vector_t = FixedVector<T>;
class WiFiAP { class WiFiAP {
public: public:
void set_ssid(const std::string &ssid); void set_ssid(const std::string &ssid);
void set_bssid(bssid_t bssid); void set_bssid(const bssid_t &bssid);
void set_bssid(optional<bssid_t> bssid); void clear_bssid();
void set_password(const std::string &password); void set_password(const std::string &password);
#ifdef USE_WIFI_WPA2_EAP #ifdef USE_WIFI_WPA2_EAP
void set_eap(optional<EAPAuth> eap_auth); void set_eap(optional<EAPAuth> eap_auth);
#endif // USE_WIFI_WPA2_EAP #endif // USE_WIFI_WPA2_EAP
void set_channel(optional<uint8_t> channel); void set_channel(uint8_t channel);
void clear_channel();
void set_priority(int8_t priority) { priority_ = priority; } void set_priority(int8_t priority) { priority_ = priority; }
#ifdef USE_WIFI_MANUAL_IP #ifdef USE_WIFI_MANUAL_IP
void set_manual_ip(optional<ManualIP> manual_ip); void set_manual_ip(optional<ManualIP> manual_ip);
#endif #endif
void set_hidden(bool hidden); void set_hidden(bool hidden);
const std::string &get_ssid() const; const std::string &get_ssid() const;
const optional<bssid_t> &get_bssid() const; const bssid_t &get_bssid() const;
bool has_bssid() const;
const std::string &get_password() const; const std::string &get_password() const;
#ifdef USE_WIFI_WPA2_EAP #ifdef USE_WIFI_WPA2_EAP
const optional<EAPAuth> &get_eap() const; const optional<EAPAuth> &get_eap() const;
#endif // USE_WIFI_WPA2_EAP #endif // USE_WIFI_WPA2_EAP
const optional<uint8_t> &get_channel() const; uint8_t get_channel() const;
bool has_channel() const;
int8_t get_priority() const { return priority_; } int8_t get_priority() const { return priority_; }
#ifdef USE_WIFI_MANUAL_IP #ifdef USE_WIFI_MANUAL_IP
const optional<ManualIP> &get_manual_ip() const; const optional<ManualIP> &get_manual_ip() const;
@@ -179,16 +182,17 @@ class WiFiAP {
protected: protected:
std::string ssid_; std::string ssid_;
std::string password_; std::string password_;
optional<bssid_t> bssid_;
#ifdef USE_WIFI_WPA2_EAP #ifdef USE_WIFI_WPA2_EAP
optional<EAPAuth> eap_; optional<EAPAuth> eap_;
#endif // USE_WIFI_WPA2_EAP #endif // USE_WIFI_WPA2_EAP
#ifdef USE_WIFI_MANUAL_IP #ifdef USE_WIFI_MANUAL_IP
optional<ManualIP> manual_ip_; optional<ManualIP> manual_ip_;
#endif #endif
optional<uint8_t> channel_; // Group small types together to minimize padding
int8_t priority_{0}; bssid_t bssid_{}; // 6 bytes, all zeros = any/not set
bool hidden_{false}; uint8_t channel_{0}; // 1 byte, 0 = auto/not set
int8_t priority_{0}; // 1 byte
bool hidden_{false}; // 1 byte (+ 3 bytes end padding to 4-byte align)
}; };
class WiFiScanResult { class WiFiScanResult {
@@ -590,7 +594,7 @@ class WiFiComponent : public Component {
#ifdef USE_WIFI_AP #ifdef USE_WIFI_AP
WiFiAP ap_; WiFiAP ap_;
#endif #endif
optional<float> output_power_; float output_power_{NAN};
#ifdef USE_WIFI_LISTENERS #ifdef USE_WIFI_LISTENERS
std::vector<WiFiIPStateListener *> ip_state_listeners_; std::vector<WiFiIPStateListener *> ip_state_listeners_;
std::vector<WiFiScanResultsListener *> scan_results_listeners_; std::vector<WiFiScanResultsListener *> scan_results_listeners_;

View File

@@ -257,9 +257,9 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
memcpy(reinterpret_cast<char *>(conf.ssid), ap.get_ssid().c_str(), ap.get_ssid().size()); memcpy(reinterpret_cast<char *>(conf.ssid), ap.get_ssid().c_str(), ap.get_ssid().size());
memcpy(reinterpret_cast<char *>(conf.password), ap.get_password().c_str(), ap.get_password().size()); memcpy(reinterpret_cast<char *>(conf.password), ap.get_password().c_str(), ap.get_password().size());
if (ap.get_bssid().has_value()) { if (ap.has_bssid()) {
conf.bssid_set = 1; conf.bssid_set = 1;
memcpy(conf.bssid, ap.get_bssid()->data(), 6); memcpy(conf.bssid, ap.get_bssid().data(), 6);
} else { } else {
conf.bssid_set = 0; conf.bssid_set = 0;
} }
@@ -381,8 +381,8 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
} }
#endif /* USE_NETWORK_IPV6 */ #endif /* USE_NETWORK_IPV6 */
if (ap.get_channel().has_value()) { if (ap.has_channel()) {
ret = wifi_set_channel(*ap.get_channel()); ret = wifi_set_channel(ap.get_channel());
if (!ret) { if (!ret) {
ESP_LOGV(TAG, "wifi_set_channel failed"); ESP_LOGV(TAG, "wifi_set_channel failed");
return false; return false;
@@ -845,7 +845,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
} }
memcpy(reinterpret_cast<char *>(conf.ssid), ap.get_ssid().c_str(), ap.get_ssid().size()); memcpy(reinterpret_cast<char *>(conf.ssid), ap.get_ssid().c_str(), ap.get_ssid().size());
conf.ssid_len = static_cast<uint8>(ap.get_ssid().size()); conf.ssid_len = static_cast<uint8>(ap.get_ssid().size());
conf.channel = ap.get_channel().value_or(1); conf.channel = ap.has_channel() ? ap.get_channel() : 1;
conf.ssid_hidden = ap.get_hidden(); conf.ssid_hidden = ap.get_hidden();
conf.max_connection = 5; conf.max_connection = 5;
conf.beacon_interval = 100; conf.beacon_interval = 100;

View File

@@ -339,14 +339,14 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
conf.sta.rm_enabled = this->rrm_; conf.sta.rm_enabled = this->rrm_;
#endif #endif
if (ap.get_bssid().has_value()) { if (ap.has_bssid()) {
conf.sta.bssid_set = true; conf.sta.bssid_set = true;
memcpy(conf.sta.bssid, ap.get_bssid()->data(), 6); memcpy(conf.sta.bssid, ap.get_bssid().data(), 6);
} else { } else {
conf.sta.bssid_set = false; conf.sta.bssid_set = false;
} }
if (ap.get_channel().has_value()) { if (ap.has_channel()) {
conf.sta.channel = *ap.get_channel(); conf.sta.channel = ap.get_channel();
conf.sta.scan_method = WIFI_FAST_SCAN; conf.sta.scan_method = WIFI_FAST_SCAN;
} else { } else {
conf.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; conf.sta.scan_method = WIFI_ALL_CHANNEL_SCAN;
@@ -1003,7 +1003,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
return false; return false;
} }
memcpy(reinterpret_cast<char *>(conf.ap.ssid), ap.get_ssid().c_str(), ap.get_ssid().size()); memcpy(reinterpret_cast<char *>(conf.ap.ssid), ap.get_ssid().c_str(), ap.get_ssid().size());
conf.ap.channel = ap.get_channel().value_or(1); conf.ap.channel = ap.has_channel() ? ap.get_channel() : 1;
conf.ap.ssid_hidden = ap.get_ssid().size(); conf.ap.ssid_hidden = ap.get_ssid().size();
conf.ap.max_connection = 5; conf.ap.max_connection = 5;
conf.ap.beacon_interval = 100; conf.ap.beacon_interval = 100;

View File

@@ -139,8 +139,8 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
s_sta_connecting = true; s_sta_connecting = true;
WiFiStatus status = WiFi.begin(ap.get_ssid().c_str(), ap.get_password().empty() ? NULL : ap.get_password().c_str(), WiFiStatus status = WiFi.begin(ap.get_ssid().c_str(), ap.get_password().empty() ? NULL : ap.get_password().c_str(),
ap.get_channel().has_value() ? *ap.get_channel() : 0, ap.get_channel(), // 0 = auto
ap.get_bssid().has_value() ? ap.get_bssid()->data() : NULL); ap.has_bssid() ? ap.get_bssid().data() : NULL);
if (status != WL_CONNECTED) { if (status != WL_CONNECTED) {
ESP_LOGW(TAG, "esp_wifi_connect failed: %d", status); ESP_LOGW(TAG, "esp_wifi_connect failed: %d", status);
return false; return false;
@@ -522,7 +522,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
yield(); yield();
return WiFi.softAP(ap.get_ssid().c_str(), ap.get_password().empty() ? NULL : ap.get_password().c_str(), return WiFi.softAP(ap.get_ssid().c_str(), ap.get_password().empty() ? NULL : ap.get_password().c_str(),
ap.get_channel().value_or(1), ap.get_hidden()); ap.has_channel() ? ap.get_channel() : 1, ap.get_hidden());
} }
network::IPAddress WiFiComponent::wifi_soft_ap_ip() { return {WiFi.softAPIP()}; } network::IPAddress WiFiComponent::wifi_soft_ap_ip() { return {WiFi.softAPIP()}; }

View File

@@ -192,7 +192,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
} }
#endif #endif
WiFi.beginAP(ap.get_ssid().c_str(), ap.get_password().c_str(), ap.get_channel().value_or(1)); WiFi.beginAP(ap.get_ssid().c_str(), ap.get_password().c_str(), ap.has_channel() ? ap.get_channel() : 1);
return true; return true;
} }