それ、ラズパイでつくれるよ
それ、ラズパイでつくれるよ——スマホから家の鍵を開けられるよ!
「Raspberry Pi」の活用例を紹介する連載企画「それ、ラズパイでつくれるよ」。第13回はLINEボットにメッセージを送ることで、鍵のサムターンをサーボモータで回せるようにしてみよう。
ただいまって言えてますか?
独り暮らしをしているfabcrossのわくわくライターの淺野さんは寂しがっていた。
昨今は外出や人と会うこともままならず、家にいても独り。たまの買い物から帰ってきても、玄関に向かってさえ声に出して「ただいま」と言えないそうだ。
それ、ラズパイでなんとかしてあげたい。そこで今回はLINE Messaging APIを利用して、ラズパイ上で動くLINEボットへ「ただいま」と送ることでサーボモーターを回し、ドアの鍵を開けるシステムを作る。
システム構成概要
今回構築するシステムの概要図は以下の通り。
用意するのは以下のもの。
- ラズパイ(今回はRaspberry Pi 4を利用した)
- サーボモーター(GWSのラジコン向けサーボを利用した)
- ガムテープ
LINE Messaging APIの設定
まずはLINE Messaging APIを利用してボットを作成するための設定をしていく。
LINE DevelopersコンソールのMessaging APIページへアクセスし、「今すぐはじめよう」をクリック。
LINEアカウントでログインする。アカウントを持っていない場合は作成しておこう。初めてログインした場合は開発者アカウントの作成も続けて行うことになる。
次にプロバイダーを作成する。何も考えずに「Create a new provider」をクリック。
好きな組織名で作成しよう。
プロバイダーができたら、チャネルを作成する。今回はMessaging APIチャネルだ。
名前やアイコンなど必要な情報を入力すると、
チャネルが作成され、Messaging APIタブのBot InformationにあるQRコードを使って友達に追加できるようになる。読みこんで友達追加しておこう。
ラズパイ上でLINEボットアプリを動かすためには「チャネルシークレット」と「チャネルアクセストークン」が必要となる。それぞれ、Basic settingsタブのBasic Information、Messaging API SettingsタブのChannel Access Tokenで発行することができるので、確認しておく。
これでAPIの設定はいったん終了だ。
Webhookの設定
次にラズパイでWebhookを受け取るための準備をする。コンソールを開いて、とりあえず、
$ sudo apt-get update
と入力して、先ほど確認しておいたチャネルシークレットとチャネルアクセストークンを環境変数として設定する。YOUR_LINE_CHANNEL_SECRETとYOUR_LINE_CHANNEL_ACCESS_TOKENを、先ほど確認したものに適宜変更して設定しよう。
$ export LINE_CHANNEL_SECRET= YOUR_LINE_CHANNEL_SECRET
$ export LINE_CHANNEL_ACCESS_TOKEN= YOUR_LINE_CHANNEL_ACCESS_TOKEN
ラズパイが再起動した後に再度設定するのは面倒なので、.profileに同じコマンドを追記しておこう。
$ nano .profile
ラズパイ上で動くLINEボットがWebhookを受け取れるようにするために、ngrokというラズパイ上で稼働するネットワークサービスを無料で外部公開できるサービスを利用する。
Webブラウザーで公式Webサイトにアクセスし、「Get started for free」をクリック。
アカウント登録もしくはログインして、Linux(ARM)版をダウンロードしよう。
あとは「Setup & Installation」に従って、ターミナルからzipファイルを解凍して実行ファイルを作成。
$ unzip /path/to/ngrok-stable-linux-arm.zip
アカウントとひも付ければ利用可能だ。YOUR_AUTHTOKENはブラウザーに表示されているものに適宜変更する。
$ ./ngrok authtoken YOUR_AUTHTOKEN
次のコマンドでngrokを起動するとlocalhost:8080に対して外部からアクセスできるランダムなサブドメインを持ったURLが発行される。8080はポート番号と呼ばれる数字で、よく分からなければ何も考えず8080にしておけば問題ない。
$ ./ngrok http 8080
表示されたForwardingのURLのうち、httpsのものを確認したら、
ブラウザーのLINE Developersコンソールに戻り、Messaging APIタブのWebhook settingsからWebhook URLで/callbackを最後に付け足す(ここ重要)
設定はこれで完了だ。
サーボモーターをつないで鍵開けボットを作る
第6回でも登場しているサーボモーターは以下のようにラズパイと接続しよう。
サムターンとの接続は、淺野さんの得意分野でもある3Dプリントで作製した。ガムテープにサーボモーターをマウントする部品と、サムターンとサーボモーターの回転部分を接続する部品がある。
ガムテープやマジックテープを駆使してサムターン付近に設置すれば、家族に鍵を開けてもらえる感覚を味わえる。
ラズパイの画面に戻って、myservo.pyとしてpythonスクリプトを以下のように作成する。
import RPi.GPIO as GPIO import time from argparse import ArgumentParser def main(degree): print(degree) servo_pin = 18 GPIO.setmode(GPIO.BCM) GPIO.setup(servo_pin, GPIO.OUT) servo = GPIO.PWM(servo_pin, 50) servo.start(0.0) servo.ChangeDutyCycle(float(degree)) time.sleep(1.0) GPIO.cleanup() if __name__ == "__main__": arg_parser = ArgumentParser( usage='Usage: python ' + __file__ + ' [--d]' ) arg_parser.add_argument('-d', '--degree', default=7.0, help='degree') options = arg_parser.parse_args() main(degree=options.degree)
できたら、
$ python3 myservo.py -d XXX(数字)
として、XXXに任意の数字を入れて起動するとサーボモーターがウイーと回る。いくつか試して解錠状態と施錠状態の数字を確認しておく。参考に、淺野さんちのサムターンではそれぞれ6.5と10.5であった。これらの確認が終わったらsesame.pyとしてpythonスクリプトを以下のように作成する。SERVO_OPEN_STATEとSERVO_CLOSE_STATEを確認した数字に変更しておこう。
import RPi.GPIO as GPIO import time import os import sys from argparse import ArgumentParser from flask import Flask, request, abort from linebot import ( LineBotApi, WebhookHandler ) from linebot.exceptions import ( InvalidSignatureError ) from linebot.models import ( MessageEvent, TextMessage, TextSendMessage, ) app = Flask(__name__) # チャンネルシークレットとチャンネルアクセストークンの登録 channel_secret = os.getenv('LINE_CHANNEL_SECRET', None) channel_access_token = os.getenv('LINE_CHANNEL_ACCESS_TOKEN', None) if channel_secret is None: print('Specify LINE_CHANNEL_SECRET as environment variable.') sys.exit(1) if channel_access_token is None: print('Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.') sys.exit(1) line_bot_api = LineBotApi(channel_access_token) handler = WebhookHandler(channel_secret) # サーボモータを回す関数の登録 SERVO_PIN = 18 SERVO_OPEN_STATE = YYY(開錠状態) SERVO_CLOSE_STATE = ZZZ(施錠状態) def KeyOpener(): GPIO.setmode(GPIO.BCM) GPIO.setup(SERVO_PIN, GPIO.OUT) servo = GPIO.PWM(SERVO_PIN, 50) servo.start(0.0) servo.ChangeDutyCycle(SERVO_OPEN_STATE) time.sleep(1.0) GPIO.cleanup() def KeyCloser(): GPIO.setmode(GPIO.BCM) GPIO.setup(SERVO_PIN, GPIO.OUT) servo = GPIO.PWM(SERVO_PIN, 50) servo.start(0.0) servo.ChangeDutyCycle(SERVO_CLOSE_STATE) time.sleep(1.0) GPIO.cleanup() @app.route("/callback", methods=['POST']) def callback(): signature = request.headers['X-Line-Signature'] body = request.get_data(as_text=True) app.logger.info("Request body: " + body) try: handler.handle(body, signature) except InvalidSignatureError: abort(400) return 'OK' @handler.add(MessageEvent, message=TextMessage) def message_text(event): text = event.message.text # テキストの内容で条件分岐 if text == 'ただいま': # 鍵開ける KeyOpener() # 返事 line_bot_api.reply_message( event.reply_token, TextSendMessage('おかえり〜 鍵開けといたよ') ) elif text == '行ってきます': # 鍵閉める KeyCloser() # 返事 line_bot_api.reply_message( event.reply_token, TextSendMessage('いってらっしゃい 鍵閉めといたよ') ) else: # 木霊 line_bot_api.reply_message( event.reply_token, TextSendMessage(text=event.message.text) ) if __name__ == "__main__": arg_parser = ArgumentParser( usage='Usage: python ' + __file__ + ' [--port] [--help]' ) arg_parser.add_argument('-p', '--port', default=8000, help='port') arg_parser.add_argument('-d', '--debug', default=False, help='debug') options = arg_parser.parse_args() app.run(debug=options.debug, port=options.port)
最後に、ngrokが起動しているターミナルとは別にもうひとつターミナルを開き、sesame.pyを起動しておく。外出前に鍵を開けてほしい家族をセットしておけば準備完了だ。
ただいま!
あ、淺野さんが外出先から帰ってきたようだ。
玄関前で「ただいま」と送信すれば、
家族が優しく鍵を開けてくれる。
淺野さんも家族も挨拶できて気分が良さそうで何より。
今回はLINEボットにメッセージを送ることで、ラズパイに家の鍵を開けてもらう方法を紹介した。タクトスイッチを追加して内側からは簡単に開けられるようにしたり、リードスイッチを追加してオートロック機能を追加したり、まだまだできることはたくさんあると思う。思い思いの方法で機能を追加してぜひ自分だけのスマートロックを作ってみてほしい。
※このコーナーでは、みなさんの「それ、ラズパイでつくれるよ」をお待ちしています。問い合わせフォームからドシドシご応募ください。
新型コロナウイルス感染拡大防止のため、fabcross編集部では、記事作成にあたって
極力テレビ会議アプリやメッセージアプリなどを利用しています。
また、ものづくりや対面での取材が伴う記事では、社会的距離を取り、接触を避けるなどの配慮をしています。