Kurs ESP8266 & MicroPython #7: JSON-y i stacja pogodowa z użyciem SSD1306 i DHT11

Tym razem ESP8266 zadziała jako samodzielne urządzenie, pobierające dane z Internetu i czujnika wilgotności i temperatury DHT11 oraz wyświetlające je na wyświetlaczu OLED zgodnym ze sterownikiem SSD1306. Powstanie z tego stacja pogodowa, która nie wymaga użycia czujników na zewnątrz domu. Dane dotyczące aktualnej pogody uzyskamy z OpenWeatherMap w postaci JSON-a. Finalny efekt zbliżony będzie do tego:

ESP8266 Weather Station

JSON
JSON, czyli JavaScript Object Notation to tekstowy format wymiany danych, łatwy do zrozumienia przez człowieka i z obsługą zaimplementowaną w wielu językach programowania, w tym – co interesuje nas najbardziej – przez Pythona. W tym formacie udostępniana jest prognoza pogody w serwisie OpenWeatherMap. Po zarejestrowaniu i utworzeniu klucza API, możemy otworzyć adres w formacie http://api.openweathermap.org/data/2.5/weather?units=metric&id=IdMiasta&appid=KluczAPI, aby zobaczyć udostępniany JSON (oczywiście podstawiając odpowiednie ID miasta i klucz API). Przydatne będą także strony, które przedstawiają JSON-y w bardziej przystępny sposób, jak na przykład ta.

JSON
Przykładowy JSON

Do obsługi JSON-a w postaci tekstowej służy metoda loads z modułu ujson. Używa się jej bardzo prosto: p = ujson.loads(json). Zwracanym typem jest zagnieżdżony słownik. Ale JSON-a najpierw należałoby uzyskać korzystając z modułu socket, co zajęłoby kilka linijek. Na nasze szczęście to wszystko można zrobić szybciej korzystając z modułu urequest, wówczas zagnieżdżony słownik uzyskamy wywołując tylko jedną linijkę:
p = urequests.get('http://api.openweathermap.org/data/2.5/weather?units=metric&id=IdMiasta&appid=KluczAPI').json()

Jak widać na obrazku, temperatura jest zagnieżdżona w main. Aby uzyskać ją z obiektu p należy wywołać temp = p['main']['temp']. Tak samo postępujemy, jeśli chcemy uzyskać inne wartości za wyjątkiem tych znajdujących się w weather, które jest tablicą. W tym przypadku wywołanie nieznacznie się różni i wygląda tak: p['weather'][0]['id'], ponieważ indeks tablicy jest liczbą, a nie ciągiem znakowym.

utime
w JSON-ie zawarta jest jeszcze między innymi informacja o wschodzie i zachodzie Słońca – czas podany jako tzw. Unix Timestamp, czyli ilość sekund, które upłynęły od 1 stycznia 1970 roku. Do konwersji takiej wartości na bardziej przystępny format można użyć funkcji localtime z modułu utime. Jest tylko jeden haczyk – jako „początku czasu” używa ona 1-go stycznia 2000 roku, więc konieczne jest odjęcie 946681200 sekund od wartości z JSON-a. Całe wywołanie wygląda tak:
sunrise = utime.localtime(p['sys']['sunrise'] - 946681200)
Zwracanym typem jest tuple, czyli w dużym skrócie nieedytowalna lista w formacie (rok, miesiąc, dzień, godziny, minuty, sekundy, dzień_tygodnia, dzień_roku), do której odwołujemy się tak, jak do elementów tablicy w C, czyli na przykład sunrise[0].

DHT11
DHT11 to kolejny po DS18B20 czujnik obsługiwany natywnie przez MicroPythona na ESP8266. Czujnik ten poza pomiarem temperatury pozwala jeszcze na pomiar wilgotności względnej powietrza. Również korzysta on z magistrali OneWire, choć tym razem obsługa jest nieco prostsza i zawrzeć ją można w kilku linijkach, bez konieczności używania timerów czy opóźnień.

1
2
3
4
5
import machine, dht
dh = dht.DHT11(machine.Pin(0))
dh.measure()
dh.temperature() #zwraca temperaturę w stopniach Celsjusza
dh.humidity() #zwraca wilgotność względną w procentach

Pomiary nie powinny być częstsze niż raz na sekundę. Przy zastosowaniu jako czujnik temperatury w domu można ograniczyć się do pomiaru raz na 30 minut, w końcu temperatura wewnątrz nie zmienia się zbyt szybko. Schemat podłączenia czujnika OneWire pokazywałem w poprzedniej lekcji, dlatego nie będę go powielał. Jeśli posiadasz ten czujnik w postaci modułu na PCB, na którym jest też rezystor, to jest to rezystor podciągający – możesz zatem połączyć linię danych bezpośrednio do ESP8266, bez dodatkowego podciągania.

