simulate-aws-iot-device

AWS makes it easy to simulate an IoT device with a script run from the CLI of your local machine. Let’s walk through it. We’ll reference the script pasted below.

simulate_aws_iot_device.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import ssl
import csv
import json
import random
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
from pathlib import Path

CLIENT_NAME = 'city-temp-device'
TOPIC = 'city-temp-device/1'

BROKER_PATH = 'XXXXXXXXXXXXXXX.iot.region.amazonaws.com'

ROOT_CA_PATH = './certs/AmazonRootCA1.pem'
PRIVATE_KEY_PATH = './certs/urban-temp/XXXXXXXXXXXXXX.pem.key'
CERTIFICATE_PATH = './certs/urban-temp/XXXXXXXXXXX-certificate.pem.crt'

IoTclient = AWSIoTMQTTClient(CLIENT_NAME)
IoTclient.configureEndpoint(BROKER_PATH, 8883)
IoTclient.configureCredentials(
ROOT_CA_PATH,
PRIVATE_KEY_PATH,
CERTIFICATE_PATH
)

#https://s3.amazonaws.com/aws-iot-device-sdk-python-docs/html/index.html#AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient.configureOfflinePublishQueueing
#If set to -1, the queue size is set to be infinite.
IoTclient.configureOfflinePublishQueueing(-1)

#https://s3.amazonaws.com/aws-iot-device-sdk-python-docs/html/index.html#AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient.configureDrainingFrequency
#Used to configure the draining speed to clear up the queued requests when the connection is back. Should be called before connect.
IoTclient.configureDrainingFrequency(2)

#https://s3.amazonaws.com/aws-iot-device-sdk-python-docs/html/index.html#AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient.configureConnectDisconnectTimeout
#Used to configure the time in seconds to wait for a CONNACK or a disconnect to complete. Should be called before connect.
IoTclient.configureConnectDisconnectTimeout(10)

#https://s3.amazonaws.com/aws-iot-device-sdk-python-docs/html/index.html#AWSIoTPythonSDK.MQTTLib.AWSIoTMQTTClient.configureMQTTOperationTimeout
#Used to configure the timeout in seconds for MQTT QoS 1 publish, subscribe and unsubscribe. Should be called before connect.
IoTclient.configureMQTTOperationTimeout(5)

IoTclient.connect()

IoTclient.publish(TOPIC, "connection status: ok", 0)

def payload():
locations = ["El Paso", "Dallas", "Los Angeles", "Seattle", "NYC", "Lincoln", "Omaha", "Uvalde"]
payload = json.dumps({"location":random.choice(locations),"temperature":round(random.uniform(0,100),2)})
return payload

while True:
IoTclient.publish(TOPIC, payload(), 0)

First, open the AWS console and search for “IoT Core” service. Next, click “Get Started,” then, “Manage” >> “Things.” Then, “Create” >> “Create a single thing.”

Create a thing
  1. name your thing
  2. create or assign a thing type
  3. add to a group / create group

Click “Next”

Certificates

Your “device” will need to generate three authentication certificates to enable authentication between itself and AWS.

Click “Create certificate” and you’ll see “Certificate created!” on the next page along with three certificates: “A certificate for this thing”, “A public key” and “A private key.” Download these three certificates.

Underneath where it says “You also need to download a root CA for AWS IoT:“, click the “Download” button which will open a new tab. On this new page, download the “RSA 2048 bit key: Amazon Root CA 1.” Save that new page into a file named “AmazonRootCA1.pem.”

As AWS states in the documentation: “Server certificates allow your devices to verify that they’re communicating with AWS IoT and not another server impersonating AWS IoT. Service certificates must be copied onto your device and referenced when devices connect to AWS IoT.”

Return to the first certificate page and click “Activate.” We don’t have any policies yet, that’s next, so just click done. You’ll return to the ‘Things’ page, where you’ll see your newly created thing.

Policies

From the main IoT page, under ‘Secure’, select ‘Policies’ and then ‘Create’ a new policy. Give your policy a name and an ‘Action.’

The ‘Action’ section will look similar to IAM and/or S3 bucket policies and the principle is the same. For this example, we’ll give our policy the action statement of “iot:*,” which allows the policy to execute all possible actions underneath IoT. This policy is obviously too permissive for real world applications. You can explore examples of more restrictive and specific actions from those suggested in the dropdown.

We use the ‘Resource ARN’ section to allow or restrict access to specific topics on specific resources or accounts. For our purposes, we’ll just use the “*“, with the “Effect” of “Allow.” Again this policy, allowing any action to any topic, falls under “Do Not Do This At Home/Prod,” but it makes our lives easier for right now. Click ‘Create.’

Once the policy is created, click on ‘Certificates’ again, find the certificate that you just created. Select it, then, under “Actions,” attach the just created policy.

Now, on the main AWS IoT console page, under settings in the lower left, copy the “Endpoint” value into the “Broker Path” variable in the above script. You’ll also see in the script that we’re referencing the certificates that we downloaded earlier. Set those paths appropriately and make sure the certificates are available at those locations.

Test

Now, we can test our IoT ‘device.’ On the lower left, select “Test” and under “Subscription Topic” insert the value from the “TOPIC” variable in the above script. The value under “Subscription Topic” needs to match that variable’s value. Subscribe to the topic, then, on the next screen, “Publish to topic” and verify this message:

1
2
3
{
"message": "Hello from AWS IoT console"
}

Good.

At this point, run the above script from your command line. You should see your “devices” from around the globe dumping their json temperature data. Currently, you’re not saving this data, however. In a later post, I’ll cover how to use Kinesis streams to ingest this data and then pipe it to S3, Glacier, Redshift or DynamoDB for durable storage.