26
26
import json
27
27
from adafruit_minimqtt .adafruit_minimqtt import MMQTTException
28
28
29
+ try :
30
+ from typing import Optional , Type , Union
31
+ from types import TracebackType
32
+ from adafruit_minimqtt .adafruit_minimqtt import MQTT
33
+ except ImportError :
34
+ pass
35
+
29
36
__version__ = "0.0.0-auto.0"
30
37
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_AWS_IOT.git"
31
38
@@ -40,13 +47,13 @@ class AWS_IOT_ERROR(Exception):
40
47
class MQTT_CLIENT :
41
48
"""Client for interacting with Amazon AWS IoT MQTT API.
42
49
43
- :param MiniMQTT mmqttclient: Pre-configured MiniMQTT Client object.
50
+ :param ~MQTT.MQTT mmqttclient: Pre-configured MiniMQTT Client object.
44
51
:param int keep_alive: Optional Keep-alive timer interval, in seconds.
45
52
Provided interval must be 30 <= keep_alive <= 1200.
46
53
47
54
"""
48
55
49
- def __init__ (self , mmqttclient , keep_alive = 30 ):
56
+ def __init__ (self , mmqttclient : MQTT , keep_alive : int = 30 ) -> None :
50
57
if "MQTT" in str (type (mmqttclient )):
51
58
self .client = mmqttclient
52
59
else :
@@ -88,18 +95,23 @@ def __init__(self, mmqttclient, keep_alive=30):
88
95
self .client .on_unsubscribe = self ._on_unsubscribe_mqtt
89
96
self .connected_to_aws = False
90
97
91
- def __enter__ (self ):
98
+ def __enter__ (self ) -> "MQTT_CLIENT" :
92
99
return self
93
100
94
- def __exit__ (self , exception_type , exception_value , traceback ):
101
+ def __exit__ (
102
+ self ,
103
+ exception_type : Optional [Type [type ]],
104
+ exception_value : Optional [BaseException ],
105
+ traceback : Optional [TracebackType ],
106
+ ) -> None :
95
107
self .disconnect ()
96
108
97
109
@property
98
- def is_connected (self ):
110
+ def is_connected (self ) -> bool :
99
111
"""Returns if MQTT_CLIENT is connected to AWS IoT MQTT Broker"""
100
112
return self .connected_to_aws
101
113
102
- def disconnect (self ):
114
+ def disconnect (self ) -> None :
103
115
"""Disconnects from Amazon AWS IoT MQTT Broker and de-initializes the MiniMQTT Client."""
104
116
try :
105
117
self .client .disconnect ()
@@ -114,15 +126,16 @@ def disconnect(self):
114
126
self .on_unsubscribe = None
115
127
self .client .deinit ()
116
128
117
- def reconnect (self ):
129
+ def reconnect (self ) -> None :
118
130
"""Reconnects to the AWS IoT MQTT Broker"""
119
131
try :
120
132
self .client .reconnect ()
121
133
except MMQTTException as error :
122
134
raise AWS_IOT_ERROR ("Error re-connecting to AWS IoT:" , error ) from error
123
135
124
- def connect (self , clean_session = True ):
136
+ def connect (self , clean_session : bool = True ) -> None :
125
137
"""Connects to Amazon AWS IoT MQTT Broker with Client ID.
138
+
126
139
:param bool clean_session: Establishes a clean session with AWS broker.
127
140
128
141
"""
@@ -134,9 +147,12 @@ def connect(self, clean_session=True):
134
147
135
148
# MiniMQTT Callback Handlers
136
149
# pylint: disable=not-callable, unused-argument
137
- def _on_connect_mqtt (self , client , userdata , flag , ret_code ):
150
+ def _on_connect_mqtt (
151
+ self , client : MQTT , userdata : str , flag : int , ret_code : int
152
+ ) -> None :
138
153
"""Runs when code calls on_connect.
139
- :param MiniMQTT client: MiniMQTT client object.
154
+
155
+ :param ~MQTT.MQTT client: MiniMQTT client object.
140
156
:param str user_data: User data from broker
141
157
:param int flag: QoS flag from broker.
142
158
:param int ret_code: Return code from broker.
@@ -148,9 +164,12 @@ def _on_connect_mqtt(self, client, userdata, flag, ret_code):
148
164
self .on_connect (self , userdata , flag , ret_code )
149
165
150
166
# pylint: disable=not-callable, unused-argument
151
- def _on_disconnect_mqtt (self , client , userdata , flag , ret_code ):
167
+ def _on_disconnect_mqtt (
168
+ self , client : MQTT , userdata : str , flag : int , ret_code : int
169
+ ) -> None :
152
170
"""Runs when code calls on_disconnect.
153
- :param MiniMQTT client: MiniMQTT client object.
171
+
172
+ :param ~MQTT.MQTT client: MiniMQTT client object.
154
173
:param str user_data: User data from broker
155
174
:param int flag: QoS flag from broker.
156
175
:param int ret_code: Return code from broker.
@@ -162,9 +181,10 @@ def _on_disconnect_mqtt(self, client, userdata, flag, ret_code):
162
181
self .on_connect (self , userdata , flag , ret_code )
163
182
164
183
# pylint: disable=not-callable
165
- def _on_message_mqtt (self , client , topic , payload ) :
184
+ def _on_message_mqtt (self , client : MQTT , topic : str , payload : str ) -> None :
166
185
"""Runs when the client calls on_message.
167
- :param MiniMQTT client: MiniMQTT client object.
186
+
187
+ :param ~MQTT.MQTT client: MiniMQTT client object.
168
188
:param str topic: MQTT broker topic.
169
189
:param str payload: Payload returned by MQTT broker topic
170
190
@@ -173,26 +193,36 @@ def _on_message_mqtt(self, client, topic, payload):
173
193
self .on_message (self , topic , payload )
174
194
175
195
# pylint: disable=not-callable
176
- def _on_subscribe_mqtt (self , client , user_data , topic , qos ):
196
+ def _on_subscribe_mqtt (
197
+ self , client : MQTT , user_data : str , topic : int , qos : int
198
+ ) -> None :
177
199
"""Runs when the client calls on_subscribe.
178
200
179
- :param MiniMQTT client: MiniMQTT client object.
201
+ :param ~MQTT.MQTT client: MiniMQTT client object.
180
202
:param str user_data: User data from broker
181
203
:param str topic: Desired MQTT topic.
182
- param int qos: Quality of service level for topic, from broker.
204
+ : param int qos: Quality of service level for topic, from broker.
183
205
184
206
"""
185
207
if self .on_subscribe is not None :
186
208
self .on_subscribe (self , user_data , topic , qos )
187
209
188
210
# pylint: disable=not-callable
189
- def _on_unsubscribe_mqtt (self , client , user_data , topic , pid ):
190
- """Runs when the client calls on_unsubscribe."""
211
+ def _on_unsubscribe_mqtt (
212
+ self , client : MQTT , user_data : str , topic : str , pid : int
213
+ ) -> None :
214
+ """Runs when the client calls on_unsubscribe.
215
+
216
+ :param ~MQTT.MQTT client: MiniMQTT client object.
217
+ :param str user_data: User data from broker
218
+ :param str topic: Desired MQTT topic.
219
+ :param int pid: Process ID.
220
+ """
191
221
if self .on_unsubscribe is not None :
192
222
self .on_unsubscribe (self , user_data , topic , pid )
193
223
194
224
# MiniMQTT Network Control Flow
195
- def loop (self ):
225
+ def loop (self ) -> None :
196
226
"""Starts a synchronous message loop which maintains connection with AWS IoT.
197
227
Must be called within the keep_alive timeout specified to init.
198
228
This method does not handle network connection/disconnection.
@@ -207,28 +237,28 @@ def loop(self):
207
237
if self .connected_to_aws :
208
238
self .client .loop ()
209
239
210
- def loop_forever (self ):
240
+ def loop_forever (self ) -> None :
211
241
"""Begins a blocking, asynchronous message loop.
212
242
This method handles network connection/disconnection.
213
-
214
243
"""
215
244
if self .connected_to_aws :
216
245
self .client .loop_forever ()
217
246
218
247
@staticmethod
219
- def validate_topic (topic ) :
248
+ def validate_topic (topic : str ) -> None :
220
249
"""Validates if user-provided pub/sub topics adhere to AWS Service Limits.
221
250
https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html
222
- :param str topic: Desired topic to validate
223
251
252
+ :param str topic: Desired topic to validate
224
253
"""
225
254
assert hasattr (topic , "split" ), "Topic must be a string"
226
255
assert len (topic ) < 256 , "Topic must be less than 256 bytes!"
227
256
assert len (topic .split ("/" )) <= 9 , "Topics are limited to 7 forward slashes."
228
257
229
258
# MiniMQTT Pub/Sub Methods, for usage with AWS IoT
230
- def subscribe (self , topic , qos = 1 ) :
259
+ def subscribe (self , topic : str , qos : int = 1 ) -> None :
231
260
"""Subscribes to an AWS IoT Topic.
261
+
232
262
:param str topic: MQTT topic to subscribe to.
233
263
:param int qos: Desired topic subscription's quality-of-service.
234
264
@@ -237,14 +267,16 @@ def subscribe(self, topic, qos=1):
237
267
self .validate_topic (topic )
238
268
self .client .subscribe (topic , qos )
239
269
240
- def publish (self , topic , payload , qos = 1 ):
270
+ def publish (
271
+ self , topic : str , payload : Union [str , float , bytes ], qos : int = 1
272
+ ) -> None :
241
273
"""Publishes to a AWS IoT Topic.
274
+
242
275
:param str topic: MQTT topic to publish to.
243
- :param str payload: Data to publish to topic.
244
- :param int payload: Data to publish to topic.
245
- :param float payload: Data to publish to topic.
246
- :param json payload: JSON-formatted data to publish to topic.
247
- :param int qos: Quality of service level for publishing.
276
+ :param payload: Data to publish to topic. Must be able to be converted
277
+ to a string using ``str()``
278
+ :type payload: str|float|bytes
279
+ :param int qos: Quality of service level for publishing
248
280
249
281
"""
250
282
assert qos < 2 , "AWS IoT does not support publishing with QoS 2."
@@ -255,35 +287,37 @@ def publish(self, topic, payload, qos=1):
255
287
256
288
# AWS IoT Device Shadow Service
257
289
258
- def shadow_get_subscribe (self , qos = 1 ) :
290
+ def shadow_get_subscribe (self , qos : int = 1 ) -> None :
259
291
"""Subscribes to device's shadow get response.
260
- :param int qos: Optional quality of service level.
261
292
293
+ :param int qos: Optional quality of service level.
262
294
"""
263
295
self .client .subscribe (self .shadow_topic + "/get/#" , qos )
264
296
265
- def shadow_subscribe (self , qos = 1 ) :
297
+ def shadow_subscribe (self , qos : int = 1 ) -> None :
266
298
"""Subscribes to all notifications on the device's shadow update topic.
267
- :param int qos: Optional quality of service level.
268
299
300
+ :param int qos: Optional quality of service level.
269
301
"""
270
302
self .client .subscribe (self .shadow_topic + "/update/#" , qos )
271
303
272
- def shadow_update (self , document ):
304
+ def shadow_update (self , document : str ):
273
305
"""Publishes a request state document to update the device's shadow.
274
- :param json state_document: JSON-formatted state document.
275
306
307
+ :param str state_document: JSON-formatted state document string.
276
308
"""
277
309
self .client .publish (self .shadow_topic + "/update" , document )
278
310
279
- def shadow_get (self ):
311
+ def shadow_get (self ) -> None :
280
312
"""Publishes an empty message to shadow get topic to get the device's shadow."""
313
+
281
314
self .client .publish (
282
315
self .shadow_topic + "/get" , json .dumps ({"message" : "ignore" })
283
316
)
284
317
285
- def shadow_delete (self ):
318
+ def shadow_delete (self ) -> None :
286
319
"""Publishes an empty message to the shadow delete topic to delete a device's shadow"""
320
+
287
321
self .client .publish (
288
322
self .shadow_topic + "/delete" , json .dumps ({"message" : "delete" })
289
323
)
0 commit comments