mqttwrapper 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/PKG-INFO +18 -58
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/README.rst +17 -54
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/mqttwrapper/paho_backend.py +45 -10
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/mqttwrapper.egg-info/PKG-INFO +18 -58
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/mqttwrapper.egg-info/SOURCES.txt +0 -1
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/mqttwrapper.egg-info/requires.txt +0 -3
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/setup.py +3 -5
- mqttwrapper-0.2.0/mqttwrapper/hbmqtt_backend.py +0 -43
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/LICENSE +0 -0
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/mqttwrapper/__init__.py +0 -0
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/mqttwrapper/run.py +0 -0
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/mqttwrapper.egg-info/dependency_links.txt +0 -0
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/mqttwrapper.egg-info/top_level.txt +0 -0
- {mqttwrapper-0.2.0 → mqttwrapper-0.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mqttwrapper
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: MQTT utility scripts made easy
|
|
5
5
|
Home-page: https://github.com/davea/mqttwrapper
|
|
6
6
|
Author: Dave Arter
|
|
@@ -17,8 +17,6 @@ Classifier: Programming Language :: Python :: 3.6
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.7
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: paho-mqtt>=2.0.0
|
|
20
|
-
Provides-Extra: hbmqtt
|
|
21
|
-
Requires-Dist: hbmqtt; extra == "hbmqtt"
|
|
22
20
|
Dynamic: author
|
|
23
21
|
Dynamic: author-email
|
|
24
22
|
Dynamic: classifier
|
|
@@ -27,7 +25,6 @@ Dynamic: home-page
|
|
|
27
25
|
Dynamic: keywords
|
|
28
26
|
Dynamic: license
|
|
29
27
|
Dynamic: license-file
|
|
30
|
-
Dynamic: provides-extra
|
|
31
28
|
Dynamic: requires-dist
|
|
32
29
|
Dynamic: summary
|
|
33
30
|
|
|
@@ -44,11 +41,7 @@ Install from PyPI::
|
|
|
44
41
|
|
|
45
42
|
$ pip install mqttwrapper
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
``hbmqtt`` if you wish, though support for this is deprecated and will be
|
|
49
|
-
removed in the future. To install, use::
|
|
50
|
-
|
|
51
|
-
$ pip install mqttwrapper[hbmqtt]
|
|
44
|
+
``paho-mqtt`` is used as the underlying MQTT library.
|
|
52
45
|
|
|
53
46
|
Usage
|
|
54
47
|
-----
|
|
@@ -77,7 +70,7 @@ or in non blocking mode::
|
|
|
77
70
|
echo "Alive and kicking"
|
|
78
71
|
time.sleep(1)
|
|
79
72
|
|
|
80
|
-
|
|
73
|
+
Most extra keyword arguments passed to ``run_script`` are passed back to the
|
|
81
74
|
callback function when it's called::
|
|
82
75
|
|
|
83
76
|
from mqttwrapper import run_script
|
|
@@ -91,6 +84,18 @@ callback function when it's called::
|
|
|
91
84
|
run_script(callback, broker="mqtt://127.0.0.1", topics=["my/awesome/topic1", "another/awesome/topic2"], context="hello", foo="bar")
|
|
92
85
|
|
|
93
86
|
|
|
87
|
+
However some are reserved and will be consumed by ```run_script``` to configure how the MQTT connection behaves:
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
- ``broker`` (default ``MQTT_BROKER`` from environment, otherwise ``None``): broker URL, e.g ``mybroker``, ``mqtts://securebroker:8884``, ``mqtt://username:password@coolbroker.example.org``
|
|
91
|
+
- ``topics`` (default ``MQTT_TOPICS`` from environment, otherwise ``None``): list of topics to subscribe to
|
|
92
|
+
- ``ignore_retained`` (default ``False``): whether to ignore a received message if it was marked as retained
|
|
93
|
+
- ``blocking`` (default ``True``): run in blocking or threaded mode
|
|
94
|
+
- ``client_id`` (default ``"",``): client ID to use when connecting to broker
|
|
95
|
+
- ``clean_session`` (default ``True``): whether to use a clean session upon (re)connect, or resume previous session. ``client_id`` must be provided if ``True``
|
|
96
|
+
- ``qos`` (default ``0``): QoS to use for connection
|
|
97
|
+
- ``raise_exceptions`` (default ``False``): whether to raise exceptions that occur during callback execution
|
|
98
|
+
|
|
94
99
|
If you don't need any context passed to your callback, just the topic and
|
|
95
100
|
payload of messages, you can run in 'importless' mode by creating a `callback`
|
|
96
101
|
module which has a `callback` function defined, then execute the
|
|
@@ -106,8 +111,7 @@ Retained messages
|
|
|
106
111
|
-----------------
|
|
107
112
|
|
|
108
113
|
You can ignore MQTT retained messages by passing ``ignore_retained=True`` when
|
|
109
|
-
calling ``run_script``.
|
|
110
|
-
backend.
|
|
114
|
+
calling ``run_script``.
|
|
111
115
|
|
|
112
116
|
Publishing messages from the callback
|
|
113
117
|
-------------------------------------
|
|
@@ -129,6 +133,8 @@ e.g.::
|
|
|
129
133
|
These tuples can optionally take the form ``(topic, payload, True)`` if you want
|
|
130
134
|
the published message to be marked as retained.
|
|
131
135
|
|
|
136
|
+
NB any exceptions raised during execution of the callback will be logged and ignored, unless ``raise_exceptions=True`` is passed to ``run_script``.
|
|
137
|
+
|
|
132
138
|
Configuration
|
|
133
139
|
-------------
|
|
134
140
|
|
|
@@ -138,56 +144,10 @@ environment variables used instead:
|
|
|
138
144
|
- ``MQTT_BROKER``: MQTT broker to connect to, e.g. ``mqtt://127.0.0.1/``
|
|
139
145
|
- ``MQTT_TOPICS``: Comma-separated list of topics to subscribe to, e.g. ``my/topic1,my/topic2``
|
|
140
146
|
|
|
141
|
-
asyncio/hbmqtt
|
|
142
|
-
--------------
|
|
143
|
-
|
|
144
|
-
NB This feature is deprecated and will be removed in the future.
|
|
145
|
-
|
|
146
|
-
The asyncio-powered ``hbmqtt`` MQTT library can be used instead, if you like::
|
|
147
|
-
|
|
148
|
-
from mqttwrapper.hbmqtt_backend import run_script
|
|
149
|
-
|
|
150
|
-
async def callback(topic, payload):
|
|
151
|
-
print("Received payload {} on topic {}".format(payload, topic))
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
Note that your callback must be an awaitable in this case.
|
|
155
|
-
|
|
156
|
-
Your callback may require context arguments which themselves are async objects
|
|
157
|
-
or awaitables which poses a challenge: how to set these up outside of an asyncio
|
|
158
|
-
event loop before calling ``run_script``? In this case, you can pass a
|
|
159
|
-
``context_callback`` awaitable as a kwarg to ``run_script``. This is run at the
|
|
160
|
-
start of the MQTT loop, and should return a dict which will be merged into the
|
|
161
|
-
kwargs which are passed to your callback. For example::
|
|
162
|
-
|
|
163
|
-
from mqttwrapper.hbmqtt_backend import run_script
|
|
164
|
-
|
|
165
|
-
async def setup_db():
|
|
166
|
-
return {
|
|
167
|
-
"query_db": query_db
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async def query_db(value):
|
|
171
|
-
# pretend this is some slow DB query, for example.
|
|
172
|
-
await asyncio.sleep(3)
|
|
173
|
-
return value * 2
|
|
174
|
-
|
|
175
|
-
async def callback(topic, payload, query_db):
|
|
176
|
-
db_result = await query_db(int(payload))
|
|
177
|
-
print("Received payload {} on topic {}, db result: {}".format(payload, topic, db_result))
|
|
178
|
-
|
|
179
|
-
def main():
|
|
180
|
-
run_script(callback, context_callback=setup_db)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
NB hbmqtt's reconnection handling does not resubscribe to topics upon
|
|
184
|
-
reconnection, and ``mqttwrapper`` does not yet work around this.
|
|
185
147
|
|
|
186
148
|
Examples
|
|
187
149
|
--------
|
|
188
150
|
|
|
189
151
|
- rxv2mqtt_
|
|
190
|
-
- tradfri-mqtt_ (uses asyncio)
|
|
191
152
|
|
|
192
153
|
.. _rxv2mqtt: https://github.com/davea/rxv2mqtt/blob/master/main.py
|
|
193
|
-
.. _tradfri-mqtt: https://github.com/davea/tradfri-mqtt/blob/master/main.py
|
|
@@ -11,11 +11,7 @@ Install from PyPI::
|
|
|
11
11
|
|
|
12
12
|
$ pip install mqttwrapper
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
``hbmqtt`` if you wish, though support for this is deprecated and will be
|
|
16
|
-
removed in the future. To install, use::
|
|
17
|
-
|
|
18
|
-
$ pip install mqttwrapper[hbmqtt]
|
|
14
|
+
``paho-mqtt`` is used as the underlying MQTT library.
|
|
19
15
|
|
|
20
16
|
Usage
|
|
21
17
|
-----
|
|
@@ -44,7 +40,7 @@ or in non blocking mode::
|
|
|
44
40
|
echo "Alive and kicking"
|
|
45
41
|
time.sleep(1)
|
|
46
42
|
|
|
47
|
-
|
|
43
|
+
Most extra keyword arguments passed to ``run_script`` are passed back to the
|
|
48
44
|
callback function when it's called::
|
|
49
45
|
|
|
50
46
|
from mqttwrapper import run_script
|
|
@@ -58,6 +54,18 @@ callback function when it's called::
|
|
|
58
54
|
run_script(callback, broker="mqtt://127.0.0.1", topics=["my/awesome/topic1", "another/awesome/topic2"], context="hello", foo="bar")
|
|
59
55
|
|
|
60
56
|
|
|
57
|
+
However some are reserved and will be consumed by ```run_script``` to configure how the MQTT connection behaves:
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
- ``broker`` (default ``MQTT_BROKER`` from environment, otherwise ``None``): broker URL, e.g ``mybroker``, ``mqtts://securebroker:8884``, ``mqtt://username:password@coolbroker.example.org``
|
|
61
|
+
- ``topics`` (default ``MQTT_TOPICS`` from environment, otherwise ``None``): list of topics to subscribe to
|
|
62
|
+
- ``ignore_retained`` (default ``False``): whether to ignore a received message if it was marked as retained
|
|
63
|
+
- ``blocking`` (default ``True``): run in blocking or threaded mode
|
|
64
|
+
- ``client_id`` (default ``"",``): client ID to use when connecting to broker
|
|
65
|
+
- ``clean_session`` (default ``True``): whether to use a clean session upon (re)connect, or resume previous session. ``client_id`` must be provided if ``True``
|
|
66
|
+
- ``qos`` (default ``0``): QoS to use for connection
|
|
67
|
+
- ``raise_exceptions`` (default ``False``): whether to raise exceptions that occur during callback execution
|
|
68
|
+
|
|
61
69
|
If you don't need any context passed to your callback, just the topic and
|
|
62
70
|
payload of messages, you can run in 'importless' mode by creating a `callback`
|
|
63
71
|
module which has a `callback` function defined, then execute the
|
|
@@ -73,8 +81,7 @@ Retained messages
|
|
|
73
81
|
-----------------
|
|
74
82
|
|
|
75
83
|
You can ignore MQTT retained messages by passing ``ignore_retained=True`` when
|
|
76
|
-
calling ``run_script``.
|
|
77
|
-
backend.
|
|
84
|
+
calling ``run_script``.
|
|
78
85
|
|
|
79
86
|
Publishing messages from the callback
|
|
80
87
|
-------------------------------------
|
|
@@ -96,6 +103,8 @@ e.g.::
|
|
|
96
103
|
These tuples can optionally take the form ``(topic, payload, True)`` if you want
|
|
97
104
|
the published message to be marked as retained.
|
|
98
105
|
|
|
106
|
+
NB any exceptions raised during execution of the callback will be logged and ignored, unless ``raise_exceptions=True`` is passed to ``run_script``.
|
|
107
|
+
|
|
99
108
|
Configuration
|
|
100
109
|
-------------
|
|
101
110
|
|
|
@@ -105,56 +114,10 @@ environment variables used instead:
|
|
|
105
114
|
- ``MQTT_BROKER``: MQTT broker to connect to, e.g. ``mqtt://127.0.0.1/``
|
|
106
115
|
- ``MQTT_TOPICS``: Comma-separated list of topics to subscribe to, e.g. ``my/topic1,my/topic2``
|
|
107
116
|
|
|
108
|
-
asyncio/hbmqtt
|
|
109
|
-
--------------
|
|
110
|
-
|
|
111
|
-
NB This feature is deprecated and will be removed in the future.
|
|
112
|
-
|
|
113
|
-
The asyncio-powered ``hbmqtt`` MQTT library can be used instead, if you like::
|
|
114
|
-
|
|
115
|
-
from mqttwrapper.hbmqtt_backend import run_script
|
|
116
|
-
|
|
117
|
-
async def callback(topic, payload):
|
|
118
|
-
print("Received payload {} on topic {}".format(payload, topic))
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
Note that your callback must be an awaitable in this case.
|
|
122
|
-
|
|
123
|
-
Your callback may require context arguments which themselves are async objects
|
|
124
|
-
or awaitables which poses a challenge: how to set these up outside of an asyncio
|
|
125
|
-
event loop before calling ``run_script``? In this case, you can pass a
|
|
126
|
-
``context_callback`` awaitable as a kwarg to ``run_script``. This is run at the
|
|
127
|
-
start of the MQTT loop, and should return a dict which will be merged into the
|
|
128
|
-
kwargs which are passed to your callback. For example::
|
|
129
|
-
|
|
130
|
-
from mqttwrapper.hbmqtt_backend import run_script
|
|
131
|
-
|
|
132
|
-
async def setup_db():
|
|
133
|
-
return {
|
|
134
|
-
"query_db": query_db
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async def query_db(value):
|
|
138
|
-
# pretend this is some slow DB query, for example.
|
|
139
|
-
await asyncio.sleep(3)
|
|
140
|
-
return value * 2
|
|
141
|
-
|
|
142
|
-
async def callback(topic, payload, query_db):
|
|
143
|
-
db_result = await query_db(int(payload))
|
|
144
|
-
print("Received payload {} on topic {}, db result: {}".format(payload, topic, db_result))
|
|
145
|
-
|
|
146
|
-
def main():
|
|
147
|
-
run_script(callback, context_callback=setup_db)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
NB hbmqtt's reconnection handling does not resubscribe to topics upon
|
|
151
|
-
reconnection, and ``mqttwrapper`` does not yet work around this.
|
|
152
117
|
|
|
153
118
|
Examples
|
|
154
119
|
--------
|
|
155
120
|
|
|
156
121
|
- rxv2mqtt_
|
|
157
|
-
- tradfri-mqtt_ (uses asyncio)
|
|
158
122
|
|
|
159
123
|
.. _rxv2mqtt: https://github.com/davea/rxv2mqtt/blob/master/main.py
|
|
160
|
-
.. _tradfri-mqtt: https://github.com/davea/tradfri-mqtt/blob/master/main.py
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import logging
|
|
3
|
-
import
|
|
2
|
+
import os
|
|
4
3
|
import threading
|
|
4
|
+
from urllib.parse import urlsplit
|
|
5
|
+
|
|
6
|
+
import paho.mqtt.client as mqtt
|
|
5
7
|
|
|
6
8
|
log = logging.getLogger("mqttwrapper.paho_backend")
|
|
7
9
|
|
|
8
10
|
def on_connect(client, userdata, flags, rc):
|
|
9
11
|
log.debug("Connected")
|
|
10
12
|
for topic in userdata['topics']:
|
|
11
|
-
client.subscribe(topic)
|
|
13
|
+
client.subscribe(topic, qos=userdata['qos'])
|
|
12
14
|
log.debug("Subscribed to %s", topic)
|
|
13
15
|
|
|
16
|
+
def on_disconnect(client, userdata, rc):
|
|
17
|
+
if rc != mqtt.MQTT_ERR_SUCCESS:
|
|
18
|
+
log.warning("Lost broker connection (%s), reconnecting",
|
|
19
|
+
mqtt.error_string(rc))
|
|
20
|
+
|
|
14
21
|
def on_message(client, userdata, msg):
|
|
15
22
|
log.debug("Received message on %s", msg.topic)
|
|
16
23
|
if msg.retain and userdata['ignore_retained']:
|
|
@@ -19,8 +26,10 @@ def on_message(client, userdata, msg):
|
|
|
19
26
|
replies = None
|
|
20
27
|
try:
|
|
21
28
|
replies = userdata['callback'](msg.topic, msg.payload, **userdata['kwargs'])
|
|
22
|
-
except Exception
|
|
23
|
-
|
|
29
|
+
except Exception:
|
|
30
|
+
if userdata['raise_exceptions']:
|
|
31
|
+
raise
|
|
32
|
+
log.exception("Callback caused exception")
|
|
24
33
|
log.debug("Callback completed.")
|
|
25
34
|
if replies is not None:
|
|
26
35
|
replies = list(replies)
|
|
@@ -35,28 +44,54 @@ def on_message(client, userdata, msg):
|
|
|
35
44
|
client.publish(topic, payload, retain=retain)
|
|
36
45
|
log.debug("Published '%s' to %s (retain: %s)", payload, topic, retain)
|
|
37
46
|
|
|
47
|
+
def parse_broker(broker):
|
|
48
|
+
if "//" not in broker:
|
|
49
|
+
broker = "mqtt://" + broker
|
|
50
|
+
url = urlsplit(broker)
|
|
51
|
+
if url.scheme not in ("mqtt", "mqtts"):
|
|
52
|
+
raise ValueError(f"Unsupported broker URL scheme: {url.scheme}")
|
|
53
|
+
tls = url.scheme == "mqtts"
|
|
54
|
+
port = url.port or (8883 if tls else 1883)
|
|
55
|
+
return url.hostname, port, tls, url.username, url.password
|
|
56
|
+
|
|
38
57
|
def mqtt_thread(client):
|
|
39
58
|
client.loop_forever()
|
|
40
59
|
|
|
41
|
-
def run_script(callback, broker=None, topics=None, ignore_retained=False, blocking=True,
|
|
60
|
+
def run_script(callback, broker=None, topics=None, ignore_retained=False, blocking=True,
|
|
61
|
+
client_id="", clean_session=True, qos=0, raise_exceptions=False, **kwargs):
|
|
42
62
|
if not broker:
|
|
43
63
|
broker = os.environ['MQTT_BROKER']
|
|
44
64
|
if not topics:
|
|
45
65
|
topics = os.environ['MQTT_TOPICS'].split(",")
|
|
66
|
+
if not clean_session and not client_id:
|
|
67
|
+
raise ValueError("client_id is required when using clean_session")
|
|
68
|
+
if raise_exceptions and not blocking:
|
|
69
|
+
raise ValueError("raise_exceptions can't be used with blocking=False")
|
|
46
70
|
|
|
47
71
|
userdata = {
|
|
48
72
|
'topics': topics,
|
|
73
|
+
'qos': qos,
|
|
49
74
|
'callback': callback,
|
|
50
75
|
'ignore_retained': ignore_retained,
|
|
76
|
+
'raise_exceptions': raise_exceptions,
|
|
51
77
|
'kwargs': kwargs
|
|
52
78
|
}
|
|
53
79
|
|
|
54
|
-
client = mqtt.Client(
|
|
80
|
+
client = mqtt.Client(
|
|
81
|
+
mqtt.CallbackAPIVersion.VERSION1,
|
|
82
|
+
client_id=client_id,
|
|
83
|
+
clean_session=clean_session,
|
|
84
|
+
userdata=userdata,
|
|
85
|
+
)
|
|
55
86
|
client.on_connect = on_connect
|
|
56
87
|
client.on_message = on_message
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
88
|
+
client.on_disconnect = on_disconnect
|
|
89
|
+
host, port, tls, username, password = parse_broker(broker)
|
|
90
|
+
if tls:
|
|
91
|
+
client.tls_set()
|
|
92
|
+
if username:
|
|
93
|
+
client.username_pw_set(username, password)
|
|
94
|
+
client.connect(host, port)
|
|
60
95
|
if blocking:
|
|
61
96
|
client.loop_forever()
|
|
62
97
|
else:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mqttwrapper
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: MQTT utility scripts made easy
|
|
5
5
|
Home-page: https://github.com/davea/mqttwrapper
|
|
6
6
|
Author: Dave Arter
|
|
@@ -17,8 +17,6 @@ Classifier: Programming Language :: Python :: 3.6
|
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.7
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: paho-mqtt>=2.0.0
|
|
20
|
-
Provides-Extra: hbmqtt
|
|
21
|
-
Requires-Dist: hbmqtt; extra == "hbmqtt"
|
|
22
20
|
Dynamic: author
|
|
23
21
|
Dynamic: author-email
|
|
24
22
|
Dynamic: classifier
|
|
@@ -27,7 +25,6 @@ Dynamic: home-page
|
|
|
27
25
|
Dynamic: keywords
|
|
28
26
|
Dynamic: license
|
|
29
27
|
Dynamic: license-file
|
|
30
|
-
Dynamic: provides-extra
|
|
31
28
|
Dynamic: requires-dist
|
|
32
29
|
Dynamic: summary
|
|
33
30
|
|
|
@@ -44,11 +41,7 @@ Install from PyPI::
|
|
|
44
41
|
|
|
45
42
|
$ pip install mqttwrapper
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
``hbmqtt`` if you wish, though support for this is deprecated and will be
|
|
49
|
-
removed in the future. To install, use::
|
|
50
|
-
|
|
51
|
-
$ pip install mqttwrapper[hbmqtt]
|
|
44
|
+
``paho-mqtt`` is used as the underlying MQTT library.
|
|
52
45
|
|
|
53
46
|
Usage
|
|
54
47
|
-----
|
|
@@ -77,7 +70,7 @@ or in non blocking mode::
|
|
|
77
70
|
echo "Alive and kicking"
|
|
78
71
|
time.sleep(1)
|
|
79
72
|
|
|
80
|
-
|
|
73
|
+
Most extra keyword arguments passed to ``run_script`` are passed back to the
|
|
81
74
|
callback function when it's called::
|
|
82
75
|
|
|
83
76
|
from mqttwrapper import run_script
|
|
@@ -91,6 +84,18 @@ callback function when it's called::
|
|
|
91
84
|
run_script(callback, broker="mqtt://127.0.0.1", topics=["my/awesome/topic1", "another/awesome/topic2"], context="hello", foo="bar")
|
|
92
85
|
|
|
93
86
|
|
|
87
|
+
However some are reserved and will be consumed by ```run_script``` to configure how the MQTT connection behaves:
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
- ``broker`` (default ``MQTT_BROKER`` from environment, otherwise ``None``): broker URL, e.g ``mybroker``, ``mqtts://securebroker:8884``, ``mqtt://username:password@coolbroker.example.org``
|
|
91
|
+
- ``topics`` (default ``MQTT_TOPICS`` from environment, otherwise ``None``): list of topics to subscribe to
|
|
92
|
+
- ``ignore_retained`` (default ``False``): whether to ignore a received message if it was marked as retained
|
|
93
|
+
- ``blocking`` (default ``True``): run in blocking or threaded mode
|
|
94
|
+
- ``client_id`` (default ``"",``): client ID to use when connecting to broker
|
|
95
|
+
- ``clean_session`` (default ``True``): whether to use a clean session upon (re)connect, or resume previous session. ``client_id`` must be provided if ``True``
|
|
96
|
+
- ``qos`` (default ``0``): QoS to use for connection
|
|
97
|
+
- ``raise_exceptions`` (default ``False``): whether to raise exceptions that occur during callback execution
|
|
98
|
+
|
|
94
99
|
If you don't need any context passed to your callback, just the topic and
|
|
95
100
|
payload of messages, you can run in 'importless' mode by creating a `callback`
|
|
96
101
|
module which has a `callback` function defined, then execute the
|
|
@@ -106,8 +111,7 @@ Retained messages
|
|
|
106
111
|
-----------------
|
|
107
112
|
|
|
108
113
|
You can ignore MQTT retained messages by passing ``ignore_retained=True`` when
|
|
109
|
-
calling ``run_script``.
|
|
110
|
-
backend.
|
|
114
|
+
calling ``run_script``.
|
|
111
115
|
|
|
112
116
|
Publishing messages from the callback
|
|
113
117
|
-------------------------------------
|
|
@@ -129,6 +133,8 @@ e.g.::
|
|
|
129
133
|
These tuples can optionally take the form ``(topic, payload, True)`` if you want
|
|
130
134
|
the published message to be marked as retained.
|
|
131
135
|
|
|
136
|
+
NB any exceptions raised during execution of the callback will be logged and ignored, unless ``raise_exceptions=True`` is passed to ``run_script``.
|
|
137
|
+
|
|
132
138
|
Configuration
|
|
133
139
|
-------------
|
|
134
140
|
|
|
@@ -138,56 +144,10 @@ environment variables used instead:
|
|
|
138
144
|
- ``MQTT_BROKER``: MQTT broker to connect to, e.g. ``mqtt://127.0.0.1/``
|
|
139
145
|
- ``MQTT_TOPICS``: Comma-separated list of topics to subscribe to, e.g. ``my/topic1,my/topic2``
|
|
140
146
|
|
|
141
|
-
asyncio/hbmqtt
|
|
142
|
-
--------------
|
|
143
|
-
|
|
144
|
-
NB This feature is deprecated and will be removed in the future.
|
|
145
|
-
|
|
146
|
-
The asyncio-powered ``hbmqtt`` MQTT library can be used instead, if you like::
|
|
147
|
-
|
|
148
|
-
from mqttwrapper.hbmqtt_backend import run_script
|
|
149
|
-
|
|
150
|
-
async def callback(topic, payload):
|
|
151
|
-
print("Received payload {} on topic {}".format(payload, topic))
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
Note that your callback must be an awaitable in this case.
|
|
155
|
-
|
|
156
|
-
Your callback may require context arguments which themselves are async objects
|
|
157
|
-
or awaitables which poses a challenge: how to set these up outside of an asyncio
|
|
158
|
-
event loop before calling ``run_script``? In this case, you can pass a
|
|
159
|
-
``context_callback`` awaitable as a kwarg to ``run_script``. This is run at the
|
|
160
|
-
start of the MQTT loop, and should return a dict which will be merged into the
|
|
161
|
-
kwargs which are passed to your callback. For example::
|
|
162
|
-
|
|
163
|
-
from mqttwrapper.hbmqtt_backend import run_script
|
|
164
|
-
|
|
165
|
-
async def setup_db():
|
|
166
|
-
return {
|
|
167
|
-
"query_db": query_db
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async def query_db(value):
|
|
171
|
-
# pretend this is some slow DB query, for example.
|
|
172
|
-
await asyncio.sleep(3)
|
|
173
|
-
return value * 2
|
|
174
|
-
|
|
175
|
-
async def callback(topic, payload, query_db):
|
|
176
|
-
db_result = await query_db(int(payload))
|
|
177
|
-
print("Received payload {} on topic {}, db result: {}".format(payload, topic, db_result))
|
|
178
|
-
|
|
179
|
-
def main():
|
|
180
|
-
run_script(callback, context_callback=setup_db)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
NB hbmqtt's reconnection handling does not resubscribe to topics upon
|
|
184
|
-
reconnection, and ``mqttwrapper`` does not yet work around this.
|
|
185
147
|
|
|
186
148
|
Examples
|
|
187
149
|
--------
|
|
188
150
|
|
|
189
151
|
- rxv2mqtt_
|
|
190
|
-
- tradfri-mqtt_ (uses asyncio)
|
|
191
152
|
|
|
192
153
|
.. _rxv2mqtt: https://github.com/davea/rxv2mqtt/blob/master/main.py
|
|
193
|
-
.. _tradfri-mqtt: https://github.com/davea/tradfri-mqtt/blob/master/main.py
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
from setuptools import setup, find_packages
|
|
2
1
|
from codecs import open
|
|
3
2
|
from os import path
|
|
4
3
|
|
|
4
|
+
from setuptools import find_packages, setup
|
|
5
|
+
|
|
5
6
|
here = path.abspath(path.dirname(__file__))
|
|
6
7
|
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
|
|
7
8
|
long_description = f.read()
|
|
8
9
|
|
|
9
10
|
setup(
|
|
10
11
|
name='mqttwrapper',
|
|
11
|
-
version='0.
|
|
12
|
+
version='0.3.0',
|
|
12
13
|
description='MQTT utility scripts made easy',
|
|
13
14
|
long_description=long_description,
|
|
14
15
|
url='https://github.com/davea/mqttwrapper',
|
|
@@ -28,7 +29,4 @@ setup(
|
|
|
28
29
|
keywords='mqtt',
|
|
29
30
|
packages=find_packages(),
|
|
30
31
|
install_requires=['paho-mqtt>=2.0.0'],
|
|
31
|
-
extras_require={
|
|
32
|
-
'hbmqtt': ['hbmqtt'],
|
|
33
|
-
},
|
|
34
32
|
)
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import logging
|
|
3
|
-
import asyncio
|
|
4
|
-
from warnings import warn
|
|
5
|
-
|
|
6
|
-
from hbmqtt.client import MQTTClient, ClientException
|
|
7
|
-
from hbmqtt.mqtt.constants import QOS_0
|
|
8
|
-
|
|
9
|
-
log = logging.getLogger("mqttwrapper.hbmqtt_backend")
|
|
10
|
-
|
|
11
|
-
warn("hbmqtt backend is deprecated and will be removed in the future.", DeprecationWarning)
|
|
12
|
-
log.warn("hbmqtt backend is deprecated and will be removed in the future.")
|
|
13
|
-
|
|
14
|
-
async def mqtt_loop(broker, topics, callback, context_callback, **kwargs):
|
|
15
|
-
if context_callback is not None:
|
|
16
|
-
kwargs.update(await context_callback())
|
|
17
|
-
client = MQTTClient()
|
|
18
|
-
await client.connect(broker, cleansession=True)
|
|
19
|
-
log.debug("Connected")
|
|
20
|
-
await client.subscribe([(topic, QOS_0) for topic in topics])
|
|
21
|
-
log.debug("Subscribed to %s", topics)
|
|
22
|
-
try:
|
|
23
|
-
while True:
|
|
24
|
-
message = await client.deliver_message()
|
|
25
|
-
packet = message.publish_packet
|
|
26
|
-
topic = packet.variable_header.topic_name
|
|
27
|
-
payload = bytes(packet.payload.data)
|
|
28
|
-
replies = await callback(topic, payload, **kwargs)
|
|
29
|
-
if replies is not None:
|
|
30
|
-
for reply_topic, reply_payload in replies:
|
|
31
|
-
await client.publish(reply_topic, reply_payload)
|
|
32
|
-
except ClientException:
|
|
33
|
-
log.exception("hbmqtt.client.ClientException:")
|
|
34
|
-
raise
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def run_script(callback, broker=None, topics=None, context_callback=None, **kwargs):
|
|
38
|
-
if not broker:
|
|
39
|
-
broker = os.environ['MQTT_BROKER']
|
|
40
|
-
if not topics:
|
|
41
|
-
topics = os.environ['MQTT_TOPICS'].split(",")
|
|
42
|
-
|
|
43
|
-
asyncio.get_event_loop().run_until_complete(mqtt_loop(broker, topics, callback, context_callback, **kwargs))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|