As the title says... Chat on...

User avatar
By MikeV
#10699 I've eventually got MQTT to work on this build, but it's taken a long time! To figure out why it wasn't working I created a state machine so I could monitor each step. The main issue seemed to be the m:publish function which can't be recalled until it's completed its work. I've now trimmed it back and the code to the minimum that works for me. It seems to survive temporarily stopping the broker and the wifi node. "init.lua" contains just dofile("MQTT.lc") after compiling with node.compile("MQTT.lua"). Remaining HEAP is 11912 - so not much left to play with!

Code: Select all--—————————————————————————–
--MQTT.lua test code for NODEMCU 0.9.5 build 20150213
--LICENCE: http://opensource.org/licenses/MIT 
--Over engineered by: MikeV for an ESP01 module
--—————————————————————————–
--External modules
--—————————————————————————–
t=require("DS18B20")  --see http://tech.scargill.net/lua-and-the-ds18b20ds18b20p-temperature-sensor/
--—————————————————————————–
--Configuration parameters & initialise variables
--—————————————————————————–
broker = "192.168.1.108" -- IP or hostname of MQTT broker
mqttport = 1883          -- MQTT port (default 1883)
userID = ""              -- username for authentication if required
userPWD  = ""            -- user password if needed for security
clientID = "ESP1"        -- Device ID
GPIO0 = 3                -- IO Index of GPIO0 which is connected to a DS18B20
GPIO2 = 4                -- IO Index of GPIO2 which is connected to an LED
gpio.mode(GPIO2,gpio.OUTPUT) -- Make GPIO2 an output

count = 0  -- Test number of mqtt_do cycles
mqtt_state = 0 -- State control
--—————————————————————————–

function mqtt_do()
     count = count + 1  -- For testing number of interations before failure
     temp = t.readNumber(GPIO0) -- get reading from DS18B20
     if mqtt_state < 5 then
          mqtt_state = wifi.sta.status() --State: Waiting for wifi
     elseif mqtt_state == 5 then
          m = mqtt.Client(clientID, 120, userID, userPWD)
          mqtt_state = 10 -- State: initialised but not connected
          m:on("message",
          function(conn, topic, data)
               print(topic .. ":" )  --topic is not examined only printed for the purposes of this test
               if data ~= nil then
                    print(data)
                    if data == "OFF" then -- Only "OFF" or "ON" is recognised to change GPIO2 state
                         gpio.write(GPIO2,gpio.LOW)
                    elseif data == "ON" then
                         gpio.write(GPIO2,gpio.HIGH)
                    end
               end
          end)
          m:on("offline",
          function(conn)
               print("Offline!")
               mqtt_state = 10  -- State: reset to initialised but not connected
          end)
     elseif mqtt_state == 10 then
          m:connect( broker , mqttport, 0,
          function(conn)
               print("Connected to MQTT:" .. broker .. ":" .. mqttport .." as " .. clientID )
               m:subscribe("sensor/"..clientID.."/action",0,
               function(conn)
                    print("subscribed!")
                    mqtt_state = 20 -- Go to publish state
               end)
          end)
     elseif mqtt_state == 20 then
          mqtt_state = 25 -- Publishing...
          if gpio.read(GPIO2) == 0 then  -- Read the current state of GPIO2
                io_status = "OFF"
          else
                io_status = "ON"
          end
          m:publish("sensor/"..clientID.."/temp", temp.."C GPIO:"..io_status.." #:"..count.." ", 0, 0,
          function(conn)
              -- Print confirmation of data published
              print(temp.." degC GPIO:"..io_status.." #:"..count.." published!")
              mqtt_state = 20  -- Finished publishing - go back to publish state.
          end)
     else print("Publishing..."..mqtt_state)
          mqtt_state = mqtt_state - 1  -- takes us gradually back to publish state to retry
     end
end
--—————————————————————————–
--Run it!
--—————————————————————————–
tmr.alarm(0, 1000, 1, function() mqtt_do() end)
User avatar
By biobier
#10734
MikeV wrote:I've eventually got MQTT to work on this build, but it's taken a long time! To figure out why it wasn't working I created a state machine so I could monitor each step. The main issue seemed to be the m:publish function which can't be recalled until it's completed its work. I've now trimmed it back and the code to the minimum that works for me. It seems to survive temporarily stopping the broker and the wifi node. "init.lua" contains just dofile("MQTT.lc") after compiling with node.compile("MQTT.lua"). Remaining HEAP is 11912 - so not much left to play with!


Try to make some variables local it will speed things up as I learned.
User avatar
By m-cin
#10763
MikeV wrote:The main issue seemed to be the m:publish function which can't be recalled until it's completed its work.


Could anybody inlcude this info in NodeMCU API wiki? Every beginner stumbles over this little... peculiarity :)

There is even an open issue on this behaviour:

https://github.com/nodemcu/nodemcu-firmware/issues/146

None of the solutions proposed (lua_async and use of coroutine, as well as building all kind of queues) worked for me - not enough memory.

Next project - pure C :)

Regards
M.