From 41ead949149c6190101caf6033677bec9cb27df4 Mon Sep 17 00:00:00 2001 From: liuszeng Date: Wed, 12 Oct 2016 22:12:02 +0000 Subject: [PATCH] Release of version 1.1.0 --- AWSIoTPythonSDK/MQTTLib.py | 104 +++++++++++++++++- AWSIoTPythonSDK/__init__.py | 5 +- AWSIoTPythonSDK/core/protocol/mqttCore.py | 39 ++++--- AWSIoTPythonSDK/core/protocol/paho/client.py | 8 +- .../securedWebsocket/securedWebsocketCore.py | 6 +- AWSIoTPythonSDK/core/shadow/deviceShadow.py | 2 +- .../core/util/progressiveBackoffCore.py | 5 + .../{core => }/exception/AWSIoTExceptions.py | 4 +- .../{core => }/exception/__init__.py | 0 .../{core => }/exception/operationError.py | 0 .../exception/operationTimeoutException.py | 0 CHANGELOG.rst | 7 ++ README.rst | 2 +- setup.py | 2 +- 14 files changed, 153 insertions(+), 31 deletions(-) rename AWSIoTPythonSDK/{core => }/exception/AWSIoTExceptions.py (95%) rename AWSIoTPythonSDK/{core => }/exception/__init__.py (100%) rename AWSIoTPythonSDK/{core => }/exception/operationError.py (100%) rename AWSIoTPythonSDK/{core => }/exception/operationTimeoutException.py (100%) diff --git a/AWSIoTPythonSDK/MQTTLib.py b/AWSIoTPythonSDK/MQTTLib.py index 1942b2f..1c11e5a 100755 --- a/AWSIoTPythonSDK/MQTTLib.py +++ b/AWSIoTPythonSDK/MQTTLib.py @@ -20,7 +20,6 @@ import core.shadow.shadowManager as shadowManager # import deviceShadow import core.shadow.deviceShadow as deviceShadow - # Constants # - Protocol types: MQTTv3_1 = 3 @@ -30,7 +29,6 @@ DROP_NEWEST = 1 # - class AWSIoTMQTTClient: def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanSession=True): @@ -87,6 +85,56 @@ def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanS self._mqttCore = mqttCore.mqttCore(clientID, cleanSession, protocolType, useWebsocket) # 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. + + **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 + + """ + # mqttCore.setLastWill(srcTopic, srcPayload, srcQos) + self._mqttCore.setLastWill(topic, payload, QoS) + + 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 + + """ + #mqttCore.clearLastWill() + self._mqttCore.clearLastWill() + def configureEndpoint(self, hostName, portNumber): """ **Description** @@ -399,7 +447,7 @@ def publish(self, topic, payload, QoS): *payload* - Payload to publish. - *QoS* - Quality of Service. Could be 0 ot 1. + *QoS* - Quality of Service. Could be 0 or 1. **Returns** @@ -525,6 +573,56 @@ def __init__(self, clientID, protocolType=MQTTv3_1_1, useWebsocket=False, cleanS self._shadowManager = shadowManager.shadowManager(self._AWSIoTMQTTClient._mqttCore) # 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. + + **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 + + """ + # 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. + + **Syntax** + + ..code:: python + myAWSIoTShadowMQTTClient.clearLastWill() + + **Parameter** + + None + + **Returns** + + None + + """ + # AWSIoTMQTTClient.clearLastWill() + self._AWSIoTMQTTClient.clearLastWill() + def configureEndpoint(self, hostName, portNumber): """ **Description** diff --git a/AWSIoTPythonSDK/__init__.py b/AWSIoTPythonSDK/__init__.py index 13e3d46..d8176fb 100755 --- a/AWSIoTPythonSDK/__init__.py +++ b/AWSIoTPythonSDK/__init__.py @@ -1,5 +1,6 @@ import os import sys -sys.path.insert(0, os.path.dirname(__file__)) -__version__ = "1.0.1" +__version__ = "1.1.0" + + diff --git a/AWSIoTPythonSDK/core/protocol/mqttCore.py b/AWSIoTPythonSDK/core/protocol/mqttCore.py index e71a2f7..1c5a465 100755 --- a/AWSIoTPythonSDK/core/protocol/mqttCore.py +++ b/AWSIoTPythonSDK/core/protocol/mqttCore.py @@ -18,20 +18,20 @@ import time import logging import threading -import core.protocol.paho.client as mqtt -import core.util.offlinePublishQueue as offlinePublishQueue +import AWSIoTPythonSDK.core.protocol.paho.client as mqtt +import AWSIoTPythonSDK.core.util.offlinePublishQueue as offlinePublishQueue from threading import Lock -from core.exception.AWSIoTExceptions import connectError -from core.exception.AWSIoTExceptions import connectTimeoutException -from core.exception.AWSIoTExceptions import disconnectError -from core.exception.AWSIoTExceptions import disconnectTimeoutException -from core.exception.AWSIoTExceptions import publishError -from core.exception.AWSIoTExceptions import publishQueueFullException -from core.exception.AWSIoTExceptions import publishQueueDisabledException -from core.exception.AWSIoTExceptions import subscribeError -from core.exception.AWSIoTExceptions import subscribeTimeoutException -from core.exception.AWSIoTExceptions import unsubscribeError -from core.exception.AWSIoTExceptions import unsubscribeTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import connectError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import connectTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import disconnectError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import disconnectTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishQueueFullException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import publishQueueDisabledException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import subscribeError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import subscribeTimeoutException +from AWSIoTPythonSDK.exception.AWSIoTExceptions import unsubscribeError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import unsubscribeTimeoutException # Class that holds queued publish request details class _publishRequest: @@ -221,6 +221,15 @@ def configIAMCredentials(self, srcAWSAccessKeyID, srcAWSSecretAccessKey, srcAWSS raise TypeError("None type inputs detected.") self._pahoClient.configIAMCredentials(srcAWSAccessKeyID, srcAWSSecretAccessKey, srcAWSSessionToken) + def setLastWill(self, srcTopic, srcPayload, srcQos): + if srcTopic is None or srcPayload is None or srcQos is None: + self._log.error("setLastWill: None type inputs detected.") + raise TypeError("None type inputs detected.") + self._pahoClient.will_set(srcTopic, srcPayload, srcQos, False) + + def clearLastWill(self): + self._pahoClient.will_clear() + def setBackoffTime(self, srcBaseReconnectTimeSecond, srcMaximumReconnectTimeSecond, srcMinimumConnectTimeSecond): if srcBaseReconnectTimeSecond is None or srcMaximumReconnectTimeSecond is None or srcMinimumConnectTimeSecond is None: self._log.error("setBackoffTime: None type inputs detected.") @@ -231,7 +240,6 @@ def setBackoffTime(self, srcBaseReconnectTimeSecond, srcMaximumReconnectTimeSeco self._log.debug("Custom setting for backoff timing: maximumReconnectTime = " + str(srcMaximumReconnectTimeSecond) + " sec") self._log.debug("Custom setting for backoff timing: minimumConnectTime = " + str(srcMinimumConnectTimeSecond) + " sec") - def setOfflinePublishQueueing(self, srcQueueSize, srcDropBehavior=mqtt.MSG_QUEUEING_DROP_NEWEST): if srcQueueSize is None or srcDropBehavior is None: self._log.error("setOfflinePublishQueueing: None type inputs detected.") @@ -333,7 +341,8 @@ def publish(self, topic, payload, qos, retain): if queuedPublishCondition: if self._connectResultCode == sys.maxsize: self._log.info("Offline publish request detected.") - if not self._drainingComplete: + # If the client is connected but draining is not completed... + elif not self._drainingComplete: self._log.info("Drainging is still on-going.") self._log.info("Try queueing up this request...") # Publish to the queue and report error (raise Exception) diff --git a/AWSIoTPythonSDK/core/protocol/paho/client.py b/AWSIoTPythonSDK/core/protocol/paho/client.py index 7163dd6..53852db 100755 --- a/AWSIoTPythonSDK/core/protocol/paho/client.py +++ b/AWSIoTPythonSDK/core/protocol/paho/client.py @@ -45,9 +45,9 @@ else: EAGAIN = errno.EAGAIN # AWS WSS implementation -import core.protocol.paho.securedWebsocket.securedWebsocketCore as wssCore -import core.util.progressiveBackoffCore as backoffCore -import core.util.offlinePublishQueue as offlinePublishQueue +import AWSIoTPythonSDK.core.protocol.paho.securedWebsocket.securedWebsocketCore as wssCore +import AWSIoTPythonSDK.core.util.progressiveBackoffCore as backoffCore +import AWSIoTPythonSDK.core.util.offlinePublishQueue as offlinePublishQueue VERSION_MAJOR=1 VERSION_MINOR=0 @@ -989,6 +989,8 @@ def disconnect(self): self._state = mqtt_cs_disconnecting self._state_mutex.release() + self._backoffCore.stopStableConnectionTimer() + if self._sock is None and self._ssl is None: return MQTT_ERR_NO_CONN diff --git a/AWSIoTPythonSDK/core/protocol/paho/securedWebsocket/securedWebsocketCore.py b/AWSIoTPythonSDK/core/protocol/paho/securedWebsocket/securedWebsocketCore.py index 7c4946b..8699f97 100755 --- a/AWSIoTPythonSDK/core/protocol/paho/securedWebsocket/securedWebsocketCore.py +++ b/AWSIoTPythonSDK/core/protocol/paho/securedWebsocket/securedWebsocketCore.py @@ -29,9 +29,9 @@ import socket import base64 import hashlib -from core.util.sigV4Core import sigV4Core -from core.exception.AWSIoTExceptions import wssNoKeyInEnvironmentError -from core.exception.AWSIoTExceptions import wssHandShakeError +from AWSIoTPythonSDK.core.util.sigV4Core import sigV4Core +from AWSIoTPythonSDK.exception.AWSIoTExceptions import wssNoKeyInEnvironmentError +from AWSIoTPythonSDK.exception.AWSIoTExceptions import wssHandShakeError # This is an internal class that buffers the incoming bytes into an # internal buffer until it gets the full desired length of bytes. diff --git a/AWSIoTPythonSDK/core/shadow/deviceShadow.py b/AWSIoTPythonSDK/core/shadow/deviceShadow.py index 1390d0f..e7997f6 100755 --- a/AWSIoTPythonSDK/core/shadow/deviceShadow.py +++ b/AWSIoTPythonSDK/core/shadow/deviceShadow.py @@ -329,7 +329,7 @@ def shadowUpdate(self, srcJSONPayload, srcCallback, srcTimeout): .. code:: python - # Retrieve the shadow JSON document from AWS IoT, with a timeout set to 5 seconds + # Update the shadow JSON document from AWS IoT, with a timeout set to 5 seconds BotShadow.shadowUpdate(newShadowJSONDocumentString, customCallback, 5) **Parameters** diff --git a/AWSIoTPythonSDK/core/util/progressiveBackoffCore.py b/AWSIoTPythonSDK/core/util/progressiveBackoffCore.py index 096b572..cc56533 100755 --- a/AWSIoTPythonSDK/core/util/progressiveBackoffCore.py +++ b/AWSIoTPythonSDK/core/util/progressiveBackoffCore.py @@ -78,6 +78,11 @@ def startStableConnectionTimer(self): self._resetBackoffTimer = threading.Timer(self._minimumConnectTimeSecond, self._connectionStableThenResetBackoffTime) self._resetBackoffTimer.start() + def stopStableConnectionTimer(self): + if self._resetBackoffTimer is not None: + # Cancel the timer + self._resetBackoffTimer.cancel() + # Timer callback to reset _currentBackoffTimeSecond # If the connection is stable for longer than _minimumConnectTimeSecond, # reset the currentBackoffTimeSecond to _baseReconnectTimeSecond diff --git a/AWSIoTPythonSDK/core/exception/AWSIoTExceptions.py b/AWSIoTPythonSDK/exception/AWSIoTExceptions.py similarity index 95% rename from AWSIoTPythonSDK/core/exception/AWSIoTExceptions.py rename to AWSIoTPythonSDK/exception/AWSIoTExceptions.py index dca44aa..0ddfa73 100755 --- a/AWSIoTPythonSDK/core/exception/AWSIoTExceptions.py +++ b/AWSIoTPythonSDK/exception/AWSIoTExceptions.py @@ -13,8 +13,8 @@ # * permissions and limitations under the License. # */ -import core.exception.operationTimeoutException as operationTimeoutException -import core.exception.operationError as operationError +import AWSIoTPythonSDK.exception.operationTimeoutException as operationTimeoutException +import AWSIoTPythonSDK.exception.operationError as operationError # Serial Exception diff --git a/AWSIoTPythonSDK/core/exception/__init__.py b/AWSIoTPythonSDK/exception/__init__.py similarity index 100% rename from AWSIoTPythonSDK/core/exception/__init__.py rename to AWSIoTPythonSDK/exception/__init__.py diff --git a/AWSIoTPythonSDK/core/exception/operationError.py b/AWSIoTPythonSDK/exception/operationError.py similarity index 100% rename from AWSIoTPythonSDK/core/exception/operationError.py rename to AWSIoTPythonSDK/exception/operationError.py diff --git a/AWSIoTPythonSDK/core/exception/operationTimeoutException.py b/AWSIoTPythonSDK/exception/operationTimeoutException.py similarity index 100% rename from AWSIoTPythonSDK/core/exception/operationTimeoutException.py rename to AWSIoTPythonSDK/exception/operationTimeoutException.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 246f611..7994b64 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,13 @@ CHANGELOG ========= +1.1.0 +===== +* feature:AWSIoTMQTTClient:last will configuration APIs +* bugfix:Pull request:`#12 `__ +* bugfix:Pull request:`#14 `__ +* Addressed issue:`#15 `__ + 1.0.1 ===== * bugfix:Pull request:`#9 `__ diff --git a/README.rst b/README.rst index fa730be..921da90 100755 --- a/README.rst +++ b/README.rst @@ -220,7 +220,7 @@ You can initialize and configure the client like this: # For TLS mutual authentication myMQTTClient.configureEndpoint("YOUR.ENDPOINT", 8883) # For Websocket - # myShadowClient.configureEndpoint("YOUR.ENDPOINT", 443) + # myMQTTClient.configureEndpoint("YOUR.ENDPOINT", 443) myMQTTClient.configureCredentials("YOUR/ROOT/CA/PATH", "PRIVATE/KEY/PATH", "CERTIFICATE/PATH") # For Websocket, we only need to configure the root CA # myMQTTClient.configureCredentials("YOUR/ROOT/CA/PATH") diff --git a/setup.py b/setup.py index 1384f50..86ba48a 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( name = 'AWSIoTPythonSDK', packages = ['AWSIoTPythonSDK', "AWSIoTPythonSDK.core", \ - "AWSIoTPythonSDK.core.exception", "AWSIoTPythonSDK.core.shadow", \ + "AWSIoTPythonSDK.exception", "AWSIoTPythonSDK.core.shadow", \ "AWSIoTPythonSDK.core.util", \ "AWSIoTPythonSDK.core.protocol", "AWSIoTPythonSDK.core.protocol.paho", \ "AWSIoTPythonSDK.core.protocol.paho.securedWebsocket"],