]> www.vanbest.org Git - motioneye-debian/commitdiff
email notifications have now event pictures attached
authorCalin Crisan <ccrisan@gmail.com>
Tue, 19 Aug 2014 10:55:44 +0000 (13:55 +0300)
committerCalin Crisan <ccrisan@gmail.com>
Tue, 19 Aug 2014 10:58:08 +0000 (13:58 +0300)
motioneye.py
sendmail.py
settings_default.py
src/config.py
src/mediafiles.py
templates/main.html

index 8a3b4923bbab061d746416445691b0f604e2c177..0da299c495b04d84d631167b9622f2c8b59e9afd 100755 (executable)
@@ -60,7 +60,9 @@ def _configure_settings():
     set_default_setting('WPA_SUPPLICANT_CONF', None)
     set_default_setting('LOCAL_TIME_FILE', None)
     set_default_setting('ENABLE_REBOOT', False)
-    
+    set_default_setting('SMTP_TIMEOUT', 60)
+    set_default_setting('NOTIFY_MEDIA_TIMESPAN', 5)
+
     length = len(sys.argv) - 1
     for i in xrange(length):
         arg = sys.argv[i + 1]
index 3216867f624613b1fa6e3f292618c5d973ed5791..de0dda87ef317517da6ab82dce1b121f3114e3b1 100755 (executable)
 import datetime
 import logging
 import os
+import re
 import smtplib
 import socket
 import sys
+import time
 
+from email import Encoders
 from email.mime.text import MIMEText
+from email.MIMEMultipart import MIMEMultipart
+from email.MIMEBase import MIMEBase
+from tornado.ioloop import IOLoop
 
 import settings
 
-from motioneye import _configure_settings, _configure_logging
+from motioneye import _configure_settings, _configure_logging, _configure_signals
 
 _configure_settings()
+_configure_signals()
 _configure_logging()
 
 import config
+import mediafiles
 import tzctl
 
 
@@ -45,7 +53,7 @@ subjects = {
 }
 
 
-def send_mail(server, port, account, password, tls, to, subject, message):
+def send_mail(server, port, account, password, tls, to, subject, message, files):
     conn = smtplib.SMTP(server, port, timeout=getattr(settings, 'SMTP_TIMEOUT', 60))
     if tls:
         conn.starttls()
@@ -55,40 +63,65 @@ def send_mail(server, port, account, password, tls, to, subject, message):
     
     _from = account or 'motioneye@' + socket.gethostname()
     
-    email = MIMEText(message)
+    email = MIMEMultipart()
     email['Subject'] = subject
     email['From'] = _from
     email['To'] = to
+    email.attach(MIMEText(message))
     
+    for file in reversed(files):
+        part = MIMEBase('application', 'image/jpg')
+        with open(file, 'rb') as f:
+            part.set_payload(f.read())
+        
+        Encoders.encode_base64(part)
+        part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file))
+        email.attach(part)
+    
+    if files:
+        logging.debug('attached %d pictures' % len(files))
+
     conn.sendmail(_from, to, email.as_string())
     conn.quit()
 
 
-def format_message(subject, message, camera_id, moment):
-    format_dict = {
-        'camera': config.get_camera(camera_id)['@name'],
-        'hostname': socket.gethostname(),
-        'moment': moment.strftime('%Y-%m-%d %H:%M:%S'),
-    }
+def make_message(subject, message, camera_id, moment, callback):
+    camera_config = config.get_camera(camera_id)
     
-    if settings.LOCAL_TIME_FILE:
-        format_dict['timezone'] = tzctl.get_time_zone()
+    def on_media_files(media_files):
+        timestamp = time.mktime(moment.timetuple())
+
+        media_files = [m for m in media_files if abs(m['timestamp'] - timestamp) < settings.NOTIFY_MEDIA_TIMESPAN] # filter out non-recent media files
+        media_files.sort(key=lambda m: m['timestamp'], reverse=True)
+        media_files = [os.path.join(camera_config['target_dir'], re.sub('^/', '', m['path'])) for m in media_files]
+
+        format_dict = {
+            'camera': camera_config['@name'],
+            'hostname': socket.gethostname(),
+            'moment': moment.strftime('%Y-%m-%d %H:%M:%S'),
+        }
+        
+        if settings.LOCAL_TIME_FILE:
+            format_dict['timezone'] = tzctl.get_time_zone()
+        
+        else:
+            format_dict['timezone'] = 'local time'
     
-    else:
-        format_dict['timezone'] = 'local time'
-
-    message = message % format_dict
-    subject = subject % format_dict
-    subject = subject.replace('\n', ' ')
-
-    message += '\n\n'
-    message += 'motionEye.'
+        m = message % format_dict
+        s = subject % format_dict
+        s = s.replace('\n', ' ')
+    
+        m += '\n\n'
+        m += 'motionEye.'
+        
+        callback(s, m, media_files)
 
-    return (subject, message)
+    time.sleep(settings.NOTIFY_MEDIA_TIMESPAN)
+    mediafiles.list_media(camera_config, media_type='picture', callback=on_media_files)
 
 
 def print_usage():
