Integrare LAN8720 con ESP32 per la connettività Ethernet con plain (HTTP) e SSL (HTTPS)


Nel mondo dell’IoT e dei sistemi embedded, l’ESP32 è emerso come un microcontrollore molto popolare grazie alla sua versatilità e alle capacità WiFi. Tuttavia, per progetti che richiedono connessioni di rete stabili e veloci, Ethernet è spesso la scelta preferita.

Integrazione di LAN8720 con ESP32 per connettività Ethernet con plain (HTTP) e SSL (HTTPS)

Qui entra in gioco l’Ethernet PHY LAN8720. In questa guida, esploreremo come integrare senza problemi il modulo LAN8720 con un ESP32, fornendo una connessione Ethernet robusta e affidabile per i vostri progetti IoT.

Qui la mia selezione di esp32 ESP32 Dev Kit v1 - TTGO T-Display 1.14 ESP32 - NodeMCU V3 V2 ESP8266 Lolin32 - NodeMCU ESP-32S - WeMos Lolin32 - WeMos Lolin32 mini - ESP32-CAM programmer - ESP32-CAM bundle - ESP32-WROOM-32 - ESP32-S

LAN8720 vs W5500

Il W5500 e il LAN8720 sono entrambi controllori Ethernet, ma svolgono ruoli diversi e hanno caratteristiche distinte:

  1. W5500:
    • Produttore: Wiznet
    • Tipo: Controller Ethernet con stack TCP/IP hardware completo.
    • Principali caratteristiche:
      • Stack protocollo TCP/IP integrato che può gestire protocolli TCP, UDP, IPv4, ICMP, ARP, IGMP e PPPoE.
      • Supporta fino a 8 connessioni socket simultanee.
      • SPI (Serial Peripheral Interface) per la comunicazione con i controllori host.
      • Memoria interna di 32Kbyte per i buffer TX/RX.
      • Adatto per applicazioni embedded grazie alla sua facilità di integrazione e al minimo carico sul processore host.
      • Utilizzato tipicamente con microcontrollori come Arduino, STM32, ecc.
  2. LAN8720:
    • Produttore: Microchip Technology (precedentemente SMSC)
    • Tipo: Trasmettitore di livello fisico (PHY).
    • Principali caratteristiche:
      • Opera al livello fisico del modello OSI.
      • Supporta gli standard Ethernet 10BASE-T e 100BASE-TX.
      • Utilizza RMII (Reduced Media Independent Interface) per la comunicazione con i controllori host.
      • Consumo energetico ridotto.
      • Generalmente utilizzato in applicazioni che richiedono un controller separato per il livello MAC (Media Access Control), spesso presente in sistemi più complessi come quelli con processori ARM.

Qui una selezione dei dispositivi ethernet più diffusi w5500 lite - w5500 - enc26j60 mini - enc26j60 - lan8720

Differenze chiave:

  • Funzionalità: Il W5500 è una soluzione più integrata con uno stack TCP/IP incorporato, rendendolo più semplice da gestire per le comunicazioni di rete in progetti basati su microcontrollori semplici. Il LAN8720, essendo un dispositivo di livello PHY, richiede un controller MAC separato ed è più adatto per applicazioni complesse.
  • Interfaccia: Il W5500 utilizza SPI, che è più semplice e comunemente trovato nei microcontrollori. Il LAN8720 utilizza RMII, che è più complesso ma offre prestazioni superiori per i sistemi che lo supportano.
  • Caso d’uso: Il W5500 è preferito in progetti basati su microcontrollori più semplici dove la facilità d’uso e di integrazione sono chiave. Il LAN8720 è migliore per sistemi più avanzati dove è disponibile un MAC separato e si richiede più controllo sullo stack di rete.

Cablaggio

Per impostazione predefinita, il dispositivo CHIP ha questo cablaggio.

Assegnazioni comuni dei pin dalla documentazione ufficiale

Utilizzo del MAC interno ESP32

  • Il cablaggio PHY RMII è fisso e non può essere cambiato tramite IOMUX o GPIO Matrix. Per impostazione predefinita, sono connessi come segue:
GPIOSegnale RMIINote
GPIO21TX_ENEMAC_TX_EN
GPIO19TX0EMAC_TXD0
GPIO22TX1EMAC_TXD1
GPIO25RX0EMAC_RXD0
GPIO26RX1EMAC_RXD1
GPIO27CRS_DVEMAC_RX_DRV
  • Uno dei seguenti pin GPIO può essere utilizzato come input/output di RMII REF_CLK:
GPIOFunzioneNote
GPIO0EMAC_TX_CLK/CLK_OUT1input/output
GPIO16EMAC_CLK_OUToutput
GPIO17EMAC_CLK_180output
  • Il cablaggio dell’interfaccia di gestione seriale (SMI) non è fisso. Potrebbe essere necessario modificarlo in base allo schema del vostro circuito. Per impostazione predefinita, sono connessi come segue:
