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 <stijn@linux-ipv6.be>

* 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 <stijn@linux-ipv6.be>

* 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 <stijn@linux-ipv6.be>

* 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 <stijn@linux-ipv6.be>

* 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 d42f35de5d 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 <stijn@linux-ipv6.be>

* 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 <stijn@linux-ipv6.be>

* 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 <stijn@linux-ipv6.be>

---------

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Co-authored-by: Stijn Tintel <stijn@linux-ipv6.be>
This commit is contained in:
Keith Burzinski 2023-04-19 22:54:06 -05:00 committed by GitHub
parent 4c39631428
commit c0ad5d1d16
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 53 deletions

View file

@ -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 \

View file

@ -7,6 +7,7 @@
#include <freertos/task.h>
#include <esp_idf_version.h>
#include <esp_task_wdt.h>
#include <esp_timer.h>
#include <soc/rtc.h>
#if ESP_IDF_VERSION_MAJOR >= 4

View file

@ -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

View file

@ -8,6 +8,10 @@
#include <esp_ota_ops.h>
#include "esphome/components/md5/md5.h"
#if ESP_IDF_VERSION_MAJOR >= 5
#include <spi_flash_mmap.h>
#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;

View file

@ -17,6 +17,7 @@
#ifdef USE_WIFI_WPA2_EAP
#include <esp_wpa2.h>
#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<ManualIP> 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<ManualIP> 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<uint32_t>(manual_ip->static_ip);
info.gw.addr = static_cast<uint32_t>(manual_ip->gateway);
info.netmask.addr = static_cast<uint32_t>(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<uint32_t>(manual_ip->dns1);
#else
dns.addr = static_cast<uint32_t>(manual_ip->dns1);
#endif
dns_setserver(0, &dns);
dns.ip.u_addr.ip4.addr = static_cast<uint32_t>(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<uint32_t>(manual_ip->dns2);
#else
dns.addr = static_cast<uint32_t>(manual_ip->dns2);
#endif
dns_setserver(1, &dns);
dns.ip.u_addr.ip4.addr = static_cast<uint32_t>(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<ManualIP> 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<ManualIP> 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<uint32_t>(manual_ip->static_ip);
info.gw.addr = static_cast<uint32_t>(manual_ip->gateway);
@ -781,17 +767,17 @@ bool WiFiComponent::wifi_ap_ip_config_(optional<ManualIP> manual_ip) {
info.gw.addr = static_cast<uint32_t>(network::IPAddress(192, 168, 4, 1));
info.netmask.addr = static_cast<uint32_t>(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<ManualIP> manual_ip) {
start_address[3] += 100;
lease.end_ip.addr = static_cast<uint32_t>(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(); }

View file

@ -18,6 +18,8 @@
#elif defined(USE_ESP32_FRAMEWORK_ARDUINO)
#include <Esp.h>
#elif defined(USE_ESP_IDF)
#include "esp_mac.h"
#include "esp_random.h"
#include "esp_system.h"
#include <freertos/FreeRTOS.h>
#include <freertos/portmacro.h>

View file

@ -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