Motion – envoyer les videos sur Google Drive

J’ai mit en place Motion sur ma Raspberry PI pour faire un système de vidéo surveillance qui enregistre une vidéo uniquement lorsqu’il y a un mouvement.

Pour cela, j’ai installé Raspbian sur ma Raspberry PI puis le packet motion après avoir branché une webcam compatible en USB.

Pour que le script fonctionne, vous devez installer ffmpeg et python-gdata.

  • ffmpeg - Multimedia player, server, encoder and transcoder (transitional package)
    • Je l’utilise pour ré-encoder l’avi généré
  • python-gdata - Google Data Python client library

Descriptions des fichiers utilisé

/etc/motion/motion.conf

Fichier de configuration du daemon motion.

  • videodevice : indiquer votre webcam
  • v4l2_palette : la palette à utiliser (17 correspond a celle pour une PlayStation Eye)
  • target_dir : est l’emplacement ou la vidéo sera écrite, dans mon cas, je la met sur mon NAS pour ne pas utiliser la SD-CARD
  • on_movie_end : commande a exécuter dés qu’une vidéo est écrite.

/home/pascal/bin/motion_upload.sh

Ce petit script ré-encode la vidéo puis lance uploader.py

/home/pascal/bin/uploader.py

Script écrit par Jeremy Blythe que j’ai corrigé, il avait fait une boucle sur tous les fichiers de votre google drive pour vérifier que le dossier de destination existe, j’ai remplacé cela par une recherche via gdata

/home/pascal/bin/uploader.conf

Fichier de configuration du script Python à completer avec vos identifiants Google.

N’oubliez pas de définir la variable folder avec le " dossier " Google Drive de destination

Les fichiers de configurations et scripts

/etc/motion/motion.conf - sans patch mmalcam

process_id_file /var/run/motion/motion.pid
setup_mode off
logfile /tmp/motion.log
log_level 5
log_type all
videodevice /dev/video0
v4l2_palette 17
input 8
norm 0
frequency 0
rotate 0
width 1024
height 576
framerate 2
minimum_frame_time 0
netcam_tolerant_check off
auto_brightness on
brightness 0
contrast 0
saturation 0
hue 0
roundrobin_frames 1
roundrobin_skip 1
switchfilter off
threshold 1500
threshold_tune on
noise_level 32
noise_tune on
despeckle_filter EedDl
despeckle EedDl
smart_mask_speed 0
lightswitch 0
minimum_motion_frames 1
pre_capture 2
post_capture 2
gap 60
max_mpeg_time 600
output_all off
output_normal first
output_motion off
quality 100
ppm off
ffmpeg_output_movies on
ffmpeg_output_debug_movies off
ffmpeg_cap_new on
ffmpeg_cap_motion off
ffmpeg_timelapse 0
ffmpeg_timelapse_mode daily
ffmpeg_bps 500000
ffmpeg_variable_bitrate 0
ffmpeg_video_codec mpeg4
ffmpeg_deinterlace off
snapshot_interval 0
locate on
text_right %Y-%m-%d\n%T-%q
text_changes off
text_event %Y%m%d%H%M%S
text_double on
target_dir /media/nas/Private/motion/rpiB01
snapshot_filename %Y-%m-%d_%H%M%S-%v-snapshot
jpeg_filename %Y-%m-%d_%H%M%S-%v-%q
movie_filename %Y-%m-%d_%H%M%S-%v-%q
timelapse_filename %Y-%m-%d_timelapse
webcam_port 8080
webcam_quality 75
webcam_motion off
webcam_maxrate 1
webcam_localhost on
webcam_limit 0
control_port 0
control_localhost on
control_html_output on
track_type 0
track_auto off
track_iomojo_id 0
track_step_angle_x 10
track_step_angle_y 10
track_move_wait 10
track_speed 255
track_stepsize 40
quiet on
on_movie_end /home/pascal/bin/motion_upload.sh %f
night_compensate on
sql_log_image on
sql_log_snapshot on
sql_log_mpeg off
sql_log_timelapse off
sql_query insert into security(camera, filename, frame, file_type, time_stamp, event_time_stamp) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C')
ipv6_enabled

