3mannennhosii2のアイコン画像
3mannennhosii2 2024年09月30日作成 (2024年10月30日更新)
製作品 製作品 閲覧数 48
3mannennhosii2 2024年09月30日作成 (2024年10月30日更新) 製作品 製作品 閲覧数 48

Sentinel Watch

Sentinel Watch

目次

  1. 概要
  2. アイデアの詳細
  3. 特徴
  4. 使用部品
  5. ソースコード
  6. 現状・今後
  7. 参考文献

概要

ラズベリーパイ4と開閉スイッチを使用してドアの開閉の検知、ドアが開いた場合には録画の開始、一定期間ドアが開いていればブザーでの警告とスマホへの送信をすることによって注意を促すことができる。これにより遠隔監視、侵入検知が可能になります。

キャプションを入力できます

アイデアの詳細

・監視機能:開閉スイッチを使用してドアの開閉の検知
・アラート機能:45秒以上ドアが開いているのを検知するとブザーでの警告とLEDを点滅させる
・記録機能:監視機能が反応するとカメラを使って録画を開始、ドアが閉まるまで録画を続ける
・通知機能:ドアが開いた際にスマホに通知、一定以上開いていたら閉まっていないことの通知
・削除機能:録画した動画が多すぎると重くなるので一定期間経過した動画を削除する
ラズパイと接続した磁気センサーの入った開閉スイッチをドアと壁に設置します。ドアが開いた場合にスマホにLINE Notifyを使い開いたことの通知を行い、ラズパイで録画をはじめドアが閉まるまで撮影を続けます。

追記
LINE Notifyでは録画した動画の送信はできなかったため代案としてスマホアプリでVNCを入れWifi機能を利用することによって直接確認をするか、Google Driveに保存することによって確認をすることが可能

特徴

このシステムはドアが開いたとき限定で反応するシステムなので常に監視できるわけではありませんが、反応した際にはスマホに通知を行い動画の確認もすることが可能です。そのため、何かあった場合にはすぐに確認や対応することを可能となります。

使用部品

・ラズベリーパイ4
・磁気センサー(ドア開閉スイッチ)
・ラズパイカメラ
・ブザー
・LED

ソースコード

Sentinel Watchのソースコードになります。今回は、GPIO18ピンとグランドに接続してドア開閉スイッチを使用しました。削除機能の時間は今回は一時間に設定しています。

Sentinel

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) GPIO.setup(DOOR_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(BUZZER_PIN, GPIO.OUT) # 録画回数(リビジョン)を管理 revision_counter = 0 # Line Notify設定 LINE_NOTIFY_TOKEN = "YOUR_LINE_NOTIFY_TOKEN" 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}") # 録画ファイルの削除関数 (1時間経過した .mp4 ファイルを削除) def delete_old_videos(directory, max_age_minutes=60): 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分おきに60分以上経過したファイルを削除) def video_cleanup_watcher(): while True: delete_old_videos("/home/pi/sentinel", max_age_minutes=15) time.sleep(60) # カメラ録画関数 def camera01(): global DOOR_PIN, revision_counter print("CAMERA START") try: camera = Picamera2() camera.configure(camera.create_video_configuration()) camera.configure(camera.create_preview_configuration(main={"format": 'XRGB8888', "size": (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) # ドアが開いたことを通知(まだ通知していない場合) 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 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) door_open_start_time = None door_was_open = False notified_open = False notified_open_long = False time.sleep(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()

プログラムの動きとしては、ドアを開閉した際に磁気センサーが反応して信号を送ることによって開閉の検知、その際にLINE Notifyに「ドアが開きました」と送信。もし、45秒以上ドアが開いているなら続いて「ドアが開いたままです」と送信するのに加えてLEDの点滅やブザーでの警告も行っています。
録画の部分は動画の順番がわかりやすいように番号を付けています。削除は一分ごとにファイルの監視を行い一時間以上経過した動画は削除するようにしています。

現状・今後

現状ドアの開閉の検知や監視機能・録画機能・削除機能ともに動作できていますが、LINE Notifyでの録画した動画の送信についてはできないため、Google Driveを使用した動画の保存を試そうと考えています。そのため現状は代案の一つ目のVNCアプリとWifi機能を使用しての動作の確認になります。

参考文献

https://monomonotech.jp/kurage/raspberrypi/daiso_sensorlight.html

3mannennhosii2のアイコン画像
3万円ほしいです>=======Σ
ログインしてコメントを投稿する