【GAS】Nature Remoの温度や直近の操作をLINEに通知する
はじめに
祖母の認知症が進み、エアコンの操作が難しくなってきました。そこで、Nature Remo mini2を導入し、母や他の身内が遠隔でエアコンの操作を行えるようにしました。
ここで、以下の問題が発生。
- たまに部屋が冷えない
- だれが、どんな操作をしたか履歴が残らない
⇒Nature Remo mini2の動作履歴を取りつつ、操作履歴はLINEで通知することにしました。
追記:たまに部屋が冷えない問題は、エアコンのリモコン自体が故障していた模様。別のエアコンのリモコンで登録したら、問題なく動くようになりました。
方針
管理費用等の負担がほぼないこと。
⇒サーバーなしで定期実行できる、Googleスプレットシート&GASで作成することにしました。
必要なもの
今回の開発に必要なものは以下となります。
- Nature Remo (Nature Remo mini2を使用しました。約6000円)
- LINE ID
- Googleアカウント
- スマートフォン
- PC(開発用)
開発手順
-
Nature APIを使えるようにする
以下の記事を参考に、アクセストークンを発行しました。
https://qiita.com/sohsatoh/items/b710ab3fa05e77ab2b0a -
Line Notifyを使えるようにする
以下の記事を参考に、アクセストークンを発行しました。
https://qiita.com/iitenkida7/items/576a8226ba6584864d95 -
Googleスプレットシートを作成する
Nature Remoがどのような動きをするかわからなかったこともあり、以下の情報をスプレットシートに記入するようにしています。
B~F列がDevices(今回の場合は、Nature Remo mini2)のデータであり、G~K列はAppliances(今回の場合はエアコン)のデータです。
Nature Remo Miniを使用しているため、湿度(D列)と照度(E列)は取得できていません。
-
GoogleスプレットシートのIDを確認する
IDは、GoogleスプレットシートのURL:https://docs.google.com/spreadsheets/d/xxxxxxxxxxxxxxxx/editの xxxxxxxxxxxxxxxx の部分です。 -
スクリプトを作成する
作成したGoogleスプレットシートを開き、「ツール」⇒「スクリプトエディタ」をクリックします。スクリプトエディタが開いたら、ソースコードを書いていきます。⇒(参考)作成したスクリプト -
スクリプトを定期実行するように設定する
作成したスクリプトを1時間おきに実行するように設定します。
スクリプトエディタの「トリガー」をクリックし、以下のトリガーを追加しました。
スクリプト
参考までに作成したスクリプトを紹介します。言語はGAS(Google Apps Script)です。
※アクセストークンは各自のものに置き換えてください。
参考:https://qiita.com/t-chi/items/01b9a9b98fbccef880c3
const access_token_remo = 'xxx'; //Nature Remoのアクセストークン
const access_token_line = 'xxx'; //LINE Notifyのアクセストークン
const spreadsheetId = 'xxx'; //スプレッドシートのIDを入れる(URL参照)
const COL_DEVICE_TEMP = 3;
const COL_DEVICE_HUMIDITY = 4;
const COL_DEVICE_ILLUMINANCE = 5;
const COL_DEVICE_UPDATE = 6;
const COL_APPLIANCE_NAME = 7;
const COL_APPLIANCE_VOL = 8;
const COL_APPLIANCE_TEMP = 9;
const COL_APPLIANCE_BUTTON = 10;
const COL_APPLIANCE_UPDATE = 11;
const COL_APPLIANCE2_NAME = 12;
const COL_APPLIANCE2_UPDATE = 13;
// Main Function
function remo() {
// Stage 1
var data = getNatureRemoData(); //data取得
var data_appliances = getNatureRemoData_Appliances() //家電ごとのデータを取得
// Stage 2
var lastData = getLastData(); //最終date取得
setLaremoData(
{
// Devices
date:convertToJapanTime(data[0].newest_events.te.created_at), //日時
te:data[0].newest_events.te.val, //温度
hu:'No data', //data[0].newest_events.hu.val, //湿度
il:'No data', //data[0].newest_events.il.val, //照度
updated_at:convertToJapanTime(data[0].updated_at), //更新日時
// Appliance No.1
appliances1_name : data_appliances[0].nickname,
appliances1_vol : data_appliances[0].settings.vol,
appliances1_temp : data_appliances[0].settings.temp,
appliances1_button : data_appliances[0].settings.button,
appliances1_updated_at : convertToJapanTime(data_appliances[0].settings.updated_at),
},
lastData.row + 1//最終data追加作業
);
// Stage 3
// Line Notifyで通知
var temperature = data[0].newest_events.te.val;
var nowData = getLastData(); //最終date取得
Logger.log(nowData.data_deviceUpdate);
Logger.log(lastData.data_deviceUpdate);
let text = '';
// (1)エアコンの操作があった
if (nowData.data_applianceUpdate.getTime() > lastData.data_applianceUpdate.getTime()){
// var text = '';
if (nowData.data_applianceButton == 'power-off'){
text = '※エアコン操作あり\n'
+ '操作:' + nowData.data_applianceButton + '\n'
+ '設定温度:' + '\n'
+ '現在室温:' + temperature + '℃\n'
+ '日時:' + Utilities.formatDate(nowData.data_applianceUpdate,'JST', 'MM/dd HH:mm');
}
else{
text = '※エアコン操作あり\n'
+ '操作:' + 'power-onなど' + '\n'
+ '設定温度:' + nowData.data_applianceTemp + '℃\n'
+ '現在室温:' + temperature + '℃\n'
+ '日時:' + Utilities.formatDate(nowData.data_applianceUpdate,'JST', 'MM/dd HH:mm');
}
lineNotify(text);
}
// (2)エアコンの操作はなかったが、その他の操作があった(Remoのアップデートがあった)
else if (nowData.data_deviceUpdate.getTime() > lastData.data_deviceUpdate.getTime()){
// テスト中。手動で割り当てたボタンの操作があった場合は、ここを通る。
// ただし、ボタンのON/OFFの判別はできそうにない。
}
}
/*
Sub Function #1-1
Nature Remo API経由でDevicesの情報を取得する関数
Input:
Output:
*/
function getNatureRemoData() {
var url = "https://api.nature.global/1/devices";
var headers = {
'accept': 'application/json',
'Authorization': 'Bearer ' + access_token_remo,
};
var postData = {
};
var options = {
"method" : "get",
"headers" : headers,
};
var data = JSON.parse(UrlFetchApp.fetch(url, options));
Logger.log(data[0])
return data;
}
/*
Sub Function #1-2
Nature Remo API経由でAppliancesの情報を取得する関数
Input:
Output:
*/
function getNatureRemoData_Appliances() {
var url = "https://api.nature.global/1/appliances";
var headers = {
'accept': 'application/json',
'Authorization': 'Bearer ' + access_token_remo,
};
var postData = {
};
var options = {
"method" : "get",
"headers" : headers,
};
var data = JSON.parse(UrlFetchApp.fetch(url, options));
Logger.log(data[0])
return data;
}
/*
Sub Function #2-1
スプレットシートの最終行の情報を取得する関数
Input:
Output:
*/
function getLastData() {
var datas = SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getDataRange().getValues() //logシートをゲットする
var data = datas[datas.length - 1]
return {
data_deviceUpdate:data[COL_DEVICE_UPDATE-1],
data_applianceUpdate:data[COL_APPLIANCE_UPDATE-1],
data_applianceName:data[COL_APPLIANCE_NAME-1],
data_applianceTemp:data[COL_APPLIANCE_TEMP-1],
data_applianceButton:data[COL_APPLIANCE_BUTTON-1],
row:datas.length
}
}
/*
Sub Function #2-2
各種情報をスプレットシートに記入する関数
Input: data, row
Output:
*/
function setLaremoData(data, row) {
// Devices
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, 1).setValue(new Date())//A2にゲットした日時ほりこむ
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, 2).setValue(data.date) //A2に日時
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, COL_DEVICE_TEMP).setValue(data.te) //B2に温度追加
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, COL_DEVICE_HUMIDITY).setValue(data.hu) //C2湿度追加(幅があるけど気にしない)
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, COL_DEVICE_ILLUMINANCE).setValue(data.il) //D2照度追加
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, COL_DEVICE_UPDATE).setValue(data.updated_at) //アップデート日時(アプリから指令したら更新される)
// Appliances No.1
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, COL_APPLIANCE_NAME).setValue(data.appliances1_name) //名前
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, COL_APPLIANCE_VOL).setValue(data.appliances1_vol) //vol
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, COL_APPLIANCE_TEMP).setValue(data.appliances1_temp) //温度
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, COL_APPLIANCE_BUTTON).setValue(data.appliances1_button) //ボタン
SpreadsheetApp.openById(spreadsheetId).getSheetByName('log').getRange(row, COL_APPLIANCE_UPDATE).setValue(data.appliances1_updated_at) //更新日時
}
/*
Sub Function #3-1
LINE NotifyにPOSTする関数
Input: LINEに通知する文字列
Output:
*/
function lineNotify(postText){
try {
const url = 'https://notify-api.line.me/api/notify';
const params = {
method: 'post',
headers: {
'Authorization': 'Bearer '+ access_token_line
},
payload: {
message : postText
}
}
const res = UrlFetchApp.fetch(url, params);
console.log(res);
} catch (error) {
console.log(error);
}
}
/*
Sub Function #4-1
文字列をDate型(日本時間)に変換する。
Input: '2021-08-09T09:54:08Z'
Output: +9h
*/
function convertToJapanTime(dateText) {
let date;
if (dateText != null){
date = new Date(dateText);
}
else{
date = 'null';
}
return date;
}
さいごに
とりあえず、冒頭で述べた問題は解決できたのでよかったです。
運用していく中で、以下の課題が判明しました。忘れないようにメモ。
- 祖母が誤ってエアコンをOFFし、それを覚えておらず暑いと電話来るパターン
⇒見守りカメラを置き、こちらが視認できるようにする or リモコン隠す
⇒リモコンを隠すと、コンセント抜くことがわかりました...(別案検討中) - 祖母の暑い/寒いの基準が温度だけではわからない
⇒温度だけでなく、湿度も取得できると適切な操作や自動化ができる? - 遠隔でエアコンを操作すると、エアコンの音が鳴り、それが祖母の混乱を招く
⇒日立のエアコンは、操作音OFFの設定がなさそう。エアコンのブザー外す?
Discussion