ESP32: ethernet w5500 con chiamate standard (HTTP) e SSL (HTTPS)

Spread the love

Innanzitutto, va detto che l’ESP32 ha già un MAC, uno stack TCP/IP e una libreria di rete Arduino, ma andremo comunque ad usare con una libreria Ethernet con dispositivi W5500 visto che sono i più diffusi in assoluto e funzionano molto bene.

ESP32 use ethernet w5500 with plain HTTP and SSL HTTPS
ESP32 use ethernet w5500 with plain HTTP and SSL HTTPS

Molte persone mi chiedono alcuni esempi di connessioni cablate; nella mia mente la prima cosa a cui ho pensato è il dispositivo w5500, uno dei più famosi e potenti. Inizieremo a imparare come gestire le richieste semplici e SSL.

Dispositivi

Il chip W5500 è un controller Ethernet integrato TCP/IP cablato che fornisce una connessione Internet più semplice ai sistemi embedded. W5500 consente agli utenti di avere connettività Internet nelle loro applicazioni semplicemente utilizzando il singolo chip in cui sono incorporati stack TCP/IP, MAC Ethernet 10/100 e PHY.

L’Hardwired TCP/IP di WIZnet è la tecnologia collaudata sul mercato che supporta i protocolli TCP, UDP, IPv4, ICMP, ARP, IGMP e PPPoE. W5500 incorpora il buffer di memoria interna da 32 Kbyte per l’elaborazione dei pacchetti Ethernet. Se utilizzi il W5500, puoi implementare un’applicazione Ethernet aggiungendo il semplice programma di gestione socket. È un modo più rapido e semplice rispetto a qualsiasi altra soluzione Ethernet integrata. Gli utenti possono utilizzare otto socket hardware indipendenti contemporaneamente.

SPI (Serial Peripheral Interface) è fornita per una facile integrazione con l’MCU esterno. Lo SPI del W5500 supporta una velocità di 80 MHz. Per ridurre il consumo energetico del sistema, il W5500 fornisce WOL (Wake on LAN) e una modalità di spegnimento.

Caratteristiche

  • Supporta protocolli TCP/IP cablati: TCP, UDP, ICMP, IPv4, ARP, IGMP, PPPoE
  • Supporta 8 socket indipendenti contemporaneamente
  • Supporta la modalità di spegnimento
  • Supporta Wake on LAN su UDP
  • Supporta l’interfaccia periferica seriale ad alta velocità (MODALITÀ SPI 0, 3)
  • Memoria interna da 32 Kbyte per buffer TX/RX
  • PHY Ethernet 10BaseT/100BaseTX integrato
  • Supporta la negoziazione automatica (Full e half duplex, 10 e 100-based)
  • Non supporta la frammentazione IP
  • Funzionamento a 3,3 V con tolleranza del segnale I/O a 5 V
  • Uscite LED (Full/Halfduplex, Link, Speed, Active)
  • Pacchetto senza piombo LQFP a 48 pin (7×7 mm, passo 0,5 mm)

Esiste un’ampia serie di dispositivi w5500, ma i più diffusi sono 2 in particolare.

Il meno costoso è il w5500 che vedete in foto.

w5500 ethernet network modules spi
w5500 ethernet network modules SPI

Ma ora c’è una versione compatta denominata w5500 lite, molto interessante come dispositivo per la produzione.

w5500 lite ethernet network modules spi
w5500 lite ethernet network modules SPI

Qui la mia selezione di dispositivi Ethernet w5500 lite - w5500 - enc26j60 mini - enc26j60 - lan8720

Collegamenti

ESP32 DOIT DEV KIT v1 pinout
ESP32 DOIT DEV KIT v1 pinout

Qui la mia selezione di dispositivi 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

Questo dispositivo utilizza un’interfaccia SPI; per impostazione predefinita, utilizzerò un’interfaccia SPI di base.

