How to Invoke AWS IoT Actions Only When a Reported Value Has Been Changed
Introduction
In this post, I'd like to give you tips on how to use AWS IoT.
If you already have used AWS IoT, you also would have used the AWS IoT Rule Engine. It gives your IoT devices the ability to interact with AWS Services. If your devices report or publish MQTT messages to a Device Shadow service, then the AWS IoT Rule Engine will evaluate them and invoke Actions (AWS Lambda, DynamoDB, etc...).
The Rule Engine can be defined using AWS IoT SQL. The constitution of SQL statements includes three clauses: SELECT, what data is delivered to following Actions (AWS Services); FROM, when the rule is triggered; and WHERE, whether the rule is evaluated as true or false.
For example, let's look at the SQL below:
SELECT topic(3) as deviceId FROM '$aws/things/+/shadow/update' WHERE state.reported.someIllegalState = True
The SQL describes that the rule is triggered when messages are published to $aws/things/+/shadow/update
(MQTT topic), evaluated as true when state.reported.someIllegalState
(the data reported by IoT devices) is true. Then, the SQL delivers the data ( topic(3)
as deviceId) to following Actions.
When you used AWS IoT in your project, was there a time when you'd like to invoke Actions only when a reported value had been changed? In other words, have you ever thought about invoking Actions only when a previous and current value reported by your IoT devices are differed? For example, in my project, we defined the illegal state of our IoT devices as boolean, and we invoked AWS Lambda only when it had been changed ( true
to false
and vice versa).
There are some methods to meet the requirement. In this post, I'd like to introduce the solution using $aws/things/+/shadow/update/documents
topic as it's the easier one.
How to use the topic
At first, I quote the document to explain its usage.
AWS IoT publishes a state document to this topic whenever an update to the shadow is successfully performed:
$aws/things/thingName/shadow/update/documents
The JSON document will contain two primary nodes: previous and current. The previous node will contain the contents of the full shadow document before the update was performed while current will contain the full shadow document after the update is successfully applied. When the shadow is updated (created) for the first time, the previous node will contain null.
The point is that if you subscribe the topic, or define it in the SQL statements, you can retrieve the previous and current data and also use them in the SQL statement. The real data can be like this.
{ "previous": { "state": { "reported": { "color": "red" } }, "metadata": { "reported": { "color": { "timestamp": 1483470355 } } }, "version": 3 }, "current": { "state": { "reported": { "color": "green" } }, "metadata": { "reported": { "color": { "timestamp": 1483470364 } } }, "version": 4 }, "timestamp": 1483470364 }
In this sample, you yourself can find that the previous value is red
and the value has been changed to green
.
It's pretty cool! But, well, how to use the topic? I'd like to introduce its usage with AWS SAM. If you'd like to invoke AWS Lambda when a value published by your IoT devices are differed, you can define such rules as below:
TestFunc: Type: AWS::Serverless::Function Properties: FunctionName: test-func CodeUri: src/handlers/test_func Handler: index.handler Runtime: python3.6 Events: TestFuncRule: Type: IoTRule Properties: AwsIotSqlVersion: 2016-03-23 Sql: | SELECT topic(3) as deviceId FROM '$aws/things/+/shadow/update/documents' WHERE previous.state.reported.someIllegalState = true AND current.state.reported.someIllegalState = false
In the above sample, if the previous someIllegalState
value is true and its current value is false, then the TestFunc
can be invoked.
Conclusion
The use of $aws/things/+/shadow/update/documents
is discussed in this post. I think there are many cases to match the solution to IoT projects. I hope you find this post helpful.