ESPHome 2026.9.0-dev
Loading...
Searching...
No Matches
network_component.cpp
Go to the documentation of this file.
1#include "network_component.h"
2
4#if defined(USE_NETWORK) && defined(USE_ESP32)
5#include "esphome/core/log.h"
6#include "esp_err.h"
7#include "esp_netif.h"
8#include "esp_event.h"
9#include "lwip/opt.h"
10
11#ifdef USE_NETWORK_DEFAULT_ROUTE
14#include "esp_netif_net_stack.h"
15#include "lwip/netif.h"
16#ifdef USE_ETHERNET
18#endif
19#ifdef USE_WIFI
21#endif
22#endif
23
24namespace esphome::network {
25
26static const char *const TAG = "network";
27
29 // Initialize ESP-IDF network interfaces and ensure the default event loop exists
30 esp_err_t err;
31 err = esp_netif_init();
32 if (err != ESP_OK) {
33 ESP_LOGE(TAG, "esp_netif_init failed: (%d) %s", err, esp_err_to_name(err));
34 this->mark_failed();
35 return;
36 }
37 err = esp_event_loop_create_default();
38 // ESP_ERR_INVALID_STATE is returned if the default loop already exists,
39 // which is fine since we just want to make sure it exists
40 if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
41 ESP_LOGE(TAG, "esp_event_loop_create_default failed: (%d) %s", err, esp_err_to_name(err));
42 this->mark_failed();
43 return;
44 }
45}
46
48 // The effective compile-time lwIP value, so the log reflects tcp_send_buffer
49 // or the high performance bundle when either changed it.
50 ESP_LOGCONFIG(TAG,
51 "Network:\n"
52 " TCP send buffer: %d bytes",
53 TCP_SND_BUF);
54}
55
56#ifdef USE_NETWORK_DEFAULT_ROUTE
57static esp_netif_t *connected_wifi_netif() {
58#ifdef USE_WIFI
59 auto *wifi = wifi::global_wifi_component;
60 if (wifi != nullptr && wifi->is_connected())
61 return wifi->get_esp_netif_sta();
62#endif
63 return nullptr;
64}
65
66static esp_netif_t *connected_ethernet_netif() {
67#ifdef USE_ETHERNET
69 if (eth != nullptr && eth->is_connected())
70 return eth->get_esp_netif();
71#endif
72 return nullptr;
73}
74
76 // Pin the default route to the first connected interface in the user's priority
77 // order; ESP-IDF's own route_prio selection would always favor WiFi.
78 // USE_NETWORK_PRIMARY_INTERFACE_WIFI is emitted for a wifi-first priority list;
79 // it selects the reported address in util.cpp and doubles as the route-order
80 // pivot here — the two uses must stay in sync.
81 esp_netif_t *best;
82#ifdef USE_NETWORK_PRIMARY_INTERFACE_WIFI
83 best = connected_wifi_netif();
84 if (best == nullptr)
85 best = connected_ethernet_netif();
86#else
87 best = connected_ethernet_netif();
88 if (best == nullptr)
89 best = connected_wifi_netif();
90#endif
91 if (best == nullptr) {
92 // Forget the last winner: stopping its netif cleared lwIP's default route and
93 // IDF's manual override suppresses re-election, so reconnect must re-assert it.
94 this->default_netif_ = nullptr;
95 return;
96 }
97 if (best == this->default_netif_) {
98 // Same winner as the last assert. Still re-assert if lwIP's default route is
99 // not the winner's netif: a winner whose netif bounced down and up between two
100 // polls would otherwise stay routeless (stopping a netif nulls lwIP's
101 // netif_default). Checking lwIP directly keeps this independent of IDF's
102 // re-election bookkeeping (esp_netif_get_default_netif() cannot detect it).
103 // Throttled: LwIPLock is the global lwIP core mutex, and this branch runs on
104 // every pass once the route has settled.
107 return;
108 this->last_route_check_ = now;
109 bool route_is_ours;
110 {
112 route_is_ours = static_cast<void *>(netif_default) == esp_netif_get_netif_impl(best);
113 }
114 if (route_is_ours)
115 return;
116 }
117 esp_err_t err = esp_netif_set_default_netif(best);
118 if (err != ESP_OK) {
119 ESP_LOGW(TAG, "Failed to set default interface: (%d) %s", err, esp_err_to_name(err));
120 // Cache the intent anyway: subsequent passes take the same-winner branch
121 // above, so retries are throttled to ROUTE_CHECK_INTERVAL_MS and the lwIP
122 // verification keeps re-attempting until the route is actually ours.
123 this->default_netif_ = best;
125 return;
126 }
127 this->default_netif_ = best;
128 ESP_LOGI(TAG, "Default interface: %s", esp_netif_get_desc(best));
129}
130#endif // USE_NETWORK_DEFAULT_ROUTE
131
132} // namespace esphome::network
133#endif
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void mark_failed()
Mark this component as failed.
Helper class to lock the lwIP TCPIP core when making lwIP API calls from non-TCPIP threads.
Definition helpers.h:2020
esp_netif_t * get_esp_netif()
esp_netif handle, used by network for default-route arbitration.
static constexpr uint32_t ROUTE_CHECK_INTERVAL_MS
esp_netif_t * get_esp_netif_sta()
esp_netif handle of the station interface, used by network for default-route arbitration.
EthernetComponent * global_eth_component
WiFiComponent * global_wifi_component
Application App
Global storage of Application pointer - only one Application can exist.
struct esp_netif_obj esp_netif_t
static void uint32_t
SemaphoreHandle_t lock