ESP32 DOIT DevKit v1 w5500 wiring breadboard
ESP32 DOIT DevKit v1 w5500 wiring breadboard
ESP32w5500
D5CS
D18SCK
D19MISO
D23MOSI
3.3v (meglio con 200mha esterni)VCC
GNDGND

Stessa connessione per w5500 lite, ma la versione appena descritta del w5500 può funzionare con i 3.3v dell’ESP32 (non sempre vero); questo dispositivo invece è improbabile che funzioni senza alimentazione esterna.

ESP32 DOIT DevKit v1 w5500 lite wiring breadboard
ESP32 DOIT DevKit v1 w5500 lite wiring breadboard

Attenzione non tutti i dispositivi hanno così tanti ampere per alimentare il dispositivo w5500, quindi se hai problemi devi aggiungere un alimentatore esterno.

In caso di problemi, provare ad alimentare il dispositivo Ethernet con un alimentatore esterno.

ESP32 DOIT DevKit v1 w5500 wiring external power supply
ESP32 DOIT DevKit v1 w5500 wiring external power supply

Librerie

Esiste un’ampia selezione di librerie, ma quella standard è la scelta migliore. Puoi trovarlo nel gestore della libreria Arduino standard.

Arduino esp32 ethernet w5500 library manager
Arduino esp32 ethernet w5500 library manager

SSLClient

Questa libreria e questo dispositivo non supportano SSL, quindi aggiungendo queste funzionalità esiste una libreria alternativa denominata SSLClient che necessita di una piccola patch di Ethernet.

SSLClient aggiunge  la funzionalità TLS 1.2  a qualsiasi libreria di rete che implementa l’interfaccia Arduino Client, comprese le classi Arduino EthernetClient e WiFiClient. SSLClient è stato creato per integrare TLS perfettamente con l’infrastruttura Arduino utilizzando il BearSSL come motore TLS sottostante. A differenza di ArduinoBearSSL, SSLClient è completamente autonomo e non richiede alcun hardware aggiuntivo (a parte una connessione di rete). (cit.)

Arduino esp32 ethernet w5500 SSLClient library manager
Arduino esp32 ethernet w5500 SSLClient library manager

Client SSL con Ethernet

Se stai utilizzando la libreria Arduino Ethernet, dovrai modificare la libreria per supportare le grandi dimensioni del buffer per le richieste da SSL. Puoi modificare tu stesso la libreria o utilizzare questo fork della libreria Ethernet con la modifica. Per utilizzare il fork: scarica una copia zippata del fork tramite GitHub, usa il pulsante “aggiungi una libreria .zip” in Arduino per installare la libreria e sostituiscila  #include "Ethernet.h" con  #include "EthernetLarge.h" nel tuo sketch. In alternativa, se, per qualche motivo, questa soluzione non funziona, puoi applicare la modifica manualmente utilizzando le istruzioni seguenti.

Estensione del buffer

Noto anche che per ottenere una buona stabilità probabilmente devi cambiare qualcos’altro.

In SSLClient.h devi cambiare questa riga.

unsigned char m_iobuf[2048];

in

unsigned char m_iobuf[BR_SSL_BUFSIZE_BIDI];

Modifica manuale

Innanzitutto, trova la posizione della libreria nella directory in cui è installato Arduino ( C:\Program Files (x86)\Arduino su Windows). All’interno di questa directory, vai a  libraries\Ethernet\src ( C:\Program Files (x86)\Arduino\libraries\Ethernet\src su Windows). Modifica  Ethernet.h per sostituire queste righe:

...
// Configure the maximum number of sockets to support.  W5100 chips can have
// up to 4 sockets.  W5200 & W5500 can have up to 8 sockets.  Several bytes
// of RAM are used for each socket.  Reducing the maximum can save RAM, but
// you are limited to fewer simultaneous connections.
#if defined(RAMEND) && defined(RAMSTART) && ((RAMEND - RAMSTART) <= 2048)
#define MAX_SOCK_NUM 4
#else
#define MAX_SOCK_NUM 8
#endif

