Skip to content

Commit 4b4f626

Browse files
committed
Release of version 1.3.0
1 parent 333ffdb commit 4b4f626

File tree

12 files changed

+285
-32
lines changed

12 files changed

+285
-32
lines changed

AWSIoTPythonSDK/MQTTLib.py

Lines changed: 160 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,81 @@ def configureMQTTOperationTimeout(self, timeoutSecond):
378378
"""
379379
self._mqtt_core.configure_operation_timeout_sec(timeoutSecond)
380380

381+
def configureUsernamePassword(self, username, password=None):
382+
"""
383+
**Description**
384+
385+
Used to configure the username and password used in CONNECT packet.
386+
387+
**Syntax**
388+
389+
.. code:: python
390+
391+
# Configure user name and password
392+
myAWSIoTMQTTClient.configureUsernamePassword("myUsername", "myPassword")
393+
394+
**Parameters**
395+
396+
*username* - Username used in the username field of CONNECT packet.
397+
398+
*password* - Password used in the password field of CONNECT packet.
399+
400+
**Returns**
401+
402+
None
403+
404+
"""
405+
self._mqtt_core.configure_username_password(username, password)
406+
407+
def enableMetricsCollection(self):
408+
"""
409+
**Description**
410+
411+
Used to enable SDK metrics collection. Username field in CONNECT packet will be used to append the SDK name
412+
and SDK version in use and communicate to AWS IoT cloud. This metrics collection is enabled by default.
413+
414+
**Syntax**
415+
416+
.. code:: python
417+
418+
myAWSIoTMQTTClient.enableMetricsCollection()
419+
420+
**Parameters**
421+
422+
None
423+
424+
**Returns**
425+
426+
None
427+
428+
"""
429+
self._mqtt_core.enable_metrics_collection()
430+
431+
def disableMetricsCollection(self):
432+
"""
433+
**Description**
434+
435+
Used to disable SDK metrics collection.
436+
437+
**Syntax**
438+
439+
.. code:: python
440+
441+
myAWSIoTMQTTClient.disableMetricsCollection()
442+
443+
**Parameters**
444+
445+
None
446+
447+
**Returns**
448+
449+
None
450+
451+
"""
452+
self._mqtt_core.disable_metrics_collection()
453+
381454
# MQTT functionality APIs
382-
def connect(self, keepAliveIntervalSecond=30):
455+
def connect(self, keepAliveIntervalSecond=600):
383456
"""
384457
**Description**
385458
@@ -389,15 +462,15 @@ def connect(self, keepAliveIntervalSecond=30):
389462
390463
.. code:: python
391464
392-
# Connect to AWS IoT with default keepalive set to 30 seconds
465+
# Connect to AWS IoT with default keepalive set to 600 seconds
393466
myAWSIoTMQTTClient.connect()
394-
# Connect to AWS IoT with keepalive interval set to 55 seconds
395-
myAWSIoTMQTTClient.connect(55)
467+
# Connect to AWS IoT with keepalive interval set to 1200 seconds
468+
myAWSIoTMQTTClient.connect(1200)
396469
397470
**Parameters**
398471
399472
*keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request.
400-
Default set to 30 seconds.
473+
Default set to 600 seconds.
401474
402475
**Returns**
403476
@@ -407,7 +480,7 @@ def connect(self, keepAliveIntervalSecond=30):
407480
self._load_callbacks()
408481
return self._mqtt_core.connect(keepAliveIntervalSecond)
409482

