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