Zajmiemy się teraz protokołem http, ale tylko od strony klienta. Będziemy wysyłać zapytania do serwerów http i skupię się tutaj tylko na dwóch konkretnych rodzajach zapytań http; GET, oraz POST.
Protokół http, tak jak logika jego działania jest chyba najprostszy do opanowania i często używany w projektach hobbystycznych. Za jego pomocą bardzo łatwo stworzymy system wymiany danych między urządzeniami np. systemu smart home. Do tego, zapytania możemy kierować także do publicznych serwerów http i pobierać zawartość stron internetowych, pliki, czy strumienie danych (audio/wideo).
ESP-IDF GET Request
Zapytanie GET jest najprostszym i najpowszechniejszym typem zapytania http. Wykonujemy go zawsze, gdy przechodzimy na jakąś stronę internetową. Efektem jego wykonania jest otrzymanie danych od serwera http. W zapytaniu typu GET możemy zagnieżdżać argumenty, które służyć mogą do manewrowania po witrynie internetowej, a nawet możemy w ten sposób przekazywać dane do serwera http, chociaż do tego celu lepsze będzie zapytanie POST.
Tak wygląda przekazywanie argumentów w zapytaniu GET:
http://192.168.0.100/index.php?arg1=abc&arg2=bca – w ten sposób przekazujemy serwerowi dwa argumnenty: „arg1″:”abc” i „arg2″:”bca”.
Client HTTP inicjalizacja
Właściwie, inicjalizacja to za dużo powiedziane, bo jedyne co tutaj musimy zrobić to zdefiniować strukturę, w której określimy preferowane przez nas opcje. Przed tym załączyć należy bibliotekę odpowiedzialną za obsługę klienta http – „esp_http_client.h”.
#include "esp_http_client.h" static void get_req(void) { esp_http_client_config_t req_config = { .url = "http://piteusz.ovh/blog.php", .method = HTTP_METHOD_GET, .event_handler = get_handler }; }
Do poprawnego wykonania zapytania wystarczy taka konfiguracja. Określam tutaj kolejno url, pod jaki słane jest zapytanie, typ metody (zapytania), i event handler, czyli nazwę funkcji obsługującej eventy.
Jedyne co zostało to dodanie trzech funkcji.
static void get_req(void) { esp_http_client_config_t req_config = { .url = "http://piteusz.ovh/blog.php", .method = HTTP_METHOD_GET, .event_handler = get_handler }; esp_http_client_handle_t client = esp_http_client_init(&req_config); esp_http_client_perform(client); esp_http_client_cleanup(client); }
Pierwsza linia to zdefiniowanie zmiennej, która będzie uchwytem naszej sesji, jej przypisujemy wywołanie funkcji inicjalizującej clienta.
Następne polecenie wykonuje określone zapytanie, a trzecie przerywa połączenie i czyści zaalokowaną na potrzebę instancji klienta http pamięć.
Zdefiniować można znacznie więcej opcji. Możemy na przykład określić hosta do jakiego będziemy się odwoływać i podawać tylko ścieżkę zamiast definiowania całego urla. Jest też opcja zmiany wartości user-agent itp. Wszystkie zmienne struktury esp_http_client_config_t znajdziesz w linku: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_http_client.html#_CPPv424esp_http_client_config_t
Dane są przekazywane poprzez event, a więc napiszmy funkcję, która będzie je obsługiwać.
static void get_handler(esp_http_client_event_handle_t event) { switch (event->event_id) { case HTTP_EVENT_ON_DATA: printf("%.*s", event->data_len, (char*)event->data); break; default: break; } }
Ta nasza obsługuje tylko jeden event HTTP_EVENT_ON_DATA, czyli otrzymanie danych, jeżeli takie otrzyma – wyświetla je w terminalu. Nic jednak nie stoi na przeszkodzie by otrzymane dane przeskrapować i wydobyć z nich istotne dla nas informacje.
Makrodefinicje pozostałych event’ów, oczywiście w dokumentacji: https://docs.espressif.com/projects/esp-idf/en/v4.2-beta1/esp32/api-reference/protocols/esp_http_client.html#_CPPv426esp_http_client_event_id_t
ESP-IDF POST Request
Zapytania typu POST są używane gdy chcemy wysłać większą ilość danych, bądź dane mają być ukryte. W przypadku zapytania GET, wszystkie przekazywane dane zawarte są w wywoływanym URL’u. Zapytań POST wykorzystuje się chociażby do logowania w większości serwisów.
Protokół http jest nieszyfrowany, a więc i tak da się podejrzeć przesyłane do serwera dane.
By zobrazować wykonanie zapytania typu POST, postawiłem na moim komputerze serwer http, który zwróci nam przekazywane przez esp dane. Kod php wygląda następująco.
<?php if ($_SERVER["REQUEST_METHOD"] === "POST") { echo "Wykonales zapytanie POST"; $data = json_decode(file_get_contents("php://input"), true); print_r($data); echo $data["dane"]; } else echo "Wykonales zapytanie GET."; ?>
W kodzie programu mikrokontrolera w zasadzie zmienić musimy tylko nieznacznie funckję wykonującą zapytanie.
static void post_req(void) { esp_http_client_config_t req_config = { .url = "http://192.168.0.190", .method = HTTP_METHOD_POST, .event_handler = get_handler }; esp_http_client_handle_t client = esp_http_client_init(&req_config); const char *dane = "{\"dane\":{\"czujnik1\":"243\",\"czujnik2\":\"20\"}}"; esp_http_client_set_post_field(client, dane, strlen(dane)); esp_http_client_set_header(client, "Content-Type", "application/json"); esp_http_client_perform(client); esp_http_client_cleanup(client); }
Zmieniłem url na adres IP mojego komputera, oraz typ metody na POST. Dodałem też ciąg znaków, który jest json’owym słownikiem, a także dwie funkcje – pierwsza załącza nasz ciąg znaków jako przesyłane dane, a druga służy do ustawiania nagłówków http.
Handler zostawiłem taki sam, nawet nie zmieniam zawartości jego funkcji. Taki jest efekt wywołania programu:
Dane tutaj są wysyłane w standardzie json. Dzięki temu po stronie serwera http bardzo łatwo będziemy mogli wyciągać istotne dla nas wartości.