Ta strona używa ciasteczek (cookies), dzięki którym możliwe jest między innymi poprawne wyświetlanie elementów strony, zapamiętywanie sesji użytkowników. Dodatkowo na stronie znajduje się skrypt Google Analytics oraz PIWIK (statystyki oglądalności). Znajdują się również skrypty przycisków serwisów społecznościowych Facebook, Twitter i Google+ oraz YouTube, które również mogą zapisywać ciasteczka.

ESP8266 część 4

Mając zainstalowany firmware NodeMCU, możemy przejść do konfiguracji układu ESP8266 wykorzystując do tego celu biblioteki NodeMCU oraz język LUA. Jak wspominałem w trzecim poradniku, do pisania skryptów oraz ich wgrywania do ESP, będziemy korzystali z programu ESPlorer.

ESPlorer

Program po uruchomieniu wyszuka w systemie dostępne porty służące do komunikacji z peryferiami podpiętymi do komputera. Do nas będzie należało wybranie właściwego do obsługi posiadanego przez nas konwertera. W przypadku konwertera na układzie FTDI musi być on podpięty do USB aby port był aktywny, a co za tym idzie widoczny w programie. Przy korzystaniu z huba USB może się zdarzyć sytuacja że port nie będzie widoczny w programie ESPlorer pomimo podłączenia konwertera do USB. Wystarczy wtedy przepiąć kabel USB do innego wolnego gniazda, nacisnąć przycisk "Refresh" i port powinien się pojawić na liście. Po wybraniu właściwego portu, należy jeszcze ustawić prędkość komunikacji na 9600, jest to domyślna prędkość po wgraniu świeżego firmware'u, i naciskamy "Open".

Jeśli połączenie zostało nawiązane prawidłowo można zacząć wydawać polecenia do modułu korzystając z funkcji jakie są dostępne w bibliotekach NodeMCU. Kroki jakie trzeba wykonać podczas podstawowej konfiguracji ESP z zainstalowanym firmware NodeMCU, są praktycznie takie same jak przy użyciu komend AT. W tym wypadku również należy określić jaki tryb pracy modułu wybieramy, STA, AP lub STA-AP, połączyć się z wybraną siecią, ustalić IP, itd. Można te wszystkie parametry poustawiać wpisując komendy z bibliotek NodeMCU w linii poleceń. No ale nie po to instalowaliśmy firmware NodeMCU żeby za każdym razem ręcznie konfigurować moduł. NodeMCU daje nam możliwość korzystania z plików, które po wgraniu do pamięci układu będą odczytywane. Chcąc więc aby przy każdym restarcie modułu konfiguracja odbywała się automatycznie, należy utworzyć plik o nazwie init.lua. Standardowo podczas instalacji firmware'u plik ten nie jest tworzony w pamięci ESP8266. Musimy go sobie sami utworzyć i wgrać do ESP. Jak się można domyśleć po nazwie pliku, jest to plik inicjalizacyjny wykonywany zawsze przy starcie układu. Właśnie w tym pliku powinny znaleźć się komendy które chcemy wykonać od razu po starcie modułu. Można co prawda zapisać te polecenia w pliku o innej nazwie, ale i tak trzeba będzie utworzyć plik init.lua a w nim umieścić polecenie odczytujące dane z innego pliku. Oczywiście wielkość pliku/plików zależy od dostępnej pamięci w module z ESP.

Po uruchomieniu ESPlorera, po lewej stronie znajduje się edytor w którym wpisujemy kod programu który chcemy wgrać. Powyżej są ikony znane z edytorów tekstowych, poniżej natomiast przyciski służące do wgrywania "wsadu" do ESP. Oczywiście nie musimy pisać skryptu w ESPlorerze, można go napisać w dowolnym edytorze tekstowym. Ważne tylko aby zapisać go potem pod właściwą nazwą. Skupmy się jednak na ESPlorerze. W tym poradniku będę dzielił skrypty na pliki. Na początku nie musimy się martwić o ich nazwy. Po prostu piszemy kod skryptu, a jak chcemy przejść do nowego pliku to naciskamy ikonę "New file" i w nowym oknie wpisujemy nowy kod. Przykładowy plik init.lua może wyglądać tak:

