ラインから手軽にスマートデバイスを操作する方法について解説します。
この記事ではラズパイで自作したスマートデバイスをラインで操作する方法について解説しますが、IFTTT経由で操作できるものであれば市販のスマーロックやスマートリモコンなども操作可能です。
今回作成するのはこのようなLINE BOTです。
初心者でもこの記事で紹介する作成手順で行えば1時間ほどでスマートデバイスとLINEを連携することが可能です。
LINE BOT は GAS(google apps script) で作成します。
目次
必要なもの
- スマートデバイス(今回はラズパイ)
※市販のスマートデバイスでも可
必要なものはたったこれだけです。
LINE BOTのサーバーもGASで作るのでgoogleアカウントがあれば作成できます。
Raspberry Pi4 ModelB 4GB ラズベリーパイ4 技適対応品
概要
ラインでスマートデバイスを操作する流れは、
- GASでMQTTブローカーであるbeebotteにWEBリクエストを送信
- beebotteから送られてきたデータをラズパイで動かしているpythonのMQTTサブスクライバープログラムで取得
- そのデータを読み取り、操作するデバイスとアクションを判定し、ラズパイで動かす
といった感じです。後で詳しく説明します。
ちなみに市販のスマートデバイスを操作する場合は、
- GASでIFTTT(webhook)にWEBリクエストを送信
- IFTTT経由でスマートデバイスを操作
といった感じでできます!
導入手順
- LINE BOTの作成
- LINEのリッチメニューの実装
- IoTデバイスとの連携
・LINE BOTの作成
今回は GAS(google app script)とLINE message APIを使って、LINE BOTを作成していきます。
GASを使用することで20分ほどでLINE BOTを作成 することができます。
LINE BOTの作成方法については以下の記事をご覧ください。
・LINEのリッチメニューの実装
リッチメニューとは・・
リッチメニューとは 、よく公式アカウントなどのトーク画面に表示される↑このような メニューのことです。
ちなみにこのリッチメニューでは、ボタンを押した際に、
- 登録済みのメッセージが送信される
- 指定済みのURLへ飛ぶ
- クーポン画面を表示させる
- ショップカード画面を表示させる
というような動作を行うことができます。
今回はボタンを押したら、
- 登録済みのメッセージが送信される
という機能を使います。
リッチメニューの実装
1. ラインアカウントマネージャーにアクセスします。
ログインすると先ほど作成したBOTのアカウントが表示されるので、クリックします。
2. 左サイドバーの中のリッチメニューをクリックします。
3. 右上の作成をクリックします。
4. リッチメニューの表示設定
リッチメニューの作成画面が表示されたら、
- タイトル(ライン管理画面に表示されるリッチメニューの名前)
- 表示期間(リッチメニューを表示させる期間)
- メニュバーテキスト(リッチメニューの下に表示される名前)
を記入します。
5. コンテンツ設定
「コンテンツ設定」→「テンプレートを選択」をクリックすると、以下のようなポップアップが表示されるので、リッチメニューのレイアウトを選択します。
「画像を作成」をクリックすると、手軽にリッチメニューのアイコンを作成できます。
今回はリッチメニューをタップしたら自動で登録済みのテキストを送信するという機能を使用するので、「タイプ」では「テキスト」を選択し、その下の入力欄には送信するテキストを指定します。
6. 「保存」をクリックする。
最後に画面右上の「保存」をクリックしたら、リッチメニュー作成完了です。
作成したラインアカウントを開いてみると、リッチメニューが反映されているはずなので、リッチメニューをタップしてテキストが自動送信されるか確認してください。
※補足
今回はラインオフィシャルアカウントマネージャーからリッチメニューを作成しましたが、特定のフォーマットのjsonデータを送信することでもリッチメニューの作成は可能です。この方法で設定を行うと任意の範囲をタップ可能になり、タップ可能な場所も6個以上設定できるようになります。
・IoTデバイスとの連携
連携の概要
次にIoTデバイスとの連携を行っていきます。
先ほど作成したリッチメニューでアイコンをタップすると、設定済みのテキストが送信されるので、LINE BOTのサーバー側であるGASでその送信されてきたテキストを読み取り、そのテキストに応じた処理を行うようなプログラムを作成します。
「そのテキストに応じた処理 」というのはMQTTブローカーであるbeebotteにテキストに応じたデータを送信するという処理です。
例えば、「エアコンON」というアイコンがタップされると「エアコンつけて」と自動で送信されます。それをGASで受信し、 beebotteに
{"data":[{"terminal":"LINE","device":"エアコン","action":"オン"}]}
といったようなデータを送信します。 beebotteはMQTTサブスクライバーであるラズパイにそのデータを転送し、ラズパイでスマートデバイスを操作(赤外線LEDでエアコンをつける)するという感じです。
市販のスマートデバイスを操作する場合は、データの送信先を beebotte ではなく、IFTTTのwebhook 宛にします。
https://maker.ifttt.com/use/fdfaneonjnkjean #送信先の例
そして送るデータは
{"value1":"LINE","value2":"エアコン","value3":"オン"}
というようにします。
beebotteの設定
まず、beebotteの設定を行います。
beebotte の設定方法についてはこちらの記事に詳しく書いてあるので参照してください。
LINE BOTの編集
次に、「LINE BOTの作成」で作成したGASのプログラムを変更して、特定のメッセージが来たら特定の処理をさせるようにします。
プログラムを以下のように書き変えて、 「Project version」を「new」として公開してください。
function doPost(e) {
var replyToken= JSON.parse(e.postData.contents).events[0].replyToken;
if (typeof replyToken === 'undefined') {
return;
}
var url = 'https://api.line.me/v2/bot/message/reply';
var channelToken = 'diangjrnganeje/gaekannogaga/XXXXXXXXXXXXX/145/a=';
var receive_message = JSON.parse(e.postData.contents).events[0].message.text;
var reply_text = receive_message + "\n" + "に対応するアクションはありません" + "\n" + "実行可能なメッセージを確認するには\"ヘルプ\"と言ってみてください";
if(receive_message == "エアコンつけて") {
beebotte_publish("air_con","on");
reply_text = "エアコンをつけます";
} else if(receive_message == "エアコン消して") {
beebotte_publish("air_con","off");
reply_text = "エアコンを消します";
}
if(receive_message == "鍵開けて") {
beebotte_publish("lock","open");
reply_text = "玄関の鍵を開錠します";
} else if(receive_message == "鍵閉めて") {
beebotte_publish("lock","close");
reply_text = "玄関の鍵を閉錠します";
}
if(receive_message == "リビングの電気つけて") {
beebotte_publish("room_light","on");
reply_text = "リビングの電気を操作します";
} else if(receive_message == "玄関の電気つけて") {
beebotte_publish("entrance_light","off");
reply_text = "玄関の電気を操作します";
}
if(receive_message == "ヘルプ") {
reply_text = "実行可能なコマンドは以下の通りです。\n" +
"・エアコンつけて\n" +
"・エアコン消して\n" +
"・鍵開けて\n" +
"・鍵閉めて\n" +
"・リビングの電気つけて\n" +
"・玄関の電気つけて";
}
var messages = [{
'type': 'text',
'text': reply_text,
}];
UrlFetchApp.fetch(url, {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + channelToken,
},
'method': 'post',
'payload': JSON.stringify({
'replyToken': replyToken,
'messages': messages,
}),
});
return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}
function beebotte_publish(device,action) {
var headers = {
"Content-Type": "application/json"
};
var json = `{"data":[{"terminal":"LINE","device":"${device}","action":"${action}"}]}`;
var options = {
"headers": headers,
"method": "post",
"payload": json
};
UrlFetchApp.fetch("https://api.beebotte.com/v1/data/publish/チャンネル名/トピック名?token=token_XXXXXXXXXXXXX", options);
}
※channelTokenにはラインボットのトークンを、
token_XXXXXXXXXXXXXには、beebotteのトークンを、
チャンネル名/トピック名 には beebotteのチャンネル名とトピック名を入力してください。
Pythonプログラムの作成
最後にラズベリーパイ側で実行するプログラムを作成します。
プログラムはこんな感じです。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#smartremocon.py
import paho.mqtt.client as mqtt
import subprocess
import json
from time import sleep
HOST = 'mqtt.beebotte.com'
PORT = 8883
CA_CERTS = 'mqtt.beebotte.com.pem'
TOKEN = 'token_xxxxxxxxxxxxxxxxxx' #Beebotteで作成したチャンネルのトークンを入力
TOPIC = 'RaspberryPi/SmartRemocon' #Beebotteで作成したトピック名を入力
def on_connect(client, userdata, flags, respons_code):
print('status {0}'.format(respons_code))
def on_disconnect(client, userdata, flags, respons_code):
print("Unexpected disconnection.")
client.loop_stop()
def on_message(client, userdata, msg):
data = json.loads(msg.payload.decode("utf-8"))["data"][0]
# control air_con
list_summer=[5,6,7,8,9,10]
list_winter=[11,12,1,2,3,4]
if (data["device"] == 'air_con'):
if (data["action"] == 'on'):
date = datetime.datetime.now()
if date.month in list_summer:
print(date.month,"月 ","冷房をつけます")
subprocess.call(["python3", "irrp.py", "-p", "-g17", "-f", "codes", data["device"]+":"+"on"])
elif date.month in list_winter:
print(date.month,"月 ","暖房をつけます")
subprocess.call(["python3", "irrp.py", "-p", "-g17", "-f", "codes", data["device"]+":"+"on-winter"])
# control ps4
elif (data["device"] == 'ps4'):
if (data["action"] == 'on'):
subprocess.call(["sudo", "ps4-waker"])
if (data["action"] == 'standby'):
subprocess.call(["sudo", "ps4-waker", "standby"])
if (data["action"] == 'torne'):
subprocess.call(["sudo", "ps4-waker", "start", "CUSA00442"])
if (data["action"] == 'primevideo'):
subprocess.call(["sudo", "ps4-waker", "start", "CUSA03099"])
if (data["action"] == 'youtube'):
subprocess.call(["sudo", "ps4-waker", "start", "CUSA01065"])
if __name__ == '__main__':
client = mqtt.Client()
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_message = on_message
client.username_pw_set('token:%s' % TOKEN)
client.tls_set(CA_CERTS)
client.connect(HOST, PORT)
client.subscribe(TOPIC)
client.loop_forever()
※tokenには、beebotteのトークンを、
topic には beebotteのチャンネル名とトピック名を入力してください。
このプログラムを実行させるには beebotte の証明書やモジュールのインストールが必要です。
詳しくはこちら↓の記事を参照してください。
以上で完成です!
今回は市販のスマートデバイスをラインで操作する方法については軽くしか説明しませんでしたが、詳しく知りたい方はTwitterやこの記事にコメントをくれればできる限り対応します。
分かりにくいところなどありましたらご指摘ください!
とても面白いです。自分でもやってみたくなりました。
1つ気になったのですが、もしもLINE BotのIDを誰かに知られてしまった場合、その人が部屋のエアコンなどを操作できてしまうことになりませんか?
知識不足故に的はずれなことを言っていたら申し訳ありません。LINE Botは非公開設定にできない仕様なので気になりました。
コメントありがとうございます!
この記事ではセキュリティー面についてはあまり深く考えていません。
あくまで”こんな使い方があるよ”というようなことを紹介するために書かせていただいており、誰でも簡単に実装できるようにセキュリティに関する部分は省略しています。
ですのでセキュリティ面も考えて実装したい場合は、もう少し工夫する必要があります。
仰る通り、LINE BotアカウントのIDを何らかの方法で知られてしまった場合、誰でもアクセスすることができてしまいます。
これに対する対策法のひとつとしてuseridを使用する方法があります。
useridは個人のLINEアカウント一つ一つに固有に割り当てられているものであり、
とすることで、LINE Botアカウントに対してメッセージを送信した人のuseridを取得することができます。
これを利用して自分のuseridを取得し、自分以外のuseridからのアクセスの場合は拒否するようにGASプログラムを作成することで、第三者からスマートデバイスを操作されることを防ぐことができます。
(ただし、もちろんこれだけではハッキングされたりした場合は防げない可能性はあります。あくまで通常の方法でのアクセスから防げるようになるだけです。)
また、セキュリティに関して、Messaging APIの開発ガイドラインでは、リクエストがなりすましではなくLINから送られたことを確認するために署名を検証することが推奨されています。
ですので、本来ならば署名の確認処理も実装する必要があります。今回は上記の理由につき、この処理の部分についての説明はこの記事では割愛しています。
本気でセキュリティ対策をしたい場合は以下のMessaging Apiの公式ドキュメントをご覧になってみてください。
https://developers.line.biz/ja/docs/messaging-api/
また、気になることや分からないことがありましたら、お気軽にコメントください!
お返事ありがとうございます。
具体的な方法までお教えいただき感謝致します。理解しました。
他の記事もいくつか拝読致しましたが、どれも大変分かりやすい解説で助かっております。初心者なので適宜それらを参照しながら、自分でできることを増やしていきたいと思います。ありがとうございました。