logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

ESP32 i wyświetlacz dotykowy - tutorial cz. 4 - pogoda z internetu, API, JSON

p.kaczmarek2 20 Lip 2024 14:01 2307 2
REKLAMA
  • Wyświetlacz z informacjami o pogodzie
    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
    Zaloguj się, aby zobaczyć kod

    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:
    Zrzut ekranu strony OpenWeather z komunikatem
    Nasz klucz będzie widoczny w API Keys, po chwili powinien mieć status "Active", lecz to zwodnicze - o tym za chwilę.
    Strona zarządzania kluczami API na OpenWeather
    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++
    Zaloguj się, aby zobaczyć kod

    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:
    Zrzut ekranu z terminala pokazujący dane pogodowe w formacie 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:
    Interfejs PlatformIO z biblioteką ArduinoJson
    Zrzut ekranu z dokumentacją biblioteki ArduinoJson
    Dodawanie zależności projektowej w 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++
    Zaloguj się, aby zobaczyć kod


    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
    Zaloguj się, aby zobaczyć kod

    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++
    Zaloguj się, aby zobaczyć kod

    Analogicznie np. dla pól temperatura i wilgotność:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Zostaje wyświetlić je na ekranie - ale raczej znamy już tft.printf?

    Chyba nie ma co tego omawiać, oto kompletne demko:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    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
    

    Wyświetlacz dotykowy ESP32 pokazujący pogodę
    I porównajmy z wynikiem z Google:
    Zrzut ekranu prognozy pogody dla Warszawy w Google, pokazujący aktualną temperaturę 26°C, częściowe zachmurzenie oraz prognozę na następne dni.
    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ę.
    O autorze
    p.kaczmarek2
    Moderator Smart Home
    Offline 
  • REKLAMA
  • #2 21164624
    Erbit
    Poziom 34  
    p.kaczmarek2 napisał:
    weather?lat={lat}&lon={lon}&appid={API key}


    Nie chcę szukać w dokumentacji... ;)

    Czy ja dobrze rozumiem, że za pomocą swojego klucza możemy sprawdzić pogodę w dowolnym miejscu na świecie (podając odpowiednie dane geograficzne)?
  • #3 21164637
    p.kaczmarek2
    Moderator Smart Home
    Tak, możesz sprawdzić dowolne miejsce. Klucz nie jest przypisany do danej lokalizacji oraz na etapie rejestracji w żaden sposób Twoja lokalizacja nie jest sprawdzana.

    Jedyne co Cię ogranicza, to limit zapytań, który można sprawdzić... w dokumentacji:
    Tabela z planami subskrypcyjnymi dla API pogodowego OpenWeatherMap.
    Link: https://openweathermap.org/full-price

    Więc jeśli chcesz się pobawić, to wystarczy darmowy klucz, ale jeśli już chcesz wykonać produkt to już zaczniesz przekraczać limity a wtedy:
    Komunikat o przekroczeniu limitu wywołań API z OpenWeatherMap.
    Pomogłem? Kup mi kawę.
REKLAMA