// By default, each socket uses 2K buffers inside the Wiznet chip.  If
// MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting
// this will use larger buffers within the Wiznet chip.  Large buffers
// can really help with UDP protocols like Artnet.  In theory larger
// buffers should allow faster TCP over high-latency links, but this
// does not always seem to work in practice (maybe Wiznet bugs?)
//#define ETHERNET_LARGE_BUFFERS
...

Con queste:

...
// Configure the maximum number of sockets to support.  W5100 chips can have
// up to 4 sockets.  W5200 & W5500 can have up to 8 sockets.  Several bytes
// of RAM are used for each socket.  Reducing the maximum can save RAM, but
// you are limited to fewer simultaneous connections.
#define MAX_SOCK_NUM 2

// By default, each socket uses 2K buffers inside the Wiznet chip.  If
// MAX_SOCK_NUM is set to fewer than the chip's maximum, uncommenting
// this will use larger buffers within the Wiznet chip.  Large buffers
// can really help with UDP protocols like Artnet.  In theory larger
// buffers should allow faster TCP over high-latency links, but this
// does not always seem to work in practice (maybe Wiznet bugs?)
#define ETHERNET_LARGE_BUFFERS
...

Potrebbe essere necessario utilizzare  sudo o autorizzazioni da amministratore per apportare questa modifica. Cambiamo MAX_SOCK_NUMETHERNET_LARGE_BUFFERSquindi l’hardware Ethernet può allocare uno spazio maggiore per SSLClient. Tuttavia, uno svantaggio di questa modifica è che possiamo avere solo due socket contemporaneamente. Poiché la maggior parte dei microprocessori ha a malapena memoria sufficiente per una connessione SSL, questa limitazione si incontra raramente nella pratica.

Codice

Ora proviamo a fare una semplice WebRequest con un client nativo.

Ma prima scriviamo il codice necessario per la connessione, proviamo a chiedere l’IP al server DHCP e, se fallisce, avviamo una connessione con un IP statico.

Inizializzare il dispositivo

Ethernet utilizza l’interfaccia SPI predefinita per impostazione predefinita, quindi prima dobbiamo impostare il pin SS corretto (probabilmente non necessario).

    // You can use Ethernet.init(pin) to configure the CS pin
    //Ethernet.init(10);  // Most Arduino shields
    Ethernet.init(5);   // MKR ETH Shield
    //Ethernet.init(0);   // Teensy 2.0
    //Ethernet.init(20);  // Teensy++ 2.0
    //Ethernet.init(15);  // ESP8266 with Adafruit FeatherWing Ethernet
    //Ethernet.init(33);  // ESP32 with Adafruit FeatherWing Ethernet

Questa scheda è diversa da LAN8720 (dispositivo predefinito per esp32) e necessita di un indirizzo MAC.

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

Quindi proviamo a fare una richiesta DHCP.

    if (Ethernet.begin(mac)) { // Dynamic IP setup
        Serial.println("DHCP OK!");
    }

Ma se fallisce, proviamo a stabilire una connessione IP statica con questi parametri

// Set the static IP address to use if the DHCP fails to assign
#define MYIPADDR 192,168,1,28
#define MYIPMASK 255,255,255,0
#define MYDNS 192,168,1,1
#define MYGW 192,168,1,1

ed ecco il codice di connessione

		Serial.println("Failed to configure Ethernet using DHCP");
		// Check for Ethernet hardware present
		if (Ethernet.hardwareStatus() == EthernetNoHardware) {
			Serial.println(
					"Ethernet shield was not found.  Sorry, can't run without hardware. :(");
			while (true) {
				delay(1); // do nothing, no point running without Ethernet hardware
			}
		}
		if (Ethernet.linkStatus() == LinkOFF) {
			Serial.println("Ethernet cable is not connected.");
		}

		IPAddress ip(MYIPADDR);
		IPAddress dns(MYDNS);
		IPAddress gw(MYGW);
		IPAddress sn(MYIPMASK);
		Ethernet.begin(mac, ip, dns, gw, sn);
		Serial.println("STATIC OK!");