SSD1306
Na koniec pozostała sprawa wyświetlenia pobranych danych na ekranie OLED. Poza podłączeniem zasilania 3.3V, pozostałe piny, tj. SCL (SCK) i SDA podłączamy odpowiednio do D1 i D2. Najpierw konfigurujemy wyświetlacz, wybierając piny oraz częstotliwość pracy magistrali I2C (która i tak nie wynosi 400 kHz, tylko maksymalnie około 170 kHz):

1
2
3
import machine
i2c = machine.I2C(scl=machine.Pin(5), sda=machine.Pin(4), freq=400000)
d = display(128, 64, i2c)

Po czym możemy zacząć wyświetlanie. Obsługiwane polecenia to:
d.fill(val) – wypełnia lub czyści ekran, w zależności od val (0 lub 1)
d.text('tekst', x, y) – wypisuje ciąg znaków na pozycji (x, y) – lewy górny róg
d.pixel(x, y, col) – wstawia piksel o kolorze col na pozycji (x,y)
d.scroll(dx, dy) – przesuwa obraz o (dx,dy)
d.show() – dopiero ta komenda powoduje odświeżenie ekranu i wyświetlenie zadanej ramki

Ponadto istnieją jeszcze polecenia, które nie wymagają odświeżenia ekranu po ich użyciu:
d.invert(val) – odwraca kolory jeśli val=1
d.contrast(val) – zmienia kontrast w zakresie od 0 do 255

Nie zalecam natomiast używania d.poweroff() – analogiczna funkcja poweron nie istnieje, więc sam możesz domyślić się (lub sprawdzić), czym to poskutkuje. Na koniec jeszcze jedna ważna uwaga – przed każdym wypisywaniem nowego tekstu ekran należy wyczyścić korzystając z fill, w przeciwnym wypadku znaki będą się pokrywać i będą nieczytelne.

Tym razem nie zamieszczam gotowego kodu, a jedynie dokładną instrukcję, jak wykorzystać NodeMCU z MicroPythonem jako stację pogodową. W razie problemów zachęcam do komentowania.

2 myśli na temat “Kurs ESP8266 & MicroPython #7: JSON-y i stacja pogodowa z użyciem SSD1306 i DHT11

  1. Witaj.

    Dobra i ciekawa inspiracja. Podpowiedz proszę jakbyś podszedł do tematu „termostat na esp32 bazujący na micropython”.

    Ja osobiście zakładam wykorzystać komunikację z esp32 via json (czyli musi być jakiś serwer www na micropython). Czyli przez json czytam aktualną temperaturę i tą samą drogą ustawiam temperaturę załączenia np. pieca CO.

    Czyli muszę wykorzystać nazwijmy to wielowątkowość (biblioteka uasyncio) wbudowaną w micropython.

    Jeden „wątek” (piszę w cudzysłowiu wątek gdyż defacto nie są to wątki sensu stricte) sprawdza temperaturę otoczenia i załącza piec przy zadanym parametrze a drugi „wątek” serwuje/pobiera komendy json.

    Co sądzisz? Jakbyś podszedł do tematu?

    P.S.
    Celowo pomijam wykorzystanie MQTT i chmurowego zarządzania kontrolerem gdyż uważam, że to może być co najwyżej wizualizacja a nie sterowanie czymś co musi być pewnym, działającym urządzeniem typu „embedded”.

    Pozdrawiam

    1. MQTT z QoS1 zapewni, że wiadomość dotrze co najmniej raz. Jest tam funkcja check_msg, która może sprawdzać, czy jest jakaś wiadomość w kolejce, a nie blokuje procesu aż do jej otrzymania, więc nie trzeba używać asynchroniczności. Generalnie udało mi się zrobić urządzenie na ESP8266 z Micropythonem, które działało bez większych przerw przez miesiąc, wysyłając 10 razy na sekundę dane przez MQTT. Wtedy problem utraty połączenia, o które pytałeś pod innym artykułem rozwiązywałem tak, że jeśli nie udało się wysłać wiadomości (wysyłanie w bloku try) n razy, to próbowałem się połączyć ponownie do brokera MQTT, a jeśli się nie udało, to wtedy próbowałem ponownie podłączyć się do sieci Wi-Fi.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Rozwiąż równanie: *