Unable to connect to googleapis.com

Hi, I want to use the google api to get the geolocation of the nano33iot board via wifi. When I curl the request I get a normal response - api key is not restricted in any way, on arduino however i alwas get false when i call client.connect("www.googleapis.com", 443). I have tried with other SSL sites (https://jsonplaceholder.typicode.com/posts/1), where the connection works normally.

Any help or ideas will be much appreciated!

The whole code:

#include <WiFiNINA.h>
#include <ArduinoJson.h>
#include "secrets.h"

// Server details
const char* server = "www.googleapis.com";
const int port = 443;

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

  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  Serial.println(SECRET_SSID);
  WiFi.begin(SECRET_SSID, SECRET_PASS);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("\nConnected to WiFi");

  // Get location
  getLocation();
}

void loop() {
  // put your main code here, to run repeatedly:
}

void getLocation() {
  // Scan for Wi-Fi networks
  int numNetworks = WiFi.scanNetworks();
  if (numNetworks == -1) {
    Serial.println("Failed to scan WiFi networks");
    return;
  }

  // Create JSON request payload
  StaticJsonDocument<1024> doc;
  JsonArray wifiAccessPoints = doc.createNestedArray("wifiAccessPoints");

  for (int i = 0; i < numNetworks; i++) {
    uint8_t bssid[6];
    WiFi.BSSID(i, bssid);
    JsonObject wifiObject = wifiAccessPoints.createNestedObject();
    wifiObject["macAddress"] = macToString(bssid);
    wifiObject["signalStrength"] = WiFi.RSSI(i);
  }

  String requestBody;
  serializeJson(doc, requestBody);

  // Make HTTPS request to Google Geolocation API
  WiFiSSLClient client;
  if (!client.connect(server, port)) {
    Serial.println("Connection to server failed");
    return;
  }

  // Send HTTP POST request
  client.println("POST /geolocation/v1/geolocate?key=" + String(SECRET_GOOGLE_API) + " HTTP/1.1");
  client.println("Host: " + String(server));
  client.println("Content-Type: application/json");
  client.println("Connection: close");
  client.print("Content-Length: ");
  client.println(requestBody.length());
  client.println();
  client.println(requestBody);

  // Read response
  while (client.connected() || client.available()) {
    if (client.available()) {
      String line = client.readStringUntil('\n');
      if (line == "\r") {
        break;
      }
    }
  }

  String response = "";
  while (client.available()) {
    response += client.readString();
  }

  client.stop();

  // Parse response
  StaticJsonDocument<1024> responseDoc;
  DeserializationError error = deserializeJson(responseDoc, response);
  if (error) {
    Serial.print("deserializeJson() failed: ");
    Serial.println(error.f_str());
    return;
  }

  float latitude = responseDoc["location"]["lat"];
  float longitude = responseDoc["location"]["lng"];
  float accuracy = responseDoc["accuracy"];

  // Print location data
  Serial.print("Latitude: ");
  Serial.println(latitude, 7);
  Serial.print("Longitude: ");
  Serial.println(longitude, 7);
  Serial.print("Accuracy: ");
  Serial.println(accuracy);
}

String macToString(const uint8_t* mac) {
  String macStr = "";
  for (int i = 0; i < 6; ++i) {
    if (mac[i] < 0x10) {
      macStr += "0";
    }
    macStr += String(mac[i], HEX);
    if (i < 5) {
      macStr += ":";
    }
  }
  return macStr;
}

have you printed the content of your post request to ensure it's legit or you don't even get there and stops at the connection ?

Can you connect to www.google.com? It uses the same root CA, but the cert for googleapis is more... complicated.

Yes i have. Printed the request, copied it into Postman to send a request with it. Got a connection and a response without a problem.

Looks like there might be a problem somewhere.
I used the follwing code just to test if i can connect to google.com via ssl:

void testGoogleConnection() {
  WiFiSSLClient client;
  Serial.print("Connecting to ");
  Serial.print(testServer);
  Serial.print(":");
  Serial.println(port);

  if (!client.connect(testServer, port)) {
    Serial.println("Connection to test server failed");
    return;
  }

  // Send HTTP GET request
  client.println("GET / HTTP/1.1");
  client.println("Host: " + String(testServer));
  client.println("Connection: close");
  client.println();

  // Read response
  String response = "";
  while (client.connected() || client.available()) {
    if (client.available()) {
      response += client.readString();
    }
  }
  client.stop();

  Serial.println("Test Server Response:");
  Serial.println(response);
}

The only output i get is Connecting to www.google.com:443 and it hangs (for more than 10min, then i tried with something else)

I still have no idea why it does not want to connect to google.com via ssl.

Are the certificates up to date?

They should be. I updated the firmware to latest (1.5.0) and uploaded the google.com:443 ssl root certificate (I'm using IDE 2.3.2). Is there anything else that i'm missing?

Finally solved the problem. Looks like the bug was further in the code. The certs are working. The main thing I was trying to achieve was to call Google geolocation API, which is used to retrieve approximate location based on nearby access points. My initial workflow was: connect to wifi -> scan networks and construct a request body json -> send to api and parse response. The one thing i did not take into account was that scanning the networks disrupts the currently established wifi connection. This was not solved even by using many delays.

My workflow is now as follows:

String requestBody = scanNetworks();
ensureConnection();
sendHardcodedRequest(requestBody);

Where ensureConnection() is a simple function that reconnects the device to wifi if the connection is lost:

void ensureConnection() {
  Serial.println("Ensuring connection is stable...");

  int retryCount = 0;
  const int maxRetries = 10;

  while (WiFi.status() != WL_CONNECTED && retryCount < maxRetries) {
    Serial.println("Reconnecting to WiFi...");
    WiFi.disconnect();
    WiFi.begin(ssid, pass);
    delay(1000);  // Wait a second before retrying
    retryCount++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("Connection stable.");
    printWiFiStatus();
  } else {
    Serial.println("Failed to stabilize connection.");
  }
}
1 Like

weird I think the ESP32 is designed to handle tasks like network scanning while maintaining connectivity to the WiFi network

what kind of disruption do you see ?

I'm not using ESP32. I'm using Nano 33 IoT, which has a NINA-W102 radio module.

the NINA-W102 is not an ESP32, but it is a wireless module based on the ESP32. It uses the ESP32 chip for its core functionality, providing Wi-Fi and Bluetooth capabilities.