1. 概要
LINE Messaging APIで特定のメッセージを送信すると、扉が施錠か開錠される
鍵の状態が変化するとカメラで鍵を撮影し施錠、開錠のメッセージとともに画像を返信する
3. アイデアの詳細
• 施錠したいとき…LINE Messaging APIで「施錠」や「鍵閉めて」などのキーワードを送信する
• 開錠したいとき…LINE Messaging APIで「開錠」や「鍵開けて」などのキーワードを送信する
• サーボモータで鍵の状態が変化するとカメラで撮影する
• 開錠したか施錠したかを知らせるメッセージとともに撮影した画像を返信する
4. 必要となるもの
• Raspberry Pi 4
• サーボモータ(SG90)
• python(今回はver3.9.2、開発環境はThonny)
• ngrok Raspberry Piでのインストール
• Pi camera
• LINE Messaging API v3 (pythonでは3.9以上が必要)
ngrokとLINE Messaging API v3については参考文献をご覧ください。
6. ソースコード
カメラで動画をとってjpegとmp4で保存することはできたのですが、画像をテキストメッセージと同時に返信することができませんでした。返信がきても鍵がかかっているかどうか不安になることがあると思うので改善していきたいです。
メインのプログラム
import pigpio, requests, datetime
import RPi.GPIO as GPIO
from picamera2 import MappedArray, Picamera2
from picamera2.encoders import H264Encoder
import time, sys, io, cv2, shutil
import threading, os
from argparse import ArgumentParser
from flask import Flask, request, abort
from linebot.v3 import (
WebhookHandler
)
from linebot.v3.messaging import (
Configuration,
ApiClient,
MessagingApi,
)
from linebot.v3.exceptions import (
InvalidSignatureError
)
from linebot.v3.messaging import (
Configuration,
ApiClient,
MessagingApi,
ReplyMessageRequest,
TextMessage
)
from linebot.v3.webhooks import (
MessageEvent,
TextMessageContent
)
app = Flask(__name__)
# チャンネルシークレットとチャンネルアクセストークンの登録
channel_secret = 'シークレットトークンを記入する'
channel_access_token = "アクセストークンを記入する"
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)
configuration = Configuration(access_token=channel_access_token)
handler = WebhookHandler(channel_secret)
SERVO = 18 # サーボモータのピン番号
LED1 = 17 # LED
PIR = 4 # モーションセンサー
GPIO.setwarnings(False) # 警告を無視
GPIO.setmode(GPIO.BCM) # GPIOのピン番号で指定する
GPIO.setup(LED1, GPIO.OUT) # LED1 出力指定
GPIO.setup(PIR, GPIO.IN) # PIR 入力指定
# pigpioを初期化
pi = pigpio.pi()
# サーボモーターを特定の角度に設定する関数
def set_angle(angle):
assert 0 <= angle <= 180, '角度は0から180の間で指定する'
pulse_width = (angle / 180) * (2500 - 500) + 500
pi.set_servo_pulsewidth(SERVO, pulse_width)
open_message = ["あけて", "開けて", "鍵開けて"]
close_message = ["閉めて", "しめて", "締めて", "鍵閉めて"]
def open_key():
set_angle(0)
time.sleep(1)
set_angle(90)
time.sleep(1)
print("開けました")
def close_key():
set_angle(0)
time.sleep(1)
set_angle(90)
time.sleep(1)
print("締めました")
@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=TextMessageContent)
def handle_message(event):
with ApiClient(configuration) as api_client:
line_bot_api = MessagingApi(api_client)
if event.message.text in open_message:
open_key()
response_text = "鍵を開けました"
camera01() # 録画開始
elif event.message.text in close_message:
close_key()
response_text = "鍵を閉めました"
camera01() # 録画開始
else:
response_text = "認識できないメッセージです"
webhook_url = "https://Webhookに入力したリンク" #
image_url = "/var/www/html/movie/servo_img.mp4"
line_bot_api.reply_message_with_http_info(
ReplyMessageRequest(
reply_token=event.reply_token,
messages=[TextMessage(text=response_text)]
)
)
def camera01():
print("CAMERA START")
camera = Picamera2()
camera.configure(camera.create_video_configuration())
camera.configure(camera.create_preview_configuration(main={"format": 'XRGB8888', "size": (640, 480)}))
color = (0, 255, 0) # タイムスタンプの色を設定
origin = (0, 30)
font = cv2.FONT_HERSHEY_SIMPLEX
scale = 1
thickness = 2
camera.start_and_capture_file("timestamp.jpg")
def apply_timestamp(request):
timestamp = time.strftime("%Y-%m-%d %X") # タイムスタンプのフォーマットを設定
with MappedArray(request, "main") as m:
cv2.putText(m.array, timestamp, origin, font, scale, color, thickness)
camera.pre_callback = apply_timestamp
encoder = H264Encoder(10000000)
camera.start_recording(encoder, "timestamped.h264") # 録画開始
time.sleep(1) # 録画時間
camera.stop_recording() # 録画終了
os.system('/usr/bin/MP4Box -add timestamped.h264 timestamped.mp4') # mp4に変換
shutil.move("./timestamped.mp4", "/var/www/html/movie/")
os.rename("/var/www/html/movie/timestamped.mp4", f"/var/www/html/movie/servo_img.mp4") # 録画データのファイル名変更
camera.close() # カメラ停止処理
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)
LINEから送信したメッセージが開錠と施錠するためのキーワードが格納されている配列のopen_messageとclose_messageの文字列と一致すると、サーボモータが開錠するopen_keyと施錠するclose_keyを実行します。カメラの動作は、camera01で処理しています。その他は参考文献をご覧ください。
7. 参考文献
-
takechi
さんが
2024/09/20
に
編集
をしました。
(メッセージ: 初版)
-
takechi
さんが
2024/09/20
に
編集
をしました。
-
takechi
さんが
2024/10/30
に
編集
をしました。
-
takechi
さんが
2024/10/30
に
編集
をしました。
ログインしてコメントを投稿する