GPIO#

GPIO (General Purpose Input/Output) pozwala na bezposrednie sterowanie pinami Raspberry Pi z poziomu Lua. Na tej warstwie bazuja obiekty wyzszego poziomu - GPIO_DOUT i GPIO_DIN.

Architektura#

  user.lua / om.lua
       │
  ┌────┴─────────────────┐
  │  GPIO_DOUT / GPIO_DIN │   ← obiekty wysokiego poziomu
  └────┬─────────────────┘
       │
  ┌────┴──────────┐
  │  gpio.*       │   ← niskopoziomowe API Lua
  └────┬──────────┘
       │
  ┌────┴──────────┐
  │  Go Controller │   ← RPiController (ARM64) lub MockController (dev)
  └───────────────┘
  • RPiController - uzywa /dev/gpiochip0 na Raspberry Pi (linux + arm64)
  • MockController - symuluje GPIO na innych platformach (macOS, x86) - do developmentu

Numeracja pinow#

GPIO uzywa numeracji BCM (Broadcom), nie fizycznej numeracji headerow. Popularne piny:

BCMOpisTypowe zastosowanie
17GPIO17przekaznik 1
27GPIO27przycisk 1
22GPIO22przekaznik 2
23GPIO23przycisk 2
24GPIO24przekaznik 3
25GPIO25przycisk 3

Niskopoziomowe API - gpio.*#

gpio.setup(pin, mode, pull, safeState)#

Konfiguruje pin GPIO.

ParametrTypOpis
pinnumberNumer pinu BCM
modestring"input" lub "output"
pullstring"up", "down" lub "off" (domyslnie "off")
safeStatebooleanStan fizyczny po zamknieciu (domyslnie false)
-- Pin 17 jako wyjscie
gpio.setup(17, "output")

-- Pin 27 jako wejscie z pull-up
gpio.setup(27, "input", "up")

gpio.read(pin)#

Odczytuje wartosc pinu.

local val = gpio.read(27)  -- 0 lub 1

gpio.write(pin, value)#

Ustawia wartosc pinu wyjsciowego.

gpio.write(17, true)   -- HIGH
gpio.write(17, false)  -- LOW

gpio.toggle(pin)#

Przelacza wartosc pinu na przeciwna.

gpio.toggle(17)  -- HIGH → LOW lub LOW → HIGH

gpio.release(pin)#

Zwalnia pin (kasuje rejestracje i resetuje w kontrolerze).

gpio.release(17)

gpio.stats()#

Zwraca statystyki kontrolera GPIO.

local s = gpio.stats()
-- { allocatedPins = 3, pollQueueSize = 0, ... }

Rejestr pinow#

Kazdy pin moze byc uzyty tylko raz. Proba uzycia zajeto pinu wyrzuca blad:

gpio.setup(17, "output")
gpio.setup(17, "input")  -- ERROR: gpio: pin 17 already allocated by direct

Zwalnianie:

gpio.release(17)
gpio.setup(17, "input")  -- OK

Obiekty GPIO_DOUT i GPIO_DIN rowniez rejestruja piny - nie mozna uzyc tego samego pinu dwa razy:

local relay = GPIO_DOUT:new("RELAY1", 17)
gpio.setup(17, "input")  -- ERROR: pin 17 already allocated by RELAY1

Polling zmian wejsc#

Kontroler Go polluje piny wejsciowe co 50ms. Wykryte zmiany trafiaja do kolejki, ktora Lua odpytuje przez gpio.pollChanges(). Kazda zmiana emituje trzy zdarzenia:

gpio.pin.{pin}.OnChange   ← zdarzenie per-pin
gpio.OnChange              ← zdarzenie globalne
state_changed              ← StateBus (dla MQTT/HomeKit)

Payload zdarzenia:

{
    pin = 27,
    value = 1,       -- nowa wartosc
    oldValue = 0     -- poprzednia wartosc
}

Subskrypcja zdarzen (niskopoziomowa)#

-- Reaguj na zmiane konkretnego pinu
EventBus:getShared():on("gpio.pin.27.OnChange", function(data)
    if data.value == 1 then
        log.info("Pin 27: HIGH")
    else
        log.info("Pin 27: LOW")
    end
end)

-- Reaguj na kazda zmiane GPIO
EventBus:getShared():on("gpio.OnChange", function(data)
    log.info("Pin " .. data.pin .. " → " .. data.value)
end)
W praktyce lepiej uzywac `GPIO_DIN` zamiast surowego `gpio.setup` + `EventBus` - daje debounce, rozpoznawanie krotkich/dlugich nacisnieci i kompatybilnosc z API Grenton.

Kiedy uzywac gpio.* a kiedy GPIO_DOUT/GPIO_DIN#

ScenariuszUzyj
Przekaznik, lampa, zaworGPIO_DOUT
Przycisk, czujnik binarnyGPIO_DIN
Niestandardowe urzadzenie (PWM, syrena, LED)gpio.* bezposrednio
Debugging, testygpio.read(), gpio.stats()