「Alexa、パソコンを起動して」を実装した話


# はじめに

3月頭におこなわれたAmazonタイムセールで、Amazon Echo dotが40%引きの3,280円で販売！
ということで、iPhoneのSiriもAppleWatchのSiriも端末を口元に近づけないと反応しない不満があった僕は、「やっす！買っちゃおｗ」などと言ってあっさり買ってしまったのでした。

* タイマーやアラーム設定したり、
* カレンダーに予定を追加したり、
* 朝起きたら天気やニュースを読み上げさせたり

なんかはEcho単体でもできて、そこそこ便利に使っていたのですが、「折角だからスマートホーム的なこともしたいな～」と思うようになったものの、照明やらエアコンやらを操作するには[それ](https://www.amazon.co.jp/SwitchBot-スマートスイッチ-タイマー機能搭載-いろんな家電のスイッチに適用-IFTTTなどに対応可能（白）/dp/B0869GJVG4/)[なりの](https://www.amazon.co.jp/%E3%83%A9%E3%83%88%E3%83%83%E3%82%AF%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0-%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E5%AE%B6%E9%9B%BB%E3%83%AA%E3%83%A2%E3%82%B3%E3%83%B3-%E3%82%B9%E3%83%9E%E3%83%9B%E3%81%A7%E5%AE%B6%E9%9B%BB%E3%82%92%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB-%E8%B5%A4%E5%A4%96%E7%B7%9A%E5%88%B0%E9%81%94%E8%B7%9D%E9%9B%A230m-%E3%80%90%E6%97%A5%E6%9C%AC%E6%AD%A3%E8%A6%8F%E4%BB%A3%E7%90%86%E5%BA%97%E5%93%81%E3%80%91RS-WFIREX4/dp/B07MVC7394/)[もの](https://www.amazon.co.jp/Philips-シングルランプ-2個セット-Bluetooth-Zigbee対応/dp/B084GFMMFH/)が必要で・・・
「Echoがもう一台買えるやん！」
となってしまったので、お金のないぼく[^sb69]は、自宅のラズパイ使ってPC起動するだけならお金かからないと思い立ち、エセスマートホーム気分に浸ることにしたのでした。
[^sb69]: お金がなくてもSHOW BY ROCK!!ましゅまいれっしゅ!!Blu-ray BOXは買ってしまう。みんなも観ようね

## 使用したもの・サービス

* Raspberry PI 1 Model B 
  * OS: Raspbian GNU/Linux 8.0 (jessie)
  * Python, MQTTライブラリ
* Amazon Echo dot
* IFTTT
* Beebotte

## 構成
各種サービスを以下のようにつなげていきます。
Amazon Echo Dot
　↓（定型アクション）
IFTTT
　↓（Webhooks）
Beebotte
　↓（MQTT）
Raspberry Pi
　↓（Wake on LAN）
PCを起動

## 類似記事
全般的に以下の記事などなどを参考にさせて頂きました。
[IFTTTとBeebotteを使ってGoogleHomeからRaspberryPiを操作する - Qiita](https://qiita.com/msquare33/items/9f0312585bb4707c686b)
[Alexaの定型アクションへIFTTTを追加してシュッと帰宅しよう - Qiita](https://qiita.com/mongamae-nioh/items/990b6505961d5a61444a)

# Beebotteの設定
Beebotteの設定内容を色んな所で参照するため、まずはBeebotteの設定を先に行います。
[参考記事](https://qiita.com/msquare33/items/9f0312585bb4707c686b#beebotte%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)が詳しいので、以下では概略だけ説明します。

1. https://beebotte.com/ にアクセス、アカウント作成、ログイン
1. Channel作成
2. Channel名、Resource名を登録する。
3. Channelトークンを取得（控えておく）
4. BeebotteのConsoleで動作確認
5. ターミナルで動作確認

# RaspberryPiの設定
## Wake on LAN（マジックパケット）の送信
色々な方法があると思いますが、PythonにもWoLパケット送信のライブラリがあるようなので、そういったものを使用するのが良いかと思います。
僕の場合、[SENGOKU's Free Software様](http://www.gcd.org/sengoku/freesoft.ja.html)のC言語のプログラムをコンパイルした実行ファイルを呼び出すことにしました。というか、以前にコンパイルした物があったので、そのまま流用した形です。

```zsh:zsh
$ cd /opt/smarthome/wol
$ wget www.gcd.org/sengoku/docs/wol.c
（実行結果略）
$ gcc wol.c -o wol.out
$ ls
wol.c  wol.out*
```

`wol.out （IPアドレス） （MACアドレス）`として実行するとマジックパケットが送信されます。PCを終了かスリープして、ラズパイから実行してみて確認してみると良いでしょう。[^2]
起動しない場合、Windowsの電源オプションや、マザーボードの設定を確認します（割愛します）。
[^2]: ラズパイには普段TeraTermなどで接続している方は、スマホからSSH接続できるアプリなどを活用すると便利です。僕なんかそうですが、ラズパイにはディスプレイもキーボードも繋がっていません。

## pip、MQTTライブラリのインストール、Beebotteアクセス証明書のダウンロード
なぜか僕のラズパイ、python3は入っているのにpipが入っていなかったため、インストール。
証明書は以下のURLからダウンロードして、ラズパイサーバ内に配置します。
https://beebotte.com/certs/mqtt.beebotte.com.pem

```zsh
$ sudo apt-get -y install python3-dev
$ sudo apt-get -y install python3-pip
$ sudo pip3 install paho-mqtt
$ wget https://beebotte.com/certs/mqtt.beebotte.com.pem -O /opt/smarthome/mqtt.beebotte.com.pem
```

## Beebotteを受け付けるPythonプログラムの実行
参考記事や色々なサイトのコードを流用し、切り貼りして作成します。
ちなみに以下のプログラムではPC2台へマジックパケットを送信しようとしているのは、メイン機の他にWindowsタブレットを起動しようとしているためです。（タブレットで無線LAN接続の場合、電源の落ちた状態から起動することはできませんが、スリープからであれば復帰できます。）

以下のプログラム中、`（Channelトークン文字列）`、`（チャンネル名）/（リソース名）`としているところは、Beebotteの設定ページで入力したものを設定します。

```python:smarthome.py
import paho.mqtt.client as mqtt
import json
import subprocess
import datetime

# Beebotteから取得したトークン文字列
TOKEN = "（Channelトークン文字列）"
# ホスト名
HOSTNAME = "mqtt.beebotte.com"
# ポート
PORT = 8883
# Beebotteの設定内容 "チャンネル名/リソース名"
TOPIC = "（チャンネル名）/（リソース名）"
# ダウンロードした証明書のパス
CACERT = "/opt/smarthome/mqtt.beebotte.com.pem"

# 起動させたいPCのMACアドレス、ブロードキャストアドレス
mac1="（MACアドレス）"
mac2="（MACアドレス）"
brc="192.168.1.255"

# ログファイル保存先
logfile = "/opt/smarthome/log.txt"

# いい感じの書式で現在時刻を返す関数
def formattime():
	return datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')

# 接続時に呼ばれるコールバック関数
def on_connect(client, userdata, flags, respons_code):
	print('status {0}'.format(respons_code))
	with open(logfile,mode='a') as f:
		f.write("["+formattime()+"] service started. status {0}\n".format(respons_code))
	client.subscribe(TOPIC)

# メッセージ受信時に呼ばれるコールバック関数
def on_message(client, userdata, msg):
	data = json.loads(msg.payload.decode("utf-8"))["data"][0]
	data = {key:value.strip() for key, value in data.items()}
	with open(logfile,mode='a') as f:
		if ("room" in data.keys()) and ("message" in data.keys()):
			if (data["room"] == "living") and (data["message"] == "PC_wake"):
				# 正しいデータが送信された場合は、WoLの実行ファイルを起動する
				# 以下の実行ファイルパスは適宜変更する
				subprocess.check_output(['/opt/smarthome/wol/wol.out', brc, mac1])
				subprocess.check_output(['/opt/smarthome/wol/wol.out', brc, mac2])
				f.write("["+formattime()+"] Wake up!!\n")
			else:
				f.write("["+formattime()+"] undefined message: "+str(data)+"\n")
		else:
			f.write("["+formattime()+"] invalid message: "+str(data)+"\n")

client = mqtt.Client()
client.username_pw_set("token:%s"%TOKEN)
client.on_connect = on_connect
client.on_message = on_message
client.tls_set(CACERT)
client.connect(HOSTNAME, port=PORT, keepalive=60)
client.loop_forever()
```

BeebotteからJSON形式の文字列でデータが送信されてくるので、data変数に展開します。が入って来ます。今回、PC起動指示は以下のデータが送信されてくるものとしました。

```JSON
{"data":[{"room":"living","message":"PC_wake"}]}
```

messageの内容が違ったり、オブジェクトの構造が違ったりする場合は、logfileに記録を残します。

## 実行テスト
以下のコマンド（先ほどと同じ）を実行して、受付側に反応があれば成功。

```zsh:zsh
$ curl -i -H "Content-Type: application/json" -X POST -d '{"data":[{"room":"living","message":"PC_wake"}]}' 'http://api.beebotte.com/v1/data/publish/（channel名）/（resource名）?token=（Channelトークン）'
```


# IFTTTの設定

[IFTTT](https://ifttt.com/)は、「If **This** Then **That**」の**This**および**That**に様々なウェブサービスを連携させることで、「**This**からの何かトリガーに、**That**で何かをする」という設定（Applet）が作成ができるサービスです。スマートホーム界隈で有名なようです。
今回は、Alexaへの呼びかけでIFTTTがトリガーし、Beebotteへコマンドを送るように設定します。Beebotteへ送信するのは、Webhooksというものを使います（このあたり僕もよく分かってません）

* https://ifttt.com/ にアクセスし、アカウントを作成しておく
* Appletを作成する
* **This**は、Amazon Alexaを選択
* **That**は、Webhooksを選択

人気のAppletは誰かが投稿したものを探す（Explore）こともあるようですが、今回は作成（Create）します。

## This設定

1. ログイン後、メニュー（右上の自分アイコン）からCreateをクリック
2. ✚**This**をクリック、Amazon Alexaを選択
3. Say a specific phraseを選択
4. What phrase?欄に、「パソコン起動」など、わかりやすいタイトルを記入<br>
※ここで入力した文字列はAlexaアプリで設定するときの選択肢になります。Alexaへ呼びかける言葉は別途設定します。

ここまで設定すると、✚**This**だった部分がAmazon Alexaのアイコンに変わります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33728/5ac7754a-3751-c612-74c8-8686be210849.png)

## That設定

1. ✚**That**をクリック、Webhooksを選択
2. Make a web requestを選択
3. 設定画面で、各種パラメータを以下のように設定

| 項目 | 値 |
|:--|:--|
| URL | http://api.beebotte.com/v1/data/publish/（channel名）/（resource名）?token=（Channelトークン） <br>※（channel名）、（resource名）、（Channelトークン）はBeebotteで設定したときの文字列を指定します。|
| Method | POST |
| Content Type | application/json |
| Body | `{"data":[{"room":"living","message":"PC_wake"}]}` |

最後に確認画面でFinishをクリックし、以下の画面表示になったら準備完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33728/1b0a1601-71ce-45f8-36f5-a62068b03f24.png)


# Alexaの設定
Echoなどのデバイスに向かって「Alexa、パソコンを起動して」というフレーズで話しかけることでIFTTTがトリガーされるよう、スマートフォンのAlexaアプリから定型アクションを設定します。

1. Alexaアプリのメニューから、「定型アクション」を選択
2. 新しい定型アクションを作成
3. 定型アクション名を入力。わかりやすいタイトルを入力。
4. 実行条件を設定する。開始フレーズを設定→「パソコンを起動して」などのフレーズを入力。
5. アクションを追加→IFTTT→「パソコン起動」（先程IFTTTの設定で入力したもの）を選択
6. 保存

設定が反映されるまで数分かかる旨のメッセージが流れます（でも、大抵すぐ反映されます）。
Echoに「Alexa、パソコンを起動して」と話しかけてみましょう。


# 設定完了！

以上で、設定完了です。ぼくの家では、「Alexa、パソコンを起動して」と言うだけでパソコンが起動するようになりました。
これで、朝眠くて布団から出れなくても、SHOW BY ROCK!!Fes A Live!!をプレイ中で手が離せなくても、PCを起動できます。便利です。

ついでに僕の場合、以下のような感じで「Alexa、ただいま」と言ってもパソコンが起動するようにしてみました。
帰宅して手を洗っている間にもパソコンを起動できます。流行りのウイルスにかかりたくない人はまず手洗いうがいをしよう！

<img width="375" alt="写真 2020-03-29 15 05 34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33728/1f37ca97-4f08-0a8a-e004-afeb594d55af.png">
（ただ、↑の「帰宅時のフレーズを言う」だと、単純に「Alexa、ただいま」と言うと歌ってくれた"おかえりの歌"を歌ってくれなくなってしまうのが玉に瑕です。。。）