mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Nanoleaf fixes and enhancements
This commit is contained in:
parent
8f9d94e390
commit
1e85dac292
@ -10,13 +10,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Nanoleaf: Wizard to generate user authorization token allowing users to configure the device via a single window
|
||||||
|
- Nanoleaf: Generation of a default layout per device's configuration
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed missing Include limits in QJsonSchemaChecker
|
- Fixed missing Include limits in QJsonSchemaChecker
|
||||||
- Fixed dependencies for deb packages in Debian Bookworm
|
- Fixed dependencies for deb packages in Debian Bookworm
|
||||||
|
- Nanoleaf: "Panel numbering sequence" was not configurable any longer
|
||||||
|
- Nanoleaf: Number of panels increased during retries (#1643)
|
||||||
|
|
||||||
## Removed
|
## Removed
|
||||||
|
- Nanoleaf: Removed "Start Position" in favour of the general Blacklist feature provided
|
||||||
|
|
||||||
## [2.0.15](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.15) - 2023-02
|
## [2.0.15](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.15) - 2023-02
|
||||||
|
|
||||||
|
@ -46,6 +46,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer" style="text-align:right">
|
<div class="panel-footer" style="text-align:right">
|
||||||
|
<button id='btn_layout_controller' class="btn btn-primary" disabled data-toggle="tooltip" data-placement="top" title="Generate a layout for the configured device">
|
||||||
|
<i class="fa fa-fw fa-save"></i><span data-i18n="wiz_layout">Generate Layout</span>
|
||||||
|
</button>
|
||||||
<button id='btn_test_controller' class="btn btn-primary" disabled data-toggle="tooltip" data-placement="top" title="Identify configured device by lighting it up">
|
<button id='btn_test_controller' class="btn btn-primary" disabled data-toggle="tooltip" data-placement="top" title="Identify configured device by lighting it up">
|
||||||
<i class="fa fa-fw fa-save"></i><span data-i18n="wiz_identify">Identify/Test</span>
|
<i class="fa fa-fw fa-save"></i><span data-i18n="wiz_identify">Identify/Test</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -118,6 +118,8 @@
|
|||||||
"conf_leds_layout_cl_vleddepth": "Vertical LED depth",
|
"conf_leds_layout_cl_vleddepth": "Vertical LED depth",
|
||||||
"conf_leds_layout_frame": "Classic Layout (LED Frame)",
|
"conf_leds_layout_frame": "Classic Layout (LED Frame)",
|
||||||
"conf_leds_layout_generatedconf": "Generated/Current LED Configuration",
|
"conf_leds_layout_generatedconf": "Generated/Current LED Configuration",
|
||||||
|
"conf_leds_layout_generation_success": "LED Layout generated sucessfully",
|
||||||
|
"conf_leds_layout_generation_error": "LED Layout was not generated",
|
||||||
"conf_leds_layout_intro": "You also need an LED layout, which reflects your LED positions. The classic layout is the usually used TV frame, but we also support LED matrix (LED walls) creation. The view on this layout is ALWAYS from the FRONT of your TV.",
|
"conf_leds_layout_intro": "You also need an LED layout, which reflects your LED positions. The classic layout is the usually used TV frame, but we also support LED matrix (LED walls) creation. The view on this layout is ALWAYS from the FRONT of your TV.",
|
||||||
"conf_leds_layout_ma_cabling": "Cabling",
|
"conf_leds_layout_ma_cabling": "Cabling",
|
||||||
"conf_leds_layout_ma_direction": "Direction",
|
"conf_leds_layout_ma_direction": "Direction",
|
||||||
@ -1121,6 +1123,8 @@
|
|||||||
"wiz_identify": "Identify",
|
"wiz_identify": "Identify",
|
||||||
"wiz_identify_tip": "Identify configured device by lighting it up",
|
"wiz_identify_tip": "Identify configured device by lighting it up",
|
||||||
"wiz_identify_light": "Identify $1",
|
"wiz_identify_light": "Identify $1",
|
||||||
|
"wiz_layout": "Generate Layout",
|
||||||
|
"wiz_layout_tip": "Generate a layout for the configured device",
|
||||||
"wiz_ids_disabled": "Deactivated",
|
"wiz_ids_disabled": "Deactivated",
|
||||||
"wiz_ids_entire": "Whole picture",
|
"wiz_ids_entire": "Whole picture",
|
||||||
"wiz_nanoleaf_failure_auth_token": "Please press the Nanoleaf Power On/Off button within 30 seconds",
|
"wiz_nanoleaf_failure_auth_token": "Please press the Nanoleaf Power On/Off button within 30 seconds",
|
||||||
|
@ -1050,7 +1050,7 @@ $(document).ready(function () {
|
|||||||
// change save button state based on validation result
|
// change save button state based on validation result
|
||||||
conf_editor.validate().length || window.readOnlyMode ? $('#btn_submit_controller').prop('disabled', true) : $('#btn_submit_controller').prop('disabled', false);
|
conf_editor.validate().length || window.readOnlyMode ? $('#btn_submit_controller').prop('disabled', true) : $('#btn_submit_controller').prop('disabled', false);
|
||||||
|
|
||||||
// led controller sepecific wizards
|
// LED controller specific wizards
|
||||||
$('#btn_wiz_holder').html("");
|
$('#btn_wiz_holder').html("");
|
||||||
$('#btn_led_device_wiz').off();
|
$('#btn_led_device_wiz').off();
|
||||||
|
|
||||||
@ -1091,6 +1091,7 @@ $(document).ready(function () {
|
|||||||
var colorOrderDefault = "rgb";
|
var colorOrderDefault = "rgb";
|
||||||
var filter = {};
|
var filter = {};
|
||||||
|
|
||||||
|
$('#btn_layout_controller').hide();
|
||||||
$('#btn_test_controller').hide();
|
$('#btn_test_controller').hide();
|
||||||
|
|
||||||
switch (ledType) {
|
switch (ledType) {
|
||||||
@ -1351,7 +1352,7 @@ $(document).ready(function () {
|
|||||||
switch (ledType) {
|
switch (ledType) {
|
||||||
|
|
||||||
case "nanoleaf":
|
case "nanoleaf":
|
||||||
$('#btn_wiz_holder').hide();
|
$('#btn_wiz_holder').hide();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
@ -1684,6 +1685,33 @@ $(document).ready(function () {
|
|||||||
$("#leddevices").val(window.serverConfig.device.type);
|
$("#leddevices").val(window.serverConfig.device.type);
|
||||||
$("#leddevices").trigger("change");
|
$("#leddevices").trigger("change");
|
||||||
|
|
||||||
|
// Generate layout for LED-Device
|
||||||
|
$("#btn_layout_controller").off().on("click", function () {
|
||||||
|
var ledType = $("#leddevices").val();
|
||||||
|
var isGenerated = false;
|
||||||
|
|
||||||
|
switch (ledType) {
|
||||||
|
case "nanoleaf":
|
||||||
|
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
|
||||||
|
var ledDeviceProperties = devicesProperties[ledType][host];
|
||||||
|
if (ledDeviceProperties) {
|
||||||
|
var panelOrderTopDown = conf_editor.getEditor("root.specificOptions.panelOrderTopDown").getValue() === "top2down";
|
||||||
|
var panelOrderLeftRight = conf_editor.getEditor("root.specificOptions.panelOrderLeftRight").getValue() === "left2right";
|
||||||
|
var ledArray = nanoleafGeneratelayout(ledDeviceProperties.panelLayout.layout, panelOrderTopDown, panelOrderLeftRight);
|
||||||
|
aceEdt.set(ledArray);
|
||||||
|
isGenerated = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGenerated) {
|
||||||
|
showInfoDialog('success', "", $.i18n('conf_leds_layout_generation_success'));
|
||||||
|
} else {
|
||||||
|
showInfoDialog('error', "", $.i18n('conf_leds_layout_generation_error'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Identify/ Test LED-Device
|
// Identify/ Test LED-Device
|
||||||
$("#btn_test_controller").off().on("click", function () {
|
$("#btn_test_controller").off().on("click", function () {
|
||||||
var ledType = $("#leddevices").val();
|
var ledType = $("#leddevices").val();
|
||||||
@ -2163,6 +2191,7 @@ async function identify_device(type, params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateElements(ledType, key) {
|
function updateElements(ledType, key) {
|
||||||
|
var canLayout = false;
|
||||||
if (devicesProperties[ledType][key]) {
|
if (devicesProperties[ledType][key]) {
|
||||||
var hardwareLedCount = 1;
|
var hardwareLedCount = 1;
|
||||||
switch (ledType) {
|
switch (ledType) {
|
||||||
@ -2183,9 +2212,9 @@ function updateElements(ledType, key) {
|
|||||||
|
|
||||||
if (ledProperties) {
|
if (ledProperties) {
|
||||||
hardwareLedCount = ledProperties.ledCount;
|
hardwareLedCount = ledProperties.ledCount;
|
||||||
|
canLayout = true;
|
||||||
}
|
}
|
||||||
conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(hardwareLedCount);
|
conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(hardwareLedCount);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "udpraw":
|
case "udpraw":
|
||||||
@ -2234,11 +2263,19 @@ function updateElements(ledType, key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!conf_editor.validate().length) {
|
if (!conf_editor.validate().length) {
|
||||||
|
if (canLayout) {
|
||||||
|
$("#btn_layout_controller").show();
|
||||||
|
$('#btn_layout_controller').prop('disabled', false);
|
||||||
|
} else {
|
||||||
|
$('#btn_layout_controller').hide();
|
||||||
|
}
|
||||||
|
|
||||||
if (!window.readOnlyMode) {
|
if (!window.readOnlyMode) {
|
||||||
$('#btn_submit_controller').attr('disabled', false);
|
$('#btn_submit_controller').attr('disabled', false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
$('#btn_layout_controller').prop('disabled', true);
|
||||||
$('#btn_submit_controller').attr('disabled', true);
|
$('#btn_submit_controller').attr('disabled', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2416,4 +2453,112 @@ function updateElementsWled(ledType, key) {
|
|||||||
}
|
}
|
||||||
showInputOptionForItem(conf_editor, "root.specificOptions.segments", "switchOffOtherSegments", showAdditionalOptions);
|
showInputOptionForItem(conf_editor, "root.specificOptions.segments", "switchOffOtherSegments", showAdditionalOptions);
|
||||||
}
|
}
|
||||||
|
function sortByPanelCoordinates(arr, topToBottom, leftToRight) {
|
||||||
|
arr.sort((a, b) => {
|
||||||
|
//Nanoleaf corodinates start at bottom left, therefore reverse topToBottom
|
||||||
|
if (!topToBottom) {
|
||||||
|
if (a.y === b.y) {
|
||||||
|
if (leftToRight) {
|
||||||
|
return a.x - b.x;
|
||||||
|
} else {
|
||||||
|
return b.x - a.x;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return a.y - b.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (a.y === b.y) {
|
||||||
|
if (leftToRight) {
|
||||||
|
return a.x - b.x;
|
||||||
|
} else {
|
||||||
|
return b.x - a.x;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return b.y - a.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function nanoleafGeneratelayout(layout, panelOrderTopDown, panelOrderLeftRight) {
|
||||||
|
|
||||||
|
// Dictionary for Nanoleaf shape types
|
||||||
|
let shapeTypes = {
|
||||||
|
0: { name: "LightsTriangle", sideLengthX: 150, sideLengthY: 150 },
|
||||||
|
1: { name: "LightsRythm", sideLengthX: 0, sideLengthY: 0 },
|
||||||
|
2: { name: "Square", sideLengthX: 100, sideLengthY: 100 },
|
||||||
|
3: { name: "SquareControllerMaster", sideLengthX: 100, sideLengthY: 100 },
|
||||||
|
4: { name: "SquareControllerPassive", sideLengthX: 100, sideLengthY: 100 },
|
||||||
|
5: { name: "PowerSupply", sideLengthX: 100, sideLengthY: 100 },
|
||||||
|
7: { name: "ShapesHexagon", sideLengthX: 67, sideLengthY: 67 },
|
||||||
|
8: { name: "ShapesTriangle", sideLengthX: 134, sideLengthY: 134 },
|
||||||
|
9: { name: "ShapesMiniTriangle", sideLengthX: 67, sideLengthY: 67 },
|
||||||
|
12: { name: "ShapesController", sideLengthX: 0, sideLengthY: 0 },
|
||||||
|
14: { name: "ElementsHexagon", sideLengthX: 134, sideLengthY: 134 },
|
||||||
|
15: { name: "ElementsHexagonCorner", sideLengthX: 33.5, sideLengthX: 58 },
|
||||||
|
16: { name: "LinesConnector", sideLengthX: 11, sideLengthY: 11 },
|
||||||
|
17: { name: "LightLines", sideLengthX: 154, sideLengthY: 154 },
|
||||||
|
18: { name: "LightLinesSingleZone", sideLengthX: 77, sideLengthY: 77 },
|
||||||
|
19: { name: "ControllerCap", sideLengthX: 11, sideLengthY: 11 },
|
||||||
|
20: { name: "PowerConnector", sideLengthX: 11, sideLengthY: 11 },
|
||||||
|
999: { name: "Unknown", sideLengthX: 100, sideLengthY: 100 }
|
||||||
|
};
|
||||||
|
|
||||||
|
let { positionData, numPanels, sideLength } = layout;
|
||||||
|
var minX = positionData[0].x;
|
||||||
|
var maxX = positionData[0].x;
|
||||||
|
var minY = positionData[0].y;
|
||||||
|
var maxY = positionData[0].y;
|
||||||
|
|
||||||
|
//Define capture rectangle per panel
|
||||||
|
var factorPartial = 0.25;
|
||||||
|
positionData.forEach(panel => {
|
||||||
|
|
||||||
|
if (shapeTypes[panel.shapeType] == undefined) {
|
||||||
|
panel.shapeType = 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
panel.maxX = panel.x + shapeTypes[panel.shapeType].sideLengthX * factorPartial;
|
||||||
|
panel.maxY = panel.y + shapeTypes[panel.shapeType].sideLengthY * factorPartial;
|
||||||
|
panel.shapeName = shapeTypes[panel.shapeType].name;
|
||||||
|
|
||||||
|
if (panel.maxX > maxX) {
|
||||||
|
maxX = panel.maxX;
|
||||||
|
}
|
||||||
|
if (panel.x < minX) {
|
||||||
|
minX = panel.x;
|
||||||
|
}
|
||||||
|
if (panel.maxY > maxY) {
|
||||||
|
maxY = panel.maxY;
|
||||||
|
}
|
||||||
|
if (panel.y < minY) {
|
||||||
|
minY = panel.y
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const width = (maxX - minX);
|
||||||
|
const height = (maxY - minY);
|
||||||
|
const scaleX = 1 / width;
|
||||||
|
const scaleY = 1 / height;
|
||||||
|
|
||||||
|
var layoutObjects = [];
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
sortByPanelCoordinates(positionData, panelOrderTopDown, panelOrderLeftRight);
|
||||||
|
positionData.forEach(panel => {
|
||||||
|
|
||||||
|
let layoutObject = {
|
||||||
|
name: i + "-" + panel.panelId,
|
||||||
|
hmin: (panel.x - minX) * scaleX,
|
||||||
|
hmax: (panel.maxX - minX) * scaleX,
|
||||||
|
//Nanoleaf corodinates start at bottom left, therefore reverse vertical positioning
|
||||||
|
vmin: 1 - ((panel.maxY - minY) * scaleY),
|
||||||
|
vmax: 1 - ((panel.y - minY) * scaleY)
|
||||||
|
};
|
||||||
|
++i;
|
||||||
|
|
||||||
|
layoutObjects.push(JSON.parse(JSON.stringify(layoutObject)));
|
||||||
|
});
|
||||||
|
return layoutObjects;
|
||||||
|
}
|
||||||
|
@ -2240,7 +2240,7 @@ function createNanoleafUserAuthorization() {
|
|||||||
abortConnection(UserInterval);
|
abortConnection(UserInterval);
|
||||||
clearInterval(UserInterval);
|
clearInterval(UserInterval);
|
||||||
|
|
||||||
showNotification('warning', $.i18n('wiz_nanoleaf_failure_auth_token'), $.i18n('wiz_nanoleaf_failure_auth_token_t'))
|
showNotification('warning', $.i18n('wiz_nanoleaf_failure_auth_token'), $.i18n('wiz_nanoleaf_failure_auth_token_t'));
|
||||||
|
|
||||||
resetWizard(true);
|
resetWizard(true);
|
||||||
}
|
}
|
||||||
|
@ -21,19 +21,19 @@ using namespace semver;
|
|||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
namespace {
|
namespace {
|
||||||
const char DEFAULT_VERSION[] = "2.0.0-alpha.8";
|
const char DEFAULT_VERSION[] = "2.0.0-alpha.8";
|
||||||
} //End of constants
|
} //End of constants
|
||||||
|
|
||||||
QJsonObject SettingsManager::schemaJson;
|
QJsonObject SettingsManager::schemaJson;
|
||||||
|
|
||||||
SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonlyMode)
|
SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonlyMode)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, _log(Logger::getInstance("SETTINGSMGR", "I"+QString::number(instance)))
|
, _log(Logger::getInstance("SETTINGSMGR", "I" + QString::number(instance)))
|
||||||
, _instance(instance)
|
, _instance(instance)
|
||||||
, _sTable(new SettingsTable(instance, this))
|
, _sTable(new SettingsTable(instance, this))
|
||||||
, _configVersion(DEFAULT_VERSION)
|
, _configVersion(DEFAULT_VERSION)
|
||||||
, _previousVersion(DEFAULT_VERSION)
|
, _previousVersion(DEFAULT_VERSION)
|
||||||
, _readonlyMode(readonlyMode)
|
, _readonlyMode(readonlyMode)
|
||||||
{
|
{
|
||||||
_sTable->setReadonlyMode(_readonlyMode);
|
_sTable->setReadonlyMode(_readonlyMode);
|
||||||
// get schema
|
// get schema
|
||||||
@ -739,12 +739,12 @@ bool SettingsManager::handleConfigUpgrade(QJsonObject& config)
|
|||||||
{
|
{
|
||||||
QString type = newDeviceConfig["type"].toString();
|
QString type = newDeviceConfig["type"].toString();
|
||||||
|
|
||||||
const QStringList serialDevices {"adalight", "dmx", "atmo", "sedu", "tpm2", "karate"};
|
const QStringList serialDevices{ "adalight", "dmx", "atmo", "sedu", "tpm2", "karate" };
|
||||||
if ( serialDevices.contains(type ))
|
if (serialDevices.contains(type))
|
||||||
{
|
{
|
||||||
if (!newDeviceConfig.contains("rateList"))
|
if (!newDeviceConfig.contains("rateList"))
|
||||||
{
|
{
|
||||||
newDeviceConfig["rateList"] = "CUSTOM";
|
newDeviceConfig["rateList"] = "CUSTOM";
|
||||||
migrated = true;
|
migrated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -791,7 +791,7 @@ bool SettingsManager::handleConfigUpgrade(QJsonObject& config)
|
|||||||
if (newDeviceConfig.contains("type"))
|
if (newDeviceConfig.contains("type"))
|
||||||
{
|
{
|
||||||
QString type = newDeviceConfig["type"].toString();
|
QString type = newDeviceConfig["type"].toString();
|
||||||
if ( type == "philipshue")
|
if (type == "philipshue")
|
||||||
{
|
{
|
||||||
if (newDeviceConfig.contains("groupId"))
|
if (newDeviceConfig.contains("groupId"))
|
||||||
{
|
{
|
||||||
@ -805,7 +805,7 @@ bool SettingsManager::handleConfigUpgrade(QJsonObject& config)
|
|||||||
|
|
||||||
if (newDeviceConfig.contains("lightIds"))
|
if (newDeviceConfig.contains("lightIds"))
|
||||||
{
|
{
|
||||||
QJsonArray lightIds = newDeviceConfig.value( "lightIds").toArray();
|
QJsonArray lightIds = newDeviceConfig.value("lightIds").toArray();
|
||||||
// Iterate through the JSON array and update integer values to strings
|
// Iterate through the JSON array and update integer values to strings
|
||||||
for (int i = 0; i < lightIds.size(); ++i) {
|
for (int i = 0; i < lightIds.size(); ++i) {
|
||||||
QJsonValue value = lightIds.at(i);
|
QJsonValue value = lightIds.at(i);
|
||||||
@ -820,6 +820,69 @@ bool SettingsManager::handleConfigUpgrade(QJsonObject& config)
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == "nanoleaf")
|
||||||
|
{
|
||||||
|
if (newDeviceConfig.contains("panelStartPos"))
|
||||||
|
{
|
||||||
|
newDeviceConfig.remove("panelStartPos");
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newDeviceConfig.contains("panelOrderTopDown"))
|
||||||
|
{
|
||||||
|
QString panelOrderTopDown;
|
||||||
|
if (newDeviceConfig["panelOrderTopDown"].isDouble())
|
||||||
|
{
|
||||||
|
panelOrderTopDown = QString(newDeviceConfig["panelOrderTopDown"].toInt());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
panelOrderTopDown = newDeviceConfig["panelOrderTopDown"].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newDeviceConfig["panelOrderTopDown"] == "0")
|
||||||
|
{
|
||||||
|
newDeviceConfig["panelOrderTopDown"] = "top2down";
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (newDeviceConfig["panelOrderTopDown"] == "1")
|
||||||
|
{
|
||||||
|
newDeviceConfig["panelOrderTopDown"] = "bottom2up";
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newDeviceConfig.contains("panelOrderLeftRight"))
|
||||||
|
{
|
||||||
|
QString panelOrderLeftRight;
|
||||||
|
if (newDeviceConfig["panelOrderLeftRight"].isDouble())
|
||||||
|
{
|
||||||
|
panelOrderLeftRight = QString(newDeviceConfig["panelOrderLeftRight"].toInt());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
panelOrderLeftRight = newDeviceConfig["panelOrderLeftRight"].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newDeviceConfig["panelOrderLeftRight"] == "0")
|
||||||
|
{
|
||||||
|
newDeviceConfig["panelOrderLeftRight"] = "left2right";
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (newDeviceConfig["panelOrderLeftRight"] == "1")
|
||||||
|
{
|
||||||
|
newDeviceConfig["panelOrderTopDown"] = "right2left";
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (migrated)
|
if (migrated)
|
||||||
|
@ -21,73 +21,72 @@
|
|||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
namespace {
|
namespace {
|
||||||
const bool verbose = false;
|
const bool verbose = false;
|
||||||
const bool verbose3 = false;
|
const bool verbose3 = false;
|
||||||
|
|
||||||
// Configuration settings
|
// Configuration settings
|
||||||
const char CONFIG_HOST[] = "host";
|
const char CONFIG_HOST[] = "host";
|
||||||
const char CONFIG_AUTH_TOKEN[] = "token";
|
const char CONFIG_AUTH_TOKEN[] = "token";
|
||||||
const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
|
const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
|
||||||
const char CONFIG_BRIGHTNESS[] = "brightness";
|
const char CONFIG_BRIGHTNESS[] = "brightness";
|
||||||
const char CONFIG_BRIGHTNESS_OVERWRITE[] = "overwriteBrightness";
|
const char CONFIG_BRIGHTNESS_OVERWRITE[] = "overwriteBrightness";
|
||||||
|
|
||||||
const char CONFIG_PANEL_ORDER_TOP_DOWN[] = "panelOrderTopDown";
|
const char CONFIG_PANEL_ORDER_TOP_DOWN[] = "panelOrderTopDown";
|
||||||
const char CONFIG_PANEL_ORDER_LEFT_RIGHT[] = "panelOrderLeftRight";
|
const char CONFIG_PANEL_ORDER_LEFT_RIGHT[] = "panelOrderLeftRight";
|
||||||
const char CONFIG_PANEL_START_POS[] = "panelStartPos";
|
|
||||||
|
|
||||||
const bool DEFAULT_IS_RESTORE_STATE = true;
|
const bool DEFAULT_IS_RESTORE_STATE = true;
|
||||||
const bool DEFAULT_IS_BRIGHTNESS_OVERWRITE = true;
|
const bool DEFAULT_IS_BRIGHTNESS_OVERWRITE = true;
|
||||||
const int BRI_MAX = 100;
|
const int BRI_MAX = 100;
|
||||||
|
|
||||||
// Panel configuration settings
|
// Panel configuration settings
|
||||||
const char PANEL_LAYOUT[] = "layout";
|
const char PANEL_LAYOUT[] = "layout";
|
||||||
const char PANEL_NUM[] = "numPanels";
|
const char PANEL_NUM[] = "numPanels";
|
||||||
const char PANEL_ID[] = "panelId";
|
const char PANEL_ID[] = "panelId";
|
||||||
const char PANEL_POSITIONDATA[] = "positionData";
|
const char PANEL_POSITIONDATA[] = "positionData";
|
||||||
const char PANEL_SHAPE_TYPE[] = "shapeType";
|
const char PANEL_SHAPE_TYPE[] = "shapeType";
|
||||||
const char PANEL_POS_X[] = "x";
|
const char PANEL_POS_X[] = "x";
|
||||||
const char PANEL_POS_Y[] = "y";
|
const char PANEL_POS_Y[] = "y";
|
||||||
|
|
||||||
// List of State Information
|
// List of State Information
|
||||||
const char STATE_ON[] = "on";
|
const char STATE_ON[] = "on";
|
||||||
const char STATE_BRI[] = "brightness";
|
const char STATE_BRI[] = "brightness";
|
||||||
const char STATE_HUE[] = "hue";
|
const char STATE_HUE[] = "hue";
|
||||||
const char STATE_SAT[] = "sat";
|
const char STATE_SAT[] = "sat";
|
||||||
const char STATE_CT[] = "ct";
|
const char STATE_CT[] = "ct";
|
||||||
const char STATE_COLORMODE[] = "colorMode";
|
const char STATE_COLORMODE[] = "colorMode";
|
||||||
const QStringList COLOR_MODES {"hs", "ct", "effect"};
|
const QStringList COLOR_MODES{ "hs", "ct", "effect" };
|
||||||
const char STATE_VALUE[] = "value";
|
const char STATE_VALUE[] = "value";
|
||||||
|
|
||||||
// Device Data elements
|
// Device Data elements
|
||||||
const char DEV_DATA_NAME[] = "name";
|
const char DEV_DATA_NAME[] = "name";
|
||||||
const char DEV_DATA_MODEL[] = "model";
|
const char DEV_DATA_MODEL[] = "model";
|
||||||
const char DEV_DATA_MANUFACTURER[] = "manufacturer";
|
const char DEV_DATA_MANUFACTURER[] = "manufacturer";
|
||||||
const char DEV_DATA_FIRMWAREVERSION[] = "firmwareVersion";
|
const char DEV_DATA_FIRMWAREVERSION[] = "firmwareVersion";
|
||||||
|
|
||||||
// Nanoleaf Stream Control elements
|
// Nanoleaf Stream Control elements
|
||||||
const quint16 STREAM_CONTROL_DEFAULT_PORT = 60222;
|
const quint16 STREAM_CONTROL_DEFAULT_PORT = 60222;
|
||||||
|
|
||||||
// Nanoleaf OpenAPI URLs
|
// Nanoleaf OpenAPI URLs
|
||||||
const int API_DEFAULT_PORT = 16021;
|
const int API_DEFAULT_PORT = 16021;
|
||||||
const char API_BASE_PATH[] = "/api/v1/%1/";
|
const char API_BASE_PATH[] = "/api/v1/%1/";
|
||||||
const char API_ROOT[] = "";
|
const char API_ROOT[] = "";
|
||||||
const char API_EXT_MODE_STRING_V2[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\", \"extControlVersion\" : \"v2\"}}";
|
const char API_EXT_MODE_STRING_V2[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\", \"extControlVersion\" : \"v2\"}}";
|
||||||
const char API_STATE[] = "state";
|
const char API_STATE[] = "state";
|
||||||
const char API_PANELLAYOUT[] = "panelLayout";
|
const char API_PANELLAYOUT[] = "panelLayout";
|
||||||
const char API_EFFECT[] = "effects";
|
const char API_EFFECT[] = "effects";
|
||||||
const char API_IDENTIFY[] = "identify";
|
const char API_IDENTIFY[] = "identify";
|
||||||
const char API_ADD_USER[] = "new";
|
const char API_ADD_USER[] = "new";
|
||||||
const char API_EFFECT_SELECT[] = "select";
|
const char API_EFFECT_SELECT[] = "select";
|
||||||
|
|
||||||
//Nanoleaf Control data stream
|
//Nanoleaf Control data stream
|
||||||
const int STREAM_FRAME_PANEL_NUM_SIZE = 2;
|
const int STREAM_FRAME_PANEL_NUM_SIZE = 2;
|
||||||
const int STREAM_FRAME_PANEL_INFO_SIZE = 8;
|
const int STREAM_FRAME_PANEL_INFO_SIZE = 8;
|
||||||
|
|
||||||
// Nanoleaf ssdp services
|
// Nanoleaf ssdp services
|
||||||
const char SSDP_ID[] = "ssdp:all";
|
const char SSDP_ID[] = "ssdp:all";
|
||||||
const char SSDP_FILTER_HEADER[] = "ST";
|
const char SSDP_FILTER_HEADER[] = "ST";
|
||||||
const char SSDP_NANOLEAF[] = "nanoleaf:nl*";
|
const char SSDP_NANOLEAF[] = "nanoleaf:nl*";
|
||||||
const char SSDP_LIGHTPANELS[] = "nanoleaf_aurora:light";
|
const char SSDP_LIGHTPANELS[] = "nanoleaf_aurora:light";
|
||||||
} //End of constants
|
} //End of constants
|
||||||
|
|
||||||
// Nanoleaf Panel Shapetypes
|
// Nanoleaf Panel Shapetypes
|
||||||
@ -97,7 +96,7 @@ enum SHAPETYPES {
|
|||||||
SQUARE = 2,
|
SQUARE = 2,
|
||||||
CONTROL_SQUARE_PRIMARY = 3,
|
CONTROL_SQUARE_PRIMARY = 3,
|
||||||
CONTROL_SQUARE_PASSIVE = 4,
|
CONTROL_SQUARE_PASSIVE = 4,
|
||||||
POWER_SUPPLY= 5,
|
POWER_SUPPLY = 5,
|
||||||
HEXAGON_SHAPES = 7,
|
HEXAGON_SHAPES = 7,
|
||||||
TRIANGE_SHAPES = 8,
|
TRIANGE_SHAPES = 8,
|
||||||
MINI_TRIANGE_SHAPES = 9,
|
MINI_TRIANGE_SHAPES = 9,
|
||||||
@ -119,18 +118,16 @@ enum EXTCONTROLVERSIONS {
|
|||||||
|
|
||||||
LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject& deviceConfig)
|
LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject& deviceConfig)
|
||||||
: ProviderUdp(deviceConfig)
|
: ProviderUdp(deviceConfig)
|
||||||
, _restApi(nullptr)
|
, _restApi(nullptr)
|
||||||
, _apiPort(API_DEFAULT_PORT)
|
, _apiPort(API_DEFAULT_PORT)
|
||||||
, _topDown(true)
|
, _topDown(true)
|
||||||
, _leftRight(true)
|
, _leftRight(true)
|
||||||
, _startPos(0)
|
, _extControlVersion(EXTCTRLVER_V2)
|
||||||
, _endPos(0)
|
, _panelLedCount(0)
|
||||||
, _extControlVersion(EXTCTRLVER_V2)
|
|
||||||
, _panelLedCount(0)
|
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_MDNS
|
#ifdef ENABLE_MDNS
|
||||||
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||||
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
|
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +144,7 @@ LedDeviceNanoleaf::~LedDeviceNanoleaf()
|
|||||||
|
|
||||||
bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
||||||
{
|
{
|
||||||
bool isInitOK {false};
|
bool isInitOK{ false };
|
||||||
|
|
||||||
// Overwrite non supported/required features
|
// Overwrite non supported/required features
|
||||||
setLatchTime(0);
|
setLatchTime(0);
|
||||||
@ -158,9 +155,9 @@ bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
|||||||
Info(_log, "Device Nanoleaf does not require rewrites. Refresh time is ignored.");
|
Info(_log, "Device Nanoleaf does not require rewrites. Refresh time is ignored.");
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugIf(verbose,_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
if ( ProviderUdp::init(deviceConfig) )
|
if (ProviderUdp::init(deviceConfig))
|
||||||
{
|
{
|
||||||
//Set hostname as per configuration and default port
|
//Set hostname as per configuration and default port
|
||||||
_hostName = deviceConfig[CONFIG_HOST].toString();
|
_hostName = deviceConfig[CONFIG_HOST].toString();
|
||||||
@ -172,30 +169,14 @@ bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
|||||||
_isBrightnessOverwrite = _devConfig[CONFIG_BRIGHTNESS_OVERWRITE].toBool(DEFAULT_IS_BRIGHTNESS_OVERWRITE);
|
_isBrightnessOverwrite = _devConfig[CONFIG_BRIGHTNESS_OVERWRITE].toBool(DEFAULT_IS_BRIGHTNESS_OVERWRITE);
|
||||||
_brightness = _devConfig[CONFIG_BRIGHTNESS].toInt(BRI_MAX);
|
_brightness = _devConfig[CONFIG_BRIGHTNESS].toInt(BRI_MAX);
|
||||||
|
|
||||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostName) );
|
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostName));
|
||||||
Debug(_log, "RestoreOrigState : %d", _isRestoreOrigState);
|
Debug(_log, "RestoreOrigState : %d", _isRestoreOrigState);
|
||||||
Debug(_log, "Overwrite Brightn.: %d", _isBrightnessOverwrite);
|
Debug(_log, "Overwrite Brightn.: %d", _isBrightnessOverwrite);
|
||||||
Debug(_log, "Set Brightness to : %d", _brightness);
|
Debug(_log, "Set Brightness to : %d", _brightness);
|
||||||
|
|
||||||
// Read panel organisation configuration
|
// Read panel organisation configuration
|
||||||
if (deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].isString())
|
_topDown = deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].toString("top2down") == "top2down";
|
||||||
{
|
_leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toString("left2right") == "left2right";
|
||||||
_topDown = deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].toString().toInt() == 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_topDown = deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].toInt() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].isString())
|
|
||||||
{
|
|
||||||
_leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toString().toInt() == 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toInt() == 0;
|
|
||||||
}
|
|
||||||
_startPos = deviceConfig[CONFIG_PANEL_START_POS].toInt(0);
|
|
||||||
|
|
||||||
isInitOK = true;
|
isInitOK = true;
|
||||||
}
|
}
|
||||||
@ -204,16 +185,16 @@ bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
|||||||
|
|
||||||
int LedDeviceNanoleaf::getHwLedCount(const QJsonObject& jsonLayout) const
|
int LedDeviceNanoleaf::getHwLedCount(const QJsonObject& jsonLayout) const
|
||||||
{
|
{
|
||||||
int hwLedCount {0};
|
int hwLedCount{ 0 };
|
||||||
|
|
||||||
const QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
|
const QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
|
||||||
for(const QJsonValue & value : positionData)
|
for (const QJsonValue& value : positionData)
|
||||||
{
|
{
|
||||||
QJsonObject panelObj = value.toObject();
|
QJsonObject panelObj = value.toObject();
|
||||||
int panelId = panelObj[PANEL_ID].toInt();
|
int panelId = panelObj[PANEL_ID].toInt();
|
||||||
int panelshapeType = panelObj[PANEL_SHAPE_TYPE].toInt();
|
int panelshapeType = panelObj[PANEL_SHAPE_TYPE].toInt();
|
||||||
|
|
||||||
DebugIf(verbose,_log, "Panel [%d] - Type: [%d]", panelId, panelshapeType);
|
DebugIf(verbose, _log, "Panel [%d] - Type: [%d]", panelId, panelshapeType);
|
||||||
|
|
||||||
// Skip Rhythm and Shapes controller panels
|
// Skip Rhythm and Shapes controller panels
|
||||||
if (panelshapeType != RHYTM && panelshapeType != SHAPES_CONTROLLER)
|
if (panelshapeType != RHYTM && panelshapeType != SHAPES_CONTROLLER)
|
||||||
@ -240,7 +221,7 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
|||||||
if (response.error())
|
if (response.error())
|
||||||
{
|
{
|
||||||
QString errorReason = QString("Getting device details failed with error: '%1'").arg(response.getErrorReason());
|
QString errorReason = QString("Getting device details failed with error: '%1'").arg(response.getErrorReason());
|
||||||
this->setInError ( errorReason );
|
this->setInError(errorReason);
|
||||||
isInitOK = false;
|
isInitOK = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -262,6 +243,7 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
|||||||
QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject();
|
QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject();
|
||||||
|
|
||||||
_panelLedCount = getHwLedCount(jsonLayout);
|
_panelLedCount = getHwLedCount(jsonLayout);
|
||||||
|
_devConfig["hardwareLedCount"] = _panelLedCount;
|
||||||
|
|
||||||
int panelNum = jsonLayout[PANEL_NUM].toInt();
|
int panelNum = jsonLayout[PANEL_NUM].toInt();
|
||||||
const QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
|
const QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
|
||||||
@ -269,7 +251,7 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
|||||||
std::map<int, std::map<int, int>> panelMap;
|
std::map<int, std::map<int, int>> panelMap;
|
||||||
|
|
||||||
// Loop over all children.
|
// Loop over all children.
|
||||||
for(const QJsonValue & value : positionData)
|
for (const QJsonValue& value : positionData)
|
||||||
{
|
{
|
||||||
QJsonObject panelObj = value.toObject();
|
QJsonObject panelObj = value.toObject();
|
||||||
|
|
||||||
@ -278,7 +260,7 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
|||||||
int panelY = panelObj[PANEL_POS_Y].toInt();
|
int panelY = panelObj[PANEL_POS_Y].toInt();
|
||||||
int panelshapeType = panelObj[PANEL_SHAPE_TYPE].toInt();
|
int panelshapeType = panelObj[PANEL_SHAPE_TYPE].toInt();
|
||||||
|
|
||||||
DebugIf(verbose,_log, "Panel [%d] (%d,%d) - Type: [%d]", panelId, panelX, panelY, panelshapeType);
|
DebugIf(verbose, _log, "Panel [%d] (%d,%d) - Type: [%d]", panelId, panelX, panelY, panelshapeType);
|
||||||
|
|
||||||
// Skip Rhythm and Shapes controller panels
|
// Skip Rhythm and Shapes controller panels
|
||||||
if (panelshapeType != RHYTM && panelshapeType != SHAPES_CONTROLLER)
|
if (panelshapeType != RHYTM && panelshapeType != SHAPES_CONTROLLER)
|
||||||
@ -331,25 +313,18 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_devConfig["hardwareLedCount"] = _panelLedCount;
|
|
||||||
|
|
||||||
Debug(_log, "PanelsNum : %d", panelNum);
|
Debug(_log, "PanelsNum : %d", panelNum);
|
||||||
Debug(_log, "PanelLedCount : %d", _panelLedCount);
|
Debug(_log, "PanelLedCount : %d", _panelLedCount);
|
||||||
|
Debug(_log, "Sort Top>Down : %d", _topDown);
|
||||||
|
Debug(_log, "Sort Left>Right: %d", _leftRight);
|
||||||
|
|
||||||
// Check. if enough panels were found.
|
// Check. if enough panels were found.
|
||||||
int configuredLedCount = this->getLedCount();
|
int configuredLedCount = this->getLedCount();
|
||||||
_endPos = _startPos + configuredLedCount - 1;
|
|
||||||
|
|
||||||
Debug(_log, "Sort Top>Down : %d", _topDown);
|
|
||||||
Debug(_log, "Sort Left>Right: %d", _leftRight);
|
|
||||||
Debug(_log, "Start Panel Pos: %d", _startPos);
|
|
||||||
Debug(_log, "End Panel Pos : %d", _endPos);
|
|
||||||
|
|
||||||
if (_panelLedCount < configuredLedCount)
|
if (_panelLedCount < configuredLedCount)
|
||||||
{
|
{
|
||||||
QString errorReason = QString("Not enough panels [%1] for configured LEDs [%2] found!")
|
QString errorReason = QString("Not enough panels [%1] for configured LEDs [%2] found!")
|
||||||
.arg(_panelLedCount)
|
.arg(_panelLedCount)
|
||||||
.arg(configuredLedCount);
|
.arg(configuredLedCount);
|
||||||
this->setInError(errorReason, false);
|
this->setInError(errorReason, false);
|
||||||
isInitOK = false;
|
isInitOK = false;
|
||||||
}
|
}
|
||||||
@ -359,16 +334,6 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
|||||||
{
|
{
|
||||||
Info(_log, "%s: More panels [%d] than configured LEDs [%d].", QSTRING_CSTR(this->getActiveDeviceType()), _panelLedCount, configuredLedCount);
|
Info(_log, "%s: More panels [%d] than configured LEDs [%d].", QSTRING_CSTR(this->getActiveDeviceType()), _panelLedCount, configuredLedCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check, if start position + number of configured LEDs is greater than number of panels available
|
|
||||||
if (_endPos >= _panelLedCount)
|
|
||||||
{
|
|
||||||
QString errorReason = QString("Start panel [%1] out of range. Start panel position can be max [%2] given [%3] panel available!")
|
|
||||||
.arg(_startPos).arg(_panelLedCount - configuredLedCount).arg(_panelLedCount);
|
|
||||||
|
|
||||||
this->setInError(errorReason, false);
|
|
||||||
isInitOK = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isInitOK;
|
return isInitOK;
|
||||||
@ -376,7 +341,7 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
|||||||
|
|
||||||
bool LedDeviceNanoleaf::openRestAPI()
|
bool LedDeviceNanoleaf::openRestAPI()
|
||||||
{
|
{
|
||||||
bool isInitOK {true};
|
bool isInitOK{ true };
|
||||||
|
|
||||||
if (_restApi == nullptr)
|
if (_restApi == nullptr)
|
||||||
{
|
{
|
||||||
@ -396,7 +361,7 @@ int LedDeviceNanoleaf::open()
|
|||||||
|
|
||||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||||
{
|
{
|
||||||
if ( openRestAPI() )
|
if (openRestAPI())
|
||||||
{
|
{
|
||||||
// Read LedDevice configuration and validate against device configuration
|
// Read LedDevice configuration and validate against device configuration
|
||||||
if (initLedsConfiguration())
|
if (initLedsConfiguration())
|
||||||
@ -451,7 +416,7 @@ QJsonObject LedDeviceNanoleaf::discover(const QJsonObject& /*params*/)
|
|||||||
MdnsServiceRegister::getServiceType(_activeDeviceType),
|
MdnsServiceRegister::getServiceType(_activeDeviceType),
|
||||||
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
|
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
|
||||||
DEFAULT_DISCOVER_TIMEOUT
|
DEFAULT_DISCOVER_TIMEOUT
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
QString discoveryMethod("ssdp");
|
QString discoveryMethod("ssdp");
|
||||||
deviceList = discover();
|
deviceList = discover();
|
||||||
@ -460,25 +425,25 @@ QJsonObject LedDeviceNanoleaf::discover(const QJsonObject& /*params*/)
|
|||||||
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
||||||
devicesDiscovered.insert("devices", deviceList);
|
devicesDiscovered.insert("devices", deviceList);
|
||||||
|
|
||||||
DebugIf(verbose,_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose, _log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
return devicesDiscovered;
|
return devicesDiscovered;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject LedDeviceNanoleaf::getProperties(const QJsonObject& params)
|
QJsonObject LedDeviceNanoleaf::getProperties(const QJsonObject& params)
|
||||||
{
|
{
|
||||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
QJsonObject properties;
|
QJsonObject properties;
|
||||||
|
|
||||||
_hostName = params[CONFIG_HOST].toString("");
|
_hostName = params[CONFIG_HOST].toString("");
|
||||||
_apiPort = API_DEFAULT_PORT;
|
_apiPort = API_DEFAULT_PORT;
|
||||||
_authToken = params[CONFIG_AUTH_TOKEN].toString("");
|
_authToken = params[CONFIG_AUTH_TOKEN].toString("");
|
||||||
|
|
||||||
Info(_log, "Get properties for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
Info(_log, "Get properties for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName));
|
||||||
|
|
||||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||||
{
|
{
|
||||||
if ( openRestAPI() )
|
if (openRestAPI())
|
||||||
{
|
{
|
||||||
QString filter = params["filter"].toString("");
|
QString filter = params["filter"].toString("");
|
||||||
_restApi->setPath(filter);
|
_restApi->setPath(filter);
|
||||||
@ -506,17 +471,17 @@ QJsonObject LedDeviceNanoleaf::getProperties(const QJsonObject& params)
|
|||||||
|
|
||||||
void LedDeviceNanoleaf::identify(const QJsonObject& params)
|
void LedDeviceNanoleaf::identify(const QJsonObject& params)
|
||||||
{
|
{
|
||||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
_hostName = params[CONFIG_HOST].toString("");
|
_hostName = params[CONFIG_HOST].toString("");
|
||||||
_apiPort = API_DEFAULT_PORT;
|
_apiPort = API_DEFAULT_PORT;
|
||||||
_authToken = params[CONFIG_AUTH_TOKEN].toString("");
|
_authToken = params[CONFIG_AUTH_TOKEN].toString("");
|
||||||
|
|
||||||
Info(_log, "Identify %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
Info(_log, "Identify %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName));
|
||||||
|
|
||||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||||
{
|
{
|
||||||
if ( openRestAPI() )
|
if (openRestAPI())
|
||||||
{
|
{
|
||||||
_restApi->setPath(API_IDENTIFY);
|
_restApi->setPath(API_IDENTIFY);
|
||||||
httpResponse response = _restApi->put();
|
httpResponse response = _restApi->put();
|
||||||
@ -534,23 +499,23 @@ QJsonObject LedDeviceNanoleaf::addAuthorization(const QJsonObject& params)
|
|||||||
QJsonObject responseBody;
|
QJsonObject responseBody;
|
||||||
|
|
||||||
_hostName = params[CONFIG_HOST].toString("");
|
_hostName = params[CONFIG_HOST].toString("");
|
||||||
_apiPort = API_DEFAULT_PORT;
|
_apiPort = API_DEFAULT_PORT;
|
||||||
|
|
||||||
Info(_log, "Generate user authorization token for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
Info(_log, "Generate user authorization token for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName));
|
||||||
|
|
||||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||||
{
|
{
|
||||||
if ( openRestAPI() )
|
if (openRestAPI())
|
||||||
{
|
{
|
||||||
_restApi->setBasePath(QString(API_BASE_PATH).arg(API_ADD_USER));
|
_restApi->setBasePath(QString(API_BASE_PATH).arg(API_ADD_USER));
|
||||||
httpResponse response = _restApi->post();
|
httpResponse response = _restApi->post();
|
||||||
if (response.error())
|
if (response.error())
|
||||||
{
|
{
|
||||||
Warning(_log, "%s generating user authorization token failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
Warning(_log, "%s generating user authorization token failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug(_log, "Generated user authorization token: \"%s\"", QSTRING_CSTR(response.getBody().object().value("auth_token").toString()) );
|
Debug(_log, "Generated user authorization token: \"%s\"", QSTRING_CSTR(response.getBody().object().value("auth_token").toString()));
|
||||||
responseBody = response.getBody().object();
|
responseBody = response.getBody().object();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -567,12 +532,12 @@ bool LedDeviceNanoleaf::powerOn()
|
|||||||
{
|
{
|
||||||
QJsonObject newState;
|
QJsonObject newState;
|
||||||
|
|
||||||
QJsonObject onValue { {STATE_VALUE, true} };
|
QJsonObject onValue{ {STATE_VALUE, true} };
|
||||||
newState.insert(STATE_ON, onValue);
|
newState.insert(STATE_ON, onValue);
|
||||||
|
|
||||||
if ( _isBrightnessOverwrite)
|
if (_isBrightnessOverwrite)
|
||||||
{
|
{
|
||||||
QJsonObject briValue { {STATE_VALUE, _brightness} };
|
QJsonObject briValue{ {STATE_VALUE, _brightness} };
|
||||||
newState.insert(STATE_BRI, briValue);
|
newState.insert(STATE_BRI, briValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,9 +547,10 @@ bool LedDeviceNanoleaf::powerOn()
|
|||||||
if (response.error())
|
if (response.error())
|
||||||
{
|
{
|
||||||
QString errorReason = QString("Power-on request failed with error: '%1'").arg(response.getErrorReason());
|
QString errorReason = QString("Power-on request failed with error: '%1'").arg(response.getErrorReason());
|
||||||
this->setInError ( errorReason );
|
this->setInError(errorReason);
|
||||||
on = false;
|
on = false;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
on = true;
|
on = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,7 +566,7 @@ bool LedDeviceNanoleaf::powerOff()
|
|||||||
{
|
{
|
||||||
QJsonObject newState;
|
QJsonObject newState;
|
||||||
|
|
||||||
QJsonObject onValue { {STATE_VALUE, false} };
|
QJsonObject onValue{ {STATE_VALUE, false} };
|
||||||
newState.insert(STATE_ON, onValue);
|
newState.insert(STATE_ON, onValue);
|
||||||
|
|
||||||
//Power-off the Nanoleaf device physically
|
//Power-off the Nanoleaf device physically
|
||||||
@ -609,7 +575,7 @@ bool LedDeviceNanoleaf::powerOff()
|
|||||||
if (response.error())
|
if (response.error())
|
||||||
{
|
{
|
||||||
QString errorReason = QString("Power-off request failed with error: '%1'").arg(response.getErrorReason());
|
QString errorReason = QString("Power-off request failed with error: '%1'").arg(response.getErrorReason());
|
||||||
this->setInError ( errorReason );
|
this->setInError(errorReason);
|
||||||
off = false;
|
off = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -620,12 +586,12 @@ bool LedDeviceNanoleaf::storeState()
|
|||||||
{
|
{
|
||||||
bool rc = true;
|
bool rc = true;
|
||||||
|
|
||||||
if ( _isRestoreOrigState )
|
if (_isRestoreOrigState)
|
||||||
{
|
{
|
||||||
_restApi->setPath(API_STATE);
|
_restApi->setPath(API_STATE);
|
||||||
|
|
||||||
httpResponse response = _restApi->get();
|
httpResponse response = _restApi->get();
|
||||||
if ( response.error() )
|
if (response.error())
|
||||||
{
|
{
|
||||||
QString errorReason = QString("Storing device state failed with error: '%1'").arg(response.getErrorReason());
|
QString errorReason = QString("Storing device state failed with error: '%1'").arg(response.getErrorReason());
|
||||||
setInError(errorReason);
|
setInError(errorReason);
|
||||||
@ -634,7 +600,7 @@ bool LedDeviceNanoleaf::storeState()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_originalStateProperties = response.getBody().object();
|
_originalStateProperties = response.getBody().object();
|
||||||
DebugIf(verbose, _log, "state: [%s]", QString(QJsonDocument(_originalStateProperties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
DebugIf(verbose, _log, "state: [%s]", QString(QJsonDocument(_originalStateProperties).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
QJsonObject isOn = _originalStateProperties.value(STATE_ON).toObject();
|
QJsonObject isOn = _originalStateProperties.value(STATE_ON).toObject();
|
||||||
if (!isOn.isEmpty())
|
if (!isOn.isEmpty())
|
||||||
@ -650,7 +616,7 @@ bool LedDeviceNanoleaf::storeState()
|
|||||||
|
|
||||||
_originalColorMode = _originalStateProperties[STATE_COLORMODE].toString();
|
_originalColorMode = _originalStateProperties[STATE_COLORMODE].toString();
|
||||||
|
|
||||||
switch(COLOR_MODES.indexOf(_originalColorMode)) {
|
switch (COLOR_MODES.indexOf(_originalColorMode)) {
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
// hs
|
// hs
|
||||||
@ -682,7 +648,7 @@ bool LedDeviceNanoleaf::storeState()
|
|||||||
_restApi->setPath(API_EFFECT);
|
_restApi->setPath(API_EFFECT);
|
||||||
|
|
||||||
httpResponse responseEffects = _restApi->get();
|
httpResponse responseEffects = _restApi->get();
|
||||||
if ( responseEffects.error() )
|
if (responseEffects.error())
|
||||||
{
|
{
|
||||||
QString errorReason = QString("Storing device state failed with error: '%1'").arg(responseEffects.getErrorReason());
|
QString errorReason = QString("Storing device state failed with error: '%1'").arg(responseEffects.getErrorReason());
|
||||||
setInError(errorReason);
|
setInError(errorReason);
|
||||||
@ -691,7 +657,7 @@ bool LedDeviceNanoleaf::storeState()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
QJsonObject effects = responseEffects.getBody().object();
|
QJsonObject effects = responseEffects.getBody().object();
|
||||||
DebugIf(verbose, _log, "effects: [%s]", QString(QJsonDocument(_originalStateProperties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
DebugIf(verbose, _log, "effects: [%s]", QString(QJsonDocument(_originalStateProperties).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
_originalEffect = effects[API_EFFECT_SELECT].toString();
|
_originalEffect = effects[API_EFFECT_SELECT].toString();
|
||||||
_originalIsDynEffect = _originalEffect == "*Dynamic*" || _originalEffect == "*Solid*";
|
_originalIsDynEffect = _originalEffect == "*Dynamic*" || _originalEffect == "*Solid*";
|
||||||
}
|
}
|
||||||
@ -712,21 +678,21 @@ bool LedDeviceNanoleaf::restoreState()
|
|||||||
{
|
{
|
||||||
bool rc = true;
|
bool rc = true;
|
||||||
|
|
||||||
if ( _isRestoreOrigState )
|
if (_isRestoreOrigState)
|
||||||
{
|
{
|
||||||
QJsonObject newState;
|
QJsonObject newState;
|
||||||
switch(COLOR_MODES.indexOf(_originalColorMode)) {
|
switch (COLOR_MODES.indexOf(_originalColorMode)) {
|
||||||
case 0:
|
case 0:
|
||||||
{ // hs
|
{ // hs
|
||||||
QJsonObject hueValue { {STATE_VALUE, _originalHue} };
|
QJsonObject hueValue{ {STATE_VALUE, _originalHue} };
|
||||||
newState.insert(STATE_HUE, hueValue);
|
newState.insert(STATE_HUE, hueValue);
|
||||||
QJsonObject satValue { {STATE_VALUE, _originalSat} };
|
QJsonObject satValue{ {STATE_VALUE, _originalSat} };
|
||||||
newState.insert(STATE_SAT, satValue);
|
newState.insert(STATE_SAT, satValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
{ // ct
|
{ // ct
|
||||||
QJsonObject ctValue { {STATE_VALUE, _originalCt} };
|
QJsonObject ctValue{ {STATE_VALUE, _originalCt} };
|
||||||
newState.insert(STATE_CT, ctValue);
|
newState.insert(STATE_CT, ctValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -738,37 +704,38 @@ bool LedDeviceNanoleaf::restoreState()
|
|||||||
newEffect[API_EFFECT_SELECT] = _originalEffect;
|
newEffect[API_EFFECT_SELECT] = _originalEffect;
|
||||||
_restApi->setPath(API_EFFECT);
|
_restApi->setPath(API_EFFECT);
|
||||||
httpResponse response = _restApi->put(newEffect);
|
httpResponse response = _restApi->put(newEffect);
|
||||||
if ( response.error() )
|
if (response.error())
|
||||||
{
|
{
|
||||||
Warning (_log, "%s restoring effect failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
Warning(_log, "%s restoring effect failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
Warning (_log, "%s restoring effect failed with error: Cannot restore dynamic or solid effect. Device is switched off", QSTRING_CSTR(_activeDeviceType));
|
else {
|
||||||
|
Warning(_log, "%s restoring effect failed with error: Cannot restore dynamic or solid effect. Device is switched off", QSTRING_CSTR(_activeDeviceType));
|
||||||
_originalIsOn = false;
|
_originalIsOn = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
Warning (_log, "%s restoring failed with error: Unknown ColorMode", QSTRING_CSTR(_activeDeviceType));
|
Warning(_log, "%s restoring failed with error: Unknown ColorMode", QSTRING_CSTR(_activeDeviceType));
|
||||||
rc = false;
|
rc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_originalIsDynEffect)
|
if (!_originalIsDynEffect)
|
||||||
{
|
{
|
||||||
QJsonObject briValue { {STATE_VALUE, _originalBri} };
|
QJsonObject briValue{ {STATE_VALUE, _originalBri} };
|
||||||
newState.insert(STATE_BRI, briValue);
|
newState.insert(STATE_BRI, briValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject onValue { {STATE_VALUE, _originalIsOn} };
|
QJsonObject onValue{ {STATE_VALUE, _originalIsOn} };
|
||||||
newState.insert(STATE_ON, onValue);
|
newState.insert(STATE_ON, onValue);
|
||||||
|
|
||||||
_restApi->setPath(API_STATE);
|
_restApi->setPath(API_STATE);
|
||||||
|
|
||||||
httpResponse response = _restApi->put(newState);
|
httpResponse response = _restApi->put(newState);
|
||||||
|
|
||||||
if ( response.error() )
|
if (response.error())
|
||||||
{
|
{
|
||||||
Warning (_log, "%s restoring state failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
Warning(_log, "%s restoring state failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||||
rc = false;
|
rc = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -793,7 +760,7 @@ bool LedDeviceNanoleaf::changeToExternalControlMode(QJsonDocument& resp)
|
|||||||
if (response.error())
|
if (response.error())
|
||||||
{
|
{
|
||||||
QString errorReason = QString("Change to external control mode failed with error: '%1'").arg(response.getErrorReason());
|
QString errorReason = QString("Change to external control mode failed with error: '%1'").arg(response.getErrorReason());
|
||||||
this->setInError ( errorReason );
|
this->setInError(errorReason);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -833,25 +800,14 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb>& ledValues)
|
|||||||
int ledCounter = 0;
|
int ledCounter = 0;
|
||||||
for (int panelCounter = 0; panelCounter < _panelLedCount; panelCounter++)
|
for (int panelCounter = 0; panelCounter < _panelLedCount; panelCounter++)
|
||||||
{
|
{
|
||||||
int panelID = _panelIds[panelCounter];
|
|
||||||
|
|
||||||
// Set panels configured
|
|
||||||
if (panelCounter >= _startPos && panelCounter <= _endPos) {
|
|
||||||
color = static_cast<ColorRgb>(ledValues.at(ledCounter));
|
|
||||||
++ledCounter;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Set panels not configured to black
|
|
||||||
color = ColorRgb::BLACK;
|
|
||||||
DebugIf(verbose3, _log, "[%d] >= panelLedCount [%d] => Set to BLACK", panelCounter, _panelLedCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set panelID
|
// Set panelID
|
||||||
|
int panelID = _panelIds[panelCounter];
|
||||||
qToBigEndian<quint16>(static_cast<quint16>(panelID), udpbuffer.data() + i);
|
qToBigEndian<quint16>(static_cast<quint16>(panelID), udpbuffer.data() + i);
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
||||||
// Set panel's color LEDs
|
// Set panel's color LEDs
|
||||||
|
color = static_cast<ColorRgb>(ledValues.at(ledCounter));
|
||||||
|
++ledCounter;
|
||||||
udpbuffer[i++] = static_cast<char>(color.red);
|
udpbuffer[i++] = static_cast<char>(color.red);
|
||||||
udpbuffer[i++] = static_cast<char>(color.green);
|
udpbuffer[i++] = static_cast<char>(color.green);
|
||||||
udpbuffer[i++] = static_cast<char>(color.blue);
|
udpbuffer[i++] = static_cast<char>(color.blue);
|
||||||
@ -870,7 +826,7 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb>& ledValues)
|
|||||||
if (verbose3)
|
if (verbose3)
|
||||||
{
|
{
|
||||||
Debug(_log, "UDP-Address [%s], UDP-Port [%u], udpBufferSize[%d], Bytes to send [%d]", QSTRING_CSTR(_address.toString()), _port, udpBufferSize, i);
|
Debug(_log, "UDP-Address [%s], UDP-Port [%u], udpBufferSize[%d], Bytes to send [%d]", QSTRING_CSTR(_address.toString()), _port, udpBufferSize, i);
|
||||||
Debug( _log, "packet: [%s]", QSTRING_CSTR(toHex(udpbuffer, 64)));
|
Debug(_log, "packet: [%s]", QSTRING_CSTR(toHex(udpbuffer, 64)));
|
||||||
}
|
}
|
||||||
|
|
||||||
retVal = writeBytes(udpbuffer);
|
retVal = writeBytes(udpbuffer);
|
||||||
|
@ -210,8 +210,6 @@ private:
|
|||||||
|
|
||||||
bool _topDown;
|
bool _topDown;
|
||||||
bool _leftRight;
|
bool _leftRight;
|
||||||
int _startPos;
|
|
||||||
int _endPos;
|
|
||||||
|
|
||||||
//Nanoleaf device details
|
//Nanoleaf device details
|
||||||
QString _deviceModel;
|
QString _deviceModel;
|
||||||
|
@ -72,41 +72,28 @@
|
|||||||
"propertyOrder": 7
|
"propertyOrder": 7
|
||||||
},
|
},
|
||||||
"panelOrderTopDown": {
|
"panelOrderTopDown": {
|
||||||
"type": "integer",
|
"type": "string",
|
||||||
"title": "edt_dev_spec_order_top_down_title",
|
"title": "edt_dev_spec_order_top_down_title",
|
||||||
"enum": [ 0, 1 ],
|
"enum": [ "top2down", "bottom2up" ],
|
||||||
"default": 0,
|
"default": "top2down",
|
||||||
"required": true,
|
"required": true,
|
||||||
"options": {
|
"options": {
|
||||||
"enum_titles": [ "edt_conf_enum_top_down", "edt_conf_enum_bottom_up" ]
|
"enum_titles": [ "edt_conf_enum_top_down", "edt_conf_enum_bottom_up" ]
|
||||||
},
|
},
|
||||||
"minimum": 0,
|
|
||||||
"maximum": 1,
|
|
||||||
"access": "advanced",
|
"access": "advanced",
|
||||||
"propertyOrder": 8
|
"propertyOrder": 8
|
||||||
},
|
},
|
||||||
"panelOrderLeftRight": {
|
"panelOrderLeftRight": {
|
||||||
"type": "integer",
|
"type": "string",
|
||||||
"title": "edt_dev_spec_order_left_right_title",
|
"title": "edt_dev_spec_order_left_right_title",
|
||||||
"enum": [ 0, 1 ],
|
"enum": [ "left2right", "right2left" ],
|
||||||
"default": 0,
|
"default": "left2right",
|
||||||
"required": true,
|
"required": true,
|
||||||
"options": {
|
"options": {
|
||||||
"enum_titles": [ "edt_conf_enum_left_right", "edt_conf_enum_right_left" ]
|
"enum_titles": [ "edt_conf_enum_left_right", "edt_conf_enum_right_left" ]
|
||||||
},
|
},
|
||||||
"minimum": 0,
|
|
||||||
"maximum": 1,
|
|
||||||
"access": "advanced",
|
"access": "advanced",
|
||||||
"propertyOrder": 9
|
"propertyOrder": 9
|
||||||
},
|
|
||||||
"panelStartPos": {
|
|
||||||
"type": "integer",
|
|
||||||
"title": "edt_dev_spec_panel_start_position",
|
|
||||||
"step": 1,
|
|
||||||
"minimum": 0,
|
|
||||||
"default": 0,
|
|
||||||
"access": "advanced",
|
|
||||||
"propertyOrder": 10
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": true
|
"additionalProperties": true
|
||||||
|
Loading…
x
Reference in New Issue
Block a user