410-
def connectAsync(self, keepAliveIntervalSecond=30, ackCallback=None):
483+
def connectAsync(self, keepAliveIntervalSecond=600, ackCallback=None):
411484
"""
412485
**Description**
413486
@@ -417,15 +490,15 @@ def connectAsync(self, keepAliveIntervalSecond=30, ackCallback=None):
417490
418491
.. code:: python
419492
420-
# Connect to AWS IoT with default keepalive set to 30 seconds and a custom CONNACK callback
493+
# Connect to AWS IoT with default keepalive set to 600 seconds and a custom CONNACK callback
421494
myAWSIoTMQTTClient.connectAsync(ackCallback=my_connack_callback)
422-
# Connect to AWS IoT with default keepalive set to 55 seconds and a custom CONNACK callback
423-
myAWSIoTMQTTClient.connectAsync(keepAliveInternvalSecond=55, ackCallback=myConnackCallback)
495+
# Connect to AWS IoT with default keepalive set to 1200 seconds and a custom CONNACK callback
496+
myAWSIoTMQTTClient.connectAsync(keepAliveInternvalSecond=1200, ackCallback=myConnackCallback)
424497
425498
**Parameters**
426499
427500
*keepAliveIntervalSecond* - Time in seconds for interval of sending MQTT ping request.
428-
Default set to 30 seconds.
501+
Default set to 600 seconds.
429502
430503
*ackCallback* - Callback to be invoked when the client receives a CONNACK. Should be in form
431504
:code:`customCallback(mid, data)`, where :code:`mid` is the packet id for the connect request
@@ -1036,8 +1109,81 @@ def configureMQTTOperationTimeout(self, timeoutSecond):
10361109
# AWSIoTMQTTClient.configureMQTTOperationTimeout
10371110
self._AWSIoTMQTTClient.configureMQTTOperationTimeout(timeoutSecond)
10381111

1112+
def configureUsernamePassword(self, username, password=None):
1113+
"""
1114+
**Description**
1115+
1116+
Used to configure the username and password used in CONNECT packet.
1117+
1118+
**Syntax**
1119+
1120+
.. code:: python
1121+
1122+
# Configure user name and password
1123+
myAWSIoTMQTTShadowClient.configureUsernamePassword("myUsername", "myPassword")
1124+
1125+
**Parameters**
1126+
1127+
*username* - Username used in the username field of CONNECT packet.
1128+
1129+
*password* - Password used in the password field of CONNECT packet.
1130+
1131+
**Returns**
1132+
1133+
None
1134+
1135+
"""
1136+
self._AWSIoTMQTTClient.configureUsernamePassword(username, password)
1137+
1138+
def enableMetricsCollection(self):
1139+
"""
1140+
**Description**
1141+
1142+
Used to enable SDK metrics collection. Username field in CONNECT packet will be used to append the SDK name
1143+
and SDK version in use and communicate to AWS IoT cloud. This metrics collection is enabled by default.
1144+
1145+
**Syntax**
1146+
1147+
.. code:: python
1148+
1149+
myAWSIoTMQTTClient.enableMetricsCollection()
1150+
1151+
**Parameters**
1152+
1153+
None
1154+
1155+
**Returns**
1156+
1157+
None
1158+
1159+
"""
1160+
self._AWSIoTMQTTClient.enableMetricsCollection()
1161+
1162+
def disableMetricsCollection(self):
1163+
"""
1164+
**Description**
1165+
1166+
Used to disable SDK metrics collection.
1167+
1168+
**Syntax**
1169+
1170+
.. code:: python
1171+
1172+
myAWSIoTMQTTClient.disableMetricsCollection()
1173+
1174+
**Parameters**
1175+
1176+
None
1177+
1178+
**Returns**
1179+
1180+
None
1181+
1182+
"""
1183+
self._AWSIoTMQTTClient.disableMetricsCollection()
1184+
10391185
# Start the MQTT connection
1040-
def connect(self, keepAliveIntervalSecond=30):
1186+
def connect(self, keepAliveIntervalSecond=600):
10411187
"""
10421188
**Description**
10431189
@@ -1047,10 +1193,10 @@ def connect(self, keepAliveIntervalSecond=30):
10471193
10481194
.. code:: python
10491195
1050-
# Connect to AWS IoT with default keepalive set to 30 seconds
1196+
# Connect to AWS IoT with default keepalive set to 600 seconds
10511197
myAWSIoTMQTTShadowClient.connect()
1052-
# Connect to AWS IoT with keepalive interval set to 55 seconds
1053-
myAWSIoTMQTTShadowClient.connect(55)
1198+
# Connect to AWS IoT with keepalive interval set to 1200 seconds
1199+
myAWSIoTMQTTShadowClient.connect(1200)
10541200
10551201
**Parameters**
10561202

AWSIoTPythonSDK/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
__version__ = "1.2.0"
1+
__version__ = "1.3.0"
22

33

