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
This commit is contained in:
LordGrey 2024-03-30 15:43:50 +01:00 committed by GitHub
parent 35d8992bcc
commit ac57fea09a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 2432 additions and 2338 deletions

View File

@ -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');
}
});

View File

@ -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;

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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 += '<option value="' + val + '"';
if (pos === val) options += ' selected="selected"';
options += '>' + $.i18n(txt + val) + '</option>';
}
let enabled = 'enabled';
if (orbId < 1 || orbId > 255) {
enabled = 'disabled';
options = '<option value=disabled>' + $.i18n('wiz_atmoorb_unsupported') + '</option>';
}
let lightAnnotation = "";
if (orbIp !== "") {
lightAnnotation = ': ' + orbIp + '<br>(' + orbHostname + ')';
}
$('.lidsb').append(createTableRow([orbId + lightAnnotation, '<select id="orb_' + lightid + '" ' + enabled + ' class="orb_sel_watch form-control">'
+ options
+ '</select>', '<button class="btn btn-sm btn-primary btn-identify" ' + enabled + ' data-orb-id="' + orbId + '")>'
+ $.i18n('wiz_identify_light', orbId) + '</button>']));
}
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 = '<p style="font-weight:bold;color:red;">' + $.i18n('wiz_noLights', 'AtmoOrbs') + '</p>';
$('#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('<i class="fa fa-magic fa-fw"></i>' + $.i18n(atmoorb_title));
$('#wizp1_body').html('<h4 style="font-weight:bold;text-transform:uppercase;">' + $.i18n(atmoorb_title) + '</h4><p>' + $.i18n(atmoorb_intro1) + '</p>');
$('#wizp1_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_cont"><i class="fa fa-fw fa-check"></i>'
+ $.i18n('general_btn_continue') + '</button><button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-fw fa-close"></i>'
+ $.i18n('general_btn_cancel') + '</button>');
$('#wizp2_body').html('<div id="wh_topcontainer"></div>');
$('#wh_topcontainer').append('<div class="form-group" id="usrcont" style="display:none"></div>');
$('#wizp2_body').append('<div id="orb_ids_t" style="display:none"><p style="font-weight:bold" id="orb_id_headline">' + $.i18n('wiz_atmoorb_desc2') + '</p></div>');
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('<button type="button" class="btn btn-primary" id="btn_wiz_save" style="display:none"><i class="fa fa-fw fa-save"></i>'
+ $.i18n('general_btn_save') + '</button><buttowindow.serverConfig.device = d;n type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>'
+ $.i18n('general_btn_cancel') + '</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 () {
begin();
$('#wizp1').toggle(false);
$('#wizp2').toggle(true);
});
}
};
})();
export { atmoorbWizard };

View File

@ -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(
`<i class="fa fa-magic fa-fw"></i>${$.i18n(nanoleaf_user_auth_title)}`
);
$('#wizp1_body').html(
`<h4 style="font-weight:bold;text-transform:uppercase;">${$.i18n(nanoleaf_user_auth_title)}</h4><p>${$.i18n(nanoleaf_user_auth_intro)}</p>`
);
$('#wizp1_footer').html(
`<button type="button" class="btn btn-primary" id="btn_wiz_cont"><i class="fa fa-fw fa-check"></i>${$.i18n('general_btn_continue')}</button><button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-fw fa-close"></i>${$.i18n('general_btn_cancel')}</button>`
);
$('#wizp3_body').html(
`<span>${$.i18n('wiz_nanoleaf_press_onoff_button')}</span> <br /><br /><center><span id="connectionTime"></span><br /><i class="fa fa-cog fa-spin" style="font-size:100px"></i></center>`
);
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 };

View File

