-> add a previewer for movies
-> add a previewer for snapshots
-> add a motioneye.svg icon
--> other todos
\ No newline at end of file
+-> other todos
+-> add a messaging mechanism
from collections import OrderedDict
import settings
+import v4l2ctl
_CAMERA_CONFIG_FILE_NAME = 'thread-%(id)s.conf'
data = OrderedDict()
data['@name'] = 'Camera' + str(camera_id)
data['@proto'] = proto
+ data['@enabled'] = True
data['videodevice'] = device
+ # find a suitable resolution
+ for (w, h) in v4l2ctl.list_resolutions(device):
+ if w > 300:
+ data['width'] = w
+ data['height'] = h
+ break
+
# write the configuration to file
set_camera(camera_id, data)
data.setdefault('@proto', 'v4l2')
data.setdefault('videodevice', '')
data.setdefault('lightswitch', 0)
- data.setdefault('auto_brightness', False)
- data.setdefault('brightness', 0)
- data.setdefault('contrast', 0)
- data.setdefault('saturation', 0)
- data.setdefault('hue', 0)
+ data.setdefault('auto_brightness', True)
+ data.setdefault('brightness', 127)
+ data.setdefault('contrast', 127)
+ data.setdefault('saturation', 127)
+ data.setdefault('hue', 127)
data.setdefault('width', 352)
data.setdefault('height', 288)
- data.setdefault('framerate', 1)
+ data.setdefault('framerate', 5)
data.setdefault('rotate', 0)
data.setdefault('@storage_device', 'local-disk')
data.setdefault('webcam_localhost', False)
data.setdefault('webcam_port', 8080)
- data.setdefault('webcam_maxrate', 1)
+ data.setdefault('webcam_maxrate', 5)
data.setdefault('webcam_quality', 75)
data.setdefault('webcam_motion', False)
- data.setdefault('text_left', '')
- data.setdefault('text_right', '')
+ data.setdefault('text_left', data['@name'])
+ data.setdefault('text_right', '%Y-%m-%d\\n%T')
data.setdefault('text_double', False)
data.setdefault('text_changes', False)
data.setdefault('noise_level', 32)
data.setdefault('gap', 60)
- data.setdefault('pre_capture', 0)
- data.setdefault('post_capture', 0)
+ data.setdefault('pre_capture', 5)
+ data.setdefault('post_capture', 5)
data.setdefault('output_all', False)
data.setdefault('output_normal', False)
data.setdefault('motion_movies', False)
data.setdefault('ffmpeg_variable_bitrate', 14)
- data.setdefault('movie_filename', '')
+ data.setdefault('movie_filename', '%Y-%m-%d-%H-%M-%S')
data.setdefault('ffmpeg_cap_new', False)
data.setdefault('@preserve_movies', 0)
camera_id, data = config.add_camera(device)
data['@id'] = camera_id
+ data['@enabled'] = True
- self.finish_json(data)
+ if motionctl.running():
+ motionctl.stop()
+
+ if config.has_enabled_cameras():
+ motionctl.start()
+
+ self.finish_json(self._camera_dict_to_ui(data))
def rem_camera(self, camera_id):
logging.debug('removing camera %(id)s' % {'id': camera_id})
config.rem_camera(camera_id)
+ if motionctl.running():
+ motionctl.stop()
+
+ if config.has_enabled_cameras():
+ motionctl.start()
+
def _main_ui_to_dict(self, ui):
return {
'@enabled': ui.get('enabled', True),
class SnapshotHandler(BaseHandler):
def get(self, camera_id, op, filename=None):
+ if camera_id is not None:
+ camera_id = int(camera_id)
+ if camera_id not in config.get_camera_ids():
+ raise HTTPError(404, 'no such camera')
+
if op == 'current':
self.current(camera_id)
def list(self, camera_id):
logging.debug('listing snapshots for camera %(id)s' % {'id': camera_id})
+
+ # TODO implement me
def download(self, camera_id, filename):
logging.debug('downloading snapshot %(filename)s of camera %(id)s' % {
'filename': filename, 'id': camera_id})
+
+ # TODO implement me
class MovieHandler(BaseHandler):
else {
$('#videoDeviceSelect')[0].selectedIndex = -1;
}
- $('#videoDeviceSelect').change();
+
+ updateConfigUi();
}
else {
fetchCurrentCameraConfig();
/* whenever the window is resized,
* if a modal dialog is visible, it should be repositioned */
$(window).resize(updateModalDialogPosition);
+
+ /* remove camera button */
+ $('div.button.rem-camera-button').click(function () {
+ var cameraId = $('#videoDeviceSelect').val();
+ if (cameraId == null || cameraId === 'add') {
+ runAlertDialog('No camera to remove!');
+ return;
+ }
+
+ var deviceName = $('#videoDeviceSelect').find('option[value=' + cameraId + ']').text();
+
+ runConfirmDialog('Remove device ' + deviceName + '?', function () {
+ showProgress();
+ ajax('POST', '/config/' + cameraId + '/rem/', null, function () {
+ hideApply();
+ fetchCurrentConfig();
+ });
+ });
+ });
}
objs.not($('#motionEyeSwitch').parents('div').get(0)).each(markHide);
}
+ if ($('#videoDeviceSelect').find('option').length < 2) { /* no camera configured */
+ $('#videoDeviceSwitch').parent().each(markHide);
+ $('#videoDeviceSwitch').parent().nextAll('div.settings-section-title, table.settings').each(markHide);
+ }
+
/* advanced settings */
var showAdvanced = $('#showAdvancedSwitch').get(0).checked;
if (!showAdvanced) {
}
videoDeviceSelect.append('<option value="add">add camera...</option>');
- if (cameras.length > 1) {
+ if (cameras.length > 0) {
videoDeviceSelect[0].selectedIndex = 0;
fetchCurrentCameraConfig();
}
else {
videoDeviceSelect[0].selectedIndex = -1;
+ // TODO if admin, set a message saying that the user should add a camera
}
recreateCameraFrames(cameras);
+ updateConfigUi();
});
});
}
runModalDialog({title: message, buttons: 'ok'});
}
-function runAddCameraDialog(devices) {
+function runConfirmDialog(message, onYes) {
+ runModalDialog({title: message, buttons: 'yesno', onYes: onYes});
+}
+
+function runAddCameraDialog() {
var content =
$('<table class="add-camera-dialog">' +
'<tr>' +
buttons: 'okcancel',
content: content,
onOk: function () {
+ var fullDevice;
+ if (deviceSelect.val() == 'remote') {
+ fullDevice = 'http://' + usernameEntry.val() + ':' + passwordEntry.val() + '@' + hostEntry + ':' + portEntry;
+ }
+ else {
+ fullDevice = 'v4l2://' + deviceSelect.val();
+ }
+
+ showProgress();
+ ajax('POST', '/config/add/?device=' + fullDevice, null, function (data) {
+ hideApply();
+ var addCameraOption = $('#videoDeviceSelect').find('option[value=add]');
+ addCameraOption.before('<option value="' + data.id + '">' + data.name + '</option>');
+ $('#videoDeviceSelect').val(data.id).change();
+ recreateCameraFrames();
+ });
}
});
});
showProgress();
ajax('GET', '/config/' + cameraId + '/get/', null, function (data) {
data['enabled'] = false;
+ data['restart'] = true;
ajax('POST', '/config/' + cameraId + '/set/', data, function () {
endProgress();
/* if the current camera in the settings panel is the closed camera,
* we refresh its settings and update the UI */
- if (isSettingsOpen() && ($('#videoDeviceSelect').val() === '' + cameraId)) {
+ if ($('#videoDeviceSelect').val() === '' + cameraId) {
fetchCurrentCameraConfig();
}
});