IoT Eventsでデバイス毎に異なるしきい値を超えたらSNSトピックを発行する

デバイス毎に異なる「しきい値」を設けて、しきい値を超えた際に通知する仕組みをIoT Eventsを使って実現してみました。
2020.10.15

デバイスから来たデータについて、とあるしきい値を超えた際にメール送信したい要件があるとします。 すべてのデバイスでしきい値が同じであれば簡単ですが、デバイス毎にしきい値が異なる場合は、一工夫する必要があります。

というわけで、デバイス毎に異なるしきい値の通知をIoT Evnetsを使って実現してみました。 仕組みとしては、デバイス毎のしきい値をディテクター内に変数として保持して参照しています。

IoT Eventsを使った概要

おすすめの方

  • IoT Eventsの雰囲気を知りたい方
  • デバイス毎に異なるしきい値でイベント発行したい方

IoT Eventsとは

下記をご覧ください。

仕様を簡単に決める

デバイス

  • 水位情報をクラウドに送信する
  • デバイスが送信する水位情報は下記とする
    • 水位(メートル):waterLevel
    • 時刻(ミリ秒):timestamp
{
    "waterLevel": 10,
    "timestamp": 1601258079088
}

トピック

  • デバイスは下記トピックにデータを送信する
    • sample/<デバイスID>/waterLevel

クラウド

  • しきい値を超えた場合、SNSトピックを発行してメール送信する
  • しきい値を下回った場合、SNSトピックを発行してメール送信する
  • しきい値はデバイス毎に設定可能とする
  • しきい値のデフォルト値は「30」とする
  • しきい値の更新は、Low状態(しきい値を下回っている状態)のみ可能とする

しきい値の設定方法

MQTTで下記のJSONを送信するだけです。

{
    "threshold": 55
}

デバイス側からしきい値を設定する場合は、そのまま送信すればOKです。 もしユーザがWebブラウザ等で設定する場合は、API GatewayのバックにいるLambdaを使って、MQTTトピックにPublishするなどができます。

通知先のSNSトピックを作成する

しきい値を超えた際と下回った際にIoT Eventsが発行するSNSトピックを作成します。

  • トピック名: notify-water-level-sensor

SNSトピックの作成

続いてEメールのサブスクリプション設定を行います。

SNSトピックのサブスクリプション登録

IoT Eventsで探知機モデルを作成する

完成図は下記です。

IoT Eventsで作った探知機モデル

探知機モデルの作成

新しい探知機モデルを作成します。

新しい検知モデルを作成する

初期状態の探知機モデルができたので、これを作り込んでいきます。

検知モデルの初期状態

入力の設定

右上の「入力の作成」を選択して設定します。

  • 入力名: TestWaterLevelInputData

sample_input.json

{
    "deviceId": "d1234",
    "payload": {
        "waterLevel": 10,
        "timestamp": 1595817156346,
        "threshold": 30
    }
}

IoT Eventsの入力データを作成

入力属性はすべて選択しておきます(すべて使います)。

IoT Eventsの入力データを作成

Low状態の作成

既存のState_1を選択し、状態名をLowに変更します。

Low状態を作成

OnEnterイベントの設定(しきい値の初期値設定)

OnEnterのイベント追加を選択し、しきい値の初期値を設定します。

項目
イベント名 InitThreshold
条件 isUndefined($variable.threshold)
アクション 変数の設定
変数オペレーション 値の割り当て
変数名 threshold
値の割り当て 30

OnEnterイベントを作成

OnEnterイベントを作成

OnInputイベントの設定(しきい値の更新)

OnInputのイベント追加を選択し、しきい値の更新を設定します。

項目
イベント名 UpdateThreshold
条件 $input.TestWaterLevelInputData.payload.threshold > 0
アクション 変数の設定
変数オペレーション 値の割り当て
変数名 threshold
値の割り当て $input.TestWaterLevelInputData.payload.threshold

OnInputイベントを作成

OnInputイベントを作成

High状態の作成

状態をドラッグして新しい状態を追加し、状態名をHighに変更します。

High状態を作成

OnEnterイベントの設定

OnEnterのイベント追加を選択し、SNSトピックを発行してメール送信する設定を追加します。

項目
イベント名 SendMailToHigh
条件 true
アクション SNSメッセージの送信
SNSトピック 値の割り当て
ペイロード カスタムペイロード
種類 文字列
カスタムペイロード '水位の上昇を検知しました。対象デバイスID: ${$input.TestWaterLevelInputData.deviceId}, 水位: ${$input.TestWaterLevelInputData.payload.waterLevel}'

OnEnterイベントを作成

OnEnterイベントを作成

OnExitイベントの設定

