Dzisiaj wykonamy prosty wyświetlacz pogody w oparciu o ESP32. Pogoda będzie pobierana z internetu dzięki użyciu jednej z wielu darmowych usług typu "weather API". Projekt nie będzie używać żadnych czujników typu DHT11 czy BMP280, wszystkie informacje będą pobierane z sieci poprzez proste zapytanie HTTP. Nauczymy się też tutaj korzystać z kluczy API przykładowej usługi oraz przetwarzać odpowiedź w formacie JSON.
Ten temat stanowi kontynuację serii o ESP32-2432S028R:
ESP32 i wyświetlacz dotykowy - tutorial - część 1 - jak programować? Podstawy
ESP32 i wyświetlacz dotykowy - część 2 - jak rysować piksele, linie, kształty, kwestia wydajności
ESP32 i wyświetlacz dotykowy - tutorial cz. 3 - interakcje, gry i zabawy
Nie zdecydowałem się tutaj jeszcze wprowadzać LVGL, LVGL pojawi się w następnej części.
Krok 1 - wywiad w sieci
Najpierw musimy zdecydować się której z dostępnych za darmo usług użyjemy. Nie powinno być tutaj problemu. Wiele z tych usług ma nałożone pewne mniej lub bardziej restrykcyjne limity. Przede wszystkim wymagane jest utworzenie konta, które dopiero wtedy zapewnia nam dostęp do tzw. "klucza API". API to tutaj jest "application programming interface", czyli to, co oferuje dla nas dana aplikacja (to, co jest dostępne z zewnątrz, interfejs).
Dodatkowo nawet po zarejestrowaniu się pewnie będą jakieś limity, typu maksymalna dozwolona ilość zapytań do API na np. godzinę czasu, ale to nie jest dla nas problem - my nie tworzymy komercyjnego produktu, tylko małe demko na własny użytek.
A więc szukamy "weather API" w sieci i przeglądamy oferty...
Moją uwagę przykuło: https://openweathermap.org
Ich oferta jest naprawdę bogata, jest też oczywiście płatne API:
https://openweathermap.org/api
ale nas interesuje darmowe. Konkretnie wybrałem API "CurrentWeather", opisane tutaj:
https://openweathermap.org/current
W dokumentacji znajduje się oczekiwany format zapytania:
https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={API key}
jak również i przykładowa odpowiedź:
Kod: JSON
A więc wystarczy podać szerokość i długość geograficzną (wraz z naszym kluczem API) i już wiemy jaka jest pogoda. Można to też podpiąć do GPS, ale w tym temacie zrealizuje zapytanie "na sztywno" oraz wyświetlimy jego wynik.
Krok 2 - Rejestracja
Zakładamy zatem konto na openweathermap i wedle instrukcji z tej strony dostajemy klucz API:
Nasz klucz będzie widoczny w API Keys, po chwili powinien mieć status "Active", lecz to zwodnicze - o tym za chwilę.
Skoro mamy klucz, to pora wysłać HTTP GET... format argumentów i odpowiedzi znamy już z dokumentacji
Krok 3 - Wysyłanie HTTP GET
Przykładów wysyłania GET w sieci jest mnóstwo. Na PlatformIO mamy do tego gotowe biblioteki. Po naszej stronie leży tylko złożenie URL zapytania z naszego klucza i poszukiwanej lokacji. Starczy do tego sprintf, a może lepiej snprintf (sprintf dodatkowo przyjmujący rozmiar docelowego bufora):
Kod: C / C++
Powyższy kod tylko łączy się z WiFi i wysyła żądanie HTTP z naszymi danymi. Nasz klucz jest uwzględniony. Czy zadziała? Co otrzymujemy?
Connecting to WiFi...
Connected to WiFi
{"cod":401, "message": "Invalid API key. Please see https://openweathermap.org/faq#error401 for more info."}
Niespodzianka, nie działa.
Teraz pytanie, co jest nie tak? Tutaj pomaga znajomość tematu.
Na próżno szukać jest błędu u nas w kodzie.
Po prostu klucz API, mimo iż jest oznaczony jako aktywny, potrzebuje nieco czasu by się "rozpropagować" na serwerach/CDN usługodawcy, więc musimy po prostu poczekać. Gdy robiłem tego typu projekt pierwszy raz, to mocno się zdziwiłem, szukając błędu u siebie a potem dowiadując się, że warto poczekać.
Dopiero po jakimś czasie poprawnie pobierze się dla nas JSON:
Sukces!
Krok 4 - Arduino JSON
Teraz trzeba jakoś przetworzyć ten tekst w formacie JSON. Nie będziemy przecież ręcznie pisali parsera respektującego nawiasy, przecinki i zagnieżdżone obiekty. Mamy do tego gotowca - biblioteka ArduinoJSON, do pobrania przez PlatformIO:
Samą instalację zostawiam bez większego komentarza, pokazywałem to szczegółowo kilka razy.
Teraz trzeba nasz odebrany tekst (String) zamienić na wygodną w przetwarzaniu reprezentację JSON.
Używamy klasy DynamicJsonDocument, czyli klasy korzystającej z pamięci na stercie (heap), ale szczegóły jego działania pominiemy. Najważniejsze, że pozwala on dobrać się nam dynamicznie do dowolnego obiektu i pola odebranego tekstu JSON, chociażby do "message":
Kod: C / C++
Krok 5 - Przerzucenie danych na ekran
Teraz wystarczy tylko umiejętnie pobrać dane z obiektów wczytanych z JSON.
Rozważmy przykładową odpowiedź:
Kod: JSON
Jak dostać się do opisu "description" z "weather"?
Najpierw musimy dostać się do tablicy "weather", potem do pierwszego elementu z tej tablicy, a potem do jego pola "description". W kodzie wygląda to tak:
Kod: C / C++
Analogicznie np. dla pól temperatura i wilgotność:
Kod: C / C++
Zostaje wyświetlić je na ekranie - ale raczej znamy już tft.printf?
Chyba nie ma co tego omawiać, oto kompletne demko:
Kod: C / C++
Jeszcze podejrzyjmy jakiś JSON nie z przykładów dokumentacji, lecz pobrany przeze mnie w momencie pisania kodu. Oto fragment logu z konsoli:
{"coord":{"lon":21.0118,"lat":52.2298},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"base":"stations","main":{"temp":25.39,"feels_like":25.11,"temp_min":22.44,"temp_max":27.19,"pressure":1010,"humidity":43},"visibility":10000,"wind":{"speed":3.09,"deg":230},"clouds":{"all":40},"dt":1716205773,"sys":{"type":2,"id":2032856,"country":"PL","sunrise":1716172416,"sunset":1716229901},"timezone":7200,"id":756135,"name":"Warsaw","cod":200}
Weather: scattered clouds
I porównajmy z wynikiem z Google:
Mniej więcej zgadza się. System działa!
Podsumowanie
Tak można pobrać informacje o bieżącej pogodzie z Internetu. W podobny sposób możemy pobierać też różne inne informacje, o ile tylko znajdziemy odpowiednie API. Oczywiście zasady używanego API należy respektować - nie wolno przekraczać narzuconych nam limitów. W naszym programie też trzeba się do tego stosować - jakbyśmy mieli kontynuować ten projekt, to trzeba by zwiększyć delay w pętli. Szczegóły są w dokumentacji API.
W przypadku poważniejszych zastosowań należy wykupić płatne API - chociażby liczone od ilości zapytań. Wtedy zapłacimy tyle, ile zużyjemy. To z pewnością się przyda do większych i komercyjnych zastosowań.
Podobne API też oferują np. mapy - chociażby pobór informacji o mapie w danym punkcie współrzędnych (jakie to miasto, ulica, itd).
Zapraszam do kontynuacji projektu, podstawę kodu macie ode mnie, może by zmodyfikować wyświetlanie by pokazywać pogodę w postaci grafik? Ikonka chmurek, słońca? Może animacja termometru? Jak myślicie?
Zapraszam do komentowania, czy ktoś tworzył tego typu odtwórczą "stację pogody"?
PS: Największą pułapką w takich projektach chyba jest to, że na aktywację klucza do API czasem się troszkę czeka i warto być cierpliwym, zamiast szukać nieistniejącego błędu w kodzie..
Fajne? Ranking DIY Pomogłem? Kup mi kawę.