Using ESP32 with EthernetClient to make a Request using HTTPClient

Hi,

I am using an ESP32 WROOM, and a W5500 Lite. Im attempting to send an Http post command using the code:

EthernetClient client;

HTTPClient http;

http.begin(client, url);

Im getting the Error below:

no matching function for call to 'HTTPClient::begin(EthernetClient&, String)'

When i look at the HTTPCLient.h i see that it accepts a WifiFClient and not an Ethernet Client.

Has anyone ever experience this and have gotten HTTPClient to work? I'm specifically using HTTPClient library bc it has a Digest Authentication with all the functions already, but if there's another library i can transfer over to that allows Ethernet I would be interested.

Code Below:

#include <Ethernet.h>
#include <SPI.h>
#include <HTTPClient.h>
#include <MD5Builder.h>
#include "Arduino.h"


// Set Mac and IP Info
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10,100,0,195);
IPAddress subnet(255,255,255,0);
IPAddress gateway(10,100,0,1);

// Dijest POST Variables 
int InthttpCode = 0; // so we dont need to loop the first POST
String authReq;

// Dijest User Pass
const char *username = "USer";
const char *password = "pass";

// Digest Server and Request
const char *postServer = "http://10.100.0.178";
const char *uri = "ExtraStuff";
String params = "params";

void setup() {
  esp_random();
  Serial.begin(115200);
  Serial.println("Running Startup");
  
  // Changes SPI Mode
  SPISettings settingsA(8000000, MSBFIRST, SPI_MODE3);
//  wiznet_SPI_settings = settingsA; (Used with Ethernet2.h Lib)

  // Print out SPI Pins
//  Serial.print("MISO : ");
//  Serial.println(PIN_SPI_MISO);
//  Serial.print("MOSI : ");
//  Serial.println(PIN_SPI_MOSI);
//  Serial.print("SCK : ");
//  Serial.println(PIN_SPI_SCK);
//  Serial.print("SS : ");
//  Serial.println(PIN_SPI_SS);

  // Set CS pin to 4
  Ethernet.init(5);

  Serial.println("Starting Ethernet Connection");
  // start the Ethernet connection:= with DHCP

  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  }  

  Serial.println(Ethernet.localIP());
  postRequest();
}

void loop() {
  
}

//Dijest POST Functions

int postRequest(){
  Serial.println("Starting POST Request...");
  EthernetClient client;
  HTTPClient http; //must be declared after WiFiClient for correct destruction order, because used by http.begin(client,...)
  int httpCode;

   if (InthttpCode == 0){

  String urlRequest = String(postServer) + String(uri);
  
    // configure traged server and url
    http.begin(client, String(urlRequest));


    const char *keys[] = {"WWW-Authenticate"};
    http.collectHeaders(keys, 1);
  
    Serial.print("[HTTP] GET...\n");
    // start connection and send HTTP header
    InthttpCode = http.POST(params);
    Serial.println("First Post");
    Serial.println(InthttpCode);
    if (InthttpCode > 0){
      authReq = http.header("WWW-Authenticate");
    }
  }

  if (InthttpCode > 0) {
    String authorization = getDigestAuth(authReq, String(username), String(password), "POST", String(uri), 1);
    Serial.println(authorization);
    String urlRequest = String(postServer) + String(uri)+"?" + String(params);

    http.end();
    http.begin(client, String(urlRequest));

    http.addHeader("Authorization", authorization);
    http.addHeader("Content-Type", "text/xml");
    http.addHeader("Content-Encoding", "br");

    httpCode = http.POST(params);
    Serial.println(httpCode);
    Serial.println("Second Post");
    if (httpCode > 0) {
      String payload = http.getString();
      Serial.println(payload);
    } else {
      Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
    }
    
  } else {
    Serial.printf("[HTTP]Initial POST... failed, error: %s\n", http.errorToString(InthttpCode).c_str());
  }
  http.end();
  delay(10000);
  return httpCode;
}

String exractParam(String& authReq, const String& param, const char delimit) {
  int _begin = authReq.indexOf(param);
  if (_begin == -1) {
    return "";
  }
  return authReq.substring(_begin + param.length(), authReq.indexOf(delimit, _begin + param.length()));
}

String getCNonce(const int len) {
  static const char alphanum[] =
    "0123456789"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz";
  String s = "";

  for (int i = 0; i < len; ++i) {
    s += alphanum[rand() % (sizeof(alphanum) - 1)];
  }

  return s;
}

String getDigestAuth(String& authReq, const String& username, const String& password, const String& method, const String& uri, unsigned int counter) {
  // extracting required parameters for RFC 2069 simpler Digest
  String realm = exractParam(authReq, "realm=\"", '"');
  String nonce = exractParam(authReq, "nonce=\"", '"');
  String cNonce = getCNonce(8);

  char nc[9];
  snprintf(nc, sizeof(nc), "%08x", counter);

  // parameters for the RFC 2617 newer Digest
  MD5Builder md5;
  md5.begin();
  md5.add(username + ":" + realm + ":" + password);  // md5 of the user:realm:user
  md5.calculate();
  String h1 = md5.toString();

  md5.begin();
  md5.add(method + ":" + uri);
  md5.calculate();
  String h2 = md5.toString();

  md5.begin();
  md5.add(h1 + ":" + nonce + ":" + String(nc) + ":" + cNonce + ":" + "auth" + ":" + h2);
  md5.calculate();
  String response = md5.toString();

  String authorization = "Digest username=\"" + username + "\", realm=\"" + realm + "\", nonce=\"" + nonce +
                         "\", uri=\"" + uri + "\", algorithm=\"MD5\", qop=auth, nc=" + String(nc) + ", cnonce=\"" + cNonce + "\", response=\"" + response + "\"";
  //Serial.println(authorization);

  return authorization;
}

the esp32 arduino WiFi library supports LAN8720 Ethernet
https://github.com/espressif/arduino-esp32/tree/master/libraries/Ethernet/examples/ETH_LAN8720

You might want to try the HttpClient library, it works with the Ethernet library.

Hi, Thank you for the reply! I was trying to do that but i cant figure out how to transfer over the Digest Auth code to make it work with that HttpClient instead of HTTPClient. When looking at HttpClient.h, i don't see any functions that request the headers like HTTPClient.collectHeaders.
Any thoughts on this?

But would HTTPClient accept an ETH client object instead of WiFiCLient because its a type error i think im getting

No, you would have to code that yourself. Derive your own class and read the headers you need.

you would use the same WiFiClient as for esp32 WiFi. WiFiClient has nothing to do with WiFi. it is just a bad choice of class name. the underlying network interface of the TCP/IP stack can be WiFi or wired Ethernet. but esp32 only has 'drivers' for LAN8720 or TLK110 wired modules. (and esp8266 arduino has 'drivers' for W5500 and ENC28J60)

im using W5500 with the ESP32. Will that affect it?

I tried using WiFiClient instead of EthernetClient but i was unable to get a connection on my test script. I declared WiFiClient as client and used that after i had initiated Ethernet. Any thoughts on how I can use the WiFiClient Object to make this connection?

yes. it will not work

So you think my only way to accomplish this is to create the functions needed with HttpClient from HTTPClient?

Hi, did you make the code work with ESP32 and W5500?

Yes i did. I had to rewrite the HTTPClient library so that I could use the EthernetClient class

could you please share your changed library?

I used HttpClient (https://github.com/amcewen/HttpClient) instead of HTTPClient in order to rewrite how they accomplished Digest Autho

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.