wifi.setmode(wifi.STATION)
wifi.sta.config("nazwa sieci", "hasło do sieci")
wifi.sta.connect()

Pewnie każdy już się domyślił co polecenia z tego pliku robią, ale dla porządku wyjaśnię. Pierwsze ustawia tryb pracy modułu na STA, drugie przypisuje do wskazanej sieci, natomiast trzecie łączy moduł z siecią. Oczywiście jest to podstawowa konfiguracja. Można by ją bez problemu rozszerzyć o funkcje które np. resetowały by moduł w przypadku nie znalezienia wskazanej sieci, tak aby była podjęta kolejna próba połączenia się z siecią, albo np. włączenie diody jak wszystko OK.

Przejdźmy do konfigurowania modułu do pracy wykorzystując protokół TCP i UDP. Zaczynamy od pisania kodu który później zapiszemy w ESP jako plik init.lua. Może on wyglądać tak jak w przykładzie podanym powyżej, gdzie mamy tylko polecenia potrzebne do połączenia się siecią. W tym wypadku IP zostanie przydzielone automatycznie przez DHCP. Osobiście wolę jednak samemu przypisać IP do modułu, przynajmniej nie będzie problemu ze sprawdzaniem za każdym połączeniem jakie IP zostało nadane. Dlatego też należy dopisać jeszcze kilka linijek kodu, oprócz tych które znajdują się wyżej:

wifi.ap.dhcp.stop()
wifi.sta.setip({
  ip = "192.168.1.51",
  netmask = "255.255.255.0",
  gateway = "192.168.1.1"
})

Wyłączamy więc DHCP i ustawiamy stałe IP modułu. W przypadku komendy AT wystarczyło podać tylko adres IP jaki chcemy nadać modułowi, jednak teraz oprócz adresu IP musimy również podać maskę i bramę sieci. Każdy oczywiście musi wpisać takie parametry jakie ma w swojej sieci.

Skoro więc kod pliku init.lua już mamy, to teraz kolej na plik tcp.lua, naciskamy "New file" i w nowym oknie wpisujemy:

server=net.createServer(net.TCP)
server:listen(80,function(connection)
    connection:on("receive",function(connection)
    connection:send("HTTP/1.1 200 OK\r\n")
    connection:send("Content-type: text/html\r\n")
    connection:send("Connection: close\r\n\r\n") 
    connection:send("<h1> Witaj, Marcin!!! </h1>")
    connection:send("<h1> ESP8266 connected :) </h1>")
  end)
    connection:on("sent",function(connection)
    connection:close()
  end)
end)

Powyższy skrypt zawiera już polecenia potrzebne do poprawnego wyświetlenia napisu w Safari, są to trzy pierwsze polecenia connection:send.... Bez tych trzech linijek Safari nie wyświetli tekstu podanego w następnych liniach skryptu. W Firefoxie, Chrome dodatkowe polecenia są nie potrzebne aby przeglądarki wyświetliły tekst.

Patrząc na kod skryptu serwera TCP, widać że oprócz komend z biblioteki net NodeMCU zawiera on również elementy języka LUA. Żeby dokładniej zrozumieć formę zapisu, trzeba zapoznać się chociaż z podstawami składni języka LUA. Spróbuję choć trochę objaśnić co skrypt ten robi.