GPIOSegnale SMINote
GPIO23MDCOutput verso PHY
GPIO18MDIOBidirezionale

Cablaggio del prototipo

Ecco il cablaggio con un ESP32 a 38 pin.

Sul nostro prototipo, iniziamo il cablaggio con questa configurazione (quella standard)

esp32lan8720
3V3Vcc
GNDGND
GPIO18MDIO
GPIO19TXD0
GPIO21TXEN
GPIO22TXD1
GPIO23MDC
GPIO25RXD0
GPIO26RXD1
GPIO27CRS_DV
GPIO0nINT/RETCLM

Ma con questa versione e la scheda lan8720 cinese si può incontrare un problema, casualmente si riceve un messaggio come questo.

mode:DIO, clock div:1
load:0x3fff0030,len:1184
load:0x40078000,len:13260
load:0x40080400,len:3028
entry 0x400805e4
ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
waiting for download 
ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
waiting for download 

A volte funziona e altre volte no, questo perché si collega GPIO0 all’oscillatore al quarzo, e quando l’oscillatore è ALTO, GPIO0 mette l’ESP32 in modalità di avvio, se si è fortunati e l’oscillatore è BASSO si avvia normalmente.

Per risolvere questo problema è necessario saldare un filo dal pin di abilitazione dell’oscillatore al pin NC (Non collegato), e cablare in questo modo.

esp32lan8720 modificato
3V3Vcc
GNDGND
GPIO18MDIO
GPIO19TXD0
GPIO21TXEN
GPIO22TXD1
GPIO23MDC
GPIO25RXD0
GPIO26RXD1
GPIO27CRS_DV
GPIO0nINT/RETCLM
GPIO17NC

Ecco la modifica sul mio dispositivo.

Test del dispositivo

Connessione standard senza patch

Prima, lo sketch più comune che si può trovare sul web senza utilizzare la patch. Ricorda che probabilmente devi resettare più di una volta per farlo funzionare senza entrare in modalità di download.

/*
 This sketch shows how to use lan8720 with esp32 with minimal/standard configuration

 You can set the parameter in begin function or at start with define before the import
 of ETH.h file, this way is preferible.

 by Renzo Mischianti <mischianti.org>
 */

// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_PHY_ADDR 1 						// DEFAULT VALUE IS 0 YOU CAN OMIT IT
// Type of the Ethernet PHY (LAN8720 or TLK110)
#define ETH_PHY_TYPE ETH_PHY_LAN8720 		// DEFAULT VALUE YOU CAN OMIT IT
// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_PHY_POWER -1 					// DEFAULT VALUE YOU CAN OMIT IT
// Pin# of the I²C clock signal for the Ethernet PHY
#define ETH_PHY_MDC 23 						// DEFAULT VALUE YOU CAN OMIT IT
// Pin# of the I²C IO signal for the Ethernet PHY
#define ETH_PHY_MDIO 18 					// DEFAULT VALUE YOU CAN OMIT IT
// External clock from crystal oscillator
#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN 	// DEFAULT VALUE YOU CAN OMIT IT

#include <ETH.h>

static bool eth_connected = false;

void WiFiEvent(WiFiEvent_t event) {
	switch (event) {
	case ARDUINO_EVENT_ETH_START:
		Serial.println("ETH Started");
		ETH.setHostname("esp32-mischianti-eth");
		break;
	case ARDUINO_EVENT_ETH_CONNECTED:
		Serial.println("ETH Connected");
		break;
	case ARDUINO_EVENT_ETH_GOT_IP:
		Serial.print("ETH MAC: ");
		Serial.print(ETH.macAddress());
		Serial.print(", IPv4: ");
		Serial.print(ETH.localIP());
		if (ETH.fullDuplex()) {
			Serial.print(", FULL_DUPLEX");
		}
		Serial.print(", ");
		Serial.print(ETH.linkSpeed());
		Serial.println("Mbps");
		eth_connected = true;
		break;
	case ARDUINO_EVENT_ETH_DISCONNECTED:
		Serial.println("ETH Disconnected");
		eth_connected = false;
		break;
	case ARDUINO_EVENT_ETH_STOP:
		Serial.println("ETH Stopped");
		eth_connected = false;
		break;
	default:
		break;
	}
}

void testClient(const char *host, uint16_t port) {
	Serial.print("\nconnecting to ");
	Serial.println(host);

	WiFiClient client;
	if (!client.connect(host, port)) {
		Serial.println("connection failed");
		return;
	}
	client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
	while (client.connected() && !client.available())
		;
	while (client.available()) {
		Serial.write(client.read());
	}

	Serial.println("closing connection\n");
	client.stop();
}

void setup() {
	Serial.begin(115200);
	WiFi.onEvent(WiFiEvent);
	ETH.begin();
}

void loop() {
	if (eth_connected) {
		testClient("mischianti.org", 80);
	}
	delay(10000);

}

