10
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Google Home + IFTTT + GAS + LINEBOTでToDo管理

Posted at

はじめに

簡単なToDoをPCのテキストエディタで管理していたのですが、PCを起動するところから面倒になりました。
手間がかからないように管理をする方法を検討・調査、作成したのでこの記事でまとめています。

この記事の「利用」の項目から行ったことの結果がだいたいわかると思います。

行うこと

以下の記事を参考にToDo管理の実現方法を決めました。
Google Home、IFTTT、Googleスプレッドシートを使って独自音声コマンドでログをとる(ついでにNode.jsやngrokやらも使ってLINEやGoogle Homeに通知する)

以下、まとめ
(以降、GoogleAppsScriptをGASと記載)

行いたいこと 実現方法 備考
ToDoを保持する Google Sheets ToDoをどこかに持っておく。
サーバを用意したくなかったので、
Google Sheetsを代わりに利用する。
ToDo一覧を見る GAS, LINEBOT GASから結果をLINEに出力する。
個人的に目で一覧で見たいのでGoogle Homeには出力しない。
定常的にToDoを表示 GAS, LINEBOT 「ToDo一覧を見る」とやりたいことは同じ、
ただし定常的にToDoをリマインドするようにしたい。
ToDoを追加する Google Home,
IFTTT,
GAS
追加は音声入力が楽だと思い、Google Homeを利用する。
IFTTTでGoogle Sheetsに出力し、
足りない部分をGASで補う。
ToDoを削除する GAS, LINEBOT ToDo一覧を見て、完了したものを削除する。
こちらもLINEから入力を行う。

Google Sheetsなどそれぞれの解説はたくさんあるのでここでは割愛します。
自身が参照したものは参考にまとめますので、そちらからご確認ください。

IFTTT, Google Sheets, LINEBOTの設定

それぞれで連携を取るための設定をします。
ここではそれぞれの設定内容や引っかかった部分をまとめています。

IFTTT設定

Google Homeへの音声入力をGoogle Sheetsに出力するための設定をします。
New Appletから以下の設定を行います。

  • This設定
    1. Choose a serviceから「Google Assistant」を選択
    2. Choose triggerから「Say a phrase with a text ingredient」を選択
    3. Complete trigger fieldsを下記画像のように設定

20180504_IFTTT_THIS.png
ここで「What do you want to say?」はなるべく単純にして、かつリストという単語を使用しない方がいいかもしれません。
「リストに$を追加」のように設定すると入力そのものができなかったり、ショッピングリストに追加されてしまうことがありました。

  • That設定
    1. Choose action serviceから「Google Sheets」を選択
    2. Choose actionから「Add row to spreadsheet」を選択
    3. Complete action fieldsを下記画像のように設定

20180504_IFTTT_THAT.png

これでGoogle Homeへの音声入力をGoogle Sheetsに追記していくことができるようになります。

Google Sheets設定

Google Sheetsに対してLINEBOTからPostできるように設定します。
IFTTTのComplete action fieldsで設定したDrive folder path以下にSpread sheet nameのシートを事前に作成しておきます。
(一回Google Homeに「○○を追加」と音声入力してもシートが作成されます)

  1. シートを開き、「ツール」から「スクリプトエディタ」を選択

20180504_GoogleSheet_script.png
2. 「公開」から「ウェブアプリケーションとして導入」を選択し、以下のように設定

項目 設定内容 備考
次のユーザとしてアプリケーションを実行 自分
プロジェクトバージョン 任意のバージョン GASを更新する際に適宜このバージョンも変更する必要がある点に注意
アプリケーションにアクセスできるユーザー 全員(匿名ユーザーを含む) 匿名ユーザーを含まないとLINEからPostできない
ウェブアプリケーションのURLは変更等しないで利用します。

LINEBOT設定

Post先をGoogle Sheetsに設定します。
LINEログインを利用するにはなどを参考に、事前にチャネル作成までを行っておきます。
(料金体系はDeveloper Trialを利用)

1. Channel基本設定のメッセージ送受信設定を以下のように設定

項目 設定内容
アクセストークン 発行してあればよい
Webhook送信 利用する
Webhook URL Google SheetsのウェブアプリケーションURL

2. LINE@機能の利用から「自動応答メッセージ」を利用しないに設定

GAS作成

ToDoの追加や一覧取得など、必要なGASを作成します。

ToDoの追加(Google Homeの入力以外の情報追加)

Google Homeだけでは取得できない、ToDoのid番号(ToDoの削除用)と
ToDoの登録日(リスト一覧を見た時に古いものを判別する用)を補うようにします。
下記のコードと後述のトリガー設定で動作させます。

var sheet = SpreadsheetApp.getActiveSheet();

function addRowInfo() {
  // 空いている番号を見つける
  var data = sheet.getDataRange().getValues();
  var lastRow = sheet.getLastRow();
  var numArray = [];
  for (i = 0; i < lastRow; i++){
    numArray.push (data[i][0]);
  }
  numArray.sort(compareNumbers);
  addRowNum = 0;
  for (i = 0; i < numArray.length + 1; i++){
    addRowNum = i;
    //バグによる同値防止
    if (i != numArray[i] && i < numArray[i]) break;
  }
  SpreadsheetApp.getActiveSheet().getRange(lastRow, 1).setValue(addRowNum);
  //とりあえず見やすい形にフォーマットしておく
  SpreadsheetApp.getActiveSheet().getRange(lastRow, 3).setValue(Utilities.formatDate(new Date(), 'Asia/Tokyo', '/yyyy-MM-dd/'));
}

//ソート用
function compareNumbers(a, b) {
  return a - b;
}

