ESPHome  2023.3.1
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  // Delay here to allow power to stabilise before Ethernet is initialised.
30  delay(300); // NOLINT
31 
32  esp_err_t err;
33  err = esp_netif_init();
34  ESPHL_ERROR_CHECK(err, "ETH netif init error");
35  err = esp_event_loop_create_default();
36  ESPHL_ERROR_CHECK(err, "ETH event loop error");
37 
38  esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
39  this->eth_netif_ = esp_netif_new(&cfg);
40 
41  // Init MAC and PHY configs to default
42  eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
43  eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
44 
45  phy_config.phy_addr = this->phy_addr_;
46  phy_config.reset_gpio_num = this->power_pin_;
47 
48  mac_config.smi_mdc_gpio_num = this->mdc_pin_;
49  mac_config.smi_mdio_gpio_num = this->mdio_pin_;
50  mac_config.clock_config.rmii.clock_mode = this->clk_mode_;
51  mac_config.clock_config.rmii.clock_gpio = this->clk_gpio_;
52 
53  esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
54 
55  esp_eth_phy_t *phy;
56  switch (this->type_) {
57  case ETHERNET_TYPE_LAN8720: {
58  phy = esp_eth_phy_new_lan87xx(&phy_config);
59  break;
60  }
61  case ETHERNET_TYPE_RTL8201: {
62  phy = esp_eth_phy_new_rtl8201(&phy_config);
63  break;
64  }
65  case ETHERNET_TYPE_DP83848: {
66  phy = esp_eth_phy_new_dp83848(&phy_config);
67  break;
68  }
69  case ETHERNET_TYPE_IP101: {
70  phy = esp_eth_phy_new_ip101(&phy_config);
71  break;
72  }
73  case ETHERNET_TYPE_JL1101: {
74  phy = esp_eth_phy_new_jl1101(&phy_config);
75  break;
76  }
77  default: {
78  this->mark_failed();
79  return;
80  }
81  }
82 
83  esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
84  this->eth_handle_ = nullptr;
85  err = esp_eth_driver_install(&eth_config, &this->eth_handle_);
86  ESPHL_ERROR_CHECK(err, "ETH driver install error");
87  /* attach Ethernet driver to TCP/IP stack */
88  err = esp_netif_attach(this->eth_netif_, esp_eth_new_netif_glue(this->eth_handle_));
89  ESPHL_ERROR_CHECK(err, "ETH netif attach error");
90 
91  // Register user defined event handers
92  err = esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &EthernetComponent::eth_event_handler, nullptr);
93  ESPHL_ERROR_CHECK(err, "ETH event handler register error");
94  err = esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &EthernetComponent::got_ip_event_handler, nullptr);
95  ESPHL_ERROR_CHECK(err, "GOT IP event handler register error");
96 
97  /* start Ethernet driver state machine */
98  err = esp_eth_start(this->eth_handle_);
99  ESPHL_ERROR_CHECK(err, "ETH start error");
100 }
101 
103  const uint32_t now = millis();
104 
105  switch (this->state_) {
107  if (this->started_) {
108  ESP_LOGI(TAG, "Starting ethernet connection");
110  this->start_connect_();
111  }
112  break;
114  if (!this->started_) {
115  ESP_LOGI(TAG, "Stopped ethernet connection");
117  } else if (this->connected_) {
118  // connection established
119  ESP_LOGI(TAG, "Connected via Ethernet!");
121 
122  this->dump_connect_params_();
123  this->status_clear_warning();
124  } else if (now - this->connect_begin_ > 15000) {
125  ESP_LOGW(TAG, "Connecting via ethernet failed! Re-connecting...");
126  this->start_connect_();
127  }
128  break;
130  if (!this->started_) {
131  ESP_LOGI(TAG, "Stopped ethernet connection");
133  } else if (!this->connected_) {
134  ESP_LOGW(TAG, "Connection via Ethernet lost! Re-connecting...");
136  this->start_connect_();
137  }
138  break;
139  }
140 }
141 
143  std::string eth_type;
144  switch (this->type_) {
146  eth_type = "LAN8720";
147  break;
148 
150  eth_type = "RTL8201";
151  break;
152 
154  eth_type = "DP83848";
155  break;
156 
157  case ETHERNET_TYPE_IP101:
158  eth_type = "IP101";
159  break;
160 
161  default:
162  eth_type = "Unknown";
163  break;
164  }
165 
166  ESP_LOGCONFIG(TAG, "Ethernet:");
167  this->dump_connect_params_();
168  if (this->power_pin_ != -1) {
169  ESP_LOGCONFIG(TAG, " Power Pin: %u", this->power_pin_);
170  }
171  ESP_LOGCONFIG(TAG, " MDC Pin: %u", this->mdc_pin_);
172  ESP_LOGCONFIG(TAG, " MDIO Pin: %u", this->mdio_pin_);
173  ESP_LOGCONFIG(TAG, " Type: %s", eth_type.c_str());
174 }
175 
177 
179 
181  esp_netif_ip_info_t ip;
182  esp_netif_get_ip_info(this->eth_netif_, &ip);
183  return {ip.ip.addr};
184 }
185 
186 void EthernetComponent::eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event, void *event_data) {
187  const char *event_name;
188 
189  switch (event) {
190  case ETHERNET_EVENT_START:
191  event_name = "ETH started";
192  global_eth_component->started_ = true;
193  break;
194  case ETHERNET_EVENT_STOP:
195  event_name = "ETH stopped";
196  global_eth_component->started_ = false;
197  global_eth_component->connected_ = false;
198  break;
199  case ETHERNET_EVENT_CONNECTED:
200  event_name = "ETH connected";
201  break;
202  case ETHERNET_EVENT_DISCONNECTED:
203  event_name = "ETH disconnected";
204  global_eth_component->connected_ = false;
205  break;
206  default:
207  return;
208  }
209 
210  ESP_LOGV(TAG, "[Ethernet event] %s (num=%d)", event_name, event);
211 }
212 
213 void EthernetComponent::got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id,
214  void *event_data) {
215  global_eth_component->connected_ = true;
216  ESP_LOGV(TAG, "[Ethernet event] ETH Got IP (num=%d)", event_id);
217 }
218 
220  this->connect_begin_ = millis();
221  this->status_set_warning();
222 
223  esp_err_t err;
224  err = esp_netif_set_hostname(this->eth_netif_, App.get_name().c_str());
225  if (err != ERR_OK) {
226  ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err));
227  }
228 
229  esp_netif_ip_info_t info;
230  if (this->manual_ip_.has_value()) {
231  info.ip.addr = static_cast<uint32_t>(this->manual_ip_->static_ip);
232  info.gw.addr = static_cast<uint32_t>(this->manual_ip_->gateway);
233  info.netmask.addr = static_cast<uint32_t>(this->manual_ip_->subnet);
234  } else {
235  info.ip.addr = 0;
236  info.gw.addr = 0;
237  info.netmask.addr = 0;
238  }
239 
240  esp_netif_dhcp_status_t status = ESP_NETIF_DHCP_INIT;
241 
242  err = esp_netif_dhcpc_get_status(this->eth_netif_, &status);
243  ESPHL_ERROR_CHECK(err, "DHCPC Get Status Failed!");
244 
245  ESP_LOGV(TAG, "DHCP Client Status: %d", status);
246 
247  err = esp_netif_dhcpc_stop(this->eth_netif_);
248  if (err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
249  ESPHL_ERROR_CHECK(err, "DHCPC stop error");
250  }
251 
252  err = esp_netif_set_ip_info(this->eth_netif_, &info);
253  ESPHL_ERROR_CHECK(err, "DHCPC set IP info error");
254 
255  if (this->manual_ip_.has_value()) {
256  if (uint32_t(this->manual_ip_->dns1) != 0) {
257  ip_addr_t d;
258  d.type = IPADDR_TYPE_V4;
259  d.u_addr.ip4.addr = static_cast<uint32_t>(this->manual_ip_->dns1);
260  dns_setserver(0, &d);
261  }
262  if (uint32_t(this->manual_ip_->dns1) != 0) {
263  ip_addr_t d;
264  d.type = IPADDR_TYPE_V4;
265  d.u_addr.ip4.addr = static_cast<uint32_t>(this->manual_ip_->dns2);
266  dns_setserver(1, &d);
267  }
268  } else {
269  err = esp_netif_dhcpc_start(this->eth_netif_);
270  if (err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) {
271  ESPHL_ERROR_CHECK(err, "DHCPC start error");
272  }
273  }
274 
275  this->connect_begin_ = millis();
276  this->status_set_warning();
277 }
278 
280 
282  esp_netif_ip_info_t ip;
283  esp_netif_get_ip_info(this->eth_netif_, &ip);
284  ESP_LOGCONFIG(TAG, " IP Address: %s", network::IPAddress(ip.ip.addr).str().c_str());
285  ESP_LOGCONFIG(TAG, " Hostname: '%s'", App.get_name().c_str());
286  ESP_LOGCONFIG(TAG, " Subnet: %s", network::IPAddress(ip.netmask.addr).str().c_str());
287  ESP_LOGCONFIG(TAG, " Gateway: %s", network::IPAddress(ip.gw.addr).str().c_str());
288 
289  const ip_addr_t *dns_ip1 = dns_getserver(0);
290  const ip_addr_t *dns_ip2 = dns_getserver(1);
291 
292  ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1->u_addr.ip4.addr).str().c_str());
293  ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->u_addr.ip4.addr).str().c_str());
294 
295  esp_err_t err;
296 
297  uint8_t mac[6];
298  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_MAC_ADDR, &mac);
299  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_MAC error");
300  ESP_LOGCONFIG(TAG, " MAC Address: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
301 
302  eth_duplex_t duplex_mode;
303  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_DUPLEX_MODE, &duplex_mode);
304  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_DUPLEX_MODE error");
305  ESP_LOGCONFIG(TAG, " Is Full Duplex: %s", YESNO(duplex_mode == ETH_DUPLEX_FULL));
306 
307  eth_speed_t speed;
308  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_SPEED, &speed);
309  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_SPEED error");
310  ESP_LOGCONFIG(TAG, " Link Speed: %u", speed == ETH_SPEED_100M ? 100 : 10);
311 }
312 
313 void EthernetComponent::set_phy_addr(uint8_t phy_addr) { this->phy_addr_ = phy_addr; }
314 void EthernetComponent::set_power_pin(int power_pin) { this->power_pin_ = power_pin; }
315 void EthernetComponent::set_mdc_pin(uint8_t mdc_pin) { this->mdc_pin_ = mdc_pin; }
316 void EthernetComponent::set_mdio_pin(uint8_t mdio_pin) { this->mdio_pin_ = mdio_pin; }
318 void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio) {
319  this->clk_mode_ = clk_mode;
320  this->clk_gpio_ = clk_gpio;
321 }
322 void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
323 
325  if (this->use_address_.empty()) {
326  return App.get_name() + ".local";
327  }
328  return this->use_address_;
329 }
330 
331 void EthernetComponent::set_use_address(const std::string &use_address) { this->use_address_ = use_address; }
332 
333 } // namespace ethernet
334 } // namespace esphome
335 
336 #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:26
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:27