]> www.vanbest.org Git - motioneye-debian/commitdiff
implemented working schedule support
authorCalin Crisan <ccrisan@gmail.com>
Sun, 24 Aug 2014 11:19:04 +0000 (14:19 +0300)
committerCalin Crisan <ccrisan@gmail.com>
Sun, 24 Aug 2014 11:19:04 +0000 (14:19 +0300)
motioneye.py
src/config.py
src/motionctl.py
src/wsswitch.py
static/js/main.js
templates/main.html

index a44ea58fe1bb6ecf497b172bd72d6ab6add09ce2..446fa32fa4e83d01eef39e0a50b4f4ec1793efd5 100755 (executable)
@@ -362,5 +362,5 @@ if __name__ == '__main__':
     
     if settings.THUMBNAILER_INTERVAL:
         _start_thumbnailer()
-    
+
     _run_server()
index 1e4b106afad661ac03b4db337c50d5e1cf5990dc..4219e9cd0725632003677e64908633a1ed2582c7 100644 (file)
@@ -708,6 +708,8 @@ def camera_ui_to_dict(ui):
                 ui['friday_from'] + '-' + ui['friday_to'] + '|' + 
                 ui['saturday_from'] + '-' + ui['saturday_to'] + '|' + 
                 ui['sunday_from'] + '-' + ui['sunday_to'])
+        
+        data['@working_schedule_type'] = ui['working_schedule_type']
     
     # event start notifications
     on_event_start = []
@@ -994,6 +996,7 @@ def camera_dict_to_ui(data):
     working_schedule = data['@working_schedule']
     if working_schedule:
         days = working_schedule.split('|')
+        ui['working_schedule'] = True
         ui['monday_from'], ui['monday_to'] = days[0].split('-')
         ui['tuesday_from'], ui['tuesday_to'] = days[1].split('-')
         ui['wednesday_from'], ui['wednesday_to'] = days[2].split('-')
@@ -1001,7 +1004,7 @@ def camera_dict_to_ui(data):
         ui['friday_from'], ui['friday_to'] = days[4].split('-')
         ui['saturday_from'], ui['saturday_to'] = days[5].split('-')
         ui['sunday_from'], ui['sunday_to'] = days[6].split('-')
-        ui['working_schedule'] = True
+        ui['working_schedule_type'] = data['@working_schedule_type']
     
     # event start notifications    
     on_event_start = data.get('on_event_start') or []
@@ -1335,6 +1338,7 @@ def _set_default_motion_camera(camera_id, data, old_motion=False):
     data.setdefault('@preserve_movies', 0)
     
     data.setdefault('@working_schedule', '')
+    data.setdefault('@working_schedule_type', 'outside')
 
     data.setdefault('on_event_start', '')
 
index 9d681bfa60a18c33e3e58cb74ee0a2d3f381e95c..e96e735c82467c97525e41c486e480cf2faac8ed 100644 (file)
@@ -23,8 +23,11 @@ import signal
 import subprocess
 import time
 
+from tornado.httpclient import HTTPClient, AsyncHTTPClient, HTTPRequest
+
 import config
 import settings
+import utils
 
 
 _started = False
@@ -169,6 +172,85 @@ def started():
     return _started
 
 
