NodeMCU + MQTT + relé vezérlés egy lua-val

 ( Hyperion | 2016. február 25., csütörtök - 9:30 )

Sziasztok!

Bocs a kusza címért.
Hobbiprojektnél ismerkedem a nodeMCU-s lua programozással.
Amit szeretnék:

- DHT22-n kinyert hőmérséklet + páratartalom küldése az MQTT felé(Openhab interfésszel)
- Relé modul vezérlése, az MQTT-től kapott álapottal.

Nem bonyolult, külön-külön szépen működik. Viszont 1 szkriptbe nem bírom összehozni.
Ugyanis, ha bontom a subscribe-et hogy elküldjem a hőmérséklet adatokat, a relé állapotváltozást, értelem szerűen nem fogja ezen id alatt lekövetni.

Tudtok esetleg példaprogramkódot linkelni, vagy javaslatot adni?

Mindenképpen csak NodeMCU-t szeretnék használni, külső eszközt(Raspi, Ardu-t) nem szeretnék bevonni.

Köszönöm!

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

sub
Nálam is tervben van egy ilyen implementáció, de még nem kezdtem neki, csak figyelek.

Félek, hogy marad a 2 eszköz.. Nem nagy összeg, kb 600Ft az ESP8266, de azért jobb lett volna 1-ben. :/

Nem hiszem, hogy ne lehetne megoldani, de tapasztalatom még nincs vele, talán majd a hétvégén. :)

Valószínű hogy meglehet, de kérdés hogy ez mennyire fogja befolyásolni az üzembiztonságot. Azon az állásponton vagyok, hogy inkább sok kis szegmensből álljon a rendszer(LED vezérlő, TV áramellátás, termosztát stb) így, kisebb galibát okoz ha valami gond van..
Pl.: Készítettem egy fél éve egy arduinós, esp-s időjárás-állomást, egyben cirkóvezérléssel.
Netről szedi az előrejelzést + kommunikál a lakás érzékelőivel (DHT22). Tök jól működött kb 2 hétig. Majd gondolt egyet és berántotta a relét, ezzel elindítva a fűtést majd lefagyott..
Mire hazaértünk, volt vagy 28fok a lakásban! :x

Szóval azóta kicsit óvatosabb vagyok :)
(Megjegyzem azóta sem tudom, hogy miért volt ez a bug.:))

Nekem pár éjszakám volt így... elég rossz érzés így ébredni. Bár, esetedben, hogy nem voltál otthon sem jobb...

A probléma az volt, hogy naívan vettem egy analóg frevenciás Sony vezeték nélküli fejhallgatót (azóta már kicseréltem 2,4Ghz-s Pioneer-ra). Amikor áram alatt volt a Sony adó egysége (ha használtam, ha nem), elnyomta a cirkó felé menő Computherm wireless rádiófrekvenciás termosztát "lekapcsolás" üzenetet.
Ezt követően a termosztát úgy tekintette, hogy az üzenet elment (visszaigazolást nem várt) és vígan mérte az emelkedő hőmérsékletet.

Ekkor határoztam el, hogy majd én is inkább saját rendszert építek, ahol a hőmérő a zsinór nélküli és a döntéshozó a kábeles...!
Még nem csináltam meg, de ami késik nem múlik... főleg, hogy a fiam új távirányítós autója is hasonlókat kezd csinálni, így minden nap figyelni kell, hogy ne maradjon bekapcsolva....

A dht már hetek óta stabil, az adc-re kötött fotoellenállás szintén. Pár napja a relé is gond nélkül megy. Nem a nodemcu boarddal csináltam csak egy natúr esp12e van összeforrasztva.


wifi.setmode(wifi.STATION)
wifi.setphymode(wifi.PHYMODE_N)
wifi.sta.config("apname", "appasswd")

relay = gpio.LOW
gpio.mode(8, gpio.OUTPUT)

m = mqtt.Client("mymqttendpoint", 120, "", "")
conn = false

