MQTT using CURLSMBS

Hi all,

i wanted to share my mqtt eperiences, trying to find a fast way to implement MQTT in xojo is pretty hard since MQTT can get pretty complex. So i found that CURL has MQTT (limited) implemented and is usable with the CURLSMBS class (maybe using CURLMBS etc also).

You need a subclass of CURLSMBS named myCURLSMBS, add the “Write” event:

Function Write(data as string, dataSize as Integer) Handles Write as integer
  Var packet As MemoryBlock = data
  packet.LittleEndian = False
  Var stream As New BinaryStream(packet)
  
  var topic_length As UInt16 = stream.ReadUInt16
  Var topic As String = stream.Read(topic_length, Encodings.UTF8)
  var payload As String = stream.Read(stream.Length - (2 + topic_length))
  
  System.DebugLog "Topic: " + topic
  System.DebugLog "Payload: "  + payload
  
  Return dataSize
End Function

On your main window add “c As myCURLSMBS” (to receive/subscribe) and “c1 As myCURLSMBS” (to send/publish) as a property.

So this is how to get started to SUBSCRIBE:

c = New myCURLSMBS
'c.OptionVerbose=true
'c.CollectDebugMessages = True
c.YieldTime = True
c.OptionGet = True
c.OptionURL = "mqtt://broker.hivemq.com:1883/testing123"
Var status As Integer = c.Perform

What is happening is we request the “mqtt://” protocol to be used as a GET request, internally this means “subscribe to an mqtt topic given by the OptionURL”. We set the required values, you could optionally set the optionVerbose and CollectDebugMessages to get more info.

Now we can also PUBLISH to a topic:

c1 = New CURLSMBS
c1.OptionUserAgent = "Xojo CURL MQTT 1"
c1.CollectDebugMessages = True
c1.CollectOutputData = true
c1.OptionVerbose=true
c1.YieldTime = True
c1.OptionURL = "mqtt://broker.hivemq.com:1883/testing123"
c1.OptionPostFields = "Hello World from Xojo"
c1.OptionPost = True

Var status As Integer = c1.Perform
System.DebugLog CurrentMethodName + ", code: " + status.ToString
System.DebugLog c1.DebugMessages
System.DebugLog c1.OutputData
System.DebugLog "------------------"

I’ve commented out some additionals so you can easily enable them. We set the same topic and host, but this time we set OptionPOST = True and we create a new instance since this just publishes and quits.

Currently CURL doesn’t support all mqtt features like client id (i tried the useragent option but it didn’t work).
So there are some limitations:

  • Only QoS level 0 is implemented for publish
  • No way to set retain flag for publish
  • No TLS (mqtts) support
  • Naive EAGAIN handling will not handle split messages

I hope you have a happy day using MQTT with CURL provided by Xojo, CURL and MBS.

5 Likes

The RabbitMQ plug-in doesn’t work for you here?

https://www.monkeybreadsoftware.de/xojo/plugin-rabbitmq.shtml

That has too much overhead requirements. It does work however but still requires alot of setup and configuration (channeling AMPQ and MQTT). I’d rather have Mosquitto or some other broker for ease-of-use.

If you can add Mosquitto i’d be even happier…:wink:

i’m actually not sure if you can directly connect to an mqtt broker with the RabbitMQ plugin, can i? @Christian_Schmitz

A few months ago, I had a similar need.

I ended up developing a Xojo Web 2.0-based middleware application that uses the MBS RabbitMQ plugin. It integrates with a RabbitMQ message broker hosted at AWS (“AmazonMQ” - Message Broker - Amazon MQ - Apache ActiveMQ and RabbitMQ Message Service - AWS ).

I chose RabbitMQ over MQTT primarily because the MBS plugin made everything easy. RabbitMQ is much more feature-rich (with support for complicated routing, etc) than MQTT. However, MQTT seems to me to be much more lightweight (making it ideal for IOT apps).

That all being said, it is possible to add MQTT support to RabbitMQ via the MQTT Plugin: MQTT Plugin — RabbitMQ It’s not ideal, but it is an interesting option.

I wish that we had a pure MQTT option. I know there are (or were) some open source attempts at this, but I had no luck with them.

3 Likes

That is pretty nice but for my usage i need a local running broker that can be setup by anyone without too much knowledge and that’s where mqtt does a good job. Also there seems to be more developers with mqtt knowledge. And all that is why we use mqtt, but we also mis a good plugin or class for xojo.

We did use rabbitmq in our tests but it was just too much for the people that need to manage it.

We also tried all kinks of other solutions, like tcpserver with json transport over tcp and udp etc. Mqtt just came out stable, reliable, easy and as an overall winner.

I guess it depends on your requirements, and flexibility.
The above mqtt solution is not my preferred solution but it’s one that works in xojo for now.

I just tried the receiver (listener) part. I have the bad effect that the Prepare call for the subscription kind of hogs the CPU until it eventually times out after a minute or so.

Tried it within a Thread to no avail. I’d expect that the Prepare call returns immediately and then only invokes the Write event when a msg is received.

Using MBS 22.5 for this test (I can’t easily use newer because, well, I’m using REAL Studio :slight_smile: )

I have figured it out - instead of calling Perform immediately, one needs to create a CURLSMultiMBS instance, add the curl object to it, and then call the multi’s Perform function regularly from a Timer. That’s what’s needed for Plugins 22.5.

With recent plugins, it’s easier - there’s a MQTT example with MBS now.

2 Likes

Note: CURLSMBS read drops the connection after some seconds (60?) like alwasy, even tcp keep alive options won’t help!

I’d be really really happy if there was some actual MQTT library in xojo with QOS 0,1,2 and Retain ability !

1 Like

Even that should be done automaticly when you set the AutoPerform = True for the CURLSMultiMBS instance but that don’t seem to work ?

What have you tried?
OptionTCPKeepAlive property?

yes:

The sample code:

Var c As New CURLMqttRec

c.OptionURL = URLField.Text
c.OptionConnectionTimeout = 30
c.Tag = "my-address-that-works.local"
c.OptionTCPNoDelay = False
c.OptionTCPKeepAlive = True
c.OptionTCPKeepInterval = 15
'c.OptionTCPKeepIdle = 15

curl = c

// this runs asynchron in background and calls Write event when needed
CURLSMultiMBS.SharedInstance.AutoPerform = True
Call CURLSMultiMBS.SharedInstance.AddCURL(C)

result directly after mqtt message from remote, i see:
content: “hello from mqtt”

after 1-60 seconds later:
finished: 56 (curl error code)

on mosquitto mqtt broker/server side:
Client curl839fgfg has exceeded timeout, disconnecting

clearly the CURL plugin doesn’t respond to the mqtt pings (PINGREQ) …