Post your best Lua script examples here

User avatar
By Nubble
#16675 Hi,
I have been developing and implementing MQTT and Mote functionality into IoT devices - mostly arduino but also on rpi [using twisted matrix]. Now with the ESP8266 I ported [and condensed] the Mote library into the esp8266 module [ESP-03].

Functionality achieved with each is:
esp/200/$M/sub -> tell the esp8266 to subscribe to new topic. payload will be the new topic to subscribe to
esp/200/$R -> soft restart the esp8266
esp/200/$Lua -> send lua console commands to the esp8266. get response console messages from esp/200/@Lua - [still buggy]
esp/200/$L/g2 -> latch a gpio [a binary output]. payload is latch state ie, 1 or 0. Once executed a mqtt message is send resembling esp/200/@L/g2 with the state of the gpio as the payload
esp/200/$P/g2-> pulse a gpio[a binary output]. payload is pulse duration in ms. For each gpio state change [pulse up and down] a mqtt message is send resembling esp/200/@P/g2 with the state of the gpio as the payload.

esp/200/@A/heap ->Heap size reporting [delta = 2000 ; only report changes greater/less than delta value]
esp/200/@S/g0 -> g0 reporting
esp/200/@S/g15 ->g15 reporting


topics resemble: <deviceType>/<deviceAddress>/<msgType>/<msgIndex>
An example is esp/200/@S/g2 -> which is on esp with device id 200 [src address] of type binary/status input at gpio2
Another example is esp/200/$P/g14 -> which is on esp with device id 200 [dest address] of type binary pulse output at gpio14. The payload [ms] will pulse g14 for that period

msgTypes are:
@S - status/ binary input
@A - analog input
@L - response message to gpio latch control received
@P - response message to gpio pulse control received
@Lua - response message to Lua console message received

$L - binary output latch control on gpio
$P - binary output pulse control on gpio
$M/sub - subscribe to new topic
$M/unsub - unsubscribe to topic [unsubscribe functionality not yet in nodeMcu MQTT module. Hopefully soon.. :D ]
$R - reset the esp
$Lua - send lua messages to the console [Lua file integration coming soon]
$T - time control to send time to the esp [coming soon]

This code is not optomised for RAM [and I ran out of memory pretty quickly], and so had to compile all the files into lc on the esp besides init.lua. And because of the RAM problem I only have 2 inputs gpio 0 and 25 and 2 gpio outputs gpio 2 and 14. Im using an ESP-03. Once optomised all available gpio will be available through a config file.

Here is the code:

init.lua

Code: Select all--print('baudrate='..uart.setup(0,115200,8,0,1))
--setup wifi hotspot

--dofile('wifiStn_smc.lua')
--node.compile('wifiStn_smc.lua')
dofile('wifiStn_smc.lc')


--pause a little - 1 sec
tmr.delay(1000000)

--dofile('glue.lua')
--node.compile('glue.lua')
dofile('glue.lc')

print('INITDONE. heapsize='..node.heap())


glue.lua
Code: Select all-- glue.lua
--glue script for mqtt and mote
--gpioIndex=    {   0 ,   1 ,   2 ,   3 ,   4 ,   5  ,   6  ,   7  ,   8  ,   9 ,  10 ,  11 ,  12},
--gpioMap=      {'g16', 'g5', 'g4', 'g0', 'g2', 'g14', 'g12', 'g13', 'g15', 'g3', 'g1', 'g9', 'g10'},

--local scanPeriod=500                  --moved to moteScan.lua
local brokerIp='192.168.2.100'
local brokerPort=1883
--local user=''
--local password=''
local keepAlive=120
local clientId='esp/200'
--local lwTopic='lwt'
--local lwPayload='offline'
--local subListAll = '/#'          --everything esp/200/#
--local subM, subR, subLua, subP, subL, subA, subT= '$M/sub','$R','$Lua','$P/+','$L/+','$A/+','$T'
local subR, subLua, subP, subL= '$R','$Lua','$P/+','$L/+'
--local ioHeapValue, ioHeapStoreValue, ioHeapDelta = -1,-1,100      --moved to moteScan.lua
--local ioVddValue, ioVddStoreValue, ioVddDelta = -1,-1,0.1         --moved to moteScan.lua
--local iog0Index, iog0Value, iog0StoreValue, iog0Type = 3,-1,-1,'@S'     --moved to moteScan.lua
local iog2Index, iog2Value, iog2StoreValue, iog2Type = 4,-1,-1,'$L'     --moved to moteExecute.lua
--local iog3Index, iog3Value, iog3StoreValue, iog3Type = 9,-1,-1,'$L'


m = mqtt.Client(clientId,keepAlive, '','')--user,password)

local function pub(topicPart, pl)
    --print('clientId='..clientId)
    --print('topicPart='..topicPart)
    --print('payload='..pl)
    m:publish(clientId..topicPart,pl,0,0, function(conn) print("--> "..clientId..topicPart..'\t\t'..pl) end)
end

local moteScan= require('moteScan')

local function subscribed(con)
    print (clientId..' subscribed to topics')
    moteScan:scanIo(pub)
end

local function connected(con)
    print(clientId..'  connected to '..brokerIp..':'..brokerPort)
    --m:subscribe(clientId..subListAll,0,subscribed)
    m:subscribe(clientId..'/'..subP,0,function()
        m:subscribe(clientId..'/'..subL,0,function()
            m:subscribe(clientId..'/'..subR,0,function()
                m:subscribe(clientId..'/'..subLua,0,subscribed)
            end)
        end)
    end)
end

local motex= require('moteExecute')
local spl= require('spl')
local function execute(conn, topic, data)
    if data ~= nil then
        print('<-- '..topic .. ":\t"..data )
        --decoding the following topics:
        --    <destType>/<destAddress>/<msgType>/<pointId>
        --  $M - Mqtt pub and sub
        --  $R - Reset Device
        --args: <msgType>,<pointid>,<payload>
        --  $L - Latch Control
        --  $R - Pulse Control
        --  $A - Analog Control
        --  $T - Time Control
        local splits = spl.split(topic,'/')
        --test for <destype> and <destAddress> match
        if splits[1]..'/'..splits[2] == clientId then
            --after match execute for types
            motex:execute(splits,data,m,pub)
        end
    end
end

--m:lwt("/lwt", "offline", 0, 0)
m:on("connect", function(con) print ("connected..") end)
m:on("offline", function(con) print ("offline") end)
m:on("message", execute)

tmr.alarm(1,200,1,function()
    local ip=wifi.sta.getip()
    if ip ==nil then
        --print('.')
    else
      m:connect(brokerIp,brokerPort, 0,connected)
      tmr.stop(1)
    end
end)


moteExecute.lua
Code: Select all-- mote.lua
--inteface definition to mqtt
--gpioIndex=    {   0 ,   1 ,   2 ,   3 ,   4 ,   5  ,   6  ,   7  ,   8  ,   9 ,  10 ,  11 ,  12},
--gpioMap=      {'g16', 'g5', 'g4', 'g0', 'g2', 'g14', 'g12', 'g13', 'g15', 'g3', 'g1', 'g9', 'g10'},

local mote={}

--output values
local iog2Index, iog2Value, iog2StoreValue, iog2Type = 4,-1,-1,'$L'
local iog14Index, iog14Value, iog14StoreValue, iog14Type = 5,-1,-1,'$L'

function mote:execute(splits,payload,m, pub)
   if splits[3]=='$M' then
            --sub/unsub to payload
            if splits[4] == 'sub' then
                m:subscribe(payload,0,function() print ('Additionally subscribed to'..payload) end)
