THINGS USED IN THIS PROJECT
|
× | 1 |
|
STORY
Background
The objective is to show a method to exchange state information between Particle devices and AWS-IoT. The use case is an IoT application where the device sleeps most of the time (to save battery) and retrieve commands from the cloud/server when the device wakes up. A motorized window treatment which uses a Particle to control a motor and position a shade/curtain is an example. It wakes up and connects to a server every few minutes; it retrieves the desired window treatment position from the server. If the desired position is different than the current position, the Particle changes the position to the desired position. Currently, the Particle.io server software does not store any state; if the Particle is off-line, then function calls to it are ignored.
AWS-IoT services provide a stateful entity called ‘thingShadow’ which maintains a desired and reported state data dictionary. A device can retrieve the state from AWS-IoT when it wakes up. Clients can change the desired state using Amazon’s API. Other Amazon services (Cognito, Lamda Functions, data stores) can be employed to add features like authentication, authorization and logging.
The thingShadow state is persisted in the Amazon cloud. It benefits from the Amazon infrastructure – it is highly available and is preserved through software updates. It has metadata for versioning and timestamping, so message duplication can be handled to avoid performing commands twice.
I could not locate a Particle library that supports the Amazon AWS-IoT API which is based on MQTT. To work around this, I wrote a small Node.js application that bridges the Particle javascipt API with the AWS-IoT javascript API. This application can be run on a Raspberry Pi or other server. I ran it on a macBook.
An objective of the javascript bridge software was to have it be completely generic: no hardcoded identifiers so that it could bridge devices that have different functions. The bridge is just passing the desired/reported state dictionary from AWS-IoT to the device and back.
Overview
This example has 4 behaviors that can be controlled by editing the ‘desired’ values in the AWS-IoT thingShadow state:
{
"desired": {
"blink": 0,
"wakeInterval": 7,
"rate": 5,
"duration": 6
},
"reported": {
"blink": 0,
"wakeInterval": 7,
"duration": 6,
"rate": 5,
"exampleValue": 12345
}
}
The desired state is what the client can edit; the Particle retrieves it on wake-up. The reported state is what the Particle publishes to acknowledge the desired state has been reached.
This example app has 4 configuration variables:
- blink: a transition from 0->1 or 1->0 results the particle running a task that blinks the blue LED as controlled by the duration and rate parameters below
- duration: how long the particle blinks the LED; range: 5 to 60 seconds
- rate: the number of blinks per second; range: 2 to 9
- wakeInterval: how long the particle goes to sleep for; range: 5 to 600 seconds
The Particle can report additional state information, such as environmental conditions, battery state or other operational parameters. AWS DB or logging services can be used to store state change histories using the thingShadow metadata.
Preparation
In this demo, we are not using any sensors or actuators. You need:
- An account on particle.io Your Access Token is needed when starting the bridge Node.js application.
- A Particle. You will need the device ID (aka coreID) for each Particle. The coreID will be used as the AWS-IoT thingShadow ID.
- Node.js installed on a server (PC or Raspberry)
- The particle API installed on the server: npm install particle-api-js –save
- A logger facility installed on the server: npm install nodejslogger –save
- The AWS-IoT SDK installed on the server: npm install aws-iot-device-sdk –save
- An AWS account which allows manipulating AWS-IoT resources.
- An AWS-IoT ‘thing’ having the same name as the particle CoreID. Refer to the AWS console documentation for how to create it. Edit the shadow state to have the 4 behavior control variables:
"desired": {
"blink": 0,
"wakeInterval": 7,
"rate": 5,
"duration": 6
},
- An AWS client certificate which can be created using the AWS IoT console. Store the certificate at: ~/certs/certificate.pem.crt
- A root/CA certificate stored at ~/certs/root-CA.crt CA stands for Certificate Authority. Refer to the Authentication in AWS IoT webpage for instructions on copying the VeriSign root CA certificate onto your node server.
- An AWS-IoT policy which defines the access control, again created using the console. I created a policy named ‘do_anything’ with the following content:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iot:*",
"Resource": "*"
}
]
}
Software
There are 2 software components:
- The C/C++ firmware, particle-aws-iot-listener.ino, which needs to be flashed onto your Particle. It requires the SparkJson library.
- The javascript module, aws-iot-particle-bridge.js, which runs under Node.js on the server. This can be downloaded from github.
The Particle software wakes up, publishes its function name to receive the state updates, waits for the state update, and based on the change of desired state, performs a task, which in this example is to blink the LED.
The javascript connects to AWS using the IoT credentials created during the ‘preparation’. It listens for events from the particle.io service and will retrieve or update the thingShadow’s state information. The intent was to keep the bridge as stateless as possible; it only stores the advertised function name.
Here is a log from the showing the AWS & Particle events when the shadow has been updated:
[20160628,06:10:12] DEBUG: (aws) connected to AWS IoT
[20160628,06:12:16] DEBUG: (particle) event received: {"data":"online","ttl":"60","published_at":"2016-06-28T10:12:12.734Z","coreid":"1c0023000a47343432313031","name":"spark/status"}
[20160628,06:12:16] DEBUG: (particle) event received: {"data":"desired","ttl":"10","published_at":"2016-06-28T10:12:12.783Z","coreid":"1c0023000a47343432313031","name":"function"}
[20160628,06:12:16] DEBUG: (aws) registering for coreId: 1c0023000a47343432313031
[20160628,06:12:16] DEBUG: (aws) getting state for coreId: 1c0023000a47343432313031
[20160628,06:12:17] DEBUG: (particle) calling function: desired with argument: {"bli":1,"wak":7,"rat":5,"dur":6} for coreId: 1c0023000a47343432313031
[20160628,06:12:33] DEBUG: (particle) event received: {"data":"{\"blink\":1,\"wakeInterval\":7,\"duration\":6,\"rate\":5,\"exampleValue\":12345}","ttl":"10","published_at":"2016-06-28T10:12:31.860Z","coreid":"1c0023000a47343432313031","name":"stateReport"}
[20160628,06:12:33] DEBUG: (aws) updating state for coreId: 1c0023000a47343432313031
[20160628,06:12:33] DEBUG: (particle) event received: {"data":"offline","ttl":"60","published_at":"2016-06-28T10:12:31.861Z","coreid":"1c0023000a47343432313031","name":"spark/status"}
Particle.io uses publish to send data to the cloud and can use a function call to recieve data. The function call is limited to 63 characters, so the key names are truncated to 3 characters by the bridge when going from AWS-IoT to the particle. The truncation is not necessary on the particle publish since that supports 255 characters.
The intent of the bridge is to allow multiple Particles to be supported – it will listen for events from all your devices. It will only synchronize with AWS-IoT if the Particle publishes a function name. Only a single Particle was tested, however.
An objective for the bridge was to not embed any identifiers in the code. The AWS supplied aws-iot-device-sdk/examples/lib/cmdline is employed to allow passing the user’s credentials to the bridge module; the module used thethingname argument to pass in the Particle access token. Hence the shell command to start the bridge is as follows:
node aws-iot-particle-bridge -f ~/certs -T yourParticleAccessToken
You can start the Particle or bridge in either order. Once both are started, you should see:
- events being logged by the bridge as shown in the example above
- the Particle’s LED will cycle through the modes eventually showing the ‘connected’ mode. It will then go to sleep (the LED will turn off) and then restart.
- the ‘Shadow status’ in the AWS-IoT console should display ‘in-sync’.
To send a command to your particle, click the ‘Update shadow’ URL in the AWS-IoT console and edit one or more of the desired parameters. To see the blue LED blink, you need to change the blink value from 0 to 1 or 1 to 0. The blue LED should blink the next time the Particle wakes up. The Shadow status in the console should display ‘out of sync’ for a few minutes and then return to ‘in sync’.
The window in which to flash the particle is kind of tricky when the particle goes to sleep. If using the Particle Build web page, click on the ‘flash’ icon right when the Particle wakes up (as determined by the LED or the Particle status) – there is a time period after power-up when the Particle accepts flash commands. (An enhancement to the bridge would be to detect when a new version of software is available and flash it when the device comes on-line).
Conclusion
The Particle code can be used as template a IoT controller that sleeps. The AWS-IoT service allows clients to see a highly available view of the IoT device; the clients can change the desired state when the device is off-line or there are network outages. The bridge code will become obsolete when a Particle library that supports directly connecting to the AWS-IoT becomes available, but for now it provides visibility and flexibility.
There are other AWS-IoT examples that provide more step-by-step screenshots or other ways of using AWS:
COMMENTS
Please log in or sign up to comment.