AWSIoTPythonSDK/core/greengrass/discovery/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ def _decode_core_info(self, core_object, group_id):
460460
connectivity_info = ConnectivityInfo(connectivity_info_object[KEY_CONNECTIVITY_INFO_ID],
461461
connectivity_info_object[KEY_HOST_ADDRESS],
462462
connectivity_info_object[KEY_PORT_NUMBER],
463-
connectivity_info_object[KEY_METADATA])
463+
connectivity_info_object.get(KEY_METADATA,''))
464464
core_info.appendConnectivityInfo(connectivity_info)
465465

466466
return core_info

AWSIoTPythonSDK/core/protocol/connection/cores.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import hmac
3333
from AWSIoTPythonSDK.exception.AWSIoTExceptions import wssNoKeyInEnvironmentError
3434
from AWSIoTPythonSDK.exception.AWSIoTExceptions import wssHandShakeError
35+
from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC
3536
try:
3637
from urllib.parse import quote # Python 3+
3738
except ImportError:
@@ -378,6 +379,8 @@ class SecuredWebSocketCore:
378379
_WebsocketConnectInit = -1
379380
_WebsocketDisconnected = 1
380381

382+
_logger = logging.getLogger(__name__)
383+
381384
def __init__(self, socket, hostAddress, portNumber, AWSAccessKeyID="", AWSSecretAccessKey="", AWSSessionToken=""):
382385
self._connectStatus = self._WebsocketConnectInit
383386
# Handlers
@@ -481,21 +484,27 @@ def _handShake(self, hostAddress, portNumber):
481484
handshakeBytes = handshakeBytes.encode('utf-8')
482485
self._sslSocket.write(handshakeBytes)
483486
# Read it back (Non-blocking socket)
484-
# Do we need a timeout here?
487+
timeStart = time.time()
485488
wssHandshakeResponse = bytearray()
486489
while len(wssHandshakeResponse) == 0:
487490
try:
488491
wssHandshakeResponse += self._sslSocket.read(1024) # Response is always less than 1024 bytes
489492
except socket.error as err:
490493
if err.errno == ssl.SSL_ERROR_WANT_READ or err.errno == ssl.SSL_ERROR_WANT_WRITE:
491-
pass
494+
if time.time() - timeStart > self._getTimeoutSec():
495+
raise err # We make sure that reconnect gets retried in Paho upon a wss reconnect response timeout
496+
else:
497+
raise err
492498
# Verify response
493499
# Now both wssHandshakeResponse and rawSecWebSocketKey are byte strings
494500
if not self._verifyWSSResponse(wssHandshakeResponse, rawSecWebSocketKey):
495501
raise wssHandShakeError()
496502
else:
497503
pass
498504

505+
def _getTimeoutSec(self):
506+
return DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC
507+
499508
# Used to create a single wss frame
500509
# Assume that the maximum length of a MQTT packet never exceeds the maximum length
501510
# for a wss frame. Therefore, the FIN bit for the encoded frame will always be 1.

AWSIoTPythonSDK/core/protocol/internal/clients.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ def configure_last_will(self, topic, payload, qos, retain=False):
9797
def clear_last_will(self):
9898
self._paho_client.will_clear()
9999

100+
def set_username_password(self, username, password=None):
101+
self._paho_client.username_pw_set(username, password)
102+
100103
def configure_reconnect_back_off(self, base_reconnect_quiet_sec, max_reconnect_quiet_sec, stable_connection_sec):
101104
self._paho_client.setBackoffTiming(base_reconnect_quiet_sec, max_reconnect_quiet_sec, stable_connection_sec)
102105

AWSIoTPythonSDK/core/protocol/internal/defaults.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515

1616
DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC = 30
1717
DEFAULT_OPERATION_TIMEOUT_SEC = 5
18-
DEFAULT_DRAINING_INTERNAL_SEC = 0.5
18+
DEFAULT_DRAINING_INTERNAL_SEC = 0.5
19+
METRICS_PREFIX = "?SDK=Python&Version="

AWSIoTPythonSDK/core/protocol/mqtt_core.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# * permissions and limitations under the License.
1414
# */
1515

