NodeMCU – pierwsza aplikacja sieciowa

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 magnetometremModuł 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ć.

 

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.