Vamos agora acessar uma API REST com a Raspberry Pi Pico, usando o SDK C/C++.
Exemplo de chamada a uma API REST usando o Postman |
Simplificando bastante, uma API REST é (tipicamente) o uso dos métodos HTTP (como GET e POST) para o acesso e manipulação de "recursos". Como exemplo vamos usar uma API de consulta a CEPs. O método que vamos chamar permite obter informações sobre um CEP:
GET http:viacep.com.br/ws/{cep}/json/
onde {cep} é o cep a consultar (oito digitos sem separadores).
A biblioteca lwIP possui um módulo HTTP client para realizar acessos HTTP. Este módulo possui dois métodos: httpc_get_file() e httpc_get_file_dns(). Pode trazer um pouco de confusão o fato dos métodos se chamarem "get file", originalmente o objetivo do HTTP era acessar arquivos de um servidor web.De resto temos a velha brincadeira de callbacks. A assinatura de httpc_get_file_dns() é:
err_t httpc_get_file_dns ( const char *server_name, u16_t port, const char *uri, const httpc_connection_t *settings, altcp_recv_fn recv_fn, void *callback_arg, httpc_state_t **connection)
Onde httpc_connection_t contém
typedef struct _httpc_connection { ip_addr_t proxy_addr; u16_t proxy_port; u8_t use_proxy; /* this callback is called when the transfer is finished (or aborted) */ httpc_result_fn result_fn; /* this callback is called after receiving the http headers It can abort the connection by returning != ERR_OK */ httpc_headers_done_fn headers_done_fn; } httpc_connection_t;
Temos, portanto, três callbacks envolvidos:
- recv_fn é onde recebemos os dados
- result_fn é onde se recebe somente o resultado final (sem os dados)
- headers_done_fn é onde se recebe os cabeçalhos da resposta
Visto tudo isso podemos fazer um exemplo simples, consultando o CEP 01001000 e enviando o resultado para stdio:
#include <stdio.h> #include <string.h> #include <time.h> #include "pico/stdlib.h" #include "pico/cyw43_arch.h" #include "hardware/i2c.h" #include "lwip/pbuf.h" #include "lwip/tcp.h" #include "lwip/apps/http_client.h" #include "secret.h" char myBuff[2000]; // chamada quando termina a transferência void recebeu_resultado(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err) { printf("\nTransferencia finalizada\n"); printf("resultado=%d\n", httpc_result); printf("código http=%d\n", srv_res); } // chamada quando recebeu os cabeçalhos err_t recebeu_headers(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len) { printf("\nRecebeu cabecalhos\n"); printf("Tamanho dos dados=%d\n", content_len); printf("Tamanho dos cabeçalhos %d\n", hdr_len); pbuf_copy_partial(hdr, myBuff, hdr_len, 0); myBuff[hdr_len] = 0; printf("Cabeçalhos: \n"); printf("%s", myBuff); printf("\nCorpo da resposta:\n"); return ERR_OK; } // chamada quando recebeu dados err_t recebeu_dados(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err) { pbuf_copy_partial(p, myBuff, p->tot_len, 0); myBuff[p->tot_len] = 0; printf("%s", myBuff); return ERR_OK; } // Programa Principal int main() { // Inicia stdio e aguarda conectar USB stdio_init_all(); while (!stdio_usb_connected()) { sleep_ms(100); } printf("\nTeste API REST\n"); // Inicia CYW43 e defeine o pais if (cyw43_arch_init_with_country(CYW43_COUNTRY_BRAZIL)) { printf("failed to initialise\n"); return 1; } // Inicia WiFi no modo Station cyw43_arch_enable_sta_mode(); // Tenta conectar if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 10000)) { printf("Erro ao conectar WiFi\n"); return 1; } char sIP[] = "xxx.xxx.xxx.xxx"; strcpy (sIP, ip4addr_ntoa(netif_ip4_addr(netif_list))); printf ("Conectado, IP %s\n", sIP); // Acessa a API httpc_connection_t settings; settings.result_fn = recebeu_resultado; settings.headers_done_fn = recebeu_headers; cyw43_arch_lwip_begin(); err_t err = httpc_get_file_dns( "viacep.com.br", 80, "/ws/01001000/json/", &settings, recebeu_dados, NULL, NULL ); cyw43_arch_lwip_end(); printf("Status imediato: %d \n", err); while (true){ #if PICO_CYW43_ARCH_POLL cyw43_arch_poll(); sleep_ms(1); #else sleep_ms(10); #endif } cyw43_arch_deinit(); return 0; }
O resultado obtido é:
Teste API REST Conectado, IP 192.168.15.60 Status imediato: 0 Recebeu cabecalhos Tamanho dos dados=-1 Tamanho dos cabeçalhos 494 Cabeçalhos: HTTP/1.1 200 OK Server: nginx/1.22.0 Date: Tue, 08 Nov 2022 23:16:17 GMT Content-Type: application/json; charset=utf-8 Transfer-Encoding: chunked Connection: close Expires: Wed, 09 Nov 2022 00:16:17 GMT Cache-Control: max-age=3600 Pragma: public Cache-Control: public Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET Access-Control-Allow-Headers: Content-Type, X-Request-With, X-Requested-By Access-Control-Allow-Credentials: true Access-Control-Max-Age: 86400 Corpo da resposta: e0 { "cep": "01001-000", "logradouro": "Praça da Sé", "complemento": "lado ímpar", "bairro": "Sé", "localidade": "São Paulo", "uf": "SP", "ibge": "3550308", "gia": "1004", "ddd": "11", "siafi": "7107" } 0 Transferencia finalizada resultado=0 código http=200
O código acima é bastante grosseiro e limitado. A maioria das APIs utilizam https, o que requer o estabelecimento de uma conexão criptografada (o que ainda preciso estudar como fazer). O módulo HTTP Client não suporta redirecionamento (o que quebrou o primeiro exemplo que eu tentei).
Quem estiver curioso com como é acessar uma API REST usando MicroPython, fique de olho no blog Maker Hero onde vai ser publicado um artigo meu sobre os primeiros passos com a Pi Pico. De um modo geral é bem mais simples (inclusive usar https, porém tive problemas com a acentuação na resposta da API que estou usando aqui);
No próximo (e talvez último) post desta série vamos ver como fazer um webserver rudimentar, permitindo interagir com a Pico W através de um browser.
Um comentário:
Daniel, gostei dos seus projetos em raspberry. Estou fazendo um curso no IFCE, aqui em Fortaleza-Ce., de sistemas embarcados, utilizando a Raspberry Pi Pico W, em linguagem de programação C (visual code). Estou pensando em fazer um projeto para entregar no final do curso que: vou utilizar um mEedidor de temperatura DH22, medir a temperatura, a aumidade, me conectar na internet via Wifi da placa, conectar no e-mail e enviar menssagem para os responsáveis, quando a temperarura e a umidade estiverem fora dos padrões de normalidade. Pergunto você tem alguma coisa que poderia me ajudar a implementar tal projeto?
Menu nome é: Raimu do Eumazio Rocha
E-mail: rocharaimun@gmail.com
Postar um comentário