mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 16:37:52 +01:00
Add IPv6 support for ESP-IDF framework (#2953)
Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
This commit is contained in:
parent
7a0827e3d0
commit
d92f297bc0
@ -24,7 +24,7 @@ static const char *const TAG = "api";
|
||||
void APIServer::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up Home Assistant API server...");
|
||||
this->setup_controller();
|
||||
socket_ = socket::socket(AF_INET, SOCK_STREAM, 0);
|
||||
socket_ = socket::socket_ip(SOCK_STREAM, 0);
|
||||
if (socket_ == nullptr) {
|
||||
ESP_LOGW(TAG, "Could not create socket.");
|
||||
this->mark_failed();
|
||||
@ -43,13 +43,16 @@ void APIServer::setup() {
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in server;
|
||||
memset(&server, 0, sizeof(server));
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = ESPHOME_INADDR_ANY;
|
||||
server.sin_port = htons(this->port_);
|
||||
struct sockaddr_storage server;
|
||||
|
||||
err = socket_->bind((struct sockaddr *) &server, sizeof(server));
|
||||
socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), htons(this->port_));
|
||||
if (sl == 0) {
|
||||
ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
err = socket_->bind((struct sockaddr *) &server, sl);
|
||||
if (err != 0) {
|
||||
ESP_LOGW(TAG, "Socket unable to bind: errno %d", errno);
|
||||
this->mark_failed();
|
||||
|
@ -1,7 +1,27 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components.esp32 import add_idf_sdkconfig_option
|
||||
|
||||
from esphome.const import (
|
||||
CONF_ENABLE_IPV6,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
AUTO_LOAD = ["mdns"]
|
||||
|
||||
network_ns = cg.esphome_ns.namespace("network")
|
||||
IPAddress = network_ns.class_("IPAddress")
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.SplitDefault(CONF_ENABLE_IPV6, esp32_idf=False): cv.All(
|
||||
cv.only_with_esp_idf, cv.boolean
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
if CONF_ENABLE_IPV6 in config and config[CONF_ENABLE_IPV6]:
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", True)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_IPV6_AUTOCONFIG", True)
|
||||
|
@ -36,7 +36,7 @@ std::unique_ptr<OTABackend> make_ota_backend() {
|
||||
}
|
||||
|
||||
void OTAComponent::setup() {
|
||||
server_ = socket::socket(AF_INET, SOCK_STREAM, 0);
|
||||
server_ = socket::socket_ip(SOCK_STREAM, 0);
|
||||
if (server_ == nullptr) {
|
||||
ESP_LOGW(TAG, "Could not create socket.");
|
||||
this->mark_failed();
|
||||
@ -55,11 +55,14 @@ void OTAComponent::setup() {
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in server;
|
||||
memset(&server, 0, sizeof(server));
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = ESPHOME_INADDR_ANY;
|
||||
server.sin_port = htons(this->port_);
|
||||
struct sockaddr_storage server;
|
||||
|
||||
socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), htons(this->port_));
|
||||
if (sl == 0) {
|
||||
ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
err = server_->bind((struct sockaddr *) &server, sizeof(server));
|
||||
if (err != 0) {
|
||||
|
43
esphome/components/socket/socket.cpp
Normal file
43
esphome/components/socket/socket.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "socket.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
|
||||
namespace esphome {
|
||||
namespace socket {
|
||||
|
||||
std::unique_ptr<Socket> socket_ip(int type, int protocol) {
|
||||
#if LWIP_IPV6
|
||||
return socket(AF_INET6, type, protocol);
|
||||
#else
|
||||
return socket(AF_INET, type, protocol);
|
||||
#endif
|
||||
}
|
||||
|
||||
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port) {
|
||||
#if LWIP_IPV6
|
||||
if (addrlen < sizeof(sockaddr_in6)) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
auto *server = reinterpret_cast<sockaddr_in6 *>(addr);
|
||||
memset(server, 0, sizeof(sockaddr_in6));
|
||||
server->sin6_family = AF_INET6;
|
||||
server->sin6_port = port;
|
||||
server->sin6_addr = in6addr_any;
|
||||
return sizeof(sockaddr_in6);
|
||||
#else
|
||||
if (addrlen < sizeof(sockaddr_in)) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
auto *server = reinterpret_cast<sockaddr_in *>(addr);
|
||||
memset(server, 0, sizeof(sockaddr_in));
|
||||
server->sin_family = AF_INET;
|
||||
server->sin_addr.s_addr = ESPHOME_INADDR_ANY;
|
||||
server->sin_port = port;
|
||||
return sizeof(sockaddr_in);
|
||||
#endif
|
||||
}
|
||||
} // namespace socket
|
||||
} // namespace esphome
|
@ -38,7 +38,14 @@ class Socket {
|
||||
virtual int loop() { return 0; };
|
||||
};
|
||||
|
||||
/// Create a socket of the given domain, type and protocol.
|
||||
std::unique_ptr<Socket> socket(int domain, int type, int protocol);
|
||||
|
||||
/// Create a socket in the newest available IP domain (IPv6 or IPv4) of the given type and protocol.
|
||||
std::unique_ptr<Socket> socket_ip(int type, int protocol);
|
||||
|
||||
/// Set a sockaddr to the any address for the IP version used by socket_ip().
|
||||
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port);
|
||||
|
||||
} // namespace socket
|
||||
} // namespace esphome
|
||||
|
@ -56,6 +56,7 @@ 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;
|
||||
ip_event_got_ip6_t ip_got_ip6;
|
||||
ip_event_ap_staipassigned_t ip_ap_staipassigned;
|
||||
} data;
|
||||
};
|
||||
@ -79,6 +80,8 @@ 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));
|
||||
} 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));
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_LOST_IP) { // NOLINT(bugprone-branch-clone)
|
||||
// no data
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) {
|
||||
@ -497,12 +500,8 @@ const char *get_auth_mode_str(uint8_t mode) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string format_ip4_addr(const esp_ip4_addr_t &ip) {
|
||||
char buf[20];
|
||||
snprintf(buf, sizeof(buf), "%u.%u.%u.%u", uint8_t(ip.addr >> 0), uint8_t(ip.addr >> 8), uint8_t(ip.addr >> 16),
|
||||
uint8_t(ip.addr >> 24));
|
||||
return buf;
|
||||
}
|
||||
std::string format_ip4_addr(const esp_ip4_addr_t &ip) { return str_snprintf(IPSTR, 15, IP2STR(&ip)); }
|
||||
std::string format_ip6_addr(const esp_ip6_addr_t &ip) { return str_snprintf(IPV6STR, 39, IPV62STR(ip)); }
|
||||
const char *get_disconnect_reason_str(uint8_t reason) {
|
||||
switch (reason) {
|
||||
case WIFI_REASON_AUTH_EXPIRE:
|
||||
@ -635,10 +634,17 @@ 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;
|
||||
#ifdef LWIP_IPV6_AUTOCONFIG
|
||||
tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
|
||||
#endif
|
||||
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;
|
||||
|
||||
} 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());
|
||||
|
||||
} 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;
|
||||
|
@ -188,6 +188,7 @@ CONF_ECO2 = "eco2"
|
||||
CONF_EFFECT = "effect"
|
||||
CONF_EFFECTS = "effects"
|
||||
CONF_ELSE = "else"
|
||||
CONF_ENABLE_IPV6 = "enable_ipv6"
|
||||
CONF_ENABLE_PIN = "enable_pin"
|
||||
CONF_ENABLE_TIME = "enable_time"
|
||||
CONF_ENERGY = "energy"
|
||||
|
Loading…
Reference in New Issue
Block a user