mirror of
https://github.com/esphome/esphome.git
synced 2026-11-15 17:45:57 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ea12bb5c3 | ||
|
|
a460c21e96 | ||
|
|
6bd1de6860 |
No files matched your search
@@ -784,6 +784,11 @@ CONFIG_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
def _eap_string(value: str | None) -> cg.Expression | str:
|
||||
"""A std::string field whose literal stays in flash on ESP8266."""
|
||||
return cg.progmem_string(value) if value else ""
|
||||
|
||||
|
||||
def eap_auth(config):
|
||||
if config is None:
|
||||
return None
|
||||
@@ -798,9 +803,9 @@ def eap_auth(config):
|
||||
key = wpa2_eap.read_relative_config_path(config[CONF_KEY])
|
||||
return cg.StructInitializer(
|
||||
EAPAuth,
|
||||
("identity", config.get(CONF_IDENTITY, "")),
|
||||
("username", config.get(CONF_USERNAME, "")),
|
||||
("password", config.get(CONF_PASSWORD, "")),
|
||||
("identity", _eap_string(config.get(CONF_IDENTITY))),
|
||||
("username", _eap_string(config.get(CONF_USERNAME))),
|
||||
("password", _eap_string(config.get(CONF_PASSWORD))),
|
||||
("ca_cert", ca_cert),
|
||||
("client_cert", client_cert),
|
||||
("client_key", key),
|
||||
@@ -822,8 +827,11 @@ def manual_ip_entry(config: ConfigType) -> bytes:
|
||||
|
||||
|
||||
def wifi_network(config, ap, manual_ip_index: int | None):
|
||||
cg.add_optional(ap.set_ssid, config.get(CONF_SSID))
|
||||
cg.add_optional(ap.set_password, config.get(CONF_PASSWORD))
|
||||
# The setters copy the text, so the literal can stay in flash on ESP8266.
|
||||
if (ssid := config.get(CONF_SSID)) is not None:
|
||||
cg.add(ap.set_ssid(cg.FlashStringLiteral(ssid)))
|
||||
if (password := config.get(CONF_PASSWORD)) is not None:
|
||||
cg.add(ap.set_password(cg.FlashStringLiteral(password)))
|
||||
if CONF_EAP in config:
|
||||
cg.add(ap.set_eap(eap_auth(config[CONF_EAP])))
|
||||
cg.add_define("USE_WIFI_WPA2_EAP")
|
||||
|
||||
@@ -78,6 +78,15 @@ CompactString::CompactString(const char *str, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
CompactString CompactString::from_progmem(ProgmemStr str) {
|
||||
char buf[MAX_LENGTH + 1];
|
||||
ESPHOME_strncpy_P(buf, reinterpret_cast<const char *>(str), MAX_LENGTH);
|
||||
buf[MAX_LENGTH] = '\0';
|
||||
return CompactString(buf, strlen(buf));
|
||||
}
|
||||
#endif
|
||||
|
||||
CompactString::CompactString(const CompactString &other) : CompactString(other.data(), other.size()) {}
|
||||
|
||||
CompactString &CompactString::operator=(const CompactString &other) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/progmem.h"
|
||||
#ifdef USE_ESP32
|
||||
#include "esphome/core/lock_free_queue.h"
|
||||
#endif
|
||||
@@ -241,6 +242,10 @@ class CompactString {
|
||||
|
||||
CompactString() : length_(0), is_heap_(0) { this->storage_[0] = '\0'; }
|
||||
CompactString(const char *str, size_t len);
|
||||
#ifdef USE_ESP8266
|
||||
/// Copy a string kept in flash with ESPHOME_F.
|
||||
static CompactString from_progmem(ProgmemStr str);
|
||||
#endif
|
||||
CompactString(const CompactString &other);
|
||||
CompactString(CompactString &&other) noexcept;
|
||||
CompactString &operator=(const CompactString &other);
|
||||
@@ -296,11 +301,17 @@ class WiFiAP {
|
||||
void set_ssid(const std::string &ssid) { this->ssid_ = CompactString(ssid.c_str(), ssid.size()); }
|
||||
void set_ssid(const char *ssid) { this->set_ssid(StringRef(ssid)); }
|
||||
void set_ssid(StringRef ssid) { this->ssid_ = CompactString(ssid.c_str(), ssid.size()); }
|
||||
#ifdef USE_ESP8266
|
||||
void set_ssid(ProgmemStr ssid) { this->ssid_ = CompactString::from_progmem(ssid); }
|
||||
#endif
|
||||
void set_bssid(const bssid_t &bssid) { this->bssid_ = bssid; }
|
||||
void clear_bssid() { this->bssid_ = {}; }
|
||||
void set_password(const std::string &password) { this->password_ = CompactString(password.c_str(), password.size()); }
|
||||
void set_password(const char *password) { this->set_password(StringRef(password)); }
|
||||
void set_password(StringRef password) { this->password_ = CompactString(password.c_str(), password.size()); }
|
||||
#ifdef USE_ESP8266
|
||||
void set_password(ProgmemStr password) { this->password_ = CompactString::from_progmem(password); }
|
||||
#endif
|
||||
#ifdef USE_WIFI_WPA2_EAP
|
||||
void set_eap(optional<EAPAuth> eap_auth) { this->eap_ = std::move(eap_auth); }
|
||||
#endif // USE_WIFI_WPA2_EAP
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp8266:
|
||||
board: d1_mini
|
||||
|
||||
wifi:
|
||||
networks:
|
||||
- ssid: enterprise
|
||||
eap:
|
||||
identity: eap_identity
|
||||
username: eap_username
|
||||
password: eap_password
|
||||
@@ -0,0 +1,15 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
wifi:
|
||||
networks:
|
||||
- ssid: enterprise
|
||||
eap:
|
||||
identity: eap_identity
|
||||
username: eap_username
|
||||
password: eap_password
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Tests that wifi codegen keeps the configured credentials in flash on ESP8266."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("config_file", ["bare.yaml", "bare_ln882x.yaml"])
|
||||
def test_ssid_and_password_use_flash_literals(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
config_file: str,
|
||||
) -> None:
|
||||
"""Codegen emits ESPHOME_F for station and AP credentials; the macro decides placement."""
|
||||
main_cpp = generate_main(component_config_path(config_file))
|
||||
|
||||
assert 'set_ssid(ESPHOME_F("test"));' in main_cpp
|
||||
assert 'set_password(ESPHOME_F("testtest"));' in main_cpp
|
||||
assert 'set_ssid(ESPHOME_F("fallback"));' in main_cpp
|
||||
assert 'set_ssid("' not in main_cpp
|
||||
assert 'set_password("' not in main_cpp
|
||||
|
||||
|
||||
def test_eap_strings_use_flash_literals(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""EAP identity, username and password are built from flash on ESP8266."""
|
||||
main_cpp = generate_main(component_config_path("eap.yaml"))
|
||||
|
||||
for value in ("eap_identity", "eap_username", "eap_password"):
|
||||
assert f'progmem_string(ESPHOME_F("{value}"))' in main_cpp
|
||||
|
||||
|
||||
def test_eap_strings_plain_off_esp8266(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""Off ESP8266 the EAP strings stay plain literals, with no copy from flash."""
|
||||
main_cpp = generate_main(component_config_path("eap_esp32.yaml"))
|
||||
|
||||
assert "progmem_string(" not in main_cpp
|
||||
for value in ("eap_identity", "eap_username", "eap_password"):
|
||||
assert f'"{value}"' in main_cpp
|
||||
@@ -33,6 +33,16 @@ esphome:
|
||||
then:
|
||||
- logger.log: "WiFi is enabled!"
|
||||
- wifi.roam
|
||||
# Runtime credentials keep resolving to the RAM setters, never the flash one
|
||||
- lambda: |-
|
||||
wifi::WiFiAP sta;
|
||||
std::string ssid = "RuntimeSSID";
|
||||
sta.set_ssid(ssid);
|
||||
char password[16] = "runtime_pass";
|
||||
sta.set_password(password);
|
||||
const char *ssid_ptr = ssid.c_str();
|
||||
sta.set_ssid(ssid_ptr);
|
||||
sta.set_password(StringRef(password));
|
||||
|
||||
wifi:
|
||||
networks:
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "esphome/components/wifi/wifi_component.h"
|
||||
|
||||
namespace esphome::wifi::testing {
|
||||
|
||||
TEST(WiFiAP, RuntimeSetters) {
|
||||
// Credentials from improv, captive portal, wifi.configure and lambdas arrive in RAM and are copied.
|
||||
WiFiAP ap;
|
||||
std::string ssid = "runtime_ssid";
|
||||
ap.set_ssid(ssid);
|
||||
char password[] = "runtime_pass";
|
||||
ap.set_password(password);
|
||||
ssid[0] = 'X';
|
||||
password[0] = 'X';
|
||||
EXPECT_EQ(ap.get_ssid(), "runtime_ssid");
|
||||
EXPECT_EQ(ap.get_password(), "runtime_pass");
|
||||
|
||||
const char *ssid_ptr = ssid.c_str();
|
||||
ap.set_ssid(ssid_ptr);
|
||||
ap.set_password(StringRef(password, 4));
|
||||
EXPECT_EQ(ap.get_ssid(), "Xuntime_ssid");
|
||||
EXPECT_EQ(ap.get_password(), "Xunt");
|
||||
}
|
||||
|
||||
} // namespace esphome::wifi::testing
|
||||
Reference in new issue
Block a user