Skip to content

Commit 6270110

Browse files
authored
Merge pull request #188 from vladak/user_data_public
make user_data "public"
2 parents 1c25441 + 66309c1 commit 6270110

File tree

2 files changed

+116
-8
lines changed

2 files changed

+116
-8
lines changed

adafruit_minimqtt/adafruit_minimqtt.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,10 @@ class MQTT:
168168
in seconds.
169169
:param int connect_retries: How many times to try to connect to the broker before giving up
170170
on connect or reconnect. Exponential backoff will be used for the retries.
171-
:param class user_data: arbitrary data to pass as a second argument to the callbacks.
171+
:param class user_data: arbitrary data to pass as a second argument to most of the callbacks.
172+
This works with all callbacks but the "on_message" and those added via add_topic_callback();
173+
for those, to get access to the user_data use the 'user_data' member of the MQTT object
174+
passed as 1st argument.
172175
173176
"""
174177

@@ -205,7 +208,7 @@ def __init__(
205208
self._recv_timeout = recv_timeout
206209

207210
self.keep_alive = keep_alive
208-
self._user_data = user_data
211+
self.user_data = user_data
209212
self._is_connected = False
210213
self._msg_size_lim = MQTT_MSG_SZ_LIM
211214
self._pid = 0
@@ -413,6 +416,11 @@ def add_topic_callback(self, mqtt_topic: str, callback_method) -> None:
413416
414417
:param str mqtt_topic: MQTT topic identifier.
415418
:param function callback_method: The callback method.
419+
420+
Expected method signature is ``on_message(client, topic, message)``
421+
To get access to the user_data, use the client argument.
422+
423+
If a callback is called for the topic, then any "on_message" callback will not be called.
416424
"""
417425
if mqtt_topic is None or callback_method is None:
418426
raise ValueError("MQTT topic and callback method must both be defined.")
@@ -437,6 +445,7 @@ def on_message(self):
437445
"""Called when a new message has been received on a subscribed topic.
438446
439447
Expected method signature is ``on_message(client, topic, message)``
448+
To get access to the user_data, use the client argument.
440449
"""
441450
return self._on_message
442451

