Summary:

HTTPS requests on the ESP8266 can be a hassle. Let's attempt to fix that, so that I don't have to use IFTTT as an HTTPS proxy. See Day 7: Open Data Logger for the previous IFTTT approach to this problem.

Materials:

materials-4

  1. ESP8266 Development Board
  2. Analog or Digital Sensor
  3. USB-Micro Cable
  4. Arduino IDE
  5. Google account

Prerequisites:

Complete Day 7: Open Data Logger for hardware and software basics.

Process:

To make life easier, let's assume we're performing the same task as last time: Uploading sensor data to Google sheets. We'll need to obtain the SHA fingerprint of the API, write some code to open a connection, verify the fingerprint with TLS, and send our data via HTTP through the secure connection.

Extracting the SHA Fingerprint:

We can use openssl to grab the fingerprint for us, by using the command: echo | openssl s_client -connect script.google.com:443 | openssl x509 -fingerprint -noout

Which yields the following:

depth=1 C = US, O = Google Trust Services, CN = Google Internet Authority G3
verify error:num=20:unable to get local issuer certificate
verify return:0
DONE
SHA1 Fingerprint=29:40:55:83:01:36:FA:5D:BD:5E:6B:91:58:29:EA:8F:26:7E:22:0B

Save the SHA1 Fingerprint for use in our code.

Writing a new httpsGet:

We no longer need the ESP8266HTTPClient.h header. Instead we'll use WiFiClientSecure.h. We'll also break up our endpoint URL into some smaller variables for using the HTTPS client.

#include <WiFiClientSecure.h>

const char* GOOGLE_HOST = "script.google.com";
const char* FINGERPRINT = "29 40 55 83 01 36 FA 5D BD 5E 6B 91 58 29 EA 8F 26 7E 22 0B";
String GOOGLE_URL = "/macros/s/{script_id}/exec";

The new HTTPS GET method will need to take the URL split into hostname and URL. First we'll connect to the host on port 443. Then we'll verify the SHA fingerprint for our TLS connection. We'll build and send an HTTP/1.1 GET request with our URL. Finally we'll read from the connection looking for HTTP return codes.

int httpsGET(const char *host, const char *fingerprint, String url) {
    WiFiClientSecure client;
    
    Serial.print("Connecting to: ");
    Serial.println(host);
    if (!client.connect(host, 443)) {
        Serial.println("connection failed");
        return -1;
    }
    
    if (client.verify(fingerprint, host)) {
        Serial.println("certificate matches");
    } else {
        Serial.println("certificate doesn't match");
    }

    // Send GET
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: ESP8266\r\n" +
               "Connection: close\r\n\r\n");
    
    Serial.println("GET sent");
    while (client.connected()) {
        String line = client.readStringUntil('\n');
        if (line.startsWith("HTTP/1.1")) {
            // Get HTTP return code
            return line.substring(9,12).toInt();
        }
    }
    
    return -1;
}

Using the New GET:

Most of the logic from before still holds. This time, instead of building a JSON object to POST we'll build a URL to GET. Then we'll call our new HTTPS GET and check for the return code.

String url = GOOGLE_URL + "?tag=" + TAG_NAME + "&value=" + soilMoistureLevel;

Serial.print("[-] Sending GET to URL : ");
Serial.println(url);

int retCode = httpsGET(GOOGLE_HOST, FINGERPRINT, url);
if (retCode==HTTP_CODE_OK) {
    Serial.println("[-] Reporting succeeded.");
} else {
     Serial.print("[!] Reporting failed: Code ");
    Serial.println(retCode);          
}

Testing:

Save and flash the new code to the assembled ESP8266. Open up the Serial Monitor (Tools > Serial Monitor) and you should see output like the following:

[-] Connecting to WiFi
Connecting to MyWifi
...
...
...

WiFi connected
IP address: 
192.168.1.99
[-] Reading soil moisture
Moisture level: 26%
[-] Sending GET to URL : /macros/s/**{script_id}**/exec?tag=SoilMoistureLevel&value=26
Connecting to: script.google.com
certificate matches
GET sent
[-] Reporting succeeded.
[-] Sleeping

Code:

Sample code for today can be found here..

Future Work:

This makes the project much more useful, as being able to directly interface with https servers opens up the possibility to use more modern API's. With this change it's possible I'll pursue building a multi-sensor datalogger for tracking multiple plants.