Add Home Assistant Lights support (#1763)

* New HomeAssistant LEDDevice

* Fix typos

* Ping Qt for Windows to 6.7 until aqtinstaller is fixed

* Fix HA default port handling

* HA - Update default latchtime and range

* Add HA Wizard and light selection

* Naming consistency

* Fix "Selected Hyperion instance is not running"

* CodeQL findings

* HA - allow to overwrite brightness by HA yes or no

* HA - Support switch off on black

* HA - Add transition time
This commit is contained in:
LordGrey
2024-08-25 17:34:27 +02:00
committed by GitHub
parent df2b2b2372
commit 4f1b95ec83
19 changed files with 1020 additions and 76 deletions

View File

@@ -85,6 +85,7 @@
"conf_leds_layout_cl_bottomleft": "Bottom Left (Corner)",
"conf_leds_layout_cl_bottomright": "Bottom Right (Corner)",
"conf_leds_layout_cl_cornergap": "Corner Gap",
"conf_leds_layout_cl_disabled": "Deactivated",
"conf_leds_layout_cl_edgegap": "Edge Gap",
"conf_leds_layout_cl_entertainment": "Entertainment Area",
"conf_leds_layout_cl_entertainment_center": "Entertainment Area Center",
@@ -103,6 +104,7 @@
"conf_leds_layout_cl_lightPosBottomLeft112": "Bottom: 0 - 50% from Left",
"conf_leds_layout_cl_lightPosBottomLeft121": "Bottom: 50 - 100% from Left",
"conf_leds_layout_cl_lightPosBottomLeftNewMid": "Bottom: 25 - 75% from Left",
"conf_leds_layout_cl_lightPosEntire": "Whole picture",
"conf_leds_layout_cl_lightPosTopLeft112": "Top: 0 - 50% from Left",
"conf_leds_layout_cl_lightPosTopLeft121": "Top: 50 - 100% from Left",
"conf_leds_layout_cl_lightPosTopLeftNewMid": "Top: 25 - 75% from Left",
@@ -661,13 +663,14 @@
"edt_dev_spec_colorComponent_title": "Colour component",
"edt_dev_spec_debugLevel_title": "Debug Level",
"edt_dev_spec_delayAfterConnect_title": "Delay after connect",
"edt_dev_spec_devices_discovered_none": "No Devices Discovered",
"edt_dev_spec_devices_discovered_title": "Devices Discovered",
"edt_dev_spec_devices_discovered_none": "No Devices discovered",
"edt_dev_spec_devices_discovered_title": "Devices discovered",
"edt_dev_spec_devices_discovered_title_info": "Select your LED-Device discovered",
"edt_dev_spec_devices_discovered_title_info_custom": "Select your LED-Device discovered or configure a custome one",
"edt_dev_spec_devices_discovery_inprogress": "Discovery in progress",
"edt_dev_spec_dithering_title": "Dithering",
"edt_dev_spec_dmaNumber_title": "DMA channel",
"edt_dev_spec_fullBrightnessAtStart_title": "Full brightness at start",
"edt_dev_spec_gamma_title": "Gamma",
"edt_dev_spec_globalBrightnessControlMaxLevel_title": "Max Current Level",
"edt_dev_spec_globalBrightnessControlThreshold_title": "Adaptive Current Threshold",
@@ -685,6 +688,7 @@
"edt_dev_spec_ledType_title": "LED Type",
"edt_dev_spec_lightid_itemtitle": "ID",
"edt_dev_spec_lightid_title": "Light ID(s)",
"edt_dev_spec_lights_discovered_none": "No Lights discovered",
"edt_dev_spec_lights_itemtitle": "Light",
"edt_dev_spec_lights_name": "Name",
"edt_dev_spec_lights_title": "Light(s)",
@@ -1184,9 +1188,10 @@
"wiz_identify_tip": "Identify configured device by lighting it up",
"wiz_identify_light": "Identify $1",
"wiz_layout": "Generate Layout",
"wiz_layout_led_position_title": "LED position",
"wiz_layout_led_positions_title": "LED position layout wizard",
"wiz_layout_led_positions_expl": "Select the LED position for the $1 controller lights.",
"wiz_layout_tip": "Generate a layout for the configured device",
"wiz_ids_disabled": "Deactivated",
"wiz_ids_entire": "Whole picture",
"wiz_nanoleaf_failure_auth_token": "Please press the Nanoleaf Power On/Off button within 30 seconds",
"wiz_nanoleaf_failure_auth_token_t": "User authorization token generating timeout",
"wiz_nanoleaf_press_onoff_button": "Please press the Power On/Off button on your Nanoleaf device for 5-7 seconds",

View File

@@ -197,7 +197,7 @@ $(document).ready(function () {
removeStorage("loginToken");
requestRequiresDefaultPasswortChange();
}
else if (event.reason == "Selected Hyperion instance isn't running") {
else if (event.reason == "Selected Hyperion instance is not running") {
//Switch to default instance
instanceSwitch(0);
} else {

View File

@@ -22,7 +22,7 @@ var devSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk68
var devFTDI = ['apa102_ftdi', 'sk6812_ftdi', 'ws2812_ftdi'];
var devRPiPWM = ['ws281x'];
var devRPiGPIO = ['piblaster'];
var devNET = ['atmoorb', 'cololight', 'fadecandy', 'philipshue', 'nanoleaf', 'razer', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udpddp', 'udph801', 'udpraw', 'wled', 'yeelight'];
var devNET = ['atmoorb', 'cololight', 'fadecandy', 'homeassistant', 'philipshue', 'nanoleaf', 'razer', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udpddp', 'udph801', 'udpraw', 'wled', 'yeelight'];
var devSerial = ['adalight', 'dmx', 'atmo', 'sedu', 'tpm2', 'karate'];
var devHID = ['hyperionusbasp', 'lightpack', 'paintpack', 'rawhid'];
@@ -1100,6 +1100,7 @@ $(document).ready(function () {
switch (ledType) {
case "wled":
case "cololight":
case "homeassistant":
case "nanoleaf":
showAllDeviceInputOptions("hostList", false);
case "apa102":
@@ -1279,7 +1280,21 @@ $(document).ready(function () {
if (hostList !== "SELECT") {
const host = conf_editor.getEditor("root.specificOptions.host").getValue();
const token = conf_editor.getEditor("root.specificOptions.token").getValue();
if (host !== "" && token !== "") {
if (host !== "" && token !== "" && entityIds) {
canIdentify = true;
canSave = true;
}
}
}
break;
case "homeassistant": {
const hostList = conf_editor.getEditor("root.specificOptions.hostList").getValue();
if (hostList !== "SELECT") {
const host = conf_editor.getEditor("root.specificOptions.host").getValue();
const token = conf_editor.getEditor("root.specificOptions.token").getValue();
const entityIds = conf_editor.getEditor("root.specificOptions.entityIds").getValue();
if (host !== "" && token !== "" && entityIds) {
canIdentify = true;
canSave = true;
}
@@ -1387,6 +1402,16 @@ $(document).ready(function () {
getProperties_device(ledType, host, params);
break;
case "homeassistant":
var token = conf_editor.getEditor("root.specificOptions.token").getValue();
if (token === "") {
return;
}
params = { host: host, token: token, filter: "states" };
getProperties_device(ledType, host, params);
break;
case "nanoleaf":
$('#btn_wiz_holder').show();
@@ -1552,6 +1577,14 @@ $(document).ready(function () {
var host = "";
switch (ledType) {
case "homeassistant":
host = conf_editor.getEditor("root.specificOptions.host").getValue();
if (host === "") {
return
}
params = { host: host, token: token, filter: "states" };
break;
case "nanoleaf":
host = conf_editor.getEditor("root.specificOptions.host").getValue();
if (host === "") {
@@ -1654,6 +1687,16 @@ $(document).ready(function () {
default:
}
});
conf_editor.watch('root.specificOptions.entityIds', () => {
var entityIds = conf_editor.getEditor("root.specificOptions.entityIds").getValue();
if (entityIds.length > 0) {
$('#btn_test_controller').prop('disabled', false);
} else {
$('#btn_test_controller').prop('disabled', true);
}
});
});
//philipshueentertainment backward fix
@@ -1684,7 +1727,7 @@ $(document).ready(function () {
else if ($.inArray(ledDevices[idx], devHID) != -1)
optArr[4].push(ledDevices[idx]);
else if (ledDevices[idx].endsWith("_ftdi")) {
var title = ledDevices[idx].replace('_ftdi','');
var title = ledDevices[idx].replace('_ftdi', '');
optArr[5].push(ledDevices[idx] + ":" + title);
}
else
@@ -1744,6 +1787,13 @@ $(document).ready(function () {
params = { host: host };
break;
case "homeassistant":
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
var token = conf_editor.getEditor("root.specificOptions.token").getValue();
const entityIds = conf_editor.getEditor("root.specificOptions.entityIds").getValue();
params = { host: host, token: token, entity_id: entityIds };
break;
case "nanoleaf":
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
var token = conf_editor.getEditor("root.specificOptions.token").getValue();
@@ -1878,6 +1928,7 @@ function saveLedConfig(genDefLayout = false) {
}
break;
case "homeassistant":
case "nanoleaf":
case "wled":
case "yeelight":
@@ -2311,6 +2362,12 @@ function updateElements(ledType, key) {
}
break;
case "homeassistant":
updateElementsHomeAssistant(ledType, key);
hardwareLedCount = 1;
conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(hardwareLedCount);
break;
case "atmo":
case "karate":
var ledProperties = devicesProperties[ledType][key];
@@ -2438,6 +2495,63 @@ function validateWledLedCount(hardwareLedCount) {
}
}
function updateElementsHomeAssistant(ledType, key) {
// Get configured device's details
var configuredDeviceType = window.serverConfig.device.type;
var configuredHost = window.serverConfig.device.host;
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
// New light selection list values
var enumVals = [];
var enumTitleVals = [];
var enumDefaultVal = [];
if (devicesProperties[ledType] && devicesProperties[ledType][key]) {
var ledDeviceProperties = devicesProperties[ledType][key];
if (!jQuery.isEmptyObject(ledDeviceProperties)) {
if (ledDeviceProperties && ledDeviceProperties.lightEntities) {
for (const light of ledDeviceProperties.lightEntities) {
enumVals.push(light.entity_id);
enumTitleVals.push(light.attributes.friendly_name);
}
}
}
}
// Select configured device
if (configuredDeviceType == ledType && configuredHost == host) {
let configuredEntityIds = window.serverConfig.device.entityIds;
for (const light of configuredEntityIds) {
if ($.inArray(enumVals, light) != -1) {
enumVals.push(light);
}
enumDefaultVal.push(light);
}
}
if (enumVals.length < 1) {
enumVals.push("NONE");
enumTitleVals.push($.i18n('edt_dev_spec_lights_discovered_none'));
}
else {
$('#btn_wiz_holder').show();
}
let addSchemaElements = {
"uniqueItems": true,
"minItems": 1,
"required": true
};
updateJsonEditorMultiSelection(conf_editor, 'root.specificOptions', 'entityIds', addSchemaElements, enumVals, enumTitleVals, enumDefaultVal);
}
function updateElementsWled(ledType, key) {
// Get configured device's details
@@ -2533,6 +2647,7 @@ function updateElementsWled(ledType, key) {
}
showInputOptionForItem(conf_editor, "root.specificOptions.segments", "switchOffOtherSegments", showAdditionalOptions);
}
function sortByPanelCoordinates(arr, topToBottom, leftToRight) {
arr.sort((a, b) => {
//Nanoleaf corodinates start at bottom left, therefore reverse topToBottom
@@ -2591,7 +2706,7 @@ function nanoleafGeneratelayout(panelLayout, panelOrderTopDown, panelOrderLeftRi
29: { name: "4DLightstrip", led: true, sideLengthX: 50, sideLengthY: 50 },
30: { name: "Skylight Panel", led: true, sideLengthX: 180, sideLengthY: 180 },
31: { name: "SkylightControllerPrimary", led: true, sideLengthX: 180, sideLengthY: 180 },
32: { name: "SkylightControllerPassive", led: true, sideLengthX: 180, sideLengthY: 180 },
32: { name: "SkylightControllerPassive", led: true, sideLengthX: 180, sideLengthY: 180 },
999: { name: "Unknown", led: true, sideLengthX: 100, sideLengthY: 100 }
};

View File

@@ -321,7 +321,7 @@ function showInfoDialog(type, header, message) {
$(document).on('click', '[data-dismiss-modal]', function () {
var target = $(this).data('dismiss-modal');
$($.find(target)).modal('hide');
});
});
}
function createHintH(type, text, container) {
@@ -478,7 +478,7 @@ function createJsonEditor(container, schema, setconfig, usePanel, arrayre) {
return editor;
}
function updateJsonEditorSelection(rootEditor, path, key, addElements, newEnumVals, newTitelVals, newDefaultVal, addSelect, addCustom, addCustomAsFirst, customText) {
function updateJsonEditorSelection(rootEditor, path, key, addElements, newEnumVals, newTitleVals, newDefaultVal, addSelect, addCustom, addCustomAsFirst, customText) {
var editor = rootEditor.getEditor(path);
var orginalProperties = editor.schema.properties[key];
@@ -516,8 +516,8 @@ function updateJsonEditorSelection(rootEditor, path, key, addElements, newEnumVa
if (addCustom) {
if (newTitelVals.length === 0) {
newTitelVals = [...newEnumVals];
if (newTitleVals.length === 0) {
newTitleVals = [...newEnumVals];
}
if (!!!customText) {
@@ -526,10 +526,10 @@ function updateJsonEditorSelection(rootEditor, path, key, addElements, newEnumVa
if (addCustomAsFirst) {
newEnumVals.unshift("CUSTOM");
newTitelVals.unshift(customText);
newTitleVals.unshift(customText);
} else {
newEnumVals.push("CUSTOM");
newTitelVals.push(customText);
newTitleVals.push(customText);
}
if (newSchema[key].options.infoText) {
@@ -540,7 +540,7 @@ function updateJsonEditorSelection(rootEditor, path, key, addElements, newEnumVa
if (addSelect) {
newEnumVals.unshift("SELECT");
newTitelVals.unshift("edt_conf_enum_please_select");
newTitleVals.unshift("edt_conf_enum_please_select");
newDefaultVal = "SELECT";
}
@@ -548,8 +548,8 @@ function updateJsonEditorSelection(rootEditor, path, key, addElements, newEnumVa
newSchema[key]["enum"] = newEnumVals;
}
if (newTitelVals) {
newSchema[key]["options"]["enum_titles"] = newTitelVals;
if (newTitleVals) {
newSchema[key]["options"]["enum_titles"] = newTitleVals;
}
if (newDefaultVal) {
newSchema[key]["default"] = newDefaultVal;
@@ -572,7 +572,7 @@ function updateJsonEditorSelection(rootEditor, path, key, addElements, newEnumVa
rootEditor.notifyWatchers(path + "." + key);
}
function updateJsonEditorMultiSelection(rootEditor, path, key, addElements, newEnumVals, newTitelVals, newDefaultVal) {
function updateJsonEditorMultiSelection(rootEditor, path, key, addElements, newEnumVals, newTitleVals, newDefaultVal) {
var editor = rootEditor.getEditor(path);
var orginalProperties = editor.schema.properties[key];
@@ -617,8 +617,8 @@ function updateJsonEditorMultiSelection(rootEditor, path, key, addElements, newE
newSchema[key]["items"]["enum"] = newEnumVals;
}
if (newTitelVals) {
newSchema[key]["items"]["options"]["enum_titles"] = newTitelVals;
if (newTitleVals) {
newSchema[key]["items"]["options"]["enum_titles"] = newTitleVals;
}
if (newDefaultVal) {
@@ -923,8 +923,8 @@ function createTableRow(list, head, align) {
el.style.verticalAlign = "middle";
var purifyConfig = {
ADD_TAGS: ['button'],
ADD_ATTR: ['onclick']
ADD_TAGS: ['button'],
ADD_ATTR: ['onclick']
};
el.innerHTML = DOMPurify.sanitize(list[i], purifyConfig);
row.appendChild(el);
@@ -1403,7 +1403,7 @@ function loadScript(src, callback, ...params) {
if (isScriptLoaded(src)) {
debugMessage('Script ' + src + ' already loaded');
if (callback && typeof callback === 'function') {
callback( ...params);
callback(...params);
}
return;
}

View File

@@ -37,27 +37,37 @@ function createLedDeviceWizards(ledType) {
$('#btn_led_device_wiz').off();
if (ledType == "philipshue") {
$('#btn_wiz_holder').show();
data = { ledType };
wizardName = ledType;
data = { wizardName };
title = 'wiz_hue_title';
}
else if (ledType == "nanoleaf") {
$('#btn_wiz_holder').hide();
data = { ledType };
wizardName = ledType;
data = { wizardName };
title = 'wiz_nanoleaf_user_auth_title';
}
else if (ledType == "homeassistant") {
$('#btn_wiz_holder').hide();
wizardName = "layoutLedPositions";
data = { wizardName, ledType };
title = 'wiz_layout_led_positions_title';
}
else if (ledType == "atmoorb") {
$('#btn_wiz_holder').show();
data = { ledType };
wizardName = ledType;
data = { wizardName };
title = 'wiz_atmoorb_title';
}
else if (ledType == "yeelight") {
$('#btn_wiz_holder').show();
data = { ledType };
wizardName = ledType;
data = { wizardName };
title = 'wiz_yeelight_title';
}
if (Object.keys(data).length !== 0) {
startLedDeviceWizard(data, title, ledType + "Wizard");
startLedDeviceWizard(data, title, wizardName + "Wizard");
}
}
@@ -66,8 +76,7 @@ function startLedDeviceWizard(data, hint, wizardName) {
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);
const { [wizardName]: winzardObject } = await import('./wizards/LedDevice_' + data.wizardName + '.js');
winzardObject.start(e, data);
});
}

View File

@@ -151,17 +151,7 @@ const atmoorbWizard = (() => {
$('#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"
];
const lightOptions = utils.getLayoutPositions();
lightOptions.unshift("disabled");
$('.lidsb').html("");
@@ -178,10 +168,9 @@ const atmoorbWizard = (() => {
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>';
options += '>' + $.i18n('conf_leds_layout_cl_' + val) + '</option>';
}
let enabled = 'enabled';

View File

@@ -0,0 +1,74 @@
//****************************
// Wizard LED Layout
//****************************
import { ledDeviceWizardUtils as utils } from './LedDevice_utils.js';
const layoutLedPositionsWizard = (() => {
let wiz_editor;
function createEditor() {
wiz_editor = createJsonEditor('editor_container_wiz', {
layoutPosition: {
"type": "string",
"title": "wiz_layout_led_position_title",
"enum": utils.getLayoutPositions(),
"options": {
"enum_titles": utils.getLayoutPositionsTitles()
}
}
}, true, true);
}
function stopWizardLedLayout(reload) {
resetWizard(reload);
}
function beginWizardLayoutLedPositions() {
createEditor();
setStorage("wizardactive", true);
$('#btn_wiz_abort').off().on('click', function () {
stopWizardLedLayout(true);
});
$('#btn_wiz_ok').off().on('click', function () {
const layoutPosition = wiz_editor.getEditor("root.layoutPosition").getValue();
const layoutObject = utils.assignLightPos(layoutPosition);
var layoutObjects = [];
layoutObjects.push(JSON.parse(JSON.stringify(layoutObject)));
aceEdt.set(layoutObjects);
stopWizardLedLayout(true);
});
}
return {
start: function (e, data) {
$('#wiz_header').html('<i class="fa fa-magic fa-fw"></i>' + $.i18n('wiz_layout_led_positions_title'));
$('#wizp1_body').html('<div <p style="font-weight:bold">' + $.i18n('wiz_layout_led_positions_expl', data.ledType) + '</p></div>' +
'<div id="editor_container_wiz"></div>'
);
$('#wizp1_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_ok"><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
});
beginWizardLayoutLedPositions();
}
};
})();
export { layoutLedPositionsWizard };

View File

@@ -794,17 +794,7 @@ const philipshueWizard = (() => {
}
$('#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"
];
const lightOptions = utils.getLayoutPositions();
if (isEntertainmentReady && hueEntertainmentConfigs.length > 0) {
lightOptions.unshift("entertainment_center");
lightOptions.unshift("entertainment");
@@ -866,10 +856,9 @@ const philipshueWizard = (() => {
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>';
options += '>' + $.i18n('conf_leds_layout_cl_' + val) + '</option>';
}
$('.lidsb').append(createTableRow([id + ' (' + lightName + ')',

View File

@@ -52,6 +52,17 @@ const ledDeviceWizardUtils = (() => {
const i = positionMap[pos] || positionMap["lightPosEntire"];
i.name = name;
return i;
},
getLayoutPositions: function () {
return Object.keys(positionMap);
},
getLayoutPositionsTitles: function () {
let layoutPositionTitles = [];
for (const layoutPosition of Object.keys(positionMap)) {
layoutPositionTitles.push($.i18n('conf_leds_layout_cl_' + layoutPosition));
}
return layoutPositionTitles;
}
};

View File

@@ -173,17 +173,7 @@ const yeelightWizard = (() => {
$('#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"
];
const lightOptions = utils.getLayoutPositions();
lightOptions.unshift("disabled");
$('.lidsb').html("");
@@ -200,10 +190,9 @@ const yeelightWizard = (() => {
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>';
options += '>' + $.i18n('conf_leds_layout_cl_' + val) + '</option>';
}
let enabled = 'enabled';