気の向くままに辿るIT/ICT/IoT
IoT・電子工作

IPカメラから映像配信通知を受信・動画/画像としてサーバに保存

ホーム前へ次へ
Raspberry Piって?

IPカメラから映像配信通知を受信・動画/画像としてサーバに保存

IPカメラから映像配信通知を受信・動画/画像としてサーバに保存

2022/07/16

 IPカメラ|ネットワークカメラとしてのボタン押下でディープスリープから復帰する技適対応ESP32-WROVER+OV2640 CAMからのストリーム配信中の通知を受信し、Raspberry Pi上のPython/OpenCVでストリーム映像・フレーム画像を保存してみた話。

 自作見守りカメラ|定点カメラ|監視|防犯|ドアカメラ用であり、超高機能な監視カメラシステムZoneMinderの使用を想定していましたが、Raspberry Pi 3B+には荷が重そうなこともあり、ドアカメラの代替策の一環として。

 ネットワークカメラ|IPカメラと言っても市販の完成品ではなく、プログラム可能なWiFi搭載カメラ付きESP32-WROVER-DEVボードのようなマイコンだからこそ成せる技。

 このマイコン、通常はスリープ状態、ボタン押下で復帰、一定時間ストリーム配信、その通知までを行なうわけですが、これを受けてラズベリーパイによるカメラサーバに保存するスクリプトを作るのが、この記事のゴールです。

 更に同時にスマホなどのLINEやメールアドレスに動画や画像付きで通知を送るように仕込めば、応対はできないまでも、外出先(遠隔地)からであっても、ほぼリアルタイムで来訪者を確認できますね。

ESP32-WROVER-DEV+OV2640カメラの配信通知を受けて映像・画像をPython+OpenCVで保存

USER@raspberrypi:~ $ cat save_as_video_image_esp32_wrover_cam_stream.py
#!/usr/bin/env python3
 
import cv2
import time
import socket
import datetime
from contextlib import closing
 
#REC_UDP_IP = '0.0.0.0'
REC_UDP_IP = ''
REC_UDP_PORT = 9998
REC_MESSAGE = espcam1
 
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
sock.bind((REC_UDP_IP, REC_UDP_PORT))
 
with closing(sock):
  
  while True:
    now = datetime.datetime.now()
    nowifn = "work/" + REC_MESSAGE + "_" + now.strftime('%Y%m%d_%H%M%S') + '.png'
    nowvfn = "work/" + REC_MESSAGE + "_" + now.strftime('%Y%m%d_%H%M%S') + '.mp4'
    cap = cv2.VideoCapture(f"http://esp32_wrover_cam.local:81/stream")
    number = len(str(int(cap.get(cv2.CAP_PROP_FRAME_COUNT))))
    
    # 動画ファイル保存用の設定
    fps = int(cap.get(cv2.CAP_PROP_FPS))
    w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
    video = cv2.VideoWriter(nowvfn, fourcc, fps, (w, h))
 
    data, addr = sock.recvfrom(1024)
    n = 0  
    print("Send from ESP", addr, ":", data)
    str_data = data.decode("utf-8", errors="ignore")
    str_data = str_data[:str_data.find('\x00\r')]
    print("After trim : ", str_data)
 
    if ( str_data == 'REC_MESSAGE' and n == 0 ):
      otime = time.time()
      while True:
        ret, frame = cap.read()
        if ret:
          cv2.imwrite(nowifn.format(str(n).zfill(number)), frame)
        #cv2.imshow('frame',frame)
        video.write(frame)
        ntime = time.time()
        if ntime - otime >= 6:
          print("ntime - otime == ", ntime - otime)
          video.release()
          break
    n += 1
    print("n == ", n)
 
    time.sleep(1)
