In Sparkplug, what is the purpose of the messages in EoN node session establishment - mqtt

I'm currently trying to understand section 8.2 "EoN Node Session Establishment" of the Sparkplug specification (rev 2.2). Figure 4 shows several key points that seem to contradict my current understanding:
step 1, CONNECT, is clear to me
step 2 in the figure says that the EoN sends a SUBSCRIBE(NBIRTH) to the MQTT server. Why would the EoN subscribe to that topic? I would have expected it to PUBLISH a message to tell other clients that it is now connected, but that doesn't seem to happen at all.
step 2 as explained below sets the EoN Node Death Certificate, but I would have expected that to happen in step 1, CONNECT, as a Will Message.
step 3 in the figure is the EoN sending PUBLISH(NCMD, DCMD, STATE), but my previous understanding was that NCMD and DCMD are sent by the Primary Application. I would have expected the EoN to SUBSCRIBE to these, but again that doesn't happen. I what case do EoN nodes send NCMD or DCMD?
step 3 as explained below more matches my expectations and seems to contradict the figure.
at the bottom of the figure (not numbered) is the EoN sending SUBSCRIBE(NDATA), and while I haven't read the full spec yet, my understanding is that the EoN would PUBLISH(NDATA). In what scenario would another client send NDATA to an EoN, and which client would do that? Is there a simple trick to remember what gets sent to an EoN as NCMD and what gets sent to it as NDATA? (I'm assuming that the EoN sends NDATA as the normal monitoring flow, so I'm not talking about that case here.)

Related

NodeMCU resest with mqtt.client:close()), or mqtt.client:connect()

I have an application that uses mqtt for communication between modules and with a mobile terminal.
In some situations when the messages do not arrive, the node performs a self test of MQTT (sending a msg to itself), and when the selftest fails, tries to reconnect to the broker (mqtt offline not always arrives). And then two problems may arise:
If I perform a mqtt.client:close() to assure that the client is closed (to avoid the second problem) and the client is already closed, the node resets.
If I perform a mqtt.client:connect() and the client is still connected, an exception and a restet occurs.
is there a way to know if the mqtt client is connected or not?
Thanks for your comment. I am going to describe what I am doing, to see if you can help me:
I have two independent system, a master and a slave. The master publish a test message every 10 minutes. If there is no answer from the slave. it publish a test message to itself. If this self test does not arrive, a disconnection from the broker is assumed, and a reconnection is initiated.
And here is where the problem comes, sometimes the client is disconnected and everything go well, but sometimes it is still connected but unresponsive, and the node resets with an exception "already connected".
Performing a mqtt:close() previously to the reconnection, should be safe, but if I send it and the client is truly disconnected, the node resets without any reason (known to me).
All this is happening without receiving any offline message.
Instead of waiting for messages manually sent by the master client (which could fail to send for various reasons, leading a listening device to the wrong conclusion about the state of its connection to the broker), I recommend using MQTT's built-in connection management.
First, you can make sure that each client's initial connection has succeeded by including an error handler in :connect(). If the client really opens, nothing in the NodeMCU documentation indicates that it will close itself; it may go offline.
Once connected, the client only knows that something is wrong when it sends a message and does not receive a response. It sounds like you are not calling :publish() much (which would otherwise let you know by returning false), so pinging may be best. If you expect to receive a message from the broker every n seconds, set a keepalive time slightly higher than that on the client.
Then, failure to get a response to those messages should trigger an event that you can respond to. That might be something like the following (not tested, may work better called outside the callback):
m:on("offline", function(client) m:close() end)

deepstream message delivery gaurantees

I have been looking at various real time message libraries but I could not find following details of them.
1) Guaranteed delivery of messages
if a message was sent by client a - it's guaranteed that client b will receive it? (built-in ack and retry mechanisms)
2) Guaranteed order of messages
if 2 messages were sent by client a - it's guaranteed that client b will receive them in correct order ?
I googled but didn't find answers to my questions, so I'm posting here.
I would like to know it for following libraries
deepstream.io https://deepstreamhub.com
socket.io http://socket.io
emitter.io http://emitter.io
Thanks!

Receive offline messages mqtt