function tick()
if wifi.sta.status() ~= 5 then
conn = false
return
end
if not conn then
m:connect("test.mosquitto.org", 1883)
return
end
s, t, h, td, hd = dht.readxx(4)
if s == dht.OK then
m:publish("mysensor/esp1/temperature", t.."."..td, 0, 0)
m:publish("mysensor/esp1/humidity", h.."."..hd, 0, 0)
end
m:publish("mysensor/esp1/light", adc.read(0)..".0", 0, 0)
end

m:on("connect", function(c)
conn = true
m:subscribe("mysensor/esp1/relay", 0)
tick()
end)

m:on("offline", function(c)
m:close()
conn = false
end)

m:on("message", function(c, topic, data)
if data == "on" then
relay = gpio.HIGH
elseif data == "off" then
relay = gpio.LOW
elseif data == "toggle" then
if relay == gpio.LOW then
relay = gpio.HIGH
else
relay = gpio.LOW
end
end
gpio.write(8, relay)
end)

tmr.alarm(0, 10000, tmr.ALARM_AUTO, tick)

Sub

+1

.

Tökéletes...
Stabil, gyors.

Köszönöm, kicsit átfaragom és tesztelem huzamosabb ideig!

Későn találtam erre a threadre, de talán lehet érdekes ez a megoldás is. Egy példaprogramot faragtam át, nem értek a LUA-hoz és nem tudom, miért így lett megoldva:

init.lua:

-- file : init.lua
app = require("application")
config = require("config")
setup = require("setup")

setup.start()

config.lua:

-- file : config.lua
local module = {}

module.SSID = {}
module.SSID["***"] = "***"

module.HOST = "172.***"
module.PORT = 1883
module.ID = node.chipid()

module.ENDPOINT = "saabi/sensors/room/"
return module

setup.lua:

-- file: setup.lua
local module = {}

local function wifi_wait_ip()
    if wifi.sta.getip()== nil then
        print("IP unavailable, waiting...")
    else
        tmr.stop(1)
        print("\n====================================")
        print("ESP8266 mode is: " .. wifi.getmode())
        print("MAC address is: " .. wifi.ap.getmac())
        print("IP is : " .. wifi.sta.getip())
        print("====================================")
        app.start()
    end
end

local function wifi_start(list_aps)
    if list_aps then
        for key,value in pairs(list_aps) do
            if config.SSID and config.SSID[key] then
                wifi.setmode(wifi.STATION)
                wifi.sta.config(key,config.SSID[key])
                wifi.sta.connect()
                print("Connecting to " .. key .. " ...")
                -- config.SSD = nil -- can save memory
                tmr.alarm(1, 2500, 1, wifi_wait_ip)
            end
        end
    else
        print("Error getting AP list")
    end
end

function module.start()
    print("Configuring WiFi ...")
    wifi.setmode(wifi.STATION);
    wifi.sta.getap(wifi_start)
end

return module

application.lua:

-- file : application.lua
local module = {}
m = nil
dhtpin = 4
sw1pin = 1
sw2pin = 2

gpio.mode(sw1pin, gpio.INT, gpio.PULLUP)
gpio.mode(sw2pin, gpio.INT, gpio.PULLUP)

function sw1pushed()
    m:publish("saabi/switches/SW1","CLOSED",0,0)
    tmr.delay(50)
    gpio.trig(sw1pin, "up", sw1released)
end

function sw1released()
    m:publish("saabi/switches/SW1","OPEN",0,0)
    tmr.delay(50)
    gpio.trig(sw1pin, "down", sw1pushed)
end

function sw2pushed()
    m:publish("saabi/switches/SW2","CLOSED",0,0)
    tmr.delay(50)
    gpio.trig(sw2pin, "up", sw2released)
end

function sw2released()
    m:publish("saabi/switches/SW2","OPEN",0,0)
    tmr.delay(50)
    gpio.trig(sw2pin, "down", sw2pushed)
end