W pierwszej linii powołujemy zmienną server której przypisujemy utworzony serwer korzystający z protokołu TCP. Została do tego użyta funkcja net.createServer z biblioteki net NodeMCU, której argumentem jest w tym przypadku stała net.TCP. W kolejnej linii włączamy nasłuchiwanie na porcie 80. Składnia server:listen bierze się z tego że korzystamy z serwera utworzonego według parametrów podanych w pliku init.lua, czyli IP serwera będzie takie jakie podaliśmy w tym pliku. Drugim elementem który należy podać jest funkcja zwrotna, tzw. callback, którą w tym miejscu powołujemy. W sytuacji gdy połączenie przebiegnie prawidłowo, zostaną do niej przekazane dane poprzez argument. W dokumentacji biblioteki jest to dokładniej opisane i na przykładzie wytłumaczone. Następnie rejestrujemy funkcję zwrotną dla konkretnego zdarzenia, w tym wypadku odbiór zapytania od przeglądarki. Jak widać odwołujemy się do argumentu z funkcji którą wcześniej powołaliśmy. Polecenie on, pochodzi z biblioteki net NodeMCU i wymaga ono podania zdarzenia w postaci stringa oraz rejestrowanej funkcji zwrotnej. W kolejnych liniach następuje przesłanie do funkcji przy użyciu bibliotecznego polecenia send, danych jakie chcemy przekazać do przeglądarki. Na informacje jakie wysyłamy w pierwszej kolejności (trzy pierwsze connection:send), składają się polecenia HTTP, które jak wspominałem wcześniej, są potrzebne aby Safari wyświetliło tekst który wysyłamy. W następnych dwóch przekazywany jest tekst do wyświetlenia na stronie, gdzie oprócz samego tekstu także przekazujemy znaczniki HTML. Kolejnym poleceniem jest end). Jest ono niezbędnym elementem oznaczającym w tym przypadku zakończenie funkcji. Funkcji z linii connection:on.... W kolejnej linii znowu rejestrujemy funkcję, tym razem dla zdarzenia "sent". Zamykamy połączenie, connection:close(), i ostatnie dwa polecenia zamykają funkcje.

Uff, koniec. Mam nadzieję że to co napisałem powyżej ma sens i jest właściwą interpretacją skryptu. Czytając objaśnienia w bibliotece net  poszczególnych poleceń, wszystko wydaje się dość jasne i proste. Jednak jak zacznie się dodawać do tego polecenia z LUA, to zaczyna się to trochę gmatwać. Bo na przykład, możemy w liniach connection:on odpuścić sobie wpisywanie funkcji w postaci function(connection). Wystarczy jakbyśmy wpisali function(), a cały skrypt się  prawidłowo wykona. Hmm...

Wróćmy jednak do naszego serwera TCP. Zanim wgramy pliki do ESP trzeba dopisać jeszcze jedno polecenie w pliku init.lua. Skoro podzieliliśmy projekt na dwa pliki, musimy poinformować układ aby oprócz pliku inicjalizacyjnego wczytał również plik tcp.lua. Służy do tego polecenie

dofile("tcp.lua")

a więc cały plik init.lua powinien wyglądać tak:

wifi.setmode(wifi.STATION)
wifi.sta.config("nazwa sieci", "hasło do sieci")
wifi.sta.connect()
wifi.ap.dhcp.stop()
wifi.sta.setip({
  ip = "192.168.1.51",
  netmask = "255.255.255.0",
  gateway = "192.168.1.1"
})
dofile("tcp.lua")

ESP connected

Mamy już kod podzielony na dwa pliki, możemy więc przejść do wgrania ich do ESP. W tym celu naciskamy przycisk "Save to ESP". Pojawi się okno w którym zostaniemy poproszeni o podanie nazwy pliku oraz lokalizacji w jakiej chcemy ten plik zapisać na dysku. Wpisujemy więc nazwę właściwą dla wgrywanego kodu, czyli init.lua lub tcp.lua, naciskamy "Save" i plik zostanie nagrany na dysku oraz przesłany do ESP. Kolejność w jakiej będziemy wgrywać pliki do ESP nie ma znaczenia. Jeśli zaczniemy od init.lua to zaraz po wgraniu do układu plik zostanie wykonany, ale poinformowani zostaniemy że nie można znaleźć pliku tcp.lua. Po wgraniu więc pierwszego pliku, wybieramy drugą zakładkę w której mamy kod następnego pliku i powtarzamy operację z zapisem. Jak oba pliku są już wgrane, resetujemy układ, otwieramy przeglądarkę internetową, w pasku adresu wpisujemy numer IP jaki nadaliśmy modułowi i naciskamy Enter. W oknie przeglądarki powinien pojawić się napis jaki wpisaliśmy w pliku tcp.lua.