-    print 'Usage: sendmail.py <server> <port> <account> <password> <tls> <to> <msg_id> <camera_id> <moment>'
+    print 'Usage: sendmail.py <server> <port> <account> <password> <tls> <to> <msg_id> <camera_id> <moment> <frames>'
 
 
 if __name__ == '__main__':
@@ -113,8 +146,35 @@ if __name__ == '__main__':
         sys.exit(-1)
     
     moment = datetime.datetime.strptime(moment, '%Y-%m-%dT%H:%M:%S')
-    subject, message = format_message(subject, message, camera_id, moment)
     
-    send_mail(server, port, account, password, tls, to, subject, message)
+    logging.debug('server = %s' % server)
+    logging.debug('port = %s' % port)
+    logging.debug('account = %s' % account)
+    logging.debug('password = ******')
+    logging.debug('server = %s' % server)
+    logging.debug('tls = %s' % tls)
+    logging.debug('to = %s' % to)
+    logging.debug('msg_id = %s' % msg_id)
+    logging.debug('camera_id = %s' % camera_id)
+    logging.debug('moment = %s' % moment.strftime('%Y-%m-%d %H:%M:%S'))
+    logging.debug('smtp timeout = %d' % settings.SMTP_TIMEOUT)
     
-    logging.info('message sent.')
+    io_loop = IOLoop.instance()
+    
+    def on_message(subject, message, files):
+        try:
+            send_mail(server, port, account, password, tls, to, subject, message, files)
+            logging.info('email sent')
+        
+        except Exception as e:
+            logging.error('failed to send mail: %s' % e, exc_info=True)
+
+        io_loop.stop()
+    
+    def ioloop_timeout():
+        io_loop.stop()
+    
+    make_message(subject, message, camera_id, moment, on_message)
+
+    io_loop.add_timeout(datetime.timedelta(seconds=settings.SMTP_TIMEOUT), ioloop_timeout)
+    io_loop.start()
index 961738827f27e091399acf4602eea93ba34aff21..54cc9241dedd281235f132b47affeec53084078b 100644 (file)
@@ -70,3 +70,6 @@ ENABLE_REBOOT = False
 
 # the timeout in seconds to use when talking to a SMTP server
 SMTP_TIMEOUT = 60
+
+# the interval in seconds to consider around the moment of the event when attaching media files to notifications 
+NOTIFY_MEDIA_TIMESPAN = 5
index d27371a964c6cfa19cee8c80ea616fdf706c1d9e..1bc5668e8ad5a73ff60b3428e4a8ff14e80f61b1 100644 (file)
@@ -700,8 +700,8 @@ def camera_ui_to_dict(ui):
         send_mail_path = os.path.abspath(send_mail_path)
         
         emails = re.sub('\\s', '', ui['motion_notifications_emails'])
-        
-        on_event_start.append('%(script)s %(server)s %(port)s %(account)s %(password)s %(tls)s %(to)s motion_start %%t %%Y-%%m-%%dT%%H:%%M:%%S' % {
+
+        on_event_start.append('%(script)s "%(server)s" "%(port)s" "%(account)s" "%(password)s" "%(tls)s" "%(to)s" "motion_start" "%%t" "%%Y-%%m-%%dT%%H:%%M:%%S"' % {
                 'script': send_mail_path,
                 'server': ui['smtp_server'],
                 'port': ui['smtp_port'],
@@ -933,7 +933,7 @@ def camera_dict_to_ui(data):
     
     for e in on_event_start:
         if e.count('sendmail.py') and e.count('motion_start'):
-            e = e.split(' ')
+            e = e.replace('"', '').split(' ')
             if len(e) != 10:
                 continue
 
index d3b5ab00c41dfa20bdbea19ec42e8759437c143d..1b09d628fe26938e4e721ba1638edfac00decf6a 100644 (file)
@@ -27,7 +27,6 @@ import tornado
 from PIL import Image
 
 import config
-import mjpgclient
 import settings
 import utils
 
@@ -94,7 +93,7 @@ def _list_media_files(dir, exts, prefix=None):
                     continue
                 
                 media_files.append((full_path, st))
-        
+
     return media_files
 
 
@@ -288,7 +287,7 @@ def list_media(camera_config, media_type, callback, prefix=None):
             callback(media_list)
     
     poll_process()
-    
+
 
 def get_media_content(camera_config, path, media_type):
     target_dir = camera_config.get('target_dir')
@@ -344,6 +343,8 @@ def get_media_preview(camera_config, path, media_type, width, height):
 
 
 def get_current_picture(camera_config, width, height):
+    import mjpgclient
+
     jpg = mjpgclient.get_jpg(camera_config['@id'])
     
     if jpg is None:
index 61f38f8f779740833d5044f9918809b0cfc3d20b..62484dd4d25da96f5d99e03f84441108b8d7b5b9 100644 (file)
                     <tr class="settings-item advanced-setting">
                         <td class="settings-item-label"><span class="settings-item-label">Use TLS</span></td>
                         <td class="settings-item-value"><input type="checkbox" class="styled notifications" id="smtpTlsSwitch"></td>
-                        <td><span class="help-mark" title="enable this if your SMTP server requires TLS (Gmail works either way)">?</span></td>
+                        <td><span class="help-mark" title="enable this if your SMTP server requires TLS (Gmail needs this to be enabled)">?</span></td>
                     </tr>
                 </table>