Semplice richiesta HTTP

ESP32 DOIT DevKit v1 w5500 lite
ESP32 DOIT DevKit v1 w5500 lite

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

Userò un semplice servizio fornito da httpbin.org e puoi utilizzare la stessa API REST in HTTP e HTTPS .

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

Per stabilire la nostra connessione, utilizziamo l’EthernetClient di base.

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

E poi, proviamo a connetterci e facciamo una richiesta ad un endpoint in GET.

  // 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");
  }

Nel ciclo, attendi una risposta dal server.

  // if there are incoming bytes available
  // from the server, read them and print them:
  int len = client.available();

E poi leggi la risposta e mettila sull’uscita seriale.

  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 (!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 per finire, lo sketch completo.

/*
 Web client

 This sketch connects to a test website (httpbin.org)
 and try to do a GET request, the output is printed
 on Serial

 by Renzo Mischianti <www.mischianti.org>

 https://www.mischianti.org

 */

#include <SPI.h>
#include <Ethernet.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)

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// Set the static IP address to use if the DHCP fails to assign
#define MYIPADDR 192,168,1,28
#define MYIPMASK 255,255,255,0
#define MYDNS 192,168,1,1
#define MYGW 192,168,1,1

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

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

void setup() {
    Serial.begin(115200);
    delay(1000);
    Serial.println("Begin Ethernet");

    // You can use Ethernet.init(pin) to configure the CS pin
    //Ethernet.init(10);  // Most Arduino shields
    Ethernet.init(5);   // MKR ETH Shield
    //Ethernet.init(0);   // Teensy 2.0
    //Ethernet.init(20);  // Teensy++ 2.0
    //Ethernet.init(15);  // ESP8266 with Adafruit FeatherWing Ethernet
    //Ethernet.init(33);  // ESP32 with Adafruit FeatherWing Ethernet

    if (Ethernet.begin(mac)) { // Dynamic IP setup
        Serial.println("DHCP OK!");
    }else{
        Serial.println("Failed to configure Ethernet using DHCP");
        // Check for Ethernet hardware present
        if (Ethernet.hardwareStatus() == EthernetNoHardware) {
          Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
          while (true) {
            delay(1); // do nothing, no point running without Ethernet hardware
          }
        }
        if (Ethernet.linkStatus() == LinkOFF) {
          Serial.println("Ethernet cable is not connected.");
        }

    	  IPAddress ip(MYIPADDR);
    	  IPAddress dns(MYDNS);
    	  IPAddress gw(MYGW);
    	  IPAddress sn(MYIPMASK);
    	  Ethernet.begin(mac, ip, dns, gw, sn);
		  Serial.println("STATIC OK!");
    }
    delay(5000);


    Serial.print("Local IP : ");
    Serial.println(Ethernet.localIP());
    Serial.print("Subnet Mask : ");
    Serial.println(Ethernet.subnetMask());
    Serial.print("Gateway IP : ");
    Serial.println(Ethernet.gatewayIP());
    Serial.print("DNS Server : ");
    Serial.println(Ethernet.dnsServerIP());

   Serial.println("Ethernet Successfully Initialized");
  // 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 (!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 è questo.

Begin Ethernet
DHCP OK!
Local IP : 192.168.1.138
Subnet Mask : 255.255.255.0
Gateway IP : 192.168.1.1
DNS Server : 192.168.1.1
Ethernet Successfully Initialized

Connected!
HTTP/1.1 200 OK 
Date: Wed, 09 Mar 2022 11:15:49 GMT
Content-Type: application/json 
Content-Length: 197
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-62288c65-1fe4f19070d3ab7c773aee09"
  }, 
  "origin": "82.51.127.46", 
  "url": "http://httpbin.org/get"
}

disconnecting.
Received 422 bytes in 0.2663, rate = 1.58 kbytes/second

Richiesta HTTPS

Ora, se cambiamo l’endpoint sulla porta 443, richiederemo un server sicuro con crittografia SSL.

  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");
  }

E otteniamo questa risposta.

