Raspberry Pi とSlackとLINE Messaging APIでLINEから家電を操作する

Raspberry Pi

はじめに

これまででAlexaやiPhoneから家電を操作できるようなりました。

しかし、Alexaはともかくsshでコマンド実行などという操作方法は普通の人に理解させることは容易ではありません。
自分だけが使うならともかく、家族など別の人が使うには難易度が高すぎます。

そこでLINEを使う方法を検討します。
LINEであれば誰でも知っていますし、嬉しいことに無料で使用できるAPIも用意されています。

LINE BOTを構築してRaspberry Piと連携させることを実施します。

Raspberry PiでLINE BOTを作るときの問題点

LineBOTとRaspberry Piを接続するには簡単にはできません。
Raspberry PiからLINEにはLINE Notifyで簡単ですが、LINEからRaspberryPiは少々準備が必要です。

まずは方法を検討します。

方法案1. ドメインを取得して公開する

直接Raspberry PiをWebサーバにする方法です。

ある程度簡単ですが、セキュリティリスクが高いです。

下手に公開して攻撃された場合を考えるとあまりやりたくないですね。

また、固定IPを取得する必要があります。
プロパイダによっては月1000~3000円程度オプション料金が必要になります。

私の契約しているプロパイダは固定IPが使えません。
DynamicDNSを使う方法もありますが、あまりローカルを外に晒す行為はしたくないですね。

方法案2. ngrokを使う

ngrokを使えば簡単にlocalhostをhttpsで外部公開することができます。

しかし、簡単にできるのですが、無料で行うには制限があります。
例えばアクセスする際のURLが起動するたびに変わってしまうことです。

つまり、Raspberry Piが再起動した場合必ずLINE Messaging APIのURLを変更する必要があります。

常用には向きません。

有料プランもありますが、今回はパスします。

また、1と同様にセキュリティリスクがあります。

方法案3. クラウドサービスを使う

AWSやAzure、GCPを使うことでもできそうです。

例えばAzure Web Appsや仮想マシンにLINE BOTに応答するサービスを作って、Raspberry Piとの接続にはAzure VPN Gatewayを使うといった方法が挙げられます。

インターネット向けにAzureが接続を受け持ち、家電の操作は裏足からVPNで接続すればこれまでの方法よりはセキュアに使えることができそうです。

しかし、Azure VPNは従量課金です。
どれくらい使うのか想像できないものであまり使いたくはないですね。。。

方法案4. VPSをレンタルする

クラウドが従量課金で怖いなら、定額のVPSを借りればいいじゃない。
ということで、VPSを検討してみます。

VPSを使えば簡単に固定IPを取得できますし、Raspberry PiとVPNで接続すればある程度セキュアな環境が得られそうです。

一番安いWeb AlenaのVPSで一番ランクの低いもので400円程度で運営可能みたいです。

ただし、やはりランニングコストが必要です。

方法案4. Slackを使う

一番有力な案としてSlackを経由してRaspberry Piに接続することを考えます。

Slack BotをRaspberry Pi上で立ち上げて、それにLINEを接続すれば、外部にサーバ公開することなくLINE BOTが使えるかもしれません。

slackbotのセキュリティリスクは今回は考えないことにします。

この方法をやってみます。

構成図

今回やりたいことの大まかな概要図です。

Raspberry PiにSlackbotを構築する

LINEとの接続の前にまずはSlack Botを作る必要があります。

以下のサイトを参考にさせていただきました。ありがとうございます。

PythonのslackbotライブラリでSlackボットを作る - Qiita
前置き このページは基本的な使い方を説明するページです。使い方のすべてを説明するわけではありません。 Pythonのslackbotライブラリを用いれば、Slackで特定のメッセージを受け取って、処理を行ったり、返事を行うことが...
Raspberry piでslackbotを動かす - Qiita
はじめに 久しぶりにラズパイでslackbotを動かしたくなったので、設定した内容まとめ。 過去に一度設定したけど、微塵も覚えてないので、まとめついでに一から設定します。 ついでに、前に設定してなかったip固定とかsystemc...
Raspberry PiでSlackbotを飼う - Qiita
このエントリは「Raspberry Piでスマートロックつくった」の解説6つめになります。 前回まででスマートロック開閉の記録をとるところまでつくることができました。 今回は遠隔での鍵開閉を実現するため、Slack経由で開閉命令を出せ...

SlackでBOTを作成する

以下のURLからSlackにログインしてBOTを作成します。

Login
Log in to Slack, or try for free with your teammates. All it takes is an email address to get started.

BOTが作成できたらチャンネルに招待します。
今回はrasp_botというチャンネルを作ってそこに招待しました。

slackbotのインストール

Raspberry Pi 3にpipで導入します。

slackbotのインストール
$ sudo pip3 install slackbot

Slack Botを動かす

Raspberry Piでの設定を行っていきます。

slackbot_settings.py
# -*- coding: utf-8 -*-
API_TOKEN = '<BOTのトークン>'

