概要
ラズパイ4でpythonとOpenCVを使い、USBカメラの撮影画像を保存できることが判りましたので、今度はインターネット経由で撮影画像をレンタルサーバーに自動でアップロードします。
次回、遠隔でこれらの画像をブラウザーで確認できるちょっとした監視の仕組を作ってみたいと思っています。
pythonでFTPファイル転送
撮影した画像をサーバーにアップロードする為に FTP(File Transfer Protocol) を使います。調査時、FTP転送は暗号化されていない等のセキュレティ的リスクに関する記述をみましたが、今回はFTPでアップロードすることにします。いずれSFTP 等のより安全な方法についても確認したいと思います。
python で、FTP転送を行う為の ”ftplib” という標準ライブラリ を使います。次の python プログラムは、ラズパイから私が借りているレンタルサーバーに jpeg ファイルをアップロードし、アップロードしたファイルを再びダウンロードするものです。今回はダウンロードしない予定ですが、いつか使うこともあると思って確認しました。サーバー,ユーザー,パスワード等は、“*” で表示しています。
import ftplib
host_name = '**********' # サーバーホスト名
user_name = '**********' # ユーザー名
user_pass = '**********' # パスワード
svr_d_pth = '/**********/**********/' # ファイル転送パス
def ftp_upload( src_f_pth , tgt_f_name , svr_pth):
ftp=ftplib.FTP( host_name )
ftp.set_pasv( 'true' )
ftp.login( user_name , user_pass )
ftp.cwd( svr_pth )
f = open( src_f_pth , 'rb' ) # rb:バイナリ,r:テキスト
ftp.storbinary('STOR ' + tgt_f_name, f )
ftp.close()
f.close()
def ftp_download( src_f_pth , tgt_f_name , svr_pth):
ftp=ftplib.FTP( host_name )
ftp.set_pasv( 'true' )
ftp.login( user_name , user_pass )
ftp.cwd( svr_pth )
f = open( src_f_pth , 'wb' )
ftp.retrbinary('RETR ' + tgt_f_name, f.write )
ftp.close()
f.close()
# 転送元ファイルパス, 転送後ファイル名, サーバー側ディレクトリ
ftp_upload('./template4.jpg','test.jpg',svr_d_pth)
# ダウンロードファイルパス, ダウンロードファイル名, サーバー側ディレクトリ
ftp_download('./dwn_test.jpg','test.jpg',svr_d_pth)
撮影写真をFTPアップロード
次の python プログラムは、写真撮影・保存後・保存したファイルをサーバーにFTPアップロードします。
import ftplib
import sys
import cv2
import datetime
host_name = '**********' # サーバーホスト名
user_name = '**********' # ユーザー名
user_pass = '**********' # パスワード
svr_d_pth = '/**********/**********/' # ファイル転送パス
def ftp_upload( src_f_pth , tgt_f_name , svr_pth):
ftp=ftplib.FTP( host_name )
ftp.set_pasv( 'true' )
ftp.login( user_name , user_pass )
ftp.cwd( svr_pth )
f = open( src_f_pth , 'rb' ) # rb:バイナリ,r:テキスト
ftp.storbinary('STOR ' + tgt_f_name, f )
ftp.close()
f.close()
def ftp_download( src_f_pth , tgt_f_name , svr_pth):
ftp=ftplib.FTP( host_name )
ftp.set_pasv( 'true' )
ftp.login( user_name , user_pass )
ftp.cwd( svr_pth )
f = open( src_f_pth , 'wb' )
ftp.retrbinary('RETR ' + tgt_f_name, f.write )
ftp.close()
f.close()
capture = cv2.VideoCapture(0)
try:
if capture.isOpened() is False:
print("カメラを開けませんでした。")
sys.exit()
ret, frame = capture.read()
if( ret == True ):
now = datetime.datetime.now()
now_str = now.strftime('%Y%m%d_%H%M%S')
up_fpth = "./ftp_img/" + now_str + ".jpg"
cv2.imwrite( up_fpth , frame)
ftp_upload( up_fpth , now_str + ".jpg" ,svr_d_pth)
else:
print("Err_image_capture")
capture.release()
cv2.destroyAllWindows()
except:
print("Error:",sys.exc_info()[0])
print(sys.exc_info()[1])
import traceback
print(traceback.format_tb(sys.exc_info()[2]))
# 転送元ファイルパス, 転送後ファイル名, サーバー側ディレクトリ
# ftp_upload('./template4.jpg','test.jpg',svr_d_pth)
#
# ダウンロードファイルパス, ダウンロードファイル名, サーバー側ディレクトリ
# ftp_download('./dwn_test.jpg','test.jpg',svr_d_pth)
下記はサーバー側のファイル状況です。ラズパイ側でプログラムを1回起動すると、1ファイル転送されます。撮影日時がファイル名から判ります。

CRONで一定間隔でFTPアップロード
CRONを使って、一定間隔で python プログラムを実行し、レンタルサーバーにファイルをアップロードします。実行結果は次の通り、2分間隔でファイルがアップロードされていることが確認できました。幾つか設定したことなどを書き留めておきます。

① crontab 編集
下記の通りターミナルで、“crontab -e” を入力。初回のみどのエディッターを使うか確認される様です。1の “nano” エディッターを選択しました。「easiest (一番簡単)」と書かれているからで、特に根拠はありません。

エディッターが開きます。最下段2行が今回追加した行です。
下記は最終的に書いた内容で、途中試行錯誤がありましたので、1行目が絶対必要かは確認していません。要は日本語表記を使う宣言の様なものです。今回、どうしても日本語を使う必要性はないので、python プログラム内のコメントも含めた日本語表記は全て抹消しましたが、参考までに残しています。
また、ファイルパスはフルパス指定しないとエラーが出る様なので、python プログラムも含め修正しています。
2行目は2分に1回指定の python プログラムを実行する為の記載です。以前、centos7のテストをした時に記載方法を少し調べた記憶があります。
1行目:LANG=ja_JP.UTF-8
2行目:* /2 * * * * python3 /home/pi/sample_py2/ftp_03.py

② cronログ出力設定
システムログ制御の cronログ出力設定を確認します。この設定が cron 実行に絶対必要かは確認していませんが、ログを確認しエラー原因の特定には有効と思われます。

エディッターが開くので、スクロール,または検索して下記の箇所を探します。下図の場合、もし3行目の “cron” の前に“#”があり、コメントアウトされていたら、“#” を外し、下記の通り有効化し保存します。(下記は、有効化された状態)

③ cronログレベル設定
ターミナルから、“nano” エディッターを起動します。

ログレベルは設定内容の合計値で表す様です。
「EXTRA_OPT=”-L 15″」を設定します。合計値とすると、1,2,4,8 が設定していることになると思われます。

以上です。アップロードできるまで、少しづつ設定を追加しているので、どれが必ず必要なのかは理解していません。
cron アップロード用に変更したラズパイ側 python プログラムです。ファイル指定をフルパスに変更、日本語表記を抹消、FTPアップロード後、アップロード用に一時保存したファイルを都度抹消する処理を追加しました。
import ftplib
import sys
import cv2
import datetime
import os
host_name = '**********'
user_name = '**********'
user_pass = '**********'
svr_d_pth = '/**********/**********/'
def ftp_upload( src_f_pth , tgt_f_name , svr_pth):
ftp=ftplib.FTP( host_name )
ftp.set_pasv( 'true' )
ftp.login( user_name , user_pass )
ftp.cwd( svr_pth )
f = open( src_f_pth , 'rb' )
ftp.storbinary('STOR ' + tgt_f_name, f )
ftp.close()
f.close()
def ftp_download( src_f_pth , tgt_f_name , svr_pth):
ftp=ftplib.FTP( host_name )
ftp.set_pasv( 'true' )
ftp.login( user_name , user_pass )
ftp.cwd( svr_pth )
f = open( src_f_pth , 'wb' )
ftp.retrbinary('RETR ' + tgt_f_name, f.write )
ftp.close()
f.close()
capture = cv2.VideoCapture(0)
try:
if capture.isOpened() is False:
print("ERR_CAMERA_OPEN")
sys.exit()
ret, frame = capture.read()
if( ret == True ):
now = datetime.datetime.now()
now_str = now.strftime('%Y%m%d_%H%M%S')
up_fpth = "/home/pi/sample_py2/ftp_img/" + now_str + ".jpg"
cv2.imwrite( up_fpth , frame)
ftp_upload( up_fpth , now_str + ".jpg" ,svr_d_pth)
os.remove(up_fpth)
else:
print("Err_image_capture")
capture.release()
cv2.destroyAllWindows()
except:
print("Error:",sys.exc_info()[0])
print(sys.exc_info()[1])
import traceback
print(traceback.format_tb(sys.exc_info()[2]))
まとめ
ブラウザーで見る為のレンタルサーバー側の処理(PHPで作成予定)が出来ていませんが、とりえあず一定時間間隔で撮影した写真をFTPでアップロード出来ることは確認出来ました。
サーバー側にアップロードした写真も定期的に抹消する方法も検討しないといけません。(→明日の私に指示)