diff --git a/README.md b/README.md index 873cf1e9..34cd1b76 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,169 @@ -## AWS IoT SDK for Python v2 +# AWS IoT SDK for Python v2 -Next generation AWS IoT Client SDK for Python using the AWS Common Runtime +Next generation AWS IoT Client SDK for Python. -## License +This SDK is built on the AWS Common Runtime, a collection of libraries +([1](https://github.com/awslabs/aws-c-common), +[2](https://github.com/awslabs/aws-c-io), +[3](https://github.com/awslabs/aws-c-mqtt), ...) written in C to be +cross-platform, high-performance, secure, and reliable. The libraries are bound +to Python by the [awscrt](https://github.com/awslabs/aws-crt-python) package. -This library is licensed under the Apache 2.0 License. +Integration with AWS IoT Services such as +[Device Shadow](https://docs.aws.amazon.com/iot/latest/developerguide/iot-device-shadows.html) +and [Jobs](https://docs.aws.amazon.com/iot/latest/developerguide/iot-jobs.html) +is provided by code that been generated from a model of the service. + +# Installation +## Minimum Requirements +* Python 3.5+ or Python 2.7+ +* CMake 3.1+ +* Clang 3.9+ or GCC 4.4+ or MSVC 2015+ + +## Build from source +``` +git clone https://github.com/awslabs/aws-crt-python.git --recursive +git clone https://github.com/awslabs/aws-iot-device-sdk-python-v2.git +pip install ./aws-crt-python +pip install ./aws-iot-device-sdk-python-v2 +``` + +# Samples + +## pubsub +This sample uses the Message Broker for AWS IoT to send and receive messages +through an MQTT connection. On startup, the device connects to the server, +subscribes to a topic, and begins publishing messages to that topic. +The device should receive those same messages back from the message broker, +since it is subscribed to that same topic. +Status updates are continually printed to the console. + +Source: `samples/pubsub.py` + +Run the sample like this: +``` +python pubsub.py --endpoint --root-ca --cert --key +``` + +Your Thing's +[Policy](https://docs.aws.amazon.com/iot/latest/developerguide/iot-policies.html) +must provide privileges for this sample to connect, subscribe, publish, +and receive. The Policy document should look something like this: + +
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Action": [
+        "iot:Publish",
+        "iot:Receive"
+      ],
+      "Resource": [
+        "arn:aws:iot:region:account:topic/samples/test"
+      ]
+    },
+    {
+      "Effect": "Allow",
+      "Action": [
+        "iot:Subscribe"
+      ],
+      "Resource": [
+        "arn:aws:iot:region:account:topicfilter/samples/test"
+      ]
+    },
+    {
+      "Effect": "Allow",
+      "Action": [
+        "iot:Connect"
+      ],
+      "Resource": [
+        "arn:aws:iot:region:account:client/samples-client-id"
+      ]
+    }
+  ]
+}
+
+ +## shadow + +This sample uses the AWS IoT Device Shadow Service to keep a property in +sync between device and server. Imagine a light whose color may be changed +through an app, or set by a local user. + +Once connected, type a value in the terminal and press Enter to update +the property's "reported" value. The sample also responds when the "desired" +value changes on the server. To observe this, edit the Shadow document in +the AWS Console and set a new "desired" value. + +On startup, the sample requests the shadow document to learn the property's +initial state. The sample also subscribes to "delta" events from the server, +which are sent when a property's "desired" value differs from its "reported" +value. When the sample learns of a new desired value, that value is changed +on the device and an update is sent to the server with the new "reported" +value. + +Source: `samples/shadow.py` + +Run the sample like this: +``` +python shadow.py --endpoint --root-ca --cert --key --thing-name +``` + +Your Thing's +[Policy](https://docs.aws.amazon.com/iot/latest/developerguide/iot-policies.html) +must provide privileges for this sample to connect, subscribe, publish, +and receive. The Policy document should look something like this: + +
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Action": [
+        "iot:Publish"
+      ],
+      "Resource": [
+        "arn:aws:iot:region:account:topic/$aws/things/thingname/shadow/get",
+        "arn:aws:iot:region:account:topic/$aws/things/thingname/shadow/update"
+      ]
+    },
+    {
+      "Effect": "Allow",
+      "Action": [
+        "iot:Receive"
+      ],
+      "Resource": [
+        "arn:aws:iot:region:account:topic/$aws/things/thingname/shadow/get/accepted",
+        "arn:aws:iot:region:account:topic/$aws/things/thingname/shadow/get/rejected",
+        "arn:aws:iot:region:account:topic/$aws/things/thingname/shadow/update/accepted",
+        "arn:aws:iot:region:account:topic/$aws/things/thingname/shadow/update/rejected",
+        "arn:aws:iot:region:account:topic/$aws/things/thingname/shadow/update/delta"
+      ]
+    },
+    {
+      "Effect": "Allow",
+      "Action": [
+        "iot:Subscribe"
+      ],
+      "Resource": [
+        "arn:aws:iot:region:account:topicfilter/$aws/things/thingname/shadow/get/accepted",
+        "arn:aws:iot:region:account:topicfilter/$aws/things/thingname/shadow/get/rejected",
+        "arn:aws:iot:region:account:topicfilter/$aws/things/thingname/shadow/update/accepted",
+        "arn:aws:iot:region:account:topicfilter/$aws/things/thingname/shadow/update/rejected",
+        "arn:aws:iot:region:account:topicfilter/$aws/things/thingname/shadow/update/delta"
+      ]
+    },
+    {
+      "Effect": "Allow",
+      "Action": "iot:Connect",
+      "Resource": "arn:aws:iot:region:account:client/samples-client-id"
+    }
+  ]
+}
+
+# License + +This library is licensed under the Apache 2.0 License. diff --git a/samples/pubsub.py b/samples/pubsub.py index 3cd6ef03..10e31ba1 100644 --- a/samples/pubsub.py +++ b/samples/pubsub.py @@ -18,21 +18,22 @@ import threading import time -# This sample uses the Message Broken for AWS IoT to send and receive messages +# This sample uses the Message Broker for AWS IoT to send and receive messages # through an MQTT connection. On startup, the device connects to the server, # subscribes to a topic, and begins publishing messages to that topic. -# The device should receive those same messages back from the message broken, +# The device should receive those same messages back from the message broker, # since it is subscribed to that same topic. parser = argparse.ArgumentParser(description="Send and receive messages through and MQTT connection.") parser.add_argument('--endpoint', required=True, help="Your AWS IoT custom endpoint, not including a port. " + - "Ex: \"w6zbse3vjd5b4p-ats.iot.us-west-2.amazonaws.com\"") + "Ex: \"abcd123456wxyz-ats.iot.us-east-1.amazonaws.com\"") parser.add_argument('--cert', required=True, help="File path to your client certificate, in PEM format.") parser.add_argument('--key', required=True, help="File path to your private key, in PEM format.") parser.add_argument('--root-ca', help="File path to root certificate authority, in PEM format. " + "Necessary if MQTT server uses a certificate that's not already in " + "your trust store.") -parser.add_argument('--topic', default="sample/test", help="Topic to subscribe to, and publish messages to.") +parser.add_argument('--client-id', default='samples-client-id', help="Client ID for MQTT connection.") +parser.add_argument('--topic', default="samples/test", help="Topic to subscribe to, and publish messages to.") parser.add_argument('--message', default="Hello World!", help="Message to publish. " + "Specify empty string to publish nothing.") parser.add_argument('--count', default=10, type=int, help="Number of messages to publish/receive before exiting. " + @@ -102,10 +103,13 @@ def on_message_received(topic, message): # Create connection port = 443 if io.is_alpn_available() else 8883 - print("Connecting to {} on port {}...".format(args.endpoint, port)) + + print("Connecting to {} on port {} with client ID '{}'...".format( + args.endpoint, port, args.client_id)) + mqtt_connection = mqtt.Connection( client=mqtt_client, - client_id='samples_client_id') + client_id=args.client_id) mqtt_connection.connect( host_name = args.endpoint, port = port, @@ -152,6 +156,9 @@ def on_message_received(topic, message): # Wait for all messages to be received. # This waits forever if count was set to 0. + if args.count != 0 and not received_all_event.is_set(): + print("Waiting for all messages to be received...") + received_all_event.wait() print("{} message(s) received.".format(received_count)) diff --git a/samples/shadow.py b/samples/shadow.py index 728e3682..568fada3 100644 --- a/samples/shadow.py +++ b/samples/shadow.py @@ -47,6 +47,7 @@ parser.add_argument('--root-ca', help="File path to root certificate authority, in PEM format. " + "Necessary if MQTT server uses a certificate that's not already in " + "your trust store") +parser.add_argument('--client-id', default='samples-client-id', help="Client ID for MQTT connection.") parser.add_argument('--thing-name', required=True, help="The name assigned to your IoT Thing") parser.add_argument('--shadow-property', default="color", help="Name of property in shadow to keep in sync") @@ -244,7 +245,7 @@ def user_input_thread_fn(): print("Connecting to {} on port {}...".format(args.endpoint, port)) mqtt_connection = mqtt.Connection( client=mqtt_client, - client_id='samples_client_id') + client_id=args.client_id) mqtt_connection.connect( host_name = args.endpoint, port = port,