V.06 11/3
Dependencies: FT6206 SDFileSystem SPI_TFT_ILI9341 TFT_fonts
Fork of ATT_AWS_IoT_demo by
ATT_AWS_IoT_Demo_GUI.py
00001 ''' 00002 /* 00003 * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"). 00006 * You may not use this file except in compliance with the License. 00007 * A copy of the License is located at 00008 * 00009 * http://aws.amazon.com/apache2.0 00010 * 00011 * or in the "license" file accompanying this file. This file is distributed 00012 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 00013 * express or implied. See the License for the specific language governing 00014 * permissions and limitations under the License. 00015 */ 00016 ''' 00017 00018 from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient 00019 import sys 00020 import os.path 00021 import logging 00022 import time 00023 import json 00024 import re 00025 import getopt 00026 import Tkinter 00027 import tkFont 00028 import time 00029 from threading import Timer 00030 from Tkinter import * 00031 from PIL import Image, ImageTk 00032 00033 exePath = os.path.dirname(os.path.realpath(__file__)) 00034 assetPath = exePath + "\\assets\\" 00035 00036 ####################################################################################################################### 00037 # 00038 # Set up our Tkinter based GUI 00039 # 00040 ####################################################################################################################### 00041 accepted = ["0", "1", "2", "4", "7"] 00042 colorDict = {0 : 'off', 1 : 'red', 2 : 'green', 4 : "blue", 7 : "white"} 00043 ledImgPaths = {0 : "LEDOff.png", 1 : 'LEDRed.png', 2 : 'LEDGreen.png', 4 : "LEDBlue.png", 7 : "LEDWhite.png"} 00044 00045 window = Tkinter.Tk() 00046 window.wm_title("AT&T AWS IoT Starter Kit Demo") 00047 window.iconbitmap(assetPath + "ATT_Icon.ico") 00048 window.resizable(width=False, height=False) 00049 00050 buttonColor = 'dark slate gray' 00051 buttonTxtColor = 'tv white' 00052 headerBgColor = 'snow' 00053 bgColor = 'steel blue' 00054 fgTextColor = 'white' 00055 00056 # Setup frames 00057 def initFrames(_window, side, color=bgColor): 00058 frame = Frame(_window, background=color) 00059 frame.pack(fill=X, side=side) 00060 return frame 00061 00062 headerframe = initFrames(window, TOP, headerBgColor) 00063 frameR1 = initFrames(window, TOP) 00064 frameR2 = initFrames(window, TOP) 00065 frameR3 = initFrames(window, TOP) 00066 frameR4 = initFrames(window, TOP) 00067 frameR5 = initFrames(window, TOP) 00068 frameR6 = initFrames(window, TOP) 00069 frameR7 = initFrames(window, TOP) 00070 frameR8 = initFrames(window, TOP) 00071 frameR9 = initFrames(window, TOP) 00072 buttonFrame = initFrames(window, BOTTOM) 00073 00074 # So we can loop through our frames 00075 frameIndex = 0 00076 frames = [headerframe, 00077 frameR1, frameR2, frameR3, frameR4, frameR5, 00078 frameR6, frameR7, frameR8, frameR9, 00079 buttonFrame] 00080 00081 def curFrame(): 00082 return frames[frameIndex] 00083 00084 def nextFrame(): 00085 global frameIndex 00086 frameIndex += 1 00087 return frames[frameIndex] 00088 00089 # Label vars (controls shown text) 00090 ledStaticLabelTxt = StringVar() 00091 ledStatusLabelTxt = StringVar() 00092 tempStaticLabelTxt = StringVar() 00093 tempStatusLabelTxt = StringVar() 00094 humidStaticLabelTxt = StringVar() 00095 humidStatusLabelTxt = StringVar() 00096 versionStaticLabelTxt = StringVar() 00097 versionStatusLabelTxt = StringVar() 00098 versionLastValue = -1 00099 00100 # Control callbacks 00101 def setStatus(ledStatus, tempStatus, humidStatus, version): 00102 global versionLastValue 00103 00104 ledStatusLabelTxt.set(colorDict[ledStatus]) 00105 updateLEDImage(ledImgPaths[ledStatus]) 00106 tempStatusLabelTxt.set(str(tempStatus) + " (F)") 00107 humidStatusLabelTxt.set(str(humidStatus) + " %") 00108 00109 isStale = "" 00110 if (versionLastValue == version): 00111 isStale = " (stale data)" 00112 else: 00113 versionLastValue = version 00114 versionStatusLabelTxt.set(str(version) + isStale) 00115 00116 def updateLEDImage(path): 00117 global ledPicture 00118 img2 = ImageTk.PhotoImage(Image.open(assetPath + path)) 00119 ledPicture.configure(image=img2) 00120 ledPicture.image = img2 00121 00122 def offButtonCallBack(): 00123 sendLEDRequest("0") 00124 00125 def redButtonCallBack(): 00126 sendLEDRequest("1") 00127 00128 def greenButtonCallBack(): 00129 sendLEDRequest("2") 00130 00131 def blueButtonCallBack(): 00132 sendLEDRequest("4") 00133 00134 def whiteButtonCallBack(): 00135 sendLEDRequest("7") 00136 00137 # Photos 00138 def initPhotoLabels(frame, photoName, color=bgColor, side=LEFT, pad=0): 00139 image = Image.open(assetPath + photoName) 00140 photo = ImageTk.PhotoImage(image) 00141 00142 label = Label(frame, image=photo, background=color) 00143 label.image = photo # keep a reference! 00144 label.pack(side=side, padx=pad) 00145 return label 00146 00147 # Create our Labels 00148 headerLabel1 = initPhotoLabels(curFrame(), "attLogo.png", headerBgColor) 00149 headerLabel2 = initPhotoLabels(curFrame(), "awsLogo.png", headerBgColor, pad=10) 00150 00151 starterKitBoxLabel = initPhotoLabels(nextFrame(), "starterKitBox.png") 00152 00153 labelFont = tkFont.Font(family='Times', size=14, weight='bold') 00154 def initLargeTextLabels(frame, text): 00155 label = Label(frame, font=labelFont, text=text, anchor=W, relief=FLAT, fg=fgTextColor, background=bgColor) 00156 label.pack(side=LEFT) 00157 00158 setLEDColorLabel = initLargeTextLabels(nextFrame(),"Reported Values") 00159 00160 def initLabels(frame, lableVar, text): 00161 lableVar.set(text) 00162 label = Label(frame, textvariable=lableVar, anchor=W, relief=FLAT, fg=fgTextColor, background=bgColor) 00163 label.pack(side = LEFT) 00164 return label 00165 00166 ledStaticLabel = initLabels(nextFrame(), ledStaticLabelTxt, "LED Color: ") 00167 ledStatusLabel = initLabels(curFrame(), ledStatusLabelTxt, "unknown (needs to sync)") 00168 00169 tempStaticLabel = initLabels(nextFrame(), tempStaticLabelTxt, "Temperature: ") 00170 tempStatusLabel = initLabels(curFrame(), tempStatusLabelTxt, "unknown (needs to sync)") 00171 00172 humidStaticLabel = initLabels(nextFrame(), humidStaticLabelTxt, "Humidity: ") 00173 humidStatusLabel = initLabels(curFrame(), humidStatusLabelTxt, "unknown (needs to sync)") 00174 00175 versionStaticLabel = initLabels(nextFrame(), versionStaticLabelTxt, "Shadow Version: ") 00176 versionStatusLabel = initLabels(curFrame(), versionStatusLabelTxt, "unknown (needs to sync)") 00177 00178 lineLabel = initLargeTextLabels(nextFrame(), "_______________________________________") 00179 setLEDColorLabel = initLargeTextLabels(nextFrame(),"Set LED Color") 00180 00181 starterKitBoardLabel = initPhotoLabels(nextFrame(), "startKitBoard.png", side=TOP) 00182 00183 # Creates an LED label (image) that we can update. 00184 ledPicture = Label(starterKitBoardLabel, background=bgColor, relief=FLAT, width=10, height=12) 00185 ledPicture.place(relx=1.0, rely=1.0, x=(40-300), y=(85-245), anchor="se") 00186 updateLEDImage("LEDOff.png") 00187 00188 # Create our Buttons 00189 def buttonInit(text, bg, command): 00190 return Tkinter.Button(buttonFrame, text =text, fg="snow", bg=bg, height=1, width=6, command=command) 00191 00192 O = buttonInit("OFF", buttonColor, offButtonCallBack) 00193 R = buttonInit("RED", buttonColor, redButtonCallBack) 00194 G = buttonInit("GREEN", buttonColor, greenButtonCallBack) 00195 B = buttonInit("BLUE", buttonColor, blueButtonCallBack) 00196 W = buttonInit("WHITE", buttonColor, whiteButtonCallBack) 00197 ledButtons = [O, R, G, B, W] 00198 00199 # Set font 00200 buttonFont = tkFont.Font(family='Arial', size=12, weight='bold') 00201 for button in ledButtons: 00202 button['font'] = buttonFont 00203 00204 buttonPadX = 5 00205 for button in ledButtons: 00206 button.pack(side=LEFT, padx=buttonPadX) 00207 00208 # NOTE: If you want to test the GUI layout without running the AWS code comment these lines in 00209 #window.mainloop() 00210 #exit(0) 00211 00212 ####################################################################################################################### 00213 # 00214 # These functions are for AWS 00215 # 00216 ####################################################################################################################### 00217 # Shadow JSON schema: 00218 ''' 00219 Name: AIT (AWS IoT Thing) 00220 { 00221 "state": { 00222 "desired": { 00223 "ledColor": <UINT8> 00224 }, 00225 "reported": { 00226 "ledColor": <UINT8>, 00227 "temperature": <FLOAT>, 00228 "humidity": <INT16> 00229 } 00230 } 00231 } 00232 ''' 00233 00234 def sendLEDRequest(color_input): 00235 if (color_input in accepted): 00236 JSONPayload = '{"state":{"desired":{"ledColor":' + str(color_input) + '}}}' 00237 AIT.shadowUpdate(JSONPayload, customShadowCallback_Update, 5) 00238 else: 00239 print("WARN: Color input invalid - " + color_input) 00240 00241 # Custom Shadow callback 00242 def customShadowCallback_Delta(payload, responseStatus, token): 00243 # payload is a JSON string ready to be parsed using json.loads(...) 00244 # in both Py2.x and Py3.x 00245 print(responseStatus) 00246 payloadDict = json.loads(payload) 00247 print("++++++++DELTA++++++++++") 00248 print("ledColor: " + str(payloadDict["state"]["ledColor"])) 00249 print("version: " + str(payloadDict["version"])) 00250 print("+++++++++++++++++++++++\n\n") 00251 00252 # Custom Shadow callback 00253 def customShadowCallback_Update(payload, responseStatus, token): 00254 # payload is a JSON string ready to be parsed using json.loads(...) 00255 # in both Py2.x and Py3.x 00256 if responseStatus == "timeout": 00257 print("Update request " + token + " time out!") 00258 if responseStatus == "accepted": 00259 payloadDict = json.loads(payload) 00260 print("~~~~~~~~~~~~~~~~~~~~~~~") 00261 print("Update request with token: " + token + " accepted!") 00262 print("ledColor: " + str(payloadDict["state"]["desired"]["ledColor"])) 00263 print("~~~~~~~~~~~~~~~~~~~~~~~\n\n") 00264 if responseStatus == "rejected": 00265 print("Update request " + token + " rejected!") 00266 00267 def customShadowCallback_Delete(payload, responseStatus, token): 00268 if responseStatus == "timeout": 00269 print("Delete request " + token + " time out!") 00270 if responseStatus == "accepted": 00271 print("~~~~~~~~~~~~~~~~~~~~~~~") 00272 print("Delete request with token: " + token + " accepted!") 00273 print("~~~~~~~~~~~~~~~~~~~~~~~\n\n") 00274 if responseStatus == "rejected": 00275 print("Delete request " + token + " rejected!") 00276 00277 # Custom Shadow callback 00278 def customShadowCallback_Get(payload, responseStatus, token): 00279 print(responseStatus) 00280 payloadDict = json.loads(payload) 00281 reportedColor = payloadDict["state"]["reported"]["ledColor"] 00282 reportedTemp = payloadDict["state"]["reported"]["temperature"] 00283 reportedHumid = payloadDict["state"]["reported"]["humidity"] 00284 reportedVersion = payloadDict["version"] 00285 print("++++++++GET++++++++++") 00286 print("ledColor : " + str(reportedColor) + " (" + colorDict[reportedColor] + ")") 00287 print("temperature: " + str(reportedTemp)) 00288 print("humidity : " + str(reportedHumid)) 00289 print("version: " + str(reportedVersion)) 00290 print("+++++++++++++++++++++\n\n") 00291 00292 # Send payload to our status 00293 setStatus(reportedColor, reportedTemp, reportedHumid, reportedVersion) 00294 00295 getTimerAlive = TRUE 00296 def customShadowTimer_Get(): 00297 while (getTimerAlive): 00298 AIT.shadowGet(customShadowCallback_Get, 5) 00299 time.sleep(3) 00300 00301 ####################################################################################################################### 00302 # 00303 # Vars 00304 # 00305 ####################################################################################################################### 00306 # Usage 00307 usageInfo = """Usage: 00308 00309 Use certificate based mutual authentication: 00310 python basicShadowDeltaListener.py -e <endpoint> -r <rootCAFilePath> -c <certFilePath> -k <privateKeyFilePath> 00311 00312 Use MQTT over WebSocket: 00313 python basicShadowDeltaListener.py -e <endpoint> -r <rootCAFilePath> -w 00314 00315 Type "python basicShadowDeltaListener.py -h" for available options. 00316 00317 00318 """ 00319 # Help info 00320 helpInfo = """-e, --endpoint 00321 Your AWS IoT custom endpoint 00322 -r, --rootCA 00323 Root CA file path 00324 -c, --cert 00325 Certificate file path 00326 -k, --key 00327 Private key file path 00328 -w, --websocket 00329 Use MQTT over WebSocket 00330 -h, --help 00331 Help information 00332 00333 00334 """ 00335 00336 ####################################################################################################################### 00337 # 00338 # AWS IoT Config Parameters. The user needs to enter these (they should match the parameters in aws_iot_config.h) 00339 # 00340 ####################################################################################################################### 00341 useWebsocket = False # The FRDM-K64F demo isn't designed to work with web socket 00342 hardCodeMQTT = False # Set this to true if you want to hard code the MQTT params below 00343 00344 # AWS parameters 00345 AWS_IOT_MQTT_HOST = "TODO" 00346 AWS_IOT_MQTT_PORT = 8883 00347 AWS_IOT_MQTT_CLIENT_ID = "TODO" 00348 AWS_IOT_MY_THING_NAME = "TODO" 00349 AWS_MQTT_CONFIG_FILENAME = "C:/Temp/certs/mqtt_config.txt" 00350 AWS_IOT_ROOT_CA_FILENAME = "C:/Temp/certs/rootCA-certificate.crt" 00351 AWS_IOT_PRIVATE_KEY_FILENAME = "C:/Temp/certs/private.pem.key" 00352 AWS_IOT_CERTIFICATE_FILENAME = "C:/Temp/certs/certificate.pem.crt" 00353 00354 ####################################################################################################################### 00355 # 00356 # Arg Parser (TODO) 00357 # 00358 ####################################################################################################################### 00359 ''' 00360 try: 00361 opts, args = getopt.getopt(sys.argv[1:], "hwe:k:c:r:", ["help", "endpoint=", "key=","cert=","rootCA=", "websocket"]) 00362 if len(opts) == 0: 00363 raise getopt.GetoptError("No input parameters!") 00364 for opt, arg in opts: 00365 if opt in ("-h", "--help"): 00366 print(helpInfo) 00367 exit(0) 00368 if opt in ("-e", "--endpoint"): 00369 AWS_IOT_MQTT_HOST = arg 00370 if opt in ("-r", "--rootCA"): 00371 AWS_IOT_ROOT_CA_FILENAME = arg 00372 if opt in ("-c", "--cert"): 00373 AWS_IOT_CERTIFICATE_FILENAME = arg 00374 if opt in ("-k", "--key"): 00375 AWS_IOT_PRIVATE_KEY_FILENAME = arg 00376 if opt in ("-w", "--websocket"): 00377 useWebsocket = True 00378 except getopt.GetoptError: 00379 print(usageInfo) 00380 #exit(1) 00381 00382 # Missing configuration notification 00383 missingConfiguration = False 00384 if not AWS_IOT_MQTT_HOST: 00385 print("Missing '-e' or '--endpoint'") 00386 missingConfiguration = True 00387 if not AWS_IOT_ROOT_CA_FILENAME: 00388 print("Missing '-r' or '--rootCA'") 00389 missingConfiguration = True 00390 if not useWebsocket: 00391 if not AWS_IOT_CERTIFICATE_FILENAME: 00392 print("Missing '-c' or '--cert'") 00393 missingConfiguration = True 00394 if not AWS_IOT_PRIVATE_KEY_FILENAME: 00395 print("Missing '-k' or '--key'") 00396 missingConfiguration = True 00397 if missingConfiguration: 00398 exit(2) 00399 ''' 00400 00401 # Configure logging 00402 logger = logging.getLogger("AWSIoTPythonSDK.core") 00403 logger.setLevel(logging.DEBUG) 00404 streamHandler = logging.StreamHandler() 00405 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 00406 streamHandler.setFormatter(formatter) 00407 logger.addHandler(streamHandler) 00408 00409 ####################################################################################################################### 00410 # 00411 # Main Code 00412 # 00413 ####################################################################################################################### 00414 # This block parses the MQTT file. 00415 ''' Example format for mqtt_config.txt: 00416 AWS_IOT_MQTT_HOST=1234asdf.iot.us-west-2.amazonaws.com 00417 AWS_IOT_MQTT_PORT=8883 00418 AWS_IOT_MQTT_CLIENT_ID=MyThingName 00419 WS_IOT_MY_THING_NAME=MyThingName 00420 ''' 00421 00422 if (not hardCodeMQTT): 00423 if not os.path.exists(AWS_MQTT_CONFIG_FILENAME): 00424 print "ERROR: MQTT Config file not found, " + AWS_MQTT_CONFIG_FILENAME 00425 exit(1) 00426 00427 mqtt_file = open(AWS_MQTT_CONFIG_FILENAME) 00428 mqtt_tokens = re.split('=|\n', mqtt_file.read()) 00429 print mqtt_tokens 00430 00431 if (len(mqtt_tokens) != 8): 00432 print "ERROR: Detected incorrect MQTT file format" 00433 exit(1) 00434 00435 index = 0 00436 for token in mqtt_tokens: 00437 if (token == "AWS_IOT_MQTT_HOST"): 00438 AWS_IOT_MQTT_HOST = mqtt_tokens[index+1] 00439 if (token == "AWS_IOT_MQTT_PORT"): 00440 AWS_IOT_MQTT_PORT = int(mqtt_tokens[index + 1]) 00441 if (token == "AWS_IOT_MQTT_CLIENT_ID"): 00442 AWS_IOT_MQTT_CLIENT_ID = mqtt_tokens[index + 1] 00443 if (token == "AWS_IOT_MY_THING_NAME"): 00444 AWS_IOT_MY_THING_NAME = mqtt_tokens[index+1] 00445 00446 index += 1 00447 00448 print "MQTT Params:" 00449 print "AWS_IOT_MQTT_HOST = " + AWS_IOT_MQTT_HOST 00450 print "AWS_IOT_MQTT_PORT = " + str(AWS_IOT_MQTT_PORT) 00451 print "AWS_IOT_MQTT_CLIENT_ID = " + AWS_IOT_MQTT_CLIENT_ID 00452 print "AWS_IOT_MY_THING_NAME = " + AWS_IOT_MY_THING_NAME 00453 00454 # Makes sure cert/key files exist 00455 if not os.path.exists(AWS_IOT_ROOT_CA_FILENAME): 00456 print "ERROR: Root CA file not found, " + AWS_IOT_ROOT_CA_FILENAME 00457 exit(1) 00458 if not os.path.exists(AWS_IOT_PRIVATE_KEY_FILENAME): 00459 print "ERROR: Private Key file not found, " + AWS_IOT_PRIVATE_KEY_FILENAME 00460 exit(1) 00461 if not os.path.exists(AWS_IOT_CERTIFICATE_FILENAME): 00462 print "ERROR: AWS IOT cert file not found, " + AWS_IOT_CERTIFICATE_FILENAME 00463 exit(1) 00464 00465 # Init AWSIoTMQTTShadowClient 00466 myAWSIoTMQTTShadowClient = None 00467 if useWebsocket: 00468 myAWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient("basicShadowDeltaListener", useWebsocket=True) 00469 myAWSIoTMQTTShadowClient.configureEndpoint(AWS_IOT_MQTT_HOST, 443) 00470 myAWSIoTMQTTShadowClient.configureCredentials(AWS_IOT_ROOT_CA_FILENAME) 00471 else: 00472 myAWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient("basicShadowDeltaListener") 00473 myAWSIoTMQTTShadowClient.configureEndpoint(AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT) 00474 myAWSIoTMQTTShadowClient.configureCredentials(AWS_IOT_ROOT_CA_FILENAME, AWS_IOT_PRIVATE_KEY_FILENAME, AWS_IOT_CERTIFICATE_FILENAME) 00475 00476 # AWSIoTMQTTShadowClient configuration 00477 myAWSIoTMQTTShadowClient.configureAutoReconnectBackoffTime(1, 32, 20) 00478 myAWSIoTMQTTShadowClient.configureConnectDisconnectTimeout(10) # 10 sec 00479 myAWSIoTMQTTShadowClient.configureMQTTOperationTimeout(5) # 5 sec 00480 00481 # Connect to AWS IoT 00482 myAWSIoTMQTTShadowClient.connect() 00483 00484 # Create a deviceShadow with persistent subscription 00485 AIT = myAWSIoTMQTTShadowClient.createShadowHandlerWithName(AWS_IOT_MY_THING_NAME, True) 00486 00487 # Listen on deltas 00488 AIT.shadowRegisterDeltaCallback(customShadowCallback_Delta) 00489 00490 # Delete shadow JSON doc 00491 #AIT.shadowDelete(customShadowCallback_Delete, 5) 00492 00493 # NOTE: We make this slightly slower than the target loop (to prevent 'stale data') 00494 getTimer = Timer(3.5, customShadowTimer_Get, ()) 00495 getTimer.start() 00496 00497 # GUI loop (loops until closed) 00498 window.mainloop() 00499 00500 # Kill our timer after the GUI closes 00501 getTimerAlive = FALSE 00502 getTimer.cancel()
Generated on Tue Jul 12 2022 14:16:19 by 1.7.2