From: Calin Crisan Date: Sun, 24 Aug 2014 11:19:04 +0000 (+0300) Subject: implemented working schedule support X-Git-Url: http://www.vanbest.org/gitweb/?a=commitdiff_plain;h=ebb1eef7339722eefb5b5516b4795dc152dbadba;p=motioneye-debian implemented working schedule support --- diff --git a/motioneye.py b/motioneye.py index a44ea58..446fa32 100755 --- a/motioneye.py +++ b/motioneye.py @@ -362,5 +362,5 @@ if __name__ == '__main__': if settings.THUMBNAILER_INTERVAL: _start_thumbnailer() - + _run_server() diff --git a/src/config.py b/src/config.py index 1e4b106..4219e9c 100644 --- a/src/config.py +++ b/src/config.py @@ -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', '') diff --git a/src/motionctl.py b/src/motionctl.py index 9d681bf..e96e735 100644 --- a/src/motionctl.py +++ b/src/motionctl.py @@ -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') diff --git a/src/wsswitch.py b/src/wsswitch.py index 9a63d55..3710172 100644 --- a/src/wsswitch.py +++ b/src/wsswitch.py @@ -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) diff --git a/static/js/main.js b/static/js/main.js index ae9542e..a683c7e 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -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(); } diff --git a/templates/main.html b/templates/main.html index c0a878f..de0f447 100644 --- a/templates/main.html +++ b/templates/main.html @@ -468,7 +468,7 @@ HTTP Method - @@ -555,6 +555,16 @@ ? + + Detect Motion + + + + ? +