AWS IoT CoreからTimestreamにルーティングする際、デバイスで付与した日時をタイムスタンプにするIoT Ruleの作り方

# はじめに
Timesteramが東京リージョンで使えるようになりました！
IoTのデータを保存する際に、デバイスで付与した日時をタイムスタンプとして使用するためのIoTルールの設定の方法を記載します。

# 前提
- デバイス~AWS IoT Coreは接続済み
- Timestreamのテーブルは作成済み
- IoTルールからTimestreamに書き込むためのIAM Roleは作成済み

### サービスにつけた名前など
- Timestreamデータベース名：ts-test
- Timestreamテーブル名：ts-table
- メモリストアの保存時間：3時間
とりあえず3時間にした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/fef4c153-6871-d38c-9d60-34f94038fb94.png)

この記事では、**IoT Rule**の作成方法を記載します。

### IoT CoreのTopicに送信するデータ
日時は日本時間で、タイムゾーンはついていないものとします。

```json
{
  "timestamp": "2022-08-04 17:50:00.111",
  "device_id": "device1",
  "condition": 10
}
```




## と、ここで・・・
マネジメントコンソールからIoT Ruleを作ろうとすると、ルールアクションにTimestreamが出てこない:cry::cry::cry:
デベロッパーガイドなどに書いてあるので、IoT RuleからTimestreamに連携出来ないはずは無い。**マネージメントコンソールが対応していない**のでしょう。仕方ないので、CLIで作るとします:cry:

　　`2022/8/3 AWSにフィードバックは出しておいたので、そのうち対応してもらえるとは思います。`
　　`今のところ、CLIで作成した後に、編集も出来ません。`

# 手順

payload.jsonを作って、CLIでIoTルールを作成する。

### IoT ルール作成
- IoT ルール名：iot_timestream　とする。

CLI
```sh
aws iot create-topic-rule --rule-name iot_timestream --topic-rule-payload file://payload.json
```

```payload.json
{
    "sql": "SELECT * FROM 'topic/timestream'",
    "ruleDisabled": false,
    "awsIotSqlVersion": "2016-03-23",
    "actions": [
        {
            "timestream": {
                "roleArn": "arn:aws:iam::<アカウント>:role/<IAMロール>",
                "databaseName": "ts-test",
                "tableName": "ts-table",
                "dimensions": [
                    {
                        "name": "device_id",
                        "value": "${device_id}"
                    }
                ],
                "timestamp": {
                  "value": "${time_to_epoch(timestamp,'yyyy-MM-dd HH:mm:ss.SSS') - 32400000}",
                  "unit": "MILLISECONDS"
                }
            }
        }
    ],
    "errorAction": {
      "cloudwatchLogs": {
        "roleArn": "arn:aws:iam::<アカウント>:role/<IAMロール>",
        "logGroupName": "<CloudWatchのロググループ>"
      }
    }
}
```

IoT ルール削除のCLI
```sh
aws iot delete-topic-rule --rule-name iot_timestream
```

## 説明
- IoTの"timestamp"をタイムスタンプにする方法
  actions.timestream.timestampにエポック日時を設定します。
(エポック日時、UNIX timeは、1970年1月1日からの経過時間)
  デベロッパーガイドに、「time_to_epoch() 関数を使用して、メッセージペイロードで渡される日付または時刻の値から有効なタイムスタンプを作成できます。」とあります。
  **関数を、actions.timestream.timestamp.valueに書きます。**
  **関数を使用するので、"sql"に書きたくなりますが、それだとうまくいきません。**

- タイムゾーンの変換
  変換前のデータ「例："2022-08-04 17:50:00.111"」にタイムゾーンなどもなく、UTC日時として認識されてしまいます。ここでは、日本時間は+9H、つまり、９時間のミリ秒(32400000)を引き算して変換しています。。
  ここで、**-の前後にスペースを入れる必要があります。**


```json
"timestamp": {
  "value": "${time_to_epoch(timestamp,'yyyy-MM-dd HH:mm:ss.SSS') - 32400000}",
  "unit": "MILLISECONDS"
}
```

- Timestreamが受け取ってくれる時間の範囲
**格納できる時間の範囲があります。**
"2022-08-04 17:50:00.111"（日本時間）をキーにする場合、
　
ここで、メモリストアを３時間にしています。
　
"2022-08-04 08:50:31"（標準日時）にデータを格納すると、
2022-08-04 05:45:31〜2022-08-04 09:25:31が格納可能な範囲のようです。
３時間５分前から35分後まで
　
範囲外のデータを格納しようとしたときは、以下のエラーが出ました。
``2022-08-04T08:50:31.407+00:00
The record timestamp is outside the time range [2022-08-04T05:45:31.270Z, 2022-08-04T09:25:31.270Z) of the memory store.``

# 結果
### IoTトピックに送信
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/e5950a61-7242-6442-5f6a-463209a09e9b.png)

### テーブルに格納された結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/c5208dcc-541d-2146-753b-1ad6303fd13b.png)

# おわりに
Timestreamを使いこなしていきたい！

# 参考
- デベロッパーガイド

https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/timestream-rule-action.html

- IoT Coreのtime_to_epoch()関数

https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-sql-functions.html#iot-sql-function-time-to-epoch

- AWS CLI Command Reference
aws iot create-topic-rule

https://docs.aws.amazon.com/cli/latest/reference/iot/create-topic-rule.html

- IOT Core rules to map timestamp to timestream

https://repost.aws/questions/QUmWAjLqG7RwGHCSL2tMrXvw/iot-core-rules-to-map-timestamp-to-timestream