(ToDo登録時に)シートを探索し、現在のid番号を昇順に並べた時に、存在しない一番小さい値をid番号として持つようにしています。
登録日時は適当にフォーマットして見やすい形にしておきます。1列目にid、3列目に時刻を入れるようにしています。

ToDo一覧を見る

ToDo一覧を文字列にまとめて、LINEにメッセージを送信します。
コードは以下のようにしています。

  • リスト作成
var sheet = SpreadsheetApp.getActiveSheet();

function createMessage(timecheck){
  var message = "";
  var data = sheet.getDataRange().getValues();
  
  for(var i = 0; i < data.length; i++) {
    tmpMessage = "";
    for (var j = 0; j < data[i].length; j++) {
      if (j != 0 && j != 1 && !timecheck) continue;
      tmpMessage += data[i][j] + ":";
    }
    tmpMessage = tmpMessage.substring(0, tmpMessage.length-1);
    message = message + tmpMessage + "\n";
  }
  message = message.substring(0, message.length-1);
  return message;
}

シートのセルの値を「:」、各行を改行コードで結合しています。
timecheckがtrueの場合に限り登録日をつけるようにしています。

  • LINEに送信
var token = "[LINEのChannel基本設定にあるアクセストークンを指定]";
var sheet = SpreadsheetApp.getActiveSheet();

function sendMessage(message) {
  var to = "[LINEのChannel基本設定にあるYour user IDを指定]";
  var url = "https://api.line.me/v2/bot/message/push";
  var headers = {
    "Content-Type" : "application/json; charset=UTF-8",
    'Authorization': 'Bearer ' + token,
  };

  var postData = {
    "to" : to,
    "messages" : [
      {
        'type':'text',
        'text':message,
      }
    ]
  };

  var options = {
    "method" : "post",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };

  return UrlFetchApp.fetch(url, options);  
}

公式ページLINE BOTからTodoistのタスク作成を参考に作成

ToDoの削除

与えられた番号のidを持つToDoを消去します。

function deleteSelectColumn(num) {
  var data = sheet.getDataRange().getValues();
  var lastRow = sheet.getLastRow();
  var numArray = [];
  for (i = 0; i < lastRow; i++){
    if (String(num) == data[i][0]){
      sheet.deleteRow(i+1);
      return true;
    }
  }
  return false;
}

LINEからの入力を受け取る(ToDo削除やToDo一覧の表示)

LINE BOTからTodoistのタスク作成の記事を参考に作成

LINEからPostされた入力を受け取り、対応した処理を行います。
コードは以下の通りです(コード中の一部関数についてはここまでに記載しているものを利用)。

function doPost(e) {
  var userMessage = JSON.parse(e.postData.contents).events[0].message.text;
  if (userMessage == "リスト") { 
    sendMessage(createMessage(false));
  } else if (!isNaN(userMessage)) {
    if(deleteSelectColumn(userMessage)){
      sendMessage(createMessage(false));
    }else{
      sendMessage("対応ToDoなし");
    }
  } else if (userMessage == "タイムリスト"){
    sendMessage(createMessage(true));
  } else {
    sendMessage("受け付けていない入力です");
  }
}
  • リストと入力されている場合はToDo一覧を返す。
  • 入力が数値であればその数値のidを持つToDoを消して一覧を返す。
  • タイムリストと入力されている場合は登録日も含めて返す。

定常的なToDoの表示

以下の記事を参考に作成

下記のコードと後述のトリガー設定で動作します。

// 実行時間の設定
function setNotifications() {
  setTrigger("Noti01", 8, 30);
}

//トリガーを作成
function setTrigger(funcName, h, m) {
  var triggerDay = new Date();
  triggerDay.setHours(h);
  triggerDay.setMinutes(m);
  ScriptApp.newTrigger(funcName).timeBased().at(triggerDay).create();
}

// 残ってしまうトリガーを削除する
function deleteTrigger() {
  var triggers = ScriptApp.getProjectTriggers();
  for(var i = 0; i < triggers.length; i++) {
    if (triggers[i].getHandlerFunction() == "Noti01") {
      ScriptApp.deleteTrigger(triggers[i]);
    }
  }
}

// 定常実行されるfunction
function Noti01(){
  deleteTrigger();
  sendMessage(createMessage());
}

GASのトリガーでは特定の時刻に定常実行を行うことができないので、特定時間に動作するトリガーを用意し、
毎日、用意したトリガーをセット・削除することで定常的に特定の時間にリマインドをします。

トリガーの設定

定常実行とToDoのidなどを付与するためにGASのトリガーを設定します。
以下は設定内容です。
20180504_Trigger.png

定常実行のためのトリガー作成自体を日タイマーのトリガーとして設定しています。
ToDoのidなどはスプレッドシートの更新時(Google Homeの入力がGoogle Sheetsに与えられた時)に付与されるようにしています。

利用

以下はテストとして機能の利用をした時の結果です。
(定常実行、音声入力の結果については記事に載せにくいので省略)

  1. ToDo一覧の取得と登録日を含めた一覧の取得
    Screenshot_20180504-221145.jpg
    リストやタイムリストといった決まった単語で一覧が返ってくることを確認しました。

  2. idが10のToDoの削除
    Screenshot_20180504-221156.jpg
    id番号が10のToDoが消えてリストを返したことを確認しました。

  3. Google Homeに「追加 きーた用のテスト」と音声入力した後のリスト
    Screenshot_20180504-221206.jpg
    固有名詞が入るのでうまく入力できていないようですが、リストに追加されること自体は確認できました。

参考リンク

10
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?