ESPHome  2023.5.4
ethernet_component.cpp
Go to the documentation of this file.
1 #include "ethernet_component.h"
2 #include "esphome/core/log.h"
3 #include "esphome/core/util.h"
5 
6 #ifdef USE_ESP32
7 
8 #include <lwip/dns.h>
9 #include "esp_event.h"
10 
11 namespace esphome {
12 namespace ethernet {
13 
14 static const char *const TAG = "ethernet";
15 
16 EthernetComponent *global_eth_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
17 
18 #define ESPHL_ERROR_CHECK(err, message) \
19  if ((err) != ESP_OK) { \
20  ESP_LOGE(TAG, message ": (%d) %s", err, esp_err_to_name(err)); \
21  this->mark_failed(); \
22  return; \
23  }
24 
25 EthernetComponent::EthernetComponent() { global_eth_component = this; }
26 
28  ESP_LOGCONFIG(TAG, "Setting up Ethernet...");
29  if (esp_reset_reason() != ESP_RST_DEEPSLEEP) {
30  // Delay here to allow power to stabilise before Ethernet is initialized.
31  delay(300); // NOLINT
32  }
33 
34  esp_err_t err;
35  err = esp_netif_init();
36  ESPHL_ERROR_CHECK(err, "ETH netif init error");
37  err = esp_event_loop_create_default();
38  ESPHL_ERROR_CHECK(err, "ETH event loop error");
39 
40  esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
41  this->eth_netif_ = esp_netif_new(&cfg);
42 
43  // Init MAC and PHY configs to default
44  eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
45  eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
46 
47  phy_config.phy_addr = this->phy_addr_;
48  phy_config.reset_gpio_num = this->power_pin_;
49 
50  mac_config.smi_mdc_gpio_num = this->mdc_pin_;
51  mac_config.smi_mdio_gpio_num = this->mdio_pin_;
52  mac_config.clock_config.rmii.clock_mode = this->clk_mode_;
53  mac_config.clock_config.rmii.clock_gpio = this->clk_gpio_;
54 
55  esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
56 
57  switch (this->type_) {
58  case ETHERNET_TYPE_LAN8720: {
59  this->phy_ = esp_eth_phy_new_lan87xx(&phy_config);
60  break;
61  }
62  case ETHERNET_TYPE_RTL8201: {
63  this->phy_ = esp_eth_phy_new_rtl8201(&phy_config);
64  break;
65  }
66  case ETHERNET_TYPE_DP83848: {
67  this->phy_ = esp_eth_phy_new_dp83848(&phy_config);
68  break;
69  }
70  case ETHERNET_TYPE_IP101: {
71  this->phy_ = esp_eth_phy_new_ip101(&phy_config);
72  break;
73  }
74  case ETHERNET_TYPE_JL1101: {
75  this->phy_ = esp_eth_phy_new_jl1101(&phy_config);
76  break;
77  }
78  case ETHERNET_TYPE_KSZ8081: {
79  this->phy_ = esp_eth_phy_new_ksz8081(&phy_config);
80  break;
81  }
82  default: {
83  this->mark_failed();
84  return;
85  }
86  }
87 
88  esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, this->phy_);
89  this->eth_handle_ = nullptr;
90  err = esp_eth_driver_install(&eth_config, &this->eth_handle_);
91  ESPHL_ERROR_CHECK(err, "ETH driver install error");
92  /* attach Ethernet driver to TCP/IP stack */
93  err = esp_netif_attach(this->eth_netif_, esp_eth_new_netif_glue(this->eth_handle_));
94  ESPHL_ERROR_CHECK(err, "ETH netif attach error");
95 
96  // Register user defined event handers
97  err = esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &EthernetComponent::eth_event_handler, nullptr);
98  ESPHL_ERROR_CHECK(err, "ETH event handler register error");
99  err = esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &EthernetComponent::got_ip_event_handler, nullptr);
100  ESPHL_ERROR_CHECK(err, "GOT IP event handler register error");
101 
102  /* start Ethernet driver state machine */
103  err = esp_eth_start(this->eth_handle_);
104  ESPHL_ERROR_CHECK(err, "ETH start error");
105 }
106 
108  const uint32_t now = millis();
109 
110  switch (this->state_) {
112  if (this->started_) {
113  ESP_LOGI(TAG, "Starting ethernet connection");
115  this->start_connect_();
116  }
117  break;
119  if (!this->started_) {
120  ESP_LOGI(TAG, "Stopped ethernet connection");
122  } else if (this->connected_) {
123  // connection established
124  ESP_LOGI(TAG, "Connected via Ethernet!");
126 
127  this->dump_connect_params_();
128  this->status_clear_warning();
129  } else if (now - this->connect_begin_ > 15000) {
130  ESP_LOGW(TAG, "Connecting via ethernet failed! Re-connecting...");
131  this->start_connect_();
132  }
133  break;
135  if (!this->started_) {
136  ESP_LOGI(TAG, "Stopped ethernet connection");
138  } else if (!this->connected_) {
139  ESP_LOGW(TAG, "Connection via Ethernet lost! Re-connecting...");
141  this->start_connect_();
142  }
143  break;
144  }
145 }
146 
148  const char *eth_type;
149  switch (this->type_) {
151  eth_type = "LAN8720";
152  break;
153 
155  eth_type = "RTL8201";
156  break;
157 
159  eth_type = "DP83848";
160  break;
161 
162  case ETHERNET_TYPE_IP101:
163  eth_type = "IP101";
164  break;
165 
167  eth_type = "JL1101";
168  break;
169 
171  eth_type = "KSZ8081";
172  break;
173 
174  default:
175  eth_type = "Unknown";
176  break;
177  }
178 
179  ESP_LOGCONFIG(TAG, "Ethernet:");
180  this->dump_connect_params_();
181  if (this->power_pin_ != -1) {
182  ESP_LOGCONFIG(TAG, " Power Pin: %u", this->power_pin_);
183  }
184  ESP_LOGCONFIG(TAG, " MDC Pin: %u", this->mdc_pin_);
185  ESP_LOGCONFIG(TAG, " MDIO Pin: %u", this->mdio_pin_);
186  ESP_LOGCONFIG(TAG, " Type: %s", eth_type);
187  ESP_LOGCONFIG(TAG, " PHY addr: %u", this->phy_addr_);
188 }
189 
191 
193 
195  esp_netif_ip_info_t ip;
196  esp_netif_get_ip_info(this->eth_netif_, &ip);
197  return {ip.ip.addr};
198 }
199 
200 void EthernetComponent::eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event, void *event_data) {
201  const char *event_name;
202 
203  switch (event) {
204  case ETHERNET_EVENT_START:
205  event_name = "ETH started";
206  global_eth_component->started_ = true;
207  break;
208  case ETHERNET_EVENT_STOP:
209  event_name = "ETH stopped";
210  global_eth_component->started_ = false;
211  global_eth_component->connected_ = false;
212  break;
213  case ETHERNET_EVENT_CONNECTED:
214  event_name = "ETH connected";
215  break;
216  case ETHERNET_EVENT_DISCONNECTED:
217  event_name = "ETH disconnected";
218  global_eth_component->connected_ = false;
219  break;
220  default:
221  return;
222  }
223 
224  ESP_LOGV(TAG, "[Ethernet event] %s (num=%d)", event_name, event);
225 }
226 
227 void EthernetComponent::got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id,
228  void *event_data) {
229  global_eth_component->connected_ = true;
230  ESP_LOGV(TAG, "[Ethernet event] ETH Got IP (num=%d)", event_id);
231 }
232 
234  this->connect_begin_ = millis();
235  this->status_set_warning();
236 
237  esp_err_t err;
238  err = esp_netif_set_hostname(this->eth_netif_, App.get_name().c_str());
239  if (err != ERR_OK) {
240  ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err));
241  }
242 
243  esp_netif_ip_info_t info;
244  if (this->manual_ip_.has_value()) {
245  info.ip.addr = static_cast<uint32_t>(this->manual_ip_->static_ip);
246  info.gw.addr = static_cast<uint32_t>(this->manual_ip_->gateway);
247  info.netmask.addr = static_cast<uint32_t>(this->manual_ip_->subnet);
248  } else {
249  info.ip.addr = 0;
250  info.gw.addr = 0;
251  info.netmask.addr = 0;
252  }
253 
254  esp_netif_dhcp_status_t status = ESP_NETIF_DHCP_INIT;
255 
256  err = esp_netif_dhcpc_get_status(this->eth_netif_, &status);
257  ESPHL_ERROR_CHECK(err, "DHCPC Get Status Failed!");
258 
259  ESP_LOGV(TAG, "DHCP Client Status: %d", status);
260 
261  err = esp_netif_dhcpc_stop(this->eth_netif_);
262  if (err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
263  ESPHL_ERROR_CHECK(err, "DHCPC stop error");
264  }
265 
266  err = esp_netif_set_ip_info(this->eth_netif_, &info);
267  ESPHL_ERROR_CHECK(err, "DHCPC set IP info error");
268 
269  if (this->manual_ip_.has_value()) {
270  if (uint32_t(this->manual_ip_->dns1) != 0) {
271  ip_addr_t d;
272 #if LWIP_IPV6
273  d.type = IPADDR_TYPE_V4;
274  d.u_addr.ip4.addr = static_cast<uint32_t>(this->manual_ip_->dns1);
275 #else
276  d.addr = static_cast<uint32_t>(this->manual_ip_->dns1);
277 #endif
278  dns_setserver(0, &d);
279  }
280  if (uint32_t(this->manual_ip_->dns2) != 0) {
281  ip_addr_t d;
282 #if LWIP_IPV6
283  d.type = IPADDR_TYPE_V4;
284  d.u_addr.ip4.addr = static_cast<uint32_t>(this->manual_ip_->dns2);
285 #else
286  d.addr = static_cast<uint32_t>(this->manual_ip_->dns2);
287 #endif
288  dns_setserver(1, &d);
289  }
290  } else {
291  err = esp_netif_dhcpc_start(this->eth_netif_);
292  if (err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) {
293  ESPHL_ERROR_CHECK(err, "DHCPC start error");
294  }
295  }
296 
297  this->connect_begin_ = millis();
298  this->status_set_warning();
299 }
300 
302 
304  esp_netif_ip_info_t ip;
305  esp_netif_get_ip_info(this->eth_netif_, &ip);
306  ESP_LOGCONFIG(TAG, " IP Address: %s", network::IPAddress(ip.ip.addr).str().c_str());
307  ESP_LOGCONFIG(TAG, " Hostname: '%s'", App.get_name().c_str());
308  ESP_LOGCONFIG(TAG, " Subnet: %s", network::IPAddress(ip.netmask.addr).str().c_str());
309  ESP_LOGCONFIG(TAG, " Gateway: %s", network::IPAddress(ip.gw.addr).str().c_str());
310 
311  const ip_addr_t *dns_ip1 = dns_getserver(0);
312  const ip_addr_t *dns_ip2 = dns_getserver(1);
313 
314 #if LWIP_IPV6
315  ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1->u_addr.ip4.addr).str().c_str());
316  ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->u_addr.ip4.addr).str().c_str());
317 #else
318  ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1->addr).str().c_str());
319  ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->addr).str().c_str());
320 #endif
321 
322  esp_err_t err;
323 
324  uint8_t mac[6];
325  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_MAC_ADDR, &mac);
326  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_MAC error");
327  ESP_LOGCONFIG(TAG, " MAC Address: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
328 
329  eth_duplex_t duplex_mode;
330  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_DUPLEX_MODE, &duplex_mode);
331  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_DUPLEX_MODE error");
332  ESP_LOGCONFIG(TAG, " Is Full Duplex: %s", YESNO(duplex_mode == ETH_DUPLEX_FULL));
333 
334  eth_speed_t speed;
335  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_SPEED, &speed);
336  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_SPEED error");
337  ESP_LOGCONFIG(TAG, " Link Speed: %u", speed == ETH_SPEED_100M ? 100 : 10);
338 }
339 
340 void EthernetComponent::set_phy_addr(uint8_t phy_addr) { this->phy_addr_ = phy_addr; }
341 void EthernetComponent::set_power_pin(int power_pin) { this->power_pin_ = power_pin; }
342 void EthernetComponent::set_mdc_pin(uint8_t mdc_pin) { this->mdc_pin_ = mdc_pin; }
343 void EthernetComponent::set_mdio_pin(uint8_t mdio_pin) { this->mdio_pin_ = mdio_pin; }
345 void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio) {
346  this->clk_mode_ = clk_mode;
347  this->clk_gpio_ = clk_gpio;
348 }
349 void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
350 
352  if (this->use_address_.empty()) {
353  return App.get_name() + ".local";
354  }
355  return this->use_address_;
356 }
357 
358 void EthernetComponent::set_use_address(const std::string &use_address) { this->use_address_ = use_address; }
359 
361  ESP_LOGI(TAG, "Powering down ethernet PHY");
362  if (this->phy_ == nullptr) {
363  ESP_LOGE(TAG, "Ethernet PHY not assigned");
364  return false;
365  }
366  this->connected_ = false;
367  this->started_ = false;
368  if (this->phy_->pwrctl(this->phy_, false) != ESP_OK) {
369  ESP_LOGE(TAG, "Error powering down ethernet PHY");
370  return false;
371  }
372  return true;
373 }
374 
375 } // namespace ethernet
376 } // namespace esphome
377 
378 #endif // USE_ESP32
void set_manual_ip(const ManualIP &manual_ip)
esp_eth_phy_t * esp_eth_phy_new_jl1101(const eth_phy_config_t *config)
std::string str() const
Definition: ip_address.h:28
int speed
Definition: fan.h:35
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:27
EthernetComponent * global_eth_component
void set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio)
static void got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
void status_clear_warning()
Definition: component.cpp:153
uint8_t type
Application App
Global storage of Application pointer - only one Application can exist.
const std::string & get_name() const
Get the name of this Application set by pre_setup().
Definition: application.h:143
void status_set_warning()
Definition: component.cpp:145
void set_use_address(const std::string &use_address)
uint8_t status
Definition: bl0942.h:23
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:112
Definition: a4988.cpp:4
static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:28