Paulo Borges
Paulo Borges

Reputation: 45

ESP32 Google Vision Face Detection request fail

I am trying to submit an image on the web to Google Vision Face detection. Submitting the image directly on the Google Vision page:

https://cloud.google.com/vision/docs/ocr?apix_params=%7B%22resource%22%3A%7B%22requests%22%3A%5B%7B%22features%22%3A%5B%7B%22type%22%3A%22FACE_DETECTION%22%7D%5D%2C%22image%22%3A%7B%22source%22%3A%7B%22imageUri%22%3A%22http%3A%2F%2Fwww.newdesignfile.com%2Fpostpic%2F2010%2F05%2Ffree-stock-photos-people_102217.jpg%22%7D%7D%2C%22imageContext%22%3A%7B%22languageHints%22%3A%5B%22pt%22%5D%7D%7D%5D%7D%7D

works OK. Also using NodeRed on a raspberry Pi works ok. But I can not make it work with ESP32. It always responds on the console with: HTTP Response code: -5 Error code: -5

My code is as below:

/*
  Rui Santos
  Complete project details at Complete project details at https://RandomNerdTutorials.com/esp32-http-get-post-arduino/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "mySSID";
const char* password = "myPass";

//Your Domain name with URL path or IP address with path
const char* serverName   = "https://vision.googleapis.com/v1/images:annotate?key=MyAPIKey";

String _request = "{\"requests\":[{\"image\":{\"source\":{\"imageUri\":\"http://www.newdesignfile.com/postpic/2010/05/free-stock-photos-people_102217.jpg\"}},\"features\":[{\"type\":\"FACE_DETECTION\",\"maxResults\":10}]}]}";


// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastTime = 0;
unsigned long timerDelay = 15000;

void setup() {
  Serial.begin(115200);

  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
 
}

void loop() {
  //Send an HTTP POST request every 10 minutes
  if ((millis() - lastTime) > timerDelay) {
    //Check WiFi connection status
    if(WiFi.status()== WL_CONNECTED){
      WiFiClient client;
      HTTPClient http;
    
      // Your Domain name with URL path or IP address with path
      http.begin(client, serverName);
      Serial.print("Conected to Server: ");
      Serial.println(serverName);
      
      //If you need an HTTP request with a content type: application/json, use the following:
      http.addHeader("Content-Type", "application/json");
      Serial.print("Posting request: ");    
      Serial.println(_request);
      int httpResponseCode = http.POST(_request); 
      
      Serial.print("HTTP Response code: ");
      Serial.println(httpResponseCode);

      String payload = "{}"; 

      if(httpResponseCode>0) {
        Serial.print("HTTP Response code: ");
        Serial.println(httpResponseCode);
        payload = http.getString();
        Serial.println(payload);        
      }else{
        Serial.print("Error code: ");
        Serial.println(httpResponseCode);
      }    
        
      // Free resources
      http.end();
    }else {
      Serial.println("WiFi Disconnected");
    }
    lastTime = millis();
  }
}

Assistance welcome.

Upvotes: 1

Views: 179

Answers (1)

romkey
romkey

Reputation: 7109

You're trying to load an HTTPS URL over an HTTP connection.

You'll need to use WiFiClientSecure in order to use HTTPS - you can find examples in the HTTPClient library.

Your code needs to look like:

      WiFiClientSecure client;
      HTTPClient http;

      client.setCACert(rootCACertificate);

      // Your Domain name with URL path or IP address with path
      http.begin(client, serverName);

You'll need to find and store a copy of the root certificate authority certificate for the domain you're accessing. If it ever changes (and it will eventually expire) you'll need to update that. Generally you'd define that at the start of your file - most people unnecessarily define it as a global variable, like so:

#include <WiFi.h>
#include <HTTPClient.h>

const char* rootCACertificate = \
"-----BEGIN CERTIFICATE-----\n" \
...
"-----END CERTIFICATE-----\n";

You'd replace the ... with the actual contents of the certificate. You can find many explanations of how to do this via a search engine or here on Stack Overflow. Make sure you write each line of it as a C string ending with \n" \ so that the lines are concatenated into a single string.

You can sidestep the need for the root CA certificate by writing your code like this:

      WiFiClientSecure client;
      HTTPClient http;

      client.setInsecure();

      // Your Domain name with URL path or IP address with path
      http.begin(client, serverName);

this is fine for testing but it defeats the security that HTTPS gives you and should not be used in production or deployed code. Running it as insecure means you don't know that the server you connected to is the correct server and you don't know that the data you exchange with it (including any passwords or API keys) will actually be private from anyone trying to eavesdrop on network traffic.

Upvotes: 1

Related Questions