Puoi passare lo stesso parametro anche nella funzione begin in questo modo (aggiungo solo come esempio in questo caso).

/*
 This sketch shows how to use lan8720 with esp32 with minimal/standard configuration

 Parameter in begin function

 by Renzo Mischianti <mischianti.org>
 */

#include <ETH.h>

#define ETH_PARAM_PHY_ADDR 1
#define ETH_PARAM_PHY_TYPE ETH_PHY_LAN8720
#define ETH_PARAM_PHY_POWER -1
#define ETH_PARAM_PHY_MDC 23
#define ETH_PARAM_PHY_MDIO 18
#define ETH_PARAM_CLK_MODE ETH_CLOCK_GPIO0_IN


static bool eth_connected = false;

void WiFiEvent(WiFiEvent_t event) {
	switch (event) {
	case ARDUINO_EVENT_ETH_START:
		Serial.println("ETH Started");
		ETH.setHostname("esp32-mischianti-eth");
		break;
	case ARDUINO_EVENT_ETH_CONNECTED:
		Serial.println("ETH Connected");
		break;
	case ARDUINO_EVENT_ETH_GOT_IP:
		Serial.print("ETH MAC: ");
		Serial.print(ETH.macAddress());
		Serial.print(", IPv4: ");
		Serial.print(ETH.localIP());
		if (ETH.fullDuplex()) {
			Serial.print(", FULL_DUPLEX");
		}
		Serial.print(", ");
		Serial.print(ETH.linkSpeed());
		Serial.println("Mbps");
		eth_connected = true;
		break;
	case ARDUINO_EVENT_ETH_DISCONNECTED:
		Serial.println("ETH Disconnected");
		eth_connected = false;
		break;
	case ARDUINO_EVENT_ETH_STOP:
		Serial.println("ETH Stopped");
		eth_connected = false;
		break;
	default:
		break;
	}
}

void testClient(const char *host, uint16_t port) {
	Serial.print("\nconnecting to ");
	Serial.println(host);

	WiFiClient client;
	if (!client.connect(host, port)) {
		Serial.println("connection failed");
		return;
	}
	client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
	while (client.connected() && !client.available())
		;
	while (client.available()) {
		Serial.write(client.read());
	}

	Serial.println("closing connection\n");
	client.stop();
}

void setup() {
	Serial.begin(115200);
	WiFi.onEvent(WiFiEvent);
	ETH.begin(ETH_PARAM_PHY_ADDR, ETH_PARAM_PHY_POWER, ETH_PARAM_PHY_MDC, ETH_PARAM_PHY_MDIO, ETH_PARAM_PHY_TYPE, ETH_PARAM_CLK_MODE);
}

void loop() {
	if (eth_connected) {
		testClient("mischianti.org", 80);
	}
	delay(10000);

}

L’output del codice è qui.

ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1184
load:0x40078000,len:13260
load:0x40080400,len:3028
entry 0x400805e4
ETH Started
ETH Connected
ETH MAC: B8:D6:1A:68:E5:7F, IPv4: 192.168.1.115, FULL_DUPLEX, 100Mbps

connecting to mischianti.org
HTTP/1.1 301 Moved Permanently
Connection: Keep-Alive
Keep-Alive: timeout=5, max=100
content-type: text/html
content-length: 3145
date: Fri, 02 Feb 2024 10:55:05 GMT
server: LiteSpeed
x-qc-pop: EU-FR-NTE-51
location: https://mischianti.org/

