Skip to content

Commit

Permalink
Initial attempt at supporting ESP-IDF 5.0.0 (#4364)
Browse files Browse the repository at this point in the history
* 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 d42f35d 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>
  • Loading branch information
kbx81 and stintel committed Apr 20, 2023
1 parent 4c39631 commit c0ad5d1
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 53 deletions.
1 change: 1 addition & 0 deletions docker/Dockerfile
Expand Up @@ -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 \
Expand Down
1 change: 1 addition & 0 deletions esphome/components/esp32/core.cpp
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions esphome/components/mdns/__init__.py
Expand Up @@ -4,10 +4,13 @@
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"]
Expand Down Expand Up @@ -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

Expand Down
27 changes: 25 additions & 2 deletions esphome/components/ota/ota_backend_esp_idf.cpp
Expand Up @@ -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 {

Expand All @@ -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;
Expand Down
88 changes: 37 additions & 51 deletions esphome/components/wifi/wifi_component_esp_idf.cpp
Expand Up @@ -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"

Expand All @@ -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)
Expand Down Expand Up @@ -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);
}
Expand All @@ -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;
Expand All @@ -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};
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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(); }
Expand Down
2 changes: 2 additions & 0 deletions esphome/core/helpers.cpp
Expand Up @@ -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>
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Expand Up @@ -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

0 comments on commit c0ad5d1

Please sign in to comment.