【ホームセキュリティ】ラズパイで人感センサ式の監視カメラを作成する

2024/02/23

Discord HC-SR501 IoT ラズパイ

  • B!

今回は人感センサ「HC-SR501」を使用して監視カメラを作っていきます。

今回使用するもの

  • RaspberryPi
  • HC-SR501
  • ジャンプワイヤ
  • DiscordWebhook URL
  • GoogleDrive API

実現したい動き

HC-SR501が人体を検知する
WEBカメラで画像を撮影する

撮影した画像に日時透かしを入れる
編集した画像をGoogleDriveにアップロード
Discordに画像のURLを送信する

ラズパイのディレクトリ構成

/home/pi/Desktop/Detect_Camera/
    |_____Data
    |          |_____yyyy_mm_dd_H_M_S.jpg (アップロード用の画像)
    |_____Sample.py (今回作成するプログラム)
    |_____detect.jpg (編集前の画像)
    |_____credentials.json
    |_____client_secret.json
    |_____settings.yaml

サンプルコード

import cv2
from PIL import Image, ImageDraw, ImageFont
import datetime
from pydrive2.auth import GoogleAuth
from pydrive2.drive import GoogleDrive
import requests, json
import time
import RPi.GPIO as GPIO

SENSOR_GPIO = 14
GPIO.setmode(GPIO.BCM)
GPIO.setup(SENSOR_GPIO, GPIO.IN)

def upload():
    gauth = GoogleAuth()
    gauth.LocalWebserverAuth()
    drive = GoogleDrive(gauth)
    folder_id = 'GoogleDriveのフォルダID'
    file_path = 'Data/' + dt_name
    file = drive.CreateFile({'title': dt_name, 'parents': [{'id': folder_id}]})
    file.SetContentFile(file_path)
    file.Upload()
    img_url = '<https://drive.google.com/uc?id=' + str(file['id'] + '>')

    webhook_url = 'DiscordWebhook URL'
    main_content = {'content': '[Motion Detected]\n' + str(dt_txt) + '\n' + img_url,
                    'username': 'Attention'}
    headers = {'Content-Type': 'application/json'}
    response = requests.post(webhook_url, json.dumps(main_content), headers=headers)

    print('Uploaded', img_url)

f_name = 'detect.jpg'
font_path = "/usr/share/fonts/truetype/ipafont-nonfree-uigothic/ipagui.ttf"
try:
    while True:
        status = GPIO.input(SENSOR_GPIO)
        if (status == GPIO.HIGH):
            #print('detect')
            
            #撮影
            capture = cv2.VideoCapture(0)
            ret, frame = capture.read()
            cv2.imwrite(f_name, frame)
            capture.release()
            
            im = Image.open(f_name)
            font = ImageFont.truetype(font_path, 20)
            draw = ImageDraw.Draw(im)
            dt_name = str(datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S') + '.jpg')
            
            #画像の上部に日付の透かしを入れる
            dt_txt = str(datetime.datetime.now().replace(microsecond=0))
            draw.multiline_text((10,10), dt_txt, font=font, fill=(255, 255, 255, 255), stroke_width=2,stroke_fill=(0, 0, 0, 255))
            im.save('Data/' + dt_name)
            
            upload()
            cv2.destroyAllWindows()
            im.close()
            time.sleep(1)
            
        else:
            time.sleep(1)

except KeyboardInterrupt:
    print("Cleanup")
    GPIO.cleanup()

実行結果

人が検知されると画像が撮影されてGoogleDriveにアップロードされます。

次にDiscordに画像が撮影されたという通知とともにアップロードした画像のURLが送られてきます。

URLをタップするとGoogleDriveの画像に直接アクセスできます。

画像の保存も可能です。

まとめ

今回はsleep時間を1秒にしていますが「画像の撮影」と「アップロード」に時間がかかってしまい、撮影してから再撮影できるまで1秒以上かかってしまいます。

RaspberryPi4(8GB)を使ってもラグが出るのでRaspberryPi Zeroを使って低消費電力化するともっとラグが出ると思われます。

GoogleDriveにアップロードするときに認証する時間がかかっているので画像を直接Discordに送信するようにするとラグは減少すると考えられます。

しかし、複数回画像が撮影された場合、通知とチャンネルの中が埋め尽くされてしまいます。

撮影した画像を別のラズパイに送信して、そのラズパイがGoogleDriveにアップロードするようにするといいかもしれません。

Ranking

Community

Search