Begin Ethernet
DHCP OK!
Local IP : 192.168.1.138
Subnet Mask : 255.255.255.0
Gateway IP : 192.168.1.1
DNS Server : 192.168.1.1
Ethernet Successfully Initialized
 
Connected!
HTTP/1.1 400 Bad Request
Server: awselb/2.0
Date: Wed, 09 Mar 2022 11:23:16 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.4333, rate = 0.85 kbytes/second

Quindi il problema è che i messaggi di request e response non vengono trasmessi utilizzando SSL (Secure Sockets Layer) o il suo successore TLS (Transport Layer Security). Per aggiungere questa funzione, utilizzeremo SSLClient.

Recuperare il certificato

Per utilizzare un SSL, abbiamo bisogno del certificato del server, ma in questo caso SSLClient utilizza un trucco fornito dall’implementazione di BearSSL. Questo motore di verifica x509 minimo consente l’utilizzo di Trust Anchors.

Aggiungo un semplice generatore online che puoi trovare qui .

Devi solo scrivere l’indirizzo del sito (httpbin.org) nella prima casella di input, fare clic su Generate code, copiare il codice e inserirlo in un file chiamato trust_anchors.h e metterlo nella cartella dello sketch.

BearSSL certificate trust anchor retriever online

Ecco il contenuto di trust_anchors.h.

#ifndef _CERTIFICATES_H_
#define _CERTIFICATES_H_

