1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-08 21:03:49 +01:00

Improve dualstack and IPv6 support (#5449)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
Jimmy Hedman
2024-02-27 09:16:20 +01:00
committed by GitHub
parent 5e04914a11
commit f73518dbeb
26 changed files with 300 additions and 140 deletions

View File

@@ -207,14 +207,13 @@ void WiFiComponent::set_fast_connect(bool fast_connect) { this->fast_connect_ =
void WiFiComponent::set_btm(bool btm) { this->btm_ = btm; }
void WiFiComponent::set_rrm(bool rrm) { this->rrm_ = rrm; }
#endif
network::IPAddress WiFiComponent::get_ip_address() {
network::IPAddresses WiFiComponent::get_ip_addresses() {
if (this->has_sta())
return this->wifi_sta_ip();
return this->wifi_sta_ip_addresses();
#ifdef USE_WIFI_AP
if (this->has_ap())
return this->wifi_soft_ap_ip();
return {this->wifi_soft_ap_ip()};
#endif // USE_WIFI_AP
return {};
@@ -412,7 +411,11 @@ void WiFiComponent::print_connect_params_() {
return;
}
ESP_LOGCONFIG(TAG, " SSID: " LOG_SECRET("'%s'"), wifi_ssid().c_str());
ESP_LOGCONFIG(TAG, " IP Address: %s", wifi_sta_ip().str().c_str());
for (auto &ip : wifi_sta_ip_addresses()) {
if (ip.is_set()) {
ESP_LOGCONFIG(TAG, " IP Address: %s", ip.str().c_str());
}
}
ESP_LOGCONFIG(TAG, " BSSID: " LOG_SECRET("%02X:%02X:%02X:%02X:%02X:%02X"), bssid[0], bssid[1], bssid[2], bssid[3],
bssid[4], bssid[5]);
ESP_LOGCONFIG(TAG, " Hostname: '%s'", App.get_name().c_str());

View File

@@ -258,7 +258,7 @@ class WiFiComponent : public Component {
#endif
network::IPAddress get_dns_address(int num);
network::IPAddress get_ip_address();
network::IPAddresses get_ip_addresses();
std::string get_use_address() const;
void set_use_address(const std::string &use_address);
@@ -293,7 +293,7 @@ class WiFiComponent : public Component {
});
}
network::IPAddress wifi_sta_ip();
network::IPAddresses wifi_sta_ip_addresses();
std::string wifi_ssid();
bssid_t wifi_bssid();
@@ -396,6 +396,10 @@ class WiFiComponent : public Component {
bool rrm_{false};
#endif
bool enable_on_boot_;
bool got_ipv4_address_{false};
#if USE_NETWORK_IPV6
uint8_t num_ipv6_addresses_{0};
#endif /* USE_NETWORK_IPV6 */
Trigger<> *connect_trigger_{new Trigger<>()};
Trigger<> *disconnect_trigger_{new Trigger<>()};

View File

@@ -131,7 +131,7 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
// TODO: is this needed?
#if LWIP_IPV6
dns.type = IPADDR_TYPE_V4;
#endif
#endif /* LWIP_IPV6 */
if (manual_ip->dns1.is_set()) {
dns = manual_ip->dns1;
dns_setserver(0, &dns);
@@ -144,12 +144,36 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
return true;
}
network::IPAddress WiFiComponent::wifi_sta_ip() {
network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() {
if (!this->has_sta())
return {};
network::IPAddresses addresses;
tcpip_adapter_ip_info_t ip;
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip);
return network::IPAddress(&ip.ip);
esp_err_t err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip);
if (err != ESP_OK) {
ESP_LOGV(TAG, "esp_netif_get_ip_info failed: %s", esp_err_to_name(err));
// TODO: do something smarter
// return false;
} else {
addresses[0] = network::IPAddress(&ip.ip);
}
#if LWIP_IPV6
ip6_addr_t ipv6;
err = tcpip_adapter_get_ip6_global(TCPIP_ADAPTER_IF_STA, &ipv6);
if (err != ESP_OK) {
ESP_LOGV(TAG, "esp_netif_get_ip6_gobal failed: %s", esp_err_to_name(err));
} else {
addresses[1] = network::IPAddress(&ipv6);
}
err = tcpip_adapter_get_ip6_linklocal(TCPIP_ADAPTER_IF_STA, &ipv6);
if (err != ESP_OK) {
ESP_LOGV(TAG, "esp_netif_get_ip6_linklocal failed: %s", esp_err_to_name(err));
} else {
addresses[2] = network::IPAddress(&ipv6);
}
#endif /* LWIP_IPV6 */
return addresses;
}
bool WiFiComponent::wifi_apply_hostname_() {
@@ -440,9 +464,9 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
buf[it.ssid_len] = '\0';
ESP_LOGV(TAG, "Event: Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf,
format_mac_addr(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
#if ENABLE_IPV6
#if USE_NETWORK_IPV6
this->set_timeout(100, [] { WiFi.enableIpV6(); });
#endif /* ENABLE_IPV6 */
#endif /* USE_NETWORK_IPV6 */
break;
}
@@ -494,18 +518,26 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
auto it = info.got_ip.ip_info;
ESP_LOGV(TAG, "Event: Got IP static_ip=%s gateway=%s", format_ip4_addr(it.ip).c_str(),
format_ip4_addr(it.gw).c_str());
this->got_ipv4_address_ = true;
#if USE_NETWORK_IPV6
s_sta_connecting = this->num_ipv6_addresses_ < USE_NETWORK_MIN_IPV6_ADDR_COUNT;
#else
s_sta_connecting = false;
#endif /* USE_NETWORK_IPV6 */
break;
}
#if ENABLE_IPV6
#if USE_NETWORK_IPV6
case ESPHOME_EVENT_ID_WIFI_STA_GOT_IP6: {
auto it = info.got_ip6.ip6_info;
ESP_LOGV(TAG, "Got IPv6 address=" IPV6STR, IPV62STR(it.ip));
this->num_ipv6_addresses_++;
s_sta_connecting = !(this->got_ipv4_address_ & (this->num_ipv6_addresses_ >= USE_NETWORK_MIN_IPV6_ADDR_COUNT));
break;
}
#endif /* ENABLE_IPV6 */
#endif /* USE_NETWORK_IPV6 */
case ESPHOME_EVENT_ID_WIFI_STA_LOST_IP: {
ESP_LOGV(TAG, "Event: Lost IP");
this->got_ipv4_address_ = false;
break;
}
case ESPHOME_EVENT_ID_WIFI_AP_START: {

View File

@@ -17,10 +17,8 @@ extern "C" {
#include "lwip/dhcp.h"
#include "lwip/init.h" // LWIP_VERSION_
#include "lwip/apps/sntp.h"
#if LWIP_IPV6
#include "lwip/netif.h" // struct netif
#include <AddrList.h>
#endif
#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 0, 0)
#include "LwipDhcpServer.h"
#define wifi_softap_set_dhcps_lease(lease) dhcpSoftAP.set_dhcps_lease(lease)
@@ -185,12 +183,15 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
return ret;
}
network::IPAddress WiFiComponent::wifi_sta_ip() {
network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() {
if (!this->has_sta())
return {};
struct ip_info ip {};
wifi_get_ip_info(STATION_IF, &ip);
return network::IPAddress(&ip.ip);
network::IPAddresses addresses;
uint8_t index = 0;
for (auto &addr : addrList) {
addresses[index++] = addr.ipFromNetifNum();
}
return addresses;
}
bool WiFiComponent::wifi_apply_hostname_() {
const std::string &hostname = App.get_name();
@@ -327,17 +328,20 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
return false;
}
#if ENABLE_IPV6
for (bool configured = false; !configured;) {
#if USE_NETWORK_IPV6
bool connected = false;
while (!connected) {
uint8_t ipv6_addr_count = 0;
for (auto addr : addrList) {
ESP_LOGV(TAG, "Address %s", addr.toString().c_str());
if ((configured = !addr.isLocal() && addr.isV6())) {
break;
if (addr.isV6()) {
ipv6_addr_count++;
}
}
delay(500); // NOLINT
connected = (ipv6_addr_count >= USE_NETWORK_MIN_IPV6_ADDR_COUNT);
}
#endif
#endif /* USE_NETWORK_IPV6 */
if (ap.get_channel().has_value()) {
ret = wifi_set_channel(*ap.get_channel());

View File

@@ -39,14 +39,11 @@ static const char *const TAG = "wifi_esp32";
static EventGroupHandle_t s_wifi_event_group; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static QueueHandle_t s_event_queue; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static esp_netif_t *s_sta_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
#ifdef USE_WIFI_AP
static esp_netif_t *s_ap_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
#endif // USE_WIFI_AP
static esp_netif_t *s_ap_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
#endif // USE_WIFI_AP
static bool s_sta_started = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static bool s_sta_connected = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static bool s_sta_got_ip = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static bool s_ap_started = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static bool s_sta_connect_not_found = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
static bool s_sta_connect_error = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
@@ -66,9 +63,9 @@ struct IDFWiFiEvent {
wifi_event_ap_probe_req_rx_t ap_probe_req_rx;
wifi_event_bss_rssi_low_t bss_rssi_low;
ip_event_got_ip_t ip_got_ip;
#if ENABLE_IPV6
#if USE_NETWORK_IPV6
ip_event_got_ip6_t ip_got_ip6;
#endif /* ENABLE_IPV6 */
#endif /* USE_NETWORK_IPV6 */
ip_event_ap_staipassigned_t ip_ap_staipassigned;
} data;
};
@@ -92,7 +89,7 @@ void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, voi
memcpy(&event.data.sta_disconnected, event_data, sizeof(wifi_event_sta_disconnected_t));
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
memcpy(&event.data.ip_got_ip, event_data, sizeof(ip_event_got_ip_t));
#if ENABLE_IPV6
#if USE_NETWORK_IPV6
} else if (event_base == IP_EVENT && event_id == IP_EVENT_GOT_IP6) {
memcpy(&event.data.ip_got_ip6, event_data, sizeof(ip_event_got_ip6_t));
#endif
@@ -411,7 +408,6 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
// may be called from wifi_station_connect
s_sta_connecting = true;
s_sta_connected = false;
s_sta_got_ip = false;
s_sta_connect_error = false;
s_sta_connect_not_found = false;
@@ -476,17 +472,29 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
return true;
}
network::IPAddress WiFiComponent::wifi_sta_ip() {
network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() {
if (!this->has_sta())
return {};
network::IPAddresses addresses;
esp_netif_ip_info_t ip;
esp_err_t err = esp_netif_get_ip_info(s_sta_netif, &ip);
if (err != ESP_OK) {
ESP_LOGV(TAG, "esp_netif_get_ip_info failed: %s", esp_err_to_name(err));
// TODO: do something smarter
// return false;
} else {
addresses[0] = network::IPAddress(&ip.ip);
}
return network::IPAddress(&ip.ip);
#if USE_NETWORK_IPV6
struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES];
uint8_t count = 0;
count = esp_netif_get_all_ip6(s_sta_netif, if_ip6s);
assert(count <= CONFIG_LWIP_IPV6_NUM_ADDRESSES);
for (int i = 0; i < count; i++) {
addresses[i + 1] = network::IPAddress(&if_ip6s[i]);
}
#endif /* USE_NETWORK_IPV6 */
return addresses;
}
bool WiFiComponent::wifi_apply_hostname_() {
@@ -521,7 +529,7 @@ const char *get_auth_mode_str(uint8_t mode) {
std::string format_ip4_addr(const esp_ip4_addr_t &ip) { return str_snprintf(IPSTR, 15, IP2STR(&ip)); }
#if LWIP_IPV6
std::string format_ip6_addr(const esp_ip6_addr_t &ip) { return str_snprintf(IPV6STR, 39, IPV62STR(ip)); }
#endif
#endif /* LWIP_IPV6 */
const char *get_disconnect_reason_str(uint8_t reason) {
switch (reason) {
case WIFI_REASON_AUTH_EXPIRE:
@@ -658,22 +666,23 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_GOT_IP) {
const auto &it = data->data.ip_got_ip;
#if ENABLE_IPV6
#if USE_NETWORK_IPV6
esp_netif_create_ip6_linklocal(s_sta_netif);
#endif /* ENABLE_IPV6 */
#endif /* USE_NETWORK_IPV6 */
ESP_LOGV(TAG, "Event: Got IP static_ip=%s gateway=%s", format_ip4_addr(it.ip_info.ip).c_str(),
format_ip4_addr(it.ip_info.gw).c_str());
s_sta_got_ip = true;
this->got_ipv4_address_ = true;
#if ENABLE_IPV6
#if USE_NETWORK_IPV6
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_GOT_IP6) {
const auto &it = data->data.ip_got_ip6;
ESP_LOGV(TAG, "Event: Got IPv6 address=%s", format_ip6_addr(it.ip6_info.ip).c_str());
#endif /* ENABLE_IPV6 */
this->num_ipv6_addresses_++;
#endif /* USE_NETWORK_IPV6 */
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_LOST_IP) {
ESP_LOGV(TAG, "Event: Lost IP");
s_sta_got_ip = false;
this->got_ipv4_address_ = false;
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_SCAN_DONE) {
const auto &it = data->data.sta_scan_done;
@@ -737,8 +746,14 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
}
WiFiSTAConnectStatus WiFiComponent::wifi_sta_connect_status_() {
if (s_sta_connected && s_sta_got_ip) {
if (s_sta_connected && this->got_ipv4_address_) {
#if USE_NETWORK_IPV6
if (this->num_ipv6_addresses_ >= USE_NETWORK_MIN_IPV6_ADDR_COUNT) {
return WiFiSTAConnectStatus::CONNECTED;
}
#else
return WiFiSTAConnectStatus::CONNECTED;
#endif /* USE_NETWORK_IPV6 */
}
if (s_sta_connect_error) {
return WiFiSTAConnectStatus::ERROR_CONNECT_FAILED;

View File

@@ -81,7 +81,7 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
return true;
}
network::IPAddress WiFiComponent::wifi_sta_ip() {
network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() {
if (!this->has_sta())
return {};
return {WiFi.localIP()};

View File

@@ -6,6 +6,7 @@
#include "lwip/dns.h"
#include "lwip/err.h"
#include "lwip/netif.h"
#include <AddrList.h>
#include "esphome/core/application.h"
#include "esphome/core/hal.h"
@@ -173,7 +174,14 @@ std::string WiFiComponent::wifi_ssid() { return WiFi.SSID().c_str(); }
int8_t WiFiComponent::wifi_rssi() { return WiFi.RSSI(); }
int32_t WiFiComponent::wifi_channel_() { return WiFi.channel(); }
network::IPAddress WiFiComponent::wifi_sta_ip() { return {(const ip_addr_t *) WiFi.localIP()}; }
network::IPAddresses WiFiComponent::wifi_sta_ip_addresses() {
network::IPAddresses addresses;
uint8_t index = 0;
for (auto addr : addrList) {
addresses[index++] = addr.ipFromNetifNum();
}
return addresses;
}
network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {(const ip_addr_t *) WiFi.subnetMask()}; }
network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {(const ip_addr_t *) WiFi.gatewayIP()}; }
network::IPAddress WiFiComponent::wifi_dns_ip_(int num) {