local function send_temp()
    status, temp, humi, temp_dec, humi_dec = dht.read(dhtpin)
    if status == dht.OK then
        print("Temp: "..temp)
        m:publish(config.ENDPOINT .. "temp",temp,0,0)
        m:publish(config.ENDPOINT .. "humi",humi,0,0)
    end
end

local function register_myself()
    m:subscribe(config.ENDPOINT .. config.ID,0,function(conn)
        print("Successfully subscribed to data endpoint")
    end)
end

local function mqtt_start()
    m = mqtt.Client(config.ID, 120)
    m:connect(config.HOST, config.PORT, 0, 1, function(conn)
        register_myself()
        tmr.stop(6)
        tmr.alarm(6, 200000, tmr.ALARM_AUTO, send_temp)
        gpio.trig(sw1pin, "down", sw1pushed)
        gpio.trig(sw2pin, "down", sw2pushed)
    end)
end

function module.start()
    mqtt_start()
end

return module

Két kapcsoló állapotát is küldi, ezeket használom az előszoba és nappali világításának kapcsolására.

Ave, Saabi.

Szerintetek mi van olyankor, ha:
Volt egy sikeresen nodeMCU-val flashelt ESP8266-om.
Írtam is hozzá lua scripteket, fel is töltöttem ESPlorer-el. Működött is!
Egészen addig még nem vétetem egy fatális program hibát, minek következtében már csatlakozni sem tudtam az ESP-hez.
Fogtam, újra flasheltem, de továbbra sem tudok csatlakozni:

PORT OPEN 9600
Communication with MCU..Waiting answer from ESP - Timeout reached. Command aborted.
PORT CLOSED

Tehát meghalt minden ami eddig jó volt :(

Hogy tudnám vajon javítani? van tippetek?

Amikor flash-elsz, akkor 57600 baud-ot kell beállítani. Ha a flash-elt eszközre akarsz csatlakozni, akkor 115200 baud-ot kell beállítani az ESPlorer-ben. Ezt ugyan át tudod állítani, de előtte 115200 baud-dal kell feltölteni az átállítást végző lua fájlt. :-)

Kiegészítés: A helyes sebesség beállítása mellett is előfordulhat ez az üzenet, ugyanis ha kihúzod, és újra bedugod az eszközt, akkor megváltozhat az eszköz neve ttyUSB0-ról ttyUSB1-re. Vagy fordítva. Ha minden rendben van, akkor is néha nem tud csatlakozni. Ilyenkor egy FS Info kérés (jobb szélen) segíteni szokott. Utána már lehet kommunikálni az eszközzel. Ez utóbbi esetben az állhat a háttérben, hogy először nem tud csatlakozni valami miatt, erről üzen is, de aztán mégis sikerül, de erről már nem tájékoztat.

Eddig mindent 9600-on csináltam és sikerült a flashelés és a lia feltöltés is. De miután program hibát vétettem és újra flasheltem, már a csatlakozás nem sikerül.

Most újra flasheltem 57600 baud-on.
Próbálok csatlakozni 9600 és 115200 baud-on is, és bár valóban nem mindig sikerül neki, de néhány próba után csatlakozik mindkettőn, csak ép semmit nem tudok csinálni ezután.

PORT OPEN 115200
Communication with MCU..Got answer! Communication with MCU established.
AutoDetect firmware...
Can't autodetect firmware, because proper answer not received (may be unknown firmware).
Please, reset module or continue.
Waiting answer from ESP - Timeout reached. Command aborted.Waiting answer from ESP - Timeout reached. Command aborted.
PORT CLOSED

Mondjuk ezt a "Can't autodetect firmware..." üzenetet akkor is írta, amikor még minden jó volt.
De akkor pl. működtek a lenti Chip Info, Chip ID ... gombok is. Most ezekre nem jön üzenet.

-------

Nah bakker. Most hogy ezt leírtam, egyszer csak elkezdett működni :D

Feltettem egy lua-t is, amivel csatlakozik is a routerhez!

