Como fazer HTTPS get com ESP8266

Já não tenho mais tanto ânimo em escrever sobre ESP8266 devido ao poder do ESP32, mas ainda há casos que preciso utilizá-lo, querendo ou não. Além de ser mais barato para projetos, tem clock o suficiente para colocar qualquer Arduino no bolso, sem contar com o WiFi nativo. E não por acaso, tive que fazer HTTPS get com ESP8266 para o mini-curso do Arduino Day 2020 UNIVAG. Se deseja fazê-lo (de forma mais simples ainda) com ESP32, o artigo relacionado trata também da manipulação de json.

Objetivo: fazer HTTPS get com ESP8266

Esse é o primeiro passo para chegar no bitcômetro. Por mais que pareça simples, diversos conceitos estão envolvidos, dos quais alguns sequer me lembro dos detalhes, ainda que eu tenha formação superior em redes de computadores. De qualquer modo, buscar por referências para provar o conceito é uma boa prática, agilizando assim o processo. Como não parto desse ponto, sofri um bocado até começar a me debater a partir de um exemplo. Feito isso, não foi suficiente mudar a URL, tive que modificar código e algumas outras coisas para fazer “exatamente” o mesmo. Vamos lá.

Passo 0: pegar a fingerprint do site alvo

Quando fazemos uma conexão HTTP, a coisa é bem mais simples. Basta mandar o header e ler o conteúdo. Já com SSL (HTTPS) devemos ter alguns cuidados adicionais, dependendo das bibliotecas e arquitetura utilizadas. Algumas bibliotecas são chamadas intrinsecamente por outras, mas dependendo da plataforma, elas devem ser chamadas de forma explícita. É o caso, para fazer HTTPS get com ESP8266.

O fingerprint é o SHA-1 encontrado no site alvo. Isso significa que só é válido por 1 ano, então será necessário atualizar o firmware, exceto utilize a EEPROM ou o sistema de arquivos do ESP8266 para guardar o arquivo com esse dado, que deverá ser atualizado de algum modo. Para pegar o SHA-1, siga os passos no Firefox:

1 – Abra a URL no browser

2 – Clique no cadeado no canto esquerdo da URL.

HTTPS get com ESP8266

3 – Clique na seta ao lado dessa mensagem de “não segura” (trata-se de imagens que não estão passando pelo SSL, não é nada significativo).

4 – Clique em “mais informações”.

HTTPS get com ESP8266

5 – Clique em “ver certificado”.

6 – Use Ctrl+F e procure por SHA-1.

No código, a variável deverá ficar nesse formato:

const char fingerprint[] PROGMEM =  "31 B5 D0 C3 74 CC 25 98 7F 67 32 9D DE FE 5149 E9 AD 8C D1";

Aqui já estou utilizando o fingerprint da URL do mini-curso.

Passo 1: Adicionar as bibliotecas relacionadas

Se não tiver as bibliotecas instaladas, não faltará mensagem de erro na compilação. Supra-as conforme forem surgindo, mas reduza o número de dependências instalando previamente as que forem claras, como ESP8266WiFi, ESP8266HTTPClient, BearSSL e ArduinoJson.

Passo 2: Fazer a requisição para testar a comunicação

A configuração do WiFi vai ficar atípica, mas não tem complexidade. Em setup() apenas adicionei duas linhas ao restante do código:

WiFi.mode(WIFI_STA);
WiFiMulti.addAP(SSID, PASSWD);

No loop há outro procedimento incomum para nossos projetos maker, que é a chamada de um método estático instanciando um novo objeto WiFiClientSecure. Após isso, passamos a fingerprint para o client, então temos um objeto HTTPClient, iniciando à posteriori a conexão mais uma vez de uma maneira “estranha”, passando o ponteiro do client e a URL. Seguidamente, fazemos o get. Na lógica fica mais ou menos assim:

a – Testa a conexão WiFi;

b – cria-se o objeto SSL;

c – passa-se a fingerprint para o client;

d – cria-se o objeto HTTP;

e – inicia-se a conexão com a URL pretendida;

f – faz-se o get;

g – avalia-se o resultado;

h – finaliza-se a conexão.

Isso é tudo que precisa ser feito. O propósito era examente o mesmo do artigo com json, pegando o valor do bitcoin na API do Mercado Bitcoin, mas o processo mudou um tanto. As demais tratativas foram explanadas no artigo citado logo no inicio. Se quiser mais detalhes, sugiro a leitura.

Um pedaço do resultado:

HTTPS get com ESP8266

Código completo

O código utilizado para esse exemplo (incluindo minhas credenciais WiFi de laboratório):

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiClientSecureBearSSL.h>
#include <Wire.h>
#include <WiFiClient.h>
#include "ArduinoJson.h"

#define SSID "SuhankoFamily"
#define PASSWD "fsjmr112"

ESP8266WiFiMulti WiFiMulti;

const char fingerprint[] PROGMEM =  "31 B5 D0 C3 74 CC 25 98 7F 67 32 9D DE FE 5149 E9 AD 8C D1";
char json[400] = {0};

StaticJsonDocument<256> doc;

void resultOfGet(String msg){
    memset(json,0,sizeof(json));
    msg.toCharArray(json, 400);
    deserializeJson(doc, json);

    JsonObject ticker = doc["ticker"];
    const char* ticker_high = ticker["high"]; // "33395.00000000"
    const char* ticker_low = ticker["low"]; // "32911.01001000"
    const char* ticker_vol = ticker["vol"]; // "29.80139592"
    const char* ticker_last = ticker["last"]; // "33146.89715000"
    const char* ticker_buy = ticker["buy"]; // "33005.10011000"
    const char* ticker_sell = ticker["sell"]; // "33146.89715000"
    const char* ticker_open = ticker["open"]; // "33094.94851000"
    long ticker_date = ticker["date"]; // 1578889119

    Serial.println(ticker_last);
}

void setup() {
  //1 - Para testar, vamos usar a serial
  Serial.begin(9600);

  //2 - iniciamos a conexão WiFi...
  WiFi.mode(WIFI_STA);
  WiFiMulti.addAP(SSID, PASSWD);

  //3 - acesse arduinojson.org/v6/assistant e passe uma amostra pra calcular a capacidade
  const size_t capacity = JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(8) + 146;
  DynamicJsonDocument doc(capacity);

}

void loop() {
  Serial.println("loop started...");
        if ((WiFiMulti.run() == WL_CONNECTED)){
          std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
          client->setFingerprint(fingerprint);
          Serial.println("connected...");
          //WiFiClient client;

          HTTPClient http;

        //3 - iniciamos a URL alvo, pega a resposta e finaliza a conexão
        if (http.begin(*client,"https://www.mercadobitcoin.net/api/BTC/ticker")){
          Serial.println("http.begin ok");
        }
        int httpCode = http.GET();
        if (httpCode > 0) { //Maior que 0, tem resposta a ser lida
            String payload = http.getString();
            Serial.println(httpCode);
            Serial.println(payload);
            resultOfGet(payload);
        }
        else {
          Serial.println(httpCode);
            Serial.println("Falha na requisição");
        }
        http.end();
        }
        delay(5000);
}

E vem mais por aí!

Djames Suhanko

Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.