From ac57fea09a219efd89550c7409e2404163db649e Mon Sep 17 00:00:00 2001
From: LordGrey <48840279+Lord-Grey@users.noreply.github.com>
Date: Sat, 30 Mar 2024 15:43:50 +0100
Subject: [PATCH] Fix Kodi Color Calibration, Refactor Wizards (#1718)
* Fix #1674 and refactor wizards
* Have own code file per LED-Device Wizard
* Include SonarLint feedback
* Cleanups
* Apply module pattern
* Address CodeQL findings
* Address CodeQL findings
---
assets/webconfig/js/content_huebridge.js | 52 -
assets/webconfig/js/content_leds.js | 35 +-
assets/webconfig/js/ui_utils.js | 29 +
assets/webconfig/js/wizard.js | 2301 +----------------
.../webconfig/js/wizards/LedDevice_atmoorb.js | 283 ++
.../js/wizards/LedDevice_nanoleaf.js | 94 +
.../js/wizards/LedDevice_philipshue.js | 988 +++++++
.../webconfig/js/wizards/LedDevice_utils.js | 60 +
.../js/wizards/LedDevice_yeelight.js | 300 +++
.../js/wizards/colorCalibrationKodiWizard.js | 485 ++++
.../js/wizards/rgbByteOrderWizard.js | 143 +
11 files changed, 2432 insertions(+), 2338 deletions(-)
delete mode 100644 assets/webconfig/js/content_huebridge.js
create mode 100644 assets/webconfig/js/wizards/LedDevice_atmoorb.js
create mode 100644 assets/webconfig/js/wizards/LedDevice_nanoleaf.js
create mode 100644 assets/webconfig/js/wizards/LedDevice_philipshue.js
create mode 100644 assets/webconfig/js/wizards/LedDevice_utils.js
create mode 100644 assets/webconfig/js/wizards/LedDevice_yeelight.js
create mode 100644 assets/webconfig/js/wizards/colorCalibrationKodiWizard.js
create mode 100644 assets/webconfig/js/wizards/rgbByteOrderWizard.js
diff --git a/assets/webconfig/js/content_huebridge.js b/assets/webconfig/js/content_huebridge.js
deleted file mode 100644
index 99da3c76..00000000
--- a/assets/webconfig/js/content_huebridge.js
+++ /dev/null
@@ -1,52 +0,0 @@
-$(document).ready( function() {
-
- $("#create_user").on("click", function() {
- var connectionRetries = 15;
- var data = {"devicetype":"hyperion#"+Date.now()};
- var UserInterval = setInterval(function(){
- $.ajax({
- type: "POST",
- url: 'http://'+$("#ip").val()+'/api',
- processData: false,
- timeout: 1000,
- contentType: 'application/json',
- data: JSON.stringify(data),
- success: function(r) {
- connectionRetries--;
- $("#connectionTime").html(connectionRetries);
- if(connectionRetries == 0) {
- abortConnection(UserInterval);
- }
- else
- {
- $("#abortConnection").hide();
- $('#pairmodal').modal('show');
- $("#ip_alert").hide();
- if (typeof r[0].error != 'undefined') {
- console.log("link not pressed");
- }
- if (typeof r[0].success != 'undefined') {
- $('#pairmodal').modal('hide');
- $('#user').val(r[0].success.username);
-
- $( "#hue_lights" ).empty();
- get_hue_lights();
- clearInterval(UserInterval);
- }
- }
- },
- error: function(XMLHttpRequest, textStatus, errorThrown) {
- $("#ip_alert").show();
- clearInterval(UserInterval);
- }
- });
- },1000);
-});
-
-function abortConnection(UserInterval){
- clearInterval(UserInterval);
- $("#abortConnection").show();
- $('#pairmodal').modal('hide');
-}
-
-});
diff --git a/assets/webconfig/js/content_leds.js b/assets/webconfig/js/content_leds.js
index 0432524a..938bf8ee 100755
--- a/assets/webconfig/js/content_leds.js
+++ b/assets/webconfig/js/content_leds.js
@@ -1086,40 +1086,7 @@ $(document).ready(function () {
conf_editor.validate().length || window.readOnlyMode ? $('#btn_submit_controller').prop('disabled', true) : $('#btn_submit_controller').prop('disabled', false);
// LED controller specific wizards
- $('#btn_wiz_holder').html("");
- $('#btn_led_device_wiz').off();
-
- if (ledType == "philipshue") {
- var ledWizardType = ledType;
- var data = { type: ledWizardType };
- var hue_title = 'wiz_hue_title';
- changeWizard(data, hue_title, startWizardPhilipsHue);
- }
- else if (ledType == "nanoleaf") {
- var ledWizardType = ledType;
- var data = { type: ledWizardType };
- var nanoleaf_user_auth_title = 'wiz_nanoleaf_user_auth_title';
- changeWizard(data, nanoleaf_user_auth_title, startWizardNanoleafUserAuth);
- $('#btn_wiz_holder').hide();
- }
- else if (ledType == "atmoorb") {
- var ledWizardType = (this.checked) ? "atmoorb" : ledType;
- var data = { type: ledWizardType };
- var atmoorb_title = 'wiz_atmoorb_title';
- changeWizard(data, atmoorb_title, startWizardAtmoOrb);
- }
- else if (ledType == "yeelight") {
- var ledWizardType = (this.checked) ? "yeelight" : ledType;
- var data = { type: ledWizardType };
- var yeelight_title = 'wiz_yeelight_title';
- changeWizard(data, yeelight_title, startWizardYeelight);
- }
-
- function changeWizard(data, hint, fn) {
- $('#btn_wiz_holder').html("")
- createHint("wizard", $.i18n(hint), "btn_wiz_holder", "btn_led_device_wiz");
- $('#btn_led_device_wiz').off().on('click', data, fn);
- }
+ createLedDeviceWizards(ledType);
conf_editor.on('ready', function () {
var hwLedCountDefault = 1;
diff --git a/assets/webconfig/js/ui_utils.js b/assets/webconfig/js/ui_utils.js
index 0061dde9..4cbb7967 100644
--- a/assets/webconfig/js/ui_utils.js
+++ b/assets/webconfig/js/ui_utils.js
@@ -1393,3 +1393,32 @@ function isValidHostnameOrIP(value) {
return (isValidHostnameOrIP4(value) || isValidIPv6(value) || isValidServicename(value));
}
+const loadedScripts = [];
+
+function isScriptLoaded(src) {
+ return loadedScripts.indexOf(src) > -1;
+}
+
+function loadScript(src, callback, ...params) {
+ if (isScriptLoaded(src)) {
+ debugMessage('Script ' + src + ' already loaded');
+ if (callback && typeof callback === 'function') {
+ callback( ...params);
+ }
+ return;
+ }
+
+ const script = document.createElement('script');
+ script.src = src;
+
+ script.onload = function () {
+ debugMessage('Script ' + src + ' loaded successfully');
+ loadedScripts.push(src);
+
+ if (callback && typeof callback === 'function') {
+ callback(...params);
+ }
+ };
+
+ document.head.appendChild(script);
+}
diff --git a/assets/webconfig/js/wizard.js b/assets/webconfig/js/wizard.js
index 70584ddb..2524924f 100755
--- a/assets/webconfig/js/wizard.js
+++ b/assets/webconfig/js/wizard.js
@@ -3,2274 +3,71 @@ $(window.hyperion).one("ready", function (event) {
if (getStorage("wizardactive") === 'true') {
requestPriorityClear();
setStorage("wizardactive", false);
- if (getStorage("kodiAddress") != null) {
- kodiAddress = getStorage("kodiAddress");
-
- if (getStorage("kodiPort") != null) {
- kodiPort = getStorage("kodiPort");
- }
- sendToKodi("stop");
- }
}
});
+$("#btn_wizard_colorcalibration").click(async function () {
+ const { colorCalibrationKodiWizard } = await import('./wizards/colorCalibrationKodiWizard.js');
+ colorCalibrationKodiWizard.start();
+});
+
+$('#btn_wizard_byteorder').on('click', async () => {
+ const { rgbByteOrderWizard } = await import('./wizards/rgbByteOrderWizard.js');
+ rgbByteOrderWizard.start();
+});
+
function resetWizard(reload) {
$("#wizard_modal").modal('hide');
- clearInterval(wIntveralId);
requestPriorityClear();
setStorage("wizardactive", false);
$('#wizp1').toggle(true);
$('#wizp2').toggle(false);
$('#wizp3').toggle(false);
- //cc
- if (withKodi)
- sendToKodi("stop");
- step = 0;
- if (!reload) location.reload();
-}
-
-//rgb byte order wizard
-var wIntveralId;
-var new_rgb_order;
-
-function changeColor() {
- var color = $("#wiz_canv_color").css('background-color');
-
- if (color == 'rgb(255, 0, 0)') {
- $("#wiz_canv_color").css('background-color', 'rgb(0, 255, 0)');
- requestSetColor('0', '255', '0');
- }
- else {
- $("#wiz_canv_color").css('background-color', 'rgb(255, 0, 0)');
- requestSetColor('255', '0', '0');
+ if (!reload) {
+ location.reload();
}
}
-function startWizardRGB() {
- //create html
- $('#wiz_header').html('' + $.i18n('wiz_rgb_title'));
- $('#wizp1_body').html('
' + $.i18n('wiz_rgb_title') + '
' + $.i18n('wiz_rgb_intro1') + '
' + $.i18n('wiz_rgb_intro2') + '
');
- $('#wizp1_footer').html('');
- $('#wizp2_body').html('' + $.i18n('wiz_rgb_expl') + '
');
- $('#wizp2_body').append('');
- $('#wizp2_body').append('');
- $('#wizp2_body').append(' | |
| |
');
- $('#wizp2_footer').html('');
+function createLedDeviceWizards(ledType) {
- if (getStorage("darkMode") == "on")
- $('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
+ let data = {};
+ let title;
- //open modal
- $("#wizard_modal").modal({
- backdrop: "static",
- keyboard: false,
- show: true
- });
+ $('#btn_wiz_holder').html("");
+ $('#btn_led_device_wiz').off();
+ if (ledType == "philipshue") {
+ $('#btn_wiz_holder').show();
+ data = { ledType };
+ title = 'wiz_hue_title';
+ }
+ else if (ledType == "nanoleaf") {
+ $('#btn_wiz_holder').hide();
+ data = { ledType };
+ title = 'wiz_nanoleaf_user_auth_title';
+ }
+ else if (ledType == "atmoorb") {
+ $('#btn_wiz_holder').show();
+ data = { ledType };
+ title = 'wiz_atmoorb_title';
+ }
+ else if (ledType == "yeelight") {
+ $('#btn_wiz_holder').show();
+ data = { ledType };
+ title = 'wiz_yeelight_title';
+ }
- //listen for continue
- $('#btn_wiz_cont').off().on('click', function () {
- beginWizardRGB();
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
+ if (Object.keys(data).length !== 0) {
+ startLedDeviceWizard(data, title, ledType + "Wizard");
+ }
+}
+
+function startLedDeviceWizard(data, hint, wizardName) {
+ $('#btn_wiz_holder').html("")
+ createHint("wizard", $.i18n(hint), "btn_wiz_holder", "btn_led_device_wiz");
+ $('#btn_led_device_wiz').off();
+ $('#btn_led_device_wiz').on('click', async (e) => {
+ const { [wizardName]: winzardObject } = await import('./wizards/LedDevice_' + data.ledType + '.js');
+ winzardObject.start(e);
});
}
-function beginWizardRGB() {
- $("#wiz_switchtime_select").off().on('change', function () {
- clearInterval(wIntveralId);
- var time = $("#wiz_switchtime_select").val();
- wIntveralId = setInterval(function () { changeColor(); }, time * 1000);
- });
-
- $('.wselect').on("change", function () {
- var rgb_order = window.serverConfig.device.colorOrder.split("");
- var redS = $("#wiz_r_select").val();
- var greenS = $("#wiz_g_select").val();
- var blueS = rgb_order.toString().replace(/,/g, "").replace(redS, "").replace(greenS, "");
-
- for (var i = 0; i < rgb_order.length; i++) {
- if (redS == rgb_order[i])
- $('#wiz_g_select option[value=' + rgb_order[i] + ']').prop('disabled', true);
- else
- $('#wiz_g_select option[value=' + rgb_order[i] + ']').prop('disabled', false);
- if (greenS == rgb_order[i])
- $('#wiz_r_select option[value=' + rgb_order[i] + ']').prop('disabled', true);
- else
- $('#wiz_r_select option[value=' + rgb_order[i] + ']').prop('disabled', false);
- }
-
- if (redS != 'null' && greenS != 'null') {
- $('#btn_wiz_save').prop('disabled', false);
-
- for (var i = 0; i < rgb_order.length; i++) {
- if (rgb_order[i] == "r")
- rgb_order[i] = redS;
- else if (rgb_order[i] == "g")
- rgb_order[i] = greenS;
- else
- rgb_order[i] = blueS;
- }
-
- rgb_order = rgb_order.toString().replace(/,/g, "");
-
- if (redS == "r" && greenS == "g") {
- $('#btn_wiz_save').toggle(false);
- $('#btn_wiz_checkok').toggle(true);
-
- window.readOnlyMode ? $('#btn_wiz_checkok').prop('disabled', true) : $('#btn_wiz_checkok').prop('disabled', false);
- }
- else {
- $('#btn_wiz_save').toggle(true);
- window.readOnlyMode ? $('#btn_wiz_save').prop('disabled', true) : $('#btn_wiz_save').prop('disabled', false);
-
- $('#btn_wiz_checkok').toggle(false);
- }
- new_rgb_order = rgb_order;
- }
- else
- $('#btn_wiz_save').prop('disabled', true);
- });
-
- $("#wiz_switchtime_select").append(createSelOpt('5', '5'), createSelOpt('10', '10'), createSelOpt('15', '15'), createSelOpt('30', '30'));
- $("#wiz_switchtime_select").trigger('change');
-
- $("#wiz_r_select").append(createSelOpt("null", ""), createSelOpt('r', $.i18n('general_col_red')), createSelOpt('g', $.i18n('general_col_green')), createSelOpt('b', $.i18n('general_col_blue')));
- $("#wiz_g_select").html($("#wiz_r_select").html());
- $("#wiz_r_select").trigger('change');
-
- requestSetColor('255', '0', '0');
- setTimeout(requestSetSource, 100, 'auto');
- setStorage("wizardactive", true);
-
- $('#btn_wiz_abort').off().on('click', function () { resetWizard(true); });
-
- $('#btn_wiz_checkok').off().on('click', function () {
- showInfoDialog('success', "", $.i18n('infoDialog_wizrgb_text'));
- resetWizard();
- });
-
- $('#btn_wiz_save').off().on('click', function () {
- resetWizard();
- window.serverConfig.device.colorOrder = new_rgb_order;
- requestWriteConfig({ "device": window.serverConfig.device });
- });
-}
-
-$('#btn_wizard_byteorder').off().on('click', startWizardRGB);
-
-//color calibration wizard
-
-const defaultKodiPort = 9090;
-
-var kodiAddress = document.location.hostname;
-var kodiPort = defaultKodiPort;
-
-var kodiUrl = new URL("ws://" + kodiAddress);
-kodiUrl.port = kodiPort;
-kodiUrl.pathname = "/jsonrpc/websocket";
-
-var wiz_editor;
-var colorLength;
-var cobj;
-var step = 0;
-var withKodi = false;
-var profile = 0;
-var websAddress;
-var imgAddress;
-var vidAddress = "https://sourceforge.net/projects/hyperion-project/files/resources/vid/";
-var picnr = 0;
-var availVideos = ["Sweet_Cocoon", "Caminandes_2_GranDillama", "Caminandes_3_Llamigos"];
-
-if (getStorage("kodiAddress") != null) {
-
- kodiAddress = getStorage("kodiAddress");
- kodiUrl.host = kodiAddress;
-}
-
-if (getStorage("kodiPort") != null) {
- kodiPort = getStorage("kodiPort");
- kodiUrl.port = kodiPort;
-}
-
-function switchPicture(pictures) {
- if (typeof pictures[picnr] === 'undefined')
- picnr = 0;
-
- sendToKodi('playP', pictures[picnr]);
- picnr++;
-}
-
-function sendToKodi(type, content, cb) {
- var command;
-
- switch (type) {
- case "msg":
- command = { "jsonrpc": "2.0", "method": "GUI.ShowNotification", "params": { "title": $.i18n('wiz_cc_title'), "message": content, "image": "info", "displaytime": 5000 }, "id": "1" };
- break;
- case "stop":
- command = { "jsonrpc": "2.0", "method": "Player.Stop", "params": { "playerid": 2 }, "id": "1" };
- break;
- case "playP":
- content = imgAddress + content + '.png';
- command = { "jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "file": content } }, "id": "1" };
- break;
- case "playV":
- content = vidAddress + content;
- command = { "jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "file": content } }, "id": "1" };
- break;
- case "rotate":
- command = { "jsonrpc": "2.0", "method": "Player.Rotate", "params": { "playerid": 2 }, "id": "1" };
- break;
- default:
- if (cb != undefined) {
- cb("error");
- }
- }
-
- if ("WebSocket" in window) {
-
- if (kodiUrl.port === '') {
- kodiUrl.port = defaultKodiPort;
- }
- var ws = new WebSocket(kodiUrl);
-
- ws.onopen = function () {
- ws.send(JSON.stringify(command));
- };
-
- ws.onmessage = function (evt) {
- var response = JSON.parse(evt.data);
- if (response.method === "System.OnQuit") {
- ws.close();
- } else {
- if (cb != undefined) {
- if (response.result != undefined) {
- if (response.result === "OK") {
- cb("success");
- ws.close();
- } else {
- cb("error");
- ws.close();
- }
- }
- }
- }
- };
-
- ws.onerror = function (evt) {
- if (cb != undefined) {
- cb("error");
- ws.close();
- }
- };
-
- ws.onclose = function (evt) {
- };
-
- }
- else {
- console.log("Kodi Access: WebSocket NOT supported by this browser");
- cb("error");
- }
-}
-
-function performAction() {
- var h;
-
- if (step == 1) {
- $('#wiz_cc_desc').html($.i18n('wiz_cc_chooseid'));
- updateWEditor(["id"]);
- $('#btn_wiz_back').prop("disabled", true);
- }
- else
- $('#btn_wiz_back').prop("disabled", false);
-
- if (step == 2) {
- updateWEditor(["white"]);
- h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_white_title'));
- if (withKodi) {
- h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_white_title'));
- sendToKodi('playP', "white");
- }
- else
- h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_white_title'));
- $('#wiz_cc_desc').html(h);
- }
- if (step == 3) {
- updateWEditor(["gammaRed", "gammaGreen", "gammaBlue"]);
- h = '' + $.i18n('wiz_cc_adjustgamma') + '
';
- if (withKodi) {
- sendToKodi('playP', "HGradient");
- h += '';
- }
- else
- h += '' + $.i18n('wiz_cc_lettvshowm', "grey_1, grey_2, grey_3, HGradient, VGradient") + '
';
- $('#wiz_cc_desc').html(h);
- $('#wiz_cc_btn_sp').off().on('click', function () {
- switchPicture(["VGradient", "grey_1", "grey_2", "grey_3", "HGradient"]);
- });
- }
- if (step == 4) {
- updateWEditor(["red"]);
- h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_red_title'));
- if (withKodi) {
- h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_red_title'));
- sendToKodi('playP', "red");
- }
- else
- h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_red_title'));
- $('#wiz_cc_desc').html(h);
- }
- if (step == 5) {
- updateWEditor(["green"]);
- h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_green_title'));
- if (withKodi) {
- h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_green_title'));
- sendToKodi('playP', "green");
- }
- else
- h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_green_title'));
- $('#wiz_cc_desc').html(h);
- }
- if (step == 6) {
- updateWEditor(["blue"]);
- h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_blue_title'));
- if (withKodi) {
- h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_blue_title'));
- sendToKodi('playP', "blue");
- }
- else
- h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_blue_title'));
- $('#wiz_cc_desc').html(h);
- }
- if (step == 7) {
- updateWEditor(["cyan"]);
- h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_cyan_title'));
- if (withKodi) {
- h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_cyan_title'));
- sendToKodi('playP', "cyan");
- }
- else
- h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_cyan_title'));
- $('#wiz_cc_desc').html(h);
- }
- if (step == 8) {
- updateWEditor(["magenta"]);
- h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_magenta_title'));
- if (withKodi) {
- h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_magenta_title'));
- sendToKodi('playP', "magenta");
- }
- else
- h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_magenta_title'));
- $('#wiz_cc_desc').html(h);
- }
- if (step == 9) {
- updateWEditor(["yellow"]);
- h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_yellow_title'));
- if (withKodi) {
- h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_yellow_title'));
- sendToKodi('playP', "yellow");
- }
- else
- h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_yellow_title'));
- $('#wiz_cc_desc').html(h);
- }
- if (step == 10) {
- updateWEditor(["backlightThreshold", "backlightColored"]);
- h = $.i18n('wiz_cc_backlight');
- if (withKodi) {
- h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_black_title'));
- sendToKodi('playP', "black");
- }
- else
- h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_black_title'));
- $('#wiz_cc_desc').html(h);
- }
- if (step == 11) {
- updateWEditor([""], true);
- h = '' + $.i18n('wiz_cc_testintro') + '
';
- if (withKodi) {
- h += '' + $.i18n('wiz_cc_testintrok') + '
';
- sendToKodi('stop');
- for (var i = 0; i < availVideos.length; i++) {
- var txt = availVideos[i].replace(/_/g, " ");
- h += '';
- }
- h += '';
- }
- else
- h += '' + $.i18n('wiz_cc_testintrowok') + ' ' + $.i18n('wiz_cc_link') + '
';
- h += '' + $.i18n('wiz_cc_summary') + '
';
- $('#wiz_cc_desc').html(h);
-
- $('.videobtn').off().on('click', function (e) {
- if (e.target.id == "stop")
- sendToKodi("stop");
- else
- sendToKodi("playV", e.target.id + '.mp4');
-
- $(this).prop("disabled", true);
- setTimeout(function () { $('.videobtn').prop("disabled", false) }, 10000);
- });
-
- $('#btn_wiz_next').prop("disabled", true);
- $('#btn_wiz_save').toggle(true);
- window.readOnlyMode ? $('#btn_wiz_save').prop('disabled', true) : $('#btn_wiz_save').prop('disabled', false);
- }
- else {
- $('#btn_wiz_next').prop("disabled", false);
- $('#btn_wiz_save').toggle(false);
- }
-}
-
-function updateWEditor(el, all) {
- for (var key in cobj) {
- if (all === true || el[0] == key || el[1] == key || el[2] == key)
- $('#editor_container_wiz [data-schemapath*=".' + profile + '.' + key + '"]').toggle(true);
- else
- $('#editor_container_wiz [data-schemapath*=".' + profile + '.' + key + '"]').toggle(false);
- }
-}
-
-function startWizardCC() {
-
- //create html
- $('#wiz_header').html('' + $.i18n('wiz_cc_title'));
- $('#wizp1_body').html('' + $.i18n('wiz_cc_title') + '
' +
- '' + $.i18n('wiz_cc_intro1') + '
' +
- '' +
- '' +
- ''
- );
- $('#wizp1_footer').html('' +
- ''
- );
- $('#wizp2_body').html(''
- );
- $('#wizp2_footer').html('' +
- '' +
- '' +
- ''
- );
-
- if (getStorage("darkMode") == "on")
- $('#wizard_logo').prop("src", 'img/hyperion/logo_negativ.png');
-
- //open modal
- $("#wizard_modal").modal({
- backdrop: "static",
- keyboard: false,
- show: true
- });
-
- $('#wiz_cc_kodiip').off().on('change', function () {
-
- kodiAddress = encodeURIComponent($(this).val().trim());
-
- $('#kodi_status').html('');
- if (kodiAddress !== "") {
-
- if (!isValidHostnameOrIP(kodiAddress)) {
-
- $('#kodi_status').html('' + $.i18n('edt_msgcust_error_hostname_ip') + '
');
- withKodi = false;
-
- } else {
-
- if (isValidIPv6(kodiAddress)) {
- kodiUrl.hostname = "[" + kodiAddress + "]";
- } else {
- kodiUrl.hostname = kodiAddress;
- }
-
- $('#kodi_status').html('' + $.i18n('wiz_cc_try_connect') + '
');
- $('#btn_wiz_cont').prop('disabled', true);
-
- sendToKodi("msg", $.i18n('wiz_cc_kodimsg_start'), function (cb) {
- if (cb == "error") {
- $('#kodi_status').html('' + $.i18n('wiz_cc_kodidiscon') + '
' + $.i18n('wiz_cc_kodidisconlink') + ' ' + $.i18n('wiz_cc_link') + '
');
- withKodi = false;
- }
- else {
- setStorage("kodiAddress", kodiAddress);
- setStorage("kodiPort", defaultKodiPort);
-
- $('#kodi_status').html('' + $.i18n('wiz_cc_kodicon') + '
');
- withKodi = true;
- }
-
- $('#btn_wiz_cont').prop('disabled', false);
- });
- }
- }
- });
-
- //listen for continue
- $('#btn_wiz_cont').off().on('click', function () {
- beginWizardCC();
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- });
-
- $('#wiz_cc_kodiip').trigger("change");
- colorLength = window.serverConfig.color.channelAdjustment;
- cobj = window.schema.color.properties.channelAdjustment.items.properties;
- websAddress = document.location.hostname + ':' + window.serverConfig.webConfig.port;
- imgAddress = 'http://' + websAddress + '/img/cc/';
- setStorage("wizardactive", true);
-
- //check profile count
- if (colorLength.length > 1) {
- $('#multi_cali').html('' + $.i18n('wiz_cc_morethanone') + '
');
- for (var i = 0; i < colorLength.length; i++)
- $('#wiz_select').append(createSelOpt(i, i + 1 + ' (' + colorLength[i].id + ')'));
-
- $('#wiz_select').off().on('change', function () {
- profile = $(this).val();
- });
- }
-
- //prepare editor
- wiz_editor = createJsonEditor('editor_container_wiz', {
- color: window.schema.color
- }, true, true);
-
- $('#editor_container_wiz h4').toggle(false);
- $('#editor_container_wiz .btn-group').toggle(false);
- $('#editor_container_wiz [data-schemapath="root.color.imageToLedMappingType"]').toggle(false);
- for (var i = 0; i < colorLength.length; i++)
- $('#editor_container_wiz [data-schemapath*="root.color.channelAdjustment.' + i + '."]').toggle(false);
-}
-
-function beginWizardCC() {
- $('#btn_wiz_next').off().on('click', function () {
- step++;
- performAction();
- });
-
- $('#btn_wiz_back').off().on('click', function () {
- step--;
- performAction();
- });
-
- $('#btn_wiz_abort').off().on('click', resetWizard);
-
- $('#btn_wiz_save').off().on('click', function () {
- requestWriteConfig(wiz_editor.getValue());
- resetWizard();
- });
-
- wiz_editor.on("change", function (e) {
- var val = wiz_editor.getEditor('root.color.channelAdjustment.' + profile + '').getValue();
- var temp = JSON.parse(JSON.stringify(val));
- delete temp.leds
- requestAdjustment(JSON.stringify(temp), "", true);
- });
-
- step++
- performAction();
-}
-
-$('#btn_wizard_colorcalibration').off().on('click', startWizardCC);
-
-// Layout positions
-var lightPosTop = { hmin: 0.15, hmax: 0.85, vmin: 0, vmax: 0.2 };
-var lightPosTopLeft = { hmin: 0, hmax: 0.15, vmin: 0, vmax: 0.15 };
-var lightPosTopRight = { hmin: 0.85, hmax: 1.0, vmin: 0, vmax: 0.15 };
-var lightPosBottom = { hmin: 0.15, hmax: 0.85, vmin: 0.8, vmax: 1.0 };
-var lightPosBottomLeft = { hmin: 0, hmax: 0.15, vmin: 0.85, vmax: 1.0 };
-var lightPosBottomRight = { hmin: 0.85, hmax: 1.0, vmin: 0.85, vmax: 1.0 };
-var lightPosLeft = { hmin: 0, hmax: 0.15, vmin: 0.15, vmax: 0.85 };
-var lightPosLeftTop = { hmin: 0, hmax: 0.15, vmin: 0, vmax: 0.5 };
-var lightPosLeftMiddle = { hmin: 0, hmax: 0.15, vmin: 0.25, vmax: 0.75 };
-var lightPosLeftBottom = { hmin: 0, hmax: 0.15, vmin: 0.5, vmax: 1.0 };
-var lightPosRight = { hmin: 0.85, hmax: 1.0, vmin: 0.15, vmax: 0.85 };
-var lightPosRightTop = { hmin: 0.85, hmax: 1.0, vmin: 0, vmax: 0.5 };
-var lightPosRightMiddle = { hmin: 0.85, hmax: 1.0, vmin: 0.25, vmax: 0.75 };
-var lightPosRightBottom = { hmin: 0.85, hmax: 1.0, vmin: 0.5, vmax: 1.0 };
-var lightPosEntire = { hmin: 0.0, hmax: 1.0, vmin: 0.0, vmax: 1.0 };
-
-var lightPosBottomLeft14 = { hmin: 0, hmax: 0.25, vmin: 0.85, vmax: 1.0 };
-var lightPosBottomLeft12 = { hmin: 0.25, hmax: 0.5, vmin: 0.85, vmax: 1.0 };
-var lightPosBottomLeft34 = { hmin: 0.5, hmax: 0.75, vmin: 0.85, vmax: 1.0 };
-var lightPosBottomLeft11 = { hmin: 0.75, hmax: 1, vmin: 0.85, vmax: 1.0 };
-
-var lightPosBottomLeft112 = { hmin: 0, hmax: 0.5, vmin: 0.85, vmax: 1.0 };
-var lightPosBottomLeft121 = { hmin: 0.5, hmax: 1, vmin: 0.85, vmax: 1.0 };
-var lightPosBottomLeftNewMid = { hmin: 0.25, hmax: 0.75, vmin: 0.85, vmax: 1.0 };
-
-var lightPosTopLeft112 = { hmin: 0, hmax: 0.5, vmin: 0, vmax: 0.15 };
-var lightPosTopLeft121 = { hmin: 0.5, hmax: 1, vmin: 0, vmax: 0.15 };
-var lightPosTopLeftNewMid = { hmin: 0.25, hmax: 0.75, vmin: 0, vmax: 0.15 };
-
-function assignLightPos(pos, name) {
- var i = null;
-
- if (pos === "top")
- i = lightPosTop;
- else if (pos === "topleft")
- i = lightPosTopLeft;
- else if (pos === "topright")
- i = lightPosTopRight;
- else if (pos === "bottom")
- i = lightPosBottom;
- else if (pos === "bottomleft")
- i = lightPosBottomLeft;
- else if (pos === "bottomright")
- i = lightPosBottomRight;
- else if (pos === "left")
- i = lightPosLeft;
- else if (pos === "lefttop")
- i = lightPosLeftTop;
- else if (pos === "leftmiddle")
- i = lightPosLeftMiddle;
- else if (pos === "leftbottom")
- i = lightPosLeftBottom;
- else if (pos === "right")
- i = lightPosRight;
- else if (pos === "righttop")
- i = lightPosRightTop;
- else if (pos === "rightmiddle")
- i = lightPosRightMiddle;
- else if (pos === "rightbottom")
- i = lightPosRightBottom;
- else if (pos === "lightPosBottomLeft14")
- i = lightPosBottomLeft14;
- else if (pos === "lightPosBottomLeft12")
- i = lightPosBottomLeft12;
- else if (pos === "lightPosBottomLeft34")
- i = lightPosBottomLeft34;
- else if (pos === "lightPosBottomLeft11")
- i = lightPosBottomLeft11;
- else if (pos === "lightPosBottomLeft112")
- i = lightPosBottomLeft112;
- else if (pos === "lightPosBottomLeft121")
- i = lightPosBottomLeft121;
- else if (pos === "lightPosBottomLeftNewMid")
- i = lightPosBottomLeftNewMid;
- else if (pos === "lightPosTopLeft112")
- i = lightPosTopLeft112;
- else if (pos === "lightPosTopLeft121")
- i = lightPosTopLeft121;
- else if (pos === "lightPosTopLeftNewMid")
- i = lightPosTopLeftNewMid;
- else
- i = lightPosEntire;
-
- i.name = name;
- return i;
-}
-
-function getHostInLights(hostname) {
- return lights.filter(
- function (lights) {
- return lights.host === hostname
- }
- );
-}
-
-function getIpInLights(ip) {
- return lights.filter(
- function (lights) {
- return lights.ip === ip
- }
- );
-}
-
-function getIdInLights(id) {
- return lights.filter(
- function (lights) {
- return lights.id === id
- }
- );
-}
-
-// External properties properties, 2-dimensional arry of [ledType][key]
-devicesProperties = {};
-
-//****************************
-// Wizard Philips Hue
-//****************************
-
-var hueIPs = [];
-var hueIPsinc = 0;
-var hueLights = [];
-var hueEntertainmentConfigs = [];
-var hueEntertainmentServices = [];
-var lightLocation = [];
-var groupLights = [];
-var groupChannels = [];
-var groupLightsLocations = [];
-var isAPIv2Ready = true;
-var isEntertainmentReady = true;
-
-function startWizardPhilipsHue(e) {
- //create html
-
- var hue_title = 'wiz_hue_title';
- var hue_intro1 = 'wiz_hue_e_intro1';
- var hue_desc1 = 'wiz_hue_desc1';
- var hue_create_user = 'wiz_hue_create_user';
-
- $('#wiz_header').html('' + $.i18n(hue_title));
- $('#wizp1_body').html('' + $.i18n(hue_title) + '
' + $.i18n(hue_intro1) + '
');
- $('#wizp1_footer').html('');
- $('#wizp2_body').html('');
-
- var topContainer_html = '' + $.i18n(hue_desc1) + '
' +
- '' +
- '
' +
- '
' + $.i18n('wiz_hue_ip') + '
' +
- '
' +
- ' ' +
- ' ' + '
' +
- '
';
-
- if (storedAccess === 'expert') {
- topContainer_html += '
';
- }
-
- topContainer_html += '
';
- topContainer_html += '';
-
- $('#wh_topcontainer').append(topContainer_html);
-
- $('#usrcont').append('' + $.i18n('wiz_hue_username') + '
' +
- '
' +
- ''
- );
-
- $('#usrcont').append('
');
-
- $('#usrcont').append('<\p>' +
- '');
-
- $('#wizp2_body').append('
' + $.i18n('wiz_hue_e_desc2') + '
');
- createTable("gidsh", "gidsb", "hue_grp_ids_t");
- $('.gidsh').append(createTableRow([$.i18n('edt_dev_spec_groupId_title'), ""], true));
-
- $('#wizp2_body').append('' + $.i18n('wiz_hue_e_desc3') + '
');
-
- createTable("lidsh", "lidsb", "hue_ids_t");
- $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lightid_title'), $.i18n('wiz_pos'), $.i18n('wiz_identify')], true));
- $('#wizp2_footer').html('');
- $('#wizp3_body').html('' + $.i18n('wiz_hue_press_link') + '
');
-
- if (getStorage("darkMode") == "on")
- $('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
-
- //open modal
- $("#wizard_modal").modal({
- backdrop: "static",
- keyboard: false,
- show: true
- });
-
- //listen for continue
- $('#btn_wiz_cont').off().on('click', function () {
- beginWizardHue();
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- });
-}
-
-function checkHueBridge(cb, hueUser) {
- var usr = (typeof hueUser != "undefined") ? hueUser : 'config';
- if (usr === 'config') {
- $('#wiz_hue_discovered').html("");
- }
-
- if (hueIPs[hueIPsinc]) {
- var host = hueIPs[hueIPsinc].host;
- var port = hueIPs[hueIPsinc].port;
-
- if (usr != '')
- {
- getProperties_hue_bridge(cb, decodeURIComponent(host), port, usr);
- }
- else
- {
- cb(false, usr);
- }
-
- if (isAPIv2Ready) {
- $('#port').val(443);
- }
- }
-}
-
-function checkBridgeResult(reply, usr) {
- if (reply) {
- //abort checking, first reachable result is used
- $('#wiz_hue_ipstate').html("");
- $('#host').val(hueIPs[hueIPsinc].host)
- $('#port').val(hueIPs[hueIPsinc].port)
-
- $('#usrcont').toggle(true);
-
- checkHueBridge(checkUserResult, $('#user').val());
- }
- else {
- $('#usrcont').toggle(false);
- $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
- }
-};
-
-function checkUserResult(reply, username) {
- $('#usrcont').toggle(true);
-
- var hue_create_user = 'wiz_hue_e_create_user';
- if (!isEntertainmentReady) {
- hue_create_user = 'wiz_hue_create_user';
- $('#hue_client_key_r').toggle(false);
- } else {
- $('#hue_client_key_r').toggle(true);
- }
-
- $('#wiz_hue_create_user').text($.i18n(hue_create_user));
- $('#wiz_hue_create_user').toggle(true);
-
- if (reply) {
- $('#user').val(username);
-
- if (isEntertainmentReady && $('#clientkey').val() == "") {
- $('#wiz_hue_usrstate').html($.i18n('wiz_hue_e_clientkey_needed'));
- $('#wiz_hue_create_user').toggle(true);
- } else {
- $('#wiz_hue_usrstate').html("");
- $('#wiz_hue_create_user').toggle(false);
-
- if (isEntertainmentReady) {
- $('#hue_id_headline').text($.i18n('wiz_hue_e_desc3'));
- $('#hue_grp_ids_t').toggle(true);
-
- get_hue_groups(username);
-
- } else {
- $('#hue_id_headline').text($.i18n('wiz_hue_desc2'));
- $('#hue_grp_ids_t').toggle(false);
-
- get_hue_lights(username);
-
- }
- }
- }
- else {
- //abort checking, first reachable result is used
- $('#wiz_hue_usrstate').html($.i18n('wiz_hue_failure_user'));
- $('#wiz_hue_create_user').toggle(true);
- }
-};
-
-function useGroupId(id, username) {
- $('#groupId').val(hueEntertainmentConfigs[id].id);
- if (isAPIv2Ready) {
- var group = hueEntertainmentConfigs[id];
-
- groupLights = [];
- for (const light of group.light_services) {
- groupLights.push(light.rid);
- }
-
- groupChannels = [];
- for (const channel of group.channels) {
- groupChannels.push(channel);
- }
-
- groupLightsLocations = [];
- for (const location of group.locations.service_locations) {
- groupLightsLocations.push(location);
- }
- } else {
- //Ensure ligthIDs are strings
- groupLights = hueEntertainmentConfigs[id].lights.map(num => {
- return String(num);
- });
-
- var lightLocations = hueEntertainmentConfigs[id].locations;
- for (var locationID in lightLocations) {
- var lightLocation = {};
-
- let position = {
- x: lightLocations[locationID][0],
- y: lightLocations[locationID][1],
- z: lightLocations[locationID][2]
- };
- lightLocation.position = position;
-
- groupLightsLocations.push(lightLocation);
- }
- }
-
- get_hue_lights(username);
-}
-
-function updateBridgeDetails(properties) {
- var ledDeviceProperties = properties.config;
-
- if (!jQuery.isEmptyObject(ledDeviceProperties)) {
- isEntertainmentReady = properties.isEntertainmentReady;
- isAPIv2Ready = properties.isAPIv2Ready;
-
- if (ledDeviceProperties.name && ledDeviceProperties.bridgeid && ledDeviceProperties.modelid) {
- $('#wiz_hue_discovered').html(
- "Bridge: " + ledDeviceProperties.name +
- ", Modelid: " + ledDeviceProperties.modelid +
- ", Firmware: " + ledDeviceProperties.swversion + "
" +
- "API-Version: " + ledDeviceProperties.apiversion +
- ", Entertainment: " + (isEntertainmentReady ? "✓" : "-") +
- ", APIv2: " + (isAPIv2Ready ? "✓" : "-")
- );
- }
- }
-}
-
-async function discover_hue_bridges() {
- $('#wiz_hue_ipstate').html($.i18n('edt_dev_spec_devices_discovery_inprogress'));
-
- // $('#wiz_hue_discovered').html("")
- const res = await requestLedDeviceDiscovery('philipshue');
- if (res && !res.error) {
- const r = res.info;
-
- // Process devices returned by discovery
- if (r.devices.length == 0) {
- $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
- $('#wiz_hue_discovered').html("")
- }
- else {
- hueIPs = [];
- hueIPsinc = 0;
-
- var discoveryMethod = "ssdp";
- if (res.info.discoveryMethod) {
- discoveryMethod = res.info.discoveryMethod;
- }
-
- for (const device of r.devices) {
- if (device) {
- var host;
- var port;
- if (discoveryMethod === "ssdp") {
- if (device.hostname && device.domain) {
- host = device.hostname + "." + device.domain;
- port = device.port;
- } else {
- host = device.ip;
- port = device.port;
- }
- } else {
- host = device.service;
- port = device.port;
- }
-
- if (host) {
-
- if (!hueIPs.some(item => item.host === host)) {
- hueIPs.push({ host: host, port: port });
- }
- }
- }
- }
-
- $('#wiz_hue_ipstate').html("");
- $('#host').val(hueIPs[hueIPsinc].host)
- $('#port').val(hueIPs[hueIPsinc].port)
-
- $('#hue_bridge_select').html("");
-
- for (var key in hueIPs) {
- $('#hue_bridge_select').append(createSelOpt(key, hueIPs[key].host));
- }
-
- $('.hue_bridge_sel_watch').on("click", function () {
- hueIPsinc = $(this).val();
-
- var name = $("#hue_bridge_select option:selected").text();
- $('#host').val(name);
- $('#port').val(hueIPs[hueIPsinc].port)
-
- var usr = $('#user').val();
- if (usr != "") {
- checkHueBridge(checkUserResult, usr);
- } else {
- checkHueBridge(checkBridgeResult);
- }
- });
-
- $('.hue_bridge_sel_watch').click();
- }
- }
-}
-
-async function getProperties_hue_bridge(cb, hostAddress, port, username, resourceFilter) {
- let params = { host: hostAddress, username: username, filter: resourceFilter };
- if (port !== 'undefined') {
- params.port = parseInt(port);
- }
-
- var ledType = 'philipshue';
- var key = hostAddress;
-
- //Create ledType cache entry
- if (!devicesProperties[ledType]) {
- devicesProperties[ledType] = {};
- }
-
- // Use device's properties, if properties in chache
- if (devicesProperties[ledType][key] && devicesProperties[ledType][key][username]) {
- updateBridgeDetails(devicesProperties[ledType][key]);
- cb(true, username);
- } else {
- const res = await requestLedDeviceProperties(ledType, params);
- if (res && !res.error) {
- var ledDeviceProperties = res.info.properties;
- if (!jQuery.isEmptyObject(ledDeviceProperties)) {
-
- devicesProperties[ledType][key] = {};
- devicesProperties[ledType][key][username] = ledDeviceProperties;
-
- isAPIv2Ready = res.info.isAPIv2Ready;
- devicesProperties[ledType][key].isAPIv2Ready = isAPIv2Ready;
- isEntertainmentReady = res.info.isEntertainmentReady;
- devicesProperties[ledType][key].isEntertainmentReady = isEntertainmentReady;
-
- updateBridgeDetails(devicesProperties[ledType][key]);
- if (username === "config") {
- cb(true);
- } else {
- cb(true, username);
- }
- } else {
- cb(false, username);
- }
- } else {
- cb(false, username);
- }
- }
-}
-
-async function identify_hue_device(hostAddress, port, username, name, id, id_v1) {
- var disabled = $('#btn_wiz_save').is(':disabled');
- // Take care that new record cannot be save during background process
- $('#btn_wiz_save').prop('disabled', true);
-
- let params = { host: decodeURIComponent(hostAddress), username: username, lightName: decodeURIComponent(name), lightId: id, lightId_v1: id_v1 };
-
- if (port !== 'undefined') {
- params.port = parseInt(port);
- }
-
- await requestLedDeviceIdentification('philipshue', params);
-
- if (!window.readOnlyMode) {
- $('#btn_wiz_save').prop('disabled', disabled);
- }
-}
-
-//return editor Value
-function eV(vn, defaultVal = "") {
- var editor = (vn) ? conf_editor.getEditor("root.specificOptions." + vn) : null;
- return (editor == null) ? defaultVal : ((defaultVal != "" && !isNaN(defaultVal) && isNaN(editor.getValue())) ? defaultVal : editor.getValue());
-}
-
-function beginWizardHue() {
- var usr = eV("username");
- if (usr != "") {
- $('#user').val(usr);
- }
-
- var clkey = eV("clientkey");
- if (clkey != "") {
- $('#clientkey').val(clkey);
- }
-
- //check if host is empty/reachable/search for bridge
- if (eV("host") == "") {
- hueIPs = [];
- hueIPsinc = 0;
-
- discover_hue_bridges();
- }
- else {
- var host = eV("host");
- $('#host').val(host);
-
- var port = eV("port");
- if (port > 0) {
- $('#port').val(port);
- }
- else {
- $('#port').val('');
- }
- hueIPs.push({ host: host, port: port });
-
- if (usr != "") {
- checkHueBridge(checkUserResult, usr);
- } else {
- checkHueBridge(checkBridgeResult);
- }
- }
-
- $('#retry_bridge').off().on('click', function () {
- var host = $('#host').val();
- var port = parseInt($('#port').val());
-
- if (host != "") {
-
- var idx = hueIPs.findIndex(item => item.host === host && item.port === port);
- if (idx === -1) {
- hueIPs.push({ host: host, port: port });
- hueIPsinc = hueIPs.length - 1;
- } else {
- hueIPsinc = idx;
- }
- }
- else {
- discover_hue_bridges();
- }
-
- var usr = $('#user').val();
- if (usr != "") {
- checkHueBridge(checkUserResult, usr);
- } else {
- checkHueBridge(checkBridgeResult);
- }
- });
-
- $('#retry_usr').off().on('click', function () {
- checkHueBridge(checkUserResult, $('#user').val());
- });
-
- $('#wiz_hue_create_user').off().on('click', function () {
- createHueUser();
- });
-
- function assignLightEntertainmentPos(isFocusCenter, position, name, id) {
-
- var x = position.x;
- var z = position.z;
-
- if (isFocusCenter) {
- // Map lights as in centered range -0.5 to 0.5
- if (x < -0.5) {
- x = -0.5;
- } else if (x > 0.5) {
- x = 0.5;
- }
- if (z < -0.5) {
- z = -0.5;
- } else if (z > 0.5) {
- z = 0.5;
- }
- } else {
- // Map lights as in full range -1 to 1
- x /= 2;
- z /= 2;
- }
-
- var h = x + 0.5;
- var v = -z + 0.5;
-
- var hmin = h - 0.05;
- var hmax = h + 0.05;
- var vmin = v - 0.05;
- var vmax = v + 0.05;
-
- let layoutObject = {
- hmin: hmin < 0 ? 0 : hmin,
- hmax: hmax > 1 ? 1 : hmax,
- vmin: vmin < 0 ? 0 : vmin,
- vmax: vmax > 1 ? 1 : vmax,
- name: name
- };
-
- if (id) {
- layoutObject.name += "_" + id;
- }
- return layoutObject;
- }
-
- function assignSegmentedLightPos(segment, position, name) {
- var layoutObjects = [];
-
- var segTotalLength = 0;
- for (var key in segment) {
-
- segTotalLength += segment[key].length;
- }
-
- var min;
- var max;
- var horizontal = true;
-
- var layoutObject = assignLightPos(position, name);
- if (position === "left" || position === "right") {
- // vertical distribution
- min = layoutObject.vmin;
- max = layoutObject.vmax;
- horizontal = false;
-
- } else {
- // horizontal distribution
- min = layoutObject.hmin;
- max = layoutObject.hmax;
- }
-
- var step = (max - min) / segTotalLength;
- var start = min;
-
- for (var key in segment) {
- min = start;
- max = round(start + segment[key].length * step);
-
- if (horizontal) {
- layoutObject.hmin = min;
- layoutObject.hmax = max;
- } else {
- layoutObject.vmin = min;
- layoutObject.vmax = max;
- }
- layoutObject.name = name + "_" + key;
- layoutObjects.push(JSON.parse(JSON.stringify(layoutObject)));
-
- start = max;
- }
-
- return layoutObjects;
- }
-
- $('#btn_wiz_save').off().on("click", function () {
- var hueLedConfig = [];
- var finalLightIds = [];
- var channelNumber = 0;
-
- //create hue led config
- for (var key in groupLights) {
- var lightId = groupLights[key];
-
- if ($('#hue_' + lightId).val() != "disabled") {
- finalLightIds.push(lightId);
-
- var lightName;
- if (isAPIv2Ready) {
- var light = hueLights.find(light => light.id === lightId);
- lightName = light.metadata.name;
- } else {
- lightName = hueLights[lightId].name;
- }
-
- var position = $('#hue_' + lightId).val();
- var lightIdx = groupLights.indexOf(lightId);
- var lightLocation = groupLightsLocations[lightIdx];
-
- var serviceID;
- if (isAPIv2Ready) {
- serviceID = lightLocation.service.rid;
- }
-
- if (position.startsWith("entertainment")) {
-
- // Layout per entertainment area definition at bridge
- var isFocusCenter = false;
- if (position === "entertainment_center") {
- isFocusCenter = true;
- }
-
- if (isAPIv2Ready) {
-
- groupChannels.forEach((channel) => {
- if (channel.members[0].service.rid === serviceID) {
- var layoutObject = assignLightEntertainmentPos(isFocusCenter, channel.position, lightName, channel.channel_id);
- hueLedConfig.push(JSON.parse(JSON.stringify(layoutObject)));
- ++channelNumber;
- }
- });
- } else {
- var layoutObject = assignLightEntertainmentPos(isFocusCenter, lightLocation.position, lightName);
- hueLedConfig.push(JSON.parse(JSON.stringify(layoutObject)));
- }
- }
- else {
- // Layout per manual settings
- var maxSegments = 1;
-
- if (isAPIv2Ready) {
- var service = hueEntertainmentServices.find(service => service.id === serviceID);
- maxSegments = service.segments.max_segments;
- }
-
- if (maxSegments > 1) {
- var segment = service.segments.segments;
- var layoutObjects = assignSegmentedLightPos(segment, position, lightName);
- hueLedConfig.push(...layoutObjects);
- } else {
- var layoutObject = assignLightPos(position, lightName);
- hueLedConfig.push(JSON.parse(JSON.stringify(layoutObject)));
- }
- channelNumber += maxSegments;
- }
- }
- }
-
- var sc = window.serverConfig;
- sc.leds = hueLedConfig;
-
- //Adjust gamma, brightness and compensation
- var c = sc.color.channelAdjustment[0];
- c.gammaBlue = 1.0;
- c.gammaRed = 1.0;
- c.gammaGreen = 1.0;
- c.brightness = 100;
- c.brightnessCompensation = 0;
-
- //device config
-
- //Start with a clean configuration
- var d = {};
- d.host = $('#host').val();
- d.port = parseInt($('#port').val());
- d.username = $('#user').val();
- d.type = 'philipshue';
- d.colorOrder = 'rgb';
- d.lightIds = finalLightIds;
- d.transitiontime = parseInt(eV("transitiontime", 1));
- d.restoreOriginalState = (eV("restoreOriginalState", false) == true);
- d.switchOffOnBlack = (eV("switchOffOnBlack", false) == true);
-
- d.blackLevel = parseFloat(eV("blackLevel", 0.009));
- d.onBlackTimeToPowerOff = parseInt(eV("onBlackTimeToPowerOff", 600));
- d.onBlackTimeToPowerOn = parseInt(eV("onBlackTimeToPowerOn", 300));
- d.brightnessFactor = parseFloat(eV("brightnessFactor", 1));
-
- d.clientkey = $('#clientkey').val();
- d.groupId = $('#groupId').val();
- d.blackLightsTimeout = parseInt(eV("blackLightsTimeout", 5000));
- d.brightnessMin = parseFloat(eV("brightnessMin", 0));
- d.brightnessMax = parseFloat(eV("brightnessMax", 1));
- d.brightnessThreshold = parseFloat(eV("brightnessThreshold", 0.0001));
- d.handshakeTimeoutMin = parseInt(eV("handshakeTimeoutMin", 300));
- d.handshakeTimeoutMax = parseInt(eV("handshakeTimeoutMax", 1000));
- d.verbose = (eV("verbose") == true);
-
- d.autoStart = conf_editor.getEditor("root.generalOptions.autoStart").getValue();
- d.enableAttempts = parseInt(conf_editor.getEditor("root.generalOptions.enableAttempts").getValue());
- d.enableAttemptsInterval = parseInt(conf_editor.getEditor("root.generalOptions.enableAttemptsInterval").getValue());
-
- d.useEntertainmentAPI = isEntertainmentReady;
- d.useAPIv2 = isAPIv2Ready;
-
- if (isEntertainmentReady) {
- d.hardwareLedCount = channelNumber;
- if (window.serverConfig.device.type !== d.type) {
- //smoothing on, if new device
- sc.smoothing = { enable: true };
- }
- } else {
- d.hardwareLedCount = finalLightIds.length;
- d.verbose = false;
- if (window.serverConfig.device.type !== d.type) {
- //smoothing off, if new device
- sc.smoothing = { enable: false };
- }
- }
-
- window.serverConfig.device = d;
-
- requestWriteConfig(sc, true);
- resetWizard();
- });
-
- $('#btn_wiz_abort').off().on('click', resetWizard);
-}
-
-function createHueUser() {
- var host = hueIPs[hueIPsinc].host;
- var port = hueIPs[hueIPsinc].port;
-
- let params = { host: host };
- if (port !== 'undefined') {
- params.port = parseInt(port);
- }
-
- var retryTime = 30;
- var retryInterval = 2;
-
- var UserInterval = setInterval(function () {
-
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(false);
- $('#wizp3').toggle(true);
-
- (async () => {
-
- retryTime -= retryInterval;
- $("#connectionTime").html(retryTime);
- if (retryTime <= 0) {
- abortConnection(UserInterval);
- clearInterval(UserInterval);
- }
- else {
- const res = await requestLedDeviceAddAuthorization('philipshue', params);
- if (res && !res.error) {
- var response = res.info;
-
- if (jQuery.isEmptyObject(response)) {
- debugMessage(retryTime + ": link button not pressed or device not reachable");
- } else {
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- $('#wizp3').toggle(false);
-
- var username = response.username;
- if (username != 'undefined') {
- $('#user').val(username);
- conf_editor.getEditor("root.specificOptions.username").setValue(username);
- conf_editor.getEditor("root.specificOptions.host").setValue(host);
- conf_editor.getEditor("root.specificOptions.port").setValue(port);
- }
-
- if (isEntertainmentReady) {
- var clientkey = response.clientkey;
- if (clientkey != 'undefined') {
- $('#clientkey').val(clientkey);
- conf_editor.getEditor("root.specificOptions.clientkey").setValue(clientkey);
- }
- }
- checkHueBridge(checkUserResult, username);
- clearInterval(UserInterval);
- }
- } else {
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- $('#wizp3').toggle(false);
- clearInterval(UserInterval);
- }
- }
- })();
-
- }, retryInterval * 1000);
-}
-
-function get_hue_groups(username) {
- var host = hueIPs[hueIPsinc].host;
-
- if (devicesProperties['philipshue'][host] && devicesProperties['philipshue'][host][username]) {
- var ledProperties = devicesProperties['philipshue'][host][username];
-
- if (isAPIv2Ready) {
- if (!jQuery.isEmptyObject(ledProperties.data)) {
- if (Object.keys(ledProperties.data).length > 0) {
- hueEntertainmentConfigs = ledProperties.data.filter(config => {
- return config.type === "entertainment_configuration";
- });
- hueEntertainmentServices = ledProperties.data.filter(config => {
- return (config.type === "entertainment" && config.renderer === true);
- });
- }
- }
- } else {
- if (!jQuery.isEmptyObject(ledProperties.groups)) {
- hueEntertainmentConfigs = [];
- var hueGroups = ledProperties.groups;
- for (var groupid in hueGroups) {
- if (hueGroups[groupid].type == 'Entertainment') {
- hueGroups[groupid].id = groupid;
- hueEntertainmentConfigs.push(hueGroups[groupid]);
- }
- }
- }
- }
-
- if (Object.keys(hueEntertainmentConfigs).length > 0) {
-
- $('.lidsb').html("");
- $('#wh_topcontainer').toggle(false);
- $('#hue_grp_ids_t').toggle(true);
-
- for (var groupid in hueEntertainmentConfigs) {
- $('.gidsb').append(createTableRow([groupid + ' (' + hueEntertainmentConfigs[groupid].name + ')', '']));
- }
- } else {
- noAPISupport('wiz_hue_e_noegrpids', username);
- }
- }
-}
-
-function noAPISupport(txt, username) {
- showNotification('danger', $.i18n('wiz_hue_e_title'), $.i18n('wiz_hue_e_noapisupport_hint'));
- conf_editor.getEditor("root.specificOptions.useEntertainmentAPI").setValue(false);
- $("#root_specificOptions_useEntertainmentAPI").trigger("change");
- $('#btn_wiz_holder').append('' + $.i18n('wiz_hue_e_noapisupport_hint') + '
');
- $('#hue_grp_ids_t').toggle(false);
- var txt = (txt) ? $.i18n(txt) : $.i18n('wiz_hue_e_nogrpids');
- $('' + txt + '
' + $.i18n('wiz_hue_e_noapisupport') + '
').insertBefore('#wizp2_body #hue_ids_t');
- $('#hue_id_headline').html($.i18n('wiz_hue_desc2'));
-
- get_hue_lights(username);
-}
-
-function get_hue_lights(username) {
- var host = hueIPs[hueIPsinc].host;
-
- if (devicesProperties['philipshue'][host] && devicesProperties['philipshue'][host][username]) {
- var ledProperties = devicesProperties['philipshue'][host][username];
-
- if (isAPIv2Ready) {
- if (!jQuery.isEmptyObject(ledProperties.data)) {
- if (Object.keys(ledProperties.data).length > 0) {
- hueLights = ledProperties.data.filter(config => {
- return config.type === "light";
- });
- }
- }
- } else {
- if (!jQuery.isEmptyObject(ledProperties.lights)) {
- hueLights = ledProperties.lights;
- }
- }
-
- if (Object.keys(hueLights).length > 0) {
- if (!isEntertainmentReady) {
- $('#wh_topcontainer').toggle(false);
- }
- $('#hue_ids_t, #btn_wiz_save').toggle(true);
-
- var lightOptions = [
- "top", "topleft", "topright",
- "bottom", "bottomleft", "bottomright",
- "left", "lefttop", "leftmiddle", "leftbottom",
- "right", "righttop", "rightmiddle", "rightbottom",
- "entire",
- "lightPosTopLeft112", "lightPosTopLeftNewMid", "lightPosTopLeft121",
- "lightPosBottomLeft14", "lightPosBottomLeft12", "lightPosBottomLeft34", "lightPosBottomLeft11",
- "lightPosBottomLeft112", "lightPosBottomLeftNewMid", "lightPosBottomLeft121"
- ];
-
- if (isEntertainmentReady) {
- lightOptions.unshift("entertainment_center");
- lightOptions.unshift("entertainment");
- } else {
- lightOptions.unshift("disabled");
- groupLights = Object.keys(hueLights);
- }
-
- $('.lidsb').html("");
-
- var pos = "";
- for (var id in groupLights) {
- var lightId = groupLights[id];
- var lightId_v1 = "/lights/" + lightId;
-
- var lightName;
- if (isAPIv2Ready) {
- var light = hueLights.find(light => light.id === lightId);
- lightName = light.metadata.name;
- lightId_v1 = light.id_v1;
- } else {
- lightName = hueLights[lightId].name;
- }
-
- if (isEntertainmentReady) {
- var lightLocation = {};
- lightLocation = groupLightsLocations[id];
- if (lightLocation) {
- if (isAPIv2Ready) {
- pos = 0;
- } else {
- var x = lightLocation.position.x;
- var y = lightLocation.position.y;
- var z = lightLocation.position.z;
-
- var xval = (x < 0) ? "left" : "right";
- if (z != 1 && x >= -0.25 && x <= 0.25) xval = "";
- switch (z) {
- case 1: // top / Ceiling height
- pos = "top" + xval;
- break;
- case 0: // middle / TV height
- pos = (xval == "" && y >= 0.75) ? "bottom" : xval + "middle";
- break;
- case -1: // bottom / Ground height
- pos = xval + "bottom";
- break;
- }
- }
- }
- }
-
- var options = "";
- for (var opt in lightOptions) {
- var val = lightOptions[opt];
- var txt = (val != 'entire' && val != 'disabled') ? 'conf_leds_layout_cl_' : 'wiz_ids_';
- options += '';
- }
-
- $('.lidsb').append(createTableRow([id + ' (' + lightName + ')', '', '']));
- }
-
- if (!isEntertainmentReady) {
- $('.hue_sel_watch').on("change", function () {
- var cC = 0;
- for (var key in hueLights) {
- if ($('#hue_' + key).val() != "disabled") {
- cC++;
- }
- }
-
- (cC == 0 || window.readOnlyMode) ? $('#btn_wiz_save').prop("disabled", true) : $('#btn_wiz_save').prop("disabled", false);
- });
- }
- $('.hue_sel_watch').trigger('change');
- }
- else {
- var txt = '' + $.i18n('wiz_hue_noids') + '
';
- $('#wizp2_body').append(txt);
- }
- }
-}
-
-function abortConnection(UserInterval) {
- clearInterval(UserInterval);
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- $('#wizp3').toggle(false);
- $("#wiz_hue_usrstate").html($.i18n('wiz_hue_failure_connection'));
-}
-
-//****************************
-// Wizard Yeelight
-//****************************
-var lights = null;
-function startWizardYeelight(e) {
- //create html
-
- var yeelight_title = 'wiz_yeelight_title';
- var yeelight_intro1 = 'wiz_yeelight_intro1';
-
- $('#wiz_header').html('' + $.i18n(yeelight_title));
- $('#wizp1_body').html('' + $.i18n(yeelight_title) + '
' + $.i18n(yeelight_intro1) + '
');
-
- $('#wizp1_footer').html('');
-
- $('#wizp2_body').html('');
-
- $('#wh_topcontainer').append('');
-
- $('#wizp2_body').append('' + $.i18n('wiz_yeelight_desc2') + '
');
-
- createTable("lidsh", "lidsb", "yee_ids_t");
- $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lights_title'), $.i18n('wiz_pos'), $.i18n('wiz_identify')], true));
- $('#wizp2_footer').html(''
- + $.i18n('general_btn_cancel') + '');
-
- if (getStorage("darkMode") == "on")
- $('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
-
- //open modal
- $("#wizard_modal").modal({ backdrop: "static", keyboard: false, show: true });
-
- //listen for continue
- $('#btn_wiz_cont').off().on('click', function () {
- beginWizardYeelight();
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- });
-}
-
-function beginWizardYeelight() {
- lights = [];
- configuredLights = conf_editor.getEditor("root.specificOptions.lights").getValue();
-
- discover_yeelight_lights();
-
- $('#btn_wiz_save').off().on("click", function () {
- var yeelightLedConfig = [];
- var finalLights = [];
-
- //create yeelight led config
- for (var key in lights) {
- if ($('#yee_' + key).val() !== "disabled") {
-
- var name = lights[key].name;
- // Set Name to layout-position, if empty
- if (name === "") {
- name = lights[key].host;
- }
-
- finalLights.push(lights[key]);
-
- var idx_content = assignLightPos($('#yee_' + key).val(), name);
- yeelightLedConfig.push(JSON.parse(JSON.stringify(idx_content)));
- }
- }
-
- //LED layout
- window.serverConfig.leds = yeelightLedConfig;
-
- //LED device config
- var currentDeviceType = window.serverConfig.device.type;
-
- //Start with a clean configuration
- var d = {};
-
- d.type = 'yeelight';
- d.hardwareLedCount = finalLights.length;
- d.colorOrder = conf_editor.getEditor("root.generalOptions.colorOrder").getValue();
- d.colorModel = parseInt(conf_editor.getEditor("root.specificOptions.colorModel").getValue());
-
- d.transEffect = parseInt(conf_editor.getEditor("root.specificOptions.transEffect").getValue());
- d.transTime = parseInt(conf_editor.getEditor("root.specificOptions.transTime").getValue());
- d.extraTimeDarkness = parseInt(conf_editor.getEditor("root.specificOptions.extraTimeDarkness").getValue());
-
- d.brightnessMin = parseInt(conf_editor.getEditor("root.specificOptions.brightnessMin").getValue());
- d.brightnessSwitchOffOnMinimum = JSON.parse(conf_editor.getEditor("root.specificOptions.brightnessSwitchOffOnMinimum").getValue());
- d.brightnessMax = parseInt(conf_editor.getEditor("root.specificOptions.brightnessMax").getValue());
- d.brightnessFactor = parseFloat(conf_editor.getEditor("root.specificOptions.brightnessFactor").getValue());
-
- d.latchTime = parseInt(conf_editor.getEditor("root.specificOptions.latchTime").getValue());;
- d.debugLevel = parseInt(conf_editor.getEditor("root.specificOptions.debugLevel").getValue());
-
- d.lights = finalLights;
-
- window.serverConfig.device = d;
-
- if (currentDeviceType !== d.type) {
- //smoothing off, if new device
- window.serverConfig.smoothing = { enable: false };
- }
-
- requestWriteConfig(window.serverConfig, true);
- resetWizard();
- });
-
- $('#btn_wiz_abort').off().on('click', resetWizard);
-}
-
-async function discover_yeelight_lights() {
- var light = {};
- // Get discovered lights
- const res = await requestLedDeviceDiscovery('yeelight');
-
- // TODO: error case unhandled
- // res can be: false (timeout) or res.error (not found)
- if (res && !res.error) {
- const r = res.info;
-
- var discoveryMethod = "ssdp";
- if (res.info.discoveryMethod) {
- discoveryMethod = res.info.discoveryMethod;
- }
-
- // Process devices returned by discovery
- for (const device of r.devices) {
- if (device.hostname !== "") {
- if (getHostInLights(device.hostname).length === 0) {
- var light = {};
-
-
-
- if (discoveryMethod === "ssdp") {
- //Create a valid hostname
- if (device.domain) {
- light.host += '.' + device.domain;
- }
- } else {
- light.host = device.service;
- light.name = device.name;
- }
- light.port = device.port;
-
- if (device.txt) {
- light.model = device.txt.md;
- //Yeelight does not provide correct API port with mDNS response, use default one
- light.port = 55443;
- }
- else {
- light.name = device.other.name;
- light.model = device.other.model;
- }
- lights.push(light);
- }
- }
- }
-
- // Add additional items from configuration
- for (var keyConfig in configuredLights) {
- var host = configuredLights[keyConfig].host;
-
- //In case port has been explicitly provided, overwrite port given as part of hostname
- if (configuredLights[keyConfig].port !== 0)
- port = configuredLights[keyConfig].port;
-
- if (host !== "")
- if (getHostInLights(host).length === 0) {
- var light = {};
- light.host = host;
- light.port = port;
- light.name = configuredLights[keyConfig].name;
- light.model = "color4";
- lights.push(light);
- }
- }
-
- assign_yeelight_lights();
- }
-}
-
-function assign_yeelight_lights() {
- // Model mappings, see https://www.home-assistant.io/integrations/yeelight/
- var models = ['color', 'color1', 'YLDP02YL', 'YLDP02YL', 'color2', 'YLDP06YL', 'color4', 'YLDP13YL', 'color6', 'YLDP13AYL', 'colorb', "YLDP005", 'colorc', "YLDP004-A", 'stripe', 'YLDD04YL', 'strip1', 'YLDD01YL', 'YLDD02YL', 'strip4', 'YLDD05YL', 'strip6', 'YLDD05YL'];
-
- // If records are left for configuration
- if (Object.keys(lights).length > 0) {
- $('#wh_topcontainer').toggle(false);
- $('#yee_ids_t, #btn_wiz_save').toggle(true);
-
- var lightOptions = [
- "top", "topleft", "topright",
- "bottom", "bottomleft", "bottomright",
- "left", "lefttop", "leftmiddle", "leftbottom",
- "right", "righttop", "rightmiddle", "rightbottom",
- "entire",
- "lightPosTopLeft112", "lightPosTopLeftNewMid", "lightPosTopLeft121",
- "lightPosBottomLeft14", "lightPosBottomLeft12", "lightPosBottomLeft34", "lightPosBottomLeft11",
- "lightPosBottomLeft112", "lightPosBottomLeftNewMid", "lightPosBottomLeft121"
- ];
-
- lightOptions.unshift("disabled");
-
- $('.lidsb').html("");
- var pos = "";
-
- for (var lightid in lights) {
- var lightHostname = lights[lightid].host;
- var lightPort = lights[lightid].port;
- var lightName = lights[lightid].name;
-
- if (lightName === "")
- lightName = $.i18n('edt_dev_spec_lights_itemtitle') + '(' + lightHostname + ')';
-
- var options = "";
- for (var opt in lightOptions) {
- var val = lightOptions[opt];
- var txt = (val !== 'entire' && val !== 'disabled') ? 'conf_leds_layout_cl_' : 'wiz_ids_';
- options += '';
- }
-
- var enabled = 'enabled';
- if (!models.includes(lights[lightid].model)) {
- var enabled = 'disabled';
- options = '';
- }
-
- $('.lidsb').append(createTableRow([(parseInt(lightid, 10) + 1) + '. ' + lightName, '', '']));
- }
-
- $('.yee_sel_watch').on("change", function () {
- var cC = 0;
- for (var key in lights) {
- if ($('#yee_' + key).val() !== "disabled") {
- cC++;
- }
- }
-
- if (cC === 0 || window.readOnlyMode)
- $('#btn_wiz_save').prop("disabled", true);
- else
- $('#btn_wiz_save').prop("disabled", false);
- });
- $('.yee_sel_watch').trigger('change');
- }
- else {
- var noLightsTxt = '' + $.i18n('wiz_noLights', 'Yeelights') + '
';
- $('#wizp2_body').append(noLightsTxt);
- }
-}
-
-async function getProperties_yeelight(host, port) {
- let params = { host: host, port: port };
-
- const res = await requestLedDeviceProperties('yeelight', params);
-
- // TODO: error case unhandled
- // res can be: false (timeout) or res.error (not found)
- if (res && !res.error) {
- const r = res.info
- console.log("Yeelight properties: ", r);
- }
-}
-
-async function identify_yeelight_device(host, port) {
-
- var disabled = $('#btn_wiz_save').is(':disabled');
-
- // Take care that new record cannot be save during background process
- $('#btn_wiz_save').prop('disabled', true);
-
- let params = { host: host, port: port };
- await requestLedDeviceIdentification("yeelight", params);
-
- if (!window.readOnlyMode) {
- $('#btn_wiz_save').prop('disabled', disabled);
- }
-}
-
-//****************************
-// Wizard AtmoOrb
-//****************************
-var lights = null;
-function startWizardAtmoOrb(e) {
- //create html
-
- var atmoorb_title = 'wiz_atmoorb_title';
- var atmoorb_intro1 = 'wiz_atmoorb_intro1';
-
- $('#wiz_header').html('' + $.i18n(atmoorb_title));
- $('#wizp1_body').html('' + $.i18n(atmoorb_title) + '
' + $.i18n(atmoorb_intro1) + '
');
-
- $('#wizp1_footer').html('');
-
- $('#wizp2_body').html('');
-
- $('#wh_topcontainer').append('');
-
- $('#wizp2_body').append('' + $.i18n('wiz_atmoorb_desc2') + '
');
-
- createTable("lidsh", "lidsb", "orb_ids_t");
- $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lights_title'), $.i18n('wiz_pos'), $.i18n('wiz_identify')], true));
- $('#wizp2_footer').html(''
- + $.i18n('general_btn_cancel') + '');
-
- if (getStorage("darkMode") == "on")
- $('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
-
- //open modal
- $("#wizard_modal").modal({ backdrop: "static", keyboard: false, show: true });
-
- //listen for continue
- $('#btn_wiz_cont').off().on('click', function () {
- beginWizardAtmoOrb();
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- });
-}
-
-function beginWizardAtmoOrb() {
- lights = [];
- configuredLights = [];
-
- var configruedOrbIds = conf_editor.getEditor("root.specificOptions.orbIds").getValue().trim();
- if (configruedOrbIds.length !== 0) {
- configuredLights = configruedOrbIds.split(",").map(Number);
- }
-
- var multiCastGroup = conf_editor.getEditor("root.specificOptions.host").getValue();
- var multiCastPort = parseInt(conf_editor.getEditor("root.specificOptions.port").getValue());
-
- discover_atmoorb_lights(multiCastGroup, multiCastPort);
-
- $('#btn_wiz_save').off().on("click", function () {
- var atmoorbLedConfig = [];
- var finalLights = [];
-
- //create atmoorb led config
- for (var key in lights) {
- if ($('#orb_' + key).val() !== "disabled") {
- // Set Name to layout-position, if empty
- if (lights[key].name === "") {
- lights[key].name = $.i18n('conf_leds_layout_cl_' + $('#orb_' + key).val());
- }
-
- finalLights.push(lights[key].id);
-
- var name = lights[key].id;
- if (lights[key].host !== "")
- name += ':' + lights[key].host;
-
- var idx_content = assignLightPos($('#orb_' + key).val(), name);
- atmoorbLedConfig.push(JSON.parse(JSON.stringify(idx_content)));
- }
- }
-
- //LED layout
- window.serverConfig.leds = atmoorbLedConfig;
-
- //LED device config
- //Start with a clean configuration
- var d = {};
-
- d.type = 'atmoorb';
- d.hardwareLedCount = finalLights.length;
- d.colorOrder = conf_editor.getEditor("root.generalOptions.colorOrder").getValue();
-
- d.orbIds = finalLights.toString();
- d.useOrbSmoothing = (eV("useOrbSmoothing") == true);
-
- d.host = conf_editor.getEditor("root.specificOptions.host").getValue();
- d.port = parseInt(conf_editor.getEditor("root.specificOptions.port").getValue());
- d.latchTime = parseInt(conf_editor.getEditor("root.specificOptions.latchTime").getValue());;
-
- window.serverConfig.device = d;
-
- requestWriteConfig(window.serverConfig, true);
- resetWizard();
- });
-
- $('#btn_wiz_abort').off().on('click', resetWizard);
-}
-
-async function discover_atmoorb_lights(multiCastGroup, multiCastPort) {
- var light = {};
-
- var params = {};
- if (multiCastGroup !== "") {
- params.multiCastGroup = multiCastGroup;
- }
-
- if (multiCastPort !== 0) {
- params.multiCastPort = multiCastPort;
- }
-
- // Get discovered lights
- const res = await requestLedDeviceDiscovery('atmoorb', params);
-
- // TODO: error case unhandled
- // res can be: false (timeout) or res.error (not found)
- if (res && !res.error) {
- const r = res.info;
-
- // Process devices returned by discovery
- for (const device of r.devices) {
- if (device.id !== "") {
- if (getIdInLights(device.id).length === 0) {
- var light = {};
- light.id = device.id;
- light.ip = device.ip;
- light.host = device.hostname;
- lights.push(light);
- }
- }
- }
-
- // Add additional items from configuration
- for (const keyConfig in configuredLights) {
- if (configuredLights[keyConfig] !== "" && !isNaN(configuredLights[keyConfig])) {
- if (getIdInLights(configuredLights[keyConfig]).length === 0) {
- var light = {};
- light.id = configuredLights[keyConfig];
- light.ip = "";
- light.host = "";
- lights.push(light);
- }
- }
- }
-
- lights.sort((a, b) => (a.id > b.id) ? 1 : -1);
-
- assign_atmoorb_lights();
- }
-}
-
-function assign_atmoorb_lights() {
- // If records are left for configuration
- if (Object.keys(lights).length > 0) {
- $('#wh_topcontainer').toggle(false);
- $('#orb_ids_t, #btn_wiz_save').toggle(true);
-
- var lightOptions = [
- "top", "topleft", "topright",
- "bottom", "bottomleft", "bottomright",
- "left", "lefttop", "leftmiddle", "leftbottom",
- "right", "righttop", "rightmiddle", "rightbottom",
- "entire",
- "lightPosTopLeft112", "lightPosTopLeftNewMid", "lightPosTopLeft121",
- "lightPosBottomLeft14", "lightPosBottomLeft12", "lightPosBottomLeft34", "lightPosBottomLeft11",
- "lightPosBottomLeft112", "lightPosBottomLeftNewMid", "lightPosBottomLeft121"
- ];
-
- lightOptions.unshift("disabled");
-
- $('.lidsb').html("");
- var pos = "";
-
- for (var lightid in lights) {
- var orbId = lights[lightid].id;
- var orbIp = lights[lightid].ip;
- var orbHostname = lights[lightid].host;
-
- if (orbHostname === "")
- orbHostname = $.i18n('edt_dev_spec_lights_itemtitle');
-
- var options = "";
- for (var opt in lightOptions) {
- var val = lightOptions[opt];
- var txt = (val !== 'entire' && val !== 'disabled') ? 'conf_leds_layout_cl_' : 'wiz_ids_';
- options += '';
- }
-
- var enabled = 'enabled';
- if (orbId < 1 || orbId > 255) {
- enabled = 'disabled';
- options = '';
- }
-
- var lightAnnotation = "";
- if (orbIp !== "") {
- lightAnnotation = ': ' + orbIp + '
(' + orbHostname + ')';
- }
-
- $('.lidsb').append(createTableRow([orbId + lightAnnotation, '', '']));
- }
-
- $('.orb_sel_watch').on("change", function () {
- var cC = 0;
- for (var key in lights) {
- if ($('#orb_' + key).val() !== "disabled") {
- cC++;
- }
- }
- if (cC === 0 || window.readOnlyMode)
- $('#btn_wiz_save').prop("disabled", true);
- else
- $('#btn_wiz_save').prop("disabled", false);
- });
- $('.orb_sel_watch').trigger('change');
- }
- else {
- var noLightsTxt = '' + $.i18n('wiz_noLights', 'AtmoOrbs') + '
';
- $('#wizp2_body').append(noLightsTxt);
- }
-}
-
-async function identify_atmoorb_device(orbId) {
- var disabled = $('#btn_wiz_save').is(':disabled');
-
- // Take care that new record cannot be save during background process
- $('#btn_wiz_save').prop('disabled', true);
-
- let params = { id: orbId };
- await requestLedDeviceIdentification("atmoorb", params);
-
- if (!window.readOnlyMode) {
- $('#btn_wiz_save').prop('disabled', disabled);
- }
-}
-
-//****************************
-// Nanoleaf Token Wizard
-//****************************
-var lights = null;
-function startWizardNanoleafUserAuth(e) {
- //create html
- var nanoleaf_user_auth_title = 'wiz_nanoleaf_user_auth_title';
- var nanoleaf_user_auth_intro = 'wiz_nanoleaf_user_auth_intro';
-
- $('#wiz_header').html('' + $.i18n(nanoleaf_user_auth_title));
- $('#wizp1_body').html('' + $.i18n(nanoleaf_user_auth_title) + '
' + $.i18n(nanoleaf_user_auth_intro) + '
');
-
- $('#wizp1_footer').html('');
-
- $('#wizp3_body').html('' + $.i18n('wiz_nanoleaf_press_onoff_button') + '
');
-
- if (getStorage("darkMode") == "on")
- $('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
-
- //open modal
- $("#wizard_modal").modal({ backdrop: "static", keyboard: false, show: true });
-
- //listen for continue
- $('#btn_wiz_cont').off().on('click', function () {
- createNanoleafUserAuthorization();
- $('#wizp1').toggle(false);
- $('#wizp3').toggle(true);
- });
-}
-
-function createNanoleafUserAuthorization() {
- var host = conf_editor.getEditor("root.specificOptions.host").getValue();
-
- let params = { host: host };
-
- var retryTime = 30;
- var retryInterval = 2;
-
- var UserInterval = setInterval(function () {
-
- $('#wizp1').toggle(false);
- $('#wizp3').toggle(true);
-
- (async () => {
-
- retryTime -= retryInterval;
- $("#connectionTime").html(retryTime);
- if (retryTime <= 0) {
- abortConnection(UserInterval);
- clearInterval(UserInterval);
-
- showNotification('warning', $.i18n('wiz_nanoleaf_failure_auth_token'), $.i18n('wiz_nanoleaf_failure_auth_token_t'));
-
- resetWizard(true);
- }
- else {
- const res = await requestLedDeviceAddAuthorization('nanoleaf', params);
- if (res && !res.error) {
- var response = res.info;
-
- if (jQuery.isEmptyObject(response)) {
- debugMessage(retryTime + ": Power On/Off button not pressed or device not reachable");
- } else {
- $('#wizp1').toggle(false);
- $('#wizp3').toggle(false);
-
- var token = response.auth_token;
- if (token != 'undefined') {
- conf_editor.getEditor("root.specificOptions.token").setValue(token);
- }
- clearInterval(UserInterval);
- resetWizard(true);
- }
- } else {
- $('#wizp1').toggle(false);
- $('#wizp3').toggle(false);
- clearInterval(UserInterval);
- resetWizard(true);
- }
- }
- })();
-
- }, retryInterval * 1000);
-}
-
diff --git a/assets/webconfig/js/wizards/LedDevice_atmoorb.js b/assets/webconfig/js/wizards/LedDevice_atmoorb.js
new file mode 100644
index 00000000..67d9bd5a
--- /dev/null
+++ b/assets/webconfig/js/wizards/LedDevice_atmoorb.js
@@ -0,0 +1,283 @@
+//****************************
+// Wizard AtmoOrb
+//****************************
+
+import { ledDeviceWizardUtils as utils } from './LedDevice_utils.js';
+
+const atmoorbWizard = (() => {
+
+ const lights = [];
+ let configuredLights = [];
+
+ function getIdInLights(id) {
+ return lights.filter(
+ function (lights) {
+ return lights.id === id
+ }
+ );
+ }
+
+ function begin() {
+
+ const configruedOrbIds = conf_editor.getEditor("root.specificOptions.orbIds").getValue().trim();
+ if (configruedOrbIds.length !== 0) {
+ configuredLights = configruedOrbIds.split(",").map(Number);
+ }
+
+ const multiCastGroup = conf_editor.getEditor("root.specificOptions.host").getValue();
+ const multiCastPort = parseInt(conf_editor.getEditor("root.specificOptions.port").getValue());
+
+ discover(multiCastGroup, multiCastPort);
+
+ $('#btn_wiz_save').off().on("click", function () {
+ let ledConfig = [];
+ let finalLights = [];
+
+ //create atmoorb led config
+ for (let key in lights) {
+ if ($('#orb_' + key).val() !== "disabled") {
+ // Set Name to layout-position, if empty
+ if (lights[key].name === "") {
+ lights[key].name = $.i18n('conf_leds_layout_cl_' + $('#orb_' + key).val());
+ }
+
+ finalLights.push(lights[key].id);
+
+ let name = lights[key].id;
+ if (lights[key].host !== "")
+ name += ':' + lights[key].host;
+
+ const idx_content = utils.assignLightPos($('#orb_' + key).val(), name);
+ ledConfig.push(JSON.parse(JSON.stringify(idx_content)));
+ }
+ }
+
+ //LED layout
+ window.serverConfig.leds = ledConfig;
+
+ //LED device config
+ //Start with a clean configuration
+ let d = {};
+
+ d.type = 'atmoorb';
+ d.hardwareLedCount = finalLights.length;
+ d.colorOrder = conf_editor.getEditor("root.generalOptions.colorOrder").getValue();
+
+ d.orbIds = finalLights.toString();
+ d.useOrbSmoothing = utils.eV("useOrbSmoothing");
+
+ d.host = conf_editor.getEditor("root.specificOptions.host").getValue();
+ d.port = parseInt(conf_editor.getEditor("root.specificOptions.port").getValue());
+ d.latchTime = parseInt(conf_editor.getEditor("root.specificOptions.latchTime").getValue());;
+
+ window.serverConfig.device = d;
+
+ requestWriteConfig(window.serverConfig, true);
+ resetWizard();
+ });
+
+ $('#btn_wiz_abort').off().on('click', resetWizard);
+ }
+
+ async function discover(multiCastGroup, multiCastPort) {
+ let params = {};
+ if (multiCastGroup !== "") {
+ params.multiCastGroup = multiCastGroup;
+ }
+
+ if (multiCastPort !== 0) {
+ params.multiCastPort = multiCastPort;
+ }
+
+ // Get discovered lights
+ const res = await requestLedDeviceDiscovery('atmoorb', params);
+ if (res && !res.error) {
+ const r = res.info;
+
+ // Process devices returned by discovery
+ processDiscoveredDevices(r.devices);
+
+ // Add additional items from configuration
+ for (const configuredLight of configuredLights) {
+ processConfiguredLight(configuredLight);
+ }
+
+ sortLightsById();
+ assign_lights();
+ }
+ }
+
+ function processDiscoveredDevices(devices) {
+ for (const device of devices) {
+ if (device.id !== "" && getIdInLights(device.id).length === 0) {
+ const light = {
+ id: device.id,
+ ip: device.ip,
+ host: device.hostname
+ };
+ lights.push(light);
+ }
+ }
+ }
+
+ function processConfiguredLight(configuredLight) {
+ if (configuredLight !== "" && !isNaN(configuredLight)) {
+ if (getIdInLights(configuredLight).length === 0) {
+ const light = {
+ id: configuredLight,
+ ip: "",
+ host: ""
+ };
+ lights.push(light);
+ }
+ }
+ }
+
+ function attachIdentifyButtonEvent() {
+ // Use event delegation to handle clicks on buttons with class "btn-identify"
+ $('#wizp2_body').on('click', '.btn-identify', function () {
+ const orbId = $(this).data('orb-id');
+ identify(orbId);
+ });
+ }
+
+ function sortLightsById() {
+ lights.sort((a, b) => (a.id > b.id) ? 1 : -1);
+ }
+
+ function assign_lights() {
+ // If records are left for configuration
+ if (Object.keys(lights).length > 0) {
+ $('#wh_topcontainer').toggle(false);
+ $('#orb_ids_t, #btn_wiz_save').toggle(true);
+
+ const lightOptions = [
+ "top", "topleft", "topright",
+ "bottom", "bottomleft", "bottomright",
+ "left", "lefttop", "leftmiddle", "leftbottom",
+ "right", "righttop", "rightmiddle", "rightbottom",
+ "entire",
+ "lightPosTopLeft112", "lightPosTopLeftNewMid", "lightPosTopLeft121",
+ "lightPosBottomLeft14", "lightPosBottomLeft12", "lightPosBottomLeft34", "lightPosBottomLeft11",
+ "lightPosBottomLeft112", "lightPosBottomLeftNewMid", "lightPosBottomLeft121"
+ ];
+
+ lightOptions.unshift("disabled");
+
+ $('.lidsb').html("");
+ let pos = "";
+
+ for (const lightid in lights) {
+ const orbId = lights[lightid].id;
+ const orbIp = lights[lightid].ip;
+ let orbHostname = lights[lightid].host;
+
+ if (orbHostname === "")
+ orbHostname = $.i18n('edt_dev_spec_lights_itemtitle');
+
+ let options = "";
+ for (const opt in lightOptions) {
+ const val = lightOptions[opt];
+ const txt = (val !== 'entire' && val !== 'disabled') ? 'conf_leds_layout_cl_' : 'wiz_ids_';
+ options += '';
+ }
+
+ let enabled = 'enabled';
+ if (orbId < 1 || orbId > 255) {
+ enabled = 'disabled';
+ options = '';
+ }
+
+ let lightAnnotation = "";
+ if (orbIp !== "") {
+ lightAnnotation = ': ' + orbIp + '
(' + orbHostname + ')';
+ }
+
+ $('.lidsb').append(createTableRow([orbId + lightAnnotation, '', '']));
+ }
+ attachIdentifyButtonEvent();
+
+ $('.orb_sel_watch').on("change", function () {
+ let cC = 0;
+ for (const key in lights) {
+ if ($('#orb_' + key).val() !== "disabled") {
+ cC++;
+ }
+ }
+ if (cC === 0 || window.readOnlyMode)
+ $('#btn_wiz_save').prop("disabled", true);
+ else
+ $('#btn_wiz_save').prop("disabled", false);
+ });
+ $('.orb_sel_watch').trigger('change');
+ }
+ else {
+ const noLightsTxt = '' + $.i18n('wiz_noLights', 'AtmoOrbs') + '
';
+ $('#wizp2_body').append(noLightsTxt);
+ }
+
+
+ }
+
+ async function identify(orbId) {
+ const disabled = $('#btn_wiz_save').is(':disabled');
+
+ // Take care that new record cannot be save during background process
+ $('#btn_wiz_save').prop('disabled', true);
+
+ const params = { id: orbId };
+ await requestLedDeviceIdentification("atmoorb", params);
+
+ if (!window.readOnlyMode) {
+ $('#btn_wiz_save').prop('disabled', disabled);
+ }
+ }
+
+ return {
+ start: function (e) {
+
+ //create html
+ const atmoorb_title = 'wiz_atmoorb_title';
+ const atmoorb_intro1 = 'wiz_atmoorb_intro1';
+
+ $('#wiz_header').html('' + $.i18n(atmoorb_title));
+ $('#wizp1_body').html('' + $.i18n(atmoorb_title) + '
' + $.i18n(atmoorb_intro1) + '
');
+
+ $('#wizp1_footer').html('');
+
+ $('#wizp2_body').html('');
+
+ $('#wh_topcontainer').append('');
+
+ $('#wizp2_body').append('' + $.i18n('wiz_atmoorb_desc2') + '
');
+
+ createTable("lidsh", "lidsb", "orb_ids_t");
+ $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lights_title'), $.i18n('wiz_pos'), $.i18n('wiz_identify')], true));
+ $('#wizp2_footer').html(''
+ + $.i18n('general_btn_cancel') + '');
+
+ if (getStorage("darkMode") == "on")
+ $('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
+
+ //open modal
+ $("#wizard_modal").modal({ backdrop: "static", keyboard: false, show: true });
+
+ //listen for continue
+ $('#btn_wiz_cont').off().on('click', function () {
+ begin();
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ });
+ }
+ };
+})();
+
+export { atmoorbWizard };
diff --git a/assets/webconfig/js/wizards/LedDevice_nanoleaf.js b/assets/webconfig/js/wizards/LedDevice_nanoleaf.js
new file mode 100644
index 00000000..83220003
--- /dev/null
+++ b/assets/webconfig/js/wizards/LedDevice_nanoleaf.js
@@ -0,0 +1,94 @@
+//****************************
+// Wizard Nanoleaf
+//****************************
+
+const nanoleafWizard = (() => {
+
+ const retryInterval = 2;
+
+ async function createNanoleafUserAuthorization() {
+ const host = conf_editor.getEditor("root.specificOptions.host").getValue();
+ const params = { host };
+ let retryTime = 30;
+
+ const UserInterval = setInterval(async function () {
+ retryTime -= retryInterval;
+ $("#connectionTime").html(retryTime);
+
+ if (retryTime <= 0) {
+ handleTimeout();
+ } else {
+ const res = await requestLedDeviceAddAuthorization('nanoleaf', params);
+ handleResponse(res);
+ }
+ }, retryInterval * 1000);
+
+ function handleTimeout() {
+ clearInterval(UserInterval);
+ showNotification(
+ 'warning',
+ $.i18n('wiz_nanoleaf_failure_auth_token'),
+ $.i18n('wiz_nanoleaf_failure_auth_token_t')
+ );
+ resetWizard(true);
+ }
+
+ function handleResponse(res) {
+ if (res && !res.error) {
+ const response = res.info;
+ if (jQuery.isEmptyObject(response)) {
+ debugMessage(`${retryTime}: Power On/Off button not pressed or device not reachable`);
+ } else {
+ const token = response.auth_token;
+ if (token !== 'undefined') {
+ conf_editor.getEditor("root.specificOptions.token").setValue(token);
+ }
+ clearInterval(UserInterval);
+ resetWizard(true);
+ }
+ } else {
+ clearInterval(UserInterval);
+ resetWizard(true);
+ }
+ }
+ }
+
+ return {
+ start: function () {
+ const nanoleaf_user_auth_title = 'wiz_nanoleaf_user_auth_title';
+ const nanoleaf_user_auth_intro = 'wiz_nanoleaf_user_auth_intro';
+
+ $('#wiz_header').html(
+ `${$.i18n(nanoleaf_user_auth_title)}`
+ );
+ $('#wizp1_body').html(
+ `${$.i18n(nanoleaf_user_auth_title)}
${$.i18n(nanoleaf_user_auth_intro)}
`
+ );
+ $('#wizp1_footer').html(
+ ``
+ );
+ $('#wizp3_body').html(
+ `${$.i18n('wiz_nanoleaf_press_onoff_button')}
`
+ );
+
+ if (getStorage("darkMode") == "on") {
+ $('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
+ }
+
+ $("#wizard_modal").modal({
+ backdrop: "static",
+ keyboard: false,
+ show: true
+ });
+
+ $('#btn_wiz_cont').off().on('click', function () {
+ createNanoleafUserAuthorization();
+ $('#wizp1').toggle(false);
+ $('#wizp3').toggle(true);
+ });
+ }
+ };
+})();
+
+export { nanoleafWizard };
+
diff --git a/assets/webconfig/js/wizards/LedDevice_philipshue.js b/assets/webconfig/js/wizards/LedDevice_philipshue.js
new file mode 100644
index 00000000..92f1c173
--- /dev/null
+++ b/assets/webconfig/js/wizards/LedDevice_philipshue.js
@@ -0,0 +1,988 @@
+//****************************
+// Wizard Philips Hue
+//****************************
+
+import { ledDeviceWizardUtils as utils } from './LedDevice_utils.js';
+
+const philipshueWizard = (() => {
+
+ // External properties, 2-dimensional arry of [ledType][key]
+ let devicesProperties = {};
+
+ let hueIPs = [];
+ let hueIPsinc = 0;
+ let hueLights = [];
+ let hueEntertainmentConfigs = [];
+ let hueEntertainmentServices = [];
+ let groupLights = [];
+ let groupChannels = [];
+ let groupLightsLocations = [];
+ let isAPIv2Ready = true;
+ let isEntertainmentReady = true;
+
+ function checkHueBridge(cb, hueUser) {
+ const usr = (typeof hueUser != "undefined") ? hueUser : 'config';
+ if (usr === 'config') {
+ $('#wiz_hue_discovered').html("");
+ }
+
+ if (hueIPs[hueIPsinc]) {
+ const host = hueIPs[hueIPsinc].host;
+ const port = hueIPs[hueIPsinc].port;
+
+ if (usr != '') {
+ getProperties(cb, decodeURIComponent(host), port, usr);
+ }
+ else {
+ cb(false, usr);
+ }
+
+ if (isAPIv2Ready) {
+ $('#port').val(443);
+ }
+ }
+ }
+
+ function checkBridgeResult(reply, usr) {
+ if (reply) {
+ //abort checking, first reachable result is used
+ $('#wiz_hue_ipstate').html("");
+ $('#host').val(hueIPs[hueIPsinc].host)
+ $('#port').val(hueIPs[hueIPsinc].port)
+
+ $('#usrcont').toggle(true);
+
+ checkHueBridge(checkUserResult, $('#user').val());
+ }
+ else {
+ $('#usrcont').toggle(false);
+ $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
+ }
+ };
+
+ function checkUserResult(reply, username) {
+ $('#usrcont').toggle(true);
+
+ let hue_create_user = 'wiz_hue_e_create_user';
+ if (!isEntertainmentReady) {
+ hue_create_user = 'wiz_hue_create_user';
+ $('#hue_client_key_r').toggle(false);
+ } else {
+ $('#hue_client_key_r').toggle(true);
+ }
+
+ $('#wiz_hue_create_user').text($.i18n(hue_create_user));
+ $('#wiz_hue_create_user').toggle(true);
+
+ if (reply) {
+ $('#user').val(username);
+
+ if (isEntertainmentReady && $('#clientkey').val() == "") {
+ $('#wiz_hue_usrstate').html($.i18n('wiz_hue_e_clientkey_needed'));
+ $('#wiz_hue_create_user').toggle(true);
+ } else {
+ $('#wiz_hue_usrstate').html("");
+ $('#wiz_hue_create_user').toggle(false);
+
+ if (isEntertainmentReady) {
+ $('#hue_id_headline').text($.i18n('wiz_hue_e_desc3'));
+ $('#hue_grp_ids_t').toggle(true);
+
+ get_hue_groups(username);
+
+ } else {
+ $('#hue_id_headline').text($.i18n('wiz_hue_desc2'));
+ $('#hue_grp_ids_t').toggle(false);
+
+ get_hue_lights(username);
+
+ }
+ }
+ }
+ else {
+ //abort checking, first reachable result is used
+ $('#wiz_hue_usrstate').html($.i18n('wiz_hue_failure_user'));
+ $('#wiz_hue_create_user').toggle(true);
+ }
+ };
+
+ function useGroupId(id, username) {
+ $('#groupId').val(hueEntertainmentConfigs[id].id);
+ if (isAPIv2Ready) {
+ const group = hueEntertainmentConfigs[id];
+
+ groupLights = [];
+ for (const light of group.light_services) {
+ groupLights.push(light.rid);
+ }
+
+ groupChannels = [];
+ for (const channel of group.channels) {
+ groupChannels.push(channel);
+ }
+
+ groupLightsLocations = [];
+ for (const location of group.locations.service_locations) {
+ groupLightsLocations.push(location);
+ }
+ } else {
+ //Ensure ligthIDs are strings
+ groupLights = hueEntertainmentConfigs[id].lights.map(num => {
+ return String(num);
+ });
+
+ const lightLocations = hueEntertainmentConfigs[id].locations;
+ for (const locationID in lightLocations) {
+ let lightLocation = {};
+
+ let position = {
+ x: lightLocations[locationID][0],
+ y: lightLocations[locationID][1],
+ z: lightLocations[locationID][2]
+ };
+ lightLocation.position = position;
+
+ groupLightsLocations.push(lightLocation);
+ }
+ }
+
+ get_hue_lights(username);
+ }
+
+ function assignLightEntertainmentPos(isFocusCenter, position, name, id) {
+
+ let x = position.x;
+ let z = position.z;
+
+ if (isFocusCenter) {
+ // Map lights as in centered range -0.5 to 0.5
+ if (x < -0.5) {
+ x = -0.5;
+ } else if (x > 0.5) {
+ x = 0.5;
+ }
+ if (z < -0.5) {
+ z = -0.5;
+ } else if (z > 0.5) {
+ z = 0.5;
+ }
+ } else {
+ // Map lights as in full range -1 to 1
+ x /= 2;
+ z /= 2;
+ }
+
+ const h = x + 0.5;
+ const v = -z + 0.5;
+
+ const hmin = h - 0.05;
+ const hmax = h + 0.05;
+ const vmin = v - 0.05;
+ const vmax = v + 0.05;
+
+ let layoutObject = {
+ hmin: hmin < 0 ? 0 : hmin,
+ hmax: hmax > 1 ? 1 : hmax,
+ vmin: vmin < 0 ? 0 : vmin,
+ vmax: vmax > 1 ? 1 : vmax,
+ name: name
+ };
+
+ if (id !== undefined && id !== null) {
+ layoutObject.name += "_" + id;
+ }
+ return layoutObject;
+ }
+
+ function assignSegmentedLightPos(segment, position, name) {
+ let layoutObjects = [];
+
+ let segTotalLength = 0;
+ for (const key in segment) {
+
+ segTotalLength += segment[key].length;
+ }
+
+ let min;
+ let max;
+ let horizontal = true;
+
+ let layoutObject = utils.assignLightPos(position, name);
+ if (position === "left" || position === "right") {
+ // vertical distribution
+ min = layoutObject.vmin;
+ max = layoutObject.vmax;
+ horizontal = false;
+
+ } else {
+ // horizontal distribution
+ min = layoutObject.hmin;
+ max = layoutObject.hmax;
+ }
+
+ const step = (max - min) / segTotalLength;
+ let start = min;
+
+ for (const key in segment) {
+ min = start;
+ max = round(start + segment[key].length * step);
+
+ if (horizontal) {
+ layoutObject.hmin = min;
+ layoutObject.hmax = max;
+ } else {
+ layoutObject.vmin = min;
+ layoutObject.vmax = max;
+ }
+ layoutObject.name = name + "_" + key;
+ layoutObjects.push(JSON.parse(JSON.stringify(layoutObject)));
+
+ start = max;
+ }
+
+ return layoutObjects;
+ }
+
+ function updateBridgeDetails(properties) {
+ const ledDeviceProperties = properties.config;
+
+ if (!jQuery.isEmptyObject(ledDeviceProperties)) {
+ isEntertainmentReady = properties.isEntertainmentReady;
+ isAPIv2Ready = properties.isAPIv2Ready;
+
+ if (ledDeviceProperties.name && ledDeviceProperties.bridgeid && ledDeviceProperties.modelid) {
+ $('#wiz_hue_discovered').html(
+ "Bridge: " + ledDeviceProperties.name +
+ ", Modelid: " + ledDeviceProperties.modelid +
+ ", Firmware: " + ledDeviceProperties.swversion + "
" +
+ "API-Version: " + ledDeviceProperties.apiversion +
+ ", Entertainment: " + (isEntertainmentReady ? "✓" : "-") +
+ ", APIv2: " + (isAPIv2Ready ? "✓" : "-")
+ );
+ }
+ }
+ }
+
+ async function discover() {
+ $('#wiz_hue_ipstate').html($.i18n('edt_dev_spec_devices_discovery_inprogress'));
+
+ // $('#wiz_hue_discovered').html("")
+ const res = await requestLedDeviceDiscovery('philipshue');
+ if (res && !res.error) {
+ const r = res.info;
+
+ // Process devices returned by discovery
+ if (r.devices.length == 0) {
+ $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
+ $('#wiz_hue_discovered').html("")
+ }
+ else {
+ hueIPs = [];
+ hueIPsinc = 0;
+
+ let discoveryMethod = "ssdp";
+ if (res.info.discoveryMethod) {
+ discoveryMethod = res.info.discoveryMethod;
+ }
+
+ for (const device of r.devices) {
+ if (device) {
+ let host;
+ let port;
+ if (discoveryMethod === "ssdp") {
+ if (device.hostname && device.domain) {
+ host = device.hostname + "." + device.domain;
+ port = device.port;
+ } else {
+ host = device.ip;
+ port = device.port;
+ }
+ } else {
+ host = device.service;
+ port = device.port;
+ }
+ if (host) {
+
+ if (!hueIPs.some(item => item.host === host)) {
+ hueIPs.push({ host: host, port: port });
+ }
+ }
+ }
+ }
+
+ $('#wiz_hue_ipstate').html("");
+ $('#host').val(hueIPs[hueIPsinc].host)
+ $('#port').val(hueIPs[hueIPsinc].port)
+
+ $('#hue_bridge_select').html("");
+
+ for (const key in hueIPs) {
+ $('#hue_bridge_select').append(createSelOpt(key, hueIPs[key].host));
+ }
+
+ $('.hue_bridge_sel_watch').on("click", function () {
+ hueIPsinc = $(this).val();
+
+ const name = $("#hue_bridge_select option:selected").text();
+ $('#host').val(name);
+ $('#port').val(hueIPs[hueIPsinc].port)
+
+ const usr = $('#user').val();
+ if (usr != "") {
+ checkHueBridge(checkUserResult, usr);
+ } else {
+ checkHueBridge(checkBridgeResult);
+ }
+ });
+
+ $('.hue_bridge_sel_watch').click();
+ }
+ }
+ }
+
+ async function getProperties(cb, hostAddress, port, username, resourceFilter) {
+ let params = { host: hostAddress, username: username, filter: resourceFilter };
+ if (port !== 'undefined') {
+ params.port = parseInt(port);
+ }
+
+ const ledType = 'philipshue';
+ const key = hostAddress;
+
+ //Create ledType cache entry
+ if (!devicesProperties[ledType]) {
+ devicesProperties[ledType] = {};
+ }
+
+ // Use device's properties, if properties in chache
+ if (devicesProperties[ledType][key] && devicesProperties[ledType][key][username]) {
+ updateBridgeDetails(devicesProperties[ledType][key]);
+ cb(true, username);
+ } else {
+ const res = await requestLedDeviceProperties(ledType, params);
+ if (res && !res.error) {
+ const ledDeviceProperties = res.info.properties;
+ if (!jQuery.isEmptyObject(ledDeviceProperties)) {
+
+ devicesProperties[ledType][key] = {};
+ devicesProperties[ledType][key][username] = ledDeviceProperties;
+
+ isAPIv2Ready = res.info.isAPIv2Ready;
+ devicesProperties[ledType][key].isAPIv2Ready = isAPIv2Ready;
+ isEntertainmentReady = res.info.isEntertainmentReady;
+ devicesProperties[ledType][key].isEntertainmentReady = isEntertainmentReady;
+
+ updateBridgeDetails(devicesProperties[ledType][key]);
+ if (username === "config") {
+ cb(true);
+ } else {
+ cb(true, username);
+ }
+ } else {
+ cb(false, username);
+ }
+ } else {
+ cb(false, username);
+ }
+ }
+ }
+
+ async function identify(hostAddress, port, username, name, id, id_v1) {
+ const disabled = $('#btn_wiz_save').is(':disabled');
+ // Take care that new record cannot be save during background process
+ $('#btn_wiz_save').prop('disabled', true);
+
+ let params = { host: decodeURIComponent(hostAddress), username: username, lightName: decodeURIComponent(name), lightId: id, lightId_v1: id_v1 };
+
+ if (port !== 'undefined') {
+ params.port = parseInt(port);
+ }
+
+ await requestLedDeviceIdentification('philipshue', params);
+
+ if (!window.readOnlyMode) {
+ $('#btn_wiz_save').prop('disabled', disabled);
+ }
+ }
+
+ function begin() {
+ const usr = utils.eV("username");
+ if (usr != "") {
+ $('#user').val(usr);
+ }
+
+ const clkey = utils.eV("clientkey");
+ if (clkey != "") {
+ $('#clientkey').val(clkey);
+ }
+
+ //check if host is empty/reachable/search for bridge
+ if (utils.eV("host") == "") {
+ hueIPs = [];
+ hueIPsinc = 0;
+
+ discover();
+ }
+ else {
+ const host = utils.eV("host");
+ $('#host').val(host);
+
+ const port = utils.eV("port");
+ if (port > 0) {
+ $('#port').val(port);
+ }
+ else {
+ $('#port').val('');
+ }
+ hueIPs.push({ host: host, port: port });
+
+ if (usr != "") {
+ checkHueBridge(checkUserResult, usr);
+ } else {
+ checkHueBridge(checkBridgeResult);
+ }
+ }
+
+ $('#retry_bridge').off().on('click', function () {
+ const host = $('#host').val();
+ const port = parseInt($('#port').val());
+
+ if (host != "") {
+
+ const idx = hueIPs.findIndex(item => item.host === host && item.port === port);
+ if (idx === -1) {
+ hueIPs.push({ host: host, port: port });
+ hueIPsinc = hueIPs.length - 1;
+ } else {
+ hueIPsinc = idx;
+ }
+ }
+ else {
+ discover();
+ }
+
+ const usr = $('#user').val();
+ if (usr != "") {
+ checkHueBridge(checkUserResult, usr);
+ } else {
+ checkHueBridge(checkBridgeResult);
+ }
+ });
+
+ $('#retry_usr').off().on('click', function () {
+ checkHueBridge(checkUserResult, $('#user').val());
+ });
+
+ $('#wiz_hue_create_user').off().on('click', function () {
+ createHueUser();
+ });
+ $('#btn_wiz_save').off().on("click", function () {
+ let hueLedConfig = [];
+ let finalLightIds = [];
+ let channelNumber = 0;
+
+ //create hue led config
+ for (const key in groupLights) {
+ const lightId = groupLights[key];
+
+ if ($('#hue_' + lightId).val() != "disabled") {
+ finalLightIds.push(lightId);
+
+ let lightName;
+ if (isAPIv2Ready) {
+ const light = hueLights.find(light => light.id === lightId);
+ lightName = light.metadata.name;
+ } else {
+ lightName = hueLights[lightId].name;
+ }
+
+ const position = $('#hue_' + lightId).val();
+ const lightIdx = groupLights.indexOf(lightId);
+ const lightLocation = groupLightsLocations[lightIdx];
+
+ let serviceID;
+ if (isAPIv2Ready) {
+ serviceID = lightLocation.service.rid;
+ }
+
+ if (position.startsWith("entertainment")) {
+
+ // Layout per entertainment area definition at bridge
+ let isFocusCenter = false;
+ if (position === "entertainment_center") {
+ isFocusCenter = true;
+ }
+
+ if (isAPIv2Ready) {
+
+ groupChannels.forEach((channel) => {
+ if (channel.members[0].service.rid === serviceID) {
+ const layoutObject = assignLightEntertainmentPos(isFocusCenter, channel.position, lightName, channel.channel_id);
+ hueLedConfig.push(JSON.parse(JSON.stringify(layoutObject)));
+ ++channelNumber;
+ }
+ });
+ } else {
+ const layoutObject = assignLightEntertainmentPos(isFocusCenter, lightLocation.position, lightName);
+ hueLedConfig.push(JSON.parse(JSON.stringify(layoutObject)));
+ }
+ }
+ else {
+ // Layout per manual settings
+ let maxSegments = 1;
+
+ if (isAPIv2Ready) {
+ const service = hueEntertainmentServices.find(service => service.id === serviceID);
+ maxSegments = service.segments.max_segments;
+ }
+
+ if (maxSegments > 1) {
+ const segment = service.segments.segments;
+ const layoutObjects = assignSegmentedLightPos(segment, position, lightName);
+ hueLedConfig.push(...layoutObjects);
+ } else {
+ const layoutObject = utils.assignLightPos(position, lightName);
+ hueLedConfig.push(JSON.parse(JSON.stringify(layoutObject)));
+ }
+ channelNumber += maxSegments;
+ }
+ }
+ }
+
+ let sc = window.serverConfig;
+ sc.leds = hueLedConfig;
+
+ //Adjust gamma, brightness and compensation
+ let c = sc.color.channelAdjustment[0];
+ c.gammaBlue = 1.0;
+ c.gammaRed = 1.0;
+ c.gammaGreen = 1.0;
+ c.brightness = 100;
+ c.brightnessCompensation = 0;
+
+ //device config
+
+ //Start with a clean configuration
+ let d = {};
+ d.host = $('#host').val();
+ d.port = parseInt($('#port').val());
+ d.username = $('#user').val();
+ d.type = 'philipshue';
+ d.colorOrder = 'rgb';
+ d.lightIds = finalLightIds;
+ d.transitiontime = parseInt(utils.eV("transitiontime", 1));
+ d.restoreOriginalState = utils.eV("restoreOriginalState", false);
+ d.switchOffOnBlack = utils.eV("switchOffOnBlack", false);
+
+ d.blackLevel = parseFloat(utils.eV("blackLevel", 0.009));
+ d.onBlackTimeToPowerOff = parseInt(utils.eV("onBlackTimeToPowerOff", 600));
+ d.onBlackTimeToPowerOn = parseInt(utils.eV("onBlackTimeToPowerOn", 300));
+ d.brightnessFactor = parseFloat(utils.eV("brightnessFactor", 1));
+
+ d.clientkey = $('#clientkey').val();
+ d.groupId = $('#groupId').val();
+ d.blackLightsTimeout = parseInt(utils.eV("blackLightsTimeout", 5000));
+ d.brightnessMin = parseFloat(utils.eV("brightnessMin", 0));
+ d.brightnessMax = parseFloat(utils.eV("brightnessMax", 1));
+ d.brightnessThreshold = parseFloat(utils.eV("brightnessThreshold", 0.0001));
+ d.handshakeTimeoutMin = parseInt(utils.eV("handshakeTimeoutMin", 300));
+ d.handshakeTimeoutMax = parseInt(utils.eV("handshakeTimeoutMax", 1000));
+ d.verbose = utils.eV("verbose");
+
+ d.autoStart = conf_editor.getEditor("root.generalOptions.autoStart").getValue();
+ d.enableAttempts = parseInt(conf_editor.getEditor("root.generalOptions.enableAttempts").getValue());
+ d.enableAttemptsInterval = parseInt(conf_editor.getEditor("root.generalOptions.enableAttemptsInterval").getValue());
+
+ d.useEntertainmentAPI = isEntertainmentReady;
+ d.useAPIv2 = isAPIv2Ready;
+
+ if (isEntertainmentReady) {
+ d.hardwareLedCount = channelNumber;
+ if (window.serverConfig.device.type !== d.type) {
+ //smoothing on, if new device
+ sc.smoothing = { enable: true };
+ }
+ } else {
+ d.hardwareLedCount = finalLightIds.length;
+ d.verbose = false;
+ if (window.serverConfig.device.type !== d.type) {
+ //smoothing off, if new device
+ sc.smoothing = { enable: false };
+ }
+ }
+
+ window.serverConfig.device = d;
+
+ requestWriteConfig(sc, true);
+ resetWizard();
+ });
+
+ $('#btn_wiz_abort').off().on('click', resetWizard);
+ }
+
+ function createHueUser() {
+ const host = hueIPs[hueIPsinc].host;
+ const port = hueIPs[hueIPsinc].port;
+
+ let params = { host: host };
+ if (port !== 'undefined') {
+ params.port = parseInt(port);
+ }
+
+ let retryTime = 30;
+ const retryInterval = 2;
+
+ const UserInterval = setInterval(function () {
+
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(false);
+ $('#wizp3').toggle(true);
+
+ (async () => {
+
+ retryTime -= retryInterval;
+ $("#connectionTime").html(retryTime);
+ if (retryTime <= 0) {
+ abortConnection(UserInterval);
+ clearInterval(UserInterval);
+ }
+ else {
+ const res = await requestLedDeviceAddAuthorization('philipshue', params);
+ if (res && !res.error) {
+ const response = res.info;
+
+ if (jQuery.isEmptyObject(response)) {
+ debugMessage(retryTime + ": link button not pressed or device not reachable");
+ } else {
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ $('#wizp3').toggle(false);
+
+ const username = response.username;
+ if (username != 'undefined') {
+ $('#user').val(username);
+ conf_editor.getEditor("root.specificOptions.username").setValue(username);
+ conf_editor.getEditor("root.specificOptions.host").setValue(host);
+ conf_editor.getEditor("root.specificOptions.port").setValue(port);
+ }
+
+ if (isEntertainmentReady) {
+ const clientkey = response.clientkey;
+ if (clientkey != 'undefined') {
+ $('#clientkey').val(clientkey);
+ conf_editor.getEditor("root.specificOptions.clientkey").setValue(clientkey);
+ }
+ }
+ checkHueBridge(checkUserResult, username);
+ clearInterval(UserInterval);
+ }
+ } else {
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ $('#wizp3').toggle(false);
+ clearInterval(UserInterval);
+ }
+ }
+ })();
+
+ }, retryInterval * 1000);
+ }
+
+ function get_hue_groups(username) {
+ const host = hueIPs[hueIPsinc].host;
+
+ if (devicesProperties['philipshue'][host] && devicesProperties['philipshue'][host][username]) {
+ const ledProperties = devicesProperties['philipshue'][host][username];
+
+ if (isAPIv2Ready) {
+ if (!jQuery.isEmptyObject(ledProperties.data)) {
+ if (Object.keys(ledProperties.data).length > 0) {
+ hueEntertainmentConfigs = ledProperties.data.filter(config => {
+ return config.type === "entertainment_configuration";
+ });
+ hueEntertainmentServices = ledProperties.data.filter(config => {
+ return (config.type === "entertainment" && config.renderer === true);
+ });
+ }
+ }
+ } else if (!jQuery.isEmptyObject(ledProperties.groups)) {
+ hueEntertainmentConfigs = [];
+ let hueGroups = ledProperties.groups;
+ for (const groupid in hueGroups) {
+ if (hueGroups[groupid].type == 'Entertainment') {
+ hueGroups[groupid].id = groupid;
+ hueEntertainmentConfigs.push(hueGroups[groupid]);
+ }
+ }
+ }
+
+ if (Object.keys(hueEntertainmentConfigs).length > 0) {
+
+ $('.lidsb').html("");
+ $('#wh_topcontainer').toggle(false);
+ $('#hue_grp_ids_t').toggle(true);
+
+ for (const groupid in hueEntertainmentConfigs) {
+ $('.gidsb').append(createTableRow([groupid + ' (' + hueEntertainmentConfigs[groupid].name + ')',
+ '']));
+ }
+ attachGroupButtonEvent();
+
+ } else {
+ noAPISupport('wiz_hue_e_noegrpids', username);
+ }
+ }
+ }
+ function attachIdentifyButtonEvent() {
+ $('#wizp2_body').on('click', '.btn-identify', function () {
+ const hostname = $(this).data('hostname');
+ const port = $(this).data('port');
+ const user = $(this).data('user');
+ const lightName = $(this).data('light-name');
+ const lightId = $(this).data('light-id');
+ const lightId_v1 = $(this).data('light-id-v1');
+
+ identify(hostname, port, user, lightName, lightId, lightId_v1);
+ });
+ }
+ function attachGroupButtonEvent() {
+ $('#wizp2_body').on('click', '.btn-group', function () {
+ const groupid = $(this).data('groupid');
+ const username = $(this).data('username');
+
+ useGroupId(groupid, username);
+ });
+ }
+
+ function noAPISupport(txt, username) {
+ showNotification('danger', $.i18n('wiz_hue_e_title'), $.i18n('wiz_hue_e_noapisupport_hint'));
+ conf_editor.getEditor("root.specificOptions.useEntertainmentAPI").setValue(false);
+ $("#root_specificOptions_useEntertainmentAPI").trigger("change");
+ $('#btn_wiz_holder').append('' + $.i18n('wiz_hue_e_noapisupport_hint') + '
');
+ $('#hue_grp_ids_t').toggle(false);
+ const errorMessage = txt ? $.i18n(txt) : $.i18n('wiz_hue_e_nogrpids');
+ $('' + errorMessage + '
' + $.i18n('wiz_hue_e_noapisupport') + '
').insertBefore('#wizp2_body #hue_ids_t');
+ $('#hue_id_headline').html($.i18n('wiz_hue_desc2'));
+
+ get_hue_lights(username);
+ }
+
+ function get_hue_lights(username) {
+ const host = hueIPs[hueIPsinc].host;
+
+ if (devicesProperties['philipshue'][host] && devicesProperties['philipshue'][host][username]) {
+ const ledProperties = devicesProperties['philipshue'][host][username];
+
+ if (isAPIv2Ready) {
+ if (!jQuery.isEmptyObject(ledProperties.data)) {
+ if (Object.keys(ledProperties.data).length > 0) {
+ hueLights = ledProperties.data.filter(config => {
+ return config.type === "light";
+ });
+ }
+ }
+ } else if (!jQuery.isEmptyObject(ledProperties.lights)) {
+ hueLights = ledProperties.lights;
+ }
+
+ if (Object.keys(hueLights).length > 0) {
+ if (!isEntertainmentReady) {
+ $('#wh_topcontainer').toggle(false);
+ }
+ $('#hue_ids_t, #btn_wiz_save').toggle(true);
+
+ const lightOptions = [
+ "top", "topleft", "topright",
+ "bottom", "bottomleft", "bottomright",
+ "left", "lefttop", "leftmiddle", "leftbottom",
+ "right", "righttop", "rightmiddle", "rightbottom",
+ "entire",
+ "lightPosTopLeft112", "lightPosTopLeftNewMid", "lightPosTopLeft121",
+ "lightPosBottomLeft14", "lightPosBottomLeft12", "lightPosBottomLeft34", "lightPosBottomLeft11",
+ "lightPosBottomLeft112", "lightPosBottomLeftNewMid", "lightPosBottomLeft121"
+ ];
+
+ if (isEntertainmentReady) {
+ lightOptions.unshift("entertainment_center");
+ lightOptions.unshift("entertainment");
+ } else {
+ lightOptions.unshift("disabled");
+ groupLights = Object.keys(hueLights);
+ }
+
+ $('.lidsb').html("");
+
+ let pos = "";
+ for (const id in groupLights) {
+ const lightId = groupLights[id];
+ let lightId_v1 = "/lights/" + lightId;
+
+ let lightName;
+ if (isAPIv2Ready) {
+ const light = hueLights.find(light => light.id === lightId);
+ lightName = light.metadata.name;
+ lightId_v1 = light.id_v1;
+ } else {
+ lightName = hueLights[lightId].name;
+ }
+
+ if (isEntertainmentReady) {
+ let lightLocation = {};
+ lightLocation = groupLightsLocations[id];
+ if (lightLocation) {
+ if (isAPIv2Ready) {
+ pos = 0;
+ } else {
+ const x = lightLocation.position.x;
+ const y = lightLocation.position.y;
+ const z = lightLocation.position.z;
+
+ let xval = (x < 0) ? "left" : "right";
+ if (z != 1 && x >= -0.25 && x <= 0.25) xval = "";
+ switch (z) {
+ case 1: // top / Ceiling height
+ pos = "top" + xval;
+ break;
+ case 0: // middle / TV height
+ pos = (xval == "" && y >= 0.75) ? "bottom" : xval + "middle";
+ break;
+ case -1: // bottom / Ground height
+ pos = xval + "bottom";
+ break;
+ }
+ }
+ }
+ }
+
+ let options = "";
+ for (const opt in lightOptions) {
+ const val = lightOptions[opt];
+ const txt = (val != 'entire' && val != 'disabled') ? 'conf_leds_layout_cl_' : 'wiz_ids_';
+ options += '';
+ }
+
+ $('.lidsb').append(createTableRow([id + ' (' + lightName + ')',
+ '',
+ '']));
+ }
+ attachIdentifyButtonEvent();
+
+ if (!isEntertainmentReady) {
+ $('.hue_sel_watch').on("change", function () {
+ let cC = 0;
+ for (const key in hueLights) {
+ if ($('#hue_' + key).val() != "disabled") {
+ cC++;
+ }
+ }
+
+ (cC == 0 || window.readOnlyMode) ? $('#btn_wiz_save').prop("disabled", true) : $('#btn_wiz_save').prop("disabled", false);
+ });
+ }
+ $('.hue_sel_watch').trigger('change');
+ }
+ else {
+ const txt = '' + $.i18n('wiz_hue_noids') + '
';
+ $('#wizp2_body').append(txt);
+ }
+ }
+ }
+
+ function abortConnection(UserInterval) {
+ clearInterval(UserInterval);
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ $('#wizp3').toggle(false);
+ $("#wiz_hue_usrstate").html($.i18n('wiz_hue_failure_connection'));
+ }
+
+ return {
+ start: function (e) {
+ //create html
+ const hue_title = 'wiz_hue_title';
+ const hue_intro1 = 'wiz_hue_e_intro1';
+ const hue_desc1 = 'wiz_hue_desc1';
+ const hue_create_user = 'wiz_hue_create_user';
+
+ $('#wiz_header').html('' + $.i18n(hue_title));
+ $('#wizp1_body').html('' + $.i18n(hue_title) + '
' + $.i18n(hue_intro1) + '
');
+ $('#wizp1_footer').html('');
+ $('#wizp2_body').html('');
+
+ let topContainer_html = '' + $.i18n(hue_desc1) + '
' +
+ '' +
+ '
' +
+ '
' + $.i18n('wiz_hue_ip') + '
' +
+ '
' +
+ ' ' +
+ ' ' + '
' +
+ '
';
+
+ if (storedAccess === 'expert') {
+ topContainer_html += '
';
+ }
+
+ topContainer_html += '
';
+ topContainer_html += '';
+
+ $('#wh_topcontainer').append(topContainer_html);
+
+ $('#usrcont').append('' + $.i18n('wiz_hue_username') + '
' +
+ '
' +
+ ''
+ );
+
+ $('#usrcont').append('
');
+
+ $('#usrcont').append('
' +
+ '');
+
+ $('#wizp2_body').append('' + $.i18n('wiz_hue_e_desc2') + '
');
+ createTable("gidsh", "gidsb", "hue_grp_ids_t");
+ $('.gidsh').append(createTableRow([$.i18n('edt_dev_spec_groupId_title'), ""], true));
+
+ $('#wizp2_body').append('' + $.i18n('wiz_hue_e_desc3') + '
');
+
+ createTable("lidsh", "lidsb", "hue_ids_t");
+ $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lightid_title'), $.i18n('wiz_pos'), $.i18n('wiz_identify')], true));
+ $('#wizp2_footer').html('');
+ $('#wizp3_body').html('' + $.i18n('wiz_hue_press_link') + '
');
+
+ if (getStorage("darkMode") == "on")
+ $('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
+
+ //open modal
+ $("#wizard_modal").modal({
+ backdrop: "static",
+ keyboard: false,
+ show: true
+ });
+
+ //listen for continue
+ $('#btn_wiz_cont').off().on('click', function () {
+ begin();
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ });
+ }
+ };
+})();
+
+export { philipshueWizard }
+
diff --git a/assets/webconfig/js/wizards/LedDevice_utils.js b/assets/webconfig/js/wizards/LedDevice_utils.js
new file mode 100644
index 00000000..1f3eab3e
--- /dev/null
+++ b/assets/webconfig/js/wizards/LedDevice_utils.js
@@ -0,0 +1,60 @@
+
+const ledDeviceWizardUtils = (() => {
+
+ // Layout positions
+ const positionMap = {
+ "top": { hmin: 0.15, hmax: 0.85, vmin: 0, vmax: 0.2 },
+ "topleft": { hmin: 0, hmax: 0.15, vmin: 0, vmax: 0.15 },
+ "topright": { hmin: 0.85, hmax: 1.0, vmin: 0, vmax: 0.15 },
+ "bottom": { hmin: 0.15, hmax: 0.85, vmin: 0.8, vmax: 1.0 },
+ "bottomleft": { hmin: 0, hmax: 0.15, vmin: 0.85, vmax: 1.0 },
+ "bottomright": { hmin: 0.85, hmax: 1.0, vmin: 0.85, vmax: 1.0 },
+ "left": { hmin: 0, hmax: 0.15, vmin: 0.15, vmax: 0.85 },
+ "lefttop": { hmin: 0, hmax: 0.15, vmin: 0, vmax: 0.5 },
+ "leftmiddle": { hmin: 0, hmax: 0.15, vmin: 0.25, vmax: 0.75 },
+ "leftbottom": { hmin: 0, hmax: 0.15, vmin: 0.5, vmax: 1.0 },
+ "right": { hmin: 0.85, hmax: 1.0, vmin: 0.15, vmax: 0.85 },
+ "righttop": { hmin: 0.85, hmax: 1.0, vmin: 0, vmax: 0.5 },
+ "rightmiddle": { hmin: 0.85, hmax: 1.0, vmin: 0.25, vmax: 0.75 },
+ "rightbottom": { hmin: 0.85, hmax: 1.0, vmin: 0.5, vmax: 1.0 },
+ "lightPosBottomLeft14": { hmin: 0, hmax: 0.25, vmin: 0.85, vmax: 1.0 },
+ "lightPosBottomLeft12": { hmin: 0.25, hmax: 0.5, vmin: 0.85, vmax: 1.0 },
+ "lightPosBottomLeft34": { hmin: 0.5, hmax: 0.75, vmin: 0.85, vmax: 1.0 },
+ "lightPosBottomLeft11": { hmin: 0.75, hmax: 1, vmin: 0.85, vmax: 1.0 },
+ "lightPosBottomLeft112": { hmin: 0, hmax: 0.5, vmin: 0.85, vmax: 1.0 },
+ "lightPosBottomLeft121": { hmin: 0.5, hmax: 1, vmin: 0.85, vmax: 1.0 },
+ "lightPosBottomLeftNewMid": { hmin: 0.25, hmax: 0.75, vmin: 0.85, vmax: 1.0 },
+ "lightPosTopLeft112": { hmin: 0, hmax: 0.5, vmin: 0, vmax: 0.15 },
+ "lightPosTopLeft121": { hmin: 0.5, hmax: 1, vmin: 0, vmax: 0.15 },
+ "lightPosTopLeftNewMid": { hmin: 0.25, hmax: 0.75, vmin: 0, vmax: 0.15 },
+ "lightPosEntire": { hmin: 0.0, hmax: 1.0, vmin: 0.0, vmax: 1.0 }
+ };
+
+ return {
+
+ //return editor Value
+ eV: function (vn, defaultVal = "") {
+ let editor = null;
+ if (vn) {
+ editor = conf_editor.getEditor("root.specificOptions." + vn);
+ }
+
+ if (editor === null) {
+ return defaultVal;
+ } else if (defaultVal !== "" && !isNaN(defaultVal) && isNaN(editor.getValue())) {
+ return defaultVal;
+ } else {
+ return editor.getValue();
+ }
+ },
+ assignLightPos: function (pos, name) {
+ // Retrieve the corresponding position object from the positionMap
+ const i = positionMap[pos] || positionMap["lightPosEntire"];
+ i.name = name;
+ return i;
+ }
+ };
+
+})();
+
+export { ledDeviceWizardUtils };
diff --git a/assets/webconfig/js/wizards/LedDevice_yeelight.js b/assets/webconfig/js/wizards/LedDevice_yeelight.js
new file mode 100644
index 00000000..4f53eb07
--- /dev/null
+++ b/assets/webconfig/js/wizards/LedDevice_yeelight.js
@@ -0,0 +1,300 @@
+//****************************
+// Wizard Yeelight
+//****************************
+
+import { ledDeviceWizardUtils as utils } from './LedDevice_utils.js';
+
+const yeelightWizard = (() => {
+
+ const lights = [];
+ let configuredLights = conf_editor.getEditor("root.specificOptions.lights").getValue();
+
+ function getHostInLights(hostname) {
+ return lights.filter(
+ function (lights) {
+ return lights.host === hostname
+ }
+ );
+ }
+
+ function begin() {
+ discover();
+
+ $('#btn_wiz_save').off().on("click", function () {
+ let ledConfig = [];
+ let finalLights = [];
+
+ //create yeelight led config
+ for (const key in lights) {
+ if ($('#yee_' + key).val() !== "disabled") {
+
+ let name = lights[key].name;
+ // Set Name to layout-position, if empty
+ if (name === "") {
+ name = lights[key].host;
+ }
+
+ finalLights.push(lights[key]);
+
+ const idx_content = utils.assignLightPos($('#yee_' + key).val(), name);
+ ledConfig.push(JSON.parse(JSON.stringify(idx_content)));
+ }
+ }
+
+ //LED layout
+ window.serverConfig.leds = ledConfig;
+
+ //LED device config
+ const currentDeviceType = window.serverConfig.device.type;
+
+ //Start with a clean configuration
+ let d = {};
+
+ d.type = 'yeelight';
+ d.hardwareLedCount = finalLights.length;
+ d.colorOrder = conf_editor.getEditor("root.generalOptions.colorOrder").getValue();
+ d.colorModel = parseInt(conf_editor.getEditor("root.specificOptions.colorModel").getValue());
+
+ d.transEffect = parseInt(conf_editor.getEditor("root.specificOptions.transEffect").getValue());
+ d.transTime = parseInt(conf_editor.getEditor("root.specificOptions.transTime").getValue());
+ d.extraTimeDarkness = parseInt(conf_editor.getEditor("root.specificOptions.extraTimeDarkness").getValue());
+
+ d.brightnessMin = parseInt(conf_editor.getEditor("root.specificOptions.brightnessMin").getValue());
+ d.brightnessSwitchOffOnMinimum = JSON.parse(conf_editor.getEditor("root.specificOptions.brightnessSwitchOffOnMinimum").getValue());
+ d.brightnessMax = parseInt(conf_editor.getEditor("root.specificOptions.brightnessMax").getValue());
+ d.brightnessFactor = parseFloat(conf_editor.getEditor("root.specificOptions.brightnessFactor").getValue());
+
+ d.latchTime = parseInt(conf_editor.getEditor("root.specificOptions.latchTime").getValue());;
+ d.debugLevel = parseInt(conf_editor.getEditor("root.specificOptions.debugLevel").getValue());
+
+ d.lights = finalLights;
+
+ window.serverConfig.device = d;
+
+ if (currentDeviceType !== d.type) {
+ //smoothing off, if new device
+ window.serverConfig.smoothing = { enable: false };
+ }
+
+ requestWriteConfig(window.serverConfig, true);
+ resetWizard();
+ });
+
+ $('#btn_wiz_abort').off().on('click', resetWizard);
+ }
+
+ async function discover() {
+ // Get discovered lights
+ const res = await requestLedDeviceDiscovery('yeelight');
+ if (res && !res.error) {
+ const r = res.info;
+
+ let discoveryMethod = "ssdp";
+ if (res.info.discoveryMethod) {
+ discoveryMethod = res.info.discoveryMethod;
+ }
+
+ // Process devices returned by discovery
+ for (const device of r.devices) {
+ if (device.hostname !== "") {
+ processDiscoverdDevice(device, discoveryMethod);
+ }
+ }
+
+ // Add additional items from configuration
+ for (const configuredLight of configuredLights) {
+ processConfiguredLight(configuredLight);
+ }
+
+ assign_lights();
+ }
+ }
+
+ function processDiscoverdDevice(device, discoveryMethod) {
+ if (getHostInLights(device.hostname).length > 0) {
+ return;
+ }
+
+ const light = {
+ host: device.hostname
+ };
+
+ if (discoveryMethod === "ssdp") {
+ if (device.domain) {
+ light.host += '.' + device.domain;
+ }
+ } else {
+ light.host = device.service;
+ light.name = device.name;
+ }
+
+ light.port = device.port;
+
+ if (device.txt) {
+ light.model = device.txt.md;
+ light.port = 55443; // Yeelight default port
+ } else {
+ light.name = device.other.name;
+ light.model = device.other.model;
+ }
+
+ lights.push(light);
+ }
+ function processConfiguredLight(configuredLight) {
+ const host = configuredLight.host;
+ let port = configuredLight.port || 0;
+
+ if (host !== "" && getHostInLights(host).length === 0) {
+ const light = {
+ host: host,
+ port: port,
+ name: configuredLight.name,
+ model: "color4"
+ };
+
+ lights.push(light);
+ }
+ }
+
+ function attachIdentifyButtonEvent() {
+ $('#wizp2_body').on('click', '.btn-identify', function () {
+ const hostname = $(this).data('hostname');
+ const port = $(this).data('port');
+ identify(hostname, port);
+ });
+ }
+
+ function assign_lights() {
+ // Model mappings, see https://www.home-assistant.io/integrations/yeelight/
+ const models = ['color', 'color1', 'YLDP02YL', 'YLDP02YL', 'color2', 'YLDP06YL', 'color4', 'YLDP13YL', 'color6', 'YLDP13AYL', 'colorb', "YLDP005", 'colorc', "YLDP004-A", 'stripe', 'YLDD04YL', 'strip1', 'YLDD01YL', 'YLDD02YL', 'strip4', 'YLDD05YL', 'strip6', 'YLDD05YL'];
+
+ // If records are left for configuration
+ if (Object.keys(lights).length > 0) {
+ $('#wh_topcontainer').toggle(false);
+ $('#yee_ids_t, #btn_wiz_save').toggle(true);
+
+ const lightOptions = [
+ "top", "topleft", "topright",
+ "bottom", "bottomleft", "bottomright",
+ "left", "lefttop", "leftmiddle", "leftbottom",
+ "right", "righttop", "rightmiddle", "rightbottom",
+ "entire",
+ "lightPosTopLeft112", "lightPosTopLeftNewMid", "lightPosTopLeft121",
+ "lightPosBottomLeft14", "lightPosBottomLeft12", "lightPosBottomLeft34", "lightPosBottomLeft11",
+ "lightPosBottomLeft112", "lightPosBottomLeftNewMid", "lightPosBottomLeft121"
+ ];
+
+ lightOptions.unshift("disabled");
+
+ $('.lidsb').html("");
+ let pos = "";
+
+ for (const lightid in lights) {
+ const lightHostname = lights[lightid].host;
+ const lightPort = lights[lightid].port;
+ let lightName = lights[lightid].name;
+
+ if (lightName === "")
+ lightName = $.i18n('edt_dev_spec_lights_itemtitle') + '(' + lightHostname + ')';
+
+ let options = "";
+ for (const opt in lightOptions) {
+ const val = lightOptions[opt];
+ const txt = (val !== 'entire' && val !== 'disabled') ? 'conf_leds_layout_cl_' : 'wiz_ids_';
+ options += '';
+ }
+
+ let enabled = 'enabled';
+ if (!models.includes(lights[lightid].model)) {
+ enabled = 'disabled';
+ options = '';
+ }
+
+ $('.lidsb').append(createTableRow([(parseInt(lightid, 10) + 1) + '. ' + lightName, '', '']));
+ }
+ attachIdentifyButtonEvent();
+
+ $('.yee_sel_watch').on("change", function () {
+ let cC = 0;
+ for (const key in lights) {
+ if ($('#yee_' + key).val() !== "disabled") {
+ cC++;
+ }
+ }
+
+ if (cC === 0 || window.readOnlyMode)
+ $('#btn_wiz_save').prop("disabled", true);
+ else
+ $('#btn_wiz_save').prop("disabled", false);
+ });
+ $('.yee_sel_watch').trigger('change');
+ }
+ else {
+ const noLightsTxt = '' + $.i18n('wiz_noLights', 'lights') + '
';
+ $('#wizp2_body').append(noLightsTxt);
+ }
+ }
+
+ async function identify(host, port) {
+
+ const disabled = $('#btn_wiz_save').is(':disabled');
+
+ // Take care that new record cannot be save during background process
+ $('#btn_wiz_save').prop('disabled', true);
+
+ const params = { host: host, port: port };
+ await requestLedDeviceIdentification("yeelight", params);
+
+ if (!window.readOnlyMode) {
+ $('#btn_wiz_save').prop('disabled', disabled);
+ }
+ }
+
+ return {
+ start: function (e) {
+ //create html
+ const yeelight_title = 'wiz_yeelight_title';
+ const yeelight_intro1 = 'wiz_yeelight_intro1';
+
+ $('#wiz_header').html('' + $.i18n(yeelight_title));
+ $('#wizp1_body').html('' + $.i18n(yeelight_title) + '
' + $.i18n(yeelight_intro1) + '
');
+
+ $('#wizp1_footer').html('');
+
+ $('#wizp2_body').html('');
+
+ $('#wh_topcontainer').append('');
+
+ $('#wizp2_body').append('' + $.i18n('wiz_yeelight_desc2') + '
');
+
+ createTable("lidsh", "lidsb", "yee_ids_t");
+ $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lights_title'), $.i18n('wiz_pos'), $.i18n('wiz_identify')], true));
+ $('#wizp2_footer').html(''
+ + $.i18n('general_btn_cancel') + '');
+
+ if (getStorage("darkMode") == "on")
+ $('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
+
+ //open modal
+ $("#wizard_modal").modal({ backdrop: "static", keyboard: false, show: true });
+
+ //listen for continue
+ $('#btn_wiz_cont').off().on('click', function () {
+ begin();
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ });
+ }
+};
+}) ();
+
+export { yeelightWizard };
+
diff --git a/assets/webconfig/js/wizards/colorCalibrationKodiWizard.js b/assets/webconfig/js/wizards/colorCalibrationKodiWizard.js
new file mode 100644
index 00000000..7879d641
--- /dev/null
+++ b/assets/webconfig/js/wizards/colorCalibrationKodiWizard.js
@@ -0,0 +1,485 @@
+//****************************
+// Wizard Color calibration via Kodi
+//****************************
+const colorCalibrationKodiWizard = (() => {
+
+ let ws;
+ const defaultKodiPort = 9090;
+
+ let kodiAddress = document.location.hostname;
+ let kodiPort = defaultKodiPort;
+
+ const kodiUrl = new URL("ws://" + kodiAddress);
+ kodiUrl.port = kodiPort;
+ kodiUrl.pathname = "/jsonrpc/websocket";
+
+ let wiz_editor;
+ let colorLength;
+ let cobj;
+ let step = 0;
+ let withKodi = false;
+ let profile = 0;
+ let websAddress;
+ let imgAddress;
+ let picnr = 0;
+ let id = 1;
+ const vidAddress = "https://sourceforge.net/projects/hyperion-project/files/resources/vid/";
+ const availVideos = ["Sweet_Cocoon", "Caminandes_2_GranDillama", "Caminandes_3_Llamigos"];
+
+ if (getStorage("kodiAddress") != null) {
+
+ kodiAddress = getStorage("kodiAddress");
+ kodiUrl.host = kodiAddress;
+ }
+
+ if (getStorage("kodiPort") != null) {
+ kodiPort = getStorage("kodiPort");
+ kodiUrl.port = kodiPort;
+ }
+
+ $(window).on('beforeunload', function () {
+ closeWebSocket();
+ });
+
+ function closeWebSocket() {
+ // Check if the WebSocket is open
+ if (ws && ws.readyState === WebSocket.OPEN) {
+ ws.close();
+ }
+ }
+
+ function sendToKodi(type, content) {
+ let command;
+
+ switch (type) {
+ case "msg":
+ command = { "jsonrpc": "2.0", "method": "GUI.ShowNotification", "params": { "title": $.i18n('wiz_cc_title'), "message": content, "image": "info", "displaytime": 5000 }, "id": id };
+ break;
+ case "stop":
+ command = { "jsonrpc": "2.0", "method": "Player.Stop", "params": { "playerid": 2 }, "id": id };
+ break;
+ case "playP":
+ content = imgAddress + content + '.png';
+ command = { "jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "file": content } }, "id": id };
+ break;
+ case "playV":
+ content = vidAddress + content;
+ command = { "jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "file": content } }, "id": id };
+ break;
+ case "rotate":
+ command = { "jsonrpc": "2.0", "method": "Player.Rotate", "params": { "playerid": 2 }, "id": id };
+ break;
+ default:
+ console.error('Unknown Kodi command type: ', type);
+ }
+
+ if (ws.readyState === WebSocket.OPEN) {
+ ws.send(JSON.stringify(command));
+ ++id;
+ } else {
+ console.error('WebSocket connection is not open. Unable to send command.');
+ }
+ }
+
+ function performAction() {
+ let h;
+
+ if (step == 1) {
+ $('#wiz_cc_desc').html($.i18n('wiz_cc_chooseid'));
+ updateEditor(["id"]);
+ $('#btn_wiz_back').prop("disabled", true);
+ }
+ else
+ $('#btn_wiz_back').prop("disabled", false);
+
+ if (step == 2) {
+ updateEditor(["white"]);
+ h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_white_title'));
+ if (withKodi) {
+ h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_white_title'));
+ sendToKodi('playP', "white");
+ }
+ else
+ h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_white_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if (step == 3) {
+ updateEditor(["gammaRed", "gammaGreen", "gammaBlue"]);
+ h = '' + $.i18n('wiz_cc_adjustgamma') + '
';
+ if (withKodi) {
+ sendToKodi('playP', "HGradient");
+ h += '';
+ }
+ else
+ h += '' + $.i18n('wiz_cc_lettvshowm', "grey_1, grey_2, grey_3, HGradient, VGradient") + '
';
+ $('#wiz_cc_desc').html(h);
+ $('#wiz_cc_btn_sp').off().on('click', function () {
+ switchPicture(["VGradient", "grey_1", "grey_2", "grey_3", "HGradient"]);
+ });
+ }
+ if (step == 4) {
+ updateEditor(["red"]);
+ h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_red_title'));
+ if (withKodi) {
+ h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_red_title'));
+ sendToKodi('playP', "red");
+ }
+ else
+ h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_red_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if (step == 5) {
+ updateEditor(["green"]);
+ h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_green_title'));
+ if (withKodi) {
+ h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_green_title'));
+ sendToKodi('playP', "green");
+ }
+ else
+ h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_green_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if (step == 6) {
+ updateEditor(["blue"]);
+ h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_blue_title'));
+ if (withKodi) {
+ h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_blue_title'));
+ sendToKodi('playP', "blue");
+ }
+ else
+ h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_blue_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if (step == 7) {
+ updateEditor(["cyan"]);
+ h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_cyan_title'));
+ if (withKodi) {
+ h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_cyan_title'));
+ sendToKodi('playP', "cyan");
+ }
+ else
+ h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_cyan_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if (step == 8) {
+ updateEditor(["magenta"]);
+ h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_magenta_title'));
+ if (withKodi) {
+ h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_magenta_title'));
+ sendToKodi('playP', "magenta");
+ }
+ else
+ h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_magenta_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if (step == 9) {
+ updateEditor(["yellow"]);
+ h = $.i18n('wiz_cc_adjustit', $.i18n('edt_conf_color_yellow_title'));
+ if (withKodi) {
+ h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_yellow_title'));
+ sendToKodi('playP', "yellow");
+ }
+ else
+ h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_yellow_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if (step == 10) {
+ updateEditor(["backlightThreshold", "backlightColored"]);
+ h = $.i18n('wiz_cc_backlight');
+ if (withKodi) {
+ h += '
' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_black_title'));
+ sendToKodi('playP', "black");
+ }
+ else
+ h += '
' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_black_title'));
+ $('#wiz_cc_desc').html(h);
+ }
+ if (step == 11) {
+ updateEditor([""], true);
+ h = '' + $.i18n('wiz_cc_testintro') + '
';
+ if (withKodi) {
+ h += '' + $.i18n('wiz_cc_testintrok') + '
';
+ sendToKodi('stop');
+ availVideos.forEach(video => {
+ const txt = video.replace(/_/g, " ");
+ h += ``;
+ });
+
+ h += '';
+ }
+ else
+ h += '' + $.i18n('wiz_cc_testintrowok') + ' ' + $.i18n('wiz_cc_link') + '
';
+ h += '' + $.i18n('wiz_cc_summary') + '
';
+ $('#wiz_cc_desc').html(h);
+
+ $('.videobtn').off().on('click', function (e) {
+ if (e.target.id == "stop")
+ sendToKodi("stop");
+ else
+ sendToKodi("playV", e.target.id + '.mp4');
+
+ $(this).prop("disabled", true);
+ setTimeout(function () { $('.videobtn').prop("disabled", false) }, 10000);
+ });
+
+ $('#btn_wiz_next').prop("disabled", true);
+ $('#btn_wiz_save').toggle(true);
+ window.readOnlyMode ? $('#btn_wiz_save').prop('disabled', true) : $('#btn_wiz_save').prop('disabled', false);
+ }
+ else {
+ $('#btn_wiz_next').prop("disabled", false);
+ $('#btn_wiz_save').toggle(false);
+ }
+ }
+
+
+
+ function switchPicture(pictures) {
+ if (typeof pictures[picnr] === 'undefined')
+ picnr = 0;
+
+ sendToKodi('playP', pictures[picnr]);
+ picnr++;
+ }
+
+
+ function initializeWebSocket(cb) {
+ if ("WebSocket" in window) {
+
+ if (kodiUrl.port === '') {
+ kodiUrl.port = defaultKodiPort;
+ }
+
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
+
+ // Establish WebSocket connection
+ ws = new WebSocket(kodiUrl);
+
+ // WebSocket onopen event
+ ws.onopen = function (event) {
+ withKodi = true;
+ cb("opened");
+ };
+
+ // WebSocket onmessage event (handle incoming messages)
+ ws.onmessage = function (event) {
+ const response = JSON.parse(event.data);
+ if (response.method === "System.OnQuit") {
+ closeWebSocket();
+ } else if (response.result != undefined) {
+ if (response.result !== "OK") {
+ cb("error");
+ }
+ }
+ };
+
+ // WebSocket onerror event
+ ws.onerror = function (error) {
+ cb("error");
+ };
+
+ // WebSocket onclose event
+ ws.onclose = function (event) {
+ withKodi = false;
+ if (event.code === 1006) {
+ // Ignore error 1006 due to Kodi issue
+ console.log("WebSocket closed with error code 1006. Ignoring due to Kodi bug.");
+ }
+ else {
+ console.error("WebSocket closed with code:", event.code);
+ }
+ };
+ } else {
+ console.log("WebSocket connection is already open.");
+ }
+ }
+ else {
+ console.log("Kodi Access: WebSocket NOT supported by this browser");
+ cb("error");
+ }
+ }
+
+ function setupEventListeners() {
+ $('#btn_wiz_cancel').off().on('click', function () {
+ stop(true);
+ });
+ $('#wiz_cc_kodiip').off().on('change', function () {
+
+ kodiAddress = encodeURIComponent($(this).val().trim());
+
+ $('#kodi_status').html('');
+ if (kodiAddress !== "") {
+
+ if (!isValidHostnameOrIP(kodiAddress)) {
+
+ $('#kodi_status').html('' + $.i18n('edt_msgcust_error_hostname_ip') + '
');
+ withKodi = false;
+
+ } else {
+
+ if (isValidIPv6(kodiAddress)) {
+ kodiUrl.hostname = "[" + kodiAddress + "]";
+ } else {
+ kodiUrl.hostname = kodiAddress;
+ }
+
+ $('#kodi_status').html('' + $.i18n('wiz_cc_try_connect') + '
');
+ $('#btn_wiz_cont').prop('disabled', true);
+
+ closeWebSocket();
+ initializeWebSocket(function (cb) {
+
+ if (cb == "opened") {
+ setStorage("kodiAddress", kodiAddress);
+ setStorage("kodiPort", defaultKodiPort);
+
+ $('#kodi_status').html('' + $.i18n('wiz_cc_kodicon') + '
');
+ $('#btn_wiz_cont').prop('disabled', false);
+
+ if (withKodi) {
+ sendToKodi("msg", $.i18n('wiz_cc_kodimsg_start'));
+ }
+ }
+ else {
+ $('#kodi_status').html('' + $.i18n('wiz_cc_kodidiscon') + '
' + $.i18n('wiz_cc_kodidisconlink') + ' ' + $.i18n('wiz_cc_link') + '
');
+ withKodi = false;
+ }
+
+ $('#btn_wiz_cont').prop('disabled', false);
+ });
+ }
+ }
+ });
+
+ //listen for continue
+ $('#btn_wiz_cont').off().on('click', function () {
+ begin();
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ });
+ }
+
+ function init() {
+ colorLength = window.serverConfig.color.channelAdjustment;
+ cobj = window.schema.color.properties.channelAdjustment.items.properties;
+ websAddress = document.location.hostname + ':' + window.serverConfig.webConfig.port;
+ imgAddress = 'http://' + websAddress + '/img/cc/';
+ setStorage("wizardactive", true);
+ }
+
+ function initProfiles() {
+ //check profile count
+ if (colorLength.length > 1) {
+ $('#multi_cali').html('' + $.i18n('wiz_cc_morethanone') + '
');
+ for (let i = 0; i < colorLength.length; i++)
+ $('#wiz_select').append(createSelOpt(i, i + 1 + ' (' + colorLength[i].id + ')'));
+
+ $('#wiz_select').off().on('change', function () {
+ profile = $(this).val();
+ });
+ }
+ }
+
+ function createEditor() {
+ wiz_editor = createJsonEditor('editor_container_wiz', {
+ color: window.schema.color
+ }, true, true);
+
+ $('#editor_container_wiz h4').toggle(false);
+ $('#editor_container_wiz .btn-group').toggle(false);
+ $('#editor_container_wiz [data-schemapath="root.color.imageToLedMappingType"]').toggle(false);
+ $('#editor_container_wiz [data-schemapath="root.color.reducedPixelSetFactorFactor"]').toggle(false);
+ for (let i = 0; i < colorLength.length; i++)
+ $('#editor_container_wiz [data-schemapath*="root.color.channelAdjustment.' + i + '."]').toggle(false);
+ }
+ function updateEditor(el, all) {
+ for (let key in cobj) {
+ if (all === true || el[0] == key || el[1] == key || el[2] == key)
+ $('#editor_container_wiz [data-schemapath*=".' + profile + '.' + key + '"]').toggle(true);
+ else
+ $('#editor_container_wiz [data-schemapath*=".' + profile + '.' + key + '"]').toggle(false);
+ }
+ }
+
+ function stop(reload) {
+ if (withKodi) {
+ sendToKodi("stop");
+ }
+ closeWebSocket();
+ resetWizard(reload);
+ }
+
+ function begin() {
+ step = 0;
+
+ $('#btn_wiz_next').off().on('click', function () {
+ step++;
+ performAction();
+ });
+
+ $('#btn_wiz_back').off().on('click', function () {
+ step--;
+ performAction();
+ });
+
+ $('#btn_wiz_abort').off().on('click', function () {
+ stop(true);
+ });
+
+ $('#btn_wiz_save').off().on('click', function () {
+ requestWriteConfig(wiz_editor.getValue());
+ stop(true);
+ });
+
+ wiz_editor.on("change", function (e) {
+ const val = wiz_editor.getEditor('root.color.channelAdjustment.' + profile + '').getValue();
+ const temp = JSON.parse(JSON.stringify(val));
+ delete temp.leds
+ requestAdjustment(JSON.stringify(temp), "", true);
+ });
+
+ step++
+ performAction();
+ }
+
+ return {
+ start: function () {
+ //create html
+ $('#wiz_header').html('' + $.i18n('wiz_cc_title'));
+ $('#wizp1_body').html('' + $.i18n('wiz_cc_title') + '
' +
+ '' + $.i18n('wiz_cc_intro1') + '
' +
+ '' +
+ '' +
+ ''
+ );
+ $('#wizp1_footer').html('' +
+ ''
+ );
+ $('#wizp2_body').html(''
+ );
+ $('#wizp2_footer').html('' +
+ '' +
+ '' +
+ ''
+ );
+
+ if (getStorage("darkMode") == "on")
+ $('#wizard_logo').prop("src", 'img/hyperion/logo_negativ.png');
+
+ //open modal
+ $("#wizard_modal").modal({
+ backdrop: "static",
+ keyboard: false,
+ show: true
+ });
+
+ setupEventListeners();
+ $('#wiz_cc_kodiip').trigger("change");
+ init();
+ initProfiles();
+ createEditor();
+ }
+ };
+})();
+
+export { colorCalibrationKodiWizard };
diff --git a/assets/webconfig/js/wizards/rgbByteOrderWizard.js b/assets/webconfig/js/wizards/rgbByteOrderWizard.js
new file mode 100644
index 00000000..5d612174
--- /dev/null
+++ b/assets/webconfig/js/wizards/rgbByteOrderWizard.js
@@ -0,0 +1,143 @@
+//****************************
+// Wizard RGB byte order
+//****************************
+
+const rgbByteOrderWizard = (() => {
+
+ let wIntveralId;
+ let new_rgb_order;
+
+ function changeColor() {
+ let color = $("#wiz_canv_color").css('background-color');
+
+ if (color == 'rgb(255, 0, 0)') {
+ $("#wiz_canv_color").css('background-color', 'rgb(0, 255, 0)');
+ requestSetColor('0', '255', '0');
+ }
+ else {
+ $("#wiz_canv_color").css('background-color', 'rgb(255, 0, 0)');
+ requestSetColor('255', '0', '0');
+ }
+ }
+
+
+ function stopWizardRGB(reload) {
+ console.log("stopWizardRGB - reload: ", reload);
+ clearInterval(wIntveralId);
+ resetWizard(reload);
+ }
+
+ function beginWizardRGB() {
+ $("#wiz_switchtime_select").off().on('change', function () {
+ clearInterval(wIntveralId);
+ const time = $("#wiz_switchtime_select").val();
+ wIntveralId = setInterval(function () { changeColor(); }, time * 1000);
+ });
+
+ $('.wselect').on("change", function () {
+ let rgb_order = window.serverConfig.device.colorOrder.split("");
+ const redS = $("#wiz_r_select").val();
+ const greenS = $("#wiz_g_select").val();
+ const blueS = rgb_order.toString().replace(/,/g, "").replace(redS, "").replace(greenS, "");
+
+ for (const color of rgb_order) {
+ if (redS == color)
+ $('#wiz_g_select option[value=' + color + ']').prop('disabled', true);
+ else
+ $('#wiz_g_select option[value=' + color + ']').prop('disabled', false);
+ if (greenS == color)
+ $('#wiz_r_select option[value=' + color + ']').prop('disabled', true);
+ else
+ $('#wiz_r_select option[value=' + color + ']').prop('disabled', false);
+ }
+
+ if (redS != 'null' && greenS != 'null') {
+ $('#btn_wiz_save').prop('disabled', false);
+
+ for (let i = 0; i < rgb_order.length; i++) {
+ if (rgb_order[i] == "r")
+ rgb_order[i] = redS;
+ else if (rgb_order[i] == "g")
+ rgb_order[i] = greenS;
+ else
+ rgb_order[i] = blueS;
+ }
+
+ rgb_order = rgb_order.toString().replace(/,/g, "");
+
+ if (redS == "r" && greenS == "g") {
+ $('#btn_wiz_save').toggle(false);
+ $('#btn_wiz_checkok').toggle(true);
+
+ window.readOnlyMode ? $('#btn_wiz_checkok').prop('disabled', true) : $('#btn_wiz_checkok').prop('disabled', false);
+ }
+ else {
+ $('#btn_wiz_save').toggle(true);
+ window.readOnlyMode ? $('#btn_wiz_save').prop('disabled', true) : $('#btn_wiz_save').prop('disabled', false);
+
+ $('#btn_wiz_checkok').toggle(false);
+ }
+ new_rgb_order = rgb_order;
+ }
+ else
+ $('#btn_wiz_save').prop('disabled', true);
+ });
+
+ $("#wiz_switchtime_select").append(createSelOpt('5', '5'), createSelOpt('10', '10'), createSelOpt('15', '15'), createSelOpt('30', '30'));
+ $("#wiz_switchtime_select").trigger('change');
+
+ $("#wiz_r_select").append(createSelOpt("null", ""), createSelOpt('r', $.i18n('general_col_red')), createSelOpt('g', $.i18n('general_col_green')), createSelOpt('b', $.i18n('general_col_blue')));
+ $("#wiz_g_select").html($("#wiz_r_select").html());
+ $("#wiz_r_select").trigger('change');
+
+ requestSetColor('255', '0', '0');
+ setTimeout(requestSetSource, 100, 'auto');
+ setStorage("wizardactive", true);
+
+ $('#btn_wiz_abort').off().on('click', function () { stopWizardRGB(true); });
+
+ $('#btn_wiz_checkok').off().on('click', function () {
+ showInfoDialog('success', "", $.i18n('infoDialog_wizrgb_text'));
+ stopWizardRGB();
+ });
+
+ $('#btn_wiz_save').off().on('click', function () {
+ stopWizardRGB();
+ window.serverConfig.device.colorOrder = new_rgb_order;
+ requestWriteConfig({ "device": window.serverConfig.device });
+ });
+ }
+
+ return {
+ start: function () {
+ //create html
+ $('#wiz_header').html('' + $.i18n('wiz_rgb_title'));
+ $('#wizp1_body').html('' + $.i18n('wiz_rgb_title') + '
' + $.i18n('wiz_rgb_intro1') + '
' + $.i18n('wiz_rgb_intro2') + '
');
+ $('#wizp1_footer').html('');
+ $('#wizp2_body').html('' + $.i18n('wiz_rgb_expl') + '
');
+ $('#wizp2_body').append('');
+ $('#wizp2_body').append('');
+ $('#wizp2_body').append(' | |
| |
');
+ $('#wizp2_footer').html('');
+
+ if (getStorage("darkMode") == "on")
+ $('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
+
+ //open modal
+ $("#wizard_modal").modal({
+ backdrop: "static",
+ keyboard: false,
+ show: true
+ });
+
+ //listen for continue
+ $('#btn_wiz_cont').off().on('click', function () {
+ beginWizardRGB();
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ });
+ }
+ };
+})();
+
+export { rgbByteOrderWizard };