# デフォルトの返答
default_reply = 'わかりません。'

# プラグインを記述するディレクトリ名
PLUGINS = ['plugin']

API_TOKENの部分に作成したボットのAPIトークンを入れます。

プラグインファイルを作成します。

plugin.py

作業用ディレクトリはどこでもいいですが、今回は/opt/slackbotで作業します。

$ cd /opt/slackbot
$ mkdir plugin
$ touch plugin/__init__.py
$ vim plugin/plugin.py
# -*- coding: utf-8 -*-
from slackbot.bot import respond_to, listen_to
import re

# おはようテスト
@listen_to('おはよう')
@respond_to('おはよう')
def ohayou(message, *something):
    message.reply('おはよう')

__init__.py は空でいいみたいです。

SlackBotを実行するスクリプトを書きます。

run.py
# -*- coding: utf-8 -*-

from slackbot.bot import Bot


def main():
    bot = Bot()
    bot.run()


if __name__ == "__main__":
    print('start slackbot')
    main()

実行してみます。

$ python3 run.py

エラーが無く「start slackbot」と表示されていれば起動完了です。

Slack上で入力してみます。

今回の設定だと、「おはよう」と言うと、「おはよう」と返してくれました。

設定がない「こんばんは」と入れると反応がありません。
直接「こんばんは」とリプライしてみると、「わかりません。」と上で設定したデフォルトの言葉を返しました。

Slackbotを自動起動するようにsystemdに登録する

自動起動するようにサービス化します。

まず、slackbotを起動するシェルスクリプトを書きます。
実行権限も与えておきます。

ディレクトリはご自身の環境にあったものを使用してください。

$ cd /opt/slackbot/
$ vim start_slackbot.sh
$ chmod +x start_slackbot.sh
start_slackbot.sh
#!/bin/bash

cd `dirname $0`
python3 run.py

次に、systemdへ登録します。

$ sudo vim /etc/systemd/system/slackbot.service
slackbot.service
[Unit]
Description = Slackbot

[Service]
ExecStart = /opt/slackbot/start_slackbot.sh

Restart = always
Type = simple

[Install]
WantedBy = multi-user.target

自動起動設定と、サービスの起動を行います。

$ sudo systemctl enable slackbot.service
$ sudo start slackbot.service

以下のようにactive となっていれば起動完了です。

pi@raspberrypi3:/opt/slackbot $ sudo systemctl status slackbot.service
● slackbot.service - Slackbot
   Loaded: loaded (/etc/systemd/system/slackbot.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2020-09-10 12:47:45 JST; 3s ago
 Main PID: 31612 (start_slackbot.)
    Tasks: 12 (limit: 2068)
   CGroup: /system.slice/slackbot.service
           ├─31612 /bin/bash /opt/slackbot/start_slackbot.sh
           └─31614 python3 run.py

 9月 10 12:47:45 raspberrypi3 systemd[1]: Started Slackbot.
pi@raspberrypi3:/opt/slackbot $

これからplugin.pyなどを編集した場合は以下のコマンドで設定を読み込み直す必要があります。

$ sudo systemctl restart slackbot.service

Slackから家電を操作する

これでSlack上からRaspberry Piにアクセスすることができるようになったので、家電を操作してみます。

先程のプラグインファイルを編集して、エアコンの電源を入れるシェルスクリプトを叩いてみます。

plugin.pyを編集します。

subprocessのインポートと新たなコマンドを認識するように記述を追加します。

正規表現で若干の表記ゆれにも対応できるようにします。

plugin.py
# -*- coding: utf-8 -*-
from slackbot.bot import respond_to, listen_to
import re
import subprocess

# おはようテスト
@listen_to('おはよう')
@respond_to('おはよう')
def ohayou(message, *something):
    message.reply('おはよう')

@listen_to('(寝室|ベッドルーム)+.*(エアコン)+.*を(付|つ)+.*')
@respond_to('(寝室|ベッドルーム)+.*(エアコン)+.*を(付|つ)+.*')
def bedroom_aircon_on(message, *something):
    subprocess.run(["/opt/ir/bin/bedroom_aircon.sh" , "on"])
    message.reply('寝室のエアコンを付けました')

subprocess.runの部分にはエアコンの操作ができるシェルスクリプトやpythonスクリプトを起動できるように各自変更してください。

現状では以下のコマンドでエアコンの操作ができる状態です。

/opt/ir/bin/bedroom_aircon.sh on

実際に実行してみます。

ブログ上では表現できませんが、たしかにエアコンが反応しました。

これで簡単にSlack経由で家電の操作ができるようになりました!

SlackとLINE BOTを連携する

今回の本題はここからです。

SlackではなくLINEから操作したいのです!

LINE Messaging APIの設定などは終わっている前提です。

前回の記事を参照。

Google App Script (GAS)を利用してオウム返しを作る

以下のサイトを参考にさせていただきました。ありがとうございます。

Google Apps ScriptでLINE BOTつくったら30分で動かせた件 - Qiita
GWだし前々から作ろうと思ってたLINE botをつくってみた。 サーバーどうしよ ちょっと前まではherokuが定番だったが、無料枠のできることが変わって、常時稼働ができないみたい。 AWSのlambdaとかもありだけど、確実...

まず、Google Driveからスプレッドシートを作成します。

スプレッドシート名を適当に入力します。

「ツール」からスクリプトエディタを押します。

プロジェクト名を適当に入れて、以下のスクリプトを入れます。

// LINE developersのメッセージ送受信設定に記載のアクセストークン
var ACCESS_TOKEN = '<Your Access Token>';

function doPost(e) {
  // WebHookで受信した応答用Token
  var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
  // ユーザーのメッセージを取得
  var userMessage = JSON.parse(e.postData.contents).events[0].message.text;
  // 応答メッセージ用のAPI URL
  var url = 'https://api.line.me/v2/bot/message/reply';

  UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': replyToken,
      'messages': [{
        'type': 'text',
        'text': userMessage,
      }],
    }),
    });
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

