[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
#include <cassert>
#include <cinttypes>
#include <cmath>
#ifdef USE_ESP32
#if (ESP_IDF_VERSION_MAJOR >= 5 && ESP_IDF_VERSION_MINOR >= 1)
@@ -394,7 +395,7 @@ void WiFiComponent::start() {
if (this->has_sta()) {
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");
}
@@ -441,7 +442,7 @@ void WiFiComponent::start() {
#ifdef USE_WIFI_AP
} else if (this->has_ap()) {
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");
}
#ifdef USE_CAPTIVE_PORTAL
@@ -713,8 +714,8 @@ WiFiAP WiFiComponent::build_params_for_current_phase_() {
case WiFiRetryPhase::RETRY_HIDDEN:
// Hidden network mode: clear BSSID/channel to trigger probe request
// (both explicit hidden and retry hidden use same behavior)
params.set_bssid(optional<bssid_t>{});
params.set_channel(optional<uint8_t>{});
params.clear_bssid();
params.clear_channel();
break;
case WiFiRetryPhase::SCAN_CONNECTING:
@@ -766,21 +767,20 @@ void WiFiComponent::start_connecting(const WiFiAP &ap) {
char bssid_s[18];
int8_t priority = 0;
if (ap.get_bssid().has_value()) {
format_mac_addr_upper(ap.get_bssid().value().data(), bssid_s);
priority = this->get_sta_priority(ap.get_bssid().value());
if (ap.has_bssid()) {
format_mac_addr_upper(ap.get_bssid().data(), bssid_s);
priority = this->get_sta_priority(ap.get_bssid());
}
ESP_LOGI(TAG,
"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,
this->num_retried_ + 1, get_max_retries_for_phase(this->retry_phase_),
LOG_STR_ARG(retry_phase_to_log_string(this->retry_phase_)));
ap.get_ssid().c_str(), ap.has_bssid() ? bssid_s : LOG_STR_LITERAL("any"), priority, this->num_retried_ + 1,
get_max_retries_for_phase(this->retry_phase_), LOG_STR_ARG(retry_phase_to_log_string(this->retry_phase_)));
#ifdef ESPHOME_LOG_HAS_VERBOSE
ESP_LOGV(TAG, "Connection Params:");
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);
} else {
ESP_LOGV(TAG, " BSSID: Not Set");
@@ -808,8 +808,8 @@ void WiFiComponent::start_connecting(const WiFiAP &ap) {
#ifdef USE_WIFI_WPA2_EAP
}
#endif
if (ap.get_channel().has_value()) {
ESP_LOGV(TAG, " Channel: %u", *ap.get_channel());
if (ap.has_channel()) {
ESP_LOGV(TAG, " Channel: %u", ap.get_channel());
} else {
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(),
wifi_dns_ip_(0).str().c_str(), wifi_dns_ip_(1).str().c_str());
#ifdef ESPHOME_LOG_HAS_VERBOSE
if (const WiFiAP *config = this->get_selected_sta_(); config && config->get_bssid().has_value()) {
ESP_LOGV(TAG, " Priority: %d", this->get_sta_priority(*config->get_bssid()));
if (const WiFiAP *config = this->get_selected_sta_(); config && config->has_bssid()) {
ESP_LOGV(TAG, " Priority: %d", this->get_sta_priority(config->get_bssid()));
}
#endif
#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()) {
// Scan-based phase: always use best result (index 0)
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)
failed_bssid = *config->get_bssid();
failed_bssid = config->get_bssid();
}
if (!failed_bssid.has_value()) {
@@ -1784,24 +1784,27 @@ void WiFiComponent::save_fast_connect_settings_() {
#endif
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(optional<bssid_t> bssid) { this->bssid_ = bssid; }
void WiFiAP::set_bssid(const bssid_t &bssid) { this->bssid_ = bssid; }
void WiFiAP::clear_bssid() { this->bssid_ = {}; }
void WiFiAP::set_password(const std::string &password) { this->password_ = password; }
#ifdef USE_WIFI_WPA2_EAP
void WiFiAP::set_eap(optional<EAPAuth> eap_auth) { this->eap_ = std::move(eap_auth); }
#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
void WiFiAP::set_manual_ip(optional<ManualIP> manual_ip) { this->manual_ip_ = manual_ip; }
#endif
void WiFiAP::set_hidden(bool hidden) { this->hidden_ = hidden; }
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_; }
#ifdef USE_WIFI_WPA2_EAP
const optional<EAPAuth> &WiFiAP::get_eap() const { return this->eap_; }
#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
const optional<ManualIP> &WiFiAP::get_manual_ip() const { return this->manual_ip_; }
#endif
@@ -1829,7 +1832,7 @@ bool WiFiScanResult::matches(const WiFiAP &config) const {
// network is configured without SSID - match other settings
}
// 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;
#ifdef USE_WIFI_WPA2_EAP
@@ -1847,7 +1850,7 @@ bool WiFiScanResult::matches(const WiFiAP &config) const {
#endif
// 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 true;

View File

@@ -151,25 +151,28 @@ template<typename T> using wifi_scan_vector_t = FixedVector<T>;
class WiFiAP {
public:
void set_ssid(const std::string &ssid);
void set_bssid(bssid_t bssid);
void set_bssid(optional<bssid_t> bssid);
void set_bssid(const bssid_t &bssid);
void clear_bssid();
void set_password(const std::string &password);
#ifdef USE_WIFI_WPA2_EAP
void set_eap(optional<EAPAuth> eap_auth);
#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; }
#ifdef USE_WIFI_MANUAL_IP
void set_manual_ip(optional<ManualIP> manual_ip);
#endif
void set_hidden(bool hidden);
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;
#ifdef USE_WIFI_WPA2_EAP
const optional<EAPAuth> &get_eap() const;
#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_; }
#ifdef USE_WIFI_MANUAL_IP
const optional<ManualIP> &get_manual_ip() const;
@@ -179,16 +182,17 @@ class WiFiAP {
protected:
std::string ssid_;
std::string password_;
optional<bssid_t> bssid_;
#ifdef USE_WIFI_WPA2_EAP
optional<EAPAuth> eap_;
#endif // USE_WIFI_WPA2_EAP
#ifdef USE_WIFI_MANUAL_IP
optional<ManualIP> manual_ip_;
#endif
optional<uint8_t> channel_;
int8_t priority_{0};
bool hidden_{false};
// Group small types together to minimize padding
bssid_t bssid_{}; // 6 bytes, all zeros = any/not set
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 {
@@ -590,7 +594,7 @@ class WiFiComponent : public Component {
#ifdef USE_WIFI_AP
WiFiAP ap_;
#endif
optional<float> output_power_;
float output_power_{NAN};
#ifdef USE_WIFI_LISTENERS
std::vector<WiFiIPStateListener *> ip_state_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.password), ap.get_password().c_str(), ap.get_password().size());
if (ap.get_bssid().has_value()) {
if (ap.has_bssid()) {
conf.bssid_set = 1;
memcpy(conf.bssid, ap.get_bssid()->data(), 6);
memcpy(conf.bssid, ap.get_bssid().data(), 6);
} else {
conf.bssid_set = 0;
}
@@ -381,8 +381,8 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
}
#endif /* USE_NETWORK_IPV6 */
if (ap.get_channel().has_value()) {
ret = wifi_set_channel(*ap.get_channel());
if (ap.has_channel()) {
ret = wifi_set_channel(ap.get_channel());
if (!ret) {
ESP_LOGV(TAG, "wifi_set_channel failed");
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());
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.max_connection = 5;
conf.beacon_interval = 100;

View File

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

View File

@@ -139,8 +139,8 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
s_sta_connecting = true;
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_bssid().has_value() ? ap.get_bssid()->data() : NULL);
ap.get_channel(), // 0 = auto
ap.has_bssid() ? ap.get_bssid().data() : NULL);
if (status != WL_CONNECTED) {
ESP_LOGW(TAG, "esp_wifi_connect failed: %d", status);
return false;
@@ -522,7 +522,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
yield();
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()}; }

View File

@@ -192,7 +192,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
}
#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;
}