@ -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 + "<br/>" +
"API-Version: " + ledDeviceProperties.apiversion +
", Entertainment: " + (isEntertainmentReady ? "&#10003;" : "-") +
", APIv2: " + (isAPIv2Ready ? "&#10003;" : "-")
);
}
}
}
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 + ')',
'<button class="btn btn-sm btn-primary btn-group" data-groupid="' + groupid + '" data-username="' + username + '")>'
+ $.i18n('wiz_hue_e_use_group') + '</button>']));
}
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('<div class="bs-callout bs-callout-danger" style="margin-top:0px">' + $.i18n('wiz_hue_e_noapisupport_hint') + '</div>');
$('#hue_grp_ids_t').toggle(false);
const errorMessage = txt ? $.i18n(txt) : $.i18n('wiz_hue_e_nogrpids');
$('<p style="font-weight:bold;color:red;">' + errorMessage + '<br />' + $.i18n('wiz_hue_e_noapisupport') + '</p>').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 += '<option value="' + val + '"';
if (pos == val) options += ' selected="selected"';
options += '>' + $.i18n(txt + val) + '</option>';
}
$('.lidsb').append(createTableRow([id + ' (' + lightName + ')',
'<select id="hue_' + lightId + '" class="hue_sel_watch form-control">'
+ options
+ '</select>',
'<button class="btn btn-sm btn-primary btn-identify" data-hostname="' + encodeURIComponent($(" #host").val()) + '" data-port="' + $('#port').val() + '" data-user="' + $("#user").val() + '" data-light-name="' + encodeURIComponent(lightName) + '" data-light-id="' + lightId + '" data-light-id-v1="' + lightId_v1 + '">'
+ $.i18n('wiz_hue_blinkblue', id)
+ '</button>']));
}
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 = '<p style="font-weight:bold;color:red;">' + $.i18n('wiz_hue_noids') + '</p>';
$('#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('<i class="fa fa-magic fa-fw"></i>' + $.i18n(hue_title));
$('#wizp1_body').html('<h4 style="font-weight:bold;text-transform:uppercase;">' + $.i18n(hue_title) + '</h4><p>' + $.i18n(hue_intro1) + '</p>');
$('#wizp1_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_cont"><i class="fa fa-fw fa-check"></i>' + $.i18n('general_btn_continue') + '</button><button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
$('#wizp2_body').html('<div id="wh_topcontainer"></div>');
let topContainer_html = '<p class="text-left" style="font-weight:bold">' + $.i18n(hue_desc1) + '</p>' +
'<div class="row">' +
'<div class="col-md-2">' +
' <p class="text-left">' + $.i18n('wiz_hue_ip') + '</p></div>' +
' <div class="col-md-7"><div class="input-group">' +
' <span class="input-group-addon" id="retry_bridge" style="cursor:pointer"><i class="fa fa-refresh"></i></span>' +
' <select id="hue_bridge_select" class="hue_bridge_sel_watch form-control">' + '</select>' + '</div></div>' +
' <div class="col-md-7"><div class="input-group">' +
' <span class="input-group-addon"><i class="fa fa-arrow-right"></i></span>' +
' <input type="text" class="input-group form-control" id="host" placeholder="' + $.i18n('wiz_hue_ip') + '"></div></div>';
if (storedAccess === 'expert') {
topContainer_html += '<div class="col-md-3"><div class="input-group">' +
'<span class="input-group-addon">:</span>' +
'<input type="text" class="input-group form-control" id="port" placeholder="' + $.i18n('edt_conf_general_port_title') + '"></div></div>';
}
topContainer_html += '</div><p><span style="font-weight:bold;color:red" id="wiz_hue_ipstate"></span><span style="font-weight:bold;" id="wiz_hue_discovered"></span></p>';
topContainer_html += '<div class="form-group" id="usrcont" style="display:none"></div>';
$('#wh_topcontainer').append(topContainer_html);
$('#usrcont').append('<div class="row"><div class="col-md-2"><p class="text-left">' + $.i18n('wiz_hue_username') + '</p ></div>' +
'<div class="col-md-7">' +
'<div class="input-group">' +
' <span class="input-group-addon" id="retry_usr" style="cursor:pointer"><i class="fa fa-refresh"></i></span>' +
' <input type="text" class="input-group form-control" id="user">' +
'</div></div></div><br>' +
'</div><input type="hidden" id="groupId">'
);
$('#usrcont').append('<div id="hue_client_key_r" class="row"><div class="col-md-2"><p class="text-left">' + $.i18n('wiz_hue_clientkey') +
'</p></div><div class="col-md-7"><input class="form-control" id="clientkey" type="text"></div></div><br>');
$('#usrcont').append('<p><span style="font-weight:bold;color:red" id="wiz_hue_usrstate"></span></p>' +
'<button type="button" class="btn btn-primary" style="display:none" id="wiz_hue_create_user"> <i class="fa fa-fw fa-plus"></i>' + $.i18n(hue_create_user) + '</button>');
$('#wizp2_body').append('<div id="hue_grp_ids_t" style="display:none"><p class="text-left" style="font-weight:bold">' + $.i18n('wiz_hue_e_desc2') + '</p></div>');
createTable("gidsh", "gidsb", "hue_grp_ids_t");
$('.gidsh').append(createTableRow([$.i18n('edt_dev_spec_groupId_title'), ""], true));
$('#wizp2_body').append('<div id="hue_ids_t" style="display:none"><p class="text-left" style="font-weight:bold" id="hue_id_headline">' + $.i18n('wiz_hue_e_desc3') + '</p></div>');
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('<button type="button" class="btn btn-primary" id="btn_wiz_save" style="display:none"><i class="fa fa-fw fa-save"></i>' + $.i18n('general_btn_save') + '</button><button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
$('#wizp3_body').html('<span>' + $.i18n('wiz_hue_press_link') + '</span> <br /><br /><center><span id="connectionTime"></span><br /><i class="fa fa-cog fa-spin" style="font-size:100px"></i></center>');
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 }

View File

@ -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 };

View File

@ -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 += '<option value="' + val + '"';
if (pos === val) options += ' selected="selected"';
options += '>' + $.i18n(txt + val) + '</option>';
}
let enabled = 'enabled';
if (!models.includes(lights[lightid].model)) {
enabled = 'disabled';
options = '<option value=disabled>' + $.i18n('wiz_yeelight_unsupported') + '</option>';
}
$('.lidsb').append(createTableRow([(parseInt(lightid, 10) + 1) + '. ' + lightName, '<select id="yee_' + lightid + '" ' + enabled + ' class="yee_sel_watch form-control">'
+ options
+ '</select>', '<button class="btn btn-sm btn-primary btn-identify" data-hostname="' + lightHostname + '" data-port="' + lightPort + '")>'
+ $.i18n('wiz_identify') + '</button>']));
}
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 = '<p style="font-weight:bold;color:red;">' + $.i18n('wiz_noLights', 'lights') + '</p>';
$('#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('<i class="fa fa-magic fa-fw"></i>' + $.i18n(yeelight_title));
$('#wizp1_body').html('<h4 style="font-weight:bold;text-transform:uppercase;">' + $.i18n(yeelight_title) + '</h4><p>' + $.i18n(yeelight_intro1) + '</p>');
$('#wizp1_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_cont"><i class="fa fa-fw fa-check"></i>'
+ $.i18n('general_btn_continue') + '</button><button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-fw fa-close"></i>'
+ $.i18n('general_btn_cancel') + '</button>');
$('#wizp2_body').html('<div id="wh_topcontainer"></div>');
$('#wh_topcontainer').append('<div class="form-group" id="usrcont" style="display:none"></div>');
$('#wizp2_body').append('<div id="yee_ids_t" style="display:none"><p style="font-weight:bold" id="yee_id_headline">' + $.i18n('wiz_yeelight_desc2') + '</p></div>');
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('<button type="button" class="btn btn-primary" id="btn_wiz_save" style="display:none"><i class="fa fa-fw fa-save"></i>'
+ $.i18n('general_btn_save') + '</button><buttowindow.serverConfig.device = d;n type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>'
+ $.i18n('general_btn_cancel') + '</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 () {
begin();
$('#wizp1').toggle(false);
$('#wizp2').toggle(true);
});
}
};
}) ();
export { yeelightWizard };

