Discovery VideoSources and Dynamically Update Editor

This commit is contained in:
Lord-Grey
2021-02-14 11:39:03 +01:00
parent f25b152d51
commit 054d3dac41
11 changed files with 2782 additions and 2515 deletions

View File

@@ -0,0 +1,28 @@
{
"type":"object",
"required":true,
"properties": {
"command": {
"type": "string",
"required": true,
"enum": [ "inputsource" ]
},
"tan": {
"type": "integer"
},
"subcommand": {
"type": "string",
"required": true,
"enum": [ "discover", "getProperties" ]
},
"sourceType": {
"type": "string",
"required": true
},
"params": {
"type": "object",
"required": false
}
},
"additionalProperties": false
}

View File

@@ -5,7 +5,7 @@
"command": {
"type" : "string",
"required" : true,
"enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "transform", "correction" , "temperature"]
"enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "transform", "correction", "temperature" ]
}
}
}

View File

@@ -20,7 +20,8 @@
<file alias="schema-videomode">JSONRPC_schema/schema-videomode.json</file>
<file alias="schema-authorize">JSONRPC_schema/schema-authorize.json</file>
<file alias="schema-instance">JSONRPC_schema/schema-instance.json</file>
<file alias="schema-leddevice">JSONRPC_schema/schema-leddevice.json</file>
<file alias="schema-leddevice">JSONRPC_schema/schema-leddevice.json</file>
<file alias="schema-inputsource">JSONRPC_schema/schema-inputsource.json</file>
<!-- The following schemas are derecated but used to ensure backward compatibility with hyperion Classic remote control-->
<file alias="schema-transform">JSONRPC_schema/schema-hyperion-classic.json</file>
<file alias="schema-correction">JSONRPC_schema/schema-hyperion-classic.json</file>

View File