Powyższy przykład jest najprostszą wersją komunikacji po protokole TCP. Możemy utworzyć stronę w pamięci ESP która będzie zawierała więcej elementów, zapewniających np interakcję z użytkownikiem. Tutaj już jednak oprócz znajomości LUA potrzebna też jest wiedza na temat budowania stron z wykorzystaniem języka HTML. Niemniej przykład ten pokazuje, że moduł z układem ESP8266 może pracować jako samodzielne urządzenie na którym możemy "postawić" stronę www.

Czas zatem na UDP.

Plik init.lua mamy już gotowy. Jedyną zmianą jakiej należy w nim dokonać, to linię dofile("tcp.lua"), zamienić na dofile("udp.lua"). Od razu możemy go też wgrać do ESP poprzez naciśnięcie "Save to ESP". Tym razem program nie będzie się pytał gdzie na dysku chcemy zapisać plik, nadpisze istniejący. Trzeba o tym pamiętać, bo gdy zacznie się zabawę z modyfikowaniem kodu w plikach, może się okazać że tak namieszamy w kodzie że nic nie będzie działać. Dlatego dobrze jest robić sobie kopie zapasowe plików w których mamy sprawdzony, działający poprawnnie kod. Będzie przynajmniej skąd skopiować w razie potrzeby.

Teraz naciskamy ikonę "New File". W oknie które się pojawi wklejamy poniższy kod:

function esp_send(data)
    socket=net.createConnection(net.UDP,0)
    socket:connect(55056,"192.168.1.106")
    socket:send(data)
    socket:close()
end
udp_server=net.createServer(net.UDP)
udp_server:on("receive",function(udp_server,data)
    esp_send("ESP8266 - "..data)
    print(data)
end)
udp_server:listen(10000)

Tak jak w przypadku serwera TCP, tak i teraz wykorzystujemy przykłady jakie można znaleźć w opisie poszczególnych funkcji biblioteki net NodeMCU. Zmiana jakiej dokonałem względem przykładów jest taka, że oprócz serwera UDP jaki tworzymy, zamknąłem w funkcji utworzenie klienta UDP, dzięki któremu będzie można wysłać dane na podany port i adres IP. Myślę że szczegółowe objaśnienie powyższego kodu nie jest konieczne. Nie różni się on w swoich podstawowych funkcjach od kodu dla serwera TCP. Numer portu jaki wpisałem bierze się z serwera UDP tworzonego w programie PacketSender, zaś numer IP to adres mojej sieci WIFI. Numer portu w udp_server:listen(10000) informuje moduł ESP na jakim porcie ma oczekiwać na napływające dane z zewnątrz, i numer ten należy wpisać w PacketSender wraz z adresem IP modułu, aby mógł on odbierać wysyłane dane z komputera. W trzeciej części poradnika jest dokładnie opisana obsługa programu PacketSender, to tak dla przypomnienia jakby ktoś zapomniał gdzie co wpisywać.

ESPlorer1

Zostaje więc wgranie pliku do ESP. Naciskamy "Save to ESP", wskazujemy miejsce gdzie ma na dysku zapisać się plik, wpisujemy nazwę udp.lua i naciskamy Save. Po wgraniu do ESP moduł należy zresetować i można zacząć wysyłać dane z programu PacketSender. To co wyślemy powinno zostać wyświetlone w konsoli w programie ESPlorer, natomiast do programu PacketSender powinna przyjść informacja zwrotna w postaci "ESP8266 - "tutaj to co wysłaliśmy"". Niestety zdarza się czasami, że o ile moduł odbierze wysłane dane, to nie zawsze chce odpowiedzieć. Nie wiem czy wynika to z faktu że kod jest niepoprawnie, nieoptymalnie napisany, dopiero próbuję jakoś ogarnąć język LUA, czy jest też to wina firmware'u NodeMCU. W internecie bowiem, można natrafić na informacje o niestabilnym działaniu NodeMCU w połączeniu z LUA. W tym jednak wypadku raczej zrzucałbym winę na jakieś, jeszcze mi nie znane, popełnione błędy podczas pisania kodu. Wszystko to jednak nie przeszkadza w zabawie z ESP8266 i można naprawdę zacząć myśleć o budowaniu własnych urządzeń IoT w oparciu o ten układ. Możliwości są ogromne. Na moim kanale YouTube umieściłem przykładowy film na którym załączam diody korzystając z protokołu UDP, a do wysyłania poleceń używam iPhona. Diody z powodzeniem można by zastąpić przekaźnikeim i po zbudowaniu odpowiedniego układu sterującego, załączać np światło w pokoju za pomocą telefonu. Program użyty na iPhonie nie jest żadną dedykowaną aplikacją dla ESP8266. Jest to jeden z wielu programów do testowania UDP i TCP jakie można znaleźć w AppStore.