--            elseif splits[4] == 'unsub' then
--                --m:unsubscribe(payload,0,unsubscribed)
--                print('no mqtt:unsubscribe() available yet')
            end
        elseif splits[3]=='$R' then
            --reset the 'program'
            print ('$R-RESTARTING...') node.restart()
        elseif splits[3]=='$Lua' then
            --send to Lua interpreter'
            node.output(function(str) pub('/@Lua',str) end, 1)   -- re-direct output to function
            node.input(payload..'\r\n')
            tmr.alarm(6,500,0,function() node.output(nil) end)  -- 500ms should do for the return value??
        elseif splits[3]=='$L' then
            --iog2 - FW pin 4 - write gpio2
            if splits[4]=='g2' then
                gpio.mode(iog2Index,gpio.OUTPUT)
                if payload=='0' or payload== 0 then
                    gpio.write(iog2Index,gpio.LOW)
                    --print ('$L GPIO LOW')
                    pub('/@L/g2',gpio.LOW)
                    iog2Value,iog2StoreValue = gpio.LOW,gpio.LOW
                else
                    gpio.write(iog2Index,gpio.HIGH)
                    --print ('$L GPIO HIGH')
                    pub('/@L/g2',gpio.HIGH)
                    iog2Value,iog2StoreValue = gpio.HIGH,gpio.HIGH
                end
            --iog14 - pin 13 - write gpio14
            elseif splits[4]=='g14' then
                gpio.mode(iog14Index,gpio.OUTPUT)
                if payload=='0' or payload== 0 then
                    gpio.write(iog14Index,gpio.LOW)
                    pub('/@L/g14',gpio.LOW)
                    iog14Value,iog14StoreValue = gpio.LOW,gpio.LOW
                else
                    gpio.write(iog14Index,gpio.HIGH)
                    pub('/@L/g14',gpio.HIGH)
                    iog14Value,iog14StoreValue = gpio.HIGH,gpio.HIGH
                end
            end
        elseif splits[3]=='$P' then   
            --iog2 - FW pin 4 - write gpio2
            if splits[4]=='g2' then
                gpio.mode(iog2Index,gpio.OUTPUT)
                if iog2StoreValue>0 then
                    gpio.write(iog2Index,gpio.LOW)
                    --print ('$P GPIO LOW')
                    pub('/@P/g2',gpio.LOW)
                    tmr.alarm(4,payload,0,function()
                        gpio.write(iog2Index,gpio.HIGH)
                        --print ('$P GPIO HIGH')
                        pub('/@P/g2',gpio.HIGH)
                        iog2Value,iog2StoreValue = gpio.HIGH,gpio.HIGH
                        tmr.stop(4) 
                    end)
                     
                else
                    gpio.write(iog2Index,gpio.HIGH)
                    --print ('$P GPIO HIGH')
                    pub('/@P/g2',gpio.HIGH)
                    tmr.alarm(3,payload,0,function()
                        --tmr.delay(data*1000)
                        gpio.write(iog2Index,gpio.LOW)
                        --print ('$P GPIO LOW')
                        pub('/@P/g2',gpio.LOW)
                        iog2Value,iog2StoreValue = gpio.LOW,gpio.LOW
                        tmr.stop(3)
                    end)                 
                end
            elseif splits[4]=='g14' then
                gpio.mode(iog14Index,gpio.OUTPUT)
                if iog14StoreValue>0 then
                    gpio.write(iog14Index,gpio.LOW)
                    --print ('$P GPIO LOW')
                    pub('/@P/g14',gpio.LOW)
                    tmr.alarm(4,payload,0,function()
                        gpio.write(iog14Index,gpio.HIGH)
                        --print ('$P GPIO HIGH')
                        pub('/@P/g14',gpio.HIGH)
                        iog14Value,iog14StoreValue = gpio.HIGH,gpio.HIGH
                        tmr.stop(4) 
                    end)
                     
                else
                    gpio.write(iog14Index,gpio.HIGH)
                    --print ('$P GPIO HIGH')
                    pub('/@P/g14',gpio.HIGH)
                    tmr.alarm(3,payload,0,function()
                        --tmr.delay(data*1000)
                        gpio.write(iog14Index,gpio.LOW)
                        --print ('$P GPIO LOW')
                        pub('/@P/g14',gpio.LOW)
                        iog14Value,iog14StoreValue = gpio.LOW,gpio.LOW
                        tmr.stop(3)
                    end)                 
                end
           
            end
    end
end

-- ------------------------------------------------------------------------- --
-- Define Mote "module"
-- ~~~~~~~~~~~~~~~~~~~~~~~


return(mote)

-- ------------------------------------------------------------------------- --


