• dev
  • luamqtt - MQTT client written in pure lua

zt190 take a look at device policy. It should allow your client to connect to the hub with given client-id, subscribe and publish to specific topics. Enable all options if unsure.
Here is the article we touch Azure device policy a bit: https://flespi.com/kb/flespi-to-azure

    8 months later

    Hi guys, many thanks for the great module! I'm trying to utilize SSL/TLS in order to securely communicate with flespi broker. Is my understanding correct, that luamqtt is not supporting certificate based authentication?

    So if token is regarded as not secure enough and luamqtt is used as MQTT client, the only way would to go would be via port 8883 or 443?

      jp_one I'm trying to utilize SSL/TLS in order to securely communicate with flespi broker. Is my understanding correct, that luamqtt is not supporting certificate based authentication?

      If you mean SSL/TLS secure transport for MQTT protocol - it's fully supported if your Lua runtime has a luasec (or compatible) module. And you can specify any custom SSL parameters like certificate file in the secure={...} table parameter in mqtt client instance constructor (see secure parameter description there).

      If you are talking about new MQTT 5.0 packet type AUTH - it's also supported in the luamqtt with client:auth() method. But this is a broker-specific authentication method, thus you cannot use it with flespi broker.

      jp_one So if token is regarded as not secure enough and luamqtt is used as MQTT client

      Sorry, I can't understand this part. Can you please rephrase it?

      jp_one the only way would to go would be via port 8883 or 443?

      I would say that you always should use port 8883 and SSL/TLS secure connection.
      But port 443 is for websocket transport, which is not supported by luamqtt.

        6 months later

        I currently have the problem that both update functions (loop and sync) block the process until a message is received.
        With the system I want to implement this library in I don't have the possibility to create a thread or have this run externally somehow. So the whole program will stop running until messages come in. I do however have the possibility to continually call a function. I thought I could use the run_sync methode as from the description, but that also waits for an incoming message.
        So I would need something more in line of a function that checks if a message was reveiced, if not it just moves along. Is there a straightforward way of calling such a function?

        • kial replied to this.

          Unfortunately the pull request didn't help with the problem.

            OleBier Do you have a way to operate with TCP sockets in async (non-blocking) mode in your system? What is the system?

              Honestly I have no idea. I haven't worked with networking that much to have a deeper understanding of it.
              I'm working with the Defold game engine which incorporates luasocket as default. It is possible to use other libraries, but anything that's not pure Lua needs to be adapted to the engine for it to work properly, so I would like to avoid that.
              Previously I used the MQTT client library from Paho, with which you manually had to call the handler in intervalls, which was perfect for my use case as the game engine does provide a function that gets periodically called. Recently we've updated our server and along with it switched to a newer version of Mosquitto, but I constantly get disconnected from it. So I was looking into using a newer MQTT library that also features MQTT version 5 and this one looked very promising.
              I hoped that there possibly would be some kind of function I could call instead of using the two give one. But poking at the library myself a bit I guess I will needs to make certain adjustments to use it.

                OleBier Regarding your description I suppose you need function ioloop_mt:iteration() - https://github.com/xHasKx/luamqtt/blob/master/mqtt/ioloop.lua#L109

                You can access it with

                local ioloop = require("mqtt.ioloop")
                
                print(ioloop.get().iteration) -- function: 0x612d866782c0

                This function intended to be run in some outer loop, but I think your engine's handler will be suitable for that too.

                  Thank you for creating the library and all the help you have given me. I managed to get it working with adding the following code to the init.lua. Which is basically just a slightly changed run_ioloop(...)

                  local loop = ioloop_get()
                  function mqtt.init_ioloop(...)
                  	for i = 1, select("#", ...) do
                  		local cl = select(i, ...)
                  		loop:add(cl)
                  		if type(cl) ~= "function" then
                  			cl:start_connecting()
                  		end
                  	end
                  end
                  
                  function mqtt.iterate_ioloop()
                  	loop:iteration()
                  end
                  7 months later

                  Hello,

                  I’m using CoppeliaSim for robot simulation and LuaMQTT to connect the robot to a local Mosquitto MQTT broker. The issue is that the MQTT connection is blocking the simulation, preventing the robot from moving based on MQTT payloads received in topics.

                  I’m trying to use async code to handle the MQTT connection without blocking the simulation, but it’s not working as expected. When the MQTT connection is established, the simulation gets blocked.

                  I’ve used coroutines in CoppeliaSim and LuaMQTT’s callback functions, but the MQTT connection still seems to block the simulation.

                  Has anyone managed to make this work asynchronously in CoppeliaSim? Any help would be appreciated!

                  PS: Just to be clear, the broker works, and both publish and subscribe functions work. However, when the MQTT connection is established, the simulation crashes.

                  Thank you in advance for your help!

                  BochraDahmen , the call for mqtt.run_ioloop(client) is blocking your runtime. You need to run ioloop_mt:iteration() method of the default ioloop instance there instead. Default ioloop can be obtained with require("mqtt.ioloop").get() function

                  kial Thank you very much for your help! My code required a few adjustments related to the luamqtt library, such as using ioloop_mt:iteration(), as well as modifications specific to CoppeliaSim, like ensuring the coroutine is resumed at least once per simulation step.

                  For anyone who might find it useful, here is the working code, it connects CoppeliaSim to a local MQTT broker in a non-blocking way :

                  function sysCall_init()
                      sim = require('sim')
                  
                      -- Initialize MQTT
                      package.path = package.path .. ";C:/Program Files/CoppeliaRobotics/CoppeliaSimEdu/lua/mqtt/?.lua"
                      print("Package path updated:", package.path)
                  
                      local mqtt = require("mqtt")
                      local ioloop = require("mqtt.ioloop").get()  -- Get the default ioloop instance
                  
                      if not mqtt then
                          error("Failed to load MQTT library. Check the path and ensure the library exists.")
                      end
                  
                      -- Create MQTT client
                      client = mqtt.client{
                          uri = "127.0.0.1:1883", 
                          id = "robot_client",
                          clean = true
                      }
                  
                      if not client then
                          error("Failed to create MQTT client.")
                      end
                  
                      print("Created MQTT client:", client)
                  
                      -- Set up the MQTT client on events
                      client:on{
                          connect = function(connack)
                              if connack.rc ~= 0 then
                                  print("Connection to broker failed:", connack:reason_string(), connack)
                                  return
                              end
                              print("Connected to broker:", connack)  
                  
                              -- Subscribe to the topic after connection
                              assert(client:subscribe{
                                  topic = "robot/commands",
                                  qos = 2,
                                  callback = function(suback)
                                      print("Subscribed to topic:", suback)
                                  end
                              })
                          end,
                  
                          message = function(msg)
                              assert(client:acknowledge(msg))  
                              print("Received message:", msg.topic, msg.payload)
                          end,
                  
                          error = function(err)
                              print("MQTT client error:", err)
                          end,
                  
                          close = function()
                              print("MQTT connection closed")
                          end
                      }
                  
                      -- Attach client to the ioloop
                      local success, err = pcall(function()
                          ioloop:add(client)
                      end)
                      if not success then
                          print("Failed to add client to ioloop:", err)
                          return
                      end
                      print("Client added to ioloop")
                  
                      -- Create the coroutine for the MQTT loop
                      mqttCoroutine = coroutine.create(function()
                          while true do
                              local success, err = pcall(function()
                                  ioloop:iteration(0.1)  -- Small timeout to prevent excessive CPU usage
                              end)
                              if not success then
                                  print("Error in ioloop iteration:", err)
                              end
                              coroutine.yield()  -- Yield control back to CoppeliaSim
                          end
                      end)
                  end
                  
                  -- Resume the coroutine in the sensing function
                  function sysCall_sensing()
                      if coroutine.status(mqttCoroutine) ~= 'dead' then
                          local ok, errorMsg = coroutine.resume(mqttCoroutine)
                          if errorMsg then
                              error(debug.traceback(mqttCoroutine, errorMsg), 2)
                          end
                      end
                  end
                  Write a Reply...