Skip to content

Add Home Assistant Lights support #1763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/qt5_6.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ jobs:
version: ${{ inputs.qt_version == '6' && '6.7' || '5.15.*' }}
target: 'desktop'
modules: ${{ inputs.qt_version == '6' && 'qtserialport' || '' }}
arch: 'win64_msvc2019_64'
cache: 'true'
cache-key-prefix: 'cache-qt-windows'

Expand Down
13 changes: 9 additions & 4 deletions assets/webconfig/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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)",
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion assets/webconfig/js/content_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
123 changes: 119 additions & 4 deletions assets/webconfig/js/content_leds.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'];

Expand Down Expand Up @@ -1100,6 +1100,7 @@ $(document).ready(function () {
switch (ledType) {
case "wled":
case "cololight":
case "homeassistant":
case "nanoleaf":
showAllDeviceInputOptions("hostList", false);
case "apa102":
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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 === "") {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -1878,6 +1928,7 @@ function saveLedConfig(genDefLayout = false) {
}
break;

case "homeassistant":
case "nanoleaf":
case "wled":
case "yeelight":
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 }
};

Expand Down
30 changes: 15 additions & 15 deletions assets/webconfig/js/ui_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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];

Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -540,16 +540,16 @@ 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";
}

if (newEnumVals) {
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;
Expand All @@ -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];

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
Loading