@@ -6,3 +6,105 @@ MicroPython shortcuts and doesn't work with CPython). It consists of
6
6
two submodules: umqtt.simple and umqtt.robust. umqtt.robust is built
7
7
on top of umqtt.simple and adds auto-reconnect facilities for some of
8
8
networking errors.
9
+
10
+ What does it mean to be "robust" ?
11
+ ----------------------------------
12
+
13
+ Modern computing systems are sufficiently complex and have multiple
14
+ points of failure. Consider for example that nothing will work if
15
+ there's no power (mains outage or battery ran out). As you may imagine,
16
+ umqtt.robust won't help you with your flat battery. Most computing
17
+ systems are now networked, and communication is another weak link.
18
+ This is especially true for wireless communications. If two of your
19
+ systems can't connect reliably communicate via WiFi, umqtt.robust
20
+ can't magically resolve that (but it may help with intermittent
21
+ WiFi issues).
22
+
23
+ What umqtt.robust tries to do is very simple - if while trying to
24
+ perform some operation, it detects that connection to MQTT breaks,
25
+ it tries to reconnect to it. That's good direction towards "robustness",
26
+ but the problem that there is no single definition of what "robust"
27
+ is. Let's consider following usecase:
28
+
29
+ 1. A temperature reading gets transmitted once a minute. Then the
30
+ best option in case of a transmission error might be not doing
31
+ anything at all - in a minute, another reading will be transmitted,
32
+ and for slowly-changing parameter like a temperature, a one-minute
33
+ lost reading is not a problem. Actually, if the sending device is
34
+ battery-powered, any connection retries will just drain battery and
35
+ make device "less robust" (it will run out of juice sooner and more
36
+ unexpectedly, which may be a criteria for "robustness").
37
+
38
+ 2. If there's a button, which communicates its press event, then
39
+ perhaps it's really worth to retry to deliver this event (a user
40
+ expects something to happen when they press the button, right?).
41
+ But if a button is battery-power, unconstrained retries won't do
42
+ much good still. Consider mains power outage for several hours,
43
+ MQTT server down all this time, and battery-powered button trying
44
+ to re-publish event every second. It will likely drain battery
45
+ during this time, which is very non-robust. Perhaps, if a press
46
+ isn't delivered in 15 seconds, it's no longer relevant (depending
47
+ on what press does, the above may be good for a button turning
48
+ on lights, but not for something else!)
49
+
50
+ 3. Finally, let's consider security sensors, like a window broken
51
+ sensor. That's the hardest case. Apparently, those events are
52
+ important enough to be delivered no matter what. But if done with
53
+ short, dumb retries, it will only lead to quick battery drain. So,
54
+ a robust device would retry, but in smart manner, to let battery
55
+ run for as long as possible, to maximize the chance of the message
56
+ being delivered.
57
+
58
+ Let's sum it up:
59
+
60
+ a) There's no single definition of what "robust" is. It depends on
61
+ a particular application.
62
+ b) Robustness is a complex measure, it doesn't depend on one single
63
+ feature, but rather many different features working together.
64
+ Consider for example that to make button from the case 2 above
65
+ work better, it would help to add a visual feedback, so a user
66
+ knew what happens.
67
+
68
+ As you may imagine, umqtt.robust doesn't, and can't, cover all possible
69
+ "robustness" scenarios, nor it alone can make your MQTT application
70
+ "robust". Rather, it's a barebones example of how to reconnect to an
71
+ MQTT server in case of a connection error. As such, it's just one
72
+ of many steps required to make your app robust, and majority of those
73
+ steps lie on *your application * side. With that in mind, any realistic
74
+ application would subclass umqtt.robust.MQTTClient class and override
75
+ delay() and reconnect() methods to suit particular usage scenario. It
76
+ may even happen that umqtt.robust won't even suit your needs, and you
77
+ will need to implement your "robust" handling from scratch.
78
+
79
+
80
+ Persistent and non-persistent MQTT servers
81
+ ------------------------------------------
82
+
83
+ Consider an example: you subscribed to some MQTT topics, then connection
84
+ went down. If we talk "robust", then once you reconnect, you want any
85
+ messages which arrived when the connection was down, to be still delivered
86
+ to you. That requires retainment and persistency enabled on MQTT server.
87
+ As umqtt.robust tries to achieve as much "robustness" as possible, it
88
+ makes a requirement that the MQTT server it communicates to has persistency
89
+ enabled. This include persistent sessions, meaning that any client
90
+ subscriptions are retained across disconnect, and if you subscribed once,
91
+ you no longer need to resubscribe again on next connection(s). This makes
92
+ it more robust, minimizing amount of traffic to transfer on each connection
93
+ (the more you transfer, the higher probability of error), and also saves
94
+ battery power.
95
+
96
+ However, not all broker offer true, persistent MQTT support:
97
+
98
+ * If you use self-hosted broker, you may need to configure it for
99
+ persistency. E.g., a popular open-source broker Mosquitto requires
100
+ following line::
101
+
102
+ persistence true
103
+
104
+ to be added to ``mosquitto.conf ``. Please consult documentation of
105
+ your broker.
106
+
107
+ * Many so-called "cloud providers" offer very limited subset of MQTT for
108
+ their free/inexpensive tiers. Persistence and QoS are features usually
109
+ not supported. It's hard to achieve any true robustness with these
110
+ demo-like offerings, and umqtt.robust isn't designed to work with them.
0 commit comments