Manual

do

Maker

.

com

Como fazer HTTPS get com ESP8266

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

cadeado.webp

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"

mais_informacoes.webp

5 - Clique em "ver certificado"

ver_certificado.webp

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

sha-1.webp

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:

  1. testa a conexão WiFi
  2. cria-se o objeto SSL
  3. passa-se a fingerprint para o client
  4. cria-se o objeto HTTP
  5. inicia-se a conexão com a URL pretendida
  6. faz-se o get
  7. avalia-se o resultado
  8. finaliza-se a conexão

Isso é tudo que precisa ser feito. O propósito era exatamente 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:

result-bitcoin-value.webp

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í!

 

Revisão: Ricardo Amaral de Andrade

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.