Demo application for using the AT&T IoT Starter Kit Powered by AWS.
Dependencies: SDFileSystem
Fork of ATT_AWS_IoT_demo by
IoT Starter Kit Powered by AWS Demo
This program demonstrates the AT&T IoT Starter Kit sending data directly into AWS IoT. It's explained and used in the Getting Started with the IoT Starter Kit Powered by AWS on starterkit.att.com.
What's required
- AT&T IoT LTE Add-on (also known as the Cellular Shield)
- NXP K64F - for programming
- microSD card - used to store your AWS security credentials
- AWS account
- Python, locally installed
If you don't already have an IoT Starter Kit, you can purchase a kit here. The IoT Starter Kit Powered by AWS includes the LTE cellular shield, K64F, and a microSD card.
PythonGUI/ATT_AWS_IoT_Demo_GUI.py@19:488dad1e168e, 2016-12-06 (annotated)
- Committer:
- ampembeng
- Date:
- Tue Dec 06 22:45:00 2016 +0000
- Revision:
- 19:488dad1e168e
- Parent:
- 17:46780b2de3e4
- Child:
- 20:ee34856ae510
Added Python GUI changes that match the SD card changes so Python no longer requires code updates to run the demo either.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ampembeng | 17:46780b2de3e4 | 1 | ''' |
ampembeng | 17:46780b2de3e4 | 2 | /* |
ampembeng | 17:46780b2de3e4 | 3 | * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
ampembeng | 17:46780b2de3e4 | 4 | * |
ampembeng | 17:46780b2de3e4 | 5 | * Licensed under the Apache License, Version 2.0 (the "License"). |
ampembeng | 17:46780b2de3e4 | 6 | * You may not use this file except in compliance with the License. |
ampembeng | 17:46780b2de3e4 | 7 | * A copy of the License is located at |
ampembeng | 17:46780b2de3e4 | 8 | * |
ampembeng | 17:46780b2de3e4 | 9 | * http://aws.amazon.com/apache2.0 |
ampembeng | 17:46780b2de3e4 | 10 | * |
ampembeng | 17:46780b2de3e4 | 11 | * or in the "license" file accompanying this file. This file is distributed |
ampembeng | 17:46780b2de3e4 | 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
ampembeng | 17:46780b2de3e4 | 13 | * express or implied. See the License for the specific language governing |
ampembeng | 17:46780b2de3e4 | 14 | * permissions and limitations under the License. |
ampembeng | 17:46780b2de3e4 | 15 | */ |
ampembeng | 17:46780b2de3e4 | 16 | ''' |
ampembeng | 17:46780b2de3e4 | 17 | |
ampembeng | 17:46780b2de3e4 | 18 | from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient |
ampembeng | 17:46780b2de3e4 | 19 | import sys |
ampembeng | 17:46780b2de3e4 | 20 | import os.path |
ampembeng | 17:46780b2de3e4 | 21 | import logging |
ampembeng | 17:46780b2de3e4 | 22 | import time |
ampembeng | 17:46780b2de3e4 | 23 | import json |
ampembeng | 19:488dad1e168e | 24 | import re |
ampembeng | 17:46780b2de3e4 | 25 | import getopt |
ampembeng | 17:46780b2de3e4 | 26 | import Tkinter |
ampembeng | 17:46780b2de3e4 | 27 | import tkFont |
ampembeng | 17:46780b2de3e4 | 28 | import time |
ampembeng | 17:46780b2de3e4 | 29 | from threading import Timer |
ampembeng | 17:46780b2de3e4 | 30 | from Tkinter import * |
ampembeng | 17:46780b2de3e4 | 31 | |
ampembeng | 17:46780b2de3e4 | 32 | ####################################################################################################################### |
ampembeng | 17:46780b2de3e4 | 33 | # |
ampembeng | 17:46780b2de3e4 | 34 | # Set up our Tkinter based GUI |
ampembeng | 17:46780b2de3e4 | 35 | # |
ampembeng | 17:46780b2de3e4 | 36 | ####################################################################################################################### |
ampembeng | 17:46780b2de3e4 | 37 | accepted = ["0", "1", "2", "4", "7"] |
ampembeng | 17:46780b2de3e4 | 38 | colorDict = {0 : 'off', 1 : 'red', 2 : 'green', 4 : "blue", 7 : "white"} |
ampembeng | 17:46780b2de3e4 | 39 | |
ampembeng | 17:46780b2de3e4 | 40 | window = Tkinter.Tk() |
ampembeng | 17:46780b2de3e4 | 41 | window.wm_title("AT&T AWS IoT Demo") |
ampembeng | 17:46780b2de3e4 | 42 | |
ampembeng | 17:46780b2de3e4 | 43 | topframe = Frame(window) |
ampembeng | 17:46780b2de3e4 | 44 | topframe.pack() |
ampembeng | 17:46780b2de3e4 | 45 | bottomframe = Frame(window) |
ampembeng | 17:46780b2de3e4 | 46 | bottomframe.pack( side = BOTTOM ) |
ampembeng | 17:46780b2de3e4 | 47 | |
ampembeng | 17:46780b2de3e4 | 48 | statusLabel = StringVar() |
ampembeng | 17:46780b2de3e4 | 49 | statusString = StringVar() |
ampembeng | 17:46780b2de3e4 | 50 | |
ampembeng | 17:46780b2de3e4 | 51 | # Control callbacks |
ampembeng | 17:46780b2de3e4 | 52 | def setStatus(statusStr): |
ampembeng | 17:46780b2de3e4 | 53 | if(statusString == statusStr): |
ampembeng | 17:46780b2de3e4 | 54 | statusString.set("unknown") |
ampembeng | 17:46780b2de3e4 | 55 | else: |
ampembeng | 17:46780b2de3e4 | 56 | statusString.set(statusStr) |
ampembeng | 17:46780b2de3e4 | 57 | |
ampembeng | 17:46780b2de3e4 | 58 | def offButtonCallBack(): |
ampembeng | 17:46780b2de3e4 | 59 | sendLEDRequest("0") |
ampembeng | 17:46780b2de3e4 | 60 | |
ampembeng | 17:46780b2de3e4 | 61 | def redButtonCallBack(): |
ampembeng | 17:46780b2de3e4 | 62 | sendLEDRequest("1") |
ampembeng | 17:46780b2de3e4 | 63 | |
ampembeng | 17:46780b2de3e4 | 64 | def greenButtonCallBack(): |
ampembeng | 17:46780b2de3e4 | 65 | sendLEDRequest("2") |
ampembeng | 17:46780b2de3e4 | 66 | |
ampembeng | 17:46780b2de3e4 | 67 | def blueButtonCallBack(): |
ampembeng | 17:46780b2de3e4 | 68 | sendLEDRequest("4") |
ampembeng | 17:46780b2de3e4 | 69 | |
ampembeng | 17:46780b2de3e4 | 70 | def whiteButtonCallBack(): |
ampembeng | 17:46780b2de3e4 | 71 | sendLEDRequest("7") |
ampembeng | 17:46780b2de3e4 | 72 | |
ampembeng | 17:46780b2de3e4 | 73 | # Create our Labels |
ampembeng | 17:46780b2de3e4 | 74 | StaticLabel = Label(topframe, textvariable=statusLabel, relief=FLAT) |
ampembeng | 17:46780b2de3e4 | 75 | statusLabel.set("AWS Reported LED Status: ") |
ampembeng | 17:46780b2de3e4 | 76 | |
ampembeng | 17:46780b2de3e4 | 77 | StatusLabel = Label(topframe, textvariable=statusString, relief=FLAT) |
ampembeng | 17:46780b2de3e4 | 78 | statusString.set("unknown (needs to sync)") |
ampembeng | 17:46780b2de3e4 | 79 | |
ampembeng | 17:46780b2de3e4 | 80 | # Create our Buttons |
ampembeng | 17:46780b2de3e4 | 81 | O = Tkinter.Button(bottomframe, text ="Off", fg="gray", bg="black", command = offButtonCallBack) |
ampembeng | 17:46780b2de3e4 | 82 | R = Tkinter.Button(bottomframe, text ="R", fg="gray", bg="red", command = redButtonCallBack) |
ampembeng | 17:46780b2de3e4 | 83 | G = Tkinter.Button(bottomframe, text ="G", fg="gray", bg="green", command = greenButtonCallBack) |
ampembeng | 17:46780b2de3e4 | 84 | B = Tkinter.Button(bottomframe, text ="B", fg="gray", bg="blue", command = blueButtonCallBack) |
ampembeng | 17:46780b2de3e4 | 85 | W = Tkinter.Button(bottomframe, text ="W", fg="gray", bg="white", command = whiteButtonCallBack) |
ampembeng | 17:46780b2de3e4 | 86 | |
ampembeng | 17:46780b2de3e4 | 87 | # Set font |
ampembeng | 17:46780b2de3e4 | 88 | font = tkFont.Font(family='Times', size=24, weight='bold') |
ampembeng | 17:46780b2de3e4 | 89 | O['font'] = font |
ampembeng | 17:46780b2de3e4 | 90 | R['font'] = font |
ampembeng | 17:46780b2de3e4 | 91 | G['font'] = font |
ampembeng | 17:46780b2de3e4 | 92 | B['font'] = font |
ampembeng | 17:46780b2de3e4 | 93 | W['font'] = font |
ampembeng | 17:46780b2de3e4 | 94 | |
ampembeng | 17:46780b2de3e4 | 95 | # Arrange our controls |
ampembeng | 17:46780b2de3e4 | 96 | StaticLabel.pack(side = LEFT) |
ampembeng | 17:46780b2de3e4 | 97 | StatusLabel.pack(side = LEFT) |
ampembeng | 17:46780b2de3e4 | 98 | O.pack(side = LEFT) |
ampembeng | 17:46780b2de3e4 | 99 | R.pack(side = LEFT) |
ampembeng | 17:46780b2de3e4 | 100 | G.pack(side = LEFT) |
ampembeng | 17:46780b2de3e4 | 101 | B.pack(side = LEFT) |
ampembeng | 17:46780b2de3e4 | 102 | W.pack(side = LEFT) |
ampembeng | 17:46780b2de3e4 | 103 | |
ampembeng | 17:46780b2de3e4 | 104 | ####################################################################################################################### |
ampembeng | 17:46780b2de3e4 | 105 | # |
ampembeng | 17:46780b2de3e4 | 106 | # These functions are for AWS |
ampembeng | 17:46780b2de3e4 | 107 | # |
ampembeng | 17:46780b2de3e4 | 108 | ####################################################################################################################### |
ampembeng | 17:46780b2de3e4 | 109 | # Shadow JSON schema: |
ampembeng | 17:46780b2de3e4 | 110 | # |
ampembeng | 17:46780b2de3e4 | 111 | # Name: Bot |
ampembeng | 17:46780b2de3e4 | 112 | # { |
ampembeng | 17:46780b2de3e4 | 113 | # "state": { |
ampembeng | 17:46780b2de3e4 | 114 | # "desired":{ |
ampembeng | 17:46780b2de3e4 | 115 | # "ledColor":<INT VALUE> |
ampembeng | 17:46780b2de3e4 | 116 | # } |
ampembeng | 17:46780b2de3e4 | 117 | # } |
ampembeng | 17:46780b2de3e4 | 118 | #} |
ampembeng | 17:46780b2de3e4 | 119 | |
ampembeng | 17:46780b2de3e4 | 120 | def sendLEDRequest(color_input): |
ampembeng | 17:46780b2de3e4 | 121 | if (color_input in accepted): |
ampembeng | 17:46780b2de3e4 | 122 | JSONPayload = '{"state":{"desired":{"ledColor":' + str(color_input) + '}}}' |
ampembeng | 17:46780b2de3e4 | 123 | Bot.shadowUpdate(JSONPayload, customShadowCallback_Update, 5) |
ampembeng | 17:46780b2de3e4 | 124 | else: |
ampembeng | 17:46780b2de3e4 | 125 | print("WARN: Color input invalid - " + color_input) |
ampembeng | 17:46780b2de3e4 | 126 | |
ampembeng | 17:46780b2de3e4 | 127 | # Custom Shadow callback |
ampembeng | 17:46780b2de3e4 | 128 | def customShadowCallback_Delta(payload, responseStatus, token): |
ampembeng | 17:46780b2de3e4 | 129 | # payload is a JSON string ready to be parsed using json.loads(...) |
ampembeng | 17:46780b2de3e4 | 130 | # in both Py2.x and Py3.x |
ampembeng | 17:46780b2de3e4 | 131 | print(responseStatus) |
ampembeng | 17:46780b2de3e4 | 132 | payloadDict = json.loads(payload) |
ampembeng | 17:46780b2de3e4 | 133 | print("++++++++DELTA++++++++++") |
ampembeng | 17:46780b2de3e4 | 134 | print("ledColor: " + str(payloadDict["state"]["ledColor"])) |
ampembeng | 17:46780b2de3e4 | 135 | print("version: " + str(payloadDict["version"])) |
ampembeng | 17:46780b2de3e4 | 136 | print("+++++++++++++++++++++++\n\n") |
ampembeng | 17:46780b2de3e4 | 137 | |
ampembeng | 17:46780b2de3e4 | 138 | # Custom Shadow callback |
ampembeng | 17:46780b2de3e4 | 139 | def customShadowCallback_Update(payload, responseStatus, token): |
ampembeng | 17:46780b2de3e4 | 140 | # payload is a JSON string ready to be parsed using json.loads(...) |
ampembeng | 17:46780b2de3e4 | 141 | # in both Py2.x and Py3.x |
ampembeng | 17:46780b2de3e4 | 142 | if responseStatus == "timeout": |
ampembeng | 17:46780b2de3e4 | 143 | print("Update request " + token + " time out!") |
ampembeng | 17:46780b2de3e4 | 144 | if responseStatus == "accepted": |
ampembeng | 17:46780b2de3e4 | 145 | payloadDict = json.loads(payload) |
ampembeng | 17:46780b2de3e4 | 146 | print("~~~~~~~~~~~~~~~~~~~~~~~") |
ampembeng | 17:46780b2de3e4 | 147 | print("Update request with token: " + token + " accepted!") |
ampembeng | 17:46780b2de3e4 | 148 | print("ledColor: " + str(payloadDict["state"]["desired"]["ledColor"])) |
ampembeng | 17:46780b2de3e4 | 149 | print("~~~~~~~~~~~~~~~~~~~~~~~\n\n") |
ampembeng | 17:46780b2de3e4 | 150 | if responseStatus == "rejected": |
ampembeng | 17:46780b2de3e4 | 151 | print("Update request " + token + " rejected!") |
ampembeng | 17:46780b2de3e4 | 152 | |
ampembeng | 17:46780b2de3e4 | 153 | def customShadowCallback_Delete(payload, responseStatus, token): |
ampembeng | 17:46780b2de3e4 | 154 | if responseStatus == "timeout": |
ampembeng | 17:46780b2de3e4 | 155 | print("Delete request " + token + " time out!") |
ampembeng | 17:46780b2de3e4 | 156 | if responseStatus == "accepted": |
ampembeng | 17:46780b2de3e4 | 157 | print("~~~~~~~~~~~~~~~~~~~~~~~") |
ampembeng | 17:46780b2de3e4 | 158 | print("Delete request with token: " + token + " accepted!") |
ampembeng | 17:46780b2de3e4 | 159 | print("~~~~~~~~~~~~~~~~~~~~~~~\n\n") |
ampembeng | 17:46780b2de3e4 | 160 | if responseStatus == "rejected": |
ampembeng | 17:46780b2de3e4 | 161 | print("Delete request " + token + " rejected!") |
ampembeng | 17:46780b2de3e4 | 162 | |
ampembeng | 17:46780b2de3e4 | 163 | # Custom Shadow callback |
ampembeng | 17:46780b2de3e4 | 164 | def customShadowCallback_Get(payload, responseStatus, token): |
ampembeng | 17:46780b2de3e4 | 165 | print(responseStatus) |
ampembeng | 17:46780b2de3e4 | 166 | payloadDict = json.loads(payload) |
ampembeng | 17:46780b2de3e4 | 167 | reportedColor = payloadDict["state"]["reported"]["ledColor"] |
ampembeng | 17:46780b2de3e4 | 168 | print("++++++++GET++++++++++") |
ampembeng | 17:46780b2de3e4 | 169 | print("ledColor: " + str(reportedColor) + " (" + colorDict[reportedColor] + ")") |
ampembeng | 17:46780b2de3e4 | 170 | print("version: " + str(payloadDict["version"])) |
ampembeng | 17:46780b2de3e4 | 171 | print("+++++++++++++++++++++\n\n") |
ampembeng | 17:46780b2de3e4 | 172 | |
ampembeng | 17:46780b2de3e4 | 173 | # Send payload to our status |
ampembeng | 17:46780b2de3e4 | 174 | setStatus(colorDict[reportedColor]) |
ampembeng | 17:46780b2de3e4 | 175 | |
ampembeng | 17:46780b2de3e4 | 176 | getTimerAlive = TRUE |
ampembeng | 17:46780b2de3e4 | 177 | def customShadowTimer_Get(): |
ampembeng | 17:46780b2de3e4 | 178 | while (getTimerAlive): |
ampembeng | 17:46780b2de3e4 | 179 | Bot.shadowGet(customShadowCallback_Get, 5) |
ampembeng | 17:46780b2de3e4 | 180 | time.sleep(3) |
ampembeng | 17:46780b2de3e4 | 181 | |
ampembeng | 17:46780b2de3e4 | 182 | ####################################################################################################################### |
ampembeng | 17:46780b2de3e4 | 183 | # |
ampembeng | 17:46780b2de3e4 | 184 | # Vars |
ampembeng | 17:46780b2de3e4 | 185 | # |
ampembeng | 17:46780b2de3e4 | 186 | ####################################################################################################################### |
ampembeng | 17:46780b2de3e4 | 187 | # Usage |
ampembeng | 17:46780b2de3e4 | 188 | usageInfo = """Usage: |
ampembeng | 17:46780b2de3e4 | 189 | |
ampembeng | 17:46780b2de3e4 | 190 | Use certificate based mutual authentication: |
ampembeng | 17:46780b2de3e4 | 191 | python basicShadowDeltaListener.py -e <endpoint> -r <rootCAFilePath> -c <certFilePath> -k <privateKeyFilePath> |
ampembeng | 17:46780b2de3e4 | 192 | |
ampembeng | 17:46780b2de3e4 | 193 | Use MQTT over WebSocket: |
ampembeng | 17:46780b2de3e4 | 194 | python basicShadowDeltaListener.py -e <endpoint> -r <rootCAFilePath> -w |
ampembeng | 17:46780b2de3e4 | 195 | |
ampembeng | 17:46780b2de3e4 | 196 | Type "python basicShadowDeltaListener.py -h" for available options. |
ampembeng | 17:46780b2de3e4 | 197 | |
ampembeng | 17:46780b2de3e4 | 198 | |
ampembeng | 17:46780b2de3e4 | 199 | """ |
ampembeng | 17:46780b2de3e4 | 200 | # Help info |
ampembeng | 17:46780b2de3e4 | 201 | helpInfo = """-e, --endpoint |
ampembeng | 17:46780b2de3e4 | 202 | Your AWS IoT custom endpoint |
ampembeng | 17:46780b2de3e4 | 203 | -r, --rootCA |
ampembeng | 17:46780b2de3e4 | 204 | Root CA file path |
ampembeng | 17:46780b2de3e4 | 205 | -c, --cert |
ampembeng | 17:46780b2de3e4 | 206 | Certificate file path |
ampembeng | 17:46780b2de3e4 | 207 | -k, --key |
ampembeng | 17:46780b2de3e4 | 208 | Private key file path |
ampembeng | 17:46780b2de3e4 | 209 | -w, --websocket |
ampembeng | 17:46780b2de3e4 | 210 | Use MQTT over WebSocket |
ampembeng | 17:46780b2de3e4 | 211 | -h, --help |
ampembeng | 17:46780b2de3e4 | 212 | Help information |
ampembeng | 17:46780b2de3e4 | 213 | |
ampembeng | 17:46780b2de3e4 | 214 | |
ampembeng | 17:46780b2de3e4 | 215 | """ |
ampembeng | 17:46780b2de3e4 | 216 | |
ampembeng | 17:46780b2de3e4 | 217 | ####################################################################################################################### |
ampembeng | 17:46780b2de3e4 | 218 | # |
ampembeng | 17:46780b2de3e4 | 219 | # AWS IoT Config Parameters. The user needs to enter these (they should match the parameters in aws_iot_config.h) |
ampembeng | 17:46780b2de3e4 | 220 | # |
ampembeng | 17:46780b2de3e4 | 221 | ####################################################################################################################### |
ampembeng | 19:488dad1e168e | 222 | useWebsocket = False # The FRDM-K64F demo isn't designed to work with web socket |
ampembeng | 19:488dad1e168e | 223 | hardCodeMQTT = False # Set this to true if you want to hard code the MQTT params below |
ampembeng | 19:488dad1e168e | 224 | |
ampembeng | 19:488dad1e168e | 225 | # AWS parameters |
ampembeng | 19:488dad1e168e | 226 | AWS_IOT_MQTT_HOST = "TODO" |
ampembeng | 17:46780b2de3e4 | 227 | AWS_IOT_MQTT_PORT = 8883 |
ampembeng | 19:488dad1e168e | 228 | AWS_IOT_MQTT_CLIENT_ID = "TODO" |
ampembeng | 19:488dad1e168e | 229 | AWS_IOT_MY_THING_NAME = "TODO" |
ampembeng | 19:488dad1e168e | 230 | AWS_MQTT_CONFIG_FILENAME = "C:/Temp/certs/mqtt_config.txt" |
ampembeng | 17:46780b2de3e4 | 231 | AWS_IOT_ROOT_CA_FILENAME = "C:/Temp/certs/rootCA-certificate.crt" |
ampembeng | 17:46780b2de3e4 | 232 | AWS_IOT_PRIVATE_KEY_FILENAME = "C:/Temp/certs/private.pem.key" |
ampembeng | 17:46780b2de3e4 | 233 | AWS_IOT_CERTIFICATE_FILENAME = "C:/Temp/certs/certificate.pem.crt" |
ampembeng | 17:46780b2de3e4 | 234 | |
ampembeng | 17:46780b2de3e4 | 235 | ####################################################################################################################### |
ampembeng | 17:46780b2de3e4 | 236 | # |
ampembeng | 19:488dad1e168e | 237 | # Arg Parser (TODO) |
ampembeng | 17:46780b2de3e4 | 238 | # |
ampembeng | 17:46780b2de3e4 | 239 | ####################################################################################################################### |
ampembeng | 17:46780b2de3e4 | 240 | ''' |
ampembeng | 17:46780b2de3e4 | 241 | try: |
ampembeng | 17:46780b2de3e4 | 242 | opts, args = getopt.getopt(sys.argv[1:], "hwe:k:c:r:", ["help", "endpoint=", "key=","cert=","rootCA=", "websocket"]) |
ampembeng | 17:46780b2de3e4 | 243 | if len(opts) == 0: |
ampembeng | 17:46780b2de3e4 | 244 | raise getopt.GetoptError("No input parameters!") |
ampembeng | 17:46780b2de3e4 | 245 | for opt, arg in opts: |
ampembeng | 17:46780b2de3e4 | 246 | if opt in ("-h", "--help"): |
ampembeng | 17:46780b2de3e4 | 247 | print(helpInfo) |
ampembeng | 17:46780b2de3e4 | 248 | exit(0) |
ampembeng | 17:46780b2de3e4 | 249 | if opt in ("-e", "--endpoint"): |
ampembeng | 17:46780b2de3e4 | 250 | AWS_IOT_MQTT_HOST = arg |
ampembeng | 17:46780b2de3e4 | 251 | if opt in ("-r", "--rootCA"): |
ampembeng | 17:46780b2de3e4 | 252 | AWS_IOT_ROOT_CA_FILENAME = arg |
ampembeng | 17:46780b2de3e4 | 253 | if opt in ("-c", "--cert"): |
ampembeng | 17:46780b2de3e4 | 254 | AWS_IOT_CERTIFICATE_FILENAME = arg |
ampembeng | 17:46780b2de3e4 | 255 | if opt in ("-k", "--key"): |
ampembeng | 17:46780b2de3e4 | 256 | AWS_IOT_PRIVATE_KEY_FILENAME = arg |
ampembeng | 17:46780b2de3e4 | 257 | if opt in ("-w", "--websocket"): |
ampembeng | 17:46780b2de3e4 | 258 | useWebsocket = True |
ampembeng | 17:46780b2de3e4 | 259 | except getopt.GetoptError: |
ampembeng | 17:46780b2de3e4 | 260 | print(usageInfo) |
ampembeng | 17:46780b2de3e4 | 261 | #exit(1) |
ampembeng | 17:46780b2de3e4 | 262 | |
ampembeng | 17:46780b2de3e4 | 263 | # Missing configuration notification |
ampembeng | 17:46780b2de3e4 | 264 | missingConfiguration = False |
ampembeng | 17:46780b2de3e4 | 265 | if not AWS_IOT_MQTT_HOST: |
ampembeng | 17:46780b2de3e4 | 266 | print("Missing '-e' or '--endpoint'") |
ampembeng | 17:46780b2de3e4 | 267 | missingConfiguration = True |
ampembeng | 17:46780b2de3e4 | 268 | if not AWS_IOT_ROOT_CA_FILENAME: |
ampembeng | 17:46780b2de3e4 | 269 | print("Missing '-r' or '--rootCA'") |
ampembeng | 17:46780b2de3e4 | 270 | missingConfiguration = True |
ampembeng | 17:46780b2de3e4 | 271 | if not useWebsocket: |
ampembeng | 17:46780b2de3e4 | 272 | if not AWS_IOT_CERTIFICATE_FILENAME: |
ampembeng | 17:46780b2de3e4 | 273 | print("Missing '-c' or '--cert'") |
ampembeng | 17:46780b2de3e4 | 274 | missingConfiguration = True |
ampembeng | 17:46780b2de3e4 | 275 | if not AWS_IOT_PRIVATE_KEY_FILENAME: |
ampembeng | 17:46780b2de3e4 | 276 | print("Missing '-k' or '--key'") |
ampembeng | 17:46780b2de3e4 | 277 | missingConfiguration = True |
ampembeng | 17:46780b2de3e4 | 278 | if missingConfiguration: |
ampembeng | 17:46780b2de3e4 | 279 | exit(2) |
ampembeng | 17:46780b2de3e4 | 280 | ''' |
ampembeng | 17:46780b2de3e4 | 281 | |
ampembeng | 17:46780b2de3e4 | 282 | # Configure logging |
ampembeng | 17:46780b2de3e4 | 283 | logger = logging.getLogger("AWSIoTPythonSDK.core") |
ampembeng | 17:46780b2de3e4 | 284 | logger.setLevel(logging.DEBUG) |
ampembeng | 17:46780b2de3e4 | 285 | streamHandler = logging.StreamHandler() |
ampembeng | 17:46780b2de3e4 | 286 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') |
ampembeng | 17:46780b2de3e4 | 287 | streamHandler.setFormatter(formatter) |
ampembeng | 17:46780b2de3e4 | 288 | logger.addHandler(streamHandler) |
ampembeng | 17:46780b2de3e4 | 289 | |
ampembeng | 17:46780b2de3e4 | 290 | ####################################################################################################################### |
ampembeng | 17:46780b2de3e4 | 291 | # |
ampembeng | 17:46780b2de3e4 | 292 | # Main Code |
ampembeng | 17:46780b2de3e4 | 293 | # |
ampembeng | 17:46780b2de3e4 | 294 | ####################################################################################################################### |
ampembeng | 19:488dad1e168e | 295 | # This block parses the MQTT file. |
ampembeng | 19:488dad1e168e | 296 | ''' Example format for mqtt_config.txt: |
ampembeng | 19:488dad1e168e | 297 | AWS_IOT_MQTT_HOST=1234asdf.iot.us-west-2.amazonaws.com |
ampembeng | 19:488dad1e168e | 298 | AWS_IOT_MQTT_PORT=8883 |
ampembeng | 19:488dad1e168e | 299 | AWS_IOT_MQTT_CLIENT_ID=MyThingName |
ampembeng | 19:488dad1e168e | 300 | WS_IOT_MY_THING_NAME=MyThingName |
ampembeng | 19:488dad1e168e | 301 | ''' |
ampembeng | 19:488dad1e168e | 302 | |
ampembeng | 19:488dad1e168e | 303 | if (not hardCodeMQTT): |
ampembeng | 19:488dad1e168e | 304 | if not os.path.exists(AWS_MQTT_CONFIG_FILENAME): |
ampembeng | 19:488dad1e168e | 305 | print "ERROR: MQTT Config file not found, " + AWS_MQTT_CONFIG_FILENAME |
ampembeng | 19:488dad1e168e | 306 | exit(1) |
ampembeng | 19:488dad1e168e | 307 | |
ampembeng | 19:488dad1e168e | 308 | mqtt_file = open(AWS_MQTT_CONFIG_FILENAME) |
ampembeng | 19:488dad1e168e | 309 | mqtt_tokens = re.split('=|\n', mqtt_file.read()) |
ampembeng | 19:488dad1e168e | 310 | print mqtt_tokens |
ampembeng | 19:488dad1e168e | 311 | |
ampembeng | 19:488dad1e168e | 312 | if (len(mqtt_tokens) != 8): |
ampembeng | 19:488dad1e168e | 313 | print "ERROR: Detected incorrect MQTT file format" |
ampembeng | 19:488dad1e168e | 314 | exit(1) |
ampembeng | 19:488dad1e168e | 315 | |
ampembeng | 19:488dad1e168e | 316 | index = 0 |
ampembeng | 19:488dad1e168e | 317 | for token in mqtt_tokens: |
ampembeng | 19:488dad1e168e | 318 | if (token == "AWS_IOT_MQTT_HOST"): |
ampembeng | 19:488dad1e168e | 319 | AWS_IOT_MQTT_HOST = mqtt_tokens[index+1] |
ampembeng | 19:488dad1e168e | 320 | if (token == "AWS_IOT_MQTT_PORT"): |
ampembeng | 19:488dad1e168e | 321 | AWS_IOT_MQTT_PORT = int(mqtt_tokens[index + 1]) |
ampembeng | 19:488dad1e168e | 322 | if (token == "AWS_IOT_MQTT_CLIENT_ID"): |
ampembeng | 19:488dad1e168e | 323 | AWS_IOT_MQTT_CLIENT_ID = mqtt_tokens[index + 1] |
ampembeng | 19:488dad1e168e | 324 | if (token == "AWS_IOT_MY_THING_NAME"): |
ampembeng | 19:488dad1e168e | 325 | AWS_IOT_MY_THING_NAME = mqtt_tokens[index+1] |
ampembeng | 19:488dad1e168e | 326 | |
ampembeng | 19:488dad1e168e | 327 | index += 1 |
ampembeng | 19:488dad1e168e | 328 | |
ampembeng | 19:488dad1e168e | 329 | print "MQTT Params:" |
ampembeng | 19:488dad1e168e | 330 | print "AWS_IOT_MQTT_HOST = " + AWS_IOT_MQTT_HOST |
ampembeng | 19:488dad1e168e | 331 | print "AWS_IOT_MQTT_PORT = " + str(AWS_IOT_MQTT_PORT) |
ampembeng | 19:488dad1e168e | 332 | print "AWS_IOT_MQTT_CLIENT_ID = " + AWS_IOT_MQTT_CLIENT_ID |
ampembeng | 19:488dad1e168e | 333 | print "AWS_IOT_MY_THING_NAME = " + AWS_IOT_MY_THING_NAME |
ampembeng | 19:488dad1e168e | 334 | |
ampembeng | 19:488dad1e168e | 335 | # Makes sure cert/key files exist |
ampembeng | 17:46780b2de3e4 | 336 | if not os.path.exists(AWS_IOT_ROOT_CA_FILENAME): |
ampembeng | 17:46780b2de3e4 | 337 | print "ERROR: Root CA file not found, " + AWS_IOT_ROOT_CA_FILENAME |
ampembeng | 17:46780b2de3e4 | 338 | exit(1) |
ampembeng | 17:46780b2de3e4 | 339 | if not os.path.exists(AWS_IOT_PRIVATE_KEY_FILENAME): |
ampembeng | 17:46780b2de3e4 | 340 | print "ERROR: Private Key file not found, " + AWS_IOT_PRIVATE_KEY_FILENAME |
ampembeng | 17:46780b2de3e4 | 341 | exit(1) |
ampembeng | 17:46780b2de3e4 | 342 | if not os.path.exists(AWS_IOT_CERTIFICATE_FILENAME): |
ampembeng | 17:46780b2de3e4 | 343 | print "ERROR: AWS IOT cert file not found, " + AWS_IOT_CERTIFICATE_FILENAME |
ampembeng | 17:46780b2de3e4 | 344 | exit(1) |
ampembeng | 17:46780b2de3e4 | 345 | |
ampembeng | 17:46780b2de3e4 | 346 | # Init AWSIoTMQTTShadowClient |
ampembeng | 17:46780b2de3e4 | 347 | myAWSIoTMQTTShadowClient = None |
ampembeng | 17:46780b2de3e4 | 348 | if useWebsocket: |
ampembeng | 17:46780b2de3e4 | 349 | myAWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient("basicShadowDeltaListener", useWebsocket=True) |
ampembeng | 17:46780b2de3e4 | 350 | myAWSIoTMQTTShadowClient.configureEndpoint(AWS_IOT_MQTT_HOST, 443) |
ampembeng | 17:46780b2de3e4 | 351 | myAWSIoTMQTTShadowClient.configureCredentials(AWS_IOT_ROOT_CA_FILENAME) |
ampembeng | 17:46780b2de3e4 | 352 | else: |
ampembeng | 17:46780b2de3e4 | 353 | myAWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient("basicShadowDeltaListener") |
ampembeng | 17:46780b2de3e4 | 354 | myAWSIoTMQTTShadowClient.configureEndpoint(AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT) |
ampembeng | 17:46780b2de3e4 | 355 | myAWSIoTMQTTShadowClient.configureCredentials(AWS_IOT_ROOT_CA_FILENAME, AWS_IOT_PRIVATE_KEY_FILENAME, AWS_IOT_CERTIFICATE_FILENAME) |
ampembeng | 17:46780b2de3e4 | 356 | |
ampembeng | 17:46780b2de3e4 | 357 | # AWSIoTMQTTShadowClient configuration |
ampembeng | 17:46780b2de3e4 | 358 | myAWSIoTMQTTShadowClient.configureAutoReconnectBackoffTime(1, 32, 20) |
ampembeng | 17:46780b2de3e4 | 359 | myAWSIoTMQTTShadowClient.configureConnectDisconnectTimeout(10) # 10 sec |
ampembeng | 17:46780b2de3e4 | 360 | myAWSIoTMQTTShadowClient.configureMQTTOperationTimeout(5) # 5 sec |
ampembeng | 17:46780b2de3e4 | 361 | |
ampembeng | 17:46780b2de3e4 | 362 | # Connect to AWS IoT |
ampembeng | 17:46780b2de3e4 | 363 | myAWSIoTMQTTShadowClient.connect() |
ampembeng | 17:46780b2de3e4 | 364 | |
ampembeng | 17:46780b2de3e4 | 365 | # Create a deviceShadow with persistent subscription |
ampembeng | 17:46780b2de3e4 | 366 | Bot = myAWSIoTMQTTShadowClient.createShadowHandlerWithName(AWS_IOT_MY_THING_NAME, True) |
ampembeng | 17:46780b2de3e4 | 367 | |
ampembeng | 17:46780b2de3e4 | 368 | # Listen on deltas |
ampembeng | 17:46780b2de3e4 | 369 | Bot.shadowRegisterDeltaCallback(customShadowCallback_Delta) |
ampembeng | 17:46780b2de3e4 | 370 | |
ampembeng | 17:46780b2de3e4 | 371 | # Delete shadow JSON doc |
ampembeng | 17:46780b2de3e4 | 372 | #Bot.shadowDelete(customShadowCallback_Delete, 5) |
ampembeng | 17:46780b2de3e4 | 373 | |
ampembeng | 17:46780b2de3e4 | 374 | getTimer = Timer(3.0, customShadowTimer_Get, ()) |
ampembeng | 17:46780b2de3e4 | 375 | getTimer.start() |
ampembeng | 17:46780b2de3e4 | 376 | |
ampembeng | 17:46780b2de3e4 | 377 | # GUI loop (loops until closed) |
ampembeng | 17:46780b2de3e4 | 378 | window.mainloop() |
ampembeng | 17:46780b2de3e4 | 379 | |
ampembeng | 17:46780b2de3e4 | 380 | # Kill our timer after the GUI closes |
ampembeng | 17:46780b2de3e4 | 381 | getTimerAlive = FALSE |
ampembeng | 19:488dad1e168e | 382 | getTimer.cancel() |