I'm looking into implementing MQTT-SN on tiny embedded nodes in a home automation setting. Mostly JeeNodes (arduino + rfm12b) or wimpy ARM uC with 16KB flash and 4KB RAM. In these systems every byte counts. It seems to me that MQTT-SN is still too complex. I'm new to MQTT, so I expect there are some things I mis-understand or simply don't understand.
What I mean by "too complex" is the following. MQTT provides solutions for a number of issues: the core pub/sub routing, dynamic topic management, state retention (the Will notion), QoS/reliability, gateway/router detection, node/client presence/liveness, and perhaps more. MQTT-SN simplifies the verbosity of the message format and of the topics, but it doesn't really simplify the rest much, or perhaps not enough for me. And it doesn't offer a way to say "I want state retention and QoS but I don't want gateway detection nor node liveness". (The QoS -1 mode is one step in this direction, but it's a fixed package deal.) As a result it doesn't simplify the protocol state machine and that just ends up in a ton of code on a tiny uC. For example, as far as I can tell the arduino implementations out there use up the majority of program memory for MQTT. That's great for a demo, for real life the comm protocol has to use a minority of program space. At least in my book...
I believe the worst part of MQTT-SN is the QoS. The first problem is that it's solved anew for each message type: PUB has a PUBACK, SUB has a SUBACK, CONNECT has a CONNACK, etc. Trivial on a real machine, but on a uC just the dispatch of all the message types and the code fragment for each one becomes significant. But the bigger problem is that MQTT-SN doesn't allow QoS to be solved at the link layer (yes, I know that QoS=2 can't really be solved there). This is subtle until you try to implement retransmission. The key question is: if I just transmitted a packet can I sit there waiting for an ACK or rexmit timeout (whichever comes first) and drop everything else on the floor or can't I?
If the answer is "no, you have to accept other incoming messages" then you have to either buffer them (yet you have almost no memory) or deliver them to the app (which ends up requiring dynamic dispatch). If you deliver to the app chances are that the app will want to send something which will need to be queued (here goes the memory again). So you inherently buy into dynamic dispatch and buffering of a somewhat unbounded number of messages (the peer could easily feed you a dozen data packets before sending you the ACK you're waiting for).
In order for the answer to be "yes, you can just sit there" both ends must prioritize ACKs, which means that if they receive a message that requires an ACK they must send that ACK before sending anything else they may want to send. Unless I'm missing something this is the only way to ensure you don't have deadlock (or is that livelock?) where two nodes don't make progress because they're waiting on each other's ACK and neither can send it because they're repeatedly retransmitting another data packet.
Coming back to MQTT-SN, the ACKs are not at the transport level, they're higher up, which means that you actually can't generate immediate ACKs. In fact a forwarder or a GW can't generate most of the ACKs, only the broker can (right?). Thus I would claim that you cannot write a proper MQTT-SN implementation without dynamic scheduling and/or packet buffering. And the result of that is that by the time you've implemented MQTT-SN you have very little room left.
The simplification of the topics in MQTT-SN is nice, but I feel like I'm falling through the cracks. With "pre-defined" topics something still needs to pre-define the topics with the GW, and with "short topics" there's no wildcarding. Why is there no wildcarding? I was thinking about mapping the physical topology into the topic space: for each node there's a network id and a node id, and each message could have a 1-byte sub-topic and all this could be mapped into something like "/rfm12/<network_id>/<node_id>/<sub-topic>", where <xxx> refers to the decimal representation of the value. In addition each node could be auto-subscribed to it's part of the sub-tree (assuming this wouldn't cause it to receive its own messages). In the end this is like short topics but using fewer bytes and providing more functionality...
In the end I feel like I want a MQTT-UL (ultralight) or more flexibility in MQTT-SN that would have the following features:
- make gateway location/detection optional
- make node liveness optional
- allow retransmissions to be implemented at the link layer
- give me "handshake-less" topics that support wildcarding plus auto-subscription
- eliminate the flags byte in the publish message (after moving retransmission into the link layer the only flag that's left is the Will flag and that could be associated with the topic)
Whoa, this is a long post already. Apologies for that, this stuff has been swirling in my head for the past 2 days. Am I missing the point of MQTT and MQTT-SN completely perhaps? Do others feel similarly? Am I trying to shove a square peg into a round hole?
NB: I still see not MQTT-SN tag, I do see an mqtt and a MQTT tag now, so something probably went awry...