Home Rolled MQTT Module

I think everyone is quite aware of the cirrus link offering.

A question for the forum: has anyone here ever written your own MQTT module?

We've done one for Kafka and I'm considering making one for MQTT subscribe but before setting about writing it, wanted to see if anyone has already done it.

Thanks,

Nick

What's missing from Cirrus Link's stuff that is a deal-breaker? I wouldn't re-invent the wheel, unless it's going to be a much, much better wheel.

Right now our fleet is around ~150 gateways and I guess it will double in a few years.

The answer to your question is: cost.

Nick

1 Like

If you don’t need sparkplug and just want to publish or consume simple MQTT it seems feasible.

1 Like

You could probably use:

And a managed tag proviser

To build a module for Ignition to consume raw mqtt and expose the data for the gateway.

Yes, exactly. Using the python client in my example repo and the Adafruit IO broker, it was simple enough to get messages on reception in java.

What I am thinking about is pretty much what you mentioned:

  1. MQTT client
  2. Managed tag provider
  3. Settings page
  4. Status page or status page contributor

Then inside Igniton the message is just a string memory tag which can be used however needed, for example explode JSON values into individual key pairs with a UDT.

Quick Test Subscription Code

import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.util.UUID;

public class subscribe {
    static String BROKER = "tcp://io.adafruit.com:1883";
    static String USERNAME = "";
    static String TOPIC = "onoff";
    static String AOIKEY = "";

    public static void main(String[] args) throws MqttException {
        String FEED = String.format("%s/feeds/%s", USERNAME, TOPIC);
        String publisherId = UUID.randomUUID().toString();

        MqttConnectOptions options = new MqttConnectOptions();
        options.setUserName(USERNAME);
        options.setPassword(AOIKEY.toCharArray());
        MemoryPersistence persistence = new MemoryPersistence();

        MqttClient client = new MqttClient(BROKER, publisherId, persistence);

        client.setCallback(new MqttCallback() {
            @Override
            public void connectionLost(Throwable cause) {
                System.out.println("Connection Lost: " + cause.getMessage());
            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                System.out.println("Topic: " + topic);
                System.out.println("Qos: " + message.getQos());
                System.out.println("message: " + new String(message.getPayload()));
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {
                System.out.println("Delivery Complete" + token.isComplete());
            }
        });

        client.connect(options);
        System.out.println(client.isConnected());
        client.subscribe(FEED);
    }
}

Nick

The biggest issue with MQTT in Ignition is its lack of ability to backfill derived ignition tags with the linked mqtt tag backfill data. Not so much anissue with the mqtt modules I assume, but a feature missing from IA's derived tags (if it's even possible to add). With our experience with the Alexandrina project presented at ICC, I would stay away from mqtt altogether until that's added. There was also the added complexity of adding a middle man protocol converter (redlion) to map plc tags into mqtt tags

Edit: and the issue with adding history directly on mqtt tags is that if the device goes offline for a period of time, the mqtt tags disappear from mqtt engine along with their history configuration, so if these tags come back, they've lost their history configuration which is another reason I will stay away from mqtt. I don't know if this can be resolved in the mqtt module?
Of course, this is only an issue if you care about backfilled history

3 Likes

Backfill on derived tags isn’t something that should exist. They’re just simple data mirrors and have no concept of what kind their source is.

You’re using them as a crutch to make up for shortcomings in the MQTT and managed tags when it comes to modeling flexibility. That’s where improvements should focus, not adding some tightly coupled feature to derived tags.

Hmm, yes and no. I feel that the MQTT Engine tags are similar to tags coming in from any other PLC source. Similarly to tags from the Logix driver, we create links to those tags in the Ignition tag browser using the opc type tags - we don't try to use the tags coming from the OPC-UA server itself. The same thing for tags coming from other 3rd party OPC-UA servers like those onboard Siemens PLCs. MQTT Engine is just another, fixed source of data pushed from the edge/PLC devices themselves. They're not complex enough to use directly as Ignition tags and hence must be referenced in Ignition tags to leverage the features offered such as history, alarms, UDT types, etc. etc.
The only difference is, to reference MQTT tags you must use Derived Tags

