一人暮らしの寂しさを推しとIoTとLINE Botで解決した話

この記事は[「ニフティグループ Advent Calendar 2019」](https://qiita.com/advent-calendar/2019/nifty) 7日目の記事です。
6日目は「[私のチームで行っているプラクティスとスクラムマスターとしての考え方](https://qiita.com/yt_hatterene/items/868e766229512ed3a2f1)」でした。
私のチームでもスクラム開発を導入していますが、同じスクラムと言ってもチームごとに進め方の違いが見えて面白かったです。
特に `ファシリテーターを持ち回り制にする` や `デイリースクラムでBGMを流す` がとても新鮮でした！

# はじめに
10月に実家を出て一人暮らしを始め、**一人暮らしデビューあるある**の例に漏れず数日でホームシックになった @saikei です。
*誰も出迎えてくれない真っ暗で無音の家に帰る*のはメンタル的にしんどいですね。寂しい。家族って大事。

このままでは本当に家に帰りたくなくなってしまうので、どうにか対策方法は無いかと考えた結果、「推しとIoTとLINEに頼ろう！」という結論になりました。

# 何を作ったのか
家に帰る前に「今から帰るよ！」とメッセージを送ると、部屋のライトやエアコン、テレビなどの電源を入れてくれるLINE Botを作りました。
（※画像は投稿用にカスタマイズしていますが、タイトルの通り**推し**や**好きなキャラクター**としてBotを作るといいと思います）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187334/4d50ff67-2aa7-3f9c-6ae5-c72da735c020.jpeg" width=70%>

## 構成図
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187334/cdc1833c-499e-c3dd-0a99-e5c5221b1540.png">

# 前提
- **Webhookをトリガーに家電を操作する環境が整っている**
- **phpが動くサーバーがある** （私がphpが好きなだけでなんでも良いです）  
一番大事なのが「**Webhookをトリガーに家電を操作する環境が整っている**」という点ですが、3千円程度で手に入る学習リモコンで実現することができます。  
（※ 私が使用しているのは**[SwitchBot Hub Mini](https://www.amazon.co.jp/dp/B07TTH5TMW/)**という学習リモコンで、家中の赤外線リモコンを学習させてIFTTT（Webhook）経由で外から家電を操作することができる様になりました！）

# 1. LINE Botチャンネル（アカウント）
## 1.1 チャンネルの作成
1. [LINE Developersコンソール](https://developers.line.biz/console/)へアクセス
2. プライベートで使っているアカウントでログインして「新規プロバイダー作成」を行う（名前はなんでも良い） 
3. チャンネル設定から「Messaging API」を作成する
    - **チャンネルアイコン**：LINE Botのアイコン （※重要）
    - **チャンネル名**：LINE Botのユーザー名 （※重要）
    - **チャンネル説明**：LINE Botの説明
    - **大業種／小業種**：個人
    - **メールアドレス**：（公開されません）
    - **プライバシーポリシー／利用規約**：今回は個人利用のため空欄で良いと思います

### 作成されたチャンネル
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187334/8c70fa7b-c2e5-af54-b6fd-fbb65d3bec6e.png" width=70%>

## 1.2 Messaging API の設定
先ほど作成したBotページの「Messaging API設定」タブから設定します 
### 1.2.1 ボット情報
QRコードを、自分のスマホで読み取り友達に追加します
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187334/982fb731-5648-6414-9440-25ba1ff47ee1.jpeg" width=70%>

### 1.2.2 Webhook設定
「Webhook URL」には後ほど作成するページのURLを入力するので覚えておいてください。
### 1.2.3 LINE公式アカウント機能
- **グループ・複数人チャットへの参加を許可する**：グループ内にBotを招待して家電を操作することができる様になります
- **応答メッセージ**： 後ほどコード内で設定するためオフにしておいてください
- **あいさつメッセージ**： 友達追加時のメッセージなので気にしなくて良いです

### 1.2.4 チャネルアクセストークン
この後必要になるので、**チャネルアクセストークン（ロングターム）**を控えておいてください。

# 2. サーバーサイド
今回はphpで作成しましたが、特にライブラリなどは使っていないため好きな言語で作ってください。
機能を一部簡略化したこちらのコードについて解説していきます。

```php
<?php
## 2.1 アクセストークン
$access_token = '{チャネルアクセストークン（ロングターム）}';

// 処理を実行する
getMessage();

## 2.2 getMessage()
function getMessage(){
  
  ### 2.2.1 投稿メッセージオブジェクトから値を取り出す
  // メッセージとreplyTokenの取り出し
  $json_string = file_get_contents('php://input');
  $json_object = json_decode($json_string, true);
  $message = $json_object["events"][0]["message"]["text"];
  $reply_token = $json_object["events"][0]["replyToken"];
  
  ### 2.2.2 正規表現でメッセージの内容を判別する
  $WORD_RETURN = "/帰るよ|帰る/";

  if ( preg_match($WORD_RETURN, $message) ) {
    remoteControll("{webhookURL}");
    remoteControll("{webhookURL}");
    replyMessage($reply_token, "気をつけて帰ってきてね！");
    return;
  }

  // 判定：　登録ワード以外の場合
  replyMessage($reply_token, "ボク、ソノコトバ、シラナイ");
}

// 2.3 webhookを叩いて家電をコントロールする
function remoteControll($webhook_url){
  $ch = curl_init($webhook_url);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_exec($ch);
  curl_close($ch);
}

## 2.4 LINE botからメッセージを返信する
function replyMessage($replyToken, $messages){
  global $access_token;
  $headers = array(
    'Content-Type:application/json',
    'Authorization: Bearer ' . $access_token
  );
  $data = array(
    'replyToken'=>$replyToken,
    'messages'=> array(
      array(
        'type'=>'text',
        'text'=>$messages
      )
    )
  );
  $data_json = json_encode($data);

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
  curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_URL, 'https://api.line.me/v2/bot/message/reply');
  curl_exec($ch);
  curl_close($ch);
}
```

## 2.1 アクセストークン
```php
$access_token = '{チャネルアクセストークン（ロングターム）}';
```
**LINE Messaging API**を利用してbotから返信するために必要なトークンです。
[先ほど控えたチャネルアクセストークン](#124-チャネルアクセストークン)に書き換えてください。

## 2.2 getMessage()
投稿メッセージオブジェクトを受け取り、ユーザー（自分）からの指示を判別する関数です
### 2.2.1 投稿メッセージオブジェクトから値を取り出す
```php
$message = $json_object["events"][0]["message"]["text"];
$reply_token = $json_object["events"][0]["replyToken"];
```
**$message**：投稿メッセージ
**$reply_token**：返信するために必要なトークン（都度更新されます）
> 応答メッセージを送るには、Webhookイベントオブジェクトに含まれる応答トークンが必要です。
>[Messaging APIリファレンス：応答メッセージを送る](https://developers.line.biz/ja/reference/messaging-api/#send-reply-message)

### 2.2.2 正規表現でメッセージの内容を判別する
```php
$WORD_RETURN = "/帰るよ|帰る/";

  if ( preg_match($WORD_RETURN, $message) ) {
    remoteControll("{webhookURL}");
    remoteControll("{webhookURL}");
    replyMessage($reply_token, "気をつけて帰ってきてね！");
    return;
  }
```
`preg_match` でメッセージ内に `$WORD_RETURN` で指定した単語があるかを確認し「Webhookを叩き、LINEの返信」を行います。
※ 実際はここで*「電気をつけて／消して」*など複数の分岐を行い処理します。

## 2.3 remoteControll($webhook_url)
```php
function remoteControll($webhook_url){
  $ch = curl_init($webhook_url);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_exec($ch);
  curl_close($ch);
}
```
webhookのURLを引数で受け取り実行します。

## 2.4 replyMessage($replyToken, $messages)
応答トークンと、返信メッセージを引数で受け取り、フォーマットに従い「リクエストヘッダー」「リクエストボディー」を整形したのちに「エンドポイントAPI」に送信します。
> リクエストヘッダー、リクエストボディの仕様
> [Messaging APIリファレンス：応答メッセージを送る](https://developers.line.biz/ja/reference/messaging-api/#send-reply-message)

# 3. LINE Botとの接続
1. 先ほど作成したコードを任意のサーバーに公開し、[LINE Developerコンソールのwebhook](#122-webhook設定)にURLを登録します。
2. 作業は以上です！実際に作成したBotに話しかけてみてください。

# まとめ
推し成分抑えめでしたがタイトルの通りIoTとLINE Botで生活を改善することができました。
phpでは `出迎えてくれる人` を生み出す事はできませんでしたが、`真っ暗で無音の家に帰る` の部分は解決できたので満足です。
そして記事では省略しましたが、実際は「ライト・エアコン・テレビ」の単体での制御は勿論、細かい制御も入れているのでLINEでいろいろな事ができる様になりました。

SwitchBotシリーズには他に[コンセントを制御できるタイプ](https://www.amazon.co.jp/dp/B07TVSGJT4/)や、[物理ボタンを制御できるタイプ](https://www.amazon.co.jp/dp/B07B7NXV4R/)もあるので、今後いろいろと活用していけたら良いなと思っています。

お仕事も推し事も頑張っていきたいですね。

明日は @motaHack さんです！よろしくおねがいします。