+def get_motion_detection(camera_id):
+    thread_id = _get_thread_id(camera_id)
+    if thread_id is None:
+        return logging.error('could not find thread id for camera with id %s' % camera_id)
+    
+    url = 'http://127.0.0.1:7999/%(id)s/detection/status' % {'id': thread_id}
+    
+    request = HTTPRequest(url, connect_timeout=2, request_timeout=2)
+    http_client = HTTPClient()
+    response = http_client.fetch(request)
+
+    if response.error:
+        logging.error('failed to get motion detection status for camera with id %(id)s: %(msg)s' % {
+                'id': camera_id,
+                'msg': unicode(response.error)})
+        
+        return None
+    
+    enabled = bool(response.body.lower().count('active'))
+    
+    logging.debug('motion detection is %(what)s for camera with id %(id)s' % {
+            'what': ['disabled', 'enabled'][enabled],
+            'id': camera_id})
+    
+    return enabled
+
+
+def set_motion_detection(camera_id, enabled):
+    thread_id = _get_thread_id(camera_id)
+    if thread_id is None:
+        return logging.error('could not find thread id for camera with id %s' % camera_id)
+    
+    logging.debug('%(what)s motion detection for camera with id %(id)s' % {
+            'what': ['disabling', 'enabling'][enabled],
+            'id': camera_id})
+    
+    url = 'http://127.0.0.1:7999/%(id)s/detection/%(enabled)s' % {
+            'id': thread_id,
+            'enabled': ['pause', 'start'][enabled]}
+    
+    def on_response(response):
+        if response.error:
+            logging.error('failed to %(what)s motion detection for camera with id %(id)s: %(msg)s' % {
+                    'what': ['disable', 'enable'][enabled],
+                    'id': camera_id,
+                    'msg': unicode(response.error)})
+        
+        else:
+            logging.debug('successfully %(what)s motion detection for camera with id %(id)s' % {
+                    'what': ['disabled', 'enabled'][enabled],
+                    'id': camera_id})
+
+    request = HTTPRequest(url, connect_timeout=4, request_timeout=4)
+    http_client = AsyncHTTPClient()
+    http_client.fetch(request, on_response)
+
+
+def _get_thread_id(camera_id):
+    # find the corresponding thread_id
+    # (which can be different from camera_id)
+    camera_ids = config.get_camera_ids()
+    thread_id = 0
+    for cid in camera_ids:
+        camera_config = config.get_camera(cid)
+        if utils.local_camera(camera_config):
+            thread_id += 1
+        
+        if cid == camera_id:
+            break
+    
+    else:
+        return None
+    
+    if thread_id == 0:
+        return None
+    
+    return thread_id
+
+
 def _get_pid():
     motion_pid_path = os.path.join(settings.RUN_PATH, 'motion.pid')
     
index 9a63d5581def132cd04507fce043fb9cc7f5da21..37101723a3f1fa75f0074080f9dabc76da991e46 100644 (file)
@@ -21,10 +21,52 @@ import tornado
 
 import config
 import motionctl
+import utils
 
 
 def start():
-    pass
+    ioloop = tornado.ioloop.IOLoop.instance()
+    ioloop.add_timeout(datetime.timedelta(seconds=10), _check_ws)
+
+
+def _during_working_schedule(now, working_schedule):
+    parts = working_schedule.split('|')
+    if len(parts) < 7:
+        return False # invalid ws
+
+    ws_day = parts[now.weekday()]
+    parts = ws_day.split('-')
+    if len(parts) != 2:
+        return False # invalid ws
+    
+    _from, to = parts
+    if not _from or not to:
+        return False # ws disabled for this day
+    
+    _from = _from.split(':')
+    to = to.split(':')
+    if len(_from) != 2 or len(to) != 2:
+        return False # invalid ws
+    
+    try:
+        from_h = int(_from[0])
+        from_m = int(_from[1])
+        to_h = int(to[0])
+        to_m = int(to[1])
+    
+    except ValueError:
+        return False # invalid ws
+    
+    if now.hour < from_h or now.hour > to_h:
+        return False
+
+    if now.hour == from_h and now.minute < from_m:
+        return False
+
+    if now.hour == to_h and now.minute > to_m:
+        return False
+    
+    return True
 
 
 def _check_ws():
@@ -34,3 +76,35 @@ def _check_ws():
 
     if not motionctl.running():
         return
