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.

Dodaj komentarz

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

Rozwiąż równanie: *