From c0ad5d1d16461acf0fe6de59e38bd9f224aff16d Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 19 Apr 2023 22:54:06 -0500 Subject: [PATCH] Initial attempt at supporting ESP-IDF 5.0.0 (#4364) * requirements: add pyparsing >= 3.0 ESP-IDF >= 5.0 requires pyparsing's rest_of_file, which was introduced in version 3.0. Signed-off-by: Stijn Tintel * esp32: fix build with ESP-IDF >= 5 We need to include esp_timer.h to be able to use esp_timer_get_time(). This header existed in ESP-IDF < 5 so we don't need if guards. Signed-off-by: Stijn Tintel * ota: fix build with ESP-IDF >= 5 As of version 5, esp_task_wdt_init() takes a struct as argument. We also need to include spi_flash_mmap.h. [split unrelated change into separate commits, maintain ESP-IDF < 5 compat, use esp_task_wdt_reconfigure, add commit message] Signed-off-by: Stijn Tintel * core: fix build with ESP-IDF >= 5 These header files already existed in ESP-IDF < 5 so skip if guards. [add commit message] Signed-off-by: Stijn Tintel * wifi: fix build with ESP-IDF >= 5 ESP-IDF 4.1 introduced the esp-netif API as successor to the tcp_adapter API. The tcp_adapter API was removed in ESP-IDF 5.0.0. Part of the wifi component was already migrated to the new API. Migrate the leftover uses of the old API to the new API to fix build on ESP-IDF >= 5. The version of ESP-IDF currently in use (4.4.4) supports the new API, so we don't need any if guards to maintain backwards compatibility. Also replace xQueueHandle, which is a pre FreeRTOS v8.0.0 data type, with QueueHandle_t, so we don't need to enable backward compatibility (CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY). This reverts part of commit d42f35de5d54 to wifi_component_esp_idf.cpp, as the esp-netif API handles that internally. [replace pre FreeRTOS v8.0.0 data type, add commit message] Signed-off-by: Stijn Tintel * mdns: fix build with ESP-IDF >= 5 In ESP-IDF 5.0.0, the mdns component was removed and moved to another repository. Since the mdns component in esphome is always built, we need to add the mdns component from the esp-protocols repository. This component depends on ESP-IDF >= 5.0, so we need to add a version guard. Signed-off-by: Stijn Tintel * docker: install python3-venv As of version 6.0.1, platform-espressif32 requires python3-venv. Switching between esp-idf 4.4.4 and 5.0 causes problems with esp-idf python dependencies installed by PlatformIO. They've solved this by using venv. Install python3-venv so that platform-espressif32 6.0.1 and later can be used, and we don't need to wipe the dependencies manually when switching esp-idf versions. Signed-off-by: Stijn Tintel --------- Signed-off-by: Stijn Tintel Co-authored-by: Stijn Tintel --- docker/Dockerfile | 1 + esphome/components/esp32/core.cpp | 1 + esphome/components/mdns/__init__.py | 13 +++ .../components/ota/ota_backend_esp_idf.cpp | 27 +++++- .../wifi/wifi_component_esp_idf.cpp | 88 ++++++++----------- esphome/core/helpers.cpp | 2 + requirements.txt | 3 + 7 files changed, 82 insertions(+), 53 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 383c73565d..13fba50288 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -24,6 +24,7 @@ RUN \ python3-setuptools=52.0.0-4 \ python3-pil=8.1.2+dfsg-0.3+deb11u1 \ python3-cryptography=3.3.2-1 \ + python3-venv=3.9.2-3 \ iputils-ping=3:20210202-1 \ git=1:2.30.2-1 \ curl=7.74.0-1.3+deb11u7 \ diff --git a/esphome/components/esp32/core.cpp b/esphome/components/esp32/core.cpp index b47392bc6b..512a8857b6 100644 --- a/esphome/components/esp32/core.cpp +++ b/esphome/components/esp32/core.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #if ESP_IDF_VERSION_MAJOR >= 4 diff --git a/esphome/components/mdns/__init__.py b/esphome/components/mdns/__init__.py index e27786a98b..66c84da8d8 100644 --- a/esphome/components/mdns/__init__.py +++ b/esphome/components/mdns/__init__.py @@ -4,10 +4,13 @@ from esphome.const import ( CONF_PROTOCOL, CONF_SERVICES, CONF_SERVICE, + KEY_CORE, + KEY_FRAMEWORK_VERSION, ) import esphome.codegen as cg import esphome.config_validation as cv from esphome.core import CORE, coroutine_with_priority +from esphome.components.esp32 import add_idf_component CODEOWNERS = ["@esphome/core"] DEPENDENCIES = ["network"] @@ -79,6 +82,16 @@ async def to_code(config): elif CORE.is_rp2040: cg.add_library("LEAmDNS", None) + if CORE.using_esp_idf and CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version( + 5, 0, 0 + ): + add_idf_component( + "mdns", + "https://github.com/espressif/esp-protocols.git", + "mdns-v1.0.9", + "components/mdns", + ) + if config[CONF_DISABLED]: return diff --git a/esphome/components/ota/ota_backend_esp_idf.cpp b/esphome/components/ota/ota_backend_esp_idf.cpp index 2fdc00c54d..7688629e39 100644 --- a/esphome/components/ota/ota_backend_esp_idf.cpp +++ b/esphome/components/ota/ota_backend_esp_idf.cpp @@ -8,6 +8,10 @@ #include #include "esphome/components/md5/md5.h" +#if ESP_IDF_VERSION_MAJOR >= 5 +#include +#endif + namespace esphome { namespace ota { @@ -16,9 +20,28 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) { if (this->partition_ == nullptr) { return OTA_RESPONSE_ERROR_NO_UPDATE_PARTITION; } - esp_task_wdt_init(15, false); // The following function takes longer than the 5 seconds timeout of WDT + + // The following function takes longer than the 5 seconds timeout of WDT +#if ESP_IDF_VERSION_MAJOR >= 5 + esp_task_wdt_config_t wdtc; + wdtc.timeout_ms = 15000; + wdtc.idle_core_mask = 0; + wdtc.trigger_panic = false; + esp_task_wdt_reconfigure(&wdtc); +#else + esp_task_wdt_init(15, false); +#endif + esp_err_t err = esp_ota_begin(this->partition_, image_size, &this->update_handle_); - esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false); // Set the WDT back to the configured timeout + + // Set the WDT back to the configured timeout +#if ESP_IDF_VERSION_MAJOR >= 5 + wdtc.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S; + esp_task_wdt_reconfigure(&wdtc); +#else + esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false); +#endif + if (err != ESP_OK) { esp_ota_abort(this->update_handle_); this->update_handle_ = 0; diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 9b2fdaf500..1c70f33040 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -17,6 +17,7 @@ #ifdef USE_WIFI_WPA2_EAP #include #endif +#include "dhcpserver/dhcpserver.h" #include "lwip/err.h" #include "lwip/dns.h" @@ -32,7 +33,7 @@ namespace wifi { static const char *const TAG = "wifi_esp32"; static EventGroupHandle_t s_wifi_event_group; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -static xQueueHandle s_event_queue; // 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) static esp_netif_t *s_ap_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) static bool s_sta_started = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) @@ -414,17 +415,17 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { if (!this->wifi_mode_(true, {})) return false; - tcpip_adapter_dhcp_status_t dhcp_status; - esp_err_t err = tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_STA, &dhcp_status); + esp_netif_dhcp_status_t dhcp_status; + esp_err_t err = esp_netif_dhcpc_get_status(s_sta_netif, &dhcp_status); if (err != ESP_OK) { - ESP_LOGV(TAG, "tcpip_adapter_dhcpc_get_status failed: %s", esp_err_to_name(err)); + ESP_LOGV(TAG, "esp_netif_dhcpc_get_status failed: %s", esp_err_to_name(err)); return false; } if (!manual_ip.has_value()) { - // Use DHCP client - if (dhcp_status != TCPIP_ADAPTER_DHCP_STARTED) { - err = tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA); + // No manual IP is set; use DHCP client + if (dhcp_status != ESP_NETIF_DHCP_STARTED) { + err = esp_netif_dhcpc_start(s_sta_netif); if (err != ESP_OK) { ESP_LOGV(TAG, "Starting DHCP client failed! %d", err); } @@ -433,43 +434,29 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { return true; } - tcpip_adapter_ip_info_t info; - memset(&info, 0, sizeof(info)); + esp_netif_ip_info_t info; // struct of ip4_addr_t with ip, netmask, gw info.ip.addr = static_cast(manual_ip->static_ip); info.gw.addr = static_cast(manual_ip->gateway); info.netmask.addr = static_cast(manual_ip->subnet); - - err = tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA); + err = esp_netif_dhcpc_stop(s_sta_netif); if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) { - ESP_LOGV(TAG, "tcpip_adapter_dhcpc_stop failed: %s", esp_err_to_name(err)); + ESP_LOGV(TAG, "esp_netif_dhcpc_stop failed: %s", esp_err_to_name(err)); return false; } - - err = tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &info); + err = esp_netif_set_ip_info(s_sta_netif, &info); if (err != ESP_OK) { - ESP_LOGV(TAG, "tcpip_adapter_set_ip_info failed: %s", esp_err_to_name(err)); + ESP_LOGV(TAG, "esp_netif_set_ip_info failed: %s", esp_err_to_name(err)); return false; } - ip_addr_t dns; -#if LWIP_IPV6 - dns.type = IPADDR_TYPE_V4; -#endif + esp_netif_dns_info_t dns; if (uint32_t(manual_ip->dns1) != 0) { -#if LWIP_IPV6 - dns.u_addr.ip4.addr = static_cast(manual_ip->dns1); -#else - dns.addr = static_cast(manual_ip->dns1); -#endif - dns_setserver(0, &dns); + dns.ip.u_addr.ip4.addr = static_cast(manual_ip->dns1); + esp_netif_set_dns_info(s_sta_netif, ESP_NETIF_DNS_MAIN, &dns); } if (uint32_t(manual_ip->dns2) != 0) { -#if LWIP_IPV6 - dns.u_addr.ip4.addr = static_cast(manual_ip->dns2); -#else - dns.addr = static_cast(manual_ip->dns2); -#endif - dns_setserver(1, &dns); + dns.ip.u_addr.ip4.addr = static_cast(manual_ip->dns2); + esp_netif_set_dns_info(s_sta_netif, ESP_NETIF_DNS_BACKUP, &dns); } return true; @@ -478,10 +465,10 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { network::IPAddress WiFiComponent::wifi_sta_ip() { if (!this->has_sta()) return {}; - tcpip_adapter_ip_info_t ip; - esp_err_t err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip); + 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, "tcpip_adapter_get_ip_info failed: %s", esp_err_to_name(err)); + ESP_LOGV(TAG, "esp_netif_get_ip_info failed: %s", esp_err_to_name(err)); return false; } return {ip.ip.addr}; @@ -601,9 +588,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_START) { ESP_LOGV(TAG, "Event: WiFi STA start"); // apply hostname - err = tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, App.get_name().c_str()); + err = esp_netif_set_hostname(s_sta_netif, App.get_name().c_str()); if (err != ERR_OK) { - ESP_LOGW(TAG, "tcpip_adapter_set_hostname failed: %s", esp_err_to_name(err)); + ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err)); } s_sta_started = true; @@ -651,7 +638,7 @@ 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 LWIP_IPV6_AUTOCONFIG - tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA); + esp_netif_create_ip6_linklocal(s_sta_netif); #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()); @@ -770,8 +757,7 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { if (!this->wifi_mode_({}, true)) return false; - tcpip_adapter_ip_info_t info; - memset(&info, 0, sizeof(info)); + esp_netif_ip_info_t info; if (manual_ip.has_value()) { info.ip.addr = static_cast(manual_ip->static_ip); info.gw.addr = static_cast(manual_ip->gateway); @@ -781,17 +767,17 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { info.gw.addr = static_cast(network::IPAddress(192, 168, 4, 1)); info.netmask.addr = static_cast(network::IPAddress(255, 255, 255, 0)); } - tcpip_adapter_dhcp_status_t dhcp_status; - tcpip_adapter_dhcps_get_status(TCPIP_ADAPTER_IF_AP, &dhcp_status); - err = tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP); + esp_netif_dhcp_status_t dhcp_status; + esp_netif_dhcps_get_status(s_sta_netif, &dhcp_status); + err = esp_netif_dhcps_stop(s_sta_netif); if (err != ESP_OK) { - ESP_LOGV(TAG, "tcpip_adapter_dhcps_stop failed! %d", err); + ESP_LOGV(TAG, "esp_netif_dhcps_stop failed! %d", err); return false; } - err = tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP, &info); + err = esp_netif_set_ip_info(s_sta_netif, &info); if (err != ESP_OK) { - ESP_LOGV(TAG, "tcpip_adapter_set_ip_info failed! %d", err); + ESP_LOGV(TAG, "esp_netif_set_ip_info failed! %d", err); return false; } @@ -804,17 +790,17 @@ bool WiFiComponent::wifi_ap_ip_config_(optional manual_ip) { start_address[3] += 100; lease.end_ip.addr = static_cast(start_address); ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str()); - err = tcpip_adapter_dhcps_option(TCPIP_ADAPTER_OP_SET, TCPIP_ADAPTER_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); + err = esp_netif_dhcps_option(s_sta_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease, sizeof(lease)); if (err != ESP_OK) { - ESP_LOGV(TAG, "tcpip_adapter_dhcps_option failed! %d", err); + ESP_LOGV(TAG, "esp_netif_dhcps_option failed! %d", err); return false; } - err = tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP); + err = esp_netif_dhcps_start(s_sta_netif); if (err != ESP_OK) { - ESP_LOGV(TAG, "tcpip_adapter_dhcps_start failed! %d", err); + ESP_LOGV(TAG, "esp_netif_dhcps_start failed! %d", err); return false; } @@ -860,8 +846,8 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) { return true; } network::IPAddress WiFiComponent::wifi_soft_ap_ip() { - tcpip_adapter_ip_info_t ip; - tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip); + esp_netif_ip_info_t ip; + esp_netif_get_ip_info(s_sta_netif, &ip); return {ip.ip.addr}; } bool WiFiComponent::wifi_disconnect_() { return esp_wifi_disconnect(); } diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 7f5c3ad333..7e8ba41987 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -18,6 +18,8 @@ #elif defined(USE_ESP32_FRAMEWORK_ARDUINO) #include #elif defined(USE_ESP_IDF) +#include "esp_mac.h" +#include "esp_random.h" #include "esp_system.h" #include #include diff --git a/requirements.txt b/requirements.txt index 5f73cf3a06..bb2c736709 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,3 +16,6 @@ zeroconf==0.56.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 kconfiglib==13.7.1 + +# esp-idf >= 5.0 requires this +pyparsing >= 3.0