@@ -174,6 +174,8 @@ proceed:
handleInstanceCommand(message, command, tan);
else if (command == "leddevice")
handleLedDeviceCommand(message, command, tan);
else if (command == "inputsource")
handleInputSourceCommand(message, command, tan);
// BEGIN | The following commands are deprecated but used to ensure backward compatibility with hyperion Classic remote control
else if (command == "clearall")
@@ -487,75 +489,6 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
availableGrabbers.append(grabber);
}
#endif
#if defined(ENABLE_V4L2) || defined(ENABLE_MF)
QJsonArray availableDevices;
for (const auto& devicePath : GrabberWrapper::getInstance()->getDevices())
{
QJsonObject device;
device["device"] = devicePath;
device["device_name"] = GrabberWrapper::getInstance()->getDeviceName(devicePath);
device["type"] = "v4l2";
QJsonArray video_inputs;
QMultiMap<QString, int> inputs = GrabberWrapper::getInstance()->getDeviceInputs(devicePath);
for (auto input = inputs.begin(); input != inputs.end(); input++)
{
QJsonObject in;
in["name"] = input.key();
in["inputIdx"] = input.value();
QJsonArray standards;
QList<VideoStandard> videoStandards = GrabberWrapper::getInstance()->getAvailableDeviceStandards(devicePath, input.value());
for (auto standard : videoStandards)
{
standards.append(VideoStandard2String(standard));
}
QJsonArray formats;
QStringList encodingFormats = GrabberWrapper::getInstance()->getAvailableEncodingFormats(devicePath, input.value());
for (auto encodingFormat : encodingFormats)
{
QJsonObject format;
format["format"] = encodingFormat;
QJsonArray resolutionArray;
QMultiMap<int, int> deviceResolutions = GrabberWrapper::getInstance()->getAvailableDeviceResolutions(devicePath, input.value(), parsePixelFormat(encodingFormat));
for (auto width_height = deviceResolutions.begin(); width_height != deviceResolutions.end(); width_height++)
{
QJsonObject resolution;
resolution["width"] = width_height.key();
resolution["height"] = width_height.value();
QJsonArray fps;
QIntList framerates = GrabberWrapper::getInstance()->getAvailableDeviceFramerates(devicePath, input.value(), parsePixelFormat(encodingFormat), width_height.key(), width_height.value());
for (auto framerate : framerates)
{
fps.append(framerate);
}
resolution["fps"] = fps;
resolutionArray.append(resolution);
}
format["resolutions"] = resolutionArray;
formats.append(format);
}
in["standards"] = standards;
in["formats"] = formats;
video_inputs.append(in);
}
device["video_inputs"] = video_inputs;
availableDevices.append(device);
}
grabbers["video_sources"] = availableDevices;
#endif
grabbers["available"] = availableGrabbers;
@@ -1485,6 +1418,117 @@ void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const QString &
}
}
void JsonAPI::handleInputSourceCommand(const QJsonObject& message, const QString& command, int tan)
{
Debug(_log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData());
const QString& subc = message["subcommand"].toString().trimmed();
const QString& sourceType = message["sourceType"].toString().trimmed();
QString full_command = command + "-" + subc;
// TODO: Validate that source type is a valid one
/* if ( ! valid type )
{
sendErrorReply("Unknown device", full_command, tan);
}
else
*/ {
if (subc == "discover")
{
QJsonObject inputSourcesDiscovered;
inputSourcesDiscovered.insert("sourceType", sourceType);
QJsonArray videoInputs;
#if defined(ENABLE_V4L2) || defined(ENABLE_MF)
if (sourceType == "video" )
{
//for (const auto& instance : GrabberWrapper::getInstance()->getDevices())
//{
for (const auto& devicePath : GrabberWrapper::getInstance()->getDevices())
{
QJsonObject device;
device["device"] = devicePath;
device["device_name"] = GrabberWrapper::getInstance()->getDeviceName(devicePath);
device["type"] = "v4l2";
QJsonArray video_inputs;
QMultiMap<QString, int> inputs = GrabberWrapper::getInstance()->getDeviceInputs(devicePath);
for (auto input = inputs.begin(); input != inputs.end(); input++)
{
QJsonObject in;
in["name"] = input.key();
in["inputIdx"] = input.value();
QJsonArray standards;
QList<VideoStandard> videoStandards = GrabberWrapper::getInstance()->getAvailableDeviceStandards(devicePath, input.value());
for (auto standard : videoStandards)
{
standards.append(VideoStandard2String(standard));
}
if (!standards.isEmpty())
{
in["standards"] = standards;
}
QJsonArray formats;
QStringList encodingFormats = GrabberWrapper::getInstance()->getAvailableEncodingFormats(devicePath, input.value());
for (auto encodingFormat : encodingFormats)
{
QJsonObject format;
format["format"] = encodingFormat;
QJsonArray resolutionArray;
QMultiMap<int, int> deviceResolutions = GrabberWrapper::getInstance()->getAvailableDeviceResolutions(devicePath, input.value(), parsePixelFormat(encodingFormat));
for (auto width_height = deviceResolutions.begin(); width_height != deviceResolutions.end(); width_height++)
{
QJsonObject resolution;
resolution["width"] = width_height.key();
resolution["height"] = width_height.value();
QJsonArray fps;
QIntList framerates = GrabberWrapper::getInstance()->getAvailableDeviceFramerates(devicePath, input.value(), parsePixelFormat(encodingFormat), width_height.key(), width_height.value());
for (auto framerate : framerates)
{
fps.append(framerate);
}
resolution["fps"] = fps;
resolutionArray.append(resolution);
}
format["resolutions"] = resolutionArray;
formats.append(format);
}
in["formats"] = formats;
video_inputs.append(in);
}
device["video_inputs"] = video_inputs;
videoInputs.append(device);
}
}
#endif
inputSourcesDiscovered["video_sources"] = videoInputs;
Debug(_log, "response: [%s]", QString(QJsonDocument(inputSourcesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
sendSuccessDataReply(QJsonDocument(inputSourcesDiscovered), full_command, tan);
}
else
{
sendErrorReply("Unknown or missing subcommand", full_command, tan);
}
}
}
void JsonAPI::handleNotImplemented(const QString &command, int tan)
{
sendErrorReply("Command not implemented", command, tan);

View File

@@ -234,5 +234,18 @@ bool SettingsManager::handleConfigUpgrade(QJsonObject& config)
Debug(_log,"LED Layout migrated");
}
}
if (config.contains("grabberV4L2"))
{
QJsonObject newGrabberV4L2Config = config["grabberV4L2"].toObject();
if (newGrabberV4L2Config.contains("encoding_format"))
{
newGrabberV4L2Config.remove("encoding_format");
config["grabberV4L2"] = newGrabberV4L2Config;
migrated = true;
Debug(_log, "GrabberV4L2 Layout migrated");
}
}
return migrated;
}

View File

@@ -2,345 +2,350 @@
"type" : "object",
"required" : true,
"title" : "edt_conf_v4l2_heading_title",
"properties" :
{
"device" :
{
"type" : "string",
"title" : "edt_conf_enum_custom",
"default" : "auto",
"options" : {
"hidden":true
"properties": {
"available_devices": {
"type": "string",
"title": "edt_conf_v4l2_device_title",
"propertyOrder": 1,
"required": true
},
"device": {
"type": "string",
"title": "edt_conf_enum_custom",
"options": {
"hidden": true
},
"required" : true,
"propertyOrder" : 2,
"comment" : "The 'available_devices' settings are dynamically inserted into the WebUI under PropertyOrder '1'."
"required": true,
"comment": "The 'available_devices' settings are dynamically inserted into the WebUI under PropertyOrder '1'.",
"propertyOrder": 2
},
"input" :
{
"type" : "integer",
"title" : "edt_conf_enum_custom",
"default" : 0,
"options" : {
"hidden":true
"device_inputs": {
"type": "string",
"title": "edt_conf_v4l2_input_title",
"propertyOrder": 3,
"required": true
},
"input": {
"type": "integer",
"title": "edt_conf_enum_custom",
"default": 0,
"options": {
"hidden": true
},
"required" : true,
"propertyOrder" : 4,
"comment" : "The 'device_inputs' settings are dynamically inserted into the WebUI under PropertyOrder '3'."
"required": true,
"propertyOrder": 4,
"comment": "The 'device_inputs' settings are dynamically inserted into the WebUI under PropertyOrder '3'."
},
"encoding" :
{
"type" : "string",
"title" : "edt_conf_enum_custom",
"default" : "auto",
"options" : {
"hidden":true
"standard": {
"type": "string",
"title": "edt_conf_v4l2_standard_title",
"default": "auto",
"required": true,
"propertyOrder": 5
},
"encoding": {
"type": "string",
"title": "edt_conf_v4l2_encoding_title",
"default": "auto",
"required": true,
"propertyOrder": 6
},
"resolutions": {
"type": "string",
"title": "edt_conf_v4l2_resolution_title",
"propertyOrder": 7,
"required": true
},
"width": {
"type": "integer",
"title": "edt_conf_fg_width_title",
"default": 0,
"minimum": 0,
"append": "edt_append_pixel",
"options": {
"hidden": true
},
"required" : true,
"propertyOrder" : 6,
"comment" : "The 'device_encodings' settings are dynamically inserted into the WebUI under PropertyOrder '5'."
"required": true,
"propertyOrder": 8,
"comment": "The 'resolutions' settings are dynamically inserted into the WebUI under PropertyOrder '7'."
},
"standard" :
{
"type" : "string",
"title" : "edt_conf_v4l2_standard_title",
"enum" : ["NO_CHANGE", "PAL","NTSC","SECAM"],
"default" : "NO_CHANGE",
"options" : {
"enum_titles" : ["edt_conf_enum_NO_CHANGE", "edt_conf_enum_PAL", "edt_conf_enum_NTSC", "edt_conf_enum_SECAM"]
"height": {
"type": "integer",
"title": "edt_conf_fg_height_title",
"default": 0,
"minimum": 0,
"append": "edt_append_pixel",
"options": {
"hidden": true
},
"required" : true,
"propertyOrder" : 7
"required": true,
"propertyOrder": 9,
"comment": "The 'resolutions' settings are dynamically inserted into the WebUI under PropertyOrder '7'."
},
"flip" :
{
"type" : "string",
"title" : "edt_conf_v4l2_flip_title",
"enum" : ["NO_CHANGE", "HORIZONTAL","VERTICAL","BOTH"],
"default" : "NO_CHANGE",
"options" : {
"enum_titles" : ["edt_conf_enum_NO_CHANGE", "edt_conf_enum_HORIZONTAL", "edt_conf_enum_VERTICAL", "edt_conf_enum_BOTH"]
"framerates": {
"type": "string",
"title": "edt_conf_v4l2_framerate_title",
"propertyOrder": 10,
"required": true
},
"fps": {
"type": "integer",
"title": "edt_conf_enum_custom",
"default": 15,
"minimum": 0,
"append": "fps",
"options": {
"hidden": true
},
"required" : true,
"propertyOrder" : 8
"required": true,
"propertyOrder": 11,
"comment": "The 'framerates' setting is dynamically inserted into the WebUI under PropertyOrder '10'."
},
"width" :
{
"type" : "integer",
"title" : "edt_conf_fg_width_title",
"default" : 0,
"minimum" : 0,
"append" : "edt_append_pixel",
"options" : {
"hidden":true
"fpsSoftwareDecimation": {
"type": "integer",
"title": "edt_conf_v4l2_fpsSoftwareDecimation_title",
"minimum": 0,
"maximum": 60,
"default": 0,
"required": true,
"access": "advanced",
"propertyOrder": 12
},
"flip": {
"type": "string",
"title": "edt_conf_v4l2_flip_title",
"enum": [ "NO_CHANGE", "HORIZONTAL", "VERTICAL", "BOTH" ],
"default": "NO_CHANGE",
"options": {
"enum_titles": [ "edt_conf_enum_NO_CHANGE", "edt_conf_enum_HORIZONTAL", "edt_conf_enum_VERTICAL", "edt_conf_enum_BOTH" ]
},
"required" : true,
"propertyOrder" : 10,
"comment" : "The 'resolutions' settings are dynamically inserted into the WebUI under PropertyOrder '9'."
"required": true,
"access": "advanced",
"propertyOrder": 13
},
"height" :
{
"type" : "integer",
"title" : "edt_conf_fg_height_title",
"default" : 0,
"minimum" : 0,
"append" : "edt_append_pixel",
"options" : {
"hidden":true
},
"required" : true,
"propertyOrder" : 11,
"comment" : "The 'resolutions' settings are dynamically inserted into the WebUI under PropertyOrder '9'."
"sizeDecimation": {
"type": "integer",
"title": "edt_conf_v4l2_sizeDecimation_title",
"minimum": 1,
"maximum": 30,
"default": 6,
"required": true,
"propertyOrder": 14
},
"fps" :
{
"type" : "integer",
"title" : "edt_conf_enum_custom",
"default" : 15,
"minimum" : 1,
"append" : "fps",
"options" : {
"hidden":true
},
"required" : true,
"propertyOrder" : 13,
"comment" : "The 'framerates' setting is dynamically inserted into the WebUI under PropertyOrder '12'."
"cropLeft": {
"type": "integer",
"title": "edt_conf_v4l2_cropLeft_title",
"minimum": 0,
"default": 0,
"append": "edt_append_pixel",
"required": true,
"access": "advanced",
"propertyOrder": 15
},
"fpsSoftwareDecimation" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_fpsSoftwareDecimation_title",
"minimum" : 0,
"maximum" : 60,
"default" : 0,
"required" : true,
"propertyOrder" : 14
"cropRight": {
"type": "integer",
"title": "edt_conf_v4l2_cropRight_title",
"minimum": 0,
"default": 0,
"append": "edt_append_pixel",
"required": true,
"access": "advanced",
"propertyOrder": 16
},
"sizeDecimation" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_sizeDecimation_title",
"minimum" : 1,
"maximum" : 30,
"default" : 6,
"required" : true,
"propertyOrder" : 15
"cropTop": {
"type": "integer",
"title": "edt_conf_v4l2_cropTop_title",
"minimum": 0,
"default": 0,
"append": "edt_append_pixel",
"required": true,
"access": "advanced",
"propertyOrder": 17
},
"cropLeft" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_cropLeft_title",
"minimum" : 0,
"default" : 0,
"append" : "edt_append_pixel",
"required" : true,
"propertyOrder" : 16
"cropBottom": {
"type": "integer",
"title": "edt_conf_v4l2_cropBottom_title",
"minimum": 0,
"default": 0,
"append": "edt_append_pixel",
"required": true,
"access": "advanced",
"propertyOrder": 18
},
"cropRight" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_cropRight_title",
"minimum" : 0,
"default" : 0,
"append" : "edt_append_pixel",
"required" : true,
"propertyOrder" : 17
"cecDetection": {
"type": "boolean",
"title": "edt_conf_v4l2_cecDetection_title",
"default": false,
"required": true,
"propertyOrder": 19
},
"cropTop" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_cropTop_title",
"minimum" : 0,
"default" : 0,
"append" : "edt_append_pixel",
"required" : true,
"propertyOrder" : 18
"signalDetection": {
"type": "boolean",
"title": "edt_conf_v4l2_signalDetection_title",
"default": false,
"required": true,
"access": "advanced",
"propertyOrder": 20
},
"cropBottom" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_cropBottom_title",
"minimum" : 0,
"default" : 0,
"append" : "edt_append_pixel",
"required" : true,
"propertyOrder" : 19
},
"cecDetection" :
{
"type" : "boolean",
"title" : "edt_conf_v4l2_cecDetection_title",
"default" : false,
"required" : true,
"propertyOrder" : 20
},
"signalDetection" :
{
"type" : "boolean",
"title" : "edt_conf_v4l2_signalDetection_title",
"default" : false,
"required" : true,
"propertyOrder" : 21
},
"redSignalThreshold" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_redSignalThreshold_title",
"minimum" : 0,
"maximum" : 100,
"default" : 5,
"append" : "edt_append_percent",
"redSignalThreshold": {
"type": "integer",
"title": "edt_conf_v4l2_redSignalThreshold_title",
"minimum": 0,
"maximum": 100,
"default": 5,
"append": "edt_append_percent",
"options": {
"dependencies": {
"signalDetection": true
}
},
"required" : true,
"propertyOrder" : 22
"access": "advanced",
"required": true,
"propertyOrder": 21
},
"greenSignalThreshold" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_greenSignalThreshold_title",
"minimum" : 0,
"maximum" : 100,
"default" : 5,
"append" : "edt_append_percent",
"greenSignalThreshold": {
"type": "integer",
"title": "edt_conf_v4l2_greenSignalThreshold_title",
"minimum": 0,
"maximum": 100,
"default": 5,
"append": "edt_append_percent",
"options": {
"dependencies": {
"signalDetection": true
}
},
"required" : true,
"propertyOrder" : 23
"required": true,
"access": "advanced",
"propertyOrder": 22
},
"blueSignalThreshold" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_blueSignalThreshold_title",
"minimum" : 0,
"maximum" : 100,
"default" : 5,
"append" : "edt_append_percent",
"blueSignalThreshold": {
"type": "integer",
"title": "edt_conf_v4l2_blueSignalThreshold_title",
"minimum": 0,
"maximum": 100,
"default": 5,
"append": "edt_append_percent",
"options": {
"dependencies": {
"signalDetection": true
}
},
"required" : true,
"propertyOrder" : 24
"required": true,
"access": "advanced",
"propertyOrder": 23
},
"noSignalCounterThreshold" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_noSignalCounterThreshold_title",
"minimum" : 1,
"maximum" : 1000,
"default" : 200,
"noSignalCounterThreshold": {
"type": "integer",
"title": "edt_conf_v4l2_noSignalCounterThreshold_title",
"minimum": 1,
"maximum": 1000,
"default": 200,
"options": {
"dependencies": {
"signalDetection": true
}
},
"required" : true,
"propertyOrder" : 25
"required": true,
"access": "advanced",
"propertyOrder": 24
},
"sDVOffsetMin" :
{
"type" : "number",
"title" : "edt_conf_v4l2_sDVOffsetMin_title",
"minimum" : 0.0,
"maximum" : 1.0,
"default" : 0.25,
"step" : 0.01,
"sDVOffsetMin": {
"type": "number",
"title": "edt_conf_v4l2_sDVOffsetMin_title",
"minimum": 0.0,
"maximum": 1.0,
"default": 0.25,
"step": 0.01,
"options": {
"dependencies": {
"signalDetection": true
}
},
"required" : true,
"propertyOrder" : 26
"required": true,
"access": "advanced",
"propertyOrder": 25
},
"sDVOffsetMax" :
{
"type" : "number",
"title" : "edt_conf_v4l2_sDVOffsetMax_title",
"minimum" : 0.0,
"maximum" : 1.0,
"default" : 0.75,
"step" : 0.01,
"sDVOffsetMax": {
"type": "number",
"title": "edt_conf_v4l2_sDVOffsetMax_title",
"minimum": 0.0,
"maximum": 1.0,
"default": 0.75,
"step": 0.01,
"options": {
"dependencies": {
"signalDetection": true
}
},
"required" : true,
"propertyOrder" : 27
"required": true,
"access": "advanced",
"propertyOrder": 26
},
"sDHOffsetMin" :
{
"type" : "number",
"title" : "edt_conf_v4l2_sDHOffsetMin_title",
"minimum" : 0.0,
"maximum" : 1.0,
"default" : 0.25,
"step" : 0.01,
"sDHOffsetMin": {
"type": "number",
"title": "edt_conf_v4l2_sDHOffsetMin_title",
"minimum": 0.0,
"maximum": 1.0,
"default": 0.25,
"step": 0.01,
"options": {
"dependencies": {
"signalDetection": true
}
},
"required" : true,
"propertyOrder" : 28
"required": true,
"access": "advanced",
"propertyOrder": 27
},
"sDHOffsetMax" :
{
"type" : "number",
"title" : "edt_conf_v4l2_sDHOffsetMax_title",
"minimum" : 0.0,
"maximum" : 1.0,
"default" : 0.75,
"step" : 0.01,
"sDHOffsetMax": {
"type": "number",
"title": "edt_conf_v4l2_sDHOffsetMax_title",
"minimum": 0.0,
"maximum": 1.0,
"default": 0.75,
"step": 0.01,
"options": {
"dependencies": {
"signalDetection": true
}
},
"required" : true,
"propertyOrder" : 29
"required": true,
"propertyOrder": 28
},
"hardware_brightness" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_hardware_brightness_title",
"default" : 0,
"required" : true,
"propertyOrder" : 30
"hardware_brightness": {
"type": "integer",
"title": "edt_conf_v4l2_hardware_brightness_title",
"default": 0,
"required": true,
"access": "advanced",
"propertyOrder": 29
},
"hardware_contrast" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_hardware_contrast_title",
"default" : 0,
"required" : true,
"propertyOrder" : 31
"hardware_contrast": {
"type": "integer",
"title": "edt_conf_v4l2_hardware_contrast_title",
"default": 0,
"required": true,
"access": "advanced",
"propertyOrder": 30
},
"hardware_saturation" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_hardware_saturation_title",
"default" : 0,
"required" : true,
"propertyOrder" : 32
"hardware_saturation": {
"type": "integer",
"title": "edt_conf_v4l2_hardware_saturation_title",
"default": 0,
"required": true,
"access": "advanced",
"propertyOrder": 31
},
"hardware_hue" :
{
"type" : "integer",
"title" : "edt_conf_v4l2_hardware_hue_title",
"default" : 0,
"required" : true,
"propertyOrder" : 33
"hardware_hue": {
"type": "integer",
"title": "edt_conf_v4l2_hardware_hue_title",
"default": 0,
"required": true,
"access": "advanced",
"propertyOrder": 32
}
},
"additionalProperties" : true
}
"additionalProperties": true
}