De basszus, ez ennyire instabil dolog?
Állandóan ki-be kell dugdosnom az USB-t, hogy csatlakozzon.
És ha vétek egy programhibát, akkor szívni kell fél napot, hogy újra működésbe hozzam? :S

De lehet még csak én nem értek eléggé hozzá :)

Egyébként úgy vettem észre, hogy a csatlakozás akkor müködik csak, ha a GPIO0 is kap 3.3V-ot. Bár ezt nem minden how-to írja követelménynek.

„Can't autodetect firmware, because proper answer not received (may be unknown firmware).
Please, reset module or continue.
Waiting answer from ESP - Timeout reached. Command aborted.Waiting answer from ESP - Timeout reached. Command aborted.”

Tapasztalatom szerint ez nem jelent hibát. Arra tippelek, hogy ez olyankor fordul elő, amikor a modul a lekérdezés pillanatában olyan állapotban van, hogy nem tud válaszolni a kérésre. Egyrészt fut a lua interpreter, másrészt futtatja a lua kódot, ha éppen van rajta. Így aztán előfordulhat, hogy éppen nem ér rá az ESPlorer-nek válaszolni. Ettől még működik, így nem is szoktam foglalkozni ezzel.

Amire figyelj: Célszerű egy kisméretű init.lua-t feltölteni, és abból meghívni a fő modult. Ennek akkor lesz jelentősége, ha elszúrsz valamit a fő modulban, és folyamatosan újraindul az MCU. Ilyenkor két újraindulás között nincs idő feltölteni egy nagyobb fájlt. Viszont egy néhány (2–3) soros fájl feltöltésére marad elég idő. Ilyenkor feltöltesz egy init.lua-t, ami annyiban tér el használt változattól, hogy a dofile("xxx.lua") sort kikommentelted. Így a következő újraindításnál már nem fogja meghívni a hibás modult.

Ez jó tipp, köszi!

Célom az, hogy egyszer legyen jó a program rá és akkor hagyom is a fenébe.
Egyszer sikerült hozzá csatlakoznom, amikor az előbb írtam, hogy jó, de azóta megint nem.
Vagy nem történik semmi, vagy a "Communication with MCU.." -nál beragad.
Tehát így, hogy 2 óra csak azzal megy el hogy csatlakozzak hozzá, nem egy jó móka.
Bár egy 900Ft-os cucctól nem vártam csodákat :)

Nem jól fogod. :-)

„Vagy nem történik semmi, vagy a "Communication with MCU.." -nál beragad.”

Nem szoktam foglalkozni vele. Egy FS Info-t nyomok, és akkor általában kiderül, hogy minden rendben van.

Javaslom olvasásra: http://www.esp8266.com/wiki/doku.php?id=nodemcu-unofficial-faq

Szubjektív megközelítés: Mivel egyszerre két-három eszköz is fut, így egy idő után zavart, hogy hosszabb tesztelésnél egymáshoz képest elcsúsznak a mérések. Először azt akartam csinálni, hogy sntp-vel szinkronizálom az időt. Aztán meggondoltam magam, és az eszközök csak akkor mérnek, ha erre utasítást kapnak. Mindegyikhez tartozik egy mqtt vezérlő csatorna, amire feliratkozott, és ha azon érkezik egy „measuring” üzenet, akkor mér, és elküldi a saját csatornáján a mérési eredményt. Kivétel ez alól a PIR szenzor. A home assistantot futtató cubietruck pedig cronból ad utasítást a mérésre. Így a mérések időpontja közötti eltérés gyakorlatilag elhanyagolható. További előny, hogy tesztelésnél akkor mérek, amikor akarok. Mikor rátaláltam a fenti FAQ-ra, akkor rájöttem, hogy ez jobb módszer, mint az sntp.

