Skip to content

Commit f55c2ca

Browse files
authored
Ensure grabber default hardware contols are used (#1914)
1 parent 912083b commit f55c2ca

File tree

3 files changed

+76
-58
lines changed

3 files changed

+76
-58
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
### 🔧 Changed
2424

2525
- Hue Bridge - Wizard updates to support bridge-ids, overall code refactoring
26+
- USB Grabber - Default hardware control properties are now applied when a new USB grabber is selected (avoids black images)
2627

2728
- **Fixes:**
2829
- UI - Language is not selectable (#1877)

assets/webconfig/js/content_grabber.js

Lines changed: 69 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ $(document).ready(function () {
348348
updateJsonEditorRange(conf_editor_video, "root.grabberV4L2", key,
349349
properties.minValue,
350350
properties.maxValue,
351-
properties.current,
351+
properties.default,
352352
properties.step,
353353
true);
354354

@@ -411,73 +411,84 @@ $(document).ready(function () {
411411
});
412412

413413
conf_editor_video.watch('root.grabberV4L2.available_devices', () => {
414-
var deviceSelected = conf_editor_video.getEditor("root.grabberV4L2.available_devices").getValue();
415-
if (deviceSelected === "SELECT" || deviceSelected === "NONE" || deviceSelected === "") {
414+
const editor = conf_editor_video.getEditor("root.grabberV4L2.available_devices");
415+
const deviceSelected = editor.getValue();
416+
const invalidSelections = ["SELECT", "NONE", ""];
417+
418+
if (invalidSelections.includes(deviceSelected)) {
416419
$('#btn_submit_videograbber').prop('disabled', true);
417420
showInputOptionsForKey(conf_editor_video, "grabberV4L2", ["enable", "available_devices"], false);
421+
return;
418422
}
419-
else {
420-
showInputOptionsForKey(conf_editor_video, "grabberV4L2", ["enable", "available_devices"], true);
421-
var addSchemaElements = {};
422-
var enumVals = [];
423-
var enumTitelVals = [];
424-
var enumDefaultVal = "";
425423

426-
var deviceProperties = getPropertiesOfDevice("video", deviceSelected);
424+
showInputOptionsForKey(conf_editor_video, "grabberV4L2", ["enable", "available_devices"], true);
427425

428-
//Update hidden input element
429-
conf_editor_video.getEditor("root.grabberV4L2.device").setValue(deviceProperties.device);
426+
const deviceProperties = getPropertiesOfDevice("video", deviceSelected);
427+
conf_editor_video.getEditor("root.grabberV4L2.device").setValue(deviceProperties.device);
430428

431-
if (deviceProperties.hasOwnProperty('default') && !jQuery.isEmptyObject(deviceProperties.default.properties)) {
432-
$('#btn_videograbber_set_defaults').prop('disabled', false);
433-
} else {
434-
$('#btn_videograbber_set_defaults').prop('disabled', true);
435-
}
429+
const defaultProperties = deviceProperties.default?.properties ?? {};
430+
const hasDefaults = Object.keys(defaultProperties).length > 0;
431+
$('#btn_videograbber_set_defaults').prop('disabled', !hasDefaults);
436432

437-
//If configured device is selected, use the saved values as current values
438-
if (deviceSelected === configuredDevice) {
439-
// Only if the device reported properties, use the configured values. In case no properties are presented, the device properties cannot be controlled.
440-
if (deviceProperties.hasOwnProperty('properties') && !jQuery.isEmptyObject(deviceProperties.properties)) {
441-
let properties = {
442-
brightness: { current: window.serverConfig.grabberV4L2.hardware_brightness },
443-
contrast: { current: window.serverConfig.grabberV4L2.hardware_contrast },
444-
saturation: { current: window.serverConfig.grabberV4L2.hardware_saturation },
445-
hue: { current: window.serverConfig.grabberV4L2.hardware_hue }
446-
};
447-
deviceProperties.properties = properties;
448-
}
449-
}
433+
const isConfiguredDevice = (deviceSelected === configuredDevice);
434+
const { grabberV4L2 } = window.serverConfig;
435+
const currentProps = deviceProperties.properties;
450436

451-
updateDeviceProperties(deviceProperties.properties, "brightness", "hardware_brightness");
452-
updateDeviceProperties(deviceProperties.properties, "contrast", "hardware_contrast");
453-
updateDeviceProperties(deviceProperties.properties, "saturation", "hardware_saturation");
454-
updateDeviceProperties(deviceProperties.properties, "hue", "hardware_hue");
437+
const propMappings = {
438+
brightness: 'hardware_brightness',
439+
contrast: 'hardware_contrast',
440+
saturation: 'hardware_saturation',
441+
hue: 'hardware_hue'
442+
};
455443

456-
var video_inputs = deviceProperties.video_inputs;
457-
if (video_inputs.length <= 1) {
458-
addSchemaElements.access = "expert";
444+
for (const prop in propMappings) {
445+
if (hasDefaults) {
446+
currentProps[prop].default = defaultProperties[prop];
459447
}
448+
// Ensure min,max and step values are set inline with the selected grabber to ensure valid input
449+
updateDeviceProperties(currentProps, prop, [propMappings[prop]]);
460450

461-
for (const video_input of video_inputs) {
462-
enumVals.push(video_input.inputIdx.toString());
463-
enumTitelVals.push(video_input.name);
451+
let currentValue = 0;
452+
if (isConfiguredDevice) {
453+
currentValue = window.serverConfig.grabberV4L2[propMappings[prop]];
454+
} else if (hasDefaults) {
455+
currentValue = currentProps.default;
464456
}
465457

466-
if (enumVals.length > 0) {
467-
if (deviceSelected === configuredDevice) {
468-
var configuredVideoInput = window.serverConfig.grabberV4L2.input.toString();
469-
if ($.inArray(configuredVideoInput, enumVals) != -1) {
470-
enumDefaultVal = configuredVideoInput;
471-
}
472-
}
473-
474-
updateJsonEditorSelection(conf_editor_video, 'root.grabberV4L2',
475-
'device_inputs', addSchemaElements, enumVals, enumTitelVals, enumDefaultVal, false, false);
458+
if (currentValue !== undefined) {
459+
conf_editor_video.getEditor("root.grabberV4L2." + propMappings[prop]).setValue(currentValue);
476460
}
461+
}
477462

478-
if (conf_editor_video.validate().length && !window.readOnlyMode) {
479-
$('#btn_submit_videograbber').prop('disabled', false);
463+
const { video_inputs = [] } = deviceProperties;
464+
465+
const addSchemaElements = {};
466+
467+
if (video_inputs.length <= 1) {
468+
addSchemaElements.access = "expert";
469+
}
470+
471+
const enumVals = video_inputs.map(input => input.inputIdx.toString());
472+
const enumTitelVals = video_inputs.map(input => input.name);
473+
474+
if (enumVals.length > 0) {
475+
let enumDefaultVal = "";
476+
if (isConfiguredDevice) {
477+
const configuredInput = grabberV4L2.input.toString();
478+
if (enumVals.includes(configuredInput)) {
479+
enumDefaultVal = configuredInput;
480+
}
480481
}
482+
483+
updateJsonEditorSelection(
484+
conf_editor_video, 'root.grabberV4L2', 'device_inputs',
485+
addSchemaElements, enumVals, enumTitelVals, enumDefaultVal, false, false
486+
);
487+
}
488+
489+
const isValid = conf_editor_video.validate().length === 0;
490+
if (isValid && !window.readOnlyMode) {
491+
$('#btn_submit_videograbber').prop('disabled', false);
481492
}
482493
});
483494

@@ -983,14 +994,16 @@ $(document).ready(function () {
983994
}
984995

985996
function getPropertiesOfDevice(type, deviceName) {
986-
deviceProperties = {};
987-
for (const deviceRecord of discoveredInputSources[type]) {
997+
let props = {};
998+
const sourceList = discoveredInputSources[type] || [];
999+
for (const deviceRecord of sourceList) {
9881000
if (deviceRecord.device_name === deviceName) {
989-
deviceProperties = deviceRecord;
1001+
// Deep copy to prevent modifying the original object in discoveredInputSources
1002+
props = structuredClone(deviceRecord);
9901003
break;
9911004
}
9921005
}
993-
return deviceProperties;
1006+
return props;
9941007
}
9951008

9961009
});

assets/webconfig/js/ui_utils.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -865,8 +865,12 @@ function updateJsonEditorRange(rootEditor, path, key, minimum, maximum, defaultV
865865
delete editor.cached_editors[key];
866866
editor.addObjectProperty(key);
867867

868-
// Restore the current value after updating the range
869-
rootEditor.getEditor(path + "." + key).setValue(currentValue);
868+
// restore the current value, if no default value given
869+
if (typeof defaultValue === "undefined") {
870+
rootEditor.getEditor(path + "." + key).setValue(currentValue);
871+
} else {
872+
rootEditor.getEditor(path + "." + key).setValue(defaultValue);
873+
}
870874
}
871875

872876
// Add custom host validation to JSON Editor

0 commit comments

Comments
 (0)