This lab module will walk through how the dispenser, dispenser app, and coupled services interact. It will go into level of detail specific for the workshop. If you would like to review more details, please reference the Setting Up the Workshop documentation for deeper insights.
By then end of this module you will have:
Follow each step in order and use the Click to open for detailed step-by-step instructions if required.
As this solution is designed as a software-as-a-service (SaaS) environment, there needs to be a specific relationship between all of the resources to help enforce the security and operational controls of the actions. At a high level this is how the resources are associated with each other:
Each thing has a unique X.509 client certificate for authentication allowing the dispenser to connect to AWS IoT and publish and subscribe to the MQTT topics specific for that dispenser. This authorization of MQTT topics comes from a common policy attached to the certificate that uses substitution variables that read the Common Name value from the X.509 certificate which contains the dispenser Id. This allows for an easier management of the authorization policies, as a single policy can be used for all dispensers. The relationship between the dispenser and the user is modeled into a Cognito User attribute, custom:dispenserId
, that is read for every API call. Finally, your dispenser has an entry in the DynamoDB DispenserTable that tracks the credit balance and any in-flight or stale command operations.
Go to the AWS Console to review the relationships for your dispenser and your own user in the following AWS services:
custom:group
and custom:dispenserId
attribute values.The Device Shadow Service for AWS IoT is a service that can be used by things and applications to set and track the state of device. There are two main sections in the shadow document: the desired state and the reported state. In our solution the desired settings originate from the dispenser app. The dispenser acts upon them and set the correct reported state.
To see this in action, from the AWS Console navigate to your Thing in IoT Core, then select Shadow which will show the current shadow document. Note the led
attribute in the desired and reported sections, which should be the same. Also notice the value for version
in the metadata. This increments each time the shadow is updated. To see how the shadow is working, use the dispenser app to change the state of the LED by either toggling or setting to the other state. You will see the value for led
has changed in the shadow document, in both desired and reported sections, and version
has incremented.
To see how the shadow works when the device is in a disconnected state, unplug the microcontroller from your laptop. Now, in the dispenser app change the state of the LED and notice that the desired change to show the new value but that the reported state is still what the dispenser was in before being disconnected. Notice also that a new delta section has appeared in the document, containing just this led
field. This is automatically calculated by the Shadow service. Plug the microcontroller back into your laptop. Once it has booted and connected AWS IoT, the LED will change to the desired state value and the dispenser will update the reported state. Since desired and reported states are the same, the delta state for the LED is removed.
The shadow can also be used for more complex operations. While changing the state of the LED can be tracked via a single attribute, operations such as dispensing a drink are more complex and require multiple states such as request and response. The dispenser app initiates the dispense operation as a request, and when the dispenser completes the operation it, in turn, sets a corresponding response. We use a short, random, requestId
value to match the correlate the request and response states.
As we cannot be sure that the dispenser is online, the dispenser app initiates the request and sets the desired state of the shadow with a request
object containing the command
to execute, a unique requestId
, and the timestamp
of when the user clicked "Dispense a Drink" in the dispenser app.
To verify, ensure the microcontroller is connected and LED operations take place. Next, use Test from the IoT Core console and subscribe to the topic $aws/things/dispenserId/shadow/#
(replace dispenserId
with your value) to track all shadow operations. Next, in the dispenser app click the Dispense! button (should still be green) to initiate a dispense operation. From the MQTT Client tab, you should see a few shadow topic messages. Scroll through and review how the first message sets the request
object, and after the dispenser completes turning the pump (indicated by the animated LED pattern on the LED Ring) the reported state is updated with a response
object that has the same requestId
, and finally that the the request
and response
objects are both deleted from all shadow sections once the response has been reconciliated.
In this situation, we are using the shadow to track the status of a command sent to the dispenser, and the response once it acts upon it.
Oops! While testing how the Shadow works We used up all of our credits. Each dispense operation costs $1.00, and has been deducted from our dispenser credit, as shown by the dispenser app. Navigate to the DynamoDB DispenserTable and verify the credits match the dispenser app. Also, review the EventsTable for your dispenser (review the first steps in this lab if needed) to see the various logging entries made while testing the Ring LED and drink dispense test.
We use these tables as the source of truth for the status of our dispenser. While the dispenser code you compiled and installed could be modified, a dispense operation can only be performed if there are sufficient credits in the account (e.g., DynamoDB DispenserTable entry). We use the value of the dispenserId
across the dispenser app (user account custom attribute), IoT Core (Thing name, Certificate CN) and DynamoDB DispenserTable (dispenserId key) to enforce the desired controls in the overall SaaS application.
The dispenser app is your main interface for interacting with the dispenser, eg to dispense a drink, and to check its state. As the dispenser app is running inside your local browser, there are two methods that can be used to track what is the current status. We can continuously poll via an API to return the status, or use a callback mechanism to alert the dispenser app when something has changed. In our app we use the callback method, and specifically it does this by subscribing to the MQTT topics for your specific dispenser. This reduces the overall load on the SaaS service and demonstrates how we can use the features of AWS IoT Core to simplify the implementation.
Modern web browsers have the ability to monitor what is running locally. Our dispenser app has additional debug, or console.log()
statements to give an indication when something is happening. From your browser, enable the Web Console (name varies based on browser), and select the Console tab. Now change the status of the LED. Every time you make a change, you will see an Received MQTT message with change in LED or credit status message. This is alerted when an incoming MQTT message of interest such as a shadow update occurs.
These messages then trigger the dispenser app to make an API call requesting the complete status of the dispenser (LED status, credits, etc.), which in turn updates the main dispenser page. If there are no changes being made, no MQTT messages are generated, and subsequently, no API calls are made to request an update to the dispenser app.
Now that we have shown how you interact with your dispenser via the dispenser app, let’s build our credits up to a sufficient level to complete the rest of the lab. To do this, click on the Share the Love! panel underneath the LED status panel and follow the instructions. First, try giving credit to another dispenser number and monitor the Last credit response message (with or without browser logging). Next, try to give yourself credits and note that the gray button to the right does not change to SEND CREDIT!. This is a constraint built into the dispenser app. However, even if you were to make a direct API call, the backend will also deny the request.
Finally, talk to your neighbors and ask them to start sending you credits. You may also see that as the credits increase, the LED Ring will also start to fill until you have at least $1.00, and after that the colors will changes as your balance goes above $2.00, $3.00, etc.
It is recommended that you have at least $2.00 or $3.00 to perform a couple dispenses with a fully built dispenser unit.
Good work!
Please ensure the following checkpoints are validated before moving on to the next module.
Why do we use the shadow document for command and control, when it could also be done with regular MQTT messages? While either pattern are good practices, combining all of the operations into a single location makes it easier to follow for the workshop. As long as there is a way to track each request, the mechanism used doesn’t matter.
One thing that we didn’t discuss is the LED Ring. In this case, it is used to give a visual indication of the credit levels. From the dispensers perspective, it is another shadow attribute set to manage. But instead of being set by clicking buttons in the dispenser app, this value is programmatically set by the cloud services whenever there is a change in the credit state of a dispenser. This demonstrates that functionality in not static and can be modified in either device (dispenser) or the application (cloud-side).