OnExitのイベント追加を選択し、SNSトピックを発行してメール送信する設定を追加します。

項目
イベント名 SendMailToLow
条件 true
アクション SNSメッセージの送信
SNSトピック 値の割り当て
ペイロード カスタムペイロード
種類 文字列
カスタムペイロード '水位が低下しました。対象デバイスID: ${$input.TestWaterLevelInputData.deviceId}, 水位: ${$input.TestWaterLevelInputData.payload.waterLevel}'

OnExitイベントを作成

OnExitイベントを作成

状態遷移を定義する

LowからHighの繊維

項目
イベント名 over_threshold
トリガーロジック $input.TestWaterLevelInputData.payload.waterLevel >= $variable.threshold

状態遷移を作成(LowからHigh)

HighからLowの繊維

項目
イベント名 under_threshold
トリガーロジック $input.TestWaterLevelInputData.payload.waterLevel < $variable.threshold

状態遷移を作成(HighからLow)

探知機モデルを発行する

右上の「発行」ボタンを選択し、モデル名とIAMロール名を入力します。IAMロールはここで同時に新規作成してもらいます。

項目
モデル名 SampleWaterLevelModel
IAMロール名 iot-events-sample-water-level-role
探知機生成メソッド 一意のキー値ごとに探知器を作成する
探知機作成キー deviceId
ディテクターの評価方法 バッチ評価

探知機モデルを保存する

探知機モデルを保存する

最後に「保存して発行する」ボタンを押せば完了です!

探知機モデルができた

ログの有効化

IoT Eventsのログを有効化して、CloudWatch Logsで見れるようにしておきます。

IoT Eventsのログ設定をする

IoTルールアクションの作成

IoT Coreでルールを作成します。

項目
ルールの名前 sample_iot_events_water_level_rule
SQLルール 下記
アクション IoT Events入力にメッセージを送信する
入力名 TestWaterLevelInputData
ロール sample-iot-events-water-level-rule-role (※新規作成)
SELECT
 topic(2) as deviceId
 * as payload
FROM
 'sample/+/waterLevel'

IoTルールアクションを作成

動作確認してみる

水位情報を送信する(水位:10)

  • トピック: sample/d0001/waterLevel
  • データ: 下記
{
    "waterLevel": 10,
    "timestamp": 1602661307957
}

IoT Coreのテスト画面でデータを送信する

探知機モデルの様子

ディテクターにデバイス(d0001)が追加されました。現在の状態はLowです。

探知機モデルの様子

しきい値として、デフォルト値の30が設定されています。

探知機モデルの様子

水位情報を送信する(水位:40)

  • トピック: sample/d0001/waterLevel
  • データ: 下記
{
    "waterLevel": 40,
    "timestamp": 1602661307957
}

探知機モデルの様子

状態がHighになりました!

探知機モデルの様子

メールも届きました!

メールの様子

水位情報を送信する(水位:20)

  • トピック: sample/d0001/waterLevel
  • データ: 下記
{
    "waterLevel": 20,
    "timestamp": 1602661307957
}

探知機モデルの様子

状態がLowになりました!

探知機モデルの様子

メールも届きました!

メールの様子

新しいしきい値を送信する(しきい値:50)

  • トピック: sample/d0001/waterLevel
  • データ: 下記
{
    "threshold": 50
}

探知機モデルの様子

しきい値が50になりました。

探知機モデルの様子

水位情報を送信する(水位:40)

  • トピック: sample/d0001/waterLevel
  • データ: 下記
{
    "waterLevel": 40,
    "timestamp": 1602661307957
}

探知機モデルの様子

期待通り、特に変わりはありません。

探知機モデルの様子

水位情報を送信する(水位:60)

  • トピック: sample/d0001/waterLevel
  • データ: 下記
{
    "waterLevel": 60,
    "timestamp": 1602661307957
}

探知機モデルの様子

状態がHighになりました!

探知機モデルの様子

メールも届きました!

メールの様子

新しいしきい値を送信する(しきい値:55)

  • トピック: sample/d0001/waterLevel
  • データ: 下記
{
    "threshold": 55
}

探知機モデルの様子

しきい値は50のまま変化ありません。期待通りですね。

探知機モデルの様子

水位情報を送信する(水位:40)

  • トピック: sample/d0001/waterLevel
  • データ: 下記
{
    "waterLevel": 40,
    "timestamp": 1602661307957
}

探知機モデルの様子

状態がLowになりました!

メールも届きました!

メールの様子

さいごに

AWS IoT Eventsの各ディテクターの変数内にしきい値を設けることで、デバイス毎に異なるしきい値を設定してみました。 変数を使いこなすことで、もっと様々なモデル定義ができそうですね。

参考