IFTTTとGoogle Nest Miniでオンライン授業ブッチを回避する

# はじめに

この記事は，[TDU CPSLab Advent Calender 2020](https://adventar.org/calendars/5298) の記事です。
ひとつ前の記事は[こちら](https://qiita.com/kueika/items/a085251a35791c1f9458)です。

- 本記事ではこれ以降 `Google Nest Mini` を `Nest Mini` と表記します。~~(長いから)~~
- `Google Nest Mini` は `Google Home Mini` の後継モデルです。

# この記事でやること

授業時間が近くなったら Nest Mini にしゃべらせて，「授業が始まってるのに気づかなかった」ということを防ぎます。

**つまり...**
Google カレンダーの予定を Google Nest Mini に喋らせます。

# 背景

お急ぎの方は "使うもの" 以降に飛んでください。

COVID-19 の影響により大学の授業がオンライン化されました。これによって，自宅から移動せずに授業を受けることができるようになりました。空き時間にすこし他の作業を…ということも多くなります。
そんなある日 **空きコマに作業をしていたら授業開始に気づかず30分ほど遅刻した** という事件が発生。
我が家に置いてある Nest Mini をその再発防止のために活用したいが，Nest Mini は自発的に喋ることが基本的にできません。そこで，google-home-notifier や IFTTT などを活用して，今回のシステムを構築することにしました。

なお，今回は Google Nest Mini を使用していますが，Google アシスタントに対応したスマートスピーカー等であれば同様の手順が使えるかと思われます。

**Q. なぜ Nest Mini なのか？**
A. コストコで安かったからです。2000円ほどで買えました。

**Q. スマホのカレンダーの通知機能で良くない？**
A. スマートスピーカーがしゃべってくれた方が "未来感" があると思います。

# 使うもの

主なものを抜粋。そのほか必要なものについては手順で解説します

- Google Nest Mini
- Raspberry Pi
- Google カレンダー
- IFTTT
- ngrok

IFTTT と ngrok では，無料版に対して制限がありますので，念の為ご注意ください。基本的には無料版でも今回の内容には十分対応できます。

# 手順

## 1. Google カレンダーの準備

Google カレンダーに喋らせたい予定を登録してください。
**新しいカレンダーを作成して，そこに登録してください。**
（授業をカレンダーに登録しておくと何かと便利なのでおすすめです。ただし，この登録する作業がちょっと面倒なので，何かいい方法があったら教えてください…。）

## 2. Google Nest Mini と Raspberry Pi の準備

初期設定が済んでいない方は，**Google Home** アプリを使って初期設定を済ませてください。
また，Nest Mini の IP アドレスを Google Home アプリで確認して控えておいてください。このアドレスは後で使います。

本記事では Raspberry Pi を使ってシステム構築を行います。こちらも OS のインストールを済ませて，使用できる状態にしておいてください。
今回使用している OS は Raspberry Pi OS (旧 Raspbian) です。これとは違う OS を利用される方は，コマンド等を適宜読み替えてください。

以下，Raspberry Pi 上での操作です。

**パッケージの更新**

```
$ sudo apt upgrade
```

**Node.js と npm のインストール**
Node.js と npm は，google-home-notifier をインストールおよび動作させるために使います。

```
$ sudo apt install -y nodejs npm
```

**ngrok の準備**
ngrok は，ローカル環境で動作するサーバーを外部からアクセス可能にするサービスです。
[ngrok 公式サイト](https://ngrok.com/)で登録とログインをしてください。
ダッシュボードに記載されている

```
./ngrok authtoken xxxxxxxxxxxxxxxxx
```
の部分を控えておいてください。

**ngrok のダウンロード**
先述の公式サイトで，適切なダウンロードリンクをコピーして，ターミナルに貼り付けて Raspberry Pi にダウンロードしてください。
次に，ダウンロードしてきた zip ファイルを展開してください。ファイル名は，実際にダウンロードしてきたものへ読み替えてください。

```
$ curl -O https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-arm.zip
$ unzip ngrok-stable-linux.arm.zip
```

次に，先ほど控えたトークンを入力してください。

```
$ ./ngrok authtoken xxxxxxxxxxxxxxxxx
```

アクセストークンを使う準備ができました。

## 3. google-home-notifier

**ディレクトリの作成**
作業に使うディレクトリを用意して，そこに移動します。
ディレクトリ名はお好みのものを使用してください。

```
$ mkdir google-home
$ cd google-home
```

**インストール**

```
$ npm init
$ npm install google-home-notifier
```

インストール完了までしばらくかかるので，待ちます。

**インストールの確認**
インストールが完了すると，フォルダとファイルが生成されているはずです。`ls`コマンドで確認できます。

```
$ ls
node_modules package-lock.json
```

**設定ファイルの修正**
google-home-notifier は，設定ファイルの情報が古いままで，そのまま使おうとするとエラーを吐かれて正常に動作しません。これを修正する必要があります。

```
$ nano node_modules/google-home-notifier/package.json
```
**`google-tts-api`の部分を，`0.0.5`に書き換えてください。**
> tts-api とは，**Text-to-Speech API** のことです。
> なお，バージョン `0.0.5` は，執筆時点での最新版です。
> **今後の Google TTS API の仕様変更などにより，適切なバージョン番号が変更になる可能性があります。**
> 
> そのほか，google-tts-api が正常に動作してくれない時は，[こちらの GitHub リポジトリの Issues](https://github.com/zlargon/google-tts/issues) を確認すると何か情報が載っているかもしれません。

```json:node_modules/google-home-notifier/package.json
(前略)
  "bundleDependencies": false,
  "dependencies": {
    "body-parser": "^1.15.2",
    "castv2-client": "^1.1.2",
    "express": "^4.14.0",
    "google-tts-api": "0.0.5", //ここを書き換え
    "mdns": "^2.3.3",
    "ngrok": "^2.2.4"
  },
(後略)
```

**とりあえず喋らせてみる**
新しくファイルを作成します。

```
$ nano test.js
```
```js:test.js
const googlehome = require('google-home-notifier');
const lang = 'ja';

googlehome.ip('192.168.0.10');
googlehome.device('Google-Home', lang);
googlehome.notify('こんにちは', function(res){
    console.log(res);
});
```

Node.js で実行します。

```
$ node test.js
```

エラーが発生せず正常に処理されれば，「ﾃﾞｩﾙﾝ♪」という効果音の後に「こんにちは」と喋ってくれるはずです。
ちなみに，この声は通常の Google アシスタントのものとは異なっています。Google 翻訳で使われている音声のようです。

**外部から叩く**
作業用フォルダに，google-home-notifier の GitHub リポジトリから `example.js` をダウンロードして使います。

```
$ curl -O https://raw.githubusercontent.com/noelportugal/google-home-notifier/master/example.js
```
環境に合わせて内容を書き換えます。

```js:example.js
var express = require('express');
var googlehome = require('./google-home-notifier');
var ngrok = require('ngrok');
var bodyParser = require('body-parser');
var app = express();
const serverPort = 8091; // 特に理由がなければこのままでOK，必要に応じて変更

var deviceName = 'Google Home';
var ip = '192.168.x.x'; // Google Nest MiniのIPアドレス

(略)

  var language = 'jp'; // 言語を 'jp' に
  if (req.query.language) {
    language;
  }

(略)

  if (req.query.ip) {
     ip = req.query.ip;
  }

  var language = 'pl'; // 言語を 'jp' に
  if (req.query.language) {
    language;
  }
(後略)
```

起動します。

```
$ node example.js
```

Raspberry Pi 以外のコンピュータで，新しくターミナルやコマンドプロンプトなどを開き，以下のコマンドを実行してみます。

```
$ curl -X POST -d "text=こんにちは。聞こえますか？" http://Nest MiniのIPアドレス:8091/google-home-notifier
```

先ほどと同じように，テキストが Nest Mini から読み上げられるはずです。
[ctrl + C] で example.js のプロセスを終了できます。


## 4. GNU Screen
GNU Screen は，複数のターミナル画面を同時に使用することができるソフトウェアです。SSH接続を切断しても，その中で動いているプロセスは動き続けます。簡単に利用できるので，今回はこれを使ってみることにします。（もっといい方法があれば，ぜひ教えていただけると幸いです）

**インストール**

```
$ apt install screen
```

**screen の起動 (新しいセッションを作成)**

```
$ screen
```

**ngrok の起動**

```
$ ./ngrok http 8091
```

`Session Status, Account, Version` などが表示されていれば，起動できています。
`Forwarding https://xxxxxxxxxxxx.ngrok.io` のアドレスは後述の IFTTT で使いますので，控えておいてください。


**google-home-notifier の起動**
まず，screen で新しいウインドウを作成します。
順番にキーボードで操作します。

```:screen
[ctrl + J] or [ctrl + A]
[C]
```
新しく作成したウインドウで操作します。

```
$ node example.js
```

**ウインドウの巡回**
先ほど，新しいウインドウを作成しました。以前のウインドウに戻りたい場合は，

```:screen
[ctrl + J] or [ctrl + A]
[N]
```
でウインドウを巡回できます。

**アタッチとデタッチ**
現在開いている screen のセッションから**デタッチ** (離脱) するには，

```:screen
[ctrl + J] or [ctrl + A]
[D]
```
です。screen を開く前の画面に戻ることができますが，実行したプロセスは動き続けています。
**アタッチ**することで，セッションに戻ることができます。

```:screen
[ctrl + J] or [ctrl + A]
[A]
```

GNU Screen の使い方については，こちらの記事がわかりやすいです。
[Linux screenコマンド使い方](https://qiita.com/hnishi/items/3190f2901f88e2594a5f)

## 5. IFTTT

**アプレットの作成**
[IFTTT](https://ifttt.com/home) で，新しいアプレットを作成します。
アプレット一覧画面で，Create をクリックします。

### If This

- **Google Calendar** を検索して選択
- **Any event starts** を選択
- Which calendar?
    - **通知に使うカレンダーを選択。** このカレンダーのすべての予定が通知されます。
- Time before event starts
    - **15 minutes がオススメ** です。
        - 毎回ピッタリ15分前というわけではなく，実際には10分ほど稀に通知されることが多いです。
        - 0 minutes に設定すると，予定が始まってから通知されることがあるため，オススメしません。

### Then That

- **Webhooks** を検索して選択
- **Make a web request**
    - **URL: `https://xxxxxxxxxxxx.ngrok.io/google-home-notifier`**
        - "ngrok の起動" で控えたものに `/google-home-notifier` を加えたもの。
    - **Method: `POST`**
    - **Content Type: `application/x-www-form-urlencorded`**
    - **Body: `text=もうすぐ[Title]が始まります。`**
        - [Title]の部分は，"Add ingredient" ボタンから選択して追加してください。


以上の内容を入力したら**Save**。
あとは予定が始まる時間の10〜15分前に Nest Mini が喋ってくれるはずです。

# さいごに

Nest Mini が喋ってくれるようになったことで，気づかないうちに授業ブッチしてた…ということはなくなりました。やったね！
~~お布団から出られないとか，そういった問題はまた別です。~~

**通知の音量は Nest Mini 本体の音量に依存するので，はっきり聞き取ることができる音量に設定しておいてください。** 

ちなみに，この記事の初めのほうに，「授業開始に気づかず遅刻した」と書きましたが，それが起こったのはまさにこのシステムを組んでいるときでした。
最後までお読みいただき，ありがとうございます。