<!DOCTYPE html><html lang="en-US"><head>
<title> 301 Moved Permanently
</title>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
*{box-sizing:border-box}.site-logo{max-width:100%;background-repeat:none;display:inline-block;height:45px;width:75px;margin:5px}body{font-family:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Helvetica,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";margin:0;line-height:1.3;font-size:.95em}.text-center,h2{text-align:center;margin-top:1.5em;margin-bottom:.5em}h2{font-size:7em;color:#555;margin-top:0}h4{font-size:1.25em;font-weight:400;color:#6d6c64;margin-top:0}a{color:#36f;font-weight:600;word-break:break-word}.text-center{margin-bottom:3em}
</style>
</head>
<body style="background-color:#f7f9fb; display: flex; min-height: 100vh;flex-direction: column;">
<div style="display:flex;background-color:#004262;padding:8px"><a href="https://quic.cloud/" title="QUIC.cloud" rel="home"><div class="site-logo"><svg height="50" viewBox="0 0 75 50" width="75" xmlns="http://www.w3.org/2000/svg"><path d="m71.301 15.049c-2.885-3.792-7.072-6.232-11.791-6.872-3.709-.503-7.415.154-10.721 1.901-.44.232-.873.484-1.289.75l-1.486 1.117 3.835 5.041 1.169-.889c.236-.147.481-.288.73-.421 2.13-1.124 4.518-1.547 6.908-1.224 3.045.413 5.744 1.987 7.604 4.432 1.861 2.445 2.657 5.467 2.244 8.511-.853 6.283-6.663 10.7-12.942 9.849-2.389-.324-4.579-1.37-6.332-3.022-.209-.198-.407-.399-.59-.599l-14.45-18.99-.005.059-1.522-2-.165-.199c-.346-.385-.712-.76-1.086-1.111-2.838-2.677-6.382-4.369-10.249-4.895-10.162-1.38-19.56 5.769-20.939 15.935-1.38 10.164 5.768 19.558 15.934 20.937 3.868.525 7.733-.16 11.186-1.983.14-.074.275-.153.413-.229l-3.895-5.119c-2.14 1.006-4.493 1.377-6.852 1.057-6.706-.912-11.419-7.106-10.51-13.812.91-6.705 7.099-11.418 13.811-10.509 2.549.346 4.885 1.461 6.758 3.228.219.206.432.422.637.644l11.357 14.928.006-.061 4.612 6.062.158.193c.324.361.676.723 1.046 1.072 2.72 2.564 6.117 4.187 9.825 4.689.811.111 1.614.164 2.412.164 8.775-.002 16.444-6.504 17.658-15.438.642-4.718-.594-9.405-3.479-13.196z" fill="#97a3aa"/><path d="m40.375 40.139c-.059-.061-.123-.121-.179-.182l-7.318-9.609c-.318-.356-.665-.711-1.03-1.056-2.72-2.565-6.117-4.186-9.825-4.69-.354-.047-.707-.082-1.061-.108h-.542l2.7 3.533c.058.06.123.121.178.181l7.317 9.61c.319.355.665.711 1.03 1.055 2.72 2.564 6.117 4.188 9.825 4.689.354.049.707.082 1.061.109h.542z" fill="#9ff"/></svg></div></a><div style="margin-top:20px;margin-left:5px"><a href="https://quic.cloud/" title="QUIC.cloud" rel="home" style="color:#fff;font-size:1.25em;text-decoration:none">QUIC<span style="color:#f60">.</span><span style="color:#e4e4f1">cloud</span></a></a></div></div><div style="max-width:1140px;margin:auto;padding:0 1.6em 1.6em; display:flex; align-items: center;flex: 1;"><div style="color:#555"><div class="text-center"><h2>301</h2>
<h4>Moved Permanently
</h4>
<h4>The document has been permanently moved.</h4>
<p>This page is generated by <a href="https://quic.cloud/">QUIC.cloud</a> CDN on the EU-FR-NTE-51 server.</p>
</div></div></div></body></html>
closing connection

Connessione del dispositivo con la patch

Se applichi la patch, devi gestire lo stato di abilitazione dell’oscillatore al quarzo, devi impostare il GPIO17 come pin di alimentazione; questo trucco ti permette di avviare il dispositivo e, dopo l’operazione di boot del MCU, abilitare l’oscillatore al quarzo.

Probabilmente con una scheda di alta qualità, non ne hai bisogno.

/*
 This sketch shows how to use patched lan8720 with esp32

 Remeber you must connect the enable pin of Crystal Oscillator to the NC pin of the board

 by Renzo Mischianti <mischianti.org>
 */

// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_PHY_ADDR 1 						// DEFAULT VALUE IS 0 YOU CAN OMIT IT
// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_PHY_POWER 17 					// DEFAULT VALUE YOU CAN OMIT IT

#include <ETH.h>

static bool eth_connected = false;

void WiFiEvent(WiFiEvent_t event) {
	switch (event) {
	case ARDUINO_EVENT_ETH_START:
		Serial.println("ETH Started");
		ETH.setHostname("esp32-mischianti-eth");
		break;
	case ARDUINO_EVENT_ETH_CONNECTED:
		Serial.println("ETH Connected");
		break;
	case ARDUINO_EVENT_ETH_GOT_IP:
		Serial.print("ETH MAC: ");
		Serial.print(ETH.macAddress());
		Serial.print(", IPv4: ");
		Serial.print(ETH.localIP());
		if (ETH.fullDuplex()) {
			Serial.print(", FULL_DUPLEX");
		}
		Serial.print(", ");
		Serial.print(ETH.linkSpeed());
		Serial.println("Mbps");
		eth_connected = true;
		break;
	case ARDUINO_EVENT_ETH_DISCONNECTED:
		Serial.println("ETH Disconnected");
		eth_connected = false;
		break;
	case ARDUINO_EVENT_ETH_STOP:
		Serial.println("ETH Stopped");
		eth_connected = false;
		break;
	default:
		break;
	}
}

void testClient(const char *host, uint16_t port) {
	Serial.print("\nconnecting to ");
	Serial.println(host);

	WiFiClient client;
	if (!client.connect(host, port)) {
		Serial.println("connection failed");
		return;
	}
	client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
	while (client.connected() && !client.available())
		;
	while (client.available()) {
		Serial.write(client.read());
	}

	Serial.println("closing connection\n");
	client.stop();
}

void setup() {
	Serial.begin(115200);
	WiFi.onEvent(WiFiEvent);
	ETH.begin();
}

void loop() {
	if (eth_connected) {
		testClient("mischianti.org", 80);
	}
	delay(10000);

}

Effettuare una richiesta GET semplice

Prima di tutto, cercheremo di effettuare una semplice richiesta HTTP. Ho scelto un servizio online creato per testare questo tipo di richiesta per fare questo test.

Utilizzerò un servizio semplice fornito da httpbin.org, e puoi usare la stessa API REST in HTTP e HTTPS.

Ricorda che HTTP funziona sulla porta 80 e HTTPS sulla 443, quindi devi validare un certificato per interrogare l’endpoint sulla porta 443.

Ecco la semplice richiesta get

/*
 This sketch shows how to use patched lan8720 with esp32

 We are going to do a raw GET request to online service httpbin.org
 http://httpbin.org/get

 by Renzo Mischianti <mischianti.org>
 */


// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_PHY_ADDR 1 						// DEFAULT VALUE IS 0 YOU CAN OMIT IT
// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_PHY_POWER 17 					// DEFAULT VALUE YOU CAN OMIT IT

#include <ETH.h>

// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
//char server[] = "www.google.com";    // name address for Google (using DNS)
char server[] = "httpbin.org";    // name address for Google (using DNS)

// Initialize the Ethernet client library
WiFiClient client;

// Variables to measure the speed
unsigned long beginMicros, endMicros;
unsigned long byteCount = 0;
bool printWebData = true;  // set to false for better speed measurement

static bool eth_connected = false;

void WiFiEvent(WiFiEvent_t event) {
	switch (event) {
	case ARDUINO_EVENT_ETH_START:
		Serial.println("ETH Started");
		ETH.setHostname("esp32-mischianti-eth");
		break;
	case ARDUINO_EVENT_ETH_CONNECTED:
		Serial.println("ETH Connected");
		break;
	case ARDUINO_EVENT_ETH_GOT_IP:
		Serial.println();
		Serial.print("ETH MAC: ");
		Serial.print(ETH.macAddress());
		Serial.print(", IPv4: ");
		Serial.print(ETH.localIP());
		if (ETH.fullDuplex()) {
			Serial.print(", FULL_DUPLEX");
		}
		Serial.print(", ");
		Serial.print(ETH.linkSpeed());
		Serial.println("Mbps");
		eth_connected = true;
		break;
	case ARDUINO_EVENT_ETH_DISCONNECTED:
		Serial.println("ETH Disconnected");
		eth_connected = false;
		break;
	case ARDUINO_EVENT_ETH_STOP:
		Serial.println("ETH Stopped");
		eth_connected = false;
		break;
	default:
		break;
	}
}

void setup() {
	Serial.begin(115200);
	WiFi.onEvent(WiFiEvent);
	ETH.begin();

	while (!eth_connected) {
		Serial.print(".");
		delay(100);
	}

	// if you get a connection, report back via serial:
	if (client.connect(server, 80)) {
		Serial.println("Connected!");
		// Make a HTTP request:
		client.println("GET /get HTTP/1.1");
		client.println("Host: httpbin.org");
		client.println("Connection: close");
		client.println();
	} else {
		// if you didn't get a connection to the server:
		Serial.println("connection failed");
	}
	beginMicros = micros();

}

void loop() {
	  // if there are incoming bytes available
	  // from the server, read them and print them:
	  int len = client.available();
	  if (len > 0) {
	    byte buffer[80];
	    if (len > 80) len = 80;
	    client.read(buffer, len);
	    if (printWebData) {
	      Serial.write(buffer, len); // show in the serial monitor (slows some boards)
	    }
	    byteCount = byteCount + len;
	  }

	  // if the server's disconnected, stop the client:
	  if (len == 0 && !client.connected()) {
	    endMicros = micros();
	    Serial.println();
	    Serial.println("disconnecting.");
	    client.stop();
	    Serial.print("Received ");
	    Serial.print(byteCount);
	    Serial.print(" bytes in ");
	    float seconds = (float)(endMicros - beginMicros) / 1000000.0;
	    Serial.print(seconds, 4);
	    float rate = (float)byteCount / seconds / 1000.0;
	    Serial.print(", rate = ");
	    Serial.print(rate);
	    Serial.print(" kbytes/second");
	    Serial.println();

	    // do nothing forevermore:
	    while (true) {
	      delay(1);
	    }
	  }
}

E questo è il risultato.

ETH Started
ETH Connected
...........
ETH MAC: B8:D6:1A:68:E5:7F, IPv4: 192.168.1.115, FULL_DUPLEX, 100Mbps
Connected!
HTTP/1.1 200 OK
Date: Fri, 02 Feb 2024 15:44:00 GMT
Content-Type: application/json
Content-Length: 199
Connection: close
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
 
{
  "args": {}, 
  "headers": {
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-65bd0dc0-4ea2c7a33ad187b40ac5cda8"
  }, 
  "origin": "84.221.199.122", 
  "url": "http://httpbin.org/get"
}

disconnecting.
Received 424 bytes in 0.2767, rate = 1.53 kbytes/second

Ora, una richiesta HTTPS.

Se cambiamo solo la porta da

	if (client.connect(server, 80)) {

to

	if (client.connect(server, 443)) {

riceviamo un errore esplicito come questo.

ETH Started
ETH Connected
.
ETH MAC: B8:D6:1A:68:E5:7F, IPv4: 192.168.1.115, FULL_DUPLEX, 100Mbps
Connected!
HTTP/1.1 400 Bad Request
Server: awselb/2.0
Date: Fri, 02 Feb 2024 16:25:02 GMT
Content-Type: text/html
Content-Length: 220 
Connection: close

<html>
<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>The plain HTTP request was sent to HTTPS port</center>
</body>
</html>

disconnecting.
Received 370 bytes in 0.2764, rate = 1.34 kbytes/second

Prima di tutto, dobbiamo usare il WiFiClientSecure che implementa lo strato SSL. Ma se sostituisci la linea

// Initialize the Ethernet client library
WiFiClient client;

con

// Initialize the Ethernet client library
WiFiClientSecure client;

otteniamo

ETH Started
ETH Connected
.
ETH MAC: B8:D6:1A:68:E5:7F, IPv4: 192.168.1.115, FULL_DUPLEX, 100Mbps
connection failed

disconnecting.
Received 0 bytes in 0.0000, rate = 0.00 kbytes/second

Questo perché lo strato SSL necessita di validare il server remoto tramite l’Autorità di Certificazione, ma se sei una brutta persona, puoi chiedere alla libreria di evitare il controllo del certificato con questo comando.

	client.setInsecure();

Lo sketch completo diventa.

/*
 This sketch shows how to use patched lan8720 with esp32

 We are going to do a raw GET request to online service httpbin.org
 http://httpbin.org/get

 by Renzo Mischianti <mischianti.org>
 */


// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_PHY_ADDR 1 						// DEFAULT VALUE IS 0 YOU CAN OMIT IT
// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_PHY_POWER 17 					// DEFAULT VALUE YOU CAN OMIT IT

#include <ETH.h>
#include <WiFiClientSecure.h>

// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
//char server[] = "www.google.com";    // name address for Google (using DNS)
char server[] = "httpbin.org";    // name address for Google (using DNS)

// Initialize the Ethernet client library
WiFiClientSecure client;

// Variables to measure the speed
unsigned long beginMicros, endMicros;
unsigned long byteCount = 0;
bool printWebData = true;  // set to false for better speed measurement

static bool eth_connected = false;

void WiFiEvent(WiFiEvent_t event) {
	switch (event) {
	case ARDUINO_EVENT_ETH_START:
		Serial.println("ETH Started");
		ETH.setHostname("esp32-mischianti-eth");
		break;
	case ARDUINO_EVENT_ETH_CONNECTED:
		Serial.println("ETH Connected");
		break;
	case ARDUINO_EVENT_ETH_GOT_IP:
		Serial.println();
		Serial.print("ETH MAC: ");
		Serial.print(ETH.macAddress());
		Serial.print(", IPv4: ");
		Serial.print(ETH.localIP());
		if (ETH.fullDuplex()) {
			Serial.print(", FULL_DUPLEX");
		}
		Serial.print(", ");
		Serial.print(ETH.linkSpeed());
		Serial.println("Mbps");
		eth_connected = true;
		break;
	case ARDUINO_EVENT_ETH_DISCONNECTED:
		Serial.println("ETH Disconnected");
		eth_connected = false;
		break;
	case ARDUINO_EVENT_ETH_STOP:
		Serial.println("ETH Stopped");
		eth_connected = false;
		break;
	default:
		break;
	}
}

void setup() {
	Serial.begin(115200);
	WiFi.onEvent(WiFiEvent);
	ETH.begin();

	while (!eth_connected) {
		Serial.print(".");
		delay(100);
	}

	client.setInsecure();

	// if you get a connection, report back via serial:
	if (client.connect(server, 443)) {
		Serial.println("Connected!");
		// Make a HTTP request:
		client.println("GET /get HTTP/1.1");
		client.println("Host: httpbin.org");
		client.println("Connection: close");
		client.println();
	} else {
		// if you didn't get a connection to the server:
		Serial.println("connection failed");
	}
	beginMicros = micros();

}

void loop() {
	  // if there are incoming bytes available
	  // from the server, read them and print them:
	  int len = client.available();
	  if (len > 0) {
	    byte buffer[80];
	    if (len > 80) len = 80;
	    client.read(buffer, len);
	    if (printWebData) {
	      Serial.write(buffer, len); // show in the serial monitor (slows some boards)
	    }
	    byteCount = byteCount + len;
	  }

	  // if the server's disconnected, stop the client:
	  if (len == 0 && !client.connected()) {
	    endMicros = micros();
	    Serial.println();
	    Serial.println("disconnecting.");
	    client.stop();
	    Serial.print("Received ");
	    Serial.print(byteCount);
	    Serial.print(" bytes in ");
	    float seconds = (float)(endMicros - beginMicros) / 1000000.0;
	    Serial.print(seconds, 4);
	    float rate = (float)byteCount / seconds / 1000.0;
	    Serial.print(", rate = ");
	    Serial.print(rate);
	    Serial.print(" kbytes/second");
	    Serial.println();

	    // do nothing forevermore:
	    while (true) {
	      delay(1);
	    }
	  }

}

E ora il risultato è questo.

ETH Started
ETH Connected
..........
ETH MAC: B8:D6:1A:68:E5:7F, IPv4: 192.168.1.115, FULL_DUPLEX, 100Mbps
Connected!
HTTP/1.1 200 OK
Date: Fri, 02 Feb 2024 16:36:00 GMT
Content-Type: application/json
Content-Length: 200
Connection: close
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
 
{
  "args": {}, 
  "headers": {
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-65bd19f0-36775c160826895f26d52da8"
  }, 
  "origin": "84.221.199.122", 
  "url": "https://httpbin.org/get"
}

disconnecting.
Received 425 bytes in 0.1594, rate = 2.67 kbytes/second

Ok, ora proviamo ad essere dalla parte dei buoni; stiamo per scaricare il certificato dell’Autorità di Certificazione per validare l’host.

Quindi, nella pagina di httpbin, clicca sulla configurazione del sito.

Poi devi selezionare le informazioni sulla connessione.

Ora clicca su certificato.

E infine seleziona la linea in cima alla lista (il certificato radice).

Esporta il certificato e apri il file, copia il contenuto e inseriscilo in una variabile array di char.

const char* rootCA= R""""(-----BEGIN CERTIFICATE-----
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
rqXRfboQnoZsG4q5WTP468SQvvG5
-----END CERTIFICATE-----)"""";

Ora possiamo impostare il certificato dell’Autorità di Certificazione, necessario per validare il server httpbin sul WiFiClientSecure per poter effettuare il controllo.

Il codice diventa quindi.

/*
 This sketch shows how to use patched lan8720 with esp32

 We are going to do a raw GET request to online service httpbin.org
 http://httpbin.org/get

 by Renzo Mischianti <mischianti.org>
 */


// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_PHY_ADDR 1 						// DEFAULT VALUE IS 0 YOU CAN OMIT IT
// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_PHY_POWER 17 					// DEFAULT VALUE YOU CAN OMIT IT

#include <ETH.h>
#include <WiFiClientSecure.h>

// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
//char server[] = "www.google.com";    // name address for Google (using DNS)
char server[] = "httpbin.org";    // name address for Google (using DNS)

const char* rootCA= R""""(-----BEGIN CERTIFICATE-----
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
rqXRfboQnoZsG4q5WTP468SQvvG5
-----END CERTIFICATE-----)"""";

// Initialize the Ethernet client library
WiFiClientSecure client;

// Variables to measure the speed
unsigned long beginMicros, endMicros;
unsigned long byteCount = 0;
bool printWebData = true;  // set to false for better speed measurement

static bool eth_connected = false;

void WiFiEvent(WiFiEvent_t event) {
	switch (event) {
	case ARDUINO_EVENT_ETH_START:
		Serial.println("ETH Started");
		ETH.setHostname("esp32-mischianti-eth");
		break;
	case ARDUINO_EVENT_ETH_CONNECTED:
		Serial.println("ETH Connected");
		break;
	case ARDUINO_EVENT_ETH_GOT_IP:
		Serial.println();
		Serial.print("ETH MAC: ");
		Serial.print(ETH.macAddress());
		Serial.print(", IPv4: ");
		Serial.print(ETH.localIP());
		if (ETH.fullDuplex()) {
			Serial.print(", FULL_DUPLEX");
		}
		Serial.print(", ");
		Serial.print(ETH.linkSpeed());
		Serial.println("Mbps");
		eth_connected = true;
		break;
	case ARDUINO_EVENT_ETH_DISCONNECTED:
		Serial.println("ETH Disconnected");
		eth_connected = false;
		break;
	case ARDUINO_EVENT_ETH_STOP:
		Serial.println("ETH Stopped");
		eth_connected = false;
		break;
	default:
		break;
	}
}

void setup() {
	Serial.begin(115200);
	WiFi.onEvent(WiFiEvent);
	ETH.begin();

	while (!eth_connected) {
		Serial.print(".");
		delay(100);
	}

	client.setCACert(rootCA);

	// if you get a connection, report back via serial:
	if (client.connect(server, 443)) {
		Serial.println("Connected!");
		// Make a HTTP request:
		client.println("GET /get HTTP/1.1");
		client.println("Host: httpbin.org");
		client.println("Connection: close");
		client.println();
	} else {
		// if you didn't get a connection to the server:
		Serial.println("connection failed");
	}
	beginMicros = micros();

}

void loop() {
	  // if there are incoming bytes available
	  // from the server, read them and print them:
	  int len = client.available();
	  if (len > 0) {
	    byte buffer[80];
	    if (len > 80) len = 80;
	    client.read(buffer, len);
	    if (printWebData) {
	      Serial.write(buffer, len); // show in the serial monitor (slows some boards)
	    }
	    byteCount = byteCount + len;
	  }

	  // if the server's disconnected, stop the client:
	  if (len == 0 && !client.connected()) {
	    endMicros = micros();
	    Serial.println();
	    Serial.println("disconnecting.");
	    client.stop();
	    Serial.print("Received ");
	    Serial.print(byteCount);
	    Serial.print(" bytes in ");
	    float seconds = (float)(endMicros - beginMicros) / 1000000.0;
	    Serial.print(seconds, 4);
	    float rate = (float)byteCount / seconds / 1000.0;
	    Serial.print(", rate = ");
	    Serial.print(rate);
	    Serial.print(" kbytes/second");
	    Serial.println();

	    // do nothing forevermore:
	    while (true) {
	      delay(1);
	    }
	  }
}

Il risultato è lo stesso, ma il mondo ha bisogno di tante persone per bene.

Grazie

  1. ESP32: piedinatura, specifiche e configurazione dell’Arduino IDE
  2. ESP32: fileSystem integrato SPIFFS
  3. ESP32: gestire più seriali e logging per il debug
  4. ESP32 risparmio energetico pratico
    1. ESP32 risparmio energetico pratico: gestire WiFi e CPU
    2. ESP32 risparmio energetico pratico: modem e light sleep
    3. ESP32 risparmio energetico pratico: deep sleep e ibernazione
    4. ESP32 risparmio energetico pratico: preservare dati al riavvio, sveglia a tempo e tramite tocco
    5. ESP32 risparmio energetico pratico: sveglia esterna e da ULP
    6. ESP32 risparmio energetico pratico: sveglia da UART e GPIO
  5. ESP32: filesystem integrato LittleFS
  6. ESP32: filesystem integrato FFat (Fat/exFAT)
  7. ESP32-wroom-32
    1. ESP32-wroom-32: flash, piedinatura, specifiche e configurazione dell’Arduino IDE
  8. ESP32-CAM
    1. ESP32-CAM: piedinatura, specifiche e configurazione dell’Arduino IDE
    2. ESP32-CAM: upgrade CamerWebServer con gestione della luce flash
  9. ESP32: ethernet w5500 con chiamate standard (HTTP) e SSL (HTTPS)
  10. ESP32: ethernet enc28j60 con chiamate standard (HTTP) e SSL (HTTPS)
  11. Come usare la scheda SD con l’esp32
  12. esp32 e esp8266: file system FAT su memoria SPI flash esterna
  13. Gestione aggiornamenti firmware e OTA
    1. Gestione del firmware
      1. ESP32: flash del firmware binario compilato (.bin)
      2. ESP32: flash del firmware e filesystem (.bin) con strumenti grafici
    2. Aggiornamento OTA con Arduino IDE
      1. Aggiornamenti OTA su ESP32 con Arduino IDE: filesystem, firmware e password
    3. Aggiornamento OTA con browser web
      1. Aggiornamenti OTA su ESP32 tramite browser web: firmware, filesystem e autenticazione
      2. Aggiornamenti OTA su ESP32 tramite browser web: caricamento in HTTPS (SSL/TLS) con certificato autofirmato
      3. Aggiornamenti OTA su ESP32 tramite browser web: interfaccia web personalizzata
    4. Aggiornamenti automatici OTA da un server HTTP
      1. Aggiornamento automatico Firmware OTA dell’ESP32 dal server
      2. Aggiornamento automatico Firmware OTA dell’ESP32 dal server con controllo della versione
      3. Aggiornamento automatico Firmware OTA dell’ESP32 in HTTPS (SSL/TLS) con certificato autofirmato affidabile
    5. Aggiornamento del firmware non standard
      1. Aggiornamento firmware e filesystem ESP32 dalla scheda SD
      2. Aggiornamento firmware e filesystem ESP32 con client FTP
  14. Integrare LAN8720 con ESP32 per la connettività Ethernet con plain (HTTP) e SSL (HTTPS)
  15. Collegare l’EByte E70 (CC1310) ai dispositivi ESP32 c3/s3 ed un semplice sketch di esempio
  16. i2c esp32: gestione rete a 5v, 3.3v e interfaccia aggiuntiva
  17. […]

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *