1780 lines
60 KiB
Python
1780 lines
60 KiB
Python
#
|
|
#/*
|
|
# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
# *
|
|
# * Licensed under the Apache License, Version 2.0 (the "License").
|
|
# * You may not use this file except in compliance with the License.
|
|
# * A copy of the License is located at
|
|
# *
|
|
# * http://aws.amazon.com/apache2.0
|
|
# *
|
|
# * or in the "license" file accompanying this file. This file is distributed
|
|
# * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
|
# * express or implied. See the License for the specific language governing
|
|
# * permissions and limitations under the License.
|
|
# */
|
|
|
|
from AWSIoTPythonSDK.core.util.providers import CertificateCredentialsProvider
|
|
from AWSIoTPythonSDK.core.util.providers import IAMCredentialsProvider
|
|
from AWSIoTPythonSDK.core.util.providers import EndpointProvider
|
|
from AWSIoTPythonSDK.core.jobs.thingJobManager import jobExecutionTopicType
|
|
from AWSIoTPythonSDK.core.jobs.thingJobManager import jobExecutionTopicReplyType
|
|
from AWSIoTPythonSDK.core.protocol.mqtt_core import MqttCore
|
|
import AWSIoTPythonSDK.core.shadow.shadowManager as shadowManager
|
|
import AWSIoTPythonSDK.core.shadow.deviceShadow as deviceShadow
|
|
import AWSIoTPythonSDK.core.jobs.thingJobManager as thingJobManager
|
|
|
|
# Constants
|
|
# - Protocol types:
|
|
MQTTv3_1 = 3
|
|
MQTTv3_1_1 = 4
|
|
|
|
DROP_OLDEST = 0
|
|
DROP_NEWEST = 1
|
|
|
|
class AWSIoTMQTTClient:
|
|
|
|
def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True):
|
|
"""
|
|
|
|
The client class that connects to and accesses AWS IoT over MQTT v3.1/3.1.1.
|
|
|
|
The following connection types are available:
|
|
|
|
- TLSv1.2 Mutual Authentication
|
|
|
|
X.509 certificate-based secured MQTT connection to AWS IoT
|
|
|
|
- Websocket SigV4
|
|
|
|
IAM credential-based secured MQTT connection over Websocket to AWS IoT
|
|
|
|
It provides basic synchronous MQTT operations in the classic MQTT publish-subscribe
|
|
model, along with configurations of on-top features:
|
|
|
|
- Auto reconnect/resubscribe
|
|
|
|
- Progressive reconnect backoff
|
|
|
|
- Offline publish requests queueing with draining
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT
|
|
|
|
# Create an AWS IoT MQTT Client using TLSv1.2 Mutual Authentication
|
|
myAWSIoTMQTTClient = AWSIoTPyMQTT.AWSIoTMQTTClient("testIoTPySDK")
|
|
# Create an AWS IoT MQTT Client using Websocket SigV4
|
|
myAWSIoTMQTTClient = AWSIoTPyMQTT.AWSIoTMQTTClient("testIoTPySDK", useWebsocket=True)
|
|
|
|
**Parameters**
|
|
|
|
*clientID* - String that denotes the client identifier used to connect to AWS IoT.
|
|
If empty string were provided, client id for this connection will be randomly generated
|
|
n server side.
|
|
|
|
*protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1`
|
|
|
|
*useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not.
|
|
|
|
**Returns**
|
|
|
|
:code:`AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient` object
|
|
|
|
"""
|
|
self._mqtt_core = MqttCore(clientID, cleanSession, protocolType, useWebsocket)
|
|
|
|
# Configuration APIs
|
|
def configureLastWill(self, topic, payload, QoS, retain=False):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the last will topic, payload and QoS of the client. Should be called before connect.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.configureLastWill("last/Will/Topic", "lastWillPayload", 0)
|
|
|
|
**Parameters**
|
|
|
|
*topic* - Topic name that last will publishes to.
|
|
|
|
*payload* - Payload to publish for last will.
|
|
|
|
*QoS* - Quality of Service. Could be 0 or 1.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.configure_last_will(topic, payload, QoS, retain)
|
|
|
|
def clearLastWill(self):
|
|
"""
|
|
**Description**
|
|
|
|
Used to clear the last will configuration that is previously set through configureLastWill.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.clearLastWill()
|
|
|
|
**Parameter**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.clear_last_will()
|
|
|
|
def configureEndpoint(self, hostName, portNumber):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the host name and port number the client tries to connect to. Should be called
|
|
before connect.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.configureEndpoint("random.iot.region.amazonaws.com", 8883)
|
|
|
|
**Parameters**
|
|
|
|
*hostName* - String that denotes the host name of the user-specific AWS IoT endpoint.
|
|
|
|
*portNumber* - Integer that denotes the port number to connect to. Could be :code:`8883` for
|
|
TLSv1.2 Mutual Authentication or :code:`443` for Websocket SigV4 and TLSv1.2 Mutual Authentication
|
|
with ALPN extension.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
endpoint_provider = EndpointProvider()
|
|
endpoint_provider.set_host(hostName)
|
|
endpoint_provider.set_port(portNumber)
|
|
self._mqtt_core.configure_endpoint(endpoint_provider)
|
|
if portNumber == 443 and not self._mqtt_core.use_wss():
|
|
self._mqtt_core.configure_alpn_protocols()
|
|
|
|
def configureIAMCredentials(self, AWSAccessKeyID, AWSSecretAccessKey, AWSSessionToken=""):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure/update the custom IAM credentials for Websocket SigV4 connection to
|
|
AWS IoT. Should be called before connect.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.configureIAMCredentials(obtainedAccessKeyID, obtainedSecretAccessKey, obtainedSessionToken)
|
|
|
|
.. note::
|
|
|
|
Hard-coding credentials into custom script is NOT recommended. Please use AWS Cognito identity service
|
|
or other credential provider.
|
|
|
|
**Parameters**
|
|
|
|
*AWSAccessKeyID* - AWS Access Key Id from user-specific IAM credentials.
|
|
|
|
*AWSSecretAccessKey* - AWS Secret Access Key from user-specific IAM credentials.
|
|
|
|
*AWSSessionToken* - AWS Session Token for temporary authentication from STS.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
iam_credentials_provider = IAMCredentialsProvider()
|
|
iam_credentials_provider.set_access_key_id(AWSAccessKeyID)
|
|
iam_credentials_provider.set_secret_access_key(AWSSecretAccessKey)
|
|
iam_credentials_provider.set_session_token(AWSSessionToken)
|
|
self._mqtt_core.configure_iam_credentials(iam_credentials_provider)
|
|
|
|
def configureCredentials(self, CAFilePath, KeyPath="", CertificatePath=""): # Should be good for MutualAuth certs config and Websocket rootCA config
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the rootCA, private key and certificate files. Should be called before connect.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.configureCredentials("PATH/TO/ROOT_CA", "PATH/TO/PRIVATE_KEY", "PATH/TO/CERTIFICATE")
|
|
|
|
**Parameters**
|
|
|
|
*CAFilePath* - Path to read the root CA file. Required for all connection types.
|
|
|
|
*KeyPath* - Path to read the private key. Required for X.509 certificate based connection.
|
|
|
|
*CertificatePath* - Path to read the certificate. Required for X.509 certificate based connection.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
cert_credentials_provider = CertificateCredentialsProvider()
|
|
cert_credentials_provider.set_ca_path(CAFilePath)
|
|
cert_credentials_provider.set_key_path(KeyPath)
|
|
cert_credentials_provider.set_cert_path(CertificatePath)
|
|
self._mqtt_core.configure_cert_credentials(cert_credentials_provider)
|
|
|
|
def configureAutoReconnectBackoffTime(self, baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the auto-reconnect backoff timing. Should be called before connect.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure the auto-reconnect backoff to start with 1 second and use 128 seconds as a maximum back off time.
|
|
# Connection over 20 seconds is considered stable and will reset the back off time back to its base.
|
|
myAWSIoTMQTTClient.configureAutoReconnectBackoffTime(1, 128, 20)
|
|
|
|
**Parameters**
|
|
|
|
*baseReconnectQuietTimeSecond* - The initial back off time to start with, in seconds.
|
|
Should be less than the stableConnectionTime.
|
|
|
|
*maxReconnectQuietTimeSecond* - The maximum back off time, in seconds.
|
|
|
|
*stableConnectionTimeSecond* - The number of seconds for a connection to last to be considered as stable.
|
|
Back off time will be reset to base once the connection is stable.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.configure_reconnect_back_off(baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond)
|
|
|
|
def configureOfflinePublishQueueing(self, queueSize, dropBehavior=DROP_NEWEST):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the queue size and drop behavior for the offline requests queueing. Should be
|
|
called before connect. Queueable offline requests include publish, subscribe and unsubscribe.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT
|
|
|
|
# Configure the offline queue for publish requests to be 20 in size and drop the oldest
|
|
request when the queue is full.
|
|
myAWSIoTMQTTClient.configureOfflinePublishQueueing(20, AWSIoTPyMQTT.DROP_OLDEST)
|
|
|
|
**Parameters**
|
|
|
|
*queueSize* - Size of the queue for offline publish requests queueing.
|
|
If set to 0, the queue is disabled. If set to -1, the queue size is set to be infinite.
|
|
|
|
*dropBehavior* - the type of drop behavior when the queue is full.
|
|
Could be :code:`AWSIoTPythonSDK.core.util.enums.DropBehaviorTypes.DROP_OLDEST` or
|
|
:code:`AWSIoTPythonSDK.core.util.enums.DropBehaviorTypes.DROP_NEWEST`.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.configure_offline_requests_queue(queueSize, dropBehavior)
|
|
|
|
def configureDrainingFrequency(self, frequencyInHz):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the draining speed to clear up the queued requests when the connection is back.
|
|
Should be called before connect.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure the draining speed to be 2 requests/second
|
|
myAWSIoTMQTTClient.configureDrainingFrequency(2)
|
|
|
|
.. note::
|
|
|
|
Make sure the draining speed is fast enough and faster than the publish rate. Slow draining
|
|
could result in inifinite draining process.
|
|
|
|
**Parameters**
|
|
|
|
*frequencyInHz* - The draining speed to clear the queued requests, in requests/second.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.configure_draining_interval_sec(1/float(frequencyInHz))
|
|
|
|
def configureConnectDisconnectTimeout(self, timeoutSecond):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the time in seconds to wait for a CONNACK or a disconnect to complete.
|
|
Should be called before connect.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure connect/disconnect timeout to be 10 seconds
|
|
myAWSIoTMQTTClient.configureConnectDisconnectTimeout(10)
|
|
|
|
**Parameters**
|
|
|
|
*timeoutSecond* - Time in seconds to wait for a CONNACK or a disconnect to complete.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.configure_connect_disconnect_timeout_sec(timeoutSecond)
|
|
|
|
def configureMQTTOperationTimeout(self, timeoutSecond):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the timeout in seconds for MQTT QoS 1 publish, subscribe and unsubscribe.
|
|
Should be called before connect.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure MQTT operation timeout to be 5 seconds
|
|
myAWSIoTMQTTClient.configureMQTTOperationTimeout(5)
|
|
|
|
**Parameters**
|
|
|
|
*timeoutSecond* - Time in seconds to wait for a PUBACK/SUBACK/UNSUBACK.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.configure_operation_timeout_sec(timeoutSecond)
|
|
|
|
def configureUsernamePassword(self, username, password=None):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the username and password used in CONNECT packet.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure user name and password
|
|
myAWSIoTMQTTClient.configureUsernamePassword("myUsername", "myPassword")
|
|
|
|
**Parameters**
|
|
|
|
*username* - Username used in the username field of CONNECT packet.
|
|
|
|
*password* - Password used in the password field of CONNECT packet.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.configure_username_password(username, password)
|
|
|
|
def configureSocketFactory(self, socket_factory):
|
|
"""
|
|
**Description**
|
|
|
|
Configure a socket factory to custom configure a different socket type for
|
|
mqtt connection. Creating a custom socket allows for configuration of a proxy
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure socket factory
|
|
custom_args = {"arg1": "val1", "arg2": "val2"}
|
|
socket_factory = lambda: custom.create_connection((host, port), **custom_args)
|
|
myAWSIoTMQTTClient.configureSocketFactory(socket_factory)
|
|
|
|
**Parameters**
|
|
|
|
*socket_factory* - Anonymous function which creates a custom socket to spec.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.configure_socket_factory(socket_factory)
|
|
|
|
def enableMetricsCollection(self):
|
|
"""
|
|
**Description**
|
|
|
|
Used to enable SDK metrics collection. Username field in CONNECT packet will be used to append the SDK name
|
|
and SDK version in use and communicate to AWS IoT cloud. This metrics collection is enabled by default.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.enableMetricsCollection()
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.enable_metrics_collection()
|
|
|
|
def disableMetricsCollection(self):
|
|
"""
|
|
**Description**
|
|
|
|
Used to disable SDK metrics collection.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.disableMetricsCollection()
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._mqtt_core.disable_metrics_collection()
|
|
|
|
# MQTT functionality APIs
|
|
def connect(self, keepAliveIntervalSecond=600):
|
|
"""
|
|
**Description**
|
|
|
|
Connect to AWS IoT, with user-specific keepalive interval configuration.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Connect to AWS IoT with default keepalive set to 600 seconds
|
|
myAWSIoTMQTTClient.connect()
|
|
# Connect to AWS IoT with keepalive interval set to 1200 seconds
|
|
myAWSIoTMQTTClient.connect(1200)
|
|
|
|
**Parameters**
|
|
|
|
*keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request.
|
|
A shorter keep-alive interval allows the client to detect disconnects more quickly.
|
|
Default set to 600 seconds.
|
|
|
|
**Returns**
|
|
|
|
True if the connect attempt succeeded. False if failed.
|
|
|
|
"""
|
|
self._load_callbacks()
|
|
return self._mqtt_core.connect(keepAliveIntervalSecond)
|
|
|
|
def connectAsync(self, keepAliveIntervalSecond=600, ackCallback=None):
|
|
"""
|
|
**Description**
|
|
|
|
Connect asynchronously to AWS IoT, with user-specific keepalive interval configuration and CONNACK callback.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Connect to AWS IoT with default keepalive set to 600 seconds and a custom CONNACK callback
|
|
myAWSIoTMQTTClient.connectAsync(ackCallback=my_connack_callback)
|
|
# Connect to AWS IoT with default keepalive set to 1200 seconds and a custom CONNACK callback
|
|
myAWSIoTMQTTClient.connectAsync(keepAliveInternvalSecond=1200, ackCallback=myConnackCallback)
|
|
|
|
**Parameters**
|
|
|
|
*keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request.
|
|
Default set to 600 seconds.
|
|
|
|
*ackCallback* - Callback to be invoked when the client receives a CONNACK. Should be in form
|
|
:code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the connect request
|
|
and :code:`data` is the connect result code.
|
|
|
|
**Returns**
|
|
|
|
Connect request packet id, for tracking purpose in the corresponding callback.
|
|
|
|
"""
|
|
self._load_callbacks()
|
|
return self._mqtt_core.connect_async(keepAliveIntervalSecond, ackCallback)
|
|
|
|
def _load_callbacks(self):
|
|
self._mqtt_core.on_online = self.onOnline
|
|
self._mqtt_core.on_offline = self.onOffline
|
|
self._mqtt_core.on_message = self.onMessage
|
|
|
|
def disconnect(self):
|
|
"""
|
|
**Description**
|
|
|
|
Disconnect from AWS IoT.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.disconnect()
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
True if the disconnect attempt succeeded. False if failed.
|
|
|
|
"""
|
|
return self._mqtt_core.disconnect()
|
|
|
|
def disconnectAsync(self, ackCallback=None):
|
|
"""
|
|
**Description**
|
|
|
|
Disconnect asynchronously to AWS IoT.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.disconnectAsync(ackCallback=myDisconnectCallback)
|
|
|
|
**Parameters**
|
|
|
|
*ackCallback* - Callback to be invoked when the client finishes sending disconnect and internal clean-up.
|
|
Should be in form :code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the disconnect
|
|
request and :code:`data` is the disconnect result code.
|
|
|
|
**Returns**
|
|
|
|
Disconnect request packet id, for tracking purpose in the corresponding callback.
|
|
|
|
"""
|
|
return self._mqtt_core.disconnect_async(ackCallback)
|
|
|
|
def publish(self, topic, payload, QoS):
|
|
"""
|
|
**Description**
|
|
|
|
Publish a new message to the desired topic with QoS.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Publish a QoS0 message "myPayload" to topic "myTopic"
|
|
myAWSIoTMQTTClient.publish("myTopic", "myPayload", 0)
|
|
# Publish a QoS1 message "myPayloadWithQos1" to topic "myTopic/sub"
|
|
myAWSIoTMQTTClient.publish("myTopic/sub", "myPayloadWithQos1", 1)
|
|
|
|
**Parameters**
|
|
|
|
*topic* - Topic name to publish to.
|
|
|
|
*payload* - Payload to publish.
|
|
|
|
*QoS* - Quality of Service. Could be 0 or 1.
|
|
|
|
**Returns**
|
|
|
|
True if the publish request has been sent to paho. False if the request did not reach paho.
|
|
|
|
"""
|
|
return self._mqtt_core.publish(topic, payload, QoS, False) # Disable retain for publish by now
|
|
|
|
def publishAsync(self, topic, payload, QoS, ackCallback=None):
|
|
"""
|
|
**Description**
|
|
|
|
Publish a new message asynchronously to the desired topic with QoS and PUBACK callback. Note that the ack
|
|
callback configuration for a QoS0 publish request will be ignored as there are no PUBACK reception.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Publish a QoS0 message "myPayload" to topic "myTopic"
|
|
myAWSIoTMQTTClient.publishAsync("myTopic", "myPayload", 0)
|
|
# Publish a QoS1 message "myPayloadWithQos1" to topic "myTopic/sub", with custom PUBACK callback
|
|
myAWSIoTMQTTClient.publishAsync("myTopic/sub", "myPayloadWithQos1", 1, ackCallback=myPubackCallback)
|
|
|
|
**Parameters**
|
|
|
|
*topic* - Topic name to publish to.
|
|
|
|
*payload* - Payload to publish.
|
|
|
|
*QoS* - Quality of Service. Could be 0 or 1.
|
|
|
|
*ackCallback* - Callback to be invoked when the client receives a PUBACK. Should be in form
|
|
:code:`customCallback(mid)`, where :code:`mid` is the packet id for the disconnect request.
|
|
|
|
**Returns**
|
|
|
|
Publish request packet id, for tracking purpose in the corresponding callback.
|
|
|
|
"""
|
|
return self._mqtt_core.publish_async(topic, payload, QoS, False, ackCallback)
|
|
|
|
def subscribe(self, topic, QoS, callback):
|
|
"""
|
|
**Description**
|
|
|
|
Subscribe to the desired topic and register a callback.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Subscribe to "myTopic" with QoS0 and register a callback
|
|
myAWSIoTMQTTClient.subscribe("myTopic", 0, customCallback)
|
|
# Subscribe to "myTopic/#" with QoS1 and register a callback
|
|
myAWSIoTMQTTClient.subscribe("myTopic/#", 1, customCallback)
|
|
|
|
**Parameters**
|
|
|
|
*topic* - Topic name or filter to subscribe to.
|
|
|
|
*QoS* - Quality of Service. Could be 0 or 1.
|
|
|
|
*callback* - Function to be called when a new message for the subscribed topic
|
|
comes in. Should be in form :code:`customCallback(client, userdata, message)`, where
|
|
:code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are
|
|
here just to be aligned with the underneath Paho callback function signature. These fields are pending to be
|
|
deprecated and should not be depended on.
|
|
|
|
**Returns**
|
|
|
|
True if the subscribe attempt succeeded. False if failed.
|
|
|
|
"""
|
|
return self._mqtt_core.subscribe(topic, QoS, callback)
|
|
|
|
def subscribeAsync(self, topic, QoS, ackCallback=None, messageCallback=None):
|
|
"""
|
|
**Description**
|
|
|
|
Subscribe to the desired topic and register a message callback with SUBACK callback.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Subscribe to "myTopic" with QoS0, custom SUBACK callback and a message callback
|
|
myAWSIoTMQTTClient.subscribe("myTopic", 0, ackCallback=mySubackCallback, messageCallback=customMessageCallback)
|
|
# Subscribe to "myTopic/#" with QoS1, custom SUBACK callback and a message callback
|
|
myAWSIoTMQTTClient.subscribe("myTopic/#", 1, ackCallback=mySubackCallback, messageCallback=customMessageCallback)
|
|
|
|
**Parameters**
|
|
|
|
*topic* - Topic name or filter to subscribe to.
|
|
|
|
*QoS* - Quality of Service. Could be 0 or 1.
|
|
|
|
*ackCallback* - Callback to be invoked when the client receives a SUBACK. Should be in form
|
|
:code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the disconnect request and
|
|
:code:`data` is the granted QoS for this subscription.
|
|
|
|
*messageCallback* - Function to be called when a new message for the subscribed topic
|
|
comes in. Should be in form :code:`customCallback(client, userdata, message)`, where
|
|
:code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are
|
|
here just to be aligned with the underneath Paho callback function signature. These fields are pending to be
|
|
deprecated and should not be depended on.
|
|
|
|
**Returns**
|
|
|
|
Subscribe request packet id, for tracking purpose in the corresponding callback.
|
|
|
|
"""
|
|
return self._mqtt_core.subscribe_async(topic, QoS, ackCallback, messageCallback)
|
|
|
|
def unsubscribe(self, topic):
|
|
"""
|
|
**Description**
|
|
|
|
Unsubscribe to the desired topic.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.unsubscribe("myTopic")
|
|
|
|
**Parameters**
|
|
|
|
*topic* - Topic name or filter to unsubscribe to.
|
|
|
|
**Returns**
|
|
|
|
True if the unsubscribe attempt succeeded. False if failed.
|
|
|
|
"""
|
|
return self._mqtt_core.unsubscribe(topic)
|
|
|
|
def unsubscribeAsync(self, topic, ackCallback=None):
|
|
"""
|
|
**Description**
|
|
|
|
Unsubscribe to the desired topic with UNSUBACK callback.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myAWSIoTMQTTClient.unsubscribe("myTopic", ackCallback=myUnsubackCallback)
|
|
|
|
**Parameters**
|
|
|
|
*topic* - Topic name or filter to unsubscribe to.
|
|
|
|
*ackCallback* - Callback to be invoked when the client receives a UNSUBACK. Should be in form
|
|
:code:`customCallback(mid)`, where :code:`mid` is the packet id for the disconnect request.
|
|
|
|
**Returns**
|
|
|
|
Unsubscribe request packet id, for tracking purpose in the corresponding callback.
|
|
|
|
"""
|
|
return self._mqtt_core.unsubscribe_async(topic, ackCallback)
|
|
|
|
def onOnline(self):
|
|
"""
|
|
**Description**
|
|
|
|
Callback that gets called when the client is online. The callback registration should happen before calling
|
|
connect/connectAsync.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Register an onOnline callback
|
|
myAWSIoTMQTTClient.onOnline = myOnOnlineCallback
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
pass
|
|
|
|
def onOffline(self):
|
|
"""
|
|
**Description**
|
|
|
|
Callback that gets called when the client is offline. The callback registration should happen before calling
|
|
connect/connectAsync.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Register an onOffline callback
|
|
myAWSIoTMQTTClient.onOffline = myOnOfflineCallback
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
pass
|
|
|
|
def onMessage(self, message):
|
|
"""
|
|
**Description**
|
|
|
|
Callback that gets called when the client receives a new message. The callback registration should happen before
|
|
calling connect/connectAsync. This callback, if present, will always be triggered regardless of whether there is
|
|
any message callback registered upon subscribe API call. It is for the purpose to aggregating the processing of
|
|
received messages in one function.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Register an onMessage callback
|
|
myAWSIoTMQTTClient.onMessage = myOnMessageCallback
|
|
|
|
**Parameters**
|
|
|
|
*message* - Received MQTT message. It contains the source topic as :code:`message.topic`, and the payload as
|
|
:code:`message.payload`.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
pass
|
|
|
|
class _AWSIoTMQTTDelegatingClient(object):
|
|
|
|
def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True, awsIoTMQTTClient=None):
|
|
"""
|
|
|
|
This class is used internally by the SDK and should not be instantiated directly.
|
|
|
|
It delegates to a provided AWS IoT MQTT Client or creates a new one given the configuration
|
|
parameters and exposes core operations for subclasses provide convenience methods
|
|
|
|
**Syntax**
|
|
|
|
None
|
|
|
|
**Parameters**
|
|
|
|
*clientID* - String that denotes the client identifier used to connect to AWS IoT.
|
|
If empty string were provided, client id for this connection will be randomly generated
|
|
n server side.
|
|
|
|
*protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1`
|
|
|
|
*useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not.
|
|
|
|
**Returns**
|
|
|
|
AWSIoTPythonSDK.MQTTLib._AWSIoTMQTTDelegatingClient object
|
|
|
|
"""
|
|
# AWSIOTMQTTClient instance
|
|
self._AWSIoTMQTTClient = awsIoTMQTTClient if awsIoTMQTTClient is not None else AWSIoTMQTTClient(clientID, protocolType, useWebsocket, cleanSession)
|
|
|
|
# Configuration APIs
|
|
def configureLastWill(self, topic, payload, QoS):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the last will topic, payload and QoS of the client. Should be called before connect. This is a public
|
|
facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myShadowClient.configureLastWill("last/Will/Topic", "lastWillPayload", 0)
|
|
myJobsClient.configureLastWill("last/Will/Topic", "lastWillPayload", 0)
|
|
|
|
**Parameters**
|
|
|
|
*topic* - Topic name that last will publishes to.
|
|
|
|
*payload* - Payload to publish for last will.
|
|
|
|
*QoS* - Quality of Service. Could be 0 or 1.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
# AWSIoTMQTTClient.configureLastWill(srcTopic, srcPayload, srcQos)
|
|
self._AWSIoTMQTTClient.configureLastWill(topic, payload, QoS)
|
|
|
|
def clearLastWill(self):
|
|
"""
|
|
**Description**
|
|
|
|
Used to clear the last will configuration that is previously set through configureLastWill. This is a public
|
|
facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myShadowClient.clearLastWill()
|
|
myJobsClient.clearLastWill()
|
|
|
|
**Parameter**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
# AWSIoTMQTTClient.clearLastWill()
|
|
self._AWSIoTMQTTClient.clearLastWill()
|
|
|
|
def configureEndpoint(self, hostName, portNumber):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the host name and port number the underneath AWS IoT MQTT Client tries to connect to. Should be called
|
|
before connect. This is a public facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myShadowClient.clearLastWill("random.iot.region.amazonaws.com", 8883)
|
|
myJobsClient.clearLastWill("random.iot.region.amazonaws.com", 8883)
|
|
|
|
**Parameters**
|
|
|
|
*hostName* - String that denotes the host name of the user-specific AWS IoT endpoint.
|
|
|
|
*portNumber* - Integer that denotes the port number to connect to. Could be :code:`8883` for
|
|
TLSv1.2 Mutual Authentication or :code:`443` for Websocket SigV4 and TLSv1.2 Mutual Authentication
|
|
with ALPN extension.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
# AWSIoTMQTTClient.configureEndpoint
|
|
self._AWSIoTMQTTClient.configureEndpoint(hostName, portNumber)
|
|
|
|
def configureIAMCredentials(self, AWSAccessKeyID, AWSSecretAccessKey, AWSSTSToken=""):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure/update the custom IAM credentials for the underneath AWS IoT MQTT Client
|
|
for Websocket SigV4 connection to AWS IoT. Should be called before connect. This is a public
|
|
facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myShadowClient.clearLastWill(obtainedAccessKeyID, obtainedSecretAccessKey, obtainedSessionToken)
|
|
myJobsClient.clearLastWill(obtainedAccessKeyID, obtainedSecretAccessKey, obtainedSessionToken)
|
|
|
|
.. note::
|
|
|
|
Hard-coding credentials into custom script is NOT recommended. Please use AWS Cognito identity service
|
|
or other credential provider.
|
|
|
|
**Parameters**
|
|
|
|
*AWSAccessKeyID* - AWS Access Key Id from user-specific IAM credentials.
|
|
|
|
*AWSSecretAccessKey* - AWS Secret Access Key from user-specific IAM credentials.
|
|
|
|
*AWSSessionToken* - AWS Session Token for temporary authentication from STS.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
# AWSIoTMQTTClient.configureIAMCredentials
|
|
self._AWSIoTMQTTClient.configureIAMCredentials(AWSAccessKeyID, AWSSecretAccessKey, AWSSTSToken)
|
|
|
|
def configureCredentials(self, CAFilePath, KeyPath="", CertificatePath=""): # Should be good for MutualAuth and Websocket
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the rootCA, private key and certificate files. Should be called before connect. This is a public
|
|
facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myShadowClient.clearLastWill("PATH/TO/ROOT_CA", "PATH/TO/PRIVATE_KEY", "PATH/TO/CERTIFICATE")
|
|
myJobsClient.clearLastWill("PATH/TO/ROOT_CA", "PATH/TO/PRIVATE_KEY", "PATH/TO/CERTIFICATE")
|
|
|
|
**Parameters**
|
|
|
|
*CAFilePath* - Path to read the root CA file. Required for all connection types.
|
|
|
|
*KeyPath* - Path to read the private key. Required for X.509 certificate based connection.
|
|
|
|
*CertificatePath* - Path to read the certificate. Required for X.509 certificate based connection.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
# AWSIoTMQTTClient.configureCredentials
|
|
self._AWSIoTMQTTClient.configureCredentials(CAFilePath, KeyPath, CertificatePath)
|
|
|
|
def configureAutoReconnectBackoffTime(self, baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the auto-reconnect backoff timing. Should be called before connect. This is a public
|
|
facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure the auto-reconnect backoff to start with 1 second and use 128 seconds as a maximum back off time.
|
|
# Connection over 20 seconds is considered stable and will reset the back off time back to its base.
|
|
myShadowClient.clearLastWill(1, 128, 20)
|
|
myJobsClient.clearLastWill(1, 128, 20)
|
|
|
|
**Parameters**
|
|
|
|
*baseReconnectQuietTimeSecond* - The initial back off time to start with, in seconds.
|
|
Should be less than the stableConnectionTime.
|
|
|
|
*maxReconnectQuietTimeSecond* - The maximum back off time, in seconds.
|
|
|
|
*stableConnectionTimeSecond* - The number of seconds for a connection to last to be considered as stable.
|
|
Back off time will be reset to base once the connection is stable.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
# AWSIoTMQTTClient.configureBackoffTime
|
|
self._AWSIoTMQTTClient.configureAutoReconnectBackoffTime(baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond)
|
|
|
|
def configureConnectDisconnectTimeout(self, timeoutSecond):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the time in seconds to wait for a CONNACK or a disconnect to complete.
|
|
Should be called before connect. This is a public facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure connect/disconnect timeout to be 10 seconds
|
|
myShadowClient.configureConnectDisconnectTimeout(10)
|
|
myJobsClient.configureConnectDisconnectTimeout(10)
|
|
|
|
**Parameters**
|
|
|
|
*timeoutSecond* - Time in seconds to wait for a CONNACK or a disconnect to complete.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
# AWSIoTMQTTClient.configureConnectDisconnectTimeout
|
|
self._AWSIoTMQTTClient.configureConnectDisconnectTimeout(timeoutSecond)
|
|
|
|
def configureMQTTOperationTimeout(self, timeoutSecond):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the timeout in seconds for MQTT QoS 1 publish, subscribe and unsubscribe.
|
|
Should be called before connect. This is a public facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure MQTT operation timeout to be 5 seconds
|
|
myShadowClient.configureMQTTOperationTimeout(5)
|
|
myJobsClient.configureMQTTOperationTimeout(5)
|
|
|
|
**Parameters**
|
|
|
|
*timeoutSecond* - Time in seconds to wait for a PUBACK/SUBACK/UNSUBACK.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
# AWSIoTMQTTClient.configureMQTTOperationTimeout
|
|
self._AWSIoTMQTTClient.configureMQTTOperationTimeout(timeoutSecond)
|
|
|
|
def configureUsernamePassword(self, username, password=None):
|
|
"""
|
|
**Description**
|
|
|
|
Used to configure the username and password used in CONNECT packet. This is a public facing API
|
|
inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure user name and password
|
|
myShadowClient.configureUsernamePassword("myUsername", "myPassword")
|
|
myJobsClient.configureUsernamePassword("myUsername", "myPassword")
|
|
|
|
**Parameters**
|
|
|
|
*username* - Username used in the username field of CONNECT packet.
|
|
|
|
*password* - Password used in the password field of CONNECT packet.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._AWSIoTMQTTClient.configureUsernamePassword(username, password)
|
|
|
|
def configureSocketFactory(self, socket_factory):
|
|
"""
|
|
**Description**
|
|
|
|
Configure a socket factory to custom configure a different socket type for
|
|
mqtt connection. Creating a custom socket allows for configuration of a proxy
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Configure socket factory
|
|
custom_args = {"arg1": "val1", "arg2": "val2"}
|
|
socket_factory = lambda: custom.create_connection((host, port), **custom_args)
|
|
myAWSIoTMQTTClient.configureSocketFactory(socket_factory)
|
|
|
|
**Parameters**
|
|
|
|
*socket_factory* - Anonymous function which creates a custom socket to spec.
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._AWSIoTMQTTClient.configureSocketFactory(socket_factory)
|
|
|
|
def enableMetricsCollection(self):
|
|
"""
|
|
**Description**
|
|
|
|
Used to enable SDK metrics collection. Username field in CONNECT packet will be used to append the SDK name
|
|
and SDK version in use and communicate to AWS IoT cloud. This metrics collection is enabled by default.
|
|
This is a public facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myShadowClient.enableMetricsCollection()
|
|
myJobsClient.enableMetricsCollection()
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._AWSIoTMQTTClient.enableMetricsCollection()
|
|
|
|
def disableMetricsCollection(self):
|
|
"""
|
|
**Description**
|
|
|
|
Used to disable SDK metrics collection. This is a public facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myShadowClient.disableMetricsCollection()
|
|
myJobsClient.disableMetricsCollection()
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
self._AWSIoTMQTTClient.disableMetricsCollection()
|
|
|
|
# Start the MQTT connection
|
|
def connect(self, keepAliveIntervalSecond=600):
|
|
"""
|
|
**Description**
|
|
|
|
Connect to AWS IoT, with user-specific keepalive interval configuration. This is a public facing API inherited
|
|
by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Connect to AWS IoT with default keepalive set to 600 seconds
|
|
myShadowClient.connect()
|
|
myJobsClient.connect()
|
|
# Connect to AWS IoT with keepalive interval set to 1200 seconds
|
|
myShadowClient.connect(1200)
|
|
myJobsClient.connect(1200)
|
|
|
|
**Parameters**
|
|
|
|
*keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request.
|
|
Default set to 30 seconds.
|
|
|
|
**Returns**
|
|
|
|
True if the connect attempt succeeded. False if failed.
|
|
|
|
"""
|
|
self._load_callbacks()
|
|
return self._AWSIoTMQTTClient.connect(keepAliveIntervalSecond)
|
|
|
|
def _load_callbacks(self):
|
|
self._AWSIoTMQTTClient.onOnline = self.onOnline
|
|
self._AWSIoTMQTTClient.onOffline = self.onOffline
|
|
|
|
# End the MQTT connection
|
|
def disconnect(self):
|
|
"""
|
|
**Description**
|
|
|
|
Disconnect from AWS IoT. This is a public facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
myShadowClient.disconnect()
|
|
myJobsClient.disconnect()
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
True if the disconnect attempt succeeded. False if failed.
|
|
|
|
"""
|
|
return self._AWSIoTMQTTClient.disconnect()
|
|
|
|
# MQTT connection management API
|
|
def getMQTTConnection(self):
|
|
"""
|
|
**Description**
|
|
|
|
Retrieve the AWS IoT MQTT Client used underneath, making it possible to perform
|
|
plain MQTT operations along with specialized operations using the same single connection.
|
|
This is a public facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Retrieve the AWS IoT MQTT Client used in the AWS IoT MQTT Delegating Client
|
|
thisAWSIoTMQTTClient = myShadowClient.getMQTTConnection()
|
|
thisAWSIoTMQTTClient = myJobsClient.getMQTTConnection()
|
|
# Perform plain MQTT operations using the same connection
|
|
thisAWSIoTMQTTClient.publish("Topic", "Payload", 1)
|
|
...
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient object
|
|
|
|
"""
|
|
# Return the internal AWSIoTMQTTClient instance
|
|
return self._AWSIoTMQTTClient
|
|
|
|
def onOnline(self):
|
|
"""
|
|
**Description**
|
|
|
|
Callback that gets called when the client is online. The callback registration should happen before calling
|
|
connect. This is a public facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Register an onOnline callback
|
|
myShadowClient.onOnline = myOnOnlineCallback
|
|
myJobsClient.onOnline = myOnOnlineCallback
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
pass
|
|
|
|
def onOffline(self):
|
|
"""
|
|
**Description**
|
|
|
|
Callback that gets called when the client is offline. The callback registration should happen before calling
|
|
connect. This is a public facing API inherited by application level public clients.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Register an onOffline callback
|
|
myShadowClient.onOffline = myOnOfflineCallback
|
|
myJobsClient.onOffline = myOnOfflineCallback
|
|
|
|
**Parameters**
|
|
|
|
None
|
|
|
|
**Returns**
|
|
|
|
None
|
|
|
|
"""
|
|
pass
|
|
|
|
|
|
class AWSIoTMQTTShadowClient(_AWSIoTMQTTDelegatingClient):
|
|
|
|
def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True, awsIoTMQTTClient=None):
|
|
"""
|
|
|
|
The client class that manages device shadow and accesses its functionality in AWS IoT over MQTT v3.1/3.1.1.
|
|
|
|
It delegates to the AWS IoT MQTT Client and exposes devive shadow related operations.
|
|
It shares the same connection types, synchronous MQTT operations and partial on-top features
|
|
with the AWS IoT MQTT Client:
|
|
|
|
- Auto reconnect/resubscribe
|
|
|
|
Same as AWS IoT MQTT Client.
|
|
|
|
- Progressive reconnect backoff
|
|
|
|
Same as AWS IoT MQTT Client.
|
|
|
|
- Offline publish requests queueing with draining
|
|
|
|
Disabled by default. Queueing is not allowed for time-sensitive shadow requests/messages.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT
|
|
|
|
# Create an AWS IoT MQTT Shadow Client using TLSv1.2 Mutual Authentication
|
|
myAWSIoTMQTTShadowClient = AWSIoTPyMQTT.AWSIoTMQTTShadowClient("testIoTPySDK")
|
|
# Create an AWS IoT MQTT Shadow Client using Websocket SigV4
|
|
myAWSIoTMQTTShadowClient = AWSIoTPyMQTT.AWSIoTMQTTShadowClient("testIoTPySDK", useWebsocket=True)
|
|
|
|
**Parameters**
|
|
|
|
*clientID* - String that denotes the client identifier used to connect to AWS IoT.
|
|
If empty string were provided, client id for this connection will be randomly generated
|
|
n server side.
|
|
|
|
*protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1`
|
|
|
|
*useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not.
|
|
|
|
**Returns**
|
|
|
|
AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTShadowClient object
|
|
|
|
"""
|
|
super(AWSIoTMQTTShadowClient, self).__init__(clientID, protocolType, useWebsocket, cleanSession, awsIoTMQTTClient)
|
|
#leave passed in clients alone
|
|
if awsIoTMQTTClient is None:
|
|
# Configure it to disable offline Publish Queueing
|
|
self._AWSIoTMQTTClient.configureOfflinePublishQueueing(0) # Disable queueing, no queueing for time-sensitive shadow messages
|
|
self._AWSIoTMQTTClient.configureDrainingFrequency(10)
|
|
# Now retrieve the configured mqttCore and init a shadowManager instance
|
|
self._shadowManager = shadowManager.shadowManager(self._AWSIoTMQTTClient._mqtt_core)
|
|
|
|
# Shadow management API
|
|
def createShadowHandlerWithName(self, shadowName, isPersistentSubscribe):
|
|
"""
|
|
**Description**
|
|
|
|
Create a device shadow handler using the specified shadow name and isPersistentSubscribe.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
# Create a device shadow handler for shadow named "Bot1", using persistent subscription
|
|
Bot1Shadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("Bot1", True)
|
|
# Create a device shadow handler for shadow named "Bot2", using non-persistent subscription
|
|
Bot2Shadow = myAWSIoTMQTTShadowClient.createShadowHandlerWithName("Bot2", False)
|
|
|
|
**Parameters**
|
|
|
|
*shadowName* - Name of the device shadow.
|
|
|
|
*isPersistentSubscribe* - Whether to unsubscribe from shadow response (accepted/rejected) topics
|
|
when there is a response. Will subscribe at the first time the shadow request is made and will
|
|
not unsubscribe if isPersistentSubscribe is set.
|
|
|
|
**Returns**
|
|
|
|
AWSIoTPythonSDK.core.shadow.deviceShadow.deviceShadow object, which exposes the device shadow interface.
|
|
|
|
"""
|
|
# Create and return a deviceShadow instance
|
|
return deviceShadow.deviceShadow(shadowName, isPersistentSubscribe, self._shadowManager)
|
|
# Shadow APIs are accessible in deviceShadow instance":
|
|
###
|
|
# deviceShadow.shadowGet
|
|
# deviceShadow.shadowUpdate
|
|
# deviceShadow.shadowDelete
|
|
# deviceShadow.shadowRegisterDelta
|
|
# deviceShadow.shadowUnregisterDelta
|
|
|
|
class AWSIoTMQTTThingJobsClient(_AWSIoTMQTTDelegatingClient):
|
|
|
|
def __init__(self, clientID, thingName, QoS=0, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True, awsIoTMQTTClient=None):
|
|
"""
|
|
|
|
The client class that specializes in handling jobs messages and accesses its functionality in AWS IoT over MQTT v3.1/3.1.1.
|
|
|
|
It delegates to the AWS IoT MQTT Client and exposes jobs related operations.
|
|
It shares the same connection types, synchronous MQTT operations and partial on-top features
|
|
with the AWS IoT MQTT Client:
|
|
|
|
- Auto reconnect/resubscribe
|
|
|
|
Same as AWS IoT MQTT Client.
|
|
|
|
- Progressive reconnect backoff
|
|
|
|
Same as AWS IoT MQTT Client.
|
|
|
|
- Offline publish requests queueing with draining
|
|
|
|
Same as AWS IoT MQTT Client
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT
|
|
|
|
# Create an AWS IoT MQTT Jobs Client using TLSv1.2 Mutual Authentication
|
|
myAWSIoTMQTTJobsClient = AWSIoTPyMQTT.AWSIoTMQTTThingJobsClient("testIoTPySDK")
|
|
# Create an AWS IoT MQTT Jobs Client using Websocket SigV4
|
|
myAWSIoTMQTTJobsClient = AWSIoTPyMQTT.AWSIoTMQTTThingJobsClient("testIoTPySDK", useWebsocket=True)
|
|
|
|
**Parameters**
|
|
|
|
*clientID* - String that denotes the client identifier and client token for jobs requests
|
|
If empty string is provided, client id for this connection will be randomly generated
|
|
on server side. If an awsIotMQTTClient is specified, this will not override the client ID
|
|
for the existing MQTT connection and only impact the client token for jobs request payloads
|
|
|
|
*thingName* - String that represents the thingName used to send requests to proper topics and subscribe
|
|
to proper topics.
|
|
|
|
*QoS* - QoS used for all requests sent through this client
|
|
|
|
*awsIoTMQTTClient* - An instance of AWSIoTMQTTClient to use if not None. If not None, clientID, protocolType, useWebSocket,
|
|
and cleanSession parameters are not used. Caller is expected to invoke connect() prior to calling the pub/sub methods on this client.
|
|
|
|
*protocolType* - MQTT version in use for this connection. Could be :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1` or :code:`AWSIoTPythonSDK.MQTTLib.MQTTv3_1_1`
|
|
|
|
*useWebsocket* - Boolean that denotes enabling MQTT over Websocket SigV4 or not.
|
|
|
|
**Returns**
|
|
|
|
AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTJobsClient object
|
|
|
|
"""
|
|
# AWSIOTMQTTClient instance
|
|
super(AWSIoTMQTTThingJobsClient, self).__init__(clientID, protocolType, useWebsocket, cleanSession, awsIoTMQTTClient)
|
|
self._thingJobManager = thingJobManager.thingJobManager(thingName, clientID)
|
|
self._QoS = QoS
|
|
|
|
def createJobSubscription(self, callback, jobExecutionType=jobExecutionTopicType.JOB_WILDCARD_TOPIC, jobReplyType=jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId=None):
|
|
"""
|
|
**Description**
|
|
|
|
Synchronously creates an MQTT subscription to a jobs related topic based on the provided arguments
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
#Subscribe to notify-next topic to monitor change in job referred to by $next
|
|
myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC)
|
|
#Subscribe to notify topic to monitor changes to jobs in pending list
|
|
myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_NOTIFY_TOPIC)
|
|
#Subscribe to receive messages for job execution updates
|
|
myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_UPDATE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE)
|
|
#Subscribe to receive messages for describing a job execution
|
|
myAWSIoTMQTTJobsClient.createJobSubscription(callback, jobExecutionTopicType.JOB_DESCRIBE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE, jobId)
|
|
|
|
**Parameters**
|
|
|
|
*callback* - Function to be called when a new message for the subscribed job topic
|
|
comes in. Should be in form :code:`customCallback(client, userdata, message)`, where
|
|
:code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are
|
|
here just to be aligned with the underneath Paho callback function signature. These fields are pending to be
|
|
deprecated and should not be depended on.
|
|
|
|
*jobExecutionType* - Member of the jobExecutionTopicType class specifying the jobs topic to subscribe to
|
|
Defaults to jobExecutionTopicType.JOB_WILDCARD_TOPIC
|
|
|
|
*jobReplyType* - Member of the jobExecutionTopicReplyType class specifying the (optional) reply sub-topic to subscribe to
|
|
Defaults to jobExecutionTopicReplyType.JOB_REQUEST_TYPE which indicates the subscription isn't intended for a jobs reply topic
|
|
|
|
*jobId* - JobId string if the topic type requires one.
|
|
Defaults to None
|
|
|
|
**Returns**
|
|
|
|
True if the subscribe attempt succeeded. False if failed.
|
|
|
|
"""
|
|
topic = self._thingJobManager.getJobTopic(jobExecutionType, jobReplyType, jobId)
|
|
return self._AWSIoTMQTTClient.subscribe(topic, self._QoS, callback)
|
|
|
|
def createJobSubscriptionAsync(self, ackCallback, callback, jobExecutionType=jobExecutionTopicType.JOB_WILDCARD_TOPIC, jobReplyType=jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId=None):
|
|
"""
|
|
**Description**
|
|
|
|
Asynchronously creates an MQTT subscription to a jobs related topic based on the provided arguments
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
#Subscribe to notify-next topic to monitor change in job referred to by $next
|
|
myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC)
|
|
#Subscribe to notify topic to monitor changes to jobs in pending list
|
|
myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_NOTIFY_TOPIC)
|
|
#Subscribe to receive messages for job execution updates
|
|
myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_UPDATE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE)
|
|
#Subscribe to receive messages for describing a job execution
|
|
myAWSIoTMQTTJobsClient.createJobSubscriptionAsync(callback, jobExecutionTopicType.JOB_DESCRIBE_TOPIC, jobExecutionTopicReplyType.JOB_ACCEPTED_REPLY_TYPE, jobId)
|
|
|
|
**Parameters**
|
|
|
|
*ackCallback* - Callback to be invoked when the client receives a SUBACK. Should be in form
|
|
:code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the disconnect request and
|
|
:code:`data` is the granted QoS for this subscription.
|
|
|
|
*callback* - Function to be called when a new message for the subscribed job topic
|
|
comes in. Should be in form :code:`customCallback(client, userdata, message)`, where
|
|
:code:`message` contains :code:`topic` and :code:`payload`. Note that :code:`client` and :code:`userdata` are
|
|
here just to be aligned with the underneath Paho callback function signature. These fields are pending to be
|
|
deprecated and should not be depended on.
|
|
|
|
*jobExecutionType* - Member of the jobExecutionTopicType class specifying the jobs topic to subscribe to
|
|
Defaults to jobExecutionTopicType.JOB_WILDCARD_TOPIC
|
|
|
|
*jobReplyType* - Member of the jobExecutionTopicReplyType class specifying the (optional) reply sub-topic to subscribe to
|
|
Defaults to jobExecutionTopicReplyType.JOB_REQUEST_TYPE which indicates the subscription isn't intended for a jobs reply topic
|
|
|
|
*jobId* - JobId of the topic if the topic type requires one.
|
|
Defaults to None
|
|
|
|
**Returns**
|
|
|
|
Subscribe request packet id, for tracking purpose in the corresponding callback.
|
|
|
|
"""
|
|
topic = self._thingJobManager.getJobTopic(jobExecutionType, jobReplyType, jobId)
|
|
return self._AWSIoTMQTTClient.subscribeAsync(topic, self._QoS, ackCallback, callback)
|
|
|
|
def sendJobsQuery(self, jobExecTopicType, jobId=None):
|
|
"""
|
|
**Description**
|
|
|
|
Publishes an MQTT jobs related request for a potentially specific jobId (or wildcard)
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
#send a request to describe the next job
|
|
myAWSIoTMQTTJobsClient.sendJobsQuery(jobExecutionTopicType.JOB_DESCRIBE_TOPIC, '$next')
|
|
#send a request to get list of pending jobs
|
|
myAWSIoTMQTTJobsClient.sendJobsQuery(jobExecutionTopicType.JOB_GET_PENDING_TOPIC)
|
|
|
|
**Parameters**
|
|
|
|
*jobExecutionType* - Member of the jobExecutionTopicType class that correlates the jobs topic to publish to
|
|
|
|
*jobId* - JobId string if the topic type requires one.
|
|
Defaults to None
|
|
|
|
**Returns**
|
|
|
|
True if the publish request has been sent to paho. False if the request did not reach paho.
|
|
|
|
"""
|
|
topic = self._thingJobManager.getJobTopic(jobExecTopicType, jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId)
|
|
payload = self._thingJobManager.serializeClientTokenPayload()
|
|
return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS)
|
|
|
|
def sendJobsStartNext(self, statusDetails=None, stepTimeoutInMinutes=None):
|
|
"""
|
|
**Description**
|
|
|
|
Publishes an MQTT message to the StartNextJobExecution topic. This will attempt to get the next pending
|
|
job execution and change its status to IN_PROGRESS.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
#Start next job (set status to IN_PROGRESS) and update with optional statusDetails
|
|
myAWSIoTMQTTJobsClient.sendJobsStartNext({'StartedBy': 'myClientId'})
|
|
|
|
**Parameters**
|
|
|
|
*statusDetails* - Dictionary containing the key value pairs to use for the status details of the job execution
|
|
|
|
*stepTimeoutInMinutes - Specifies the amount of time this device has to finish execution of this job.
|
|
|
|
**Returns**
|
|
|
|
True if the publish request has been sent to paho. False if the request did not reach paho.
|
|
|
|
"""
|
|
topic = self._thingJobManager.getJobTopic(jobExecutionTopicType.JOB_START_NEXT_TOPIC, jobExecutionTopicReplyType.JOB_REQUEST_TYPE)
|
|
payload = self._thingJobManager.serializeStartNextPendingJobExecutionPayload(statusDetails, stepTimeoutInMinutes)
|
|
return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS)
|
|
|
|
def sendJobsUpdate(self, jobId, status, statusDetails=None, expectedVersion=0, executionNumber=0, includeJobExecutionState=False, includeJobDocument=False, stepTimeoutInMinutes=None):
|
|
"""
|
|
**Description**
|
|
|
|
Publishes an MQTT message to a corresponding job execution specific topic to update its status according to the parameters.
|
|
Can be used to change a job from QUEUED to IN_PROGRESS to SUCEEDED or FAILED.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
#Update job with id 'jobId123' to succeeded state, specifying new status details, with expectedVersion=1, executionNumber=2.
|
|
#For the response, include job execution state and not the job document
|
|
myAWSIoTMQTTJobsClient.sendJobsUpdate('jobId123', jobExecutionStatus.JOB_EXECUTION_SUCCEEDED, statusDetailsMap, 1, 2, True, False)
|
|
|
|
|
|
#Update job with id 'jobId456' to failed state
|
|
myAWSIoTMQTTJobsClient.sendJobsUpdate('jobId456', jobExecutionStatus.JOB_EXECUTION_FAILED)
|
|
|
|
**Parameters**
|
|
|
|
*jobId* - JobID String of the execution to update the status of
|
|
|
|
*status* - job execution status to change the job execution to. Member of jobExecutionStatus
|
|
|
|
*statusDetails* - new status details to set on the job execution
|
|
|
|
*expectedVersion* - The expected current version of the job execution. IoT jobs increments expectedVersion each time you update the job execution.
|
|
If the version of the job execution stored in Jobs does not match, the update is rejected with a VersionMismatch error, and an ErrorResponse
|
|
that contains the current job execution status data is returned. (This makes it unnecessary to perform a separate DescribeJobExecution request
|
|
n order to obtain the job execution status data.)
|
|
|
|
*executionNumber* - A number that identifies a particular job execution on a particular device. If not specified, the latest job execution is used.
|
|
|
|
*includeJobExecutionState* - When included and set to True, the response contains the JobExecutionState field. The default is False.
|
|
|
|
*includeJobDocument* - When included and set to True, the response contains the JobDocument. The default is False.
|
|
|
|
*stepTimeoutInMinutes - Specifies the amount of time this device has to finish execution of this job.
|
|
|
|
**Returns**
|
|
|
|
True if the publish request has been sent to paho. False if the request did not reach paho.
|
|
|
|
"""
|
|
topic = self._thingJobManager.getJobTopic(jobExecutionTopicType.JOB_UPDATE_TOPIC, jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId)
|
|
payload = self._thingJobManager.serializeJobExecutionUpdatePayload(status, statusDetails, expectedVersion, executionNumber, includeJobExecutionState, includeJobDocument, stepTimeoutInMinutes)
|
|
return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS)
|
|
|
|
def sendJobsDescribe(self, jobId, executionNumber=0, includeJobDocument=True):
|
|
"""
|
|
**Description**
|
|
|
|
Publishes a method to the describe topic for a particular job.
|
|
|
|
**Syntax**
|
|
|
|
.. code:: python
|
|
|
|
#Describe job with id 'jobId1' of any executionNumber, job document will be included in response
|
|
myAWSIoTMQTTJobsClient.sendJobsDescribe('jobId1')
|
|
|
|
#Describe job with id 'jobId2', with execution number of 2, and includeJobDocument in the response
|
|
myAWSIoTMQTTJobsClient.sendJobsDescribe('jobId2', 2, True)
|
|
|
|
**Parameters**
|
|
|
|
*jobId* - jobID to describe. This is allowed to be a wildcard such as '$next'
|
|
|
|
*executionNumber* - A number that identifies a particular job execution on a particular device. If not specified, the latest job execution is used.
|
|
|
|
*includeJobDocument* - When included and set to True, the response contains the JobDocument.
|
|
|
|
**Returns**
|
|
|
|
True if the publish request has been sent to paho. False if the request did not reach paho.
|
|
|
|
"""
|
|
topic = self._thingJobManager.getJobTopic(jobExecutionTopicType.JOB_DESCRIBE_TOPIC, jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId)
|
|
payload = self._thingJobManager.serializeDescribeJobExecutionPayload(executionNumber, includeJobDocument)
|
|
return self._AWSIoTMQTTClient.publish(topic, payload, self._QoS)
|