@@ -638,7 +647,7 @@ def _connect(
638647
self._is_connected = True
639648
result = rc[0] & 1
640649
if self.on_connect is not None:
641-
self.on_connect(self, self._user_data, result, rc[2])
650+
self.on_connect(self, self.user_data, result, rc[2])
642651

643652
return result
644653

@@ -661,7 +670,7 @@ def disconnect(self) -> None:
661670
self._is_connected = False
662671
self._subscribed_topics = []
663672
if self.on_disconnect is not None:
664-
self.on_disconnect(self, self._user_data, 0)
673+
self.on_disconnect(self, self.user_data, 0)
665674

666675
def ping(self) -> list[int]:
667676
"""Pings the MQTT Broker to confirm if the broker is alive or if
@@ -757,7 +766,7 @@ def publish(
757766
self._sock.send(pub_hdr_var)
758767
self._sock.send(msg)
759768
if qos == 0 and self.on_publish is not None:
760-
self.on_publish(self, self._user_data, topic, self._pid)
769+
self.on_publish(self, self.user_data, topic, self._pid)
761770
if qos == 1:
762771
stamp = time.monotonic()
763772
while True:
@@ -769,7 +778,7 @@ def publish(
769778
rcv_pid = rcv_pid_buf[0] << 0x08 | rcv_pid_buf[1]
770779
if self._pid == rcv_pid:
771780
if self.on_publish is not None:
772-
self.on_publish(self, self._user_data, topic, rcv_pid)
781+
self.on_publish(self, self.user_data, topic, rcv_pid)
773782
return
774783

775784
if op is None:
@@ -849,7 +858,7 @@ def subscribe(self, topic: str, qos: int = 0) -> None:
849858

850859
for t, q in topics:
851860
if self.on_subscribe is not None:
852-
self.on_subscribe(self, self._user_data, t, q)
861+
self.on_subscribe(self, self.user_data, t, q)
853862
self._subscribed_topics.append(t)
854863
return
855864

@@ -907,7 +916,7 @@ def unsubscribe(self, topic: str) -> None:
907916
assert rc[1] == packet_id_bytes[0] and rc[2] == packet_id_bytes[1]
908917
for t in topics:
909918
if self.on_unsubscribe is not None:
910-
self.on_unsubscribe(self, self._user_data, t, self._pid)
919+
self.on_unsubscribe(self, self.user_data, t, self._pid)
911920
self._subscribed_topics.remove(t)
912921
return
913922

examples/cpython/user_data.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# SPDX-FileCopyrightText: 2023 Vladimír Kotal
2+
# SPDX-License-Identifier: Unlicense
3+
4+
# pylint: disable=logging-fstring-interpolation
5+
6+
"""
7+
Demonstrate on how to use user_data for various callbacks.
8+
"""
9+
10+
import logging
11+
import socket
12+
import ssl
13+
import sys
14+
15+
import adafruit_minimqtt.adafruit_minimqtt as MQTT
16+
17+
18+
# pylint: disable=unused-argument
19+
def on_connect(mqtt_client, user_data, flags, ret_code):
20+
"""
21+
connect callback
22+
"""
23+
logger = logging.getLogger(__name__)
24+
logger.debug("Connected to MQTT Broker!")
25+
logger.debug(f"Flags: {flags}\n RC: {ret_code}")
26+
27+
28+
# pylint: disable=unused-argument
29+
def on_subscribe(mqtt_client, user_data, topic, granted_qos):
30+
"""
31+
subscribe callback
32+
"""
33+
logger = logging.getLogger(__name__)
34+
logger.debug(f"Subscribed to {topic} with QOS level {granted_qos}")
35+
36+
37+
def on_message(client, topic, message):
38+
"""
39+
received message callback
40+
"""
41+
logger = logging.getLogger(__name__)
42+
logger.debug(f"New message on topic {topic}: {message}")
43+
44+
messages = client.user_data
45+
if not messages.get(topic):
46+
messages[topic] = []
47+
messages[topic].append(message)
48+
49+
50+
# pylint: disable=too-many-statements,too-many-locals
51+
def main():
52+
"""
53+
Main loop.
54+
"""
55+
56+
logging.basicConfig()
57+
logger = logging.getLogger(__name__)
58+
logger.setLevel(logging.DEBUG)
59+
60+
# dictionary/map of topic to list of messages
61+
messages = {}
62+
63+
# connect to MQTT broker
64+
mqtt = MQTT.MQTT(
65+
broker="172.40.0.3",
66+
port=1883,
67+
socket_pool=socket,
68+
ssl_context=ssl.create_default_context(),
69+
user_data=messages,
70+
)
71+
72+
mqtt.on_connect = on_connect
73+
mqtt.on_subscribe = on_subscribe
74+
mqtt.on_message = on_message
75+
76+
logger.info("Connecting to MQTT broker")
77+
mqtt.connect()
78+
logger.info("Subscribing")
79+
mqtt.subscribe("foo/#", qos=0)
80+
mqtt.add_topic_callback("foo/bar", on_message)
81+
82+
i = 0
83+
while True:
84+
i += 1
85+
logger.debug(f"Loop {i}")
86+
# Make sure to stay connected to the broker e.g. in case of keep alive.
87+
mqtt.loop(1)
88+
89+
for topic, msg_list in messages.items():
90+
logger.info(f"Got {len(msg_list)} messages from topic {topic}")
91+
for msg_cnt, msg in enumerate(msg_list):
92+
logger.debug(f"#{msg_cnt}: {msg}")
93+
94+
95+
if __name__ == "__main__":
96+
try:
97+
main()
98+
except KeyboardInterrupt:
99+
sys.exit(0)

0 commit comments

Comments
 (0)