岡田あーみん先生に捧ぐ
はじめに
私の妻はとても心配症です。
外出したらガスを消し忘れたんじゃないかと心配し、子供が学校に行けば誘拐されるんじゃないかと心配し、私が会社に行けば交通事故にあっているんじゃないかと心配します。
とりあえず無事会社に着いたことが分かれば心配が一つでも消えると思い、会社に着いたら自動で妻にLINE通知をするシステムを作りました。
同じ仕組みで帰る時も自動で通知するようにしています。
おかげで帰りに寄り道したら必ずバレるようになりました。
仕組み
- 私が出社するとスマートフォンが会社のWiFiに自動接続される
- IFTTTがWiFi接続を検知してGoogleスプレッドシートに「Enter」と書き込む
- Googleスプレッドシートに連動したGoogle Apps Scriptが文字列と時刻から状況を判断し、出社の場合はトリガーURLにアクセスする
- トリガーURLに連動したIFTTTがLINE通知を行う
- 私が無事に会社に着いたことを知った妻が安心する
退社時はWiFiからの切断をトリガーにしてGoogleスプレッドシートに「Exit」と書き込まれます。
昼休みに外出して戻ってきた場合もGoogleスプレッドシートに「Exit」と「Enter」が書き込まれてしまいますが、この場合はLINE通知しないようにGoogle Apps Script側で制御しています。
前提
- IFTTTのアカウントを持っていること
- Googleアカウントを持っていること
- LINEアカウントを持っていること
- IFTTTとGoogleアカウントを連携していること
- IFTTTとLINEアカウントを連携していること
- Android携帯にIFTTTアプリをインストール済みであること
私がAndroidユーザーなのでAndroid携帯で説明しますが、iPhoneでも実現可能です。
iPhoneの場合はGPSをトリガーとして出社と退社を判断すると良いようです。
IFTTTのアカウントは下記URLから作ることができます。
IFTTT側の準備
IFTTTでは「もし〜だったら〜する」という形式で単純なプログラムを作ることができ、これをアプレットと呼んでいます。
今回の仕組みを作るにあたって、以下の3つのアプレットを作成します。
- Android携帯が会社のWiFiに接続したらGoogleスプレッドシートに「Enter」と書き込むアプレット
- Android携帯が任意のWiFiから切断されたらGoogleスプレッドシートに「Exit」と書き込むアプレット
- トリガーURLにアクセスがあったらLINE通知を行うアプレット
Android携帯が会社のWiFiに接続したらGoogleスプレッドシートに「Enter」と書き込むアプレットを作る
IFTTTにログインしたら右上のアカウント名をクリックすると下図のようなメニューが表示されます。
「New Applet」をクリックしてください。
検索欄に「android」と入力すると候補が絞り込まれるので、「Android Device」をクリックします。
「Choose trigger」で「Connects to a specific WiFi network」をクリックします。
会社のWiFiのSSIDを入力して「Create trigger」をクリックします。
検索欄に「google」と入力してから「Google Sheets」を選択します。
「Add row to spreadsheet」をクリックします。
「Formated row」には「Enter」と入力します。シート名とパスは何でも構いません。
入力が終わったら「Create action」をクリックします。
アプレットの名前は分かりやすいものに変更しておきましょう。変更したら「Finish」をクリックします。
動作確認をします。
IFTTTと連携させたスマートフォンを先ほど設定したWiFiに接続してください。
すでに接続済みの場合はWiFiをいったんOffにして再接続してください。
しばらくするとGoogleスプレッドシートが生成されて、1行目に「Enter」と入力されます。
WiFiをOffにして再接続してみてください。
2行目に自動で「Enter」と入力されれば動作確認は成功です。
Android携帯が任意のWiFiから切断されたらGoogleスプレッドシートに「Exit」と書き込むアプレットを作る
「Enter」と書き込むアプレットとほとんど同じなので、違うところだけ説明します。
「this」の選択では「Disconnects from any WiFi network」を選びます。
最初は「Disconnects from a specific WiFi network」を使用していましたが、今年のある時期から正常に動作しなくなりました。
私の環境だけかもしれませんが、WiFi切断時にSSIDを判別できなくなったようです。
「Disconnects from a specific WiFi network」の方は問題なく動作しています。
スプレッドシートの設定では「Formated row」は「Exit」と入力します。それ以外の設定は上述と同じにしてください。
アプレットができたら動作確認をしましょう。
Android携帯のWiFiを切断して、スプレッドシートにExitと入力されたらOKです。
トリガーURLにアクセスがあったらLINE通知を行うアプレットを作る
アプレットの新規作成をします。
「this」の選択では検索欄に「web」と入力し、「Webhooks」を選択してください。
「Receive a web request」をクリックします。
「Event name」に適当な値を入力します。ここでは「send_line_message」としました。
「that」のイベントを選択します。
検索欄に「line」と入力し、「LINE」を選択してください。
通知したいLINEグループを選択します。LINEグループがなかったら作って再ロードしてください。
グループには「LINE Notify」を招待しておいてください。
「Message」欄は「{{Value1}}」だけ残してあとは削除します。
最後に「Create action」をクリックします。
わかりやすいアプレット名をつけたらFinishをクリックします。
「My Applets > Webhooks」をクリックしてください。
下図のような画面になるので表示されたキーをメモしてください。
動作確認します。
ブラウザで以下のURLにアクセスしてみてください。
Google Apps Scriptの準備
上記のIFTTTアプレットによって自動生成されたスプレッドシートを開き、「ツール→スクリプトエディタ」をクリックします。
コード.gs
を下記のスクリプトで上書き保存してください。
var sheet = SpreadsheetApp.getActiveSheet();
var base_url = '{IFTTTのWebhookURL}'
/* スプレッドシートが編集された時刻を記録(「スプレッドシートから」「値の変更」イベントでトリガーを設定すること) */
function addDate() {
setDate(2, 'yyyy/M/d');
setDate(3, 'H:m:s');
// 条件付きでLine通知
sendLineMessage();
}
/* 日付フォーマット */
function formatDate(date, format) {
return Utilities.formatDate(date, 'Asia/Tokyo', format)
}
/* 最終行の指定したカラムに指定したフォーマットで日付時刻情報を入力 */
function setDate(col, format) {
var lastrow = sheet.getLastRow();
if (sheet.getRange(lastrow, col).getValue() == '')
sheet.getRange(lastrow, col).setValue(formatDate(new Date(), format));
}
/* 始業時刻前の入室時と終業時刻後の退室時にLine通知 */
function sendLineMessage() {
var date1 = new Date(); // 現在時刻
var date2 = new Date(); // 始業時刻(08:30)
var date3 = new Date(); // 終業時刻(17:30)
// TODO:時刻の設定と比較をもう少し洗練させたい
date2.setHours(8);
date2.setMinutes(30);
date2.setSeconds(0);
date3.setHours(17);
date3.setMinutes(30);
date3.setSeconds(0);
var triggerUrl = '';
var lastrow = sheet.getLastRow();
var lastStatus = sheet.getRange(lastrow, 1).getValue(); // 最新の入退室状況
var prevStatus = sheet.getRange(lastrow-1, 1).getValue(); // 一つ前の入退室状況
if ((lastStatus === 'Enter') && (date1.getTime() < date2.getTime())) {
// 8:30前に入室したら到着連絡を送信
triggerUrl = base_url + '?value1=会社に到着';
} else if ((lastStatus === 'Exit') && (prevStatus === 'Enter' ) && (date1.getTime() > date3.getTime())) {
// 17:30以降に退室したら帰宅連絡を送信(誤送信防止の為、一つ前のステータスが入室の場合のみ送信する)
triggerUrl = base_url + '?value1=会社を出たよ';
}
if (triggerUrl != '') {
// LINE通知用のトリガーURLにアクセス
UrlFetchApp.fetch(triggerUrl);
}
}
スクリプトを保存したらトリガーを設定します。
「現在のプロジェクトのトリガー」アイコンをクリックします。
下図の通り設定します。
「実行する関数を選択」は「addDate」、「イベントのソースを選択」は「スプレッドシートから」、「イベントの種類を選択」は「編集時」をそれぞれ選択してください。
保存時に承認が必要となるはずなので、画面の指示に従って承認を与えます。
動作確認をします。
スプレッドシートに「Enter」もしくは「Exit」と入力してください。
下図のように日付と時刻が自動で入力されればトリガーは正常に設定されています。
勤務時間帯と現在時刻、および入退室状況の条件がそろえばLINE通知が行われます。
このスクリプトはいろいろ応用ができます。
私はこのスクリプトに機能追加して、出社しているときだけ残業申請を自動で行うようにしています。
おまけ
この仕組は実運用して半年以上経ちますが、ほぼ安定して動いています。
しかし、極まれに動かなくなると、下図のように本当に出社しているのか疑われる事態を招いたりするのでご用心ください。
ちなみに最初に設定してたLINEグループ名は「お父さんを監視しよう」でしたが、外聞が悪いということで、「お父さんの安全を見守ろう」という名前に変えられました。
google-home-voicetextとの連携
(2019年5月21日追記)
現在は更に改良して、Line通知だけでなくGoogle Homeが喋って通知してくれるようになりました。
参考URL
https://qiita.com/sikkim/items/f03df7e2db13ea7f5a2b
スクリプトはこんな感じに修正しています。
Cloud Firestoreのドキュメントを更新する処理が追加されています。
function sendLineMessage() {
(中略)
var triggerUrl = '';
var message = '';
var lastrow = sheet.getLastRow();
var lastStatus = sheet.getRange(lastrow, 1).getValue(); // 最新の入退室状況
var prevStatus = sheet.getRange(lastrow-1, 1).getValue(); // 一つ前の入退室状況
if ((lastStatus === 'Enter') && (date1.getTime() < date2.getTime())) {
// 8:30前に入室したら到着連絡を送信
triggerUrl = base_url + '?value1=会社に到着';
message = 'お父さんが会社に到着したよ';
} else if ((lastStatus === 'Exit') && (prevStatus === 'Enter' ) && (date1.getTime() > date3.getTime())) {
// 17:30以降に退室したら帰宅連絡を送信(誤送信防止の為、一つ前のステータスが入室の場合のみ送信する)
triggerUrl = base_url + '?value1=会社を出たよ';
message = 'お父さんが会社を出たよ';
}
if (triggerUrl != '') {
// LINE通知用のトリガーURLにアクセス
UrlFetchApp.fetch(triggerUrl);
updateMessage(message);
}
}
/* Firebase Cloud Firestoreに格納されたメッセージを更新する */
function updateMessage(message) {
var email = '{JSONファイルのclient_emailの値}';
var key = '{JSONファイルのprivate_keyの値}';
var projectId = '{JSONファイルのproject_idの値}';
var firestore = FirestoreApp.getFirestore(email, key, projectId);
const data = {
message: message
};
firestore.updateDocument("googlehome/chant", data);
}
ここでいう「JSONファイル」とはFirebaseからダウンロードした秘密鍵のことです。
取得方法はこちらの記事を参考にしてください。
Firebaseとの接続はFirestoreAppを利用しています。
メニューの「リソース」> 「ライブラリ」で「ライブラリを追加」に1VUSl4b1r1eoNcRWotZM3e87ygkxvXltOgyDZhixqncz9lQ3MjfT1iKFw
を追加すると利用することができます。