IFTTTとFlaskとLINEで自宅のルンバを制御する

念願の**ルンバe5**が自宅にやってきました。プレゼントしていただいた親戚に感謝です:blush:
このルンバ、せっかくなので名前をつけることに。妻と協議して「**るんちゃん**」と命名しました。

妹には「安直な名前」と言われましたがw
シンプルイズベストです。

さて、この機種はWi-Fi通信ができるため、iRobot home アプリ<sup>[[1](https://play.google.com/store/apps/details?id=com.irobot.home&hl=ja),[2](https://apps.apple.com/jp/app/irobot-home/id1012014442)]</sup>を通じて掃除の開始・終了指示やスケジュール設定、部品状況などを確認することができます。ただし、このアプリにはプッシュ機能がないため、スケジュール通りに掃除が開始・終了したのかや、本体内にどれくらいゴミが溜まっているかを確認するためには、毎回このアプリを起動しないといけません。
また、自分は自宅用のiPadと外出用のandroidの2台持ちであり、さらに同居の家族がルンバの状況を確認するためにわざわざ本アプリをDLするのはなかなか面倒です。



どうせならLINE上でるんちゃんと会話できたら幸せだったので、自分の勉強がてら、LINE bot「るんちゃん」の開発を行いました。
本記事は、その際の**アーキテクチャ紹介**と、私自身の備忘録を兼ねた**作業内容の共有**です。
（なお、結論としては、IFTTTのレシピ制約によって開始・終了・ドックコマンドの送信とタスク完了の受信は実現できましたが、スケジュール設定やゴミ状況の確認は現時点では実現できていません。）


# アーキテクチャ
以下のアーキテクチャを実装しました。

![architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84670/ad88b328-e1a1-bacf-540a-1822ab69e6ff.png)

るんちゃんが掃除を開始した時、**掃除開始アクション**をIFTTTが**this**として検知し、**that**としてheroku上に作成したAPIサーバーへ**webhook**を飛ばします。その後、APIサーバーは「るんちゃん」として作成したLINEbotに対して**webhook**を飛ばし、LINEbotは家族に対して掃除を開始したことを**通知**します。
LINE上からドックに戻るよう指示した場合はその逆の処理が行われます。

### IFTTT経由にした理由

IFTTT経由ではなく、直接ルンバとAPI経由でやり取りが行えてしまえばよかったのですが、執筆時点ではofficialかつopenなAPIは公開されていないとのことです<sup>[[3](https://homesupport.irobot.com/app/answers/detail/a_id/9840/)]</sup>。


また、非公式ながらルンバAPIを紹介している複数の事例<sup>[[4](https://blog.sikmi.com/hacking-roomba-slackbot), [5](https://github.com/umesan/til/tree/master/Roomba), [6](https://qiita.com/umesan/items/ea9d1603d139387b6a97), [7](https://techblog.nhn-techorus.com/archives/2999)]</sup>が確認できました。
そこで、[[4](https://blog.sikmi.com/hacking-roomba-slackbot)]で行われていたように、charlesによるパケットチャプタも試みたのですが、残念ながら記事で述べられているドメインへの通信は確認できず、非公式APIの利用は叶いませんした。もしかしたら最近、ルンバとの通信方法が変わったのかもしれません。

そのため、今回はIFTTTを経由するようなアーキテクチャとなりました。

### LINE bot経由にした理由

IFTTTから直接LINE通知を送ってもよかったのですが、どうせならLINEbotとして可愛いるんちゃんと話がしたかったので、LINEbotを作成しました。
あと、自分自身のLINEbot作成勉強のためでもあります。

# 各種作業内容
以下、各レイヤーにおける作業内容や設定内容です。

## IFTTT
るんちゃんに開始・終了命令を送信したり、るんちゃんから完了通知を受け取る役割を持ちます。
IFTTT上でiRobotサービスを使うには、前述のiRobot Homeアプリのアカウント登録が必要です。

また、e5モデルとして**this**および**that**として登録できるのは以下のタスクに限定されていました<sup>[8](http://irobot-homesupport-ja-jp.custhelp.com/app/answers/detail/a_id/1620/~/overview-of-irobot%C2%AE-and-if-this%2C-then-that-%28ifttt%29.)</sup>。

- **this** （るんちゃん起点）
    - ルンバが掃除を開始したら、
    - ルンバがミッションを完了したら、
    - ルンバがスタックしたら、
- **that** （ユーザー起点）
    - ルンバを開始する / 一時停止する / 終了する / ドックに戻す
  
本当は「今の状況（掃除中やドックにいる）の確認」や「ルンバ内のゴミの溜まり状況の確認」もしたかったのですが、現時点では対応していないようです。
リクエストは送ったので、よりリッチになることを待ちましょう。

this側とthat側で作成したレシピは以下の通りです。

### thisレシピ
<img width="1220" alt="ifttt_this.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84670/098ae14f-5e9f-0d65-7307-9ea1d43f790b.png">

るんちゃんが掃除を開始したり、終了したりした時にAPIサーバーにHTTPリクエストを送信してくれるよう設定します。
this側の条件「mission complete」、「robot started」、「robot stuck」のそれぞれに対して、that側のアクションとして「webhook (make a web request)」を選択します。

- URLには自身で作成したAPIサーバーの任意のアドレスを設定 `https://<APIサーバー>/ifttt/started`
- methodにはPOSTを選択
- json型のbodyに、timestampとstatusを埋め込みました。ingredientがtimestampしかなかったのでリッチなPOSTにはできなかったので残念ですが。

<img width="491" alt="this_action.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84670/276fb111-b562-01c3-0043-8edd0a171f7a.png">



### thatレシピ
<img width="1177" alt="スクリーンショット 2019-10-13 16.32.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84670/f67a0754-9237-400b-21a7-084932ede9c5.png">

特定のhttpリクエストを受けるとるんちゃんを開始したり終了したりできるよう設定します。

- thisには「webhook」を選択
- イベント名には「start」、「stop」など、対応する動作が分かりやすいような名前を指定
- thatにはiRobotアクションの「Dock robot」、「Start robot」、「Stop Robot」、「Pause robot」などを指定

<img width="442" alt="that_action.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84670/243ddec8-e8ac-c866-6a3e-e5b7721988b5.png">



## APIサーバー
IFTTTで設定したサービスに対してwebhook通信を行ったり、LINEbotとしてLINEの友だちに通知を行ったりする役割を持ちます。

こちらの記事<sup>[9](https://qiita.com/shimajiri/items/cf7ccf69d184fdb2fb26)</sup>を参考に、python flaskによるLINEbotのバックエンド開発を行い、heroku上にデプロイしました。

以下、IFTTTからのwebhook通信に対してLINE通知を行う機能と、LINEからのwebhook通信に対してIFTTTへのwebhook通信を行う機能の詳細です。

### IFTTT → LINE
るんちゃんが掃除を開始したことをLINEで通知するよう設定します。
前段のIFTTTで設定した通り、るんちゃんが掃除を始めると`https://<APIサーバー>/ifttt/started`に対してPOSTリクエストが飛んできますので、LINE通知を`broadcast`してあげるだけのシンプルな構造です。

```run.py
@app.route("/ifttt/started", methods=['POST'])
def started():
    text = 'るんちゃん、お掃除始めるよ！\n頑張るん！'
    line_bot_api.broadcast(messages=TextSendMessage(text=text))
    return "started"
```
`https://<APIサーバー>/ifttt/completed`や`https://<APIサーバー>/ifttt/stacked`に対しても同様に設定します。

### LINE → IFTTT
LINEからるんちゃんを開始、終了させたりできるようにします。

るんちゃんを制御するにはthatレシピとして作ったアドレスに対してhttpリクエストを送信すれば良いです。webhookのためのkeyをIFTTT上のWebhooksのページにある「Documentation」で確認<sup>[10](https://ifttt-japan.club/apply-webhooks)</sup>し、heroku環境変数として設定します。

そしてIFTTTへPOSTする関数を定義し、

```run.py
YOUR_IFTTT_WEBHOOK_KEY = os.environ["YOUR_IFTTT_WEBHOOK_KEY"]

def post_to_ifttt(event):
    url = 'https://maker.ifttt.com/trigger/{}/with/key/{}'.format(event, YOUR_IFTTT_WEBHOOK_KEY)
    requests.post(url)
```

LINE上で特定のコマンド（文字列）を受けると、るんちゃんを制御できる構造にします。
コマンド以外の会話文の場合はまだオウム返ししかできません。

```run.py
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    if event.message.text == 'お掃除をはじめる':
        post_to_ifttt('start')
        # 掃除が開始されると started が呼ばれるのでここでは通知しない
    elif event.message.text == '一時停止':
        post_to_ifttt('pause')
        text = 'るんちゃん、ちょっと待ちます！\nぴたっ！'
        line_bot_api.broadcast(messages=TextSendMessage(text=text))
    elif event.message.text == 'ドックに戻る':
        post_to_ifttt('dock')
        text = 'るんちゃん、おうちに帰ります！\nてくてく！'
        line_bot_api.broadcast(messages=TextSendMessage(text=text))
    else:
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text='「' + event.message.text + '」って言ってくれてありがとるん！'))
```


## LINE bot

最後に、LINEbotとしての「るんちゃん」を作成します。

これらの記事<sup>[10](https://developers.line.biz/ja/docs/messaging-api/building-bot/),[11](https://qiita.com/nkjm/items/38808bbc97d6927837cd),[12](https://qiita.com/yoshizaki_kkgk/items/bd4277d3943200beab26)</sup>を参考に、Messaging APIを使ってLINEボットを作成しました。
webhook先のURLはもちろんheroku上のAPIサーバーとします。


### リッチメニュー作成
どうせならと思いLINEリッチメニューも作成しました。
なお、[[13](http://manual-at.line.me/archives/1067959676.html)]には「リッチメニューは「ベーシック」プランより上位のプランをご購入の方のみお使いいただける機能」との記載がありましたが、現在は無料プランでも選択できるようになっているようです<sup>[14](https://watayoro.com/richmenu)</sup>。

テンプレートをもとに画像をパワポで作成し、リッチメニューとして設定します。
リッチメニューのアクションとしては「テキスト」を選択し、サーバー側で記述したコマンド文と一致させます。つまり、「お掃除をはじめる」のメニューボタンをタップすると、「お掃除をはじめる」というテキストメッセージが送信されるようにします。


# 動作確認
herokuへのデプロイ、LINEbotの友達登録、ルンバのスケジュール登録などを経て、動作確認です。
以下、Androidスマホ上でのキャプチャですが、スケジュール登録した時間になればるんちゃんが掃除を開始・終了したことを伝えてくれますし、LINE上から指示を出しても正しく動作してくれました！

<img width="442" alt="demo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84670/2cd1372f-3011-7fcf-dbee-ff2d2a8cdbcc.jpeg">

# 参考
1. https://play.google.com/store/apps/details?id=com.irobot.home&hl=ja
2. https://apps.apple.com/jp/app/irobot-home/id1012014442
3. https://homesupport.irobot.com/app/answers/detail/a_id/9840/
4. https://blog.sikmi.com/hacking-roomba-slackbot
5. https://github.com/umesan/til/tree/master/Roomba
6. https://qiita.com/umesan/items/ea9d1603d139387b6a97
7. https://techblog.nhn-techorus.com/archives/2999
8. http://irobot-homesupport-ja-jp.custhelp.com/app/answers/detail/a_id/1620/~/overview-of-irobot%C2%AE-and-if-this%2C-then-that-%28ifttt%29.
9. https://qiita.com/shimajiri/items/cf7ccf69d184fdb2fb26
10. https://developers.line.biz/ja/docs/messaging-api/building-bot/
11. https://qiita.com/nkjm/items/38808bbc97d6927837cd
12. https://qiita.com/yoshizaki_kkgk/items/bd4277d3943200beab26
13. http://manual-at.line.me/archives/1067959676.html
14. https://watayoro.com/richmenu