View File

@ -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 += '<br/>' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_white_title'));
sendToKodi('playP', "white");
}
else
h += '<br/>' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_white_title'));
$('#wiz_cc_desc').html(h);
}
if (step == 3) {
updateEditor(["gammaRed", "gammaGreen", "gammaBlue"]);
h = '<p>' + $.i18n('wiz_cc_adjustgamma') + '</p>';
if (withKodi) {
sendToKodi('playP', "HGradient");
h += '<button id="wiz_cc_btn_sp" class="btn btn-primary">' + $.i18n('wiz_cc_btn_switchpic') + '</button>';
}
else
h += '<p>' + $.i18n('wiz_cc_lettvshowm', "grey_1, grey_2, grey_3, HGradient, VGradient") + '</p>';
$('#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 += '<br/>' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_red_title'));
sendToKodi('playP', "red");
}
else
h += '<br/>' + $.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 += '<br/>' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_green_title'));
sendToKodi('playP', "green");
}
else
h += '<br/>' + $.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 += '<br/>' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_blue_title'));
sendToKodi('playP', "blue");
}
else
h += '<br/>' + $.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 += '<br/>' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_cyan_title'));
sendToKodi('playP', "cyan");
}
else
h += '<br/>' + $.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 += '<br/>' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_magenta_title'));
sendToKodi('playP', "magenta");
}
else
h += '<br/>' + $.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 += '<br/>' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_yellow_title'));
sendToKodi('playP', "yellow");
}
else
h += '<br/>' + $.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 += '<br/>' + $.i18n('wiz_cc_kodishould', $.i18n('edt_conf_color_black_title'));
sendToKodi('playP', "black");
}
else
h += '<br/>' + $.i18n('wiz_cc_lettvshow', $.i18n('edt_conf_color_black_title'));
$('#wiz_cc_desc').html(h);
}
if (step == 11) {
updateEditor([""], true);
h = '<p>' + $.i18n('wiz_cc_testintro') + '</p>';
if (withKodi) {
h += '<p>' + $.i18n('wiz_cc_testintrok') + '</p>';
sendToKodi('stop');
availVideos.forEach(video => {
const txt = video.replace(/_/g, " ");
h += `<div><button id="${video}" class="btn btn-sm btn-primary videobtn"><i class="fa fa-fw fa-play"></i> ${txt}</button></div>`;
});
h += '<div><button id="stop" class="btn btn-sm btn-danger videobtn" style="margin-bottom:15px"><i class="fa fa-fw fa-stop"></i> ' + $.i18n('wiz_cc_btn_stop') + '</button></div>';
}
else
h += '<p>' + $.i18n('wiz_cc_testintrowok') + ' <a href="https://sourceforge.net/projects/hyperion-project/files/resources/vid/" target="_blank">' + $.i18n('wiz_cc_link') + '</a></p>';
h += '<p>' + $.i18n('wiz_cc_summary') + '</p>';
$('#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('<p style="color:red;font-weight:bold;margin-top:5px">' + $.i18n('edt_msgcust_error_hostname_ip') + '</p>');
withKodi = false;
} else {
if (isValidIPv6(kodiAddress)) {
kodiUrl.hostname = "[" + kodiAddress + "]";
} else {
kodiUrl.hostname = kodiAddress;
}
$('#kodi_status').html('<p style="font-weight:bold;margin-top:5px">' + $.i18n('wiz_cc_try_connect') + '</p>');
$('#btn_wiz_cont').prop('disabled', true);
closeWebSocket();
initializeWebSocket(function (cb) {
if (cb == "opened") {
setStorage("kodiAddress", kodiAddress);
setStorage("kodiPort", defaultKodiPort);
$('#kodi_status').html('<p style="color:green;font-weight:bold;margin-top:5px">' + $.i18n('wiz_cc_kodicon') + '</p>');
$('#btn_wiz_cont').prop('disabled', false);
if (withKodi) {
sendToKodi("msg", $.i18n('wiz_cc_kodimsg_start'));
}
}
else {
$('#kodi_status').html('<p style="color:red;font-weight:bold;margin-top:5px">' + $.i18n('wiz_cc_kodidiscon') + '</p><p>' + $.i18n('wiz_cc_kodidisconlink') + ' <a href="https://sourceforge.net/projects/hyperion-project/files/resources/Hyperion_calibration_pictures.zip/download" target="_blank">' + $.i18n('wiz_cc_link') + '</p>');
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('<p style="font-weight:bold;">' + $.i18n('wiz_cc_morethanone') + '</p><select id="wiz_select" class="form-control" style="width:200px;margin:auto"></select>');
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('<i class="fa fa-magic fa-fw"></i>' + $.i18n('wiz_cc_title'));
$('#wizp1_body').html('<h4 style="font-weight:bold;text-transform:uppercase;">' + $.i18n('wiz_cc_title') + '</h4>' +
'<p>' + $.i18n('wiz_cc_intro1') + '</p>' +
'<label>' + $.i18n('wiz_cc_kwebs') + '</label>' +
'<input class="form-control" style="width:280px;margin:auto" id="wiz_cc_kodiip" type="text" placeholder="' + kodiAddress + '" value="' + kodiAddress + '" />' +
'<span id="kodi_status"></span><span id="multi_cali"></span>'
);
$('#wizp1_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_cont" disabled="disabled">' + '<i class="fa fa-fw fa-check"></i>' + $.i18n('general_btn_continue') + '</button>' +
'<button type="button" class="btn btn-danger" id="btn_wiz_cancel" data-dismiss="modal"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>'
);
$('#wizp2_body').html('<div id="wiz_cc_desc" style="font-weight:bold"></div><div id="editor_container_wiz"></div>'
);
$('#wizp2_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_back">' + '<i class="fa fa-fw fa-chevron-left"></i>' + $.i18n('general_btn_back') + '</button>' +
'<button type="button" class="btn btn-primary" id="btn_wiz_next">' + $.i18n('general_btn_next') + '<i style="margin-left:4px;"class="fa fa-fw fa-chevron-right"></i>' + '</button>' +
'<button type="button" class="btn btn-warning" id="btn_wiz_save" style="display:none"><i class="fa fa-fw fa-save"></i>' + $.i18n('general_btn_save') + '</button>' +
'<button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>'
);
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 };

View File

@ -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('<i class="fa fa-magic fa-fw"></i>' + $.i18n('wiz_rgb_title'));
$('#wizp1_body').html('<h4 style="font-weight:bold;text-transform:uppercase;">' + $.i18n('wiz_rgb_title') + '</h4><p>' + $.i18n('wiz_rgb_intro1') + '</p><p style="font-weight:bold;">' + $.i18n('wiz_rgb_intro2') + '</p>');
$('#wizp1_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_cont"><i class="fa fa-fw fa-check"></i>' + $.i18n('general_btn_continue') + '</button><button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
$('#wizp2_body').html('<p style="font-weight:bold">' + $.i18n('wiz_rgb_expl') + '</p>');
$('#wizp2_body').append('<div class="form-group"><label>' + $.i18n('wiz_rgb_switchevery') + '</label><div class="input-group" style="width:100px"><select id="wiz_switchtime_select" class="form-control"></select><div class="input-group-addon">' + $.i18n('edt_append_s') + '</div></div></div>');
$('#wizp2_body').append('<canvas id="wiz_canv_color" width="100" height="100" style="border-radius:60px;background-color:red; display:block; margin: 10px 0;border:4px solid grey;"></canvas><label>' + $.i18n('wiz_rgb_q') + '</label>');
$('#wizp2_body').append('<table class="table borderless" style="width:200px"><tbody><tr><td class="ltd"><label>' + $.i18n('wiz_rgb_qrend') + '</label></td><td class="itd"><select id="wiz_r_select" class="form-control wselect"></select></td></tr><tr><td class="ltd"><label>' + $.i18n('wiz_rgb_qgend') + '</label></td><td class="itd"><select id="wiz_g_select" class="form-control wselect"></select></td></tr></tbody></table>');
$('#wizp2_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_save"><i class="fa fa-fw fa-save"></i>' + $.i18n('general_btn_save') + '</button><button type="button" class="btn btn-primary" id="btn_wiz_checkok" style="display:none" data-dismiss="modal"><i class="fa fa-fw fa-check"></i>' + $.i18n('general_btn_ok') + '</button><button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</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 () {
beginWizardRGB();
$('#wizp1').toggle(false);
$('#wizp2').toggle(true);
});
}
};
})();
export { rgbByteOrderWizard };