3mannennhosii2 が 2024年10月28日09時56分44秒 に編集
コメント無し
本文の変更
目次 -- 1. 概要 1. アイデアの詳細 1. 使用部品 1. 参考文献 概要 --- ラズベリーパイ4と開閉スイッチを使用してドアの開閉の検知、ドアが開いた場合には録画の開始、一定期間ドアが開いていればブザーでの警告とスマホへの送信をすることによって注意を促すことができる。これにより遠隔監視、侵入検知が可能になります。 ![キャプションを入力できます](https://camo.elchika.com/99893ca68e51f1745466456df84311077399eac8/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38383737316534312d373834652d343662372d393466652d3163333535323865643336342f30346233383562342d303030652d343730612d626137642d643766653139333366383733/) アイデアの詳細 --- ・監視機能:開閉スイッチを使用してドアの開閉の検知 ・アラート機能:45秒以上ドアが開いているのを検知するとブザーでの警告とLEDを点滅させる ・記録機能:監視機能が反応するとカメラを使って録画を開始、ドアが閉まるまで録画を続ける ・通知機能:ドアが開いた際にスマホに通知、一定以上開いていたら閉まっていないことの通知 ・削除機能:録画した動画が多すぎると重くなるので一定期間経過した動画を削除する ラズパイと接続した磁気センサーの入った開閉スイッチをドアと壁に設置します。ドアが開いた場合にスマホにLINE Notifyを使い開いたことの通知を行い、ラズパイで録画をはじめドアが閉まるまで撮影を続けます。 ++追記 LINE Notifyでは録画した動画の送信はできなかったため代案としてスマホアプリでVNCを入れWifi機能を利用することによって直接確認をするか、Google Driveに保存することによって確認をすることができる++ 使用部品 --- ・ラズベリーパイ4 ・磁気センサー ・ラズパイカメラ ・ブザー ・LED ソースコード ---
```import threading import RPi.GPIO as GPIO import sys import os import cv2 from picamera2 import MappedArray, Picamera2 import datetime import shutil import time from picamera2.encoders import H264Encoder import subprocess import requests # LINE Notify送信のために追加 from datetime import datetime, timedelta # ファイル削除用に追加
# GPIOの設定 GPIO.setmode(GPIO.BCM)
# ピン番号の設定 LED1 = 27 # GPIO 27 DOOR_PIN = 18 # ドア開閉スイッチ BUZZER_PIN = 23 # ブザー # GPIOピンの設定 GPIO.setup(LED1, GPIO.OUT) # LED 出力設定 GPIO.setup(DOOR_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(BUZZER_PIN, GPIO.OUT) # 録画回数(リビジョン)を管理 revision_counter = 0 # 初期リビジョンを0に設定 # Line Notify設定 LINE_NOTIFY_TOKEN = "YOUR_LINE_NOTIFY_TOKEN" # ここにLINE Notifyのトークンを入力 LINE_NOTIFY_API = 'https://notify-api.line.me/api/notify' # Line Notify送信関数 def send_line_notify(message): headers = { 'Authorization': f'Bearer {LINE_NOTIFY_TOKEN}' } payload = {'message': message} response = requests.post(LINE_NOTIFY_API, headers=headers, params=payload) print(f"LINE Notify Response: {response.status_code}, {response.text}") # 録画ファイルの削除関数 (15分経過した .mp4 ファイルを削除) def delete_old_videos(directory, max_age_minutes=15): now = time.time() max_age_seconds = max_age_minutes * 60 for filename in os.listdir(directory): file_path = os.path.join(directory, filename) # 拡張子が .mp4 のファイルのみを対象とする if os.path.isfile(file_path) and file_path.endswith('.mp4'): file_age_seconds = now - os.path.getmtime(file_path) if file_age_seconds > max_age_seconds: print(f"削除対象: {file_path} (経過時間: {file_age_seconds}秒)") os.remove(file_path) # 録画ファイルの監視スレッド(1分おきに15分以上経過したファイルを削除) def video_cleanup_watcher(): while True: delete_old_videos("/home/pi/sentinel", max_age_minutes=15) time.sleep(60) # 1分おきに監視 # カメラ録画関数 def camera01(): global DOOR_PIN, revision_counter # グローバル変数宣言 print("CAMERA START") # カメラスタートをターミナルに表示 try: camera = Picamera2() # PiCamera2()をcameraで宣言 camera.configure(camera.create_video_configuration()) camera.configure(camera.create_preview_configuration(main={"format": 'XRGB8888', "size": (640, 480)})) # 解像度640×480で設定 # タイムスタンプを追加 colour = (0, 255, 0) # タイムスタンプの色を設定 origin = (0, 30) font = cv2.FONT_HERSHEY_SIMPLEX scale = 1 thickness = 2 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, colour, thickness) camera.pre_callback = apply_timestamp encoder = H264Encoder(10000000) # エンコーダの設定 # 保存先ディレクトリを確認・作成 os.makedirs("/home/pi/sentinel", exist_ok=True) # 録画ファイル名にタイムスタンプとリビジョンを追加 timestamp = time.strftime("%Y%m%d_%H%M%S") revision_counter += 1 # リビジョンをインクリメント h264_file_path = f"/home/pi/sentinel/DoorIsOpen_{timestamp}_rev{revision_counter}.h264" mp4_file_path = f"/home/pi/sentinel/DoorIsOpen_{timestamp}_rev{revision_counter}.mp4" camera.start_recording(encoder, h264_file_path) # 録画開始 # ドアが開いている間録画を続ける while GPIO.input(DOOR_PIN) == 0: GPIO.output(LED1, True) # LED点灯 camera.stop_recording() # ドアが閉まったら録画停止 camera.close() # カメラをクローズしてリソース解放 print("録画を終了しました") # H264をMP4に変換 (subprocess.runでエラーチェックを追加) result = subprocess.run(['/usr/bin/MP4Box', '-add', h264_file_path, mp4_file_path], capture_output=True, text=True) # MP4Boxのエラーを確認 if result.returncode != 0: print(f"MP4Boxエラー: {result.stderr}") raise RuntimeError(f"MP4Boxによる変換に失敗しました。") # MP4ファイルが存在するか確認 if not os.path.exists(mp4_file_path): raise FileNotFoundError(f"{mp4_file_path} が見つかりません。変換に失敗しました。") # 元の.h264ファイルを削除 os.remove(h264_file_path) GPIO.output(LED1, False) # LED消灯 print(f"録画ファイルが保存されました: {mp4_file_path}") return mp4_file_path except Exception as e: print(f"Error in camera recording: {e}") return None # LED点灯スレッド 録画時に点灯する def ledmain(): global stopstr1 stopstr1 = " " last_buzzer_time = 0 # ブザーのタイマー door_open_start_time = None # ドアが開いた時間を初期化 door_was_open = False # ドアの状態を記録 notified_open = False # 「ドアが開いています」を送信したかどうか notified_open_long = False # 「ドアが開いたままです」を送信したかどうか while True: if stopstr1 != " ": GPIO.cleanup() print("ドア監視終了") sys.exit() current_time = time.time() # ドアが開いているかチェック door_open = GPIO.input(DOOR_PIN) == 0 if door_open: if door_open_start_time is None: door_open_start_time = current_time # ドアが開いた時間を記録 if not door_was_open: # 状態が変わった場合のみ通知 print("ドアが開いています") door_was_open = True notified_open = False notified_open_long = False GPIO.output(LED1, True) # LEDを点灯 # ドアが開いたことを通知(まだ通知していない場合) if not notified_open: send_line_notify("ドアが開いています") notified_open = True # 45秒以上開いている場合に「ドアが開いたままです」を通知(まだ通知していない場合) if current_time - door_open_start_time > 45 and not notified_open_long: send_line_notify("ドアが開いたままです") notified_open_long = True # 10秒以上開いていると45秒ごとにブザーを鳴らす if current_time - last_buzzer_time > 45 and current_time - door_open_start_time > 10: GPIO.output(BUZZER_PIN, GPIO.HIGH) # ブザーを鳴らす time.sleep(0.5) GPIO.output(BUZZER_PIN, GPIO.LOW) last_buzzer_time = current_time # 録画処理 video_file = camera01() if video_file: print(f"録画ファイルが作成されました: {video_file}") else: if door_was_open: # ドアが閉まったときだけ通知 print("ドアが閉まりました") GPIO.output(LED1, False) # LEDを消灯 door_open_start_time = None # ドアが閉まったらリセット door_was_open = False # ドアが閉まったことを記録 notified_open = False notified_open_long = False time.sleep(1) # 処理を1秒ごとに制御し、頻度を抑える # プログラム終了時の割り込み入力処理 def stopinput(): global stopstr1 stopstr1 = input() # キー入力待ち # スレッドの開始 stop_thread = threading.Thread(target=stopinput) stop_thread.start() led_thread = threading.Thread(target=ledmain) led_thread.start() # 録画ファイルの監視スレッドの開始 cleanup_thread = threading.Thread(target=video_cleanup_watcher) cleanup_thread.start() # スレッドの終了を待つ stop_thread.join() led_thread.join() cleanup_thread.join() # GPIOのクリーンアップ GPIO.cleanup() ```
参考文献 --- > https://monomonotech.jp/kurage/raspberrypi/daiso_sensorlight.html [](url)