#背景
おうちハックの一つとして、スマートロックがあります。
先人の例
Raspberry Piでスマートロックをつくった
アキバに行ったときに900円でジャンク品のFelicaリーダ(SONY RC-S330)が売っていたので筆者も作ってみました。
スマートロックシステムついに完成 pic.twitter.com/vZSmr9icfz
— ふな (@funaki_0814) 2018年9月3日
ICカードを読み取り機にかざすことでサーボモータが回転して鍵が開け締めできるようになりました。
これだけだと面白くないのでアプリから操作できるようにしたいなーと思ったけどいちからアプリ作ると開発コストかかりそうなので身近なLINE使って操作できないかやってみました。
#使ったもの
##ハード
・Raspberry Pi 3 Model B
・サーボモータ(SG92R)
・LINEがインストールされたスマフォ
##ソフト
・Python3
・LINE Messaging API
・ngrok
#手順
##LINE Messaging APIのセットアップ
https://developers.line.me/ja/
にてLINEアカウントでログインします。
プロバイダーリストが出てくるので新規で適当に名前つけてプロバイダーを作成します。
新規チャネル→Messaging APIから操作用のLINEチャネルを作成します。
プランはdeveloper trialで良いかと
このような画面になります。下の方にあるQRコードで友だち追加出来ます。
Channel Secretとアクセストークンは後で使うのでメモしときます。
##Raspberry Piのセットアップ
LINE Messaging APIをngrok経由でRaspberry Pi 3で使ってみる(サンプルbot編)
このサイトが詳しいので、Raspberry PiにLINE API側からアクセスするためのngrok、各種SDKをセットアップします。
セットアップ後、先程追加したアカウントに話しかけてみてオウム返しができればOKです。
##特定のキーワードに反応してサーボモータを回す。
https://github.com/line/line-bot-sdk-python/blob/master/examples/flask-echo/app.py
を少し改良して、特定のキーワードに反応してサーボモータを回転させるようにします。
# -*- coding: utf-8 -*-
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import unicode_literals
import os
import sys
import function
from argparse import ArgumentParser
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookParser
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
app = Flask(__name__)
# get channel_secret and channel_access_token from your environment variable
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)
parser = WebhookParser(channel_secret)
@app.route("/callback", methods=['POST'])
def callback():
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# parse webhook body
try:
events = parser.parse(body, signature)
except InvalidSignatureError:
abort(400)
# if event is MessageEvent and message is TextMessage, then echo text
for event in events:
if not isinstance(event, MessageEvent):
continue
if not isinstance(event.message, TextMessage):
continue
message = event.message.text
reply = event.message.text
if message.count('開錠'):
function.unlock()
reply = "開錠しました"
elif message.count('施錠'):
function.lock()
reply = "施錠しました"
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=reply)
)
return 'OK'
if __name__ == "__main__":
arg_parser = ArgumentParser(
usage='Usage: python ' + __file__ + ' [--port <port>] [--help]'
)
arg_parser.add_argument('-p', '--port', type=int, 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)
モータを回転させるための関数
# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
import time
# 鍵をかけるようにモータを回転
def lock():
GPIO.setmode(GPIO.BCM)
GPIO.setup(gp_out, GPIO.OUT)
servo = GPIO.PWM(gp_out, 50)
servo.start(0.0)
servo.ChangeDutyCycle(9.5)
time.sleep(0.5)
GPIO.cleanup()
# 鍵をあけるようにモータを回転
def unlock():
GPIO.setmode(GPIO.BCM)
GPIO.setup(gp_out, GPIO.OUT)
servo = GPIO.PWM(gp_out, 50)
servo.start(0.0)
servo.ChangeDutyCycle(5.5)
time.sleep(0.5)
GPIO.cleanup()
これで再度app.pyを実行して、先程のアカウントに開錠or施錠と話すとモータが作動します。
##リッチメニューの作成
よくLINE@のアカウントだとリッチメニューが使えたりします。
↓こんなの
開錠、施錠っていちいち送るの面倒くさいのでワンタップで送れるようにします。
https://admin-official.line.me/
LINE@Managerにログインします。作ったアカウントが表示されています。
サイドメニューのリッチコンテンツ作成→リッチメニューから新規作成でリッチメニューを作成します。
ボタンの数を選択し、デザインガイドにそってメニューを作成します。
ボタンを押したときに送ってほしいテキストを設定します。
これで再度LINEを開くと、リッチメニューが表示されるようになります。
#できたもの
LINEで操作できるようにした pic.twitter.com/BtJk7rqfn1
— ふな (@funaki_0814) 2018年9月30日
#まとめ
・LINE Messaging APIのサンプルが充実していたので思ったより簡単に出来た。
・ngrokのおかげでAPIからルータ超えしてRaspberry Piへアクセスしやすかった。
問題点としては友だち追加してれば誰でも鍵開けられるのと、ngrokのURLが起動するたびにかわるのでいちいちAPI側に設定し直さないといけないことですかね・・・
そのうち証明書取得してRaspberry Piにダイレクトにアクセスできるようにしたいです。