From a3c8fba7a3c82030fba03afd19c498f67db26c15 Mon Sep 17 00:00:00 2001
From: LordGrey
Date: Thu, 8 Apr 2021 09:26:10 +0200
Subject: [PATCH 01/58] Revert "temporarily reset mbedtls to version 2.25
#1214"
This reverts commit dc0e953c40fd46ebc20f90a1c69d35a01225e5ec.
---
dependencies/CMakeLists-mbedtls.txt.in | 2 +-
dependencies/CMakeLists.txt | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dependencies/CMakeLists-mbedtls.txt.in b/dependencies/CMakeLists-mbedtls.txt.in
index cb81adc8..12888d5b 100644
--- a/dependencies/CMakeLists-mbedtls.txt.in
+++ b/dependencies/CMakeLists-mbedtls.txt.in
@@ -14,7 +14,7 @@ include(ExternalProject)
ExternalProject_Add(
mbedtls
GIT_REPOSITORY "https://github.com/ARMmbed/mbedtls.git"
- GIT_TAG "v2.25.0" # Reset to origin/master if issue https://github.com/ARMmbed/mbedtls/issues/4233 if fixed
+ GIT_TAG origin/master
BUILD_ALWAYS OFF
DOWNLOAD_DIR "${DOWNLOAD_DIR}"
SOURCE_DIR "${SOURCE_DIR}"
diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt
index f37aa83a..318787de 100644
--- a/dependencies/CMakeLists.txt
+++ b/dependencies/CMakeLists.txt
@@ -233,7 +233,7 @@ if (NOT USE_SYSTEM_MBEDTLS_LIBS)
FetchContent_Declare(
mbedtls
GIT_REPOSITORY https://github.com/ARMmbed/mbedtls.git
- GIT_TAG "v2.25.0" # Reset to origin/master if issue https://github.com/ARMmbed/mbedtls/issues/4233 if fixed
+ GIT_TAG origin/master
BUILD_ALWAYS OFF
GIT_PROGRESS 1
DOWNLOAD_DIR "${MBEDTLS_DOWNLOAD_DIR}"
From 6f0ccdbe25a7532f766b613430ef13838d9719c0 Mon Sep 17 00:00:00 2001
From: LordGrey
Date: Sat, 10 Apr 2021 17:19:47 +0200
Subject: [PATCH 02/58] "temporarily reset mbedtls to version 2.25 #1214"
---
dependencies/CMakeLists-mbedtls.txt.in | 2 +-
dependencies/CMakeLists.txt | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dependencies/CMakeLists-mbedtls.txt.in b/dependencies/CMakeLists-mbedtls.txt.in
index 12888d5b..cb81adc8 100644
--- a/dependencies/CMakeLists-mbedtls.txt.in
+++ b/dependencies/CMakeLists-mbedtls.txt.in
@@ -14,7 +14,7 @@ include(ExternalProject)
ExternalProject_Add(
mbedtls
GIT_REPOSITORY "https://github.com/ARMmbed/mbedtls.git"
- GIT_TAG origin/master
+ GIT_TAG "v2.25.0" # Reset to origin/master if issue https://github.com/ARMmbed/mbedtls/issues/4233 if fixed
BUILD_ALWAYS OFF
DOWNLOAD_DIR "${DOWNLOAD_DIR}"
SOURCE_DIR "${SOURCE_DIR}"
diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt
index 318787de..f37aa83a 100644
--- a/dependencies/CMakeLists.txt
+++ b/dependencies/CMakeLists.txt
@@ -233,7 +233,7 @@ if (NOT USE_SYSTEM_MBEDTLS_LIBS)
FetchContent_Declare(
mbedtls
GIT_REPOSITORY https://github.com/ARMmbed/mbedtls.git
- GIT_TAG origin/master
+ GIT_TAG "v2.25.0" # Reset to origin/master if issue https://github.com/ARMmbed/mbedtls/issues/4233 if fixed
BUILD_ALWAYS OFF
GIT_PROGRESS 1
DOWNLOAD_DIR "${MBEDTLS_DOWNLOAD_DIR}"
From a4d98fd916e17f1a3834c43ba220d7838313d711 Mon Sep 17 00:00:00 2001
From: TheGroundZero <2406013+TheGroundZero@users.noreply.github.com>
Date: Wed, 14 Apr 2021 14:25:51 +0000
Subject: [PATCH 03/58] Fixes: #1229 (#1230)
* Fix "LED Test" effect colour order (#1229)
---
CHANGELOG.md | 1 +
assets/webconfig/i18n/en.json | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8b9137a4..e00f0ccc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- LED-Hue: Proper black in Entertainement mode if min brightness is set
- LED-Hue: Minor fix of setColor command
- Nanoleaf: Fix,if external control mode cannot be set
+- Fix issue #1229: "LED Test" effect description is in wrong order
### Removed
diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json
index e9b29205..f57e13cf 100644
--- a/assets/webconfig/i18n/en.json
+++ b/assets/webconfig/i18n/en.json
@@ -580,7 +580,7 @@
"edt_eff_knightrider_header_desc": "K.I.T.T is back! The front-scanner of the well known car, this time not just in red.",
"edt_eff_ledlist": "Led List",
"edt_eff_ledtest_header": "Led Test",
- "edt_eff_ledtest_header_desc": "Rotating output: Red, Blue, Green, White, Black",
+ "edt_eff_ledtest_header_desc": "Rotating output: Red, Green, Blue, White, Black",
"edt_eff_length": "Length",
"edt_eff_lightclock_header": "Light Clock",
"edt_eff_lightclock_header_desc": "A real clock as light! Adjust the colors of hours, minute, seconds. A optional 3/6/9/12 o'clock marker is also available. In case the clock is wrong, you need to check your system clock.",
From 7eeb7401777d97308cdd7490c824ae73f5ec0f71 Mon Sep 17 00:00:00 2001
From: LordGrey <48840279+Lord-Grey@users.noreply.github.com>
Date: Sat, 24 Apr 2021 19:37:29 +0200
Subject: [PATCH 04/58] Dynamic Device Selection/Configuration (#1164)
---
.github/workflows/pull-request.yml | 6 +-
assets/webconfig/content/conf_leds.html | 740 +++---
assets/webconfig/i18n/en.json | 146 +-
assets/webconfig/index.html | 4 +-
assets/webconfig/js/content_colors.js | 154 +-
assets/webconfig/js/content_index.js | 575 ++---
assets/webconfig/js/content_leds.js | 2019 ++++++++++++-----
assets/webconfig/js/ui_utils.js | 239 +-
assets/webconfig/js/wizard.js | 437 +---
cmake/debian/postinst | 4 +-
cmake/packages.cmake | 5 +-
cmake/rpm/postinst | 4 +-
include/hyperion/SettingsManager.h | 17 +-
include/leddevice/LedDevice.h | 17 +-
include/utils/version.hpp | 550 +++++
libsrc/hyperion/Hyperion.cpp | 6 +-
libsrc/hyperion/SettingsManager.cpp | 252 +-
libsrc/hyperion/schema/schema-device.json | 91 +-
libsrc/hyperion/schema/schema-general.json | 19 +
libsrc/hyperion/schema/schema-ledConfig.json | 38 +-
libsrc/leddevice/LedDevice.cpp | 48 +-
libsrc/leddevice/dev_net/LedDeviceWled.cpp | 63 +-
libsrc/leddevice/dev_net/LedDeviceWled.h | 8 +
.../leddevice/dev_net/LedDeviceYeelight.cpp | 9 +-
.../dev_other/LedDevicePiBlaster.cpp | 39 +
.../leddevice/dev_other/LedDevicePiBlaster.h | 6 +
libsrc/leddevice/dev_serial/ProviderRs232.cpp | 51 +-
libsrc/leddevice/dev_serial/ProviderRs232.h | 14 +
libsrc/leddevice/dev_spi/ProviderSpi.cpp | 41 +
libsrc/leddevice/dev_spi/ProviderSpi.h | 6 +
libsrc/leddevice/schemas/schema-adalight.json | 18 +-
libsrc/leddevice/schemas/schema-apa102.json | 2 -
libsrc/leddevice/schemas/schema-apa104.json | 1 -
libsrc/leddevice/schemas/schema-atmoorb.json | 89 +-
.../leddevice/schemas/schema-cololight.json | 58 +-
libsrc/leddevice/schemas/schema-lpd6803.json | 1 -
libsrc/leddevice/schemas/schema-lpd8806.json | 1 -
libsrc/leddevice/schemas/schema-nanoleaf.json | 132 +-
libsrc/leddevice/schemas/schema-p9813.json | 1 -
.../leddevice/schemas/schema-philipshue.json | 481 ++--
.../leddevice/schemas/schema-sk6812spi.json | 1 -
.../leddevice/schemas/schema-sk6822spi.json | 1 -
libsrc/leddevice/schemas/schema-sk9822.json | 1 -
libsrc/leddevice/schemas/schema-wled.json | 110 +-
libsrc/leddevice/schemas/schema-ws2801.json | 1 -
.../leddevice/schemas/schema-ws2812spi.json | 1 -
libsrc/leddevice/schemas/schema-yeelight.json | 352 ++-
src/hyperiond/hyperiond.cpp | 4 +-
48 files changed, 4296 insertions(+), 2567 deletions(-)
mode change 100644 => 100755 assets/webconfig/js/content_colors.js
mode change 100644 => 100755 assets/webconfig/js/content_index.js
mode change 100644 => 100755 assets/webconfig/js/content_leds.js
mode change 100644 => 100755 assets/webconfig/js/ui_utils.js
mode change 100644 => 100755 assets/webconfig/js/wizard.js
create mode 100644 include/utils/version.hpp
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 3d064eb2..3b00f57d 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -41,7 +41,7 @@ jobs:
shell: bash
run: |
tr -d '\n' < version > temp && mv temp version
- echo -n -PR#${{ github.event.pull_request.number }} >> version
+ echo -n "+PR${{ github.event.pull_request.number }}" >> version
# Build packages
- name: Build packages
@@ -87,7 +87,7 @@ jobs:
shell: bash
run: |
tr -d '\n' < version > temp && mv temp version
- echo -n "-PR#${{ github.event.pull_request.number }}" >> version
+ echo -n "+PR${{ github.event.pull_request.number }}" >> version
# Install dependencies
- name: Install dependencies
@@ -136,7 +136,7 @@ jobs:
shell: bash
run: |
tr -d '\n' < version > temp && mv temp version
- echo -n "-PR#${{ github.event.pull_request.number }}" >> version
+ echo -n "+PR${{ github.event.pull_request.number }}" >> version
- name: Cache Qt
uses: actions/cache@v2
diff --git a/assets/webconfig/content/conf_leds.html b/assets/webconfig/content/conf_leds.html
index eca4412f..60e2d16e 100755
--- a/assets/webconfig/content/conf_leds.html
+++ b/assets/webconfig/content/conf_leds.html
@@ -1,374 +1,382 @@
+
+
+
+ Hyperion - LED Device Configuration
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
This textfield shows by default your current loaded layout and will be overwritten if you generate a new one above. Optional you could perform further edits.
+
+
+
+
+
+
+
+
+
+
+
LED Layout preview
+
+
+
+
+
+
+
+
diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json
index f57e13cf..20beaeb8 100644
--- a/assets/webconfig/i18n/en.json
+++ b/assets/webconfig/i18n/en.json
@@ -1,15 +1,4 @@
{
- "InfoDialog_access_text": "Depending on settings level you could adjust more options or get access to more features. Recommended is the \"Default\" level.",
- "InfoDialog_access_title": "Settings level",
- "InfoDialog_changePassword_success": "Password successfully saved!",
- "InfoDialog_changePassword_title": "Change Password",
- "InfoDialog_iswitch_text": "If you run Hyperion more than once in your local network, you could switch between the web configurations. Select the Hyperion instance below and switch!",
- "InfoDialog_iswitch_title": "Hyperion switcher",
- "InfoDialog_lang_text": "If you don't like the result of the automatic language detection you could overwrite it here.",
- "InfoDialog_lang_title": "Language setting",
- "InfoDialog_nowrite_foottext": "The WebUI will be unlocked automatically after you solved the problem!",
- "InfoDialog_nowrite_text": "Hyperion can't write to your current loaded configuration file. Please repair the file permissions to proceed.",
- "InfoDialog_nowrite_title": "write permission error!",
"about_3rd_party_licenses": "3rd party licenses",
"about_3rd_party_licenses_error": "We had trouble collecting 3rd party licenses information from web. Please follow this link to the GitHub Resource.",
"about_build": "Build",
@@ -45,9 +34,19 @@
"conf_grabber_v4l_intro": "USB capture is a (capture)device connected via USB which is used to input source pictures for processing.",
"conf_helptable_expl": "Explanation",
"conf_helptable_option": "Option",
+ "conf_leds_config_error": "Error in LED/LED layout configuration",
+ "conf_leds_config_warning": "Check your LED/LED layout configuration",
"conf_leds_contr_label_contrtype": "Controller type:",
+ "conf_leds_device_info_log": "In case your LEDs do not work, check here for errors:",
"conf_leds_device_intro": "Hyperion supports a lot of controllers to transmit data to your target device. Select a LED controller out of the sorted list and configure it. We have chosen the best default settings for each device.",
+ "conf_leds_error_hwled_gt_layout": "The hardware LED count ($1) is greater than LEDs configured via layout ($2), $3 {{plural:$1|LED|LEDs}} will stay black if you continue.",
+ "conf_leds_error_hwled_lt_layout": "The hardware LED count ($1) is less than LEDs configured via layout ($2). The number of LEDs configured in the layout must not exceed the available LEDs",
"conf_leds_layout_advanced": "Advanced Settings",
+ "conf_leds_layout_blacklist_num_title": "Number of LEDs",
+ "conf_leds_layout_blacklist_rule_title": "Blacklist rule",
+ "conf_leds_layout_blacklist_rules_title": "Blacklist rules",
+ "conf_leds_layout_blacklist_start_title": "Start LED",
+ "conf_leds_layout_blacklistleds_title": "Blacklist LEDs",
"conf_leds_layout_btn_checklist": "Show checklist",
"conf_leds_layout_button_savelay": "Save Layout",
"conf_leds_layout_button_updsim": "Update Preview",
@@ -113,11 +112,12 @@
"conf_leds_layout_textf1": "This text field shows by default your current loaded layout and will be overwritten if you generate a new one with the options above. Optional you could perform further edits.",
"conf_leds_nav_label_ledcontroller": "LED Controller",
"conf_leds_nav_label_ledlayout": "LED Layout",
+ "conf_leds_note_layout_overwrite": "Note: Overwrite creates a default layout for {{plural:$1| $1 LED| all $1 LEDs}} given by the hardware LED count",
+ "conf_leds_optgroup_network": "Network",
+ "conf_leds_optgroup_other": "Other",
"conf_leds_optgroup_RPiGPIO": "RPi GPIO",
"conf_leds_optgroup_RPiPWM": "RPi PWM",
"conf_leds_optgroup_RPiSPI": "RPi SPI",
- "conf_leds_optgroup_debug": "Debug",
- "conf_leds_optgroup_network": "Network",
"conf_leds_optgroup_usb": "USB/Serial",
"conf_logging_btn_autoscroll": "Auto scrolling",
"conf_logging_btn_pbupload": "Upload a report for support requests",
@@ -215,10 +215,10 @@
"edt_conf_color_black_title": "Black",
"edt_conf_color_blue_expl": "The calibrated blue value.",
"edt_conf_color_blue_title": "Blue",
- "edt_conf_color_brightnessComp_expl": "Compensates brightness differences between red green blue, cyan magenta yellow and white. 100 means full compensation, 0 no compensation",
- "edt_conf_color_brightnessComp_title": "Brightness compensation",
"edt_conf_color_brightness_expl": "set overall brightness of LEDs",
"edt_conf_color_brightness_title": "Brightness",
+ "edt_conf_color_brightnessComp_expl": "Compensates brightness differences between red green blue, cyan magenta yellow and white. 100 means full compensation, 0 no compensation",
+ "edt_conf_color_brightnessComp_title": "Brightness compensation",
"edt_conf_color_channelAdjustment_header_expl": "Create color profiles that could be assigned to a specific component. Adjust color, gamma, brightness, compensation and more.",
"edt_conf_color_channelAdjustment_header_itemtitle": "Profile",
"edt_conf_color_channelAdjustment_header_title": "Color channel adjustments",
@@ -254,10 +254,6 @@
"edt_conf_effp_paths_expl": "You could define more folders that contain effects. The effect configurator will always save inside the first folder.",
"edt_conf_effp_paths_itemtitle": "Path",
"edt_conf_effp_paths_title": "Effect Path(s)",
- "edt_conf_enum_NO_CHANGE": "Automatic",
- "edt_conf_enum_NTSC": "NTSC",
- "edt_conf_enum_PAL": "PAL",
- "edt_conf_enum_SECAM": "SECAM",
"edt_conf_enum_automatic": "Automatic",
"edt_conf_enum_bbclassic": "Classic",
"edt_conf_enum_bbdefault": "Default",
@@ -288,9 +284,14 @@
"edt_conf_enum_logverbose": "Verbose",
"edt_conf_enum_logwarn": "Warning",
"edt_conf_enum_multicolor_mean": "Multicolor",
+ "edt_conf_enum_NO_CHANGE": "Automatic",
+ "edt_conf_enum_NTSC": "NTSC",
+ "edt_conf_enum_PAL": "PAL",
+ "edt_conf_enum_please_select": "Please Select",
"edt_conf_enum_rbg": "RBG",
"edt_conf_enum_rgb": "RGB",
"edt_conf_enum_right_left": "Right to left",
+ "edt_conf_enum_SECAM": "SECAM",
"edt_conf_enum_top_down": "Top down",
"edt_conf_enum_transeffect_smooth": "Smooth",
"edt_conf_enum_transeffect_sudden": "Sudden",
@@ -322,11 +323,12 @@
"edt_conf_fge_type_title": "Type",
"edt_conf_fw_flat_expl": "One flatbuffer target per line. Contains IP:PORT (Example: 127.0.0.1:19401)",
"edt_conf_fw_flat_itemtitle": "flatbuffer target",
- "edt_conf_fw_flat_title": "List of flatbuffer clients",
+ "edt_conf_fw_flat_title": "List of flatbuffer targets",
"edt_conf_fw_heading_title": "Forwarder",
"edt_conf_fw_json_expl": "One json target per line. Contains IP:PORT (Example: 127.0.0.1:19446)",
"edt_conf_fw_json_itemtitle": "Json target",
- "edt_conf_fw_json_title": "List of json clients",
+ "edt_conf_fw_json_title": "List of json targets",
+ "edt_conf_gen_configVersion_title": "Configuration version",
"edt_conf_gen_heading_title": "General Settings",
"edt_conf_gen_name_expl": "A user defined name which is used to detect Hyperion. (Helpful with more than one Hyperion instance)",
"edt_conf_gen_name_title": "Configuration name",
@@ -354,9 +356,9 @@
"edt_conf_net_heading_title": "Network",
"edt_conf_net_internetAccessAPI_expl": "Allow access to the Hyperion API/Webinterface from the internet, disable for higher security.",
"edt_conf_net_internetAccessAPI_title": "Internet API Access",
+ "edt_conf_net_ip_itemtitle": "IP",
"edt_conf_net_ipWhitelist_expl": "You can whitelist IP addresses instead allowing all connections from internet to connect to the Hyperion API/Webinterface.",
"edt_conf_net_ipWhitelist_title": "Whitelisted IP's",
- "edt_conf_net_ip_itemtitle": "IP",
"edt_conf_net_localAdminAuth_expl": "When enabled, administration access from your local network needs a password.",
"edt_conf_net_localAdminAuth_title": "Local Admin API Authentication",
"edt_conf_net_localApiAuth_expl": "When enabled, connections from your home network needs to authenticate themself against Hyperion with a token.",
@@ -436,25 +438,25 @@
"edt_conf_webc_sslport_expl": "Port oft the HTTPS-Webserver",
"edt_conf_webc_sslport_title": "HTTPS Port",
"edt_dev_auth_key_title": "Authentication Token",
+ "edt_dev_auth_key_title_info": "Authentication Token required to acccess the device",
"edt_dev_enum_sub_min_cool_adjust": "Subtract cool white",
"edt_dev_enum_sub_min_warm_adjust": "Subtract warm white",
"edt_dev_enum_subtract_minimum": "Subtract minimum",
"edt_dev_enum_white_off": "White off",
"edt_dev_general_colorOrder_title": "RGB byte order",
+ "edt_dev_general_colorOrder_title_info": "The device's color order",
"edt_dev_general_hardwareLedCount_title": "Hardware LED count",
+ "edt_dev_general_hardwareLedCount_title_info": "The number of physical LEDs availabe for the given device",
"edt_dev_general_heading_title": "General Settings",
"edt_dev_general_name_title": "Configuration name",
"edt_dev_general_rewriteTime_title": "Refresh time",
- "edt_dev_spec_FCledToOn_title": "Fadecandy LED set to on",
- "edt_dev_spec_FCmanualControl_title": "Manual control of fadecandy LED",
- "edt_dev_spec_FCsetConfig_title": "Set fadecandy configuration",
- "edt_dev_spec_LBap102Mode_title": "LightBerry APA102 Mode",
- "edt_dev_spec_PBFiFo_title": "Pi-Blaster FiFo",
"edt_dev_spec_baudrate_title": "Baudrate",
"edt_dev_spec_blackLightsTimeout_title": "Signal detection timeout on black",
+ "edt_dev_spec_brightness_title": "Brightness",
"edt_dev_spec_brightnessFactor_title": "Brightness factor",
"edt_dev_spec_brightnessMax_title": "Brightness maximum",
"edt_dev_spec_brightnessMin_title": "Brightness minimum",
+ "edt_dev_spec_brightnessOverwrite_title": "Overwrite brightness",
"edt_dev_spec_brightnessThreshold_title": "Signal detection brightness minimum",
"edt_dev_spec_chanperfixture_title": "Channels per Fixture",
"edt_dev_spec_cid_title": "CID",
@@ -463,8 +465,16 @@
"edt_dev_spec_debugLevel_title": "Debug Level",
"edt_dev_spec_debugStreamer_title": "Streamer Debug",
"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_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_FCledToOn_title": "Fadecandy LED set to on",
+ "edt_dev_spec_FCmanualControl_title": "Manual control of fadecandy LED",
+ "edt_dev_spec_FCsetConfig_title": "Set fadecandy configuration",
"edt_dev_spec_gamma_title": "Gamma",
"edt_dev_spec_globalBrightnessControlMaxLevel_title": "Max Current Level",
"edt_dev_spec_globalBrightnessControlThreshold_title": "Adaptive Current Threshold",
@@ -477,6 +487,8 @@
"edt_dev_spec_intervall_title": "Interval",
"edt_dev_spec_invert_title": "Invert signal",
"edt_dev_spec_latchtime_title": "Latch time",
+ "edt_dev_spec_latchtime_title_info": "Latch time is the time-frame a device requires until the next update can be processed. During that time-frame any updates done via ignored.",
+ "edt_dev_spec_LBap102Mode_title": "LightBerry APA102 Mode",
"edt_dev_spec_ledIndex_title": "LED index",
"edt_dev_spec_ledType_title": "LED Type",
"edt_dev_spec_lightid_itemtitle": "ID",
@@ -484,8 +496,8 @@
"edt_dev_spec_lights_itemtitle": "Light",
"edt_dev_spec_lights_name": "Name",
"edt_dev_spec_lights_title": "Light(s)",
- "edt_dev_spec_maxPacket_title": "Max packet",
"edt_dev_spec_maximumLedCount_title": "Maximum LED count",
+ "edt_dev_spec_maxPacket_title": "Max packet",
"edt_dev_spec_multicastGroup_title": "Multicast group",
"edt_dev_spec_networkDeviceName_title": "Network devicename",
"edt_dev_spec_networkDevicePort_title": "Port",
@@ -496,23 +508,27 @@
"edt_dev_spec_outputPath_title": "Output path",
"edt_dev_spec_panel_start_position": "Start panel [0-max panels]",
"edt_dev_spec_panelorganisation_title": "Panel numbering sequence",
+ "edt_dev_spec_PBFiFo_title": "Pi-Blaster FiFo",
"edt_dev_spec_pid_title": "PID",
"edt_dev_spec_port_title": "Port",
"edt_dev_spec_printTimeStamp_title": "Add timestamp",
"edt_dev_spec_pwmChannel_title": "PWM channel",
- "edt_dev_spec_restoreOriginalState_title": "Restore lights' original state when disabled",
+ "edt_dev_spec_restoreOriginalState_title": "Restore lights' state",
+ "edt_dev_spec_restoreOriginalState_title_info": "Restore the device's original state when device is disabled",
"edt_dev_spec_serial_title": "Serial number",
- "edt_dev_spec_spipath_title": "SPI path",
+ "edt_dev_spec_spipath_title": "SPI Device",
"edt_dev_spec_sslHSTimeoutMax_title": "Streamer handshake timeout maximum",
"edt_dev_spec_sslHSTimeoutMin_title": "Streamer handshake timeout minimum",
"edt_dev_spec_sslReadTimeout_title": "Streamer read timeout",
- "edt_dev_spec_switchOffOnBlack_title": "Switch off on black",
"edt_dev_spec_switchOffOnbelowMinBrightness_title": "Switch-off, below minimum",
- "edt_dev_spec_targetIpHost_title": "Target IP/Hostname",
- "edt_dev_spec_targetIp_title": "Target IP",
+ "edt_dev_spec_switchOffOnBlack_title": "Switch off on black",
+ "edt_dev_spec_syncOverwrite_title": "Disable synchronisation",
+ "edt_dev_spec_targetIp_title": "Target IP-address",
+ "edt_dev_spec_targetIpHost_title": "Target Hostname/IP-address",
+ "edt_dev_spec_targetIpHost_title_info": "The device's hostname or IP-address",
"edt_dev_spec_transeffect_title": "Transition effect",
- "edt_dev_spec_transistionTimeExtra_title": "Extra time darkness",
"edt_dev_spec_transistionTime_title": "Transition time",
+ "edt_dev_spec_transistionTimeExtra_title": "Extra time darkness",
"edt_dev_spec_uid_title": "UID",
"edt_dev_spec_universe_title": "Universe",
"edt_dev_spec_useEntertainmentAPI_title": "Use Hue Entertainment API",
@@ -538,16 +554,16 @@
"edt_eff_collision_header": "color collision",
"edt_eff_collision_header_desc": "Two color projectiles are sent from random positions and collide with each other",
"edt_eff_color": "Color",
- "edt_eff_colorHour": "Color hour",
- "edt_eff_colorMarker": "Marker color",
- "edt_eff_colorMinute": "Color minute",
- "edt_eff_colorSecond": "Color second",
"edt_eff_colorcount": "Color length",
"edt_eff_colorend": "Color end",
"edt_eff_colorendtime": "Time to hold start color",
"edt_eff_colorevel": "Color level",
+ "edt_eff_colorHour": "Color hour",
+ "edt_eff_colorMarker": "Marker color",
+ "edt_eff_colorMinute": "Color minute",
"edt_eff_colorone": "Color one",
"edt_eff_colorrandom": "Random color",
+ "edt_eff_colorSecond": "Color second",
"edt_eff_colorshift": "Color Shift",
"edt_eff_colorstart": "Color start",
"edt_eff_colorstarttime": "Time to hold end color",
@@ -603,13 +619,13 @@
"edt_eff_postcolor": "Post color",
"edt_eff_rainbowmood_header": "Rainbow Mood",
"edt_eff_rainbowmood_header_desc": "All LEDs rainbow mood",
- "edt_eff_randomCenter": "Random Center",
"edt_eff_random_header": "Random",
"edt_eff_random_header_desc": "Pixel Dot, dot, dot...",
+ "edt_eff_randomCenter": "Random Center",
"edt_eff_repeat": "Repeat",
"edt_eff_repeatcount": "Repeat count",
- "edt_eff_reverseRandomTime": "Reverse every",
"edt_eff_reversedirection": "Reverse direction",
+ "edt_eff_reverseRandomTime": "Reverse every",
"edt_eff_rotationtime": "Rotation time",
"edt_eff_saturation": "Saturation",
"edt_eff_showseconds": "Show seconds",
@@ -647,23 +663,23 @@
"edt_msg_button_expand": "Expand",
"edt_msg_button_move_down_title": "Move down",
"edt_msg_button_move_up_title": "Move up",
- "edt_msg_error_additionalItems": "No additional items allowed in this array",
"edt_msg_error_additional_properties": "No additional properties allowed, but property $1 is set",
+ "edt_msg_error_additionalItems": "No additional items allowed in this array",
"edt_msg_error_anyOf": "Value must validate against at least one of the provided schemas",
"edt_msg_error_dependency": "Must have property $1",
"edt_msg_error_disallow": "Value must not be of type $1",
"edt_msg_error_disallow_union": "Value must not be one of the provided disallowed types",
"edt_msg_error_enum": "Value must be one of the enumerated values",
+ "edt_msg_error_maximum_excl": "Value must be less than $1",
+ "edt_msg_error_maximum_incl": "Value must be at most $1",
"edt_msg_error_maxItems": "Value must have at most $1 items",
"edt_msg_error_maxLength": "Value must be at most $1 characters long",
"edt_msg_error_maxProperties": "Object must have at most $1 properties",
- "edt_msg_error_maximum_excl": "Value must be less than $1",
- "edt_msg_error_maximum_incl": "Value must be at most $1",
+ "edt_msg_error_minimum_excl": "Value must be greater than $1",
+ "edt_msg_error_minimum_incl": "Value must be at least $1",
"edt_msg_error_minItems": "Value must have at least $1 items",
"edt_msg_error_minLength": "Value must be at least $1 characters long",
"edt_msg_error_minProperties": "Object must have at least $1 properties",
- "edt_msg_error_minimum_excl": "Value must be greater than $1",
- "edt_msg_error_minimum_incl": "Value must be at least $1",
"edt_msg_error_multipleOf": "Value must be a multiple of $1",
"edt_msg_error_not": "Value must not validate against the provided schema",
"edt_msg_error_notempty": "Value required",
@@ -698,6 +714,7 @@
"general_btn_off": "Off",
"general_btn_ok": "OK",
"general_btn_on": "On",
+ "general_btn_overwrite": "Overwrite",
"general_btn_rename": "Rename",
"general_btn_restarthyperion": "Restart Hyperion",
"general_btn_save": "Save",
@@ -745,20 +762,6 @@
"general_speech_zh-CN": "Chinese (simplified)",
"general_webui_title": "Hyperion - Web Configuration",
"general_wiki_moreto": "More information to \"$1\" at our Wiki",
- "infoDialog_checklist_title": "Checklist!",
- "infoDialog_effconf_created_text": "The effect \"$1\" has been created successfully!",
- "infoDialog_effconf_deleted_text": "The effect \"$1\" has been deleted successfully!",
- "infoDialog_general_error_title": "Error",
- "infoDialog_general_success_title": "Success",
- "infoDialog_general_warning_title": "Warning",
- "infoDialog_import_comperror_text": "Sad! Your browser doesn't support a import. Please try again with another browser.",
- "infoDialog_import_confirm_text": "Are you sure to import \"$1\"? This process can't be reverted!",
- "infoDialog_import_confirm_title": "Confirm import",
- "infoDialog_import_hyperror_text": "The selected configuration file \"$1\" can't be imported. It's not compatible with Hyperion 2.0 and higher!",
- "infoDialog_import_jsonerror_text": "The selected configuration file \"$1\" is no .json file or it's corrupted. Error message: ($2)",
- "infoDialog_wizrgb_text": "Your RGB Byte Order is already well adjusted.",
- "infoDialog_writeconf_error_text": "Saving your configuration failed.",
- "infoDialog_writeimage_error_text": "The selected file \"$1\" is no image file or it's corrupted! Please select another image file.",
"info_404": "The page you requested is not available!",
"info_conlost_label_autorecon": "We reconnect again after Hyperion is available.",
"info_conlost_label_autorefresh": "This page will be automatically refreshed.",
@@ -772,6 +775,31 @@
"info_restart_contusa": "...with your last steps. Thank you!",
"info_restart_rightback": "Hyperion will be right back immediately!",
"info_restart_title": "Restarts currently...",
+ "InfoDialog_access_text": "Depending on settings level you could adjust more options or get access to more features. Recommended is the \"Default\" level.",
+ "InfoDialog_access_title": "Settings level",
+ "InfoDialog_changePassword_success": "Password successfully saved!",
+ "InfoDialog_changePassword_title": "Change Password",
+ "infoDialog_checklist_title": "Checklist!",
+ "infoDialog_effconf_created_text": "The effect \"$1\" has been created successfully!",
+ "infoDialog_effconf_deleted_text": "The effect \"$1\" has been deleted successfully!",
+ "infoDialog_general_error_title": "Error",
+ "infoDialog_general_success_title": "Success",
+ "infoDialog_general_warning_title": "Warning",
+ "infoDialog_import_comperror_text": "Sad! Your browser doesn't support a import. Please try again with another browser.",
+ "infoDialog_import_confirm_text": "Are you sure to import \"$1\"? This process can't be reverted!",
+ "infoDialog_import_confirm_title": "Confirm import",
+ "infoDialog_import_hyperror_text": "The selected configuration file \"$1\" can't be imported. It's not compatible with Hyperion 2.0 and higher!",
+ "infoDialog_import_jsonerror_text": "The selected configuration file \"$1\" is no .json file or it's corrupted. Error message: ($2)",
+ "InfoDialog_iswitch_text": "If you run Hyperion more than once in your local network, you could switch between the web configurations. Select the Hyperion instance below and switch!",
+ "InfoDialog_iswitch_title": "Hyperion switcher",
+ "InfoDialog_lang_text": "If you don't like the result of the automatic language detection you could overwrite it here.",
+ "InfoDialog_lang_title": "Language setting",
+ "InfoDialog_nowrite_foottext": "The WebUI will be unlocked automatically after you solved the problem!",
+ "InfoDialog_nowrite_text": "Hyperion can't write to your current loaded configuration file. Please repair the file permissions to proceed.",
+ "InfoDialog_nowrite_title": "write permission error!",
+ "infoDialog_wizrgb_text": "Your RGB Byte Order is already well adjusted.",
+ "infoDialog_writeconf_error_text": "Saving your configuration failed.",
+ "infoDialog_writeimage_error_text": "The selected file \"$1\" is no image file or it's corrupted! Please select another image file.",
"main_ledsim_btn_togglelednumber": "LED numbers",
"main_ledsim_btn_toggleleds": "Show LEDs",
"main_ledsim_btn_togglelivevideo": "Live video",
diff --git a/assets/webconfig/index.html b/assets/webconfig/index.html
index 12854f57..3ed6fa9a 100644
--- a/assets/webconfig/index.html
+++ b/assets/webconfig/index.html
@@ -101,7 +101,7 @@
-
+
@@ -234,7 +234,7 @@
System
diff --git a/assets/webconfig/js/content_colors.js b/assets/webconfig/js/content_colors.js
old mode 100644
new mode 100755
index 87428047..3800cc26
--- a/assets/webconfig/js/content_colors.js
+++ b/assets/webconfig/js/content_colors.js
@@ -1,84 +1,80 @@
-$(document).ready( function() {
- performTranslation();
- var editor_color = null;
- var editor_smoothing = null;
- var editor_blackborder = null;
-
- if(window.showOptHelp)
- {
- //color
- $('#conf_cont').append(createRow('conf_cont_color'));
- $('#conf_cont_color').append(createOptPanel('fa-photo', $.i18n("edt_conf_color_heading_title"), 'editor_container_color', 'btn_submit_color'));
- $('#conf_cont_color').append(createHelpTable(window.schema.color.properties, $.i18n("edt_conf_color_heading_title")));
-
- //smoothing
- $('#conf_cont').append(createRow('conf_cont_smoothing'));
- $('#conf_cont_smoothing').append(createOptPanel('fa-photo', $.i18n("edt_conf_smooth_heading_title"), 'editor_container_smoothing', 'btn_submit_smoothing'));
- $('#conf_cont_smoothing').append(createHelpTable(window.schema.smoothing.properties, $.i18n("edt_conf_smooth_heading_title")));
-
- //blackborder
- $('#conf_cont').append(createRow('conf_cont_blackborder'));
- $('#conf_cont_blackborder').append(createOptPanel('fa-photo', $.i18n("edt_conf_bb_heading_title"), 'editor_container_blackborder', 'btn_submit_blackborder'));
- $('#conf_cont_blackborder').append(createHelpTable(window.schema.blackborderdetector.properties, $.i18n("edt_conf_bb_heading_title")));
- }
- else
- {
- $('#conf_cont').addClass('row');
- $('#conf_cont').append(createOptPanel('fa-photo', $.i18n("edt_conf_color_heading_title"), 'editor_container_color', 'btn_submit_color'));
- $('#conf_cont').append(createOptPanel('fa-photo', $.i18n("edt_conf_smooth_heading_title"), 'editor_container_smoothing', 'btn_submit_smoothing'));
- $('#conf_cont').append(createOptPanel('fa-photo', $.i18n("edt_conf_bb_heading_title"), 'editor_container_blackborder', 'btn_submit_blackborder'));
- }
-
- //color
- editor_color = createJsonEditor('editor_container_color', {
- color : window.schema.color
- }, true, true);
+$(document).ready(function () {
+ performTranslation();
+ var editor_color = null;
+ var editor_smoothing = null;
+ var editor_blackborder = null;
- editor_color.on('change',function() {
- editor_color.validate().length || window.readOnlyMode ? $('#btn_submit_color').attr('disabled', true) : $('#btn_submit_color').attr('disabled', false);
- });
-
- $('#btn_submit_color').off().on('click',function() {
- requestWriteConfig(editor_color.getValue());
- });
-
- //smoothing
- editor_smoothing = createJsonEditor('editor_container_smoothing', {
- smoothing : window.schema.smoothing
- }, true, true);
+ if (window.showOptHelp) {
+ //color
+ $('#conf_cont').append(createRow('conf_cont_color'));
+ $('#conf_cont_color').append(createOptPanel('fa-photo', $.i18n("edt_conf_color_heading_title"), 'editor_container_color', 'btn_submit_color'));
+ $('#conf_cont_color').append(createHelpTable(window.schema.color.properties, $.i18n("edt_conf_color_heading_title")));
- editor_smoothing.on('change',function() {
- editor_smoothing.validate().length || window.readOnlyMode ? $('#btn_submit_smoothing').attr('disabled', true) : $('#btn_submit_smoothing').attr('disabled', false);
-
- });
-
- $('#btn_submit_smoothing').off().on('click',function() {
- requestWriteConfig(editor_smoothing.getValue());
- });
+ //smoothing
+ $('#conf_cont').append(createRow('conf_cont_smoothing'));
+ $('#conf_cont_smoothing').append(createOptPanel('fa-photo', $.i18n("edt_conf_smooth_heading_title"), 'editor_container_smoothing', 'btn_submit_smoothing'));
+ $('#conf_cont_smoothing').append(createHelpTable(window.schema.smoothing.properties, $.i18n("edt_conf_smooth_heading_title")));
- //blackborder
- editor_blackborder = createJsonEditor('editor_container_blackborder', {
- blackborderdetector: window.schema.blackborderdetector
- }, true, true);
+ //blackborder
+ $('#conf_cont').append(createRow('conf_cont_blackborder'));
+ $('#conf_cont_blackborder').append(createOptPanel('fa-photo', $.i18n("edt_conf_bb_heading_title"), 'editor_container_blackborder', 'btn_submit_blackborder'));
+ $('#conf_cont_blackborder').append(createHelpTable(window.schema.blackborderdetector.properties, $.i18n("edt_conf_bb_heading_title")));
+ }
+ else {
+ $('#conf_cont').addClass('row');
+ $('#conf_cont').append(createOptPanel('fa-photo', $.i18n("edt_conf_color_heading_title"), 'editor_container_color', 'btn_submit_color'));
+ $('#conf_cont').append(createOptPanel('fa-photo', $.i18n("edt_conf_smooth_heading_title"), 'editor_container_smoothing', 'btn_submit_smoothing'));
+ $('#conf_cont').append(createOptPanel('fa-photo', $.i18n("edt_conf_bb_heading_title"), 'editor_container_blackborder', 'btn_submit_blackborder'));
+ }
- editor_blackborder.on('change',function() {
- editor_blackborder.validate().length || window.readOnlyMode ? $('#btn_submit_blackborder').attr('disabled', true) : $('#btn_submit_blackborder').attr('disabled', false);
- });
-
- $('#btn_submit_blackborder').off().on('click',function() {
- requestWriteConfig(editor_blackborder.getValue());
- });
-
- //wiki links
- $('#editor_container_blackborder').append(buildWL("user/moretopics/bbmode","edt_conf_bb_mode_title",true));
-
- //create introduction
- if(window.showOptHelp)
- {
- createHint("intro", $.i18n('conf_colors_color_intro'), "editor_container_color");
- createHint("intro", $.i18n('conf_colors_smoothing_intro'), "editor_container_smoothing");
- createHint("intro", $.i18n('conf_colors_blackborder_intro'), "editor_container_blackborder");
- }
-
- removeOverlay();
+ //color
+ editor_color = createJsonEditor('editor_container_color', {
+ color: window.schema.color
+ }, true, true);
+
+ editor_color.on('change', function () {
+ editor_color.validate().length || window.readOnlyMode ? $('#btn_submit_color').attr('disabled', true) : $('#btn_submit_color').attr('disabled', false);
+ });
+
+ $('#btn_submit_color').off().on('click', function () {
+ requestWriteConfig(editor_color.getValue());
+ });
+
+ //smoothing
+ editor_smoothing = createJsonEditor('editor_container_smoothing', {
+ smoothing: window.schema.smoothing
+ }, true, true);
+
+ editor_smoothing.on('change', function () {
+ editor_smoothing.validate().length || window.readOnlyMode ? $('#btn_submit_smoothing').attr('disabled', true) : $('#btn_submit_smoothing').attr('disabled', false);
+ });
+
+ $('#btn_submit_smoothing').off().on('click', function () {
+ requestWriteConfig(editor_smoothing.getValue());
+ });
+
+ //blackborder
+ editor_blackborder = createJsonEditor('editor_container_blackborder', {
+ blackborderdetector: window.schema.blackborderdetector
+ }, true, true);
+
+ editor_blackborder.on('change', function () {
+ editor_blackborder.validate().length || window.readOnlyMode ? $('#btn_submit_blackborder').attr('disabled', true) : $('#btn_submit_blackborder').attr('disabled', false);
+ });
+
+ $('#btn_submit_blackborder').off().on('click', function () {
+ requestWriteConfig(editor_blackborder.getValue());
+ });
+
+ //wiki links
+ $('#editor_container_blackborder').append(buildWL("user/advanced/Advanced.html#blackbar-detection", "edt_conf_bb_mode_title", true));
+
+ //create introduction
+ if (window.showOptHelp) {
+ createHint("intro", $.i18n('conf_colors_color_intro'), "editor_container_color");
+ createHint("intro", $.i18n('conf_colors_smoothing_intro'), "editor_container_smoothing");
+ createHint("intro", $.i18n('conf_colors_blackborder_intro'), "editor_container_blackborder");
+ }
+
+ removeOverlay();
});
diff --git a/assets/webconfig/js/content_index.js b/assets/webconfig/js/content_index.js
old mode 100644
new mode 100755
index c57f1626..c2263509
--- a/assets/webconfig/js/content_index.js
+++ b/assets/webconfig/js/content_index.js
@@ -1,354 +1,357 @@
var instNameInit = false
$(document).ready(function () {
+ var darkModeOverwrite = getStorage("darkModeOverwrite", true);
- var darkModeOverwrite = getStorage("darkModeOverwrite", true);
+ if (darkModeOverwrite == "false" || darkModeOverwrite == null) {
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ handleDarkMode();
+ }
- if(darkModeOverwrite == "false" || darkModeOverwrite == null)
- {
- if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
- handleDarkMode();
- }
-
- if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
- setStorage("darkMode", "off", false);
- }
- }
-
- if(getStorage("darkMode", false) == "on")
- {
- handleDarkMode();
- }
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
+ setStorage("darkMode", "off", false);
+ }
+ }
- loadContentTo("#container_connection_lost", "connection_lost");
- loadContentTo("#container_restart", "restart");
- initWebSocket();
+ if (getStorage("darkMode", false) == "on") {
+ handleDarkMode();
+ }
- $(window.hyperion).on("cmd-serverinfo", function (event) {
- window.serverInfo = event.response.info;
-
- window.readOnlyMode = window.sysInfo.hyperion.readOnlyMode;
-
- // comps
- window.comps = event.response.info.components
+ loadContentTo("#container_connection_lost", "connection_lost");
+ loadContentTo("#container_restart", "restart");
+ initWebSocket();
- $(window.hyperion).trigger("ready");
+ $(window.hyperion).on("cmd-serverinfo", function (event) {
+ window.serverInfo = event.response.info;
- window.comps.forEach(function (obj) {
- if (obj.name == "ALL") {
- if (obj.enabled)
- $("#hyperion_disabled_notify").fadeOut("fast");
- else
- $("#hyperion_disabled_notify").fadeIn("fast");
- }
- });
+ window.readOnlyMode = window.sysInfo.hyperion.readOnlyMode;
- // determine button visibility
- var running = window.serverInfo.instance.filter(entry => entry.running);
- if (running.length > 1)
- $('#btn_hypinstanceswitch').toggle(true)
- else
- $('#btn_hypinstanceswitch').toggle(false)
- // update listing at button
- updateHyperionInstanceListing()
- if (!instNameInit) {
- window.currentHyperionInstanceName = getInstanceNameByIndex(0);
- instNameInit = true;
- }
+ // comps
+ window.comps = event.response.info.components
- updateSessions();
- }); // end cmd-serverinfo
+ $(window.hyperion).trigger("ready");
- // Update language selection
- $("#language-select").on('changed.bs.select',function (e, clickedIndex, isSelected, previousValue){
- var newLang = availLang[clickedIndex-1];
- if (newLang !== storedLang)
- {
- setStorage("langcode", newLang);
- reload();
- }
- });
+ window.comps.forEach(function (obj) {
+ if (obj.name == "ALL") {
+ if (obj.enabled)
+ $("#hyperion_disabled_notify").fadeOut("fast");
+ else
+ $("#hyperion_disabled_notify").fadeIn("fast");
+ }
+ });
- $("#language-select").selectpicker(
- {
- container: 'body'
- });
+ // determine button visibility
+ var running = window.serverInfo.instance.filter(entry => entry.running);
+ if (running.length > 1)
+ $('#btn_hypinstanceswitch').toggle(true)
+ else
+ $('#btn_hypinstanceswitch').toggle(false)
+ // update listing at button
+ updateHyperionInstanceListing()
+ if (!instNameInit) {
+ window.currentHyperionInstanceName = getInstanceNameByIndex(0);
+ instNameInit = true;
+ }
- $(".bootstrap-select").click(function () {
- $(this).addClass("open");
- });
+ updateSessions();
+ }); // end cmd-serverinfo
- $(document).click(function(){
- $(".bootstrap-select").removeClass("open");
- });
+ // Update language selection
+ $("#language-select").on('changed.bs.select', function (e, clickedIndex, isSelected, previousValue) {
+ var newLang = availLang[clickedIndex - 1];
+ if (newLang !== storedLang) {
+ setStorage("langcode", newLang);
+ reload();
+ }
+ });
- $(".bootstrap-select").click(function(e){
- e.stopPropagation();
- });
-
- //End language selection
-
- $(window.hyperion).on("cmd-sessions-update", function (event) {
- window.serverInfo.sessions = event.response.data;
- updateSessions();
- });
+ $("#language-select").selectpicker(
+ {
+ container: 'body'
+ });
- $(window.hyperion).on("cmd-authorize-tokenRequest cmd-authorize-getPendingTokenRequests", function (event) {
- var val = event.response.info;
- if (Array.isArray(event.response.info)) {
- if (event.response.info.length == 0) {
- return
- }
- val = event.response.info[0]
- if (val.comment == '')
- $('#modal_dialog').modal('hide');
- }
+ $(".bootstrap-select").click(function () {
+ $(this).addClass("open");
+ });
- showInfoDialog("grantToken", $.i18n('conf_network_tok_grantT'), $.i18n('conf_network_tok_grantMsg') + 'App: ' + val.comment + ' Code: ' + val.id + ' ')
- $("#tok_grant_acc").off().on('click', function () {
- tokenList.push(val)
- // forward event, in case we need to rebuild the list now
- $(window.hyperion).trigger({ type: "build-token-list" });
- requestHandleTokenRequest(val.id, true)
- });
- $("#tok_deny_acc").off().on('click', function () {
- requestHandleTokenRequest(val.id, false)
- });
- });
+ $(document).click(function () {
+ $(".bootstrap-select").removeClass("open");
+ });
- $(window.hyperion).one("cmd-authorize-getTokenList", function (event) {
- tokenList = event.response.info;
- requestServerInfo();
- });
+ $(".bootstrap-select").click(function (e) {
+ e.stopPropagation();
+ });
- $(window.hyperion).on("cmd-sysinfo", function (event) {
- requestServerInfo();
- window.sysInfo = event.response.info;
+ //End language selection
- window.currentVersion = window.sysInfo.hyperion.version;
- window.currentChannel = window.sysInfo.hyperion.channel;
- });
+ $(window.hyperion).on("cmd-sessions-update", function (event) {
+ window.serverInfo.sessions = event.response.data;
+ updateSessions();
+ });
- $(window.hyperion).one("cmd-config-getschema", function (event) {
- window.serverSchema = event.response.info;
- requestServerConfig();
+ $(window.hyperion).on("cmd-authorize-tokenRequest cmd-authorize-getPendingTokenRequests", function (event) {
+ var val = event.response.info;
+ if (Array.isArray(event.response.info)) {
+ if (event.response.info.length == 0) {
+ return
+ }
+ val = event.response.info[0]
+ if (val.comment == '')
+ $('#modal_dialog').modal('hide');
+ }
+
+ showInfoDialog("grantToken", $.i18n('conf_network_tok_grantT'), $.i18n('conf_network_tok_grantMsg') + 'App: ' + val.comment + ' Code: ' + val.id + ' ')
+ $("#tok_grant_acc").off().on('click', function () {
+ tokenList.push(val)
+ // forward event, in case we need to rebuild the list now
+ $(window.hyperion).trigger({ type: "build-token-list" });
+ requestHandleTokenRequest(val.id, true)
+ });
+ $("#tok_deny_acc").off().on('click', function () {
+ requestHandleTokenRequest(val.id, false)
+ });
+ });
+
+ $(window.hyperion).one("cmd-authorize-getTokenList", function (event) {
+ tokenList = event.response.info;
+ requestServerInfo();
+ });
+
+ $(window.hyperion).on("cmd-sysinfo", function (event) {
+ requestServerInfo();
+ window.sysInfo = event.response.info;
+
+ window.currentVersion = window.sysInfo.hyperion.version;
+ window.currentChannel = window.sysInfo.hyperion.channel;
+ });
+
+ $(window.hyperion).one("cmd-config-getschema", function (event) {
+ window.serverSchema = event.response.info;
+ requestServerConfig();
requestTokenInfo();
requestGetPendingTokenRequests();
- window.schema = window.serverSchema.properties;
- });
+ window.schema = window.serverSchema.properties;
+ });
- $(window.hyperion).on("cmd-config-getconfig", function (event) {
- window.serverConfig = event.response.info;
- requestSysInfo();
+ $(window.hyperion).on("cmd-config-getconfig", function (event) {
+ window.serverConfig = event.response.info;
+ requestSysInfo();
- window.showOptHelp = window.serverConfig.general.showOptHelp;
- });
+ window.showOptHelp = window.serverConfig.general.showOptHelp;
+ });
- $(window.hyperion).on("cmd-config-setconfig", function (event) {
- if (event.response.success === true) {
- showNotification('success', $.i18n('dashboard_alert_message_confsave_success'), $.i18n('dashboard_alert_message_confsave_success_t'))
- }
- });
+ $(window.hyperion).on("cmd-config-setconfig", function (event) {
+ if (event.response.success === true) {
+ showNotification('success', $.i18n('dashboard_alert_message_confsave_success'), $.i18n('dashboard_alert_message_confsave_success_t'))
+ }
+ });
- $(window.hyperion).on("cmd-authorize-login", function (event) {
- $("#main-nav").removeAttr('style')
- $("#top-navbar").removeAttr('style')
+ $(window.hyperion).on("cmd-authorize-login", function (event) {
+ $("#main-nav").removeAttr('style')
+ $("#top-navbar").removeAttr('style')
- if (window.defaultPasswordIsSet === true && getStorage("suppressDefaultPwWarning") !== "true" )
- {
- var supprPwWarnCheckbox = ''+$.i18n('dashboard_message_do_not_show_again')
- + '
'
- showNotification('warning', $.i18n('dashboard_message_default_password'), $.i18n('dashboard_message_default_password_t'), ''
- + $.i18n('InfoDialog_changePassword_title') + ' ' + supprPwWarnCheckbox)
- }
- else
- //if logged on and pw != default show option to lock ui
- $("#btn_lock_ui").removeAttr('style')
+ if (window.defaultPasswordIsSet === true && getStorage("suppressDefaultPwWarning") !== "true") {
+ var supprPwWarnCheckbox = '' + $.i18n('dashboard_message_do_not_show_again')
+ + '
'
+ showNotification('warning', $.i18n('dashboard_message_default_password'), $.i18n('dashboard_message_default_password_t'), ''
+ + $.i18n('InfoDialog_changePassword_title') + ' ' + supprPwWarnCheckbox)
+ }
+ else
+ //if logged on and pw != default show option to lock ui
+ $("#btn_lock_ui").removeAttr('style')
+ if (event.response.hasOwnProperty('info'))
+ setStorage("loginToken", event.response.info.token, true);
- if (event.response.hasOwnProperty('info'))
- setStorage("loginToken", event.response.info.token, true);
+ requestServerConfigSchema();
+ });
- requestServerConfigSchema();
- });
+ $(window.hyperion).on("cmd-authorize-newPassword", function (event) {
+ if (event.response.success === true) {
+ showInfoDialog("success", $.i18n('InfoDialog_changePassword_success'));
+ // not necessarily true, but better than nothing
+ window.defaultPasswordIsSet = false;
+ }
+ });
- $(window.hyperion).on("cmd-authorize-newPassword", function (event) {
- if (event.response.success === true) {
- showInfoDialog("success", $.i18n('InfoDialog_changePassword_success'));
- // not necessarily true, but better than nothing
- window.defaultPasswordIsSet = false;
- }
- });
+ $(window.hyperion).on("cmd-authorize-newPasswordRequired", function (event) {
+ var loginToken = getStorage("loginToken", true)
- $(window.hyperion).on("cmd-authorize-newPasswordRequired", function (event) {
- var loginToken = getStorage("loginToken", true)
+ if (event.response.info.newPasswordRequired == true) {
+ window.defaultPasswordIsSet = true;
- if (event.response.info.newPasswordRequired == true) {
- window.defaultPasswordIsSet = true;
+ if (loginToken)
+ requestTokenAuthorization(loginToken)
+ else
+ requestAuthorization('hyperion');
+ }
+ else {
+ $("#main-nav").attr('style', 'display:none')
+ $("#top-navbar").attr('style', 'display:none')
- if (loginToken)
- requestTokenAuthorization(loginToken)
- else
- requestAuthorization('hyperion');
- }
- else {
- $("#main-nav").attr('style', 'display:none')
- $("#top-navbar").attr('style', 'display:none')
+ if (loginToken)
+ requestTokenAuthorization(loginToken)
+ else
+ loadContentTo("#page-content", "login")
+ }
+ });
- if (loginToken)
- requestTokenAuthorization(loginToken)
- else
- loadContentTo("#page-content", "login")
- }
- });
+ $(window.hyperion).on("cmd-authorize-adminRequired", function (event) {
+ //Check if a admin login is required.
+ //If yes: check if default pw is set. If no: go ahead to get server config and render page
+ if (event.response.info.adminRequired === true)
+ requestRequiresDefaultPasswortChange();
+ else
+ requestServerConfigSchema();
+ });
- $(window.hyperion).on("cmd-authorize-adminRequired", function (event) {
- //Check if a admin login is required.
- //If yes: check if default pw is set. If no: go ahead to get server config and render page
- if (event.response.info.adminRequired === true)
- requestRequiresDefaultPasswortChange();
- else
- requestServerConfigSchema();
- });
+ $(window.hyperion).on("error", function (event) {
+ //If we are getting an error "No Authorization" back with a set loginToken we will forward to new Login (Token is expired.
+ //e.g.: hyperiond was started new in the meantime)
+ if (event.reason == "No Authorization" && getStorage("loginToken", true)) {
+ removeStorage("loginToken", true);
+ requestRequiresAdminAuth();
+ }
+ else {
+ showInfoDialog("error", "Error", event.reason);
+ }
+ });
- $(window.hyperion).on("error", function (event) {
- //If we are getting an error "No Authorization" back with a set loginToken we will forward to new Login (Token is expired.
- //e.g.: hyperiond was started new in the meantime)
- if (event.reason == "No Authorization" && getStorage("loginToken", true)) {
- removeStorage("loginToken", true);
- requestRequiresAdminAuth();
- }
- else {
- showInfoDialog("error", "Error", event.reason);
- }
- });
+ $(window.hyperion).on("open", function (event) {
+ requestRequiresAdminAuth();
+ });
- $(window.hyperion).on("open", function (event) {
- requestRequiresAdminAuth();
- });
+ $(window.hyperion).one("ready", function (event) {
+ loadContent();
+ });
- $(window.hyperion).one("ready", function (event) {
- loadContent();
- });
+ $(window.hyperion).on("cmd-adjustment-update", function (event) {
+ window.serverInfo.adjustment = event.response.data
+ });
- $(window.hyperion).on("cmd-adjustment-update", function (event) {
- window.serverInfo.adjustment = event.response.data
- });
+ $(window.hyperion).on("cmd-videomode-update", function (event) {
+ window.serverInfo.videomode = event.response.data.videomode
+ });
- $(window.hyperion).on("cmd-videomode-update", function (event) {
- window.serverInfo.videomode = event.response.data.videomode
- });
+ $(window.hyperion).on("cmd-components-update", function (event) {
+ let obj = event.response.data
- $(window.hyperion).on("cmd-components-update", function (event) {
- let obj = event.response.data
+ // notfication in index
+ if (obj.name == "ALL") {
+ if (obj.enabled)
+ $("#hyperion_disabled_notify").fadeOut("fast");
+ else
+ $("#hyperion_disabled_notify").fadeIn("fast");
+ }
- // notfication in index
- if (obj.name == "ALL") {
- if (obj.enabled)
- $("#hyperion_disabled_notify").fadeOut("fast");
- else
- $("#hyperion_disabled_notify").fadeIn("fast");
- }
+ window.comps.forEach((entry, index) => {
+ if (entry.name === obj.name) {
+ window.comps[index] = obj;
+ }
+ });
+ // notify the update
+ $(window.hyperion).trigger("components-updated", event.response.data);
+ });
- window.comps.forEach((entry, index) => {
- if (entry.name === obj.name) {
- window.comps[index] = obj;
- }
- });
- // notify the update
- $(window.hyperion).trigger("components-updated", event.response.data);
- });
+ $(window.hyperion).on("cmd-instance-update", function (event) {
+ window.serverInfo.instance = event.response.data
+ var avail = event.response.data;
+ // notify the update
+ $(window.hyperion).trigger("instance-updated");
- $(window.hyperion).on("cmd-instance-update", function (event) {
- window.serverInfo.instance = event.response.data
- var avail = event.response.data;
- // notify the update
- $(window.hyperion).trigger("instance-updated");
+ // if our current instance is no longer available we are at instance 0 again.
+ var isInData = false;
+ for (var key in avail) {
+ if (avail[key].instance == currentHyperionInstance && avail[key].running) {
+ isInData = true;
+ }
+ }
- // if our current instance is no longer available we are at instance 0 again.
- var isInData = false;
- for (var key in avail) {
- if (avail[key].instance == currentHyperionInstance && avail[key].running) {
- isInData = true;
- }
- }
+ if (!isInData) {
+ //Delete Storage information about the last used but now stopped instance
+ if (getStorage('lastSelectedInstance', false))
+ removeStorage('lastSelectedInstance', false)
- if (!isInData) {
- //Delete Storage information about the last used but now stopped instance
- if (getStorage('lastSelectedInstance', false))
- removeStorage('lastSelectedInstance', false)
+ currentHyperionInstance = 0;
+ currentHyperionInstanceName = getInstanceNameByIndex(0);
+ requestServerConfig();
+ setTimeout(requestServerInfo, 100)
+ setTimeout(requestTokenInfo, 200)
+ setTimeout(loadContent, 300, undefined, true)
+ }
- currentHyperionInstance = 0;
- currentHyperionInstanceName = getInstanceNameByIndex(0);
- requestServerConfig();
- setTimeout(requestServerInfo, 100)
- setTimeout(requestTokenInfo, 200)
- setTimeout(loadContent, 300, undefined, true)
- }
+ // determine button visibility
+ var running = serverInfo.instance.filter(entry => entry.running);
+ if (running.length > 1)
+ $('#btn_hypinstanceswitch').toggle(true)
+ else
+ $('#btn_hypinstanceswitch').toggle(false)
- // determine button visibility
- var running = serverInfo.instance.filter(entry => entry.running);
- if (running.length > 1)
- $('#btn_hypinstanceswitch').toggle(true)
- else
- $('#btn_hypinstanceswitch').toggle(false)
+ // update listing for button
+ updateHyperionInstanceListing()
+ });
- // update listing for button
- updateHyperionInstanceListing()
- });
+ $(window.hyperion).on("cmd-instance-switchTo", function (event) {
+ requestServerConfig();
+ setTimeout(requestServerInfo, 200)
+ setTimeout(requestTokenInfo, 400)
+ setTimeout(loadContent, 400, undefined, true)
+ });
- $(window.hyperion).on("cmd-instance-switchTo", function (event) {
- requestServerConfig();
- setTimeout(requestServerInfo, 200)
- setTimeout(requestTokenInfo, 400)
- setTimeout(loadContent, 400, undefined, true)
- });
-
- $(window.hyperion).on("cmd-effects-update", function (event) {
- window.serverInfo.effects = event.response.data.effects
- });
-
- $(".mnava").bind('click.menu', function (e) {
- loadContent(e);
- window.scrollTo(0, 0);
- });
+ $(window.hyperion).on("cmd-effects-update", function (event) {
+ window.serverInfo.effects = event.response.data.effects
+ });
+ $(".mnava").bind('click.menu', function (e) {
+ loadContent(e);
+ window.scrollTo(0, 0);
+ });
});
-function suppressDefaultPwWarning(){
-
- if (document.getElementById('chk_suppressDefaultPw').checked)
- setStorage("suppressDefaultPwWarning", "true");
- else
- setStorage("suppressDefaultPwWarning", "false");
+function suppressDefaultPwWarning() {
+ if (document.getElementById('chk_suppressDefaultPw').checked)
+ setStorage("suppressDefaultPwWarning", "true");
+ else
+ setStorage("suppressDefaultPwWarning", "false");
}
$(function () {
- var sidebar = $('#side-menu'); // cache sidebar to a variable for performance
- sidebar.delegate('a.inactive', 'click', function () {
- sidebar.find('.active').toggleClass('active inactive');
- $(this).toggleClass('active inactive');
- });
+ var sidebar = $('#side-menu'); // cache sidebar to a variable for performance
+ sidebar.delegate('a.inactive', 'click', function () {
+ sidebar.find('.active').toggleClass('active inactive');
+ $(this).toggleClass('active inactive');
+ });
});
// hotfix body padding when bs modals overlap
$(document.body).on('hide.bs.modal,hidden.bs.modal', function () {
- $('body').css('padding-right', '0');
+ $('body').css('padding-right', '0');
});
//Dark Mode
-$("#btn_darkmode").off().on("click",function(e){
-
- if(getStorage("darkMode", false) != "on")
- {
- handleDarkMode();
- setStorage("darkModeOverwrite", true, true);
- }
- else {
- setStorage("darkMode", "off", false);
- setStorage("darkModeOverwrite", true, true);
- location.reload();
- }
-
+$("#btn_darkmode").off().on("click", function (e) {
+ if (getStorage("darkMode", false) != "on") {
+ handleDarkMode();
+ setStorage("darkModeOverwrite", true, true);
+ }
+ else {
+ setStorage("darkMode", "off", false);
+ setStorage("darkModeOverwrite", true, true);
+ location.reload();
+ }
+
});
+
+// Menuitem toggle;
+function SwitchToMenuItem(target) {
+ document.getElementById(target).click(); // Get '+((led.name) ? led.name : idx)+' ';
- }
- $('#leds_preview').html(leds_html);
- $('#ledc_0').css({"background-color":"black","z-index":"12"});
- $('#ledc_1').css({"background-color":"grey","z-index":"11"});
- $('#ledc_2').css({"background-color":"#A9A9A9","z-index":"10"});
-
- if($('#leds_prev_toggle_num').hasClass('btn-success'))
- $('.led_prev_num').css("display", "inline");
-
- // update ace Editor content
- aceEdt.set(finalLedArray);
+ var leds_html = "";
+ for (var idx = 0; idx < leds.length; idx++) {
+ var led = leds[idx];
+ var led_id = 'ledc_' + [idx];
+ var bgcolor = "background-color:hsla(" + (idx * 360 / leds.length) + ",100%,50%,0.75);";
+ var pos = "left:" + (led.hmin * canvas_width) + "px;" +
+ "top:" + (led.vmin * canvas_height) + "px;" +
+ "width:" + ((led.hmax - led.hmin) * (canvas_width - 1)) + "px;" +
+ "height:" + ((led.vmax - led.vmin) * (canvas_height - 1)) + "px;";
+ leds_html += '' + ((led.name) ? led.name : idx) + '
';
+ }
+ $('#leds_preview').html(leds_html);
+ $('#ledc_0').css({ "background-color": "black", "z-index": "12" });
+ $('#ledc_1').css({ "background-color": "grey", "z-index": "11" });
+ $('#ledc_2').css({ "background-color": "#A9A9A9", "z-index": "10" });
+ if ($('#leds_prev_toggle_num').hasClass('btn-success'))
+ $('.led_prev_num').css("display", "inline");
}
-function createClassicLedLayoutSimple( ledstop,ledsleft,ledsright,ledsbottom,position,reverse ){
+function createClassicLedLayoutSimple(ledstop, ledsleft, ledsright, ledsbottom, position, reverse) {
+ let params = {
+ ledstop: 0, ledsleft: 0, ledsright: 0, ledsbottom: 0,
+ ledsglength: 0, ledsgpos: 0, position: 0,
+ ledsHDepth: 0.08, ledsVDepth: 0.05, overlap: 0,
+ edgeVGap: 0,
+ ptblh: 0, ptblv: 1, ptbrh: 1, ptbrv: 1,
+ pttlh: 0, pttlv: 0, pttrh: 1, pttrv: 0,
+ reverse: false
+ };
- let params = {
- ledstop: 0, ledsleft: 0, ledsright: 0, ledsbottom: 0,
- ledsglength: 0, ledsgpos: 0, position: 0,
- ledsHDepth: 0.08, ledsVDepth: 0.05, overlap: 0,
- edgeVGap: 0,
- ptblh: 0, ptblv: 1, ptbrh: 1, ptbrv: 1,
- pttlh: 0, pttlv: 0, pttrh: 1, pttrv: 0,
- reverse:false
- };
-
- params.ledstop = ledstop;
- params.ledsleft = ledsleft;
- params.ledsright = ledsright;
- params.ledsbottom = ledsbottom;
- params.position = position;
- params.reverse = reverse;
+ params.ledstop = ledstop;
+ params.ledsleft = ledsleft;
+ params.ledsright = ledsright;
+ params.ledsbottom = ledsbottom;
+ params.position = position;
+ params.reverse = reverse;
- return createClassicLedLayout( params );
+ return createClassicLedLayout(params);
}
-function createClassicLedLayout( params ){
+function createClassicLedLayout(params) {
+ var edgeHGap = params.edgeVGap / (16 / 9);
+ var ledArray = [];
- //helper
- var edgeHGap = params.edgeVGap/(16/9);
- var ledArray = [];
+ function createFinalArray(array) {
+ var finalLedArray = [];
+ for (var i = 0; i < array.length; i++) {
+ var hmin = array[i].hmin;
+ var hmax = array[i].hmax;
+ var vmin = array[i].vmin;
+ var vmax = array[i].vmax;
+ finalLedArray[i] = { "hmax": hmax, "hmin": hmin, "vmax": vmax, "vmin": vmin }
+ }
+ return finalLedArray;
+ }
- function createFinalArray(array){
- var finalLedArray = [];
- for(var i = 0; i 0) {
+ while (times--) {
+ array.push(array.shift())
+ }
+ return array;
+ }
+ else {
+ while (times++) {
+ array.unshift(array.pop())
+ }
+ return array;
+ }
+ }
- function rotateArray(array, times){
- if (times > 0){
- while( times-- ){
- array.push(array.shift())
- }
- return array;
- }
- else
- {
- while( times++ ){
- array.unshift(array.pop())
- }
- return array;
- }
- }
+ function valScan(val) {
+ if (val > 1)
+ return 1;
+ if (val < 0)
+ return 0;
+ return val;
+ }
- function valScan(val)
- {
- if(val > 1)
- return 1;
- if(val < 0)
- return 0;
- return val;
- }
+ function ovl(scan, val) {
+ if (scan == "+")
+ return valScan(val += params.overlap);
+ else
+ return valScan(val -= params.overlap);
+ }
- function ovl(scan,val)
- {
- if(scan == "+")
- return valScan(val += params.overlap);
- else
- return valScan(val -= params.overlap);
- }
+ function createLedArray(hmin, hmax, vmin, vmax) {
+ hmin = round(hmin);
+ hmax = round(hmax);
+ vmin = round(vmin);
+ vmax = round(vmax);
+ ledArray.push({ "hmin": hmin, "hmax": hmax, "vmin": vmin, "vmax": vmax });
+ }
- function createLedArray(hmin, hmax, vmin, vmax){
- hmin = round(hmin);
- hmax = round(hmax);
- vmin = round(vmin);
- vmax = round(vmax);
- ledArray.push({ "hmin": hmin, "hmax": hmax, "vmin": vmin, "vmax": vmax });
- }
+ function createTopLeds() {
+ var steph = (params.pttrh - params.pttlh - (2 * edgeHGap)) / params.ledstop;
+ var stepv = (params.pttrv - params.pttlv) / params.ledstop;
- function createTopLeds(){
- var steph = (params.pttrh - params.pttlh - (2*edgeHGap))/params.ledstop;
- var stepv = (params.pttrv - params.pttlv)/params.ledstop;
+ for (var i = 0; i < params.ledstop; i++) {
+ var hmin = ovl("-", params.pttlh + (steph * Number([i])) + edgeHGap);
+ var hmax = ovl("+", params.pttlh + (steph * Number([i + 1])) + edgeHGap);
+ var vmin = params.pttlv + (stepv * Number([i]));
+ var vmax = vmin + params.ledsHDepth;
+ createLedArray(hmin, hmax, vmin, vmax);
+ }
+ }
- for (var i = 0; i -1; i--) {
+ var hmin = ovl("-", params.ptblh + (steph * Number([i])) + edgeHGap);
+ var hmax = ovl("+", params.ptblh + (steph * Number([i + 1])) + edgeHGap);
+ var vmax = params.ptblv + (stepv * Number([i]));
+ var vmin = vmax - params.ledsHDepth;
+ createLedArray(hmin, hmax, vmin, vmax);
+ }
+ }
- for (var i = params.ledsbottom-1; i>-1; i--){
- var hmin = ovl("-",params.ptblh+(steph*Number([i]))+edgeHGap);
- var hmax = ovl("+",params.ptblh+(steph*Number([i+1]))+edgeHGap);
- var vmax= params.ptblv+(stepv*Number([i]));
- var vmin = vmax-params.ledsHDepth;
- createLedArray(hmin, hmax, vmin, vmax);
- }
- }
+ function createLeftLeds() {
+ var steph = (params.ptblh - params.pttlh) / params.ledsleft;
+ var stepv = (params.ptblv - params.pttlv - (2 * params.edgeVGap)) / params.ledsleft;
- function createLeftLeds(){
- var steph = (params.ptblh - params.pttlh)/params.ledsleft;
- var stepv = (params.ptblv - params.pttlv - (2*params.edgeVGap))/params.ledsleft;
+ for (var i = params.ledsleft - 1; i > -1; i--) {
+ var hmin = params.pttlh + (steph * Number([i]));
+ var hmax = hmin + params.ledsVDepth;
+ var vmin = ovl("-", params.pttlv + (stepv * Number([i])) + params.edgeVGap);
+ var vmax = ovl("+", params.pttlv + (stepv * Number([i + 1])) + params.edgeVGap);
+ createLedArray(hmin, hmax, vmin, vmax);
+ }
+ }
- for (var i = params.ledsleft-1; i>-1; i--){
- var hmin = params.pttlh+(steph*Number([i]));
- var hmax = hmin+params.ledsVDepth;
- var vmin = ovl("-",params.pttlv+(stepv*Number([i]))+params.edgeVGap);
- var vmax = ovl("+",params.pttlv+(stepv*Number([i+1]))+params.edgeVGap);
- createLedArray(hmin, hmax, vmin, vmax);
- }
+ //rectangle
+ createTopLeds();
+ createRightLeds();
+ createBottomLeds();
+ createLeftLeds();
- }
+ //check led gap pos
+ if (params.ledsgpos + params.ledsglength > ledArray.length) {
+ var mpos = Math.max(0, ledArray.length - params.ledsglength);
+ //$('#ip_cl_ledsgpos').val(mpos);
+ ledsgpos = mpos;
+ }
- //rectangle
- createTopLeds();
- createRightLeds();
- createBottomLeds();
- createLeftLeds();
-
- //check led gap pos
- if (params.ledsgpos+params.ledsglength > ledArray.length)
- {
- var mpos = Math.max(0,ledArray.length-params.ledsglength);
- //$('#ip_cl_ledsgpos').val(mpos);
- ledsgpos = mpos;
- }
+ //check led gap length
+ if (params.ledsglength >= ledArray.length) {
+ //$('#ip_cl_ledsglength').val(ledArray.length-1);
+ params.ledsglength = ledArray.length - params.ledsglength - 1;
+ }
- //check led gap length
- if(params.ledsglength >= ledArray.length)
- {
- //$('#ip_cl_ledsglength').val(ledArray.length-1);
- params.ledsglength = ledArray.length-params.ledsglength-1;
- }
+ if (params.ledsglength != 0) {
+ ledArray.splice(params.ledsgpos, params.ledsglength);
+ }
- if(params.ledsglength != 0){
- ledArray.splice(params.ledsgpos, params.ledsglength);
- }
+ if (params.position != 0) {
+ rotateArray(ledArray, params.position);
+ }
- if (params.position != 0){
- rotateArray(ledArray, params.position);
- }
+ if (params.reverse)
+ ledArray.reverse();
- if (params.reverse)
- ledArray.reverse();
-
- return createFinalArray(ledArray);
+ return createFinalArray(ledArray);
}
-function createClassicLeds(){
-
- //get values
- let params = {
- ledstop : parseInt($("#ip_cl_top").val()),
- ledsbottom : parseInt($("#ip_cl_bottom").val()),
- ledsleft : parseInt($("#ip_cl_left").val()),
- ledsright : parseInt($("#ip_cl_right").val()),
- ledsglength : parseInt($("#ip_cl_glength").val()),
- ledsgpos : parseInt($("#ip_cl_gpos").val()),
- position : parseInt($("#ip_cl_position").val()),
- reverse : $("#ip_cl_reverse").is(":checked"),
+function createClassicLeds() {
+ //get values
+ let params = {
+ ledstop: parseInt($("#ip_cl_top").val()),
+ ledsbottom: parseInt($("#ip_cl_bottom").val()),
+ ledsleft: parseInt($("#ip_cl_left").val()),
+ ledsright: parseInt($("#ip_cl_right").val()),
+ ledsglength: parseInt($("#ip_cl_glength").val()),
+ ledsgpos: parseInt($("#ip_cl_gpos").val()),
+ position: parseInt($("#ip_cl_position").val()),
+ reverse: $("#ip_cl_reverse").is(":checked"),
- //advanced values
- ledsVDepth : parseInt($("#ip_cl_vdepth").val())/100,
- ledsHDepth : parseInt($("#ip_cl_hdepth").val())/100,
- edgeVGap : parseInt($("#ip_cl_edgegap").val())/100/2,
- //cornerVGap : parseInt($("#ip_cl_cornergap").val())/100/2,
- overlap : $("#ip_cl_overlap").val()/100,
+ //advanced values
+ ledsVDepth: parseInt($("#ip_cl_vdepth").val()) / 100,
+ ledsHDepth: parseInt($("#ip_cl_hdepth").val()) / 100,
+ edgeVGap: parseInt($("#ip_cl_edgegap").val()) / 100 / 2,
+ //cornerVGap : parseInt($("#ip_cl_cornergap").val())/100/2,
+ overlap: $("#ip_cl_overlap").val() / 100,
- //trapezoid values % -> float
- ptblh : parseInt($("#ip_cl_pblh").val())/100,
- ptblv : parseInt($("#ip_cl_pblv").val())/100,
- ptbrh : parseInt($("#ip_cl_pbrh").val())/100,
- ptbrv : parseInt($("#ip_cl_pbrv").val())/100,
- pttlh : parseInt($("#ip_cl_ptlh").val())/100,
- pttlv : parseInt($("#ip_cl_ptlv").val())/100,
- pttrh : parseInt($("#ip_cl_ptrh").val())/100,
- pttrv : parseInt($("#ip_cl_ptrv").val())/100,
- }
-
- finalLedArray = createClassicLedLayout( params );
-
- //check led gap pos
- if (params.ledsgpos+params.ledsglength > finalLedArray.length) {
- var mpos = Math.max(0,finalLedArray.length-params.ledsglength);
- $('#ip_cl_ledsgpos').val(mpos);
- }
- //check led gap length
- if(params.ledsglength >= finalLedArray.length) {
- $('#ip_cl_ledsglength').val(finalLedArray.length-1);
- }
-
- createLedPreview(finalLedArray, 'classic');
+ //trapezoid values % -> float
+ ptblh: parseInt($("#ip_cl_pblh").val()) / 100,
+ ptblv: parseInt($("#ip_cl_pblv").val()) / 100,
+ ptbrh: parseInt($("#ip_cl_pbrh").val()) / 100,
+ ptbrv: parseInt($("#ip_cl_pbrv").val()) / 100,
+ pttlh: parseInt($("#ip_cl_ptlh").val()) / 100,
+ pttlv: parseInt($("#ip_cl_ptlv").val()) / 100,
+ pttrh: parseInt($("#ip_cl_ptrh").val()) / 100,
+ pttrv: parseInt($("#ip_cl_ptrv").val()) / 100,
+ }
+
+ nonBlacklistLedArray = createClassicLedLayout(params);
+ finalLedArray = blackListLeds(nonBlacklistLedArray, ledBlacklist);
+
+ //check led gap pos
+ if (params.ledsgpos + params.ledsglength > finalLedArray.length) {
+ var mpos = Math.max(0, finalLedArray.length - params.ledsglength);
+ $('#ip_cl_ledsgpos').val(mpos);
+ }
+ //check led gap length
+ if (params.ledsglength >= finalLedArray.length) {
+ $('#ip_cl_ledsglength').val(finalLedArray.length - 1);
+ }
+
+ createLedPreview(finalLedArray, 'classic');
+ aceEdt.set(finalLedArray);
}
+function createMatrixLayout(ledshoriz, ledsvert, cabling, start) {
+ // Big thank you to RanzQ (Juha Rantanen) from Github for this script
+ // https://raw.githubusercontent.com/RanzQ/hyperion-audio-effects/master/matrix-config.js
-function createMatrixLayout( ledshoriz, ledsvert, cabling, start){
-// Big thank you to RanzQ (Juha Rantanen) from Github for this script
-// https://raw.githubusercontent.com/RanzQ/hyperion-audio-effects/master/matrix-config.js
+ var parallel = false
+ var leds = []
+ var hblock = 1.0 / ledshoriz
+ var vblock = 1.0 / ledsvert
- var parallel = false
- var leds = []
- var hblock = 1.0 / ledshoriz
- var vblock = 1.0 / ledsvert
+ if (cabling == "parallel") {
+ parallel = true
+ }
- if (cabling == "parallel"){
- parallel = true
- }
+ /**
+ * Adds led to the hyperion config led array
+ * @param {Number} x Horizontal position in matrix
+ * @param {Number} y Vertical position in matrix
+ */
+ function addLed(x, y) {
+ var hscanMin = x * hblock
+ var hscanMax = (x + 1) * hblock
+ var vscanMin = y * vblock
+ var vscanMax = (y + 1) * vblock
-/**
- * Adds led to the hyperion config led array
- * @param {Number} x Horizontal position in matrix
- * @param {Number} y Vertical position in matrix
- */
- function addLed (x, y) {
- var hscanMin = x * hblock
- var hscanMax = (x + 1) * hblock
- var vscanMin = y * vblock
- var vscanMax = (y + 1) * vblock
+ hscanMin = round(hscanMin);
+ hscanMax = round(hscanMax);
+ vscanMin = round(vscanMin);
+ vscanMax = round(vscanMax);
- hscanMin = round(hscanMin);
- hscanMax = round(hscanMax);
- vscanMin = round(vscanMin);
- vscanMax = round(vscanMax);
+ leds.push({
+ hmin: hscanMin,
+ hmax: hscanMax,
+ vmin: vscanMin,
+ vmax: vscanMax
+ })
+ }
- leds.push({
- hmin: hscanMin,
- hmax: hscanMax,
- vmin: vscanMin,
- vmax: vscanMax
- })
- }
+ var startYX = start.split('-')
+ var startX = startYX[1] === 'right' ? ledshoriz - 1 : 0
+ var startY = startYX[0] === 'bottom' ? ledsvert - 1 : 0
+ var endX = startX === 0 ? ledshoriz - 1 : 0
+ var endY = startY === 0 ? ledsvert - 1 : 0
+ var forward = startX < endX
- var startYX = start.split('-')
- var startX = startYX[1] === 'right' ? ledshoriz - 1 : 0
- var startY = startYX[0] === 'bottom' ? ledsvert - 1 : 0
- var endX = startX === 0 ? ledshoriz - 1 : 0
- var endY = startY === 0 ? ledsvert - 1 : 0
- var forward = startX < endX
+ var downward = startY < endY
- var downward = startY < endY
+ var x, y
- var x, y
+ for (y = startY; downward && y <= endY || !downward && y >= endY; y += downward ? 1 : -1) {
+ for (x = startX; forward && x <= endX || !forward && x >= endX; x += forward ? 1 : -1) {
+ addLed(x, y)
+ }
+ if (!parallel) {
+ forward = !forward
+ var tmp = startX
+ startX = endX
+ endX = tmp
+ }
+ }
- for (y = startY; downward && y <= endY || !downward && y >= endY; y += downward ? 1 : -1) {
- for (x = startX; forward && x <= endX || !forward && x >= endX; x += forward ? 1 : -1) {
- addLed(x, y)
- }
- if (!parallel) {
- forward = !forward
- var tmp = startX
- startX = endX
- endX = tmp
- }
- }
-
- return leds;
+ return leds;
}
+function createMatrixLeds() {
+ // Big thank you to RanzQ (Juha Rantanen) from Github for this script
+ // https://raw.githubusercontent.com/RanzQ/hyperion-audio-effects/master/matrix-config.js
-function createMatrixLeds(){
-// Big thank you to RanzQ (Juha Rantanen) from Github for this script
-// https://raw.githubusercontent.com/RanzQ/hyperion-audio-effects/master/matrix-config.js
+ //get values
+ var ledshoriz = parseInt($("#ip_ma_ledshoriz").val());
+ var ledsvert = parseInt($("#ip_ma_ledsvert").val());
+ var cabling = $("#ip_ma_cabling").val();
+ var start = $("#ip_ma_start").val();
- //get values
- var ledshoriz = parseInt($("#ip_ma_ledshoriz").val());
- var ledsvert = parseInt($("#ip_ma_ledsvert").val());
- var cabling = $("#ip_ma_cabling").val();
- var start = $("#ip_ma_start").val();
+ nonBlacklistLedArray = createMatrixLayout(ledshoriz, ledsvert, cabling, start);
+ finalLedArray = blackListLeds(nonBlacklistLedArray, ledBlacklist);
- finalLedArray = createMatrixLayout(ledshoriz,ledsvert,cabling,start);
- createLedPreview(finalLedArray, 'matrix');
+ createLedPreview(finalLedArray, 'matrix');
+ aceEdt.set(finalLedArray);
}
-function migrateLedConfig(slConfig){
+function blackListLeds(nonBlacklistLedArray, blackList) {
- var newLedConfig = {classic:{}, matrix:{}};
+ var blacklistedLedArray = [...nonBlacklistLedArray];
+ if (blackList && blackList.length > 0) {
- //Default Classic layout
- newLedConfig.classic = {
- "top" : 1,
- "bottom" : 0,
- "left" : 0,
- "right" : 0,
- "glength" : 0,
- "gpos" : 0,
- "position" : 0,
- "reverse" : false,
- "hdepth" : 8,
- "vdepth" : 5,
- "overlap" : 0,
- "edgegap" : 0
- }
+ for (let item of blackList) {
+ var start = item.start;
+ var num = item.num
+ var layoutSize = blacklistedLedArray.length;
- //Move Classic layout
- newLedConfig.classic.top = slConfig.top;
- newLedConfig.classic.bottom = slConfig.bottom;
- newLedConfig.classic.left = slConfig.left;
- newLedConfig.classic.right = slConfig.right;
- newLedConfig.classic.glength = slConfig.glength;
- newLedConfig.classic.position = slConfig.position;
- newLedConfig.classic.reverse = slConfig.reverse;
- newLedConfig.classic.hdepth = slConfig.hdepth;
- newLedConfig.classic.vdepth = slConfig.vdepth;
- newLedConfig.classic.overlap = slConfig.overlap;
+ //Only consider rules which are in rage of defined number of LEDs
+ if (start >= 0 && start < layoutSize) {
+ // If number of LEDs exceeds layoutSize, use apply number until layout size
+ if (start + num > layoutSize) {
+ num = layoutSize - start;
- //Default Matrix layout
- newLedConfig["matrix"] = { "ledshoriz": 1,
- "ledsvert" : 1,
- "cabling" : "snake",
- "start" : "top-left"
- }
+ }
+ for (var i = 0; i < num; i++) {
+ blacklistedLedArray[start + i] = { hmax: 0, hmin: 0, vmax: 0, vmin: 0 };
+ }
+ }
+ }
+ }
- // Persit new structure
- requestWriteConfig({ledConfig:newLedConfig})
- return newLedConfig
+ return blacklistedLedArray;
+}
+function getLedConfig() {
+ var ledConfig = { classic: {}, matrix: {} };
+ var slConfig = window.serverConfig.ledConfig;
+
+ for (var key in slConfig.classic) {
+ if (typeof (slConfig.classic[key]) === "boolean")
+ ledConfig.classic[key] = $('#ip_cl_' + key).is(':checked');
+ else if (Number.isInteger(slConfig.classic[key]))
+ ledConfig.classic[key] = parseInt($('#ip_cl_' + key).val());
+ else
+ ledConfig.classic[key] = $('#ip_cl_' + key).val();
+ }
+
+ for (var key in slConfig.matrix) {
+ if (typeof (slConfig.matrix[key]) === "boolean")
+ ledConfig.matrix[key] = $('#ip_ma_' + key).is(':checked');
+ else if (Number.isInteger(slConfig.matrix[key]))
+ ledConfig.matrix[key] = parseInt($('#ip_ma_' + key).val());
+ else
+ ledConfig.matrix[key] = $('#ip_ma_' + key).val();
+ }
+
+ ledConfig.ledBlacklist = blacklist_editor.getEditor("root.ledBlacklist").getValue();
+
+ return ledConfig;
}
function isEmpty(obj) {
- for(var key in obj) {
- if(obj.hasOwnProperty(key))
- return false;
- }
- return true;
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key))
+ return false;
+ }
+ return true;
}
-$(document).ready(function() {
- // translate
- performTranslation();
+$(document).ready(function () {
+ // translate
+ performTranslation();
- //add intros
- if(window.showOptHelp)
- {
- createHintH("intro", $.i18n('conf_leds_device_intro'), "leddevice_intro");
- createHintH("intro", $.i18n('conf_leds_layout_intro'), "layout_intro");
- $('#led_vis_help').html('
'+$.i18n('conf_leds_layout_preview_l1')+'
'+$.i18n('conf_leds_layout_preview_l2')+'
');
- }
+ //add intros
+ if (window.showOptHelp) {
+ createHintH("intro", $.i18n('conf_leds_device_intro'), "leddevice_intro");
+ createHintH("intro", $.i18n('conf_leds_layout_intro'), "layout_intro");
+ $('#led_vis_help').html('
' + $.i18n('conf_leds_layout_preview_l1') + '
' + $.i18n('conf_leds_layout_preview_l2') + '
');
+ }
- var slConfig = window.serverConfig.ledConfig;
+ //**************************************************
+ // Handle LED-Layout Configuration
+ //**************************************************
+ var slConfig = window.serverConfig.ledConfig;
- //Check, if structure is not aligned to expected -> migrate structure
+ //restore ledConfig - Classic
+ for (var key in slConfig.classic) {
+ if (typeof (slConfig.classic[key]) === "boolean")
+ $('#ip_cl_' + key).prop('checked', slConfig.classic[key]);
+ else
+ $('#ip_cl_' + key).val(slConfig.classic[key]);
+ }
- if ( isEmpty(slConfig.classic) )
- {
- slConfig = migrateLedConfig( slConfig );
- }
+ //restore ledConfig - Matrix
+ for (var key in slConfig.matrix) {
+ if (typeof (slConfig.matrix[key]) === "boolean")
+ $('#ip_ma_' + key).prop('checked', slConfig.matrix[key]);
+ else
+ $('#ip_ma_' + key).val(slConfig.matrix[key]);
+ }
- //restore ledConfig - Classic
- for(var key in slConfig.classic)
- {
- if(typeof(slConfig.classic[key]) === "boolean")
- $('#ip_cl_'+key).prop('checked', slConfig.classic[key]);
- else
- $('#ip_cl_'+key).val(slConfig.classic[key]);
- }
+ // check access level and adjust ui
+ if (storedAccess == "default") {
+ $('#texfield_panel').toggle(false);
+ $('#previewcreator').toggle(false);
+ }
- //restore ledConfig - Matrix
- for(var key in slConfig.matrix)
- {
- if(typeof(slConfig.matrix[key]) === "boolean")
- $('#ip_ma_'+key).prop('checked', slConfig.matrix[key]);
- else
- $('#ip_ma_'+key).val(slConfig.matrix[key]);
- }
+ // Wiki link
+ $('#leds_wl').append('' + $.i18n('general_wiki_moreto', $.i18n('conf_leds_nav_label_ledlayout')) + buildWL("user/advanced/Advanced.html#led-layout", "Wiki") + '
');
- function saveValues()
- {
- var ledConfig = {classic:{}, matrix:{}};
+ // bind change event to all inputs
+ $('.ledCLconstr').bind("change", function () {
+ valValue(this.id, this.value, this.min, this.max);
+ createClassicLeds();
+ });
- for(var key in slConfig.classic)
- {
- if(typeof(slConfig.classic[key]) === "boolean")
- ledConfig.classic[key] = $('#ip_cl_'+key).is(':checked');
- else if(Number.isInteger(slConfig.classic[key]))
- ledConfig.classic[key] = parseInt($('#ip_cl_'+key).val());
- else
- ledConfig.classic[key] = $('#ip_cl_'+key).val();
- }
+ $('.ledMAconstr').bind("change", function () {
+ valValue(this.id, this.value, this.min, this.max);
+ createMatrixLeds();
+ });
- for(var key in slConfig.matrix)
- {
- if(typeof(slConfig.matrix[key]) === "boolean")
- ledConfig.matrix[key] = $('#ip_ma_'+key).is(':checked');
- else if(Number.isInteger(slConfig.matrix[key]))
- ledConfig.matrix[key] = parseInt($('#ip_ma_'+key).val());
- else
- ledConfig.matrix[key] = $('#ip_ma_'+key).val();
- }
- requestWriteConfig({ledConfig});
- }
+ $(document).on('click', "#classic_panel", function (e) {
+ createClassicLeds();
+ });
- // check access level and adjust ui
- if(storedAccess == "default")
- {
- $('#texfield_panel').toggle(false);
- $('#previewcreator').toggle(false);
- }
+ $(document).on('click', "#matrix_panel", function (e) {
+ createMatrixLeds();
+ });
- //Wiki link
- $('#leds_wl').append(''+$.i18n('general_wiki_moreto',$.i18n('conf_leds_nav_label_ledlayout'))+buildWL("user/moretopics/ledarea","Wiki")+'
');
+ $(document).on('click', "#current_config_panel", function (e) {
+ aceEdt.set(finalLedArray);
+ });
- // bind change event to all inputs
- $('.ledCLconstr').bind("change", function() {
- valValue(this.id,this.value,this.min,this.max);
- createClassicLeds();
- });
+ // Initialise from config and apply blacklist rules
+ nonBlacklistLedArray = window.serverConfig.leds;
+ ledBlacklist = window.serverConfig.ledConfig.ledBlacklist;
+ finalLedArray = blackListLeds(nonBlacklistLedArray, ledBlacklist);
- $('.ledMAconstr').bind("change", function() {
- valValue(this.id,this.value,this.min,this.max);
- createMatrixLeds();
- });
+ var blacklistOptions = window.serverSchema.properties.ledConfig.properties.ledBlacklist;
+ blacklist_editor = createJsonEditor('editor_container_blacklist_conf', {
+ ledBlacklist: blacklistOptions,
+ });
+ blacklist_editor.getEditor("root.ledBlacklist").setValue(ledBlacklist);
- // v4 of json schema with diff required assignment - remove when hyperion schema moved to v4
- var ledschema = { "items": { "additionalProperties": false, "required": ["hmin", "hmax", "vmin", "vmax"], "properties": { "name": { "type": "string" }, "colorOrder": { "enum": ["rgb", "bgr", "rbg", "brg", "gbr", "grb"], "type": "string" }, "hmin": { "maximum": 1, "minimum": 0, "type": "number" }, "hmax": { "maximum": 1, "minimum": 0, "type": "number" }, "vmin": { "maximum": 1, "minimum": 0, "type": "number" }, "vmax": { "maximum": 1, "minimum": 0, "type": "number" } }, "type": "object" }, "type": "array" };
- //create jsonace editor
- aceEdt = new JSONACEEditor(document.getElementById("aceedit"),{
- mode: 'code',
- schema: ledschema,
- onChange: function(){
- var success = true;
- try{
- aceEdt.get();
- }
- catch(err)
- {
- success = false;
- }
+ // v4 of json schema with diff required assignment - remove when hyperion schema moved to v4
+ var ledschema = { "items": { "additionalProperties": false, "required": ["hmin", "hmax", "vmin", "vmax"], "properties": { "name": { "type": "string" }, "colorOrder": { "enum": ["rgb", "bgr", "rbg", "brg", "gbr", "grb"], "type": "string" }, "hmin": { "maximum": 1, "minimum": 0, "type": "number" }, "hmax": { "maximum": 1, "minimum": 0, "type": "number" }, "vmin": { "maximum": 1, "minimum": 0, "type": "number" }, "vmax": { "maximum": 1, "minimum": 0, "type": "number" } }, "type": "object" }, "type": "array" };
+ //create jsonace editor
+ aceEdt = new JSONACEEditor(document.getElementById("aceedit"), {
+ mode: 'code',
+ schema: ledschema,
+ onChange: function () {
+ var success = true;
+ try {
+ aceEdt.get();
+ }
+ catch (err) {
+ success = false;
+ }
- if(success)
- {
- $('#leds_custom_updsim').attr("disabled", false);
- $('#leds_custom_save').attr("disabled", false);
- }
- else
- {
- $('#leds_custom_updsim').attr("disabled", true);
- $('#leds_custom_save').attr("disabled", true);
- }
+ if (success) {
+ $('#leds_custom_updsim').attr("disabled", false);
+ $('#leds_custom_save').attr("disabled", false);
+ }
+ else {
+ $('#leds_custom_updsim').attr("disabled", true);
+ $('#leds_custom_save').attr("disabled", true);
+ }
- if ( window.readOnlyMode )
- {
- $('#leds_custom_save').attr('disabled', true);
- }
- }
- }, window.serverConfig.leds);
+ if (window.readOnlyMode) {
+ $('#leds_custom_save').attr('disabled', true);
+ }
+ }
+ }, finalLedArray);
- //TODO: HACK! No callback for schema validation - Add it!
- setInterval(function(){
- if($('#aceedit table').hasClass('jsoneditor-text-errors'))
- {
- $('#leds_custom_updsim').attr("disabled", true);
- $('#leds_custom_save').attr("disabled", true);
- }
- },1000);
+ //TODO: HACK! No callback for schema validation - Add it!
+ setInterval(function () {
+ if ($('#aceedit table').hasClass('jsoneditor-text-errors')) {
+ $('#leds_custom_updsim').attr("disabled", true);
+ $('#leds_custom_save').attr("disabled", true);
+ }
+ }, 1000);
- $('.jsoneditor-menu').toggle();
+ $('.jsoneditor-menu').toggle();
- // leds to finalLedArray
- finalLedArray = window.serverConfig.leds;
+ // validate textfield and update preview
+ $("#leds_custom_updsim").off().on("click", function () {
+ nonBlacklistLedArray = aceEdt.get();
+ finalLedArray = blackListLeds(nonBlacklistLedArray, ledBlacklist);
+ createLedPreview(finalLedArray, 'text');
+ });
- // create and update editor
- $("#leddevices").off().on("change", function() {
- var generalOptions = window.serverSchema.properties.device;
+ // save led layout, the generated textfield configuration always represents the latest layout
+ $("#btn_ma_save, #btn_cl_save, #btn_bl_save, #leds_custom_save").off().on("click", function () {
+ var hardwareLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount").getValue();
+ var layoutLedCount = aceEdt.get().length;
+
+ if (hardwareLedCount < layoutLedCount) {
+ // Not enough hardware LEDs for configured layout
+ showInfoDialog('error', $.i18n("conf_leds_config_error"), $.i18n('conf_leds_error_hwled_lt_layout', hardwareLedCount, layoutLedCount));
+ } else {
+ saveLedConfig(false);
+ }
+ });
+
+ // toggle led numbers
+ $('#leds_prev_toggle_num').off().on("click", function () {
+ $('.led_prev_num').toggle();
+ toggleClass('#leds_prev_toggle_num', "btn-danger", "btn-success");
+ });
+
+ // open checklist
+ $('#leds_prev_checklist').off().on("click", function () {
+ var liList = [$.i18n('conf_leds_layout_checkp1'), $.i18n('conf_leds_layout_checkp3'), $.i18n('conf_leds_layout_checkp2'), $.i18n('conf_leds_layout_checkp4')];
+ var ul = document.createElement("ul");
+ ul.className = "checklist"
+
+ for (var i = 0; i < liList.length; i++) {
+ var li = document.createElement("li");
+ li.innerHTML = liList[i];
+ ul.appendChild(li);
+ }
+ showInfoDialog('checklist', "", ul);
+ });
+
+ // nav
+ $('#leds_cfg_nav a[data-toggle="tab"]').off().on('shown.bs.tab', function (e) {
+ var target = $(e.target).attr("href") // activated tab
+ if (target == "#menu_gencfg" && !ledsCustomCfgInitialized) {
+ $('#leds_custom_updsim').trigger('click');
+ ledsCustomCfgInitialized = true;
+ }
+
+ blacklist_editor.on('change', function () {
+ // only update preview, if config is valid
+ if (blacklist_editor.validate().length <= 0) {
+
+ ledBlacklist = blacklist_editor.getEditor("root.ledBlacklist").getValue();
+ finalLedArray = blackListLeds(nonBlacklistLedArray, ledBlacklist);
+ createLedPreview(finalLedArray);
+ aceEdt.set(finalLedArray);
+ }
+
+ // change save button state based on validation result
+ blacklist_editor.validate().length || window.readOnlyMode ? $('#btn_bl_save').attr('disabled', true) : $('#btn_bl_save').attr('disabled', false);
+ });
+
+ });
+
+ //**************************************************
+ // Handle LED-Device Configuration
+ //**************************************************
+
+ // External properties properties, 2-dimensional arry of [ledType][key]
+ devicesProperties = {};
+
+ $("#leddevices").off().on("change", function () {
+ var generalOptions = window.serverSchema.properties.device;
- // Modified schema entry "hardwareLedCount" in generalOptions to minimum LedCount
var ledType = $(this).val();
- //philipshueentertainment backward fix
- if(ledType == "philipshueentertainment") ledType = "philipshue";
+ // philipshueentertainment backward fix
+ if (ledType == "philipshueentertainment")
+ ledType = "philipshue";
var specificOptions = window.serverSchema.properties.alldevices[ledType];
- conf_editor = createJsonEditor('editor_container', {
- generalOptions : generalOptions,
- specificOptions : specificOptions,
- });
- var values_general = {};
- var values_specific = {};
- var isCurrentDevice = (window.serverConfig.device.type == ledType);
+ conf_editor = createJsonEditor('editor_container_leddevice', {
+ specificOptions: specificOptions,
+ generalOptions: generalOptions,
+ });
- for(var key in window.serverConfig.device) {
- if (key != "type" && key in generalOptions.properties) values_general[key] = window.serverConfig.device[key];
- };
- conf_editor.getEditor("root.generalOptions").setValue( values_general );
+ var values_general = {};
+ var values_specific = {};
+ var isCurrentDevice = (window.serverConfig.device.type == ledType);
- if (isCurrentDevice)
- {
- var specificOptions_val = conf_editor.getEditor("root.specificOptions").getValue();
- for(var key in specificOptions_val){
- values_specific[key] = (key in window.serverConfig.device) ? window.serverConfig.device[key] : specificOptions_val[key];
- };
- conf_editor.getEditor("root.specificOptions").setValue( values_specific );
- };
+ for (var key in window.serverConfig.device) {
+ if (key != "type" && key in generalOptions.properties) values_general[key] = window.serverConfig.device[key];
+ };
+ conf_editor.getEditor("root.generalOptions").setValue(values_general);
- // change save button state based on validation result
- conf_editor.validate().length || window.readOnlyMode ? $('#btn_submit_controller').attr('disabled', true) : $('#btn_submit_controller').attr('disabled', false);
+ if (isCurrentDevice) {
+ var specificOptions_val = conf_editor.getEditor("root.specificOptions").getValue();
+ for (var key in specificOptions_val) {
+ values_specific[key] = (key in window.serverConfig.device) ? window.serverConfig.device[key] : specificOptions_val[key];
+ };
+ conf_editor.getEditor("root.specificOptions").setValue(values_specific);
+ };
- conf_editor.on('change',function() {
- window.readOnlyMode ? $('#btn_cl_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
- window.readOnlyMode ? $('#btn_ma_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
- window.readOnlyMode ? $('#leds_custom_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
- });
+ // change save button state based on validation result
+ conf_editor.validate().length || window.readOnlyMode ? $('#btn_submit_controller').attr('disabled', true) : $('#btn_submit_controller').attr('disabled', false);
- // led controller sepecific wizards
- $('#btn_wiz_holder').html("");
- $('#btn_led_device_wiz').off();
+ // led controller sepecific wizards
+ $('#btn_wiz_holder').html("");
+ $('#btn_led_device_wiz').off();
- if(ledType == "philipshue") {
- $('#root_specificOptions_useEntertainmentAPI').bind("change", function() {
+ if (ledType == "philipshue") {
+ $('#root_specificOptions_useEntertainmentAPI').bind("change", function () {
var ledWizardType = (this.checked) ? "philipshueentertainment" : ledType;
var data = { type: ledWizardType };
var hue_title = (this.checked) ? 'wiz_hue_e_title' : 'wiz_hue_title';
@@ -596,150 +646,901 @@ $(document).ready(function() {
});
$("#root_specificOptions_useEntertainmentAPI").trigger("change");
}
-/*
- else if(ledType == "wled") {
- var ledWizardType = (this.checked) ? "wled" : ledType;
- var data = { type: ledWizardType };
- var wled_title = 'wiz_wled_title';
- changeWizard(data, wled_title, startWizardWLED);
- }
-*/
- 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 == "cololight") {
- var ledWizardType = (this.checked) ? "cololight" : ledType;
- var data = { type: ledWizardType };
- var cololight_title = 'wiz_cololight_title';
- changeWizard(data, cololight_title, startWizardCololight);
- }
- 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);
- }
+ 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);
+ createHint("wizard", $.i18n(hint), "btn_wiz_holder", "btn_led_device_wiz");
+ $('#btn_led_device_wiz').off().on('click', data, fn);
}
- });
+
+ conf_editor.on('ready', function () {
+ var hwLedCountDefault = 1;
+ var colorOrderDefault = "rgb";
+
+ switch (ledType) {
+ case "cololight":
+ case "wled":
+ case "nanoleaf":
+ showAllDeviceInputOptions("hostList", false);
+ case "adalight":
+ case "atmo":
+ case "dmx":
+ case "karate":
+ case "sedu":
+ case "tpm2":
+ case "apa102":
+ case "apa104":
+ case "ws2801":
+ case "lpd6803":
+ case "lpd8806":
+ case "p9813":
+ case "sk6812spi":
+ case "sk6822spi":
+ case "sk9822":
+ case "ws2812spi":
+ case "piblaster":
+ discover_device(ledType);
+ hwLedCountDefault = 1;
+ colorOrderDefault = "rgb";
+ break;
+
+ case "philipshue":
+ var lights = conf_editor.getEditor("root.specificOptions.lightIds").getValue();
+ hwLedCountDefault = lights.length;
+ colorOrderDefault = "rgb";
+ break;
+
+ case "yeelight":
+ conf_editor.getEditor("root.generalOptions").disable();
+ var lights = conf_editor.getEditor("root.specificOptions.lights").getValue();
+ hwLedCountDefault = lights.length;
+ colorOrderDefault = "rgb";
+ break;
+
+ case "atmoorb":
+ conf_editor.getEditor("root.generalOptions").disable();
+
+ var configruedOrbIds = conf_editor.getEditor("root.specificOptions.orbIds").getValue().trim();
+ if (configruedOrbIds.length !== 0) {
+ hwLedCountDefault = configruedOrbIds.split(",").map(Number).length;
+ } else {
+ hwLedCountDefault = 0;
+ }
+ colorOrderDefault = "rgb";
+ break;
+
+ default:
+ }
+
+ if (ledType !== window.serverConfig.device.type) {
+ var hwLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount")
+ if (hwLedCount) {
+ hwLedCount.setValue(hwLedCountDefault);
+ }
+ var colorOrder = conf_editor.getEditor("root.generalOptions.colorOrder")
+ if (colorOrder) {
+ colorOrder.setValue(colorOrderDefault);
+ }
+ }
+ });
+
+ conf_editor.on('change', function () {
+ //Check, if device can be identified/tested and/or saved
+ var canIdentify = false;
+ var canSave = false;
+
+ switch (ledType) {
+ case "cololight":
+ case "wled":
+ var hostList = conf_editor.getEditor("root.specificOptions.hostList").getValue();
+ if (hostList !== "SELECT") {
+ var host = conf_editor.getEditor("root.specificOptions.host").getValue();
+ if (host !== "") {
+ canIdentify = true;
+ canSave = true;
+ }
+ }
+ break;
+
+ case "nanoleaf":
+ var hostList = conf_editor.getEditor("root.specificOptions.hostList").getValue();
+ if (hostList !== "SELECT") {
+ var host = conf_editor.getEditor("root.specificOptions.host").getValue();
+ var token = conf_editor.getEditor("root.specificOptions.token").getValue();
+ if (host !== "" && token !== "") {
+ canIdentify = true;
+ canSave = true;
+ }
+ }
+ break;
+
+ case "adalight":
+ var output = conf_editor.getEditor("root.specificOptions.output").getValue();
+ if (output !== "NONE" && output !== "SELECT" && output !== "") {
+ canIdentify = true;
+ }
+ case "atmo":
+ case "dmx":
+ case "karate":
+ case "sedu":
+ case "tpm2":
+ case "apa102":
+ case "apa104":
+ case "ws2801":
+ case "lpd6803":
+ case "lpd8806":
+ case "p9813":
+ case "sk6812spi":
+ case "sk6822spi":
+ case "sk9822":
+ case "ws2812spi":
+ case "piblaster":
+ var output = conf_editor.getEditor("root.specificOptions.output").getValue();
+ if (output !== "NONE" && output !== "SELECT" && output !== "") {
+ canSave = true;
+ }
+ break;
+ default:
+ canIdentify = false;
+ canSave = true;
+ }
+
+ if (canIdentify) {
+ $("#btn_test_controller").removeClass('hidden');
+ $('#btn_test_controller').attr('disabled', false);
+ }
+ else {
+ $('#btn_test_controller').attr('disabled', true);
+ }
+
+ var hardwareLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount").getValue();
+ if (hardwareLedCount < 1) {
+ canSave = false;
+ }
+
+ if (canSave) {
+ if (!window.readOnlyMode) {
+ $('#btn_submit_controller').attr('disabled', false);
+ }
+ }
+ else {
+ $('#btn_submit_controller').attr('disabled', true);
+ }
+
+ window.readOnlyMode ? $('#btn_cl_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
+ window.readOnlyMode ? $('#btn_ma_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
+ window.readOnlyMode ? $('#leds_custom_save').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
+ });
+
+ conf_editor.watch('root.specificOptions.hostList', () => {
+ var specOptPath = 'root.specificOptions.';
+
+ //Disable General Options, as LED count will be resolved from device itself
+ conf_editor.getEditor("root.generalOptions").disable();
+
+ var hostList = conf_editor.getEditor("root.specificOptions.hostList")
+ if (hostList) {
+ var val = hostList.getValue();
+ var showOptions = true;
+
+ switch (val) {
+ case 'CUSTOM':
+ case '':
+ conf_editor.getEditor(specOptPath + "host").enable();
+ conf_editor.getEditor(specOptPath + "host").setValue("");
+ break;
+ case 'NONE':
+ conf_editor.getEditor(specOptPath + "host").enable();
+ break;
+ case 'SELECT':
+ conf_editor.getEditor(specOptPath + "host").setValue("");
+ conf_editor.getEditor(specOptPath + "host").disable();
+ showOptions = false;
+ break;
+ default:
+ conf_editor.getEditor(specOptPath + "host").disable();
+ conf_editor.getEditor(specOptPath + "host").setValue(val);
+ break;
+ }
+ }
+
+ showAllDeviceInputOptions("hostList", showOptions);
+ });
+
+ conf_editor.watch('root.specificOptions.host', () => {
+ var host = conf_editor.getEditor("root.specificOptions.host").getValue();
+
+ if (host === "") {
+ conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(1);
+ }
+ else {
+ let params = {};
+ switch (ledType) {
+ case "cololight":
+ params = { host: host };
+ break;
+
+ case "nanoleaf":
+ var token = conf_editor.getEditor("root.specificOptions.token").getValue();
+ if (token === "") {
+ return
+ }
+ params = { host: host, token: token };
+ break;
+
+ case "wled":
+ params = { host: host, filter: "info" };
+ break;
+ default:
+ }
+
+ getProperties_device(ledType, host, params);
+ }
+ });
+
+ conf_editor.watch('root.specificOptions.output', () => {
+ var output = conf_editor.getEditor("root.specificOptions.output").getValue();
+ if (output === "NONE" || output === "SELECT" || output === "") {
+ conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(1);
+ showAllDeviceInputOptions("output", false);
+ }
+ else {
+ showAllDeviceInputOptions("output", true);
+ let params = {};
+ switch (ledType) {
+ case "atmo":
+ case "karate":
+ params = { serialPort: output };
+ getProperties_device(ledType, output, params);
+ break;
+ }
+ }
+ });
+
+ conf_editor.watch('root.specificOptions.token', () => {
+ var token = conf_editor.getEditor("root.specificOptions.token").getValue();
+
+ if (token !== "") {
+ let params = {};
+
+ var host = "";
+ switch (ledType) {
+ case "nanoleaf":
+ host = conf_editor.getEditor("root.specificOptions.host").getValue();
+ if (host === "") {
+ return
+ }
+ params = { host: host, token: token };
+ break;
+ default:
+ }
+
+ getProperties_device(ledType, host, params);
+ }
+ });
+
+ //Yeelight
+ conf_editor.watch('root.specificOptions.lights', () => {
+ //Disable General Options, as LED count will be resolved from number of lights configured
+ conf_editor.getEditor("root.generalOptions").disable();
+
+ var hwLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount")
+ if (hwLedCount) {
+ var lights = conf_editor.getEditor("root.specificOptions.lights").getValue();
+ hwLedCount.setValue(lights.length);
+ }
+ });
+
+ //Philips Hue
+ conf_editor.watch('root.specificOptions.lightIds', () => {
+ //Disable General Options, as LED count will be resolved from number of lights configured
+ conf_editor.getEditor("root.generalOptions").disable();
+
+ var hwLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount")
+ if (hwLedCount) {
+ var lights = conf_editor.getEditor("root.specificOptions.lightIds").getValue();
+ hwLedCount.setValue(lights.length);
+ }
+ });
+
+ //Atmo Orb
+ conf_editor.watch('root.specificOptions.orbIds', () => {
+ //Disable General Options, as LED count will be resolved from number of lights configured
+ conf_editor.getEditor("root.generalOptions").disable();
+
+ var hwLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount")
+ if (hwLedCount) {
+ var lights = 0;
+ var configruedOrbIds = conf_editor.getEditor("root.specificOptions.orbIds").getValue().trim();
+ if (configruedOrbIds.length !== 0) {
+ lights = configruedOrbIds.split(",").map(Number);
+ }
+ hwLedCount.setValue(lights.length);
+ }
+ });
+ });
//philipshueentertainment backward fix
- if(window.serverConfig.device.type == "philipshueentertainment") window.serverConfig.device.type = "philipshue";
+ if (window.serverConfig.device.type == "philipshueentertainment") window.serverConfig.device.type = "philipshue";
- // create led device selection
- var ledDevices = window.serverInfo.ledDevices.available;
- var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'sk9822', 'ws2812spi'];
- var devRPiPWM = ['ws281x'];
- var devRPiGPIO = ['piblaster'];
-
- var devNET = ['atmoorb', 'cololight', 'fadecandy', 'philipshue', 'nanoleaf', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw', 'wled', 'yeelight'];
- var devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2', 'karate'];
+ // create led device selection
+ var ledDevices = window.serverInfo.ledDevices.available;
var optArr = [[]];
- optArr[1]=[];
- optArr[2]=[];
- optArr[3]=[];
- optArr[4]=[];
- optArr[5]=[];
+ optArr[1] = [];
+ optArr[2] = [];
+ optArr[3] = [];
+ optArr[4] = [];
+ optArr[5] = [];
- for (var idx=0; idx layoutLedCount) {
+ // More Hardware LEDs than on layout
+ $('#id_body').html('');
+ $('#id_body').append('' + $.i18n("conf_leds_config_warning") + ' ');
+ $('#id_body').append($.i18n('conf_leds_error_hwled_gt_layout', hardwareLedCount, layoutLedCount, hardwareLedCount - layoutLedCount));
+ $('#id_body').append(' ');
+ $('#id_body').append($.i18n('conf_leds_note_layout_overwrite', hardwareLedCount));
+ $('#id_footer').html(' ' + $.i18n('general_btn_back') + ' ');
+ $('#id_footer').append(' ' + $.i18n('general_btn_overwrite') + ' ');
+ $('#id_footer').append('' + $.i18n('general_btn_continue') + ' ');
+ }
+ else {
+ // Less Hardware LEDs than on layout
+ $('#id_body').html('');
+ $('#id_body').append('' + $.i18n("conf_leds_config_error") + ' ');
+ $('#id_body').append($.i18n('conf_leds_error_hwled_lt_layout', hardwareLedCount, layoutLedCount));
+ $('#id_body').append(' ');
+ $('#id_body').append($.i18n('conf_leds_note_layout_overwrite', hardwareLedCount));
+ $('#id_footer').html(' ' + $.i18n('general_btn_back') + ' ');
+ $('#id_footer').append(' ' + $.i18n('general_btn_overwrite') + ' ');
+ }
- var general = conf_editor.getEditor("root.generalOptions").getValue();
- var specific = conf_editor.getEditor("root.specificOptions").getValue();
- for(var key in general){
- result.device[key] = general[key];
- }
+ $("#modal_dialog").modal({
+ backdrop: "static",
+ keyboard: false,
+ show: true
+ });
- for(var key in specific){
- result.device[key] = specific[key];
- }
- result.device.type=ledDevice;
- requestWriteConfig(result)
- });
+ $('#btn_back').off().on('click', function () {
+ //Continue with the configuration
+ });
- removeOverlay();
+ $('#btn_continue').off().on('click', function () {
+ saveLedConfig(false);
+ });
+
+ $('#btn_overwrite').off().on('click', function () {
+ saveLedConfig(true);
+ });
+ }
+ });
+
+ removeOverlay();
});
+
+function saveLedConfig(genDefLayout = false) {
+ var ledType = $("#leddevices").val();
+ var result = { device: {} };
+
+ var general = conf_editor.getEditor("root.generalOptions").getValue();
+ var specific = conf_editor.getEditor("root.specificOptions").getValue();
+ for (var key in general) {
+ result.device[key] = general[key];
+ }
+
+ for (var key in specific) {
+ result.device[key] = specific[key];
+ }
+ result.device.type = ledType;
+
+ var ledConfig = {};
+ var leds = [];
+
+ var hardwareLedCount = conf_editor.getEditor("root.generalOptions.hardwareLedCount").getValue();
+ result.device.hardwareLedCount = hardwareLedCount;
+
+ // Special handling per LED-type
+ switch (ledType) {
+ case "cololight":
+
+ var host = conf_editor.getEditor("root.specificOptions.host").getValue();
+ result.smoothing = { enable: false };
+
+ if (genDefLayout === true) {
+ if (devicesProperties[ledType][host].modelType === "Strip") {
+ ledConfig = {
+ "classic": {
+ "top": hardwareLedCount / 2,
+ "bottom": 0,
+ "left": hardwareLedCount / 4,
+ "right": hardwareLedCount / 4,
+ "position": hardwareLedCount / 4 * 3
+ },
+ "matrix": { "cabling": "snake", "ledshoriz": 1, "ledsvert": 1, "start": "top-left" }
+ };
+ leds = createClassicLedLayoutSimple(hardwareLedCount / 2, hardwareLedCount / 4, hardwareLedCount / 4, 0, hardwareLedCount / 4 * 3, false);
+ }
+ else {
+ ledConfig = {
+ "classic": {
+ "top": hardwareLedCount,
+ "bottom": 0,
+ "left": 0,
+ "right": 0
+ },
+ "matrix": { "cabling": "snake", "ledshoriz": 1, "ledsvert": 1, "start": "top-left" }
+ };
+ leds = createClassicLedLayoutSimple(hardwareLedCount, 0, 0, 0, 0, false);
+ }
+ result.ledConfig = ledConfig;
+ result.leds = leds;
+ }
+ break;
+
+ case "nanoleaf":
+ case "wled":
+ result.smoothing = { enable: false };
+
+ case "adalight":
+ case "atmo":
+ case "dmx":
+ case "karate":
+ case "sedu":
+ case "tpm2":
+ case "apa102":
+ case "apa104":
+ case "ws2801":
+ case "lpd6803":
+ case "lpd8806":
+ case "p9813":
+ case "sk6812spi":
+ case "sk6822spi":
+ case "sk9822":
+ case "ws2812spi":
+ case "piblaster":
+ default:
+ if (genDefLayout === true) {
+ ledConfig = {
+ "classic": {
+ "top": hardwareLedCount,
+ "bottom": 0,
+ "left": 0,
+ "right": 0
+ },
+ "matrix": { "cabling": "snake", "ledshoriz": 1, "ledsvert": 1, "start": "top-left" }
+ }
+ ;
+ result.ledConfig = ledConfig;
+ leds = createClassicLedLayoutSimple(hardwareLedCount, 0, 0, 0, 0, false);
+ result.leds = leds;
+ }
+ break;
+ }
+
+ //Rewrite whole LED & Layout configuration, in case changes were done accross tabs and no default layout
+ if (genDefLayout !== true) {
+ result.ledConfig = getLedConfig();
+ result.leds = JSON.parse(aceEdt.getText());
+ }
+
+ requestWriteConfig(result);
+ location.reload();
+}
+
+// build dynamic enum
+var updateSelectList = function (ledType, discoveryInfo) {
+
+ // Only update, if ledType is equal of selected controller type and discovery info exists
+ if (ledType !== $("#leddevices").val() || !discoveryInfo.devices) {
+ return;
+ }
+
+ let addSchemaElements = {
+ };
+
+ var key;
+ var enumVals = [];
+ var enumTitelVals = [];
+ var enumDefaultVal = "";
+ var addSelect = false;
+ var addCustom = false;
+
+ var ledTypeGroup;
+
+ if ($.inArray(ledType, devNET) != -1) {
+ ledTypeGroup = "devNET";
+ } else if ($.inArray(ledType, devSerial) != -1) {
+ ledTypeGroup = "devSerial";
+ } else if ($.inArray(ledType, devRPiSPI) != -1) {
+ ledTypeGroup = "devRPiSPI";
+ } else if ($.inArray(ledType, devRPiGPIO) != -1) {
+ ledTypeGroup = "devRPiGPIO";
+ }
+
+ var specOpt = conf_editor.getEditor('root.specificOptions'); // get specificOptions of the editor
+
+ switch (ledTypeGroup) {
+ case "devNET":
+ key = "hostList";
+
+ if (discoveryInfo.devices.length === 0) {
+ enumVals.push("NONE");
+ enumTitelVals.push($.i18n('edt_dev_spec_devices_discovered_none'));
+ }
+ else {
+ var name;
+
+ var discoveryMethod = "ssdp";
+ if (discoveryInfo.discoveryMethod) {
+ discoveryMethod = discoveryInfo.discoveryMethod;
+ }
+
+ for (const device of discoveryInfo.devices) {
+ var name;
+ var host;
+
+ switch (ledType) {
+ case "nanoleaf":
+ if (discoveryMethod === "ssdp") {
+ name = device.other["nl-devicename"];
+ }
+ else {
+ name = device.name;
+ }
+ break;
+ case "cololight":
+ if (discoveryMethod === "ssdp") {
+ name = device.hostname;
+ }
+ else {
+ name = device.name;
+ }
+ break;
+ case "wled":
+ name = device.name;
+ break;
+ default:
+ name = device.name;
+ }
+
+ if (discoveryMethod === "ssdp") {
+ host = device.ip;
+ }
+ else {
+ host = device.name;
+ }
+
+ enumVals.push(host);
+ if (host !== name) {
+ enumTitelVals.push(name + " (" + host + ")");
+ }
+ else {
+ enumTitelVals.push(host);
+ }
+
+ addCustom = true;
+
+ // Select configured device
+ var configuredDeviceType = window.serverConfig.device.type;
+ var configuredHost = window.serverConfig.device.hostList;
+ if (ledType === configuredDeviceType && $.inArray(configuredHost, enumVals) != -1) {
+ enumDefaultVal = configuredHost;
+ }
+ else {
+ addSelect = true;
+ addCustom = true;
+ }
+ }
+ }
+ break;
+
+ case "devSerial":
+ key = "output";
+
+ if (discoveryInfo.devices.length == 0) {
+ enumVals.push("NONE");
+ enumTitelVals.push($.i18n('edt_dev_spec_devices_discovered_none'));
+ $('#btn_submit_controller').attr('disabled', true);
+ showAllDeviceInputOptions(key, false);
+ }
+ else {
+ switch (ledType) {
+ case "adalight":
+ case "atmo":
+ case "dmx":
+ case "karate":
+ case "sedu":
+ case "tpm2":
+ for (const device of discoveryInfo.devices) {
+ enumVals.push(device.portName);
+ enumTitelVals.push(device.portName + " (" + device.vendorIdentifier + "|" + device.productIdentifier + ") - " + device.manufacturer);
+ }
+
+ // Select configured device
+ var configuredDeviceType = window.serverConfig.device.type;
+ var configuredOutput = window.serverConfig.device.output;
+ if (ledType === configuredDeviceType && $.inArray(configuredOutput, enumVals) != -1) {
+ enumDefaultVal = configuredOutput;
+ }
+ else {
+ addSelect = true;
+ }
+
+ break;
+ default:
+ }
+ }
+ break;
+ case "devRPiSPI":
+ case "devRPiGPIO":
+ key = "output";
+
+ if (discoveryInfo.devices.length == 0) {
+ enumVals.push("NONE");
+ enumTitelVals.push($.i18n('edt_dev_spec_devices_discovered_none'));
+ $('#btn_submit_controller').attr('disabled', true);
+ showAllDeviceInputOptions(key, false);
+ }
+ else {
+ switch (ledType) {
+ case "apa102":
+ case "apa104":
+ case "ws2801":
+ case "lpd6803":
+ case "lpd8806":
+ case "p9813":
+ case "sk6812spi":
+ case "sk6822spi":
+ case "sk9822":
+ case "ws2812spi":
+ case "piblaster":
+ for (const device of discoveryInfo.devices) {
+ enumVals.push(device.systemLocation);
+ enumTitelVals.push(device.deviceName + " (" + device.systemLocation + ")");
+ }
+
+ // Select configured device
+ var configuredDeviceType = window.serverConfig.device.type;
+ var configuredOutput = window.serverConfig.device.output;
+ if (ledType === configuredDeviceType && $.inArray(configuredOutput, enumVals) != -1) {
+ enumDefaultVal = configuredOutput;
+ }
+ else {
+ addSelect = true;
+ }
+
+ break;
+ default:
+ }
+ }
+ break;
+ default:
+ }
+
+ if (enumVals.length > 0) {
+ updateJsonEditorSelection(specOpt, key, addSchemaElements, enumVals, enumTitelVals, enumDefaultVal, addSelect, addCustom);
+ }
+}
+
+async function discover_device(ledType, params) {
+ const result = await requestLedDeviceDiscovery(ledType, params);
+
+ var discoveryResult;
+ if (result && !result.error) {
+ discoveryResult = result.info;
+ }
+ else {
+ discoveryResult = {
+ devices: [],
+ ledDevicetype: ledType
+ }
+ }
+
+ updateSelectList(ledType, discoveryResult);
+}
+
+async function getProperties_device(ledType, key, params) {
+ // Take care that connfig cannot be saved during background processing
+ $('#btn_submit_controller').attr('disabled', true);
+
+ //Create ledType cache entry
+ if (!devicesProperties[ledType]) {
+ devicesProperties[ledType] = {};
+ }
+
+ // get device's properties, if properties not available in chache
+ if (!devicesProperties[ledType][key]) {
+ const res = await requestLedDeviceProperties(ledType, params);
+ if (res && !res.error) {
+ var deviceProperties = res.info.properties;
+
+ if (!jQuery.isEmptyObject(deviceProperties)) {
+ devicesProperties[ledType][key] = deviceProperties;
+
+ if (!window.readOnlyMode) {
+ $('#btn_submit_controller').attr('disabled', false);
+ }
+ }
+ else {
+ $('#btn_submit_controller').attr('disabled', true);
+ }
+ }
+ }
+
+ updateElements(ledType, key);
+}
+
+async function identify_device(type, params) {
+ // Take care that connfig cannot be saved and identification cannot be retriggerred during background processing
+ $('#btn_submit_controller').attr('disabled', true);
+ $('#btn_test_controller').attr('disabled', true);
+
+ await requestLedDeviceIdentification(type, params);
+
+ $('#btn_test_controller').attr('disabled', false);
+ if (!window.readOnlyMode) {
+ $('#btn_submit_controller').attr('disabled', false);
+ }
+}
+
+function updateElements(ledType, key) {
+ if (devicesProperties[ledType][key]) {
+ switch (ledType) {
+ case "cololight":
+ var ledProperties = devicesProperties[ledType][key];
+
+ var hardwareLedCount = 1;
+ if (ledProperties) {
+ hardwareLedCount = ledProperties.ledCount;
+ }
+ conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(hardwareLedCount);
+ break;
+ case "wled":
+ var ledProperties = devicesProperties[ledType][key];
+
+ if (ledProperties && ledProperties.leds) {
+ hardwareLedCount = ledProperties.leds.count;
+ }
+ conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(hardwareLedCount);
+ break;
+
+ case "nanoleaf":
+ var ledProperties = devicesProperties[ledType][key];
+
+ if (ledProperties && ledProperties.panelLayout.layout) {
+ //Identify non-LED type panels, e.g. Rhythm (1) and Shapes Controller (12)
+ var nonLedNum = 0;
+ for (const panel of ledProperties.panelLayout.layout.positionData) {
+ if (panel.shapeType === 1 || panel.shapeType === 12) {
+ nonLedNum++;
+ }
+ }
+ hardwareLedCount = ledProperties.panelLayout.layout.numPanels - nonLedNum;
+ }
+ conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(hardwareLedCount);
+
+ break;
+
+ case "atmo":
+ case "karate":
+ var ledProperties = devicesProperties[ledType][key];
+
+ if (ledProperties && ledProperties.ledCount) {
+ if (ledProperties.ledCount.length > 0) {
+ var configuredLedCount = window.serverConfig.device.hardwareLedCount;
+ var generalOpt = conf_editor.getEditor('root.generalOptions');
+ updateJsonEditorSelection(generalOpt, "hardwareLedCount", {}, ledProperties.ledCount, [], configuredLedCount);
+ }
+ }
+ break;
+
+ default:
+ }
+ }
+}
+
+function showInputOptions(path, elements, state) {
+ for (var i = 0; i < elements.length; i++) {
+ $('[data-schemapath="' + path + '.' + elements[i] + '"]').toggle(state);
+ }
+}
+
+function showInputOptionsForKey(editor, item, showForKey, state) {
+ var elements = [];
+ for (var key in editor.schema.properties[item].properties) {
+ if (showForKey !== key) {
+ var accessLevel = editor.schema.properties[item].properties[key].access;
+
+ //Only enable elements, if access level compliant
+ if (state && isAccessLevelCompliant(accessLevel)) {
+ elements.push(key);
+ }
+ }
+ showInputOptions("root." + item, elements, state);
+ }
+}
+
+function showAllDeviceInputOptions(showForKey, state) {
+ showInputOptionsForKey(conf_editor, "generalOptions", showForKey, state);
+ showInputOptionsForKey(conf_editor, "specificOptions", showForKey, state);
+}
diff --git a/assets/webconfig/js/ui_utils.js b/assets/webconfig/js/ui_utils.js
old mode 100644
new mode 100755
index 3f9ea3ef..126efbec
--- a/assets/webconfig/js/ui_utils.js
+++ b/assets/webconfig/js/ui_utils.js
@@ -53,7 +53,7 @@ function updateSessions() {
if (sess && sess.length) {
window.wSess = [];
for (var i = 0; i < sess.length; i++) {
- if (sess[i].type == "_hyperiond-http._tcp.") {
+ if (sess[i].type == "_http._tcp." || sess[i].type == "_https._tcp." || sess[i].type == "_hyperiond-http._tcp.") {
window.wSess.push(sess[i]);
}
}
@@ -134,13 +134,13 @@ function updateHyperionInstanceListing() {
var currInstMarker = (data[key].instance == window.currentHyperionInstance) ? "component-on" : "";
var html = ' \
- \
- \
- \
- '+ data[key].friendly_name + ' \
-
\
- \
- '
+ \
+ \
+ \
+ '+ data[key].friendly_name + ' \
+
\
+ \
+ '
if (data.length - 1 > key)
html += ' '
@@ -183,7 +183,6 @@ function initLanguageSelection() {
langText = availLangText[langIdx];
}
}
- //console.log("langLocale: ", langLocale, "langText: ", langText);
$('#language-select').prop('title', langText);
$("#language-select").val(langIdx);
@@ -463,6 +462,170 @@ function createJsonEditor(container, schema, setconfig, usePanel, arrayre) {
return editor;
}
+function updateJsonEditorSelection(editor, key, addElements, newEnumVals, newTitelVals, newDefaultVal, addSelect, addCustom, addCustomAsFirst, customText) {
+ var orginalProperties = editor.schema.properties[key];
+
+ var newSchema = [];
+ newSchema[key] =
+ {
+ "type": "string",
+ "enum": [],
+ "required": true,
+ "options": { "enum_titles": [], "infoText": "" },
+ "propertyOrder": 1
+ };
+
+ //Add additional elements to overwrite defaults
+ for (var item in addElements) {
+ newSchema[key][item] = addElements[item];
+ }
+
+ if (orginalProperties) {
+ if (orginalProperties["title"]) {
+ newSchema[key]["title"] = orginalProperties["title"];
+ }
+
+ if (orginalProperties["options"] && orginalProperties["options"]["infoText"]) {
+ newSchema[key]["options"]["infoText"] = orginalProperties["options"]["infoText"];
+ }
+
+ if (orginalProperties["propertyOrder"]) {
+ newSchema[key]["propertyOrder"] = orginalProperties["propertyOrder"];
+ }
+ }
+
+ if (addCustom) {
+
+ if (newTitelVals.length === 0) {
+ newTitelVals = [...newEnumVals];
+ }
+
+ if (!!!customText) {
+ customText = "edt_conf_enum_custom";
+ }
+
+ if (addCustomAsFirst) {
+ newEnumVals.unshift("CUSTOM");
+ newTitelVals.unshift(customText);
+ } else {
+ newEnumVals.push("CUSTOM");
+ newTitelVals.push(customText);
+ }
+
+ if (newSchema[key].options.infoText) {
+ var customInfoText = newSchema[key].options.infoText + "_custom";
+ newSchema[key].options.infoText = customInfoText;
+ }
+ }
+
+ if (addSelect) {
+ newEnumVals.unshift("SELECT");
+ newTitelVals.unshift("edt_conf_enum_please_select");
+ newDefaultVal = "SELECT";
+ }
+
+ if (newEnumVals) {
+ newSchema[key]["enum"] = newEnumVals;
+ }
+
+ if (newTitelVals) {
+ newSchema[key]["options"]["enum_titles"] = newTitelVals;
+ }
+ if (newDefaultVal) {
+ newSchema[key]["default"] = newDefaultVal;
+ }
+
+ editor.original_schema.properties[key] = orginalProperties;
+ editor.schema.properties[key] = newSchema[key];
+
+ editor.removeObjectProperty(key);
+ delete editor.cached_editors[key];
+ editor.addObjectProperty(key);
+}
+
+function updateJsonEditorMultiSelection(editor, key, addElements, newEnumVals, newTitelVals, newDefaultVal) {
+ var orginalProperties = editor.schema.properties[key];
+
+ var newSchema = [];
+ newSchema[key] =
+ {
+ "type": "array",
+ "format": "select",
+ "items": {
+ "type": "string",
+ "enum": [],
+ "options": { "enum_titles": [] },
+ },
+ "options": { "infoText": "" },
+ "default": [],
+ "propertyOrder": 1
+ };
+
+ //Add additional elements to overwrite defaults
+ for (var item in addElements) {
+ newSchema[key][item] = addElements[item];
+ }
+
+ if (orginalProperties) {
+ if (orginalProperties["title"]) {
+ newSchema[key]["title"] = orginalProperties["title"];
+ }
+
+ if (orginalProperties["options"] && orginalProperties["options"]["infoText"]) {
+ newSchema[key]["options"]["infoText"] = orginalProperties["options"]["infoText"];
+ }
+
+ if (orginalProperties["propertyOrder"]) {
+ newSchema[key]["propertyOrder"] = orginalProperties["propertyOrder"];
+ }
+ }
+
+ if (newEnumVals) {
+ newSchema[key]["items"]["enum"] = newEnumVals;
+ }
+
+ if (newTitelVals) {
+ newSchema[key]["items"]["options"]["enum_titles"] = newTitelVals;
+ }
+
+ if (newDefaultVal) {
+ newSchema[key]["default"] = newDefaultVal;
+ }
+
+ editor.original_schema.properties[key] = orginalProperties;
+ editor.schema.properties[key] = newSchema[key];
+
+ editor.removeObjectProperty(key);
+ delete editor.cached_editors[key];
+ editor.addObjectProperty(key);
+}
+
+function updateJsonEditorRange(editor, key, minimum, maximum, defaultValue, step) {
+ var orginalProperties = editor.schema.properties[key];
+ var newSchema = [];
+ newSchema[key] = orginalProperties;
+
+ if (minimum) {
+ newSchema[key]["minimum"] = minimum;
+ }
+ if (maximum) {
+ newSchema[key]["maximum"] = maximum;
+ }
+ if (defaultValue) {
+ newSchema[key]["default"] = defaultValue;
+ }
+ if (step) {
+ newSchema[key]["step"] = step;
+ }
+
+ editor.original_schema.properties[key] = orginalProperties;
+ editor.schema.properties[key] = newSchema[key];
+
+ editor.removeObjectProperty(key);
+ delete editor.cached_editors[key];
+ editor.addObjectProperty(key);
+}
+
function buildWL(link, linkt, cl) {
var baseLink = "https://docs.hyperion-project.org/";
var lang;
@@ -655,6 +818,48 @@ function createOptPanel(phicon, phead, bodyid, footerid) {
return createPanel(phead, "", pfooter, "panel-default", bodyid);
}
+function compareTwoValues(key1, key2, order = 'asc') {
+ return function innerSort(a, b) {
+ if (!a.hasOwnProperty(key1) || !b.hasOwnProperty(key1)) {
+ // property key1 doesn't exist on either object
+ return 0;
+ }
+
+ const varA1 = (typeof a[key1] === 'string')
+ ? a[key1].toUpperCase() : a[key1];
+ const varB1 = (typeof b[key1] === 'string')
+ ? b[key1].toUpperCase() : b[key1];
+
+ let comparison = 0;
+ if (varA1 > varB1) {
+ comparison = 1;
+ } else {
+ if (varA1 < varB1) {
+ comparison = -1;
+ } else {
+ if (!a.hasOwnProperty(key2) || !b.hasOwnProperty(key2)) {
+ // property key2 doesn't exist on either object
+ return 0;
+ }
+
+ const varA2 = (typeof a[key2] === 'string')
+ ? a[key2].toUpperCase() : a[key2];
+ const varB2 = (typeof b[key1] === 'string')
+ ? b[key2].toUpperCase() : b[key2];
+
+ if (varA2 > varB2) {
+ comparison = 1;
+ } else {
+ comparison = -1;
+ }
+ }
+ }
+ return (
+ (order === 'desc') ? (comparison * -1) : comparison
+ );
+ };
+}
+
function sortProperties(list) {
for (var key in list) {
list[key].key = key;
@@ -876,3 +1081,19 @@ function handleDarkMode() {
$('#btn_darkmode_icon').removeClass('fa fa-moon-o');
$('#btn_darkmode_icon').addClass('fa fa-sun-o');
}
+
+function isAccessLevelCompliant(accessLevel) {
+ var isOK = true;
+ if (accessLevel) {
+ if (accessLevel === 'system') {
+ isOK = false;
+ }
+ else if (accessLevel === 'advanced' && storedAccess === 'default') {
+ isOK = false;
+ }
+ else if (accessLevel === 'expert' && storedAccess !== 'expert') {
+ isOK = false;
+ }
+ }
+ return isOK
+}
diff --git a/assets/webconfig/js/wizard.js b/assets/webconfig/js/wizard.js
old mode 100644
new mode 100755
index 36bc09aa..620b3b62
--- a/assets/webconfig/js/wizard.js
+++ b/assets/webconfig/js/wizard.js
@@ -424,7 +424,7 @@ function startWizardCC() {
}
//create html
$('#wiz_header').html(' ' + $.i18n('wiz_cc_title'));
- $('#wizp1_body').html('' + $.i18n('wiz_cc_title') + ' ' + $.i18n('wiz_cc_intro1') + '
' + $.i18n('wiz_cc_kwebs') + ' ');
+ $('#wizp1_body').html('' + $.i18n('wiz_cc_title') + ' ' + $.i18n('wiz_cc_intro1') + '
' + $.i18n('wiz_cc_kwebs') + ' ');
$('#wizp1_footer').html(' ' + $.i18n('general_btn_continue') + ' ' + $.i18n('general_btn_cancel') + ' ');
$('#wizp2_body').html('
');
$('#wizp2_footer').html(' ' + $.i18n('general_btn_back') + '' + $.i18n('general_btn_next') + ' ' + $.i18n('general_btn_save') + ' ' + $.i18n('general_btn_cancel') + ' ');
@@ -437,10 +437,9 @@ function startWizardCC() {
});
$('#wiz_cc_kodiip').off().on('change', function () {
-
kodiAddress = $(this).val().trim();
$('#wizp1_body').find("kodiAddress").val(kodiAddress);
-
+
$('#kodi_status').html('');
// Remove Kodi's default Web-Socket port (9090) from display and ensure Kodi's default REST-API port (8080) is mapped to web-socket port to ease migration
@@ -788,8 +787,6 @@ async function discover_hue_bridges() {
const r = res.info;
// Process devices returned by discovery
- console.log(r);
-
if (r.devices.length == 0)
$('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
else {
@@ -832,7 +829,7 @@ async function identify_hue_device(hostAddress, username, id) {
$('#btn_wiz_save').attr('disabled', true);
let params = { host: hostAddress, user: username, lightId: id };
- const res = await requestLedDeviceIdentification('philipshue', params);
+ await requestLedDeviceIdentification('philipshue', params);
if (!window.readOnlyMode) {
$('#btn_wiz_save').attr('disabled', false);
@@ -1187,7 +1184,6 @@ function get_hue_lights() {
}
(cC == 0 || window.readOnlyMode) ? $('#btn_wiz_save').attr("disabled", true) : $('#btn_wiz_save').attr("disabled", false);
-
});
}
$('.hue_sel_watch').trigger('change');
@@ -1208,108 +1204,6 @@ function abortConnection(UserInterval) {
$("#wiz_hue_usrstate").html($.i18n('wiz_hue_failure_connection'));
}
-//****************************
-// Wizard WLED
-//****************************
-var lights = null;
-function startWizardWLED(e) {
- //create html
-
- var wled_title = 'wiz_wled_title';
- var wled_intro1 = 'wiz_wled_intro1';
-
- $('#wiz_header').html(' ' + $.i18n(wled_title));
- $('#wizp1_body').html('' + $.i18n(wled_title) + ' ' + $.i18n(wled_intro1) + '
');
- $('#wizp1_footer').html(' ' + $.i18n('general_btn_continue') + ' ' + $.i18n('general_btn_cancel') + ' ');
-
- /*$('#wizp2_body').html('
');
-
- $('#wh_topcontainer').append('
');
-
- $('#wizp2_body').append(''+$.i18n('wiz_wled_desc2')+'
');
-
- createTable("lidsh", "lidsb", "hue_ids_t");
- $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lights_title'),$.i18n('wiz_pos'),$.i18n('wiz_identify')], true));
- $('#wizp2_footer').html(' '+$.i18n('general_btn_save')+' '+$.i18n('general_btn_cancel')+' ');
-*/
- //open modal
- $("#wizard_modal").modal({
- backdrop: "static",
- keyboard: false,
- show: true
- });
-
- //listen for continue
- $('#btn_wiz_cont').off().on('click', function () {
- /* For testing only
-
- discover_wled();
-
- var hostAddress = conf_editor.getEditor("root.specificOptions.host").getValue();
- if(hostAddress != "")
- {
- getProperties_wled(hostAddress,"info");
- identify_wled(hostAddress)
- }
-
- For testing only */
- });
-}
-
-async function discover_wled() {
- const res = await requestLedDeviceDiscovery('wled');
-
- // TODO: error case unhandled
- // res can be: false (timeout) or res.error (not found)
- if (res && !res.error) {
- const r = res.info
-
- // Process devices returned by discovery
- console.log(r);
-
- if (r.devices.length == 0)
- $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
- else {
- for (const device of r.devices) {
- console.log("Device:", device);
-
- var ip = device.hostname + ":" + device.port;
- console.log("Host:", ip);
-
- //wledIPs.push({internalipaddress : ip});
- }
- }
- }
-}
-
-async function getProperties_wled(hostAddress, resourceFilter) {
- let params = { host: hostAddress, filter: resourceFilter };
-
- const res = await requestLedDeviceProperties('wled', params);
-
- // TODO: error case unhandled
- // res can be: false (timeout) or res.error (not found)
- if (res && !res.error) {
- const r = res.info
-
- // Process properties returned
- console.log(r);
- }
-}
-
-async function identify_wled(hostAddress) {
-
- // Take care that new record cannot be save during background process
- $('#btn_wiz_save').attr('disabled', true);
-
- let params = { host: hostAddress };
- const res = await requestLedDeviceIdentification('wled', params);
-
- if (!window.readOnlyMode) {
- $('#btn_wiz_save').attr('disabled', false);
- }
-}
-
//****************************
// Wizard Yeelight
//****************************
@@ -1438,8 +1332,17 @@ async function discover_yeelight_lights() {
var light = {};
light.host = device.hostname;
light.port = device.port;
- light.name = device.other.name;
- light.model = device.other.model;
+
+ if (device.txt) {
+ light.name = device.name;
+ light.model = device.txt.md;
+ //Yeelight does not provide correct API port with mDNS response, use default one
+ light.port = 55443;
+ }
+ else {
+ light.name = device.other.name;
+ light.model = device.other.model;
+ }
lights.push(light);
}
}
@@ -1469,7 +1372,8 @@ async function discover_yeelight_lights() {
}
function assign_yeelight_lights() {
- var models = ['color', 'color1', 'color2', 'color4', 'stripe', 'strip1'];
+ // Model mappings, see https://www.home-assistant.io/integrations/yeelight/
+ var models = ['color', 'color1', 'YLDP02YL', 'YLDP02YL', 'color2', 'YLDP06YL', 'color4', 'YLDP13YL', 'stripe', 'YLDD04YL', 'strip1', 'YLDD01YL', 'YLDD02YL'];
// If records are left for configuration
if (Object.keys(lights).length > 0) {
@@ -1534,7 +1438,7 @@ function assign_yeelight_lights() {
$('.yee_sel_watch').trigger('change');
}
else {
- var noLightsTxt = '' + $.i18n('wiz_noLights','Yeelights') + '
';
+ var noLightsTxt = '' + $.i18n('wiz_noLights', 'Yeelights') + '
';
$('#wizp2_body').append(noLightsTxt);
}
}
@@ -1555,15 +1459,14 @@ async function getProperties_yeelight(hostname, port) {
}
async function identify_yeelight_device(hostname, port) {
-
// Take care that new record cannot be save during background process
$('#btn_wiz_save').attr('disabled', true);
let params = { hostname: hostname, port: port };
- const res = await requestLedDeviceIdentification("yeelight", params);
+ await requestLedDeviceIdentification("yeelight", params);
if (!window.readOnlyMode) {
- $('#btn_wiz_save').attr('disabled', false);
+ $('#btn_wiz_save').attr('disabled', false);
}
}
@@ -1675,14 +1578,12 @@ async function discover_atmoorb_lights(multiCastGroup, multiCastPort) {
var light = {};
var params = {};
- if (multiCastGroup !== "")
- {
+ if (multiCastGroup !== "") {
params.multiCastGroup = multiCastGroup;
}
- if (multiCastPort !== 0)
- {
- params.multiCastPort = multiCastPort;
+ if (multiCastPort !== 0) {
+ params.multiCastPort = multiCastPort;
}
// Get discovered lights
@@ -1692,7 +1593,7 @@ async function discover_atmoorb_lights(multiCastGroup, multiCastPort) {
// res can be: false (timeout) or res.error (not found)
if (res && !res.error) {
const r = res.info;
-
+
// Process devices returned by discovery
for (const device of r.devices) {
if (device.id !== "") {
@@ -1774,7 +1675,7 @@ function assign_atmoorb_lights() {
$('.lidsb').append(createTableRow([orbId + lightAnnotation, ''
+ options
- + ' ', ''
+ + '', ''
+ $.i18n('wiz_identify_light', orbId) + ' ']));
}
@@ -1793,303 +1694,19 @@ function assign_atmoorb_lights() {
$('.orb_sel_watch').trigger('change');
}
else {
- var noLightsTxt = '' + $.i18n('wiz_noLights','AtmoOrbs') + '
';
+ var noLightsTxt = '' + $.i18n('wiz_noLights', 'AtmoOrbs') + '
';
$('#wizp2_body').append(noLightsTxt);
}
}
async function identify_atmoorb_device(orbId) {
-
// Take care that new record cannot be save during background process
$('#btn_wiz_save').attr('disabled', true);
let params = { id: orbId };
- const res = await requestLedDeviceIdentification("atmoorb", params);
+ await requestLedDeviceIdentification("atmoorb", params);
if (!window.readOnlyMode) {
- $('#btn_wiz_save').attr('disabled', false);
- }
-}
-
-//****************************
-// Wizard/Routines Nanoleaf
-//****************************
-async function discover_nanoleaf() {
- const res = await requestLedDeviceDiscovery('nanoleaf');
-
- // TODO: error case unhandled
- // res can be: false (timeout) or res.error (not found)
- if (res && !res.error) {
- const r = res.info
-
- // Process devices returned by discovery
- console.log(r);
-
- if (r.devices.length == 0)
- $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
- else {
- for (const device of r.devices) {
- console.log("Device:", device);
-
- var ip = device.hostname + ":" + device.port;
- console.log("Host:", ip);
-
- //nanoleafIPs.push({internalipaddress : ip});
- }
- }
- }
-}
-
-async function getProperties_nanoleaf(hostAddress, authToken, resourceFilter) {
- let params = { host: hostAddress, token: authToken, filter: resourceFilter };
-
- const res = await requestLedDeviceProperties('nanoleaf', params);
-
- // TODO: error case unhandled
- // res can be: false (timeout) or res.error (not found)
- if (res && !res.error) {
- const r = res.info
-
- // Process properties returned
- console.log(r);
- }
-}
-
-async function identify_nanoleaf(hostAddress, authToken) {
-
- // Take care that new record cannot be save during background process
- $('#btn_wiz_save').attr('disabled', true);
-
- let params = { host: hostAddress, token: authToken };
- const res = await requestLedDeviceIdentification('nanoleaf', params);
-
- if (!window.readOnlyMode) {
- $('#btn_wiz_save').attr('disabled', false);
- }
-}
-
-//****************************
-// Wizard Cololight
-//****************************
-var lights = null;
-var selectedLightId = null;
-
-function startWizardCololight(e) {
- //create html
-
- var cololight_title = 'wiz_cololight_title';
- var cololight_intro1 = 'wiz_cololight_intro1';
-
- $('#wiz_header').html(' ' + $.i18n(cololight_title));
- $('#wizp1_body').html('' + $.i18n(cololight_title) + ' ' + $.i18n(cololight_intro1) + '
');
- $('#wizp1_footer').html(' ' + $.i18n('general_btn_continue') + ' ' + $.i18n('general_btn_cancel') + ' ');
-
- $('#wizp2_body').html('
');
-
- $('#wh_topcontainer').append('
');
-
- $('#wizp2_body').append('' + $.i18n('wiz_cololight_desc2') + '
');
-
- createTable("lidsh", "lidsb", "colo_ids_t");
- $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lights_title'), $.i18n('wiz_identify')], true));
- $('#wizp2_footer').html(' '
- + $.i18n('general_btn_save') + ' '
- + $.i18n('general_btn_cancel') + ' ');
-
- //open modal
- $("#wizard_modal").modal({
- backdrop: "static",
- keyboard: false,
- show: true
- });
-
- //listen for continue
- $('#btn_wiz_cont').off().on('click', function () {
- beginWizardCololight();
- $('#wizp1').toggle(false);
- $('#wizp2').toggle(true);
- });
-}
-
-function beginWizardCololight() {
- lights = [];
-
- discover_cololights();
-
- $('#btn_wiz_save').off().on("click", function () {
- //LED device config
- //Start with a clean configuration
- var d = {};
-
- d.type = 'cololight';
-
- //Cololight does not resolve into stable hostnames (as devices named the same), therefore use IP
- if (!lights[selectedLightId].ip) {
- d.host = lights[selectedLightId].host;
- } else {
- d.host = lights[selectedLightId].ip;
- }
-
- var coloLightProperties = lights[selectedLightId].props.properties;
- if (Object.keys(coloLightProperties).length === 0) {
- alert($.i18n('wiz_cololight_noprops'));
- d.hardwareLedCount = 1;
- }
- else {
- d.hardwareLedCount = coloLightProperties.ledCount;
- }
-
- d.colorOrder = conf_editor.getEditor("root.generalOptions.colorOrder").getValue();
- d.latchTime = parseInt(conf_editor.getEditor("root.specificOptions.latchTime").getValue());;
-
- window.serverConfig.device = d;
-
- //LED layout - have initial layout prepared matching the LED-count
-
- var coloLightLedConfig = [];
-
- if (coloLightProperties.modelType === "Strip") {
- coloLightLedConfig = createClassicLedLayoutSimple(d.hardwareLedCount / 2, d.hardwareLedCount / 4, d.hardwareLedCount / 4, 0, d.hardwareLedCount / 4 * 3, false);
- } else {
- coloLightLedConfig = createClassicLedLayoutSimple(0, 0, 0, d.hardwareLedCount, 0, true);
- }
-
- window.serverConfig.leds = coloLightLedConfig;
-
- //smoothing off
- window.serverConfig.smoothing.enable = false;
-
- requestWriteConfig(window.serverConfig, true);
-
- resetWizard();
- });
-
- $('#btn_wiz_abort').off().on('click', resetWizard);
-}
-
-async function discover_cololights() {
- const res = await requestLedDeviceDiscovery('cololight');
-
- if (res && !res.error) {
- const r = res.info;
-
- // Process devices returned by discovery
- for (const device of r.devices) {
- if (device.ip !== "") {
- if (getIpInLights(device.ip).length === 0) {
- var light = {};
- light.ip = device.ip;
- light.host = device.hostname;
- light.name = device.name;
- light.type = device.type;
- lights.push(light);
- }
- }
- }
- assign_cololight_lights();
- }
-}
-
-function assign_cololight_lights() {
- // If records are left for configuration
- if (Object.keys(lights).length > 0) {
- $('#wh_topcontainer').toggle(false);
- $('#colo_ids_t, #btn_wiz_save').toggle(true);
-
- $('.lidsb').html("");
-
- var options = "";
-
- for (var lightid in lights) {
- lights[lightid].id = lightid;
-
- var lightHostname = lights[lightid].host;
- var lightIP = lights[lightid].ip;
-
- var val = lightHostname + " (" + lightIP + ")";
- options += '' + val + ' ';
- }
-
- var enabled = 'enabled';
-
- $('.lidsb').append(createTableRow([''
- + options
- + ' ', ''
- + $.i18n('wiz_identify') + ' ']));
-
- $('.colo_sel_watch').bind("change", function () {
- selectedLightId = $('#colo_select_id').val();
- var lightIP = lights[selectedLightId].ip;
-
- $('#wiz_identify_btn').unbind().bind('click', function (event) { identify_cololight_device(lightIP); });
-
- if (!lights[selectedLightId].props) {
- getProperties_cololight(lightIP);
- }
- });
- $('.colo_sel_watch').trigger('change');
- }
- else {
- var noLightsTxt = '' + $.i18n('wiz_noLights','Cololights') + '
';
- $('#wizp2_body').append(noLightsTxt);
- }
-}
-
-async function getProperties_cololight(ip) {
- let params = { host: ip };
-
- const res = await requestLedDeviceProperties('cololight', params);
-
- if (res && !res.error) {
- var coloLightProperties = res.info;
-
- //Store properties along light with given IP-address
- var id = getIpInLights(ip)[0].id;
- lights[id].props = coloLightProperties;
- }
-}
-
-async function identify_cololight_device(hostAddress) {
-
- // Take care that new record cannot be save during background process
- $('#btn_wiz_save').attr('disabled', true);
-
- let params = { host: hostAddress };
- const res = await requestLedDeviceIdentification('cololight', params);
-
- if (!window.readOnlyMode) {
- $('#btn_wiz_save').attr('disabled', false);
- }
-}
-
-//****************************
-// Wizard/Routines RS232-Devices
-//****************************
-async function discover_providerRs232(rs232Type) {
- const res = await requestLedDeviceDiscovery(rs232Type);
-
- // TODO: error case unhandled
- // res can be: false (timeout) or res.error (not found)
- if (res && !res.error) {
- const r = res.info
-
- // Process serialPorts returned by discover
- console.log(r);
- }
-}
-
-//****************************
-// Wizard/Routines HID (USB)-Devices
-//****************************
-async function discover_providerHid(hidType) {
- const res = await requestLedDeviceDiscovery(hidType);
-
- // TODO: error case unhandled
- // res can be: false (timeout) or res.error (not found)
- if (res && !res.error) {
- const r = res.info
-
- // Process HID returned by discover
- console.log(r);
+ $('#btn_wiz_save').attr('disabled', false);
}
}
diff --git a/cmake/debian/postinst b/cmake/debian/postinst
index 140a6962..4cef9515 100644
--- a/cmake/debian/postinst
+++ b/cmake/debian/postinst
@@ -141,8 +141,8 @@ echo "---> or if already used by another service try: ${NET_IP}:8091"
$REBOOTMESSAGE
echo "-----------------------------------------------------------------------------"
echo "Webpage: www.hyperion-project.org"
-echo "Wiki: wiki.hyperion-project.org"
-echo "Forum: forum.hyperion-project.org"
+echo "Forum: www.hyperion-project.org"
+echo "Documenation: docs.hyperion-project.org"
echo "-----------------------------------------------------------------------------"
diff --git a/cmake/packages.cmake b/cmake/packages.cmake
index 2626516e..d58ae627 100644
--- a/cmake/packages.cmake
+++ b/cmake/packages.cmake
@@ -34,7 +34,10 @@ endif()
SET ( CPACK_PACKAGE_NAME "Hyperion" )
SET ( CPACK_PACKAGE_DESCRIPTION_SUMMARY "Hyperion is an open source ambient light implementation" )
SET ( CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md" )
-SET ( CPACK_PACKAGE_FILE_NAME "Hyperion-${HYPERION_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
+
+# Replease "+", as cmake/rpm has an issue if "+" occurs in CPACK_PACKAGE_VERSION
+string(REPLACE "+" "." HYPERION_PACKAGE_VERSION ${HYPERION_VERSION})
+SET ( CPACK_PACKAGE_FILE_NAME "Hyperion-${HYPERION_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
SET ( CPACK_PACKAGE_CONTACT "packages@hyperion-project.org")
SET ( CPACK_PACKAGE_VENDOR "hyperion-project")
diff --git a/cmake/rpm/postinst b/cmake/rpm/postinst
index 836b7ff3..171b97b5 100644
--- a/cmake/rpm/postinst
+++ b/cmake/rpm/postinst
@@ -131,8 +131,8 @@ echo "---> or if already used by another service try: ${NET_IP}:8091"
$REBOOTMESSAGE
echo "-----------------------------------------------------------------------------"
echo "Webpage: www.hyperion-project.org"
-echo "Wiki: wiki.hyperion-project.org"
-echo "Forum: forum.hyperion-project.org"
+echo "Forum: www.hyperion-project.org"
+echo "Documenation: docs.hyperion-project.org"
echo "-----------------------------------------------------------------------------"
diff --git a/include/hyperion/SettingsManager.h b/include/hyperion/SettingsManager.h
index 027d0ece..cdb22f3c 100644
--- a/include/hyperion/SettingsManager.h
+++ b/include/hyperion/SettingsManager.h
@@ -3,9 +3,14 @@
#include
#include
+#include
+using namespace semver;
+
// qt includes
#include
+const int GLOABL_INSTANCE_ID = 255;
+
class Hyperion;
class SettingsTable;
@@ -61,12 +66,17 @@ private:
bool handleConfigUpgrade(QJsonObject& config);
- /// Hyperion instance
- Hyperion* _hyperion;
+ bool resolveConfigVersion(QJsonObject& config);
/// Logger instance
Logger* _log;
+ /// Hyperion instance
+ Hyperion* _hyperion;
+
+ /// Instance number
+ quint8 _instance;
+
/// instance of database table interface
SettingsTable* _sTable;
@@ -76,5 +86,8 @@ private:
/// the current configuration of this instance
QJsonObject _qconfig;
+ semver::version _configVersion;
+ semver::version _previousVersion;
+
bool _readonlyMode;
};
diff --git a/include/leddevice/LedDevice.h b/include/leddevice/LedDevice.h
index d725517e..aebfcd46 100644
--- a/include/leddevice/LedDevice.h
+++ b/include/leddevice/LedDevice.h
@@ -300,10 +300,21 @@ protected:
/// even if the device is not in enabled state (allowing to have a defined state during device power-off).
/// @note: latch-time is considered between each write
///
- /// @param[in] numberOfWrites Write Black given number of times
+ /// @param[in] numberOfWrites Write Black a given number of times
/// @return Zero on success else negative
///
- virtual int writeBlack(int numberOfBlack=1);
+ virtual int writeBlack(int numberOfWrites = 1);
+
+ ///
+ /// @brief Writes a color to the output stream,
+ /// even if the device is not in enabled state (allowing to have a defined state during device power-off).
+ /// @note: latch-time is considered between each write
+ ///
+ /// @param[in] color to be written
+ /// @param[in] numberOfWrites Write the color a given number of times
+ /// @return Zero on success else negative
+ ///
+ virtual int writeColor(const ColorRgb& color, int numberOfWrites = 1);
///
/// @brief Power-/turn on the LED-device.
@@ -431,7 +442,7 @@ protected slots:
///
/// @param[in] errorMsg The error message to be logged
///
- virtual void setInError( const QString& errorMsg);
+ virtual void setInError( const QString& errorMsg);
private:
diff --git a/include/utils/version.hpp b/include/utils/version.hpp
new file mode 100644
index 00000000..1e4d020d
--- /dev/null
+++ b/include/utils/version.hpp
@@ -0,0 +1,550 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+/**
+ * Semver - The Semantic Versioning, https://github.com/euskadi31/semver-cpp
+ *
+ * Copyright (c) 2013 Axel Etcheverry, 2021 enhancements & fixes Lord-Grey
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+#include
+#include
+
+namespace semver {
+
+ enum PRE_RELEASE {
+ PRE_RELEASE_ALPHA,
+ PRE_RELEASE_BETA,
+ PRE_RELEASE_RC,
+ PRE_RELEASE_NONE
+ };
+
+ typedef enum PRE_RELEASE pre_release_t;
+
+ class version
+ {
+ private:
+ std::string m_version;
+ int m_major;
+ int m_minor;
+ int m_patch;
+ pre_release_t m_pre_release_type;
+ std::string m_pre_release_id;
+ std::string m_pre_release;
+ std::string m_build;
+ bool m_is_valid;
+ bool m_is_stable;
+
+ enum m_type {
+ TYPE_MAJOR,
+ TYPE_MINOR,
+ TYPE_PATCH,
+ TYPE_PRE_RELEASE,
+ TYPE_PRE_RELEASE_ID,
+ TYPE_BUILD
+ };
+
+ void parse()
+ {
+ int type = TYPE_MAJOR;
+
+ std::string major, minor, patch;
+
+ for (std::size_t i = 0; i < m_version.length(); i++)
+ {
+ char chr = m_version[i];
+ int chr_dec = chr;
+
+ switch (type)
+ {
+ case TYPE_MAJOR:
+
+ if (chr == '.')
+ {
+ type = TYPE_MINOR;
+ continue;
+ }
+
+ if (chr_dec < 48 || chr_dec > 57)
+ {
+ m_is_valid = false;
+ }
+
+ // major
+ major += chr;
+ break;
+
+ case TYPE_MINOR:
+
+ if (chr == '.')
+ {
+ type = TYPE_PATCH;
+ continue;
+ }
+
+ if (chr_dec < 48 || chr_dec > 57)
+ {
+ m_is_valid = false;
+ }
+
+ minor += chr;
+
+ break;
+
+ case TYPE_PATCH:
+
+ if (chr == '-')
+ {
+ type = TYPE_PRE_RELEASE;
+ continue;
+ }
+
+ if (chr == '+')
+ {
+ type = TYPE_BUILD;
+ continue;
+ }
+
+
+ if (chr_dec < 48 || chr_dec > 57)
+ {
+ m_is_valid = false;
+ }
+
+ patch += chr;
+
+ break;
+
+ case TYPE_PRE_RELEASE:
+
+ if (chr == '.')
+ {
+ type = TYPE_PRE_RELEASE_ID;
+ m_pre_release += chr;
+ continue;
+ }
+
+ if (chr == '+')
+ {
+ type = TYPE_BUILD;
+ continue;
+ }
+
+ if (
+ (chr_dec < 48 || chr_dec > 57) && // 0-9
+ (chr_dec < 65 || chr_dec > 90) && // A-Z
+ (chr_dec < 97 || chr_dec > 122) && // a-z
+ (chr_dec != 45) && // -
+ (chr_dec != 46) // .
+ )
+ {
+ m_is_valid = false;
+ }
+
+ m_pre_release += chr;
+ break;
+
+ case TYPE_PRE_RELEASE_ID:
+
+ if (chr == '+')
+ {
+ type = TYPE_BUILD;
+ continue;
+ }
+
+ if (
+ (chr_dec < 48 || chr_dec > 57) && // 0-9
+ (chr_dec < 65 || chr_dec > 90) && // A-Z
+ (chr_dec < 97 || chr_dec > 122) && // a-z
+ (chr_dec != 45) // -
+ )
+ {
+ m_is_valid = false;
+ }
+
+ m_pre_release += chr;
+ m_pre_release_id += chr;
+ break;
+
+ case TYPE_BUILD:
+
+ if (
+ (chr_dec < 48 || chr_dec > 57) && // 0-9
+ (chr_dec < 65 || chr_dec > 90) && // A-Z
+ (chr_dec < 97 || chr_dec > 122) && // a-z
+ (chr_dec != 45) // -
+ )
+ {
+ m_is_valid = false;
+ }
+
+ m_build += chr;
+ break;
+ }
+ }
+
+ if (m_is_valid)
+ {
+ std::istringstream(major) >> m_major;
+ std::istringstream(minor) >> m_minor;
+ std::istringstream(patch) >> m_patch;
+
+ if (m_pre_release.empty())
+ {
+ m_pre_release_type = PRE_RELEASE_NONE;
+ }
+ else if (m_pre_release.find("alpha") != std::string::npos)
+ {
+ m_pre_release_type = PRE_RELEASE_ALPHA;
+ }
+ else if (m_pre_release.find("beta") != std::string::npos)
+ {
+ m_pre_release_type = PRE_RELEASE_BETA;
+ }
+ else if (m_pre_release.find("rc") != std::string::npos)
+ {
+ m_pre_release_type = PRE_RELEASE_RC;
+ }
+
+ if (m_major == 0 && m_minor == 0 && m_patch == 0)
+ {
+ m_is_valid = false;
+ }
+
+ if (!m_pre_release_id.empty() && m_pre_release_id[0] == '0')
+ {
+ m_is_valid = false;
+ }
+
+ if (m_major == 0)
+ {
+ m_is_stable = false;
+ }
+
+ if (m_pre_release_type != PRE_RELEASE_NONE)
+ {
+ m_is_stable = false;
+ }
+ }
+ }
+
+ public:
+ /**
+ * Parse the version string
+ */
+ version(const std::string& version)
+ {
+ setVersion(version);
+ }
+
+ version(const version&) = default;
+
+ ~version() = default;
+
+ /**
+ * Set version
+ */
+ bool setVersion(const std::string& version)
+ {
+ m_version = version;
+ m_major = 0;
+ m_minor = 0;
+ m_patch = 0;
+ m_build = "";
+ m_pre_release = "";
+ m_pre_release_id = "";
+ m_is_stable = true;
+
+ if (version.empty())
+ {
+ m_is_valid = false;
+ }
+ else
+ {
+ m_is_valid = true;
+
+ parse();
+ }
+ return m_is_valid;
+ }
+
+ /**
+ * Get full version
+ */
+ const std::string& getVersion() const
+ {
+ return m_version;
+ }
+
+ /**
+ * Get the major of the version
+ */
+ const int& getMajor() const
+ {
+ return m_major;
+ }
+
+ /**
+ * Get the minor of the version
+ */
+ const int& getMinor() const
+ {
+ return m_minor;
+ }
+
+ /**
+ * Get the patch of the version
+ */
+ const int& getPatch() const
+ {
+ return m_patch;
+ }
+
+ /**
+ * Get the build of the version
+ */
+ const std::string& getBuild() const
+ {
+ return m_build;
+ }
+
+ /**
+ * Get the release type of the version
+ */
+ const pre_release_t& getPreReleaseType() const
+ {
+ return m_pre_release_type;
+ }
+
+ /**
+ * Get the release identifier of the version
+ */
+ const std::string& getPreReleaseId() const
+ {
+ return m_pre_release_id;
+ }
+
+ /**
+ * Get the release of the version
+ */
+ const std::string& getPreRelease() const
+ {
+ return m_pre_release;
+ }
+
+ /**
+ * Check if the version is stable
+ */
+ const bool& isStable() const
+ {
+ return m_is_stable;
+ }
+
+ /**
+ * Check if the version is valid
+ */
+ const bool& isValid() const
+ {
+ return m_is_valid;
+ }
+
+
+ int compare(version& rgt)
+ {
+
+ if ((*this) == rgt)
+ {
+ return 0;
+ }
+
+ if ((*this) > rgt)
+ {
+ return 1;
+ }
+
+ return -1;
+ }
+
+ version& operator= (version& rgt)
+ {
+ if ((*this) != rgt)
+ {
+ this->m_version = rgt.getVersion();
+ this->m_major = rgt.getMajor();
+ this->m_minor = rgt.getMinor();
+ this->m_patch = rgt.getPatch();
+ this->m_pre_release_type = rgt.getPreReleaseType();
+ this->m_pre_release_id = rgt.getPreReleaseId();
+ this->m_pre_release = rgt.getPreRelease();
+ this->m_build = rgt.getBuild();
+ this->m_is_valid = rgt.isValid();
+ this->m_is_stable = rgt.isStable();
+ }
+
+ return *this;
+ }
+
+ friend bool operator== (version &lft, version &rgt)
+ {
+ return lft.getVersion().compare(rgt.getVersion()) == 0;
+ }
+
+ friend bool operator!= (version &lft, version &rgt)
+ {
+ return !(lft == rgt);
+ }
+
+ friend bool operator> (version &lft, version &rgt)
+ {
+ // Major
+ if (lft.getMajor() < 0 && rgt.getMajor() >= 0)
+ {
+ return false;
+ }
+
+ if (lft.getMajor() >= 0 && rgt.getMajor() < 0)
+ {
+ return true;
+ }
+
+ if (lft.getMajor() > rgt.getMajor())
+ {
+ return true;
+ }
+
+ if (lft.getMajor() < rgt.getMajor())
+ {
+ return false;
+ }
+
+
+ // Minor
+ if (lft.getMinor() < 0 && rgt.getMinor() >= 0)
+ {
+ return false;
+ }
+
+ if (lft.getMinor() >= 0 && rgt.getMinor() < 0)
+ {
+ return true;
+ }
+
+ if (lft.getMinor() > rgt.getMinor())
+ {
+ return true;
+ }
+
+ if (lft.getMinor() < rgt.getMinor())
+ {
+ return false;
+ }
+
+
+ // Patch
+ if (lft.getPatch() < 0 && rgt.getPatch() >= 0)
+ {
+ return false;
+ }
+
+ if (lft.getPatch() >= 0 && rgt.getPatch() < 0)
+ {
+ return true;
+ }
+
+ if (lft.getPatch() > rgt.getPatch())
+ {
+ return true;
+ }
+
+ if (lft.getPatch() < rgt.getPatch())
+ {
+ return false;
+ }
+
+ // Pre release
+ if (
+ (lft.getPreReleaseType() == rgt.getPreReleaseType()) &&
+ (lft.getPreReleaseId() == rgt.getPreReleaseId())
+ )
+ {
+ return false;
+ }
+
+ if (
+ (lft.getPreReleaseType() == rgt.getPreReleaseType()) &&
+ (lft.getPreReleaseId().find_first_not_of("0123456789") == std::string::npos) &&
+ (rgt.getPreReleaseId().find_first_not_of("0123456789") == std::string::npos)
+ )
+ {
+ if (atoi(lft.getPreReleaseId().c_str()) > atoi(rgt.getPreReleaseId().c_str()))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (
+ (lft.getPreReleaseType() == rgt.getPreReleaseType()) &&
+ (lft.getPreReleaseId().compare(rgt.getPreReleaseId()) > 0)
+ )
+ {
+ return true;
+ }
+
+ if (lft.getPreReleaseType() > rgt.getPreReleaseType())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ friend bool operator>= (version &lft, version &rgt)
+ {
+ return (lft > rgt) || (lft == rgt);
+ }
+
+ friend bool operator< (version &lft, version &rgt)
+ {
+ return (rgt > lft);
+ }
+
+ friend bool operator<= (version &lft, version &rgt)
+ {
+ return (lft < rgt) || (lft == rgt);
+ }
+
+ friend std::ostream& operator<< (std::ostream& out, const version& value)
+ {
+ out << value.getVersion();
+
+ return out;
+ }
+ };
+
+} // end semver namespace
+
+#endif // VERSION_H
diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp
index 14e14132..149a4458 100644
--- a/libsrc/hyperion/Hyperion.cpp
+++ b/libsrc/hyperion/Hyperion.cpp
@@ -83,7 +83,7 @@ void Hyperion::start()
}
// handle hwLedCount
- _hwLedCount = qMax(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount()), getLedCount());
+ _hwLedCount = getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount());
// Initialize colororder vector
for (const Led& led : _ledString.leds())
@@ -217,7 +217,7 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co
}
// handle hwLedCount update
- _hwLedCount = qMax(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount()), getLedCount());
+ _hwLedCount = getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount());
// change in leds are also reflected in adjustment
delete _raw2ledAdjustment;
@@ -231,7 +231,7 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co
QJsonObject dev = config.object();
// handle hwLedCount update
- _hwLedCount = qMax(dev["hardwareLedCount"].toInt(getLedCount()), getLedCount());
+ _hwLedCount = dev["hardwareLedCount"].toInt(getLedCount());
// force ledString update, if device ByteOrder changed
if(_ledDeviceWrapper->getColorOrder() != dev["colorOrder"].toString("rgb"))
diff --git a/libsrc/hyperion/SettingsManager.cpp b/libsrc/hyperion/SettingsManager.cpp
index b21c4c96..dca21298 100644
--- a/libsrc/hyperion/SettingsManager.cpp
+++ b/libsrc/hyperion/SettingsManager.cpp
@@ -4,6 +4,7 @@
// util
#include
#include
+#include "HyperionConfig.h"
// json schema process
#include
@@ -12,12 +13,23 @@
// write config to filesystem
#include
+#include
+using namespace semver;
+
+// Constants
+namespace {
+const char DEFAULT_VERSION[] = "2.0.0-alpha.8";
+} //End of constants
+
QJsonObject SettingsManager::schemaJson;
SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonlyMode)
: QObject(parent)
, _log(Logger::getInstance("SETTINGSMGR"))
+ , _instance(instance)
, _sTable(new SettingsTable(instance, this))
+ , _configVersion(DEFAULT_VERSION)
+ , _previousVersion(DEFAULT_VERSION)
, _readonlyMode(readonlyMode)
{
_sTable->setReadonlyMode(_readonlyMode);
@@ -38,7 +50,9 @@ SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonly
// get default config
QJsonObject defaultConfig;
if(!JsonUtils::readFile(":/hyperion_default.config", defaultConfig, _log))
+ {
throw std::runtime_error("Failed to read default config");
+ }
// transform json to string lists
QStringList keyList = defaultConfig.keys();
@@ -64,7 +78,7 @@ SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonly
_sTable->createSettingsRecord(key,val);
}
- // need to validate all data in database constuct the entire data object
+ // need to validate all data in database construct the entire data object
// TODO refactor schemaChecker to accept QJsonArray in validate(); QJsonDocument container? To validate them per entry...
QJsonObject dbConfig;
for(const auto & key : keyList)
@@ -76,8 +90,49 @@ SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonly
dbConfig[key] = doc.object();
}
+ //Check, if database requires migration
+ bool isNewRelease = false;
+ // Use instance independent SettingsManager to track migration status
+ if ( instance == GLOABL_INSTANCE_ID)
+ {
+ if ( resolveConfigVersion(dbConfig) )
+ {
+ QJsonObject newGeneralConfig = dbConfig["general"].toObject();
+
+ semver::version BUILD_VERSION(HYPERION_VERSION);
+ if ( _configVersion > BUILD_VERSION )
+ {
+ Error(_log, "Database version [%s] is greater that current Hyperion version [%s]", _configVersion.getVersion().c_str(), BUILD_VERSION.getVersion().c_str());
+ // TODO: Remove version checking and Settingsmanager from components' constructor to be able to stop hyperion.
+ }
+ else
+ {
+ if ( _previousVersion < BUILD_VERSION )
+ {
+ if ( _configVersion == BUILD_VERSION )
+ {
+ newGeneralConfig["previousVersion"] = BUILD_VERSION.getVersion().c_str();
+ dbConfig["general"] = newGeneralConfig;
+ isNewRelease = true;
+ Info(_log, "Migration completed to version [%s]", BUILD_VERSION.getVersion().c_str());
+ }
+ else
+ {
+ Info(_log, "Migration from current version [%s] to new version [%s] started", _previousVersion.getVersion().c_str(), BUILD_VERSION.getVersion().c_str());
+
+ newGeneralConfig["previousVersion"] = _configVersion.getVersion().c_str();
+ newGeneralConfig["configVersion"] = BUILD_VERSION.getVersion().c_str();
+ dbConfig["general"] = newGeneralConfig;
+ isNewRelease = true;
+ }
+ }
+ }
+ }
+ }
+
// possible data upgrade steps to prevent data loss
- if(handleConfigUpgrade(dbConfig))
+ bool migrated = handleConfigUpgrade(dbConfig);
+ if ( isNewRelease || migrated )
{
saveSettings(dbConfig, true);
}
@@ -193,77 +248,156 @@ bool SettingsManager::saveSettings(QJsonObject config, bool correct)
return rc;
}
+bool SettingsManager::resolveConfigVersion(QJsonObject& config)
+{
+ bool isValid = false;
+ if (config.contains("general"))
+ {
+ QJsonObject generalConfig = config["general"].toObject();
+ QString configVersion = generalConfig["configVersion"].toString();
+ QString previousVersion = generalConfig["previousVersion"].toString();
+
+ if ( !configVersion.isEmpty() )
+ {
+ isValid = _configVersion.setVersion(configVersion.toStdString());
+ }
+ else
+ {
+ _configVersion.setVersion(DEFAULT_VERSION);
+ isValid = true;
+ }
+
+ if ( !previousVersion.isEmpty() && isValid )
+ {
+ isValid = _previousVersion.setVersion(previousVersion.toStdString());
+ }
+ else
+ {
+ _previousVersion.setVersion(DEFAULT_VERSION);
+ isValid = true;
+ }
+ }
+ return isValid;
+}
+
bool SettingsManager::handleConfigUpgrade(QJsonObject& config)
{
bool migrated = false;
- // LED LAYOUT UPGRADE
- // from { hscan: { minimum: 0.2, maximum: 0.3 }, vscan: { minimum: 0.2, maximumn: 0.3 } }
- // from { h: { min: 0.2, max: 0.3 }, v: { min: 0.2, max: 0.3 } }
- // to { hmin: 0.2, hmax: 0.3, vmin: 0.2, vmax: 0.3}
- if(config.contains("leds"))
+ resolveConfigVersion(config);
+
+ //Do only migrate, if configuration is not up to date
+ if (_previousVersion < _configVersion)
{
- const QJsonArray ledarr = config["leds"].toArray();
- const QJsonObject led = ledarr[0].toObject();
-
- if(led.contains("hscan") || led.contains("h"))
+ //Migration steps for versions <= alpha 9
+ semver::version targetVersion {"2.0.0-alpha.9"};
+ if (_previousVersion <= targetVersion )
{
- const bool whscan = led.contains("hscan");
- QJsonArray newLedarr;
+ Info(_log, "Instance [%u]: Migrate LED Layout from current version [%s] to version [%s] or later", _instance, _previousVersion.getVersion().c_str(), targetVersion.getVersion().c_str());
- for(const auto & entry : ledarr)
+ // LED LAYOUT UPGRADE
+ // from { hscan: { minimum: 0.2, maximum: 0.3 }, vscan: { minimum: 0.2, maximum: 0.3 } }
+ // from { h: { min: 0.2, max: 0.3 }, v: { min: 0.2, max: 0.3 } }
+ // to { hmin: 0.2, hmax: 0.3, vmin: 0.2, vmax: 0.3}
+ if(config.contains("leds"))
{
- const QJsonObject led = entry.toObject();
- QJsonObject hscan;
- QJsonObject vscan;
- QJsonValue hmin;
- QJsonValue hmax;
- QJsonValue vmin;
- QJsonValue vmax;
- QJsonObject nL;
+ const QJsonArray ledarr = config["leds"].toArray();
+ const QJsonObject led = ledarr[0].toObject();
- if(whscan)
+ if(led.contains("hscan") || led.contains("h"))
{
- hscan = led["hscan"].toObject();
- vscan = led["vscan"].toObject();
- hmin = hscan["minimum"];
- hmax = hscan["maximum"];
- vmin = vscan["minimum"];
- vmax = vscan["maximum"];
+ const bool whscan = led.contains("hscan");
+ QJsonArray newLedarr;
+
+ for(const auto & entry : ledarr)
+ {
+ const QJsonObject led = entry.toObject();
+ QJsonObject hscan;
+ QJsonObject vscan;
+ QJsonValue hmin;
+ QJsonValue hmax;
+ QJsonValue vmin;
+ QJsonValue vmax;
+ QJsonObject nL;
+
+ if(whscan)
+ {
+ hscan = led["hscan"].toObject();
+ vscan = led["vscan"].toObject();
+ hmin = hscan["minimum"];
+ hmax = hscan["maximum"];
+ vmin = vscan["minimum"];
+ vmax = vscan["maximum"];
+ }
+ else
+ {
+ hscan = led["h"].toObject();
+ vscan = led["v"].toObject();
+ hmin = hscan["min"];
+ hmax = hscan["max"];
+ vmin = vscan["min"];
+ vmax = vscan["max"];
+ }
+ // append to led object
+ nL["hmin"] = hmin;
+ nL["hmax"] = hmax;
+ nL["vmin"] = vmin;
+ nL["vmax"] = vmax;
+ newLedarr.append(nL);
+ }
+ // replace
+ config["leds"] = newLedarr;
+ migrated = true;
+ Info(_log,"Instance [%u]: LED Layout migrated", _instance);
}
- else
- {
- hscan = led["h"].toObject();
- vscan = led["v"].toObject();
- hmin = hscan["min"];
- hmax = hscan["max"];
- vmin = vscan["min"];
- vmax = vscan["max"];
- }
- // append to led object
- nL["hmin"] = hmin;
- nL["hmax"] = hmax;
- nL["vmin"] = vmin;
- nL["vmax"] = vmax;
- newLedarr.append(nL);
}
- // replace
- config["leds"] = newLedarr;
- migrated = true;
- Debug(_log,"LED Layout migrated");
- }
- }
- if (config.contains("grabberV4L2"))
- {
- QJsonObject newGrabberV4L2Config = config["grabberV4L2"].toObject();
+ if(config.contains("ledConfig"))
+ {
+ QJsonObject oldLedConfig = config["ledConfig"].toObject();
+ if ( !oldLedConfig.contains("classic"))
+ {
+ QJsonObject newLedConfig;
+ newLedConfig.insert("classic", oldLedConfig );
+ QJsonObject defaultMatrixConfig {{"ledshoriz", 1}
+ ,{"ledsvert", 1}
+ ,{"cabling","snake"}
+ ,{"start","top-left"}
+ };
+ newLedConfig.insert("matrix", defaultMatrixConfig );
- if (newGrabberV4L2Config.contains("encoding_format"))
- {
- newGrabberV4L2Config.remove("encoding_format");
- config["grabberV4L2"] = newGrabberV4L2Config;
- migrated = true;
- Debug(_log, "GrabberV4L2 Layout migrated");
+ config["ledConfig"] = newLedConfig;
+ migrated = true;
+ Info(_log,"Instance [%u]: LED-Config migrated", _instance);
+ }
+ }
+
+ // LED Hardware count is leading for versions after alpha 9
+ // Setting Hardware LED count to number of LEDs configured via layout, if layout number is greater than number of hardware LEDs
+ if (config.contains("device"))
+ {
+ QJsonObject newDeviceConfig = config["device"].toObject();
+
+ if (newDeviceConfig.contains("hardwareLedCount"))
+ {
+ int hwLedcount = newDeviceConfig["hardwareLedCount"].toInt();
+ if (config.contains("leds"))
+ {
+ const QJsonArray ledarr = config["leds"].toArray();
+ int layoutLedCount = ledarr.size();
+
+ if (hwLedcount < layoutLedCount )
+ {
+ Warning(_log, "Instance [%u]: HwLedCount/Layout mismatch! Setting Hardware LED count to number of LEDs configured via layout", _instance);
+ hwLedcount = layoutLedCount;
+ newDeviceConfig["hardwareLedCount"] = hwLedcount;
+
+ config["device"] = newDeviceConfig;
+ migrated = true;
+ }
+ }
+ }
+ }
}
}
return migrated;
diff --git a/libsrc/hyperion/schema/schema-device.json b/libsrc/hyperion/schema/schema-device.json
index 4c337200..e08bca96 100644
--- a/libsrc/hyperion/schema/schema-device.json
+++ b/libsrc/hyperion/schema/schema-device.json
@@ -1,50 +1,45 @@
{
- "type" : "object",
- "title" : "edt_dev_general_heading_title",
- "required" : true,
- "defaultProperties": ["hardwareLedCount", "colorOrder"],
- "properties" :
- {
- "type" :
- {
- "type" : "string",
- "propertyOrder" : 1
- },
- "hardwareLedCount" :
- {
- "type" : "integer",
- "title" : "edt_dev_general_hardwareLedCount_title",
- "minimum" : 1,
- "default" : 1,
- "propertyOrder" : 2
- },
- "colorOrder" :
- {
- "type" : "string",
- "title" : "edt_dev_general_colorOrder_title",
- "enum" : ["rgb", "bgr", "rbg", "brg", "gbr", "grb"],
- "default" : "rgb",
- "required" : true,
- "options": {
- "enum_titles": [ "edt_conf_enum_rgb", "edt_conf_enum_bgr", "edt_conf_enum_rbg", "edt_conf_enum_brg", "edt_conf_enum_gbr", "edt_conf_enum_grb" ]
- },
- "access" : "expert",
- "propertyOrder" : 3
- }
- },
- "dependencies" :
- {
- "rewriteTime" :
- {
- "properties" :
- {
- "type" :
- {
- "enum" : ["file", "apa102", "apa104", "ws2801", "lpd6803", "lpd8806", "p9813", "sk6812spi", "sk6822spi", "sk9822", "ws2812spi","ws281x", "piblaster", "adalight", "dmx", "atmo", "hyperionusbasp", "lightpack", "multilightpack", "paintpack", "rawhid", "sedu", "tpm2", "karate"]
- }
- },
- "additionalProperties" : true
- }
- },
- "additionalProperties" : true
+ "type": "object",
+ "title": " ",
+ "defaultProperties": [ "hardwareLedCount", "colorOrder" ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "propertyOrder": 1
+ },
+ "hardwareLedCount": {
+ "type": "integer",
+ "title": "edt_dev_general_hardwareLedCount_title",
+ "minimum": 1,
+ "default": 1,
+ "options": {
+ "infoText": "edt_dev_general_hardwareLedCount_title_info"
+ },
+ "propertyOrder": 2
+ },
+ "colorOrder": {
+ "type": "string",
+ "title": "edt_dev_general_colorOrder_title",
+ "enum": [ "rgb", "bgr", "rbg", "brg", "gbr", "grb" ],
+ "default": "rgb",
+ "required": true,
+ "options": {
+ "enum_titles": [ "edt_conf_enum_rgb", "edt_conf_enum_bgr", "edt_conf_enum_rbg", "edt_conf_enum_brg", "edt_conf_enum_gbr", "edt_conf_enum_grb" ],
+ "infoText": "edt_dev_general_colorOrder_title_info"
+ },
+ "access": "expert",
+ "propertyOrder": 3
+ }
+ },
+ "dependencies": {
+ "rewriteTime": {
+ "properties": {
+ "type": {
+ "enum": [ "file", "apa102", "apa104", "ws2801", "lpd6803", "lpd8806", "p9813", "sk6812spi", "sk6822spi", "sk9822", "ws2812spi", "ws281x", "piblaster", "adalight", "dmx", "atmo", "hyperionusbasp", "lightpack", "multilightpack", "paintpack", "rawhid", "sedu", "tpm2", "karate" ]
+ }
+ },
+ "additionalProperties": true
+ }
+ },
+ "additionalProperties": true
}
diff --git a/libsrc/hyperion/schema/schema-general.json b/libsrc/hyperion/schema/schema-general.json
index afab0c29..422054b5 100644
--- a/libsrc/hyperion/schema/schema-general.json
+++ b/libsrc/hyperion/schema/schema-general.json
@@ -34,6 +34,25 @@
"default" : true,
"required" : true,
"propertyOrder" : 3
+ },
+ "configVersion" :
+ {
+ "type" : "string",
+ "title" : "edt_conf_gen_configVersion_title",
+ "options" : {
+ "hidden":true
+ },
+ "access" : "expert",
+ "propertyOrder" : 4
+ },
+ "previousVersion" :
+ {
+ "type" : "string",
+ "options" : {
+ "hidden":true
+ },
+ "access" : "expert",
+ "propertyOrder" : 5
}
},
"additionalProperties" : false
diff --git a/libsrc/hyperion/schema/schema-ledConfig.json b/libsrc/hyperion/schema/schema-ledConfig.json
index f5f58487..4fa79f87 100644
--- a/libsrc/hyperion/schema/schema-ledConfig.json
+++ b/libsrc/hyperion/schema/schema-ledConfig.json
@@ -135,15 +135,45 @@
},
"cabling": {
"type": "string",
- "enum": ["snake", "parallel"]
+ "enum": [ "snake", "parallel" ]
},
"start": {
"type": "string",
- "enum": ["top-left", "top-right", "bottom-left", "bottom-right"]
+ "enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ]
}
},
"additionalProperties": false
+ },
+ "ledBlacklist": {
+ "type": "array",
+ "title": "conf_leds_layout_blacklist_rules_title",
+ "minimum": 1,
+ "uniqueItems": true,
+ "items": {
+ "type": "object",
+ "title": "conf_leds_layout_blacklist_rule_title",
+ "required": true,
+ "properties": {
+ "start": {
+ "type": "integer",
+ "minimum": 0,
+ "default": 0,
+ "title": "conf_leds_layout_blacklist_start_title",
+ "required": true,
+ "propertyOrder": 1
+ },
+ "num": {
+ "type": "integer",
+ "minimum": 1,
+ "default": 1,
+ "title": "conf_leds_layout_blacklist_num_title",
+ "required": true,
+ "propertyOrder": 2
+ }
+ }
+ },
+ "propertyOrder": 1
}
},
- "additionalProperties": true
-}
+ "additionalProperties": true
+ }
diff --git a/libsrc/leddevice/LedDevice.cpp b/libsrc/leddevice/LedDevice.cpp
index 2ab15bf0..27dc3e8c 100644
--- a/libsrc/leddevice/LedDevice.cpp
+++ b/libsrc/leddevice/LedDevice.cpp
@@ -234,20 +234,25 @@ int LedDevice::rewriteLEDs()
return retval;
}
-int LedDevice::writeBlack(int numberOfBlack)
+int LedDevice::writeBlack(int numberOfWrites)
+{
+ return writeColor(ColorRgb::BLACK, numberOfWrites);
+}
+
+int LedDevice::writeColor(const ColorRgb& color, int numberOfWrites)
{
int rc = -1;
- for (int i = 0; i < numberOfBlack; i++)
+ for (int i = 0; i < numberOfWrites; i++)
{
- if ( _latchTime_ms > 0 )
+ if (_latchTime_ms > 0)
{
// Wait latch time before writing black
QEventLoop loop;
QTimer::singleShot(_latchTime_ms, &loop, &QEventLoop::quit);
loop.exec();
}
- _lastLedValues = std::vector(static_cast(_ledCount), ColorRgb::BLACK );
+ _lastLedValues = std::vector(static_cast(_ledCount),color);
rc = write(_lastLedValues);
}
return rc;
@@ -411,28 +416,33 @@ void LedDevice::setLatchTime( int latchTime_ms )
void LedDevice::setRewriteTime( int rewriteTime_ms )
{
assert(rewriteTime_ms >= 0);
- _refreshTimerInterval_ms = rewriteTime_ms;
- if ( _refreshTimerInterval_ms > 0 )
+ //Check, if refresh timer was not initialised due to getProperties/identify sceanrios
+ if (_refreshTimer != nullptr)
{
+ _refreshTimerInterval_ms = rewriteTime_ms;
- _isRefreshEnabled = true;
-
- if (_refreshTimerInterval_ms <= _latchTime_ms )
+ if (_refreshTimerInterval_ms > 0)
{
- int new_refresh_timer_interval = _latchTime_ms + 10;
- Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refreshTimerInterval_ms, new_refresh_timer_interval);
- _refreshTimerInterval_ms = new_refresh_timer_interval;
- _refreshTimer->setInterval( _refreshTimerInterval_ms );
+
+ _isRefreshEnabled = true;
+
+ if (_refreshTimerInterval_ms <= _latchTime_ms)
+ {
+ int new_refresh_timer_interval = _latchTime_ms + 10;
+ Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refreshTimerInterval_ms, new_refresh_timer_interval);
+ _refreshTimerInterval_ms = new_refresh_timer_interval;
+ _refreshTimer->setInterval(_refreshTimerInterval_ms);
+ }
+
+ Debug(_log, "Refresh interval = %dms", _refreshTimerInterval_ms);
+ _refreshTimer->setInterval(_refreshTimerInterval_ms);
+
+ _lastWriteTime = QDateTime::currentDateTime();
}
- Debug(_log, "Refresh interval = %dms",_refreshTimerInterval_ms );
- _refreshTimer->setInterval( _refreshTimerInterval_ms );
-
- _lastWriteTime = QDateTime::currentDateTime();
+ Debug(_log, "RewriteTime updated to %dms", _refreshTimerInterval_ms);
}
-
- Debug(_log, "RewriteTime updated to %dms", _refreshTimerInterval_ms);
}
void LedDevice::printLedValues(const std::vector& ledValues)
diff --git a/libsrc/leddevice/dev_net/LedDeviceWled.cpp b/libsrc/leddevice/dev_net/LedDeviceWled.cpp
index 1f5511cb..a2139342 100644
--- a/libsrc/leddevice/dev_net/LedDeviceWled.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceWled.cpp
@@ -15,6 +15,9 @@ const bool verbose = false;
// Configuration settings
const char CONFIG_ADDRESS[] = "host";
const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
+const char CONFIG_BRIGHTNESS[] = "brightness";
+const char CONFIG_BRIGHTNESS_OVERWRITE[] = "overwriteBrightness";
+const char CONFIG_SYNC_OVERWRITE[] = "overwriteSync";
// UDP elements
const quint16 STREAM_DEFAULT_PORT = 19446;
@@ -32,7 +35,10 @@ const char STATE_VALUE_TRUE[] = "true";
const char STATE_VALUE_FALSE[] = "false";
const char STATE_LIVE[] = "live";
+const bool DEFAULT_IS_RESTORE_STATE = false;
+const bool DEFAULT_IS_BRIGHTNESS_OVERWRITE = true;
const int BRI_MAX = 255;
+const bool DEFAULT_IS_SYNC_OVERWRITE = true;
constexpr std::chrono::milliseconds DEFAULT_IDENTIFY_TIME{ 2000 };
@@ -42,6 +48,11 @@ LedDeviceWled::LedDeviceWled(const QJsonObject &deviceConfig)
: ProviderUdp(deviceConfig)
,_restApi(nullptr)
,_apiPort(API_DEFAULT_PORT)
+ ,_isBrightnessOverwrite(DEFAULT_IS_BRIGHTNESS_OVERWRITE)
+ ,_brightness (BRI_MAX)
+ ,_isSyncOverwrite(DEFAULT_IS_SYNC_OVERWRITE)
+ ,_originalStateUdpnSend(false)
+ ,_originalStateUdpnRecv(true)
{
}
@@ -70,8 +81,15 @@ bool LedDeviceWled::init(const QJsonObject &deviceConfig)
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
Debug(_log, "LatchTime : %d", this->getLatchTime());
- _isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(false);
+ _isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(DEFAULT_IS_RESTORE_STATE);
+ _isSyncOverwrite = _devConfig[CONFIG_SYNC_OVERWRITE].toBool(DEFAULT_IS_SYNC_OVERWRITE);
+ _isBrightnessOverwrite = _devConfig[CONFIG_BRIGHTNESS_OVERWRITE].toBool(DEFAULT_IS_BRIGHTNESS_OVERWRITE);
+ _brightness = _devConfig[CONFIG_BRIGHTNESS].toInt(BRI_MAX);
+
Debug(_log, "RestoreOrigState : %d", _isRestoreOrigState);
+ Debug(_log, "Overwrite Sync. : %d", _isSyncOverwrite);
+ Debug(_log, "Overwrite Brightn.: %d", _isBrightnessOverwrite);
+ Debug(_log, "Set Brightness to : %d", _brightness);
//Set hostname as per configuration
QString hostName = deviceConfig[ CONFIG_ADDRESS ].toString();
@@ -145,6 +163,13 @@ QString LedDeviceWled::getLorRequest(int lor) const
return QString( "\"lor\":%1" ).arg(lor);
}
+QString LedDeviceWled::getUdpnRequest(bool isSendOn, bool isRecvOn) const
+{
+ QString send = isSendOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
+ QString recv = isRecvOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
+ return QString( "\"udpn\":{\"send\":%1,\"recv\":%2}" ).arg(send, recv);
+}
+
bool LedDeviceWled::sendStateUpdateRequest(const QString &request)
{
bool rc = true;
@@ -166,7 +191,20 @@ bool LedDeviceWled::powerOn()
//Power-on WLED device
_restApi->setPath(API_PATH_STATE);
- httpResponse response = _restApi->put(QString("{%1,%2}").arg(getOnOffRequest(true)).arg(getBrightnessRequest(BRI_MAX)));
+ QString cmd = getOnOffRequest(true);
+
+ if ( _isBrightnessOverwrite)
+ {
+ cmd += "," + getBrightnessRequest(_brightness);
+ }
+
+ if (_isSyncOverwrite)
+ {
+ Debug( _log, "Disable synchronisation with other WLED devices");
+ cmd += "," + getUdpnRequest(false, false);
+ }
+
+ httpResponse response = _restApi->put(QString("{%1}").arg(cmd));
if ( response.error() )
{
QString errorReason = QString("Power-on request failed with error: '%1'").arg(response.getErrorReason());
@@ -191,7 +229,16 @@ bool LedDeviceWled::powerOff()
//Power-off the WLED device physically
_restApi->setPath(API_PATH_STATE);
- httpResponse response = _restApi->put(QString("{%1}").arg(getOnOffRequest(false)));
+
+ QString cmd = getOnOffRequest(false);
+
+ if (_isSyncOverwrite)
+ {
+ Debug( _log, "Restore synchronisation with other WLED devices");
+ cmd += "," + getUdpnRequest(_originalStateUdpnSend, _originalStateUdpnRecv);
+ }
+
+ httpResponse response = _restApi->put(QString("{%1}").arg(cmd));
if ( response.error() )
{
QString errorReason = QString("Power-off request failed with error: '%1'").arg(response.getErrorReason());
@@ -206,7 +253,7 @@ bool LedDeviceWled::storeState()
{
bool rc = true;
- if ( _isRestoreOrigState )
+ if ( _isRestoreOrigState || _isSyncOverwrite )
{
_restApi->setPath(API_PATH_STATE);
@@ -221,6 +268,13 @@ bool LedDeviceWled::storeState()
{
_originalStateProperties = response.getBody().object();
DebugIf(verbose, _log, "state: [%s]", QString(QJsonDocument(_originalStateProperties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ QJsonObject udpn = _originalStateProperties.value("udpn").toObject();
+ if (!udpn.isEmpty())
+ {
+ _originalStateUdpnSend = udpn["send"].toBool(false);
+ _originalStateUdpnRecv = udpn["recv"].toBool(true);
+ }
}
}
@@ -233,7 +287,6 @@ bool LedDeviceWled::restoreState()
if ( _isRestoreOrigState )
{
- //powerOff();
_restApi->setPath(API_PATH_STATE);
_originalStateProperties[STATE_LIVE] = false;
diff --git a/libsrc/leddevice/dev_net/LedDeviceWled.h b/libsrc/leddevice/dev_net/LedDeviceWled.h
index 5871a44a..818467c0 100644
--- a/libsrc/leddevice/dev_net/LedDeviceWled.h
+++ b/libsrc/leddevice/dev_net/LedDeviceWled.h
@@ -140,9 +140,11 @@ private:
/// @return Command to switch device on/off
///
QString getOnOffRequest (bool isOn ) const;
+
QString getBrightnessRequest (int bri ) const;
QString getEffectRequest(int effect, int speed=128) const;
QString getLorRequest(int lor) const;
+ QString getUdpnRequest(bool send, bool recv) const;
bool sendStateUpdateRequest(const QString &request);
@@ -154,6 +156,12 @@ private:
QJsonObject _originalStateProperties;
+ bool _isBrightnessOverwrite;
+ int _brightness;
+
+ bool _isSyncOverwrite;
+ bool _originalStateUdpnSend;
+ bool _originalStateUdpnRecv;
};
#endif // LEDDEVICEWLED_H
diff --git a/libsrc/leddevice/dev_net/LedDeviceYeelight.cpp b/libsrc/leddevice/dev_net/LedDeviceYeelight.cpp
index 3a14cb0b..7749c23e 100644
--- a/libsrc/leddevice/dev_net/LedDeviceYeelight.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceYeelight.cpp
@@ -1,4 +1,4 @@
-#include "LedDeviceYeelight.h"
+#include "LedDeviceYeelight.h"
#include
#include
@@ -1018,10 +1018,9 @@ bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
//Get device specific configuration
- bool ok;
if ( deviceConfig[ CONFIG_COLOR_MODEL ].isString() )
{
- _outputColorModel = deviceConfig[ CONFIG_COLOR_MODEL ].toString().toInt(&ok,MODEL_RGB);
+ _outputColorModel = deviceConfig[ CONFIG_COLOR_MODEL ].toString(QString(MODEL_RGB)).toInt();
}
else
{
@@ -1030,7 +1029,7 @@ bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
if ( deviceConfig[ CONFIG_TRANS_EFFECT ].isString() )
{
- _transitionEffect = static_cast( deviceConfig[ CONFIG_TRANS_EFFECT ].toString().toInt(&ok, YeelightLight::API_EFFECT_SMOOTH) );
+ _transitionEffect = static_cast( deviceConfig[ CONFIG_TRANS_EFFECT ].toString(QString(YeelightLight::API_EFFECT_SMOOTH)).toInt() );
}
else
{
@@ -1047,7 +1046,7 @@ bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
if ( deviceConfig[ CONFIG_DEBUGLEVEL ].isString() )
{
- _debuglevel = deviceConfig[ CONFIG_DEBUGLEVEL ].toString().toInt();
+ _debuglevel = deviceConfig[ CONFIG_DEBUGLEVEL ].toString(QString("0")).toInt();
}
else
{
diff --git a/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp b/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp
index 508ba0b4..20eaf0f7 100644
--- a/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp
+++ b/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp
@@ -4,11 +4,22 @@
#include
// QT includes
+#include
#include
// Local LedDevice includes
#include "LedDevicePiBlaster.h"
+// Constants
+namespace {
+ const bool verbose = false;
+
+ // Pi-Blaster discovery service
+ const char DISCOVERY_DIRECTORY[] = "/dev/";
+ const char DISCOVERY_FILEPATTERN[] = "pi-blaster";
+
+} //End of constants
+
LedDevicePiBlaster::LedDevicePiBlaster(const QJsonObject &deviceConfig)
: LedDevice(deviceConfig)
, _fid(nullptr)
@@ -184,3 +195,31 @@ int LedDevicePiBlaster::write(const std::vector & ledValues)
return 0;
}
+
+QJsonObject LedDevicePiBlaster::discover(const QJsonObject& /*params*/)
+{
+ QJsonObject devicesDiscovered;
+ devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
+
+ QJsonArray deviceList;
+
+ QDir deviceDirectory (DISCOVERY_DIRECTORY);
+ QStringList deviceFilter(DISCOVERY_FILEPATTERN);
+ deviceDirectory.setNameFilters(deviceFilter);
+ deviceDirectory.setSorting(QDir::Name);
+ QFileInfoList deviceFiles = deviceDirectory.entryInfoList(QDir::System);
+
+ QFileInfoList::const_iterator deviceFileIterator;
+ for (deviceFileIterator = deviceFiles.constBegin(); deviceFileIterator != deviceFiles.constEnd(); ++deviceFileIterator)
+ {
+ QJsonObject deviceInfo;
+ deviceInfo.insert("deviceName", (*deviceFileIterator).fileName());
+ deviceInfo.insert("systemLocation", (*deviceFileIterator).absoluteFilePath());
+ deviceList.append(deviceInfo);
+ }
+ devicesDiscovered.insert("devices", deviceList);
+
+ DebugIf(verbose,_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
+
+ return devicesDiscovered;
+}
diff --git a/libsrc/leddevice/dev_other/LedDevicePiBlaster.h b/libsrc/leddevice/dev_other/LedDevicePiBlaster.h
index 4d6b0732..71759571 100644
--- a/libsrc/leddevice/dev_other/LedDevicePiBlaster.h
+++ b/libsrc/leddevice/dev_other/LedDevicePiBlaster.h
@@ -29,6 +29,12 @@ public:
/// @return LedDevice constructed
static LedDevice* construct(const QJsonObject &deviceConfig);
+ /// @param[in] params Parameters used to overwrite discovery default behaviour
+ ///
+ /// @return A JSON structure holding a list of devices found
+ ///
+ QJsonObject discover(const QJsonObject& params) override;
+
protected:
///
diff --git a/libsrc/leddevice/dev_serial/ProviderRs232.cpp b/libsrc/leddevice/dev_serial/ProviderRs232.cpp
index f6796749..8c5d6eaa 100644
--- a/libsrc/leddevice/dev_serial/ProviderRs232.cpp
+++ b/libsrc/leddevice/dev_serial/ProviderRs232.cpp
@@ -2,6 +2,7 @@
// LedDevice includes
#include
#include "ProviderRs232.h"
+#include
// qt includes
#include
@@ -10,10 +11,16 @@
#include
// Constants
-constexpr std::chrono::milliseconds WRITE_TIMEOUT{1000}; // device write timeout in ms
-constexpr std::chrono::milliseconds OPEN_TIMEOUT{5000}; // device open timeout in ms
-const int MAX_WRITE_TIMEOUTS = 5; // Maximum number of allowed timeouts
-const int NUM_POWEROFF_WRITE_BLACK = 2; // Number of write "BLACK" during powering off
+namespace {
+ const bool verbose = false;
+
+ constexpr std::chrono::milliseconds WRITE_TIMEOUT{ 1000 }; // device write timeout in ms
+ constexpr std::chrono::milliseconds OPEN_TIMEOUT{ 5000 }; // device open timeout in ms
+ const int MAX_WRITE_TIMEOUTS = 5; // Maximum number of allowed timeouts
+ const int NUM_POWEROFF_WRITE_BLACK = 2; // Number of write "BLACK" during powering off
+
+ constexpr std::chrono::milliseconds DEFAULT_IDENTIFY_TIME{ 500 };
+} //End of constants
ProviderRs232::ProviderRs232(const QJsonObject &deviceConfig)
: LedDevice(deviceConfig)
@@ -278,7 +285,7 @@ QJsonObject ProviderRs232::discover(const QJsonObject& /*params*/)
// Discover serial Devices
for (auto &port : QSerialPortInfo::availablePorts() )
{
- if ( !port.isNull() && !port.portName().startsWith("ttyS"))
+ if ( !port.isNull() && port.vendorIdentifier() != 0)
{
QJsonObject portInfo;
portInfo.insert("description", port.description());
@@ -294,5 +301,39 @@ QJsonObject ProviderRs232::discover(const QJsonObject& /*params*/)
}
devicesDiscovered.insert("devices", deviceList);
+ DebugIf(verbose,_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
+
return devicesDiscovered;
}
+
+void ProviderRs232::identify(const QJsonObject& params)
+{
+ DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
+
+ QString deviceName = params["output"].toString("");
+ if (!deviceName.isEmpty())
+ {
+ _devConfig = params;
+ init(_devConfig);
+ {
+ if ( open() == 0 )
+ {
+ for (int i = 0; i < 2; ++i)
+ {
+ if (writeColor(ColorRgb::RED) == 0)
+ {
+ wait(DEFAULT_IDENTIFY_TIME);
+
+ writeColor(ColorRgb::BLACK);
+ wait(DEFAULT_IDENTIFY_TIME);
+ }
+ else
+ {
+ break;
+ }
+ }
+ close();
+ }
+ }
+ }
+}
diff --git a/libsrc/leddevice/dev_serial/ProviderRs232.h b/libsrc/leddevice/dev_serial/ProviderRs232.h
index 537c51ce..2ca95982 100644
--- a/libsrc/leddevice/dev_serial/ProviderRs232.h
+++ b/libsrc/leddevice/dev_serial/ProviderRs232.h
@@ -26,6 +26,20 @@ public:
///
~ProviderRs232() override;
+ ///
+ /// @brief Send an update to the RS232 device to identify it.
+ ///
+ /// Following parameters are required
+ /// @code
+ /// {
+ /// "deviceConfig" :
+ /// }
+ ///@endcode
+ ///
+ /// @param[in] params Parameters to configure device
+ ///
+ void identify(const QJsonObject& params) override;
+
protected:
///
diff --git a/libsrc/leddevice/dev_spi/ProviderSpi.cpp b/libsrc/leddevice/dev_spi/ProviderSpi.cpp
index 44619791..2cc46d50 100644
--- a/libsrc/leddevice/dev_spi/ProviderSpi.cpp
+++ b/libsrc/leddevice/dev_spi/ProviderSpi.cpp
@@ -14,6 +14,19 @@
#include "ProviderSpi.h"
#include
+// qt includes
+#include
+
+// Constants
+namespace {
+ const bool verbose = false;
+
+ // SPI discovery service
+ const char DISCOVERY_DIRECTORY[] = "/dev/";
+ const char DISCOVERY_FILEPATTERN[] = "spidev*";
+
+} //End of constants
+
ProviderSpi::ProviderSpi(const QJsonObject &deviceConfig)
: LedDevice(deviceConfig)
, _deviceName("/dev/spidev0.0")
@@ -148,3 +161,31 @@ int ProviderSpi::writeBytes(unsigned size, const uint8_t * data)
return retVal;
}
+
+QJsonObject ProviderSpi::discover(const QJsonObject& /*params*/)
+{
+ QJsonObject devicesDiscovered;
+ devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
+
+ QJsonArray deviceList;
+
+ QDir deviceDirectory (DISCOVERY_DIRECTORY);
+ QStringList deviceFilter(DISCOVERY_FILEPATTERN);
+ deviceDirectory.setNameFilters(deviceFilter);
+ deviceDirectory.setSorting(QDir::Name);
+ QFileInfoList deviceFiles = deviceDirectory.entryInfoList(QDir::System);
+
+ QFileInfoList::const_iterator deviceFileIterator;
+ for (deviceFileIterator = deviceFiles.constBegin(); deviceFileIterator != deviceFiles.constEnd(); ++deviceFileIterator)
+ {
+ QJsonObject deviceInfo;
+ deviceInfo.insert("deviceName", (*deviceFileIterator).fileName().remove(0,6));
+ deviceInfo.insert("systemLocation", (*deviceFileIterator).absoluteFilePath());
+ deviceList.append(deviceInfo);
+ }
+ devicesDiscovered.insert("devices", deviceList);
+
+ DebugIf(verbose,_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
+
+ return devicesDiscovered;
+}
diff --git a/libsrc/leddevice/dev_spi/ProviderSpi.h b/libsrc/leddevice/dev_spi/ProviderSpi.h
index e3956b72..63dbb20f 100644
--- a/libsrc/leddevice/dev_spi/ProviderSpi.h
+++ b/libsrc/leddevice/dev_spi/ProviderSpi.h
@@ -36,6 +36,12 @@ public:
///
int open() override;
+ /// @param[in] params Parameters used to overwrite discovery default behaviour
+ ///
+ /// @return A JSON structure holding a list of devices found
+ ///
+ QJsonObject discover(const QJsonObject& params) override;
+
public slots:
///
/// Closes the output device.
diff --git a/libsrc/leddevice/schemas/schema-adalight.json b/libsrc/leddevice/schemas/schema-adalight.json
index 3d42e4cf..2aa1142e 100644
--- a/libsrc/leddevice/schemas/schema-adalight.json
+++ b/libsrc/leddevice/schemas/schema-adalight.json
@@ -25,20 +25,24 @@
},
"lightberry_apa102_mode": {
"type": "boolean",
- "title":"edt_dev_spec_LBap102Mode_title",
+ "title": "edt_dev_spec_LBap102Mode_title",
"default": false,
- "access" : "advanced",
- "propertyOrder" : 4
+ "required": true,
+ "access": "advanced",
+ "propertyOrder": 4
},
"latchTime": {
"type": "integer",
- "title":"edt_dev_spec_latchtime_title",
+ "title": "edt_dev_spec_latchtime_title",
"default": 30,
- "append" : "edt_append_ms",
+ "append": "edt_append_ms",
"minimum": 0,
"maximum": 1000,
- "access" : "expert",
- "propertyOrder" : 5
+ "access": "expert",
+ "options": {
+ "infoText": "edt_dev_spec_latchtime_title_info"
+ },
+ "propertyOrder": 5
},
"rewriteTime": {
"type": "integer",
diff --git a/libsrc/leddevice/schemas/schema-apa102.json b/libsrc/leddevice/schemas/schema-apa102.json
index eba9a708..ec8f08fc 100644
--- a/libsrc/leddevice/schemas/schema-apa102.json
+++ b/libsrc/leddevice/schemas/schema-apa102.json
@@ -5,8 +5,6 @@
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
- "enum" : ["/dev/spidev0.0","/dev/spidev0.1"],
- "default" : "/dev/spidev0.0",
"propertyOrder" : 1
},
"rate": {
diff --git a/libsrc/leddevice/schemas/schema-apa104.json b/libsrc/leddevice/schemas/schema-apa104.json
index fa409884..100f755a 100644
--- a/libsrc/leddevice/schemas/schema-apa104.json
+++ b/libsrc/leddevice/schemas/schema-apa104.json
@@ -5,7 +5,6 @@
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
- "enum" : ["/dev/spidev0.0","/dev/spidev0.1"],
"propertyOrder" : 1
},
"rate": {
diff --git a/libsrc/leddevice/schemas/schema-atmoorb.json b/libsrc/leddevice/schemas/schema-atmoorb.json
index 0f7b6e25..4b6cc4aa 100644
--- a/libsrc/leddevice/schemas/schema-atmoorb.json
+++ b/libsrc/leddevice/schemas/schema-atmoorb.json
@@ -1,46 +1,47 @@
{
- "type":"object",
- "required":true,
- "properties":{
- "orbIds": {
- "type": "string",
- "title":"edt_dev_spec_orbIds_title",
- "default": "",
- "propertyOrder" : 1
- },
- "useOrbSmoothing": {
- "type": "boolean",
- "title":"edt_dev_spec_useOrbSmoothing_title",
- "default": true,
- "access" : "advanced",
- "propertyOrder" : 2
- },
- "output": {
- "type": "string",
- "title":"edt_dev_spec_multicastGroup_title",
- "default" : "239.255.255.250",
- "access" : "expert",
- "propertyOrder" : 3
- },
- "port": {
- "type": "integer",
- "title":"edt_dev_spec_port_title",
- "minimum" : 0,
- "maximum" : 65535,
- "default": 49692,
- "access" : "expert",
- "propertyOrder" : 4
- },
- "latchTime": {
- "type": "integer",
- "title":"edt_dev_spec_latchtime_title",
- "default": 30,
- "append" : "edt_append_ms",
- "minimum": 0,
- "maximum": 1000,
- "access" : "expert",
- "propertyOrder" : 5
- }
- },
- "additionalProperties": true
+ "type": "object",
+ "required": true,
+ "properties": {
+ "orbIds": {
+ "type": "string",
+ "title": "edt_dev_spec_orbIds_title",
+ "minLength": 1,
+ "default": "",
+ "propertyOrder": 1
+ },
+ "useOrbSmoothing": {
+ "type": "boolean",
+ "title": "edt_dev_spec_useOrbSmoothing_title",
+ "default": true,
+ "access": "advanced",
+ "propertyOrder": 2
+ },
+ "output": {
+ "type": "string",
+ "title": "edt_dev_spec_multicastGroup_title",
+ "default": "239.255.255.250",
+ "access": "expert",
+ "propertyOrder": 3
+ },
+ "port": {
+ "type": "integer",
+ "title": "edt_dev_spec_port_title",
+ "minimum": 0,
+ "maximum": 65535,
+ "default": 49692,
+ "access": "expert",
+ "propertyOrder": 4
+ },
+ "latchTime": {
+ "type": "integer",
+ "title": "edt_dev_spec_latchtime_title",
+ "default": 30,
+ "append": "edt_append_ms",
+ "minimum": 0,
+ "maximum": 1000,
+ "access": "expert",
+ "propertyOrder": 5
+ }
+ },
+ "additionalProperties": true
}
diff --git a/libsrc/leddevice/schemas/schema-cololight.json b/libsrc/leddevice/schemas/schema-cololight.json
index 349826d1..11942ed2 100644
--- a/libsrc/leddevice/schemas/schema-cololight.json
+++ b/libsrc/leddevice/schemas/schema-cololight.json
@@ -1,22 +1,40 @@
{
- "type":"object",
- "required":true,
- "properties": {
- "host" : {
- "type": "string",
- "title":"edt_dev_spec_targetIpHost_title",
- "propertyOrder" : 1
- },
- "latchTime": {
- "type": "integer",
- "title":"edt_dev_spec_latchtime_title",
- "default": 0,
- "append" : "edt_append_ms",
- "minimum": 0,
- "maximum": 1000,
- "access" : "expert",
- "propertyOrder" : 2
- }
- },
- "additionalProperties": true
+ "type": "object",
+ "required": true,
+ "properties": {
+ "hostList": {
+ "type": "string",
+ "title": "edt_dev_spec_devices_discovered_title",
+ "enum": [ "NONE" ],
+ "options": {
+ "enum_titles": [ "edt_dev_spec_devices_discovery_inprogress" ],
+ "infoText": "edt_dev_spec_devices_discovered_title_info"
+ },
+ "required": true,
+ "propertyOrder": 1
+ },
+ "host": {
+ "type": "string",
+ "title": "edt_dev_spec_targetIpHost_title",
+ "options": {
+ "infoText": "edt_dev_spec_targetIpHost_title_info"
+ },
+ "required": true,
+ "propertyOrder": 2
+ },
+ "latchTime": {
+ "type": "integer",
+ "title": "edt_dev_spec_latchtime_title",
+ "default": 0,
+ "append": "edt_append_ms",
+ "minimum": 0,
+ "maximum": 1000,
+ "access": "expert",
+ "options": {
+ "infoText": "edt_dev_spec_latchtime_title_info"
+ },
+ "propertyOrder": 3
+ }
+ },
+ "additionalProperties": true
}
diff --git a/libsrc/leddevice/schemas/schema-lpd6803.json b/libsrc/leddevice/schemas/schema-lpd6803.json
index 28c31866..4bd34050 100644
--- a/libsrc/leddevice/schemas/schema-lpd6803.json
+++ b/libsrc/leddevice/schemas/schema-lpd6803.json
@@ -5,7 +5,6 @@
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
- "enum" : ["/dev/spidev0.0","/dev/spidev0.1"],
"propertyOrder" : 1
},
"rate": {
diff --git a/libsrc/leddevice/schemas/schema-lpd8806.json b/libsrc/leddevice/schemas/schema-lpd8806.json
index bbe5b474..e2252f10 100644
--- a/libsrc/leddevice/schemas/schema-lpd8806.json
+++ b/libsrc/leddevice/schemas/schema-lpd8806.json
@@ -5,7 +5,6 @@
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
- "enum" : ["/dev/spidev0.0","/dev/spidev0.1"],
"propertyOrder" : 1
},
"rate": {
diff --git a/libsrc/leddevice/schemas/schema-nanoleaf.json b/libsrc/leddevice/schemas/schema-nanoleaf.json
index 97fac11f..ec3a81d3 100644
--- a/libsrc/leddevice/schemas/schema-nanoleaf.json
+++ b/libsrc/leddevice/schemas/schema-nanoleaf.json
@@ -1,58 +1,78 @@
{
- "type":"object",
- "required":true,
- "properties":{
- "host": {
- "type": "string",
- "title":"edt_dev_spec_targetIpHost_title",
- "propertyOrder" : 1
- },
- "token": {
- "type": "string",
- "title":"edt_dev_auth_key_title",
- "propertyOrder" : 2
- },
- "title": {
- "type" : "object",
- "title":"edt_dev_spec_panelorganisation_title",
- "access" : "advanced",
- "propertyOrder" : 3
- },
- "panelOrderTopDown": {
- "type": "integer",
- "title":"edt_dev_spec_order_top_down_title",
- "enum" : [0, 1],
- "default" : 0,
- "options" : {
- "enum_titles" : ["edt_conf_enum_top_down", "edt_conf_enum_bottom_up"]
- },
- "minimum" : 0,
- "maximum" : 1,
- "access" : "advanced",
- "propertyOrder" : 4
- },
- "panelOrderLeftRight": {
- "type": "integer",
- "title":"edt_dev_spec_order_left_right_title",
- "enum" : [0, 1],
- "default" : 0,
- "options" : {
- "enum_titles" : ["edt_conf_enum_left_right", "edt_conf_enum_right_left"]
- },
- "minimum" : 0,
- "maximum" : 1,
- "access" : "advanced",
- "propertyOrder" : 5
- },
- "panelStartPos": {
- "type": "integer",
- "title":"edt_dev_spec_panel_start_position",
- "step": 1,
- "minimum" : 0,
- "default": 0,
- "access" : "advanced",
- "propertyOrder" : 6
- }
- },
- "additionalProperties": true
+ "type": "object",
+ "required": true,
+ "properties": {
+ "hostList": {
+ "type": "string",
+ "title": "edt_dev_spec_devices_discovered_title",
+ "enum": [ "NONE" ],
+ "options": {
+ "enum_titles": [ "edt_dev_spec_devices_discovery_inprogress" ],
+ "infoText": "edt_dev_spec_devices_discovered_title_info"
+ },
+ "required": true,
+ "propertyOrder": 1
+ },
+ "host": {
+ "type": "string",
+ "title": "edt_dev_spec_targetIpHost_title",
+ "options": {
+ "infoText": "edt_dev_spec_targetIpHost_title_info"
+ },
+ "required": true,
+ "propertyOrder": 2
+ },
+ "token": {
+ "type": "string",
+ "title": "edt_dev_auth_key_title",
+ "options": {
+ "infoText": "edt_dev_auth_key_title_info"
+ },
+ "propertyOrder": 4
+ },
+ "title": {
+ "type": "object",
+ "title": "edt_dev_spec_panelorganisation_title",
+ "access": "advanced",
+ "propertyOrder": 5
+ },
+ "panelOrderTopDown": {
+ "type": "integer",
+ "title": "edt_dev_spec_order_top_down_title",
+ "enum": [ 0, 1 ],
+ "default": 0,
+ "required": true,
+ "options": {
+ "enum_titles": [ "edt_conf_enum_top_down", "edt_conf_enum_bottom_up" ]
+ },
+ "minimum": 0,
+ "maximum": 1,
+ "access": "advanced",
+ "propertyOrder": 6
+ },
+ "panelOrderLeftRight": {
+ "type": "integer",
+ "title": "edt_dev_spec_order_left_right_title",
+ "enum": [ 0, 1 ],
+ "default": 0,
+ "required": true,
+ "options": {
+ "enum_titles": [ "edt_conf_enum_left_right", "edt_conf_enum_right_left" ]
+ },
+ "minimum": 0,
+ "maximum": 1,
+ "access": "advanced",
+ "propertyOrder": 7
+ },
+ "panelStartPos": {
+ "type": "integer",
+ "title": "edt_dev_spec_panel_start_position",
+ "step": 1,
+ "minimum": 0,
+ "default": 0,
+ "access": "advanced",
+ "propertyOrder": 8
+ }
+ },
+ "additionalProperties": true
}
diff --git a/libsrc/leddevice/schemas/schema-p9813.json b/libsrc/leddevice/schemas/schema-p9813.json
index a2450b5a..9309c289 100644
--- a/libsrc/leddevice/schemas/schema-p9813.json
+++ b/libsrc/leddevice/schemas/schema-p9813.json
@@ -5,7 +5,6 @@
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
- "enum" : ["/dev/spidev0.0","/dev/spidev0.1"],
"propertyOrder" : 1
},
"rate": {
diff --git a/libsrc/leddevice/schemas/schema-philipshue.json b/libsrc/leddevice/schemas/schema-philipshue.json
index 46b917e3..834f2f1b 100644
--- a/libsrc/leddevice/schemas/schema-philipshue.json
+++ b/libsrc/leddevice/schemas/schema-philipshue.json
@@ -1,242 +1,243 @@
{
- "type":"object",
- "required":true,
- "properties":{
- "output": {
- "type": "string",
- "title":"edt_dev_spec_targetIp_title",
- "default":"",
- "propertyOrder" : 1
- },
- "username": {
- "type": "string",
- "title":"edt_dev_spec_username_title",
- "default": "",
- "propertyOrder" : 2
- },
- "clientkey": {
- "type": "string",
- "title":"edt_dev_spec_clientKey_title",
- "default" : "",
- "options": {
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "propertyOrder" : 3
- },
- "useEntertainmentAPI": {
- "type": "boolean",
- "title":"edt_dev_spec_useEntertainmentAPI_title",
- "default" : false,
- "propertyOrder" : 4
- },
- "transitiontime": {
- "type": "number",
- "title":"edt_dev_spec_transistionTime_title",
- "default" : 1,
- "append" : "x100ms",
- "options": {
- "dependencies": {
- "useEntertainmentAPI": false
- }
- },
- "propertyOrder" : 5
- },
- "switchOffOnBlack": {
- "type": "boolean",
- "title":"edt_dev_spec_switchOffOnBlack_title",
- "default" : false,
- "propertyOrder" : 6
- },
- "restoreOriginalState": {
- "type": "boolean",
- "title":"edt_dev_spec_restoreOriginalState_title",
- "default" : true,
- "propertyOrder" : 7
- },
- "lightIds": {
- "type": "array",
- "title":"edt_dev_spec_lightid_title",
- "minItems": 1,
- "uniqueItems" : true,
- "items" : {
- "type" : "string",
- "minimum" : 0,
- "title" : "edt_dev_spec_lightid_itemtitle"
- },
- "options": {
- "dependencies": {
- "useEntertainmentAPI": false
- }
- },
- "propertyOrder" : 8
- },
- "groupId": {
- "type": "number",
- "title":"edt_dev_spec_groupId_title",
- "default" : 0,
- "options": {
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "propertyOrder" : 9
- },
- "blackLightsTimeout": {
- "type": "number",
- "title":"edt_dev_spec_blackLightsTimeout_title",
- "default" : 15000,
- "step": 500,
- "minimum" : 10000,
- "maximum" : 60000,
- "access" : "advanced",
- "append" : "edt_append_ms",
- "options": {
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "propertyOrder" : 10
- },
- "brightnessThreshold": {
- "type": "number",
- "title":"edt_dev_spec_brightnessThreshold_title",
- "default" : 0,
- "step": 0.005,
- "minimum" : 0,
- "maximum" : 1.0,
- "access" : "advanced",
- "options": {
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "propertyOrder" : 11
- },
- "brightnessFactor": {
- "type": "number",
- "title":"edt_dev_spec_brightnessFactor_title",
- "default" : 1.0,
- "step": 0.25,
- "minimum" : 0.5,
- "maximum" : 10.0,
- "access" : "advanced",
- "propertyOrder" : 12
- },
- "brightnessMin": {
- "type": "number",
- "title":"edt_dev_spec_brightnessMin_title",
- "default" : 0,
- "step": 0.05,
- "minimum" : 0,
- "maximum" : 1.0,
- "access" : "advanced",
- "options": {
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "propertyOrder" : 13
- },
- "brightnessMax": {
- "type": "number",
- "title":"edt_dev_spec_brightnessMax_title",
- "default" : 1.0,
- "step": 0.05,
- "minimum" : 0,
- "maximum" : 1.0,
- "access" : "advanced",
- "options": {
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "propertyOrder" : 14
- },
- "sslReadTimeout": {
- "type": "number",
- "title":"edt_dev_spec_sslReadTimeout_title",
- "default" : 0,
- "step": 100,
- "minimum" : 0,
- "maximum" : 30000,
- "access" : "expert",
- "append" : "edt_append_ms",
- "options": {
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "propertyOrder" : 15
- },
- "sslHSTimeoutMin": {
- "type": "number",
- "title":"edt_dev_spec_sslHSTimeoutMin_title",
- "default" : 400,
- "step": 100,
- "minimum" : 0,
- "maximum" : 30000,
- "access" : "expert",
- "append" : "edt_append_ms",
- "options": {
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "propertyOrder" : 16
- },
- "sslHSTimeoutMax": {
- "type": "number",
- "title":"edt_dev_spec_sslHSTimeoutMax_title",
- "default" : 1000,
- "step": 100,
- "minimum" : 0,
- "maximum" : 30000,
- "access" : "expert",
- "append" : "edt_append_ms",
- "options": {
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "propertyOrder" : 17
- },
- "verbose": {
- "type": "boolean",
- "title":"edt_dev_spec_verbose_title",
- "default" : false,
- "access" : "expert",
- "propertyOrder" : 18
- },
- "debugStreamer": {
- "type": "boolean",
- "title":"edt_dev_spec_debugStreamer_title",
- "default" : false,
- "access" : "expert",
- "options": {
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "propertyOrder" : 19
- },
- "debugLevel": {
- "type": "string",
- "title":"edt_dev_spec_debugLevel_title",
- "enum" : ["0", "1", "2", "3", "4"],
- "default" : "0",
- "options" : {
- "enum_titles" : ["edt_conf_enum_dl_nodebug", "edt_conf_enum_dl_error", "edt_conf_enum_dl_statechange", "edt_conf_enum_dl_informational", "edt_conf_enum_dl_verbose"],
- "dependencies": {
- "useEntertainmentAPI": true
- }
- },
- "minimum" : 0,
- "maximum" : 4,
- "access" : "expert",
- "propertyOrder" : 20
- }
- },
- "additionalProperties": true
+ "type": "object",
+ "required": true,
+ "properties": {
+ "output": {
+ "type": "string",
+ "title": "edt_dev_spec_targetIp_title",
+ "default": "",
+ "propertyOrder": 1
+ },
+ "username": {
+ "type": "string",
+ "title": "edt_dev_spec_username_title",
+ "default": "",
+ "propertyOrder": 2
+ },
+ "clientkey": {
+ "type": "string",
+ "title": "edt_dev_spec_clientKey_title",
+ "default": "",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder": 3
+ },
+ "useEntertainmentAPI": {
+ "type": "boolean",
+ "title": "edt_dev_spec_useEntertainmentAPI_title",
+ "default": false,
+ "propertyOrder": 4
+ },
+ "transitiontime": {
+ "type": "number",
+ "title": "edt_dev_spec_transistionTime_title",
+ "default": 1,
+ "append": "x100ms",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": false
+ }
+ },
+ "propertyOrder": 5
+ },
+ "switchOffOnBlack": {
+ "type": "boolean",
+ "title": "edt_dev_spec_switchOffOnBlack_title",
+ "default": false,
+ "propertyOrder": 6
+ },
+ "restoreOriginalState": {
+ "type": "boolean",
+ "title": "edt_dev_spec_restoreOriginalState_title",
+ "default": true,
+ "propertyOrder": 7
+ },
+ "lightIds": {
+ "type": "array",
+ "title": "edt_dev_spec_lightid_title",
+ "minimum": 1,
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "minLength": 1,
+ "required": true,
+ "title": "edt_dev_spec_lightid_itemtitle"
+ },
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": false
+ }
+ },
+ "propertyOrder": 8
+ },
+ "groupId": {
+ "type": "number",
+ "title": "edt_dev_spec_groupId_title",
+ "default": 0,
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder": 9
+ },
+ "blackLightsTimeout": {
+ "type": "number",
+ "title": "edt_dev_spec_blackLightsTimeout_title",
+ "default": 15000,
+ "step": 500,
+ "minimum": 10000,
+ "maximum": 60000,
+ "access": "advanced",
+ "append": "edt_append_ms",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder": 10
+ },
+ "brightnessThreshold": {
+ "type": "number",
+ "title": "edt_dev_spec_brightnessThreshold_title",
+ "default": 0,
+ "step": 0.005,
+ "minimum": 0,
+ "maximum": 1.0,
+ "access": "advanced",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder": 11
+ },
+ "brightnessFactor": {
+ "type": "number",
+ "title": "edt_dev_spec_brightnessFactor_title",
+ "default": 1.0,
+ "step": 0.25,
+ "minimum": 0.5,
+ "maximum": 10.0,
+ "access": "advanced",
+ "propertyOrder": 12
+ },
+ "brightnessMin": {
+ "type": "number",
+ "title": "edt_dev_spec_brightnessMin_title",
+ "default": 0,
+ "step": 0.05,
+ "minimum": 0,
+ "maximum": 1.0,
+ "access": "advanced",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder": 13
+ },
+ "brightnessMax": {
+ "type": "number",
+ "title": "edt_dev_spec_brightnessMax_title",
+ "default": 1.0,
+ "step": 0.05,
+ "minimum": 0,
+ "maximum": 1.0,
+ "access": "advanced",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder": 14
+ },
+ "sslReadTimeout": {
+ "type": "number",
+ "title": "edt_dev_spec_sslReadTimeout_title",
+ "default": 0,
+ "step": 100,
+ "minimum": 0,
+ "maximum": 30000,
+ "access": "expert",
+ "append": "edt_append_ms",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder": 15
+ },
+ "sslHSTimeoutMin": {
+ "type": "number",
+ "title": "edt_dev_spec_sslHSTimeoutMin_title",
+ "default": 400,
+ "step": 100,
+ "minimum": 0,
+ "maximum": 30000,
+ "access": "expert",
+ "append": "edt_append_ms",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder": 16
+ },
+ "sslHSTimeoutMax": {
+ "type": "number",
+ "title": "edt_dev_spec_sslHSTimeoutMax_title",
+ "default": 1000,
+ "step": 100,
+ "minimum": 0,
+ "maximum": 30000,
+ "access": "expert",
+ "append": "edt_append_ms",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder": 17
+ },
+ "verbose": {
+ "type": "boolean",
+ "title": "edt_dev_spec_verbose_title",
+ "default": false,
+ "access": "expert",
+ "propertyOrder": 18
+ },
+ "debugStreamer": {
+ "type": "boolean",
+ "title": "edt_dev_spec_debugStreamer_title",
+ "default": false,
+ "access": "expert",
+ "options": {
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "propertyOrder": 19
+ },
+ "debugLevel": {
+ "type": "string",
+ "title": "edt_dev_spec_debugLevel_title",
+ "enum": [ "0", "1", "2", "3", "4" ],
+ "default": "0",
+ "options": {
+ "enum_titles": [ "edt_conf_enum_dl_nodebug", "edt_conf_enum_dl_error", "edt_conf_enum_dl_statechange", "edt_conf_enum_dl_informational", "edt_conf_enum_dl_verbose" ],
+ "dependencies": {
+ "useEntertainmentAPI": true
+ }
+ },
+ "minimum": 0,
+ "maximum": 4,
+ "access": "expert",
+ "propertyOrder": 20
+ }
+ },
+ "additionalProperties": true
}
diff --git a/libsrc/leddevice/schemas/schema-sk6812spi.json b/libsrc/leddevice/schemas/schema-sk6812spi.json
index 229181d4..49b7fef7 100644
--- a/libsrc/leddevice/schemas/schema-sk6812spi.json
+++ b/libsrc/leddevice/schemas/schema-sk6812spi.json
@@ -5,7 +5,6 @@
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
- "enum" : ["/dev/spidev0.0","/dev/spidev0.1"],
"propertyOrder" : 1
},
"rate": {
diff --git a/libsrc/leddevice/schemas/schema-sk6822spi.json b/libsrc/leddevice/schemas/schema-sk6822spi.json
index 6116937e..b6620279 100644
--- a/libsrc/leddevice/schemas/schema-sk6822spi.json
+++ b/libsrc/leddevice/schemas/schema-sk6822spi.json
@@ -5,7 +5,6 @@
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
- "enum" : ["/dev/spidev0.0","/dev/spidev0.1"],
"propertyOrder" : 1
},
"rate": {
diff --git a/libsrc/leddevice/schemas/schema-sk9822.json b/libsrc/leddevice/schemas/schema-sk9822.json
index 7b5d5584..3777b652 100644
--- a/libsrc/leddevice/schemas/schema-sk9822.json
+++ b/libsrc/leddevice/schemas/schema-sk9822.json
@@ -5,7 +5,6 @@
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
- "enum" : ["/dev/spidev0.0","/dev/spidev0.1"],
"default" : "/dev/spidev0.0",
"propertyOrder" : 1
},
diff --git a/libsrc/leddevice/schemas/schema-wled.json b/libsrc/leddevice/schemas/schema-wled.json
index bb00f3de..881220c8 100644
--- a/libsrc/leddevice/schemas/schema-wled.json
+++ b/libsrc/leddevice/schemas/schema-wled.json
@@ -1,30 +1,84 @@
{
- "type":"object",
- "required":true,
- "properties":{
- "host" : {
- "type": "string",
- "title": "edt_dev_spec_targetIpHost_title",
- "required": true,
- "propertyOrder": 1
- },
- "restoreOriginalState": {
- "type": "boolean",
- "title": "edt_dev_spec_restoreOriginalState_title",
- "default": false,
- "required": true,
- "propertyOrder": 2
- },
- "latchTime": {
- "type": "integer",
- "title":"edt_dev_spec_latchtime_title",
- "default": 0,
- "append" : "edt_append_ms",
- "minimum": 0,
- "maximum": 1000,
- "access" : "expert",
- "propertyOrder" : 3
- }
- },
- "additionalProperties": true
+ "type": "object",
+ "title": "",
+ "required": true,
+ "properties": {
+ "hostList": {
+ "type": "string",
+ "title": "edt_dev_spec_devices_discovered_title",
+ "enum": [ "NONE" ],
+ "options": {
+ "enum_titles": [ "edt_dev_spec_devices_discovery_inprogress" ],
+ "infoText": "edt_dev_spec_devices_discovered_title_info"
+ },
+ "required": true,
+ "propertyOrder": 1
+ },
+ "host": {
+ "type": "string",
+ "title": "edt_dev_spec_targetIpHost_title",
+ "options": {
+ "infoText": "edt_dev_spec_targetIpHost_title_info"
+ },
+ "required": true,
+ "propertyOrder": 2
+ },
+ "restoreOriginalState": {
+ "type": "boolean",
+ "format": "checkbox",
+ "title": "edt_dev_spec_restoreOriginalState_title",
+ "default": false,
+ "required": true,
+ "options": {
+ "infoText": "edt_dev_spec_restoreOriginalState_title_info"
+ },
+ "propertyOrder": 3
+ },
+ "overwriteSync": {
+ "type": "boolean",
+ "format": "checkbox",
+ "title": "edt_dev_spec_syncOverwrite_title",
+ "default": true,
+ "required": true,
+ "access": "advanced",
+ "propertyOrder": 4
+ },
+ "overwriteBrightness": {
+ "type": "boolean",
+ "format": "checkbox",
+ "title": "edt_dev_spec_brightnessOverwrite_title",
+ "default": true,
+ "required": true,
+ "access": "advanced",
+ "propertyOrder": 5
+ },
+ "brightness": {
+ "type": "integer",
+ "title": "edt_dev_spec_brightness_title",
+ "default": 255,
+ "minimum": 1,
+ "maximum": 255,
+ "options": {
+ "dependencies": {
+ "overwriteBrightness": true
+ }
+ },
+ "access": "advanced",
+ "propertyOrder": 6
+ },
+ "latchTime": {
+ "type": "integer",
+ "title": "edt_dev_spec_latchtime_title",
+ "default": 0,
+ "append": "edt_append_ms",
+ "minimum": 0,
+ "maximum": 1000,
+ "access": "expert",
+ "options": {
+ "infoText": "edt_dev_spec_latchtime_title_info"
+ },
+ "propertyOrder": 7
+ }
+ },
+ "additionalProperties": true
}
diff --git a/libsrc/leddevice/schemas/schema-ws2801.json b/libsrc/leddevice/schemas/schema-ws2801.json
index c1830381..ec8f08fc 100644
--- a/libsrc/leddevice/schemas/schema-ws2801.json
+++ b/libsrc/leddevice/schemas/schema-ws2801.json
@@ -5,7 +5,6 @@
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
- "enum" : ["/dev/spidev0.0","/dev/spidev0.1","/dev/spidev1.0","/dev/spidev1.1"],
"propertyOrder" : 1
},
"rate": {
diff --git a/libsrc/leddevice/schemas/schema-ws2812spi.json b/libsrc/leddevice/schemas/schema-ws2812spi.json
index 2949565f..d8c21d4d 100644
--- a/libsrc/leddevice/schemas/schema-ws2812spi.json
+++ b/libsrc/leddevice/schemas/schema-ws2812spi.json
@@ -5,7 +5,6 @@
"output": {
"type": "string",
"title":"edt_dev_spec_spipath_title",
- "enum" : ["/dev/spidev0.0","/dev/spidev0.1"],
"propertyOrder" : 1
},
"rate": {
diff --git a/libsrc/leddevice/schemas/schema-yeelight.json b/libsrc/leddevice/schemas/schema-yeelight.json
index d91f7675..1fe8f173 100644
--- a/libsrc/leddevice/schemas/schema-yeelight.json
+++ b/libsrc/leddevice/schemas/schema-yeelight.json
@@ -1,180 +1,176 @@
{
- "type":"object",
- "required":true,
- "properties":{
- "colorModel": {
- "type": "integer",
- "title":"Output Type",
- "enum" : [0, 1],
- "default" : 1,
- "options" : {
- "enum_titles" : ["edt_conf_enum_hsv", "edt_conf_enum_rgb"]
- },
- "minimum" : 0,
- "maximum" : 1,
- "access" : "advanced",
- "propertyOrder" : 1
- },
- "transEffect": {
- "type": "integer",
- "title":"edt_dev_spec_transeffect_title",
- "enum" : [0, 1],
- "default" : 0,
- "options" : {
- "enum_titles" : ["edt_conf_enum_transeffect_smooth", "edt_conf_enum_transeffect_sudden" ]
- },
- "minimum" : 0,
- "maximum" : 1,
- "access" : "advanced",
- "propertyOrder" : 2
- },
- "transTime": {
- "type": "integer",
- "title":"edt_dev_spec_transistionTime_title",
- "default": 40,
- "append" : "ms",
- "minimum": 30,
- "maximum": 5000,
- "access" : "advanced",
- "options": {
- "dependencies": {
- "transEffect": 0
- }
- },
- "propertyOrder" : 3
- },
- "extraTimeDarkness": {
- "type": "integer",
- "title":"edt_dev_spec_transistionTimeExtra_title",
- "default" : 0,
- "step": 100,
- "minimum" : 0,
- "maximum" : 8000,
- "append" : "ms",
- "access" : "advanced",
- "propertyOrder" : 4
- },
- "brightnessMin": {
- "type": "integer",
- "title":"edt_dev_spec_brightnessMin_title",
- "default" : 1,
- "step": 1,
- "minimum" : 1,
- "maximum" : 99,
- "append" : "%",
- "access" : "advanced",
- "propertyOrder" : 5
- },
- "brightnessSwitchOffOnMinimum": {
- "type": "boolean",
- "title":"edt_dev_spec_switchOffOnbelowMinBrightness_title",
- "default" : true,
- "access" : "advanced",
- "propertyOrder" : 6
- },
- "brightnessMax": {
- "type": "integer",
- "title":"edt_dev_spec_brightnessMax_title",
- "default" : 100,
- "step": 1,
- "minimum" : 0,
- "maximum" : 100,
- "append" : "%",
- "access" : "advanced",
- "propertyOrder" : 7
- },
- "brightnessFactor": {
- "type": "number",
- "title":"edt_dev_spec_brightnessFactor_title",
- "default" : 1.0,
- "step": 0.25,
- "minimum" : 0.5,
- "maximum" : 10.0,
- "access" : "expert",
- "propertyOrder" : 8
- },
- "restoreOriginalState": {
- "type": "boolean",
- "title":"edt_dev_spec_restoreOriginalState_title",
- "default" : false,
- "propertyOrder" : 9
- },
- "lights": {
- "type": "array",
- "title":"edt_dev_spec_lights_title",
- "propertyOrder" : 9,
- "minimum" : 1,
- "uniqueItems" : true,
- "items" : {
- "type" : "object",
- "title" : "edt_dev_spec_lights_itemtitle",
- "required" : true,
- "properties" :
- {
- "host" :
- {
- "type" : "string",
- "minimum" : 7,
- "title" : "edt_dev_spec_networkDeviceName_title",
- "required" : true,
- "propertyOrder" : 1
- },
- "port" :
- {
- "type" : "integer",
- "minimum" : 0,
- "maximum" : 65535,
- "default":55443,
- "title" : "edt_dev_spec_networkDevicePort_title",
- "required" : false,
- "access" : "expert",
- "propertyOrder" : 2
- },
- "name" :
- {
- "type" : "string",
- "title" : "edt_dev_spec_lights_name",
- "minimum" : 0,
- "propertyOrder" : 3
- }
- }
- },
- "propertyOrder" : 10
- },
- "quotaWait": {
- "type": "integer",
- "title":"Wait time (quota)",
- "default": 1000,
- "append" : "edt_append_ms",
- "minimum": 0,
- "maximum": 10000,
- "step": 100,
- "access" : "expert",
- "propertyOrder" : 11
- },
- "latchTime": {
- "type": "integer",
- "title":"edt_dev_spec_latchtime_title",
- "default": 40,
- "append" : "edt_append_ms",
- "minimum": 0,
- "maximum": 1000,
- "access" : "expert",
- "propertyOrder" : 12
- },
- "debugLevel": {
- "type": "integer",
- "title":"edt_dev_spec_debugLevel_title",
- "enum" : [0, 1, 2, 3],
- "default" : 0,
- "options" : {
- "enum_titles" : ["edt_conf_enum_dl_nodebug", "edt_conf_enum_dl_verbose1", "edt_conf_enum_dl_verbose2", "edt_conf_enum_dl_verbose3"]
- },
- "minimum" : 0,
- "maximum" : 3,
- "access" : "expert",
- "propertyOrder" : 13
- }
- },
- "additionalProperties": true
+ "type": "object",
+ "required": true,
+ "properties": {
+ "colorModel": {
+ "type": "string",
+ "title": "Output Type",
+ "enum": [ "0", "1" ],
+ "default": "1",
+ "options": {
+ "enum_titles": [ "edt_conf_enum_hsv", "edt_conf_enum_rgb" ]
+ },
+ "minimum": 0,
+ "maximum": 1,
+ "access": "advanced",
+ "propertyOrder": 1
+ },
+ "transEffect": {
+ "type": "string",
+ "title": "edt_dev_spec_transeffect_title",
+ "enum": [ "0", "1" ],
+ "default": "0",
+ "options": {
+ "enum_titles": [ "edt_conf_enum_transeffect_smooth", "edt_conf_enum_transeffect_sudden" ]
+ },
+ "minimum": 0,
+ "maximum": 1,
+ "access": "advanced",
+ "propertyOrder": 2
+ },
+ "transTime": {
+ "type": "integer",
+ "title": "edt_dev_spec_transistionTime_title",
+ "default": 40,
+ "append": "ms",
+ "minimum": 30,
+ "maximum": 5000,
+ "access": "advanced",
+ "options": {
+ "dependencies": {
+ "transEffect": 0
+ }
+ },
+ "propertyOrder": 3
+ },
+ "extraTimeDarkness": {
+ "type": "integer",
+ "title": "edt_dev_spec_transistionTimeExtra_title",
+ "default": 0,
+ "step": 100,
+ "minimum": 0,
+ "maximum": 8000,
+ "append": "ms",
+ "access": "advanced",
+ "propertyOrder": 4
+ },
+ "brightnessMin": {
+ "type": "integer",
+ "title": "edt_dev_spec_brightnessMin_title",
+ "default": 1,
+ "step": 1,
+ "minimum": 1,
+ "maximum": 99,
+ "append": "%",
+ "access": "advanced",
+ "propertyOrder": 5
+ },
+ "brightnessSwitchOffOnMinimum": {
+ "type": "boolean",
+ "title": "edt_dev_spec_switchOffOnbelowMinBrightness_title",
+ "default": true,
+ "access": "advanced",
+ "propertyOrder": 6
+ },
+ "brightnessMax": {
+ "type": "integer",
+ "title": "edt_dev_spec_brightnessMax_title",
+ "default": 100,
+ "step": 1,
+ "minimum": 0,
+ "maximum": 100,
+ "append": "%",
+ "access": "advanced",
+ "propertyOrder": 7
+ },
+ "brightnessFactor": {
+ "type": "number",
+ "title": "edt_dev_spec_brightnessFactor_title",
+ "default": 1.0,
+ "step": 0.25,
+ "minimum": 0.5,
+ "maximum": 10.0,
+ "access": "expert",
+ "propertyOrder": 8
+ },
+ "restoreOriginalState": {
+ "type": "boolean",
+ "title": "edt_dev_spec_restoreOriginalState_title",
+ "default": false,
+ "propertyOrder": 9
+ },
+ "lights": {
+ "type": "array",
+ "title": "edt_dev_spec_lights_title",
+ "propertyOrder": 9,
+ "minimum": 1,
+ "uniqueItems": true,
+ "items": {
+ "type": "object",
+ "title": "edt_dev_spec_lights_itemtitle",
+ "required": true,
+ "properties": {
+ "host": {
+ "type": "string",
+ "minLength": 7,
+ "title": "edt_dev_spec_networkDeviceName_title",
+ "required": true,
+ "propertyOrder": 1
+ },
+ "port": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 65535,
+ "default": 55443,
+ "title": "edt_dev_spec_networkDevicePort_title",
+ "required": false,
+ "access": "expert",
+ "propertyOrder": 2
+ },
+ "name": {
+ "type": "string",
+ "title": "edt_dev_spec_lights_name",
+ "minimum": 0,
+ "propertyOrder": 3
+ }
+ }
+ },
+ "propertyOrder": 10
+ },
+ "quotaWait": {
+ "type": "integer",
+ "title": "Wait time (quota)",
+ "default": 1000,
+ "append": "edt_append_ms",
+ "minimum": 0,
+ "maximum": 10000,
+ "step": 100,
+ "access": "expert",
+ "propertyOrder": 11
+ },
+ "latchTime": {
+ "type": "integer",
+ "title": "edt_dev_spec_latchtime_title",
+ "default": 40,
+ "append": "edt_append_ms",
+ "minimum": 0,
+ "maximum": 1000,
+ "access": "expert",
+ "propertyOrder": 12
+ },
+ "debugLevel": {
+ "type": "string",
+ "title": "edt_dev_spec_debugLevel_title",
+ "enum": [ "0", "1", "2", "3" ],
+ "default": "0",
+ "options": {
+ "enum_titles": [ "edt_conf_enum_dl_nodebug", "edt_conf_enum_dl_verbose1", "edt_conf_enum_dl_verbose2", "edt_conf_enum_dl_verbose3" ]
+ },
+ "minimum": 0,
+ "maximum": 3,
+ "access": "expert",
+ "propertyOrder": 13
+ }
+ },
+ "additionalProperties": true
}
diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp
index 1c12289d..ebc986f7 100644
--- a/src/hyperiond/hyperiond.cpp
+++ b/src/hyperiond/hyperiond.cpp
@@ -96,8 +96,8 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
qRegisterMetaType>("QMap");
qRegisterMetaType>("std::vector");
- // init settings
- _settingsManager = new SettingsManager(0, this, readonlyMode);
+ // init settings, this settingsManager accesses global settings which are independent from instances
+ _settingsManager = new SettingsManager(GLOABL_INSTANCE_ID, this, readonlyMode);
// set inital log lvl if the loglvl wasn't overwritten by arg
if (!logLvlOverwrite)
From aede77b7caab25b23f69ba01e0efeabe08aea98a Mon Sep 17 00:00:00 2001
From: Portisch
Date: Sun, 25 Apr 2021 16:49:42 +0200
Subject: [PATCH 05/58] AmlogicGrabber: set and decrease frame grab timeout to
500ms (#1225)
This prevent an internal timeout when no frame is delivered like on playback pause.
---
libsrc/grabber/amlogic/AmlogicGrabber.cpp | 3 ++-
libsrc/grabber/amlogic/Amvideocap.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/libsrc/grabber/amlogic/AmlogicGrabber.cpp b/libsrc/grabber/amlogic/AmlogicGrabber.cpp
index 34d531d0..d4ee2f08 100644
--- a/libsrc/grabber/amlogic/AmlogicGrabber.cpp
+++ b/libsrc/grabber/amlogic/AmlogicGrabber.cpp
@@ -132,8 +132,9 @@ int AmlogicGrabber::grabFrame_amvideocap(Image & image)
long r1 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH, _width);
long r2 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT, _height);
long r3 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_AT_FLAGS, CAP_FLAG_AT_END);
+ long r4 = ioctl(_captureDev, AMVIDEOCAP_IOW_SET_WANTFRAME_WAIT_MAX_MS, 500);
- if (r1<0 || r2<0 || r3<0 || _height==0 || _width==0)
+ if (r1<0 || r2<0 || r3<0 || r4<0 || _height==0 || _width==0)
{
ErrorIf(_lastError != 2,_log,"Failed to configure capture device (%d - %s)", errno, strerror(errno));
_lastError = 2;
diff --git a/libsrc/grabber/amlogic/Amvideocap.h b/libsrc/grabber/amlogic/Amvideocap.h
index 828aa895..40c58b33 100644
--- a/libsrc/grabber/amlogic/Amvideocap.h
+++ b/libsrc/grabber/amlogic/Amvideocap.h
@@ -14,6 +14,7 @@
// #define AMVIDEOCAP_IOW_SET_WANTFRAME_FORMAT _IOW(AMVIDEOCAP_IOC_MAGIC, 0x01, int)
#define AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH _IOW(AMVIDEOCAP_IOC_MAGIC, 0x02, int)
#define AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT _IOW(AMVIDEOCAP_IOC_MAGIC, 0x03, int)
+#define AMVIDEOCAP_IOW_SET_WANTFRAME_WAIT_MAX_MS _IOW(AMVIDEOCAP_IOC_MAGIC, 0x05, unsigned long long)
#define AMVIDEOCAP_IOW_SET_WANTFRAME_AT_FLAGS _IOW(AMVIDEOCAP_IOC_MAGIC, 0x06, int)
#define _A_M 'S'
From 35ffeb740f35181298e15d3e31622cff0b9bbe4b Mon Sep 17 00:00:00 2001
From: LordGrey <48840279+Lord-Grey@users.noreply.github.com>
Date: Sun, 25 Apr 2021 16:50:27 +0200
Subject: [PATCH 06/58] Stop background effect, when it gets out of scope
(#1226)
---
include/hyperion/BGEffectHandler.h | 44 ++++++++++++++++++++++++++----
1 file changed, 39 insertions(+), 5 deletions(-)
diff --git a/include/hyperion/BGEffectHandler.h b/include/hyperion/BGEffectHandler.h
index 9c0dfcbd..ae3362f0 100644
--- a/include/hyperion/BGEffectHandler.h
+++ b/include/hyperion/BGEffectHandler.h
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
///
/// @brief Handle the background Effect settings, reacts on runtime to settings changes
@@ -14,11 +15,19 @@ class BGEffectHandler : public QObject
public:
BGEffectHandler(Hyperion* hyperion)
- : QObject(hyperion)
- , _hyperion(hyperion)
+ : QObject(hyperion)
+ , _hyperion(hyperion)
+ , _prioMuxer(_hyperion->getMuxerInstance())
+ , _isBgEffectConfigured(false)
{
// listen for config changes
- connect(_hyperion, &Hyperion::settingsChanged, this, &BGEffectHandler::handleSettingsUpdate);
+ connect(_hyperion, &Hyperion::settingsChanged,
+ [=](settings::type type, const QJsonDocument& config) { this->handleSettingsUpdate(type, config); }
+ );
+
+ connect(_prioMuxer, &PriorityMuxer::prioritiesChanged,
+ [=]() { this->handlePriorityUpdate(); }
+ );
// initialization
handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
@@ -34,14 +43,18 @@ private slots:
{
if(type == settings::BGEFFECT)
{
- const QJsonObject& BGEffectConfig = config.object();
+ _isBgEffectConfigured = false;
+ _bgEffectConfig = config;
+ const QJsonObject& BGEffectConfig = _bgEffectConfig.object();
#define BGCONFIG_ARRAY bgColorConfig.toArray()
// clear background priority
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
// initial background effect/color
if (BGEffectConfig["enable"].toBool(true))
{
+ _isBgEffectConfigured = true;
+
const QString bgTypeConfig = BGEffectConfig["type"].toString("effect");
const QString bgEffectConfig = BGEffectConfig["effect"].toString("Warm mood blobs");
const QJsonValue bgColorConfig = BGEffectConfig["color"];
@@ -63,12 +76,33 @@ private slots:
Info(Logger::getInstance("HYPERION"),"Initial background effect '%s' %s", QSTRING_CSTR(bgEffectConfig), ((result == 0) ? "started" : "failed"));
}
}
-
#undef BGCONFIG_ARRAY
}
}
+ ///
+ /// @brief Handle priority updates.
+ /// In case the background effect is not current priority, stop BG-effect to save resources; otherwise start effect again.
+ ///
+ void handlePriorityUpdate()
+ {
+ if (_prioMuxer->getCurrentPriority() != PriorityMuxer::BG_PRIORITY && _prioMuxer->hasPriority(PriorityMuxer::BG_PRIORITY))
+ {
+ Debug(Logger::getInstance("HYPERION"),"Stop background (color-) effect as it moved out of scope");
+ _hyperion->clear(PriorityMuxer::BG_PRIORITY);
+ }
+ else if (_prioMuxer->getCurrentPriority() == PriorityMuxer::LOWEST_PRIORITY && _isBgEffectConfigured)
+ {
+ emit handleSettingsUpdate (settings::BGEFFECT, _bgEffectConfig);
+ }
+ }
+
private:
/// Hyperion instance pointer
Hyperion* _hyperion;
+ /// priority muxer instance
+ PriorityMuxer* _prioMuxer;
+
+ QJsonDocument _bgEffectConfig;
+ bool _isBgEffectConfigured;
};
From 724d90bfdb0175e24c434dc1bd0bfe7300628bc4 Mon Sep 17 00:00:00 2001
From: Daniel Schwierzeck
Date: Sun, 25 Apr 2021 17:22:16 +0200
Subject: [PATCH 07/58] Initial support for Hue Play Gradient Lightstrip
(#1187)
Model ID is LCX001. Add as Gamut C device.
---
CHANGELOG.md | 1 +
libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e00f0ccc..db71eb76 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Breaking
### Added
+- LED-Devices: basic support for Hue Play Gradient Lightstrip
- WLED: Support of ["live" property] (https://github.com/Aircoookie/WLED/issues/1308), addresses #1095
- WLED: Support storing/restoring state, fixes #1101
diff --git a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
index 46e2c4b7..f5cb0f86 100644
--- a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
+++ b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
@@ -652,7 +652,7 @@ const std::set PhilipsHueLight::GAMUT_A_MODEL_IDS =
const std::set PhilipsHueLight::GAMUT_B_MODEL_IDS =
{ "LCT001", "LCT002", "LCT003", "LCT007", "LLM001" };
const std::set PhilipsHueLight::GAMUT_C_MODEL_IDS =
- { "LCA001", "LCA002", "LCA003", "LCG002", "LCP001", "LCP002", "LCT010", "LCT011", "LCT012", "LCT014", "LCT015", "LCT016", "LCT024", "LLC020", "LST002" };
+ { "LCA001", "LCA002", "LCA003", "LCG002", "LCP001", "LCP002", "LCT010", "LCT011", "LCT012", "LCT014", "LCT015", "LCT016", "LCT024", "LCX001", "LLC020", "LST002" };
PhilipsHueLight::PhilipsHueLight(Logger* log, unsigned int id, QJsonObject values, unsigned int ledidx)
: _log(log)
From 71e34a6a55ed40ed36dfbbd674ee9c5bc354cbf0 Mon Sep 17 00:00:00 2001
From: LordGrey <48840279+Lord-Grey@users.noreply.github.com>
Date: Sun, 25 Apr 2021 17:22:59 +0200
Subject: [PATCH 08/58] UI System Log - Fixes and enhancements (#1223)
---
assets/webconfig/content/about.html | 36 +--
assets/webconfig/content/conf_logging.html | 35 +--
assets/webconfig/i18n/en.json | 1 +
assets/webconfig/js/content_index.js | 4 +-
assets/webconfig/js/content_logging.js | 334 ++++++++++-----------
assets/webconfig/js/content_remote.js | 281 ++++++++---------
assets/webconfig/js/ledsim.js | 14 +-
assets/webconfig/js/ui_utils.js | 39 ++-
8 files changed, 351 insertions(+), 393 deletions(-)
diff --git a/assets/webconfig/content/about.html b/assets/webconfig/content/about.html
index 665dbc4b..a293b203 100644
--- a/assets/webconfig/content/about.html
+++ b/assets/webconfig/content/about.html
@@ -31,39 +31,9 @@
libh += " " + $.i18n("about_credits");
lang = lang.toString().replace(/,/g, ", ");
- // Github Issue bugreport infos
- var sys = window.sysInfo.system;
- var shy = window.sysInfo.hyperion;
- var info = "Hyperion Server: \n";
- info += '- Build: ' + shy.build + '\n';
- info += '- Build time: ' + shy.time + '\n';
- info += '- Git Remote: ' + shy.gitremote + '\n';
- info += '- Version: ' + shy.version + '\n';
- info += '- UI Lang: ' + storedLang + ' (BrowserLang: ' + navigator.language + ')\n';
- info += '- UI Access: ' + storedAccess + '\n';
- //info += '- Log lvl: ' + window.serverConfig.logger.level + '\n';
- info += '- Avail Capt: ' + window.serverInfo.grabbers.available + '\n';
- info += '- Database: ' + (shy.readOnlyMode ? "ready-only" : "read/write") + '\n';
-
- info += '\n';
-
- info += 'Hyperion Server OS: \n';
- info += '- Distribution: ' + sys.prettyName + '\n';
- info += '- Architecture: ' + sys.architecture + '\n';
-
- if (sys.cpuModelName)
- info += '- CPU Model: ' + sys.cpuModelName + '\n';
- if (sys.cpuModelType)
- info += '- CPU Type: ' + sys.cpuModelType + '\n';
- if (sys.cpuRevision)
- info += '- CPU Revision: ' + sys.cpuRevision + '\n';
- if (sys.cpuHardware)
- info += '- CPU Hardware: ' + sys.cpuHardware + '\n';
-
- info += '- Kernel: ' + sys.kernelType + ' (' + sys.kernelVersion + ' (WS: ' + sys.wordSize + '))\n';
- info += '- Qt Version: ' + sys.qtVersion + '\n';
- info += '- Python Version: ' + sys.pyVersion + '\n';
- info += '- Browser: ' + navigator.userAgent + ' ';
+ // Github Issue bugreport infos
+ var sysInfo = getSystemInfo();
+ var info = '' + sysInfo + ' ';
var fc = ['' + $.i18n("about_version") + '', $.i18n("about_build"), $.i18n("about_builddate"), $.i18n("about_translations"), $.i18n("about_resources", $.i18n("general_webui_title")), "System info (Github Issue)", $.i18n("about_3rd_party_licenses")];
var sc = [currentVersion, si.build, si.time, '(' + availLang.length + ')' + lang + '
' + $.i18n("about_contribute") + '
', libh, info, '
'];
diff --git a/assets/webconfig/content/conf_logging.html b/assets/webconfig/content/conf_logging.html
index a9995b2f..768f9908 100644
--- a/assets/webconfig/content/conf_logging.html
+++ b/assets/webconfig/content/conf_logging.html
@@ -1,21 +1,22 @@
diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json
index 20beaeb8..be7abeb6 100644
--- a/assets/webconfig/i18n/en.json
+++ b/assets/webconfig/i18n/en.json
@@ -125,6 +125,7 @@
"conf_logging_label_intro": "Area to check log messages, you will see more or less information depending on the logging level set.",
"conf_logging_lastreports": "Previous reports",
"conf_logging_nomessage": "No log messages available.",
+ "conf_logging_logoutput": "Log output",
"conf_logging_report": "Report",
"conf_logging_uplfailed": "Upload failed! Please check your internet connection!",
"conf_logging_uploading": "Prepare data...",
diff --git a/assets/webconfig/js/content_index.js b/assets/webconfig/js/content_index.js
index c2263509..ff44d7fc 100755
--- a/assets/webconfig/js/content_index.js
+++ b/assets/webconfig/js/content_index.js
@@ -24,8 +24,6 @@ $(document).ready(function () {
$(window.hyperion).on("cmd-serverinfo", function (event) {
window.serverInfo = event.response.info;
- window.readOnlyMode = window.sysInfo.hyperion.readOnlyMode;
-
// comps
window.comps = event.response.info.components
@@ -123,6 +121,7 @@ $(document).ready(function () {
window.currentVersion = window.sysInfo.hyperion.version;
window.currentChannel = window.sysInfo.hyperion.channel;
+ window.readOnlyMode = window.sysInfo.hyperion.readOnlyMode;
});
$(window.hyperion).one("cmd-config-getschema", function (event) {
@@ -340,7 +339,6 @@ $("#btn_darkmode").off().on("click", function (e) {
setStorage("darkModeOverwrite", true, true);
location.reload();
}
-
});
// Menuitem toggle;
diff --git a/assets/webconfig/js/content_logging.js b/assets/webconfig/js/content_logging.js
index 8ace208d..901afaa1 100644
--- a/assets/webconfig/js/content_logging.js
+++ b/assets/webconfig/js/content_logging.js
@@ -1,212 +1,192 @@
var conf_editor = null;
var createdCont = false;
+var isScroll = true;
performTranslation();
+requestLoggingStop();
requestLoggingStart();
-$(document).ready(function() {
- var messages;
- var loguplmess = "";
- var reportUrl = 'https://report.hyperion-project.org/#';
+$(document).ready(function () {
- $('#conf_cont').append(createOptPanel('fa-reorder', $.i18n("edt_conf_log_heading_title"), 'editor_container', 'btn_submit'));
- if(window.showOptHelp)
- {
- $('#conf_cont').append(createHelpTable(window.schema.logger.properties, $.i18n("edt_conf_log_heading_title")));
- createHintH("intro", $.i18n('conf_logging_label_intro'), "log_head");
- }
- $("#log_upl_pol").append(''+$.i18n("conf_logging_uplpolicy")+' '+buildWL("user/support#report_privacy_policy",$.i18n("conf_logging_contpolicy")));
+ $('#conf_cont').append(createOptPanel('fa-reorder', $.i18n("edt_conf_log_heading_title"), 'editor_container', 'btn_submit'));
+ if (window.showOptHelp) {
+ $('#conf_cont').append(createHelpTable(window.schema.logger.properties, $.i18n("edt_conf_log_heading_title")));
+ createHintH("intro", $.i18n('conf_logging_label_intro'), "log_head");
+ }
- conf_editor = createJsonEditor('editor_container', {
- logger : window.schema.logger
- }, true, true);
+ conf_editor = createJsonEditor('editor_container', {
+ logger: window.schema.logger
+ }, true, true);
- conf_editor.on('change',function() {
- conf_editor.validate().length || window.readOnlyMode ? $('#btn_submit').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
- });
+ conf_editor.on('change', function () {
+ conf_editor.validate().length || window.readOnlyMode ? $('#btn_submit').attr('disabled', true) : $('#btn_submit').attr('disabled', false);
+ });
- $('#btn_submit').off().on('click',function() {
- requestWriteConfig(conf_editor.getValue());
- });
+ $('#btn_submit').off().on('click', function () {
- $('#btn_logupload').off().on('click',function() {
- uploadLog();
- $(this).attr("disabled", true);
- $('#upl_link').html($.i18n('conf_logging_uploading'))
- });
+ var displayedLogLevel = conf_editor.getEditor("root.logger.level").getValue();
+ var newLogLevel = {logger:{}};
+ newLogLevel.logger.level = displayedLogLevel;
- //show prev uploads
- var ent;
+ requestWriteConfig(newLogLevel);
+ });
- if(getStorage("prev_reports"))
- {
- ent = JSON.parse(getStorage("prev_reports"));
- $('#prev_reports').append(''+$.i18n('conf_logging_lastreports')+' ');
- for(var i = 0; i'+ent[i].title+'('+ent[i].time+')
');
- }
- }
- else
- ent = [];
+ function infoSummary() {
+ var info = "";
- function updateLastReports(id,time,title)
- {
- if(ent.length > 4)
- ent.pop();
- ent.unshift({"id": id ,"time": time,"title": title})
- setStorage("prev_reports",JSON.stringify(ent));
- }
+ info += 'Hyperion System Summary Report (' + window.serverConfig.general.name + '), Reported instance: ' + window.currentHyperionInstanceName + '\n';
- function uploadLog()
- {
- var log = "";
- var config = JSON.stringify(window.serverConfig, null).replace(/"/g, '\\"');
- var prios = window.serverInfo.priorities;
- var comps = window.serverInfo.components;
- var sys = window.sysInfo.system;
- var shy = window.sysInfo.hyperion;
- var info;
+ info += "\n< ----- System information -------------------- >\n";
+ info += getSystemInfo() + '\n';
- //create log
- log = (messages ? loguplmess : "Log was empty!");
+ info += "\n< ----- Configured Instances ------------------ >\n";
+ var instances = window.serverInfo.instance;
+ for (var i = 0; i < instances.length; i++) {
+ info += instances[i].instance + ': ' + instances[i].friendly_name + ' Running: ' + instances[i].running + '\n';
+ }
- //create general info
- info = "### GENERAL ### \n";
- info += 'Build: '+shy.build+'\n';
- info += 'Build time: '+shy.time+'\n';
- info += 'Version: '+shy.version+'\n';
- info += 'UI Lang: '+storedLang+' (BrowserL: '+navigator.language+')\n';
- info += 'UI Access: '+storedAccess+'\n';
- info += 'Log lvl: '+window.serverConfig.logger.level+'\n';
- info += 'Avail Capt: '+window.serverInfo.grabbers.available+'\n';
- info += 'Database: '+(shy.readOnlyMode ? "ready-only" : "read/write")+'\n';
- info += '\n';
+ info += "\n< ----- This instance's priorities ------------ >\n";
+ var prios = window.serverInfo.priorities;
+ for (var i = 0; i < prios.length; i++) {
+ info += prios[i].priority + ': ';
+ if (prios[i].visible) {
+ info += ' VISIBLE!';
+ }
+ else {
+ info += ' ';
+ }
+ info += ' (' + prios[i].componentId + ') Owner: ' + prios[i].owner + '\n';
+ }
+ info += 'priorities_autoselect: ' + window.serverInfo.priorities_autoselect + '\n';
- info += 'Distribution: '+sys.prettyName+'\n';
- info += 'Architecture: '+sys.architecture+'\n';
+ info += "\n< ----- This instance components' status ------->\n";
+ var comps = window.serverInfo.components;
+ for (var i = 0; i < comps.length; i++) {
+ info += comps[i].name + ' - ' + comps[i].enabled + '\n';
+ }
- if (sys.cpuModelName)
- info += 'CPU Model: ' + sys.cpuModelName + '\n';
- if (sys.cpuModelType)
- info += 'CPU Type: ' + sys.cpuModelType + '\n';
- if (sys.cpuRevision)
- info += 'CPU Revision: ' + sys.cpuRevision + '\n';
- if (sys.cpuHardware)
- info += 'CPU Hardware: ' + sys.cpuHardware + '\n';
+ info += "\n< ----- This instance's configuration --------- >\n";
+ info += JSON.stringify(window.serverConfig) + '\n';
- info += 'Kernel: ' + sys.kernelType+' ('+sys.kernelVersion+' (WS: '+sys.wordSize+'))' + '\n';
- info += 'Qt Version: ' + sys.qtVersion + '\n';
- info += 'Python Version: ' + sys.pyVersion + '\n';
- info += 'Browser/OS: ' + navigator.userAgent + '\n\n';
+ info += "\n< ----- Current Log --------------------------- >\n";
+ var logMsgs = document.getElementById("logmessages").textContent;
+ if (logMsgs.length !== 0) {
+ info += logMsgs;
+ } else {
+ info += "Log is empty!";
+ }
- //create prios
- info += "### PRIORITIES ### \n";
- for(var i = 0; i'+reportUrl+'');
- $("html, body").animate({ scrollTop: 9999 }, "fast");
- updateLastReports(data.id,data.time,title);
- }
- else
- {
- $('#btn_logupload').attr("disabled", false);
- $('#upl_link').html(''+$.i18n('conf_logging_uplfailed')+'');
- }
- })
- .fail( function( jqXHR, textStatus ) {
- console.log(jqXHR,textStatus);
- $('#btn_logupload').attr("disabled", false);
- $('#upl_link').html(''+$.i18n('conf_logging_uplfailed')+'');
- });
- }
+ $('#log_content').html('
');
+ $('#log_footer').append(''
+ + ' '
+ + $.i18n('conf_logging_btn_autoscroll') + ' '
+ );
- if (!window.loggingHandlerInstalled)
- {
- window.loggingHandlerInstalled = true;
- $(window.hyperion).on("cmd-logging-update",function(event){
+ $(`#btn_scroll`).bootstrapToggle();
+ $(`#btn_scroll`).change(e => {
+ if (e.currentTarget.checked) {
+ //Scroll to end of log
+ isScroll = true;
+ if ($("#logmessages").length > 0) {
+ $('#logmessages')[0].scrollTop = $('#logmessages')[0].scrollHeight;
+ }
+ } else {
+ isScroll = false;
+ }
+ });
- if ($("#logmessages").length == 0 && window.loggingStreamActive)
- {
- requestLoggingStop();
- window.loggingStreamActive = false;
- }
+ $('#log_footer').append(' Copy Log to Clipboard ');
- messages = (event.response.result.messages);
- if(messages.length != 0 && !createdCont)
- {
- $('#log_content').html('
'+$.i18n('conf_logging_btn_autoscroll')+' ');
- createdCont = true;
+ $('#btn_clipboard').off().on('click', function () {
+ const temp = document.createElement('textarea');
+ temp.textContent = infoSummary();
+ document.body.append(temp);
+ temp.select();
+ document.execCommand("copy");
+ temp.remove();
+ });
+ }
- $('#btn_autoscroll').off().on('click',function() {
- toggleClass('#btn_autoscroll', "btn-success", "btn-danger");
- });
- }
+ function updateLogOutput(messages) {
- for(var idx = 0; idx < messages.length; idx++)
- {
- var app_name = messages[idx].appName;
- var logger_name = messages[idx].loggerName;
- var function_ = messages[idx].function;
- var line = messages[idx].line;
- var file_name = messages[idx].fileName;
- var msg = messages[idx].message;
- var level_string = messages[idx].levelString;
- var utime = messages[idx].utime;
+ if (messages.length != 0) {
- var debug = "";
- if(level_string == "DEBUG") {
- debug = "("+file_name+":"+line+":"+function_+"()) ";
- }
+ for (var idx = 0; idx < messages.length; idx++) {
+ var app_name = messages[idx].appName;
+ var logger_name = messages[idx].loggerName;
+ var function_ = messages[idx].function;
+ var line = messages[idx].line;
+ var file_name = messages[idx].fileName;
+ var msg = messages[idx].message;
+ var level_string = messages[idx].levelString;
+ var utime = messages[idx].utime;
- var date = new Date(parseInt(utime));
+ var debug = "";
+ if (level_string == "DEBUG") {
+ debug = "(" + file_name + ":" + line + ":" + function_ + "()) ";
+ }
- $("#logmessages").append("\n "+date.toISOString()+" ["+app_name+" "+logger_name+"] ("+level_string+") "+debug+msg+"
");
- loguplmess += "["+app_name+" "+logger_name+"] ("+level_string+") "+debug+msg+"\n";
- }
+ var date = new Date(parseInt(utime));
+ var newLogLine = date.toISOString() + " [" + app_name + " " + logger_name + "] (" + level_string + ") " + debug + msg;
- if($("#btn_autoscroll").hasClass('btn-success'))
- {
- $('#logmessages').stop().animate({
- scrollTop: $('#logmessages')[0].scrollHeight
- }, 800);
- }
- });
- }
+ $("#logmessages").append("" + newLogLine + "
\n");
+ }
- removeOverlay();
+ if (isScroll && $("#logmessages").length > 0) {
+ $('#logmessages').stop().animate({
+ scrollTop: $('#logmessages')[0].scrollHeight
+ }, 800);
+ }
+ }
+ }
+
+ if (!window.loggingHandlerInstalled) {
+ window.loggingHandlerInstalled = true;
+
+ $(window.hyperion).on("cmd-logging-update", function (event) {
+
+ messages = (event.response.result.messages);
+
+ if (messages.length != 0) {
+ if (!createdCont) {
+ createLogContainer();
+ createdCont = true;
+ }
+
+ var currentlogLevel = window.serverConfig.logger.level;
+
+ updateLogOutput(messages)
+ }
+ });
+ }
+
+ $(window.hyperion).on("cmd-settings-update", function (event) {
+
+ var obj = event.response.data
+ if (obj.logger) {
+ Object.getOwnPropertyNames(obj).forEach(function (val, idx, array) {
+ window.serverConfig[val] = obj[val];
+ });
+
+ var currentlogLevel = window.serverConfig.logger.level;
+ var displayedLogLevel = conf_editor.getEditor("root.logger.level").getValue();
+
+ //if ( currentlogLevel !== displayedLogLevel )
+ {
+ conf_editor.getEditor("root.logger.level").setValue(currentlogLevel);
+ location.reload();
+ }
+ }
+
+ });
+
+ removeOverlay();
});
diff --git a/assets/webconfig/js/content_remote.js b/assets/webconfig/js/content_remote.js
index f6898fa1..c8e07602 100644
--- a/assets/webconfig/js/content_remote.js
+++ b/assets/webconfig/js/content_remote.js
@@ -1,13 +1,13 @@
-$(document).ready(function() {
+$(document).ready(function () {
performTranslation();
var oldEffects = [];
var cpcolor = '#B500FF';
var mappingList = window.serverSchema.properties.color.properties.imageToLedMappingType.enum;
var duration = 0;
- var rgb = {r:255,g:0,b:0};
+ var rgb = { r: 255, g: 0, b: 0 };
var lastImgData = "";
- var lastFileName= "";
+ var lastFileName = "";
//create html
createTable('ssthead', 'sstbody', 'sstcont');
@@ -16,8 +16,7 @@ $(document).ready(function() {
//create introduction
- if(window.showOptHelp)
- {
+ if (window.showOptHelp) {
createHint("intro", $.i18n('remote_color_intro', $.i18n('remote_losthint')), "color_intro");
createHint("intro", $.i18n('remote_input_intro', $.i18n('remote_losthint')), "sstcont");
createHint("intro", $.i18n('remote_adjustment_intro', $.i18n('remote_losthint')), "adjust_content");
@@ -30,83 +29,73 @@ $(document).ready(function() {
var sColor = sortProperties(window.serverSchema.properties.color.properties.channelAdjustment.items.properties);
var values = window.serverInfo.adjustment[0];
- for(var key in sColor)
- {
- if(sColor[key].key != "id" && sColor[key].key != "leds")
- {
- var title = ''+$.i18n(sColor[key].title)+' ';
+ for (var key in sColor) {
+ if (sColor[key].key != "id" && sColor[key].key != "leds") {
+ var title = '' + $.i18n(sColor[key].title) + ' ';
var property;
var value = values[sColor[key].key];
- if(sColor[key].type == "array")
- {
- property = '
';
+ if (sColor[key].type == "array") {
+ property = '
';
$('.crtbody').append(createTableRow([title, property], false, true));
- createCP('cr_'+sColor[key].key, value, function(rgb,hex,e){
- requestAdjustment(e.target.id.substr(e.target.id.indexOf("_") + 1), '['+rgb.r+','+rgb.g+','+rgb.b+']');
+ createCP('cr_' + sColor[key].key, value, function (rgb, hex, e) {
+ requestAdjustment(e.target.id.substr(e.target.id.indexOf("_") + 1), '[' + rgb.r + ',' + rgb.g + ',' + rgb.b + ']');
});
}
- else if(sColor[key].type == "boolean")
- {
- property = '
';
+ else if (sColor[key].type == "boolean") {
+ property = '
';
$('.crtbody').append(createTableRow([title, property], false, true));
- $('#cr_'+sColor[key].key).off().on('change', function(e){
+ $('#cr_' + sColor[key].key).off().on('change', function (e) {
requestAdjustment(e.target.id.substr(e.target.id.indexOf("_") + 1), e.currentTarget.checked);
});
}
- else
- {
- if(sColor[key].key == "brightness" || sColor[key].key == "brightnessCompensation" || sColor[key].key == "backlightThreshold")
- property = ''+$.i18n("edt_append_percent")+'
';
+ else {
+ if (sColor[key].key == "brightness" || sColor[key].key == "brightnessCompensation" || sColor[key].key == "backlightThreshold")
+ property = '' + $.i18n("edt_append_percent") + '
';
else
- property = ' ';
+ property = ' ';
$('.crtbody').append(createTableRow([title, property], false, true));
- $('#cr_'+sColor[key].key).off().on('change', function(e){
- valValue(this.id,this.value,this.min,this.max);
+ $('#cr_' + sColor[key].key).off().on('change', function (e) {
+ valValue(this.id, this.value, this.min, this.max);
requestAdjustment(e.target.id.substr(e.target.id.indexOf("_") + 1), e.currentTarget.value);
});
}
}
}
- function sendEffect()
- {
+ function sendEffect() {
var efx = $("#effect_select").val();
- if(efx != "__none__")
- {
+ if (efx != "__none__") {
requestPriorityClear();
- $(window.hyperion).one("cmd-clear", function(event) {
- setTimeout(function() {requestPlayEffect(efx,duration)}, 100);
+ $(window.hyperion).one("cmd-clear", function (event) {
+ setTimeout(function () { requestPlayEffect(efx, duration) }, 100);
});
}
}
- function sendColor()
- {
- requestSetColor(rgb.r, rgb.g, rgb.b,duration);
+ function sendColor() {
+ requestSetColor(rgb.r, rgb.g, rgb.b, duration);
}
- function updateInputSelect()
- {
+ function updateInputSelect() {
$('.sstbody').html("");
var prios = window.serverInfo.priorities;
var clearAll = false;
- for(var i = 0; i < prios.length; i++)
- {
- var origin = prios[i].origin ? prios[i].origin : "System";
+ for (var i = 0; i < prios.length; i++) {
+ var origin = prios[i].origin ? prios[i].origin : "System";
origin = origin.split("@");
var ip = origin[1];
origin = origin[0];
- var owner = prios[i].owner;
- var active = prios[i].active;
- var visible = prios[i].visible;
+ var owner = prios[i].owner;
+ var active = prios[i].active;
+ var visible = prios[i].visible;
var priority = prios[i].priority;
- var compId = prios[i].componentId;
- var duration = prios[i].duration_ms/1000;
+ var compId = prios[i].componentId;
+ var duration = prios[i].duration_ms / 1000;
var value = "0,0,0";
var btn_type = "default";
var btn_text = $.i18n('remote_input_setsource_btn');
@@ -115,40 +104,38 @@ $(document).ready(function() {
if (active)
btn_type = "primary";
- if(priority > 254)
+ if (priority > 254)
continue;
- if(priority < 254 && (compId == "EFFECT" || compId == "COLOR" || compId == "IMAGE") )
+ if (priority < 254 && (compId == "EFFECT" || compId == "COLOR" || compId == "IMAGE"))
clearAll = true;
- if (visible)
- {
+ if (visible) {
btn_state = "disabled";
btn_type = "success";
btn_text = $.i18n('remote_input_sourceactiv_btn');
}
- if(ip)
- origin += ''+$.i18n('remote_input_ip')+' '+ip+' ';
+ if (ip)
+ origin += '' + $.i18n('remote_input_ip') + ' ' + ip + ' ';
- if("value" in prios[i])
+ if ("value" in prios[i])
value = prios[i].value.RGB;
- switch (compId)
- {
+ switch (compId) {
case "EFFECT":
- owner = $.i18n('remote_effects_label_effects')+' '+owner;
+ owner = $.i18n('remote_effects_label_effects') + ' ' + owner;
break;
case "COLOR":
- owner = $.i18n('remote_color_label_color')+' '+'
';
+ owner = $.i18n('remote_color_label_color') + ' ' + '
';
break;
case "IMAGE":
- owner = $.i18n('remote_effects_label_picture')+' '+owner;
+ owner = $.i18n('remote_effects_label_picture') + ' ' + owner;
break;
- case "GRABBER":
- owner = $.i18n('general_comp_GRABBER')+': ('+owner+')';
+ case "GRABBER":
+ owner = $.i18n('general_comp_GRABBER') + ': (' + owner + ')';
break;
case "V4L":
- owner = $.i18n('general_comp_V4L')+': ('+owner+')';
+ owner = $.i18n('general_comp_V4L') + ': (' + owner + ')';
break;
case "BOBLIGHTSERVER":
owner = $.i18n('general_comp_BOBLIGHTSERVER');
@@ -161,126 +148,112 @@ $(document).ready(function() {
break;
}
- if(duration && compId != "GRABBER" && compId != "FLATBUFSERVER" && compId != "PROTOSERVER")
- owner += ''+$.i18n('remote_input_duration')+' '+duration.toFixed(0)+$.i18n('edt_append_s')+' ';
+ if (duration && compId != "GRABBER" && compId != "FLATBUFSERVER" && compId != "PROTOSERVER")
+ owner += '' + $.i18n('remote_input_duration') + ' ' + duration.toFixed(0) + $.i18n('edt_append_s') + ' ';
- var btn = ''+btn_text+' ';
+ var btn = '' + btn_text + ' ';
- if((compId == "EFFECT" || compId == "COLOR" || compId == "IMAGE") && priority < 254)
- btn += ' ';
+ if ((compId == "EFFECT" || compId == "COLOR" || compId == "IMAGE") && priority < 254)
+ btn += ' ';
- if(btn_type != 'default')
+ if (btn_type != 'default')
$('.sstbody').append(createTableRow([origin, owner, priority, btn], false, true));
}
- var btn_auto_color = (window.serverInfo.priorities_autoselect? "btn-success" : "btn-danger");
- var btn_auto_state = (window.serverInfo.priorities_autoselect? "disabled" : "enabled");
- var btn_auto_text = (window.serverInfo.priorities_autoselect? $.i18n('general_btn_on') : $.i18n('general_btn_off'));
- var btn_call_state = (clearAll? "enabled" : "disabled");
- $('#auto_btn').html(''+$.i18n('remote_input_label_autoselect')+' ('+btn_auto_text+') ');
- $('#auto_btn').append(''+$.i18n('remote_input_clearall')+' ');
+ var btn_auto_color = (window.serverInfo.priorities_autoselect ? "btn-success" : "btn-danger");
+ var btn_auto_state = (window.serverInfo.priorities_autoselect ? "disabled" : "enabled");
+ var btn_auto_text = (window.serverInfo.priorities_autoselect ? $.i18n('general_btn_on') : $.i18n('general_btn_off'));
+ var btn_call_state = (clearAll ? "enabled" : "disabled");
+ $('#auto_btn').html('' + $.i18n('remote_input_label_autoselect') + ' (' + btn_auto_text + ') ');
+ $('#auto_btn').append('' + $.i18n('remote_input_clearall') + ' ');
- var max_width=100;
- $('.btn_input_selection').each(function() {
+ var max_width = 100;
+ $('.btn_input_selection').each(function () {
if ($(this).innerWidth() > max_width)
max_width = $(this).innerWidth();
});
- $('.btn_input_selection').css("min-width",max_width+"px");
+ $('.btn_input_selection').css("min-width", max_width + "px");
}
- function updateLedMapping()
- {
+ function updateLedMapping() {
var mapping = window.serverInfo.imageToLedMappingType;
$('#mappingsbutton').html("");
- for(var ix = 0; ix < mappingList.length; ix++)
- {
- if(mapping == mappingList[ix])
+ for (var ix = 0; ix < mappingList.length; ix++) {
+ if (mapping == mappingList[ix])
var btn_style = 'btn-success';
else
var btn_style = 'btn-primary';
- $('#mappingsbutton').append(''+$.i18n('remote_maptype_label_'+mappingList[ix])+' ');
+ $('#mappingsbutton').append('' + $.i18n('remote_maptype_label_' + mappingList[ix]) + ' ');
}
}
- function initComponents()
- {
+ function initComponents() {
var components = window.comps;
var hyperionEnabled = true;
- components.forEach( function(obj) {
- if (obj.name == "ALL")
- {
+ components.forEach(function (obj) {
+ if (obj.name == "ALL") {
hyperionEnabled = obj.enabled;
}
});
- for (const comp of components)
- {
- if(comp.name === "ALL")
+ for (const comp of components) {
+ if (comp.name === "ALL")
continue;
- const enable_style = (comp.enabled? "checked" : "");
- const comp_btn_id = "comp_btn_"+comp.name;
+ const enable_style = (comp.enabled ? "checked" : "");
+ const comp_btn_id = "comp_btn_" + comp.name;
- if ($("#"+comp_btn_id).length === 0)
- {
- var d=''
- +' '
- +' '+$.i18n('general_comp_'+comp.name)+' '
- +' ';
+ if ($("#" + comp_btn_id).length === 0) {
+ var d = ''
+ + ''
+ + ' '
+ + $.i18n('general_comp_' + comp.name) + ' '
+ + ' ';
$('#componentsbutton').append(d);
$(`#${comp_btn_id}`).bootstrapToggle();
$(`#${comp_btn_id}`).bootstrapToggle((hyperionEnabled ? "enable" : "disable"));
$(`#${comp_btn_id}`).change(e => {
- requestSetComponentState(e.currentTarget.id.split('_').pop(), e.currentTarget.checked);
- //console.log(e.currentTarget.checked)
+ requestSetComponentState(e.currentTarget.id.split('_').pop(), e.currentTarget.checked);
});
}
}
}
- function updateComponent( component )
- {
- if (component.name == "ALL")
- {
+ function updateComponent(component) {
+ if (component.name == "ALL") {
var components = window.comps;
var hyperionEnabled = component.enabled;
- for (const comp of components)
- {
+ for (const comp of components) {
- if(comp.name === "ALL")
- continue;
+ if (comp.name === "ALL")
+ continue;
- const comp_btn_id = "comp_btn_"+comp.name;
+ const comp_btn_id = "comp_btn_" + comp.name;
- if ( !hyperionEnabled )
- {
+ if (!hyperionEnabled) {
$(`#${comp_btn_id}`).bootstrapToggle('off');
$(`#${comp_btn_id}`).bootstrapToggle("disable");
}
- else
- {
+ else {
$(`#${comp_btn_id}`).bootstrapToggle("enable");
- if ( comp.enabled !== $(`#${comp_btn_id}`).prop("checked") )
- {
+ if (comp.enabled !== $(`#${comp_btn_id}`).prop("checked")) {
$(`#${comp_btn_id}`).bootstrapToggle().prop('checked', comp.enabled).change();
}
}
}
}
- else
- {
- const comp_btn_id = "comp_btn_"+component.name;
+ else {
+ const comp_btn_id = "comp_btn_" + component.name;
//console.log ("updateComponent: ", component.name, "Current Checked: ", $(`#${comp_btn_id}`).prop("checked"), "New Checked: ", component.enabled, );
// In case Buttons were disabled before, status may be different to component status
- if ( component.enabled != $(`#${comp_btn_id}`).prop("checked") )
- {
+ if (component.enabled != $(`#${comp_btn_id}`).prop("checked")) {
// console.log ("Update status to Checked = ", component.enabled);
- if ( component.enabled )
+ if (component.enabled)
$(`#${comp_btn_id}`).bootstrapToggle("on");
else
$(`#${comp_btn_id}`).bootstrapToggle("off");
@@ -288,21 +261,19 @@ $(document).ready(function() {
}
}
- function updateEffectlist()
- {
+ function updateEffectlist() {
var newEffects = window.serverInfo.effects;
- if (newEffects.length != oldEffects.length)
- {
+ if (newEffects.length != oldEffects.length) {
$('#effect_select').html(' ');
var usrEffArr = [];
var sysEffArr = [];
- for(var i = 0; i < newEffects.length; i++) {
+ for (var i = 0; i < newEffects.length; i++) {
var effectName = newEffects[i].name;
- if(!/^\:/.test(newEffects[i].file)){
+ if (!/^\:/.test(newEffects[i].file)) {
usrEffArr.push(effectName);
}
- else{
+ else {
sysEffArr.push(effectName);
}
}
@@ -312,74 +283,70 @@ $(document).ready(function() {
}
}
- function updateVideoMode()
- {
- var videoModes = ["2D","3DSBS","3DTAB"];
+ function updateVideoMode() {
+ var videoModes = ["2D", "3DSBS", "3DTAB"];
var currVideoMode = window.serverInfo.videomode;
$('#videomodebtns').html("");
- for(var ix = 0; ix < videoModes.length; ix++)
- {
- if(currVideoMode == videoModes[ix])
+ for (var ix = 0; ix < videoModes.length; ix++) {
+ if (currVideoMode == videoModes[ix])
var btn_style = 'btn-success';
else
var btn_style = 'btn-primary';
- $('#videomodebtns').append(''+$.i18n('remote_videoMode_'+videoModes[ix])+' ');
+ $('#videomodebtns').append('' + $.i18n('remote_videoMode_' + videoModes[ix]) + ' ');
}
}
// colorpicker and effect
- if (getStorage('rmcpcolor') != null)
- {
+ if (getStorage('rmcpcolor') != null) {
cpcolor = getStorage('rmcpcolor');
rgb = hexToRgb(cpcolor);
}
- if (getStorage('rmduration') != null)
- {
+ if (getStorage('rmduration') != null) {
$("#remote_duration").val(getStorage('rmduration'));
duration = getStorage('rmduration');
}
- createCP('cp2', cpcolor, function(rgbT,hex){
+ createCP('cp2', cpcolor, function (rgbT, hex) {
rgb = rgbT;
sendColor();
setStorage('rmcpcolor', hex);
updateInputSelect();
});
- $("#reset_color").off().on("click", function(){
+ $("#reset_color").off().on("click", function () {
requestPriorityClear();
lastImgData = "";
$("#effect_select").val("__none__");
$("#remote_input_img").val("");
});
- $("#remote_duration").off().on("change", function(){
- duration = valValue(this.id,this.value,this.min,this.max);
+ $("#remote_duration").off().on("change", function () {
+ duration = valValue(this.id, this.value, this.min, this.max);
setStorage('rmduration', duration);
});
- $("#effect_select").off().on("change", function(event) {
+ $("#effect_select").off().on("change", function (event) {
sendEffect();
});
- $("#remote_input_reseff, #remote_input_rescol").off().on("click", function(){
- if(this.id == "remote_input_rescol")
+ $("#remote_input_reseff, #remote_input_rescol").off().on("click", function () {
+ if (this.id == "remote_input_rescol")
sendColor();
else
sendEffect();
});
- $("#remote_input_repimg").off().on("click", function(){
- if(lastImgData != "")
+ $("#remote_input_repimg").off().on("click", function () {
+ if (lastImgData != "")
requestSetImage(lastImgData, duration, lastFileName);
});
- $("#remote_input_img").change(function(){
- readImg(this, function(src,fileName){
+ $("#remote_input_img").change(function () {
+ readImg(this, function (src, fileName) {
lastFileName = fileName;
- if(src.includes(","))
+ if (src.includes(","))
lastImgData = src.split(",")[1];
else
lastImgData = src;
@@ -397,27 +364,27 @@ $(document).ready(function() {
// interval updates
- $(window.hyperion).on('components-updated', function(e, comp){
+ $(window.hyperion).on('components-updated', function (e, comp) {
//console.log ("components-updated", e, comp);
- updateComponent (comp);
+ updateComponent(comp);
});
- $(window.hyperion).on("cmd-priorities-update", function(event){
+ $(window.hyperion).on("cmd-priorities-update", function (event) {
window.serverInfo.priorities = event.response.data.priorities;
window.serverInfo.priorities_autoselect = event.response.data.priorities_autoselect;
updateInputSelect();
});
- $(window.hyperion).on("cmd-imageToLedMapping-update", function(event){
+ $(window.hyperion).on("cmd-imageToLedMapping-update", function (event) {
window.serverInfo.imageToLedMappingType = event.response.data.imageToLedMappingType;
updateLedMapping();
});
- $(window.hyperion).on("cmd-videomode-update", function(event){
+ $(window.hyperion).on("cmd-videomode-update", function (event) {
window.serverInfo.videomode = event.response.data.videomode;
updateVideoMode();
});
- $(window.hyperion).on("cmd-effects-update", function(event){
+ $(window.hyperion).on("cmd-effects-update", function (event) {
window.serverInfo.effects = event.response.data.effects;
updateEffectlist();
});
diff --git a/assets/webconfig/js/ledsim.js b/assets/webconfig/js/ledsim.js
index 7fbdcbae..ace97bcb 100644
--- a/assets/webconfig/js/ledsim.js
+++ b/assets/webconfig/js/ledsim.js
@@ -249,12 +249,16 @@ $(document).ready(function() {
// ------------------------------------------------------------------
$(window.hyperion).on("cmd-settings-update",function(event){
+
var obj = event.response.data
- Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {
- window.serverInfo[val] = obj[val];
- });
- leds = window.serverConfig.leds
- updateLedLayout();
+ if ( obj.leds) {
+ console.log("ledsim: cmd-settings-update", event.response.data);
+ Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {
+ window.serverInfo[val] = obj[val];
+ });
+ leds = window.serverConfig.leds
+ updateLedLayout();
+ }
});
function resetImage(){
diff --git a/assets/webconfig/js/ui_utils.js b/assets/webconfig/js/ui_utils.js
index 126efbec..26221f88 100755
--- a/assets/webconfig/js/ui_utils.js
+++ b/assets/webconfig/js/ui_utils.js
@@ -330,7 +330,7 @@ function showInfoDialog(type, header, message) {
$(document).on('click', '[data-dismiss-modal]', function () {
var target = $(this).attr('data-dismiss-modal');
- $.find(target).modal.hide();
+ $(target).modal('hide');
});
}
@@ -1070,6 +1070,43 @@ function getReleases(callback) {
});
}
+function getSystemInfo() {
+ var sys = window.sysInfo.system;
+ var shy = window.sysInfo.hyperion;
+
+ var info = "Hyperion Server: \n";
+ info += '- Build: ' + shy.build + '\n';
+ info += '- Build time: ' + shy.time + '\n';
+ info += '- Git Remote: ' + shy.gitremote + '\n';
+ info += '- Version: ' + shy.version + '\n';
+ info += '- UI Lang: ' + storedLang + ' (BrowserLang: ' + navigator.language + ')\n';
+ info += '- UI Access: ' + storedAccess + '\n';
+ //info += '- Log lvl: ' + window.serverConfig.logger.level + '\n';
+ info += '- Avail Capt: ' + window.serverInfo.grabbers.available + '\n';
+ info += '- Database: ' + (shy.readOnlyMode ? "ready-only" : "read/write") + '\n';
+
+ info += '\n';
+
+ info += 'Hyperion Server OS: \n';
+ info += '- Distribution: ' + sys.prettyName + '\n';
+ info += '- Architecture: ' + sys.architecture + '\n';
+
+ if (sys.cpuModelName)
+ info += '- CPU Model: ' + sys.cpuModelName + '\n';
+ if (sys.cpuModelType)
+ info += '- CPU Type: ' + sys.cpuModelType + '\n';
+ if (sys.cpuRevision)
+ info += '- CPU Revision: ' + sys.cpuRevision + '\n';
+ if (sys.cpuHardware)
+ info += '- CPU Hardware: ' + sys.cpuHardware + '\n';
+
+ info += '- Kernel: ' + sys.kernelType + ' (' + sys.kernelVersion + ' (WS: ' + sys.wordSize + '))\n';
+ info += '- Qt Version: ' + sys.qtVersion + '\n';
+ info += '- Python Version: ' + sys.pyVersion + '\n';
+ info += '- Browser: ' + navigator.userAgent;
+ return info;
+}
+
function handleDarkMode() {
$(" ", {
rel: "stylesheet",
From aec24e92462700f139985152af4daa4d9be656ad Mon Sep 17 00:00:00 2001
From: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com>
Date: Sat, 1 May 2021 17:00:15 +0200
Subject: [PATCH 09/58] Snap (Linux x86_64) (#1232)
---
.github/workflows/pull-request.yml | 30 ++++++++-
.github/workflows/push-master.yml | 67 +++++++++++++++++++--
resources/icons/hyperion-icon-512px.png | Bin 0 -> 69597 bytes
snap/snapcraft.yaml | 77 ++++++++++++++++++++++++
4 files changed, 166 insertions(+), 8 deletions(-)
create mode 100644 resources/icons/hyperion-icon-512px.png
create mode 100644 snap/snapcraft.yaml
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 3b00f57d..8b221e12 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -63,7 +63,7 @@ jobs:
# Upload artifacts
- name: Upload artifacts
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@v2
with:
name: ${{ matrix.dockerImage }}
path: ${{ matrix.dockerImage }}
@@ -110,7 +110,7 @@ jobs:
# Upload artifacts
- name: Upload artifacts
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@v2
with:
name: macOS
path: macOS
@@ -184,7 +184,31 @@ jobs:
# Upload artifacts
- name: Upload artifacts
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@v2
with:
name: windows
path: windows
+
+##########################
+#### Snap (x86_64) #######
+##########################
+
+ snap:
+ name: Snap (x86_64)
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Build snap package
+ - name: Build snap
+ id: build
+ uses: snapcore/action-build@v1
+
+ # Upload snap artifact (only on tagged commit)
+ - name: Upload snap artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: snap
+ path: ${{ steps.build.outputs.snap }}
diff --git a/.github/workflows/push-master.yml b/.github/workflows/push-master.yml
index 2a002216..e6d658eb 100644
--- a/.github/workflows/push-master.yml
+++ b/.github/workflows/push-master.yml
@@ -146,12 +146,37 @@ jobs:
with:
path: build/Hyperion-*
-################################
-###### Publish Releases ########
-################################
+##########################
+#### Snap (x86_64) #######
+##########################
- publish:
- name: Publish Releases
+ snap:
+ name: Snap (x86_64)
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Build snap package
+ - name: Build snap
+ id: build
+ uses: snapcore/action-build@v1
+
+ # Upload snap artifact (only on tagged commit)
+ - name: Upload snap artifact
+ if: startsWith(github.event.ref, 'refs/tags')
+ uses: actions/upload-artifact@v2
+ with:
+ name: snap
+ path: ${{ steps.build.outputs.snap }}
+
+#######################################
+###### Publish GitHub Releases ########
+#######################################
+
+ github_publish:
+ name: Publish GitHub Releases
if: startsWith(github.event.ref, 'refs/tags')
needs: [Linux, macOS, windows]
runs-on: ubuntu-latest
@@ -188,3 +213,35 @@ jobs:
prerelease: ${{ env.preRelease }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+############################
+###### Snap Release ########
+############################
+
+ snap_publish:
+ name: Publish Snap Release
+ if: startsWith(github.event.ref, 'refs/tags')
+ needs: [snap]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ # Download snap from snap job
+ - name: Download snap from snap build
+ id: download-artifact
+ uses: actions/download-artifact@v2
+ with:
+ name: snap
+
+ # Get file name of the snap
+ - name: Get file name of the snap
+ run: echo "snap=$(ls ${{ steps.download-artifact.outputs.download-path }}/hyperion-ng_*.snap)" >> $GITHUB_ENV
+
+ # Publish snap build to edge channel
+ - name: Publish snap build to edge channel
+ uses: snapcore/action-publish@v1
+ with:
+ store_login: ${{ secrets.SNAP_STORE_LOGIN }}
+ snap: ${{ env.snap }}
+ release: edge
diff --git a/resources/icons/hyperion-icon-512px.png b/resources/icons/hyperion-icon-512px.png
new file mode 100644
index 0000000000000000000000000000000000000000..53ea8fe8feb1093db2049c3f8a8fe5acb24e27e2
GIT binary patch
literal 69597
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