I'm using mosquitto as broker and paho(python) as client. I'm trying to make subscriber to receive offline messages.
For that I made following changes:
Fixed client ID
qos level 2
but, still the subscriber is not able to receive messages.
any help?
Thanks,
Rahul
In order to have your client as a durable client and receive messages that were sent to topics when it was offline, you need to meet the following criteria:
Fixed client ID (as you've done)
Always connect with clean_session=False
Subscriptions must be made with QoS>0
Messages published must have QoS>0
The mistake that I make most frequently is to forget either one of points 3 and 4, so I'm publishing with QoS=0 or subscribing with QoS=0, either of which would cause messages not to be stored.
You could also look at the queue_qos0_messages option to tell the broker to store QoS=0 messages as well. Note that this is an implementation detail that may be specific to mosquitto.
Check if you have set the retain flag to true when publishing message to topic, with retain=true, new connected client which subscribes the topic will receive the retained message.

iOS: Unable to fetch Offline messages for XMPP Chat

I am facing an issue with the presence status, following the documentation and XMPPframework example code. I have written a chat application.
Problem : When the user 1 & 2 are online I get the status successfully and they can chat with each other. However when the user 2 goes physically offline via (Wifi OFF / 3G Off) User 1 is not getting the offline status from XMPP and hence what ever messages are sent from that instant of time are lost when the user 2 comes online.
It seems since the user 2 is not notified or stored as offline in XMPP and hence its not storing the offline messages to push back to user 2 when it comes online.
I have tried to resolve this by explicitly writing a [goOffline] call to XMPP, however the call is shown in 'SEND log' for 'user 2' but not received in 'RECV log' in user 1 from XMPP, due to which the message are lost in between.
Also tried with other sources replies.
Set status for presence available and send XMPP
priority changed with values non-negative
XMPPArchiving work but this is not what I wanted.
Server side Mod_zero push enables but get only first message push notification sometimes.
Setting limit on ejabberd.cfg file for users and offline message limit.
request for offline message pull.
Can anyone help me with this?
This is very typical situation where client losses network but server can't detect that it is offline.
To detect status of each client, server need to send PING packets to every client and wait for response.
If client responds then fine otherwise server will mark that client as offline and every other online client will be informed automatically.
Here is PING Module implementation for ejabberd XMPP Server (hope you are using ejabberd server):
mod_ping:
send_pings: true
ping_interval: 10
timeout_action: kill
ping_ack_timeout: 10
This has to be written in ejabberd.yml configuration file.
At client side also we need to enable ping module to respond to server pings as:
private var xmppPing: XMPPPing?
xmppPing = XMPPPing()
xmppPing!.activate(xmppStream!)
This code has to be written while we setupStream() for iOS.
For detailed info, please go through mod_ping documentations.
Sounds like your problem is at server level. The server thinks that the user is online so it sends the message but nobody gets it. This does not really have a simple solution.
1.
The best solution would be delivery receipts. Where basically when the message is sent to your client, your client returns a confirmation of delivery receipt. If the server does not get that receipt it would resend the message every n time. Depending on your XMPP server you might find a already made solution, of not you would have to roll out your own.
2.
A possible hack would be to have your server always store and deliver last 10 messages and then at client side you discard repeated... This also depends on your server implementation. XMPP MUC and PubSub have resources along these lines.
For a long term scalable solution, you'll need to deal with this both at server and client level.

MQTT messageId practical implementation

The company I am working for has evaluated MQTT and decided to use it as a core messaging platform for a large scale system. The main reason is how compact the protocol is and how easy it can actually be implemented. I have a single issue with MQTT though and I'm seeking for an answer to the following question:
QoS1 and QoS2 messages require confirmation from the client. The only thing I know about the message (identifying it) when receiving PUBACK, PUBREC, PUBREL and PUBCOMP is messageId and the clientId. Message id is an unsigned int16 so the max value is 65535. It doesn't seem to be large enough for long running clients, say a year, sending 15 QoS2 messages an hour.
I am not quite sure if there's any other way to identify the message? I would like to be as compliant with the standard as possible.
Probably the first point to make clear is that message IDs are handled on a per client and per direction basis. That is to say that the broker will create a message ID for each outgoing message with QoS>0 for each client that is connected and these message IDs will be completely independent of any other message IDs used for the same message published to other clients. Likewise, each client generates its own message IDs for messages that it sends.
The message ID doesn't have to be unique, so your client sending 15 messages per hour with QoS level 2 would simply overflow at some point. The real limitation is that there can only be a maximum of 65535 messages per direction "in flight" at once (i.e. part way through the message handshake). Once a message with a given ID has been fully processed then that message ID can be reused.
Another way of looking at it is to consider how it would work if your client only ever had one message in flight at once, whether because of the rate the messages are being transmitted or by design in the way you handle the messages. In this case, you could keep message ID set to 1 for every single message because there is never a chance that there will be a duplicate.
If you wish to support having multiple messages in flight at once it would be relatively straightforward to check there are no message ID duplicates before you assign a new one.
Because the message ID is per client, if you send a single message to >65535 clients there will be no chance of message ID collisions. If you send >65535 messages to each client at once and the message flows aren't complete then there will be problems.
Answering the comment "I have noticed that every MQTT broker tends to deliver only the last QoS1/2 message":
The broker will only send messages to clients it knows about. If you connect for the first time there is no way to get messages from the past, with one exception: retained messages. If a message is set to retained then it is a "last known good" value. When a new client subscribes it will be sent the retained message immediately which makes it useful for things that are updated infrequently. I suspect this is what you are referring to. If you want a client to have messages queued when it is not connected then you must connect with the "clean session" option disabled to make the client persistent. You must also use QoS>0 subscriptions and QoS>0 publications. When your client reconnects (with clean session still set to disabled), the queued messages will be delivered. You can normally configure the number of messages to queue in this way in the broker, where any further messages will be discarded. An important point is that queueing messages for a client that has not previously connected is not supported by design.
For delivering more messages at QOS1 or QOS2, you should use concept of persistant memory. In this when ever a subscriber is not available the message get stored in persistant memory and deliver once subscriber is connected. You can do this at QOS0 also after configuring mosquitto.conf file.

Resources