Last active
January 20, 2020 02:19
-
-
Save FanchenBao/38dc0cc4b65131a63efcce56a0fd8852 to your computer and use it in GitHub Desktop.
Sample code for updating and getting aws iot thing shadow using AWSIoTPythonSDK or boto3.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This is heavily borrowed from AWSIoTPythonSDK's sample code here: | |
https://github.com/aws/aws-iot-device-sdk-python/blob/master/samples/basicShadow/basicShadowUpdater.py | |
""" | |
from time import sleep | |
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient | |
import json | |
import logging | |
logger = logging.getLogger("AWSIoTPythonSDK.core") | |
console_handler = logging.StreamHandler() | |
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s',) | |
console_handler.setFormatter(formatter) | |
logger.addHandler(console_handler) | |
logger.setLevel(logging.INFO) | |
def customShadowCallback_Update(payload, responseStatus, token): | |
if responseStatus == "timeout": | |
logger.info("Update request " + token + " time out!") | |
if responseStatus == "accepted": | |
payloadDict = json.loads(payload) | |
logger.info("~~~~~~~~~~~~~~~~~~~~~~~") | |
logger.info("Update request with token: " + token + " accepted!") | |
logger.info("property: " + str(payloadDict["state"]["desired"]["property"])) | |
logger.info("~~~~~~~~~~~~~~~~~~~~~~~\n\n") | |
if responseStatus == "rejected": | |
logger.info("Update request " + token + " rejected!") | |
def customShadowCallback_Get(payload, responseStatus, token): | |
logger.info('coming from customShadowCallback_Get') | |
if responseStatus == "timeout": | |
logger.info("Get request " + token + " time out!") | |
if responseStatus == "accepted": | |
payloadDict = json.loads(payload) | |
logger.info("~~~~~~~~~~~~~~~~~~~~~~~") | |
logger.info("Get request with token: " + token + " accepted!") | |
logger.info("property: " + str(payloadDict["state"]["desired"]["property"])) | |
logger.info("~~~~~~~~~~~~~~~~~~~~~~~\n\n") | |
if responseStatus == "rejected": | |
logger.info("Get request " + token + " rejected!") | |
myShadowClient = AWSIoTMQTTShadowClient('<thing_name>') | |
myShadowClient.configureEndpoint('<endpoint>', 8883) | |
myShadowClient.configureCredentials( | |
'<path/to/root_ca>', | |
'<path/to/private_key>', | |
'<path/to/device_certificate>', | |
) | |
myShadowClient.configureConnectDisconnectTimeout(10) # 10 sec | |
myShadowClient.configureMQTTOperationTimeout(5) # 5 sec | |
myShadowClient.onOnline = lambda: logger.info('online') | |
myShadowClient.onOffline = lambda: logger.info('offline') | |
myShadowClient.connect() | |
myDeviceShadow = myShadowClient.createShadowHandlerWithName('<thing_name>', True) | |
# update the 'cpu_temp' field of the thing shadow state. If this field doesn't | |
# exist, create it; if it does, update it; while leaving all other fields | |
# unchanged. | |
jsonpayload = json.dumps({'state': {'desired': {'property': {'cpu_temp': 70}}}}) | |
myDeviceShadow.shadowUpdate(jsonpayload, customShadowCallback_Update, 5) | |
sleep(1) | |
# get the current thing shadow state. This call essentially subscribes to the | |
# topic "$aws/things/TestThing/shadow/get/accepted" and call the callback | |
# function once a message containing the current thing shadow state is | |
# published on that topic. Therefore, after calling `shadowGet`, we MUST NOT | |
# end the program immediately (hence the sleep at the end). | |
myDeviceShadow.shadowGet(customShadowCallback_Get, 5) | |
sleep(3) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import logging | |
import boto3 | |
logger = logging.getLogger(__name__) | |
logger.setLevel(logging.DEBUG) | |
logger.addHandler(logging.StreamHandler()) | |
client = boto3.client('iot-data', region_name='us-east-2') | |
def set_thing_state(thingName, state): | |
"""Update thing shadow with `state`.""" | |
payload = json.dumps({'state': {'desired': {'property': state}}}) | |
response = client.update_thing_shadow(thingName=thingName, payload=payload) | |
response_payload = json.loads(response['payload'].read()) | |
logger.info(f'Response after set_thing_state: {response_payload}') | |
def get_thing_state(thingName): | |
"""Get current thing shadow state.""" | |
response = client.get_thing_shadow(thingName=thingName) | |
current_state = json.loads(response['payload'].read()) | |
logger.info(f'Current thing state: {current_state}') | |
def lambda_handler(event, _): | |
""" | |
This is the set up used in aws lambda. Since aws lambda cannot have persistent connection, | |
it cannot update and get thing shadow state using MQTT. Instead, it uses boto3's API, which | |
performs update and get thing shadow via https request. | |
It is IMPORTANT to note that, this method requires internet connection. If the lambda is | |
configured within an VPC (e.g. to access a db on RDS), by default it does NOT have internet | |
access. Therefore, one either has to set up the VPC to have acccess to internet (perhaps | |
follow this guide: https://gist.github.com/reggi/dc5f2620b7b4f515e68e46255ac042a7), or use | |
two lambdas, one for use with VPC and the other open internet. | |
Also, don't forget to give the lambda sufficient permission to perform 'iot:GetThingShadow' | |
and 'iot:UpdateThingShadow'. | |
""" | |
set_thing_state('<thing_name>', {'key': '<new state>'}) | |
get_thing_state('<thing_name>') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment