]> www.vanbest.org Git - motioneye-debian/commitdiff
added support for motion triggered web hooks
authorCalin Crisan <ccrisan@gmail.com>
Wed, 20 Aug 2014 12:00:22 +0000 (15:00 +0300)
committerCalin Crisan <ccrisan@gmail.com>
Wed, 20 Aug 2014 12:00:22 +0000 (15:00 +0300)
sendmail.py
src/config.py
static/js/main.js
templates/main.html
webhook.py [new file with mode: 0755]

index de0dda87ef317517da6ab82dce1b121f3114e3b1..4ecbcb51456967a09cb372502e8c381a14110d89 100755 (executable)
@@ -159,6 +159,10 @@ if __name__ == '__main__':
     logging.debug('moment = %s' % moment.strftime('%Y-%m-%d %H:%M:%S'))
     logging.debug('smtp timeout = %d' % settings.SMTP_TIMEOUT)
     
+    if not to:
+        logging.info('no email address specified')
+        sys.exit(0)
+
     io_loop = IOLoop.instance()
     
     def on_message(subject, message, files):
index 1bc5668e8ad5a73ff60b3428e4a8ff14e80f61b1..3bbaaf72f6c84fd3f3deac9e0bf4c0b9b26f4526 100644 (file)
@@ -695,20 +695,29 @@ def camera_ui_to_dict(ui):
         
         data['ffmpeg_bps'] = int(ui['movie_quality']) * max_val / 100
     
-    if ui['motion_notifications']:
+    if ui['email_notifications_enabled']:
         send_mail_path = os.path.join(settings.PROJECT_PATH, 'sendmail.py')
         send_mail_path = os.path.abspath(send_mail_path)
+        emails = re.sub('\\s', '', ui['email_notifications_addresses'])
         
-        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"' % {
                 'script': send_mail_path,
-                'server': ui['smtp_server'],
-                'port': ui['smtp_port'],
-                'account': ui['smtp_account'],
-                'password': ui['smtp_password'],
-                'tls': ui['smtp_tls'],
+                'server': ui['email_notifications_smtp_server'],
+                'port': ui['email_notifications_smtp_port'],
+                'account': ui['email_notifications_smtp_account'],
+                'password': ui['email_notifications_smtp_password'],
+                'tls': ui['email_notifications_smtp_tls'],
                 'to': emails})
+        
+    if ui['web_hook_notifications_enabled']:
+        web_hook_path = os.path.join(settings.PROJECT_PATH, 'webhook.py')
+        web_hook_path = os.path.abspath(web_hook_path)
+        url = re.sub('\\s', '+', ui['web_hook_notifications_url'])
+
+        on_event_start.append('%(script)s "%(method)s" "%(url)s"' % {
+                'script': web_hook_path,
+                'method': ui['web_hook_notifications_http_method'],
+                'url': url})
 
     if ui['working_schedule']:
         data['@working_schedule'] = (
@@ -937,15 +946,22 @@ def camera_dict_to_ui(data):
             if len(e) != 10:
                 continue
 
-            ui['motion_notifications'] = True 
-            ui['smtp_server'] = e[1]
-            ui['smtp_port'] = e[2]
-            ui['smtp_account'] = e[3]
-            ui['smtp_password'] = e[4]
-            ui['smtp_tls'] = e[5].lower() == 'true'
-            ui['motion_notifications_emails'] = e[6]
+            ui['email_notifications_enabled'] = True 
+            ui['email_notifications_smtp_server'] = e[1]
+            ui['email_notifications_smtp_port'] = e[2]
+            ui['email_notifications_smtp_account'] = e[3]
+            ui['email_notifications_smtp_password'] = e[4]
+            ui['email_notifications_smtp_tls'] = e[5].lower() == 'true'
+            ui['email_notifications_addresses'] = e[6]
+
+        elif e.count('webhook.py'):
+            e = e.replace('"', '').split(' ')
+            if len(e) != 3:
+                continue
 
-            break
+            ui['web_hook_notifications_enabled'] = True 
+            ui['web_hook_notifications_method'] = e[1]
+            ui['web_hook_notifications_url'] = e[2]
 
     working_schedule = data['@working_schedule']
     if working_schedule:
index 19c46c016fcd291aad83f7fc71a4fa03f0a81e3f..bc6855e0e952f7813223cfe0466d0fc98ffcce69 100644 (file)
@@ -217,6 +217,7 @@ function initUI() {
     makeTextValidator($('#smtpServerEntry'), true);
     makeTextValidator($('#smtpAccountEntry'), true);
     makeTextValidator($('#smtpPasswordEntry'), true);
+    makeTextValidator($('#webHookUrlEntry'), true);
     
     /* number validators */
     makeNumberValidator($('#streamingPortEntry'), 1024, 65535, false, false, true);
@@ -263,7 +264,8 @@ function initUI() {
     $('#preservePicturesSelect').change(updateConfigUi);
     $('#motionMoviesSwitch').change(updateConfigUi);
     $('#preserveMoviesSelect').change(updateConfigUi);
-    $('#motionNotificationsSwitch').change(updateConfigUi);
+    $('#emailNotificationsSwitch').change(updateConfigUi);
+    $('#webHookNotificationsSwitch').change(updateConfigUi);
     $('#workingScheduleSwitch').change(updateConfigUi);
     
     $('#storageDeviceSelect').change(function () {
@@ -471,11 +473,21 @@ function updateConfigUi() {
         $('#moviesLifetime').parents('tr:eq(0)').each(markHide);
     }
     
-    /* motion notifications switch */
-    if (!$('#motionNotificationsSwitch').get(0).checked) {
-        $('#motionNotificationsSwitch').parent().next('table.settings').find('tr.settings-item').each(markHide);
+    /* email notifications switch */
+    if (!$('#emailNotificationsSwitch').get(0).checked) {
+        $('#emailAddressesEntry').parents('tr:eq(0)').each(markHide);
+        $('#smtpServerEntry').parents('tr:eq(0)').each(markHide);
+        $('#smtpPortEntry').parents('tr:eq(0)').each(markHide);
+        $('#smtpAccountEntry').parents('tr:eq(0)').each(markHide);
+        $('#smtpPasswordEntry').parents('tr:eq(0)').each(markHide);
+        $('#smtpTlsSwitch').parents('tr:eq(0)').each(markHide);
     }
     
+    if (!$('#webHookNotificationsSwitch').get(0).checked) {
+        $('#webHookUrlEntry').parents('tr:eq(0)').each(markHide);
+        $('#webHookHttpMethod').parents('tr:eq(0)').each(markHide);
+    }
+
     /* working schedule switch */
     if (!$('#workingScheduleSwitch').get(0).checked) {
         $('#workingScheduleSwitch').parent().next('table.settings').find('tr.settings-item').each(markHide);
@@ -651,13 +663,16 @@ function cameraUi2Dict() {
         'post_capture': $('#postCaptureEntry').val(),
         
         /* motion notifications */
-        'motion_notifications': $('#motionNotificationsSwitch')[0].checked,
-        'motion_notifications_emails': $('#emailAddressesEntry').val(),
-        'smtp_server': $('#smtpServerEntry').val(),
-        'smtp_port': $('#smtpPortEntry').val(),
-        'smtp_account': $('#smtpAccountEntry').val(),
-        'smtp_password': $('#smtpPasswordEntry').val(),
-        'smtp_tls': $('#smtpTlsSwitch')[0].checked,
+        'email_notifications_enabled': $('#emailNotificationsSwitch')[0].checked,
+        'email_notifications_addresses': $('#emailAddressesEntry').val(),
+        'email_notifications_smtp_server': $('#smtpServerEntry').val(),
+        'email_notifications_smtp_port': $('#smtpPortEntry').val(),
+        'email_notifications_smtp_account': $('#smtpAccountEntry').val(),
+        'email_notifications_smtp_password': $('#smtpPasswordEntry').val(),
+        'email_notifications_smtp_tls': $('#smtpTlsSwitch')[0].checked,
+        'web_hook_notifications_enabled': $('#webHookNotificationsSwitch')[0].checked,
+        'web_hook_notifications_url': $('#webHookUrlEntry').val(),
+        'web_hook_notifications_http_method': $('#webHookHttpMethod').val(),
         
         /* working schedule */
         'working_schedule': $('#workingScheduleSwitch')[0].checked,
@@ -827,13 +842,16 @@ function dict2CameraUi(dict) {
     $('#postCaptureEntry').val(dict['post_capture']);
     
     /* motion notifications */
-    $('#motionNotificationsSwitch')[0].checked = dict['motion_notifications'];
-    $('#emailAddressesEntry').val(dict['motion_notifications_emails']);
-    $('#smtpServerEntry').val(dict['smtp_server']);
-    $('#smtpPortEntry').val(dict['smtp_port']);
-    $('#smtpAccountEntry').val(dict['smtp_account']);
-    $('#smtpPasswordEntry').val(dict['smtp_password']);
-    $('#smtpTlsSwitch')[0].checked = dict['smtp_tls'];
+    $('#emailNotificationsSwitch')[0].checked = dict['email_notifications_enabled'];
+    $('#emailAddressesEntry').val(dict['email_notifications_addresses']);
+    $('#smtpServerEntry').val(dict['email_notifications_smtp_server']);
+    $('#smtpPortEntry').val(dict['email_notifications_smtp_port']);
+    $('#smtpAccountEntry').val(dict['email_notifications_smtp_account']);
+    $('#smtpPasswordEntry').val(dict['email_notifications_smtp_password']);
+    $('#smtpTlsSwitch')[0].checked = dict['email_notifications_smtp_tls'];
+    $('#webHookNotificationsSwitch')[0].checked = dict['web_hook_notifications_enabled'];
+    $('#webHookUrlEntry').val(dict['web_hook_notifications_url']);
+    $('#webHookHttpMethod').val(dict['web_hook_notifications_http_method']);
 
     /* working schedule */
     $('#workingScheduleSwitch')[0].checked = dict['working_schedule'];
index 62484dd4d25da96f5d99e03f84441108b8d7b5b9..7f51e496ca54cd4f7377cec1e805a6dc7a63d4c7 100644 (file)
                     </tr>
                 </table>
                 
-                <div class="settings-section-title advanced-setting"><input type="checkbox" class="styled section notifications" id="motionNotificationsSwitch">Motion Notifications</div>
+                <div class="settings-section-title advanced-setting">Motion Notifications</div>
                 <table class="settings">
+                    <tr class="settings-item advanced-setting">
+                        <td class="settings-item-label"><span class="settings-item-label">Email Notifications</span></td>
+                        <td class="settings-item-value"><input type="checkbox" class="styled notifications" id="emailNotificationsSwitch"></td>
+                        <td><span class="help-mark" title="enable this if you want to receive email notifications whenever a motion event is detected">?</span></td>
+                    </tr>
                     <tr class="settings-item advanced-setting">
                         <td class="settings-item-label"><span class="settings-item-label">Email Addresses</span></td>
                         <td class="settings-item-value"><input type="text" class="styled notifications" id="emailAddressesEntry" placeholder="email addresses..."></td>
                         <td><span class="help-mark" title="email addresses (separated by comma) that are added here will receive notifications whenever a motion event is detected">?</span></td>
                     </tr>
-                    <tr class="settings-item advanced-setting">
-                        <td colspan="100"><div class="settings-item-separator"></div></td>
-                    </tr>
                     <tr class="settings-item advanced-setting">
                         <td class="settings-item-label"><span class="settings-item-label">SMTP Server</span></td>
                         <td class="settings-item-value"><input type="text" class="styled notifications" id="smtpServerEntry" placeholder="e.g. smtp.gmail.com"></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 needs this to be enabled)">?</span></td>
                     </tr>
+                    <tr class="settings-item advanced-setting">
+                        <td colspan="100"><div class="settings-item-separator"></div></td>
+                    </tr>
+                    <tr class="settings-item advanced-setting">
+                        <td class="settings-item-label"><span class="settings-item-label">Web Hook Notifications</span></td>
+                        <td class="settings-item-value"><input type="checkbox" class="styled notifications" id="webHookNotificationsSwitch"></td>
+                        <td><span class="help-mark" title="enable this if you want a URL to be requested whenever a motion event is detected">?</span></td>
+                    </tr>
+                    <tr class="settings-item advanced-setting">
+                        <td class="settings-item-label"><span class="settings-item-label">Web Hook URL</span></td>
+                        <td class="settings-item-value"><input type="text" class="styled notifications" id="webHookUrlEntry" placeholder="e.g. http://www.example.com/notify/"></td>
+                        <td><span class="help-mark" title="a URL to be requested when motion is detected; the following special tokens are accepted: %Y = year, %m = month, %d = date, %H = hour, %M = minute, %S = second, %q = frame number">?</span></td>
+                    </tr>
+                    <tr class="settings-item advanced-setting">
+                        <td class="settings-item-label"><span class="settings-item-label">HTTP Method</span></td>
+                        <td class="settings-item-value">
+                            <select class="styled notifications" id="webHookHttpMethod">
+                                <option value="GET">GET</option>
+                                <option value="POST">POST</option>
+                            </select>
+                        </td>
+                        <td><span class="help-mark" title="the HTTP method to use when requesting the web hook URL">?</span></td>
+                    </tr>
                 </table>
 
                 <div class="settings-section-title hidden"><input type="checkbox" class="styled section working-schedule" id="workingScheduleSwitch">Working Schedule</div>
diff --git a/webhook.py b/webhook.py
new file mode 100755 (executable)
index 0000000..016a0db
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 Calin Crisan
+# This file is part of motionEye.
+#
+# motionEye is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>. 
+
+import logging
+import sys
+import urllib2
+import urlparse
+
+import settings
+
+from motioneye import _configure_settings, _configure_logging
+
+
+_configure_settings()
+_configure_logging()
+
+
+def print_usage():
+    print 'Usage: webhook.py <method> <url>'
+
+
+if __name__ == '__main__':
+    if len(sys.argv) < 3:
+        print_usage()
+        sys.exit(-1)
+    
+    method = sys.argv[1] 
+    url = sys.argv[2]
+
+    logging.debug('method = %s' % method)
+    logging.debug('url = %s' % url)
+    
+    if method == 'POST':
+        parts = urlparse.urlparse(url)
+        data = parts.query
+
+    else:
+        data = None
+
+    request = urllib2.Request(url, data)
+    try:
+        urllib2.urlopen(request, timeout=settings.REMOTE_REQUEST_TIMEOUT)
+        logging.debug('webhook successfully called')
+    
+    except Exception as e:
+        logging.error('failed to call webhook: %s' % e)