公開タブから公開します。

一番下の欄を「全員(匿名ユーザを含む)」を選択します。

今回はなぜか英語表記になったので、「Anyone, even anonymous」を選びます。

最後にデプロイをクリックします。

すると、APIのURLが表示されますので、コピーしておきます。

このURLをLINE Messaging APIのWebhook URLに登録します。

これでLINEにメッセージを送ってみます。

メッセージがおうむ返しされていれば完成です。

こんなに簡単にサーバレスでLINE BOTが作れるなんて・・・感激です。

GASからメッセージの内容をSlackに投稿する

次は、GASからSlackにそのままメッセージを投稿するように設定します。

参考にしたサイトはこちらです。ありがとうございます。

【初心者向け】GASを使ってSlackへ自動通知 - Qiita
Slackへ自動通知を行いたい! というときに、GAS(Google Apps Script)を使用することで簡単に通知を行なうことができます。 今回の手順でできるようになること 特定の時間に○○というメッセージをSlackの...

まずはSlackのIncoming WebHooksを登録します。

先程のRaspberry PiのBOTがいるrasp_botのチャネルに投稿するように設定します。

追加すると、Webhook URLが表示されるのでこれをメモっておきます。

先程のGASのスクリプトを少し修正してSlackにポストされるようにします。
LINEのアクセストークンと、SlackのWebhoolURLを忘れずに入れてください。

// LINE developersのメッセージ送受信設定に記載のアクセストークン
var ACCESS_TOKEN = '自分のLINEのアクセストークンを入れてね';

var postUrl = 'slackのWebHookURLを入れてね';
var username = 'LINE';  // 通知時に表示されるユーザー名
var icon = ':globe_with_meridians:';  // 通知時に表示されるアイコン

function doPost(e) {
  // WebHookで受信した応答用Token
  var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
  // ユーザーのメッセージを取得
  var userMessage = JSON.parse(e.postData.contents).events[0].message.text;
  // 応答メッセージ用のAPI URL
  var url = 'https://api.line.me/v2/bot/message/reply';

  UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': replyToken,
      'messages': [{
        'type': 'text',
        'text': userMessage,
      }],
    }),
    });
  
    sendSlack(userMessage);
  
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
  

}


function sendSlack(message) {
  var jsonData =
  {
     "username" : username,
     "icon_emoji": icon,
     "text" : message
  };
  var payload = JSON.stringify(jsonData);

  var options =
  {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload
  };

  UrlFetchApp.fetch(postUrl, options);
}

これでもう一度公開しなおします。

Project versionはNewを選択しないと正しくデプロイされないらしいのでNewを選択します。

LINEでもう一度メッセージを送ってみます。

このとき、Raspberry Piで忘れずにslackbotを起動しておきましょう。

Slackで応答があれば完成です!

エアコンもしっかりと反応しました。

あとは実用的な運用にするために、LINEのオウム返しを止めて、Raspberry PiからLINE Notifyに通知を飛ばせば良いでしょう。

LINE BOTの機能を使えばこのようなこともできます。
適当に作ったので文字や画像がずれているのは気にしないでください・・・

ちなみに食事のボタンは以前作成した「今日のご飯は?」スキルです。
LINE Notifyから返信されるようにしています。

Raspberry PiとAlexaでオリジナルスキルを作る 「今日のご飯は?」
Raspberry PiとAlexaでオリジナルスキルを作るRaspberry PiとAlexaでオリジナルスキルを作ります。今日のご飯は?Alexaに「今日のご飯は?」と聞くと、メニューをランダムに提...

LINE BOTが他人に友達登録されると・・・?

LINE BOTが他人に友達登録されると家電を勝手に操作されてしまいます。
LINE BOTの取り扱いにはご注意ください。

以上、LINE BOTで家電を操作する方法でした。

コメント

タイトルとURLをコピーしました