/etc/motion/motion.conf - avec patch mmalcam

process_id_file /var/run/motion/motion.pid
setup_mode off
logfile /tmp/motion.log
log_level 5
log_type all
# videodevice /dev/video0
v4l2_palette 17
input -1
norm 0
frequency 0
rotate 180
width 1024
height 576
framerate 2
minimum_frame_time 0
netcam_tolerant_check off
auto_brightness on
brightness 0
contrast 0
saturation 0
hue 0
mmalcam_name vc.ril.camera
mmalcam_use_still off
roundrobin_frames 1
roundrobin_skip 1
switchfilter off
threshold 1500
threshold_tune on
noise_level 32
noise_tune on
despeckle_filter EedDl
despeckle EedDl
smart_mask_speed 0
lightswitch 0
minimum_motion_frames 1
pre_capture 2
post_capture 2
event_gap 60
max_movie_time 600
output_all off
output_normal first
output_motion off
quality 100
ppm off
ffmpeg_output_movies on
ffmpeg_output_debug_movies off
ffmpeg_cap_new on
ffmpeg_cap_motion off
ffmpeg_timelapse 0
ffmpeg_timelapse_mode daily
ffmpeg_bps 500000
ffmpeg_variable_bitrate 0
ffmpeg_video_codec mpeg4
ffmpeg_deinterlace off
snapshot_interval 0
locate on
text_right %Y-%m-%d\n%T-%q
text_changes off
text_event %Y%m%d%H%M%S
text_double on
target_dir /media/nas/Private/motion/rpiB02
snapshot_filename %Y-%m-%d_%H%M%S-%v-snapshot
picture_filename %Y-%m-%d_%H%M%S-%v-%q
movie_filename %Y-%m-%d_%H%M%S-%v-%q
timelapse_filename %Y-%m-%d_timelapse
stream_port 8080
stream_quality 75
stream_motion off
stream_maxrate 1
stream_localhost on
stream_limit 0
webcontrol_port 0
webcontrol_localhost on
webcontrol_html_output on
track_type 0
track_auto off
track_iomojo_id 0
track_step_angle_x 10
track_step_angle_y 10
track_move_wait 10
track_speed 255
track_stepsize 40
quiet on
on_movie_end /home/pascal/bin/motion_upload.sh %f
night_compensate on
sql_log_image on
sql_log_snapshot on
sql_log_mpeg off
sql_log_timelapse off
sql_query insert into security(camera, filename, frame, file_type, time_stamp, event_time_stamp) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C')
ipv6_enabled off

/home/pascal/bin/motion_upload.sh


FILE=$(echo $1 | cut -d'.' -f1 ); do

/usr/bin/avconv -i "$FILE.avi" -vcodec mpeg4 -an -preset fast "$FILE.mp4" 1>/dev/null 2>&1
rm $FILE.avi
/home/pascal/bin/uploader.py /home/pascal/bin/uploader.conf $FILE.mp4 && rm $FILE.mp4

/home/pascal/bin/uploader.py

''
Created on 6 Jun 2012
odified on 10 Jan 2014

@author: Jeremy Blythe
@author: Pascal A.

otion Uploader - uploads videos to Google Drive

Read the blog entry at http://jeremyblythe.blogspot.com and/or http://notes.depad.fr for more information
''

import smtplib
from datetime import datetime

import os.path
import sys

import gdata.data
import gdata.docs.data
import gdata.docs.client
import ConfigParser