Hmmm. I'm not sure it wouldn't be helpful for derived tags to have a configurable hook to point at their source's history when asked for their own, maybe with post-processing of the data through the derivation function.

2 Likes

You're kinda' making the case that MQTT should be an OPC driver instead of a tag provider. :man_shrugging:

1 Like

Very true! It would make a lot more sense for them to come from an OPC source than listed as a tag provider, as you don't have a lot of flexibility with MQTT tags. e.g. you can't create tags, UDT types, you can't add a lot of the tag configuration available to you in standard Ignition tag providers... I can't see a situation where I would ever not use a combination of the MQTT tag provider and the standard Ignition tag provider side-by-side, unless it's a super simple use-case like maybe a home automation setting. But even then, I would want the flexibility provided by the standard tag provider to say, create memory tags which isn't possible in the MQTT tag provider unless you add them into the MQTT slaves themselves. If you have a lot of slaves, this is likely impractical, but it also shouldn't be the responsibility of the edge device to provide SCADA-only tags cough PlantPax cough (which is one of the many the reasons this library is so bloated and ridiculous, and terrible for SCADA performance)

Agreed, the problem is they use the managed tag abstraction instead of e.g. OPC like Phil mentioned, so you don’t get any flexibility.

I’ve toyed with the idea of building an OPC UA - SparkPlug bridge, which would act as the SP primary or secondary and just expose it nicely over OPC UA for consumption on the other side of whatever network convinced you to use MQTT in the first place. But there’s an obvious conflict of interest that has prevented me from moving beyond a rough sketch…

But if you guys can do it better........... :grimacing:
Best not to comment on that though, haha

At least, at the moment, I won't be recommending MQTT for any projects we do as it currently stands. It's far too painful to work with and feels extremely clunky with all the workarounds needed

3 Likes

I’d probably do it as a standalone, open source server/bridge. IMO it’s the obvious marriage of 2 Eclipse Foundation projects.

The primary/secondary SCADA application is by far the most complicated part of SparkPlug. There’s easy libraries for putting Edge data up, but all the other sides of it are baked into products like Ignition. I think it’s far more common for an off the shelf product to have an OPC UA connector than be able to act as SparkPlug primary (Ignition is the only one I know of, but surely there are some others…), so bridging to OPC UA seems like it would be pretty useful in general.

Edit: rambling and spelling fixes because I’m on mobile.

1 Like

As an MQTT n00b (others did most of the MQTT work in the project I was partially on), I don't really understand some of that. What do you mean by a sparkplug primary?

Indeed. Bridging Milo and Paho makes sense, for a number of reasons. FWIW, I try not to use cost as a sole determinant of what projects I pursue. I think I'd be at a disadvantage if I tromped on CL's product niche and they decided to tromp on mine. (Not that I wouldn't, given a feature/functionality need. Like my treading on IA's toes with my new Logix and Omron support.)

Doing a Milo/Paho bridge with a clear advantage over CL offerings is not a trivial undertaking.

Meanwhile, has anyone asked CL if they'd consider an OPC implementation? Probably the right place to start.

SparkPlug isn’t totally decentralized or uncoupled. One subscriber must be acting as the “primary” application, responsible for monitoring and control of the Edge nodes (publishers). There can be other subscribers that are purely observing, or waiting in standby to take over, but something needs to be acting as primary.

If you’re using Ignition and the MQTT modules then they are playing this role, and exposing that subscribed data via the managed tag provider you see.

The real advantage would be for anybody who isn’t using Ignition. Because then instead of having to figure out how to act as a SP primary or secondary or observer or whatever you just point the OPC UA connector you certainly already have at this bridge that will do it for you.

Right now I think most applications that can act as SP primary are proprietary, but I haven’t really looked much. There may be some stuff out there on GitHub already.

Understandable, considering the difficulty. Somebody would have to invest substantial time in it, and for open source, that usually means a sponsor.

Maybe. Last year after reading the spec I was convinced I could build a working prototype over the 2 week Christmas / New Years break, but decided to spend most my time skiing instead…

Like most estimates I was probably off by an order of magnitude anyway :laughing:

4 Likes