How to Invoke AWS IoT Actions Only When a Reported Value Has Been Changed

I explained how to use `$aws/things/+/shadow/update/documents` topic. I think it might be useful in many IoT projects.
2018.07.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

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.