@@ -26,11 +26,15 @@ MicroPython's `asyncio` when used in a microcontroller context.
26
26
6.1 [ Encoder class] ( ./DRIVERS.md#61-encoder-class )
27
27
7 . [ Ringbuf Queue] ( ./DRIVERS.md#7-ringbuf-queue ) A MicroPython optimised queue primitive.
28
28
8 . [ Delay_ms class] ( ./DRIVERS.md#8-delay_ms-class ) A flexible retriggerable delay with callback or Event interface.
29
- 9 . [ Additional functions] ( ./DRIVERS.md#9-additional-functions )
30
- 9.1 [ launch] ( ./DRIVERS.md#91-launch ) Run a coro or callback interchangeably.
31
- 9.2 [ set_global_exception] ( ./DRIVERS.md#92-set_global_exception ) Simplify debugging with a global exception handler.
29
+ 9 . [ Message Broker] ( ./DRIVERS.md#9-message-broker ) A flexible means of messaging between
30
+ tasks.
31
+ 9.1 [ Further examples] ( ./DRIVERS.md#91-further-examples )
32
+ 9.2 [ User agents] ( ./DRIVERS.md#92-user-agents )
33
+ 10 . [ Additional functions] ( ./DRIVERS.md#10-additional-functions )
34
+ 10.1 [ launch] ( ./DRIVERS.md#101-launch ) Run a coro or callback interchangeably.
35
+ 10.2 [ set_global_exception] ( ./DRIVERS.md#102-set_global_exception ) Simplify debugging with a global exception handler.
32
36
33
- ###### [ Tutorial] ( ./TUTORIAL.md#contents )
37
+ ###### [ asyncio Tutorial] ( ./TUTORIAL.md#contents )
34
38
35
39
# 1. Introduction
36
40
@@ -1126,9 +1130,116 @@ finally:
1126
1130
```
1127
1131
###### [ Contents] ( ./DRIVERS.md#0-contents )
1128
1132
1129
- # 9. Additional functions
1133
+ # 9. Message Broker
1134
+
1135
+ This is under development: please check for updates.
1136
+
1137
+ The ` Broker ` class provides a flexible means of messaging between running tasks.
1138
+ It uses a publish-subscribe model (akin to MQTT) whereby the transmitting task
1139
+ publishes to a topic. Any tasks subscribed to that topic will receive the
1140
+ message. This enables one to one, one to many or many to many messaging.
1141
+
1142
+ A task subscribes to a topic with an ` agent ` . This is stored by the broker. When
1143
+ the broker publishes a message, the ` agent ` of each task subscribed to its topic
1144
+ will be triggered. In the simplest case the ` agent ` is a ` Queue ` instance: the
1145
+ broker puts the topic and message onto the subscriber's queue for retrieval.
1146
+
1147
+ More advanced agents can perform actions in response to a message, such as
1148
+ calling a function or launching a ` task ` .
1149
+
1150
+ Broker methods. All are synchronous, constructor has no args:
1151
+ * ` subscribe(topic, agent) ` Passed ` agent ` will be triggered by messages with a
1152
+ matching ` topic ` .
1153
+ * ` unsubscribe(topic, agent) ` The ` agent ` will stop being triggered.
1154
+ * ` publish(topic, message) ` All ` agent ` instances subscribed to ` topic ` will be
1155
+ triggered, receiving ` topic ` and ` message ` args. Returns ` True ` unless a ` Queue `
1156
+ agent has become full, in which case data for that queue has been lost.
1157
+
1158
+ The ` topic ` arg is typically a string but may be any hashable object. A
1159
+ ` message ` is an arbitrary Python object. An ` agent ` may be any of the following:
1160
+ * ` Queue ` When a message is received receives 2-tuple ` (topic, message) ` .
1161
+ * ` function ` Called when a message is received. Gets 2 args, topic and message.
1162
+ * ` bound method ` Called when a message is received. Gets 2 args, topic and
1163
+ message.
1164
+ * ` coroutine ` Task created when a message is received with 2 args, topic and
1165
+ message.
1166
+ * ` bound coroutine ` Task created when a message is received with 2 args, topic
1167
+ and message.
1168
+ * Instance of a user class. See user agents below.
1169
+ * ` Event ` Set when a message is received.
1170
+
1171
+ Note that synchronous ` agent ` instances must run to completion quickly otherwise
1172
+ the ` publish ` method will be slowed.
1173
+
1174
+ The following is a simple example:
1175
+ ``` py
1176
+ import asyncio
1177
+ from primitives import Broker, Queue
1178
+
1179
+ broker = Broker()
1180
+ queue = Queue()
1181
+ async def sender (t ):
1182
+ for x in range (t):
1183
+ await asyncio.sleep(1 )
1184
+ broker.publish(" foo_topic" , f " test { x} " )
1185
+
1186
+ async def main ():
1187
+ broker.subscribe(" foo_topic" , queue)
1188
+ n = 10
1189
+ asyncio.create_task(sender(n))
1190
+ print (" Letting queue part-fill" )
1191
+ await asyncio.sleep(5 )
1192
+ for _ in range (n):
1193
+ topic, message = await queue.get()
1194
+ print (topic, message)
1195
+
1196
+ asyncio.run(main())
1197
+ ```
1198
+ ## 9.1 Further examples
1199
+
1200
+ An interesting application is to extend MQTT into the Python code
1201
+ (see [ mqtt_as] ( https://github.com/peterhinch/micropython-mqtt/tree/master ) ).
1202
+ This is as simple as:
1203
+ ``` py
1204
+ async def messages (client ):
1205
+ async for topic, msg, retained in client.queue:
1206
+ broker.publish(topic.decode(), msg.decode())
1207
+ ```
1208
+ Assuming the MQTT client is subscribed to multiple topics, message strings are
1209
+ directed to individual tasks each supporting one topic.
1210
+
1211
+ ## 9.2 User agents
1212
+
1213
+ An ` agent ` can be an instance of a user class. The class must be a subclass of
1214
+ ` Agent ` , and it must support a synchronous ` .put ` method. The latter takes two
1215
+ args, being ` topic ` and ` message ` . It should run to completion quickly.
1216
+
1217
+ ``` py
1218
+ import asyncio
1219
+ from primitives import Broker, Agent
1220
+
1221
+ broker = Broker()
1222
+ class MyAgent (Agent ):
1223
+ def put (sef , topic , message ):
1224
+ print (f " User agent. Topic: { topic} Message: { message} " )
1225
+
1226
+ async def sender (t ):
1227
+ for x in range (t):
1228
+ await asyncio.sleep(1 )
1229
+ broker.publish(" foo_topic" , f " test { x} " )
1230
+
1231
+ async def main ():
1232
+ broker.subscribe(" foo_topic" , MyAgent())
1233
+ await sender(10 )
1234
+
1235
+ asyncio.run(main())
1236
+ ```
1237
+
1238
+ ###### [ Contents] ( ./DRIVERS.md#0-contents )
1239
+
1240
+ # 10. Additional functions
1130
1241
1131
- ## 9 .1 Launch
1242
+ ## 10 .1 Launch
1132
1243
1133
1244
Import as follows:
1134
1245
``` python
@@ -1140,7 +1251,7 @@ runs it and returns the callback's return value. If a coro is passed, it is
1140
1251
converted to a ` task ` and run asynchronously. The return value is the ` task `
1141
1252
instance. A usage example is in ` primitives/switch.py ` .
1142
1253
1143
- ## 9 .2 set_global_exception
1254
+ ## 10 .2 set_global_exception
1144
1255
1145
1256
Import as follows:
1146
1257
``` python
0 commit comments