はじめに
アレクサで、古い家電を操作する目的で購入したNature Remo。
センサーがとても秀逸だったので、部屋のモニタリングする仕組みを作ってみました。
部屋の環境が一目でわかるようになり、色々活用できそうです。
Nature Remo Cloud APIを利用して、Googleのサービスで作ってみました。
GAS(GoogleAppsScript)でGoogleスプレッドシートにデータを頂いて、Googleデータポータルにまとめてみました。これでサーバーレスかつセキュアなクラウド型環境監視ダッシュボードが完成しました。
とりあえず、トリガーで1時間ごとに自動更新することにしました。
Nature Remo、Googleスプレッドシート、Googleデータポータルの順を現した写真
今回のゴール
Googleデータポータルでリビングの照度、温度、湿度を監視。
1時間おきのログを目視的に確認できるようにする。
必要なもの
Nature Remo
https://nature.global/
Nature Remo(ネイチャーリモ)は、お使いの家電をインターネットに繋げることで、手軽にスマートホームを実現するスマートリモコンです。
持ってない人は購入してくださいね。
Nature Remo
今回の説明は、Nature Remoセットアップ完了後を想定して説明します。
Googleアカウント
持っていない人は作成してください。
### https://support.google.com/accounts/answer/27441?hl=ja
NatureRemoのアクセストークンを発行する
### https://home.nature.global/
↑URLからログイン
Googleアカウントでログイン
Remoへのアクセスをリクエストする
アクセストークンの生成
アクセストークンの生成をクリックします。
コピーします。
アクセストークンはとても大切なので、公開することのないように、厳重に管理してください。
この後、このトークンを使用しますので、適切に保存してください。
Googleスプレッドシート作成
https://docs.google.com/spreadsheets/u/0/
シート作成
スプレッドシート名は任意でOKです。 A1に日時、B1に温度、C1に 度、D1に照度、E1に日時(補正)を入力して表題部分を作成します。 シート名を**log**に変更しておきます。GASでNatureRemo Cloud APIを呼び出す
GASって何?
簡単に言うと、Googleが開発した軽量アプリケーション開発用のスクリプト言語です。
Google Apps Script 入門
GASを作成
シートのツール、スクリプトエディタの順にクリックします。
すると、GASのスクリプトエディタが起動します。
次のソースコードを入力します。
ソースコード
var access_token = '***************'//←トークンを入れる
var spreadsheetId = '*****************'//←スプレッドシートのIDを入れる
function remo() {
var data = getNatureRemoData(); //data取得
var lastData = getLastData(); //最終date取得
setLaremoData(
{
te:data[0].newest_events.te.val, //温度
hu:data[0].newest_events.hu.val, //湿度
il:data[0].newest_events.il.val, //照度
},
lastData.row + 1//最終data追加作業
);
}
function getNatureRemoData() { //Remoのapiをお借りします
var url = "https://api.nature.global/1/devices";
var headers = {
"Content-Type" : "application/json;",
'Authorization': 'Bearer ' + access_token,
};
var postData = {
};
var options = {
"method" : "get",
"headers" : headers,
};
var data = JSON.parse(UrlFetchApp.fetch(url, options));
Logger.log(data[0].newest_events)
Logger.log(data[0].newest_events.te.val)
Logger.log(data[0].newest_events.hu.val)
Logger.log(data[0].newest_events.il.val)
return data;
}
function getLastData() {
var datas = SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getDataRange().getValues() //logシートをゲットする
var data = datas[datas.length - 1]
return {
totalpoint:data[1],
coupon:data[2],
row:datas.length,
}
}
function setLaremoData(data, row) {
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, 1).setValue(new Date())//A2にゲットした日時ほりこむ
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, 2).setValue(data.te) //B2に温度追加
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, 3).setValue(data.hu) //C2湿度追加(幅があるけど気にしない)
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, 4).setValue(data.il) //D2照度追加
}
※remoの機種によってセンサーの内容が異なります。 mini対応分もコード貼っておきます。(温度のみ)
/**
* アクセストークンとスプレッドシートのIDを設定
*/
const ACCESS_TOKEN = '**********'; // アクセストークンをここに設定
const SPREADSHEET_ID = '**********'; // スプレッドシートのIDをここに設定
/**
* Nature Remoのデータを取得してスプレッドシートに記録するメイン関数
*/
function updateRemoDataToSheet() {
try {
const data = fetchNatureRemoData(); // Nature Remoデータを取得
if (!data || data.length === 0) throw new Error('No data returned from Nature Remo.');
const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName('log');
if (!sheet) throw new Error('Sheet "log" not found.');
const rowData = buildRowData(data[0]);
appendRowDataToSheet(rowData, sheet);
Logger.log('Data updated successfully.');
} catch (error) {
Logger.log(`Error: ${error.message}`);
}
}
/**
* Nature RemoのAPIからデータを取得
* @return {Object[]} データ配列
*/
function fetchNatureRemoData() {
const url = 'https://api.nature.global/1/devices';
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${ACCESS_TOKEN}`,
};
const options = {
'method': 'get',
'headers': headers,
};
const response = UrlFetchApp.fetch(url, options);
return JSON.parse(response.getContentText());
}
/**
* 取得したデータからスプレッドシートに追加する行データを構築
* @param {Object} deviceData Nature Remoデバイスデータ
* @return {Object} 行データ
*/
function buildRowData(deviceData) {
return {
timestamp: new Date(),
temperature: deviceData.newest_events.te?.val || 'データなし',
humidity: deviceData.newest_events.hu?.val || 'データなし',
illumination: deviceData.newest_events.il?.val || 'データなし',
};
}
/**
* 構築した行データをスプレッドシートに追加
* @param {Object} rowData 行データ
* @param {GoogleAppsScript.Spreadsheet.Sheet} sheet スプレッドシート
*/
function appendRowDataToSheet(rowData, sheet) {
sheet.appendRow([rowData.timestamp, rowData.temperature, rowData.humidity, rowData.illumination]);
}
よくわかんないや!ってかたは、とにかくソースコードを貼り付けます。
貼り付ける時は最初入っているコードごと上書きしてください。
任意の名前を付けます。
ちなみに今回はリビング環境監視にしてみました。
NatureRemoのアクセストークンを指定する
初めに取得したアクセストークン(大切なやつ)をaccess_token = 'から後の***マークの部分に貼り付けます。
スプレッドシートのIDを指定する
続いて今回作成したスプレッドシートのIDをspreadsheetID = 'から後の***マーク部分に貼り付けます。
※スプレッドシートのIDって何よ!?って人は、一つ下を参考にしてください。
スプレッドシートのID確認方法
今、スクリプトエディタが開いている場合は、タブでスプレッドシートを開いてURLを確認してください。
GASを実行
ついに準備が整いました。
今、画面にスプレッドシートを開いている場合はスクリプトエディタを再度開いてください
エディタの上の方に三角の再生ボタンがありますよね。
いきなり実行してみてください
※2020/09/06追加
当初大丈夫だったのですが、現在は関数を選択で、remoを選択しておかないとエラーになるみたいです。
承認
すると、承認が必要です画面がポップアップされるので、許可を確認をクリックします。
このアプリは確認されていません
当然今作っているので確認されてたらおかしいのですが、とりあえず詳細を選択。
つづいてリビング環境監視(安全ではないページ)に移動を選択。
アカウントへのアクセスを許可
許可を選択します。
これで実行されたかと思います。
確認してみましょう。
スプレッドシートを確認
表題の下に数値が入っているでしょうか?
入っていれば、APIの呼び出しに成功です。
日時(補正)が気になりますよね。
生データだと、秒まで入っているので、不要な部分を取り除くための処理です。
GASで表示形式(フォーマット)を指定して日時を追加するようにすればいいのだけですが、スプレッドシートにはエクセルには存在しない素晴らしい関数があるので、そちらを紹介することにします。(まぁ、ぶっちゃけ手抜きです。)
これで、年月日と時間までのフォーマットのデータの列が完成しました。
E2に=ARRAYFORMULA(TEXT(A2:A,"YYYYMMDDHH"))
と入力します。
このARRAYFORMULA。発想がクレイジーで、一発目に使用すれば、数式を配列形式で表示します。Excelに無い概念ですね。
つづいて、表を整理します。
少しでも不具合を回避するために、不要な部分を消します。
3行目から1000行目(最終行)までを削除しておきます。
3行目を選択して、最終行をShiftを押したまま選択すると3行目から1000行目(最終行)までを選択できます。
※F列からZ列も同じように削除しておきましょう。また、setシートについても同じように不要な行列は削除しておきましょう。
トリガー設定
続いて、このデータを定期的にスプレッドシートに自動でためていく処理を実装します。
スクリプトエディタに戻って編集、現在のプロジェクトのトリガーを選択。
トリガーって引き金っていうことだと思うんだけど、条件によってさっき作ったGASを実行しますよ!ってことができるんです。
トリガーの設定画面に移るので、右下のトリガーを追加を選択します。
時間の間隔を選択(時間)で今回は1時間おきを選択し保存します。
スクリプトエディタに戻って保存ボタンを押して保存してスクリプトエディタを閉じます。
管理シート追加
setシートを作成していきます。
データの表題を作成します。
A1から1列目を順に温度、湿度(グラフ)、湿度、照度と入力します。
続いて式を作成していきます。
logシートのデータから、最新のものを表示してみます。
温度A2に=LOOKUP(10^10,log!B:B)
湿度(グラフ)B2に=LOOKUP(10^10,log!C:C)
つづいて、湿度については円グラフを作りたいので、残りの100分率を求めます。
ですので、B3に=100-B2
と入力します。
照度D2に=LOOKUP(10^10,log!D:D)
おつかれさまです。第2部 スプレッドシートの作成はこれで完了です!
いよいよこのシートを使って環境監視画面(ダッシュボード)を作成していきます。
Googleデータポータル
Googleデータポータルは、Googleが提供するBI(ビジネスインテリジェンス)ツールです。
データを接続して、グラフや表を使って可視化することができます。
詳しくはGoogle先生に聞いてみてくださいね。
リビング環境監視作成
で、早速新しいレポートの開始をクリック。
空白から作りたいと思います。(空白良い響きですね)
https://datastudio.google.com/u/0/
データソース接続
データソースを選択する画面になります。
ここで、先ほど作成したGoogle スプレッドシートのシートを一つづつ選択します。
まず、リビング環境監視を選択、続いてワークシートのlogを選択します。
データソースを追加します。
レポートに追加を再度クリックします
これで、Google スプレッドシートのlogシートが追加されました
もう一つ、同じ要領でsetシートも追加します。
リソースをクリックします。
先ほど追加したデータソースが表示されています。
下のデータソースを追加をクリックします。
リビング環境監視を選択、続いてワークシートのsetを選択します
データソースを追加します。
レポートに追加を再度クリックします。
監視画面作成
データソース接続が完了したので、いよいよ作りこんでいきます。
先にテーマを設定します。
現在のテーマがシンプルになっているので、**シンプル(暗)**を選択します。
私の場合は、ディスプレイの消費電力量、眼球に対する負荷、の2点(実際の影響は微小または気分だけ)からダーク色を基本としています。
※ここら辺は好みに合わせて色々いじってみてくださいね。
一覧表作成
いよいよグラフを作成していきます。
グラフを追加を選択します。
えっ、できた!?と一瞬思います。が、
Google先生が適当に作ってくれるので、これを整えていきます。
使用可能な項目からドラッグアンドドロップの方式で、必要な設定項目にデータソースを設定していきます。まず、日時(補正)を期間のディメンジョンの日時の上にドロップします。
続いて、表に湿度と照度を追加してみます。
先ほどと同じ方法で、指標の指標を追加の上あたりに対して、使用可能な項目から、湿度、照度をドラッグアンドドロップします。
表に追加されれば成功です。
ん?日時(補正)の順番がおかしい?
並べ替えを確認します。
温度とかになっていたら、クリックして、**日時(補正)**を選択します。
日時(補正)順に並び替わると成功です。
また、表の見た目を変更するにはスタイルをいじってみてください。
温度・湿度折れ線グラフ作成
またまたいい感じにGoogle先生が作ってくれるので、先ほど同様修正していきます。
期間のディメンジョンを**日時(補正)**に変更します。
照度の棒グラフ
先ほど同様、期間のディメンションを**日時(補正)**に変更します。
湿度の円グラフ
湿度を表す円グラフを作成します。
グラフを追加から円グラフを選択します。
なんかド派手なんができてしまいました。
これは、logのソースコードを使用したためです。
データソースリビング環境監視をクリックします。
ディメンション、並べ替えを湿度に、指標を**湿度(グラフ)**に変更します。
すると、円グラフが現れました。
湿度・温度・照度スコアボード
湿度、温度、照度の現在の値を作成していきたいと思います。
グラフを追加からスコアカードを選択します。
スコアボードのデザインを作る
湿度のスコアボードを先ほど作成した円グラフの真ん中に移動させます。
温度と照度のデザインも円形で囲んで統一感を出したいと思います。
円形をクリックします。
円形が作成されるので、円グラフと同じ形状になるように調整します。
円形のプロパティで背景色を透明に、枠線の色と太さを調整します。
期間の指定
期間を指定して、情報を見ることができるように、期間を選択のコンボボックスを作成します。
上部のカレンダー(期間)をクリックすると作成できます。
リンク
下のソースデータにアクセスするためのリンクを作成します。
上部のT(テキスト)をクリックします。
いったん、スプレッドシートのURLをコピーし、URLを貼り付けて適用をクリックします。
デザイン仕上げ
グラフ全体のデザインを自分の好みに調整してみてください。
各グラフを選択して、スタイルのフォント色やグラフの系列色などを変更してみてください。
これで今回のゴールに到着です。
大変お疲れさまでした。
さっそく、ビューをクリックして出来上がりをご確認ください。
おまけ
###アラート通知設定 2020年3月14日追加
リビングを環境監視して、一定温度以上になるとアラートメールで知らせる方法(Nature Remo Cloud APIとGoogleサービス連携)
###その後のお話 2021年6月5日追加
リビングの環境監視ダッシュボードを60分で作る方法をQiitaに投稿してから数年たった今のお話。
###スプレッドシートセル上限対応(暫定)
500万セル制限により、いつかはスプレッドシートの上限値到達によりダッシュボードが停止してしまいます。
IMPORTRANGE関数を利用する方法もありますが、半永久的(サービス変更がなければ)にオートメーション化したいので、上限前に指定ファルダにデータをコピーして、データをクリアする方法をざっくり作ってみました。
っていっても、不要なセルを全て削除した状態かつ、現在のルールでは100年以上上限値になることは無いのですが、とりあえず100年後にバックアップとクリアを繰り返すことにしました。
※logシートF列からZ列削除とsetシートについても同じように不要な行列削除状態。
###何列まで稼働するのか?
setシート 12行×4列=48セル
上限5,000,000セル-48セル=4,999,952セル
logシート 5行なので
4,999,952÷5行=999,990.4列
≠999,990列までは稼働可能
###100年設定
365日×75年+366×25年=36,252日 36,252日×24時間+1行=876,601列
まず、Googleドライブでバックアップ用のフォルダを作成します。
そして、GoogleスプレッドシートのGASを次のとおり変更します。
(フォルダIDを出力フォルダを指定するコードのID部分に入力)
var access_token = '***************'//←トークンを入れる
var spreadsheetId = '*****************'//←スプレッドシートのIDを入れる
function remo() {
var data = getNatureRemoData(); //data取得
var lastData = getLastData(); //最終date取得
setLaremoData(
{
te:data[0].newest_events.te.val, //温度
hu:data[0].newest_events.hu.val, //湿度
il:data[0].newest_events.il.val, //照度
},
lastData.row + 1//最終data追加作業
);
}
function getNatureRemoData() { //Remoのapiをお借りします
var url = "https://api.nature.global/1/devices";
var headers = {
"Content-Type" : "application/json;",
'Authorization': 'Bearer ' + access_token,
};
var postData = {
};
var options = {
"method" : "get",
"headers" : headers,
};
var data = JSON.parse(UrlFetchApp.fetch(url, options));
Logger.log(data[0].newest_events)
Logger.log(data[0].newest_events.te.val)
Logger.log(data[0].newest_events.hu.val)
Logger.log(data[0].newest_events.il.val)
return data;
}
function getLastData() {
var sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName('log') //20190815追加
var datas = sheet.getDataRange().getValues() //20190815変更
var data = datas[datas.length - 1]
return {
totalpoint:data[1],
coupon:data[2],
row:datas.length,
}
}
function setLaremoData(data, row) {
var sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName('log') //20190815追加
sheet.getRange(row, 1).setValue(new Date())//20190815変更
sheet.getRange(row, 2).setValue(data.te)//20190815変更
sheet.getRange(row, 3).setValue(data.hu)//20190815変更
sheet.getRange(row, 4).setValue(data.il)//20190815変更
//20190815追加 スプレッドシートを指定フォルダにコピーしてデータ削除 (スプレッドシートセル上限対応)
if (LastRow = 2) {
//E2に=ARRAYFORMULA(TEXT(A2:A,"YYYYMMDDHH"))挿入
var range = sheet.getRange("E2").setValue('=ARRAYFORMULA(TEXT(A2:A,"YYYYMMDDHH"))');
} else {
Logger.log('そのまま');
}
// A列の値を配列で取得
const columnBVals = sheet.getRange('A:A').getValues();
//空白を除き、配列の数を取得
const LastRow = columnBVals.filter(String).length;
Logger.log(LastRow);
// 行数が指定した数値を上回れば処理実行 365日×75年+366×25年=36252日 36252日×24時間+1行=876601行
if (LastRow > 876601) {
Logger.log('処理実行');
// コピー元ファイル
var templateFile = DriveApp.getFileById(spreadsheetId);
// 出力フォルダ
var OutputFolder = DriveApp.getFolderById('*****************');//←バックアップフォルダのIDを入れる
// 出力ファイル名
var OutputFileName = templateFile.getName().replace('_template', '')+'_'+Utilities.formatDate(new Date(), 'JST', 'yyyyMM')
templateFile.makeCopy(OutputFileName, OutputFolder);
sheet.deleteRows(2,876601);
} else {
Logger.log('そのまま');
}
}
とりあえずの思い付きなので、雑過ぎですが、何かの参考になればと思います。
100年間リビングの環境データを蓄積し、その後データをバックアップしてリセットを繰り返す感じです。
Googleの99%以上の可用性を誇るクラウドが100年後もあることを願って仕組みを作ってみましたが、リビングが100年以上ある可能性が極めて低いことに気づいてしまいました。というオチでした。
参考
- Nature Remo
- Google Apps Script 入門
- [Nature RemoのAPIを叩き続けて温度と湿度を集計してみた。] (https://blog.pnkts.net/2018/05/21/nature-remo-api/)
- Google Apps Script(GAS)でGoogleドライブ内のファイルを指定フォルダに複製する!