mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[wifi] Store credentials in PROGMEM on ESP8266 to reduce RAM usage
This commit is contained in:
		| @@ -140,17 +140,21 @@ EAP_AUTH_SCHEMA = cv.All( | ||||
|     cv.has_at_least_one_key(CONF_IDENTITY, CONF_CERTIFICATE), | ||||
| ) | ||||
|  | ||||
| CONF_AP_TIMEOUT = "ap_timeout" | ||||
| CONF_SSID_DATA_ID = "ssid_data_id" | ||||
| CONF_PASSWORD_DATA_ID = "password_data_id" | ||||
|  | ||||
| WIFI_NETWORK_BASE = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(WiFiAP), | ||||
|         cv.GenerateID(CONF_SSID_DATA_ID): cv.declare_id(cg.uint8), | ||||
|         cv.GenerateID(CONF_PASSWORD_DATA_ID): cv.declare_id(cg.uint8), | ||||
|         cv.Optional(CONF_SSID): cv.ssid, | ||||
|         cv.Optional(CONF_PASSWORD): validate_password, | ||||
|         cv.Optional(CONF_CHANNEL): validate_channel, | ||||
|         cv.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA, | ||||
|     } | ||||
| ) | ||||
|  | ||||
| CONF_AP_TIMEOUT = "ap_timeout" | ||||
| WIFI_NETWORK_AP = WIFI_NETWORK_BASE.extend( | ||||
|     { | ||||
|         cv.Optional( | ||||
| @@ -352,9 +356,23 @@ def manual_ip(config): | ||||
|  | ||||
| def wifi_network(config, ap, static_ip): | ||||
|     if CONF_SSID in config: | ||||
|         cg.add(ap.set_ssid(config[CONF_SSID])) | ||||
|         ssid = config[CONF_SSID] | ||||
|         if CORE.is_esp8266: | ||||
|             # On ESP8266, store SSID in PROGMEM to save RAM | ||||
|             prog_arr = cg.progmem_array(config[CONF_SSID_DATA_ID], ssid) | ||||
|             cg.add(ap.set_ssid_flash(prog_arr)) | ||||
|         else: | ||||
|             # On ESP32/RP2040, string literals are already in rodata (flash) | ||||
|             cg.add(ap.set_ssid_flash(ssid)) | ||||
|     if CONF_PASSWORD in config: | ||||
|         cg.add(ap.set_password(config[CONF_PASSWORD])) | ||||
|         password = config[CONF_PASSWORD] | ||||
|         if CORE.is_esp8266: | ||||
|             # On ESP8266, store password in PROGMEM to save RAM | ||||
|             prog_arr = cg.progmem_array(config[CONF_PASSWORD_DATA_ID], password) | ||||
|             cg.add(ap.set_password_flash(prog_arr)) | ||||
|         else: | ||||
|             # On ESP32/RP2040, string literals are already in rodata (flash) | ||||
|             cg.add(ap.set_password_flash(password)) | ||||
|     if CONF_EAP in config: | ||||
|         cg.add(ap.set_eap(eap_auth(config[CONF_EAP]))) | ||||
|         cg.add_define("USE_WIFI_WPA2_EAP") | ||||
|   | ||||
| @@ -888,19 +888,68 @@ void WiFiComponent::save_fast_connect_settings_() { | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void WiFiAP::set_ssid(const std::string &ssid) { this->ssid_ = ssid; } | ||||
| void WiFiAP::set_ssid(const std::string &ssid) { | ||||
|   this->ssid_storage_ = ssid; | ||||
|   this->ssid_ = this->ssid_storage_->c_str(); | ||||
| } | ||||
| void WiFiAP::set_bssid(bssid_t bssid) { this->bssid_ = bssid; } | ||||
| void WiFiAP::set_bssid(optional<bssid_t> bssid) { this->bssid_ = bssid; } | ||||
| void WiFiAP::set_password(const std::string &password) { this->password_ = password; } | ||||
| void WiFiAP::set_password(const std::string &password) { | ||||
|   this->password_storage_ = password; | ||||
|   this->password_ = this->password_storage_->c_str(); | ||||
| } | ||||
| #ifdef USE_ESP8266 | ||||
| void WiFiAP::set_ssid_flash(const uint8_t *ssid) { | ||||
|   this->ssid_storage_.reset(); | ||||
|   this->ssid_ = reinterpret_cast<const char *>(ssid); | ||||
| } | ||||
| void WiFiAP::set_password_flash(const uint8_t *password) { | ||||
|   this->password_storage_.reset(); | ||||
|   this->password_ = reinterpret_cast<const char *>(password); | ||||
| } | ||||
| #else | ||||
| void WiFiAP::set_ssid_flash(const char *ssid) { | ||||
|   this->ssid_storage_.reset(); | ||||
|   this->ssid_ = ssid; | ||||
| } | ||||
| void WiFiAP::set_password_flash(const char *password) { | ||||
|   this->password_storage_.reset(); | ||||
|   this->password_ = password; | ||||
| } | ||||
| #endif | ||||
| #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_manual_ip(optional<ManualIP> manual_ip) { this->manual_ip_ = manual_ip; } | ||||
| void WiFiAP::set_hidden(bool hidden) { this->hidden_ = hidden; } | ||||
| const std::string &WiFiAP::get_ssid() const { return this->ssid_; } | ||||
| std::string WiFiAP::get_ssid() const { | ||||
| #ifdef USE_ESP8266 | ||||
|   if (!this->ssid_storage_.has_value()) { | ||||
|     // Flash storage - read from PROGMEM | ||||
|     size_t len = strlen_P(this->ssid_); | ||||
|     std::string result; | ||||
|     result.resize(len); | ||||
|     memcpy_P(&result[0], this->ssid_, len); | ||||
|     return result; | ||||
|   } | ||||
| #endif | ||||
|   return std::string(this->ssid_); | ||||
| } | ||||
| const optional<bssid_t> &WiFiAP::get_bssid() const { return this->bssid_; } | ||||
| const std::string &WiFiAP::get_password() const { return this->password_; } | ||||
| std::string WiFiAP::get_password() const { | ||||
| #ifdef USE_ESP8266 | ||||
|   if (!this->password_storage_.has_value()) { | ||||
|     // Flash storage - read from PROGMEM | ||||
|     size_t len = strlen_P(this->password_); | ||||
|     std::string result; | ||||
|     result.resize(len); | ||||
|     memcpy_P(&result[0], this->password_, len); | ||||
|     return result; | ||||
|   } | ||||
| #endif | ||||
|   return std::string(this->password_); | ||||
| } | ||||
| #ifdef USE_WIFI_WPA2_EAP | ||||
| const optional<EAPAuth> &WiFiAP::get_eap() const { return this->eap_; } | ||||
| #endif | ||||
|   | ||||
| @@ -135,6 +135,18 @@ class WiFiAP { | ||||
|   void set_bssid(bssid_t bssid); | ||||
|   void set_bssid(optional<bssid_t> bssid); | ||||
|   void set_password(const std::string &password); | ||||
|   /// Set SSID from flash string (PROGMEM on ESP8266, rodata on ESP32) | ||||
| #ifdef USE_ESP8266 | ||||
|   void set_ssid_flash(const uint8_t *ssid); | ||||
| #else | ||||
|   void set_ssid_flash(const char *ssid); | ||||
| #endif | ||||
|   /// Set password from flash string (PROGMEM on ESP8266, rodata on ESP32) | ||||
| #ifdef USE_ESP8266 | ||||
|   void set_password_flash(const uint8_t *password); | ||||
| #else | ||||
|   void set_password_flash(const char *password); | ||||
| #endif | ||||
| #ifdef USE_WIFI_WPA2_EAP | ||||
|   void set_eap(optional<EAPAuth> eap_auth); | ||||
| #endif  // USE_WIFI_WPA2_EAP | ||||
| @@ -142,9 +154,9 @@ class WiFiAP { | ||||
|   void set_priority(float priority) { priority_ = priority; } | ||||
|   void set_manual_ip(optional<ManualIP> manual_ip); | ||||
|   void set_hidden(bool hidden); | ||||
|   const std::string &get_ssid() const; | ||||
|   std::string get_ssid() const; | ||||
|   const optional<bssid_t> &get_bssid() const; | ||||
|   const std::string &get_password() const; | ||||
|   std::string get_password() const; | ||||
| #ifdef USE_WIFI_WPA2_EAP | ||||
|   const optional<EAPAuth> &get_eap() const; | ||||
| #endif  // USE_WIFI_WPA2_EAP | ||||
| @@ -154,8 +166,10 @@ class WiFiAP { | ||||
|   bool get_hidden() const; | ||||
|  | ||||
|  protected: | ||||
|   std::string ssid_; | ||||
|   std::string password_; | ||||
|   const char *ssid_{nullptr}; | ||||
|   const char *password_{nullptr}; | ||||
|   optional<std::string> ssid_storage_; | ||||
|   optional<std::string> password_storage_; | ||||
|   optional<bssid_t> bssid_; | ||||
| #ifdef USE_WIFI_WPA2_EAP | ||||
|   optional<EAPAuth> eap_; | ||||
|   | ||||
| @@ -236,16 +236,25 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) { | ||||
|  | ||||
|   struct station_config conf {}; | ||||
|   memset(&conf, 0, sizeof(conf)); | ||||
|   if (ap.get_ssid().size() > sizeof(conf.ssid)) { | ||||
|  | ||||
|   std::string ssid = ap.get_ssid(); | ||||
|   std::string password = ap.get_password(); | ||||
|  | ||||
|   size_t ssid_len = ssid.length(); | ||||
|   size_t password_len = password.length(); | ||||
|  | ||||
|   if (ssid_len > sizeof(conf.ssid)) { | ||||
|     ESP_LOGE(TAG, "SSID too long"); | ||||
|     return false; | ||||
|   } | ||||
|   if (ap.get_password().size() > sizeof(conf.password)) { | ||||
|  | ||||
|   if (password_len > sizeof(conf.password)) { | ||||
|     ESP_LOGE(TAG, "Password too long"); | ||||
|     return false; | ||||
|   } | ||||
|   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(conf.ssid, ssid.c_str(), ssid_len); | ||||
|   memcpy(conf.password, password.c_str(), password_len); | ||||
|  | ||||
|   if (ap.get_bssid().has_value()) { | ||||
|     conf.bssid_set = 1; | ||||
| @@ -791,27 +800,35 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { | ||||
|     return false; | ||||
|  | ||||
|   struct softap_config conf {}; | ||||
|   if (ap.get_ssid().size() > sizeof(conf.ssid)) { | ||||
|  | ||||
|   std::string ssid = ap.get_ssid(); | ||||
|   std::string password = ap.get_password(); | ||||
|  | ||||
|   size_t ssid_len = ssid.length(); | ||||
|   size_t password_len = password.length(); | ||||
|  | ||||
|   if (ssid_len > sizeof(conf.ssid)) { | ||||
|     ESP_LOGE(TAG, "AP SSID too long"); | ||||
|     return false; | ||||
|   } | ||||
|   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()); | ||||
|  | ||||
|   memcpy(conf.ssid, ssid.c_str(), ssid_len); | ||||
|   conf.ssid_len = static_cast<uint8>(ssid_len); | ||||
|   conf.channel = ap.get_channel().value_or(1); | ||||
|   conf.ssid_hidden = ap.get_hidden(); | ||||
|   conf.max_connection = 5; | ||||
|   conf.beacon_interval = 100; | ||||
|  | ||||
|   if (ap.get_password().empty()) { | ||||
|   if (password_len == 0) { | ||||
|     conf.authmode = AUTH_OPEN; | ||||
|     *conf.password = 0; | ||||
|   } else { | ||||
|     conf.authmode = AUTH_WPA2_PSK; | ||||
|     if (ap.get_password().size() > sizeof(conf.password)) { | ||||
|     if (password_len > sizeof(conf.password)) { | ||||
|       ESP_LOGE(TAG, "AP password too long"); | ||||
|       return false; | ||||
|     } | ||||
|     memcpy(reinterpret_cast<char *>(conf.password), ap.get_password().c_str(), ap.get_password().size()); | ||||
|     memcpy(conf.password, password.c_str(), password_len); | ||||
|   } | ||||
|  | ||||
|   ETS_UART_INTR_DISABLE(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user