• dev
  • luamqtt - MQTT client written in pure lua

  • Edited


Hi all!
Let me introduce luamqtt - https://github.com/xHasKx/luamqtt - the MQTT client library for Lua programming language.
It's not based on any C module and written in pure Lua code from scratch and completely follows OASIS standards for the MQTT v5.0 and the MQTT v3.1.1 protocols.

The only main dependency is a luasocket module to open a TCP connection. But there is a mechanism to implement your own functions to open a TCP connection and send/receive from it. It's used, for example, in the OpenResty to use its ngx.socket.tcp module instead of luasocket.

This is a thread for discussion, feedback and feature requests of the luamqtt.
Alternatively, the GitHub issues are welcomed.

2 months later

Awesome work, I just found it and looking to give it a try on LogicMachine which don't have mosquitto package available.

DmitryG,
Thanks! And don't hesitate to post here your LogicMachine integration experience!

    Thanks, the main challenge with LM is that it does not support libraries, a library should be wrapped as a user script, which is basically a single file. I'm still trying to get my head around on how to "compile" this as i'm not Lua expert, yet.

      DmitryG
      So you have to emulate module loading by require() function: https://www.lua.org/manual/5.3/manual.html#pdf-require
      You may try to wrap each module file into a function, returning the module table. And write your own require() function calling that module-emulating functions.

      Do you succeed with opening TCP connection to internet from the LM device?

      Hi, it does have require(), however full module should be within a single file. Haven't had time to play around with that yet. I'm also waiting for forum account confirmation so I can get example of the other library wrapped from multiple source files.
      I will be making connections to local MQTT broker, but internet is also possible if network allows that.

        4 months later

        kial hi, I finally managed to find some time to try it out - seems to work without major changes, the only step i had to make is to pre-build scripts into single file and update bit logic wrapper (LM have built-in support bit.XXX functions, but not language "<<" feature)

          5 days later

          DmitryG , FYI, from v3.1.1 luamqtt will not require "bit" module if used with Lua 5.2, because this Lua version has a built-in module "bit32".
          If your LM runtime has Lua 5.2 or higher - it can simplify your deploy process

            7 months later

            Hi, I am trying to implement your piece of code in my Sierrawireless RV50X. I do not understand how to use the "run_ioloop" fonction in order to publish message every minute.
            can you help please ? thanks in advance

              aquaboxsalus, it depends on the Lua runtime available on your Sierrawireless RV50X.
              If it has some usual Lua interpreter - you may check out this test as an example: https://github.com/xHasKx/luamqtt/blob/master/tests/spec/ioloop.lua#L43

              Here you have a function loop_func() which will be called again and again by the ioloop.
              So you can insert a code into it to calculate how much time has passed since the last sending (use os.time for example).
              When you calculated a 1-minute diff - send an MQTT message or whatever you need.

                thanks. in the documentation i see that we can create an ioloop specifiying sleep argument ( sleep interval after each iteration (default 0))
                correct ? is it not better ? how to use that ? thanks

                  • Edited

                  aquaboxsalus
                  Yes, the documentation is correct. This parameter should be adjusted by you on the device. The lesser value leads to your handler being called more often, but check the CPU load and power consumption.

                    2 months later

                    Hello,
                    I am trying to implement mqtt support into a mudclient (Mudlet) that has lua as its backend script language. And i have almost gotten it to work the way i want it to using luamqtt. My challenge seem to be with the ioloop. If i run the ioloop the way the examples describe, I will basically crash the mudclient as the ioloop is blocking the "main thread" from executing.

                    I managed to get past this issue, by not running ioloop, but rather setting up a timer that run the client:_ioloop_iteration() at a fixed interval. This works ok'ish when i run it at 1 second period. Now i can publish, and subscribe to messages in Mudlet.
                    I would have preferred to run it faster though, as the client is "sluggish" when receiving external messages (understandably) with a 1 second period.
                    I did try to run the client:_ioloop_iteration() at 100ms instead, but then i had masive crashes again...

                    I guess my question is: Am i doing it wrong? Can i run the ioloop wihtout it crashing the main thread? Or if i need to run the ioloop manually, is this the correct way to do it, by manually calling _ioloop_iteration() at a fixed interval? Or is there a better way, calling some method that will check the inbound queue, fire the callbacks then exit without looping?

                    Thanks and regards!

                      • Edited

                      Hi EspenSolbu ,

                      To make the MQTT connection work, something in your code should periodically pull packets from the server and monitor a connection state.
                      The ioloop and its ":run_until_clients()" method (or "mqtt.run_ioloop(client)" wrapper) is the right thing to do that.

                      I'm not familiar with the Mudlet Lua environment, but if you can run a separate OS thread with the "mqtt.run_ioloop(client)" call in this - this can be the best option. So the entire CPU time of the separate thread will be used for network communication.

                      The other way is to use the networking capabilities of your Mudlet Lua environment. It's possible that it has its own sockets implementation. In this case, the best option will be to implement a "connector" based on that sockets: https://github.com/xHasKx/luamqtt#connectors

                      Finally, if you have only timers - your way is also can work. Here is a better code example:

                      local loop = require("mqtt.ioloop").get(true, {timeout=0.005}) -- NOTE: you can try to adjust this timeout value
                      
                      function on_timer()
                          loop:iteration() -- NOTE: instead of your "client:_ioloop_iteration()" call
                      end

                      I'm not sure what you mean by "masive crashes", so you may try to adjust the timeout=X value (up or down) in the code above to try to get rid of those crashes.

                      4 months later

                      Thank you for your work and this nice module. I am planning to write a simple Lua client which should get MQTT traffic and send over to our Kronometrix Analytics backend for analysis and visualization. The client will be using Lua 5.4

                      5 months later

                      hello, salam, is it possible to make a mqtt connection between browser and lua over websocket

                        i have a react app on browser which only can connect to mqtt on websocket, then on openwrt for server side i only can run lua and i want to connect it to mqtt with websocket protocol.
                        so what is the best answer and practice

                          8 months later

                          Hi folk, I'm trying to setup 2 clients running in parallel on the same device (they shall connect to different brokers. 1st to a local broker on the device, 2nd one to an off-board broker, e.g. flespi). I can add the 1st client to the loop. How to add the second client in a proper way? Shall I utilize e.g. the connack callback function? So if the 1st client is successfully connected, the second one shall start connecting. So something like this?
                          client1 = mqtt.client(client1_config)
                          mqtt.run_ioloop(client1)
                          on positive connack callback -->
                          client2 = mqtt.client(client2_config)
                          mqtt.run_ioloop(client2)

                            jp_one Use this code to add another client to current ioloop when you need (for example, in the connack callback):
                            mqtt.get_ioloop():add(client2)