Én szintén egy ESP8266-ot használok, csak arduino-val programozom C-ben. Van egy Bosch BME280 ami mér és 5 percenként küld adatokat a szervernek, ami egy Rpi. Volt egy ilyen gondom, hogy a mérés szépen csúszott, aztán kimaradt emiatt egy-egy. Én úgy szinkronizálok, hogy egy GET-tel küldöm el paraméterként az adatokat, amit a szerver nyugtáz a visszaküldött szövegben, ugyanakkor a visszaküldésben benne van az időbélyeg, ami alapján az ESP kiszámolja, hogy még mennyit kell aludnia, hogy pontosan küldje el a következő csomagot. Így mindig 1-2 mp belül érkezik az adat.
Másik előny, az ESP végig deep-sleep-ben van, akkuról is tud dolgozni. Igaz, hogy a mérések között elérhetetlen, de a kommunikáció kétirányú. Még távoli firmware feltöltést is tudok vele csinálni, hogy ne keljen behozni programozni.

--
Lenovo Z580, LMDE 2 & Xfce

Nálam csak egy modul lesz ami akkumulátorról fog menni. Azt a végére hagyom, és majd később döntöm el, hogyan oldom meg a problémát. Így a többi modulnál az altatás fel sem merült.

Az OTA update működik NodeMCU alatt is, bár ott a firmware kicsit mást jelent, és ott magát a firmware-t nem kell frissíteni normál esetben. A firmware a lua interpretert, és többnyire a hardware (néha a software) által igényelt modulokat jelenti. Azt csak akkor kell módosítani, ha új hardware-t akarunk hozzáadni. Ahhoz meg úgy is kézbe kell venni az eszközt. Az általunk írt software a lua fájlokat jelenti, ezeket lehet OTA módon is frissíteni. Illetve, mivel nálam az usb porton kapnak a modulok tápfeszültséget, így egy notebookkal a működési helyen is frissíthetők.

Én is PIR szenzorral használnám.
Ez leegyszerűsíti a dolgokat, mert csak mozgás észlelésekor kell adatot küldenie.
Sőt, már küldi is az MQTT brokernek. Még a programon kellene finomítani, csak hát 1 óra mire csatlakozni tudok hozzá, hogy feltölthessem a lua-kat. :S

LUA-zasal való bohóckodást feladtam. Több idő megy el a csatlakozási kísérletekkel, mint a kódolással.
Feldobtam egy ESPEasy frimwaret, amivel elvileg egyszerűen lehet kezelni bármilyen szenzort.
Noh ez sikerült is. Az ESP webes felületén szépen látom is hogy 1 az érték ha van mozgás, 0 ha nincs.
Itt viszont az a gond, hogy nem küldi el a Home Assistatnak. Nincs is a config listában ehhez MQTT protokoll :S
Szóval nem egyszerű ez :S Vagy az egyik fele működik, vagy a másik, teljes egészében sehogy nem akar :S

---

Update:
OpenHAB MQTT-re állítva tud kommunikálni a HA féle MQTT-vel! :)

Noh, akkor most már teljes a siker végre!

PIR szenzor + ESP01 + ESPEasy frimware + Home Assistant = Mozgásra ki-be kapcsol egy kapcsoló :)

Bedoglott modulra:

http://stackoverflow.com/questions/29721859/how-to-recover-from-infinite-reboot-loops-in-nodemcu

En volt mar hogy ellottem an init.lua-t es utana egyszeruen hasznalhatatlan volt mert folyton panikolt. A fonti megoldas visszaallitotta.

Ezert en most mar olyan init.lua-t hasznalok ami var 5mp egy gombot es ha nincs akkor futtaja a tobbi luat, ha meg gomb van akkor semmit nem csinal csak dob egy promptot.

https://bitbucket.org/lmarton/nodemcu_pub

Itt megtalalod az init scriptet es peldat a relevezerlesre MQTT stb dolgokra. A blogomban mar irtam rola...

+1, megjegyeztelek. :D

Nalam volt mar nehanyszor hogy flasheltem, es utana nem mukodott, pedig a flash azt irta hogy ok. Ujraflashelve megoldodott. Probald ki, hatha csak valami hasonlo tranziens hiba.