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