USER@raspberrypi:~ $ chmod +x save_as_video_image_esp32_wrover_cam_stream.py
USER@raspberrypi:~ $ ./save_as_video_image_esp32_wrover_cam_stream.py
USER@raspberrypi:~ $

 ESP32-WROVER+OV2640カメラボードからUDP経由で時間制限付きのストリーム配信中の通知を受けるごとに受信メッセージと日付時刻を使ったファイル名で画像(png)、映像(mp4)を保存します。

 WiFi通信には、UDPを使っています。

 自身も同ボードをとりあえず4つ買いましたが、同様のカメラが複数ある場合は、分岐するなど、もうちょっと工夫が必要です。

[2023/08/04]

 どうやら、このESP32-WROVERカメラボードの技適番号の刻印はESP32-WROOM用で偽装のようなので、世界で唯一、カメラ付きESP32で技適を通っているらしきFreenoveが販売している2種の内の1つ、技適番号201-220052の方であるカメラ付きESP32-S3-WROOM-1開発ボードを買いました。

 呼び出したい方法にも関わってきますが、スクリプトには、shebang(#!/usr/bin/env pythonとか)を入れて、実行権限も与えておくと良いでしょう。

 ちなみにESP32-WROVERボードのスケッチ上は、ブラウザなどからIP_ADDR_OR_mDNSでもアクセスはできるようにはなっていますが、ストリームは専有されてしまうので当該スクリプトが動いている時は、アクセスできません。

 もちろん、検証中などで当該スクリプトを実行せずにESPボード側でボタンを押せば、一定時間、ブラウザからアクセスすることはできますが。

 ブラウザなどから任意のタイミングでアクセスしたい場合には、常時配信のカメラを使うと良いでしょう。

 尚、なんらかの工夫次第なのか、それでも専有するので、やはり、複数同時にアクセスすることはできませんが。

2023/08/21

 数秒の遅延はあるものの、RTSP/RTPで複数のクライアントに同時にストリーミングできるようになりました。

systemdサービスファイル

 常駐させる(デーモン化する)べく、systemdサービスファイルを作ります。

USER@raspberrypi:~ $ pwd
/home/USER
USER@raspberrypi:~ $ cat save_my_ipcam_stream.sh
#!/bin/sh
 
/home/USER/save_as_video_image_esp32_wrover_cam_stream.py &
USER@raspberrypi:~ $ chmod +x save_my_ipcam_stream.sh
USER@raspberrypi:~ $

 が、サービスファイルから呼ぶスクリプトは、どうもpythonファイルではなく、shellスクリプトが良さげ。

 よって今回は、先のpythonスクリプトを呼ぶだけのシェルスクリプトを作って、これをsystemdサービスファイルから呼ぶことにします。

 ちなみにpythonスクリプトを直接呼んでみたら、systemctl startでプロンプトが返ってこなくなりました(いや、何十年か!?待ってれば返ってきたのかも...)。

USER@raspberrypi:~ $ cat /etc/systemd/system/save_esp32_wrover_cam_stream.service
[Unit]
Description=Save ESP32-WROVER CAM stream with notice as movie and frame image service
Wants=network-online.target
After=network-online.target
 
[Service]
Type=oneshot
ExecStart=/bin/su - USER /bin/sh -c "/home/USER/save_my_ipcam_stream.sh"
 
[Install]
WantedBy=multi-user.target
USER@raspberrypi:~ $ sudo systemctl enable save_esp32_wrover_cam_stream.service
USER@raspberrypi:~ $ sudo systemctl start save_esp32_wrover_cam_stream.service
USER@raspberrypi:~ $

 常駐(≒デーモン化)すべく、systemdのサービスファイルを自作します。

 長年正常に機能している自作スマートスピーカーで作ったサービスファイルをコピーして作れば良かったかな...ということで作ってみたのがこれ。

 試してみたら、動画も画像も指定の場所に保存されたので大丈夫でしょう。

 尚、保存しっぱなしでは、著しくストレージを圧迫、終いにはパンクするのでcronで定期的に削除しておくと良いでしょう。

ホーム前へ次へ