From 3ee3b0e7fbb8f093968d2fc156f9fb6f3b5f0a61 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 15 Jan 2024 20:31:55 +0000 Subject: [PATCH] deploy: be0fddf36d033abc3725eb9cbd941eaba06c2372 --- .doctrees/alongside-fastapi-and-co.doctree | Bin 9320 -> 9226 bytes .doctrees/connecting-to-the-broker.doctree | Bin 15593 -> 15166 bytes .doctrees/developer-interface.doctree | Bin 184132 -> 186016 bytes .doctrees/environment.pickle | Bin 35077 -> 37983 bytes .doctrees/index.doctree | Bin 22030 -> 21964 bytes .doctrees/migration-guide-v2.doctree | Bin 0 -> 24015 bytes .doctrees/reconnection.doctree | Bin 6082 -> 5956 bytes .doctrees/subscribing-to-a-topic.doctree | Bin 37589 -> 37423 bytes _sources/alongside-fastapi-and-co.md.txt | 7 +- _sources/connecting-to-the-broker.md.txt | 2 +- _sources/index.md.txt | 5 +- _sources/migration-guide-v2.md.txt | 154 +++++++ _sources/reconnection.md.txt | 7 +- _sources/subscribing-to-a-topic.md.txt | 105 +++-- alongside-fastapi-and-co.html | 12 +- connecting-to-the-broker.html | 7 +- developer-interface.html | 102 +++-- genindex.html | 5 +- index.html | 12 +- introduction.html | 5 +- migration-guide-v2.html | 441 +++++++++++++++++++++ objects.inv | Bin 423 -> 450 bytes publishing-a-message.html | 5 +- reconnection.html | 12 +- search.html | 5 +- searchindex.js | 2 +- subscribing-to-a-topic.html | 112 +++--- 27 files changed, 806 insertions(+), 194 deletions(-) create mode 100644 .doctrees/migration-guide-v2.doctree create mode 100644 _sources/migration-guide-v2.md.txt create mode 100644 migration-guide-v2.html diff --git a/.doctrees/alongside-fastapi-and-co.doctree b/.doctrees/alongside-fastapi-and-co.doctree index 11829e6208ac713f4ba0a4ed5a449297e42c14a6..694929358eb9608fdae96e8ccb8a8943696c2da9 100644 GIT binary patch delta 148 zcmaFi(dEI~z&iE6@fKzi?zs-p$D`n4FWDnpdKin_66)n4Vf}#kKhcrzPX$ z4o=<8g4_!kiB&m^adVbHGb^L<=69lXjEu&UbHzP@}Nym^wi9}}a+?v7Rf+%r diff --git a/.doctrees/connecting-to-the-broker.doctree b/.doctrees/connecting-to-the-broker.doctree index c3b55096d8b031a6ddcada7ccb97ec9a17fe01ab..3df3cd97edb0e200d7c20cd3edc4047443a6fbf3 100644 GIT binary patch delta 1240 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%0AX!EI2g;yIXB%J8_u*^Be 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 literal 35077 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

gPig#V{o;$>R%|6~wP(VDl~ z)7Ke}p5KM^;1dR0F#$TLmyAty#LFugoB95BqxI*U5<9vDkxhxek|Eh@!fzbDpC5qZ z+cp3PrZzZp&@l{0yQN{q)>GYr*!E#q=lDaO{@1pR{^Qt&uRWsCLHeuR(k&zXTit?K zOZqM}f=sCpxz+`U42%EXt#nmO69*+f^U~C{Qn6ut^UrS)OHqF|Tamui?citp^V8je z$VTqNZb7J#m2mz5UhXr{51W8Zb4)ditdJw($_}d-*O|Jm9V%oD|1(;^KeC{Zo9~7_OKl-{E4ik3M3QFSDBT<3n=k`SoNN zH>COAe3pVs(R$@`!89=T@&XQ#s+&IO@*(O+uY_Y{`F&M=*B7#>3Tmhn9`a%RMt4S0 zN}TM*Wy%E1{e4VE_chSM{r7lkr-S>4NLqCN1O3G<({z9CyTQA3#p#It4Db#5q#JH! z!|l@emL6R*aw))FLW}MXxaxo6zf24FKjV4T{UiK^EC0Xn4_x7NfL-;|eyq_?0|N*{ znh&T!#|iO6M`rLt@dNlFqdk6TKH!IT+xVgRfHV1VvJ0QQAPD~zjbSqMHu(F@8Qu2q z&1Ja~!}y+T85i2C3+r_2tK9f1x4p_uuX4+)-0&*5yUNY3#yn#7Z)HH;A93q4lDp~V zvn)>~(!FO$Oa`GCE@vO*(0KQ#`%0-uA3ny*!3DU(03QLwbqK@i2(Y>>IT-`}>7d^tv4LQP4-^pPi{xJFu|Qb9nNFEXh z`2^m<3T}|-11$v)V7*dE-{^`16q{aCHyOIlv^O?}{z?vdk9?P<u~o4UpNOR>7W`lzBf7<#a$-+nc}Z`&i%`B?-=4k zzSDv*sMRI@#XSqq$?#=-=a;Uqp&Fq?EqFO{G`#SDp26v{nFehVj zM;zas?8yaL5asrXPjTOey4_mcy6pZMeYaqou7P70a_+k2WN^(T%kJN&+tuCQjZZE1YGDg@57hQ9GaWb;@(&9va!KbY6M{)m{@X}-5cIEKjyNe6u b(l45}QT$0V=y-IWCm0u8jHywHE5-j0RL_VJ diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree index ae8668488a239a8c2927d5d7046b05191689ee95..6e8c9e188005be9167d9afb6803c474adc58157a 100644 GIT binary patch delta 1418 zcmb7DZA@EL80H)X4X2cq?}ipq5CmFEQ-tz0Tn8i*CPYhsxMi7Ldue;6x1=BFWCP_`?kAAX;ADI=)GKt)I)cX}r@qG@(EEg7(BT&JUP(*t&m63ItiJC`xzR@$hZ-Ux)EP0 z$OK=OQtrwmgiP^Q*_WjzWEuvus}Z?Amwl34lMiX05;6meIt>JJ#zr;^b#XFS9Vo_pUs>IBnSrGy6KblT&|jHssVOFO zg~7pEFQ=JWE0Vlf+ePRqgU|i2|BHX}e3;8T@P;P_6Iq+=_Wn;0w*}!@)KfJZ?Ov+Sp-w5;LJN z*JR@p<6h)~=H~cUOWGspE}>uO_4f$@lUE7}fgXobh`t+bkEHp$?tmlY^-Csq*y|EZ z{S}xO#F~V-xWmyB@eO40ID#P7A-4XFk64dUBq<>D2mwKI3b4^qtPow?IUq0WFC?m@ zCXYjMV?%c|VuM9f6?|8j42>;6R-fjsGaNqPaF)Y41YxWG0)}CaQ7l2mpQ+4~cc2JA zqIclY{=K9KhFe{DOY-lnHz|1_Pq+OQPjX@MWvgDBxaAKYjikQr54fEEuoN=+yizzM z1f!x3((MJrgjNl-+x0{XetT6;4i^2Vy$rsw8xqI)Y-6xtw`srN;V7Rik|a5NLg-i@ zE<1qdGY%~sr7Erug+2K^GX`&UG?G#IYKNC7Cr~&*#4)5(Q-%9ZM8!)qF0O5Yi6h97 z>%Patt6XPYLLi7Y=at;t tlC=vhi%e7_M|Ru*N|&*J+cJx7A)>Ym*idlk`vQJZaE5|d91b5X{|A?1>B#^9 delta 1309 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 delta 110 zcmX@2cSxV5fpzNkjV#@qjE<8ha9)^f%O$|Cmz!E#oS2?ktf8rpSgbI41DD+7crMe) V6SyS7>{DEqNm6}g^Ag?#oB%u*CRzXh diff --git a/.doctrees/subscribing-to-a-topic.doctree b/.doctrees/subscribing-to-a-topic.doctree index efa5c444845503c2667f3bd1f0804f98ca6f63c5..ae1b32819c67dcb9ce3bcc7891ffc6b63a35927a 100644 GIT binary patch delta 5199 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 delta 5459 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 JfX~-#`!94M-h==E diff --git a/_sources/alongside-fastapi-and-co.md.txt b/_sources/alongside-fastapi-and-co.md.txt index c390c1a..14841a9 100644 --- a/_sources/alongside-fastapi-and-co.md.txt +++ b/_sources/alongside-fastapi-and-co.md.txt @@ -12,10 +12,8 @@ import fastapi async def listen(client): - async with client.messages() as messages: - await client.subscribe("humidity/#") - async for message in messages: - print(message.payload) + async for message in client.messages: + print(message.payload) client = None @@ -28,6 +26,7 @@ async def lifespan(app): # Make client globally available client = c # Listen for MQTT messages in (unawaited) asyncio task + await client.subscribe("humidity/#") loop = asyncio.get_event_loop() task = loop.create_task(listen(client)) yield diff --git a/_sources/connecting-to-the-broker.md.txt b/_sources/connecting-to-the-broker.md.txt index c106b3a..9e2578b 100644 --- a/_sources/connecting-to-the-broker.md.txt +++ b/_sources/connecting-to-the-broker.md.txt @@ -20,7 +20,7 @@ The connection to the broker is managed by the `Client` context manager. This co Context managers make it easier to manage resources like network connections or files by ensuring that their teardown logic is always executed -- even in case of an exception. ```{tip} -If your use case does not allow you to use a context manager, you can use the client's `__aenter__` and `__aexit__` methods directly as a workaround, similar to how you would use manual `connect` and `disconnect` methods. With this approach you need to make sure that `___aexit___` is also called in case of an exception. Avoid this workaround if you can, it's a bit tricky to get right. +If your use case does not allow you to use a context manager, you can use the client's `__aenter__` and `__aexit__` methods to connect and disconnect as a workaround. With this approach you need to ensure yourself that `___aexit___` is also called in case of an exception. Avoid this workaround if you can, it's a bit tricky to get right. ``` ```{note} diff --git a/_sources/index.md.txt b/_sources/index.md.txt index 167ef6e..d43600d 100644 --- a/_sources/index.md.txt +++ b/_sources/index.md.txt @@ -27,10 +27,11 @@ alongside-fastapi-and-co ``` ```{toctree} -:caption: API reference +:caption: reference :hidden: developer-interface +migration-guide-v2 ``` ```{toctree} @@ -39,7 +40,7 @@ developer-interface GitHub Issue tracker -Discussions +Changelog Contributing PyPI ``` diff --git a/_sources/migration-guide-v2.md.txt b/_sources/migration-guide-v2.md.txt new file mode 100644 index 0000000..f31e3fa --- /dev/null +++ b/_sources/migration-guide-v2.md.txt @@ -0,0 +1,154 @@ +# Migration guide: v2.0.0 + +Version 2.0.0 introduces some breaking changes. This page aims to help you migrate to this new major version. The relevant changes are: + +- The deprecated `connect` and `disconnect` methods have been removed +- The deprecated `filtered_messages` and `unfiltered_messages` methods have been removed +- User-managed queues for incoming messages have been replaced with a single client-wide queue +- Some arguments to the `Client` have been renamed or removed + +## Changes to the client lifecycle + +The deprecated `connect` and `disconnect` methods have been removed. The best way to connect and disconnect from the broker is through the client's context manager: + +```python +import asyncio +import aiomqtt + + +async def main(): + async with aiomqtt.Client("test.mosquitto.org") as client: + await client.publish("temperature/outside", payload=28.4) + + +asyncio.run(main()) +``` + +If your use case does not allow you to use a context manager, you can use the client’s `__aenter__` and `__aexit__` methods almost interchangeably in place of the removed `connect` and `disconnect` methods. + +The `__aenter__` and `__aexit__` methods are designed to be called by the `async with` statement when the execution enters and exits the context manager. However, we can also execute them manually: + +```python +import asyncio +import aiomqtt + + +async def main(): + client = aiomqtt.Client("test.mosquitto.org") + await client.__aenter__() + try: + await client.publish("temperature/outside", payload=28.4) + finally: + await client.__aexit__(None, None, None) + + +asyncio.run(main()) +``` + +`__aenter__` is equivalent to `connect`. `__aexit__` is equivalent to `disconnect` except that it forces disconnection instead of throwing an exception in case the client cannot disconnect cleanly. + +```{note} +`__aexit__` expects three arguments: `exc_type`, `exc`, and `tb`. These arguments describe the exception that caused the context manager to exit, if any. You can pass `None` to all of these arguments in a manual call to `__aexit__`. +``` + +## Changes to the message queue + +The `filtered_messages`, `unfiltered_messages`, and `messages` methods have been removed and replaced with a single client-wide message queue. + +A minimal example of printing all messages (unfiltered) looks like this: + +```python +import asyncio +import aiomqtt + + +async def main(): + async with aiomqtt.Client("test.mosquitto.org") as client: + await client.subscribe("temperature/#") + async for message in client.messages: + print(message.payload) + + +asyncio.run(main()) +``` + +To handle messages from different topics differently, we can use `Topic.matches()`: + +```python +import asyncio +import aiomqtt + + +async def main(): + async with aiomqtt.Client("test.mosquitto.org") as client: + await client.subscribe("temperature/#") + await client.subscribe("humidity/#") + async for message in client.messages: + if message.topic.matches("humidity/inside"): + print(f"[humidity/inside] {message.payload}") + if message.topic.matches("+/outside"): + print(f"[+/outside] {message.payload}") + if message.topic.matches("temperature/#"): + print(f"[temperature/#] {message.payload}") + + +asyncio.run(main()) +``` + +```{note} +In our example, messages to `temperature/outside` are handled twice! +``` + +The `filtered_messages`, `unfiltered_messages`, and `messages` methods created isolated message queues underneath, such that you could invoke them multiple times. From Version 2.0.0 on, the client maintains a single queue that holds all incoming messages, accessible via `Client.messages`. + +If you continue to need multiple queues (e.g. because you have special concurrency requirements), you can build a "distributor" on top: + +```python +import asyncio +import aiomqtt + + +async def temperature_consumer(): + while True: + message = await temperature_queue.get() + print(f"[temperature/#] {message.payload}") + + +async def humidity_consumer(): + while True: + message = await humidity_queue.get() + print(f"[humidity/#] {message.payload}") + + +temperature_queue = asyncio.Queue() +humidity_queue = asyncio.Queue() + + +async def distributor(client): + # Sort messages into the appropriate queues + async for message in client.messages: + if message.topic.matches("temperature/#"): + temperature_queue.put_nowait(message) + elif message.topic.matches("humidity/#"): + humidity_queue.put_nowait(message) + + +async def main(): + async with aiomqtt.Client("test.mosquitto.org") as client: + await client.subscribe("temperature/#") + await client.subscribe("humidity/#") + # Use a task group to manage and await all tasks + async with asyncio.TaskGroup() as tg: + tg.create_task(distributor(client)) + tg.create_task(temperature_consumer()) + tg.create_task(humidity_consumer()) + + +asyncio.run(main()) +``` + +## Changes to client arguments + +- The `queue_class` and `queue_maxsize` arguments to `filtered_messages`, `unfiltered_messages`, and `messages` have been moved to the `Client` and have been renamed to `queue_type` and `max_queued_incoming_messages` +- The `max_queued_messages` client argument has been renamed to `max_queued_outgoing_messages` +- The deprecated `message_retry_set` client argument has been removed diff --git a/_sources/reconnection.md.txt b/_sources/reconnection.md.txt index 9ea92fb..c6b754a 100644 --- a/_sources/reconnection.md.txt +++ b/_sources/reconnection.md.txt @@ -17,10 +17,9 @@ async def main(): while True: try: async with client: - async with client.messages() as messages: - await client.subscribe("humidity/#") - async for message in messages: - print(message.payload) + await client.subscribe("humidity/#") + async for message in client.messages: + print(message.payload) except aiomqtt.MqttError: print(f"Connection lost; Reconnecting in {interval} seconds ...") await asyncio.sleep(interval) diff --git a/_sources/subscribing-to-a-topic.md.txt b/_sources/subscribing-to-a-topic.md.txt index bee45c1..74212af 100644 --- a/_sources/subscribing-to-a-topic.md.txt +++ b/_sources/subscribing-to-a-topic.md.txt @@ -1,6 +1,6 @@ # Subscribing to a topic -To receive messages for a topic, we need to subscribe to it and listen for messages. This is a minimal working example that listens for messages to the `temperature/#` wildcard: +To receive messages for a topic, we need to subscribe to it. Incoming messages are queued internally. You can use the `Client.message` generator to iterate over incoming messages. This is a minimal working example that listens for messages to the `temperature/#` wildcard: ```python import asyncio @@ -9,10 +9,9 @@ import aiomqtt async def main(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - async for message in messages: - print(message.payload) + await client.subscribe("temperature/#") + async for message in client.messages: + print(message.payload) asyncio.run(main()) @@ -37,16 +36,15 @@ import aiomqtt async def main(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - await client.subscribe("humidity/#") - async for message in messages: - if message.topic.matches("humidity/inside"): - print(f"[humidity/outside] {message.payload}") - if message.topic.matches("+/outside"): - print(f"[+/inside] {message.payload}") - if message.topic.matches("temperature/#"): - print(f"[temperature/#] {message.payload}") + await client.subscribe("temperature/#") + await client.subscribe("humidity/#") + async for message in client.messages: + if message.topic.matches("humidity/inside"): + print(f"[humidity/inside] {message.payload}") + if message.topic.matches("+/outside"): + print(f"[+/outside] {message.payload}") + if message.topic.matches("temperature/#"): + print(f"[temperature/#] {message.payload}") asyncio.run(main()) @@ -62,9 +60,9 @@ For details on the `+` and `#` wildcards and what topics they match, see the [OA ## The message queue -Messages are queued and returned sequentially from `Client.messages()`. +Messages are queued internally and returned sequentially from `Client.messages`. -The default queue is `asyncio.Queue` which returns messages on a FIFO ("first in first out") basis. You can pass [other types of asyncio queues](https://docs.python.org/3/library/asyncio-queue.html) as `queue_class` to `Client.messages()` to modify the order in which messages are returned, e.g. `asyncio.LifoQueue`. +The default queue is `asyncio.Queue` which returns messages on a FIFO ("first in first out") basis. You can pass [other types of asyncio queues](https://docs.python.org/3/library/asyncio-queue.html) as `queue_class` to the `Client` to modify the order in which messages are returned, e.g. `asyncio.LifoQueue`. You can subclass `asyncio.PriorityQueue` to queue based on priority. Messages are returned ascendingly by their priority values. In the case of ties, messages with lower message identifiers are returned first. @@ -87,12 +85,13 @@ class CustomPriorityQueue(asyncio.PriorityQueue): async def main(): - async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages(queue_class=CustomPriorityQueue) as messages: - await client.subscribe("temperature/#") - await client.subscribe("humidity/#") - async for message in messages: - print(message.payload) + async with aiomqtt.Client( + "test.mosquitto.org", queue_class=CustomPriorityQueue + ) as client: + await client.subscribe("temperature/#") + await client.subscribe("humidity/#") + async for message in client.messages: + print(message.payload) asyncio.run(main()) @@ -104,7 +103,7 @@ By default, the size of the queue is unlimited. You can set a limit by passing t ## Processing concurrently -Messages are queued and returned sequentially from `Client.messages()`. If a message takes a long time to handle, it blocks the handling of other messages. +Messages are queued internally and returned sequentially from `Client.messages`. If a message takes a long time to handle, it blocks the handling of other messages. You can handle messages concurrently by using an `asyncio.TaskGroup` like so: @@ -120,11 +119,11 @@ async def handle(message): async def main(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - async with asyncio.TaskGroup() as tg: - async for message in messages: - tg.create_task(handle(message)) # Spawn new coroutine + await client.subscribe("temperature/#") + # Use a task group to manage and await all tasks + async with asyncio.TaskGroup() as tg: + async for message in client.messages: + tg.create_task(handle(message)) # Spawn new coroutine asyncio.run(main()) @@ -134,6 +133,8 @@ asyncio.run(main()) Coroutines only make sense if your message handling is I/O-bound. If it's CPU-bound, you should spawn multiple processes instead. ``` +## Multiple queues + The code snippet above handles each message in a new coroutine. Sometimes, we want to handle messages from different topics concurrently, but sequentially inside a single topic. The idea here is to implement a "distributor" that sorts incoming messages into multiple asyncio queues. Each queue is then processed by a different coroutine. Let's see how this works for our temperature and humidity messages: @@ -160,19 +161,18 @@ humidity_queue = asyncio.Queue() async def distributor(client): - async with client.messages() as messages: - await client.subscribe("temperature/#") - await client.subscribe("humidity/#") - # Sort messages into the appropriate queues - async for message in messages: - if message.topic.matches("temperature/#"): - temperature_queue.put_nowait(message) - elif message.topic.matches("humidity/#"): - humidity_queue.put_nowait(message) + # Sort messages into the appropriate queues + async for message in client.messages: + if message.topic.matches("temperature/#"): + temperature_queue.put_nowait(message) + elif message.topic.matches("humidity/#"): + humidity_queue.put_nowait(message) async def main(): async with aiomqtt.Client("test.mosquitto.org") as client: + await client.subscribe("temperature/#") + await client.subscribe("humidity/#") # Use a task group to manage and await all tasks async with asyncio.TaskGroup() as tg: tg.create_task(distributor(client)) @@ -208,13 +208,13 @@ async def sleep(seconds): async def listen(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - async for message in messages: - print(message.payload) + await client.subscribe("temperature/#") + async for message in client.messages: + print(message.payload) async def main(): + # Use a task group to manage and await all tasks async with asyncio.TaskGroup() as tg: tg.create_task(sleep(2)) tg.create_task(listen()) # Start the listener task @@ -240,10 +240,9 @@ import aiomqtt async def listen(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - async for message in messages: - print(message.payload) + await client.subscribe("temperature/#") + async for message in client.messages: + print(message.payload) background_tasks = set() @@ -280,10 +279,9 @@ import aiomqtt async def listen(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - async for message in messages: - print(message.payload) + await client.subscribe("temperature/#") + async for message in client.messages: + print(message.payload) async def main(): @@ -315,10 +313,9 @@ import aiomqtt async def listen(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - async for message in messages: - print(message.payload) + await client.subscribe("temperature/#") + async for message in client.messages: + print(message.payload) async def main(): diff --git a/alongside-fastapi-and-co.html b/alongside-fastapi-and-co.html index 4a2cb36..eab042a 100644 --- a/alongside-fastapi-and-co.html +++ b/alongside-fastapi-and-co.html @@ -166,15 +166,16 @@

  • Reconnection
  • Alongside FastAPI & Co.
  • -

    API reference

    +

    reference

    Project links

    @@ -222,10 +223,8 @@

    Alongside FastAPI & Co.async def listen(client): - async with client.messages() as messages: - await client.subscribe("humidity/#") - async for message in messages: - print(message.payload) + async for message in client.messages: + print(message.payload) client = None @@ -238,6 +237,7 @@

    Alongside FastAPI & Co.# Make client globally available client = c # Listen for MQTT messages in (unawaited) asyncio task + await client.subscribe("humidity/#") loop = asyncio.get_event_loop() task = loop.create_task(listen(client)) yield diff --git a/connecting-to-the-broker.html b/connecting-to-the-broker.html index 2d61041..c6cabed 100644 --- a/connecting-to-the-broker.html +++ b/connecting-to-the-broker.html @@ -166,15 +166,16 @@
  • Reconnection
  • Alongside FastAPI & Co.
  • -

    API reference

    +

    reference

    Project links

    @@ -230,7 +231,7 @@

    Connecting to the broker

    Tip

    -

    If your use case does not allow you to use a context manager, you can use the client’s __aenter__ and __aexit__ methods directly as a workaround, similar to how you would use manual connect and disconnect methods. With this approach you need to make sure that ___aexit___ is also called in case of an exception. Avoid this workaround if you can, it’s a bit tricky to get right.

    +

    If your use case does not allow you to use a context manager, you can use the client’s __aenter__ and __aexit__ methods to connect and disconnect as a workaround. With this approach you need to ensure yourself that ___aexit___ is also called in case of an exception. Avoid this workaround if you can, it’s a bit tricky to get right.

    Note

    diff --git a/developer-interface.html b/developer-interface.html index 81c5ad6..340fa1f 100644 --- a/developer-interface.html +++ b/developer-interface.html @@ -3,7 +3,7 @@ - + Developer interface - aiomqtt @@ -166,15 +166,16 @@
  • Reconnection
  • Alongside FastAPI & Co.
  • -

    API reference

    +

    reference

    Project links

    @@ -217,7 +218,7 @@

    Developer interface#

    -class aiomqtt.Client(hostname: str, port: int = 1883, *, username: str | None = None, password: str | None = None, logger: logging.Logger | None = None, client_id: str | None = None, tls_context: ssl.SSLContext | None = None, tls_params: TLSParameters | None = None, tls_insecure: bool | None = None, proxy: ProxySettings | None = None, protocol: ProtocolVersion | None = None, will: Will | None = None, clean_session: bool | None = None, transport: str = 'tcp', timeout: float | None = None, keepalive: int = 60, bind_address: str = '', bind_port: int = 0, clean_start: int = 3, properties: Properties | None = None, message_retry_set: int = 20, socket_options: Iterable[SocketOption] | None = None, max_concurrent_outgoing_calls: int | None = None, websocket_path: str | None = None, websocket_headers: WebSocketHeaders | None = None, max_inflight_messages: int | None = None, max_queued_messages: int | None = None)
    +class aiomqtt.Client(hostname: str, port: int = 1883, *, username: str | None = None, password: str | None = None, logger: logging.Logger | None = None, identifier: str | None = None, queue_type: type[asyncio.Queue[Message]] | None = None, protocol: ProtocolVersion | None = None, will: Will | None = None, clean_session: bool | None = None, transport: str = 'tcp', timeout: float | None = None, keepalive: int = 60, bind_address: str = '', bind_port: int = 0, clean_start: int = 3, max_queued_incoming_messages: int | None = None, max_queued_outgoing_messages: int | None = None, max_inflight_messages: int | None = None, max_concurrent_outgoing_calls: int | None = None, properties: mqtt.Properties | None = None, tls_context: ssl.SSLContext | None = None, tls_params: TLSParameters | None = None, tls_insecure: bool | None = None, proxy: ProxySettings | None = None, socket_options: Iterable[SocketOption] | None = None, websocket_path: str | None = None, websocket_headers: WebSocketHeaders | None = None)

    The async context manager that manages the connection to the broker.

    Parameters:
    @@ -227,12 +228,11 @@

    Client

    username – The username to authenticate with.

  • password – The password to authenticate with.

  • logger – Custom logger instance.

  • -
  • client_id – The client ID to use. If None, one will be generated -automatically.

  • -
  • tls_context – The SSL/TLS context.

  • -
  • tls_params – The SSL/TLS configuration to use.

  • -
  • tls_insecure – Enable/disable server hostname verification when using SSL/TLS.

  • -
  • proxy – Configure a proxy for the connection.

  • +
  • identifier – The client identifier. Generated automatically if None.

  • +
  • queue_type – The class to use for the queue. The default is +asyncio.Queue, which stores messages in FIFO order. For LIFO order, +you can use asyncio.LifoQueue; For priority order you can subclass +asyncio.PriorityQueue.

  • protocol – The version of the MQTT protocol.

  • will – The will message to publish if the client disconnects unexpectedly.

  • clean_session – If True, the broker will remove all information about this @@ -247,19 +247,48 @@

    Client

    bind_port – The network port to bind this client to.

  • clean_start – (MQTT v5.0 only) Set the clean start flag always, never, or only on the first successful connection to the broker.

  • +
  • max_queued_incoming_messages – Restricts the incoming message queue size. If the +queue is full, further incoming messages are discarded. 0 or less means +unlimited (the default).

  • +
  • max_queued_outgoing_messages – Resticts the outgoing message queue size. If the +queue is full, further outgoing messages are discarded. 0 means +unlimited (the default).

  • +
  • max_inflight_messages – The maximum number of messages with QoS > 0 that can +be part way through their network flow at once.

  • +
  • max_concurrent_outgoing_calls – The maximum number of concurrent outgoing calls.

  • properties – (MQTT v5.0 only) The properties associated with the client.

  • -
  • message_retry_set – Deprecated.

  • +
  • tls_context – The SSL/TLS context.

  • +
  • tls_params – The SSL/TLS configuration to use.

  • +
  • tls_insecure – Enable/disable server hostname verification when using SSL/TLS.

  • +
  • proxy – Configure a proxy for the connection.

  • socket_options – Options to pass to the underlying socket.

  • -
  • max_concurrent_outgoing_calls – The maximum number of concurrent outgoing calls.

  • websocket_path – The path to use for websockets.

  • websocket_headers – The headers to use for websockets.

  • -
  • max_inflight_messages – The maximum number of messages with QoS > 0 that can -be part way through their network flow at once.

  • -
  • max_queued_messages – The maximum number of messages in the outgoing message -queue. 0 means unlimited.

  • +
    +
    +messages
    +

    Async generator that yields messages from the underlying message queue.

    +
    +
    Type:
    +

    AsyncGenerator[aiomqtt.client.Message, None]

    +
    +
    +
    + +
    +
    +identifier
    +

    The client identifier.

    +
    +
    Type:
    +

    str

    +
    +
    +
    +
    async subscribe(topic: str | tuple[str, paho.mqtt.subscribeoptions.SubscribeOptions] | list[tuple[str, paho.mqtt.subscribeoptions.SubscribeOptions]] | list[tuple[str, int]], qos: int = 0, options: paho.mqtt.subscribeoptions.SubscribeOptions | None = None, properties: paho.mqtt.properties.Properties | None = None, *args: Any, timeout: float | None = None, **kwargs: Any) tuple[int] | list[paho.mqtt.reasoncodes.ReasonCodes]
    @@ -325,28 +354,6 @@

    Client

    -
    -
    -messages(*, queue_class: type[asyncio.queues.Queue[aiomqtt.client.Message]] = <class 'asyncio.queues.Queue'>, queue_maxsize: int = 0) AsyncGenerator[AsyncGenerator[Message, None], None]
    -

    Async context manager that creates a queue for incoming messages.

    -
    -
    Parameters:
    -
      -
    • queue_class – The class to use for the queue. The default is -asyncio.Queue, which returns messages in FIFO order. For LIFO order, -you can use asyncio.LifoQueue; For priority order you can subclass -asyncio.PriorityQueue.

    • -
    • queue_maxsize – Restricts the queue size. If the queue is full, incoming -messages will be discarded and a warning logged. If set to 0 or -less, the queue size is infinite.

    • -
    -
    -
    Returns:
    -

    An async generator that yields messages from the underlying queue.

    -
    -
    -
    -
    async __aenter__() Self
    @@ -366,10 +373,10 @@

    ClientMessage#

    -class aiomqtt.Message(topic: str | aiomqtt.client.Topic, payload: str | bytes | bytearray | int | float | None, qos: int, retain: bool, mid: int, properties: paho.mqtt.properties.Properties | None)
    +class aiomqtt.Message(topic: str | aiomqtt.topic.Topic, payload: str | bytes | bytearray | int | float | None, qos: int, retain: bool, mid: int, properties: paho.mqtt.properties.Properties | None)

    Wraps the paho-mqtt message class to allow using our own matching logic.

    This class is not meant to be instantiated by the user. Instead, it is yielded by -the async generator returned from Client.messages().

    +the async generator Client.messages.

    Parameters:
    -

    API reference

    +

    reference

    Project links

    diff --git a/index.html b/index.html index ce1e696..6fcccda 100644 --- a/index.html +++ b/index.html @@ -166,15 +166,16 @@
  • Reconnection
  • Alongside FastAPI & Co.
  • -

    API reference

    +

    reference

    Project links

    @@ -221,10 +222,9 @@

    The idiomatic asyncio MQTT client
    async with Client("test.mosquitto.org") as client:
    -    async with client.messages() as messages:
    -        await client.subscribe("humidity/#")
    -        async for message in messages:
    -            print(message.payload)
    +    await client.subscribe("humidity/#")
    +    async for message in client.messages:
    +        print(message.payload)
     

    aiomqtt combines the stability of the time-proven paho-mqtt library with an idiomatic asyncio interface:

    diff --git a/introduction.html b/introduction.html index 05b0753..ad2cf22 100644 --- a/introduction.html +++ b/introduction.html @@ -166,15 +166,16 @@
  • Reconnection
  • Alongside FastAPI & Co.
  • -

    API reference

    +

    reference

    Project links

    diff --git a/migration-guide-v2.html b/migration-guide-v2.html new file mode 100644 index 0000000..649826b --- /dev/null +++ b/migration-guide-v2.html @@ -0,0 +1,441 @@ + + + + + + + + + Migration guide: v2.0.0 - aiomqtt + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    aiomqtt
    +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    + + + + + Back to top + +
    + +
    + +
    + +
    +
    +
    +

    Migration guide: v2.0.0#

    +

    Version 2.0.0 introduces some breaking changes. This page aims to help you migrate to this new major version. The relevant changes are:

    +
      +
    • The deprecated connect and disconnect methods have been removed

    • +
    • The deprecated filtered_messages and unfiltered_messages methods have been removed

    • +
    • User-managed queues for incoming messages have been replaced with a single client-wide queue

    • +
    • Some arguments to the Client have been renamed or removed

    • +
    +
    +

    Changes to the client lifecycle#

    +

    The deprecated connect and disconnect methods have been removed. The best way to connect and disconnect from the broker is through the client’s context manager:

    +
    import asyncio
    +import aiomqtt
    +
    +
    +async def main():
    +    async with aiomqtt.Client("test.mosquitto.org") as client:
    +        await client.publish("temperature/outside", payload=28.4)
    +
    +
    +asyncio.run(main())
    +
    +
    +

    If your use case does not allow you to use a context manager, you can use the client’s __aenter__ and __aexit__ methods almost interchangeably in place of the removed connect and disconnect methods.

    +

    The __aenter__ and __aexit__ methods are designed to be called by the async with statement when the execution enters and exits the context manager. However, we can also execute them manually:

    +
    import asyncio
    +import aiomqtt
    +
    +
    +async def main():
    +    client = aiomqtt.Client("test.mosquitto.org")
    +    await client.__aenter__()
    +    try:
    +        await client.publish("temperature/outside", payload=28.4)
    +    finally:
    +        await client.__aexit__(None, None, None)
    +
    +
    +asyncio.run(main())
    +
    +
    +

    __aenter__ is equivalent to connect. __aexit__ is equivalent to disconnect except that it forces disconnection instead of throwing an exception in case the client cannot disconnect cleanly.

    +
    +

    Note

    +

    __aexit__ expects three arguments: exc_type, exc, and tb. These arguments describe the exception that caused the context manager to exit, if any. You can pass None to all of these arguments in a manual call to __aexit__.

    +
    +
    +
    +

    Changes to the message queue#

    +

    The filtered_messages, unfiltered_messages, and messages methods have been removed and replaced with a single client-wide message queue.

    +

    A minimal example of printing all messages (unfiltered) looks like this:

    +
    import asyncio
    +import aiomqtt
    +
    +
    +async def main():
    +    async with aiomqtt.Client("test.mosquitto.org") as client:
    +        await client.subscribe("temperature/#")
    +        async for message in client.messages:
    +            print(message.payload)
    +
    +
    +asyncio.run(main())
    +
    +
    +

    To handle messages from different topics differently, we can use Topic.matches():

    +
    import asyncio
    +import aiomqtt
    +
    +
    +async def main():
    +    async with aiomqtt.Client("test.mosquitto.org") as client:
    +        await client.subscribe("temperature/#")
    +        await client.subscribe("humidity/#")
    +        async for message in client.messages:
    +            if message.topic.matches("humidity/inside"):
    +                print(f"[humidity/inside] {message.payload}")
    +            if message.topic.matches("+/outside"):
    +                print(f"[+/outside] {message.payload}")
    +            if message.topic.matches("temperature/#"):
    +                print(f"[temperature/#] {message.payload}")
    +
    +
    +asyncio.run(main())
    +
    +
    +
    +

    Note

    +

    In our example, messages to temperature/outside are handled twice!

    +
    +

    The filtered_messages, unfiltered_messages, and messages methods created isolated message queues underneath, such that you could invoke them multiple times. From Version 2.0.0 on, the client maintains a single queue that holds all incoming messages, accessible via Client.messages.

    +

    If you continue to need multiple queues (e.g. because you have special concurrency requirements), you can build a “distributor” on top:

    +
    import asyncio
    +import aiomqtt
    +
    +
    +async def temperature_consumer():
    +    while True:
    +        message = await temperature_queue.get()
    +        print(f"[temperature/#] {message.payload}")
    +
    +
    +async def humidity_consumer():
    +    while True:
    +        message = await humidity_queue.get()
    +        print(f"[humidity/#] {message.payload}")
    +
    +
    +temperature_queue = asyncio.Queue()
    +humidity_queue = asyncio.Queue()
    +
    +
    +async def distributor(client):
    +    # Sort messages into the appropriate queues
    +    async for message in client.messages:
    +        if message.topic.matches("temperature/#"):
    +            temperature_queue.put_nowait(message)
    +        elif message.topic.matches("humidity/#"):
    +            humidity_queue.put_nowait(message)
    +
    +
    +async def main():
    +    async with aiomqtt.Client("test.mosquitto.org") as client:
    +        await client.subscribe("temperature/#")
    +        await client.subscribe("humidity/#")
    +        # Use a task group to manage and await all tasks
    +        async with asyncio.TaskGroup() as tg:
    +            tg.create_task(distributor(client))
    +            tg.create_task(temperature_consumer())
    +            tg.create_task(humidity_consumer())
    +
    +
    +asyncio.run(main())
    +
    +
    +
    +
    +

    Changes to client arguments#

    +
      +
    • The queue_class and queue_maxsize arguments to filtered_messages, unfiltered_messages, and messages have been moved to the Client and have been renamed to queue_type and max_queued_incoming_messages

    • +
    • The max_queued_messages client argument has been renamed to max_queued_outgoing_messages

    • +
    • The deprecated message_retry_set client argument has been removed

    • +
    +
    +
    + +
    +
    + +
    + +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv index dd4a08b8cabe4ffb06c7d813e07febbafb8e03fd..130b715eaa90d28a9f227b5138ef173743407a2f 100644 GIT binary patch delta 328 zcmV-O0k{6A1HuE4gMW29_EvS8)Wf7~>kByGCTIjAAl3TzgOW5vOSKC^|7ZWUF{rI+ zypqJv=mYkOqmf)#@ImgR6~LbXAH;0h&}rCD6y74;S4Vh)gWWJ;jUf?~X?UAHfm;p+t84u4ofMj1&zHv^3|>0~jf zIq#URYz`ai6cMM`oRZ3R7?c3?S0j{#_m9&FgjQri%nr`VA&z6s(qz`BYO}&R)i_Ky z-VA92mzOg6FU=P3lMXk12N7&HTh>{*GHie46ByHDc}?Tk{ZMP=+q5I(9eIz<;t!tme`Q{!2K`Wb;Z!|- aN{mMzcUlx%j~Jb1mOd@Qjj>;|H#thPR-L2( delta 301 zcmV+|0n+}$1E&L!gMVq)-KtKLdZ?6jeE|pD1dZSb$h5xwNJ$zZrP?Km{?GpX8$iph z2}YB=Vu;uqiB3z!5Tbt5tU$g3KB?KYv9qwBDSRZlua58n2i^(A&XJ17H8Qe{Ey>#R zH~G@}Sxt66JSaqlL?Kh5>4z-$v<|zq$)eBG7DaTdH{$g- zIfLADN)48#p#4x=6WZ}qQFaspHmmd5;@PHp5I~rSD2Dx$qPoR4ZMO>JX};w3-ld+q z&xIlap;zsCUMALZ@mJ>67%&WVP~OzjGs5)g(=8Okwksy5g^kY);m*V#5oI2Fp5U1{ diff --git a/publishing-a-message.html b/publishing-a-message.html index e7ae444..f29ea96 100644 --- a/publishing-a-message.html +++ b/publishing-a-message.html @@ -166,15 +166,16 @@
  • Reconnection
  • Alongside FastAPI & Co.
  • -

    API reference

    +

    reference

    Project links

    diff --git a/reconnection.html b/reconnection.html index 38b94ee..91a985c 100644 --- a/reconnection.html +++ b/reconnection.html @@ -166,15 +166,16 @@
  • Reconnection
  • Alongside FastAPI & Co.
  • -

    API reference

    +

    reference

    Project links

    @@ -226,10 +227,9 @@

    Reconnectionwhile True: try: async with client: - async with client.messages() as messages: - await client.subscribe("humidity/#") - async for message in messages: - print(message.payload) + await client.subscribe("humidity/#") + async for message in client.messages: + print(message.payload) except aiomqtt.MqttError: print(f"Connection lost; Reconnecting in {interval} seconds ...") await asyncio.sleep(interval) diff --git a/search.html b/search.html index 053c354..ecb3cfc 100644 --- a/search.html +++ b/search.html @@ -163,15 +163,16 @@
  • Reconnection
  • Alongside FastAPI & Co.
  • -

    API reference

    +

    reference

    Project links

    diff --git a/searchindex.js b/searchindex.js index 2af6306..02e703c 100644 --- a/searchindex.js +++ b/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["alongside-fastapi-and-co", "connecting-to-the-broker", "developer-interface", "index", "introduction", "publishing-a-message", "reconnection", "subscribing-to-a-topic"], "filenames": ["alongside-fastapi-and-co.md", "connecting-to-the-broker.md", "developer-interface.md", "index.md", "introduction.md", "publishing-a-message.md", "reconnection.md", "subscribing-to-a-topic.md"], "titles": ["Alongside FastAPI & Co.", "Connecting to the broker", "Developer interface", "The idiomatic asyncio MQTT client", "Introduction", "Publishing a message", "Reconnection", "Subscribing to a topic"], "terms": {"mani": 0, "web": [0, 7], "framework": [0, 7], "take": [0, 7], "control": 0, "over": 0, "main": [0, 1, 3, 5, 6, 7], "function": [0, 1], "which": [0, 2, 5, 7], "can": [0, 1, 2, 3, 5, 6, 7], "make": [0, 1, 6, 7], "tricki": [0, 1], "figur": 0, "out": [0, 1, 7], "where": [0, 7], "creat": [0, 1, 2, 7], "client": [0, 1, 5, 6, 7], "how": [0, 1, 4, 7], "share": 0, "thi": [0, 1, 2, 3, 4, 5, 6, 7], "connect": [0, 2, 6], "With": [0, 1], "0": [0, 1, 2, 3, 5], "93": 0, "starlett": 0, "you": [0, 1, 2, 3, 4, 5, 7], "us": [0, 1, 2, 3, 4, 5, 7], "lifespan": 0, "context": [0, 1, 2, 6], "manag": [0, 1, 2, 7], "safe": [0, 7], "set": [0, 1, 2, 5, 7], "up": [0, 1], "global": 0, "instanc": [0, 1, 2], "i": [0, 1, 2, 3, 4, 5, 6, 7], "minim": [0, 1, 5, 7], "work": [0, 1, 5, 7], "exampl": [0, 1, 5, 7], "side": 0, "an": [0, 1, 2, 3, 4, 5, 6, 7], "aiomqtt": [0, 1, 2, 3, 4, 5, 6, 7], "listen": [0, 6], "task": [0, 7], "messag": [0, 1, 3, 6], "public": [0, 1, 2], "get": [0, 1, 3, 4, 7], "import": [0, 1, 3, 5, 6, 7], "asyncio": [0, 1, 2, 4, 5, 6, 7], "contextlib": 0, "async": [0, 1, 2, 3, 5, 6, 7], "def": [0, 1, 5, 6, 7], "await": [0, 1, 3, 5, 6, 7], "subscrib": [0, 1, 2, 3, 5, 6], "humid": [0, 1, 3, 6, 7], "print": [0, 3, 6, 7], "payload": [0, 1, 2, 3, 6, 7], "none": [0, 2, 5], "asynccontextmanag": 0, "app": 0, "test": [0, 1, 3, 5, 6, 7], "mosquitto": [0, 1, 3, 5, 6, 7], "org": [0, 1, 3, 5, 6, 7], "c": 0, "avail": [0, 1], "mqtt": [0, 1, 2, 4, 5, 7], "unawait": [0, 7], "loop": [0, 3, 7], "get_event_loop": [0, 7], "create_task": [0, 7], "yield": [0, 2], "cancel": [0, 7], "wait": [0, 2, 3, 7], "try": [0, 3, 4, 6, 7], "except": [0, 1, 6, 7], "cancellederror": [0, 7], "pass": [0, 1, 2, 7], "publish": [0, 1, 2, 3, 7], "outsid": [0, 1, 3, 5, 7], "38": [0, 1, 3], "combin": [0, 3, 7], "some": [0, 4, 7], "concept": 0, "address": [0, 2], "more": [0, 1, 3], "detail": [0, 7], "other": [0, 3, 7], "section": [0, 7], "The": [0, 1, 2, 5, 6], "between": [0, 5], "rout": 0, "explain": [0, 4], "we": [0, 1, 3, 4, 6, 7], "don": [0, 4, 5, 7], "t": [0, 3, 4, 5, 7], "immedi": [0, 5], "order": [0, 2, 7], "avoid": [0, 1], "block": [0, 6], "code": [0, 1, 3, 6, 7], "without": [0, 1], "initi": [0, 1], "": [0, 1, 2, 4, 5, 6, 7], "state": 0, "instead": [0, 2, 3, 7], "variabl": 0, "To": [1, 5, 6, 7], "topic": [1, 5], "first": [1, 2, 7], "need": [1, 4, 7], "temperatur": [1, 5, 7], "28": [1, 5], "4": [1, 5], "run": [1, 3, 5, 6, 7], "when": [1, 2, 4, 5, 7], "enter": 1, "statement": 1, "disconnect": [1, 2, 3], "exit": [1, 7], "again": [1, 7], "easier": 1, "resourc": 1, "like": [1, 3, 6, 7], "network": [1, 2, 6], "file": 1, "ensur": 1, "teardown": 1, "logic": [1, 2], "alwai": [1, 2], "execut": [1, 7], "even": 1, "case": [1, 7], "If": [1, 2, 3, 4, 5, 7], "your": [1, 3, 4, 7], "doe": 1, "allow": [1, 2], "__aenter__": [1, 2], "__aexit__": [1, 2], "method": [1, 2, 3], "directli": [1, 3], "workaround": 1, "similar": [1, 2], "would": 1, "manual": 1, "approach": [1, 7], "sure": 1, "___aexit___": 1, "also": [1, 5], "call": [1, 2, 3, 7], "bit": [1, 7], "right": 1, "ani": [1, 2, 6], "credenti": 1, "altern": 1, "our": [1, 2, 6, 7], "contribut": 1, "guid": [1, 4], "contain": [1, 2], "explan": 1, "spin": 1, "local": [1, 2], "docker": 1, "all": [1, 2, 5, 7], "document": [1, 4], "ar": [1, 3, 4, 5, 6, 7], "self": [1, 2, 7], "runnabl": 1, "For": [1, 2, 4, 5, 7], "list": [1, 2], "argument": [1, 2], "see": [1, 5, 7], "api": 1, "refer": [1, 4, 7], "often": 1, "want": [1, 5, 7], "send": [1, 5], "receiv": [1, 5, 7], "multipl": [1, 5, 7], "differ": [1, 3, 5, 7], "locat": 1, "could": 1, "new": [1, 4, 5, 7], "each": [1, 5, 7], "time": [1, 2, 3, 5, 6, 7], "veri": [1, 3, 7], "perform": 1, "ll": [1, 7], "bandwidth": 1, "publish_temperatur": 1, "publish_humid": 1, "insid": [1, 7], "non": [1, 5], "kept": 1, "aliv": 1, "goe": 1, "offlin": 1, "mean": [1, 2, 6], "store": [1, 5], "subscript": [1, 2, 7], "queue": [1, 2], "qo": [1, 2, 7], "1": [1, 3, 5, 7], "2": [1, 5, 7], "miss": [1, 4], "ha": 1, "yet": 1, "acknowledg": [1, 5], "retransmit": 1, "reconnect": 1, "clean_sess": [1, 2], "paramet": [1, 2, 5, 7], "fals": [1, 2], "true": [1, 2, 5, 6, 7], "amount": [1, 7], "queu": [1, 2, 7], "limit": [1, 7], "memori": 1, "come": [1, 7], "back": [1, 5], "onlin": 1, "long": [1, 6, 7], "eventu": 1, "start": [1, 2, 3, 4, 7], "discard": [1, 2], "class": [2, 7], "hostnam": 2, "str": [2, 5], "port": 2, "int": [2, 5], "1883": 2, "usernam": 2, "password": 2, "logger": 2, "log": 2, "client_id": 2, "tls_context": 2, "ssl": 2, "sslcontext": 2, "tls_param": 2, "tlsparamet": 2, "tls_insecur": 2, "bool": 2, "proxi": 2, "proxyset": 2, "protocol": 2, "protocolvers": 2, "Will": 2, "transport": 2, "tcp": 2, "timeout": 2, "float": [2, 5], "keepal": 2, "60": 2, "bind_address": 2, "bind_port": 2, "clean_start": 2, "3": [2, 3, 7], "properti": 2, "message_retry_set": 2, "20": 2, "socket_opt": 2, "iter": 2, "socketopt": 2, "max_concurrent_outgoing_cal": 2, "websocket_path": 2, "websocket_head": 2, "websockethead": 2, "max_inflight_messag": 2, "max_queued_messag": 2, "broker": [2, 3, 5], "ip": 2, "remot": 2, "authent": 2, "custom": 2, "id": 2, "one": [2, 5, 7], "gener": [2, 7], "automat": [2, 5], "tl": 2, "configur": 2, "enabl": 2, "disabl": 2, "server": 2, "verif": 2, "version": 2, "unexpectedli": 2, "remov": [2, 7], "inform": 2, "about": [2, 3], "persist": 2, "retain": 2, "either": 2, "websocket": 2, "default": [2, 3, 5, 7], "commun": [2, 5], "second": [2, 6, 7], "bind": 2, "v5": 2, "onli": [2, 3, 5, 7], "clean": 2, "flag": 2, "never": 2, "success": 2, "associ": 2, "deprec": 2, "option": [2, 5, 7], "underli": [2, 3], "socket": 2, "maximum": 2, "number": 2, "concurr": 2, "outgo": 2, "path": 2, "header": 2, "part": [2, 5], "wai": [2, 7], "through": [2, 5, 7], "flow": 2, "onc": [2, 5], "unlimit": [2, 7], "tupl": 2, "paho": [2, 3], "subscribeopt": 2, "arg": 2, "kwarg": 2, "reasoncod": 2, "request": [2, 4, 7], "level": [2, 5], "addit": 2, "posit": 2, "complet": 2, "math": 2, "inf": 2, "indefinit": 2, "keyword": 2, "unsubscrib": 2, "from": [2, 3, 6, 7], "unsubscript": 2, "byte": [2, 5], "bytearrai": [2, 5], "queue_class": [2, 7], "type": [2, 3, 5, 7], "queue_maxs": [2, 7], "asyncgener": 2, "incom": [2, 7], "return": [2, 3, 5, 7], "fifo": [2, 7], "lifo": [2, 7], "lifoqueu": [2, 7], "prioriti": [2, 7], "subclass": [2, 7], "priorityqueu": [2, 7], "restrict": 2, "size": [2, 7], "full": 2, "warn": 2, "less": 2, "infinit": [2, 7], "exc_typ": 2, "baseexcept": 2, "exc": 2, "tb": 2, "tracebacktyp": 2, "mid": [2, 7], "wrap": [2, 6], "own": 2, "match": [2, 7], "meant": 2, "instanti": 2, "user": 2, "wa": 2, "qualiti": [2, 7], "servic": [2, 7], "whether": 2, "valu": [2, 7], "string": [2, 5], "check": 2, "given": 2, "against": [2, 6], "otherwis": 2, "A": 2, "placehold": 2, "write": 3, "stabil": 3, "proven": 3, "librari": 3, "interfac": 3, "No": 3, "callback": 3, "welcom": 3, "mqtterror": [3, 6], "grace": 3, "forget": [3, 7], "on_unsubscrib": 3, "on_disconnect": 3, "etc": 3, "support": 3, "5": [3, 6, 7], "fulli": 3, "hint": 3, "did": 3, "mention": 3, "via": 3, "pip": 3, "depend": 3, "latest": 3, "github": [3, 4], "git": 3, "http": [3, 7], "com": 3, "sbtinstrument": 3, "sinc": 3, "python": [3, 7], "8": 3, "event": 3, "proactoreventloop": 3, "said": [3, 4], "doesn": [3, 7], "add_read": 3, "requir": 3, "pleas": 3, "switch": 3, "built": 3, "selectoreventloop": 3, "chang": 3, "selector": 3, "platform": 3, "sy": 3, "lower": [3, 7], "win32": 3, "o": [3, 7], "name": 3, "nt": 3, "set_event_loop_polici": 3, "windowsselectoreventlooppolici": 3, "applic": [3, 6], "usual": [3, 5], "under": 3, "bsd": 3, "claus": 3, "dual": 3, "One": 3, "so": [3, 6, 7], "eclips": 3, "distribut": 3, "v1": 3, "It": [3, 4], "almost": 3, "word": 3, "ident": 3, "copyright": 3, "owner": 3, "edl": 3, "holder": 3, "foundat": 3, "inc": 3, "re": [3, 4, 7], "happi": [3, 4], "read": [3, 4], "md": 3, "adher": 3, "semant": 3, "break": 3, "occur": 3, "major": 3, "x": 3, "releas": 3, "live": 3, "follow": 3, "principl": 3, "keep": [3, 7], "what": [3, 7], "look": 3, "There": 3, "few": 3, "synchron": 3, "micropython": 3, "asynchron": 3, "microcontrol": 3, "gmqtt": 3, "fastapi": 3, "wrapper": 3, "around": 3, "simplifi": 3, "integr": 3, "amqtt": 3, "includ": 3, "trio": 3, "base": [3, 7], "aim": 4, "cover": 4, "everyth": [4, 7], "know": 4, "project": 4, "expect": 4, "knowledg": 4, "thing": [4, 5], "clearli": 4, "possibl": [4, 7], "stuck": 4, "hesit": 4, "discuss": 4, "help": 4, "recommend": 4, "hivemq": 4, "essenti": 4, "afterward": [4, 7], "oasi": [4, 7], "specif": [4, 7], "great": 4, "realpython": 4, "walkthrough": 4, "doc": 4, "big": 4, "open": 4, "issu": 4, "pull": 4, "find": 4, "error": 4, "have": [4, 5, 6, 7], "idea": [4, 7], "improv": 4, "easi": [4, 7], "unclear": 4, "newcom": 4, "alreadi": 4, "familiar": 4, "fresh": 4, "ey": 4, "here": [4, 7], "That": [4, 7], "let": [4, 5, 7], "dive": 4, "transmit": 5, "stream": 5, "accept": 5, "convert": 5, "struct": 5, "pack": 5, "object": 5, "specifi": 5, "zero": 5, "length": 5, "sent": 5, "standard": 5, "implement": [5, 7], "yourself": 5, "dict": 5, "json": 5, "dump": 5, "On": 5, "end": 5, "load": 5, "decod": 5, "reliabl": 5, "three": 5, "At": 5, "most": 5, "guarante": 5, "deliveri": 5, "fastest": 5, "least": 5, "deliv": 5, "possibli": 5, "sender": 5, "until": [5, 7], "receipt": 5, "exactli": 5, "four": 5, "handshak": 5, "slowest": 5, "two": 5, "same": 5, "defin": 5, "relai": 5, "recent": 5, "last": 5, "after": 5, "thei": [5, 7], "per": 5, "previou": [5, 7], "overwritten": 5, "delet": 5, "empti": 5, "howev": 5, "necessari": 5, "overwrit": 5, "ones": 5, "inher": 6, "unstabl": 6, "fail": 6, "especi": 6, "challeng": 6, "resili": 6, "failur": 6, "abl": 6, "detect": 6, "recov": 6, "them": [6, 7], "design": 6, "reusabl": 6, "reentrant": 6, "interv": 6, "while": [6, 7], "f": [6, 7], "lost": 6, "sleep": [6, 7], "wildcard": 7, "now": 7, "appear": 7, "consol": 7, "imagin": 7, "measur": 7, "handl": 7, "provid": 7, "In": 7, "twice": 7, "sequenti": 7, "basi": 7, "modifi": 7, "e": 7, "g": 7, "ascendingli": 7, "ti": 7, "identifi": 7, "sai": 7, "priorit": 7, "custompriorityqueu": 7, "_put": 7, "item": 7, "assign": 7, "super": 7, "_get": 7, "By": 7, "taskgroup": 7, "simul": 7, "bound": 7, "tg": 7, "spawn": 7, "coroutin": 7, "sens": 7, "cpu": 7, "should": 7, "snippet": 7, "abov": 7, "sometim": 7, "singl": 7, "distributor": 7, "sort": 7, "temperature_consum": 7, "temperature_queu": 7, "humidity_consum": 7, "humidity_queu": 7, "appropri": 7, "put_nowait": 7, "elif": 7, "group": 7, "notic": 7, "program": 7, "finish": 7, "practic": 7, "gather": 7, "11": 7, "alongsid": 7, "slept": 7, "becaus": 7, "fire": 7, "care": 7, "rais": 7, "propag": 7, "explicitli": 7, "unhandl": 7, "silent": 7, "ignor": 7, "background_task": 7, "save": 7, "garbag": 7, "collect": 7, "add": 7, "add_done_callback": 7, "do": 7, "someth": 7, "els": 7, "might": 7, "done": 7, "certain": 7, "introduc": 7, "neat": 7, "featur": 7, "result": 7, "timeouterror": 7}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"alongsid": 0, "fastapi": 0, "co": 0, "connect": 1, "broker": 1, "share": 1, "persist": 1, "session": 1, "develop": 2, "interfac": 2, "client": [2, 3], "messag": [2, 5, 7], "topic": [2, 7], "wildcard": 2, "The": [3, 7], "idiomat": 3, "asyncio": 3, "mqtt": 3, "instal": 3, "note": 3, "window": 3, "user": 3, "licens": 3, "contribut": 3, "version": 3, "changelog": 3, "relat": 3, "project": 3, "introduct": 4, "publish": 5, "payload": 5, "encod": 5, "qualiti": 5, "servic": 5, "qo": 5, "retain": 5, "reconnect": 6, "subscrib": 7, "filter": 7, "queue": 7, "process": 7, "concurr": 7, "listen": 7, "without": 7, "block": 7, "stop": 7, "after": 7, "timeout": 7}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"Alongside FastAPI & Co.": [[0, "alongside-fastapi-co"]], "Connecting to the broker": [[1, "connecting-to-the-broker"]], "Sharing the connection": [[1, "sharing-the-connection"]], "Persistent sessions": [[1, "persistent-sessions"]], "Developer interface": [[2, "developer-interface"]], "Client": [[2, "client"]], "Message": [[2, "message"]], "Topic": [[2, "topic"]], "Wildcard": [[2, "wildcard"]], "The idiomatic asyncio MQTT client": [[3, "the-idiomatic-asyncio-mqtt-client"]], "Installation": [[3, "installation"]], "Note for Windows users": [[3, "note-for-windows-users"]], "License": [[3, "license"]], "Contributing": [[3, "contributing"]], "Versioning": [[3, "versioning"]], "Changelog": [[3, "changelog"]], "Related projects": [[3, "related-projects"]], "Introduction": [[4, "introduction"]], "Publishing a message": [[5, "publishing-a-message"]], "Payload encoding": [[5, "payload-encoding"]], "Quality of Service (QoS)": [[5, "quality-of-service-qos"]], "Retained messages": [[5, "retained-messages"]], "Reconnection": [[6, "reconnection"]], "Subscribing to a topic": [[7, "subscribing-to-a-topic"]], "Filtering messages": [[7, "filtering-messages"]], "The message queue": [[7, "the-message-queue"]], "Processing concurrently": [[7, "processing-concurrently"]], "Listening without blocking": [[7, "listening-without-blocking"]], "Stop listening": [[7, "stop-listening"]], "Stop listening after timeout": [[7, "stop-listening-after-timeout"]]}, "indexentries": {}}) \ No newline at end of file +Search.setIndex({"docnames": ["alongside-fastapi-and-co", "connecting-to-the-broker", "developer-interface", "index", "introduction", "migration-guide-v2", "publishing-a-message", "reconnection", "subscribing-to-a-topic"], "filenames": ["alongside-fastapi-and-co.md", "connecting-to-the-broker.md", "developer-interface.md", "index.md", "introduction.md", "migration-guide-v2.md", "publishing-a-message.md", "reconnection.md", "subscribing-to-a-topic.md"], "titles": ["Alongside FastAPI & Co.", "Connecting to the broker", "Developer interface", "The idiomatic asyncio MQTT client", "Introduction", "Migration guide: v2.0.0", "Publishing a message", "Reconnection", "Subscribing to a topic"], "terms": {"mani": 0, "web": [0, 8], "framework": [0, 8], "take": [0, 8], "control": 0, "over": [0, 8], "main": [0, 1, 3, 5, 6, 7, 8], "function": [0, 1], "which": [0, 2, 6, 8], "can": [0, 1, 2, 3, 5, 6, 7, 8], "make": [0, 1, 7, 8], "tricki": [0, 1], "figur": 0, "out": [0, 1, 8], "where": [0, 8], "creat": [0, 1, 5, 8], "client": [0, 1, 6, 7, 8], "how": [0, 1, 4, 8], "share": 0, "thi": [0, 1, 2, 3, 4, 5, 6, 7, 8], "connect": [0, 2, 5, 7], "With": [0, 1], "0": [0, 1, 2, 3, 6], "93": 0, "starlett": 0, "you": [0, 1, 2, 3, 4, 5, 6, 8], "us": [0, 1, 2, 3, 4, 5, 6, 8], "lifespan": 0, "context": [0, 1, 2, 5, 7], "manag": [0, 1, 2, 5, 8], "safe": [0, 8], "set": [0, 1, 2, 6, 8], "up": [0, 1], "global": 0, "instanc": [0, 1, 2], "i": [0, 1, 2, 3, 4, 5, 6, 7, 8], "minim": [0, 1, 5, 6, 8], "work": [0, 1, 6, 8], "exampl": [0, 1, 5, 6, 8], "side": 0, "an": [0, 1, 3, 4, 5, 6, 7, 8], "aiomqtt": [0, 1, 2, 3, 4, 5, 6, 7, 8], "listen": [0, 7], "task": [0, 5, 8], "messag": [0, 1, 3, 7], "public": [0, 1, 2], "get": [0, 1, 3, 4, 5, 8], "import": [0, 1, 3, 5, 6, 7, 8], "asyncio": [0, 1, 2, 4, 5, 6, 7, 8], "contextlib": 0, "async": [0, 1, 2, 3, 5, 6, 7, 8], "def": [0, 1, 5, 6, 7, 8], "print": [0, 3, 5, 7, 8], "payload": [0, 1, 2, 3, 5, 7, 8], "none": [0, 2, 5, 6], "asynccontextmanag": 0, "app": 0, "test": [0, 1, 3, 5, 6, 7, 8], "mosquitto": [0, 1, 3, 5, 6, 7, 8], "org": [0, 1, 3, 5, 6, 7, 8], "c": 0, "avail": [0, 1], "mqtt": [0, 1, 2, 4, 6, 8], "unawait": [0, 8], "await": [0, 1, 3, 5, 6, 7, 8], "subscrib": [0, 1, 2, 3, 5, 6, 7], "humid": [0, 1, 3, 5, 7, 8], "loop": [0, 3, 8], "get_event_loop": [0, 8], "create_task": [0, 5, 8], "yield": [0, 2], "cancel": [0, 8], "wait": [0, 2, 3, 8], "try": [0, 3, 4, 5, 7, 8], "except": [0, 1, 5, 7, 8], "cancellederror": [0, 8], "pass": [0, 1, 2, 5, 8], "publish": [0, 1, 2, 3, 5, 8], "outsid": [0, 1, 3, 5, 6, 8], "38": [0, 1, 3], "combin": [0, 3, 8], "some": [0, 4, 5, 8], "concept": 0, "address": [0, 2], "more": [0, 1, 3], "detail": [0, 8], "other": [0, 3, 8], "section": [0, 8], "The": [0, 1, 2, 5, 6, 7], "between": [0, 6], "rout": 0, "explain": [0, 4], "we": [0, 1, 3, 4, 5, 7, 8], "don": [0, 4, 6, 8], "t": [0, 3, 4, 6, 8], "immedi": [0, 6], "order": [0, 2, 8], "avoid": [0, 1], "block": [0, 7], "code": [0, 1, 3, 7, 8], "without": [0, 1], "initi": [0, 1], "": [0, 1, 2, 4, 5, 6, 7, 8], "state": 0, "instead": [0, 2, 3, 5, 8], "variabl": 0, "To": [1, 5, 6, 7, 8], "topic": [1, 5, 6], "first": [1, 2, 8], "need": [1, 4, 5, 8], "temperatur": [1, 5, 6, 8], "28": [1, 5, 6], "4": [1, 5, 6], "run": [1, 3, 5, 6, 7, 8], "when": [1, 2, 4, 5, 6, 8], "enter": [1, 5], "statement": [1, 5], "disconnect": [1, 2, 3, 5], "exit": [1, 5, 8], "again": [1, 8], "easier": 1, "resourc": 1, "like": [1, 3, 5, 7, 8], "network": [1, 2, 7], "file": 1, "ensur": 1, "teardown": 1, "logic": [1, 2], "alwai": [1, 2], "execut": [1, 5, 8], "even": 1, "case": [1, 5, 8], "If": [1, 2, 3, 4, 5, 6, 8], "your": [1, 3, 4, 5, 8], "doe": [1, 5], "allow": [1, 2, 5], "__aenter__": [1, 2, 5], "__aexit__": [1, 2, 5], "method": [1, 2, 3, 5], "workaround": 1, "approach": [1, 8], "yourself": [1, 6], "___aexit___": 1, "also": [1, 5, 6], "call": [1, 2, 3, 5, 8], "bit": [1, 8], "right": 1, "ani": [1, 2, 5, 7], "credenti": 1, "altern": 1, "our": [1, 2, 5, 7, 8], "contribut": 1, "guid": [1, 4], "contain": [1, 2], "explan": 1, "spin": 1, "local": [1, 2], "docker": 1, "all": [1, 2, 5, 6, 8], "document": [1, 4], "ar": [1, 2, 3, 4, 5, 6, 7, 8], "self": [1, 2, 8], "runnabl": 1, "For": [1, 2, 4, 6, 8], "list": [1, 2], "argument": [1, 2], "see": [1, 6, 8], "api": 1, "refer": [1, 4, 8], "often": 1, "want": [1, 6, 8], "send": [1, 6], "receiv": [1, 6, 8], "multipl": [1, 5, 6], "differ": [1, 3, 5, 6, 8], "locat": 1, "could": [1, 5], "new": [1, 4, 5, 6, 8], "each": [1, 6, 8], "time": [1, 2, 3, 5, 6, 7, 8], "veri": [1, 3, 8], "perform": [1, 2], "ll": [1, 8], "bandwidth": 1, "publish_temperatur": 1, "publish_humid": 1, "insid": [1, 5, 8], "non": [1, 6], "kept": 1, "aliv": 1, "goe": 1, "offlin": 1, "mean": [1, 2, 7], "store": [1, 2, 6], "subscript": [1, 2, 8], "queue": [1, 2], "qo": [1, 2, 8], "1": [1, 3, 6, 8], "2": [1, 5, 6, 8], "miss": [1, 4], "ha": [1, 5], "yet": 1, "acknowledg": [1, 6], "retransmit": 1, "reconnect": 1, "clean_sess": [1, 2], "paramet": [1, 2, 6, 8], "fals": [1, 2], "true": [1, 2, 5, 6, 7, 8], "amount": [1, 8], "queu": [1, 2, 8], "limit": [1, 8], "memori": 1, "come": [1, 8], "back": [1, 6], "onlin": 1, "long": [1, 7, 8], "eventu": 1, "start": [1, 2, 3, 4, 8], "discard": [1, 2], "class": [2, 8], "hostnam": 2, "str": [2, 6], "port": 2, "int": [2, 6], "1883": 2, "usernam": 2, "password": 2, "logger": 2, "log": 2, "identifi": [2, 8], "queue_typ": [2, 5], "type": [2, 3, 6, 8], "protocol": 2, "protocolvers": 2, "Will": 2, "bool": 2, "transport": 2, "tcp": 2, "timeout": 2, "float": [2, 6], "keepal": 2, "60": 2, "bind_address": 2, "bind_port": 2, "clean_start": 2, "3": [2, 3, 8], "max_queued_incoming_messag": [2, 5], "max_queued_outgoing_messag": [2, 5], "max_inflight_messag": 2, "max_concurrent_outgoing_cal": 2, "properti": 2, "tls_context": 2, "ssl": 2, "sslcontext": 2, "tls_param": 2, "tlsparamet": 2, "tls_insecur": 2, "proxi": 2, "proxyset": 2, "socket_opt": 2, "iter": [2, 8], "socketopt": 2, "websocket_path": 2, "websocket_head": 2, "websockethead": 2, "broker": [2, 3, 5, 6], "ip": 2, "remot": 2, "authent": 2, "custom": 2, "gener": [2, 8], "automat": [2, 6], "default": [2, 3, 6, 8], "fifo": [2, 8], "lifo": [2, 8], "lifoqueu": [2, 8], "prioriti": [2, 8], "subclass": [2, 8], "priorityqueu": [2, 8], "version": [2, 5], "unexpectedli": 2, "remov": [2, 5, 8], "inform": 2, "about": [2, 3], "persist": 2, "retain": 2, "either": 2, "websocket": 2, "commun": [2, 6], "second": [2, 7, 8], "bind": 2, "v5": 2, "onli": [2, 3, 6, 8], "clean": 2, "flag": 2, "never": 2, "success": 2, "restrict": 2, "incom": [2, 5, 8], "size": [2, 8], "full": 2, "further": 2, "less": 2, "unlimit": [2, 8], "restict": 2, "outgo": 2, "maximum": 2, "number": 2, "part": [2, 6], "wai": [2, 5, 8], "through": [2, 5, 6, 8], "flow": 2, "onc": [2, 6], "concurr": [2, 5], "associ": 2, "tl": 2, "configur": 2, "enabl": 2, "disabl": 2, "server": 2, "verif": 2, "option": [2, 6, 8], "underli": [2, 3], "socket": 2, "path": 2, "header": 2, "from": [2, 3, 5, 7, 8], "asyncgener": 2, "tupl": 2, "paho": [2, 3], "subscribeopt": 2, "arg": 2, "kwarg": 2, "reasoncod": 2, "request": [2, 4, 8], "level": [2, 6], "addit": 2, "posit": 2, "complet": 2, "math": 2, "inf": 2, "indefinit": 2, "keyword": 2, "unsubscrib": 2, "unsubscript": 2, "byte": [2, 6], "bytearrai": [2, 6], "exc_typ": [2, 5], "baseexcept": 2, "exc": [2, 5], "tb": [2, 5], "tracebacktyp": 2, "mid": [2, 8], "wrap": [2, 7], "own": 2, "match": [2, 5, 8], "meant": 2, "instanti": 2, "user": [2, 5], "wa": 2, "qualiti": [2, 8], "servic": [2, 8], "whether": 2, "id": 2, "valu": [2, 8], "string": [2, 6], "check": 2, "given": 2, "against": [2, 7], "return": [2, 3, 6, 8], "otherwis": 2, "A": [2, 5], "similar": 2, "placehold": 2, "access": [2, 5], "attribut": 2, "directli": [2, 3], "oper": 2, "write": 3, "stabil": 3, "proven": 3, "librari": 3, "interfac": 3, "No": 3, "callback": 3, "welcom": 3, "mqtterror": [3, 7], "grace": 3, "forget": [3, 8], "on_unsubscrib": 3, "on_disconnect": 3, "etc": 3, "support": 3, "5": [3, 7, 8], "fulli": 3, "hint": 3, "did": 3, "mention": 3, "via": [3, 5], "pip": 3, "depend": 3, "latest": 3, "github": [3, 4], "git": 3, "http": [3, 8], "com": 3, "sbtinstrument": 3, "sinc": 3, "python": [3, 8], "8": 3, "event": 3, "proactoreventloop": 3, "said": [3, 4], "doesn": [3, 8], "add_read": 3, "requir": [3, 5], "pleas": 3, "switch": 3, "built": 3, "selectoreventloop": 3, "chang": 3, "selector": 3, "platform": 3, "sy": 3, "lower": [3, 8], "win32": 3, "o": [3, 8], "name": 3, "nt": 3, "set_event_loop_polici": 3, "windowsselectoreventlooppolici": 3, "applic": [3, 7], "usual": [3, 6], "under": 3, "bsd": 3, "claus": 3, "dual": 3, "One": 3, "so": [3, 7, 8], "eclips": 3, "distribut": 3, "v1": 3, "It": [3, 4], "almost": [3, 5], "word": 3, "ident": 3, "copyright": 3, "owner": 3, "edl": 3, "holder": 3, "foundat": 3, "inc": 3, "re": [3, 4, 8], "happi": [3, 4], "read": [3, 4], "md": 3, "adher": 3, "semant": 3, "break": [3, 5], "occur": 3, "major": [3, 5], "x": 3, "releas": 3, "live": 3, "follow": 3, "principl": 3, "keep": [3, 8], "what": [3, 8], "look": [3, 5], "There": 3, "few": 3, "synchron": 3, "micropython": 3, "asynchron": 3, "microcontrol": 3, "gmqtt": 3, "fastapi": 3, "wrapper": 3, "around": 3, "simplifi": 3, "integr": 3, "amqtt": 3, "includ": 3, "trio": 3, "base": [3, 8], "aim": [4, 5], "cover": 4, "everyth": [4, 8], "know": 4, "project": 4, "expect": [4, 5], "knowledg": 4, "thing": [4, 6], "clearli": 4, "possibl": [4, 8], "stuck": 4, "hesit": 4, "discuss": 4, "help": [4, 5], "recommend": 4, "hivemq": 4, "essenti": 4, "afterward": [4, 8], "oasi": [4, 8], "specif": [4, 8], "great": 4, "realpython": 4, "walkthrough": 4, "doc": 4, "big": 4, "open": 4, "issu": 4, "pull": 4, "find": 4, "error": 4, "have": [4, 5, 6, 7, 8], "idea": [4, 8], "improv": 4, "easi": [4, 8], "unclear": 4, "newcom": 4, "alreadi": 4, "familiar": 4, "fresh": 4, "ey": 4, "here": [4, 8], "That": [4, 8], "let": [4, 6, 8], "dive": 4, "introduc": [5, 8], "page": 5, "relev": 5, "deprec": 5, "been": 5, "filtered_messag": 5, "unfiltered_messag": 5, "replac": 5, "singl": [5, 8], "wide": 5, "renam": 5, "best": 5, "interchang": 5, "place": 5, "design": [5, 7], "howev": [5, 6], "them": [5, 7, 8], "manual": 5, "final": 5, "equival": 5, "forc": 5, "throw": 5, "cannot": 5, "cleanli": 5, "three": [5, 6], "These": 5, "describ": 5, "caus": 5, "unfilt": 5, "handl": [5, 8], "f": [5, 7, 8], "In": [5, 8], "twice": [5, 8], "isol": 5, "underneath": 5, "invok": 5, "maintain": 5, "hold": 5, "continu": 5, "e": [5, 8], "g": [5, 8], "becaus": [5, 8], "special": 5, "build": 5, "distributor": [5, 8], "top": 5, "temperature_consum": [5, 8], "while": [5, 7, 8], "temperature_queu": [5, 8], "humidity_consum": [5, 8], "humidity_queu": [5, 8], "sort": [5, 8], "appropri": [5, 8], "put_nowait": [5, 8], "elif": [5, 8], "group": [5, 8], "taskgroup": [5, 8], "tg": [5, 8], "queue_class": [5, 8], "queue_maxs": [5, 8], "move": 5, "max_queued_messag": 5, "message_retry_set": 5, "transmit": 6, "stream": 6, "accept": 6, "convert": 6, "struct": 6, "pack": 6, "object": 6, "specifi": 6, "zero": 6, "length": 6, "sent": 6, "standard": 6, "implement": [6, 8], "dict": 6, "json": 6, "dump": 6, "On": 6, "end": 6, "load": 6, "decod": 6, "reliabl": 6, "one": [6, 8], "At": 6, "most": 6, "guarante": 6, "deliveri": 6, "fastest": 6, "least": 6, "deliv": 6, "possibli": 6, "sender": 6, "until": [6, 8], "receipt": 6, "exactli": 6, "four": 6, "handshak": 6, "slowest": 6, "two": 6, "same": 6, "defin": 6, "relai": 6, "recent": 6, "last": 6, "after": 6, "thei": [6, 8], "per": 6, "previou": [6, 8], "overwritten": 6, "delet": 6, "empti": 6, "necessari": 6, "overwrit": 6, "ones": 6, "inher": 7, "unstabl": 7, "fail": 7, "especi": 7, "challeng": 7, "resili": 7, "failur": 7, "abl": 7, "detect": 7, "recov": 7, "reusabl": 7, "reentrant": 7, "interv": 7, "lost": 7, "sleep": [7, 8], "intern": 8, "wildcard": 8, "now": 8, "appear": 8, "consol": 8, "imagin": 8, "measur": 8, "provid": 8, "sequenti": 8, "basi": 8, "modifi": 8, "ascendingli": 8, "ti": 8, "sai": 8, "priorit": 8, "custompriorityqueu": 8, "_put": 8, "item": 8, "assign": 8, "super": 8, "_get": 8, "By": 8, "simul": 8, "bound": 8, "spawn": 8, "coroutin": 8, "sens": 8, "cpu": 8, "should": 8, "snippet": 8, "abov": 8, "sometim": 8, "notic": 8, "program": 8, "finish": 8, "practic": 8, "gather": 8, "11": 8, "alongsid": 8, "slept": 8, "fire": 8, "care": 8, "rais": 8, "propag": 8, "explicitli": 8, "unhandl": 8, "silent": 8, "ignor": 8, "background_task": 8, "save": 8, "garbag": 8, "collect": 8, "add": 8, "add_done_callback": 8, "infinit": 8, "do": 8, "someth": 8, "els": 8, "might": 8, "done": 8, "certain": 8, "neat": 8, "featur": 8, "result": 8, "timeouterror": 8}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"alongsid": 0, "fastapi": 0, "co": 0, "connect": 1, "broker": 1, "share": 1, "persist": 1, "session": 1, "develop": 2, "interfac": 2, "client": [2, 3, 5], "messag": [2, 5, 6, 8], "topic": [2, 8], "wildcard": 2, "The": [3, 8], "idiomat": 3, "asyncio": 3, "mqtt": 3, "instal": 3, "note": 3, "window": 3, "user": 3, "licens": 3, "contribut": 3, "version": 3, "changelog": 3, "relat": 3, "project": 3, "introduct": 4, "migrat": 5, "guid": 5, "v2": 5, "0": 5, "chang": 5, "lifecycl": 5, "queue": [5, 8], "argument": 5, "publish": 6, "payload": 6, "encod": 6, "qualiti": 6, "servic": 6, "qo": 6, "retain": 6, "reconnect": 7, "subscrib": 8, "filter": 8, "process": 8, "concurr": 8, "multipl": 8, "listen": 8, "without": 8, "block": 8, "stop": 8, "after": 8, "timeout": 8}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"Alongside FastAPI & Co.": [[0, "alongside-fastapi-co"]], "Connecting to the broker": [[1, "connecting-to-the-broker"]], "Sharing the connection": [[1, "sharing-the-connection"]], "Persistent sessions": [[1, "persistent-sessions"]], "Developer interface": [[2, "developer-interface"]], "Client": [[2, "client"]], "Message": [[2, "message"]], "Topic": [[2, "topic"]], "Wildcard": [[2, "wildcard"]], "The idiomatic asyncio MQTT client": [[3, "the-idiomatic-asyncio-mqtt-client"]], "Installation": [[3, "installation"]], "Note for Windows users": [[3, "note-for-windows-users"]], "License": [[3, "license"]], "Contributing": [[3, "contributing"]], "Versioning": [[3, "versioning"]], "Changelog": [[3, "changelog"]], "Related projects": [[3, "related-projects"]], "Introduction": [[4, "introduction"]], "Migration guide: v2.0.0": [[5, "migration-guide-v2-0-0"]], "Changes to the client lifecycle": [[5, "changes-to-the-client-lifecycle"]], "Changes to the message queue": [[5, "changes-to-the-message-queue"]], "Changes to client arguments": [[5, "changes-to-client-arguments"]], "Publishing a message": [[6, "publishing-a-message"]], "Payload encoding": [[6, "payload-encoding"]], "Quality of Service (QoS)": [[6, "quality-of-service-qos"]], "Retained messages": [[6, "retained-messages"]], "Reconnection": [[7, "reconnection"]], "Subscribing to a topic": [[8, "subscribing-to-a-topic"]], "Filtering messages": [[8, "filtering-messages"]], "The message queue": [[8, "the-message-queue"]], "Processing concurrently": [[8, "processing-concurrently"]], "Multiple queues": [[8, "multiple-queues"]], "Listening without blocking": [[8, "listening-without-blocking"]], "Stop listening": [[8, "stop-listening"]], "Stop listening after timeout": [[8, "stop-listening-after-timeout"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/subscribing-to-a-topic.html b/subscribing-to-a-topic.html index 94edf9b..6bf616f 100644 --- a/subscribing-to-a-topic.html +++ b/subscribing-to-a-topic.html @@ -166,15 +166,16 @@
  • Reconnection
  • Alongside FastAPI & Co.
  • -

    API reference

    +

    reference

    Project links

    @@ -213,17 +214,16 @@

    Subscribing to a topic#

    -

    To receive messages for a topic, we need to subscribe to it and listen for messages. This is a minimal working example that listens for messages to the temperature/# wildcard:

    +

    To receive messages for a topic, we need to subscribe to it. Incoming messages are queued internally. You can use the Client.message generator to iterate over incoming messages. This is a minimal working example that listens for messages to the temperature/# wildcard:

    import asyncio
     import aiomqtt
     
     
     async def main():
         async with aiomqtt.Client("test.mosquitto.org") as client:
    -        async with client.messages() as messages:
    -            await client.subscribe("temperature/#")
    -            async for message in messages:
    -                print(message.payload)
    +        await client.subscribe("temperature/#")
    +        async for message in client.messages:
    +            print(message.payload)
     
     
     asyncio.run(main())
    @@ -244,16 +244,15 @@ 

    Filtering messagesasync def main(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - await client.subscribe("humidity/#") - async for message in messages: - if message.topic.matches("humidity/inside"): - print(f"[humidity/outside] {message.payload}") - if message.topic.matches("+/outside"): - print(f"[+/inside] {message.payload}") - if message.topic.matches("temperature/#"): - print(f"[temperature/#] {message.payload}") + await client.subscribe("temperature/#") + await client.subscribe("humidity/#") + async for message in client.messages: + if message.topic.matches("humidity/inside"): + print(f"[humidity/inside] {message.payload}") + if message.topic.matches("+/outside"): + print(f"[+/outside] {message.payload}") + if message.topic.matches("temperature/#"): + print(f"[temperature/#] {message.payload}") asyncio.run(main()) @@ -270,8 +269,8 @@

    Filtering messages

    The message queue#

    -

    Messages are queued and returned sequentially from Client.messages().

    -

    The default queue is asyncio.Queue which returns messages on a FIFO (“first in first out”) basis. You can pass other types of asyncio queues as queue_class to Client.messages() to modify the order in which messages are returned, e.g. asyncio.LifoQueue.

    +

    Messages are queued internally and returned sequentially from Client.messages.

    +

    The default queue is asyncio.Queue which returns messages on a FIFO (“first in first out”) basis. You can pass other types of asyncio queues as queue_class to the Client to modify the order in which messages are returned, e.g. asyncio.LifoQueue.

    You can subclass asyncio.PriorityQueue to queue based on priority. Messages are returned ascendingly by their priority values. In the case of ties, messages with lower message identifiers are returned first.

    Let’s say we measure temperature and humidity again, but we want to prioritize humidity:

    import asyncio
    @@ -290,12 +289,13 @@ 

    The message queueasync def main(): - async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages(queue_class=CustomPriorityQueue) as messages: - await client.subscribe("temperature/#") - await client.subscribe("humidity/#") - async for message in messages: - print(message.payload) + async with aiomqtt.Client( + "test.mosquitto.org", queue_class=CustomPriorityQueue + ) as client: + await client.subscribe("temperature/#") + await client.subscribe("humidity/#") + async for message in client.messages: + print(message.payload) asyncio.run(main()) @@ -308,7 +308,7 @@

    The message queue

    Processing concurrently#

    -

    Messages are queued and returned sequentially from Client.messages(). If a message takes a long time to handle, it blocks the handling of other messages.

    +

    Messages are queued internally and returned sequentially from Client.messages. If a message takes a long time to handle, it blocks the handling of other messages.

    You can handle messages concurrently by using an asyncio.TaskGroup like so:

    +
    +

    Multiple queues#

    The code snippet above handles each message in a new coroutine. Sometimes, we want to handle messages from different topics concurrently, but sequentially inside a single topic.

    The idea here is to implement a “distributor” that sorts incoming messages into multiple asyncio queues. Each queue is then processed by a different coroutine. Let’s see how this works for our temperature and humidity messages:

    import asyncio
    @@ -358,19 +361,18 @@ 

    Processing concurrentlyasync def distributor(client): - async with client.messages() as messages: - await client.subscribe("temperature/#") - await client.subscribe("humidity/#") - # Sort messages into the appropriate queues - async for message in messages: - if message.topic.matches("temperature/#"): - temperature_queue.put_nowait(message) - elif message.topic.matches("humidity/#"): - humidity_queue.put_nowait(message) + # Sort messages into the appropriate queues + async for message in client.messages: + if message.topic.matches("temperature/#"): + temperature_queue.put_nowait(message) + elif message.topic.matches("humidity/#"): + humidity_queue.put_nowait(message) async def main(): async with aiomqtt.Client("test.mosquitto.org") as client: + await client.subscribe("temperature/#") + await client.subscribe("humidity/#") # Use a task group to manage and await all tasks async with asyncio.TaskGroup() as tg: tg.create_task(distributor(client)) @@ -403,13 +405,13 @@

    Listening without blockingasync def listen(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - async for message in messages: - print(message.payload) + await client.subscribe("temperature/#") + async for message in client.messages: + print(message.payload) async def main(): + # Use a task group to manage and await all tasks async with asyncio.TaskGroup() as tg: tg.create_task(sleep(2)) tg.create_task(listen()) # Start the listener task @@ -432,10 +434,9 @@

    Listening without blockingasync def listen(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - async for message in messages: - print(message.payload) + await client.subscribe("temperature/#") + async for message in client.messages: + print(message.payload) background_tasks = set() @@ -471,10 +472,9 @@

    Stop listeningasync def listen(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - async for message in messages: - print(message.payload) + await client.subscribe("temperature/#") + async for message in client.messages: + print(message.payload) async def main(): @@ -505,10 +505,9 @@

    Stop listening after timeoutasync def listen(): async with aiomqtt.Client("test.mosquitto.org") as client: - async with client.messages() as messages: - await client.subscribe("temperature/#") - async for message in messages: - print(message.payload) + await client.subscribe("temperature/#") + async for message in client.messages: + print(message.payload) async def main(): @@ -593,6 +592,7 @@

    Stop listening after timeoutFiltering messages
  • The message queue
  • Processing concurrently
  • +
  • Multiple queues
  • Listening without blocking
  • Stop listening
  • Stop listening after timeout