How to run an mqtt-repl?

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
User avatar
tve
Posts: 214
Joined: Wed Jan 01, 2020 10:12 pm
Location: Santa Barbara, CA
Contact:

Re: How to run an mqtt-repl?

Post by tve » Sat Jan 25, 2020 10:01 pm

OK, couldn't wait, had to look... Section 4.6 "Message Ordering" of MQTT3.1.1 (http://docs.oasis-open.org/mqtt/mqtt/v3 ... c398718105) says "When it re-sends any PUBLISH packets, it MUST re-send them in the order in which the original PUBLISH packets were sent (this applies to QoS 1 and QoS 2 messages)" and further (non-normative comment explaining that message duplication may occur) "For example a publisher might send messages in the order 1,2,3,4 and the subscriber might receive them in the order 1,2,3,2,3,4.".

All this assumes that both clients (the one running on the board and the one on the "computer") use QoS 1 (or 2)

User avatar
pythoncoder
Posts: 4466
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: How to run an mqtt-repl?

Post by pythoncoder » Sun Jan 26, 2020 10:05 am

tve wrote:
Sat Jan 25, 2020 4:19 pm
I agree in general about the short message size, however, MQTT in this case is over TCP, which is a reliable byte stream, with a max packet/segment size, and with selective retransmission (IIRC LwIP does support that). TCP also has a max retransmission count, so it will eventually give up.
TCP is reliable in principle, but it can't overcome the limitations of physics. A radio link is inherently unreliable: in extremis one endpoint can move out of range of the other. At the MQTT level the qos==1 guarantee applies to the message as a whole, and the entire message will be retransmitted on error. So the statistical behaviour in the presence of an imperfect link seems inescapable.

I'm not criticising your use of long messages: if your link is reliable they should present no problems.
Peter Hinch

User avatar
tve
Posts: 214
Joined: Wed Jan 01, 2020 10:12 pm
Location: Santa Barbara, CA
Contact:

Re: How to run an mqtt-repl?

Post by tve » Sun Mar 08, 2020 6:33 am

pythoncoder wrote:
Sat Jan 25, 2020 9:41 am
tve wrote:
Fri Jan 24, 2020 6:30 pm
...
- I've made some additions to the mqtt_as library so message bodies can be processed as streams instead of just as byte buffers, this allows a call to `publish` to pass a stream and a subscription callback to receive a stream. This allows very large messages to be processed, such that a large file can be sent/received as one message, up to the limit of the broker (and whatever sits at the other end of the message exchange, e.g. paho-mqtt passes everything in in-memory buffers).
...
Interesting. The anticipated use case for mqtt_as was for microcontrollers sending and receiving short messages.

In my solutions I aim for resilience over an unreliable physical medium (radio). In poor propagation conditions resilience becomes less achievable as message length increases. This is because the probability of a mid-message dropout increases with length. If qos==0 the message will be lost. If qos==1 it will be retransmitted, potentially ad nauseam if conditions are sufficiently poor.

This may not be an issue in your application but in general I recommend short messages.
I did some tests and implemented it both ways.
Sending 24KB of data and storing it in a file in flash takes about 5 seconds with the streaming (one message) implementation and about the double if I send one message per 2600 bytes.
Fetching 24KB of data from a file in flash takes under 2 seconds with the streaming implementation and about 10 seconds if sending one message per 2600 bytes.

(Edited:) When sending the difference seems to be that with streaming it's easy to open the file once and keep writing to it, whereas for the multiple message implementation I re-open the file in append mode for each message.

When fetching as a single message stream the esp can basically stuff the TCP socket as fast as it can read from flash and send because the TCP ACKs come in fast and furious. When sending individual messages it has to wait for an MQTT ACK after each message.

Update:
I re-implemented the "sending" so it reuses the open file descriptor as opposed to re-opening the file. The result is ~6s, i.e. one second more than the streaming implementation.
I also hacked the mqtt publish function so it can send asynchronously at qos 1: it send and stores the message without waiting for an ack, and then checks for the ACK at the next call. That brought the "fetching" down to about 3 seconds, again 1 second more than the streaming implementation.

Post Reply