#ifdef __cplusplus
extern "C"
{
#endif

/* This file is auto-generated by the pycert_bearssl tool.  Do not change it manually.
 * Certificates are BearSSL br_x509_trust_anchor format.  Included certs:
 *
 * Index:    0
 * Label:    Starfield Class 2 Certification Authority
 * Subject:  OU=Starfield Class 2 Certification Authority,O=Starfield Technologies\, Inc.,C=US
 * Domain(s): httpbin.org
 */

#define TAs_NUM 1

static const unsigned char TA_DN0[] = {
    0x30, 0x68, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
    0x02, 0x55, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a,
    0x13, 0x1c, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
    0x54, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x65, 0x73,
    0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x32, 0x30, 0x30, 0x06, 0x03,
    0x55, 0x04, 0x0b, 0x13, 0x29, 0x53, 0x74, 0x61, 0x72, 0x66, 0x69, 0x65,
    0x6c, 0x64, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x43,
    0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
};

static const unsigned char TA_RSA_N0[] = {
    0xb7, 0x32, 0xc8, 0xfe, 0xe9, 0x71, 0xa6, 0x04, 0x85, 0xad, 0x0c, 0x11,
    0x64, 0xdf, 0xce, 0x4d, 0xef, 0xc8, 0x03, 0x18, 0x87, 0x3f, 0xa1, 0xab,
    0xfb, 0x3c, 0xa6, 0x9f, 0xf0, 0xc3, 0xa1, 0xda, 0xd4, 0xd8, 0x6e, 0x2b,
    0x53, 0x90, 0xfb, 0x24, 0xa4, 0x3e, 0x84, 0xf0, 0x9e, 0xe8, 0x5f, 0xec,
    0xe5, 0x27, 0x44, 0xf5, 0x28, 0xa6, 0x3f, 0x7b, 0xde, 0xe0, 0x2a, 0xf0,
    0xc8, 0xaf, 0x53, 0x2f, 0x9e, 0xca, 0x05, 0x01, 0x93, 0x1e, 0x8f, 0x66,
    0x1c, 0x39, 0xa7, 0x4d, 0xfa, 0x5a, 0xb6, 0x73, 0x04, 0x25, 0x66, 0xeb,
    0x77, 0x7f, 0xe7, 0x59, 0xc6, 0x4a, 0x99, 0x25, 0x14, 0x54, 0xeb, 0x26,
    0xc7, 0xf3, 0x7f, 0x19, 0xd5, 0x30, 0x70, 0x8f, 0xaf, 0xb0, 0x46, 0x2a,
    0xff, 0xad, 0xeb, 0x29, 0xed, 0xd7, 0x9f, 0xaa, 0x04, 0x87, 0xa3, 0xd4,
    0xf9, 0x89, 0xa5, 0x34, 0x5f, 0xdb, 0x43, 0x91, 0x82, 0x36, 0xd9, 0x66,
    0x3c, 0xb1, 0xb8, 0xb9, 0x82, 0xfd, 0x9c, 0x3a, 0x3e, 0x10, 0xc8, 0x3b,
    0xef, 0x06, 0x65, 0x66, 0x7a, 0x9b, 0x19, 0x18, 0x3d, 0xff, 0x71, 0x51,
    0x3c, 0x30, 0x2e, 0x5f, 0xbe, 0x3d, 0x77, 0x73, 0xb2, 0x5d, 0x06, 0x6c,
    0xc3, 0x23, 0x56, 0x9a, 0x2b, 0x85, 0x26, 0x92, 0x1c, 0xa7, 0x02, 0xb3,
    0xe4, 0x3f, 0x0d, 0xaf, 0x08, 0x79, 0x82, 0xb8, 0x36, 0x3d, 0xea, 0x9c,
    0xd3, 0x35, 0xb3, 0xbc, 0x69, 0xca, 0xf5, 0xcc, 0x9d, 0xe8, 0xfd, 0x64,
    0x8d, 0x17, 0x80, 0x33, 0x6e, 0x5e, 0x4a, 0x5d, 0x99, 0xc9, 0x1e, 0x87,
    0xb4, 0x9d, 0x1a, 0xc0, 0xd5, 0x6e, 0x13, 0x35, 0x23, 0x5e, 0xdf, 0x9b,
    0x5f, 0x3d, 0xef, 0xd6, 0xf7, 0x76, 0xc2, 0xea, 0x3e, 0xbb, 0x78, 0x0d,
    0x1c, 0x42, 0x67, 0x6b, 0x04, 0xd8, 0xf8, 0xd6, 0xda, 0x6f, 0x8b, 0xf2,
    0x44, 0xa0, 0x01, 0xab,
};

static const unsigned char TA_RSA_E0[] = {
    0x03,
};

static const br_x509_trust_anchor TAs[] = {
    {
        { (unsigned char *)TA_DN0, sizeof TA_DN0 },
        BR_X509_TA_CA,
        {
            BR_KEYTYPE_RSA,
            { .rsa = {
                (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0,
                (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0,
            } }
        }
    },
};

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* ifndef _CERTIFICATES_H_ */

Aggiungere il wrapper SSLClient

Ora aggiungeremo la libreria SSLClient e il file trust_anchors.h.

#include <SPI.h>
#include <EthernetLarge.h>
#include <SSLClient.h>
#include "trust_anchors.h"

Ho anche cambiato la libreria Ethernet con EthernetLarge invece della modifica descritta nella sezione superiore.

Quindi applica il wrapper EthernetClient con tutti i riferimenti di Trust Anchors. Il file contiene nomi di array di trust anchor generati  TAs con lunghezza TAs_NUM.

// Choose the analog pin to get semi-random data from for SSL
// Pick a pin that's not connected or attached to a randomish voltage source
const int rand_pin = A5;

// Initialize the SSL client library
// We input an EthernetClient, our trust anchors, and the analog pin
EthernetClient base_client;
SSLClient client(base_client, TAs, (size_t)TAs_NUM, rand_pin);

E cambiamo la porta in 443 (HTTPS).

  // if you get a connection, report back via serial:
  if (client.connect(server, 443)) {
    Serial.print("connected to ");
    // 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");
  }

Ecco lo sketch completo.

/*
 Web SSL client

 This sketch connects to a test website (httpbin.org)
 and try to do a secure GET request on port 443,
 to do the SSL request we use SSLClient with the
 site Trust Anchor
 the output is printed on Serial

 by Renzo Mischianti <www.mischianti.org>

 https://www.mischianti.org

 */

#include <SPI.h>
#include <EthernetLarge.h>
#include <SSLClient.h>
#include "trust_anchors.h"

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// 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)

// Set the static IP address to use if the DHCP fails to assign
#define MYIPADDR 192,168,1,28
#define MYIPMASK 255,255,255,0
#define MYDNS 192,168,1,1
#define MYGW 192,168,1,1

// Choose the analog pin to get semi-random data from for SSL
// Pick a pin that's not connected or attached to a randomish voltage source
const int rand_pin = A5;

// Initialize the SSL client library
// We input an EthernetClient, our trust anchors, and the analog pin
EthernetClient base_client;
SSLClient client(base_client, TAs, (size_t)TAs_NUM, rand_pin);

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

void setup() {
    Serial.begin(115200);
    delay(1000);
    Serial.println("Begin Ethernet");

    // You can use Ethernet.init(pin) to configure the CS pin
    //Ethernet.init(10);  // Most Arduino shields
    Ethernet.init(5);   // MKR ETH Shield
    //Ethernet.init(0);   // Teensy 2.0
    //Ethernet.init(20);  // Teensy++ 2.0
    //Ethernet.init(15);  // ESP8266 with Adafruit FeatherWing Ethernet
    //Ethernet.init(33);  // ESP32 with Adafruit FeatherWing Ethernet

    if (Ethernet.begin(mac)) { // Dynamic IP setup
        Serial.println("DHCP OK!");
    }else{
        Serial.println("Failed to configure Ethernet using DHCP");
        // Check for Ethernet hardware present
        if (Ethernet.hardwareStatus() == EthernetNoHardware) {
          Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
          while (true) {
            delay(1); // do nothing, no point running without Ethernet hardware
          }
        }
        if (Ethernet.linkStatus() == LinkOFF) {
          Serial.println("Ethernet cable is not connected.");
        }

    	  IPAddress ip(MYIPADDR);
    	  IPAddress dns(MYDNS);
    	  IPAddress gw(MYGW);
    	  IPAddress sn(MYIPMASK);
    	  Ethernet.begin(mac, ip, dns, gw, sn);
		  Serial.println("STATIC OK!");
    }
    delay(5000);


    Serial.print("Local IP : ");
    Serial.println(Ethernet.localIP());
    Serial.print("Subnet Mask : ");
    Serial.println(Ethernet.subnetMask());
    Serial.print("Gateway IP : ");
    Serial.println(Ethernet.gatewayIP());
    Serial.print("DNS Server : ");
    Serial.println(Ethernet.dnsServerIP());

   Serial.println("Ethernet Successfully Initialized");
  // if you get a connection, report back via serial:
  if (client.connect(server, 443)) {
    Serial.print("connected to ");
    // 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 (!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);
    }
  }
}

Ora, quando eseguiamo lo sketch, otteniamo questo output.

Begin Ethernet
DHCP OK!
Local IP : 192.168.1.138
Subnet Mask : 255.255.255.0
Gateway IP : 192.168.1.1
DNS Server : 192.168.1.1 
Ethernet Successfully Initialized

connected to HTTP/1.1 200 OK
Date: Wed, 09 Mar 2022 11:55:33 GMT
Content-Type: application/json
Content-Length: 198
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-622895b5-05f3c1351d694e66175a5335"
  }, 
  "origin": "82.51.127.46", 
  "url": "https://httpbin.org/get"
}
 
disconnecting.
Received 423 bytes in 0.2611, rate = 1.62 kbytes/second

Grazie

Uso questa libreria SSLClient nella mia libreria EMailSender per utilizzare il server SMTP (SSL) di Gmail con Ethernet. Sfortunatamente, le connessioni SSL richiedono un bel po’ di risorse e solo Arduino SAMD, STM32 ed ESP32 hanno così tante risorse.

  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. ESP32-C3: piedinatura, specifiche e configurazione dell’IDE Arduino
  17. i2c esp32: gestione rete a 5v, 3.3v e interfaccia aggiuntiva
  18. […]

Spread the love

Lascia un commento

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