class MotionUploader:
    def __init__(self, config_file_path):
        # Load config
        config = ConfigParser.ConfigParser()
        config.read(config_file_path)

        # GMail account credentials
        self.username = config.get('gmail', 'user')
        self.password = config.get('gmail', 'password')
        self.from_name = config.get('gmail', 'name')
        self.sender = config.get('gmail', 'sender')

        # Recipient email address (could be same as from_addr)
        self.recipient = config.get('gmail', 'recipient')

        # Subject line for email
        self.subject = config.get('gmail', 'subject')

        # First line of email message
        self.message = config.get('gmail', 'message')

        # Folder (or collection) in Docs where you want the videos to go
        self.folder = config.get('docs', 'folder')

        # Options
        self.delete_after_upload = config.getboolean('options', 'delete-after-upload')
        self.send_email = config.getboolean('options', 'send-email')

        self._create_gdata_client()

    def _create_gdata_client(self):
        """Create a Documents List Client."""
        self.client = gdata.docs.client.DocsClient(source='motion_uploader')
        self.client.http_client.debug = False
        self.client.client_login(self.username, self.password, service=self.client.auth_service, source=self.client.source)

    def _get_folder_resource(self):
        """Return the resource for given folder."""

        # Create a query matching exactly a title, and include collections
        q = gdata.docs.client.DocsQuery(
            title=self.folder,
            title_exact='true',
            show_collections='true
            )
        # Execute the query and get the first entry
        resource = self.client.GetResources(q=q).entry[0]

        if resource.title.text == self.folder:
            col = resource
        return col

    def _send_email(self,msg):
        '''Send an email using the GMail account.''
        senddate=datetime.strftime(datetime.now(), '%Y-%m-%d')
        m="Date: %s\r\nFrom: %s <%s>\r\nTo: %s\r\nSubject: %s\r\nX-Mailer: My-Mail\r\n\r\n" % (senddate, self.from_name, self.sender, self.recipient, self.subject)
        server = smtplib.SMTP('smtp.gmail.com:587')
        server.starttls()
        server.login(self.username, self.password)
        server.sendmail(self.sender, self.recipient, m+msg)
        server.quit()

    def _upload(self, video_file_path, folder_resource):
        '''Upload the video and return the doc''
        doc = gdata.docs.data.Resource(type='video', title=os.path.basename(video_file_path))
        media = gdata.data.MediaSource()
        media.SetFileHandle(video_file_path, 'video/mp4')
        doc = self.client.CreateResource(doc, media=media, collection=folder_resource)
        return doc

    def upload_video(self, video_file_path):
        """Upload a video to the specified folder. Then optionally send an email and optionally delete the local file."""
        folder_resource = self._get_folder_resource()
        if not folder_resource:
            raise Exception('Could not find the %s folder' % self.folder)

        doc = self._upload(video_file_path, folder_resource)

        if self.send_email:
            video_link = None
            for link in doc.link:
                if 'video.google.com' in link.href:
                    video_link = link.href
                    break
            # Send an email with the link if found
            msg = self.message
            if video_link:
                msg += '\n\n' + video_link
            self._send_email(msg)

        if self.delete_after_upload:
            os.remove(video_file_path)

if __name__ == '__main__':
    try:
        if len(sys.argv) < 3:
            exit('Motion Uploader - uploads videos to Google Drive\n   by Jeremy Blythe (http://jeremyblythe.blogspot.com)\n\n   Usage: uploader.py {config-file-path} {video-file-path}')
        cfg_path = sys.argv[1]
        vid_path = sys.argv[2]
        if not os.path.exists(cfg_path):
            exit('Config file does not exist [%s]' % cfg_path)
        if not os.path.exists(vid_path):
            exit('Video file does not exist [%s]' % vid_path)
        MotionUploader(cfg_path).upload_video(vid_path)
    except gdata.client.BadAuthentication:
        exit('Invalid user credentials given.')
    except gdata.client.Error:
        exit('Login Error')
    except Exception as e:
        exit('Error: [%s]' % e)

/home/pascal/bin/uploader.conf

[gmail]
# GMail account credentials
name =
user =
password =
sender =

# Recipient email address (could be same as from_addr)
recipient =

# Subject line for email
subject = Motion detected

# First line of email message
message = Video uploaded

[docs]
# Folder (or collection) in Docs where you want the videos to go
folder = motion

[options]
# Delete the local video file after the upload
delete-after-upload = true

# Send an email after the upload
send-email = true

Article basé sur http://jeremyblythe.blogspot.com


Suggestions de lecture :

comments powered by Disqus