Design Notes

This is a compilation of designs used in the hardware and software.

Hardware

The dispenser has four addressable components:

  1. led_ring: NeoPixel-based 5-element RGB LED ring. Can set the number of LEDs to light and the RGB color of all the LEDs.
  2. motor: Aquarium pump that can be actuated via the first addressable LED/motor h-bridge connection
  3. led: Second addressable LED/motor h-bridge connection - used for initial testing (blinky)
  4. led2: Second addressable LED on the h-bridge board

Software

API Methods

Table 1. ApiTable
MethodQuery parametersresponse bodyNotes
/getResourcesNone{"userName": username, "dispenserId": "100", "assets": null}All responses will include userName and dispenserId. If there are no assets, that will be null, otherwise will be JSON object with the parameters:

DynamoDB Tables

Table 2. UserTable
AttributePartition/Sort KeyFormatDefaultValue
usernamePartitionstringnoneuser name from Cognito
nextDispenserId-string"100"The next dispenserId to vend, only added to the admin user
dispenserId-stringnonevalue returned by default user admin
assets-JSON objectvariesDefault: null, indicator to generate users resources

The table is created empty. When the first user signs in, the Sign-in trigger will check for an admin user. If not present it will create one. The additional attributes for the admin user are:

  • nextDispenserId - The number of the next dispenser to associate with a user

These are the attributes for other users:

  • Partition key: userName (string) - User name selected during Cognito sign-up
  • dispenserId (string) - Dispenser Id associated with user, IoT thing, etc.
  • assets (object) - During sign-in, the /getResources method will create and populate
Table 3. DispenserTable
AttributePartition/Sort KeyFormatDefaultValue
dispenserIdPartitionstring-3-digit unique value of dispenser, associated with user
credits-Number1Credits available to dispenser. Increment in 0.25 and deduct by 1.00 for a dispense
leaderBoardStatus-Number1Stage of completion. 1 is starting with user/dispenser created, 2 is next step, etc.
leaderBoardTime-Number-Timestamp, without microseconds, when latest leaderBoardStatus stage changed.
requests-list[] empty listList of active requests ["requestId|command|timestamp|target"]

The table is created empty, and entries are created or deleted as individual users are registered. The table can be read by participants, but only updated by the admin user and Lambda functions.

This table tracks the status of credits, in-flight requests (requests), and other details regarding each dispenser.

The requests attribute contains a DynamoDB list of different in-flight requests. In this workshop, only the following is used (in JSON format):

[
  "1234-5678|dispense|12345678|device",
  "4567-8901|anothercommand|87654321|device",
]

Both devices and applications interact with the list and construct a JSON message based on the contents, such as:

{
  "clientId": "123",
  "requestId": "1234-5678",
  "command": "dispense",
  "timestamp": "12345678",
  "target": "device"
}

This is the representation of the first entry in the list. As requests are completed, the entity that validates the completion will remove them from the list. clientId maps to the dispenserId.

User account setup and sign-in

Cognito sign-up and sign-in calls are made. When signing in, the app calls the GetResources method which checks if the authenticated user has a resources entry in the database. If it does, the values are returns. If not, it immediately returns a message so the app can request the CreateResources method. This method executes the following to create the resources:

  • Check if at limit for workshop
  • Use username to create IAM user and credentials
  • Create thing, certificate, attach to policy
  • create Cloud9 instance for user
  • Update DynamoDB with the contents

And after creation the values are returned within a 25 second period. The application should set a notice to the user that assets are being created and to wait.

User Sign up and Sign in Flow
Figure 1. User Sign-up and Sign-in Flow

Testing Lambda Functions

From the cdd/ directory, use the following sam local command on the test events in tests/:

$ sam local invoke "FunctionName" -e event.json
$ # Or to use a specific profile
$ sam local invoke --profile my-aws-profile "FunctionName" -e event.json

Installing Packages for Lambda Functions

In order to properly operate in the Lambda runtime environment, use the following steps to include packages with proper share objects or binary components:

  1. In the root of the Lambda function, execute the following, replace python version and package(s) to install:
$ docker run -v "$PWD":/var/task -it lambci/lambda:build-python3.7 /bin/bash -c "pip install cryptography -t .; exit"

The /bin/bash -c "pip install cryptography -t .; exit" is a single line to install the packages in what is mapped to the local lambda directory. You could also use /bin/bash which will place you into the build container where the individual pip install package_name -t . lines could be processed.

Copyright © 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.