Using WiFi in the Raspberry Pi Pico (Part 5)
In this post we will see how to access a REST API with the Raspberry Pi Pico W, using the SDK C/C++ and MicroPython.
An example of a call to a RESP API, using Postman |
Basically, a REST API is uses an HTTP method (like GET and POST) to access and manipulate "resources".
GET http:viacep.com.br/ws/{cep}/json/
where {cep} is the 8 digit postcode we want to consult.
The lwIP library have an HTTP_ client module for HTTP access. This module have two methods: httpc_get_file() and httpc_get_file_dns(). The "get_file" part may be confusing, originally HTTP was only used to access files in the web server.
It may also seem that the second method only resolves the server name through DNS and then does the same thing as the first method, but there is an import difference: the second method puts the server name in the HTTP headers. It is very common for a web server (with a single IP) answer requests that come to different server names and use the name in the header to figure out what it needs to do.
Now all we have to do is the old callback programming. The signature of httpc_get_file_dns() is:
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)
Where httpc_connection_t contains:
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;
So there are three callbacks involved:
- recv_fn is where we get the data
- result_fn is where we get the final result (but not the data)
- headers_done_fn is where we get the headers in the response
#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]; // called at the end of the transfer void got_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err) { printf("\nTransfer fineshed\n"); printf("result=%d\n", httpc_result); printf("http code=%d\n", srv_res); } // called when we get the headers err_t got_headers(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len) { printf("\nHeaders received\n"); printf("Content length=%d\n", content_len); printf("Header length %d\n", hdr_len); pbuf_copy_partial(hdr, myBuff, hdr_len, 0); myBuff[hdr_len] = 0; printf("Headers: \n"); printf("%s", myBuff); printf("\nContent body:\n"); return ERR_OK; } // called when we get the data err_t got_data(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; } // Main program int main() { // Start stdio and wait USB connected stdio_init_all(); while (!stdio_usb_connected()) { sleep_ms(100); } printf("\nREST API Test\n"); // Start CYW43 and select country if (cyw43_arch_init_with_country(CYW43_COUNTRY_BRAZIL)) { printf("failed to initialise\n"); return 1; } // Start WiFi in Station Mode cyw43_arch_enable_sta_mode(); // Try to connect if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 10000)) { printf("Error connecting WiFi\n"); return 1; } char sIP[] = "xxx.xxx.xxx.xxx"; strcpy (sIP, ip4addr_ntoa(netif_ip4_addr(netif_list))); printf ("Connected, IP %s\n", sIP); // Access the API httpc_connection_t settings; settings.result_fn = got_result; settings.headers_done_fn = got_headers; cyw43_arch_lwip_begin(); err_t err = httpc_get_file_dns( "viacep.com.br", 80, "/ws/01001000/json/", &settings, got_data, NULL, NULL ); cyw43_arch_lwip_end(); printf("Immediate Status: %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; }
import rp2 import network import time import urequests import json film = 1 url = 'https://swapi.dev/api/films/{0}/'.format(film) TIMEOUT = 10 wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect('essid', 'password') print ('Connecting...') timeout = time.ticks_add(time.ticks_ms(), TIMEOUT*1000) while not wlan.isconnected() and wlan.status() >= 0 and \ time.ticks_diff(timeout, time.ticks_ms()) > 0: time.sleep(0.2) if wlan.isconnected(): print ('Connected') print ('Querying film {0}'.format(film)) r = urequests.get(url) if r.status_code == 200: response = json.loads(r.text) print ('Episode {0}: {1}'.format(response['episode_id'], response['title'])) print (response['opening_crawl']) else: print ('ERROR: {0}'.format(r.status_code)); r.close() else: print ('ERROR: Could not connect the WiFi!') wlan.active(False)
Comments
Post a Comment