Jak wspominałem wcześniej, jest to w sumie podstawowa konfiguracja serwera i klienta UDP. Aż się prosi aby rozbudować ten skrypt o funkcję która by pobierała automatycznie adres IP naszej sieci i podstawiała ten adres przy tworzeniu klienta UDP. Bo jeśli mamy kilka urządzeń podpiętych do sieci w domu, a do tego korzystamy jeszcze z przydzielania im adresów poprzez DHCP, to wpisywanie adresu IP "na sztywno" nie zda raczej egzaminu. Pierwsze już rozłączenie z siecią i powtórne z nią połączenie, może ten adres zmienić i nie uda nam się już nic wysłać z ESP.

Kto uważnie czytał może zapytać, "a co z wgranym plikiem tcp.lua?" Ano nic. Jest nadal w pamięci ESP. Wystarczy zmienić teraz w pliku init.lua linię dofile("udp.lua") na dofile("tcp.lua"), wysłać init.lua do ESP i mamy serwer TCP.

To jakie pliki są zapisane w pamięci ESP sprawdza się naciskając przycisk "Reload". Poniżej tego przycisku zostaną wyświetlone nazwy wgranych plików do układu. Wywołując menu kontekstowe nad daną nazwą, możemy przenieść plik z pamięci ESP do okna edytora, gdzie będzie można dokonywać zmian w kodzie skryptu.

To by było chyba na tyle jeśli chodzi o początek zabawy z ESP8266. Mam nadzieję że te cztery poradniki, pokazały jakie drzemią możliwości w tym tanim module WIFI który w połączeniu z NodeMCU daje nam spore pole do eksperymentowania. Pokazały też, taką mam nadzieję, że programowanie ESP8266 na Mac OS X jest możliwe i że nie brakuje narzędzi ułatwiających ten proces.

Komentarze   

#2 Marcin 2017-10-09 11:46
Dzięki za komentarz :)
Uwaga o adresach IP jest chyba nieuzasadniona ;) We wcześniejszych poradnikach na temat ESP8266, wyjaśniałem co to za adresy. Dla przypomnienia, adres ...51 jest adresem statycznym nadanym przeze mnie, natomiast adres ...106 jest adresem mojej karty sieciowej. We wszystkich częściach poradnika korzystam z tych samych adresów, żeby nie mieszać.
W kwestii przesyłania danych z innego urządzenia, to pokazałem na filmach że jest to możliwe. Ale masz rację że poradnik na ten temat spinał by je wszystkie w całość. Może więc przysiądę i spróbuję coś na ten temat skrobnąć. Na pewno jednak nie będzie to nic z wykorzystaniem RPi. Raczej prosty programik w LUA zaszyty w ESP i obsługa z telefonu po UDP.
Cytować
#1 Ryszard 2017-10-07 13:40
Cześć,
dlaczego nie wyjaśnisz skąd różne IP. Raz podajesz ...51 a drugi raz ...106. Wysylanie na serwer UDP danych z samego siebie ESP8266 nie ma praktycznego zastosowania. To takie masło maślane. Artykuł zyska na wartości jak podasz jak przesłac dane z innego urządzenia. Proponuję z RPi. (np za pomocą LUA, Python lub przy pomocy polecenia nixowego itp). A jeśli wstawisz to cyklicznego crona to będzie super.
Pozdrawiam
Cytować

Dodaj komentarz

Kod antyspamowy
Odśwież