2626import json
2727from adafruit_minimqtt .adafruit_minimqtt import MMQTTException
2828
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+
2936__version__ = "0.0.0-auto.0"
3037__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_AWS_IOT.git"
3138
@@ -40,13 +47,13 @@ class AWS_IOT_ERROR(Exception):
4047class MQTT_CLIENT :
4148 """Client for interacting with Amazon AWS IoT MQTT API.
4249
43- :param MiniMQTT mmqttclient: Pre-configured MiniMQTT Client object.
50+ :param ~MQTT.MQTT mmqttclient: Pre-configured MiniMQTT Client object.
4451 :param int keep_alive: Optional Keep-alive timer interval, in seconds.
4552 Provided interval must be 30 <= keep_alive <= 1200.
4653
4754 """
4855
49- def __init__ (self , mmqttclient , keep_alive = 30 ):
56+ def __init__ (self , mmqttclient : MQTT , keep_alive : int = 30 ) -> None :
5057 if "MQTT" in str (type (mmqttclient )):
5158 self .client = mmqttclient
5259 else :
@@ -88,18 +95,23 @@ def __init__(self, mmqttclient, keep_alive=30):
8895 self .client .on_unsubscribe = self ._on_unsubscribe_mqtt
8996 self .connected_to_aws = False
9097
91- def __enter__ (self ):
98+ def __enter__ (self ) -> "MQTT_CLIENT" :
9299 return self
93100
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 :
95107 self .disconnect ()
96108
97109 @property
98- def is_connected (self ):
110+ def is_connected (self ) -> bool :
99111 """Returns if MQTT_CLIENT is connected to AWS IoT MQTT Broker"""
100112 return self .connected_to_aws
101113
102- def disconnect (self ):
114+ def disconnect (self ) -> None :
103115 """Disconnects from Amazon AWS IoT MQTT Broker and de-initializes the MiniMQTT Client."""
104116 try :
105117 self .client .disconnect ()
@@ -114,15 +126,16 @@ def disconnect(self):
114126 self .on_unsubscribe = None
115127 self .client .deinit ()
116128
117- def reconnect (self ):
129+ def reconnect (self ) -> None :
118130 """Reconnects to the AWS IoT MQTT Broker"""
119131 try :
120132 self .client .reconnect ()
121133 except MMQTTException as error :
122134 raise AWS_IOT_ERROR ("Error re-connecting to AWS IoT:" , error ) from error
123135
124- def connect (self , clean_session = True ):
136+ def connect (self , clean_session : bool = True ) -> None :
125137 """Connects to Amazon AWS IoT MQTT Broker with Client ID.
138+
126139 :param bool clean_session: Establishes a clean session with AWS broker.
127140
128141 """
@@ -134,9 +147,12 @@ def connect(self, clean_session=True):
134147
135148 # MiniMQTT Callback Handlers
136149 # 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 :
138153 """Runs when code calls on_connect.
139- :param MiniMQTT client: MiniMQTT client object.
154+
155+ :param ~MQTT.MQTT client: MiniMQTT client object.
140156 :param str user_data: User data from broker
141157 :param int flag: QoS flag from broker.
142158 :param int ret_code: Return code from broker.
@@ -148,9 +164,12 @@ def _on_connect_mqtt(self, client, userdata, flag, ret_code):
148164 self .on_connect (self , userdata , flag , ret_code )
149165
150166 # 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 :
152170 """Runs when code calls on_disconnect.
153- :param MiniMQTT client: MiniMQTT client object.
171+
172+ :param ~MQTT.MQTT client: MiniMQTT client object.
154173 :param str user_data: User data from broker
155174 :param int flag: QoS flag from broker.
156175 :param int ret_code: Return code from broker.
@@ -162,9 +181,10 @@ def _on_disconnect_mqtt(self, client, userdata, flag, ret_code):
162181 self .on_connect (self , userdata , flag , ret_code )
163182
164183 # 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 :
166185 """Runs when the client calls on_message.
167- :param MiniMQTT client: MiniMQTT client object.
186+
187+ :param ~MQTT.MQTT client: MiniMQTT client object.
168188 :param str topic: MQTT broker topic.
169189 :param str payload: Payload returned by MQTT broker topic
170190
@@ -173,26 +193,36 @@ def _on_message_mqtt(self, client, topic, payload):
173193 self .on_message (self , topic , payload )
174194
175195 # 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 :
177199 """Runs when the client calls on_subscribe.
178200
179- :param MiniMQTT client: MiniMQTT client object.
201+ :param ~MQTT.MQTT client: MiniMQTT client object.
180202 :param str user_data: User data from broker
181203 :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.
183205
184206 """
185207 if self .on_subscribe is not None :
186208 self .on_subscribe (self , user_data , topic , qos )
187209
188210 # 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+ """
191221 if self .on_unsubscribe is not None :
192222 self .on_unsubscribe (self , user_data , topic , pid )
193223
194224 # MiniMQTT Network Control Flow
195- def loop (self ):
225+ def loop (self ) -> None :
196226 """Starts a synchronous message loop which maintains connection with AWS IoT.
197227 Must be called within the keep_alive timeout specified to init.
198228 This method does not handle network connection/disconnection.
@@ -207,28 +237,28 @@ def loop(self):
207237 if self .connected_to_aws :
208238 self .client .loop ()
209239
210- def loop_forever (self ):
240+ def loop_forever (self ) -> None :
211241 """Begins a blocking, asynchronous message loop.
212242 This method handles network connection/disconnection.
213-
214243 """
215244 if self .connected_to_aws :
216245 self .client .loop_forever ()
217246
218247 @staticmethod
219- def validate_topic (topic ) :
248+ def validate_topic (topic : str ) -> None :
220249 """Validates if user-provided pub/sub topics adhere to AWS Service Limits.
221250 https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html
222- :param str topic: Desired topic to validate
223251
252+ :param str topic: Desired topic to validate
224253 """
225254 assert hasattr (topic , "split" ), "Topic must be a string"
226255 assert len (topic ) < 256 , "Topic must be less than 256 bytes!"
227256 assert len (topic .split ("/" )) <= 9 , "Topics are limited to 7 forward slashes."
228257
229258 # 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 :
231260 """Subscribes to an AWS IoT Topic.
261+
232262 :param str topic: MQTT topic to subscribe to.
233263 :param int qos: Desired topic subscription's quality-of-service.
234264
@@ -237,14 +267,16 @@ def subscribe(self, topic, qos=1):
237267 self .validate_topic (topic )
238268 self .client .subscribe (topic , qos )
239269
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 :
241273 """Publishes to a AWS IoT Topic.
274+
242275 :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
248280
249281 """
250282 assert qos < 2 , "AWS IoT does not support publishing with QoS 2."
@@ -255,35 +287,37 @@ def publish(self, topic, payload, qos=1):
255287
256288 # AWS IoT Device Shadow Service
257289
258- def shadow_get_subscribe (self , qos = 1 ) :
290+ def shadow_get_subscribe (self , qos : int = 1 ) -> None :
259291 """Subscribes to device's shadow get response.
260- :param int qos: Optional quality of service level.
261292
293+ :param int qos: Optional quality of service level.
262294 """
263295 self .client .subscribe (self .shadow_topic + "/get/#" , qos )
264296
265- def shadow_subscribe (self , qos = 1 ) :
297+ def shadow_subscribe (self , qos : int = 1 ) -> None :
266298 """Subscribes to all notifications on the device's shadow update topic.
267- :param int qos: Optional quality of service level.
268299
300+ :param int qos: Optional quality of service level.
269301 """
270302 self .client .subscribe (self .shadow_topic + "/update/#" , qos )
271303
272- def shadow_update (self , document ):
304+ def shadow_update (self , document : str ):
273305 """Publishes a request state document to update the device's shadow.
274- :param json state_document: JSON-formatted state document.
275306
307+ :param str state_document: JSON-formatted state document string.
276308 """
277309 self .client .publish (self .shadow_topic + "/update" , document )
278310
279- def shadow_get (self ):
311+ def shadow_get (self ) -> None :
280312 """Publishes an empty message to shadow get topic to get the device's shadow."""
313+
281314 self .client .publish (
282315 self .shadow_topic + "/get" , json .dumps ({"message" : "ignore" })
283316 )
284317
285- def shadow_delete (self ):
318+ def shadow_delete (self ) -> None :
286319 """Publishes an empty message to the shadow delete topic to delete a device's shadow"""
320+
287321 self .client .publish (
288322 self .shadow_topic + "/delete" , json .dumps ({"message" : "delete" })
289323 )
0 commit comments