Dwa lata temu pisałem o pomiarze temperatury i wilgotności z użyciem ESP8266 i czujnika AM2301 (DHT-21). Korzystając z okazji, że jeden z czujników przestał działać, postanowiłem opracować nowszą, bardziej kompaktową wersję i opisać cały proces od podstaw.
Koncepcja
Sercem urządzenia będzie oczywiście ESP8266, jednak nie w wersji ESP-01, jak poprzednio, ale WeMos D1 mini, bo jest mały i ma na pokładzie stabilizator napięcia i złącze zasilania w standardzie microUSB. Dzięki temu urządzenie będzie można zasilić zwykłą ładowarką (zasilaczem) do telefonu. Czujnikiem temperatury i wilgotności będzie, jak poprzednio, AM2301. Jest od dość duży, bo to obudowana wersja DHT-21, ale takie akurat mam, a poza tym i tak trzeba by odsunąć w obudowie czujnik temperatury od ESP i układu zasilania, żeby nie wpływały na pomiar temperatury. Oba elementy połączy obudowa, wydrukowana z filamentu PET-G, którą zaprojektujemy w programie OpenSCAD. Oprogramownie powstanie w języku LUA (a właściwie zmodyfikujemy to, które powstało poprzednim razem), chociaż użycie Arduino IDE także było kuszące.
Elekronika
Połączenie elementów będzie banalnie proste. Bogactwo wejść D1 mini nie będzie potrzebne, użyjemy tylko jednego wejścia/wyjścia cyfrowego. Wystarczyłby tu jeszcze mniejszy ESP-01, ale D1 ma zintegrowany układ zasilania napięciem 5V, co przesądza o jego użyciu. Dzięki temu unikniemy tworzenia dodatkowej płytki drukowanej, a samo urządzenie będzie mniejsze.
AM2301 ma trzy przewody. Czerwony połączymy z pinem 3V3 na D1 mini, który dostarczy napięcie 3,3V. Czarny to oczywiście masa, która zostanie przylutowana do „G”. Żółty przewód sygnałowy trafi do wejścia D1 (na D1, rzecz jasna). I to wszystko. 3 przewody do przylutowania. Nic więcej. Istotne jedynie, żeby zrobić to od właściwej strony, aby umożliwić wsunięcie układu do obudowy, która będzie dość ciasna.
Przygotowanie układu
Ponieważ minęło trochę czasu, odkąd opisywałem ostatnio programowanie ESP8266, a pewne drobiazgi się zmieniły, opiszę wszystko w skrócie od początku. Przede wszystkim na stronie projektu NodeMcu nie ma już gotowych, skompilowanych obrazów do wgrania do ESP8266. Spowodowane jest to faktem, że firmware dość mocno rozrosło się o dodatkowe moduły, a nikt nie używa ich wszystkich. Przygotowuje się więc firmware możliwie lekkie, zawierające tylko to co potrzebne.
Na szczęście nic nie trzeba kompilować samemu, istnieje serwis, który to zrobi za nas. To co jest od nas wymagane, to jedynie zaznaczenie potrzebnych modułów i podanie maila, na który zostanie wysłane powiadomienie, gdy firmware będzie gotowe do pobrania. Zaznaczamy więc moduły, tylko trochę na wyrost: DHT, end user setup, file, GPIO, HTTP, net, node, 1-Wire, timer, UART, WiFi.
Po krótkim okresie powinien przyjść e-mail z linkiem do ściągnięcia firmware w dwóch wersjach. Nas będzie interesowała „float”, bo odczyty z czujnika będą od razu jako liczba wymierna, a nie całkowita.
Wgranie firmware jest bardzo proste. Używamy, jak poprzednio esptool, a konkretnie wycinka umożliwiającego flashowanie układu ESP. Przed podłączeniem D1 mini, zwieramy dwa jego złącza – D3 i G, żeby wprowadzić układ w tryb programowia, podłączamy przez USB do komputera i wydajemy komendę (w moim przypadku pod Linuksem):
esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash 0x00000 nodemcu-master-11-modules-2017-01-31-11-14-50-float.bin
Po niezbyt długiej chwili układ jest gotowy do działania. Po jego restarcie można połączyć się z nim w trybie interaktywnym używając dowolnego terminala, np.
screen /dev/ttyUSB0
Pozostały do zrobienia dwie rzeczy – obudowa i oprogramowanie.
Obudowa
Projekt obudowy tradycyjnie wykonamy w bezpłatnym programie OpenSCAD. Projektowanie w nim jest bardzo proste dla osób, które programują, ponieważ polega ono na napisaniu czegoś w rodzaju programu, tworzącego bryłę do wydruku. OpenSCAD jest w stanie wyeksportować pliki STL, które z kolei są akceptowane przez slicery, czyli programy przygotowujące wydruki 3d.
Obudowa została wydrukowana z transparentnego PETG, chociaż poważnie rozważałem też czarny PLA, z racji koloru czujnika wilgotności. Oczywiście pliki z projektem obudowy, jak zwykle, są dostępne publicznie.
Program
Program jest prawie gotowy, bo powstał dwa lata temu, jednak zaszły pewne zmiany. Jędną z nich jest włączenie obsługi czujnika DHT jako moduł firmware, nie ma więc potrzeby wgrywania dodatkowego pliku. Zamiast tego, po prostu użyjemy funkcji dht.read.
Druga zmiana dotyczy konfiguracji urządzenia. Do tej pory zaszywałem dane do logowania do sieci WiFi w kodzie, co jest zdecydowanie niepraktyczne. Zamiast tego skorzystamy z modułu end user setup, który także został wkompilowany w firmware. Co prawda nie jest on idealny, a jego funkcjonalność pozostawia trochę do życzenia, jednak póki co go użyjemy.
Jak to działa? Gdy przez 10 sekund od startu urządzenia, nie uda się połączyć z siecią wifi, tworzony jest access point, który działa przez 3 minuty. W tym czasie można się połączyć ze stroną konfiguracyjną (wpisując dowolny adres domenowy lub 192.168.4.1). Pozwala ona na wpisanie nowych danych do logowania do sieci WiFi. Dane oczywiście są zapamiętywane i po restarcie połączenie także nastąpi do wprowadzonej w ten sposób sieci.
Sieć konfiguracyjna jest otwarta. Zapewne lepiej byłoby ją zabezpieczyć. Teoretycznie moduł na to pozwala, jednak przez błąd w obecnej wersji nie do końca to działa jak trzeba. Oczywiście pewnie wkrótce przestanie to być problemem.
Przejdźmy więc do kodu.
-- dla nodemcu w wersji float local dhtpin=1 local timeout=60000 local tmrtimeout=6 local lasttemp = -100 local lasthum = -100 local numreq=0; local connwait=false; local numerr=0; wifi.setmode(wifi.STATION) print(wifi.sta.status()) local disableenduser=function() --wyłączamy konfigurację i restart print("stop enduser setup") enduser_setup.stop() -- tmr.alarm(5, 2000, 0, node.restart) -- restartujemy, albo nie, zależnie kto co woli end local checkwifi=function() --sprawdzamy połączenie wifi, jak nie ma to wystawiamy AP do konfiguracji na 120 sekund print("check wifi") if wifi.sta.status() ~= 5 then print("start enduser setup") enduser_setup.start() tmr.alarm(5, 180000, 0, disableenduser) end end tmr.alarm(5, 10000, 0, checkwifi) local httpsend=function(txt) if wifi.sta.status() ~= 5 then numerr=numerr+1 elseif connwait == true then numerr=numerr+1 else connwait=true tmr.alarm(tmrtimeout, timeout, 0, function() conn:close() connwait=false numerr=numerr+1 end) conn=net.createConnection(net.TCP, 0) conn:on("receive", function(conn, pl) print(pl) print("receive\n") end) conn:on("sent", function(conn) print("sent\n") numreq=numreq+1 end) conn:on("connection", function(conn) print("connection\n") conn:send("GET /sensor/esp.php?i="..node.chipid().."&he="..node.heap().."&rq="..numreq..txt.." HTTP/1.0\nHost: www.luksoft.org\n\n") end) conn:on("disconnection", function(conn) print("disconnection\n") conn:close() tmr.stop(tmrtimeout) connwait=false end) conn:connect(80,"www.mojserwer.com") end end local checknode=function() if numerr>20 then node.restart() end if node.heap()
Pochylonym tekstem oznaczony został nowy fragment, odpowiedzialny za konfigurację urządzenia.
Program wgrywamy komendą:
nodemcu-uploader.py --port /dev/ttyUSB0 upload init.lua
korzystając z projektu nodemcu-uploader. Oczywiście nic nie stoi też na przeszkodzie, żeby użyć innych narzędzi.
Podsumowanie
Ostatecznie podstało całkiem zgrabne urządzenie. Może nie miniaturowe, bo sam AM2301 nie jest miniaturowy, ale małe, zwarte. Dobrze też, że zasilane jest przez popularne złącze microUSB. Pora przetestować je w praktyce.