Manual
do
Maker
.
com
Antes de começar o assunto relacionado ao título, permita-me passar uma visão superficial da agenda do ano, abrindo com esse singelo artigo de como ler json no ESP32.
No final do ano anunciei o início dos trabalhos com a CNC laser da ECNC, um hardware espetacular em recursos e qualidade e com laser de 100w, que permite cortar materiais espessos de até 1.2cm tranquilamente. Bem, obviamente esse ano teremos muitos artigos relacionados a corte laser, agregando eletrônica digital.
Dentre os artigos, teremos relógios, autômatas, marble machines e diversas surpresas, das quais estou preparando os projetos de forma contínua (é bastante trabalhoso, acredite).
Em Março teremos o Arduino Day UNIVAG, organizado pelo Arduino Brasil em Mato Grosso. Lá estarão presentes alguns conhecidos da comunidade como o Waldyr da Projetos eletrônicos, O Ilustríssimo Prof. Newton Braga do Instituto Newton Braga, o Nascimento Jr e Ana Carolina da equipe Arduino Brasil, e um simplório de boa vontade, Djames Suhanko do blog Manual do Maker (esse que vos escreve).
Teremos palestras e mini-cursos, sendo o tema da minha palestra "Como ter ideias para projetos com Arduino". Nessa palestra falarei sobre a forma que me inspira a escrever os artigos, dos quais muitos são conceitos aplicados em projetos que comercializo sem divulgá-los. Citarei a importância de um código razoavelmente focado em embarcados e exporei uma ideia (que não é nova mas) que não vi colocarem em prática ainda.
No mini-curso faremos a implementação de um display Nokia em uma Waldunano com ESP-01 para pegar o valor do bitcoin online e exibir no display. Mas não só; criei um pequeno dispositivo que se assemelha a um manômetro, o qual chamei de "bitcômetro", que apontará para alta ou baixa do valor do bitcoin, baseando-se no valor de abertura do dia. Esse bitcômetro será cortado a laser e distribuído gratuitamente aos que participarem do mini-curso. Até agora, os primeiros 10 inscritos ganharão também o servo-motor, patrocinado pelo nosso parceiro Curto Circuito (talvez haja mais patrocínios, informo durante a semana).
A forma de pegar o valor do bitcoin será bastante interessante e simples, e o bitcômetro é um patrocínio do**Mercado Bitcoin,**que também estará presente no evento com um estande e uma apresentação sobre os produtos que giram em torno do bitcoin. Fui engenheiro de redes e segurança no Mercado Bitcoin e acredite, é um universo extremamente complexo, no qual se investe verdadeiras fortunas para que realmente seja preservada a integridade das carteiras. Além disso, o pouco que sei hoje sobre bitcoin foi o que consegui aprender enquanto trabalhei lá, tem muita coisa e vale a pena assistir a apresentação deles no Arduino Day UNIVAG.
Em breve divulgo a agenda do evento, provavelmente em mais um ou dois dias.
Para quem não conhece, json é um tipo de estrutura que se assemelha a um dicionário em Python:
{chave: {valor1:1, valor2:2}}
Pode-se ter montes de chaves e valores, sem problemas. Esses valores podem vir do header HTTP ou do corpo de uma requisição GET. Assim sendo, utilizaremos 2 bibliotecas importantes para essa tarefa; a HTTPClient e a ArduinoJson.
Já que falamos de bitcoin, vou mostrar a dica com parte do que será mostrado no mini-curso (mas não será só isso, tem o processo de organização e composição do código e todo o desenvolvimento da ideia até chegar no resultado pretendido. Não deixe de fazer o mini-curso para ver o desenrolar de um projeto).
Existem mais formas de fazer esse tratamento. Uma vez que fazemos a requisição HTTP, obtemos um resultado como o exemplo mais acima. Daí o que precisamos fazer é tratar cada valor de cada chave individualmente. Esse processo é chamado de "parsing", e pode ser a parte mais trabalhosa de um código, principalmente se estivermos fazendo esse parsing manualmente. Utilizando a biblioteca ArduinoJson para ler json no ESP32, a captura dos valores será transparente.
Para pegar o valor do bitcoin, utilizaremos a API do Mercado Bitcoin, cuja documentação é essa.
Para ter um parâmetro, vamos ver o resultado de um GET na API:
{"ticker": {"high":"33470.00000000","low":"32515.16000000","vol":"49.23741181","last":"33054.00730000","buy":"33054.00730000","sell":"33191.90847000","open":"33091.31237000","date":1578863707}}
Agora que sabemos o que esperar, podemos iniciar o código.
Já há algum tempo que tenho usado o Visual Studio Code para programar embarcados. Como ele tem uma versão para Linux e as qualidades são incomparáveis, recomendo que você baixe para a sua plataforma operacional, seja Windows, Linux ou Mac. Depois, basta instalar o PlatformIO pela própria IDE.
Independente da IDE de programação selecionada, não se esqueça de instalar as bibliotecas HTTPClient e ArduinoJson.
Fora das funções, crie o objeto HTTP que será utilizado para fazer a requisição e um array de char com 400 posições. Aproveite para definir também as credenciais da rede WiFi. No exemplo, exponho as credenciais da minha rede de laboratório:
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include "ArduinoJson.h"
#define SSID "SuhankoFamily"
#define PASSWD "fsjmr112"
//0 - Criamos o objeto de comunicação HTTP
HTTPClient http;
char json[400] = {0}
No setup, fazemos o processo padrão para conexão com a rede WiFi e inicialização da comunicação serial. Depois, criamos uma variável com o tamanho adequado para comportar a manipulação do json. Para calcular o tamanho correto dessa variável, acesse essa URL do ArduinoJson e passe uma amostra do que será manipulado. Os valores ideais serão exibidos na coluna da direita:
Feito isso, crie o objeto dinâmico do tamanho requerido para a transação. O setup ficará desse jeito:
void setup()
{
//1 - Para testar, vamos usar a serial
Serial.begin(9600);
//2 - iniciamos a conexão WiFi...
WiFi.begin(SSID,PASSWD);
//...e aguardamos até que esteja concluída.
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println(".");
}
Serial.println("Conectado!");
//3 - acesse arduinojson.org/v6/assistant e passe uma amostra pra calcular a capacidade
constsize_t capacity = JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(8) + 146;
DynamicJsonDocument doc(capacity);
}
Daí vamos finalmente para o loop e fazemos a requisição HTTP e a manipulação dos valores. Dá pra ler json no ESP32 de outras formas? Sim, dá, mas esse jeito me pareceu o mais simples. Mas como não gosto de esparramar código pelo programa, criei uma função para fazer a manipulação do json. A função ficou assim:
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);
}
Repare que essa função tem uma rotina bastante simples, mas essencial. Primeiramente, limpamos a variável criada para armazenar o json que eventualmente já foi utilizada e não deve conter valores anteriores. Isso é feito com memset, passando o array de char, o valor a preencher e o tamanho do array. Depois, o alimentamos com o resultado da requisição GET, feita no loop. Como o retorno da requisição gera um payload em um objeto String, devemos convertê-lo para array de char. Para isso, utilizamos o método .toCharArray(*array,tamanho_max). Esse método pertence ao objeto String passado como parâmetro de função. Em nossa função, esse parâmetro é um ponteiro com o nome msg.
Na lista posterior fazemos a desserialização (essa palavra nem existe, mas enfim) do array de char contendo o json. Essa função deserializeJson se encarrega de fazer todo o parsing necessário e nos livra de uma tarefa bastante chata. Depois, basta pegar os valores resultantes, criando uma chave com o nome desejado utilizando o JsonObject.
Finaliza-se a função com um print na serial, mas a partir desse ponto pode-se fazer o que quiser com os valores.
Mais acima vimos a função setup() completa, agora vimos a função que trata o resultado da requisição HTTP. Vamos ver essa requisição na função loop():
void loop()
{
//4 - iniciamos a URL alvo, pega a resposta e finaliza a conexão
http.begin("https://www.mercadobitcoin.net/api/BTC/ticker");
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("Falha na requisição");
}
http.end();
vTaskDelay(pdMS_TO_TICKS(60000));
}
Como pode-se notar, ficou bastante limpo e curto o código todo.
Na função loop() fazemos inicialmente a configuração do objeto HTTP, passando a URL a utilizar. Em seguida, fazemos a requisição com o método GET. Tratamos o retorno e em caso de status code 200, chamamos a função criada anteriormente para manipular o resultado. Em qualquer circunstância, não podemos nos esquecer de encerrar a comunicação com http.end(). Também não quereremos deixar o loop rodando na velocidade de cada requisição HTTP, portanto, crie um delay. No caso, utilizei o modo ESP32, fazendo uma requisição por minuto. Pode ser menos, pode ser mais, dependendo da real necessidade. Essas coisas todas falarei a respeito no mini-curso do Arduino Day UNIVAG.
O resultado na serial será algo como:
Se quiser aproveitar o código, copie daqui invés de pedaço por pedaço das explicações anteriores:
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include "ArduinoJson.h"
#define SSID "SuhankoFamily"
#define PASSWD "fsjmr112"
//0 - Criamos o objeto de comunicação HTTP
HTTPClient http;
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.begin(SSID,PASSWD);
//...e aguardamos até que esteja concluída.
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println(".");
}
Serial.println("Conectado!");
//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() {
//3 - iniciamos a URL alvo, pega a resposta e finaliza a conexão
http.begin("https://www.mercadobitcoin.net/api/BTC/ticker");
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("Falha na requisição");
}
http.end();
vTaskDelay(pdMS_TO_TICKS(60000));
}
Bom, esse é o artigo de abertura do ano. Simples, mas aguardem grandes projetos iniciados em breve!
Revisão: Ricardo Amaral de Andrade
Inscreva-se no nosso canal Manual do Maker no YouTube.
Também estamos no Instagram.
Autor do blog "Do bit Ao Byte / Manual do Maker".
Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.