moteScan.lua
Code: Select all-- mote.lua
--inteface definition to mqtt
--gpioIndex=    {   0 ,   1 ,   2 ,   3 ,   4 ,   5  ,   6  ,   7  ,   8  ,   9 ,  10 ,  11 ,  12},
--gpioMap=      {'g16', 'g5', 'g4', 'g0', 'g2', 'g14', 'g12', 'g13', 'g15', 'g3', 'g1', 'g9', 'g10'},

local mote={}

local scanPeriod=500
--input values
local ioHeapValue, ioHeapStoreValue, ioHeapDelta = -1,-1,2000
--local ioVddValue, ioVddStoreValue, ioVddDelta = -1,-1,100
local iog0Index, iog0Value, iog0StoreValue, iog0Type = 3,-1,-1,'@S'
local iog15Index, iog15Value, iog15StoreValue, iog15Type = 8,-1,-1,'@S'

local function scan()
    --print('scan pubcb='..tostring(pubcb))
    --ioHeap
        ioHeapValue = node.heap()
        if math.abs(ioHeapStoreValue - ioHeapValue) > ioHeapDelta then
            ioHeapStoreValue = ioHeapValue
            --m:publish(tostring(clientId)..'/@A/heap',ioHeapValue,0,0, function(conn) print("--> "..tostring(clientId)..'/@A/heap:\t'..ioHeapValue) end)
            --print('/@A/heap='..ioHeapValue)
            mote.pubCb('/@A/heap',ioHeapValue)
        end
        --ioVdd33
        --ioVddValue = node.readvdd33()/1000
        --if math.abs(ioVddStoreValue - ioVddValue) > ioVddDelta then
        --    ioVddStoreValue = ioVddValue
        --    m:publish(clientId..'/@A/vdd33',ioVddValue,0,0, function(conn) print("--> "..clientId..'/@A/vdd33:\t'..ioVddValue) end)
        --   --pub('/@A/vdd33',ioVddValue)
        --end
       
        --iog0 - FW pin 3 - read gpio0
        gpio.mode(iog0Index,gpio.INPUT) iog0Value = gpio.read(iog0Index)
        if iog0Value ~= iog0StoreValue then
            iog0StoreValue = iog0Value
            --m:publish(tostring(clientId)..'/@S/g0',iog0Value,0,0, function(conn) print("--> "..tostring(clientId)..'/@S/g0:\t'..iog0Value) end)
            --print('/@S/g0='..iog0Value)
            mote.pubCb('/@S/g0',iog0Value)
        end
        --iog15 - pin 8 - read gpio15
        gpio.mode(iog15Index,gpio.INPUT) iog15Value = gpio.read(iog15Index)
        if iog15Value ~= iog15StoreValue then
            iog15StoreValue = iog15Value
            --m:publish(tostring(clientId)..'/@S/g0',iog0Value,0,0, function(conn) print("--> "..tostring(clientId)..'/@S/g0:\t'..iog0Value) end)
            --print('/@S/g0='..iog0Value)
            mote.pubCb('/@S/g15',iog15Value)
        end
--print('mote.scanIo.end')
end

function mote:scanIo(pubCb)
    --print('scanIo pubCb='..tostring(pubCb))
    --for i,v in pairs(pubCb) do print('i='..i) print('v='..tostring(v)) end
    mote.pubCb = pubCb
    tmr.alarm(2,scanPeriod,1,scan)--(pubCb))
end

-- ------------------------------------------------------------------------- --
-- Define Mote "module"
-- ~~~~~~~~~~~~~~~~~~~~~~~


return(mote)

-- ------------------------------------------------------------------------- --


spl.lua
Code: Select alllocal spl={}

local function split(inputstr, sep)
        if sep == nil then
                sep = "%s"
        end
        local t={} ; i=1
        for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
                t[i] = str
                i = i + 1
        end
        return t
end

spl.split =split
return(spl)


wifiStn_smc.lua
Code: Select all--print(wifi.sta.getip())
--nil
wifi.setmode(wifi.STATION)
wifi.sta.config("SMC","dummypassword")
--tmr.delay(1000000)
tmr.alarm(1,200,1,function()
    ip=wifi.sta.getip()
    --192.168.0.x for nubbleNet
    if ip ==nil then
        --print('.')
    else
      print('Wifi connected! IP='..ip)
      tmr.stop(1)
    end
end)