16+
import AWSIoTPythonSDK
1617
from AWSIoTPythonSDK.core.protocol.internal.clients import InternalAsyncMqttClient
1718
from AWSIoTPythonSDK.core.protocol.internal.clients import ClientStatusContainer
1819
from AWSIoTPythonSDK.core.protocol.internal.clients import ClientStatus
@@ -24,6 +25,7 @@
2425
from AWSIoTPythonSDK.core.protocol.internal.requests import QueueableRequest
2526
from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_CONNECT_DISCONNECT_TIMEOUT_SEC
2627
from AWSIoTPythonSDK.core.protocol.internal.defaults import DEFAULT_OPERATION_TIMEOUT_SEC
28+
from AWSIoTPythonSDK.core.protocol.internal.defaults import METRICS_PREFIX
2729
from AWSIoTPythonSDK.core.protocol.internal.events import FixedEventMids
2830
from AWSIoTPythonSDK.core.protocol.paho.client import MQTT_ERR_SUCCESS
2931
from AWSIoTPythonSDK.exception.AWSIoTExceptions import connectError
@@ -60,6 +62,9 @@ class MqttCore(object):
6062
_logger = logging.getLogger(__name__)
6163

6264
def __init__(self, client_id, clean_session, protocol, use_wss):
65+
self._username = ""
66+
self._password = None
67+
self._enable_metrics_collection = True
6368
self._event_queue = Queue()
6469
self._event_cv = Condition()
6570
self._event_producer = EventProducer(self._event_cv, self._event_queue)
@@ -77,7 +82,6 @@ def __init__(self, client_id, clean_session, protocol, use_wss):
7782
self._operation_timeout_sec = DEFAULT_OPERATION_TIMEOUT_SEC
7883
self._init_offline_request_exceptions()
7984
self._init_workers()
80-
self._start_workers()
8185
self._logger.info("MqttCore initialized")
8286
self._logger.info("Client id: %s" % client_id)
8387
self._logger.info("Protocol version: %s" % ("MQTTv3.1" if protocol == MQTTv31 else "MQTTv3.1.1"))
@@ -153,6 +157,17 @@ def clear_last_will(self):
153157
self._logger.info("Clearing last will...")
154158
self._internal_async_client.clear_last_will()
155159

160+
def configure_username_password(self, username, password=None):
161+
self._logger.info("Configuring username and password...")
162+
self._username = username
163+
self._password = password
164+
165+
def enable_metrics_collection(self):
166+
self._enable_metrics_collection = True
167+
168+
def disable_metrics_collection(self):
169+
self._enable_metrics_collection = False
170+
156171
def configure_offline_requests_queue(self, max_size, drop_behavior):
157172
self._logger.info("Configuring offline requests queueing: max queue size: %d", max_size)
158173
self._offline_requests_manager = OfflineRequestsManager(max_size, drop_behavior)
@@ -174,7 +189,9 @@ def connect(self, keep_alive_sec):
174189
def connect_async(self, keep_alive_sec, ack_callback=None):
175190
self._logger.info("Performing async connect...")
176191
self._logger.info("Keep-alive: %f sec" % keep_alive_sec)
192+
self._start_workers()
177193
self._load_callbacks()
194+
self._load_username_password()
178195
self._client_status.set_status(ClientStatus.CONNECT)
179196
rc = self._internal_async_client.connect(keep_alive_sec, ack_callback)
180197
if MQTT_ERR_SUCCESS != rc:
@@ -188,6 +205,13 @@ def _load_callbacks(self):
188205
self._internal_async_client.on_offline = self.on_offline
189206
self._internal_async_client.on_message = self.on_message
190207

208+
def _load_username_password(self):
209+
username_candidate = self._username
210+
if self._enable_metrics_collection:
211+
username_candidate += METRICS_PREFIX
212+
username_candidate += AWSIoTPythonSDK.__version__
213+
self._internal_async_client.set_username_password(username_candidate, self._password)
214+
191215
def disconnect(self):
192216
self._logger.info("Performing sync disconnect...")
193217
event = Event()

AWSIoTPythonSDK/core/shadow/deviceShadow.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ def _parseTopicShadowName(self, srcTopic):
178178

179179
def _timerHandler(self, srcActionName, srcToken):
180180
with self._dataStructureLock:
181+
# Don't crash if we try to remove an unknown token
182+
if srcToken not in self._tokenPool:
183+
self._logger.warn('Tried to remove non-existent token from pool: %s' % str(srcToken))
184+
return
181185
# Remove the token
182186
del self._tokenPool[srcToken]
183187
# Need to unsubscribe?

0 commit comments

Comments
 (0)