Nature Remo+AWS+LINE Notifyで緩やかな自宅監視(1)
家族がいると自宅の様子が気になる、けれども監視カメラを設置するのは家族のプライバシー的に行き過ぎた感あり、もう少し緩やかな監視ができないか?と考えた際、照度の変化に着目したソリューションを思いついた。
つまり、家族が帰宅して部屋の電気を付けた、外出のため消灯した、電気を消して寝静まったといった状態の遷移を「照度の変化」によって検知し、スマホに通知する、といった具合だ。
概要
Nature Remo 3は外出先からスマートフォンで家電を制御するためのスマートリモコン製品のひとつであるが、照度や温度センサーが取得した情報を Nature Remo Cloud API によりクラウドから取得できる、という大変素晴らしい特徴がある。
自宅に設置したNature Remoの照度を、AWSのLambda関数により一定時間毎に取得してDynamoDBに蓄積する。前回取得した照度と比べて急激な変化があった場合、LINE Notify APIを使用してスマホにピロリン♪と通知してみよう。
なお、Nature Remo 3の設置、WiFi経由でのインターネット接続、スマートフォンアプリとの連動などは一通り設定済みである前提とする。
Nature Remo Cloud API アクセストークンを発行
APIを使用するにあたり、まずはhome.nature.globalのサイトへログインし、「Generate access token」ボタンからOAuth2認証のためのアクセストークンを発行する。アクセストークンはこの後使用するため、安全な場所に保管しておく。
AWS Lambda 関数を作成
ここからはAWSコンソールにサインインして作業する。
まず初めに、新規のLambda関数を作成する。
- 関数名: NatureRemo_Save
- ランタイム: Node.js 20.x
続いて、先ほど作成したトークンを環境変数として設定しておく。
「Lambda > 関数 > NatureRemo_Save > 環境変数の編集」にて下記の通り設定する。
- キー: NATURE_REMO_TOKEN
- 値: Nature Remo Cloud APIのアクセストークン
Nature Remo Cloud APIのドキュメントに書いてある通り https://api.nature.global/1/devices のURLに対してAuthorizationヘッダーにトークンをセットしてリクエストすると、センサーが取得した最新の照度などがJSON形式で返ってくる。JSONはNatureアカウントに登録されたデバイスの個数分が配列となっており、各配列要素内で下記のようにして情報を取得できる。
- name: 登録されたデバイス名
- newest_events.il.val: 最新の照度の値
- newest_events.te.val: 最新の温度の値
curlで試すとJSONが返るところまであっさり確認できたので、さっそくLambda関数の「index.mjs」を書いてみる。
import https from "https";
export const handler = (event) => {
const url = "https://api.nature.global/1/devices";
const options = {
headers: { "Authorization": "Bearer " + process.env.NATURE_REMO_TOKEN }
};
https.get(url, options, (response) => {
let data = "";
response.on("data", (chunk) => { data += chunk; });
response.on("end", () => {
data = JSON.parse(data);
console.log("name: " + data[0].name);
console.log("il: " + data[0].newest_events.il.val);
console.log("te: " + data[0].newest_events.te.val);
});
});
};
Deploy〜Testして、期待通り照度や温度が取得できた!
Function Logs
2023-12-21T15:59:21.272Z ... INFO name: Remo
2023-12-21T15:59:21.311Z ... INFO il : 106
2023-12-21T15:59:21.311Z ... INFO te : 20.4
DynamoDB テーブルを作成
AWSのDynamoDBコンソールから、照度データを保存するためのテーブルを新規に作成する。
- テーブル名: NatureRemo_Records
- パーティションキー: device(文字列)
- ソートキー: timestamp(数値)
DynamoDBではTTLという便利な機能があり、テーブルの項目の特定の列に入れたUnix時間を超過すると自動で項目を削除してくれる。項目が単調増加により増えすぎるのを防ぐことが可能。
TTLの設定はちょっとわかりにくいところにあり、dynamoDBコンソールの「テーブル > 設定の更新 > NatureRemo_Save」テーブルを選択し、「アクション > TTLをオンにする」で設定画面が開くので、「TTL属性名: ttl」と設定する。
Lambda関数からdynamoDBへデータを保存する
データ保存処理を書く前に、Lambda関数からdynamoDBへアクセス可能にするためのロール設定を行う。ロール設定をうっかり忘れると、この後のテーブルへの項目追加処理でエラーとなってしまうので要注意。
NatureRemo_Save関数の「設定 > アクセス権限 > ロール名 NatureRemo_Save-role-...」をクリックすると、「IAM > ロール > NatureRemo_Save-role-...」のロール設定画面となるので、「許可ポリシー > 許可を追加」から「AmazonDynamoDBFullAccess」を追加する。
無事にロール設定が完了したら、Lambda関数の「index.mjs」のコードへ戻り、まずはdynamoDBへアクセスするためのモジュールをインポートしてDB接続用クライアントを生成する。
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";
const db = new DynamoDBClient({ region: "ap-northeast-1" });
テーブルに項目を追加するためには PutItemCommand オブジェクトを生成して、DB接続用クライアントで send する。PutItemCommand の中身 Item には、文字列は { S: "foo" } 数値は { N: "123" } といったようにする必要があり、素人目にみてなんともイケていない仕様に感じるけど、こういうものなのか?ちなみに数年前に同じことをやったときの当時のAWS SDKでは、数値型のまま普通に突っ込めた。
response.on("end", async () => {
data = JSON.parse(data);
const unixtime = Math.floor(Date.now() / 1000);
const putCmd = new PutItemCommand({
TableName: "NatureRemo_Records",
Item: {
device : { S: data[0].name },
il : { N: data[0].newest_events.il.val.toString() },
timestamp: { N: unixtime.toString() },
ttl : { N: (unixtime + 60*60*24*3).toString() }
}
});
await db.send(putCmd);
});
テスト実行し、コンソールに出力される項目追加の処理結果が「httpStatusCode: 200」となることを確認。また NatureRemo_Records テーブルの「項目の探索」でテーブルの中身を見て、お見事、テスト実行のたびに項目が追加されるようになった!
今日はここまで
だいぶ長くなりそうなので、今日はここまで。明日からは引き続きLambda関数の定期的な繰り返し実行、LINE Notify APIを使用した通知を実装する予定。
つづきの記事はこちら
Nature Remo+AWS+LINE Notifyで緩やかな自宅監視(2)
Discussion