Dziś chciałbym podzielić się przykładem aplikacji sieciowej IoT korzystającej z modułu NodeMCU z układem ESP8266 oraz z modułu KAmodLSM303 z akcelerometrem i magnetometrem. Moduł z ESP8266 będzie przekazywał odczyty z akcelerometru LSM303D do dowolnego urządzenia, które będzie mogło połączyć się z nim przez sieć.
Pozostałe części cyklu:
Obsługa I2C w NodeMCU
Obsługa I2C w NodeMCU jest banalnie prosta, zaczynam od konfiguracji interfejsu:
i2c.setup(0, 2, 1, i2c.SLOW)
Pierwszy argument (0) to identyfikator interfejsu i2c, kolejne dwa parametry to numery linii, których chcemy użyć jako SDA i SCL, ostatni parametr określa czy I2C ma pracować ze standardową częstotliwością 100kHz (i2c.SLOW) czy z częstotliwością 400kHz (i2c.FAST). W chwili obecnej i2c w NodeMCU działa tylko z częstotliwością 100kHz.
Do przesyłania informacji w NodeMCU używamy czterech funkcji: i2c.start, i2c.stop, i2c.write i i2c.read, nie będę się zagłębiał w teorię, myślę, że kod moich funkcji odczytu i zapisu rejestru przez i2c wyjaśni wszystko:
-- adres ukladu LSM303 w module KAmodLSM303 addr = 0x1d -- funkcja odczytuje rejestr o adresie regaddr readreg = function (regaddr) i2c.start(0) i2c.address(0, addr, i2c.TRANSMITTER) i2c.write(0, regaddr) i2c.stop(0) i2c.start(0) i2c.address(0, addr, i2c.RECEIVER) i2cres = i2c.read(0, 1) i2c.stop(0) return i2cres; end -- funkcja zapisuje wartosc val do rejestru regaddr writereg = function(regaddr, val) i2c.start(0) i2c.address(0, addr, i2c.TRANSMITTER) i2c.write(0, regaddr) i2c.write(0, val) i2c.stop(0) end
Konfiguracja WiFi w NodeMCU
Chciałbym, aby mój moduł NodeMCU pracował jako access point o nazwie KAmodLSM303 z hasłem 12345678 i standardowymi ustawieniami IP (192.168.1.1/255.255.255.0). Ten kod również nie wymaga komentarza:
-- konfiguracja Access Pointu WiFi
print("Konfiguracja WiFi...")
ipcfg = {}
ipcfg.ip="192.168.1.1"
ipcfg.netmask="255.255.255.0"
ipcfg.gateway="192.168.1.1"
wifi.ap.setip(ipcfg)
cfg={}
cfg.ssid="KAmodLSM303"
cfg.pwd="12345678"
wifi.ap.config(cfg)
wifi.setmode(wifi.SOFTAP)
Serwer TCP
Tutaj niektórzy mogą mieć problem ze zrozumieniem składni, przynajmniej ja miałem, więc na początek kilka wyjaśnień:
- w Lua bardzo często używa się funkcji jako parametrów dla innych funkcji. Mam tu na myśli sens inny niż suma(pierwiastek(2), pierwiastek(3)), chodzi o coś podobnego do przekazania wskaźnika do funkcji w języku C
- w Lua często deklaruje się funkcje w tym miejscu, w którym przekazuje się je jako parametr, podobnie jak
Chcąc uruchomić serwer TCP tworzymy obiekt serwera (zmienna server), potem metodą listen konfigurujemy go do nasłuchiwania na porcie 111 i podajemy jako drugi argument funkcję, która będzie wywoływana przy każdym nawiązaniu połączenia otrzymując jako parametr zmienną c typu net.socket, ta funkcja z kolei ustawia dla obiektu c funkcję obsługi zdarzeń, w moim przypadku będzie to jedno zdarzenie – receive, czyli zdarzenie odebrania danych od klienta. Trochę to skomplikowane, ale opis i przejrzenie kodu powinny pozwolić zrozumieć o co chodzi.
W funkcji obsługującej zdarzenie odebrania danych zapalana jest dioda modułu NodeMCU, wysyłane są dane z rejestru czujnika LSM303 o adresie 0x28 i pięciu następnych (rejestry zawierają odczyty akcelerometru), na koniec dioda jest gaszona.
-- uruchomienie serwera TCP na porcie 111
-- i deklaracja funkcji wywolywanej
-- w momencie odebrania danych
print("Uruchamianie serwera TCP...")
server = net.createServer(net.TCP, 10)
gpio.write(0, 1)
server:listen(111,function(c)
c:on("receive", function(c, recvdata)
-- zapal diode LED
gpio.write(0, 0)
-- odczytaj rejestry z danymi
-- akcelerometru
v = ""
for i=0,5 do
v = v .. readreg(0x28+i)
end
-- wyslij dane
c:send(v)
-- zgas diode LED
gpio.write(0, 1)
end)
end)
Mamy już gotowy serwer, który udostępnia dane odczytane z akcelerometru, następnym razem zajmę się stroną odbierającą i przetwarzającą te dane.
Płytki NodeMCU oraz KAmodLSM303 dostarczył sklep internetowy dla elektroników Kamami.pl.