+
+    now = datetime.datetime.now()
+    for camera_id in config.get_camera_ids():
+        camera_config = config.get_camera(camera_id)
+        if not utils.local_camera(camera_config):
+            continue
+        
+        working_schedule = camera_config.get('@working_schedule')
+        working_schedule_type = camera_config.get('@working_schedule_type') or 'outside'
+        
+        must_be_enabled = False
+        if not working_schedule: # working schedule disabled, motion detection always on
+            must_be_enabled = True
+        
+        else:
+            now_during = _during_working_schedule(now, working_schedule)
+            must_be_enabled = (now_during and working_schedule_type == 'during') or (not now_during and working_schedule_type == 'outside')
+        
+        currently_enabled = motionctl.get_motion_detection(camera_id)
+        if currently_enabled and not must_be_enabled:
+            logging.debug('must disable motion detection for camera with id %(id)s (%(what)s working schedule)' % {
+                    'id': camera_id,
+                    'what': working_schedule_type})
+            
+            motionctl.set_motion_detection(camera_id, False)
+
+        elif not  currently_enabled and must_be_enabled:
+            logging.debug('must enable motion detection for camera with id %(id)s (%(what)s working schedule)' % {
+                    'id': camera_id,
+                    'what': working_schedule_type})
+            
+            motionctl.set_motion_detection(camera_id, True)
index ae9542ee1673255ca0cf1327381b2371636f10d9..a683c7ee93cbe266b2821e7981f2d881e5c42017 100644 (file)
@@ -522,7 +522,7 @@ function updateConfigUi() {
     
     if (!$('#webHookNotificationsSwitch').get(0).checked) {
         $('#webHookUrlEntry').parents('tr:eq(0)').each(markHide);
-        $('#webHookHttpMethod').parents('tr:eq(0)').each(markHide);
+        $('#webHookHttpMethodSelect').parents('tr:eq(0)').each(markHide);
     }
 
     if (!$('#commandNotificationsSwitch').get(0).checked) {
@@ -701,7 +701,7 @@ function cameraUi2Dict() {
         '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(),
+        'web_hook_notifications_http_method': $('#webHookHttpMethodSelect').val(),
         'command_notifications_enabled': $('#commandNotificationsSwitch')[0].checked,
         'command_notifications_exec': $('#commandNotificationsEntry').val(),
         
@@ -721,6 +721,7 @@ function cameraUi2Dict() {
         'saturday_to': $('#saturdayEnabledSwitch')[0].checked ? $('#saturdayToEntry').val() : '',
         'sunday_from': $('#sundayEnabledSwitch')[0].checked ? $('#sundayFromEntry').val() : '',
         'sunday_to': $('#sundayEnabledSwitch')[0].checked ? $('#sundayToEntry').val() : '',
+        'working_schedule_type': $('#workingScheduleTypeSelect').val(),
     };
 
     if ($('#resolutionSelect')[0].selectedIndex != -1) {
@@ -914,7 +915,7 @@ function dict2CameraUi(dict) {
     $('#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']);
+    $('#webHookHttpMethodSelect').val(dict['web_hook_notifications_http_method']);
     $('#commandNotificationsSwitch')[0].checked = dict['command_notifications_enabled'];
     $('#commandNotificationsEntry').val(dict['command_notifications_exec']);
 
@@ -941,6 +942,7 @@ function dict2CameraUi(dict) {
     $('#sundayEnabledSwitch')[0].checked = Boolean(dict['sunday_from'] && dict['sunday_to']);
     $('#sundayFromEntry').val(dict['sunday_from']);
     $('#sundayToEntry').val(dict['sunday_to']);
+    $('#workingScheduleTypeSelect').val(dict['working_schedule_type']);
     
     updateConfigUi();
 }
index c0a878fd2a6c1922027c77f08a800136f55156a6..de0f4476c69b4483978c0867d6fdc4a3206e3258 100644 (file)
                     <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">
+                            <select class="styled notifications" id="webHookHttpMethodSelect">
                                 <option value="GET">GET</option>
                                 <option value="POST">POST</option>
                             </select>
                         </td>
                         <td><span class="help-mark" title="sets the working schedule time interval for Sunday">?</span></td>
                     </tr>
+                    <tr class="settings-item">
+                        <td class="settings-item-label"><span class="settings-item-label">Detect Motion</span></td>
+                        <td class="settings-item-value">
+                            <select class="styled working-schedule" id="workingScheduleTypeSelect">
+                                <option value="during">During Working Schedule</option>
+                                <option value="outside">Outside Working Schedule</option>
+                            </select>
+                        </td>
+                        <td><span class="help-mark" title="sets whether motion detection should be active during or outside the working schedule">?</span></td>
+                    </tr>
                 </table>
 
                 <div class="settings-progress"></div>