├── .github └── PULL_REQUEST_TEMPLATE.md ├── AWS-IoT-Arduino-Yun-Library ├── LICENSE.txt ├── aws_iot_config_SDK.h ├── aws_iot_error.h ├── aws_iot_mqtt.cpp ├── aws_iot_mqtt.h ├── aws_iot_version.h ├── examples │ ├── BasicPubSub │ │ ├── BasicPubSub.ino │ │ └── aws_iot_config.h │ ├── ThermostatSimulatorDevice │ │ ├── ThermostatSimulatorDevice.ino │ │ └── aws_iot_config.h │ └── ThingShadowEcho │ │ ├── ThingShadowEcho.ino │ │ └── aws_iot_config.h └── keywords.txt ├── AWS-IoT-Python-Runtime ├── certs │ └── delete.me ├── lib │ ├── comm │ │ ├── __init__.py │ │ ├── communicationServer.py │ │ └── serialCommunicationServer.py │ ├── command │ │ ├── AWSIoTCommand.py │ │ ├── __init__.py │ │ ├── commandConfig.py │ │ ├── commandConnect.py │ │ ├── commandDisconnect.py │ │ ├── commandJSONKeyVal.py │ │ ├── commandLockSize.py │ │ ├── commandPublish.py │ │ ├── commandSetBackoffTiming.py │ │ ├── commandSetDrainingIntervalSecond.py │ │ ├── commandSetOfflinePublishQueueing.py │ │ ├── commandShadowDelete.py │ │ ├── commandShadowGet.py │ │ ├── commandShadowRegisterDeltaCallback.py │ │ ├── commandShadowUnregisterDeltaCallback.py │ │ ├── commandShadowUpdate.py │ │ ├── commandSubscribe.py │ │ ├── commandUnsubscribe.py │ │ └── commandYield.py │ ├── exception │ │ ├── AWSIoTExceptions.py │ │ ├── __init__.py │ │ ├── operationError.py │ │ └── operationTimeoutException.py │ └── util │ │ ├── __init__.py │ │ └── jsonManager.py ├── log │ └── delete.me └── runtime │ ├── __init__.py │ ├── run.py │ └── runtimeHub.py ├── AWSIoTArduinoYunInstallAll.sh ├── AWSIoTArduinoYunScp.sh ├── AWSIoTArduinoYunSetupEnvironment.sh ├── AWSIoTArduinoYunWebsocketCredentialConfig.sh ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ExampleAppScript └── ThermostatSimulatorApp │ ├── ThermostatSimulatorApp.py │ └── certs │ └── delete.me ├── LICENSE.txt ├── NOTICE.txt └── README.md /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 7 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/LICENSE.txt: -------------------------------------------------------------------------------- 1 | ############################################################################################################################# 2 | 3 | 4 | Apache License 5 | Version 2.0, January 2004 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 11 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 12 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 13 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 14 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 15 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 16 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 17 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 18 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 19 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 20 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 21 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 22 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 23 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and 24 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and 25 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 26 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 27 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 28 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 29 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 30 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 31 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 32 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 33 | 34 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/aws_iot_config_SDK.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef config_h 17 | #define config_h 18 | 19 | #define MAX_BUF_SIZE 256 // maximum number of bytes to publish/receive 20 | #define MAX_SUB 15 // maximum number of subscribe 21 | #define CMD_TIME_OUT 200 // maximum time to wait for feedback from AR9331, 200 = 10 sec 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/aws_iot_error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef aws_iot_error_h 17 | #define aws_iot_error_h 18 | 19 | typedef enum { 20 | NONE_ERROR = 0, 21 | GENERIC_ERROR = -1, 22 | NULL_VALUE_ERROR = -2, 23 | OVERFLOW_ERROR = -3, 24 | OUT_OF_SKETCH_SUBSCRIBE_MEMORY = -4, 25 | SERIAL1_COMMUNICATION_ERROR = -5, 26 | SET_UP_ERROR = -6, 27 | NO_SET_UP_ERROR = -7, 28 | WRONG_PARAMETER_ERROR = -8, 29 | CONFIG_GENERIC_ERROR = -9, 30 | CONNECT_SSL_ERROR = -10, 31 | CONNECT_ERROR = -11, 32 | CONNECT_TIMEOUT = -12, 33 | CONNECT_CREDENTIAL_NOT_FOUND = -13, 34 | CONNECT_GENERIC_ERROR = -14, 35 | PUBLISH_ERROR = -15, 36 | PUBLISH_TIMEOUT = -16, 37 | PUBLISH_GENERIC_ERROR = -17, 38 | SUBSCRIBE_ERROR = -18, 39 | SUBSCRIBE_TIMEOUT = -19, 40 | SUBSCRIBE_GENERIC_ERROR = -20, 41 | UNSUBSCRIBE_ERROR = -21, 42 | UNSUBSCRIBE_TIMEOUT = -22, 43 | UNSUBSCRIBE_GENERIC_ERROR = -23, 44 | DISCONNECT_ERROR = -24, 45 | DISCONNECT_TIMEOUT = -25, 46 | DISCONNECT_GENERIC_ERROR = -26, 47 | SHADOW_INIT_ERROR = -27, 48 | NO_SHADOW_INIT_ERROR = -28, 49 | SHADOW_GET_GENERIC_ERROR = -29, 50 | SHADOW_UPDATE_GENERIC_ERROR = -30, 51 | SHADOW_UPDATE_INVALID_JSON_ERROR = -31, 52 | SHADOW_DELETE_GENERIC_ERROR = -32, 53 | SHADOW_REGISTER_DELTA_CALLBACK_GENERIC_ERROR = -33, 54 | SHADOW_UNREGISTER_DELTA_CALLBACK_GENERIC_ERROR = -34, 55 | YIELD_ERROR = -35, 56 | WEBSOCKET_CREDENTIAL_NOT_FOUND = -36, 57 | JSON_FILE_NOT_FOUND = -37, 58 | JSON_KEY_NOT_FOUND = -38, 59 | JSON_GENERIC_ERROR = -39, 60 | PUBLISH_QUEUE_FULL = -40, 61 | PUBLISH_QUEUE_DISABLED = -41 62 | } IoT_Error_t; 63 | 64 | #endif 65 | 66 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/aws_iot_mqtt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #include "aws_iot_mqtt.h" 17 | #include "Arduino.h" 18 | #include "stdio.h" 19 | #include "stdlib.h" 20 | #include "string.h" 21 | #include "ctype.h" 22 | #include "avr/pgmspace.h" 23 | 24 | #define LINUX_BAUD_DEFAULT 250000 25 | #define LINUX_BAUD_LININO 115200 26 | #define RETURN_KEY 13 // ASCII code for '\r' 27 | #define NEXTLINE_KEY 10 // ASCII code for '\n' 28 | #define MAX_NUM_PARA 6 // Maximum number of parameters in protocol communication 29 | #define NUM_ATTEMPT_BEFORE_EXIT MAX_NUM_PARA/2+1 // Number of '~' to fully exit the protocol command 30 | 31 | // PGM_P is defined as const char* 32 | // Helper string constants 33 | PGM_P OUT_OF_BUFFER_ERR_MSG = "OUT OF BUFFER SIZE"; 34 | PGM_P EMPTY_STRING = ""; 35 | // Internal non-protocol commands 36 | PGM_P CMD_CHECK_LINUX_LIVE = "uname\n"; 37 | PGM_P CMD_CD_TO_PY_RUNTIME = "cd /root/AWS-IoT-Python-Runtime/runtime/\n"; 38 | PGM_P CMD_START_PY_RUNTIME = "python run.py\n"; 39 | 40 | // Choose different baudrate for different version of openWRT OS 41 | Baud_t aws_iot_mqtt_client::find_baud_type() { 42 | Baud_t rc_type = BAUD_TYPE_UNKNOWN; 43 | // 1st attempt 44 | clearProtocolOnSerialBegin(LINUX_BAUD_DEFAULT); 45 | exec_cmd(CMD_CHECK_LINUX_LIVE, true, false); // check OS version 46 | if(strncmp_P(rw_buf, PSTR("Linux"), 5) != 0) { // Not an Arduino? 47 | clearProtocolOnSerialBegin(LINUX_BAUD_LININO); 48 | exec_cmd(CMD_CHECK_LINUX_LIVE, true, false); // check OS version 49 | if(strncmp_P(rw_buf, PSTR("Linux"), 5) != 0) { 50 | // No more board types to try 51 | } 52 | else {rc_type = BAUD_TYPE_LININO;} 53 | } 54 | else {rc_type = BAUD_TYPE_ARDUINO;} 55 | 56 | return rc_type; 57 | } 58 | 59 | IoT_Error_t aws_iot_mqtt_client::setup_exec(const char* client_id, bool clean_session, MQTTv_t MQTT_version, bool useWebsocket) { 60 | // Serial1 is started before this call 61 | IoT_Error_t rc = NONE_ERROR; 62 | exec_cmd(CMD_CD_TO_PY_RUNTIME, false, false); 63 | exec_cmd(CMD_START_PY_RUNTIME, false, false); 64 | 65 | // Create obj 66 | exec_cmd("5\n", false, false); 67 | 68 | exec_cmd("i\n", false, false); 69 | 70 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), client_id); 71 | exec_cmd(rw_buf, false, false); 72 | 73 | int num_temp = clean_session ? 1 : 0; 74 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), num_temp); 75 | exec_cmd(rw_buf, false, false); 76 | 77 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%u\n"), MQTT_version); 78 | exec_cmd(rw_buf, false, false); 79 | 80 | // Websocket flag 81 | num_temp = useWebsocket ? 1 : 0; 82 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), num_temp); 83 | exec_cmd(rw_buf, true, false); 84 | 85 | if(strncmp_P(rw_buf, PSTR("I T"), 3) != 0) { 86 | if(strncmp_P(rw_buf, PSTR("I F"), 3) == 0) {rc = SET_UP_ERROR;} 87 | else rc = GENERIC_ERROR; 88 | } 89 | 90 | return rc; 91 | } 92 | 93 | IoT_Error_t aws_iot_mqtt_client::setup(const char* client_id, bool clean_session, MQTTv_t MQTT_version, bool useWebsocket) { 94 | IoT_Error_t rc = NONE_ERROR; 95 | if(client_id == NULL) {rc = NULL_VALUE_ERROR;} 96 | else if(strlen(client_id) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 97 | // No input error below this line 98 | else { 99 | Baud_t baud_type = find_baud_type(); // Find out baud type 100 | // Communication failed due to baud rate issue 101 | if(BAUD_TYPE_UNKNOWN == baud_type) {rc = SERIAL1_COMMUNICATION_ERROR;} 102 | else { 103 | rc = setup_exec(client_id, clean_session, MQTT_version, useWebsocket); 104 | } 105 | } 106 | 107 | return rc; 108 | } 109 | 110 | IoT_Error_t aws_iot_mqtt_client::configWss(const char* host, unsigned int port, const char* cafile_path) { 111 | return config(host, port, cafile_path, "", ""); // No need for key and cert, IAM credentials are used. 112 | } 113 | 114 | IoT_Error_t aws_iot_mqtt_client::config(const char* host, unsigned int port, const char* cafile_path, const char* keyfile_path, const char* certfile_path) { 115 | IoT_Error_t rc = NONE_ERROR; 116 | 117 | if(host != NULL && strlen(host) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 118 | else if(cafile_path != NULL && strlen(cafile_path) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 119 | else if(keyfile_path != NULL && strlen(keyfile_path) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 120 | else if(certfile_path != NULL && strlen(certfile_path) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 121 | else { 122 | PGM_P helper = ""; 123 | 124 | exec_cmd("6\n", false, false); 125 | 126 | exec_cmd("g\n", false, false); 127 | 128 | helper = host == NULL ? EMPTY_STRING : host; 129 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), helper); 130 | exec_cmd(rw_buf, false, false); 131 | 132 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), port); 133 | exec_cmd(rw_buf, false, false); 134 | 135 | helper = cafile_path == NULL ? EMPTY_STRING : cafile_path; 136 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), helper); 137 | exec_cmd(rw_buf, false, false); 138 | 139 | helper = keyfile_path == NULL ? EMPTY_STRING : keyfile_path; 140 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), helper); 141 | exec_cmd(rw_buf, false, false); 142 | 143 | helper = certfile_path == NULL ? EMPTY_STRING : certfile_path; 144 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), helper); 145 | exec_cmd(rw_buf, true, false); 146 | 147 | if(strncmp_P(rw_buf, PSTR("G T"), 3) != 0) { 148 | if(strncmp_P(rw_buf, PSTR("G1F"), 3) == 0) {rc = NO_SET_UP_ERROR;} 149 | else if(strncmp_P(rw_buf, PSTR("G2F"), 3) == 0) {rc = WRONG_PARAMETER_ERROR;} 150 | else if(strncmp_P(rw_buf, PSTR("GFF"), 3) == 0) {rc = CONFIG_GENERIC_ERROR;} 151 | else rc = GENERIC_ERROR; 152 | } 153 | } 154 | 155 | return rc; 156 | } 157 | 158 | IoT_Error_t aws_iot_mqtt_client::configBackoffTiming(unsigned int baseReconnectQuietTimeSecond, unsigned int maxReconnectQuietTimeSecond, unsigned int stableConnectionTimeSecond) { 159 | IoT_Error_t rc = NONE_ERROR; 160 | 161 | exec_cmd("4\n", false, false); 162 | 163 | exec_cmd("bf\n", false, false); 164 | 165 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), baseReconnectQuietTimeSecond); 166 | exec_cmd(rw_buf, false, false); 167 | 168 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), maxReconnectQuietTimeSecond); 169 | exec_cmd(rw_buf, false, false); 170 | 171 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), stableConnectionTimeSecond); 172 | exec_cmd(rw_buf, true, false); 173 | 174 | if(strncmp_P(rw_buf, PSTR("BF T"), 4) != 0) { 175 | if(strncmp_P(rw_buf, PSTR("BF1F"), 4) == 0) {rc = NO_SET_UP_ERROR;} 176 | else if(strncmp_P(rw_buf, PSTR("BF2F"), 4) == 0) {rc = WRONG_PARAMETER_ERROR;} 177 | else if(strncmp_P(rw_buf, PSTR("BF3F"), 4) == 0) {rc = WRONG_PARAMETER_ERROR;} 178 | else if(strncmp_P(rw_buf, PSTR("BFFF"), 4) == 0) {rc = CONFIG_GENERIC_ERROR;} 179 | else rc = GENERIC_ERROR; 180 | } 181 | 182 | return rc; 183 | } 184 | 185 | IoT_Error_t aws_iot_mqtt_client::configOfflinePublishQueue(unsigned int queueSize, DropBehavior_t behavior) { 186 | IoT_Error_t rc = NONE_ERROR; 187 | 188 | exec_cmd("3\n", false, false); 189 | 190 | exec_cmd("pq\n", false, false); 191 | 192 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), queueSize); 193 | exec_cmd(rw_buf, false, false); 194 | 195 | 196 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), behavior); 197 | exec_cmd(rw_buf, true, false); 198 | 199 | if(strncmp_P(rw_buf, PSTR("PQ T"), 4) != 0) { 200 | if(strncmp_P(rw_buf, PSTR("PQ1F"), 4) == 0) {rc = NO_SET_UP_ERROR;} 201 | else if(strncmp_P(rw_buf, PSTR("PQ2F"), 4) == 0) {rc = WRONG_PARAMETER_ERROR;} 202 | else if(strncmp_P(rw_buf, PSTR("PQ3F"), 4) == 0) {rc = WRONG_PARAMETER_ERROR;} 203 | else if(strncmp_P(rw_buf, PSTR("PQFF"), 4) == 0) {rc = CONFIG_GENERIC_ERROR;} 204 | else rc = GENERIC_ERROR; 205 | } 206 | 207 | return rc; 208 | } 209 | 210 | IoT_Error_t aws_iot_mqtt_client::configDrainingInterval(float numberOfSeconds) { 211 | IoT_Error_t rc = NONE_ERROR; 212 | 213 | exec_cmd("2\n", false, false); 214 | 215 | exec_cmd("di\n", false, false); 216 | 217 | dtostrf(numberOfSeconds, 5, 2, rw_buf); // Only support XX.XX (including sign+/-) 218 | strcat(rw_buf, "\n"); 219 | exec_cmd(rw_buf, true, false); 220 | 221 | if(strncmp_P(rw_buf, PSTR("DI T"), 4) != 0) { 222 | if(strncmp_P(rw_buf, PSTR("DI1F"), 4) == 0) {rc = NO_SET_UP_ERROR;} 223 | else if(strncmp_P(rw_buf, PSTR("DI2F"), 4) == 0) {rc = WRONG_PARAMETER_ERROR;} 224 | else if(strncmp_P(rw_buf, PSTR("DI3F"), 4) == 0) {rc = WRONG_PARAMETER_ERROR;} 225 | else if(strncmp_P(rw_buf, PSTR("DIFF"), 4) == 0) {rc = CONFIG_GENERIC_ERROR;} 226 | else rc = GENERIC_ERROR; 227 | } 228 | 229 | return rc; 230 | } 231 | 232 | IoT_Error_t aws_iot_mqtt_client::connect(unsigned int keepalive_interval) { 233 | IoT_Error_t rc = NONE_ERROR; 234 | exec_cmd("2\n", false, false); 235 | 236 | exec_cmd("c\n", false, false); 237 | 238 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), keepalive_interval); 239 | exec_cmd(rw_buf, true, false); 240 | 241 | if(strncmp_P(rw_buf, PSTR("C T"), 3) != 0) { 242 | if(strncmp_P(rw_buf, PSTR("C1F"), 3) == 0) {rc = NO_SET_UP_ERROR;} 243 | else if(strncmp_P(rw_buf, PSTR("C2F"), 3) == 0) {rc = WRONG_PARAMETER_ERROR;} 244 | else if(strncmp_P(rw_buf, PSTR("C3F"), 3) == 0) {rc = CONNECT_SSL_ERROR;} 245 | else if(strncmp_P(rw_buf, PSTR("C4F"), 3) == 0) {rc = CONNECT_ERROR;} 246 | else if(strncmp_P(rw_buf, PSTR("C5F"), 3) == 0) {rc = CONNECT_TIMEOUT;} 247 | else if(strncmp_P(rw_buf, PSTR("C6F"), 3) == 0) {rc = CONNECT_CREDENTIAL_NOT_FOUND;} 248 | else if(strncmp_P(rw_buf, PSTR("C7F"), 3) == 0) {rc = WEBSOCKET_CREDENTIAL_NOT_FOUND;} 249 | else if(strncmp_P(rw_buf, PSTR("CFF"), 3) == 0) {rc = CONNECT_GENERIC_ERROR;} 250 | else rc = GENERIC_ERROR; 251 | } 252 | 253 | return rc; 254 | } 255 | 256 | IoT_Error_t aws_iot_mqtt_client::publish(const char* topic, const char* payload, unsigned int payload_len, unsigned int qos, bool retain) { 257 | IoT_Error_t rc = NONE_ERROR; 258 | if(topic == NULL || payload == NULL) {rc = NULL_VALUE_ERROR;} 259 | else if(strlen(topic) >= MAX_BUF_SIZE || payload_len >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 260 | else { 261 | exec_cmd("5\n", false, false); 262 | 263 | exec_cmd("p\n", false, false); 264 | 265 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), topic); 266 | exec_cmd(rw_buf, false, false); 267 | 268 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), payload); 269 | exec_cmd(rw_buf, false, false); 270 | 271 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), qos); 272 | exec_cmd(rw_buf, false, false); 273 | 274 | int num_temp = retain ? 1 : 0; 275 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), num_temp); 276 | exec_cmd(rw_buf, true, false); 277 | 278 | if(strncmp_P(rw_buf, PSTR("P T"), 3) != 0) { 279 | if(strncmp_P(rw_buf, PSTR("P1F"), 3) == 0) {rc = NO_SET_UP_ERROR;} 280 | else if(strncmp_P(rw_buf, PSTR("P2F"), 3) == 0) {rc = WRONG_PARAMETER_ERROR;} 281 | else if(strncmp_P(rw_buf, PSTR("P3F"), 3) == 0) {rc = PUBLISH_ERROR;} 282 | else if(strncmp_P(rw_buf, PSTR("P4F"), 3) == 0) {rc = PUBLISH_TIMEOUT;} 283 | else if(strncmp_P(rw_buf, PSTR("P5F"), 3) == 0) {rc = PUBLISH_QUEUE_FULL;} 284 | else if(strncmp_P(rw_buf, PSTR("P6F"), 3) == 0) {rc = PUBLISH_QUEUE_DISABLED;} 285 | else if(strncmp_P(rw_buf, PSTR("PFF"), 3) == 0) {rc = PUBLISH_GENERIC_ERROR;} 286 | else rc = GENERIC_ERROR; 287 | } 288 | } 289 | return rc; 290 | } 291 | 292 | IoT_Error_t aws_iot_mqtt_client::subscribe(const char* topic, unsigned int qos, message_callback cb) { 293 | IoT_Error_t rc = NONE_ERROR; 294 | if(topic == NULL) {rc = NULL_VALUE_ERROR;} 295 | else if(strlen(topic) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 296 | else { 297 | // find unused slots for new subscribe 298 | int i = find_unused_subgroup(); 299 | if(i < MAX_SUB) { 300 | exec_cmd("4\n", false, false); 301 | 302 | exec_cmd("s\n", false, false); 303 | 304 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), topic); 305 | exec_cmd(rw_buf, false, false); 306 | 307 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), qos); 308 | exec_cmd(rw_buf, false, false); 309 | 310 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), i); // ino_id 311 | exec_cmd(rw_buf, true, false); 312 | 313 | if(strncmp_P(rw_buf, PSTR("S T"), 3) == 0) { 314 | sub_group[i].is_used = true; 315 | sub_group[i].is_shadow_gud = false; 316 | sub_group[i].callback = cb; 317 | } 318 | else { 319 | if(strncmp_P(rw_buf, PSTR("S1F"), 3) == 0) {rc = NO_SET_UP_ERROR;} 320 | else if(strncmp_P(rw_buf, PSTR("S2F"), 3) == 0) {rc = WRONG_PARAMETER_ERROR;} 321 | else if(strncmp_P(rw_buf, PSTR("S3F"), 3) == 0) {rc = SUBSCRIBE_ERROR;} 322 | else if(strncmp_P(rw_buf, PSTR("S4F"), 3) == 0) {rc = SUBSCRIBE_TIMEOUT;} 323 | else if(strncmp_P(rw_buf, PSTR("SFF"), 3) == 0) {rc = SUBSCRIBE_GENERIC_ERROR;} 324 | else rc = GENERIC_ERROR; 325 | } 326 | } 327 | else {rc = OUT_OF_SKETCH_SUBSCRIBE_MEMORY;} 328 | } 329 | return rc; 330 | } 331 | 332 | IoT_Error_t aws_iot_mqtt_client::unsubscribe(const char* topic) { 333 | IoT_Error_t rc = NONE_ERROR; 334 | if(topic == NULL) {rc = NULL_VALUE_ERROR;} 335 | else if(strlen(topic) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 336 | else { 337 | exec_cmd("2\n", false, false); 338 | 339 | exec_cmd("u\n", false, false); 340 | 341 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), topic); 342 | exec_cmd(rw_buf, true, false); 343 | 344 | // Unsubscribe to a topic never subscribed, ignore 345 | if(strncmp_P(rw_buf, PSTR("U T"), 3) == 0) {rc = NONE_ERROR;} 346 | else { 347 | char* saveptr; 348 | char* p; 349 | p = strtok_r(rw_buf, " ", &saveptr); // 'U' 350 | p = strtok_r(NULL, " ", &saveptr); // ino_id 351 | int ino_id = -1; 352 | if(p != NULL) {ino_id = is_num(p) ? atoi(p) : -1;} 353 | if(ino_id >= 0 && ino_id < MAX_SUB) { 354 | sub_group[ino_id].is_used = false; 355 | sub_group[ino_id].is_shadow_gud = false; 356 | sub_group[ino_id].callback = NULL; 357 | } 358 | else if(strncmp_P(rw_buf, PSTR("U1F"), 3) == 0) {rc = NO_SET_UP_ERROR;} 359 | else if(strncmp_P(rw_buf, PSTR("U2F"), 3) == 0) {rc = WRONG_PARAMETER_ERROR;} 360 | else if(strncmp_P(rw_buf, PSTR("U3F"), 3) == 0) {rc = UNSUBSCRIBE_ERROR;} 361 | else if(strncmp_P(rw_buf, PSTR("U4F"), 3) == 0) {rc = UNSUBSCRIBE_TIMEOUT;} 362 | else if(strncmp_P(rw_buf, PSTR("UFF"), 3) == 0) {rc = UNSUBSCRIBE_GENERIC_ERROR;} 363 | else rc = GENERIC_ERROR; 364 | } 365 | } 366 | return rc; 367 | } 368 | 369 | IoT_Error_t aws_iot_mqtt_client::yield() { 370 | IoT_Error_t rc = NONE_ERROR; 371 | exec_cmd("1\n", false, false); 372 | exec_cmd("z\n", true, false); // tell the python runtime to lock the current msg queue size 373 | if(strncmp_P(rw_buf, PSTR("Z T"), 3) != 0) {rc = YIELD_ERROR;} // broken protocol 374 | else { // start the BIG yield loop 375 | while(true) { 376 | exec_cmd("1\n", false, false); 377 | exec_cmd("y\n", true, false); 378 | if(strncmp_P(rw_buf, PSTR("Y F"), 3) == 0) {break;} 379 | if(rw_buf[0] != 'Y') { // filter out garbage feedback 380 | rc = YIELD_ERROR; 381 | break; 382 | } 383 | // From here, there is a new message chunk in rw_buf 384 | char* saveptr; 385 | char* p; 386 | p = strtok_r(rw_buf, " ", &saveptr); // 'Y' 387 | p = strtok_r(NULL, " ", &saveptr); // ino_id 388 | if(p != NULL) { 389 | int ino_id = is_num(p) ? atoi(p) : -1; 390 | size_t id_len = strlen(p); 391 | p = strtok_r(NULL, " ", &saveptr); // more chunks? 392 | if(p != NULL) { 393 | int more = is_num(p) ? atoi(p) : -1; 394 | if(more != 1 && more != 0) { // broken protocol 395 | rc = YIELD_ERROR; 396 | break; 397 | } 398 | else if(ino_id == -1) { 399 | rc = YIELD_ERROR; 400 | break; 401 | } 402 | else { 403 | char* payload = rw_buf + id_len + 5; // step over the protocol and get payload 404 | if(strlen(msg_buf) + strlen(payload) > MAX_BUF_SIZE) { 405 | rc = OVERFLOW_ERROR; // if it is exceeding MAX_BUF_SIZE, return the corresponding error code 406 | } 407 | else {strcat(msg_buf, payload);} 408 | if(more == 0) { // This is the end of this message, do callback and clean up 409 | // user callback, watch out for ino_id boundary issue and callback registration 410 | if(ino_id >= 0 && ino_id < MAX_SUB && sub_group[ino_id].is_used) { 411 | // User callback 412 | if(sub_group[ino_id].callback != NULL) { 413 | if(rc == NONE_ERROR) { 414 | if(sub_group[ino_id].is_shadow_gud) { 415 | // See if it is timeout 416 | if(strncmp_P(msg_buf, PSTR("JSON-X"), 6) == 0) {sub_group[ino_id].callback(msg_buf, (unsigned int)strlen(msg_buf), STATUS_SHADOW_TIMEOUT);} 417 | else { 418 | // See if it is accepted/rejected 419 | // Delta is treated as normal MQTT messages 420 | int type_num = atoi(msg_buf+5); 421 | if(type_num%3 == 0) {sub_group[ino_id].callback(msg_buf, (unsigned int)strlen(msg_buf), STATUS_SHADOW_ACCEPTED);} // accepted 422 | else if(type_num%3 == 1) {sub_group[ino_id].callback(msg_buf, (unsigned int)strlen(msg_buf), STATUS_SHADOW_REJECTED);} // rejected 423 | else { 424 | rc = YIELD_ERROR; 425 | break; 426 | } 427 | } 428 | } 429 | else {sub_group[ino_id].callback(msg_buf, (unsigned int)strlen(msg_buf), STATUS_NORMAL);} 430 | } 431 | if(rc == OVERFLOW_ERROR) { 432 | sub_group[ino_id].callback((char*)(OUT_OF_BUFFER_ERR_MSG), (unsigned int)strlen(OUT_OF_BUFFER_ERR_MSG), STATUS_MESSAGE_OVERFLOW); 433 | } 434 | } 435 | // always free the shadow slot and recover the context 436 | if(sub_group[ino_id].is_shadow_gud) { 437 | sub_group[ino_id].is_used = false; 438 | sub_group[ino_id].is_shadow_gud = false; 439 | sub_group[ino_id].callback = NULL; 440 | } 441 | } 442 | // clean up 443 | msg_buf[0] = '\0'; // mark msg_buf as 'unused', ready for the next flush 444 | } 445 | // more to come? do NOTHING to msg_buf and DO NOT call callback 446 | } 447 | } 448 | else { 449 | rc = YIELD_ERROR; 450 | break; 451 | } 452 | } 453 | else { 454 | rc = YIELD_ERROR; 455 | break; 456 | } 457 | } 458 | } 459 | return rc; 460 | } 461 | 462 | IoT_Error_t aws_iot_mqtt_client::disconnect() { 463 | IoT_Error_t rc = NONE_ERROR; 464 | exec_cmd("1\n", false, false); 465 | 466 | exec_cmd("d\n", true, false); 467 | 468 | if(strncmp_P(rw_buf, PSTR("D T"), 3) != 0) { 469 | if(strncmp_P(rw_buf, PSTR("D1F"), 3) == 0) {rc = NO_SET_UP_ERROR;} 470 | else if(strncmp_P(rw_buf, PSTR("D2F"), 3) == 0) {rc = DISCONNECT_ERROR;} 471 | else if(strncmp_P(rw_buf, PSTR("D3F"), 3) == 0) {rc = DISCONNECT_TIMEOUT;} 472 | else if(strncmp_P(rw_buf, PSTR("DFF"), 3) == 0) {rc = DISCONNECT_GENERIC_ERROR;} 473 | else rc = GENERIC_ERROR; 474 | } 475 | return rc; 476 | } 477 | 478 | // DeviceShadow-support API 479 | IoT_Error_t aws_iot_mqtt_client::shadow_init(const char* thingName) { 480 | IoT_Error_t rc = NONE_ERROR; 481 | if(thingName == NULL) {rc = NULL_VALUE_ERROR;} 482 | else if(strlen(thingName) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 483 | else { 484 | exec_cmd("3\n", false, false); 485 | 486 | exec_cmd("si\n", false, false); 487 | 488 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), thingName); 489 | exec_cmd(rw_buf, false, false); 490 | 491 | exec_cmd("1\n", true, false); // isPersistentSubscribe, always true 492 | 493 | if(strncmp_P(rw_buf, PSTR("SI T"), 4) != 0) { 494 | if(strncmp_P(rw_buf, PSTR("SI F"), 4) == 0) {rc = SHADOW_INIT_ERROR;} 495 | else rc = GENERIC_ERROR; 496 | } 497 | } 498 | return rc; 499 | } 500 | 501 | IoT_Error_t aws_iot_mqtt_client::shadow_register_delta_func(const char* thingName, message_callback cb) { 502 | IoT_Error_t rc = NONE_ERROR; 503 | if(thingName == NULL) {rc = NULL_VALUE_ERROR;} 504 | else if(strlen(thingName) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 505 | else { 506 | // find unused slots for new subscribe 507 | int i = find_unused_subgroup(); 508 | if(i < MAX_SUB) { 509 | exec_cmd("3\n", false, false); 510 | 511 | exec_cmd("s_rd\n", false, false); 512 | 513 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), thingName); 514 | exec_cmd(rw_buf, false, false); 515 | 516 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), i); 517 | exec_cmd(rw_buf, true, false); 518 | 519 | if(strncmp_P(rw_buf, PSTR("S_RD T"), 6) == 0) { 520 | sub_group[i].is_used = true; 521 | sub_group[i].callback = cb; 522 | } 523 | else { 524 | if(strncmp_P(rw_buf, PSTR("S_RD1F"), 6) == 0) {rc = NO_SHADOW_INIT_ERROR;} 525 | else if(strncmp_P(rw_buf, PSTR("S_RD2F"), 6) == 0) {rc = WRONG_PARAMETER_ERROR;} 526 | else if(strncmp_P(rw_buf, PSTR("S_RD3F"), 6) == 0) {rc = SUBSCRIBE_ERROR;} 527 | else if(strncmp_P(rw_buf, PSTR("S_RD4F"), 6) == 0) {rc = SUBSCRIBE_TIMEOUT;} 528 | else if(strncmp_P(rw_buf, PSTR("S_RDFF"), 6) == 0) {rc = SHADOW_REGISTER_DELTA_CALLBACK_GENERIC_ERROR;} 529 | else rc = GENERIC_ERROR; 530 | } 531 | } 532 | } 533 | return rc; 534 | } 535 | 536 | IoT_Error_t aws_iot_mqtt_client::shadow_unregister_delta_func(const char* thingName) { 537 | IoT_Error_t rc = NONE_ERROR; 538 | if(thingName == NULL) {rc = NULL_VALUE_ERROR;} 539 | else if(strlen(thingName) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 540 | else { 541 | exec_cmd("2\n", false, false); 542 | 543 | exec_cmd("s_ud\n", false, false); 544 | 545 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), thingName); 546 | exec_cmd(rw_buf, true, false); 547 | 548 | // Unsubscribe to a topic never subscribed, ignore 549 | if(strncmp_P(rw_buf, PSTR("S_UD T"), 6) == 0) {rc = NONE_ERROR;} 550 | else { 551 | char* saveptr; 552 | char* p; 553 | p = strtok_r(rw_buf, " ", &saveptr); // 'S_UD' 554 | p = strtok_r(NULL, " ", &saveptr); // ino_id 555 | int ino_id = -1; 556 | if(p != NULL) {ino_id = is_num(p) ? atoi(p) : -1;} 557 | if(ino_id >= 0 && ino_id < MAX_SUB) { 558 | sub_group[ino_id].is_used = false; 559 | sub_group[ino_id].callback = NULL; 560 | } 561 | else if(strncmp_P(rw_buf, PSTR("S_UD1F"), 6) == 0) {rc = NO_SHADOW_INIT_ERROR;} 562 | else if(strncmp_P(rw_buf, PSTR("S_UD2F"), 6) == 0) {rc = WRONG_PARAMETER_ERROR;} 563 | else if(strncmp_P(rw_buf, PSTR("S_UD3F"), 6) == 0) {rc = UNSUBSCRIBE_ERROR;} 564 | else if(strncmp_P(rw_buf, PSTR("S_UD4F"), 6) == 0) {rc = UNSUBSCRIBE_TIMEOUT;} 565 | else if(strncmp_P(rw_buf, PSTR("S_UDFF"), 6) == 0) {rc = SHADOW_UNREGISTER_DELTA_CALLBACK_GENERIC_ERROR;} 566 | else rc = GENERIC_ERROR; 567 | } 568 | } 569 | return rc; 570 | } 571 | 572 | IoT_Error_t aws_iot_mqtt_client::shadow_get(const char* thingName, message_callback cb, unsigned int timeout) { 573 | IoT_Error_t rc = NONE_ERROR; 574 | if(thingName == NULL) {rc = NULL_VALUE_ERROR;} 575 | else if(strlen(thingName) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 576 | else { 577 | // find unused slots for new subscribe 578 | int i = find_unused_subgroup(); 579 | if(i < MAX_SUB) { 580 | exec_cmd("4\n", false, false); 581 | 582 | exec_cmd("sg\n", false, false); 583 | 584 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), thingName); 585 | exec_cmd(rw_buf, false, false); 586 | 587 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), i); 588 | exec_cmd(rw_buf, false, false); 589 | 590 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), timeout); 591 | exec_cmd(rw_buf, true, false); 592 | 593 | if(strncmp_P(rw_buf, PSTR("SG T"), 4) == 0) { 594 | sub_group[i].is_used = true; 595 | sub_group[i].is_shadow_gud = true; 596 | sub_group[i].callback = cb; 597 | } 598 | else { 599 | if(strncmp_P(rw_buf, PSTR("SG1F"), 4) == 0) {rc = NO_SHADOW_INIT_ERROR;} 600 | else if(strncmp_P(rw_buf, PSTR("SG2F"), 4) == 0) {rc = WRONG_PARAMETER_ERROR;} 601 | else if(strncmp_P(rw_buf, PSTR("SG3F"), 4) == 0) {rc = SUBSCRIBE_ERROR;} 602 | else if(strncmp_P(rw_buf, PSTR("SG4F"), 4) == 0) {rc = SUBSCRIBE_TIMEOUT;} 603 | else if(strncmp_P(rw_buf, PSTR("SG5F"), 4) == 0) {rc = PUBLISH_ERROR;} 604 | else if(strncmp_P(rw_buf, PSTR("SG6F"), 4) == 0) {rc = PUBLISH_TIMEOUT;} 605 | else if(strncmp_P(rw_buf, PSTR("SG7F"), 4) == 0) {rc = PUBLISH_QUEUE_FULL;} 606 | else if(strncmp_P(rw_buf, PSTR("SG8F"), 4) == 0) {rc = PUBLISH_QUEUE_DISABLED;} 607 | else if(strncmp_P(rw_buf, PSTR("SGFF"), 4) == 0) {rc = SHADOW_GET_GENERIC_ERROR;} 608 | else rc = GENERIC_ERROR; 609 | } 610 | } 611 | else {rc = OUT_OF_SKETCH_SUBSCRIBE_MEMORY;} 612 | } 613 | return rc; 614 | } 615 | 616 | IoT_Error_t aws_iot_mqtt_client::shadow_update(const char* thingName, const char* payload, unsigned int payload_len, message_callback cb, unsigned int timeout) { 617 | IoT_Error_t rc = NONE_ERROR; 618 | if(thingName == NULL || payload == NULL) {rc = NULL_VALUE_ERROR;} 619 | else if(strlen(thingName) >= MAX_BUF_SIZE || payload_len >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 620 | else { 621 | // find unused slots for new subscribe 622 | int i = find_unused_subgroup(); 623 | if(i < MAX_SUB) { 624 | exec_cmd("5\n", false, false); 625 | 626 | exec_cmd("su\n", false, false); 627 | 628 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), thingName); 629 | exec_cmd(rw_buf, false, false); 630 | 631 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), payload); 632 | exec_cmd(rw_buf, false, false); 633 | 634 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), i); 635 | exec_cmd(rw_buf, false, false); 636 | 637 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), timeout); 638 | exec_cmd(rw_buf, true, false); 639 | 640 | if(strncmp_P(rw_buf, PSTR("SU T"), 4) == 0) { 641 | sub_group[i].is_used = true; 642 | sub_group[i].is_shadow_gud = true; 643 | sub_group[i].callback = cb; 644 | } 645 | else { 646 | if(strncmp_P(rw_buf, PSTR("SU1F"), 4) == 0) {rc = NO_SHADOW_INIT_ERROR;} 647 | else if(strncmp_P(rw_buf, PSTR("SU2F"), 4) == 0) {rc = WRONG_PARAMETER_ERROR;} 648 | else if(strncmp_P(rw_buf, PSTR("SU3F"), 4) == 0) {rc = SHADOW_UPDATE_INVALID_JSON_ERROR;} 649 | else if(strncmp_P(rw_buf, PSTR("SU4F"), 4) == 0) {rc = SUBSCRIBE_ERROR;} 650 | else if(strncmp_P(rw_buf, PSTR("SU5F"), 4) == 0) {rc = SUBSCRIBE_TIMEOUT;} 651 | else if(strncmp_P(rw_buf, PSTR("SU6F"), 4) == 0) {rc = PUBLISH_ERROR;} 652 | else if(strncmp_P(rw_buf, PSTR("SU7F"), 4) == 0) {rc = PUBLISH_TIMEOUT;} 653 | else if(strncmp_P(rw_buf, PSTR("SU8F"), 4) == 0) {rc = PUBLISH_QUEUE_FULL;} 654 | else if(strncmp_P(rw_buf, PSTR("SU9F"), 4) == 0) {rc = PUBLISH_QUEUE_DISABLED;} 655 | else if(strncmp_P(rw_buf, PSTR("SUFF"), 4) == 0) {rc = SHADOW_UPDATE_GENERIC_ERROR;} 656 | else rc = GENERIC_ERROR; 657 | } 658 | } 659 | else {rc = OUT_OF_SKETCH_SUBSCRIBE_MEMORY;} 660 | } 661 | return rc; 662 | } 663 | 664 | IoT_Error_t aws_iot_mqtt_client::shadow_delete(const char* thingName, message_callback cb, unsigned int timeout) { 665 | IoT_Error_t rc = NONE_ERROR; 666 | if(thingName == NULL) {rc = NULL_VALUE_ERROR;} 667 | else if(strlen(thingName) >= MAX_BUF_SIZE) {rc = OVERFLOW_ERROR;} 668 | else { 669 | // find unused slots for new subscribe 670 | int i = find_unused_subgroup(); 671 | if(i < MAX_SUB) { 672 | exec_cmd("4\n", false, false); 673 | 674 | exec_cmd("sd\n", false, false); 675 | 676 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), thingName); 677 | exec_cmd(rw_buf, false, false); 678 | 679 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), i); 680 | exec_cmd(rw_buf, false, false); 681 | 682 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), timeout); 683 | exec_cmd(rw_buf, true, false); 684 | if(strncmp_P(rw_buf, PSTR("SD T"), 4) == 0) { 685 | sub_group[i].is_used = true; 686 | sub_group[i].is_shadow_gud = true; 687 | sub_group[i].callback = cb; 688 | } 689 | else { 690 | if(strncmp_P(rw_buf, PSTR("SD1F"), 4) == 0) {rc = NO_SHADOW_INIT_ERROR;} 691 | else if(strncmp_P(rw_buf, PSTR("SD2F"), 4) == 0) {rc = WRONG_PARAMETER_ERROR;} 692 | else if(strncmp_P(rw_buf, PSTR("SD3F"), 4) == 0) {rc = SUBSCRIBE_ERROR;} 693 | else if(strncmp_P(rw_buf, PSTR("SD4F"), 4) == 0) {rc = SUBSCRIBE_TIMEOUT;} 694 | else if(strncmp_P(rw_buf, PSTR("SD5F"), 4) == 0) {rc = PUBLISH_ERROR;} 695 | else if(strncmp_P(rw_buf, PSTR("SD6F"), 4) == 0) {rc = PUBLISH_TIMEOUT;} 696 | else if(strncmp_P(rw_buf, PSTR("SD7F"), 4) == 0) {rc = PUBLISH_QUEUE_FULL;} 697 | else if(strncmp_P(rw_buf, PSTR("SD8F"), 4) == 0) {rc = PUBLISH_QUEUE_DISABLED;} 698 | else if(strncmp_P(rw_buf, PSTR("SDFF"), 4) == 0) {rc = SHADOW_DELETE_GENERIC_ERROR;} 699 | else rc = GENERIC_ERROR; 700 | } 701 | } 702 | else {rc = OUT_OF_SKETCH_SUBSCRIBE_MEMORY;} 703 | } 704 | return rc; 705 | } 706 | 707 | // Send a request for a certain value according to key names and JSON identifier 708 | // Value coming back will be stored in an external buffer as a string provided by the user 709 | // desired 710 | IoT_Error_t aws_iot_mqtt_client::getDesiredValueByKey(const char* JSONIdentifier, const char* key, char* externalJSONBuf, unsigned int bufSize) { 711 | return getJSONValueLoop(JSONIdentifier, key, externalJSONBuf, bufSize, DESIRED_SECTION); 712 | } 713 | 714 | // reported 715 | IoT_Error_t aws_iot_mqtt_client::getReportedValueByKey(const char* JSONIdentifier, const char* key, char* externalJSONBuf, unsigned int bufSize) { 716 | return getJSONValueLoop(JSONIdentifier, key, externalJSONBuf, bufSize, REPORTED_SECTION); 717 | } 718 | 719 | // delta 720 | IoT_Error_t aws_iot_mqtt_client::getDeltaValueByKey(const char* JSONIdentifier, const char* key, char* externalJSONBuf, unsigned int bufSize) { 721 | return getJSONValueLoop(JSONIdentifier, key, externalJSONBuf, bufSize, DELTA_SECTION); 722 | } 723 | 724 | // general 725 | IoT_Error_t aws_iot_mqtt_client::getValueByKey(const char* JSONIdentifier, const char* key, char* externalJSONBuf, unsigned int bufSize) { 726 | return getJSONValueLoop(JSONIdentifier, key, externalJSONBuf, bufSize, GENERAL_SECTION); 727 | } 728 | 729 | IoT_Error_t aws_iot_mqtt_client::getJSONValueLoop(const char* JSONIdentifier, const char* key, char* externalJSONBuf, unsigned int bufSize, KV_access_t accessType) { 730 | IoT_Error_t rc = NONE_ERROR; 731 | int chunk_cnt = 0; 732 | while(true) { 733 | exec_cmd("4\n", false, false); 734 | 735 | exec_cmd("j\n", false, false); 736 | 737 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), JSONIdentifier); 738 | exec_cmd(rw_buf, false, false); 739 | 740 | switch(accessType) { 741 | case DESIRED_SECTION: 742 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("state\"desired\"%s\n"), key); 743 | break; 744 | case REPORTED_SECTION: 745 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("state\"reported\"%s\n"), key); 746 | break; 747 | case DELTA_SECTION: 748 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("state\"%s\n"), key); 749 | break; 750 | case GENERAL_SECTION: 751 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), key); 752 | break; 753 | default: 754 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%s\n"), key); 755 | } 756 | exec_cmd(rw_buf, false, false); 757 | 758 | int isFirst = chunk_cnt == 0 ? 1 : 0; 759 | chunk_cnt++; 760 | if(isFirst == 1) {snprintf_P(externalJSONBuf, bufSize, PSTR("%s"), "");} // Clear the external buffer 761 | snprintf_P(rw_buf, MAX_BUF_SIZE, PSTR("%d\n"), isFirst); 762 | exec_cmd(rw_buf, true, false); 763 | 764 | if(strncmp_P(rw_buf, PSTR("J0F"), 3) == 0) {break;} // End of JSON value string transmission 765 | else if(strncmp_P(rw_buf, PSTR("J1F"), 3) == 0) { 766 | rc = NO_SET_UP_ERROR; 767 | break; 768 | } 769 | else if(strncmp_P(rw_buf, PSTR("J2F"), 3) == 0) { 770 | rc = JSON_FILE_NOT_FOUND; 771 | break; 772 | } 773 | else if(strncmp_P(rw_buf, PSTR("J3F"), 3) == 0) { 774 | rc = JSON_KEY_NOT_FOUND; 775 | break; 776 | } 777 | else if(strncmp_P(rw_buf, PSTR("JFF"), 3) == 0) { 778 | rc = JSON_GENERIC_ERROR; 779 | break; 780 | } 781 | else if(rw_buf[0] != 'J') { 782 | rc = GENERIC_ERROR; 783 | break; 784 | } 785 | // Accumulate the incoming JSON chunks below this line 786 | char* saveptr, *p; 787 | p = strtok_r(rw_buf, " ", &saveptr); // J 788 | p += (strlen(p) + 1); // Get the rest of the JSON chunk 789 | if(p != NULL) { 790 | if(strlen(p) + strlen(externalJSONBuf) > bufSize) { 791 | rc = OVERFLOW_ERROR; 792 | break; 793 | } 794 | else {strcat(externalJSONBuf, p);} // Concatinate the JSON value string 795 | } 796 | else { 797 | rc = JSON_GENERIC_ERROR; 798 | break; 799 | } 800 | } 801 | return rc; 802 | } 803 | 804 | // Exec command and get feedback into rw_buf 805 | void aws_iot_mqtt_client::exec_cmd(const char* cmd, bool wait, bool single_line) { 806 | // Write cmd 807 | int cnt = Serial1.write(cmd) + 1; 808 | timeout_flag = false; 809 | int timeout_sec = 0; 810 | // step1: forget the echo 811 | while(timeout_sec < CMD_TIME_OUT && cnt != 0) { 812 | if(Serial1.read() != -1) {cnt--;} 813 | else { // only start counting the timer when the serial1 is keeping us waiting... 814 | delay(5); // echo comes faster than python runtime client. Decreasing delay to avoid latency issue 815 | timeout_sec++; 816 | } 817 | } 818 | timeout_flag = timeout_sec == CMD_TIME_OUT; // Update timeout flag 819 | int ptr = 0; 820 | if(!timeout_flag) { // step 1 clear 821 | timeout_flag = false; 822 | timeout_sec = 0; 823 | // step2: waiting 824 | delay(6); 825 | if(wait) { 826 | while(timeout_sec < CMD_TIME_OUT && !Serial1.available()) { 827 | delay(50); // 50 ms 828 | timeout_sec++; 829 | } 830 | } 831 | timeout_flag = timeout_sec == CMD_TIME_OUT; // Update timeout flag 832 | if(!timeout_flag) { // step 2 clear 833 | // read feedback 834 | // will read all the available data in Serial1 but only store the message with the limit of MAX_BUF_SIZE 835 | bool stop_sign = false; 836 | while(Serial1.available()) { 837 | int cc = Serial1.read(); 838 | if(cc != -1) { 839 | if(cc == NEXTLINE_KEY || ptr == MAX_BUF_SIZE - 1) { 840 | stop_sign = true; 841 | if(single_line) {break;} 842 | } // end of feedback 843 | if(!stop_sign && cc != RETURN_KEY) { 844 | rw_buf[ptr++] = (char)cc; 845 | } 846 | } 847 | } 848 | } 849 | } 850 | timeout_flag = false; // Clear timeout flag 851 | rw_buf[ptr] = '\0'; // add terminator in case of garbage data in rw_buf 852 | } 853 | 854 | int aws_iot_mqtt_client::find_unused_subgroup() { 855 | int i = 0; 856 | for(i = 0; i < MAX_SUB; i++) { 857 | if(!sub_group[i].is_used) {break;} 858 | } 859 | return i; // could be MAX_SUB (Not found) 860 | } 861 | 862 | void aws_iot_mqtt_client::clearProtocolOnSerialBegin(long baudrate) { 863 | Serial1.begin(baudrate); 864 | while(!Serial1); 865 | exec_cmd("\n", true, false); // jump over the welcoming prompt for Open WRT 866 | delay(1000); // in case this is the first boot-up 867 | int i; 868 | for(i = 0; i < NUM_ATTEMPT_BEFORE_EXIT; i++) { 869 | // exit the previous python process and jump over the half-baked protocol communication 870 | exec_cmd("1\n", false, false); 871 | exec_cmd("~\n", true, false); 872 | } 873 | delay(1500); // delay 1500 ms for all related python script to exit 874 | } 875 | 876 | bool aws_iot_mqtt_client::is_num(char* src) { 877 | bool rc = true; 878 | if(src == NULL) {rc = false;} 879 | else { 880 | char* p = src; 881 | while(*p != '\0') { 882 | int currentCheck = (int)(*p); 883 | if(!isdigit(currentCheck)) { 884 | rc = false; 885 | break; 886 | } 887 | p++; 888 | } 889 | } 890 | return rc; 891 | } 892 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/aws_iot_mqtt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef aws_iot_mqtt_h 17 | #define aws_iot_mqtt_h 18 | 19 | #include "Arduino.h" 20 | #include "string.h" 21 | #include "aws_iot_config_SDK.h" 22 | #include "aws_iot_error.h" 23 | 24 | typedef enum { 25 | MQTTv31 = 3, 26 | MQTTv311 = 4 27 | } MQTTv_t; 28 | 29 | // Check baudrate 30 | typedef enum { 31 | BAUD_TYPE_UNKNOWN = -1, 32 | BAUD_TYPE_ARDUINO = 0, 33 | BAUD_TYPE_LININO = 1 34 | } Baud_t; 35 | 36 | // Callback message status 37 | typedef enum { 38 | STATUS_DEBUG = -1, 39 | STATUS_NORMAL = 0, 40 | STATUS_SHADOW_TIMEOUT = 1, 41 | STATUS_SHADOW_ACCEPTED = 2, 42 | STATUS_SHADOW_REJECTED = 3, 43 | STATUS_MESSAGE_OVERFLOW = 4 44 | } Message_status_t; 45 | 46 | // JSON key-value pair access type 47 | typedef enum { 48 | GENERAL_SECTION = 0, 49 | DESIRED_SECTION = 1, 50 | REPORTED_SECTION = 2, 51 | DELTA_SECTION = 3 52 | } KV_access_t; 53 | 54 | // PublishQueue Drop Behavior type 55 | typedef enum { 56 | DROP_OLDEST = 0, 57 | DROP_NEWEST = 1 58 | } DropBehavior_t; 59 | 60 | typedef void(*message_callback)(char*, unsigned int, Message_status_t); 61 | 62 | class aws_iot_mqtt_client { 63 | public: 64 | aws_iot_mqtt_client() { 65 | timeout_flag = false; 66 | memset(rw_buf, '\0', MAX_BUF_SIZE); 67 | memset(msg_buf, '\0', MAX_BUF_SIZE); 68 | int i; 69 | for(i = 0; i < MAX_SUB; i++) { 70 | sub_group[i].is_used = false; 71 | sub_group[i].is_shadow_gud = false; 72 | sub_group[i].callback = NULL; 73 | } 74 | } 75 | IoT_Error_t setup(const char* client_id, bool clean_session=true, MQTTv_t MQTT_version=MQTTv311, bool useWebsocket=false); 76 | IoT_Error_t config(const char* host, unsigned int port, const char* cafile_path, const char* keyfile_path, const char* certfile_path); 77 | IoT_Error_t configWss(const char* host, unsigned int port, const char* cafile_path); 78 | IoT_Error_t connect(unsigned int keepalive_interval=60); 79 | IoT_Error_t publish(const char* topic, const char* payload, unsigned int payload_len, unsigned int qos, bool retain); 80 | IoT_Error_t subscribe(const char* topic, unsigned int qos, message_callback cb); 81 | IoT_Error_t unsubscribe(const char* topic); 82 | IoT_Error_t yield(); 83 | IoT_Error_t disconnect(); 84 | // Device shadow support 85 | IoT_Error_t shadow_init(const char* thingName); 86 | IoT_Error_t shadow_update(const char* thingName, const char* payload, unsigned int payload_len, message_callback cb, unsigned int timeout); 87 | IoT_Error_t shadow_get(const char* thingName, message_callback cb, unsigned int timeout); 88 | IoT_Error_t shadow_delete(const char* thingName, message_callback cb, unsigned int timeout); 89 | IoT_Error_t shadow_register_delta_func(const char* thingName, message_callback cb); 90 | IoT_Error_t shadow_unregister_delta_func(const char* thingName); 91 | // JSON key-value-pair access 92 | IoT_Error_t getDesiredValueByKey(const char* JSONIdentifier, const char* key, char* externalJSONBuf, unsigned int bufSize); 93 | IoT_Error_t getReportedValueByKey(const char* JSONIdentifier, const char* key, char* externalJSONBuf, unsigned int bufSize); 94 | IoT_Error_t getDeltaValueByKey(const char* JSONIdentifier, const char* key, char* externalJSONBuf, unsigned int bufSize); 95 | IoT_Error_t getValueByKey(const char* JSONIdentifier, const char* key, char* externalJSONBuf, unsigned int bufSize); 96 | // Progressive backoff configuration 97 | IoT_Error_t configBackoffTiming(unsigned int baseReconnectQuietTimeSecond, unsigned int maxReconnectQuietTimeSecond, unsigned int stableConnectionTimeSecond); 98 | // Offline publish queue configuration 99 | IoT_Error_t configOfflinePublishQueue(unsigned int queueSize, DropBehavior_t behavior); 100 | // Draining interval configuration 101 | IoT_Error_t configDrainingInterval(float numberOfSeconds); 102 | 103 | private: 104 | typedef struct { 105 | bool is_used; 106 | bool is_shadow_gud; // if this is a shadow get/update/delete request 107 | message_callback callback; 108 | } mqtt_sub_element; 109 | char rw_buf[MAX_BUF_SIZE]; 110 | char msg_buf[MAX_BUF_SIZE]; // To store message chunks 111 | mqtt_sub_element sub_group[MAX_SUB]; 112 | bool timeout_flag; // Is there a timeout when executing RPC 113 | Baud_t find_baud_type(); 114 | IoT_Error_t getJSONValueLoop(const char* JSONIdentifier, const char* key, char* externalJSONBuf, unsigned int bufSize, KV_access_t accessType); 115 | IoT_Error_t setup_exec(const char* client_id, bool clean_session, MQTTv_t MQTT_version, bool useWebsocket); 116 | void exec_cmd(const char* cmd, bool wait, bool single_line); 117 | int find_unused_subgroup(); 118 | void clearProtocolOnSerialBegin(long baudrate); 119 | bool is_num(char* src); 120 | }; 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/aws_iot_version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef version_h 17 | #define version_h 18 | 19 | #define VERSION_MAJOR 2 20 | #define VERSION_MINOR 2 21 | #define VERSION_PATCH 0 22 | #define VERSION_TAG "" 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/examples/BasicPubSub/BasicPubSub.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include "aws_iot_config.h" 19 | 20 | aws_iot_mqtt_client myClient; // init iot_mqtt_client 21 | char msg[32]; // read-write buffer 22 | int cnt = 0; // loop counts 23 | int rc = -100; // return value placeholder 24 | bool success_connect = false; // whether it is connected 25 | 26 | // Basic callback function that prints out the message 27 | void msg_callback(char* src, unsigned int len, Message_status_t flag) { 28 | if(flag == STATUS_NORMAL) { 29 | Serial.println("CALLBACK:"); 30 | int i; 31 | for(i = 0; i < (int)(len); i++) { 32 | Serial.print(src[i]); 33 | } 34 | Serial.println(""); 35 | } 36 | } 37 | 38 | void setup() { 39 | // Start Serial for print-out and wait until it's ready 40 | Serial.begin(115200); 41 | while(!Serial); 42 | // 43 | char curr_version[80]; 44 | snprintf_P(curr_version, 80, PSTR("AWS IoT SDK Version(dev) %d.%d.%d-%s\n"), VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG); 45 | Serial.println(curr_version); 46 | // Set up the client 47 | if((rc = myClient.setup(AWS_IOT_CLIENT_ID)) == 0) { 48 | // Load user configuration 49 | if((rc = myClient.config(AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT, AWS_IOT_ROOT_CA_PATH, AWS_IOT_PRIVATE_KEY_PATH, AWS_IOT_CERTIFICATE_PATH)) == 0) { 50 | // Use default connect: 60 sec for keepalive 51 | if((rc = myClient.connect()) == 0) { 52 | success_connect = true; 53 | // Subscribe to "topic1" 54 | if((rc = myClient.subscribe("topic1", 1, msg_callback)) != 0) { 55 | Serial.println("Subscribe failed!"); 56 | Serial.println(rc); 57 | } 58 | } 59 | else { 60 | Serial.println(F("Connect failed!")); 61 | Serial.println(rc); 62 | } 63 | } 64 | else { 65 | Serial.println(F("Config failed!")); 66 | Serial.println(rc); 67 | } 68 | } 69 | else { 70 | Serial.println(F("Setup failed!")); 71 | Serial.println(rc); 72 | } 73 | // Delay to make sure SUBACK is received, delay time could vary according to the server 74 | delay(2000); 75 | } 76 | 77 | void loop() { 78 | if(success_connect) { 79 | // Generate a new message in each loop and publish to "topic1" 80 | sprintf(msg, "new message %d", cnt); 81 | if((rc = myClient.publish("topic1", msg, strlen(msg), 1, false)) != 0) { 82 | Serial.println(F("Publish failed!")); 83 | Serial.println(rc); 84 | } 85 | 86 | // Get a chance to run a callback 87 | if((rc = myClient.yield()) != 0) { 88 | Serial.println("Yield failed!"); 89 | Serial.println(rc); 90 | } 91 | 92 | // Done with the current loop 93 | sprintf_P(msg, PSTR("loop %d done"), cnt++); 94 | Serial.println(msg); 95 | 96 | delay(1000); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/examples/BasicPubSub/aws_iot_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef config_usr_h 17 | #define config_usr_h 18 | 19 | // Copy and paste your configuration into this file 20 | //=============================================================== 21 | #define AWS_IOT_MQTT_HOST "" // your endpoint 22 | #define AWS_IOT_MQTT_PORT 8883 // your port 23 | #define AWS_IOT_CLIENT_ID "My_ClientID" // your client ID 24 | #define AWS_IOT_MY_THING_NAME "My_Board" // your thing name 25 | #define AWS_IOT_ROOT_CA_FILENAME "aws-iot-rootCA.crt" // your root-CA filename 26 | #define AWS_IOT_CERTIFICATE_FILENAME "cert.pem" // your certificate filename 27 | #define AWS_IOT_PRIVATE_KEY_FILENAME "privkey.pem" // your private key filename 28 | //=============================================================== 29 | // SDK config, DO NOT modify it 30 | #define AWS_IOT_PATH_PREFIX "../certs/" 31 | #define AWS_IOT_ROOT_CA_PATH AWS_IOT_PATH_PREFIX AWS_IOT_ROOT_CA_FILENAME // use this in config call 32 | #define AWS_IOT_CERTIFICATE_PATH AWS_IOT_PATH_PREFIX AWS_IOT_CERTIFICATE_FILENAME // use this in config call 33 | #define AWS_IOT_PRIVATE_KEY_PATH AWS_IOT_PATH_PREFIX AWS_IOT_PRIVATE_KEY_FILENAME // use this in config call 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/examples/ThermostatSimulatorDevice/ThermostatSimulatorDevice.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include "aws_iot_config.h" 19 | 20 | aws_iot_mqtt_client myClient; 21 | char JSON_buf[50]; 22 | char float_buf[5]; 23 | float reportedTemp = 70.0; 24 | float desiredTemp = 70.0; 25 | int cnt = 0; 26 | int rc = 1; 27 | bool success_connect = false; 28 | 29 | bool print_log(const char* src, int code) { 30 | bool ret = true; 31 | if(code == 0) { 32 | #ifdef AWS_IOT_DEBUG 33 | Serial.print(F("[LOG] command: ")); 34 | Serial.print(src); 35 | Serial.println(F(" completed.")); 36 | #endif 37 | ret = true; 38 | } 39 | else { 40 | #ifdef AWS_IOT_DEBUG 41 | Serial.print(F("[ERR] command: ")); 42 | Serial.print(src); 43 | Serial.print(F(" code: ")); 44 | Serial.println(code); 45 | #endif 46 | ret = false; 47 | } 48 | Serial.flush(); 49 | return ret; 50 | } 51 | 52 | void msg_callback_delta(char* src, unsigned int len, Message_status_t flag) { 53 | if(flag == STATUS_NORMAL) { 54 | // Get Temp section in delta messages 55 | print_log("getDeltaKeyValue", myClient.getDeltaValueByKey(src, "Temp", JSON_buf, 50)); 56 | desiredTemp = String(JSON_buf).toFloat(); 57 | } 58 | } 59 | 60 | void setup() { 61 | Serial.begin(115200); 62 | while(!Serial); 63 | 64 | char curr_version[80]; 65 | snprintf_P(curr_version, 80, PSTR("AWS IoT SDK Version(dev) %d.%d.%d-%s\n"), VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG); 66 | Serial.println(curr_version); 67 | 68 | if(print_log("setup", myClient.setup(AWS_IOT_CLIENT_ID))) { 69 | if(print_log("config", myClient.config(AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT, AWS_IOT_ROOT_CA_PATH, AWS_IOT_PRIVATE_KEY_PATH, AWS_IOT_CERTIFICATE_PATH))) { 70 | if(print_log("connect", myClient.connect())) { 71 | success_connect = true; 72 | print_log("shadow init", myClient.shadow_init(AWS_IOT_MY_THING_NAME)); 73 | print_log("register thing shadow delta function", myClient.shadow_register_delta_func(AWS_IOT_MY_THING_NAME, msg_callback_delta)); 74 | } 75 | } 76 | } 77 | } 78 | 79 | void loop() { 80 | if(success_connect) { 81 | // If the desired temperature is set to a higher value, start heating. 82 | if(desiredTemp - reportedTemp > 0.001) {reportedTemp += 0.1;} 83 | // If the desired temperature is set to a lower value, start cooling. 84 | else if(reportedTemp - desiredTemp > 0.001) {reportedTemp -= 0.1;} 85 | dtostrf(reportedTemp, 4, 1, float_buf); 86 | float_buf[4] = '\0'; 87 | sprintf_P(JSON_buf, PSTR("{\"state\":{\"reported\":{\"Temp\":%s}}}"), float_buf); 88 | print_log("shadow update", myClient.shadow_update(AWS_IOT_MY_THING_NAME, JSON_buf, strlen(JSON_buf), NULL, 5)); 89 | if(myClient.yield()) { 90 | Serial.println("Yield failed."); 91 | } 92 | delay(1000); // check for incoming delta per 1000 ms 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/examples/ThermostatSimulatorDevice/aws_iot_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef config_usr_h 17 | #define config_usr_h 18 | 19 | // Copy and paste your configuration into this file 20 | //=============================================================== 21 | #define AWS_IOT_MQTT_HOST "" // your endpoint 22 | #define AWS_IOT_MQTT_PORT 8883 // your port 23 | #define AWS_IOT_CLIENT_ID "My_ClientID" // your client ID 24 | #define AWS_IOT_MY_THING_NAME "room" // your thing name 25 | #define AWS_IOT_ROOT_CA_FILENAME "aws-iot-rootCA.crt" // your root-CA filename 26 | #define AWS_IOT_CERTIFICATE_FILENAME "certificate.pem.crt" // your certificate filename 27 | #define AWS_IOT_PRIVATE_KEY_FILENAME "private.pem.key" // your private key filename 28 | #define AWS_IOT_DEBUG // Enable debug logging. Remove it if you want to disable it. 29 | //=============================================================== 30 | // SDK config, DO NOT modify it 31 | #define AWS_IOT_PATH_PREFIX "../certs/" 32 | #define AWS_IOT_ROOT_CA_PATH AWS_IOT_PATH_PREFIX AWS_IOT_ROOT_CA_FILENAME // use this in config call 33 | #define AWS_IOT_CERTIFICATE_PATH AWS_IOT_PATH_PREFIX AWS_IOT_CERTIFICATE_FILENAME // use this in config call 34 | #define AWS_IOT_PRIVATE_KEY_PATH AWS_IOT_PATH_PREFIX AWS_IOT_PRIVATE_KEY_FILENAME // use this in config call 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/examples/ThingShadowEcho/ThingShadowEcho.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #include 17 | #include 18 | #include "aws_iot_config.h" 19 | 20 | aws_iot_mqtt_client myClient; 21 | char JSON_buf[100]; 22 | int cnt = 0; 23 | int rc = 1; 24 | bool success_connect = false; 25 | 26 | bool print_log(const char* src, int code) { 27 | bool ret = true; 28 | if(code == 0) { 29 | #ifdef AWS_IOT_DEBUG 30 | Serial.print(F("[LOG] command: ")); 31 | Serial.print(src); 32 | Serial.println(F(" completed.")); 33 | #endif 34 | ret = true; 35 | } 36 | else { 37 | #ifdef AWS_IOT_DEBUG 38 | Serial.print(F("[ERR] command: ")); 39 | Serial.print(src); 40 | Serial.print(F(" code: ")); 41 | Serial.println(code); 42 | #endif 43 | ret = false; 44 | } 45 | Serial.flush(); 46 | return ret; 47 | } 48 | 49 | void msg_callback_delta(char* src, unsigned int len, Message_status_t flag) { 50 | if(flag == STATUS_NORMAL) { 51 | // Get the whole delta section 52 | print_log("getDeltaKeyValue", myClient.getDeltaValueByKey(src, "", JSON_buf, 100)); 53 | String payload = "{\"state\":{\"reported\":"; 54 | payload += JSON_buf; 55 | payload += "}}"; 56 | payload.toCharArray(JSON_buf, 100); 57 | print_log("update thing shadow", myClient.shadow_update(AWS_IOT_MY_THING_NAME, JSON_buf, strlen(JSON_buf), NULL, 5)); 58 | } 59 | } 60 | 61 | void setup() { 62 | Serial.begin(115200); 63 | while(!Serial); 64 | 65 | char curr_version[80]; 66 | snprintf_P(curr_version, 80, PSTR("AWS IoT SDK Version(dev) %d.%d.%d-%s\n"), VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG); 67 | Serial.println(curr_version); 68 | 69 | if(print_log("setup", myClient.setup(AWS_IOT_CLIENT_ID))) { 70 | if(print_log("config", myClient.config(AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT, AWS_IOT_ROOT_CA_PATH, AWS_IOT_PRIVATE_KEY_PATH, AWS_IOT_CERTIFICATE_PATH))) { 71 | if(print_log("connect", myClient.connect())) { 72 | success_connect = true; 73 | print_log("shadow init", myClient.shadow_init(AWS_IOT_MY_THING_NAME)); 74 | print_log("register thing shadow delta function", myClient.shadow_register_delta_func(AWS_IOT_MY_THING_NAME, msg_callback_delta)); 75 | } 76 | } 77 | } 78 | } 79 | 80 | void loop() { 81 | if(success_connect) { 82 | if(myClient.yield()) { 83 | Serial.println(F("Yield failed.")); 84 | } 85 | delay(1000); // check for incoming delta per 100 ms 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/examples/ThingShadowEcho/aws_iot_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef config_usr_h 17 | #define config_usr_h 18 | 19 | // Copy and paste your configuration into this file 20 | //=============================================================== 21 | #define AWS_IOT_MQTT_HOST "" // your endpoint 22 | #define AWS_IOT_MQTT_PORT 8883 // your port 23 | #define AWS_IOT_CLIENT_ID "My_ClientID" // your client ID 24 | #define AWS_IOT_MY_THING_NAME "My_Board" // your thing name 25 | #define AWS_IOT_ROOT_CA_FILENAME "aws-iot-rootCA.crt" // your root-CA filename 26 | #define AWS_IOT_CERTIFICATE_FILENAME "cert.pem" // your certificate filename 27 | #define AWS_IOT_PRIVATE_KEY_FILENAME "privkey.pem" // your private key filename 28 | #define AWS_IOT_DEBUG // Enable debug logging. Remove it if you want to disable it. 29 | //=============================================================== 30 | // SDK config, DO NOT modify it 31 | #define AWS_IOT_PATH_PREFIX "../certs/" 32 | #define AWS_IOT_ROOT_CA_PATH AWS_IOT_PATH_PREFIX AWS_IOT_ROOT_CA_FILENAME // use this in config call 33 | #define AWS_IOT_CERTIFICATE_PATH AWS_IOT_PATH_PREFIX AWS_IOT_CERTIFICATE_FILENAME // use this in config call 34 | #define AWS_IOT_PRIVATE_KEY_PATH AWS_IOT_PATH_PREFIX AWS_IOT_PRIVATE_KEY_FILENAME // use this in config call 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /AWS-IoT-Arduino-Yun-Library/keywords.txt: -------------------------------------------------------------------------------- 1 | aws_iot_mqtt KEYWORD1 2 | aws_iot_mqtt_client KEYWORD1 3 | aws_iot_version KEYWORD1 4 | aws_iot_config KEYWORD1 5 | setup KEYWORD2 6 | config KEYWORD2 7 | configWss KEYWORD2 8 | connect KEYWORD2 9 | publish KEYWORD2 10 | subscribe KEYWORD2 11 | unsubscribe KEYWORD2 12 | disconnect KEYWORD2 13 | yield KEYWORD2 14 | shadow_init KEYWORD2 15 | shadow_register_delta_func KEYWORD2 16 | shadow_unregister_delta_func KEYWORD2 17 | shadow_get KEYWORD2 18 | shadow_update KEYWORD2 19 | shadow_delete KEYWORD2 20 | getDesiredValueByKey KEYWORD2 21 | getReportedValueByKey KEYWORD2 22 | getDeltaValueByKey KEYWORD2 23 | getValueByKey KEYWORD2 24 | configBackoffTiming KEYWORD2 25 | configOfflinePublishQueue KEYWORD2 26 | configDrainingInterval KEYWORD2 27 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/certs/delete.me: -------------------------------------------------------------------------------- 1 | Please place your credentials in this directory. 2 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/comm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-iot-device-sdk-arduino-yun/cfc29219a6d3ae63779fdd024c38747d091a0654/AWS-IoT-Python-Runtime/lib/comm/__init__.py -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/comm/communicationServer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | 19 | # Base class of communicationServer that handles message traffic across a certain type of tunnel (Socket/Serial bridge) 20 | class communicationServer: 21 | def __init__(self): 22 | pass 23 | 24 | # Accept a message from the other side of the tunnel 25 | def accept(self): 26 | pass 27 | 28 | # Other server object writes to the internal buffer of communicationServer 29 | def writeToInternal(self, srcContent): 30 | pass 31 | 32 | # Upon a remote request, communicationServer write whatever is in the internal buffer to the remote client 33 | def writeToExternal(self): 34 | pass 35 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/comm/serialCommunicationServer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import sys 19 | sys.path.insert(0, "../lib/util/") 20 | sys.path.insert(0, "../lib/exception/") 21 | import communicationServer 22 | import AWSIoTExceptions 23 | import Queue 24 | import signal 25 | import logging 26 | 27 | 28 | class serialCommunicationServer(communicationServer.communicationServer): 29 | 30 | def __init__(self): 31 | self._log = logging.getLogger(__name__) 32 | self._protocolMessageQueue = Queue.Queue(0) 33 | self._yieldMessageQueue = Queue.Queue(0) 34 | self._jsonBuf = "" 35 | self._txBuf = "" 36 | self._acceptTimeout = 0 # Never timeout 37 | self._chunkSize = 50 # Biggest chunk of data that can be sent over serial1 38 | self._returnList = [] 39 | self._currentElementOut = "" # Retained message that needs to be sent out in chunks 40 | self._lockedQueueSize = 0 # Number of messages to be transmitted in this yield 41 | # Register timeout signal handler 42 | signal.signal(signal.SIGALRM, self._timeoutHandler) 43 | signal.alarm(0) # disable SIGALRM 44 | self._log.debug("Register timeout signal handler.") 45 | self._log.debug("serialCommunicationServer init.") 46 | 47 | def _timeoutHandler(self, signal, frame): 48 | self._log.debug("Raise a custom exception for accept timeout.") 49 | raise AWSIoTExceptions.acceptTimeoutException() 50 | 51 | def _basicInput(self): 52 | return raw_input() 53 | 54 | def _basicOutput(self, srcContent): 55 | print(srcContent) 56 | 57 | def setAcceptTimeout(self, srcTimeout): 58 | self._acceptTimeout = srcTimeout 59 | self._log.debug("serialCommunicationServer set accept timeout to " + str(self._acceptTimeout)) 60 | 61 | def getChunkSize(self): 62 | return self._chunkSize 63 | 64 | def setChunkSize(self, srcChunkSize): 65 | self._chunkSize = srcChunkSize 66 | self._log.debug("serialCommunicationServer set chunk size to " + str(self._chunkSize)) 67 | 68 | def updateLockedQueueSize(self): 69 | self._lockedQueueSize = self._yieldMessageQueue.qsize() 70 | 71 | def getLockedQueueSize(self): 72 | return self._lockedQueueSize 73 | 74 | def accept(self): 75 | # Messages are passed from remote client to server line by line 76 | # A number representing the number of lines to receive will be passed first 77 | # Then serialCommunicationServer should loop the exact time to receive the following lines 78 | # All these reads add up tp ONE timeout: acceptTimeout. Once exceeded, this timeout will trigger a callback raising an exception 79 | # Throw acceptTimeoutException, ValueError 80 | # Store the incoming parameters into an internal data structure 81 | self._returnList = [] 82 | self._log.debug("Clear internal list. Size: " + str(len(self._returnList))) 83 | signal.alarm(self._acceptTimeout) # Enable SIGALRM 84 | self._log.debug("Accept-timer starts, with acceptTimeout: " + str(self._acceptTimeout) + " second(s).") 85 | numLines = int(self._basicInput()) # Get number of lines to receive 86 | self._log.debug(str(numLines) + " lines to be received. Loop begins.") 87 | loopCount = 1 88 | while(loopCount <= numLines): 89 | currElementIn = self._basicInput() 90 | self._returnList.append(currElementIn) 91 | self._log.debug("Received: " + str(loopCount) + "/" + str(numLines) + " Message is: " + currElementIn) 92 | loopCount += 1 93 | signal.alarm(0) # Finish reading from remote client, disable SIGALRM 94 | self._log.debug("Finish reading from remote client. Accept-timer ends.") 95 | return self._returnList 96 | 97 | def writeToInternalProtocol(self, srcContent): 98 | self._protocolMessageQueue.put(srcContent) 99 | self._log.debug("Updated serialCommunicationServer internal protocolMessageQueue by inserting a new message. Size: " + str(self._protocolMessageQueue.qsize())) 100 | 101 | def writeToInternalYield(self, srcContent): 102 | self._yieldMessageQueue.put(srcContent) 103 | self._log.debug("Updated serialCommunicationServer internal yieldMessageQueue by inserting a new message. Size: " + str(self._yieldMessageQueue.qsize())) 104 | 105 | def writeToInternalJSON(self, srcContent): 106 | self._jsonBuf = srcContent 107 | self._log.debug("Updated serialCommunicationServer internal json buffer with a new JSON payload of size: " + str(len(self._jsonBuf))) 108 | 109 | def writeToExternalYield(self): 110 | # Write ONE chunk to the remote client 111 | # If no retained chunks, pick ONE new message from the given messageQueue and start again 112 | # Messages in the internal messageQueue should be well-formated for yield messages, serialCommunicationServer will do nothing to format it 113 | if self._lockedQueueSize > 0 or self._currentElementOut != "": 114 | if self._currentElementOut == "": # No more chunks left for current retained? 115 | self._currentElementOut = self._yieldMessageQueue.get() 116 | self._lockedQueueSize -= 1 117 | self._log.debug("Start sending a new message to remote client: " + self._currentElementOut) 118 | self._txBuf = self._currentElementOut[0:self._chunkSize] 119 | self._basicOutput(self._txBuf) 120 | self._log.debug("Send through serial to remote client. Chunk: " + self._txBuf + " Size: " + str(len(self._txBuf))) 121 | self._currentElementOut = self._currentElementOut[self._chunkSize:] 122 | else: 123 | self._basicOutput("Y F: No messages.") 124 | self._log.debug("No more messages for yield. Exiting writeToExternalYield.") 125 | 126 | def writeToExternalProtocol(self): 127 | # Wrapper for protocol serial communitation 128 | if not self._protocolMessageQueue.empty(): 129 | thisProtocolMessage = self._protocolMessageQueue.get() 130 | self._basicOutput(thisProtocolMessage) 131 | self._log.debug("Send through serial to remote client: " + thisProtocolMessage + " Size: " + str(len(thisProtocolMessage))) 132 | else: 133 | self._log.debug("No protocol messages available. Exiting writeToExternalProtocol.") 134 | 135 | def writeToExternalJSON(self): 136 | # Wrapper for JSON serial communication 137 | # Only ONE JSON payload will be tracked, this method will be called in a loop util there is not more chunks for THIS payload 138 | if self._jsonBuf != "": 139 | self._txBuf = self._jsonBuf[0:self._chunkSize] 140 | self._basicOutput(self._txBuf) 141 | self._log.debug("JSON: Send through serial to remote client. Chunk: " + self._txBuf + " Size: " + str(len(self._txBuf))) 142 | self._jsonBuf = self._jsonBuf[self._chunkSize:] 143 | else: 144 | self._basicOutput("J0F: No JSON chunks.") 145 | self._log.debug("No more chunks for this JSON payload. Exiting writeToExternalJSON.") 146 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/AWSIoTCommand.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | 19 | class AWSIoTCommand: 20 | 21 | def __init__(self, srcCommandProtocolName="x"): 22 | self._commandProtocolName = srcCommandProtocolName 23 | self._parameterList = [] 24 | self._serialCommServerHandler = None 25 | self._desiredNumberOfParameters = 0 26 | self._initSuccess = True 27 | 28 | def _validateCommand(self): 29 | if self._parameterList is None: 30 | return False 31 | else: 32 | return len(self._parameterList) == self._desiredNumberOfParameters 33 | 34 | def getCommandProtocolName(self): 35 | return self._commandProtocolName 36 | 37 | def setInitSuccess(self, src): 38 | self._initSuccess = src 39 | 40 | def getInitSuccess(self): 41 | return self._initSuccess 42 | 43 | def execute(self): 44 | pass 45 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-iot-device-sdk-arduino-yun/cfc29219a6d3ae63779fdd024c38747d091a0654/AWS-IoT-Python-Runtime/lib/command/__init__.py -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandConfig.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | 20 | 21 | class commandConfig(AWSIoTCommand.AWSIoTCommand): 22 | # Target API: 23 | # AWSIoTMQTTShadowClient.configureEndpoint(srcHost, srcPort) 24 | # AWSIoTMQTTShadowClient.configureCredentials(srcCAFile, srcKey, srcCert) 25 | 26 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcShadowClient): 27 | self._commandProtocolName = "g" 28 | self._parameterList = srcParameterList 29 | self._serialCommServerHandler = srcSerialCommuteServer 30 | self._shadowClientHandler = srcShadowClient 31 | self._desiredNumberOfParameters = 5 32 | 33 | def _validateCommand(self): 34 | ret = self._shadowClientHandler is not None and self._serialCommServerHandler is not None 35 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 36 | 37 | def execute(self): 38 | returnMessage = "G T" 39 | if not self._validateCommand(): 40 | returnMessage = "G1F: " + "No setup." 41 | else: 42 | try: 43 | self._shadowClientHandler.configureEndpoint(self._parameterList[0], int(self._parameterList[1])) 44 | self._shadowClientHandler.configureCredentials(self._parameterList[2], self._parameterList[3], self._parameterList[4]) 45 | except TypeError as e: 46 | returnMessage = "G2F: " + str(e.message) 47 | except Exception as e: 48 | returnMessage = "GFF: " + "Unknown error." 49 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 50 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandConnect.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | from ssl import SSLError 20 | from core.exception.AWSIoTExceptions import connectError 21 | from core.exception.AWSIoTExceptions import connectTimeoutException 22 | 23 | 24 | class commandConnect(AWSIoTCommand.AWSIoTCommand): 25 | # Target API: AWSIoTMQTTShadowClient.connect(keepAliveInterval) 26 | 27 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcShadowClient): 28 | self._commandProtocolName = "c" 29 | self._parameterList = srcParameterList 30 | self._serialCommServerHandler = srcSerialCommuteServer 31 | self._shadowClientHandler = srcShadowClient 32 | self._desiredNumberOfParameters = 1 33 | 34 | def _validateCommand(self): 35 | ret = self._shadowClientHandler is not None and self._serialCommServerHandler is not None 36 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 37 | 38 | def execute(self): 39 | returnMessage = "C T" 40 | if not self._validateCommand(): 41 | returnMessage = "C1F: " + "No setup." 42 | else: 43 | try: 44 | self._shadowClientHandler.connect(int(self._parameterList[0])) 45 | except TypeError as e: 46 | returnMessage = "C2F: " + str(e.message) 47 | except SSLError as e: 48 | returnMessage = "C3F: " + "Mutual Auth issues." 49 | except connectError as e: 50 | returnMessage = "C4F: " + str(e.message) 51 | except connectTimeoutException as e: 52 | returnMessage = "C5F: " + str(e.message) 53 | except IOError as e: 54 | returnMessage = "C6F: " + "Credentials not found." 55 | except ValueError as e: 56 | returnMessage = "C7F: " + "Key/KeyID not in $ENV." 57 | except Exception as e: 58 | returnMessage = "CFF: " + "Unknown error." 59 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 60 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandDisconnect.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | from core.exception.AWSIoTExceptions import disconnectError 20 | from core.exception.AWSIoTExceptions import disconnectTimeoutException 21 | 22 | 23 | class commandDisconnect(AWSIoTCommand.AWSIoTCommand): 24 | # Target API: AWSIoTMQTTShadowClient.disconnect() 25 | 26 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcShadowClient): 27 | self._commandProtocolName = "d" 28 | self._parameterList = srcParameterList 29 | self._serialCommServerHandler = srcSerialCommuteServer 30 | self._shadowClientHandler = srcShadowClient 31 | self._desiredNumberOfParameters = 0 32 | 33 | def _validateCommand(self): 34 | ret = self._shadowClientHandler is not None and self._serialCommServerHandler is not None 35 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 36 | 37 | def execute(self): 38 | returnMessage = "D T" 39 | if not self._validateCommand(): 40 | returnMessage = "D1F: " + "No setup." 41 | else: 42 | try: 43 | self._shadowClientHandler.disconnect() 44 | except disconnectError as e: 45 | returnMessage = "D2F: " + str(e.message) 46 | except disconnectTimeoutException as e: 47 | returnMessage = "D3F: " + str(e.message) 48 | except Exception as e: 49 | returnMessage = "DFF: " + "Unknown error." 50 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 51 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandJSONKeyVal.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | 20 | 21 | class commandJSONKeyVal(AWSIoTCommand.AWSIoTCommand): 22 | # Target API: getDesired/ReportedValueByKey(JSONIdentifier, key, externalJSONBuf, bufSize) 23 | # Parameter list: 24 | 25 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcJSONManager): 26 | self._commandProtocolName = "j" 27 | self._parameterList = srcParameterList 28 | self._serialCommuteServerHandler = srcSerialCommuteServer 29 | self._jsonManagerHandler = srcJSONManager 30 | self._desiredNumberOfParameters = 3 31 | 32 | def _validateCommand(self): 33 | ret = self._serialCommuteServerHandler is not None 34 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 35 | 36 | def _formatValueIntoChunks(self, srcValue): 37 | # J 38 | # Generate the meta data 39 | metaData = "J " 40 | # Get configured chunk size 41 | configuredChunkSize = self._serialCommuteServerHandler.getChunkSize() 42 | # Divide the payload into smaller chunks plus meta data 43 | messageChunkSize = configuredChunkSize - len(metaData) 44 | chunks = [metaData + srcValue[i:i + messageChunkSize] for i in range(0, len(srcValue), messageChunkSize)] 45 | # Concat them together 46 | return "".join(chunks) 47 | 48 | def execute(self): 49 | returnMessage = "J T" # Placeholder for a successful RPC 50 | if not self._validateCommand(): 51 | returnMessage = "J1F: No setup." 52 | else: 53 | try: 54 | # Check to see if this is the first get JSON command 55 | if self._parameterList[2] == '1': 56 | # If it is, load in a new JSON payload using the provided identifier/key information 57 | JSONWanted = self._jsonManagerHandler.retrieveJSONByKey(self._parameterList[0]) 58 | if JSONWanted is not None: 59 | ValueWanted = self._jsonManagerHandler.getValueByKeyInJSON(JSONWanted, self._parameterList[1]) 60 | if ValueWanted is not None: 61 | # Format the ValueWanted into chunks 62 | ValueWantedFormatted = self._formatValueIntoChunks(ValueWanted) 63 | returnMessage = ValueWantedFormatted 64 | else: 65 | returnMessage = "J3F: " + "No such key." 66 | # If not, this is a chunk-wise communication from the previous JSON payload 67 | # Do nothing 68 | else: 69 | returnMessage = "J2F: " + "No such JSON identifier." 70 | except Exception: 71 | returnMessage = "JFF: " + "Unknown error." 72 | if self._parameterList[2] == '1': 73 | self._serialCommuteServerHandler.writeToInternalJSON(returnMessage) 74 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandLockSize.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | 20 | 21 | class commandLockSize(AWSIoTCommand.AWSIoTCommand): 22 | # Target API: None 23 | 24 | def __init__(self, srcParameterList, srcSerialCommuteServer): 25 | self._commandProtocolName = "z" 26 | self._parameterList = srcParameterList 27 | self._serialCommServerHandler = srcSerialCommuteServer 28 | self._desiredNumberOfParameters = 0 29 | 30 | def _validateCommand(self): 31 | ret = self._serialCommServerHandler is not None 32 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 33 | 34 | def execute(self): 35 | returnMessage = "Z T" 36 | if not self._validateCommand(): 37 | returnMessage = "Z F: " + "Invalid information." 38 | else: 39 | try: 40 | self._serialCommServerHandler.updateLockedQueueSize() 41 | except Exception as e: 42 | returnMessage = "Z F: " + "Unknown Error " + str(type(e)) 43 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 44 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandPublish.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | from core.exception.AWSIoTExceptions import publishError 20 | from core.exception.AWSIoTExceptions import publishTimeoutException 21 | from core.exception.AWSIoTExceptions import publishQueueFullException 22 | from core.exception.AWSIoTExceptions import publishQueueDisabledException 23 | 24 | 25 | class commandPublish(AWSIoTCommand.AWSIoTCommand): 26 | # Target API: AWSIoTMQTTClient.publish(topic, payload, qos) 27 | 28 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcMQTTCore): 29 | self._commandProtocolName = "p" 30 | self._parameterList = srcParameterList 31 | self._serialCommServerHandler = srcSerialCommuteServer 32 | self._mqttCoreHandler = srcMQTTCore 33 | self._desiredNumberOfParameters = 4 34 | 35 | def _validateCommand(self): 36 | ret = self._mqttCoreHandler is not None and self._serialCommServerHandler is not None 37 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 38 | 39 | def execute(self): 40 | returnMessage = "P T" 41 | if not self._validateCommand(): 42 | returnMessage = "P1F: " + "No setup." 43 | else: 44 | try: 45 | # Retain flag is ignored 46 | self._mqttCoreHandler.publish(self._parameterList[0], self._parameterList[1], int(self._parameterList[2])) 47 | except TypeError as e: 48 | returnMessage = "P2F: " + str(e.message) 49 | except publishError as e: 50 | returnMessage = "P3F: " + str(e.message) 51 | except publishTimeoutException as e: 52 | returnMessage = "P4F: " + str(e.message) 53 | except publishQueueFullException as e: 54 | returnMessage = "P5F: " + str(e.message) 55 | except publishQueueDisabledException as e: 56 | returnMessage = "P6F: " + str(e.message) 57 | except Exception as e: 58 | returnMessage = "PFF: " + "Unknown error." 59 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 60 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandSetBackoffTiming.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | 20 | 21 | class commandSetBackoffTiming(AWSIoTCommand.AWSIoTCommand): 22 | # Target API: AWSIoTMQTTClient.configureAutoReconnectBackoffTime(baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond) 23 | 24 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcMQTTCore): 25 | self._commandProtocolName = "bf" 26 | self._parameterList = srcParameterList 27 | self._serialCommServerHandler = srcSerialCommuteServer 28 | self._mqttCoreHandler = srcMQTTCore 29 | self._desiredNumberOfParameters = 3 30 | 31 | def _validateCommand(self): 32 | ret = self._mqttCoreHandler is not None and self._serialCommServerHandler is not None 33 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 34 | 35 | def execute(self): 36 | returnMessage = "BF T" 37 | if not self._validateCommand(): 38 | returnMessage = "BF1F: " + "No setup." 39 | else: 40 | try: 41 | self._mqttCoreHandler.configureAutoReconnectBackoffTime(int(self._parameterList[0]), int(self._parameterList[1]), int(self._parameterList[2])) 42 | except TypeError as e: 43 | returnMessage = "BF2F: " + str(e.message) 44 | except ValueError as e: 45 | returnMessage = "BF3F: " + str(e.message) 46 | except Exception as e: 47 | returnMessage = "BFFF: " + "Unknown error." 48 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 49 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandSetDrainingIntervalSecond.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | 20 | 21 | class commandSetDrainingIntervalSecond(AWSIoTCommand.AWSIoTCommand): 22 | # Target API: AWSIoTMQTTClient.configureDrainingFrequency(1/srcDrainingIntervalSecond) 23 | 24 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcMQTTCore): 25 | self._commandProtocolName = "di" 26 | self._parameterList = srcParameterList 27 | self._serialCommServerHandler = srcSerialCommuteServer 28 | self._mqttCoreHandler = srcMQTTCore 29 | self._desiredNumberOfParameters = 1 30 | 31 | def _validateCommand(self): 32 | ret = self._mqttCoreHandler is not None and self._serialCommServerHandler is not None 33 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 34 | 35 | def execute(self): 36 | returnMessage = "DI T" 37 | if not self._validateCommand(): 38 | returnMessage = "DI1F: " + "No setup." 39 | else: 40 | try: 41 | self._mqttCoreHandler.configureDrainingFrequency(1/float(self._parameterList[0])) 42 | except TypeError as e: 43 | returnMessage = "DI2F: " + str(e.message) 44 | except ValueError as e: 45 | returnMessage = "DI3F: " + str(e.message) 46 | except Exception as e: 47 | returnMessage = "DIFF: " + "Unknown error." 48 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 49 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandSetOfflinePublishQueueing.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | 20 | 21 | class commandSetOfflinePublishQueueing(AWSIoTCommand.AWSIoTCommand): 22 | # Target API: AWSIoTMQTTClient.configureOfflinePublishQueueing(srcQueueSize, srcDropBehavior) 23 | 24 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcMQTTCore): 25 | self._commandProtocolName = "pq" 26 | self._parameterList = srcParameterList 27 | self._serialCommServerHandler = srcSerialCommuteServer 28 | self._mqttCoreHandler = srcMQTTCore 29 | self._desiredNumberOfParameters = 2 30 | 31 | def _validateCommand(self): 32 | ret = self._mqttCoreHandler is not None and self._serialCommServerHandler is not None 33 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 34 | 35 | def execute(self): 36 | returnMessage = "PQ T" 37 | if not self._validateCommand(): 38 | returnMessage = "PQ1F: " + "No setup." 39 | else: 40 | try: 41 | # In AWS IoT Python SDK: 42 | # queueSize == 0 -> queue feature is turned off 43 | # queueSize == -1 -> queue is infinite 44 | # In IoT Yun SDK: 45 | # queueSize == 0 -> queue is infinite 46 | # queueSize == -1 is not checked 47 | queueSizeSentToCore = int(self._parameterList[0]) 48 | if int(self._parameterList[0]) == 0: # Infinite queue 49 | queueSizeSentToCore = -1 50 | if int(self._parameterList[0]) < 0: # Disable queue 51 | queueSizeSentToCore = 0 52 | self._mqttCoreHandler.configureOfflinePublishQueueing(queueSizeSentToCore, int(self._parameterList[1])) 53 | except TypeError as e: 54 | returnMessage = "PQ2F: " + str(e.message) 55 | except ValueError as e: 56 | returnMessage = "PQ3F: " + str(e.message) 57 | except Exception as e: 58 | returnMessage = "PQFF: " + "Unknown error." 59 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 60 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandShadowDelete.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | from core.exception.AWSIoTExceptions import subscribeError 20 | from core.exception.AWSIoTExceptions import subscribeTimeoutException 21 | from core.exception.AWSIoTExceptions import publishError 22 | from core.exception.AWSIoTExceptions import publishTimeoutException 23 | from core.exception.AWSIoTExceptions import publishQueueFullException 24 | from core.exception.AWSIoTExceptions import publishQueueDisabledException 25 | 26 | 27 | class commandShadowDelete(AWSIoTCommand.AWSIoTCommand): 28 | # Target API: deviceShadow.shadowDelete(srcCallback, srcTimeout) 29 | # Parameters: deviceShadowName, sketchSubscribeSlot, srcTimeout, callback 30 | 31 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcShadowRegistrationTable, srcShadowSubscribeRecord): 32 | self._commandProtocolName = "sd" 33 | self._parameterList = srcParameterList 34 | self._serialCommServerHandler = srcSerialCommuteServer 35 | # To get the corresponding registered deviceShadow instance 36 | self._shadowRegistrationTable = srcShadowRegistrationTable 37 | # To get update the sketch slot information 38 | self._shadowSubscribeRecord = srcShadowSubscribeRecord 39 | self._desiredNumberOfParameters = 4 40 | 41 | def _validateCommand(self): 42 | isNumberOfParameterMatched = AWSIoTCommand.AWSIoTCommand._validateCommand(self) 43 | isDataStructureExist = self._shadowRegistrationTable is not None and self._serialCommServerHandler is not None 44 | isDeviceShadowNameRegistered = False 45 | if isNumberOfParameterMatched and isDataStructureExist: 46 | isDeviceShadowNameRegistered = self._shadowRegistrationTable.get(self._parameterList[0]) is not None 47 | return isNumberOfParameterMatched and isDataStructureExist and isDeviceShadowNameRegistered 48 | 49 | def execute(self): 50 | returnMessage = "SD T" 51 | if not self._validateCommand(): 52 | returnMessage = "SD1F: " + "No shadow init." 53 | else: 54 | try: 55 | currentDeviceShadow = self._shadowRegistrationTable.get(self._parameterList[0]) # By this time, currentDeviceShadow should never be None 56 | # Real shadow delete 57 | tokenForThisRequest = currentDeviceShadow.shadowDelete(self._parameterList[3], int(self._parameterList[2])) 58 | # Update sketch subscribe slot number 59 | self._shadowSubscribeRecord[tokenForThisRequest] = int(self._parameterList[1]) 60 | # A waiting will be performed in the callback to wait until the data structure is ready for device shadow name registration 61 | except TypeError as e: 62 | returnMessage = "SD2F: " + str(e.message) 63 | # 2 subscriptions and 1 publish 64 | except subscribeError as e: 65 | returnMessage = "SD3F: " + str(e.message) 66 | except subscribeTimeoutException as e: 67 | returnMessage = "SD4F: " + str(e.message) 68 | except publishError as e: 69 | returnMessage = "SD5F: " + str(e.message) 70 | except publishTimeoutException as e: 71 | returnMessage = "SD6F: " + str(e.message) 72 | except publishQueueFullException as e: 73 | returnMessage = "SD7F: " + str(e.message) 74 | except publishQueueDisabledException as e: 75 | returnMessage = "SD8F: " + str(e.message) 76 | except Exception as e: 77 | returnMessage = "SDFF: " + "Unknown error." 78 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 79 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandShadowGet.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | from core.exception.AWSIoTExceptions import subscribeError 20 | from core.exception.AWSIoTExceptions import subscribeTimeoutException 21 | from core.exception.AWSIoTExceptions import publishError 22 | from core.exception.AWSIoTExceptions import publishTimeoutException 23 | from core.exception.AWSIoTExceptions import publishQueueFullException 24 | from core.exception.AWSIoTExceptions import publishQueueDisabledException 25 | 26 | 27 | class commandShadowGet(AWSIoTCommand.AWSIoTCommand): 28 | # Target API: deviceShadow.shadowGet(srcCallback, srcTimeout) 29 | # Parameters: deviceShadowName, sketchSubscribeSlot, srcTimeout, callback 30 | 31 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcShadowRegistrationTable, srcShadowSubscribeRecord): 32 | self._commandProtocolName = "sg" 33 | self._parameterList = srcParameterList 34 | self._serialCommServerHandler = srcSerialCommuteServer 35 | # To get the corresponding registered deviceShadow instance 36 | self._shadowRegistrationTable = srcShadowRegistrationTable 37 | # To get update the sketch slot information 38 | self._shadowSubscribeRecord = srcShadowSubscribeRecord 39 | self._desiredNumberOfParameters = 4 40 | 41 | def _validateCommand(self): 42 | isNumberOfParameterMatched = AWSIoTCommand.AWSIoTCommand._validateCommand(self) 43 | isDataStructureExist = self._shadowRegistrationTable is not None and self._serialCommServerHandler is not None 44 | isDeviceShadowNameRegistered = False 45 | if isNumberOfParameterMatched and isDataStructureExist: 46 | isDeviceShadowNameRegistered = self._shadowRegistrationTable.get(self._parameterList[0]) is not None 47 | return isNumberOfParameterMatched and isDataStructureExist and isDeviceShadowNameRegistered 48 | 49 | def execute(self): 50 | returnMessage = "SG T" 51 | if not self._validateCommand(): 52 | returnMessage = "SG1F: " + "No shadow init." 53 | else: 54 | try: 55 | currentDeviceShadow = self._shadowRegistrationTable.get(self._parameterList[0]) # By this time, currentDeviceShadow should never be None 56 | # Real shadow get 57 | tokenForThisRequest = currentDeviceShadow.shadowGet(self._parameterList[3], int(self._parameterList[2])) 58 | # Update sketch subscribe slot number 59 | self._shadowSubscribeRecord[tokenForThisRequest] = int(self._parameterList[1]) 60 | # A waiting will be performed in the callback to wait until the data structure is ready for device shadow name registration 61 | except TypeError as e: 62 | returnMessage = "SG2F: " + str(e.message) 63 | # 2 subscriptions and 1 publish 64 | except subscribeError as e: 65 | returnMessage = "SG3F: " + str(e.message) 66 | except subscribeTimeoutException as e: 67 | returnMessage = "SG4F: " + str(e.message) 68 | except publishError as e: 69 | returnMessage = "SG5F: " + str(e.message) 70 | except publishTimeoutException as e: 71 | returnMessage = "SG6F: " + str(e.message) 72 | except publishQueueFullException as e: 73 | returnMessage = "SG7F: " + str(e.message) 74 | except publishQueueDisabledException as e: 75 | returnMessage = "SG8F: " + str(e.message) 76 | except Exception as e: 77 | returnMessage = "SGFF: " + "Unknown error." 78 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 79 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandShadowRegisterDeltaCallback.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | from core.exception.AWSIoTExceptions import subscribeError 20 | from core.exception.AWSIoTExceptions import subscribeTimeoutException 21 | 22 | 23 | class commandShadowRegisterDeltaCallback(AWSIoTCommand.AWSIoTCommand): 24 | # Target API: deviceShadow.shadowRegisterDeltaCallback(srcCallback) 25 | # Parameters: deviceShadowName, sketchSubscribeSlot, callback 26 | 27 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcShadowRegistrationTable, srcShadowSubscribeRecord): 28 | self._commandProtocolName = "s_rd" 29 | self._parameterList = srcParameterList 30 | self._serialCommServerHandler = srcSerialCommuteServer 31 | # To get the corresponding registered deviceShadow instance 32 | self._shadowRegistrationTable = srcShadowRegistrationTable 33 | # To get update the sketch slot information 34 | self._shadowSubscribeRecord = srcShadowSubscribeRecord 35 | self._desiredNumberOfParameters = 3 36 | 37 | def _validateCommand(self): 38 | isNumberOfParameterMatched = AWSIoTCommand.AWSIoTCommand._validateCommand(self) 39 | isDataStructureExist = self._shadowRegistrationTable is not None and self._serialCommServerHandler is not None 40 | isDeviceShadowNameRegistered = False 41 | if isNumberOfParameterMatched and isDataStructureExist: 42 | isDeviceShadowNameRegistered = self._shadowRegistrationTable.get(self._parameterList[0]) is not None 43 | return isNumberOfParameterMatched and isDataStructureExist and isDeviceShadowNameRegistered 44 | 45 | def execute(self): 46 | returnMessage = "S_RD T" 47 | if not self._validateCommand(): 48 | returnMessage = "S_RD1F: " + "No shadow init." 49 | else: 50 | try: 51 | currentDeviceShadow = self._shadowRegistrationTable.get(self._parameterList[0]) # By this time, currentDeviceShadow should never be None 52 | # Real shadow register delta callback 53 | currentDeviceShadow.shadowRegisterDeltaCallback(self._parameterList[2]) 54 | # Update sketch subscribe slot number, using deviceShadow name 55 | self._shadowSubscribeRecord[self._parameterList[0]] = int(self._parameterList[1]) 56 | except TypeError as e: 57 | returnMessage = "S_RD2F: " + str(e.message) 58 | # One subscription 59 | except subscribeError as e: 60 | returnMessage = "S_RD3F: " + str(e.message) 61 | except subscribeTimeoutException as e: 62 | returnMessage = "S_RD4F: " + str(e.message) 63 | except Exception as e: 64 | returnMessage = "S_RDFF: " + "Unknown error." 65 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 66 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandShadowUnregisterDeltaCallback.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | from core.exception.AWSIoTExceptions import unsubscribeError 20 | from core.exception.AWSIoTExceptions import unsubscribeTimeoutException 21 | 22 | 23 | class commandShadowUnregisterDeltaCallback(AWSIoTCommand.AWSIoTCommand): 24 | # Target API: deviceShadow.shadowUnregisterDeltaCallback() 25 | # Parameters: deviceShadowName 26 | 27 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcShadowRegistrationTable, srcShadowSubscribeRecord): 28 | self._commandProtocolName = "s_ud" 29 | self._parameterList = srcParameterList 30 | self._serialCommServerHandler = srcSerialCommuteServer 31 | # To get the corresponding registered deviceShadow instance 32 | self._shadowRegistrationTable = srcShadowRegistrationTable 33 | # To get update the sketch slot information 34 | self._shadowSubscribeRecord = srcShadowSubscribeRecord 35 | self._desiredNumberOfParameters = 1 36 | 37 | def _validateCommand(self): 38 | isNumberOfParameterMatched = AWSIoTCommand.AWSIoTCommand._validateCommand(self) 39 | isDataStructureExist = self._shadowRegistrationTable is not None and self._serialCommServerHandler is not None 40 | isDeviceShadowNameRegistered = False 41 | if isNumberOfParameterMatched and isDataStructureExist: 42 | isDeviceShadowNameRegistered = self._shadowRegistrationTable.get(self._parameterList[0]) is not None 43 | return isNumberOfParameterMatched and isDataStructureExist and isDeviceShadowNameRegistered 44 | 45 | def execute(self): 46 | returnMessage = "S_UD T" 47 | if not self._validateCommand(): 48 | returnMessage = "S_UD1F: " + "No shadow init." 49 | else: 50 | try: 51 | returnMessage = "S_UD " + str(self._shadowSubscribeRecord[self._parameterList[0]]) 52 | currentDeviceShadow = self._shadowRegistrationTable.get(self._parameterList[0]) # By this time, currentDeviceShadow should never be None 53 | # Real shadow unregister delta callback 54 | currentDeviceShadow.shadowUnregisterDeltaCallback() 55 | # Update sketch subscribe slot number, using deviceShadow name 56 | del self._shadowSubscribeRecord[self._parameterList[0]] 57 | except TypeError as e: 58 | returnMessage = "S_UD2F: " + str(e.message) 59 | # One unsubscription 60 | except unsubscribeError as e: 61 | returnMessage = "S_UD3F: " + str(e.message) 62 | except unsubscribeTimeoutException as e: 63 | returnMessage = "S_UD4F: " + str(e.message) 64 | except Exception as e: 65 | returnMessage = "S_UDFF: " + "Unknown error." 66 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 67 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandShadowUpdate.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | from core.exception.AWSIoTExceptions import subscribeError 20 | from core.exception.AWSIoTExceptions import subscribeTimeoutException 21 | from core.exception.AWSIoTExceptions import publishError 22 | from core.exception.AWSIoTExceptions import publishTimeoutException 23 | from core.exception.AWSIoTExceptions import publishQueueFullException 24 | from core.exception.AWSIoTExceptions import publishQueueDisabledException 25 | 26 | 27 | class commandShadowUpdate(AWSIoTCommand.AWSIoTCommand): 28 | # Target API: deviceShadow.shadowUpdate(srcJSONPayload, srcCallback, srcTimeout) 29 | # Parameters: deviceShadowName, JSONPayload, sketchSubscribeSlot, srcTimeout, callback 30 | 31 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcShadowRegistrationTable, srcShadowSubscribeRecord): 32 | self._commandProtocolName = "su" 33 | self._parameterList = srcParameterList 34 | self._serialCommServerHandler = srcSerialCommuteServer 35 | # To get the corresponding registered deviceShadow instance 36 | self._shadowRegistrationTable = srcShadowRegistrationTable 37 | # To get update the sketch slot information 38 | self._shadowSubscribeRecord = srcShadowSubscribeRecord 39 | self._desiredNumberOfParameters = 5 40 | 41 | def _validateCommand(self): 42 | isNumberOfParameterMatched = AWSIoTCommand.AWSIoTCommand._validateCommand(self) 43 | isDataStructureExist = self._shadowRegistrationTable is not None and self._serialCommServerHandler is not None 44 | isDeviceShadowNameRegistered = False 45 | if isNumberOfParameterMatched and isDataStructureExist: 46 | isDeviceShadowNameRegistered = self._shadowRegistrationTable.get(self._parameterList[0]) is not None 47 | return isNumberOfParameterMatched and isDataStructureExist and isDeviceShadowNameRegistered 48 | 49 | def execute(self): 50 | returnMessage = "SU T" 51 | if not self._validateCommand(): 52 | returnMessage = "SU1F: " + "No shadow init." 53 | else: 54 | try: 55 | currentDeviceShadow = self._shadowRegistrationTable.get(self._parameterList[0]) # By this time, currentDeviceShadow should never be None 56 | # Real shadow update 57 | tokenForThisRequest = currentDeviceShadow.shadowUpdate(self._parameterList[1], self._parameterList[4], int(self._parameterList[3])) 58 | # Update sketch subscribe slot number 59 | self._shadowSubscribeRecord[tokenForThisRequest] = int(self._parameterList[2]) 60 | # A waiting will be performed in the callback to wait until the data structure is ready for device shadow name registration 61 | except TypeError as e: 62 | returnMessage = "SU2F: " + str(e.message) 63 | except ValueError as e: 64 | returnMessage = "SU3F: " + "Invalid JSON payload." 65 | # 2 subscriptions and 1 publish 66 | except subscribeError as e: 67 | returnMessage = "SU4F: " + str(e.message) 68 | except subscribeTimeoutException as e: 69 | returnMessage = "SU5F: " + str(e.message) 70 | except publishError as e: 71 | returnMessage = "SU6F: " + str(e.message) 72 | except publishTimeoutException as e: 73 | returnMessage = "SU7F: " + str(e.message) 74 | except publishQueueFullException as e: 75 | returnMessage = "SU8F: " + str(e.message) 76 | except publishQueueDisabledException as e: 77 | returnMessage = "SU9F: " + str(e.message) 78 | except Exception as e: 79 | returnMessage = "SUFF: " + "Unknown error." 80 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 81 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandSubscribe.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | from core.exception.AWSIoTExceptions import subscribeError 20 | from core.exception.AWSIoTExceptions import subscribeTimeoutException 21 | 22 | 23 | class commandSubscribe(AWSIoTCommand.AWSIoTCommand): 24 | # Target API: AWSIoTMQTTClient.subscribe(topic, qos, callback) 25 | # Parameter list: 26 | 27 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcMQTTCore, srcMQTTSubscribeTable): 28 | self._commandProtocolName = "s" 29 | self._parameterList = srcParameterList 30 | self._serialCommServerHandler = srcSerialCommuteServer 31 | self._mqttCoreHandler = srcMQTTCore 32 | self._mqttSubscribeUnit = None 33 | self._mqttSubscribeTable = srcMQTTSubscribeTable 34 | self._desiredNumberOfParameters = 4 35 | 36 | def _validateCommand(self): 37 | ret = self._mqttCoreHandler is not None and self._serialCommServerHandler is not None 38 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 39 | 40 | def execute(self): 41 | returnMessage = "S T" 42 | if not self._validateCommand(): 43 | returnMessage = "S1F: " + "No setup." 44 | else: 45 | try: 46 | # Init the mqttSubscribeUnit 47 | self._mqttSubscribeUnit = self._parameterList[3] 48 | self._mqttSubscribeUnit.setTopicName(self._parameterList[0]) 49 | self._mqttSubscribeUnit.setSketchSlotNumber(int(self._parameterList[2])) 50 | self._mqttSubscribeUnit.setSerialCommunicationServerHub(self._serialCommServerHandler) 51 | # Real subscription 52 | self._mqttCoreHandler.subscribe(self._parameterList[0], int(self._parameterList[1]), self._mqttSubscribeUnit.individualCallback) 53 | # Update mqttSubscribeTable 54 | self._mqttSubscribeTable[self._parameterList[0]] = self._mqttSubscribeUnit 55 | except TypeError as e: 56 | returnMessage = "S2F: " + str(e.message) 57 | except subscribeError as e: 58 | returnMessage = "S3F: " + str(e.message) 59 | except subscribeTimeoutException as e: 60 | returnMessage = "S4F: " + str(e.message) 61 | except Exception as e: 62 | returnMessage = "SFF: " + "Unknown error." 63 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 64 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandUnsubscribe.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | from core.exception.AWSIoTExceptions import unsubscribeError 20 | from core.exception.AWSIoTExceptions import unsubscribeTimeoutException 21 | 22 | 23 | class commandUnsubscribe(AWSIoTCommand.AWSIoTCommand): 24 | # Target API: AWSIoTMQTTClient.unsubscribe(topic) 25 | 26 | def __init__(self, srcParameterList, srcSerialCommuteServer, srcMQTTCore, srcMQTTSubscribeTable): 27 | self._commandProtocolName = "u" 28 | self._parameterList = srcParameterList 29 | self._serialCommServerHandler = srcSerialCommuteServer 30 | self._mqttCoreHandler = srcMQTTCore 31 | self._mqttSubscribeTable = srcMQTTSubscribeTable 32 | self._desiredNumberOfParameters = 1 33 | 34 | def _validateCommand(self): 35 | ret = self._mqttCoreHandler is not None and self._serialCommServerHandler is not None 36 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 37 | 38 | def execute(self): 39 | returnMessage = "U T" 40 | if not self._validateCommand(): 41 | returnMessage = "U1F: " + "No setup." 42 | else: 43 | try: 44 | thisSubscribeUnit = self._mqttSubscribeTable.get(self._parameterList[0]) 45 | if thisSubscribeUnit is not None: 46 | returnMessage = "U " + str(thisSubscribeUnit.getSketchSlotNumber()) 47 | # Real unsubscription 48 | self._mqttCoreHandler.unsubscribe(self._parameterList[0]) 49 | # Update mqttSubscribeTable 50 | del self._mqttSubscribeTable[self._parameterList[0]] 51 | except KeyError as e: 52 | pass # Ignore unsubscribe to a topic that never been subscribed 53 | except TypeError as e: 54 | returnMessage = "U2F: " + str(e.message) 55 | except unsubscribeError as e: 56 | returnMessage = "U3F: " + str(e.message) 57 | except unsubscribeTimeoutException as e: 58 | returnMessage = "U4F: " + str(e.message) 59 | except Exception as e: 60 | returnMessage = "UFF: " + "Unknown error." 61 | self._serialCommServerHandler.writeToInternalProtocol(returnMessage) 62 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/command/commandYield.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import AWSIoTCommand 19 | 20 | 21 | class commandYield(AWSIoTCommand.AWSIoTCommand): 22 | # Target API: None 23 | 24 | def __init__(self, srcParameterList, srcSerialCommuteServer): 25 | self._commandProtocolName = "y" 26 | self._parameterList = srcParameterList 27 | self._serialCommServerHandler = srcSerialCommuteServer 28 | self._desiredNumberOfParameters = 0 29 | 30 | def _validateCommand(self): 31 | ret = self._serialCommServerHandler is not None 32 | return ret and AWSIoTCommand.AWSIoTCommand._validateCommand(self) 33 | 34 | # No execute, pass and directly go to writeToExternalYield 35 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/exception/AWSIoTExceptions.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import operationTimeoutException 19 | import operationError 20 | 21 | 22 | # Serial Exception 23 | class acceptTimeoutException(Exception): 24 | def __init__(self, msg="Accept Timeout"): 25 | self.message = msg 26 | 27 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/exception/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-iot-device-sdk-arduino-yun/cfc29219a6d3ae63779fdd024c38747d091a0654/AWS-IoT-Python-Runtime/lib/exception/__init__.py -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/exception/operationError.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | 19 | class operationError(Exception): 20 | def __init__(self, msg="Operation Error"): 21 | self.message = msg 22 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/exception/operationTimeoutException.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | 19 | class operationTimeoutException(Exception): 20 | def __init__(self, msg="Operation Timeout"): 21 | self.message = msg 22 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-iot-device-sdk-arduino-yun/cfc29219a6d3ae63779fdd024c38747d091a0654/AWS-IoT-Python-Runtime/lib/util/__init__.py -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/lib/util/jsonManager.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | class jsonManager: 5 | # This is the JSON Manager that stores all the complete JSON payload 6 | # JSON payload can be accessed by keys provided when inserting them 7 | # History limits can be configured to control the memory consumption 8 | # For those entries that are exceeding the history limit, they will be overwritten 9 | _prefix = "JSON-" 10 | 11 | def __init__(self, srcHistoryLimits): 12 | self._records = dict() 13 | self._historyLimits = srcHistoryLimits # 0 means unlimited history 14 | self._internalCountAccepted = -3 15 | self._internalCountRejected = -2 16 | self._internalCountDelta = -1 17 | # If there is a restriction on JSON history length, 18 | # initialize these items with None value 19 | if self._historyLimits >= 3: # Limited dict 20 | for i in range(0, self._historyLimits): 21 | self._records[self._prefix + str(i)] = None 22 | elif self._historyLimits == 0: # Unlimited dict 23 | pass 24 | else: # Invalid JSON history length, negative 25 | raise ValueError('History limits too small.') 26 | # Set limits for accepted/rejected/delta JSON 27 | if self._historyLimits % 3 == 0: 28 | self._acceptedHistoryLimits = self._historyLimits - 3 29 | self._rejectedHistoryLimits = self._historyLimits - 2 30 | self._deltaHistoryLimits = self._historyLimits - 1 31 | elif self._historyLimits % 3 == 1: 32 | self._acceptedHistoryLimits = self._historyLimits - 1 33 | self._rejectedHistoryLimits = self._historyLimits - 3 34 | self._deltaHistoryLimits = self._historyLimits - 2 35 | else: 36 | self._acceptedHistoryLimits = self._historyLimits - 2 37 | self._rejectedHistoryLimits = self._historyLimits - 1 38 | self._deltaHistoryLimits = self._historyLimits - 3 39 | 40 | def storeNewJSON(self, JSONPayload, Type): 41 | # Store a new JSON entry into the dictonary 42 | # Return the key to access this JSON payload 43 | if JSONPayload == "REQUEST TIME OUT": 44 | return "JSON-X" 45 | else: 46 | tempCount = -1 47 | if Type == 'accepted': 48 | if self._historyLimits != 0 and self._internalCountAccepted >= self._acceptedHistoryLimits: 49 | self._internalCountAccepted = 0 50 | else: 51 | self._internalCountAccepted += 3 52 | tempCount = self._internalCountAccepted 53 | elif Type == 'rejected': 54 | if self._historyLimits != 0 and self._internalCountRejected >= self._rejectedHistoryLimits: 55 | self._internalCountRejected = 1 56 | else: 57 | self._internalCountRejected += 3 58 | tempCount = self._internalCountRejected 59 | else: 60 | if self._historyLimits != 0 and self._internalCountDelta >= self._deltaHistoryLimits: 61 | self._internalCountDelta = 2 62 | else: 63 | self._internalCountDelta += 3 64 | tempCount = self._internalCountDelta 65 | # Format key 66 | currKey = self._prefix + str(tempCount) 67 | # Insert the key-value 68 | self._records[currKey] = JSONPayload 69 | # Return the assigned key 70 | return currKey 71 | 72 | def retrieveJSONByKey(self, key): 73 | # Get the JSON payload by key 74 | # If key is not present, None will be returned 75 | return self._records.get(key) 76 | 77 | def getValueByKeyInJSON(self, JSONPayload, key): 78 | # Get the value using the key in JSON 79 | # If key is not present/Invalid JSON input detected, None will be returned 80 | # ***Need to work on property that contains ':' 81 | try: 82 | levels = key.split('"') 83 | tempDict = json.loads(JSONPayload) 84 | returnValue = tempDict 85 | for i in range(0, len(levels)): 86 | if levels[i] != '': 87 | if returnValue is not None: 88 | returnValue = returnValue.get(levels[i]) 89 | else: 90 | break 91 | if returnValue is None: 92 | return None 93 | else: 94 | if isinstance(returnValue, basestring): 95 | return returnValue 96 | else: 97 | return json.dumps(returnValue) 98 | except ValueError: 99 | return None 100 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/log/delete.me: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-iot-device-sdk-arduino-yun/cfc29219a6d3ae63779fdd024c38747d091a0654/AWS-IoT-Python-Runtime/log/delete.me -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/runtime/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/aws-iot-device-sdk-arduino-yun/cfc29219a6d3ae63779fdd024c38747d091a0654/AWS-IoT-Python-Runtime/runtime/__init__.py -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/runtime/run.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | from runtimeHub import * 19 | 20 | AWSIoTMQTTArduinoPyHub = runtimeHub("AWSIoTMQTTArduinoHub", "../log/") 21 | AWSIoTMQTTArduinoPyHub.run() 22 | -------------------------------------------------------------------------------- /AWS-IoT-Python-Runtime/runtime/runtimeHub.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import os 19 | import sys 20 | sys.path.insert(0, "../lib/") 21 | import AWSIoTPythonSDK 22 | sys.path.insert(0, os.path.abspath(AWSIoTPythonSDK.__file__)) 23 | import logging 24 | from threading import Lock 25 | from util.jsonManager import jsonManager 26 | from exception.AWSIoTExceptions import * 27 | from comm.serialCommunicationServer import * 28 | from command.AWSIoTCommand import * 29 | from command.commandConnect import * 30 | from command.commandDisconnect import * 31 | from command.commandConfig import * 32 | from command.commandPublish import * 33 | from command.commandSubscribe import * 34 | from command.commandUnsubscribe import * 35 | from command.commandShadowGet import * 36 | from command.commandShadowDelete import * 37 | from command.commandShadowUpdate import * 38 | from command.commandShadowRegisterDeltaCallback import * 39 | from command.commandShadowUnregisterDeltaCallback import * 40 | from command.commandYield import * 41 | from command.commandLockSize import * 42 | from command.commandJSONKeyVal import * 43 | from command.commandSetBackoffTiming import * 44 | from command.commandSetOfflinePublishQueueing import * 45 | from command.commandSetDrainingIntervalSecond import * 46 | # Use IoT Python SDK as backend 47 | from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient 48 | from AWSIoTPythonSDK.MQTTLib import MQTTv3_1, MQTTv3_1_1 49 | # import traceback 50 | 51 | 52 | # Object for each MQTT subscription to hold the sketch info (slot #) 53 | class _mqttSubscribeUnit: 54 | 55 | def __init__(self, srcFormatPayloadForYieldFunctionPointer): 56 | self._topicName = None 57 | self._sketchSlotNumber = -1 58 | self._formatPayloadForYield = None 59 | self._serialCommunicationServerHub = None 60 | self._formatPayloadForYield = srcFormatPayloadForYieldFunctionPointer 61 | 62 | def setTopicName(self, srcTopicName): 63 | self._topicName = srcTopicName 64 | 65 | def setSketchSlotNumber(self, srcSketchSlotNumber): 66 | self._sketchSlotNumber = srcSketchSlotNumber 67 | 68 | def setSerialCommunicationServerHub(self, srcSerialCommunicationServerHub): 69 | self._serialCommunicationServerHub = srcSerialCommunicationServerHub 70 | 71 | def getTopicName(self): 72 | return self._topicName 73 | 74 | def getSketchSlotNumber(self): 75 | return self._sketchSlotNumber 76 | 77 | def individualCallback(self, client, userdata, message): 78 | # Process the incoming non-shadow messages for a specific MQTT subscription 79 | # Parse them into protocol-style chunks that can be transmitted over the serial 80 | # and understood by Atmega 81 | # Execution of this callback is ATOMIC (Guaranteed by paho) 82 | #### 83 | # Get the topic 84 | currentTopic = str(message.topic) 85 | # Find the sketch slot related to this topic name, ignore if not exist any more 86 | try: 87 | currentSketchSlotNumber = self._sketchSlotNumber 88 | # Refactor the payload by adding protocol head and dividing into reasonable chunks 89 | formattedPayload = self._formatPayloadForYield(str(message.payload), currentSketchSlotNumber) 90 | # Put it into the internal queue of serialCommunicationServer 91 | self._serialCommunicationServerHub.writeToInternalYield(formattedPayload) 92 | # This message will get to be transmitted in future Yield requests 93 | except KeyError: 94 | pass # Ignore messages coming between callback and unsubscription 95 | 96 | 97 | class runtimeHub: 98 | 99 | #### Methods start here #### 100 | def __init__(self, srcFileName, srcLogDirectory): 101 | # Init with basic interface for serial communication 102 | self._log = logging.getLogger(__name__) 103 | self._serialCommunicationServerHub = serialCommunicationServer() 104 | self._serialCommunicationServerHub.setAcceptTimeout(10) 105 | self._serialCommunicationServerHub.setChunkSize(50) 106 | self._jsonManagerHub = jsonManager(512*3) # Default history limits is set to be 512*3, 512 for accepted, 512 for rejected and 512 for deltas 107 | # Keep the record of MQTT subscribe sketch info (slot #), in forms of individual object 108 | self._mqttSubscribeTable = dict() 109 | # Keep the record of shadow subscribe sketch info (slot #) 110 | self._shadowSubscribeRecord = dict() 111 | # Keep track of the deviceShadow instances for each individual deviceShadow name 112 | self._shadowRegistrationTable = dict() 113 | # MQTT Connection 114 | self._mqttClientHub = None # Init when requested 115 | self._shadowClientHub = None # Init when requested 116 | # ShadowCallback Lock 117 | self._shadowCallbackLock = Lock() 118 | 119 | def _getAWSIoTMQTTShadowClient(self, clientID, protocol, useWebsocket, cleanSession): 120 | return AWSIoTMQTTShadowClient(clientID, protocol, useWebsocket, cleanSession) 121 | 122 | def _findCommand(self, srcProtocolMessage): 123 | # Whatever comes out of this method should be an AWSIoTCommand 124 | # Invalid command will have a protocol name of "x" 125 | # Never raise exceptions 126 | retCommand = None 127 | if srcProtocolMessage is None: 128 | retCommand = AWSIoTCommand.AWSIoTCommand() 129 | else: 130 | # MQTT init 131 | if srcProtocolMessage[0] == "i": 132 | retCommand = AWSIoTCommand.AWSIoTCommand("i") 133 | if len(srcProtocolMessage[1:]) == 4: 134 | clientID = srcProtocolMessage[1] 135 | cleanSession = srcProtocolMessage[2] == "1" 136 | protocol = MQTTv3_1 137 | if srcProtocolMessage[3] == "4": 138 | protocol = MQTTv3_1_1 139 | useWebsocket = srcProtocolMessage[4] == "1" 140 | try: 141 | self._shadowClientHub = self._getAWSIoTMQTTShadowClient(clientID, protocol, useWebsocket, cleanSession) 142 | self._shadowClientHub.configureConnectDisconnectTimeout(10) 143 | self._shadowClientHub.configureMQTTOperationTimeout(5) 144 | self._mqttClientHub = self._shadowClientHub.getMQTTConnection() 145 | except TypeError: 146 | retCommand.setInitSuccess(False) # Error in Init, set flag 147 | else: 148 | retCommand.setInitSuccess(False) # Error in obtain parameters for Init 149 | # Config 150 | elif srcProtocolMessage[0] == "g": 151 | retCommand = commandConfig(srcProtocolMessage[1:], self._serialCommunicationServerHub, self._shadowClientHub) 152 | # Connect 153 | elif srcProtocolMessage[0] == "c": 154 | retCommand = commandConnect(srcProtocolMessage[1:], self._serialCommunicationServerHub, self._shadowClientHub) 155 | # Disconnect 156 | elif srcProtocolMessage[0] == "d": 157 | retCommand = commandDisconnect(srcProtocolMessage[1:], self._serialCommunicationServerHub, self._shadowClientHub) 158 | # Publish 159 | elif srcProtocolMessage[0] == "p": 160 | retCommand = commandPublish(srcProtocolMessage[1:], self._serialCommunicationServerHub, self._mqttClientHub) 161 | # Subscribe 162 | elif srcProtocolMessage[0] == "s": 163 | newMQTTSubscribeUnit = _mqttSubscribeUnit(self._formatPayloadForYield) # Init an individual object for this subscribe 164 | newSrcProtocolMessage = srcProtocolMessage 165 | newSrcProtocolMessage.append(newMQTTSubscribeUnit) 166 | retCommand = commandSubscribe(newSrcProtocolMessage[1:], self._serialCommunicationServerHub, self._mqttClientHub, self._mqttSubscribeTable) 167 | # Unsubscribe 168 | elif srcProtocolMessage[0] == "u": 169 | retCommand = commandUnsubscribe(srcProtocolMessage[1:], self._serialCommunicationServerHub, self._mqttClientHub, self._mqttSubscribeTable) 170 | # Shadow init 171 | elif srcProtocolMessage[0] == "si": 172 | retCommand = AWSIoTCommand.AWSIoTCommand("si") 173 | if self._shadowClientHub is None: 174 | # Should have init a mqttCore and got it connected 175 | retCommand.setInitSuccess(False) 176 | else: 177 | # Now register the requested deviceShadow name 178 | if len(srcProtocolMessage[1:]) == 2: 179 | srcShadowName = srcProtocolMessage[1] 180 | srcIsPersistentSubscribe = srcProtocolMessage[2] == "1" 181 | try: 182 | newDeviceShadow = self._shadowClientHub.createShadowHandlerWithName(srcShadowName, srcIsPersistentSubscribe) 183 | # Now update the registration table 184 | self._shadowRegistrationTable[srcShadowName] = newDeviceShadow 185 | except TypeError: 186 | retCommand.setInitSuccess(False) 187 | else: 188 | retCommand.setInitSuccess(False) 189 | # Shadow get 190 | elif srcProtocolMessage[0] == "sg": 191 | newSrcProtocolMessage = srcProtocolMessage 192 | newSrcProtocolMessage.append(self._shadowCallback) 193 | retCommand = commandShadowGet(newSrcProtocolMessage[1:], self._serialCommunicationServerHub, self._shadowRegistrationTable, self._shadowSubscribeRecord) 194 | # Shadow update 195 | elif srcProtocolMessage[0] == "su": 196 | newSrcProtocolMessage = srcProtocolMessage 197 | newSrcProtocolMessage.append(self._shadowCallback) 198 | retCommand = commandShadowUpdate(newSrcProtocolMessage[1:], self._serialCommunicationServerHub, self._shadowRegistrationTable, self._shadowSubscribeRecord) 199 | # Shadow delete 200 | elif srcProtocolMessage[0] == "sd": 201 | newSrcProtocolMessage = srcProtocolMessage 202 | newSrcProtocolMessage.append(self._shadowCallback) 203 | retCommand = commandShadowDelete(newSrcProtocolMessage[1:], self._serialCommunicationServerHub, self._shadowRegistrationTable, self._shadowSubscribeRecord) 204 | # Shadow register delta 205 | elif srcProtocolMessage[0] == "s_rd": 206 | newSrcProtocolMessage = srcProtocolMessage 207 | newSrcProtocolMessage.append(self._shadowCallback) 208 | retCommand = commandShadowRegisterDeltaCallback(newSrcProtocolMessage[1:], self._serialCommunicationServerHub, self._shadowRegistrationTable, self._shadowSubscribeRecord) 209 | # Shadow unregister delta 210 | elif srcProtocolMessage[0] == "s_ud": 211 | retCommand = commandShadowUnregisterDeltaCallback(srcProtocolMessage[1:], self._serialCommunicationServerHub, self._shadowRegistrationTable, self._shadowSubscribeRecord) 212 | # Lock message size 213 | elif srcProtocolMessage[0] == "z": 214 | retCommand = commandLockSize(srcProtocolMessage[1:], self._serialCommunicationServerHub) 215 | # Oh the GREAT yield... 216 | elif srcProtocolMessage[0] == "y": 217 | retCommand = commandYield(srcProtocolMessage[1:], self._serialCommunicationServerHub) 218 | # JSON Key-Value Retrieve 219 | elif srcProtocolMessage[0] == 'j': 220 | retCommand = commandJSONKeyVal(srcProtocolMessage[1:], self._serialCommunicationServerHub, self._jsonManagerHub) 221 | # Backoff Timing Config 222 | elif srcProtocolMessage[0] == 'bf': 223 | retCommand = commandSetBackoffTiming(srcProtocolMessage[1:], self._serialCommunicationServerHub, self._mqttClientHub) 224 | # Offline Publish Queue Config 225 | elif srcProtocolMessage[0] == 'pq': 226 | retCommand = commandSetOfflinePublishQueueing(srcProtocolMessage[1:], self._serialCommunicationServerHub, self._mqttClientHub) 227 | # Draining Interval Config 228 | elif srcProtocolMessage[0] == 'di': 229 | retCommand = commandSetDrainingIntervalSecond(srcProtocolMessage[1:], self._serialCommunicationServerHub, self._mqttClientHub) 230 | # Exit the runtimeHub 231 | elif srcProtocolMessage[0] == "~": 232 | retCommand = AWSIoTCommand.AWSIoTCommand("~") 233 | # Unsupported protocol 234 | else: 235 | retCommand = AWSIoTCommand.AWSIoTCommand() 236 | return retCommand 237 | 238 | def _formatPayloadForYield(self, srcPayload, srcSketchSlotNumber): 239 | # Generate the formatted payload for Yield requests 240 | #### 241 | # Generate the meta data 242 | hasMore = 1 243 | metaData = "Y " + str(srcSketchSlotNumber) + " " + str(hasMore) + " " 244 | # Get configured chunk size 245 | configuredChunkSize = self._serialCommunicationServerHub.getChunkSize() 246 | # Divide the payload into smaller chunks plus meta data 247 | messageChunkSize = configuredChunkSize - len(metaData) 248 | chunks = [metaData + srcPayload[i:i+messageChunkSize] for i in range(0, len(srcPayload), messageChunkSize)] 249 | # Change hasMore flag for the last chunk 250 | chunks[len(chunks)-1] = "Y " + str(srcSketchSlotNumber) + " 0 " + chunks[len(chunks)-1][len(metaData):] 251 | # Concat them together 252 | return "".join(chunks) 253 | 254 | # Callbacks 255 | def _shadowCallback(self, srcPayload, srcCurrentType, srcCurrentToken): 256 | # Process the incoming shadow messages 257 | # Store JSON payload into jsonManager and pass the handler over 258 | # Parse the handler into protocol-style chunks that can be transimitted over the serial 259 | # and understood by Atmega 260 | # Execution of this callback can be in separate threads (SDK), therefore an extra lock is added here 261 | # All token/version controls are performed at deviceShadow level 262 | # Whatever comes in here should be delivered across serial, with care, of course 263 | #### 264 | # srcCurrentType: accepted//rejected///delta 265 | self._shadowCallbackLock.acquire() 266 | currentJSONHandler = self._jsonManagerHub.storeNewJSON(srcPayload, srcCurrentType) 267 | currentSketchSlotNumber = -1 268 | try: 269 | # Wait util internal data structure is updated 270 | if srcCurrentToken is not None: 271 | while srcCurrentToken not in self._shadowSubscribeRecord.keys(): 272 | pass 273 | # accepted//rejected: Find the sketch slot number by token 274 | if srcCurrentType in ["accepted", "rejected", "timeout"]: 275 | currentSketchSlotNumber = self._shadowSubscribeRecord[srcCurrentToken] 276 | del self._shadowSubscribeRecord[srcCurrentToken] # Retrieve the memory in dict 277 | # delta/: Find the sketch slot number by deviceShadowName 278 | else: 279 | fragments = srcCurrentType.split("/") 280 | deviceShadowNameForDelta = fragments[1] 281 | currentSketchSlotNumber = self._shadowSubscribeRecord[deviceShadowNameForDelta] 282 | # Refactor the JSONHandler by adding protocol head and dividing into reasonable chunks 283 | formattedPayload = self._formatPayloadForYield(currentJSONHandler, currentSketchSlotNumber) 284 | # Put it into the internal queue of the serialCommunicationServer 285 | self._serialCommunicationServerHub.writeToInternalYield(formattedPayload) 286 | # This message will get to be transmitted in future Yield requests 287 | except KeyError as e: 288 | self._shadowCallbackLock.release() 289 | return 290 | # Ignore messages coming between callback and unregister delta 291 | self._shadowCallbackLock.release() 292 | 293 | # Runtime function 294 | def run(self): 295 | while True: 296 | try: 297 | # Start the serialCommunicationServer and accepts protocol messages 298 | # Raises AWSIoTExceptions.acceptTimeoutException 299 | currentProtocolMessage = self._serialCommunicationServerHub.accept() 300 | # Find with command request this is 301 | currentCommand = self._findCommand(currentProtocolMessage) 302 | # See if the command is an init (MQTT/Shadow) that needs data structure operations 303 | currentCommandProtocolName = currentCommand.getCommandProtocolName() 304 | if currentCommandProtocolName == "x": 305 | pass # Ignore invalid protocol command 306 | if currentCommandProtocolName == "i": # MQTT init 307 | if currentCommand.getInitSuccess(): 308 | self._serialCommunicationServerHub.writeToInternalProtocol("I T") 309 | else: 310 | self._serialCommunicationServerHub.writeToInternalProtocol("I F") 311 | self._serialCommunicationServerHub.writeToExternalProtocol() 312 | elif currentCommandProtocolName == "si": # Shadow init 313 | if currentCommand.getInitSuccess(): 314 | self._serialCommunicationServerHub.writeToInternalProtocol("SI T") 315 | else: 316 | self._serialCommunicationServerHub.writeToInternalProtocol("SI F") 317 | self._serialCommunicationServerHub.writeToExternalProtocol() 318 | elif currentCommandProtocolName == "~": # Exit 319 | break 320 | else: # Other command 321 | # Execute the command 322 | currentCommand.execute() 323 | # Write the result back through serial (detailed error code is transmitted here) 324 | if currentCommandProtocolName == "y": 325 | self._serialCommunicationServerHub.writeToExternalYield() 326 | elif currentCommandProtocolName == "j": 327 | self._serialCommunicationServerHub.writeToExternalJSON() 328 | else: 329 | self._serialCommunicationServerHub.writeToExternalProtocol() 330 | 331 | except AWSIoTExceptions.acceptTimeoutException as e: 332 | self._log.debug(str(e.message)) 333 | break 334 | except Exception as e: 335 | self._log.debug("Exception in run: " + str(type(e)) + str(e.message)) 336 | # traceback.print_exc(file, sys.stdout) 337 | -------------------------------------------------------------------------------- /AWSIoTArduinoYunInstallAll.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # If input args not correct, echo usage 3 | if [ $# -ne 3 ]; then 4 | echo "usage: ./AWSIoTArduinoYunInstallAll.sh " 5 | else 6 | # Welcoming prompt 7 | echo "This script will install all of the depencies and upload the codebase and credentials to the targeted Arduino Yun Board for the AWS IoT Arduino Yun SDK, which includes:" 8 | echo "- Install dependencies" 9 | echo "- Upload codebase" 10 | echo "- Upload credentials" 11 | echo "Please make sure you have included your credentials (private key, certificate and rootCA) in AWS-IoT-Python-Runtime/certs/" 12 | # Load in params 13 | yunBoardIP=$1 14 | yunBoardUserName=$2 15 | yunBoardPassword=$3 16 | pyLibDir="./AWS-IoT-Python-Runtime" 17 | certsDir="$pyLibDir/certs" 18 | # Check to see if AWS-IoT-Python-Runtime/certs/ is empty 19 | if [ "`ls -A $certsDir`" = "" ]; then 20 | echo -e "\nIt seems there are no credentials in $certsDir. Please generate your credentials and put them in that directory.\n" 21 | exit 22 | fi 23 | # Change permission of functional scripts 24 | echo "Changing permissions for functional scripts..." 25 | chmod 755 AWSIoTArduinoYunScp.sh 26 | chmod 755 AWSIoTArduinoYunSetupEnvironment.sh 27 | echo "Done." 28 | # Now start uploading codebase and credentials 29 | echo "Uploading codebase and credentials..." 30 | ./AWSIoTArduinoYunScp.sh $yunBoardIP $yunBoardUserName $yunBoardPassword $pyLibDir /root/ 31 | echo "Done." 32 | # Now start installing codebase on Arduino Yun Board 33 | echo "Installing dependencies on Arduino Yun..." 34 | ./AWSIoTArduinoYunSetupEnvironment.sh $yunBoardIP $yunBoardUserName $yunBoardPassword 35 | echo "Done." 36 | # End of this script 37 | echo "Execution completed!" 38 | fi -------------------------------------------------------------------------------- /AWSIoTArduinoYunScp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect 2 | # This script helps to upload the targeted file/directory to remote Arduino Yun Board 3 | 4 | # Args check 5 | if {$argc!= 5} { 6 | send_user "usage: ./AWSIoTArduinoYunScp.sh \n" 7 | exit 8 | } 9 | 10 | set timeout 10 11 | set ArduinoYunIPAddress [lindex $argv 0] 12 | set ArduinoYunUserName [lindex $argv 1] 13 | set ArduinoYunPassword [lindex $argv 2] 14 | set TargetFile [lindex $argv 3] 15 | set Destination [lindex $argv 4] 16 | set RemoteEndpoint "$ArduinoYunUserName@$ArduinoYunIPAddress:$Destination" 17 | 18 | send_user "Arduino Yun IP is: $ArduinoYunIPAddress\n" 19 | send_user "Arduino Yun User Name is: $ArduinoYunUserName\n" 20 | send_user "\nNow start transmitting $TargetFile to remote directory: $RemoteEndpoint ...\n" 21 | 22 | # scp automatically creates the missing directory 23 | spawn scp -r $TargetFile $RemoteEndpoint 24 | expect { 25 | # In case this is the first time 26 | -re ".*yes/no.*" { 27 | send "yes\r"; exp_continue 28 | -re ".*assword.*" { send "$ArduinoYunPassword\r" } 29 | } 30 | -re ".*assword.*" { send "$ArduinoYunPassword\r" } 31 | } 32 | expect { 33 | eof { 34 | send_user "Completed!\n" 35 | } 36 | } -------------------------------------------------------------------------------- /AWSIoTArduinoYunSetupEnvironment.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect 2 | # This script helps to upload the targeted file/directory to remote Arduino Yun Board 3 | 4 | # Args check 5 | if {$argc!= 3} { 6 | send_user "usage: ./AWSIoTArduinoYunScp.sh \n" 7 | exit 8 | } 9 | 10 | set timeout -1 11 | set ArduinoYunIPAddress [lindex $argv 0] 12 | set ArduinoYunUserName [lindex $argv 1] 13 | set ArduinoYunPassword [lindex $argv 2] 14 | set RemoteEndpoint "$ArduinoYunUserName@$ArduinoYunIPAddress" 15 | 16 | send_user "Arduino Yun IP is: $ArduinoYunIPAddress\n" 17 | send_user "Arduino Yun User Name is: $ArduinoYunUserName\n" 18 | send_user "\nThe following dependencies will be remotely installed on Arduino Yun:\n" 19 | send_user "distribute\npython-openssl\n\n" 20 | send_user "Please wait until the installation completes and the program exits.\n\n" 21 | 22 | # ssh into Arduino Yun and automatically perform the installation 23 | spawn ssh $RemoteEndpoint 24 | expect { 25 | # In case this is the first time 26 | -re ".*yes/no.*" { 27 | send "yes\r"; exp_continue 28 | -re ".*assword.*" { send "$ArduinoYunPassword\r" } 29 | } 30 | -re ".*assword.*" { send "$ArduinoYunPassword\r" } 31 | } 32 | # Install all dependencies 33 | expect "*~#" { send "opkg update\r" } 34 | expect "*~#" { send "opkg install distribute\r" } 35 | expect "*~#" { send "opkg install python-openssl\r" } 36 | expect "*~#" { send "easy_install pip\r" } 37 | expect "*~#" { send "pip install AWSIoTPythonSDK==1.0.0\r" } 38 | expect "*~#" { send "exit\r" } 39 | # End of installation 40 | interact 41 | -------------------------------------------------------------------------------- /AWSIoTArduinoYunWebsocketCredentialConfig.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect 2 | # This script helps to upload the targeted file/directory to remote Arduino Yun Board 3 | 4 | # Args check 5 | if {$argc!=5} { 6 | send_user "usage: ./AWSIoTArduinoYunWebsocketCredentialConfig.sh \n" 7 | exit 8 | } 9 | 10 | set timeout 10 11 | set ArduinoYunIPAddress [lindex $argv 0] 12 | set ArduinoYunUserName [lindex $argv 1] 13 | set ArduinoYunPassword [lindex $argv 2] 14 | set AWS_ACCESS_KEY_ID [lindex $argv 3] 15 | set AWS_SECRET_ACCESS_KEY [lindex $argv 4] 16 | set RemoteEndpoint "$ArduinoYunUserName@$ArduinoYunIPAddress" 17 | set profileFullPath "/etc/profile" 18 | 19 | send_user "Arduino Yun IP is: $ArduinoYunIPAddress\n" 20 | send_user "Arduino Yun User Name is: $ArduinoYunUserName\n" 21 | send_user "New environment variables will be added to Arduino Yun:\n" 22 | send_user "AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID\n" 23 | send_user "AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY\n" 24 | send_user "$profileFullPath will be modified.\n" 25 | send_user "Please wati until the program exits.\n\n" 26 | 27 | # ssh into Arduino Yun and modify $profileFullPath 28 | spawn ssh $RemoteEndpoint 29 | expect { 30 | # In case this is the first time 31 | -re ".*yes/no.*" { 32 | send "yes\r"; exp_continue 33 | -re ".*assword.*" { send "$ArduinoYunPassword\r" } 34 | } 35 | -re ".*assword.*" { send "$ArduinoYunPassword\r" } 36 | } 37 | # Insert new environment variables 38 | expect "*~#" { 39 | # In case we need to update credentials 40 | # Remove the existing AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY 41 | send "sed -i '/^export AWS_ACCESS_KEY_ID=/'d /etc/profile\r" 42 | send "sed -i '/^export AWS_SECRET_ACCESS_KEY=/'d /etc/profile\r" 43 | # Append the new credentials to the end of the file 44 | send "echo export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID >> /etc/profile\r" 45 | send "echo export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY >> /etc/profile\r" 46 | # Enable the new profile 47 | send "source /etc/profile\r" 48 | } 49 | expect "*~#" { send "exit\r" } 50 | # Notification to the user to power-cycle the board 51 | send_user "Credentials added to Yun as environment variables. Now please power-cycle the board." 52 | send_user "Exiting..." 53 | # End of the configuration 54 | interact 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | #2.2.0 (July 5th, 2016) 2 | Features: 3 | 4 | * Migrated Yun Python runtime backend to [AWS IoT Device SDK for Python](https://github.com/aws/aws-iot-device-sdk-python) v1.0.0. 5 | 6 | Bugfixes/Improvements: 7 | 8 | * Finished memory optimization for Yun C++ library and all examples, reducing dynamic memory consumption of examples to around 50%. Adressed part of [issue #13](https://github.com/aws/aws-iot-device-sdk-arduino-yun/issues/13). 9 | * Fixed Serial write buffer issue in examples, addressing [pull request #17](https://github.com/aws/aws-iot-device-sdk-arduino-yun/pull/17). 10 | * Refactored ThermostatSimulatorApp to use [AWS IoT Device SDK for Python](https://github.com/aws/aws-iot-device-sdk-python) v1.0.0. Added support for WebSocket. 11 | 12 | #2.1.1 (May 23th, 2016) 13 | Features: 14 | 15 | N/A 16 | 17 | Bugfixes/Improvements: 18 | 19 | * Fixed issue in retrieving shadow JSON key/value pair where value starts with a certain letter conflicts with the internal protocol. 20 | 21 | # 2.1.0 (May 11th, 2016) 22 | Features: 23 | 24 | * Added new API for configurable offline publish requests queueing for both QoS0 and QoS1. 25 | * Added new API for configurable draining mechanism for queued publish/resubscribe requests. 26 | 27 | Bugfixes/Improvements: 28 | 29 | * Improved auto-resubscribe logic to allow resubscribe requests go out at a configured draining rate. 30 | 31 | # 2.0.0 (April 26th, 2016) 32 | Features: 33 | 34 | * Added support for individual key-value pair access with configurable JSON history limits for shadow JSON document. Nested JSON key-value pair access is also included. 35 | * Added configurable progressive backoff logic in auto-reconnect process. 36 | 37 | Bugfixes/Improvements: 38 | 39 | * Improved API function signature to remove compilation warnings from Arduino IDE v1.6.6+. 40 | * Improved message callback function signature to include message status information for each MQTT messages received. 41 | * Updated shadow examples to use new individual JSON key-value pair access APIs. 42 | 43 | # 1.1.2 (April 1st, 2016) 44 | Features: 45 | 46 | N/A 47 | 48 | Bugfixes/Improvements: 49 | 50 | * Removing the executable bit set on all files 51 | 52 | # 1.1.1 (March 23rd, 2016) 53 | Features: 54 | 55 | N/A 56 | 57 | Bugfixes/Improvements: 58 | 59 | * Improved auto-resubscribe logic. Guaranteed that re-subscribe requests get out and acked before any of the publish requests of the queued messages 60 | 61 | # 1.1.0 (March 8, 2016) 62 | Features: 63 | 64 | * Added support for MQTT over Websocket using AWS Identity and Access Management (IAM) 65 | * Added new API for MQTT Websocket configuration 66 | * Added support for auto-reconnect for MQTT over Websocket 67 | * Added support for auto-resubscribe 68 | 69 | Bugfixes/Improvements: 70 | 71 | N/A 72 | 73 | # 1.0.3 (January 22, 2016) 74 | Features: 75 | 76 | * Switch from subscribe-unsubscribe mechanism to persistent subscription for shadow response processing, avoiding slow rate of shadow requests 77 | * Multiple shadow support 78 | 79 | Bugfixes/Improvements: 80 | 81 | * Detailed error code for better debugging experience directly in Arduino IDE 82 | * New example of device shadow: Thermostat App/Device simulator, with sketch for device and scripts for App both included 83 | 84 | # 1.0.2 (November 5, 2015) 85 | Features: 86 | 87 | N/A 88 | 89 | Bugfixes/Improvements: 90 | 91 | * Added compatibility for Linino openWRT embedded Linux OS (BusyBox v1.19.4 2015-10-03 14:03:26 CEST) 92 | * Refactored file names for credential/codebase upload shell scripts and environment setup shell scripts 93 | 94 | # 1.0.1 (November 3, 2015) 95 | Features: 96 | 97 | N/A 98 | 99 | Bugfixes/Improvements: 100 | 101 | * Updated README.md 102 | * Updated examples with error detection 103 | * Fixed timeout interrupt handler function signature 104 | * Improved background thread termination in Python script 105 | 106 | # 1.0.0 (October 8, 2015) 107 | Features: 108 | 109 | * Release to github 110 | * SDK zip file made available for public download 111 | 112 | Bugfixes/Improvements: 113 | 114 | * Updated README.md 115 | 116 | # 0.2.0 (October 6, 2015) 117 | Features: 118 | 119 | * MQTT publish and subscribe with TLS 120 | * Thing Shadow Actions - Update, Get, Delete for any Thing Name 121 | * Thing Shadow Version Control support for current device Thing Name 122 | 123 | Bugfixes/Improvements: 124 | 125 | * N/A 126 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/aws/aws-iot-device-sdk-arduino-yun/issues), or [recently closed](https://github.com/aws/aws-iot-device-sdk-arduino-yun/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws/aws-iot-device-sdk-arduino-yun/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/aws/aws-iot-device-sdk-arduino-yun/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /ExampleAppScript/ThermostatSimulatorApp/ThermostatSimulatorApp.py: -------------------------------------------------------------------------------- 1 | ''' 2 | /* 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | ''' 17 | 18 | import sys 19 | import getopt 20 | import time 21 | import json 22 | import glob 23 | from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient 24 | # Tkinter 25 | try: 26 | import tkinter # Python 3.x 27 | except ImportError: 28 | import Tkinter as tkinter 29 | 30 | # Class that defines and manages callback used in this app 31 | class ThermoSimAppCallbackPool: 32 | def __init__(self, srcTkRoot, srcReportedDataDisplayBox, srcDeviceShadowHandler, srcReportedDataVariable, srcDesiredDataVariable): 33 | self._tkRootHandler = srcTkRoot 34 | self._reportedDataDisplayBox = srcReportedDataDisplayBox 35 | self._reportedDataVariableHandler = srcReportedDataVariable 36 | self._desiredDataVariableHandler = srcDesiredDataVariable 37 | self._deviceShadowHandler = srcDeviceShadowHandler 38 | self._reportedTemperatureDataFromNetwork = "XX.X" 39 | 40 | def buttonCallback(self, srcSetTemperatureInputBox, srcDesiredDataVariable): 41 | desiredData = None 42 | try: 43 | desiredData = "{:.1f}".format((float)(srcSetTemperatureInputBox.get())) 44 | if float(desiredData) >= 100.0: 45 | print("Cannot set temperature higher than 100 F.") 46 | elif float(desiredData) <= -100.0: 47 | print("Cannot set temperature lower than -100 F.") 48 | else: 49 | JSONString = '{"state":{"desired":{"Temp":' + str(desiredData) + '}}}' 50 | srcDesiredDataVariable.set(str(desiredData) + " F") 51 | self._deviceShadowHandler.shadowUpdate(JSONString, None, 5) 52 | except ValueError: 53 | print("Setting desired temperature: Invalid temperature value!") 54 | except Exception as e: 55 | print(e.message) 56 | 57 | def shadowGetCallback(self, payload, responseStatus, token): 58 | print(payload) 59 | print("---------------") 60 | print(responseStatus) 61 | print("\n\n") 62 | if responseStatus == "accepted": 63 | try: 64 | JSONResponseDictionary = json.loads(payload) 65 | self._reportedTemperatureDataFromNetwork = JSONResponseDictionary[u"state"][u"reported"][u"Temp"] 66 | except: 67 | print("Invalid JSON or missing attribute") 68 | 69 | def sendShadowGetForReportedTemperature(self, event=None): 70 | try: 71 | self._deviceShadowHandler.shadowGet(self.shadowGetCallback, 5) 72 | except Exception as e: 73 | print(e.message) 74 | self._tkRootHandler.after(500, self.sendShadowGetForReportedTemperature) 75 | 76 | def updateReportedTemperatureDataVariable(self, event=None): 77 | # Also update the color 78 | currentDesiredData = self._desiredDataVariableHandler.get()[:4] 79 | if currentDesiredData != "XX.X": 80 | if self._reportedTemperatureDataFromNetwork > float(currentDesiredData): 81 | self._reportedDataDisplayBox.config(fg="blue") 82 | elif self._reportedTemperatureDataFromNetwork < float(currentDesiredData): 83 | self._reportedDataDisplayBox.config(fg="red") 84 | else: 85 | self._reportedDataDisplayBox.config(fg="black") 86 | self._reportedDataVariableHandler.set(str(self._reportedTemperatureDataFromNetwork) + " F") 87 | self._tkRootHandler.after(500, self.updateReportedTemperatureDataVariable) 88 | 89 | # Class that generates the GUI and starts the application 90 | class ThermoSimAppGUI: 91 | 92 | _usage = """Usage: 93 | 94 | Make sure that you put all your credentials under: ./certs/ 95 | with the following naming conventions: 96 | Root CA file: *CA.crt 97 | Certificate file (not required if using MQTT over WebSocket): *.pem.crt 98 | Private key file (not required if using MQTT over WebSocket): *.pem.key 99 | 100 | Use X.509 certificate based mutual authentication: 101 | python ThermostatSimulatorApp -e 102 | 103 | Use MQTT over WebSocket: 104 | python ThermostatSimulatorApp -e -w 105 | 106 | Type "python ThermostatSimulatorApp -h" for detailed command line options. 107 | 108 | 109 | """ 110 | 111 | _helpInfo = """Available command line options: 112 | -e, --endpoint: Your custom AWS IoT custom endpoint 113 | -w, --websocket: Use MQTT over websocket 114 | -h, --help: Help infomation 115 | 116 | 117 | """ 118 | 119 | def __init__(self): 120 | # Init data members 121 | # Connection related 122 | self._endpoint = "" 123 | self._rootCAFilePathList = "" 124 | self._certificateFilePathList = "" 125 | self._privateKeyFilePathList = "" 126 | self._useWebsocket = False 127 | self._AWSIoTMQTTShadowClient = None 128 | self._thermostatSimulatorShadowHandler = None 129 | # GUI related 130 | self._tkRootHandler = tkinter.Tk() 131 | self._reportedDataVariable = None 132 | self._reportedDataDisplayBox = None 133 | self._desiredDataVariable = None 134 | self._desiredDataDisplayBox = None 135 | self._setTemperatureInputBox = None 136 | self._setTemperatureButton = None 137 | # Check command line inputs 138 | if not self._checkInputs(): 139 | raise ValueError("Malformed/Missing command line inputs.") 140 | # Create and configure AWSIoTMQTTShadowClient 141 | self._AWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient("ThermostatSimulatorApp", useWebsocket=self._useWebsocket) 142 | if self._useWebsocket: 143 | self._AWSIoTMQTTShadowClient.configureEndpoint(self._endpoint, 443) 144 | self._AWSIoTMQTTShadowClient.configureCredentials(self._rootCAFilePathList[0]) 145 | else: 146 | self._AWSIoTMQTTShadowClient.configureEndpoint(self._endpoint, 8883) 147 | self._AWSIoTMQTTShadowClient.configureCredentials(self._rootCAFilePathList[0], self._privateKeyFilePathList[0], self._certificateFilePathList[0]) 148 | self._AWSIoTMQTTShadowClient.configureAutoReconnectBackoffTime(1, 128, 20) 149 | self._AWSIoTMQTTShadowClient.configureConnectDisconnectTimeout(10) 150 | self._AWSIoTMQTTShadowClient.configureMQTTOperationTimeout(5) 151 | # Set keepAlive interval to be 1 second and connect 152 | # Raise exception if there is an error in connecting to AWS IoT 153 | self._AWSIoTMQTTShadowClient.connect(5) 154 | self._thermostatSimulatorShadowHandler = self._AWSIoTMQTTShadowClient.createShadowHandlerWithName("room", True) 155 | # Generate GUI 156 | self._packModule() 157 | 158 | # Validate command line inputs 159 | # Return False there is any malformed inputs 160 | # Return True if all the necessary inputs have been discovered 161 | def _checkInputs(self): 162 | gotEoughInputs = True 163 | # Check command line inputs 164 | try: 165 | opts, args = getopt.getopt(sys.argv[1:], "hwe:", ["endpoint=", "websocket", "help"]) 166 | if len(opts) == 0: 167 | raise getopt.GetoptError("No input parameters") 168 | for opt, arg in opts: 169 | if opt in ("-e", "--endpoint"): 170 | self._endpoint = arg 171 | if opt in ("-w", "--websocket"): 172 | self._useWebsocket = True 173 | if opt in ("-h", "--help"): 174 | print(self._helpInfo) 175 | gotEoughInputs = False 176 | except getopt.GetoptError: 177 | print(self._usage) 178 | gotEoughInputs = False 179 | # Check credential files 180 | if gotEoughInputs: 181 | self._rootCAFilePathList = glob.glob("./certs/*CA.crt") 182 | if self._useWebsocket: 183 | gotEoughInputs = gotEoughInputs and len(self._rootCAFilePathList) != 0 184 | if not gotEoughInputs: 185 | print("Missing rootCA in ./certs/") 186 | else: 187 | self._certificateFilePathList = glob.glob("./certs/*.pem.crt") 188 | self._privateKeyFilePathList = glob.glob("./certs/*.pem.key") 189 | gotEoughInputs = gotEoughInputs and len(self._rootCAFilePathList) != 0 and len(self._certificateFilePathList) != 0 and len(self._privateKeyFilePathList) != 0 190 | if not gotEoughInputs: 191 | print("Missing rootCA, certificate or private key in ./certs/") 192 | return gotEoughInputs 193 | 194 | def _packModule(self): 195 | self._tkRootHandler.title("ThermostatSimulatorApp") 196 | self._tkRootHandler.geometry("500x250") 197 | self._tkRootHandler.resizable(width=False, height=False) 198 | # Pack all frames 199 | baseFrame = tkinter.Frame(self._tkRootHandler) 200 | temperatureFrame = tkinter.Frame(baseFrame) 201 | temperatureFrame.pack(side="top") 202 | controlPanelFrame = tkinter.Frame(baseFrame) 203 | controlPanelFrame.pack(side="bottom") 204 | baseFrame.pack() 205 | # Pack all modules for temperature frame 206 | self._reportedDataVariable = tkinter.StringVar() 207 | self._reportedDataVariable.set("XX.X F") 208 | reportedDataTag = tkinter.Label(temperatureFrame, text="Reported Temperature:", justify="left") 209 | self._reportedDataDisplayBox = tkinter.Label(temperatureFrame, textvariable=self._reportedDataVariable, font=("Arial", 55), justify="left") 210 | # 211 | self._desiredDataVariable = tkinter.StringVar() 212 | self._desiredDataVariable.set("XX.X F") 213 | desiredDataTag = tkinter.Label(temperatureFrame, text="Desired Temperature:", justify="left") 214 | self._desiredDataDisplayBox = tkinter.Label(temperatureFrame, textvariable=self._desiredDataVariable, font=("Arial", 55), justify="left") 215 | # 216 | reportedDataTag.pack() 217 | self._reportedDataDisplayBox.pack() 218 | desiredDataTag.pack() 219 | self._desiredDataDisplayBox.pack() 220 | # Create a callback pool 221 | self._callbackPoolHandler = ThermoSimAppCallbackPool(self._tkRootHandler, self._reportedDataDisplayBox, self._thermostatSimulatorShadowHandler, self._reportedDataVariable, self._desiredDataVariable) 222 | # Pack all modules for control panel frame 223 | self._setTemperatureInputBox = tkinter.Entry(controlPanelFrame) 224 | self._setTemperatureInputBox.pack(sid="left") 225 | self._setTemperatureButton = tkinter.Button(controlPanelFrame, text="SET", command=lambda: self._callbackPoolHandler.buttonCallback(self._setTemperatureInputBox, self._desiredDataVariable)) 226 | self._setTemperatureButton.pack() 227 | 228 | def runApp(self): 229 | # Start and run the app 230 | self._tkRootHandler.after(500, self._callbackPoolHandler.sendShadowGetForReportedTemperature) # per 500ms 231 | self._tkRootHandler.after(500, self._callbackPoolHandler.updateReportedTemperatureDataVariable) # per 500ms 232 | self._tkRootHandler.mainloop() 233 | 234 | # Main 235 | if __name__ == '__main__': 236 | # Start the app 237 | try: 238 | thisThermoSimAppGUI = ThermoSimAppGUI() 239 | thisThermoSimAppGUI.runApp() 240 | except ValueError: 241 | print("Terminated.") 242 | except KeyboardInterrupt: 243 | print("Terminated.") 244 | 245 | -------------------------------------------------------------------------------- /ExampleAppScript/ThermostatSimulatorApp/certs/delete.me: -------------------------------------------------------------------------------- 1 | Please place your credentials in this directory. 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ############################################################################################################################# 2 | 3 | 4 | Apache License 5 | Version 2.0, January 2004 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 11 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 12 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 13 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 14 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 15 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 16 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 17 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 18 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 19 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 20 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 21 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 22 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 23 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and 24 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and 25 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 26 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 27 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 28 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 29 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 30 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 31 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 32 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 33 | 34 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | AWS Arduino Yun SDK for Internet of Things Service 2 | Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | This product includes software developed by 5 | Amazon Inc (http://www.amazon.com/). --------------------------------------------------------------------------------