mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
mDNS Support (#1452)
* Allow build, if no grabbers are enabled * Align available functions to right Qt version * Update to next development version * Align available functions to right Qt version * fix workflows (apt/nightly) * Disable QNetworkConfigurationManager deprecation warnings * Initial go on Smart Pointers * Add Deallocation * Correct QT_WARNING_DISABLE_DEPRECATED (available since 5.9) * Cluster Build Variables * Hyperion Light * Address build warnings * Hyperion Light - UI * Update Protobuf to latest master * Removed compiler warnings * Added restart ability to systray * Correct Protobuf * Ignore 'no-return' warning on protobuf build * hyperion-remote: Fix auto discovery of hyperion server * Fix Qt version override * Update changelog * Remove Grabber Components, if no Grabber exists * Standalone Grabber - Fix fps default * Remote Control - Have Source Selction accrosswhole screen * Enable Blackborder detection only, if relevant input sources available * Enable Blackborder detection only, if relevant input sources available * Remote UI - rearrange containers * Checkout * Fix compilation on windows * Re-added qmdnsengine template cmake * chrono added for linux * Removed existing AVAHI/Bonjour, allow to enable/disable mDNS * hyperiond macos typo fix * Fix macOS Bundle build * Fix macOS bundle info details * Correct CMake files * Removed existing AVAHI/Bonjour (2) * Share hyperion's services via mDNS * Add mDNS Browser and mDNS for LED-Devices * Support mDNS discovery for standalone grabbers * Remove ZLib Dependency & Cleanup * mDNS - hanle 2.local2 an ".local." domains equally * Hue - Link discovery to bridge class, workaround port 443 for mDNS discovery * Fix save button state when switching between devices * Removed sessions (of other hyperions) * mDNS Publisher - Simplify service naming * mDNS refactoring & Forwarder discovery * mDNS Updates to use device service name * Consistency of standalone grabbers with mDNS Service Registry * Merge branch 'hyperion-project:master' into mDNS * Start JSON and WebServers only after Instance 0 is available * Remove bespoke qDebug Output again * MDNS updates and refactor Forwarder * Minor updates * Upgrade to CMake 3.1 * typo * macOS fix * Correct merge * - Remove dynamic linker flag from standalone dispmanX Grabber - Added ability to use system qmdns libs * Cec handler library will load at runtime * typo fix * protobuf changes * mDNS changes for Windows/macOS * test window build qmdnsengine * absolute path to protobuf cmake dir * Rework Hue Wizard supporting mDNS * LED-Devices - Retry support + Refactoring (excl. Hue) * LED-Devices - Refactoring/Retry support Hue + additional alignments * Address LGTM findings * Fix CI-Build, revert test changes * Build Windows in Release mode to avoid python problem * Correct that WebServerObject is available earlier * Ensure that instance name in logs for one instance are presented * Update content LEDs * Rework mDNS Address lookup * Fix LED UI * Fix for non mDNS Services (ignore default port) * Disbale device when now input is available * Revert back some updates, ensure last color is updated when switched on * Handle reopening case and changed IP, port for API-calls * Add UPD-DDP Device * WLED support for DDP * Fix printout * LEDDevice - Allow more retries, udapte defaults * LED-Net Devices - Select Custom device, if configured Co-authored-by: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com> Co-authored-by: Paulchen Panther <Paulchen-Panter@protonmail.com>
This commit is contained in:
parent
3ef4ebc1a4
commit
e9936e131b
@ -3,6 +3,7 @@
|
|||||||
# detect CI
|
# detect CI
|
||||||
if [ "$HOME" != "" ]; then
|
if [ "$HOME" != "" ]; then
|
||||||
# GitHub Actions
|
# GitHub Actions
|
||||||
|
echo "Github Actions detected"
|
||||||
CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
CI_NAME="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||||
CI_BUILD_DIR="$GITHUB_WORKSPACE"
|
CI_BUILD_DIR="$GITHUB_WORKSPACE"
|
||||||
else
|
else
|
||||||
@ -20,8 +21,11 @@ else
|
|||||||
PLATFORM=${PLATFORM}-dev
|
PLATFORM=${PLATFORM}-dev
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "Platform: ${PLATFORM}, build type: ${BUILD_TYPE}, CI_NAME: $CI_NAME, docker image: ${DOCKER_IMAGE}, docker type: ${DOCKER_TAG}"
|
||||||
|
|
||||||
# Build the package on osx or linux
|
# Build the package on osx or linux
|
||||||
if [[ "$CI_NAME" == 'osx' || "$CI_NAME" == 'darwin' ]]; then
|
if [[ "$CI_NAME" == 'osx' || "$CI_NAME" == 'darwin' ]]; then
|
||||||
|
echo "Compile Hyperion on OSX or Darwin"
|
||||||
# compile prepare
|
# compile prepare
|
||||||
mkdir build || exit 1
|
mkdir build || exit 1
|
||||||
cd build
|
cd build
|
||||||
@ -31,12 +35,13 @@ if [[ "$CI_NAME" == 'osx' || "$CI_NAME" == 'darwin' ]]; then
|
|||||||
exit 0;
|
exit 0;
|
||||||
exit 1 || { echo "---> Hyperion compilation failed! Abort"; exit 5; }
|
exit 1 || { echo "---> Hyperion compilation failed! Abort"; exit 5; }
|
||||||
elif [[ $CI_NAME == *"mingw64_nt"* || "$CI_NAME" == 'windows_nt' ]]; then
|
elif [[ $CI_NAME == *"mingw64_nt"* || "$CI_NAME" == 'windows_nt' ]]; then
|
||||||
|
echo "Compile Hyperion on Windows"
|
||||||
# compile prepare
|
# compile prepare
|
||||||
echo "Number of Cores $NUMBER_OF_PROCESSORS"
|
echo "Number of Cores $NUMBER_OF_PROCESSORS"
|
||||||
mkdir build || exit 1
|
mkdir build || exit 1
|
||||||
cd build
|
cd build
|
||||||
cmake -G "Visual Studio 17 2022" -A x64 -DPLATFORM=${PLATFORM} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ../ || exit 2
|
cmake -G "Visual Studio 17 2022" -A x64 -DPLATFORM=${PLATFORM} -DCMAKE_BUILD_TYPE="Release" ../ || exit 2
|
||||||
cmake --build . --target package --config Release -- -nologo -v:m -maxcpucount || exit 3
|
cmake --build . --target package --config "Release" -- -nologo -v:m -maxcpucount || exit 3
|
||||||
exit 0;
|
exit 0;
|
||||||
exit 1 || { echo "---> Hyperion compilation failed! Abort"; exit 5; }
|
exit 1 || { echo "---> Hyperion compilation failed! Abort"; exit 5; }
|
||||||
elif [[ "$CI_NAME" == 'linux' ]]; then
|
elif [[ "$CI_NAME" == 'linux' ]]; then
|
||||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -9,3 +9,6 @@
|
|||||||
[submodule "dependencies/external/protobuf"]
|
[submodule "dependencies/external/protobuf"]
|
||||||
path = dependencies/external/protobuf
|
path = dependencies/external/protobuf
|
||||||
url = https://github.com/protocolbuffers/protobuf
|
url = https://github.com/protocolbuffers/protobuf
|
||||||
|
[submodule "dependencies/external/qmdnsengine"]
|
||||||
|
path = dependencies/external/qmdnsengine
|
||||||
|
url = https://github.com/nitroshare/qmdnsengine.git
|
||||||
|
1
.vscode/hyperion.code-workspace
vendored
1
.vscode/hyperion.code-workspace
vendored
@ -16,7 +16,6 @@
|
|||||||
"ms-vscode.cmake-tools",
|
"ms-vscode.cmake-tools",
|
||||||
"spmeesseman.vscode-taskexplorer",
|
"spmeesseman.vscode-taskexplorer",
|
||||||
"yzhang.markdown-all-in-one",
|
"yzhang.markdown-all-in-one",
|
||||||
"CoenraadS.bracket-pair-colorizer",
|
|
||||||
"vscode-icons-team.vscode-icons",
|
"vscode-icons-team.vscode-icons",
|
||||||
"editorconfig.editorconfig"
|
"editorconfig.editorconfig"
|
||||||
]
|
]
|
||||||
|
14
CHANGELOG.md
14
CHANGELOG.md
@ -12,10 +12,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- Allow to build a "light" version of Hyperion, i.e. no grabbers, or services like flat-/proto buffers, boblight, CEC
|
- Allow to build a "light" version of Hyperion, i.e. no grabbers, or services like flat-/proto buffers, boblight, CEC
|
||||||
- Allow to restart Hyperion via Systray
|
- Allow to restart Hyperion via Systray
|
||||||
|
- LED-Device: Support retry attempts enabling devices, e.g. to open devices after network or a device itself got available (#1302)
|
||||||
|
(Fixes that devices got "stuck", if initial open failed e.g. for WLED, Hue)
|
||||||
|
- LED-Devices: New UDP-DDP (Distributed Display Protocol) device to overcome the 490 LEDs limitation of UDP-RAW
|
||||||
- LED Matrix Layout - Support vertical cabling direction (#1420)
|
- LED Matrix Layout - Support vertical cabling direction (#1420)
|
||||||
- Support additional Yeelight models
|
- Support additional Yeelight models
|
||||||
- LED-Devices: Show warning, if get properties failed (Network devices: indication that network device is not reachable)
|
- LED-Devices: Show warning, if get properties failed (Network devices: indication that network device is not reachable)
|
||||||
- hyperion-remote: Show image filename in UI for images sent
|
- hyperion-remote: Show image filename in UI for images sent
|
||||||
|
- mDNS support for all platforms inkl. Windows (#740)
|
||||||
|
- LED-Devices mDNS discovery support and ease of configuration (Cololight, Nanoleaf, Philips-Hue, WLED, Yeelight); removes the need to configure IP-Address, as address is resolved automatically.
|
||||||
|
- Forwarder: mDNS discovery support and ease of configuration of other Hyperion instances
|
||||||
|
- Grabber: mDNS discovery for standalone grabbers
|
||||||
- New language: Japanese
|
- New language: Japanese
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
@ -24,6 +31,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Boblight: Support multiple Boblight clients with different priorities
|
- Boblight: Support multiple Boblight clients with different priorities
|
||||||
- UI: Allow configuration of a Boblight server per LED-instance
|
- UI: Allow configuration of a Boblight server per LED-instance
|
||||||
- UI: LED Layout - Removed limitations on indention
|
- UI: LED Layout - Removed limitations on indention
|
||||||
|
- mDNS Publisher :Aligned Hyperion mDNS names to general conventions and simplified namings
|
||||||
|
- Refactored Philips Hue wizard and LED-Device
|
||||||
|
- LED-Devices: WLED's default streaming protocol is now UDP-DDP. More than 490 LEDs are supported now (requires minimum WLED 0.11.0). UDP-RAW is still supported in parallel (via expert settings).
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@ -31,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Effects: Fix that start effect is stuck on UI
|
- Effects: Fix that start effect is stuck on UI
|
||||||
- Fixes that the Led-Device output flow was interrupted, by an enabling API request on an already enabled device (#967
|
- Fixes that the Led-Device output flow was interrupted, by an enabling API request on an already enabled device (#967
|
||||||
- Yeelight - Workaround: Ignore error when setting music mode = off, but the music-mode is already off (#1372)
|
- Yeelight - Workaround: Ignore error when setting music mode = off, but the music-mode is already off (#1372)
|
||||||
|
- Fixed: Hue Entertainment mode does not resume after no signal (#930)
|
||||||
- Standalone grabbers: Improved fps help/error text, fixed default address and port, fixed auto discovery of Hyperion server in hyperion-remote
|
- Standalone grabbers: Improved fps help/error text, fixed default address and port, fixed auto discovery of Hyperion server in hyperion-remote
|
||||||
- Fixed Qt version override, e.g. set via QTDIR
|
- Fixed Qt version override, e.g. set via QTDIR
|
||||||
- Remote control UI: Treat duration=0 as endless
|
- Remote control UI: Treat duration=0 as endless
|
||||||
@ -40,8 +51,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Fixed: Signal detection does not switch off all instances (#1281)
|
- Fixed: Signal detection does not switch off all instances (#1281)
|
||||||
- Reworked PriorityMuxer and Sub-scriptions
|
- Reworked PriorityMuxer and Sub-scriptions
|
||||||
- Do not kill application on SIGILL-signal (#1435)
|
- Do not kill application on SIGILL-signal (#1435)
|
||||||
|
- Start JSON and WebServer only, if Hyperion's instance 0 is available
|
||||||
|
|
||||||
## Removed
|
## Removed
|
||||||
|
- UI Removed sessions (of other Hyperions)
|
||||||
|
- Replaced existing AVAHI/Bonjour code by QMdnsEngine
|
||||||
|
|
||||||
## [2.0.12](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.12) - 2021-11-20
|
## [2.0.12](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.12) - 2021-11-20
|
||||||
Hyperion's November release brings you some new features, removed IPv6 address related limitations, as well as fixing a couple of issues.
|
Hyperion's November release brings you some new features, removed IPv6 address related limitations, as well as fixing a couple of issues.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.0.0)
|
cmake_minimum_required(VERSION 3.1.0)
|
||||||
|
|
||||||
message( STATUS "CMake Version: ${CMAKE_VERSION}" )
|
message( STATUS "CMake Version: ${CMAKE_VERSION}" )
|
||||||
|
|
||||||
@ -38,6 +38,26 @@ if ( CCACHE_FOUND )
|
|||||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||||
endif(CCACHE_FOUND)
|
endif(CCACHE_FOUND)
|
||||||
|
|
||||||
|
# enable C++14; MSVC doesn't have c++14 feature switch
|
||||||
|
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||||
|
if(APPLE)
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("Werror=unguarded-availability" REQUIRED_UNGUARDED_AVAILABILITY)
|
||||||
|
if(REQUIRED_UNGUARDED_AVAILABILITY)
|
||||||
|
list(APPEND CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} "Werror=unguarded-availability")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "GNU")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-psabi")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-psabi")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
set(CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CXX_EXTENSIONS OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Set build variables
|
# Set build variables
|
||||||
# Grabber
|
# Grabber
|
||||||
SET ( DEFAULT_AMLOGIC OFF )
|
SET ( DEFAULT_AMLOGIC OFF )
|
||||||
@ -69,18 +89,18 @@ SET ( DEFAULT_DEV_USB_HID OFF )
|
|||||||
SET ( DEFAULT_DEV_WS281XPWM OFF )
|
SET ( DEFAULT_DEV_WS281XPWM OFF )
|
||||||
|
|
||||||
# Services
|
# Services
|
||||||
SET ( DEFAULT_AVAHI ON )
|
|
||||||
SET ( DEFAULT_EFFECTENGINE ON )
|
SET ( DEFAULT_EFFECTENGINE ON )
|
||||||
SET ( DEFAULT_EXPERIMENTAL OFF )
|
SET ( DEFAULT_EXPERIMENTAL OFF )
|
||||||
|
SET ( DEFAULT_MDNS ON )
|
||||||
SET ( DEFAULT_REMOTE_CTL ON )
|
SET ( DEFAULT_REMOTE_CTL ON )
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
SET ( DEFAULT_JSONCHECKS ON )
|
SET ( DEFAULT_JSONCHECKS ON )
|
||||||
SET ( DEFAULT_DEPLOY_DEPENDENCIES ON )
|
SET ( DEFAULT_DEPLOY_DEPENDENCIES ON )
|
||||||
SET ( DEFAULT_USE_SHARED_AVAHI_LIBS ON )
|
|
||||||
SET ( DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS OFF )
|
SET ( DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS OFF )
|
||||||
SET ( DEFAULT_USE_SYSTEM_PROTO_LIBS OFF )
|
SET ( DEFAULT_USE_SYSTEM_PROTO_LIBS OFF )
|
||||||
SET ( DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF )
|
SET ( DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF )
|
||||||
|
SET ( DEFAULT_USE_SYSTEM_QMDNS_LIBS OFF )
|
||||||
SET ( DEFAULT_TESTS OFF )
|
SET ( DEFAULT_TESTS OFF )
|
||||||
|
|
||||||
# Build Hyperion with a reduced set of functionality, overwrites other default values
|
# Build Hyperion with a reduced set of functionality, overwrites other default values
|
||||||
@ -175,8 +195,6 @@ elseif ( "${PLATFORM}" MATCHES "x11" )
|
|||||||
endif()
|
endif()
|
||||||
elseif ( "${PLATFORM}" STREQUAL "imx6" )
|
elseif ( "${PLATFORM}" STREQUAL "imx6" )
|
||||||
SET ( DEFAULT_FB ON )
|
SET ( DEFAULT_FB ON )
|
||||||
elseif (WIN32)
|
|
||||||
SET ( DEFAULT_AVAHI OFF)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# enable tests for -dev builds
|
# enable tests for -dev builds
|
||||||
@ -319,15 +337,15 @@ removeIndent()
|
|||||||
message(STATUS "Services options:")
|
message(STATUS "Services options:")
|
||||||
addIndent(" - ")
|
addIndent(" - ")
|
||||||
|
|
||||||
option(ENABLE_AVAHI "Enable Zeroconf" ${DEFAULT_AVAHI})
|
|
||||||
message(STATUS "ENABLE_AVAHI = " ${ENABLE_AVAHI})
|
|
||||||
|
|
||||||
option(ENABLE_EFFECTENGINE "Enable Effect-Engine" ${DEFAULT_EFFECTENGINE})
|
option(ENABLE_EFFECTENGINE "Enable Effect-Engine" ${DEFAULT_EFFECTENGINE})
|
||||||
message(STATUS "ENABLE_EFFECTENGINE = " ${ENABLE_EFFECTENGINE})
|
message(STATUS "ENABLE_EFFECTENGINE = " ${ENABLE_EFFECTENGINE})
|
||||||
|
|
||||||
option(ENABLE_EXPERIMENTAL "Compile experimental features" ${DEFAULT_EXPERIMENTAL})
|
option(ENABLE_EXPERIMENTAL "Compile experimental features" ${DEFAULT_EXPERIMENTAL})
|
||||||
message(STATUS "ENABLE_EXPERIMENTAL = ${ENABLE_EXPERIMENTAL}")
|
message(STATUS "ENABLE_EXPERIMENTAL = ${ENABLE_EXPERIMENTAL}")
|
||||||
|
|
||||||
|
option(ENABLE_MDNS "Enable mDNS (aka Zeroconf)" ${DEFAULT_MDNS})
|
||||||
|
message(STATUS "ENABLE_MDNS = " ${ENABLE_MDNS})
|
||||||
|
|
||||||
option(ENABLE_REMOTE_CTL "Enable Hyperion remote control" ${DEFAULT_REMOTE_CTL})
|
option(ENABLE_REMOTE_CTL "Enable Hyperion remote control" ${DEFAULT_REMOTE_CTL})
|
||||||
message(STATUS "ENABLE_REMOTE_CTL = " ${ENABLE_REMOTE_CTL})
|
message(STATUS "ENABLE_REMOTE_CTL = " ${ENABLE_REMOTE_CTL})
|
||||||
|
|
||||||
@ -342,19 +360,27 @@ message(STATUS "ENABLE_JSONCHECKS = ${ENABLE_JSONCHECKS}")
|
|||||||
option(ENABLE_DEPLOY_DEPENDENCIES "Deploy with dependencies" ${DEFAULT_DEPLOY_DEPENDENCIES})
|
option(ENABLE_DEPLOY_DEPENDENCIES "Deploy with dependencies" ${DEFAULT_DEPLOY_DEPENDENCIES})
|
||||||
message(STATUS "ENABLE_DEPLOY_DEPENDENCIES = ${ENABLE_DEPLOY_DEPENDENCIES}")
|
message(STATUS "ENABLE_DEPLOY_DEPENDENCIES = ${ENABLE_DEPLOY_DEPENDENCIES}")
|
||||||
|
|
||||||
|
if(ENABLE_FLATBUF_SERVER OR ENABLE_FLATBUF_CONNECT)
|
||||||
|
message(STATUS "DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS = ${DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_PROTOBUF_SERVER)
|
||||||
|
message(STATUS "DEFAULT_USE_SYSTEM_PROTO_LIBS = ${DEFAULT_USE_SYSTEM_PROTO_LIBS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "DEFAULT_USE_SYSTEM_MBEDTLS_LIBS = ${DEFAULT_USE_SYSTEM_MBEDTLS_LIBS}")
|
||||||
|
|
||||||
|
if (ENABLE_MDNS)
|
||||||
|
message(STATUS "DEFAULT_USE_SYSTEM_QMDNS_LIBS = ${DEFAULT_USE_SYSTEM_QMDNS_LIBS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
option(ENABLE_PROFILER "enable profiler capabilities - not for release code" OFF)
|
option(ENABLE_PROFILER "enable profiler capabilities - not for release code" OFF)
|
||||||
message(STATUS "ENABLE_PROFILER = ${ENABLE_PROFILER}")
|
message(STATUS "ENABLE_PROFILER = ${ENABLE_PROFILER}")
|
||||||
|
|
||||||
option(ENABLE_TESTS "Compile additional test applications" ${DEFAULT_TESTS})
|
option(ENABLE_TESTS "Compile additional test applications" ${DEFAULT_TESTS})
|
||||||
message(STATUS "ENABLE_TESTS = ${ENABLE_TESTS}")
|
message(STATUS "ENABLE_TESTS = ${ENABLE_TESTS}")
|
||||||
|
|
||||||
if (ENABLE_AVAHI)
|
|
||||||
message(STATUS "DEFAULT_USE_SHARED_AVAHI_LIBS = ${DEFAULT_USE_SHARED_AVAHI_LIBS}")
|
|
||||||
endif()
|
|
||||||
message(STATUS "DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS = ${DEFAULT_USE_SYSTEM_FLATBUFFERS_LIBS}")
|
|
||||||
message(STATUS "DEFAULT_USE_SYSTEM_MBEDTLS_LIBS = ${DEFAULT_USE_SYSTEM_MBEDTLS_LIBS}")
|
|
||||||
message(STATUS "DEFAULT_USE_SYSTEM_PROTO_LIBS = ${DEFAULT_USE_SYSTEM_PROTO_LIBS}")
|
|
||||||
|
|
||||||
removeIndent()
|
removeIndent()
|
||||||
|
|
||||||
SET ( FLATBUFFERS_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/flatbuf )
|
SET ( FLATBUFFERS_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/flatbuf )
|
||||||
@ -504,21 +530,23 @@ if (DEFINED QTDIR)
|
|||||||
list(PREPEND CMAKE_PREFIX_PATH ${QTDIR} "${QTDIR}/lib")
|
list(PREPEND CMAKE_PREFIX_PATH ${QTDIR} "${QTDIR}/lib")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
message( STATUS "CMAKE_PREFIX_PATH used: ${CMAKE_PREFIX_PATH}" )
|
if (CMAKE_PREFIX_PATH)
|
||||||
|
message( STATUS "CMAKE_PREFIX_PATH used: ${CMAKE_PREFIX_PATH}" )
|
||||||
|
endif()
|
||||||
|
|
||||||
# find QT libs
|
# find QT libs
|
||||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network Sql Widgets REQUIRED)
|
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network Sql Widgets REQUIRED)
|
||||||
message( STATUS "Found Qt Version: ${QT_VERSION}" )
|
message( STATUS "Found Qt Version: ${QT_VERSION}" )
|
||||||
|
|
||||||
if (${QT_VERSION_MAJOR} GREATER_EQUAL 6 )
|
if (${QT_VERSION_MAJOR} GREATER_EQUAL 6 )
|
||||||
SET(QT_MIN_VERSION "6.2.0")
|
SET(QT_MIN_VERSION "6.2.2")
|
||||||
ELSE()
|
else()
|
||||||
SET(QT_MIN_VERSION "5.5.0")
|
SET(QT_MIN_VERSION "5.5.0")
|
||||||
ENDIF()
|
endif()
|
||||||
|
|
||||||
IF ( "${QT_VERSION}" VERSION_LESS "${QT_MIN_VERSION}" )
|
if ( "${QT_VERSION}" VERSION_LESS "${QT_MIN_VERSION}" )
|
||||||
message( FATAL_ERROR "Your Qt version is to old! Minimum required ${QT_MIN_VERSION}" )
|
message( FATAL_ERROR "Your Qt version is to old! Minimum required ${QT_MIN_VERSION}" )
|
||||||
ENDIF()
|
endif()
|
||||||
|
|
||||||
find_package(Qt${QT_VERSION_MAJOR} ${QT_VERSION} COMPONENTS Core Gui Network Sql Widgets REQUIRED)
|
find_package(Qt${QT_VERSION_MAJOR} ${QT_VERSION} COMPONENTS Core Gui Network Sql Widgets REQUIRED)
|
||||||
|
|
||||||
@ -526,7 +554,7 @@ message( STATUS "Qt version used: ${QT_VERSION}" )
|
|||||||
|
|
||||||
if (APPLE AND (${QT_VERSION_MAJOR} GREATER_EQUAL 6) )
|
if (APPLE AND (${QT_VERSION_MAJOR} GREATER_EQUAL 6) )
|
||||||
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)
|
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)
|
||||||
ENDIF()
|
endif()
|
||||||
|
|
||||||
# Add libusb and pthreads
|
# Add libusb and pthreads
|
||||||
find_package(libusb-1.0 REQUIRED)
|
find_package(libusb-1.0 REQUIRED)
|
||||||
@ -557,33 +585,6 @@ endif ()
|
|||||||
|
|
||||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${GENERATED_QRC}" )
|
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${GENERATED_QRC}" )
|
||||||
|
|
||||||
# enable C++11; MSVC doesn't have c++11 feature switch
|
|
||||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
|
||||||
include(CheckCXXCompilerFlag)
|
|
||||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
|
||||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
|
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
CHECK_CXX_COMPILER_FLAG("Werror=unguarded-availability" REQUIRED_UNGUARDED_AVAILABILITY)
|
|
||||||
if(REQUIRED_UNGUARDED_AVAILABILITY)
|
|
||||||
list(APPEND CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} "Werror=unguarded-availability")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
|
||||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-psabi")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-psabi")
|
|
||||||
endif()
|
|
||||||
if(COMPILER_SUPPORTS_CXX11)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
|
||||||
elseif(COMPILER_SUPPORTS_CXX0X)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
|
||||||
else()
|
|
||||||
message(STATUS "No support for C++11 detected. Compilation will most likely fail on your compiler")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# uninstall target
|
# uninstall target
|
||||||
configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
|
configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
|
||||||
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
],
|
],
|
||||||
"environments": [
|
"environments": [
|
||||||
// Replace path with your installation path
|
// Replace path with your installation path
|
||||||
//{ "QTDIR": "C:/Qt/6.2.0/msvc2019_64/" },
|
//{ "QTDIR": "C:/Qt/6.2.2/msvc2019_64/" },
|
||||||
//{ "VULKAN_SDK": "C:/VulkanSDK/1.2.182.0" }
|
//{ "VULKAN_SDK": "C:/VulkanSDK/1.2.182.0" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -38,7 +38,7 @@
|
|||||||
],
|
],
|
||||||
"environments": [
|
"environments": [
|
||||||
// Replace path with your installation path
|
// Replace path with your installation path
|
||||||
//{ "QTDIR": "C:/Qt/6.2.0/msvc2019_64/" },
|
//{ "QTDIR": "C:/Qt/6.2.2/msvc2019_64/" },
|
||||||
//{ "VULKAN_SDK": "C:/VulkanSDK/1.2.182.0" }
|
//{ "VULKAN_SDK": "C:/VulkanSDK/1.2.182.0" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -69,8 +69,8 @@
|
|||||||
// Define to enable the WS281x-PWM-via-DMA-device using jgarff's library
|
// Define to enable the WS281x-PWM-via-DMA-device using jgarff's library
|
||||||
#cmakedefine ENABLE_DEV_WS281XPWM
|
#cmakedefine ENABLE_DEV_WS281XPWM
|
||||||
|
|
||||||
// Define to enable AVAHI
|
// Define to enable MDNS
|
||||||
#cmakedefine ENABLE_AVAHI
|
#cmakedefine ENABLE_MDNS
|
||||||
|
|
||||||
// Define to enable EFFECTENGINE
|
// Define to enable EFFECTENGINE
|
||||||
#cmakedefine ENABLE_EFFECTENGINE
|
#cmakedefine ENABLE_EFFECTENGINE
|
||||||
|
@ -88,6 +88,16 @@
|
|||||||
"conf_leds_layout_cl_leftbottom": "Left 50% - 100% Bottom",
|
"conf_leds_layout_cl_leftbottom": "Left 50% - 100% Bottom",
|
||||||
"conf_leds_layout_cl_leftmiddle": "Left 25% - 75% Middle",
|
"conf_leds_layout_cl_leftmiddle": "Left 25% - 75% Middle",
|
||||||
"conf_leds_layout_cl_lefttop": "Left 0% - 50% Top",
|
"conf_leds_layout_cl_lefttop": "Left 0% - 50% Top",
|
||||||
|
"conf_leds_layout_cl_lightPosBottomLeft14": "Bottom: 0 - 25% from Left",
|
||||||
|
"conf_leds_layout_cl_lightPosBottomLeft12": "Bottom: 25 - 50% from Left",
|
||||||
|
"conf_leds_layout_cl_lightPosBottomLeft34": "Bottom: 50 - 75% from Left",
|
||||||
|
"conf_leds_layout_cl_lightPosBottomLeft11": "Bottom: 75 - 100% from Left",
|
||||||
|
"conf_leds_layout_cl_lightPosBottomLeft112": "Bottom: 0 - 50% from Left",
|
||||||
|
"conf_leds_layout_cl_lightPosBottomLeft121": "Bottom: 50 - 100% from Left",
|
||||||
|
"conf_leds_layout_cl_lightPosBottomLeftNewMid": "Bottom: 25 - 75% from Left",
|
||||||
|
"conf_leds_layout_cl_lightPosTopLeft112": "Top: 0 - 50% from Left",
|
||||||
|
"conf_leds_layout_cl_lightPosTopLeft121": "Top: 50 - 100% from Left",
|
||||||
|
"conf_leds_layout_cl_lightPosTopLeftNewMid": "Top: 25 - 75% from Left",
|
||||||
"conf_leds_layout_cl_overlap": "Overlap",
|
"conf_leds_layout_cl_overlap": "Overlap",
|
||||||
"conf_leds_layout_cl_reversdir": "Reverse direction",
|
"conf_leds_layout_cl_reversdir": "Reverse direction",
|
||||||
"conf_leds_layout_cl_right": "Right",
|
"conf_leds_layout_cl_right": "Right",
|
||||||
@ -329,6 +339,8 @@
|
|||||||
"edt_conf_enum_top_down": "Top down",
|
"edt_conf_enum_top_down": "Top down",
|
||||||
"edt_conf_enum_transeffect_smooth": "Smooth",
|
"edt_conf_enum_transeffect_smooth": "Smooth",
|
||||||
"edt_conf_enum_transeffect_sudden": "Sudden",
|
"edt_conf_enum_transeffect_sudden": "Sudden",
|
||||||
|
"edt_conf_enum_udp_ddp": "DDP",
|
||||||
|
"edt_conf_enum_udp_raw": "RAW",
|
||||||
"edt_conf_enum_unicolor_mean": "Unicolor",
|
"edt_conf_enum_unicolor_mean": "Unicolor",
|
||||||
"edt_conf_fbs_heading_title": "Flatbuffers Server",
|
"edt_conf_fbs_heading_title": "Flatbuffers Server",
|
||||||
"edt_conf_fbs_timeout_expl": "If no data is received for the given period, the component will be (soft) disabled.",
|
"edt_conf_fbs_timeout_expl": "If no data is received for the given period, the component will be (soft) disabled.",
|
||||||
@ -355,13 +367,20 @@
|
|||||||
"edt_conf_fge_heading_title": "Boot Effect/Color",
|
"edt_conf_fge_heading_title": "Boot Effect/Color",
|
||||||
"edt_conf_fge_type_expl": "Choose between a color or effect.",
|
"edt_conf_fge_type_expl": "Choose between a color or effect.",
|
||||||
"edt_conf_fge_type_title": "Type",
|
"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_expl": "One flatbuffer target per configuration item",
|
||||||
"edt_conf_fw_flat_itemtitle": "flatbuffer target",
|
"edt_conf_fw_flat_itemtitle": "flatbuffer target",
|
||||||
|
"edt_conf_fw_flat_services_discovered_expl": "Hyperion servers discovered providing flatbuffer services",
|
||||||
|
"edt_conf_fw_flat_services_discovered_title": "Flatbuffer targets discoverded",
|
||||||
"edt_conf_fw_flat_title": "List of flatbuffer targets",
|
"edt_conf_fw_flat_title": "List of flatbuffer targets",
|
||||||
"edt_conf_fw_heading_title": "Forwarder",
|
"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_expl": "One JSON target per configuration item",
|
||||||
"edt_conf_fw_json_itemtitle": "Json target",
|
"edt_conf_fw_json_itemtitle": "JSON target",
|
||||||
"edt_conf_fw_json_title": "List of json targets",
|
"edt_conf_fw_json_services_discovered_expl": "Hyperion servers discovered providing JSON-API services",
|
||||||
|
"edt_conf_fw_json_services_discovered_title": "JSON targets discoverded",
|
||||||
|
"edt_conf_fw_json_title": "List of JSON targets",
|
||||||
|
"edt_conf_fw_remote_service_discovered_none": "No remote services discovered",
|
||||||
|
"edt_conf_fw_service_name_expl": "Name of the service provider",
|
||||||
|
"edt_conf_fw_service_name_title": "Service name",
|
||||||
"edt_conf_gen_configVersion_title": "Configuration version",
|
"edt_conf_gen_configVersion_title": "Configuration version",
|
||||||
"edt_conf_gen_heading_title": "General Settings",
|
"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_expl": "A user defined name which is used to detect Hyperion. (Helpful with more than one Hyperion instance)",
|
||||||
@ -510,6 +529,10 @@
|
|||||||
"edt_dev_general_autostart_title_info": "The LED device is switched-on during startup or not",
|
"edt_dev_general_autostart_title_info": "The LED device is switched-on during startup or not",
|
||||||
"edt_dev_general_colorOrder_title": "RGB byte order",
|
"edt_dev_general_colorOrder_title": "RGB byte order",
|
||||||
"edt_dev_general_colorOrder_title_info": "The device's color order",
|
"edt_dev_general_colorOrder_title_info": "The device's color order",
|
||||||
|
"edt_dev_general_enableAttempts_title": "Connection attempts",
|
||||||
|
"edt_dev_general_enableAttempts_title_info": "Number of attempts connecting a device before it goes into an error state.",
|
||||||
|
"edt_dev_general_enableAttemptsInterval_title": "Retry interval",
|
||||||
|
"edt_dev_general_enableAttemptsInterval_title_info": "Intervall between two connection attempts.",
|
||||||
"edt_dev_general_hardwareLedCount_title": "Hardware LED count",
|
"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_hardwareLedCount_title_info": "The number of physical LEDs availabe for the given device",
|
||||||
"edt_dev_general_heading_title": "General Settings",
|
"edt_dev_general_heading_title": "General Settings",
|
||||||
@ -523,17 +546,15 @@
|
|||||||
"edt_dev_spec_baudrate_title": "Baudrate",
|
"edt_dev_spec_baudrate_title": "Baudrate",
|
||||||
"edt_dev_spec_blackLightsTimeout_title": "Signal detection timeout on black",
|
"edt_dev_spec_blackLightsTimeout_title": "Signal detection timeout on black",
|
||||||
"edt_dev_spec_brightnessFactor_title": "Brightness factor",
|
"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_brightnessOverwrite_title": "Overwrite brightness",
|
||||||
"edt_dev_spec_brightnessThreshold_title": "Signal detection brightness minimum",
|
"edt_dev_spec_brightnessThreshold_title": "Signal detection brightness minimum",
|
||||||
"edt_dev_spec_brightness_title": "Brightness",
|
"edt_dev_spec_brightness_title": "Brightness",
|
||||||
|
"edt_dev_spec_candyGamma_title" : "'Candy' mode (double gamma correction)",
|
||||||
"edt_dev_spec_chanperfixture_title": "Channels per Fixture",
|
"edt_dev_spec_chanperfixture_title": "Channels per Fixture",
|
||||||
"edt_dev_spec_cid_title": "CID",
|
"edt_dev_spec_cid_title": "CID",
|
||||||
"edt_dev_spec_clientKey_title": "Clientkey",
|
"edt_dev_spec_clientKey_title": "Clientkey",
|
||||||
"edt_dev_spec_colorComponent_title": "Colour component",
|
"edt_dev_spec_colorComponent_title": "Colour component",
|
||||||
"edt_dev_spec_debugLevel_title": "Debug Level",
|
"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_delayAfterConnect_title": "Delay after connect",
|
||||||
"edt_dev_spec_devices_discovered_none": "No Devices Discovered",
|
"edt_dev_spec_devices_discovered_none": "No Devices Discovered",
|
||||||
"edt_dev_spec_devices_discovered_title": "Devices Discovered",
|
"edt_dev_spec_devices_discovered_title": "Devices Discovered",
|
||||||
@ -568,6 +589,8 @@
|
|||||||
"edt_dev_spec_networkDeviceName_title": "Network devicename",
|
"edt_dev_spec_networkDeviceName_title": "Network devicename",
|
||||||
"edt_dev_spec_networkDevicePort_title": "Port",
|
"edt_dev_spec_networkDevicePort_title": "Port",
|
||||||
"edt_dev_spec_numberOfLeds_title": "Number of LEDs",
|
"edt_dev_spec_numberOfLeds_title": "Number of LEDs",
|
||||||
|
"edt_dev_spec_onBlackTimeToPowerOff": "Time to power off the lamp if the black level is triggered",
|
||||||
|
"edt_dev_spec_onBlackTimeToPowerOn": "Time to power on the lamp if the signal is restored",
|
||||||
"edt_dev_spec_orbIds_title": "Orb ID(s)",
|
"edt_dev_spec_orbIds_title": "Orb ID(s)",
|
||||||
"edt_dev_spec_order_left_right_title": "2.",
|
"edt_dev_spec_order_left_right_title": "2.",
|
||||||
"edt_dev_spec_order_top_down_title": "1.",
|
"edt_dev_spec_order_top_down_title": "1.",
|
||||||
@ -575,8 +598,10 @@
|
|||||||
"edt_dev_spec_panel_start_position": "Start panel [0-max panels]",
|
"edt_dev_spec_panel_start_position": "Start panel [0-max panels]",
|
||||||
"edt_dev_spec_panelorganisation_title": "Panel numbering sequence",
|
"edt_dev_spec_panelorganisation_title": "Panel numbering sequence",
|
||||||
"edt_dev_spec_pid_title": "PID",
|
"edt_dev_spec_pid_title": "PID",
|
||||||
|
"edt_dev_spec_port_expl": "Service Port [1-65535]",
|
||||||
"edt_dev_spec_port_title": "Port",
|
"edt_dev_spec_port_title": "Port",
|
||||||
"edt_dev_spec_printTimeStamp_title": "Add timestamp",
|
"edt_dev_spec_printTimeStamp_title": "Add timestamp",
|
||||||
|
"edt_dev_spec_stream_protocol_title": "Streaming protocol",
|
||||||
"edt_dev_spec_pwmChannel_title": "PWM channel",
|
"edt_dev_spec_pwmChannel_title": "PWM channel",
|
||||||
"edt_dev_spec_razer_device_title": "Razer Chroma Device",
|
"edt_dev_spec_razer_device_title": "Razer Chroma Device",
|
||||||
"edt_dev_spec_restoreOriginalState_title": "Restore lights' state",
|
"edt_dev_spec_restoreOriginalState_title": "Restore lights' state",
|
||||||
@ -585,10 +610,10 @@
|
|||||||
"edt_dev_spec_spipath_title": "SPI Device",
|
"edt_dev_spec_spipath_title": "SPI Device",
|
||||||
"edt_dev_spec_sslHSTimeoutMax_title": "Streamer handshake timeout maximum",
|
"edt_dev_spec_sslHSTimeoutMax_title": "Streamer handshake timeout maximum",
|
||||||
"edt_dev_spec_sslHSTimeoutMin_title": "Streamer handshake timeout minimum",
|
"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_switchOffOnBlack_title": "Switch off on black",
|
||||||
"edt_dev_spec_switchOffOnbelowMinBrightness_title": "Switch-off, below minimum",
|
"edt_dev_spec_switchOffOnbelowMinBrightness_title": "Switch-off, below minimum",
|
||||||
"edt_dev_spec_syncOverwrite_title": "Disable synchronisation",
|
"edt_dev_spec_syncOverwrite_title": "Disable synchronisation",
|
||||||
|
"edt_dev_spec_targetIpHost_expl": "Hostname (DNS/mDNS) or IP-address (IPv4 orIPv6)",
|
||||||
"edt_dev_spec_targetIpHost_title": "Hostname/IP-address",
|
"edt_dev_spec_targetIpHost_title": "Hostname/IP-address",
|
||||||
"edt_dev_spec_targetIpHost_title_info": "The device's hostname or IP-address",
|
"edt_dev_spec_targetIpHost_title_info": "The device's hostname or IP-address",
|
||||||
"edt_dev_spec_targetIp_title": "IP-address",
|
"edt_dev_spec_targetIp_title": "IP-address",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
var darkModeOverwrite = getStorage("darkModeOverwrite", true);
|
var darkModeOverwrite = getStorage("darkModeOverwrite");
|
||||||
|
|
||||||
if (darkModeOverwrite == "false" || darkModeOverwrite == null) {
|
if (darkModeOverwrite == "false" || darkModeOverwrite == null) {
|
||||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||||
@ -7,11 +7,11 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
|
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) {
|
||||||
setStorage("darkMode", "off", false);
|
setStorage("darkMode", "off");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getStorage("darkMode", false) == "on") {
|
if (getStorage("darkMode") == "on") {
|
||||||
handleDarkMode();
|
handleDarkMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,6 @@ $(document).ready(function () {
|
|||||||
$('#btn_hypinstanceswitch').toggle(true)
|
$('#btn_hypinstanceswitch').toggle(true)
|
||||||
else
|
else
|
||||||
$('#btn_hypinstanceswitch').toggle(false)
|
$('#btn_hypinstanceswitch').toggle(false)
|
||||||
updateSessions();
|
|
||||||
}); // end cmd-serverinfo
|
}); // end cmd-serverinfo
|
||||||
|
|
||||||
// Update language selection
|
// Update language selection
|
||||||
@ -73,11 +72,6 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
//End language selection
|
//End language selection
|
||||||
|
|
||||||
$(window.hyperion).on("cmd-sessions-update", function (event) {
|
|
||||||
window.serverInfo.sessions = event.response.data;
|
|
||||||
updateSessions();
|
|
||||||
});
|
|
||||||
|
|
||||||
$(window.hyperion).on("cmd-authorize-tokenRequest cmd-authorize-getPendingTokenRequests", function (event) {
|
$(window.hyperion).on("cmd-authorize-tokenRequest cmd-authorize-getPendingTokenRequests", function (event) {
|
||||||
var val = event.response.info;
|
var val = event.response.info;
|
||||||
if (Array.isArray(event.response.info)) {
|
if (Array.isArray(event.response.info)) {
|
||||||
@ -121,7 +115,7 @@ $(document).ready(function () {
|
|||||||
requestGetPendingTokenRequests();
|
requestGetPendingTokenRequests();
|
||||||
|
|
||||||
//Switch to last selected instance and load related config
|
//Switch to last selected instance and load related config
|
||||||
var lastSelectedInstance = getStorage('lastSelectedInstance', false);
|
var lastSelectedInstance = getStorage('lastSelectedInstance');
|
||||||
if (lastSelectedInstance == null || window.serverInfo.instance && !window.serverInfo.instance[lastSelectedInstance]) {
|
if (lastSelectedInstance == null || window.serverInfo.instance && !window.serverInfo.instance[lastSelectedInstance]) {
|
||||||
lastSelectedInstance = 0;
|
lastSelectedInstance = 0;
|
||||||
}
|
}
|
||||||
@ -157,7 +151,7 @@ $(document).ready(function () {
|
|||||||
$("#btn_lock_ui").removeAttr('style')
|
$("#btn_lock_ui").removeAttr('style')
|
||||||
|
|
||||||
if (event.response.hasOwnProperty('info'))
|
if (event.response.hasOwnProperty('info'))
|
||||||
setStorage("loginToken", event.response.info.token, true);
|
setStorage("loginToken", event.response.info.token);
|
||||||
|
|
||||||
requestServerConfigSchema();
|
requestServerConfigSchema();
|
||||||
});
|
});
|
||||||
@ -171,7 +165,7 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$(window.hyperion).on("cmd-authorize-newPasswordRequired", function (event) {
|
$(window.hyperion).on("cmd-authorize-newPasswordRequired", function (event) {
|
||||||
var loginToken = getStorage("loginToken", true)
|
var loginToken = getStorage("loginToken")
|
||||||
|
|
||||||
if (event.response.info.newPasswordRequired == true) {
|
if (event.response.info.newPasswordRequired == true) {
|
||||||
window.defaultPasswordIsSet = true;
|
window.defaultPasswordIsSet = true;
|
||||||
@ -204,8 +198,8 @@ $(document).ready(function () {
|
|||||||
$(window.hyperion).on("error", function (event) {
|
$(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.
|
//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)
|
//e.g.: hyperiond was started new in the meantime)
|
||||||
if (event.reason == "No Authorization" && getStorage("loginToken", true)) {
|
if (event.reason == "No Authorization" && getStorage("loginToken")) {
|
||||||
removeStorage("loginToken", true);
|
removeStorage("loginToken");
|
||||||
requestRequiresAdminAuth();
|
requestRequiresAdminAuth();
|
||||||
}
|
}
|
||||||
else if (event.reason == "Selected Hyperion instance isn't running") {
|
else if (event.reason == "Selected Hyperion instance isn't running") {
|
||||||
@ -281,8 +275,8 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
if (!isInData) {
|
if (!isInData) {
|
||||||
//Delete Storage information about the last used but now stopped instance
|
//Delete Storage information about the last used but now stopped instance
|
||||||
if (getStorage('lastSelectedInstance', false))
|
if (getStorage('lastSelectedInstance'))
|
||||||
removeStorage('lastSelectedInstance', false)
|
removeStorage('lastSelectedInstance')
|
||||||
|
|
||||||
currentHyperionInstance = 0;
|
currentHyperionInstance = 0;
|
||||||
currentHyperionInstanceName = getInstanceNameByIndex(0);
|
currentHyperionInstanceName = getInstanceNameByIndex(0);
|
||||||
@ -341,7 +335,7 @@ function suppressDefaultPwWarning() {
|
|||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
var sidebar = $('#side-menu'); // cache sidebar to a variable for performance
|
var sidebar = $('#side-menu'); // cache sidebar to a variable for performance
|
||||||
sidebar.on("click", 'a.inactive' , function () {
|
sidebar.on("click", 'a.inactive', function () {
|
||||||
sidebar.find('.active').toggleClass('active inactive');
|
sidebar.find('.active').toggleClass('active inactive');
|
||||||
$(this).toggleClass('active inactive');
|
$(this).toggleClass('active inactive');
|
||||||
});
|
});
|
||||||
@ -354,13 +348,13 @@ $(document.body).on('hide.bs.modal,hidden.bs.modal', function () {
|
|||||||
|
|
||||||
//Dark Mode
|
//Dark Mode
|
||||||
$("#btn_darkmode").off().on("click", function (e) {
|
$("#btn_darkmode").off().on("click", function (e) {
|
||||||
if (getStorage("darkMode", false) != "on") {
|
if (getStorage("darkMode") != "on") {
|
||||||
handleDarkMode();
|
handleDarkMode();
|
||||||
setStorage("darkModeOverwrite", true, true);
|
setStorage("darkModeOverwrite", true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setStorage("darkMode", "off", false);
|
setStorage("darkMode", "off",);
|
||||||
setStorage("darkModeOverwrite", true, true);
|
setStorage("darkModeOverwrite", true);
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -392,3 +386,4 @@ function SwitchToMenuItem(target, item) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ var toggleKeystoneCorrectionArea = false;
|
|||||||
var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'sk9822', 'ws2812spi'];
|
var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'sk9822', 'ws2812spi'];
|
||||||
var devRPiPWM = ['ws281x'];
|
var devRPiPWM = ['ws281x'];
|
||||||
var devRPiGPIO = ['piblaster'];
|
var devRPiGPIO = ['piblaster'];
|
||||||
var devNET = ['atmoorb', 'cololight', 'fadecandy', 'philipshue', 'nanoleaf', 'razer', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw', 'wled', 'yeelight'];
|
var devNET = ['atmoorb', 'cololight', 'fadecandy', 'philipshue', 'nanoleaf', 'razer', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udpddp', 'udph801', 'udpraw', 'wled', 'yeelight'];
|
||||||
var devSerial = ['adalight', 'dmx', 'atmo', 'sedu', 'tpm2', 'karate'];
|
var devSerial = ['adalight', 'dmx', 'atmo', 'sedu', 'tpm2', 'karate'];
|
||||||
var devHID = ['hyperionusbasp', 'lightpack', 'paintpack', 'rawhid'];
|
var devHID = ['hyperionusbasp', 'lightpack', 'paintpack', 'rawhid'];
|
||||||
|
|
||||||
@ -1075,6 +1075,7 @@ $(document).ready(function () {
|
|||||||
conf_editor.on('ready', function () {
|
conf_editor.on('ready', function () {
|
||||||
var hwLedCountDefault = 1;
|
var hwLedCountDefault = 1;
|
||||||
var colorOrderDefault = "rgb";
|
var colorOrderDefault = "rgb";
|
||||||
|
var filter = {};
|
||||||
|
|
||||||
$('#btn_test_controller').hide();
|
$('#btn_test_controller').hide();
|
||||||
|
|
||||||
@ -1083,13 +1084,7 @@ $(document).ready(function () {
|
|||||||
case "wled":
|
case "wled":
|
||||||
case "nanoleaf":
|
case "nanoleaf":
|
||||||
showAllDeviceInputOptions("hostList", false);
|
showAllDeviceInputOptions("hostList", false);
|
||||||
case "adalight":
|
case "apa102":
|
||||||
case "atmo":
|
|
||||||
case "dmx":
|
|
||||||
case "karate":
|
|
||||||
case "sedu":
|
|
||||||
case "tpm2":
|
|
||||||
case "apa102":
|
|
||||||
case "apa104":
|
case "apa104":
|
||||||
case "ws2801":
|
case "ws2801":
|
||||||
case "lpd6803":
|
case "lpd6803":
|
||||||
@ -1101,7 +1096,18 @@ $(document).ready(function () {
|
|||||||
case "ws2812spi":
|
case "ws2812spi":
|
||||||
case "piblaster":
|
case "piblaster":
|
||||||
case "ws281x":
|
case "ws281x":
|
||||||
discover_device(ledType);
|
|
||||||
|
//Serial devices
|
||||||
|
case "adalight":
|
||||||
|
case "atmo":
|
||||||
|
case "dmx":
|
||||||
|
case "karate":
|
||||||
|
case "sedu":
|
||||||
|
case "tpm2":
|
||||||
|
if (storedAccess === 'expert') {
|
||||||
|
filter.discoverAll = true;
|
||||||
|
}
|
||||||
|
discover_device(ledType, filter);
|
||||||
hwLedCountDefault = 1;
|
hwLedCountDefault = 1;
|
||||||
colorOrderDefault = "rgb";
|
colorOrderDefault = "rgb";
|
||||||
break;
|
break;
|
||||||
@ -1172,6 +1178,7 @@ $(document).ready(function () {
|
|||||||
case "tpm2net":
|
case "tpm2net":
|
||||||
case "udpe131":
|
case "udpe131":
|
||||||
case "udpartnet":
|
case "udpartnet":
|
||||||
|
case "udpddp":
|
||||||
case "udph801":
|
case "udph801":
|
||||||
case "udpraw":
|
case "udpraw":
|
||||||
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
|
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
|
||||||
@ -1255,33 +1262,43 @@ $(document).ready(function () {
|
|||||||
var hostList = conf_editor.getEditor("root.specificOptions.hostList");
|
var hostList = conf_editor.getEditor("root.specificOptions.hostList");
|
||||||
if (hostList) {
|
if (hostList) {
|
||||||
var val = hostList.getValue();
|
var val = hostList.getValue();
|
||||||
|
var host = conf_editor.getEditor("root.specificOptions.host");
|
||||||
var showOptions = true;
|
var showOptions = true;
|
||||||
|
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case 'CUSTOM':
|
case 'CUSTOM':
|
||||||
case '':
|
case '':
|
||||||
conf_editor.getEditor(specOptPath + "host").enable();
|
host.enable();
|
||||||
conf_editor.getEditor(specOptPath + "host").setValue("");
|
//Populate existing host for current custom config
|
||||||
|
if (ledType === window.serverConfig.device.type) {
|
||||||
|
host.setValue(window.serverConfig.device.host);
|
||||||
|
} else {
|
||||||
|
host.setValue("");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'NONE':
|
case 'NONE':
|
||||||
conf_editor.getEditor(specOptPath + "host").enable();
|
host.enable();
|
||||||
//Trigger getProperties via host value
|
//Trigger getProperties via host value
|
||||||
conf_editor.notifyWatchers(specOptPath + "host");
|
conf_editor.notifyWatchers(specOptPath + "host");
|
||||||
break;
|
break;
|
||||||
case 'SELECT':
|
case 'SELECT':
|
||||||
conf_editor.getEditor(specOptPath + "host").setValue("");
|
host.setValue("");
|
||||||
conf_editor.getEditor(specOptPath + "host").disable();
|
host.disable();
|
||||||
showOptions = false;
|
showOptions = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
conf_editor.getEditor(specOptPath + "host").disable();
|
host.disable();
|
||||||
conf_editor.getEditor(specOptPath + "host").setValue(val);
|
host.setValue(val);
|
||||||
//Trigger getProperties via host value
|
//Trigger getProperties via host value
|
||||||
conf_editor.notifyWatchers(specOptPath + "host");
|
conf_editor.notifyWatchers(specOptPath + "host");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
showAllDeviceInputOptions("hostList", showOptions);
|
showAllDeviceInputOptions("hostList", showOptions);
|
||||||
|
|
||||||
|
if (!host.isEnabled() && host.getValue().endsWith("._tcp.local")) {
|
||||||
|
showInputOptionForItem(conf_editor, 'specificOptions', 'host', false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1749,44 +1766,34 @@ var updateSelectList = function (ledType, discoveryInfo) {
|
|||||||
var name;
|
var name;
|
||||||
var host;
|
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") {
|
if (discoveryMethod === "ssdp") {
|
||||||
host = device.ip;
|
host = device.ip;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
host = device.name;
|
host = device.service;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ledType) {
|
||||||
|
case "nanoleaf":
|
||||||
|
if (discoveryMethod === "ssdp") {
|
||||||
|
name = device.other["nl-devicename"] + " (" + host + ")";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
name = device.name;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (discoveryMethod === "ssdp") {
|
||||||
|
name = device.hostname + " (" + host + ")";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
name = device.name;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
enumVals.push(host);
|
enumVals.push(host);
|
||||||
if (host !== name) {
|
enumTitelVals.push(name);
|
||||||
enumTitelVals.push(name + " (" + host + ")");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
enumTitelVals.push(host);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Always allow to add custom configuration
|
//Always allow to add custom configuration
|
||||||
@ -1794,8 +1801,14 @@ var updateSelectList = function (ledType, discoveryInfo) {
|
|||||||
// Select configured device
|
// Select configured device
|
||||||
var configuredDeviceType = window.serverConfig.device.type;
|
var configuredDeviceType = window.serverConfig.device.type;
|
||||||
var configuredHost = window.serverConfig.device.hostList;
|
var configuredHost = window.serverConfig.device.hostList;
|
||||||
if (ledType === configuredDeviceType && $.inArray(configuredHost, enumVals) != -1) {
|
if (ledType === configuredDeviceType) {
|
||||||
enumDefaultVal = configuredHost;
|
if ($.inArray(configuredHost, enumVals) != -1) {
|
||||||
|
enumDefaultVal = configuredHost;
|
||||||
|
} else if (configuredHost === "CUSTOM") {
|
||||||
|
enumDefaultVal = "CUSTOM";
|
||||||
|
} else {
|
||||||
|
addSelect = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addSelect = true;
|
addSelect = true;
|
||||||
@ -1928,6 +1941,7 @@ async function discover_device(ledType, params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getProperties_device(ledType, key, params) {
|
async function getProperties_device(ledType, key, params) {
|
||||||
|
var disabled = $('#btn_submit_controller').is(':disabled');
|
||||||
// Take care that connfig cannot be saved during background processing
|
// Take care that connfig cannot be saved during background processing
|
||||||
$('#btn_submit_controller').prop('disabled', true);
|
$('#btn_submit_controller').prop('disabled', true);
|
||||||
|
|
||||||
@ -1946,7 +1960,7 @@ async function getProperties_device(ledType, key, params) {
|
|||||||
devicesProperties[ledType][key] = ledDeviceProperties;
|
devicesProperties[ledType][key] = ledDeviceProperties;
|
||||||
|
|
||||||
if (!window.readOnlyMode) {
|
if (!window.readOnlyMode) {
|
||||||
$('#btn_submit_controller').prop('disabled', false);
|
$('#btn_submit_controller').prop('disabled', disabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1961,6 +1975,7 @@ async function getProperties_device(ledType, key, params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function identify_device(type, params) {
|
async function identify_device(type, params) {
|
||||||
|
var disabled = $('#btn_submit_controller').is(':disabled');
|
||||||
// Take care that connfig cannot be saved and identification cannot be retriggerred during background processing
|
// Take care that connfig cannot be saved and identification cannot be retriggerred during background processing
|
||||||
$('#btn_submit_controller').prop('disabled', true);
|
$('#btn_submit_controller').prop('disabled', true);
|
||||||
$('#btn_test_controller').prop('disabled', true);
|
$('#btn_test_controller').prop('disabled', true);
|
||||||
@ -1969,7 +1984,7 @@ async function identify_device(type, params) {
|
|||||||
|
|
||||||
$('#btn_test_controller').prop('disabled', false);
|
$('#btn_test_controller').prop('disabled', false);
|
||||||
if (!window.readOnlyMode) {
|
if (!window.readOnlyMode) {
|
||||||
$('#btn_submit_controller').prop('disabled', false);
|
$('#btn_submit_controller').prop('disabled', disabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1988,12 +2003,18 @@ function updateElements(ledType, key) {
|
|||||||
case "wled":
|
case "wled":
|
||||||
var ledProperties = devicesProperties[ledType][key];
|
var ledProperties = devicesProperties[ledType][key];
|
||||||
|
|
||||||
if (ledProperties && ledProperties.leds && ledProperties.maxLedCount) {
|
if (ledProperties && ledProperties.leds) {
|
||||||
hardwareLedCount = ledProperties.leds.count;
|
hardwareLedCount = ledProperties.leds.count;
|
||||||
var maxLedCount = ledProperties.maxLedCount;
|
if (ledProperties.maxLedCount) {
|
||||||
if (hardwareLedCount > maxLedCount) {
|
var maxLedCount = ledProperties.maxLedCount;
|
||||||
showInfoDialog('warning', $.i18n("conf_leds_config_warning"), $.i18n('conf_leds_error_hwled_gt_maxled', hardwareLedCount, maxLedCount, maxLedCount));
|
if (hardwareLedCount > maxLedCount) {
|
||||||
hardwareLedCount = maxLedCount;
|
showInfoDialog('warning', $.i18n("conf_leds_config_warning"), $.i18n('conf_leds_error_hwled_gt_maxled', hardwareLedCount, maxLedCount, maxLedCount));
|
||||||
|
hardwareLedCount = maxLedCount;
|
||||||
|
conf_editor.getEditor("root.specificOptions.streamProtocol").setValue("RAW");
|
||||||
|
//Workaround, as value seems to getting updated property when a 'getEditor("root.specificOptions").getValue()' is done during save
|
||||||
|
var editor = conf_editor.getEditor("root.specificOptions");
|
||||||
|
editor.value["streamProtocol"] = "RAW";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(hardwareLedCount);
|
conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(hardwareLedCount);
|
||||||
@ -2060,6 +2081,15 @@ function updateElements(ledType, key) {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!conf_editor.validate().length) {
|
||||||
|
if (!window.readOnlyMode) {
|
||||||
|
$('#btn_submit_controller').attr('disabled', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#btn_submit_controller').attr('disabled', true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAllDeviceInputOptions(showForKey, state) {
|
function showAllDeviceInputOptions(showForKey, state) {
|
||||||
@ -2068,6 +2098,6 @@ function showAllDeviceInputOptions(showForKey, state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function disableAutoResolvedGeneralOptions() {
|
function disableAutoResolvedGeneralOptions() {
|
||||||
conf_editor.getEditor("root.generalOptions.hardwareLedCount").disable();
|
conf_editor.getEditor("root.generalOptions.hardwareLedCount").disable();
|
||||||
conf_editor.getEditor("root.generalOptions.colorOrder").disable();
|
conf_editor.getEditor("root.generalOptions.colorOrder").disable();
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
var date = new Date(parseInt(utime));
|
var date = new Date(parseInt(utime));
|
||||||
var subComponent = "";
|
var subComponent = "";
|
||||||
if (window.serverInfo.instance.length > 1) {
|
if (window.serverInfo.instance.length >= 1) {
|
||||||
if (logger_subname.startsWith("I")) {
|
if (logger_subname.startsWith("I")) {
|
||||||
var instanceNum = logger_subname.substring(1);
|
var instanceNum = logger_subname.substring(1);
|
||||||
if (window.serverInfo.instance[instanceNum]) {
|
if (window.serverInfo.instance[instanceNum]) {
|
||||||
|
@ -11,6 +11,9 @@ $(document).ready(function () {
|
|||||||
var conf_editor_fbs = null;
|
var conf_editor_fbs = null;
|
||||||
var conf_editor_forw = null;
|
var conf_editor_forw = null;
|
||||||
|
|
||||||
|
// Service properties , 2-dimensional array of [servicetype][id]
|
||||||
|
discoveredRemoteServices = {};
|
||||||
|
|
||||||
addJsonEditorHostValidation();
|
addJsonEditorHostValidation();
|
||||||
|
|
||||||
if (window.showOptHelp) {
|
if (window.showOptHelp) {
|
||||||
@ -142,10 +145,21 @@ $(document).ready(function () {
|
|||||||
forwarder: window.schema.forwarder
|
forwarder: window.schema.forwarder
|
||||||
}, true, true);
|
}, true, true);
|
||||||
|
|
||||||
|
conf_editor_forw.on('ready', function () {
|
||||||
|
|
||||||
|
updateServiceCacheForwarderConfiguredItems("jsonapi");
|
||||||
|
updateServiceCacheForwarderConfiguredItems("flatbuffer");
|
||||||
|
|
||||||
|
var forwarderEnable = conf_editor_forw.getEditor("root.forwarder.enable").getValue();
|
||||||
|
if (forwarderEnable) {
|
||||||
|
discoverRemoteHyperionServices("jsonapi");
|
||||||
|
discoverRemoteHyperionServices("flatbuffer");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
conf_editor_forw.on('change', function () {
|
conf_editor_forw.on('change', function () {
|
||||||
var forwarderEnable = conf_editor_forw.getEditor("root.forwarder.enable").getValue();
|
var forwarderEnable = conf_editor_forw.getEditor("root.forwarder.enable").getValue();
|
||||||
if (forwarderEnable) {
|
if (forwarderEnable) {
|
||||||
showInputOptionsForKey(conf_editor_forw, "forwarder", "enable", true);
|
|
||||||
$('#forwarderHelpPanelId').show();
|
$('#forwarderHelpPanelId').show();
|
||||||
} else {
|
} else {
|
||||||
showInputOptionsForKey(conf_editor_forw, "forwarder", "enable", false);
|
showInputOptionsForKey(conf_editor_forw, "forwarder", "enable", false);
|
||||||
@ -154,6 +168,23 @@ $(document).ready(function () {
|
|||||||
conf_editor_forw.validate().length || window.readOnlyMode ? $('#btn_submit_forwarder').prop('disabled', true) : $('#btn_submit_forwarder').prop('disabled', false);
|
conf_editor_forw.validate().length || window.readOnlyMode ? $('#btn_submit_forwarder').prop('disabled', true) : $('#btn_submit_forwarder').prop('disabled', false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
conf_editor_forw.watch('root.forwarder.jsonapiselect', () => {
|
||||||
|
updateForwarderServiceSections("jsonapi");
|
||||||
|
});
|
||||||
|
|
||||||
|
conf_editor_forw.watch('root.forwarder.flatbufferselect', () => {
|
||||||
|
updateForwarderServiceSections("flatbuffer");
|
||||||
|
});
|
||||||
|
|
||||||
|
conf_editor_forw.watch('root.forwarder.enable', () => {
|
||||||
|
|
||||||
|
var forwarderEnable = conf_editor_forw.getEditor("root.forwarder.enable").getValue();
|
||||||
|
if (forwarderEnable) {
|
||||||
|
discoverRemoteHyperionServices("jsonapi");
|
||||||
|
discoverRemoteHyperionServices("flatbuffer");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('#btn_submit_forwarder').off().on('click', function () {
|
$('#btn_submit_forwarder').off().on('click', function () {
|
||||||
requestWriteConfig(conf_editor_forw.getValue());
|
requestWriteConfig(conf_editor_forw.getValue());
|
||||||
});
|
});
|
||||||
@ -238,5 +269,143 @@ $(document).ready(function () {
|
|||||||
checkApiTokenState(window.serverConfig.network.apiAuth);
|
checkApiTokenState(window.serverConfig.network.apiAuth);
|
||||||
|
|
||||||
removeOverlay();
|
removeOverlay();
|
||||||
|
|
||||||
|
function updateForwarderServiceSections(type) {
|
||||||
|
|
||||||
|
var editorPath = "root.forwarder." + type
|
||||||
|
var selectedServices = conf_editor_forw.getEditor(editorPath + "select").getValue();
|
||||||
|
|
||||||
|
if (jQuery.isEmptyObject(selectedServices) || selectedServices[0] === "NONE") {
|
||||||
|
conf_editor_forw.getEditor(editorPath).setValue([]);
|
||||||
|
showInputOptionForItem(conf_editor_forw, "forwarder", type, false);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
var newServices = [];
|
||||||
|
for (var i = 0; i < selectedServices.length; ++i) {
|
||||||
|
|
||||||
|
var service = discoveredRemoteServices[type][selectedServices[i]];
|
||||||
|
var newrecord = {};
|
||||||
|
|
||||||
|
newrecord.name = service.name;
|
||||||
|
newrecord.host = service.host;
|
||||||
|
newrecord.port = service.port;
|
||||||
|
|
||||||
|
newServices.push(newrecord);
|
||||||
|
}
|
||||||
|
conf_editor_forw.getEditor(editorPath).setValue(newServices);
|
||||||
|
|
||||||
|
showInputOptionForItem(conf_editor_forw, "forwarder", type, true);
|
||||||
|
conf_editor_forw.getEditor(editorPath).disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateForwarderSelectList(type) {
|
||||||
|
|
||||||
|
var selectionElement = type + "select"
|
||||||
|
|
||||||
|
var enumVals = [];
|
||||||
|
var enumTitelVals = [];
|
||||||
|
var enumDefaultVals = [];
|
||||||
|
|
||||||
|
for (var key in discoveredRemoteServices[type]) {
|
||||||
|
|
||||||
|
var service = discoveredRemoteServices[type][key];
|
||||||
|
enumVals.push(service.host);
|
||||||
|
enumTitelVals.push(service.name);
|
||||||
|
|
||||||
|
if (service.inConfig == true) {
|
||||||
|
enumDefaultVals.push(service.host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let addSchemaElements = {
|
||||||
|
"uniqueItems": true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (jQuery.isEmptyObject(enumVals)) {
|
||||||
|
enumVals.push("NONE");
|
||||||
|
enumTitelVals.push($.i18n('edt_conf_fw_remote_service_discovered_none'));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateJsonEditorMultiSelection(conf_editor_forw, 'root.forwarder', selectionElement, addSchemaElements, enumVals, enumTitelVals, enumDefaultVals);
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateServiceCacheForwarderConfiguredItems(serviceType) {
|
||||||
|
|
||||||
|
var editor = conf_editor_forw.getEditor("root.forwarder." + serviceType);
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
if (!discoveredRemoteServices[serviceType]) {
|
||||||
|
discoveredRemoteServices[serviceType] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
var configuredServices = JSON.parse(JSON.stringify(editor.getValue('items')));
|
||||||
|
for (const service of configuredServices) {
|
||||||
|
|
||||||
|
//Handle not named sceanrios
|
||||||
|
if (!service.name) {
|
||||||
|
service.name = service.host;
|
||||||
|
}
|
||||||
|
|
||||||
|
service.inConfig = true;
|
||||||
|
|
||||||
|
discoveredRemoteServices[serviceType][service.host] = service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRemoteServiceCache(discoveryInfo) {
|
||||||
|
|
||||||
|
for (var serviceType in discoveryInfo) {
|
||||||
|
|
||||||
|
if (!discoveredRemoteServices[serviceType]) {
|
||||||
|
discoveredRemoteServices[serviceType] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
var discoveredServices = discoveryInfo[serviceType];
|
||||||
|
for (const service of discoveredServices) {
|
||||||
|
|
||||||
|
if (!service.sameHost)
|
||||||
|
{
|
||||||
|
//Handle non mDNS sceanrios
|
||||||
|
if (!service.name) {
|
||||||
|
service.name = service.host;
|
||||||
|
} else {
|
||||||
|
service.host = service.service;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (discoveredRemoteServices[serviceType][service.host]) {
|
||||||
|
service.inConfig = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
discoveredRemoteServices[serviceType][service.host] = service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function discoverRemoteHyperionServices(type, params) {
|
||||||
|
|
||||||
|
const result = await requestServiceDiscovery(type, params);
|
||||||
|
|
||||||
|
var discoveryResult;
|
||||||
|
if (result && !result.error) {
|
||||||
|
discoveryResult = result.info;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
discoveryResult = {
|
||||||
|
"services": []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "jsonapi":
|
||||||
|
case "flatbuffer":
|
||||||
|
updateRemoteServiceCache(discoveryResult.services);
|
||||||
|
updateForwarderSelectList(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@ window.loggingStreamActive = false;
|
|||||||
window.loggingHandlerInstalled = false;
|
window.loggingHandlerInstalled = false;
|
||||||
window.watchdog = 0;
|
window.watchdog = 0;
|
||||||
window.debugMessagesActive = true;
|
window.debugMessagesActive = true;
|
||||||
window.wSess = [];
|
|
||||||
window.currentHyperionInstance = 0;
|
window.currentHyperionInstance = 0;
|
||||||
window.currentHyperionInstanceName = "?";
|
window.currentHyperionInstanceName = "?";
|
||||||
window.comps = [];
|
window.comps = [];
|
||||||
@ -136,7 +135,11 @@ function initWebSocket()
|
|||||||
// skip tan -1 error handling
|
// skip tan -1 error handling
|
||||||
if(tan != -1){
|
if(tan != -1){
|
||||||
var error = response.hasOwnProperty("error")? response.error : "unknown";
|
var error = response.hasOwnProperty("error")? response.error : "unknown";
|
||||||
$(window.hyperion).trigger({type:"error",reason:error});
|
if (error == "Service Unavailable") {
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
$(window.hyperion).trigger({type:"error",reason:error});
|
||||||
|
}
|
||||||
console.log("[window.websocket::onmessage] ",error)
|
console.log("[window.websocket::onmessage] ",error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,7 +310,7 @@ function requestInstanceSwitch(inst)
|
|||||||
|
|
||||||
function requestServerInfo()
|
function requestServerInfo()
|
||||||
{
|
{
|
||||||
sendToHyperion("serverinfo","",'"subscribe":["components-update","sessions-update","priorities-update", "imageToLedMapping-update", "adjustment-update", "videomode-update", "effects-update", "settings-update", "instance-update"]');
|
sendToHyperion("serverinfo","",'"subscribe":["components-update", "priorities-update", "imageToLedMapping-update", "adjustment-update", "videomode-update", "effects-update", "settings-update", "instance-update"]');
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestSysInfo()
|
function requestSysInfo()
|
||||||
@ -485,9 +488,21 @@ function requestLedDeviceIdentification(type, params)
|
|||||||
return sendAsyncToHyperion("leddevice", "identify", data, Math.floor(Math.random() * 1000));
|
return sendAsyncToHyperion("leddevice", "identify", data, Math.floor(Math.random() * 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function requestLedDeviceAddAuthorization(type, params) {
|
||||||
|
let data = { ledDeviceType: type, params: params };
|
||||||
|
|
||||||
|
return sendAsyncToHyperion("leddevice", "addAuthorization", data, Math.floor(Math.random() * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
async function requestInputSourcesDiscovery(type, params) {
|
async function requestInputSourcesDiscovery(type, params) {
|
||||||
let data = { sourceType: type, params: params };
|
let data = { sourceType: type, params: params };
|
||||||
|
|
||||||
return sendAsyncToHyperion("inputsource", "discover", data, Math.floor(Math.random() * 1000));
|
return sendAsyncToHyperion("inputsource", "discover", data, Math.floor(Math.random() * 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function requestServiceDiscovery(type, params) {
|
||||||
|
let data = { serviceType: type, params: params };
|
||||||
|
|
||||||
|
return sendAsyncToHyperion("service", "discover", data, Math.floor(Math.random() * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -2,14 +2,14 @@ var availAccess = ['default', 'advanced', 'expert'];
|
|||||||
var storedAccess;
|
var storedAccess;
|
||||||
|
|
||||||
//Change Password
|
//Change Password
|
||||||
function changePassword(){
|
function changePassword() {
|
||||||
showInfoDialog('changePassword', $.i18n('InfoDialog_changePassword_title'));
|
showInfoDialog('changePassword', $.i18n('InfoDialog_changePassword_title'));
|
||||||
|
|
||||||
// fill default pw if default is set
|
// fill default pw if default is set
|
||||||
if(window.defaultPasswordIsSet)
|
if (window.defaultPasswordIsSet)
|
||||||
$('#current-password').val('hyperion')
|
$('#current-password').val('hyperion')
|
||||||
|
|
||||||
$('#id_btn_ok').off().on('click',function() {
|
$('#id_btn_ok').off().on('click', function () {
|
||||||
var oldPw = $('#current-password').val();
|
var oldPw = $('#current-password').val();
|
||||||
var newPw = $('#new-password').val();
|
var newPw = $('#new-password').val();
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ function changePassword(){
|
|||||||
history.pushState({}, "New password");
|
history.pushState({}, "New password");
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#new-password, #current-password').off().on('input',function(e) {
|
$('#new-password, #current-password').off().on('input', function (e) {
|
||||||
($('#current-password').val().length >= 8 && $('#new-password').val().length >= 8) && !window.readOnlyMode ? $('#id_btn_ok').prop('disabled', false) : $('#id_btn_ok').prop('disabled', true);
|
($('#current-password').val().length >= 8 && $('#new-password').val().length >= 8) && !window.readOnlyMode ? $('#id_btn_ok').prop('disabled', false) : $('#id_btn_ok').prop('disabled', true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -44,18 +44,17 @@ $(document).ready(function () {
|
|||||||
$('#btn_setlang').prop("disabled", true);
|
$('#btn_setlang').prop("disabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#btn_setaccess').off().on('click',function() {
|
$('#btn_setaccess').off().on('click', function () {
|
||||||
var newAccess;
|
var newAccess;
|
||||||
showInfoDialog('select', $.i18n('InfoDialog_access_title'), $.i18n('InfoDialog_access_text'));
|
showInfoDialog('select', $.i18n('InfoDialog_access_title'), $.i18n('InfoDialog_access_text'));
|
||||||
|
|
||||||
for (var lcx = 0; lcx<availAccess.length; lcx++)
|
for (var lcx = 0; lcx < availAccess.length; lcx++) {
|
||||||
{
|
$('#id_select').append(createSelOpt(availAccess[lcx], $.i18n('general_access_' + availAccess[lcx])));
|
||||||
$('#id_select').append(createSelOpt(availAccess[lcx], $.i18n('general_access_'+availAccess[lcx])));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#id_select').val(storedAccess);
|
$('#id_select').val(storedAccess);
|
||||||
|
|
||||||
$('#id_select').off().on('change',function() {
|
$('#id_select').off().on('change', function () {
|
||||||
newAccess = $('#id_select').val();
|
newAccess = $('#id_select').val();
|
||||||
if (newAccess == storedAccess)
|
if (newAccess == storedAccess)
|
||||||
$('#id_btn_saveset').prop('disabled', true);
|
$('#id_btn_saveset').prop('disabled', true);
|
||||||
@ -63,7 +62,7 @@ $(document).ready(function () {
|
|||||||
$('#id_btn_saveset').prop('disabled', false);
|
$('#id_btn_saveset').prop('disabled', false);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#id_btn_saveset').off().on('click',function() {
|
$('#id_btn_saveset').off().on('click', function () {
|
||||||
setStorage("accesslevel", newAccess);
|
setStorage("accesslevel", newAccess);
|
||||||
reload();
|
reload();
|
||||||
});
|
});
|
||||||
@ -72,13 +71,13 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// change pw btn
|
// change pw btn
|
||||||
$('#btn_changePassword').off().on('click',function() {
|
$('#btn_changePassword').off().on('click', function () {
|
||||||
changePassword();
|
changePassword();
|
||||||
});
|
});
|
||||||
|
|
||||||
//Lock Ui
|
//Lock Ui
|
||||||
$('#btn_lock_ui').off().on('click',function() {
|
$('#btn_lock_ui').off().on('click', function () {
|
||||||
removeStorage('loginToken', true);
|
removeStorage('loginToken');
|
||||||
location.replace('/');
|
location.replace('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -86,27 +85,5 @@ $(document).ready(function () {
|
|||||||
if (storedAccess != 'expert')
|
if (storedAccess != 'expert')
|
||||||
$('#load_webconfig').toggle(false);
|
$('#load_webconfig').toggle(false);
|
||||||
|
|
||||||
|
|
||||||
// instance switcher
|
|
||||||
$('#btn_instanceswitch').off().on('click',function() {
|
|
||||||
var lsys = window.sysInfo.system.hostName+':'+window.serverConfig.webConfig.port;
|
|
||||||
showInfoDialog('iswitch', $.i18n('InfoDialog_iswitch_title'), $.i18n('InfoDialog_iswitch_text'));
|
|
||||||
|
|
||||||
for (var i = 0; i<window.wSess.length; i++)
|
|
||||||
{
|
|
||||||
if(lsys != window.wSess[i].host+':'+window.wSess[i].port)
|
|
||||||
{
|
|
||||||
var hyperionAddress = window.wSess[i].address;
|
|
||||||
if(hyperionAddress.indexOf(':') > -1 && hyperionAddress.length == 36) hyperionAddress = '['+hyperionAddress+']';
|
|
||||||
hyperionAddress = 'http://'+hyperionAddress+':'+window.wSess[i].port;
|
|
||||||
$('#id_select').append(createSelOpt(hyperionAddress, window.wSess[i].name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#id_btn_saveset').off().on('click',function() {
|
|
||||||
$("#loading_overlay").addClass("overlay");
|
|
||||||
window.location.href = $('#id_select').val();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -14,31 +14,22 @@ function storageComp() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStorage(item, session) {
|
function getStorage(item) {
|
||||||
if (storageComp()) {
|
if (storageComp()) {
|
||||||
if (session === true)
|
return localStorage.getItem(item);
|
||||||
return sessionStorage.getItem(item);
|
|
||||||
else
|
|
||||||
return localStorage.getItem(item);
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setStorage(item, value, session) {
|
function setStorage(item, value) {
|
||||||
if (storageComp()) {
|
if (storageComp()) {
|
||||||
if (session === true)
|
localStorage.setItem(item, value);
|
||||||
sessionStorage.setItem(item, value);
|
|
||||||
else
|
|
||||||
localStorage.setItem(item, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeStorage(item, session) {
|
function removeStorage(item) {
|
||||||
if (storageComp()) {
|
if (storageComp()) {
|
||||||
if (session === true)
|
localStorage.removeItem(item);
|
||||||
sessionStorage.removeItem(item);
|
|
||||||
else
|
|
||||||
localStorage.removeItem(item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,23 +39,6 @@ function debugMessage(msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSessions() {
|
|
||||||
var sess = window.serverInfo.sessions;
|
|
||||||
if (sess && sess.length) {
|
|
||||||
window.wSess = [];
|
|
||||||
for (var i = 0; i < sess.length; i++) {
|
|
||||||
if (sess[i].type == "_http._tcp." || sess[i].type == "_https._tcp." || sess[i].type == "_hyperiond-http._tcp.") {
|
|
||||||
window.wSess.push(sess[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.wSess.length > 1)
|
|
||||||
$('#btn_instanceswitch').toggle(true);
|
|
||||||
else
|
|
||||||
$('#btn_instanceswitch').toggle(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateDuration(d) {
|
function validateDuration(d) {
|
||||||
if (typeof d === "undefined" || d < 0)
|
if (typeof d === "undefined" || d < 0)
|
||||||
return ENDLESS;
|
return ENDLESS;
|
||||||
@ -73,8 +47,8 @@ function validateDuration(d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getHashtag() {
|
function getHashtag() {
|
||||||
if (getStorage('lasthashtag', true) != null)
|
if (getStorage('lasthashtag') != null)
|
||||||
return getStorage('lasthashtag', true);
|
return getStorage('lasthashtag');
|
||||||
else {
|
else {
|
||||||
var tag = document.URL;
|
var tag = document.URL;
|
||||||
tag = tag.substr(tag.indexOf("#") + 1);
|
tag = tag.substr(tag.indexOf("#") + 1);
|
||||||
@ -87,20 +61,20 @@ function getHashtag() {
|
|||||||
function loadContent(event, forceRefresh) {
|
function loadContent(event, forceRefresh) {
|
||||||
var tag;
|
var tag;
|
||||||
|
|
||||||
var lastSelectedInstance = getStorage('lastSelectedInstance', false);
|
var lastSelectedInstance = getStorage('lastSelectedInstance');
|
||||||
|
|
||||||
if (lastSelectedInstance && (lastSelectedInstance != window.currentHyperionInstance)) {
|
if (lastSelectedInstance && (lastSelectedInstance != window.currentHyperionInstance)) {
|
||||||
if (window.serverInfo.instance[lastSelectedInstance] && window.serverInfo.instance[lastSelectedInstance].running) {
|
if (window.serverInfo.instance[lastSelectedInstance] && window.serverInfo.instance[lastSelectedInstance].running) {
|
||||||
instanceSwitch(lastSelectedInstance);
|
instanceSwitch(lastSelectedInstance);
|
||||||
} else {
|
} else {
|
||||||
removeStorage('lastSelectedInstance', false);
|
removeStorage('lastSelectedInstance');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof event != "undefined") {
|
if (typeof event != "undefined") {
|
||||||
tag = event.currentTarget.hash;
|
tag = event.currentTarget.hash;
|
||||||
tag = tag.substr(tag.indexOf("#") + 1);
|
tag = tag.substr(tag.indexOf("#") + 1);
|
||||||
setStorage('lasthashtag', tag, true);
|
setStorage('lasthashtag', tag);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tag = getHashtag();
|
tag = getHashtag();
|
||||||
@ -112,7 +86,7 @@ function loadContent(event, forceRefresh) {
|
|||||||
if (status == "error") {
|
if (status == "error") {
|
||||||
tag = 'dashboard';
|
tag = 'dashboard';
|
||||||
console.log("Could not find page:", prevTag, ", Redirecting to:", tag);
|
console.log("Could not find page:", prevTag, ", Redirecting to:", tag);
|
||||||
setStorage('lasthashtag', tag, true);
|
setStorage('lasthashtag', tag);
|
||||||
|
|
||||||
$("#page-content").load("/content/" + tag + ".html", function (response, status, xhr) {
|
$("#page-content").load("/content/" + tag + ".html", function (response, status, xhr) {
|
||||||
if (status == "error") {
|
if (status == "error") {
|
||||||
@ -215,7 +189,7 @@ function instanceSwitch(inst) {
|
|||||||
requestInstanceSwitch(inst)
|
requestInstanceSwitch(inst)
|
||||||
window.currentHyperionInstance = inst;
|
window.currentHyperionInstance = inst;
|
||||||
window.currentHyperionInstanceName = getInstanceNameByIndex(inst);
|
window.currentHyperionInstanceName = getInstanceNameByIndex(inst);
|
||||||
setStorage('lastSelectedInstance', inst, false)
|
setStorage('lastSelectedInstance', inst)
|
||||||
updateHyperionInstanceListing()
|
updateHyperionInstanceListing()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +306,7 @@ function showInfoDialog(type, header, message) {
|
|||||||
if (type == "select" || type == "iswitch")
|
if (type == "select" || type == "iswitch")
|
||||||
$('#id_body').append('<select id="id_select" class="form-control" style="margin-top:10px;width:auto;"></select>');
|
$('#id_body').append('<select id="id_select" class="form-control" style="margin-top:10px;width:auto;"></select>');
|
||||||
|
|
||||||
if (getStorage("darkMode", false) == "on")
|
if (getStorage("darkMode") == "on")
|
||||||
$('#id_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
$('#id_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
||||||
|
|
||||||
$(type == "renInst" || type == "changePassword" ? "#modal_dialog_rename" : "#modal_dialog").modal({
|
$(type == "renInst" || type == "changePassword" ? "#modal_dialog_rename" : "#modal_dialog").modal({
|
||||||
@ -1246,7 +1220,7 @@ function handleDarkMode() {
|
|||||||
href: "../css/darkMode.css"
|
href: "../css/darkMode.css"
|
||||||
}).appendTo("head");
|
}).appendTo("head");
|
||||||
|
|
||||||
setStorage("darkMode", "on", false);
|
setStorage("darkMode", "on");
|
||||||
$('#btn_darkmode_icon').removeClass('fa fa-moon-o');
|
$('#btn_darkmode_icon').removeClass('fa fa-moon-o');
|
||||||
$('#btn_darkmode_icon').addClass('mdi mdi-white-balance-sunny');
|
$('#btn_darkmode_icon').addClass('mdi mdi-white-balance-sunny');
|
||||||
$('#navbar_brand_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
$('#navbar_brand_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
||||||
@ -1337,7 +1311,16 @@ function isValidIPv6(value) {
|
|||||||
|
|
||||||
function isValidHostname(value) {
|
function isValidHostname(value) {
|
||||||
if (value.match(
|
if (value.match(
|
||||||
'(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9].)+[a-zA-Z]{2,63}$)'
|
'^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[_a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$'
|
||||||
|
))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isValidServicename(value) {
|
||||||
|
if (value.match(
|
||||||
|
'^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9 \-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[_a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$'
|
||||||
))
|
))
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
@ -1349,6 +1332,5 @@ function isValidHostnameOrIP4(value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isValidHostnameOrIP(value) {
|
function isValidHostnameOrIP(value) {
|
||||||
return (isValidHostnameOrIP4(value) || isValidIPv6(value));
|
return (isValidHostnameOrIP4(value) || isValidIPv6(value) || isValidServicename(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ function startWizardRGB() {
|
|||||||
$('#wizp2_body').append('<table class="table borderless" style="width:200px"><tbody><tr><td class="ltd"><label>' + $.i18n('wiz_rgb_qrend') + '</label></td><td class="itd"><select id="wiz_r_select" class="form-control wselect"></select></td></tr><tr><td class="ltd"><label>' + $.i18n('wiz_rgb_qgend') + '</label></td><td class="itd"><select id="wiz_g_select" class="form-control wselect"></select></td></tr></tbody></table>');
|
$('#wizp2_body').append('<table class="table borderless" style="width:200px"><tbody><tr><td class="ltd"><label>' + $.i18n('wiz_rgb_qrend') + '</label></td><td class="itd"><select id="wiz_r_select" class="form-control wselect"></select></td></tr><tr><td class="ltd"><label>' + $.i18n('wiz_rgb_qgend') + '</label></td><td class="itd"><select id="wiz_g_select" class="form-control wselect"></select></td></tr></tbody></table>');
|
||||||
$('#wizp2_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_save"><i class="fa fa-fw fa-save"></i>' + $.i18n('general_btn_save') + '</button><button type="button" class="btn btn-primary" id="btn_wiz_checkok" style="display:none" data-dismiss="modal"><i class="fa fa-fw fa-check"></i>' + $.i18n('general_btn_ok') + '</button><button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
|
$('#wizp2_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_save"><i class="fa fa-fw fa-save"></i>' + $.i18n('general_btn_save') + '</button><button type="button" class="btn btn-primary" id="btn_wiz_checkok" style="display:none" data-dismiss="modal"><i class="fa fa-fw fa-check"></i>' + $.i18n('general_btn_ok') + '</button><button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
|
||||||
|
|
||||||
if (getStorage("darkMode", false) == "on")
|
if (getStorage("darkMode") == "on")
|
||||||
$('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
$('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
||||||
|
|
||||||
//open modal
|
//open modal
|
||||||
@ -454,7 +454,7 @@ function startWizardCC() {
|
|||||||
'<button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>'
|
'<button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (getStorage("darkMode", false) == "on")
|
if (getStorage("darkMode") == "on")
|
||||||
$('#wizard_logo').prop("src", 'img/hyperion/logo_negativ.png');
|
$('#wizard_logo').prop("src", 'img/hyperion/logo_negativ.png');
|
||||||
|
|
||||||
//open modal
|
//open modal
|
||||||
@ -591,6 +591,19 @@ var lightPosRightMiddle = { hmin: 0.85, hmax: 1.0, vmin: 0.25, vmax: 0.75 };
|
|||||||
var lightPosRightBottom = { hmin: 0.85, hmax: 1.0, vmin: 0.5, vmax: 1.0 };
|
var lightPosRightBottom = { hmin: 0.85, hmax: 1.0, vmin: 0.5, vmax: 1.0 };
|
||||||
var lightPosEntire = { hmin: 0.0, hmax: 1.0, vmin: 0.0, vmax: 1.0 };
|
var lightPosEntire = { hmin: 0.0, hmax: 1.0, vmin: 0.0, vmax: 1.0 };
|
||||||
|
|
||||||
|
var lightPosBottomLeft14 = { hmin: 0, hmax: 0.25, vmin: 0.85, vmax: 1.0 };
|
||||||
|
var lightPosBottomLeft12 = { hmin: 0.25, hmax: 0.5, vmin: 0.85, vmax: 1.0 };
|
||||||
|
var lightPosBottomLeft34 = { hmin: 0.5, hmax: 0.75, vmin: 0.85, vmax: 1.0 };
|
||||||
|
var lightPosBottomLeft11 = { hmin: 0.75, hmax: 1, vmin: 0.85, vmax: 1.0 };
|
||||||
|
|
||||||
|
var lightPosBottomLeft112 = { hmin: 0, hmax: 0.5, vmin: 0.85, vmax: 1.0 };
|
||||||
|
var lightPosBottomLeft121 = { hmin: 0.5, hmax: 1, vmin: 0.85, vmax: 1.0 };
|
||||||
|
var lightPosBottomLeftNewMid = { hmin: 0.25, hmax: 0.75, vmin: 0.85, vmax: 1.0 };
|
||||||
|
|
||||||
|
var lightPosTopLeft112 = { hmin: 0, hmax: 0.5, vmin: 0, vmax: 0.15 };
|
||||||
|
var lightPosTopLeft121 = { hmin: 0.5, hmax: 1, vmin: 0, vmax: 0.15 };
|
||||||
|
var lightPosTopLeftNewMid = { hmin: 0.25, hmax: 0.75, vmin: 0, vmax: 0.15 };
|
||||||
|
|
||||||
function assignLightPos(id, pos, name) {
|
function assignLightPos(id, pos, name) {
|
||||||
var i = null;
|
var i = null;
|
||||||
|
|
||||||
@ -622,6 +635,26 @@ function assignLightPos(id, pos, name) {
|
|||||||
i = lightPosRightMiddle;
|
i = lightPosRightMiddle;
|
||||||
else if (pos === "rightbottom")
|
else if (pos === "rightbottom")
|
||||||
i = lightPosRightBottom;
|
i = lightPosRightBottom;
|
||||||
|
else if (pos === "lightPosBottomLeft14")
|
||||||
|
i = lightPosBottomLeft14;
|
||||||
|
else if (pos === "lightPosBottomLeft12")
|
||||||
|
i = lightPosBottomLeft12;
|
||||||
|
else if (pos === "lightPosBottomLeft34")
|
||||||
|
i = lightPosBottomLeft34;
|
||||||
|
else if (pos === "lightPosBottomLeft11")
|
||||||
|
i = lightPosBottomLeft11;
|
||||||
|
else if (pos === "lightPosBottomLeft112")
|
||||||
|
i = lightPosBottomLeft112;
|
||||||
|
else if (pos === "lightPosBottomLeft121")
|
||||||
|
i = lightPosBottomLeft121;
|
||||||
|
else if (pos === "lightPosBottomLeftNewMid")
|
||||||
|
i = lightPosBottomLeftNewMid;
|
||||||
|
else if (pos === "lightPosTopLeft112")
|
||||||
|
i = lightPosTopLeft112;
|
||||||
|
else if (pos === "lightPosTopLeft121")
|
||||||
|
i = lightPosTopLeft121;
|
||||||
|
else if (pos === "lightPosTopLeftNewMid")
|
||||||
|
i = lightPosTopLeftNewMid;
|
||||||
else
|
else
|
||||||
i = lightPosEntire;
|
i = lightPosEntire;
|
||||||
|
|
||||||
@ -653,21 +686,22 @@ function getIdInLights(id) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// External properties properties, 2-dimensional arry of [ledType][key]
|
||||||
|
devicesProperties = {};
|
||||||
|
|
||||||
//****************************
|
//****************************
|
||||||
// Wizard Philips Hue
|
// Wizard Philips Hue
|
||||||
//****************************
|
//****************************
|
||||||
|
|
||||||
var hueIPs = [];
|
var hueIPs = [];
|
||||||
var hueIPsinc = 0;
|
var hueIPsinc = 0;
|
||||||
var lightIDs = null;
|
var hueLights = null;
|
||||||
var groupIDs = null;
|
var hueGroups = null;
|
||||||
var lightLocation = [];
|
var lightLocation = [];
|
||||||
var groupLights = [];
|
var groupLights = [];
|
||||||
var groupLightsLocations = [];
|
var groupLightsLocations = [];
|
||||||
var hueType = "philipshue";
|
var hueType = "philipshue";
|
||||||
|
|
||||||
let hueUrl = new URL('http://dummy');
|
|
||||||
|
|
||||||
function startWizardPhilipsHue(e) {
|
function startWizardPhilipsHue(e) {
|
||||||
if (typeof e.data.type != "undefined") hueType = e.data.type;
|
if (typeof e.data.type != "undefined") hueType = e.data.type;
|
||||||
|
|
||||||
@ -739,7 +773,7 @@ function startWizardPhilipsHue(e) {
|
|||||||
$('#wizp2_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_save" style="display:none"><i class="fa fa-fw fa-save"></i>' + $.i18n('general_btn_save') + '</button><button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
|
$('#wizp2_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_save" style="display:none"><i class="fa fa-fw fa-save"></i>' + $.i18n('general_btn_save') + '</button><button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
|
||||||
$('#wizp3_body').html('<span>' + $.i18n('wiz_hue_press_link') + '</span> <br /><br /><center><span id="connectionTime"></span><br /><i class="fa fa-cog fa-spin" style="font-size:100px"></i></center>');
|
$('#wizp3_body').html('<span>' + $.i18n('wiz_hue_press_link') + '</span> <br /><br /><center><span id="connectionTime"></span><br /><i class="fa fa-cog fa-spin" style="font-size:100px"></i></center>');
|
||||||
|
|
||||||
if (getStorage("darkMode", false) == "on")
|
if (getStorage("darkMode") == "on")
|
||||||
$('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
$('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
||||||
|
|
||||||
//open modal
|
//open modal
|
||||||
@ -762,43 +796,10 @@ function checkHueBridge(cb, hueUser) {
|
|||||||
if (usr == 'config') $('#wiz_hue_discovered').html("");
|
if (usr == 'config') $('#wiz_hue_discovered').html("");
|
||||||
|
|
||||||
if (hueIPs[hueIPsinc]) {
|
if (hueIPs[hueIPsinc]) {
|
||||||
|
|
||||||
hueUrl.hostname = "dummy";
|
|
||||||
var host = hueIPs[hueIPsinc].host;
|
var host = hueIPs[hueIPsinc].host;
|
||||||
|
|
||||||
if (isValidIPv6(host)) {
|
|
||||||
hueUrl.hostname = "[" + host + "]";
|
|
||||||
} else {
|
|
||||||
hueUrl.hostname = host;
|
|
||||||
}
|
|
||||||
|
|
||||||
var port = hueIPs[hueIPsinc].port;
|
var port = hueIPs[hueIPsinc].port;
|
||||||
if (port > 0) {
|
|
||||||
hueUrl.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
hueUrl.pathname = '/api/' + usr;
|
getProperties_hue_bridge(cb, decodeURIComponent(host), port, usr);
|
||||||
$.ajax({
|
|
||||||
url: hueUrl,
|
|
||||||
type: "GET",
|
|
||||||
dataType: "json",
|
|
||||||
timeout: 2500
|
|
||||||
})
|
|
||||||
.done(function (json) {
|
|
||||||
if (json.config) {
|
|
||||||
cb(true, usr);
|
|
||||||
} else {
|
|
||||||
if (json.name && json.bridgeid && json.modelid) {
|
|
||||||
$('#wiz_hue_discovered').html("Bridge: " + json.name + ", Modelid: " + json.modelid + ", API-Version: " + json.apiversion);
|
|
||||||
cb(true);
|
|
||||||
} else {
|
|
||||||
cb(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.fail(function () {
|
|
||||||
cb(false);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,7 +810,6 @@ function checkBridgeResult(reply, usr) {
|
|||||||
$('#host').val(hueIPs[hueIPsinc].host)
|
$('#host').val(hueIPs[hueIPsinc].host)
|
||||||
$('#port').val(hueIPs[hueIPsinc].port)
|
$('#port').val(hueIPs[hueIPsinc].port)
|
||||||
|
|
||||||
//now check hue user on this bridge
|
|
||||||
$('#usrcont').toggle(true);
|
$('#usrcont').toggle(true);
|
||||||
checkHueBridge(checkUserResult, $('#user').val() ? $('#user').val() : "newdeveloper");
|
checkHueBridge(checkUserResult, $('#user').val() ? $('#user').val() : "newdeveloper");
|
||||||
}
|
}
|
||||||
@ -852,28 +852,10 @@ function checkUserResult(reply, usr) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function identHueId(id, off, oState) {
|
|
||||||
if (off !== true) {
|
|
||||||
setTimeout(identHueId, 1500, id, true, oState);
|
|
||||||
var put_data = '{"on":true,"bri":254,"hue":47000,"sat":254}';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var put_data = '{"on":' + oState.on + ',"bri":' + oState.bri + ',"hue":' + oState.hue + ',"sat":' + oState.sat + '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
hueUrl.pathname = '/api/' + $('#user').val() + '/lights/' + id + '/state',
|
|
||||||
$.ajax({
|
|
||||||
url: hueUrl,
|
|
||||||
type: 'PUT',
|
|
||||||
timeout: 2000,
|
|
||||||
data: put_data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function useGroupId(id) {
|
function useGroupId(id) {
|
||||||
$('#groupId').val(id);
|
$('#groupId').val(id);
|
||||||
groupLights = groupIDs[id].lights;
|
groupLights = hueGroups[id].lights;
|
||||||
groupLightsLocations = groupIDs[id].locations;
|
groupLightsLocations = hueGroups[id].locations;
|
||||||
get_hue_lights();
|
get_hue_lights();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,9 +863,6 @@ async function discover_hue_bridges() {
|
|||||||
$('#wiz_hue_ipstate').html($.i18n('edt_dev_spec_devices_discovery_inprogress'));
|
$('#wiz_hue_ipstate').html($.i18n('edt_dev_spec_devices_discovery_inprogress'));
|
||||||
$('#wiz_hue_discovered').html("")
|
$('#wiz_hue_discovered').html("")
|
||||||
const res = await requestLedDeviceDiscovery('philipshue');
|
const res = await requestLedDeviceDiscovery('philipshue');
|
||||||
|
|
||||||
// TODO: error case unhandled
|
|
||||||
// res can be: false (timeout) or res.error (not found)
|
|
||||||
if (res && !res.error) {
|
if (res && !res.error) {
|
||||||
const r = res.info;
|
const r = res.info;
|
||||||
|
|
||||||
@ -896,18 +875,33 @@ async function discover_hue_bridges() {
|
|||||||
hueIPs = [];
|
hueIPs = [];
|
||||||
hueIPsinc = 0;
|
hueIPsinc = 0;
|
||||||
|
|
||||||
|
var discoveryMethod = "ssdp";
|
||||||
|
if (res.info.discoveryMethod) {
|
||||||
|
discoveryMethod = res.info.discoveryMethod;
|
||||||
|
}
|
||||||
|
|
||||||
for (const device of r.devices) {
|
for (const device of r.devices) {
|
||||||
if (device && device.ip && device.port) {
|
if (device) {
|
||||||
var host;
|
var host;
|
||||||
var port;
|
var port;
|
||||||
if (device.hostname && device.domain) {
|
if (discoveryMethod === "ssdp") {
|
||||||
host = device.hostname + "." + device.domain;
|
if (device.hostname && device.domain) {
|
||||||
port = device.port;
|
host = device.hostname + "." + device.domain;
|
||||||
|
port = device.port;
|
||||||
|
} else {
|
||||||
|
host = device.ip;
|
||||||
|
port = device.port;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
host = device.ip;
|
host = device.service;
|
||||||
port = device.port;
|
port = device.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Remap https port to http port until Hue-API v2 is supported
|
||||||
|
if (port == 443) {
|
||||||
|
port = 80;
|
||||||
|
}
|
||||||
|
|
||||||
if (host) {
|
if (host) {
|
||||||
|
|
||||||
if (!hueIPs.some(item => item.host === host)) {
|
if (!hueIPs.some(item => item.host === host)) {
|
||||||
@ -930,65 +924,71 @@ async function discover_hue_bridges() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getProperties_hue_bridge(hostAddress, port, username, resourceFilter) {
|
async function getProperties_hue_bridge(cb, hostAddress, port, username, resourceFilter) {
|
||||||
let params = { host: hostAddress, user: username, filter: resourceFilter };
|
let params = { host: hostAddress, user: username, filter: resourceFilter };
|
||||||
if (port !== 'undefined') {
|
if (port !== 'undefined') {
|
||||||
params.port = port;
|
params.port = parseInt(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await requestLedDeviceProperties('philipshue', params);
|
var ledType = 'philipshue';
|
||||||
|
var key = hostAddress;
|
||||||
|
|
||||||
// TODO: error case unhandled
|
//Create ledType cache entry
|
||||||
// res can be: false (timeout) or res.error (not found)
|
if (!devicesProperties[ledType]) {
|
||||||
if (res && !res.error) {
|
devicesProperties[ledType] = {};
|
||||||
const r = res.info
|
}
|
||||||
|
|
||||||
// Process properties returned
|
// Use device's properties, if properties in chache
|
||||||
console.log(r);
|
if (devicesProperties[ledType][key]) {
|
||||||
|
cb(true, username);
|
||||||
|
} else {
|
||||||
|
const res = await requestLedDeviceProperties(ledType, params);
|
||||||
|
|
||||||
|
|
||||||
|
if (res && !res.error) {
|
||||||
|
var ledDeviceProperties = res.info.properties;
|
||||||
|
if (!jQuery.isEmptyObject(ledDeviceProperties)) {
|
||||||
|
|
||||||
|
if (username === "config") {
|
||||||
|
if (ledDeviceProperties.name && ledDeviceProperties.bridgeid && ledDeviceProperties.modelid) {
|
||||||
|
$('#wiz_hue_discovered').html("Bridge: " + ledDeviceProperties.name + ", Modelid: " + ledDeviceProperties.modelid + ", API-Version: " + ledDeviceProperties.apiversion);
|
||||||
|
cb(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
devicesProperties[ledType][key] = ledDeviceProperties;
|
||||||
|
cb(true, username);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cb(false, username);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cb(false, username);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function identify_hue_device(hostAddress, port, username, id) {
|
async function identify_hue_device(hostAddress, port, username, id) {
|
||||||
|
var disabled = $('#btn_wiz_save').is(':disabled');
|
||||||
// Take care that new record cannot be save during background process
|
// Take care that new record cannot be save during background process
|
||||||
$('#btn_wiz_save').prop('disabled', true);
|
$('#btn_wiz_save').prop('disabled', true);
|
||||||
|
|
||||||
let params = { host: hostAddress, user: username, lightId: id };
|
let params = { host: decodeURIComponent(hostAddress), user: username, lightId: id };
|
||||||
|
|
||||||
if (port !== 'undefined') {
|
if (port !== 'undefined') {
|
||||||
params.port = port;
|
params.port = parseInt(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
await requestLedDeviceIdentification('philipshue', params);
|
await requestLedDeviceIdentification('philipshue', params);
|
||||||
|
|
||||||
if (!window.readOnlyMode) {
|
if (!window.readOnlyMode) {
|
||||||
$('#btn_wiz_save').prop('disabled', false);
|
$('#btn_wiz_save').prop('disabled', disabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHueIPs() {
|
|
||||||
$('#wiz_hue_ipstate').html($.i18n('wiz_hue_searchb'));
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: 'https://discovery.meethue.com',
|
|
||||||
crossDomain: true,
|
|
||||||
type: 'GET',
|
|
||||||
timeout: 3000
|
|
||||||
})
|
|
||||||
.done(function (data, textStatus, jqXHR) {
|
|
||||||
if (data.length == 0) {
|
|
||||||
$('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
|
|
||||||
} else {
|
|
||||||
hueIPs = data;
|
|
||||||
checkHueBridge(checkBridgeResult);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.fail(function (jqXHR, textStatus) {
|
|
||||||
$('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//return editor Value
|
//return editor Value
|
||||||
function eV(vn) {
|
function eV(vn, defaultVal = "") {
|
||||||
return (vn) ? conf_editor.getEditor("root.specificOptions." + vn).getValue() : "";
|
var editor = (vn) ? conf_editor.getEditor("root.specificOptions." + vn) : null;
|
||||||
|
return (editor == null) ? defaultVal : ((defaultVal != "" && !isNaN(defaultVal) && isNaN(editor.getValue())) ? defaultVal : editor.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
function beginWizardHue() {
|
function beginWizardHue() {
|
||||||
@ -1009,7 +1009,6 @@ function beginWizardHue() {
|
|||||||
hueIPs = [];
|
hueIPs = [];
|
||||||
hueIPsinc = 0;
|
hueIPsinc = 0;
|
||||||
|
|
||||||
//getHueIPs();
|
|
||||||
discover_hue_bridges();
|
discover_hue_bridges();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1068,13 +1067,13 @@ function beginWizardHue() {
|
|||||||
var finalLightIds = [];
|
var finalLightIds = [];
|
||||||
|
|
||||||
//create hue led config
|
//create hue led config
|
||||||
for (var key in lightIDs) {
|
for (var key in hueLights) {
|
||||||
if (hueType == 'philipshueentertainment') {
|
if (hueType == 'philipshueentertainment') {
|
||||||
if (groupLights.indexOf(key) == -1) continue;
|
if (groupLights.indexOf(key) == -1) continue;
|
||||||
}
|
}
|
||||||
if ($('#hue_' + key).val() != "disabled") {
|
if ($('#hue_' + key).val() != "disabled") {
|
||||||
finalLightIds.push(key);
|
finalLightIds.push(key);
|
||||||
var idx_content = assignLightPos(key, $('#hue_' + key).val(), lightIDs[key].name);
|
var idx_content = assignLightPos(key, $('#hue_' + key).val(), hueLights[key].name);
|
||||||
hueLedConfig.push(JSON.parse(JSON.stringify(idx_content)));
|
hueLedConfig.push(JSON.parse(JSON.stringify(idx_content)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1100,23 +1099,28 @@ function beginWizardHue() {
|
|||||||
d.type = 'philipshue';
|
d.type = 'philipshue';
|
||||||
d.colorOrder = 'rgb';
|
d.colorOrder = 'rgb';
|
||||||
d.lightIds = finalLightIds;
|
d.lightIds = finalLightIds;
|
||||||
d.transitiontime = parseInt(eV("transitiontime"));
|
d.transitiontime = parseInt(eV("transitiontime", 1));
|
||||||
d.restoreOriginalState = (eV("restoreOriginalState") == true);
|
d.restoreOriginalState = (eV("restoreOriginalState", false) == true);
|
||||||
d.switchOffOnBlack = (eV("switchOffOnBlack") == true);
|
d.switchOffOnBlack = (eV("switchOffOnBlack", false) == true);
|
||||||
d.brightnessFactor = parseFloat(eV("brightnessFactor"));
|
|
||||||
|
d.blackLevel = parseFloat(eV("blackLevel", 0.009));
|
||||||
|
d.onBlackTimeToPowerOff = parseInt(eV("onBlackTimeToPowerOff", 600));
|
||||||
|
d.onBlackTimeToPowerOn = parseInt(eV("onBlackTimeToPowerOn", 300));
|
||||||
|
d.brightnessFactor = parseFloat(eV("brightnessFactor", 1));
|
||||||
|
|
||||||
d.clientkey = $('#clientkey').val();
|
d.clientkey = $('#clientkey').val();
|
||||||
d.groupId = parseInt($('#groupId').val());
|
d.groupId = parseInt($('#groupId').val());
|
||||||
d.blackLightsTimeout = parseInt(eV("blackLightsTimeout"));
|
d.blackLightsTimeout = parseInt(eV("blackLightsTimeout", 5000));
|
||||||
d.brightnessMin = parseFloat(eV("brightnessMin"));
|
d.brightnessMin = parseFloat(eV("brightnessMin", 0));
|
||||||
d.brightnessMax = parseFloat(eV("brightnessMax"));
|
d.brightnessMax = parseFloat(eV("brightnessMax", 1));
|
||||||
d.brightnessThreshold = parseFloat(eV("brightnessThreshold"));
|
d.brightnessThreshold = parseFloat(eV("brightnessThreshold", 0.0001));
|
||||||
d.sslReadTimeout = parseInt(eV("sslReadTimeout"));
|
d.handshakeTimeoutMin = parseInt(eV("handshakeTimeoutMin", 300));
|
||||||
d.sslHSTimeoutMin = parseInt(eV("sslHSTimeoutMin"));
|
d.handshakeTimeoutMax = parseInt(eV("handshakeTimeoutMax", 1000));
|
||||||
d.sslHSTimeoutMax = parseInt(eV("sslHSTimeoutMax"));
|
|
||||||
d.verbose = (eV("verbose") == true);
|
d.verbose = (eV("verbose") == true);
|
||||||
d.debugStreamer = (eV("debugStreamer") == true);
|
|
||||||
d.debugLevel = (eV("debugLevel"));
|
d.autoStart = conf_editor.getEditor("root.generalOptions.autoStart").getValue();
|
||||||
|
d.enableAttempts = parseInt(conf_editor.getEditor("root.generalOptions.enableAttempts").getValue());
|
||||||
|
d.enableAttemptsInterval = parseInt(conf_editor.getEditor("root.generalOptions.enableAttemptsInterval").getValue());
|
||||||
|
|
||||||
if (hueType == 'philipshue') {
|
if (hueType == 'philipshue') {
|
||||||
d.useEntertainmentAPI = false;
|
d.useEntertainmentAPI = false;
|
||||||
@ -1129,7 +1133,6 @@ function beginWizardHue() {
|
|||||||
if (hueType == 'philipshueentertainment') {
|
if (hueType == 'philipshueentertainment') {
|
||||||
d.useEntertainmentAPI = true;
|
d.useEntertainmentAPI = true;
|
||||||
d.hardwareLedCount = groupLights.length;
|
d.hardwareLedCount = groupLights.length;
|
||||||
d.rewriteTime = 20;
|
|
||||||
//smoothing on
|
//smoothing on
|
||||||
sc.smoothing.enable = true;
|
sc.smoothing.enable = true;
|
||||||
}
|
}
|
||||||
@ -1144,83 +1147,92 @@ function beginWizardHue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createHueUser() {
|
function createHueUser() {
|
||||||
var connectionRetries = 30;
|
|
||||||
var data = { "devicetype": "hyperion#" + Date.now() }
|
var host = hueIPs[hueIPsinc].host;
|
||||||
if (hueType == 'philipshueentertainment') {
|
var port = hueIPs[hueIPsinc].port;
|
||||||
data = { "devicetype": "hyperion#" + Date.now(), "generateclientkey": true }
|
|
||||||
|
let params = { host: host };
|
||||||
|
if (port !== 'undefined') {
|
||||||
|
params.port = parseInt(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var retryTime = 30;
|
||||||
|
var retryInterval = 2;
|
||||||
|
|
||||||
var UserInterval = setInterval(function () {
|
var UserInterval = setInterval(function () {
|
||||||
|
|
||||||
hueUrl.pathname = '/api/';
|
$('#wizp1').toggle(false);
|
||||||
$.ajax({
|
$('#wizp2').toggle(false);
|
||||||
type: "POST",
|
$('#wizp3').toggle(true);
|
||||||
url: hueUrl,
|
|
||||||
processData: false,
|
|
||||||
timeout: 1000,
|
|
||||||
contentType: 'application/json',
|
|
||||||
data: JSON.stringify(data)
|
|
||||||
})
|
|
||||||
.done(function (r) {
|
|
||||||
$('#wizp1').toggle(false);
|
|
||||||
$('#wizp2').toggle(false);
|
|
||||||
$('#wizp3').toggle(true);
|
|
||||||
|
|
||||||
connectionRetries--;
|
(async () => {
|
||||||
$("#connectionTime").html(connectionRetries);
|
|
||||||
if (connectionRetries == 0) {
|
retryTime -= retryInterval;
|
||||||
abortConnection(UserInterval);
|
$("#connectionTime").html(retryTime);
|
||||||
}
|
if (retryTime <= 0) {
|
||||||
else {
|
abortConnection(UserInterval);
|
||||||
if (typeof r[0].error != 'undefined') {
|
clearInterval(UserInterval);
|
||||||
console.log(connectionRetries + ": link not pressed");
|
}
|
||||||
}
|
else {
|
||||||
if (typeof r[0].success != 'undefined') {
|
const res = await requestLedDeviceAddAuthorization('philipshue', params);
|
||||||
|
if (res && !res.error) {
|
||||||
|
var response = res.info;
|
||||||
|
|
||||||
|
if (jQuery.isEmptyObject(response)) {
|
||||||
|
debugMessage(retryTime + ": link button not pressed or device not reachable");
|
||||||
|
} else {
|
||||||
$('#wizp1').toggle(false);
|
$('#wizp1').toggle(false);
|
||||||
$('#wizp2').toggle(true);
|
$('#wizp2').toggle(true);
|
||||||
$('#wizp3').toggle(false);
|
$('#wizp3').toggle(false);
|
||||||
if (r[0].success.username != 'undefined') {
|
|
||||||
$('#user').val(r[0].success.username);
|
var username = response.username;
|
||||||
conf_editor.getEditor("root.specificOptions.username").setValue(r[0].success.username);
|
if (username != 'undefined') {
|
||||||
|
$('#user').val(username);
|
||||||
|
conf_editor.getEditor("root.specificOptions.username").setValue(username);
|
||||||
|
conf_editor.getEditor("root.specificOptions.host").setValue(host);
|
||||||
|
conf_editor.getEditor("root.specificOptions.port").setValue(port);
|
||||||
}
|
}
|
||||||
if (hueType == 'philipshueentertainment') {
|
if (hueType == 'philipshueentertainment') {
|
||||||
if (r[0].success.clientkey != 'undefined') {
|
var clientkey = response.clientkey;
|
||||||
$('#clientkey').val(r[0].success.clientkey);
|
if (clientkey != 'undefined') {
|
||||||
conf_editor.getEditor("root.specificOptions.clientkey").setValue(r[0].success.clientkey);
|
$('#clientkey').val(clientkey);
|
||||||
|
conf_editor.getEditor("root.specificOptions.clientkey").setValue(clientkey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkHueBridge(checkUserResult, r[0].success.username);
|
checkHueBridge(checkUserResult, username);
|
||||||
clearInterval(UserInterval);
|
clearInterval(UserInterval);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$('#wizp1').toggle(false);
|
||||||
|
$('#wizp2').toggle(true);
|
||||||
|
$('#wizp3').toggle(false);
|
||||||
|
clearInterval(UserInterval);
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.fail(function (XMLHttpRequest, textStatus, errorThrown) {
|
})();
|
||||||
$('#wizp1').toggle(false);
|
|
||||||
$('#wizp2').toggle(true);
|
}, retryInterval * 1000);
|
||||||
$('#wizp3').toggle(false);
|
|
||||||
clearInterval(UserInterval);
|
|
||||||
})
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_hue_groups() {
|
function get_hue_groups() {
|
||||||
hueUrl.pathname = '/api/' + $("#user").val() + '/groups';
|
|
||||||
$.ajax({
|
var host = hueIPs[hueIPsinc].host;
|
||||||
type: "GET",
|
|
||||||
url: hueUrl,
|
if (devicesProperties['philipshue'][host]) {
|
||||||
processData: false,
|
var ledProperties = devicesProperties['philipshue'][host];
|
||||||
contentType: 'application/json'
|
|
||||||
})
|
if (!jQuery.isEmptyObject(ledProperties)) {
|
||||||
.done(function (r) {
|
hueGroups = ledProperties.groups;
|
||||||
if (Object.keys(r).length > 0) {
|
if (Object.keys(hueGroups).length > 0) {
|
||||||
|
|
||||||
|
$('.lidsb').html("");
|
||||||
$('#wh_topcontainer').toggle(false);
|
$('#wh_topcontainer').toggle(false);
|
||||||
$('#hue_grp_ids_t').toggle(true);
|
$('#hue_grp_ids_t').toggle(true);
|
||||||
|
|
||||||
groupIDs = r;
|
|
||||||
|
|
||||||
var gC = 0;
|
var gC = 0;
|
||||||
for (var groupid in r) {
|
for (var groupid in hueGroups) {
|
||||||
if (r[groupid].type == 'Entertainment') {
|
if (hueGroups[groupid].type == 'Entertainment') {
|
||||||
$('.gidsb').append(createTableRow([groupid + ' (' + r[groupid].name + ')', '<button class="btn btn-sm btn-primary" onClick=useGroupId(' + groupid + ')>' + $.i18n('wiz_hue_e_use_groupid', groupid) + '</button>']));
|
$('.gidsb').append(createTableRow([groupid + ' (' + hueGroups[groupid].name + ')', '<button class="btn btn-sm btn-primary" onClick=useGroupId(' + groupid + ')>' + $.i18n('wiz_hue_e_use_groupid', groupid) + '</button>']));
|
||||||
gC++;
|
gC++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1228,10 +1240,8 @@ function get_hue_groups() {
|
|||||||
noAPISupport('wiz_hue_e_noegrpids');
|
noAPISupport('wiz_hue_e_noegrpids');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
noAPISupport('wiz_hue_e_nogrpids');
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function noAPISupport(txt) {
|
function noAPISupport(txt) {
|
||||||
@ -1247,42 +1257,30 @@ function noAPISupport(txt) {
|
|||||||
get_hue_lights();
|
get_hue_lights();
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_light_state(id) {
|
|
||||||
hueUrl.pathname = '/api/' + $("#user").val() + '/lights/' + id;
|
|
||||||
$.ajax({
|
|
||||||
type: "GET",
|
|
||||||
url: hueUrl,
|
|
||||||
processData: false,
|
|
||||||
contentType: 'application/json'
|
|
||||||
})
|
|
||||||
.done(function (r) {
|
|
||||||
if (Object.keys(r).length > 0) {
|
|
||||||
identHueId(id, false, r['state']);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_hue_lights() {
|
function get_hue_lights() {
|
||||||
hueUrl.pathname = '/api/' + $("#user").val() + '/lights';
|
|
||||||
$.ajax({
|
var host = hueIPs[hueIPsinc].host;
|
||||||
type: "GET",
|
|
||||||
url: hueUrl,
|
if (devicesProperties['philipshue'][host]) {
|
||||||
processData: false,
|
var ledProperties = devicesProperties['philipshue'][host];
|
||||||
contentType: 'application/json'
|
|
||||||
})
|
if (!jQuery.isEmptyObject(ledProperties.lights)) {
|
||||||
.done(function (r) {
|
hueLights = ledProperties.lights;
|
||||||
if (Object.keys(r).length > 0) {
|
if (Object.keys(hueLights).length > 0) {
|
||||||
if (hueType == 'philipshue') {
|
if (hueType == 'philipshue') {
|
||||||
$('#wh_topcontainer').toggle(false);
|
$('#wh_topcontainer').toggle(false);
|
||||||
}
|
}
|
||||||
$('#hue_ids_t, #btn_wiz_save').toggle(true);
|
$('#hue_ids_t, #btn_wiz_save').toggle(true);
|
||||||
lightIDs = r;
|
|
||||||
var lightOptions = [
|
var lightOptions = [
|
||||||
"top", "topleft", "topright",
|
"top", "topleft", "topright",
|
||||||
"bottom", "bottomleft", "bottomright",
|
"bottom", "bottomleft", "bottomright",
|
||||||
"left", "lefttop", "leftmiddle", "leftbottom",
|
"left", "lefttop", "leftmiddle", "leftbottom",
|
||||||
"right", "righttop", "rightmiddle", "rightbottom",
|
"right", "righttop", "rightmiddle", "rightbottom",
|
||||||
"entire"
|
"entire",
|
||||||
|
"lightPosTopLeft112", "lightPosTopLeftNewMid", "lightPosTopLeft121",
|
||||||
|
"lightPosBottomLeft14", "lightPosBottomLeft12", "lightPosBottomLeft34", "lightPosBottomLeft11",
|
||||||
|
"lightPosBottomLeft112", "lightPosBottomLeftNewMid", "lightPosBottomLeft121"
|
||||||
];
|
];
|
||||||
|
|
||||||
if (hueType == 'philipshue') {
|
if (hueType == 'philipshue') {
|
||||||
@ -1291,7 +1289,7 @@ function get_hue_lights() {
|
|||||||
|
|
||||||
$('.lidsb').html("");
|
$('.lidsb').html("");
|
||||||
var pos = "";
|
var pos = "";
|
||||||
for (var lightid in r) {
|
for (var lightid in hueLights) {
|
||||||
if (hueType == 'philipshueentertainment') {
|
if (hueType == 'philipshueentertainment') {
|
||||||
if (groupLights.indexOf(lightid) == -1) continue;
|
if (groupLights.indexOf(lightid) == -1) continue;
|
||||||
|
|
||||||
@ -1323,15 +1321,15 @@ function get_hue_lights() {
|
|||||||
if (pos == val) options += ' selected="selected"';
|
if (pos == val) options += ' selected="selected"';
|
||||||
options += '>' + $.i18n(txt + val) + '</option>';
|
options += '>' + $.i18n(txt + val) + '</option>';
|
||||||
}
|
}
|
||||||
$('.lidsb').append(createTableRow([lightid + ' (' + r[lightid].name + ')', '<select id="hue_' + lightid + '" class="hue_sel_watch form-control">'
|
$('.lidsb').append(createTableRow([lightid + ' (' + hueLights[lightid].name + ')', '<select id="hue_' + lightid + '" class="hue_sel_watch form-control">'
|
||||||
+ options
|
+ options
|
||||||
+ '</select>', '<button class="btn btn-sm btn-primary" onClick=identify_hue_device("' + $("#host").val() + '","' + $("#port").val() + '","' + $("#user").val() + '",' + lightid + ')>' + $.i18n('wiz_hue_blinkblue', lightid) + '</button>']));
|
+ '</select>', '<button class="btn btn-sm btn-primary" onClick=identify_hue_device("' + encodeURIComponent($("#host").val()) + '","' + $('#port').val() + '","' + $("#user").val() + '",' + lightid + ')>' + $.i18n('wiz_hue_blinkblue', lightid) + '</button>']));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hueType != 'philipshueentertainment') {
|
if (hueType != 'philipshueentertainment') {
|
||||||
$('.hue_sel_watch').on("change", function () {
|
$('.hue_sel_watch').on("change", function () {
|
||||||
var cC = 0;
|
var cC = 0;
|
||||||
for (var key in lightIDs) {
|
for (var key in hueLights) {
|
||||||
if ($('#hue_' + key).val() != "disabled") {
|
if ($('#hue_' + key).val() != "disabled") {
|
||||||
cC++;
|
cC++;
|
||||||
}
|
}
|
||||||
@ -1346,7 +1344,8 @@ function get_hue_lights() {
|
|||||||
var txt = '<p style="font-weight:bold;color:red;">' + $.i18n('wiz_hue_noids') + '</p>';
|
var txt = '<p style="font-weight:bold;color:red;">' + $.i18n('wiz_hue_noids') + '</p>';
|
||||||
$('#wizp2_body').append(txt);
|
$('#wizp2_body').append(txt);
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function abortConnection(UserInterval) {
|
function abortConnection(UserInterval) {
|
||||||
@ -1386,7 +1385,7 @@ function startWizardYeelight(e) {
|
|||||||
+ $.i18n('general_btn_save') + '</button><buttowindow.serverConfig.device = d;n type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>'
|
+ $.i18n('general_btn_save') + '</button><buttowindow.serverConfig.device = d;n type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>'
|
||||||
+ $.i18n('general_btn_cancel') + '</button>');
|
+ $.i18n('general_btn_cancel') + '</button>');
|
||||||
|
|
||||||
if (getStorage("darkMode", false) == "on")
|
if (getStorage("darkMode") == "on")
|
||||||
$('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
$('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
||||||
|
|
||||||
//open modal
|
//open modal
|
||||||
@ -1413,19 +1412,15 @@ function beginWizardYeelight() {
|
|||||||
//create yeelight led config
|
//create yeelight led config
|
||||||
for (var key in lights) {
|
for (var key in lights) {
|
||||||
if ($('#yee_' + key).val() !== "disabled") {
|
if ($('#yee_' + key).val() !== "disabled") {
|
||||||
//delete lights[key].model;
|
|
||||||
|
|
||||||
|
var name = lights[key].name;
|
||||||
// Set Name to layout-position, if empty
|
// Set Name to layout-position, if empty
|
||||||
if (lights[key].name === "") {
|
if (name === "") {
|
||||||
lights[key].name = $.i18n('conf_leds_layout_cl_' + $('#yee_' + key).val());
|
name = lights[key].host;
|
||||||
}
|
}
|
||||||
|
|
||||||
finalLights.push(lights[key]);
|
finalLights.push(lights[key]);
|
||||||
|
|
||||||
var name = lights[key].host;
|
|
||||||
if (lights[key].name !== "")
|
|
||||||
name += '_' + lights[key].name;
|
|
||||||
|
|
||||||
var idx_content = assignLightPos(key, $('#yee_' + key).val(), name);
|
var idx_content = assignLightPos(key, $('#yee_' + key).val(), name);
|
||||||
yeelightLedConfig.push(JSON.parse(JSON.stringify(idx_content)));
|
yeelightLedConfig.push(JSON.parse(JSON.stringify(idx_content)));
|
||||||
}
|
}
|
||||||
@ -1460,7 +1455,8 @@ function beginWizardYeelight() {
|
|||||||
window.serverConfig.device = d;
|
window.serverConfig.device = d;
|
||||||
|
|
||||||
//smoothing off
|
//smoothing off
|
||||||
window.serverConfig.smoothing.enable = false;
|
if (!(window.serverConfig.smoothing == null))
|
||||||
|
window.serverConfig.smoothing.enable = false;
|
||||||
|
|
||||||
requestWriteConfig(window.serverConfig, true);
|
requestWriteConfig(window.serverConfig, true);
|
||||||
resetWizard();
|
resetWizard();
|
||||||
@ -1479,24 +1475,31 @@ async function discover_yeelight_lights() {
|
|||||||
if (res && !res.error) {
|
if (res && !res.error) {
|
||||||
const r = res.info;
|
const r = res.info;
|
||||||
|
|
||||||
|
var discoveryMethod = "ssdp";
|
||||||
|
if (res.info.discoveryMethod) {
|
||||||
|
discoveryMethod = res.info.discoveryMethod;
|
||||||
|
}
|
||||||
|
|
||||||
// Process devices returned by discovery
|
// Process devices returned by discovery
|
||||||
for (const device of r.devices) {
|
for (const device of r.devices) {
|
||||||
if (device.hostname !== "") {
|
if (device.hostname !== "") {
|
||||||
if (getHostInLights(device.hostname).length === 0) {
|
if (getHostInLights(device.hostname).length === 0) {
|
||||||
var light = {};
|
var light = {};
|
||||||
|
|
||||||
light.host = device.hostname;
|
|
||||||
|
|
||||||
//Create a valid hostname
|
|
||||||
if (device.domain)
|
if (discoveryMethod === "ssdp") {
|
||||||
{
|
//Create a valid hostname
|
||||||
light.host += '.' + device.domain;
|
if (device.domain) {
|
||||||
|
light.host += '.' + device.domain;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
light.host = device.service;
|
||||||
|
light.name = device.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
light.port = device.port;
|
light.port = device.port;
|
||||||
|
|
||||||
if (device.txt) {
|
if (device.txt) {
|
||||||
light.name = device.name;
|
|
||||||
light.model = device.txt.md;
|
light.model = device.txt.md;
|
||||||
//Yeelight does not provide correct API port with mDNS response, use default one
|
//Yeelight does not provide correct API port with mDNS response, use default one
|
||||||
light.port = 55443;
|
light.port = 55443;
|
||||||
@ -1547,7 +1550,10 @@ function assign_yeelight_lights() {
|
|||||||
"bottom", "bottomleft", "bottomright",
|
"bottom", "bottomleft", "bottomright",
|
||||||
"left", "lefttop", "leftmiddle", "leftbottom",
|
"left", "lefttop", "leftmiddle", "leftbottom",
|
||||||
"right", "righttop", "rightmiddle", "rightbottom",
|
"right", "righttop", "rightmiddle", "rightbottom",
|
||||||
"entire"
|
"entire",
|
||||||
|
"lightPosTopLeft112", "lightPosTopLeftNewMid", "lightPosTopLeft121",
|
||||||
|
"lightPosBottomLeft14", "lightPosBottomLeft12", "lightPosBottomLeft34", "lightPosBottomLeft11",
|
||||||
|
"lightPosBottomLeft112", "lightPosBottomLeftNewMid", "lightPosBottomLeft121"
|
||||||
];
|
];
|
||||||
|
|
||||||
lightOptions.unshift("disabled");
|
lightOptions.unshift("disabled");
|
||||||
@ -1561,7 +1567,7 @@ function assign_yeelight_lights() {
|
|||||||
var lightName = lights[lightid].name;
|
var lightName = lights[lightid].name;
|
||||||
|
|
||||||
if (lightName === "")
|
if (lightName === "")
|
||||||
lightName = $.i18n('edt_dev_spec_lights_itemtitle');
|
lightName = $.i18n('edt_dev_spec_lights_itemtitle') + '(' + lightHostname + ')';
|
||||||
|
|
||||||
var options = "";
|
var options = "";
|
||||||
for (var opt in lightOptions) {
|
for (var opt in lightOptions) {
|
||||||
@ -1578,10 +1584,10 @@ function assign_yeelight_lights() {
|
|||||||
options = '<option value=disabled>' + $.i18n('wiz_yeelight_unsupported') + '</option>';
|
options = '<option value=disabled>' + $.i18n('wiz_yeelight_unsupported') + '</option>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.lidsb').append(createTableRow([(parseInt(lightid, 10) + 1) + '. ' + lightName + '<br>(' + lightHostname + ')', '<select id="yee_' + lightid + '" ' + enabled + ' class="yee_sel_watch form-control">'
|
$('.lidsb').append(createTableRow([(parseInt(lightid, 10) + 1) + '. ' + lightName, '<select id="yee_' + lightid + '" ' + enabled + ' class="yee_sel_watch form-control">'
|
||||||
+ options
|
+ options
|
||||||
+ '</select>', '<button class="btn btn-sm btn-primary" onClick=identify_yeelight_device("' + lightHostname + '",' + lightPort + ')>'
|
+ '</select>', '<button class="btn btn-sm btn-primary" onClick=identify_yeelight_device("' + lightHostname + '",' + lightPort + ')>'
|
||||||
+ $.i18n('wiz_identify_light', lightName) + '</button>']));
|
+ $.i18n('wiz_identify') + '</button>']));
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.yee_sel_watch').on("change", function () {
|
$('.yee_sel_watch').on("change", function () {
|
||||||
@ -1605,8 +1611,8 @@ function assign_yeelight_lights() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getProperties_yeelight(hostname, port) {
|
async function getProperties_yeelight(host, port) {
|
||||||
let params = { hostname: hostname, port: port };
|
let params = { host: host, port: port };
|
||||||
|
|
||||||
const res = await requestLedDeviceProperties('yeelight', params);
|
const res = await requestLedDeviceProperties('yeelight', params);
|
||||||
|
|
||||||
@ -1614,21 +1620,22 @@ async function getProperties_yeelight(hostname, port) {
|
|||||||
// res can be: false (timeout) or res.error (not found)
|
// res can be: false (timeout) or res.error (not found)
|
||||||
if (res && !res.error) {
|
if (res && !res.error) {
|
||||||
const r = res.info
|
const r = res.info
|
||||||
|
console.log("Yeelight properties: ", r);
|
||||||
// Process properties returned
|
|
||||||
console.log(r);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function identify_yeelight_device(hostname, port) {
|
async function identify_yeelight_device(host, port) {
|
||||||
|
|
||||||
|
var disabled = $('#btn_wiz_save').is(':disabled');
|
||||||
|
|
||||||
// Take care that new record cannot be save during background process
|
// Take care that new record cannot be save during background process
|
||||||
$('#btn_wiz_save').prop('disabled', true);
|
$('#btn_wiz_save').prop('disabled', true);
|
||||||
|
|
||||||
let params = { hostname: hostname, port: port };
|
let params = { host: host, port: port };
|
||||||
await requestLedDeviceIdentification("yeelight", params);
|
await requestLedDeviceIdentification("yeelight", params);
|
||||||
|
|
||||||
if (!window.readOnlyMode) {
|
if (!window.readOnlyMode) {
|
||||||
$('#btn_wiz_save').prop('disabled', false);
|
$('#btn_wiz_save').prop('disabled', disabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1661,7 +1668,7 @@ function startWizardAtmoOrb(e) {
|
|||||||
+ $.i18n('general_btn_save') + '</button><buttowindow.serverConfig.device = d;n type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>'
|
+ $.i18n('general_btn_save') + '</button><buttowindow.serverConfig.device = d;n type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>'
|
||||||
+ $.i18n('general_btn_cancel') + '</button>');
|
+ $.i18n('general_btn_cancel') + '</button>');
|
||||||
|
|
||||||
if (getStorage("darkMode", false) == "on")
|
if (getStorage("darkMode") == "on")
|
||||||
$('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
$('#wizard_logo').attr("src", 'img/hyperion/logo_negativ.png');
|
||||||
|
|
||||||
//open modal
|
//open modal
|
||||||
@ -1802,7 +1809,10 @@ function assign_atmoorb_lights() {
|
|||||||
"bottom", "bottomleft", "bottomright",
|
"bottom", "bottomleft", "bottomright",
|
||||||
"left", "lefttop", "leftmiddle", "leftbottom",
|
"left", "lefttop", "leftmiddle", "leftbottom",
|
||||||
"right", "righttop", "rightmiddle", "rightbottom",
|
"right", "righttop", "rightmiddle", "rightbottom",
|
||||||
"entire"
|
"entire",
|
||||||
|
"lightPosTopLeft112", "lightPosTopLeftNewMid", "lightPosTopLeft121",
|
||||||
|
"lightPosBottomLeft14", "lightPosBottomLeft12", "lightPosBottomLeft34", "lightPosBottomLeft11",
|
||||||
|
"lightPosBottomLeft112", "lightPosBottomLeftNewMid", "lightPosBottomLeft121"
|
||||||
];
|
];
|
||||||
|
|
||||||
lightOptions.unshift("disabled");
|
lightOptions.unshift("disabled");
|
||||||
@ -1865,6 +1875,8 @@ function assign_atmoorb_lights() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function identify_atmoorb_device(orbId) {
|
async function identify_atmoorb_device(orbId) {
|
||||||
|
var disabled = $('#btn_wiz_save').is(':disabled');
|
||||||
|
|
||||||
// Take care that new record cannot be save during background process
|
// Take care that new record cannot be save during background process
|
||||||
$('#btn_wiz_save').prop('disabled', true);
|
$('#btn_wiz_save').prop('disabled', true);
|
||||||
|
|
||||||
@ -1872,6 +1884,7 @@ async function identify_atmoorb_device(orbId) {
|
|||||||
await requestLedDeviceIdentification("atmoorb", params);
|
await requestLedDeviceIdentification("atmoorb", params);
|
||||||
|
|
||||||
if (!window.readOnlyMode) {
|
if (!window.readOnlyMode) {
|
||||||
$('#btn_wiz_save').prop('disabled', false);
|
$('#btn_wiz_save').prop('disabled', disabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ macro(DeployMacOS TARGET)
|
|||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
)
|
)
|
||||||
|
|
||||||
install(CODE "set(TARGET_FILE \"${TARGET_FILE}\") \n set(TARGET_BUNDLE_NAME \"${TARGET}.app\") \n set(PLUGIN_DIR \"${QT_PLUGIN_DIR}\")" COMPONENT "Hyperion")
|
install(CODE "set(TARGET_FILE \"${TARGET_FILE}\") \n set(TARGET_BUNDLE_NAME \"${TARGET}.app\") \n set(PLUGIN_DIR \"${QT_PLUGIN_DIR}\") \n set(BUILD_DIR \"${CMAKE_BINARY_DIR}\")" COMPONENT "Hyperion")
|
||||||
install(CODE [[
|
install(CODE [[
|
||||||
file(GET_RUNTIME_DEPENDENCIES
|
file(GET_RUNTIME_DEPENDENCIES
|
||||||
EXECUTABLES ${TARGET_FILE}
|
EXECUTABLES ${TARGET_FILE}
|
||||||
@ -176,7 +176,7 @@ macro(DeployLinux TARGET)
|
|||||||
COMMAND ${QT_QMAKE_EXECUTABLE} -query QT_INSTALL_PLUGINS
|
COMMAND ${QT_QMAKE_EXECUTABLE} -query QT_INSTALL_PLUGINS
|
||||||
OUTPUT_VARIABLE QT_PLUGINS_DIR
|
OUTPUT_VARIABLE QT_PLUGINS_DIR
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Copy Qt plugins to 'share/hyperion/lib'
|
# Copy Qt plugins to 'share/hyperion/lib'
|
||||||
@ -258,7 +258,7 @@ macro(DeployLinux TARGET)
|
|||||||
PATTERN "sitecustomize.py" EXCLUDE # site-specific configs
|
PATTERN "sitecustomize.py" EXCLUDE # site-specific configs
|
||||||
)
|
)
|
||||||
endif(PYTHON_MODULES_DIR)
|
endif(PYTHON_MODULES_DIR)
|
||||||
endif(ENABLE_EFFECTENGINE)
|
endif(ENABLE_EFFECTENGINE)
|
||||||
|
|
||||||
else()
|
else()
|
||||||
# Run CMake after target was built to run get_prerequisites on ${TARGET_FILE}
|
# Run CMake after target was built to run get_prerequisites on ${TARGET_FILE}
|
||||||
|
22
cmake/Findqmdnsengine.cmake
Normal file
22
cmake/Findqmdnsengine.cmake
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# QMDNSENGINE_FOUND
|
||||||
|
# QMDNS_INCLUDE_DIR
|
||||||
|
# QMDNS_LIBRARIES
|
||||||
|
|
||||||
|
find_path(QMDNS_INCLUDE_DIR
|
||||||
|
NAMES qmdnsengine/mdns.h
|
||||||
|
PATH_SUFFIXES include
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(QMDNS_LIBRARIES
|
||||||
|
NAMES libqmdnsengine.a
|
||||||
|
PATHS /usr/local /usr
|
||||||
|
PATH_SUFFIXES lib64 lib
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(qmdnsengine
|
||||||
|
FOUND_VAR QMDNSENGINE_FOUND
|
||||||
|
REQUIRED_VARS QMDNS_INCLUDE_DIR QMDNS_LIBRARIES
|
||||||
|
)
|
||||||
|
|
||||||
|
mark_as_advanced(QMDNS_INCLUDE_DIR QMDNS_LIBRARIES)
|
@ -20,7 +20,9 @@
|
|||||||
"output" : "/dev/null",
|
"output" : "/dev/null",
|
||||||
"colorOrder" : "rgb",
|
"colorOrder" : "rgb",
|
||||||
"latchTime" : 0,
|
"latchTime" : 0,
|
||||||
"rewriteTime": 0
|
"rewriteTime": 0,
|
||||||
|
"enableAttempts": 6,
|
||||||
|
"enableAttemptsInterval": 15
|
||||||
},
|
},
|
||||||
|
|
||||||
"color" :
|
"color" :
|
||||||
@ -139,9 +141,9 @@
|
|||||||
|
|
||||||
"forwarder" :
|
"forwarder" :
|
||||||
{
|
{
|
||||||
"enable" : false,
|
"enable" : false,
|
||||||
"json" : [],
|
"jsonapi" : [],
|
||||||
"flat" : []
|
"flatbuffer" : []
|
||||||
},
|
},
|
||||||
|
|
||||||
"jsonServer" :
|
"jsonServer" :
|
||||||
|
26
dependencies/CMakeLists-qmdnsengine.txt.in
vendored
Normal file
26
dependencies/CMakeLists-qmdnsengine.txt.in
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
|
|
||||||
|
project(qmdnsengine)
|
||||||
|
|
||||||
|
set(WORK_DIR "@QMDNS_WORK_DIR@")
|
||||||
|
set(SOURCE_DIR "@QMDNS_SOURCE_DIR@")
|
||||||
|
set(INSTALL_DIR "@QMDNS_INSTALL_DIR@")
|
||||||
|
set(CMAKE_ARGS "@QMDNS_CMAKE_ARGS@")
|
||||||
|
set(QMDNS_LOGGING "@QMDNS_LOGGING@")
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
|
||||||
|
ExternalProject_Add(qmdnsengine
|
||||||
|
PREFIX ${WORK_DIR}
|
||||||
|
BUILD_ALWAYS OFF
|
||||||
|
DOWNLOAD_COMMAND ""
|
||||||
|
SOURCE_DIR ${SOURCE_DIR}
|
||||||
|
INSTALL_DIR ${INSTALL_DIR}
|
||||||
|
CMAKE_ARGS ${CMAKE_ARGS}
|
||||||
|
LOG_DOWNLOAD ${QMDNS_LOGGING}
|
||||||
|
LOG_UPDATE ${QMDNS_LOGGING}
|
||||||
|
LOG_CONFIGURE ${QMDNS_LOGGING}
|
||||||
|
LOG_BUILD ${QMDNS_LOGGING}
|
||||||
|
LOG_INSTALL ${QMDNS_LOGGING}
|
||||||
|
LOG_TEST ${QMDNS_LOGGING}
|
||||||
|
)
|
96
dependencies/CMakeLists.txt
vendored
96
dependencies/CMakeLists.txt
vendored
@ -14,6 +14,58 @@ if(ENABLE_DEV_WS281XPWM)
|
|||||||
external/rpi_ws281x/rpihw.c)
|
external/rpi_ws281x/rpihw.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# QMdnsEngine
|
||||||
|
#=============================================================================
|
||||||
|
|
||||||
|
if (ENABLE_MDNS)
|
||||||
|
set(USE_SYSTEM_QMDNS_LIBS ${DEFAULT_USE_SYSTEM_QMDNS_LIBS} CACHE BOOL "use qmdnsengine library from system")
|
||||||
|
|
||||||
|
if (USE_SYSTEM_QMDNS_LIBS)
|
||||||
|
find_package(qmdnsengine REQUIRED)
|
||||||
|
else ()
|
||||||
|
if (NOT DEFINED BUILD_QMDNS_ONCE)
|
||||||
|
set(BUILD_QMDNS_ONCE CACHE INTERNAL "Done")
|
||||||
|
set(QMDNS_WORK_DIR "${CMAKE_BINARY_DIR}/dependencies/external/qmdnsengine")
|
||||||
|
set(QMDNS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/qmdnsengine")
|
||||||
|
set(QMDNS_INSTALL_DIR ${CMAKE_BINARY_DIR})
|
||||||
|
set(QMDNS_CMAKE_ARGS
|
||||||
|
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||||
|
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}
|
||||||
|
-DBIN_INSTALL_DIR:STRING=lib
|
||||||
|
-DLIB_INSTALL_DIR:STRING=lib
|
||||||
|
-DINCLUDE_INSTALL_DIR:STRING=include
|
||||||
|
-DCMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH}
|
||||||
|
-Wno-dev
|
||||||
|
)
|
||||||
|
|
||||||
|
if(${CMAKE_BUILD_TYPE} AND ${CMAKE_BUILD_TYPE} EQUAL "Debug")
|
||||||
|
set(QMDNS_LOGGING 1)
|
||||||
|
else ()
|
||||||
|
set(QMDNS_LOGGING 0)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
configure_file(${CMAKE_SOURCE_DIR}/dependencies/CMakeLists-qmdnsengine.txt.in ${QMDNS_WORK_DIR}/CMakeLists.txt @ONLY)
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${QMDNS_WORK_DIR})
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} --build . --config "${CMAKE_BUILD_TYPE}" WORKING_DIRECTORY ${QMDNS_WORK_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(QMDNS_INCLUDE_DIR "${CMAKE_BINARY_DIR}/include")
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(QMDNS_LIBRARIES ${CMAKE_BINARY_DIR}/lib/qmdnsengine${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||||
|
else()
|
||||||
|
set(QMDNS_LIBRARIES ${CMAKE_BINARY_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}qmdnsengine${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
mark_as_advanced (QMDNS_INCLUDE_DIR QMDNS_LIBRARIES)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
set(QMDNS_INCLUDE_DIR ${QMDNS_INCLUDE_DIR} PARENT_SCOPE)
|
||||||
|
set(QMDNS_LIBRARIES ${QMDNS_LIBRARIES} PARENT_SCOPE)
|
||||||
|
include_directories(${QMDNS_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
# FLATBUFFER
|
# FLATBUFFER
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
@ -50,12 +102,16 @@ if(ENABLE_FLATBUF_SERVER OR ENABLE_FLATBUF_CONNECT)
|
|||||||
set ( FLATBUFFERS_FLATC_EXECUTABLE "${CMAKE_BINARY_DIR}/../build-x86x64/bin/flatc")
|
set ( FLATBUFFERS_FLATC_EXECUTABLE "${CMAKE_BINARY_DIR}/../build-x86x64/bin/flatc")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FLATBUFFERS_FLATC_EXECUTABLE ${FLATBUFFERS_FLATC_EXECUTABLE} PARENT_SCOPE)
|
set(FLATBUFFERS_FLATC_EXECUTABLE ${FLATBUFFERS_FLATC_EXECUTABLE} PARENT_SCOPE)
|
||||||
set(FLATBUFFERS_INCLUDE_DIRS ${FLATBUFFERS_INCLUDE_DIRS} PARENT_SCOPE)
|
set(FLATBUFFERS_INCLUDE_DIRS ${FLATBUFFERS_INCLUDE_DIRS} PARENT_SCOPE)
|
||||||
include_directories(${FLATBUFFERS_INCLUDE_DIRS})
|
include_directories(${FLATBUFFERS_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
if (FLATBUFFERS_INCLUDE_DIRS AND EXISTS "${FLATBUFFERS_INCLUDE_DIRS}/../package.json")
|
||||||
# message(STATUS "Using flatbuffers compiler: " ${FLATBUFFERS_FLATC_EXECUTABLE})
|
file(STRINGS "${FLATBUFFERS_INCLUDE_DIRS}/../package.json" _FLATBUFFERS_VERSION_STRING REGEX "^[ \t\r\n]+\"version\":[ \t\r\n]+\"[0-9]+.[0-9]+.[0-9]+\",")
|
||||||
|
string(REGEX REPLACE "^[ \t\r\n]+\"version\":[ \t\r\n]+\"([0-9]+.[0-9]+.[0-9]+)\"," "\\1" FLATBUFFERS_PARSE_VERSION "${_FLATBUFFERS_VERSION_STRING}")
|
||||||
|
message(STATUS "Flatbuffers version used: ${FLATBUFFERS_PARSE_VERSION}")
|
||||||
|
endif ()
|
||||||
|
|
||||||
function(compile_flattbuffer_schema SRC_FBS OUTPUT_DIR)
|
function(compile_flattbuffer_schema SRC_FBS OUTPUT_DIR)
|
||||||
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
|
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
|
||||||
@ -76,11 +132,15 @@ endif()
|
|||||||
#=============================================================================
|
#=============================================================================
|
||||||
|
|
||||||
if(ENABLE_PROTOBUF_SERVER)
|
if(ENABLE_PROTOBUF_SERVER)
|
||||||
|
|
||||||
set(USE_SYSTEM_PROTO_LIBS ${DEFAULT_USE_SYSTEM_PROTO_LIBS} CACHE BOOL "use protobuf library from system")
|
set(USE_SYSTEM_PROTO_LIBS ${DEFAULT_USE_SYSTEM_PROTO_LIBS} CACHE BOOL "use protobuf library from system")
|
||||||
|
|
||||||
if (USE_SYSTEM_PROTO_LIBS)
|
if (USE_SYSTEM_PROTO_LIBS)
|
||||||
find_package(Protobuf REQUIRED)
|
find_package(Protobuf REQUIRED)
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER 3.5.2)
|
||||||
|
set(PROTOBUF_INCLUDE_DIRS ${Protobuf_INCLUDE_DIRS})
|
||||||
|
set(PROTOBUF_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE})
|
||||||
|
set(PROTOBUF_LIBRARIES ${Protobuf_LIBRARIES})
|
||||||
|
endif()
|
||||||
else ()
|
else ()
|
||||||
set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf with tests")
|
set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf with tests")
|
||||||
set(protobuf_BUILD_SHARED_LIBS OFF CACHE BOOL "Build protobuf shared")
|
set(protobuf_BUILD_SHARED_LIBS OFF CACHE BOOL "Build protobuf shared")
|
||||||
@ -90,26 +150,24 @@ if(ENABLE_PROTOBUF_SERVER)
|
|||||||
set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "Build protobuf static")
|
set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "Build protobuf static")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(external/protobuf/cmake)
|
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/external/protobuf/cmake")
|
||||||
|
|
||||||
if(CMAKE_CROSSCOMPILING)
|
# define the include for the protobuf library
|
||||||
# when crosscompiling import the protoc executable targets from a file generated by a native build
|
|
||||||
option(IMPORT_PROTOC "Protoc export file (protoc_export.cmake) from a native build" "IMPORT_PROTOC-FILE_NOT_FOUND")
|
|
||||||
include(${IMPORT_PROTOC})
|
|
||||||
else()
|
|
||||||
# export the protoc compiler so it can be used when cross compiling
|
|
||||||
export(TARGETS protoc FILE "${CMAKE_BINARY_DIR}/protoc_export.cmake")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# define the include for the protobuf library at the parent scope
|
|
||||||
set(PROTOBUF_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/external/protobuf/src")
|
set(PROTOBUF_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/external/protobuf/src")
|
||||||
|
|
||||||
# define the protoc executable at the parent scope
|
# define the protoc executable
|
||||||
set(PROTOBUF_PROTOC_EXECUTABLE "$<TARGET_FILE:protoc>")
|
set(PROTOBUF_PROTOC_EXECUTABLE protobuf::protoc)
|
||||||
|
|
||||||
|
# define the protobuf library
|
||||||
|
set(PROTOBUF_LIBRARIES protobuf::libprotobuf)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(PROTOBUF_PROTOC_EXECUTABLE ${PROTOBUF_PROTOC_EXECUTABLE} PARENT_SCOPE)
|
# redefine at parent scope
|
||||||
set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS} PARENT_SCOPE)
|
set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS} PARENT_SCOPE)
|
||||||
|
set(PROTOBUF_PROTOC_EXECUTABLE ${PROTOBUF_PROTOC_EXECUTABLE} PARENT_SCOPE)
|
||||||
|
set(PROTOBUF_LIBRARIES ${PROTOBUF_LIBRARIES} PARENT_SCOPE)
|
||||||
|
|
||||||
|
# include headers
|
||||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||||
|
|
||||||
# message(STATUS "Using protobuf compiler: " ${PROTOBUF_PROTOC_EXECUTABLE})
|
# message(STATUS "Using protobuf compiler: " ${PROTOBUF_PROTOC_EXECUTABLE})
|
||||||
@ -210,6 +268,7 @@ if(ENABLE_DEV_NETWORK)
|
|||||||
endif (USE_SYSTEM_MBEDTLS_LIBS)
|
endif (USE_SYSTEM_MBEDTLS_LIBS)
|
||||||
|
|
||||||
if (NOT USE_SYSTEM_MBEDTLS_LIBS)
|
if (NOT USE_SYSTEM_MBEDTLS_LIBS)
|
||||||
|
cmake_minimum_required(VERSION 3.2)
|
||||||
set(DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF CACHE BOOL "system mbedtls libraries not found, disable use system mbedtls libraries")
|
set(DEFAULT_USE_SYSTEM_MBEDTLS_LIBS OFF CACHE BOOL "system mbedtls libraries not found, disable use system mbedtls libraries")
|
||||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared mbedtls libraries")
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared mbedtls libraries")
|
||||||
|
|
||||||
@ -219,7 +278,7 @@ if(ENABLE_DEV_NETWORK)
|
|||||||
set(USE_STATIC_MBEDTLS_LIBRARY ON CACHE BOOL "Enable mbedTLS static libraries")
|
set(USE_STATIC_MBEDTLS_LIBRARY ON CACHE BOOL "Enable mbedTLS static libraries")
|
||||||
|
|
||||||
set(MBEDTLS_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/dependencies/external/mbedtls/download")
|
set(MBEDTLS_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/dependencies/external/mbedtls/download")
|
||||||
set(MBEDTLS_SOURCE_DIR "${CMAKE_BINARY_DIR}/dependencies/external/mbedtls/src")
|
set(MBEDTLS_SOURCE_DIR "${CMAKE_SOURCE_DIR}/dependencies/external/mbedtls")
|
||||||
set(MBEDTLS_BINARY_DIR "${CMAKE_BINARY_DIR}/dependencies/external/mbedtls/build")
|
set(MBEDTLS_BINARY_DIR "${CMAKE_BINARY_DIR}/dependencies/external/mbedtls/build")
|
||||||
set(MBEDTLS_INSTALL_DIR "${CMAKE_BINARY_DIR}")
|
set(MBEDTLS_INSTALL_DIR "${CMAKE_BINARY_DIR}")
|
||||||
if(${CMAKE_BUILD_TYPE} AND ${CMAKE_BUILD_TYPE} EQUAL "Debug")
|
if(${CMAKE_BUILD_TYPE} AND ${CMAKE_BUILD_TYPE} EQUAL "Debug")
|
||||||
@ -330,4 +389,3 @@ if(ENABLE_DEV_NETWORK)
|
|||||||
|
|
||||||
endif (NOT USE_SYSTEM_MBEDTLS_LIBS)
|
endif (NOT USE_SYSTEM_MBEDTLS_LIBS)
|
||||||
endif(ENABLE_DEV_NETWORK)
|
endif(ENABLE_DEV_NETWORK)
|
||||||
|
|
||||||
|
1
dependencies/external/qmdnsengine
vendored
Submodule
1
dependencies/external/qmdnsengine
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 0ca80117e853671d909b3cec9e2bdcac85a13b9f
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 412 KiB |
@ -402,13 +402,6 @@ signals:
|
|||||||
///
|
///
|
||||||
void onStartInstanceResponse(const int &tan);
|
void onStartInstanceResponse(const int &tan);
|
||||||
|
|
||||||
private slots:
|
|
||||||
///
|
|
||||||
/// @brief Is called whenever a Hyperion instance wants the current register list
|
|
||||||
/// @param callerInstance The instance should be returned in the answer call
|
|
||||||
///
|
|
||||||
void requestActiveRegister(QObject *callerInstance);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void stopDataConnectionss();
|
void stopDataConnectionss();
|
||||||
|
|
||||||
|
@ -292,6 +292,12 @@ private:
|
|||||||
///
|
///
|
||||||
void handleInputSourceCommand(const QJsonObject& message, const QString& command, int tan);
|
void handleInputSourceCommand(const QJsonObject& message, const QString& command, int tan);
|
||||||
|
|
||||||
|
/// Handle an incoming JSON message to request remote hyperion servers providing a given hyperion service
|
||||||
|
///
|
||||||
|
/// @param message the incoming message
|
||||||
|
///
|
||||||
|
void handleServiceCommand(const QJsonObject &message, const QString &command, int tan);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Handle an incoming JSON message of unknown type
|
/// Handle an incoming JSON message of unknown type
|
||||||
///
|
///
|
||||||
|
@ -6,10 +6,7 @@
|
|||||||
|
|
||||||
// components def
|
// components def
|
||||||
#include <utils/Components.h>
|
#include <utils/Components.h>
|
||||||
// bonjour
|
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
#include <bonjour/bonjourrecord.h>
|
|
||||||
#endif
|
|
||||||
// videModes
|
// videModes
|
||||||
#include <utils/VideoMode.h>
|
#include <utils/VideoMode.h>
|
||||||
// settings
|
// settings
|
||||||
@ -21,7 +18,6 @@
|
|||||||
|
|
||||||
class Hyperion;
|
class Hyperion;
|
||||||
class ComponentRegister;
|
class ComponentRegister;
|
||||||
class BonjourBrowserWrapper;
|
|
||||||
class PriorityMuxer;
|
class PriorityMuxer;
|
||||||
|
|
||||||
class JsonCB : public QObject
|
class JsonCB : public QObject
|
||||||
@ -73,13 +69,6 @@ private slots:
|
|||||||
/// @brief handle component state changes
|
/// @brief handle component state changes
|
||||||
///
|
///
|
||||||
void handleComponentState(hyperion::Components comp, bool state);
|
void handleComponentState(hyperion::Components comp, bool state);
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
///
|
|
||||||
/// @brief handle emits from bonjour wrapper
|
|
||||||
/// @param bRegisters The full register map
|
|
||||||
///
|
|
||||||
void handleBonjourChange(const QMap<QString,BonjourRecord>& bRegisters);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief handle emits from PriorityMuxer
|
/// @brief handle emits from PriorityMuxer
|
||||||
@ -140,10 +129,7 @@ private:
|
|||||||
Hyperion* _hyperion;
|
Hyperion* _hyperion;
|
||||||
/// pointer of comp register
|
/// pointer of comp register
|
||||||
ComponentRegister* _componentRegister;
|
ComponentRegister* _componentRegister;
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
/// Bonjour instance
|
|
||||||
BonjourBrowserWrapper* _bonjour;
|
|
||||||
#endif
|
|
||||||
/// priority muxer instance
|
/// priority muxer instance
|
||||||
PriorityMuxer* _prioMuxer;
|
PriorityMuxer* _prioMuxer;
|
||||||
/// contains all available commands
|
/// contains all available commands
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
// qt incl
|
|
||||||
#include <QObject>
|
|
||||||
#include <QMap>
|
|
||||||
#include <QHostInfo>
|
|
||||||
|
|
||||||
#include <bonjour/bonjourrecord.h>
|
|
||||||
|
|
||||||
class BonjourServiceBrowser;
|
|
||||||
class BonjourServiceResolver;
|
|
||||||
class QTimer;
|
|
||||||
|
|
||||||
class BonjourBrowserWrapper : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
private:
|
|
||||||
friend class HyperionDaemon;
|
|
||||||
///
|
|
||||||
/// @brief Browse for hyperion services in bonjour, constructed from HyperionDaemon
|
|
||||||
/// Searching for hyperion http service by default
|
|
||||||
///
|
|
||||||
BonjourBrowserWrapper(QObject * parent = nullptr);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Browse for a service
|
|
||||||
///
|
|
||||||
bool browseForServiceType(const QString &serviceType);
|
|
||||||
///
|
|
||||||
/// @brief Get all available sessions
|
|
||||||
///
|
|
||||||
QMap<QString, BonjourRecord> getAllServices() { return _hyperionSessions; }
|
|
||||||
|
|
||||||
static BonjourBrowserWrapper* instance;
|
|
||||||
static BonjourBrowserWrapper *getInstance() { return instance; }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
///
|
|
||||||
/// @brief Emits whenever a change happend
|
|
||||||
///
|
|
||||||
void browserChange( const QMap<QString, BonjourRecord> &bRegisters );
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// map of service names and browsers
|
|
||||||
QMap<QString, BonjourServiceBrowser *> _browsedServices;
|
|
||||||
/// Resolver
|
|
||||||
BonjourServiceResolver *_bonjourResolver;
|
|
||||||
|
|
||||||
// contains all current active service sessions
|
|
||||||
QMap<QString, BonjourRecord> _hyperionSessions;
|
|
||||||
|
|
||||||
QString _bonjourCurrentServiceToResolve;
|
|
||||||
/// timer to resolve changes
|
|
||||||
QTimer *_timerBonjourResolver;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
///
|
|
||||||
/// @brief is called whenever a BonjourServiceBrowser emits change
|
|
||||||
void currentBonjourRecordsChanged( const QList<BonjourRecord> &list );
|
|
||||||
/// @brief new record resolved
|
|
||||||
void bonjourRecordResolved( const QHostInfo &hostInfo, int port );
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief timer slot which updates regularly entries
|
|
||||||
///
|
|
||||||
void bonjourResolve();
|
|
||||||
};
|
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2007, Trenton Schulz
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. The name of the author may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BONJOURRECORD_H
|
|
||||||
#define BONJOURRECORD_H
|
|
||||||
|
|
||||||
#include <QtCore/QMetaType>
|
|
||||||
#include <QtCore/QString>
|
|
||||||
|
|
||||||
class BonjourRecord
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BonjourRecord() : port(-1) {}
|
|
||||||
BonjourRecord(const QString &name, const QString ®Type, const QString &domain)
|
|
||||||
: serviceName(name)
|
|
||||||
, registeredType(regType)
|
|
||||||
, replyDomain(domain)
|
|
||||||
, port(-1)
|
|
||||||
{}
|
|
||||||
|
|
||||||
BonjourRecord(const char *name, const char *regType, const char *domain)
|
|
||||||
: serviceName(QString::fromUtf8(name))
|
|
||||||
, registeredType(QString::fromUtf8(regType))
|
|
||||||
, replyDomain(QString::fromUtf8(domain))
|
|
||||||
, port(-1)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QString serviceName;
|
|
||||||
QString registeredType;
|
|
||||||
QString replyDomain;
|
|
||||||
QString hostName;
|
|
||||||
QString address;
|
|
||||||
int port;
|
|
||||||
|
|
||||||
bool operator==(const BonjourRecord &other) const
|
|
||||||
{
|
|
||||||
return serviceName == other.serviceName
|
|
||||||
&& registeredType == other.registeredType
|
|
||||||
&& replyDomain == other.replyDomain;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(BonjourRecord)
|
|
||||||
|
|
||||||
#endif // BONJOURRECORD_H
|
|
@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2007, Trenton Schulz
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. The name of the author may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BONJOURSERVICEBROWSER_H
|
|
||||||
#define BONJOURSERVICEBROWSER_H
|
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
#ifndef PLATFORM_AMLOGIC
|
|
||||||
#include <dns_sd.h>
|
|
||||||
#else
|
|
||||||
#include <avahi-compat-libdns_sd/dns_sd.h>
|
|
||||||
#endif
|
|
||||||
#include "bonjour/bonjourrecord.h"
|
|
||||||
|
|
||||||
|
|
||||||
class QSocketNotifier;
|
|
||||||
class BonjourServiceBrowser : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
BonjourServiceBrowser(QObject *parent = 0);
|
|
||||||
~BonjourServiceBrowser() override;
|
|
||||||
void browseForServiceType(const QString &serviceType);
|
|
||||||
inline QList<BonjourRecord> currentRecords() const { return bonjourRecords; }
|
|
||||||
inline QString serviceType() const { return browsingType; }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void currentBonjourRecordsChanged(const QList<BonjourRecord> &list);
|
|
||||||
void error(DNSServiceErrorType err);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void bonjourSocketReadyRead();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void DNSSD_API bonjourBrowseReply(DNSServiceRef , DNSServiceFlags flags, quint32,
|
|
||||||
DNSServiceErrorType errorCode, const char *serviceName,
|
|
||||||
const char *regType, const char *replyDomain, void *context);
|
|
||||||
DNSServiceRef dnssref;
|
|
||||||
QSocketNotifier *bonjourSocket;
|
|
||||||
QList<BonjourRecord> bonjourRecords;
|
|
||||||
QString browsingType;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // BONJOURSERVICEBROWSER_H
|
|
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2007, Trenton Schulz
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. The name of the author may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BONJOURSERVICEREGISTER_H
|
|
||||||
#define BONJOURSERVICEREGISTER_H
|
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
|
|
||||||
#include "bonjourrecord.h"
|
|
||||||
class QSocketNotifier;
|
|
||||||
|
|
||||||
#ifndef PLATFORM_AMLOGIC
|
|
||||||
#include <dns_sd.h>
|
|
||||||
#else
|
|
||||||
#include <avahi-compat-libdns_sd/dns_sd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class BonjourServiceRegister : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
BonjourServiceRegister(QObject *parent = 0);
|
|
||||||
~BonjourServiceRegister() override;
|
|
||||||
|
|
||||||
void registerService(const QString& service, int port);
|
|
||||||
void registerService(const BonjourRecord &record, quint16 servicePort, const std::vector<std::pair<std::string, std::string>>& txt = {});
|
|
||||||
inline BonjourRecord registeredRecord() const { return finalRecord; }
|
|
||||||
|
|
||||||
quint16 getPort() const { return _port; }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void error(DNSServiceErrorType error);
|
|
||||||
void serviceRegistered(const BonjourRecord &record);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void bonjourSocketReadyRead();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void DNSSD_API bonjourRegisterService(DNSServiceRef sdRef, DNSServiceFlags,
|
|
||||||
DNSServiceErrorType errorCode, const char *name,
|
|
||||||
const char *regtype, const char *domain,
|
|
||||||
void *context);
|
|
||||||
DNSServiceRef dnssref;
|
|
||||||
QSocketNotifier *bonjourSocket;
|
|
||||||
BonjourRecord finalRecord;
|
|
||||||
|
|
||||||
// current port
|
|
||||||
quint16 _port = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // BONJOURSERVICEREGISTER_H
|
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2007, Trenton Schulz
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. The name of the author may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BONJOURSERVICERESOLVER_H
|
|
||||||
#define BONJOURSERVICERESOLVER_H
|
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
|
|
||||||
#ifndef PLATFORM_AMLOGIC
|
|
||||||
#include <dns_sd.h>
|
|
||||||
#else
|
|
||||||
#include <avahi-compat-libdns_sd/dns_sd.h>
|
|
||||||
#endif
|
|
||||||
class QSocketNotifier;
|
|
||||||
class QHostInfo;
|
|
||||||
class BonjourRecord;
|
|
||||||
|
|
||||||
class BonjourServiceResolver : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
BonjourServiceResolver(QObject *parent);
|
|
||||||
~BonjourServiceResolver() override;
|
|
||||||
|
|
||||||
bool resolveBonjourRecord(const BonjourRecord &record);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void bonjourRecordResolved(const QHostInfo &hostInfo, int port);
|
|
||||||
void error(DNSServiceErrorType error);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void bonjourSocketReadyRead();
|
|
||||||
void cleanupResolve();
|
|
||||||
void finishConnect(const QHostInfo &hostInfo);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void DNSSD_API bonjourResolveReply(DNSServiceRef sdRef, DNSServiceFlags flags,
|
|
||||||
quint32 interfaceIndex, DNSServiceErrorType errorCode,
|
|
||||||
const char *fullName, const char *hosttarget, quint16 port,
|
|
||||||
quint16 txtLen, const char *txtRecord, void *context);
|
|
||||||
DNSServiceRef dnssref;
|
|
||||||
QSocketNotifier *bonjourSocket;
|
|
||||||
int bonjourPort;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // BONJOURSERVICERESOLVER_H
|
|
@ -7,7 +7,6 @@
|
|||||||
// qt
|
// qt
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
class BonjourServiceRegister;
|
|
||||||
class QTcpServer;
|
class QTcpServer;
|
||||||
class FlatBufferClient;
|
class FlatBufferClient;
|
||||||
class NetOrigin;
|
class NetOrigin;
|
||||||
@ -20,6 +19,7 @@ class NetOrigin;
|
|||||||
class FlatBufferServer : public QObject
|
class FlatBufferServer : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FlatBufferServer(const QJsonDocument& config, QObject* parent = nullptr);
|
FlatBufferServer(const QJsonDocument& config, QObject* parent = nullptr);
|
||||||
~FlatBufferServer() override;
|
~FlatBufferServer() override;
|
||||||
@ -34,6 +34,12 @@ public slots:
|
|||||||
|
|
||||||
void initServer();
|
void initServer();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
///
|
||||||
|
/// @emits whenever the server would like to announce its service details
|
||||||
|
///
|
||||||
|
void publishService(const QString& serviceType, quint16 servicePort, const QByteArray& serviceName = "");
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
///
|
///
|
||||||
/// @brief Is called whenever a new socket wants to connect
|
/// @brief Is called whenever a new socket wants to connect
|
||||||
@ -64,7 +70,6 @@ private:
|
|||||||
int _timeout;
|
int _timeout;
|
||||||
quint16 _port;
|
quint16 _port;
|
||||||
const QJsonDocument _config;
|
const QJsonDocument _config;
|
||||||
BonjourServiceRegister * _serviceRegister = nullptr;
|
|
||||||
|
|
||||||
QVector<FlatBufferClient*> _openConnections;
|
QVector<FlatBufferClient*> _openConnections;
|
||||||
};
|
};
|
||||||
|
@ -28,6 +28,17 @@
|
|||||||
class Hyperion;
|
class Hyperion;
|
||||||
class QTcpSocket;
|
class QTcpSocket;
|
||||||
class FlatBufferConnection;
|
class FlatBufferConnection;
|
||||||
|
class MessageForwarderFlatbufferClientsHelper;
|
||||||
|
|
||||||
|
struct TargetHost {
|
||||||
|
QHostAddress host;
|
||||||
|
quint16 port;
|
||||||
|
|
||||||
|
bool operator == (TargetHost const& a) const
|
||||||
|
{
|
||||||
|
return ((host == a.host) && (port == a.port));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class MessageForwarder : public QObject
|
class MessageForwarder : public QObject
|
||||||
{
|
{
|
||||||
@ -39,14 +50,15 @@ public:
|
|||||||
void addJsonTarget(const QJsonObject& targetConfig);
|
void addJsonTarget(const QJsonObject& targetConfig);
|
||||||
void addFlatbufferTarget(const QJsonObject& targetConfig);
|
void addFlatbufferTarget(const QJsonObject& targetConfig);
|
||||||
|
|
||||||
private slots:
|
public slots:
|
||||||
///
|
///
|
||||||
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
|
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
|
||||||
/// @param type settingyType from enum
|
/// @param type settingsType from enum
|
||||||
/// @param config configuration object
|
/// @param config configuration object
|
||||||
///
|
///
|
||||||
void handleSettingsUpdate(settings::type type, const QJsonDocument &config);
|
void handleSettingsUpdate(settings::type type, const QJsonDocument &config);
|
||||||
|
|
||||||
|
private slots:
|
||||||
///
|
///
|
||||||
/// @brief Handle component state change MessageForwarder
|
/// @brief Handle component state change MessageForwarder
|
||||||
/// @param component The component from enum
|
/// @param component The component from enum
|
||||||
@ -81,15 +93,13 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct TargetHost {
|
void enableTargets(bool enable, const QJsonObject& config);
|
||||||
QHostAddress host;
|
|
||||||
quint16 port;
|
|
||||||
|
|
||||||
bool operator == (TargetHost const& a) const
|
int startJsonTargets(const QJsonObject& config);
|
||||||
{
|
void stopJsonTargets();
|
||||||
return ((host == a.host) && (port == a.port));
|
|
||||||
}
|
int startFlatbufferTargets(const QJsonObject& config);
|
||||||
};
|
void stopFlatbufferTargets();
|
||||||
|
|
||||||
/// Hyperion instance
|
/// Hyperion instance
|
||||||
Hyperion *_hyperion;
|
Hyperion *_hyperion;
|
||||||
@ -105,10 +115,37 @@ private:
|
|||||||
|
|
||||||
/// Flatbuffer connection for forwarding
|
/// Flatbuffer connection for forwarding
|
||||||
QList<TargetHost> _flatbufferTargets;
|
QList<TargetHost> _flatbufferTargets;
|
||||||
QList<FlatBufferConnection*> _forwardClients;
|
|
||||||
|
|
||||||
/// Flag if forwarder is enabled
|
/// Flag if forwarder is enabled
|
||||||
bool _forwarder_enabled = true;
|
bool _forwarder_enabled = true;
|
||||||
|
|
||||||
const int _priority;
|
const int _priority;
|
||||||
|
|
||||||
|
MessageForwarderFlatbufferClientsHelper* _messageForwarderFlatBufHelper;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MessageForwarderFlatbufferClientsHelper : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
MessageForwarderFlatbufferClientsHelper();
|
||||||
|
~MessageForwarderFlatbufferClientsHelper();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void addClient(const QString& origin, const TargetHost& targetHost, int priority, bool skipReply);
|
||||||
|
void clearClients();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool isFree() const;
|
||||||
|
|
||||||
|
void forwardImage(const Image<ColorRgb>& image);
|
||||||
|
void addClientHandler(const QString& origin, const TargetHost& targetHost, int priority, bool skipReply);
|
||||||
|
void clearClientsHandler();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QList<FlatBufferConnection*> _forwardClients;
|
||||||
|
bool _free;
|
||||||
};
|
};
|
||||||
|
@ -22,6 +22,10 @@
|
|||||||
#include <sys/ipc.h>
|
#include <sys/ipc.h>
|
||||||
#include <sys/shm.h>
|
#include <sys/shm.h>
|
||||||
|
|
||||||
|
#ifdef Bool
|
||||||
|
#undef Bool
|
||||||
|
#endif
|
||||||
|
|
||||||
class X11Grabber : public Grabber , public QAbstractNativeEventFilter
|
class X11Grabber : public Grabber , public QAbstractNativeEventFilter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
class QTcpServer;
|
class QTcpServer;
|
||||||
class QTcpSocket;
|
class QTcpSocket;
|
||||||
class JsonClientConnection;
|
class JsonClientConnection;
|
||||||
class BonjourServiceRegister;
|
|
||||||
class NetOrigin;
|
class NetOrigin;
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -31,11 +30,18 @@ public:
|
|||||||
JsonServer(const QJsonDocument& config);
|
JsonServer(const QJsonDocument& config);
|
||||||
~JsonServer() override;
|
~JsonServer() override;
|
||||||
|
|
||||||
|
void initServer();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @return the port number on which this TCP listens for incoming connections
|
/// @return the port number on which this TCP listens for incoming connections
|
||||||
///
|
///
|
||||||
uint16_t getPort() const;
|
uint16_t getPort() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
///
|
||||||
|
/// @emits whenever the server would like to announce its service details
|
||||||
|
///
|
||||||
|
void publishService(const QString& serviceType, quint16 servicePort, const QByteArray& serviceName = "");
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
///
|
///
|
||||||
@ -71,7 +77,7 @@ private:
|
|||||||
/// port
|
/// port
|
||||||
uint16_t _port = 0;
|
uint16_t _port = 0;
|
||||||
|
|
||||||
BonjourServiceRegister * _serviceRegister = nullptr;
|
const QJsonDocument _config;
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#ifndef LEDEVICE_H
|
#ifndef LEDEVICE_H
|
||||||
#define LEDEVICE_H
|
#define LEDEVICE_H
|
||||||
|
|
||||||
// qt includes
|
// qt includes
|
||||||
@ -14,6 +14,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
// Utility includes
|
// Utility includes
|
||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
@ -50,6 +51,13 @@ public:
|
|||||||
///
|
///
|
||||||
~LedDevice() override;
|
~LedDevice() override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Set the common logger for LED-devices.
|
||||||
|
///
|
||||||
|
/// @param[in] log The logger to be used
|
||||||
|
///
|
||||||
|
void setLogger(Logger* log);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Set the current active LED-device type.
|
/// @brief Set the current active LED-device type.
|
||||||
///
|
///
|
||||||
@ -64,6 +72,8 @@ public:
|
|||||||
///
|
///
|
||||||
void setLedCount(int ledCount);
|
void setLedCount(int ledCount);
|
||||||
|
|
||||||
|
void setColorOrder(const QString& colorOrder);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Set a device's latch time.
|
/// @brief Set a device's latch time.
|
||||||
///
|
///
|
||||||
@ -83,6 +93,19 @@ public:
|
|||||||
///
|
///
|
||||||
void setRewriteTime(int rewriteTime_ms);
|
void setRewriteTime(int rewriteTime_ms);
|
||||||
|
|
||||||
|
/// @brief Set a device's enablement cycle's parameters.
|
||||||
|
///
|
||||||
|
/// @param[in] maxEnableRetries Maximum number of attempts to enable a device, if reached retries will be stopped
|
||||||
|
/// @param[in] enableAttemptsTimerInterval Interval in seconds between two enablement attempts
|
||||||
|
///
|
||||||
|
void setEnableAttempts(int maxEnablAttempts, std::chrono::seconds enableAttemptsTimerInterval);
|
||||||
|
|
||||||
|
/// @brief Enable a device automatically after Hyperion startup or not
|
||||||
|
///
|
||||||
|
/// @param[in] isAutoStart
|
||||||
|
///
|
||||||
|
void setAutoStart(bool isAutoStart);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Discover devices of this type available (for configuration).
|
/// @brief Discover devices of this type available (for configuration).
|
||||||
/// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
|
/// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
|
||||||
@ -120,6 +143,15 @@ public:
|
|||||||
///
|
///
|
||||||
virtual void identify(const QJsonObject& /*params*/) {}
|
virtual void identify(const QJsonObject& /*params*/) {}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Add an authorization/client-key or token to the device
|
||||||
|
///
|
||||||
|
/// Used in context of a set of devices of the same type.
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters to address device
|
||||||
|
/// @return A JSON structure holding the authorization key/token
|
||||||
|
virtual QJsonObject addAuthorization(const QJsonObject& /*params*/) { return QJsonObject(); }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Check, if device is properly initialised
|
/// @brief Check, if device is properly initialised
|
||||||
///
|
///
|
||||||
@ -127,7 +159,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// @return True, if device is initialised
|
/// @return True, if device is initialised
|
||||||
///
|
///
|
||||||
bool isInitialised() const { return _isDeviceInitialised; }
|
bool isInitialised() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Check, if device is ready to be used.
|
/// @brief Check, if device is ready to be used.
|
||||||
@ -136,14 +168,14 @@ public:
|
|||||||
///
|
///
|
||||||
/// @return True, if device is ready
|
/// @return True, if device is ready
|
||||||
///
|
///
|
||||||
bool isReady() const { return _isDeviceReady; }
|
bool isReady() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Check, if device is in error state.
|
/// @brief Check, if device is in error state.
|
||||||
///
|
///
|
||||||
/// @return True, if device is in error
|
/// @return True, if device is in error
|
||||||
///
|
///
|
||||||
bool isInError() const { return _isDeviceInError; }
|
bool isInError() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Prints the color values to stdout.
|
/// @brief Prints the color values to stdout.
|
||||||
@ -152,13 +184,6 @@ public:
|
|||||||
///
|
///
|
||||||
static void printLedValues(const std::vector<ColorRgb>& ledValues);
|
static void printLedValues(const std::vector<ColorRgb>& ledValues);
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Set the common logger for LED-devices.
|
|
||||||
///
|
|
||||||
/// @param[in] log The logger to be used
|
|
||||||
///
|
|
||||||
void setLogger(Logger* log) { _log = log; }
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -181,47 +206,47 @@ public slots:
|
|||||||
/// @param[in] ledValues The color per LED
|
/// @param[in] ledValues The color per LED
|
||||||
/// @return Zero on success else negative (i.e. device is not ready)
|
/// @return Zero on success else negative (i.e. device is not ready)
|
||||||
///
|
///
|
||||||
virtual int updateLeds(const std::vector<ColorRgb>& ledValues);
|
virtual int updateLeds(std::vector<ColorRgb> ledValues);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get the currently defined LatchTime.
|
/// @brief Get the currently defined LatchTime.
|
||||||
///
|
///
|
||||||
/// @return Latch time in milliseconds
|
/// @return Latch time in milliseconds
|
||||||
///
|
///
|
||||||
int getLatchTime() const { return _latchTime_ms; }
|
int getLatchTime() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get the currently defined RewriteTime.
|
/// @brief Get the currently defined RewriteTime.
|
||||||
///
|
///
|
||||||
/// @return Rewrite time in milliseconds
|
/// @return Rewrite time in milliseconds
|
||||||
///
|
///
|
||||||
int getRewriteTime() const { return _refreshTimerInterval_ms; }
|
int getRewriteTime() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get the number of LEDs supported by the device.
|
/// @brief Get the number of LEDs supported by the device.
|
||||||
///
|
///
|
||||||
/// @return Number of device's LEDs, 0 = unknown number
|
/// @return Number of device's LEDs, 0 = unknown number
|
||||||
///
|
///
|
||||||
int getLedCount() const { return _ledCount; }
|
int getLedCount() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get the current active LED-device type.
|
/// @brief Get the current active LED-device type.
|
||||||
///
|
///
|
||||||
QString getActiveDeviceType() const { return _activeDeviceType; }
|
QString getActiveDeviceType() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get color order of device.
|
/// @brief Get color order of device.
|
||||||
///
|
///
|
||||||
/// @return The color order
|
/// @return The color order
|
||||||
///
|
///
|
||||||
QString getColorOrder() const { return _colorOrder; }
|
QString getColorOrder() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get the LED-Device component's state.
|
/// @brief Get the LED-Device component's state.
|
||||||
///
|
///
|
||||||
/// @return True, if enabled
|
/// @return True, if enabled
|
||||||
///
|
///
|
||||||
inline bool componentState() const { return _isEnabled; }
|
bool componentState() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Enables the device for output.
|
/// @brief Enables the device for output.
|
||||||
@ -257,11 +282,6 @@ public slots:
|
|||||||
///
|
///
|
||||||
virtual bool switchOff();
|
virtual bool switchOff();
|
||||||
|
|
||||||
bool switchOnOff(bool onState)
|
|
||||||
{
|
|
||||||
return onState == true ? switchOn() : switchOff();
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
///
|
///
|
||||||
/// @brief Emits whenever the LED-Device switches between on/off.
|
/// @brief Emits whenever the LED-Device switches between on/off.
|
||||||
@ -361,6 +381,16 @@ protected:
|
|||||||
///
|
///
|
||||||
virtual bool restoreState();
|
virtual bool restoreState();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Start a new enable cycle
|
||||||
|
///
|
||||||
|
void startEnableAttemptsTimer();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Stop a new enable cycle
|
||||||
|
///
|
||||||
|
void stopEnableAttemptsTimer();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Converts an uint8_t array to hex string.
|
/// @brief Converts an uint8_t array to hex string.
|
||||||
///
|
///
|
||||||
@ -368,7 +398,7 @@ protected:
|
|||||||
/// @param size of the array
|
/// @param size of the array
|
||||||
/// @param number Number of array items to be converted.
|
/// @param number Number of array items to be converted.
|
||||||
/// @return array as string of hex values
|
/// @return array as string of hex values
|
||||||
QString uint8_t_to_hex_string(const uint8_t * data, const int size, int number = -1) const;
|
static QString uint8_t_to_hex_string(const uint8_t * data, const int size, int number = -1) ;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Converts a ByteArray to hex string.
|
/// @brief Converts a ByteArray to hex string.
|
||||||
@ -376,7 +406,7 @@ protected:
|
|||||||
/// @param data ByteArray
|
/// @param data ByteArray
|
||||||
/// @param number Number of array items to be converted.
|
/// @param number Number of array items to be converted.
|
||||||
/// @return array as string of hex values
|
/// @return array as string of hex values
|
||||||
QString toHex(const QByteArray& data, int number = -1) const;
|
static QString toHex(const QByteArray& data, int number = -1) ;
|
||||||
|
|
||||||
/// Current device's type
|
/// Current device's type
|
||||||
QString _activeDeviceType;
|
QString _activeDeviceType;
|
||||||
@ -414,6 +444,7 @@ protected:
|
|||||||
QJsonObject _orignalStateValues;
|
QJsonObject _orignalStateValues;
|
||||||
|
|
||||||
// Device states
|
// Device states
|
||||||
|
|
||||||
/// Is the device enabled?
|
/// Is the device enabled?
|
||||||
bool _isEnabled;
|
bool _isEnabled;
|
||||||
|
|
||||||
@ -429,9 +460,6 @@ protected:
|
|||||||
/// Is the device in error state and stopped?
|
/// Is the device in error state and stopped?
|
||||||
bool _isDeviceInError;
|
bool _isDeviceInError;
|
||||||
|
|
||||||
/// Is the device in the switchOff process?
|
|
||||||
bool _isInSwitchOff;
|
|
||||||
|
|
||||||
/// Timestamp of last write
|
/// Timestamp of last write
|
||||||
QDateTime _lastWriteTime;
|
QDateTime _lastWriteTime;
|
||||||
|
|
||||||
@ -459,6 +487,15 @@ private:
|
|||||||
/// @brief Stop refresh cycle
|
/// @brief Stop refresh cycle
|
||||||
void stopRefreshTimer();
|
void stopRefreshTimer();
|
||||||
|
|
||||||
|
/// Timer that enables a device (used to retry enablement, if enabled failed before)
|
||||||
|
QTimer* _enableAttemptsTimer;
|
||||||
|
|
||||||
|
// Device configuration parameters
|
||||||
|
|
||||||
|
std::chrono::seconds _enableAttemptTimerInterval;
|
||||||
|
int _enableAttempts;
|
||||||
|
int _maxEnableAttempts;
|
||||||
|
|
||||||
/// Is last write refreshing enabled?
|
/// Is last write refreshing enabled?
|
||||||
bool _isRefreshEnabled;
|
bool _isRefreshEnabled;
|
||||||
|
|
||||||
|
@ -94,16 +94,6 @@ signals:
|
|||||||
///
|
///
|
||||||
int updateLeds(const std::vector<ColorRgb>& ledValues);
|
int updateLeds(const std::vector<ColorRgb>& ledValues);
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Enables the LED-Device.
|
|
||||||
///
|
|
||||||
void enable();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Disables the LED-Device.
|
|
||||||
///
|
|
||||||
void disable();
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Switch the LEDs on.
|
/// @brief Switch the LEDs on.
|
||||||
///
|
///
|
||||||
@ -113,7 +103,7 @@ signals:
|
|||||||
/// @brief Switch the LEDs off.
|
/// @brief Switch the LEDs off.
|
||||||
///
|
///
|
||||||
void switchOff();
|
void switchOff();
|
||||||
|
|
||||||
void stopLedDevice();
|
void stopLedDevice();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
170
include/mdns/MdnsBrowser.h
Normal file
170
include/mdns/MdnsBrowser.h
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
#ifndef MDNS_BROWSER_H
|
||||||
|
#define MDNS_BROWSER_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <qmdnsengine/server.h>
|
||||||
|
#include <qmdnsengine/service.h>
|
||||||
|
|
||||||
|
#include <qmdnsengine/browser.h>
|
||||||
|
#include <qmdnsengine/cache.h>
|
||||||
|
#include <qmdnsengine/resolver.h>
|
||||||
|
#include <qmdnsengine/dns.h>
|
||||||
|
#include <qmdnsengine/record.h>
|
||||||
|
|
||||||
|
// Qt includes
|
||||||
|
#include <QObject>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
// Utility includes
|
||||||
|
#include <utils/Logger.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr std::chrono::milliseconds DEFAULT_DISCOVER_TIMEOUT{ 500 };
|
||||||
|
constexpr std::chrono::milliseconds DEFAULT_ADDRESS_RESOLVE_TIMEOUT{ 1000 };
|
||||||
|
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
|
class MdnsBrowser : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
// Run MdnsBrowser as singleton
|
||||||
|
|
||||||
|
private:
|
||||||
|
///
|
||||||
|
/// @brief Browse for hyperion services in bonjour, constructed from HyperionDaemon
|
||||||
|
/// Searching for hyperion http service by default
|
||||||
|
///
|
||||||
|
// Run MdnsBrowser as singleton
|
||||||
|
MdnsBrowser(QObject* parent = nullptr);
|
||||||
|
~MdnsBrowser() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static MdnsBrowser& getInstance()
|
||||||
|
{
|
||||||
|
static MdnsBrowser* instance = new MdnsBrowser();
|
||||||
|
return *instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
MdnsBrowser(const MdnsBrowser&) = delete;
|
||||||
|
MdnsBrowser(MdnsBrowser&&) = delete;
|
||||||
|
MdnsBrowser& operator=(const MdnsBrowser&) = delete;
|
||||||
|
MdnsBrowser& operator=(MdnsBrowser&&) = delete;
|
||||||
|
|
||||||
|
QMdnsEngine::Service getFirstService(const QByteArray& serviceType, const QString& filter = ".*", const std::chrono::milliseconds waitTime = DEFAULT_DISCOVER_TIMEOUT) const;
|
||||||
|
QJsonArray getServicesDiscoveredJson(const QByteArray& serviceType, const QString& filter = ".*", const std::chrono::milliseconds waitTime = std::chrono::milliseconds{ 0 }) const;
|
||||||
|
|
||||||
|
|
||||||
|
void printCache(const QByteArray& name = QByteArray(), quint16 type = QMdnsEngine::ANY) const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Browse for a service of type
|
||||||
|
///
|
||||||
|
void browseForServiceType(const QByteArray& serviceType);
|
||||||
|
|
||||||
|
QHostAddress getHostFirstAddress(const QByteArray& hostname);
|
||||||
|
|
||||||
|
void onHostNameResolved(const QHostAddress& address);
|
||||||
|
|
||||||
|
QMdnsEngine::Record getServiceInstanceRecord(const QByteArray& serviceInstance, const std::chrono::milliseconds waitTime = DEFAULT_DISCOVER_TIMEOUT) const;
|
||||||
|
|
||||||
|
bool resolveAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress, std::chrono::milliseconds timeout = DEFAULT_ADDRESS_RESOLVE_TIMEOUT);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indicate that the specified service was updated
|
||||||
|
*
|
||||||
|
* This signal is emitted when the SRV record for a service (identified by
|
||||||
|
* its name and type) or a TXT record has changed.
|
||||||
|
*/
|
||||||
|
void serviceFound(const QMdnsEngine::Service& service);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indicate that the specified service was removed
|
||||||
|
*
|
||||||
|
* This signal is emitted when an essential record (PTR or SRV) is
|
||||||
|
* expiring from the cache. This will also occur when an updated PTR or
|
||||||
|
* SRV record is received with a TTL of 0.
|
||||||
|
*/
|
||||||
|
void serviceRemoved(const QMdnsEngine::Service& service);
|
||||||
|
|
||||||
|
void addressResolved(const QHostAddress address);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void onServiceAdded(const QMdnsEngine::Service& service);
|
||||||
|
void onServiceUpdated(const QMdnsEngine::Service& service);
|
||||||
|
void onServiceRemoved(const QMdnsEngine::Service& service);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// template <typename Func1, typename Func2, typename std::enable_if_t<std::is_member_pointer<Func2>::value, int> = 0>
|
||||||
|
// static inline QMetaObject::Connection weakConnect(typename QtPrivate::FunctionPointer<Func1>::Object* sender,
|
||||||
|
// Func1 signal,
|
||||||
|
// typename QtPrivate::FunctionPointer<Func2>::Object* receiver,
|
||||||
|
// Func2 slot)
|
||||||
|
// {
|
||||||
|
// QMetaObject::Connection conn_normal = QObject::connect(sender, signal, receiver, slot);
|
||||||
|
|
||||||
|
// QMetaObject::Connection* conn_delete = new QMetaObject::Connection();
|
||||||
|
|
||||||
|
// *conn_delete = QObject::connect(sender, signal, [conn_normal, conn_delete]() {
|
||||||
|
// QObject::disconnect(conn_normal);
|
||||||
|
// QObject::disconnect(*conn_delete);
|
||||||
|
// delete conn_delete;
|
||||||
|
// });
|
||||||
|
// return conn_normal;
|
||||||
|
// }
|
||||||
|
|
||||||
|
template <typename Func1, typename Func2, typename std::enable_if_t<!std::is_member_pointer<Func2>::value, int> = 0>
|
||||||
|
static inline QMetaObject::Connection weakConnect(typename QtPrivate::FunctionPointer<Func1>::Object* sender,
|
||||||
|
Func1 signal,
|
||||||
|
Func2 slot)
|
||||||
|
{
|
||||||
|
QMetaObject::Connection conn_normal = QObject::connect(sender, signal, slot);
|
||||||
|
|
||||||
|
QMetaObject::Connection* conn_delete = new QMetaObject::Connection();
|
||||||
|
|
||||||
|
*conn_delete = QObject::connect(sender, signal, [conn_normal, conn_delete]() {
|
||||||
|
QObject::disconnect(conn_normal);
|
||||||
|
QObject::disconnect(*conn_delete);
|
||||||
|
delete conn_delete;
|
||||||
|
});
|
||||||
|
return conn_normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// template <typename Func1, typename Func2, typename std::enable_if_t<!std::is_member_pointer<Func2>::value, int> = 0>
|
||||||
|
// static inline QMetaObject::Connection weakConnect(typename QtPrivate::FunctionPointer<Func1>::Object* sender,
|
||||||
|
// Func1 signal,
|
||||||
|
// typename QtPrivate::FunctionPointer<Func2>::Object* receiver,
|
||||||
|
// Func2 slot)
|
||||||
|
// {
|
||||||
|
// Q_UNUSED(receiver);
|
||||||
|
// QMetaObject::Connection conn_normal = QObject::connect(sender, signal, slot);
|
||||||
|
|
||||||
|
// QMetaObject::Connection* conn_delete = new QMetaObject::Connection();
|
||||||
|
|
||||||
|
// *conn_delete = QObject::connect(sender, signal, [conn_normal, conn_delete]() {
|
||||||
|
// QObject::disconnect(conn_normal);
|
||||||
|
// QObject::disconnect(*conn_delete);
|
||||||
|
// delete conn_delete;
|
||||||
|
// });
|
||||||
|
// return conn_normal;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// The logger instance for mDNS-Service
|
||||||
|
Logger* _log;
|
||||||
|
|
||||||
|
QMdnsEngine::Server _server;
|
||||||
|
QMdnsEngine::Cache _cache;
|
||||||
|
|
||||||
|
QMap<QByteArray, QMdnsEngine::Browser*> _browsedServiceTypes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MDNSBROWSER_H
|
51
include/mdns/MdnsProvider.h
Normal file
51
include/mdns/MdnsProvider.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef MDNSPROVIDER_H
|
||||||
|
#define MDNSPROVIDER_H
|
||||||
|
|
||||||
|
#include <qmdnsengine/server.h>
|
||||||
|
#include <qmdnsengine/hostname.h>
|
||||||
|
#include <qmdnsengine/provider.h>
|
||||||
|
#include <qmdnsengine/service.h>
|
||||||
|
|
||||||
|
// Qt includes
|
||||||
|
#include <QObject>
|
||||||
|
#include <QByteArray>
|
||||||
|
|
||||||
|
// Utility includes
|
||||||
|
#include <utils/Logger.h>
|
||||||
|
|
||||||
|
class MdnsProvider : public QObject
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MdnsProvider(QObject* parent = nullptr);
|
||||||
|
~MdnsProvider() override;
|
||||||
|
|
||||||
|
QList<QByteArray> getServiceTypesProvided() const { return _providedServiceTypes.keys(); }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Init MdnsProvider after thread start
|
||||||
|
///
|
||||||
|
void init();
|
||||||
|
|
||||||
|
void publishService (const QString& serviceType, quint16 servicePort, const QByteArray& serviceName = "");
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void onHostnameChanged(const QByteArray& hostname);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// The logger instance for mDNS-Service
|
||||||
|
Logger* _log;
|
||||||
|
|
||||||
|
QMdnsEngine::Server* _server;
|
||||||
|
QMdnsEngine::Hostname* _hostname;
|
||||||
|
|
||||||
|
/// map of services provided
|
||||||
|
QMap<QByteArray, QMdnsEngine::Provider*> _providedServiceTypes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MDNSPROVIDER_H
|
38
include/mdns/MdnsServiceRegister.h
Normal file
38
include/mdns/MdnsServiceRegister.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef MDNSSERVICEREGISTER_H
|
||||||
|
#define MDNSSERVICEREGISTER_H
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
struct mdnsConfig
|
||||||
|
{
|
||||||
|
QByteArray serviceType;
|
||||||
|
QString serviceNameFilter;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef QMap<QString, mdnsConfig> MdnsServiceMap;
|
||||||
|
|
||||||
|
const MdnsServiceMap mDnsServiceMap = {
|
||||||
|
//Hyperion
|
||||||
|
{"jsonapi" , {"_hyperiond-json._tcp.local.", ".*"}},
|
||||||
|
{"flatbuffer" , {"_hyperiond-flatbuf._tcp.local.", ".*"}},
|
||||||
|
{"protobuffer" , {"_hyperiond-protobuf._tcp.local.", ".*"}},
|
||||||
|
{"http" , {"_http._tcp.local.", ".*"}},
|
||||||
|
{"https" , {"_https._tcp.local.", ".*"}},
|
||||||
|
|
||||||
|
//LED Devices
|
||||||
|
{"cololight" , {"_hap._tcp.local.", "ColoLight.*"}},
|
||||||
|
{"nanoleaf" , {"_nanoleafapi._tcp.local.", ".*"}},
|
||||||
|
{"philipshue" , {"_hue._tcp.local.", ".*"}},
|
||||||
|
{"wled" , {"_wled._tcp.local.", ".*"}},
|
||||||
|
{"yeelight" , {"_hap._tcp.local.", "Yeelight.*|YLBulb.*"}},
|
||||||
|
};
|
||||||
|
|
||||||
|
class MdnsServiceRegister {
|
||||||
|
public:
|
||||||
|
static QByteArray getServiceType(const QString &serviceType) { return mDnsServiceMap[serviceType].serviceType; }
|
||||||
|
static QString getServiceNameFilter(const QString &serviceType) { return mDnsServiceMap[serviceType].serviceNameFilter; }
|
||||||
|
static MdnsServiceMap getAllConfigs () { return mDnsServiceMap; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MDNSSERVICEREGISTER_H
|
@ -24,6 +24,12 @@ public:
|
|||||||
ProtoServer(const QJsonDocument& config, QObject* parent = nullptr);
|
ProtoServer(const QJsonDocument& config, QObject* parent = nullptr);
|
||||||
~ProtoServer() override;
|
~ProtoServer() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
///
|
||||||
|
/// @emits whenever the server would like to announce its service details
|
||||||
|
///
|
||||||
|
void publishService(const QString& serviceType, quint16 servicePort, const QByteArray& serviceName = "");
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
/// @brief Handle settings update
|
/// @brief Handle settings update
|
||||||
|
@ -31,6 +31,30 @@ struct ColorRgb
|
|||||||
static const ColorRgb YELLOW;
|
static const ColorRgb YELLOW;
|
||||||
/// 'White' RgbColor (255, 255, 255)
|
/// 'White' RgbColor (255, 255, 255)
|
||||||
static const ColorRgb WHITE;
|
static const ColorRgb WHITE;
|
||||||
|
|
||||||
|
ColorRgb() = default;
|
||||||
|
|
||||||
|
ColorRgb(uint8_t _red, uint8_t _green,uint8_t _blue):
|
||||||
|
red(_red),
|
||||||
|
green(_green),
|
||||||
|
blue(_blue)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorRgb operator-(const ColorRgb& b) const
|
||||||
|
{
|
||||||
|
ColorRgb a(*this);
|
||||||
|
a.red -= b.red;
|
||||||
|
a.green -= b.green;
|
||||||
|
a.blue -= b.blue;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toQString() const
|
||||||
|
{
|
||||||
|
return QString("(%1,%2,%3)").arg(red).arg(green).arg(blue);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Assert to ensure that the size of the structure is 'only' 3 bytes
|
/// Assert to ensure that the size of the structure is 'only' 3 bytes
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <utils/Logger.h>
|
|
||||||
|
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QHostInfo>
|
#include <QHostInfo>
|
||||||
|
|
||||||
|
#include <HyperionConfig.h>
|
||||||
|
#include <utils/Logger.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
#include <mdns/MdnsBrowser.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace NetUtils {
|
namespace NetUtils {
|
||||||
|
|
||||||
const int MAX_PORT = 65535;
|
const int MAX_PORT = 65535;
|
||||||
@ -38,15 +43,15 @@ namespace NetUtils {
|
|||||||
///
|
///
|
||||||
/// @brief Check if the port is in the valid range
|
/// @brief Check if the port is in the valid range
|
||||||
/// @param log The logger of the caller to print///
|
/// @param log The logger of the caller to print///
|
||||||
/// @param[in] port The port to be tested
|
/// @param[in] port The port to be tested (port = -1 is ignored for testing)
|
||||||
/// @param[in] host A hostname/IP-address to make reference to during logging
|
/// @param[in] host A hostname/IP-address to make reference to during logging
|
||||||
/// @return True on success else false
|
/// @return True on success else false
|
||||||
///
|
///
|
||||||
inline bool isValidPort(Logger* log, int port, const QString& host)
|
inline bool isValidPort(Logger* log, int port, const QString& host)
|
||||||
{
|
{
|
||||||
if (port <= 0 || port > MAX_PORT)
|
if ((port <= 0 || port > MAX_PORT) && port != -1)
|
||||||
{
|
{
|
||||||
Error(log, "Invalid port [%d] for host: %s!", port, QSTRING_CSTR(host));
|
Error(log, "Invalid port [%d] for host: (%s)! - Port must be in range [0 - %d]", port, QSTRING_CSTR(host), MAX_PORT);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -59,7 +64,7 @@ namespace NetUtils {
|
|||||||
/// @param[in/out] port The resolved port, if available.
|
/// @param[in/out] port The resolved port, if available.
|
||||||
/// @return True on success else false
|
/// @return True on success else false
|
||||||
///
|
///
|
||||||
inline bool resolveHostPort(const QString& address, QString& host, quint16& port)
|
inline bool resolveHostPort(const QString& address, QString& host, int& port)
|
||||||
{
|
{
|
||||||
if (address.isEmpty())
|
if (address.isEmpty())
|
||||||
{
|
{
|
||||||
@ -91,38 +96,109 @@ namespace NetUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Check if the port is in the valid range
|
/// @brief Resolve a hostname (DNS/mDNS) into an IP-address. A given IP address will be passed through
|
||||||
/// @param log The logger of the caller to print
|
/// @param[in/out] log The logger of the caller to print
|
||||||
/// @param[in] address The port to be tested
|
/// @param[in] hostname The hostname to be resolved
|
||||||
/// @param[out] hostAddress A hostname to make reference to during logging
|
/// @param[out] hostAddress The resolved IP-Address
|
||||||
/// @return True on success else false
|
/// @return True on success else false
|
||||||
///
|
///
|
||||||
|
inline bool resolveMdDnsHostToAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress)
|
||||||
inline bool resolveHostAddress(Logger* log, const QString& address, QHostAddress& hostAddress)
|
|
||||||
{
|
{
|
||||||
bool isHostAddressOK{ false };
|
bool isHostAddressOK{ false };
|
||||||
|
if (!hostname.isEmpty())
|
||||||
if (hostAddress.setAddress(address))
|
|
||||||
{
|
{
|
||||||
Debug(log, "Successfully parsed %s as an IP-address.", QSTRING_CSTR(hostAddress.toString()));
|
#ifdef ENABLE_MDNS
|
||||||
isHostAddressOK = true;
|
if (hostname.endsWith(".local") || hostname.endsWith(".local."))
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QHostInfo hostInfo = QHostInfo::fromName(address);
|
|
||||||
if (hostInfo.error() == QHostInfo::NoError)
|
|
||||||
{
|
{
|
||||||
hostAddress = hostInfo.addresses().first();
|
QHostAddress resolvedAddress;
|
||||||
Debug(log, "Successfully resolved IP-address (%s) for hostname (%s).", QSTRING_CSTR(hostAddress.toString()), QSTRING_CSTR(address));
|
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "resolveAddress",
|
||||||
isHostAddressOK = true;
|
Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(bool, isHostAddressOK),
|
||||||
|
Q_ARG(Logger*, log), Q_ARG(QString, hostname), Q_ARG(QHostAddress&, resolvedAddress));
|
||||||
|
hostAddress = resolvedAddress;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
QString errortext = QString("Failed resolving IP-address for [%1], (%2) %3").arg(address).arg(hostInfo.error()).arg(hostInfo.errorString());
|
if (hostAddress.setAddress(hostname))
|
||||||
Error(log, "%s", QSTRING_CSTR(errortext));
|
{
|
||||||
isHostAddressOK = false;
|
//Debug(log, "IP-address (%s) not required to be resolved.", QSTRING_CSTR(hostAddress.toString()));
|
||||||
|
isHostAddressOK = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QHostInfo hostInfo = QHostInfo::fromName(hostname);
|
||||||
|
if (hostInfo.error() == QHostInfo::NoError)
|
||||||
|
{
|
||||||
|
hostAddress = hostInfo.addresses().at(0);
|
||||||
|
Debug(log, "Successfully resolved hostname (%s) to IP-address (%s)", QSTRING_CSTR(hostname), QSTRING_CSTR(hostAddress.toString()));
|
||||||
|
isHostAddressOK = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QString errortext = QString("Failed resolving hostname (%1) to IP-address. Error: (%2) %3").arg(hostname).arg(hostInfo.error()).arg(hostInfo.errorString());
|
||||||
|
Error(log, "%s", QSTRING_CSTR(errortext));
|
||||||
|
isHostAddressOK = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isHostAddressOK;
|
return isHostAddressOK;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
///
|
||||||
|
/// @brief Resolve a hostname(DNS) or mDNS service name into an IP-address. A given IP address will be passed through
|
||||||
|
/// @param[in/out] log The logger of the caller to print
|
||||||
|
/// @param[in] hostname The hostname/mDNS service name to be resolved
|
||||||
|
/// @param[out] hostAddress The resolved IP-Address
|
||||||
|
/// @param[in/out] port The port provided by the mDNS service, if not mDNS the input port is returned
|
||||||
|
/// @return True on success else false
|
||||||
|
///
|
||||||
|
inline bool resolveHostToAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress, int& port)
|
||||||
|
{
|
||||||
|
bool areHostAddressPartOK{ false };
|
||||||
|
QString target {hostname};
|
||||||
|
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
if (hostname.endsWith("._tcp.local"))
|
||||||
|
{
|
||||||
|
//Treat hostname as service instance name that requires to be resolved into an mDNS-Hostname first
|
||||||
|
QMdnsEngine::Record service = MdnsBrowser::getInstance().getServiceInstanceRecord(hostname.toUtf8());
|
||||||
|
if (!service.target().isEmpty())
|
||||||
|
{
|
||||||
|
Info(log, "Resolved service [%s] to mDNS hostname [%s], service port [%d]", QSTRING_CSTR(hostname), service.target().constData(), service.port());
|
||||||
|
target = service.target();
|
||||||
|
port = service.port();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error(log, "Cannot resolve mDNS hostname for given service [%s]!", QSTRING_CSTR(hostname));
|
||||||
|
return areHostAddressPartOK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QHostAddress resolvedAddress;
|
||||||
|
if (NetUtils::resolveMdDnsHostToAddress(log, target, resolvedAddress))
|
||||||
|
{
|
||||||
|
hostAddress = resolvedAddress;
|
||||||
|
if (hostname != hostAddress.toString())
|
||||||
|
{
|
||||||
|
Info(log, "Resolved hostname (%s) to IP-address (%s)", QSTRING_CSTR(hostname), QSTRING_CSTR(hostAddress.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NetUtils::isValidPort(log, port, hostAddress.toString()))
|
||||||
|
{
|
||||||
|
areHostAddressPartOK = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return areHostAddressPartOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool resolveHostToAddress(Logger* log, const QString& hostname, QHostAddress& hostAddress)
|
||||||
|
{
|
||||||
|
int ignoredPort {MAX_PORT};
|
||||||
|
return resolveHostToAddress(log, hostname, hostAddress, ignoredPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
// settings
|
// settings
|
||||||
#include <utils/settings.h>
|
#include <utils/settings.h>
|
||||||
|
|
||||||
class BonjourServiceRegister;
|
|
||||||
class StaticFileServing;
|
class StaticFileServing;
|
||||||
class QtHttpServer;
|
class QtHttpServer;
|
||||||
|
|
||||||
@ -52,6 +51,11 @@ signals:
|
|||||||
///
|
///
|
||||||
void portChanged(quint16 port);
|
void portChanged(quint16 port);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @emits whenever the server would like to announce its service details
|
||||||
|
///
|
||||||
|
void publishService(const QString& serviceType, quint16 servicePort, const QByteArray& serviceName = "");
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
/// @brief Init server after thread start
|
/// @brief Init server after thread start
|
||||||
@ -93,8 +97,6 @@ private:
|
|||||||
const QString WEBSERVER_DEFAULT_CRT_PATH = ":/hyperion.crt";
|
const QString WEBSERVER_DEFAULT_CRT_PATH = ":/hyperion.crt";
|
||||||
const QString WEBSERVER_DEFAULT_KEY_PATH = ":/hyperion.key";
|
const QString WEBSERVER_DEFAULT_KEY_PATH = ":/hyperion.key";
|
||||||
quint16 WEBSERVER_DEFAULT_PORT = 8090;
|
quint16 WEBSERVER_DEFAULT_PORT = 8090;
|
||||||
|
|
||||||
BonjourServiceRegister * _serviceRegister = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WEBSERVER_H
|
#endif // WEBSERVER_H
|
||||||
|
@ -32,9 +32,9 @@ add_subdirectory(db)
|
|||||||
add_subdirectory(api)
|
add_subdirectory(api)
|
||||||
add_subdirectory(ssdp)
|
add_subdirectory(ssdp)
|
||||||
|
|
||||||
if(ENABLE_AVAHI)
|
if(ENABLE_MDNS)
|
||||||
add_subdirectory(bonjour)
|
add_subdirectory(mdns)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_EFFECTENGINE)
|
if(ENABLE_EFFECTENGINE)
|
||||||
add_subdirectory(effectengine)
|
add_subdirectory(effectengine)
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
// hyperion includes
|
// hyperion includes
|
||||||
#include <utils/jsonschema/QJsonFactory.h>
|
#include <utils/jsonschema/QJsonFactory.h>
|
||||||
@ -23,9 +24,6 @@
|
|||||||
#include <utils/ColorSys.h>
|
#include <utils/ColorSys.h>
|
||||||
#include <utils/Process.h>
|
#include <utils/Process.h>
|
||||||
|
|
||||||
// bonjour wrapper
|
|
||||||
#include <bonjour/bonjourbrowserwrapper.h>
|
|
||||||
|
|
||||||
// ledmapping int <> string transform methods
|
// ledmapping int <> string transform methods
|
||||||
#include <hyperion/ImageProcessor.h>
|
#include <hyperion/ImageProcessor.h>
|
||||||
|
|
||||||
@ -44,17 +42,13 @@ API::API(Logger *log, bool localConnection, QObject *parent)
|
|||||||
// Init
|
// Init
|
||||||
_log = log;
|
_log = log;
|
||||||
_authManager = AuthManager::getInstance();
|
_authManager = AuthManager::getInstance();
|
||||||
_instanceManager = HyperionIManager::getInstance();
|
_instanceManager = HyperionIManager::getInstance();
|
||||||
_localConnection = localConnection;
|
_localConnection = localConnection;
|
||||||
|
|
||||||
_authorized = false;
|
_authorized = false;
|
||||||
_adminAuthorized = false;
|
_adminAuthorized = false;
|
||||||
|
|
||||||
_hyperion = _instanceManager->getHyperionInstance(0);
|
|
||||||
_currInstanceIndex = 0;
|
_currInstanceIndex = 0;
|
||||||
// TODO FIXME
|
|
||||||
// report back current registers when a Hyperion instance request it
|
|
||||||
//connect(ApiSync::getInstance(), &ApiSync::requestActiveRegister, this, &API::requestActiveRegister, Qt::QueuedConnection);
|
|
||||||
|
|
||||||
// connect to possible token responses that has been requested
|
// connect to possible token responses that has been requested
|
||||||
connect(_authManager, &AuthManager::tokenResponse, [=] (bool success, QObject *caller, const QString &token, const QString &comment, const QString &id, const int &tan)
|
connect(_authManager, &AuthManager::tokenResponse, [=] (bool success, QObject *caller, const QString &token, const QString &comment, const QString &id, const int &tan)
|
||||||
@ -73,7 +67,7 @@ API::API(Logger *log, bool localConnection, QObject *parent)
|
|||||||
|
|
||||||
void API::init()
|
void API::init()
|
||||||
{
|
{
|
||||||
assert(_hyperion);
|
_hyperion = _instanceManager->getHyperionInstance(0);
|
||||||
|
|
||||||
bool apiAuthRequired = _authManager->isAuthRequired();
|
bool apiAuthRequired = _authManager->isAuthRequired();
|
||||||
|
|
||||||
@ -336,13 +330,6 @@ void API::stopInstance(quint8 index)
|
|||||||
QMetaObject::invokeMethod(_instanceManager, "stopInstance", Qt::QueuedConnection, Q_ARG(quint8, index));
|
QMetaObject::invokeMethod(_instanceManager, "stopInstance", Qt::QueuedConnection, Q_ARG(quint8, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
void API::requestActiveRegister(QObject *callerInstance)
|
|
||||||
{
|
|
||||||
// TODO FIXME
|
|
||||||
//if (_activeRegisters.size())
|
|
||||||
// QMetaObject::invokeMethod(ApiSync::getInstance(), "answerActiveRegister", Qt::QueuedConnection, Q_ARG(QObject *, callerInstance), Q_ARG(MapRegister, _activeRegisters));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool API::deleteInstance(quint8 index, QString &replyMsg)
|
bool API::deleteInstance(quint8 index, QString &replyMsg)
|
||||||
{
|
{
|
||||||
if (_adminAuthorized)
|
if (_adminAuthorized)
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
"subcommand": {
|
"subcommand": {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"enum" : ["discover","getProperties","identify"]
|
"enum": [ "discover", "getProperties", "identify", "addAuthorization" ]
|
||||||
},
|
},
|
||||||
"ledDeviceType": {
|
"ledDeviceType": {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
|
28
libsrc/api/JSONRPC_schema/schema-service.json
Normal file
28
libsrc/api/JSONRPC_schema/schema-service.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"type":"object",
|
||||||
|
"required":true,
|
||||||
|
"properties":{
|
||||||
|
"command": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"enum" : ["service"]
|
||||||
|
},
|
||||||
|
"tan" : {
|
||||||
|
"type" : "integer"
|
||||||
|
},
|
||||||
|
"subcommand": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"enum" : ["discover"]
|
||||||
|
},
|
||||||
|
"serviceType": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"type" : "object",
|
||||||
|
"required" : false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
"command": {
|
"command": {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "transform", "correction", "temperature" ]
|
"enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "service", "transform", "correction", "temperature" ]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
<file alias="schema-instance">JSONRPC_schema/schema-instance.json</file>
|
<file alias="schema-instance">JSONRPC_schema/schema-instance.json</file>
|
||||||
<file alias="schema-leddevice">JSONRPC_schema/schema-leddevice.json</file>
|
<file alias="schema-leddevice">JSONRPC_schema/schema-leddevice.json</file>
|
||||||
<file alias="schema-inputsource">JSONRPC_schema/schema-inputsource.json</file>
|
<file alias="schema-inputsource">JSONRPC_schema/schema-inputsource.json</file>
|
||||||
|
<file alias="schema-service">JSONRPC_schema/schema-service.json</file>
|
||||||
<!-- The following schemas are derecated but used to ensure backward compatibility with hyperion Classic remote control-->
|
<!-- The following schemas are derecated but used to ensure backward compatibility with hyperion Classic remote control-->
|
||||||
<file alias="schema-transform">JSONRPC_schema/schema-hyperion-classic.json</file>
|
<file alias="schema-transform">JSONRPC_schema/schema-hyperion-classic.json</file>
|
||||||
<file alias="schema-correction">JSONRPC_schema/schema-hyperion-classic.json</file>
|
<file alias="schema-correction">JSONRPC_schema/schema-hyperion-classic.json</file>
|
||||||
|
@ -63,11 +63,6 @@
|
|||||||
#include <utils/Process.h>
|
#include <utils/Process.h>
|
||||||
#include <utils/JsonUtils.h>
|
#include <utils/JsonUtils.h>
|
||||||
|
|
||||||
// bonjour wrapper
|
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
#include <bonjour/bonjourbrowserwrapper.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ledmapping int <> string transform methods
|
// ledmapping int <> string transform methods
|
||||||
#include <hyperion/ImageProcessor.h>
|
#include <hyperion/ImageProcessor.h>
|
||||||
|
|
||||||
@ -77,6 +72,15 @@
|
|||||||
// auth manager
|
// auth manager
|
||||||
#include <hyperion/AuthManager.h>
|
#include <hyperion/AuthManager.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
// mDNS discover
|
||||||
|
#include <mdns/MdnsBrowser.h>
|
||||||
|
#include <mdns/MdnsServiceRegister.h>
|
||||||
|
#else
|
||||||
|
// ssdp discover
|
||||||
|
#include <ssdp/SSDPDiscover.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace hyperion;
|
using namespace hyperion;
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
@ -98,8 +102,6 @@ void JsonAPI::initialize()
|
|||||||
{
|
{
|
||||||
// init API, REQUIRED!
|
// init API, REQUIRED!
|
||||||
API::init();
|
API::init();
|
||||||
// Initialise jsonCB with current instance
|
|
||||||
_jsonCB->setSubscriptionsTo(_hyperion);
|
|
||||||
|
|
||||||
// setup auth interface
|
// setup auth interface
|
||||||
connect(this, &API::onPendingTokenRequest, this, &JsonAPI::newPendingTokenRequest);
|
connect(this, &API::onPendingTokenRequest, this, &JsonAPI::newPendingTokenRequest);
|
||||||
@ -112,7 +114,12 @@ void JsonAPI::initialize()
|
|||||||
connect(_jsonCB, &JsonCB::newCallback, this, &JsonAPI::callbackMessage);
|
connect(_jsonCB, &JsonCB::newCallback, this, &JsonAPI::callbackMessage);
|
||||||
|
|
||||||
// notify hyperion about a jsonMessageForward
|
// notify hyperion about a jsonMessageForward
|
||||||
connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage);
|
if (_hyperion != nullptr)
|
||||||
|
{
|
||||||
|
// Initialise jsonCB with current instance
|
||||||
|
_jsonCB->setSubscriptionsTo(_hyperion);
|
||||||
|
connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JsonAPI::handleInstanceSwitch(quint8 inst, bool forced)
|
bool JsonAPI::handleInstanceSwitch(quint8 inst, bool forced)
|
||||||
@ -180,6 +187,12 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
proceed:
|
proceed:
|
||||||
|
if (_hyperion == nullptr)
|
||||||
|
{
|
||||||
|
sendErrorReply("Service Unavailable", command, tan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// switch over all possible commands and handle them
|
// switch over all possible commands and handle them
|
||||||
if (command == "color")
|
if (command == "color")
|
||||||
handleColorCommand(message, command, tan);
|
handleColorCommand(message, command, tan);
|
||||||
@ -221,6 +234,8 @@ proceed:
|
|||||||
handleLedDeviceCommand(message, command, tan);
|
handleLedDeviceCommand(message, command, tan);
|
||||||
else if (command == "inputsource")
|
else if (command == "inputsource")
|
||||||
handleInputSourceCommand(message, command, tan);
|
handleInputSourceCommand(message, command, tan);
|
||||||
|
else if (command == "service")
|
||||||
|
handleServiceCommand(message, command, tan);
|
||||||
|
|
||||||
// BEGIN | The following commands are deprecated but used to ensure backward compatibility with hyperion Classic remote control
|
// BEGIN | The following commands are deprecated but used to ensure backward compatibility with hyperion Classic remote control
|
||||||
else if (command == "clearall")
|
else if (command == "clearall")
|
||||||
@ -627,6 +642,11 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
|
|||||||
services.append("protobuffer");
|
services.append("protobuffer");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_MDNS)
|
||||||
|
services.append("mDNS");
|
||||||
|
#endif
|
||||||
|
services.append("SSDP");
|
||||||
|
|
||||||
if (!availableScreenGrabbers.isEmpty() || !availableVideoGrabbers.isEmpty() || services.contains("flatbuffer") || services.contains("protobuffer"))
|
if (!availableScreenGrabbers.isEmpty() || !availableVideoGrabbers.isEmpty() || services.contains("flatbuffer") || services.contains("protobuffer"))
|
||||||
{
|
{
|
||||||
services.append("borderdetection");
|
services.append("borderdetection");
|
||||||
@ -649,24 +669,6 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
|
|||||||
info["components"] = component;
|
info["components"] = component;
|
||||||
info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(_hyperion->getLedMappingType());
|
info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(_hyperion->getLedMappingType());
|
||||||
|
|
||||||
// add sessions
|
|
||||||
QJsonArray sessions;
|
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
for (auto session: BonjourBrowserWrapper::getInstance()->getAllServices())
|
|
||||||
{
|
|
||||||
if (session.port < 0)
|
|
||||||
continue;
|
|
||||||
QJsonObject item;
|
|
||||||
item["name"] = session.serviceName;
|
|
||||||
item["type"] = session.registeredType;
|
|
||||||
item["domain"] = session.replyDomain;
|
|
||||||
item["host"] = session.hostName;
|
|
||||||
item["address"] = session.address;
|
|
||||||
item["port"] = session.port;
|
|
||||||
sessions.append(item);
|
|
||||||
}
|
|
||||||
info["sessions"] = sessions;
|
|
||||||
#endif
|
|
||||||
// add instance info
|
// add instance info
|
||||||
QJsonArray instanceInfo;
|
QJsonArray instanceInfo;
|
||||||
for (const auto &entry : API::getAllInstanceData())
|
for (const auto &entry : API::getAllInstanceData())
|
||||||
@ -1571,6 +1573,16 @@ void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const QString &
|
|||||||
|
|
||||||
sendSuccessReply(full_command, tan);
|
sendSuccessReply(full_command, tan);
|
||||||
}
|
}
|
||||||
|
else if (subc == "addAuthorization")
|
||||||
|
{
|
||||||
|
ledDevice = LedDeviceFactory::construct(config);
|
||||||
|
const QJsonObject& params = message["params"].toObject();
|
||||||
|
const QJsonObject response = ledDevice->addAuthorization(params);
|
||||||
|
|
||||||
|
Debug(_log, "response: [%s]", QString(QJsonDocument(response).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
sendSuccessDataReply(QJsonDocument(response), full_command, tan);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sendErrorReply("Unknown or missing subcommand", full_command, tan);
|
sendErrorReply("Unknown or missing subcommand", full_command, tan);
|
||||||
@ -1725,6 +1737,55 @@ void JsonAPI::handleInputSourceCommand(const QJsonObject& message, const QString
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JsonAPI::handleServiceCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
const QString &subc = message["subcommand"].toString().trimmed();
|
||||||
|
const QString type = message["serviceType"].toString().trimmed();
|
||||||
|
|
||||||
|
QString full_command = command + "-" + subc;
|
||||||
|
|
||||||
|
if (subc == "discover")
|
||||||
|
{
|
||||||
|
QByteArray serviceType;
|
||||||
|
|
||||||
|
QJsonObject servicesDiscovered;
|
||||||
|
QJsonObject servicesOfType;
|
||||||
|
QJsonArray serviceList;
|
||||||
|
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
QString discoveryMethod("mDNS");
|
||||||
|
serviceType = MdnsServiceRegister::getServiceType(type);
|
||||||
|
#else
|
||||||
|
QString discoveryMethod("ssdp");
|
||||||
|
#endif
|
||||||
|
if (!serviceType.isEmpty())
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||||
|
Qt::QueuedConnection, Q_ARG(QByteArray, serviceType));
|
||||||
|
|
||||||
|
serviceList = MdnsBrowser::getInstance().getServicesDiscoveredJson(serviceType, MdnsServiceRegister::getServiceNameFilter(type), DEFAULT_DISCOVER_TIMEOUT);
|
||||||
|
#endif
|
||||||
|
servicesOfType.insert(type, serviceList);
|
||||||
|
|
||||||
|
servicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
||||||
|
servicesDiscovered.insert("services", servicesOfType);
|
||||||
|
|
||||||
|
sendSuccessDataReply(QJsonDocument(servicesDiscovered), full_command, tan);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendErrorReply(QString("Discovery of service type [%1] via %2 not supported").arg(type, discoveryMethod), full_command, tan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendErrorReply("Unknown or missing subcommand", full_command, tan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void JsonAPI::handleNotImplemented(const QString &command, int tan)
|
void JsonAPI::handleNotImplemented(const QString &command, int tan)
|
||||||
{
|
{
|
||||||
sendErrorReply("Command not implemented", command, tan);
|
sendErrorReply("Command not implemented", command, tan);
|
||||||
|
@ -9,10 +9,6 @@
|
|||||||
// components
|
// components
|
||||||
|
|
||||||
#include <hyperion/ComponentRegister.h>
|
#include <hyperion/ComponentRegister.h>
|
||||||
// bonjour wrapper
|
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
#include <bonjour/bonjourbrowserwrapper.h>
|
|
||||||
#endif
|
|
||||||
// priorityMuxer
|
// priorityMuxer
|
||||||
|
|
||||||
#include <hyperion/PriorityMuxer.h>
|
#include <hyperion/PriorityMuxer.h>
|
||||||
@ -33,12 +29,9 @@ JsonCB::JsonCB(QObject* parent)
|
|||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, _hyperion(nullptr)
|
, _hyperion(nullptr)
|
||||||
, _componentRegister(nullptr)
|
, _componentRegister(nullptr)
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
, _bonjour(BonjourBrowserWrapper::getInstance())
|
|
||||||
#endif
|
|
||||||
, _prioMuxer(nullptr)
|
, _prioMuxer(nullptr)
|
||||||
{
|
{
|
||||||
_availableCommands << "components-update" << "sessions-update" << "priorities-update" << "imageToLedMapping-update"
|
_availableCommands << "components-update" << "priorities-update" << "imageToLedMapping-update"
|
||||||
<< "adjustment-update" << "videomode-update" << "settings-update" << "leds-update" << "instance-update" << "token-update";
|
<< "adjustment-update" << "videomode-update" << "settings-update" << "leds-update" << "instance-update" << "token-update";
|
||||||
|
|
||||||
#if defined(ENABLE_EFFECTENGINE)
|
#if defined(ENABLE_EFFECTENGINE)
|
||||||
@ -66,16 +59,6 @@ bool JsonCB::subscribeFor(const QString& type, bool unsubscribe)
|
|||||||
connect(_componentRegister, &ComponentRegister::updatedComponentState, this, &JsonCB::handleComponentState, Qt::UniqueConnection);
|
connect(_componentRegister, &ComponentRegister::updatedComponentState, this, &JsonCB::handleComponentState, Qt::UniqueConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type == "sessions-update")
|
|
||||||
{
|
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
if(unsubscribe)
|
|
||||||
disconnect(_bonjour, &BonjourBrowserWrapper::browserChange, this, &JsonCB::handleBonjourChange);
|
|
||||||
else
|
|
||||||
connect(_bonjour, &BonjourBrowserWrapper::browserChange, this, &JsonCB::handleBonjourChange, Qt::UniqueConnection);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if(type == "priorities-update")
|
if(type == "priorities-update")
|
||||||
{
|
{
|
||||||
if (unsubscribe)
|
if (unsubscribe)
|
||||||
@ -208,26 +191,6 @@ void JsonCB::handleComponentState(hyperion::Components comp, bool state)
|
|||||||
|
|
||||||
doCallback("components-update", QVariant(data));
|
doCallback("components-update", QVariant(data));
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
void JsonCB::handleBonjourChange(const QMap<QString,BonjourRecord>& bRegisters)
|
|
||||||
{
|
|
||||||
QJsonArray data;
|
|
||||||
for (const auto & session: bRegisters)
|
|
||||||
{
|
|
||||||
if (session.port<0) continue;
|
|
||||||
QJsonObject item;
|
|
||||||
item["name"] = session.serviceName;
|
|
||||||
item["type"] = session.registeredType;
|
|
||||||
item["domain"] = session.replyDomain;
|
|
||||||
item["host"] = session.hostName;
|
|
||||||
item["address"]= session.address;
|
|
||||||
item["port"] = session.port;
|
|
||||||
data.append(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
doCallback("sessions-update", QVariant(data));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void JsonCB::handlePriorityUpdate(int currentPriority, const PriorityMuxer::InputsMap& activeInputs)
|
void JsonCB::handlePriorityUpdate(int currentPriority, const PriorityMuxer::InputsMap& activeInputs)
|
||||||
{
|
{
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
|
|
||||||
# Define the current source locations
|
|
||||||
set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/bonjour)
|
|
||||||
set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/bonjour)
|
|
||||||
|
|
||||||
FILE ( GLOB Bonjour_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" )
|
|
||||||
|
|
||||||
add_library(bonjour ${Bonjour_SOURCES} )
|
|
||||||
|
|
||||||
target_link_libraries(bonjour
|
|
||||||
hyperion
|
|
||||||
hyperion-utils
|
|
||||||
Qt${QT_VERSION_MAJOR}::Network
|
|
||||||
)
|
|
||||||
|
|
||||||
IF (NOT APPLE)
|
|
||||||
set(USE_SHARED_AVAHI_LIBS ${DEFAULT_USE_SHARED_AVAHI_LIBS} CACHE BOOL "use avahi libraries from system")
|
|
||||||
|
|
||||||
if (USE_SHARED_AVAHI_LIBS)
|
|
||||||
target_link_libraries(bonjour
|
|
||||||
dns_sd
|
|
||||||
avahi-client
|
|
||||||
avahi-common
|
|
||||||
avahi-core)
|
|
||||||
else()
|
|
||||||
target_link_libraries(bonjour
|
|
||||||
libdns_sd.a
|
|
||||||
libavahi-client.a
|
|
||||||
libavahi-common.a
|
|
||||||
libavahi-core.a)
|
|
||||||
endif()
|
|
||||||
target_link_libraries(bonjour dbus-1)
|
|
||||||
ENDIF()
|
|
@ -1,84 +0,0 @@
|
|||||||
#include <bonjour/bonjourbrowserwrapper.h>
|
|
||||||
|
|
||||||
//qt incl
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
// bonjour
|
|
||||||
#include <bonjour/bonjourservicebrowser.h>
|
|
||||||
#include <bonjour/bonjourserviceresolver.h>
|
|
||||||
|
|
||||||
BonjourBrowserWrapper* BonjourBrowserWrapper::instance = nullptr;
|
|
||||||
|
|
||||||
BonjourBrowserWrapper::BonjourBrowserWrapper(QObject * parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, _bonjourResolver(new BonjourServiceResolver(this))
|
|
||||||
, _timerBonjourResolver(new QTimer(this))
|
|
||||||
{
|
|
||||||
// register meta
|
|
||||||
qRegisterMetaType<QMap<QString,BonjourRecord>>("QMap<QString,BonjourRecord>");
|
|
||||||
|
|
||||||
BonjourBrowserWrapper::instance = this;
|
|
||||||
connect(_bonjourResolver, &BonjourServiceResolver::bonjourRecordResolved, this, &BonjourBrowserWrapper::bonjourRecordResolved);
|
|
||||||
|
|
||||||
connect(_timerBonjourResolver, &QTimer::timeout, this, &BonjourBrowserWrapper::bonjourResolve);
|
|
||||||
_timerBonjourResolver->setInterval(1000);
|
|
||||||
_timerBonjourResolver->start();
|
|
||||||
|
|
||||||
// browse for _hyperiond-http._tcp
|
|
||||||
browseForServiceType(QLatin1String("_hyperiond-http._tcp"));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BonjourBrowserWrapper::browseForServiceType(const QString &serviceType)
|
|
||||||
{
|
|
||||||
if(!_browsedServices.contains(serviceType))
|
|
||||||
{
|
|
||||||
BonjourServiceBrowser* newBrowser = new BonjourServiceBrowser(this);
|
|
||||||
connect(newBrowser, &BonjourServiceBrowser::currentBonjourRecordsChanged, this, &BonjourBrowserWrapper::currentBonjourRecordsChanged);
|
|
||||||
newBrowser->browseForServiceType(serviceType);
|
|
||||||
_browsedServices.insert(serviceType, newBrowser);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourBrowserWrapper::currentBonjourRecordsChanged(const QList<BonjourRecord> &list)
|
|
||||||
{
|
|
||||||
_hyperionSessions.clear();
|
|
||||||
for ( auto rec : list )
|
|
||||||
{
|
|
||||||
_hyperionSessions.insert(rec.serviceName, rec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourBrowserWrapper::bonjourRecordResolved(const QHostInfo &hostInfo, int port)
|
|
||||||
{
|
|
||||||
if ( _hyperionSessions.contains(_bonjourCurrentServiceToResolve))
|
|
||||||
{
|
|
||||||
QString host = hostInfo.hostName();
|
|
||||||
QString domain = _hyperionSessions[_bonjourCurrentServiceToResolve].replyDomain;
|
|
||||||
if (host.endsWith("."+domain))
|
|
||||||
{
|
|
||||||
host.remove(host.length()-domain.length()-1,domain.length()+1);
|
|
||||||
}
|
|
||||||
_hyperionSessions[_bonjourCurrentServiceToResolve].hostName = host;
|
|
||||||
_hyperionSessions[_bonjourCurrentServiceToResolve].port = port;
|
|
||||||
_hyperionSessions[_bonjourCurrentServiceToResolve].address = hostInfo.addresses().isEmpty() ? "" : hostInfo.addresses().first().toString();
|
|
||||||
//Debug(_log, "found hyperion session: %s:%d",QSTRING_CSTR(hostInfo.hostName()), port);
|
|
||||||
|
|
||||||
//emit change
|
|
||||||
emit browserChange(_hyperionSessions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourBrowserWrapper::bonjourResolve()
|
|
||||||
{
|
|
||||||
for(auto key : _hyperionSessions.keys())
|
|
||||||
{
|
|
||||||
if (_hyperionSessions[key].port < 0)
|
|
||||||
{
|
|
||||||
_bonjourCurrentServiceToResolve = key;
|
|
||||||
_bonjourResolver->resolveBonjourRecord(_hyperionSessions[key]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2007, Trenton Schulz
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. The name of the author may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "bonjour/bonjourservicebrowser.h"
|
|
||||||
|
|
||||||
#include <QtCore/QSocketNotifier>
|
|
||||||
|
|
||||||
BonjourServiceBrowser::BonjourServiceBrowser(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, dnssref(0)
|
|
||||||
, bonjourSocket(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
BonjourServiceBrowser::~BonjourServiceBrowser()
|
|
||||||
{
|
|
||||||
if (dnssref)
|
|
||||||
{
|
|
||||||
DNSServiceRefDeallocate(dnssref);
|
|
||||||
dnssref = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourServiceBrowser::browseForServiceType(const QString &serviceType)
|
|
||||||
{
|
|
||||||
DNSServiceErrorType err = DNSServiceBrowse(&dnssref, 0, 0, serviceType.toUtf8().constData(), 0, bonjourBrowseReply, this);
|
|
||||||
if (err != kDNSServiceErr_NoError)
|
|
||||||
{
|
|
||||||
emit error(err);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int sockfd = DNSServiceRefSockFD(dnssref);
|
|
||||||
if (sockfd == -1)
|
|
||||||
{
|
|
||||||
emit error(kDNSServiceErr_Invalid);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this);
|
|
||||||
connect(bonjourSocket, &QSocketNotifier::activated, this, &BonjourServiceBrowser::bonjourSocketReadyRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourServiceBrowser::bonjourSocketReadyRead()
|
|
||||||
{
|
|
||||||
DNSServiceErrorType err = DNSServiceProcessResult(dnssref);
|
|
||||||
if (err != kDNSServiceErr_NoError)
|
|
||||||
{
|
|
||||||
emit error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourServiceBrowser::bonjourBrowseReply(DNSServiceRef , DNSServiceFlags flags,
|
|
||||||
quint32 , DNSServiceErrorType errorCode,
|
|
||||||
const char *serviceName, const char *regType,
|
|
||||||
const char *replyDomain, void *context)
|
|
||||||
{
|
|
||||||
BonjourServiceBrowser *serviceBrowser = static_cast<BonjourServiceBrowser *>(context);
|
|
||||||
if (errorCode != kDNSServiceErr_NoError)
|
|
||||||
{
|
|
||||||
emit serviceBrowser->error(errorCode);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BonjourRecord bonjourRecord(serviceName, regType, replyDomain);
|
|
||||||
if ((flags & kDNSServiceFlagsAdd) != 0)
|
|
||||||
{
|
|
||||||
if (!serviceBrowser->bonjourRecords.contains(bonjourRecord))
|
|
||||||
{
|
|
||||||
serviceBrowser->bonjourRecords.append(bonjourRecord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
serviceBrowser->bonjourRecords.removeAll(bonjourRecord);
|
|
||||||
}
|
|
||||||
if (!(flags & kDNSServiceFlagsMoreComing))
|
|
||||||
{
|
|
||||||
emit serviceBrowser->currentBonjourRecordsChanged(serviceBrowser->bonjourRecords);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,151 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2007, Trenton Schulz
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. The name of the author may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <bonjour/bonjourserviceregister.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <QtCore/QSocketNotifier>
|
|
||||||
#include <QHostInfo>
|
|
||||||
|
|
||||||
#include <utils/Logger.h>
|
|
||||||
#include <HyperionConfig.h>
|
|
||||||
#include <hyperion/AuthManager.h>
|
|
||||||
|
|
||||||
BonjourServiceRegister::BonjourServiceRegister(QObject *parent)
|
|
||||||
: QObject(parent), dnssref(0), bonjourSocket(0)
|
|
||||||
{
|
|
||||||
setenv("AVAHI_COMPAT_NOWARN", "1", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
BonjourServiceRegister::~BonjourServiceRegister()
|
|
||||||
{
|
|
||||||
if (dnssref)
|
|
||||||
{
|
|
||||||
DNSServiceRefDeallocate(dnssref);
|
|
||||||
dnssref = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourServiceRegister::registerService(const QString& service, int port)
|
|
||||||
{
|
|
||||||
_port = port;
|
|
||||||
// zeroconf $configname@$hostname:port
|
|
||||||
// TODO add name of the main instance
|
|
||||||
registerService(
|
|
||||||
BonjourRecord(QHostInfo::localHostName()+ ":" + QString::number(port),
|
|
||||||
service,
|
|
||||||
QString()
|
|
||||||
),
|
|
||||||
port
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourServiceRegister::registerService(const BonjourRecord &record, quint16 servicePort, const std::vector<std::pair<std::string, std::string>>& txt)
|
|
||||||
{
|
|
||||||
if (dnssref)
|
|
||||||
{
|
|
||||||
Warning(Logger::getInstance("BonJour"), "Already registered a service for this object, aborting new register");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
quint16 bigEndianPort = servicePort;
|
|
||||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
|
||||||
{
|
|
||||||
bigEndianPort = 0 | ((servicePort & 0x00ff) << 8) | ((servicePort & 0xff00) >> 8);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// base txtRec
|
|
||||||
std::vector<std::pair<std::string, std::string> > txtBase = {{"id",AuthManager::getInstance()->getID().toStdString()},{"version",HYPERION_VERSION}};
|
|
||||||
// create txt record
|
|
||||||
TXTRecordRef txtRec;
|
|
||||||
TXTRecordCreate(&txtRec,0,NULL);
|
|
||||||
|
|
||||||
if(!txt.empty())
|
|
||||||
{
|
|
||||||
txtBase.insert(txtBase.end(), txt.begin(), txt.end());
|
|
||||||
}
|
|
||||||
// add txt records
|
|
||||||
for(std::vector<std::pair<std::string, std::string> >::const_iterator it = txtBase.begin(); it != txtBase.end(); ++it)
|
|
||||||
{
|
|
||||||
//Debug(Logger::getInstance("BonJour"), "TXTRecord: key:%s, value:%s",it->first.c_str(),it->second.c_str());
|
|
||||||
uint8_t txtLen = (uint8_t)strlen(it->second.c_str());
|
|
||||||
TXTRecordSetValue(&txtRec, it->first.c_str(), txtLen, it->second.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DNSServiceErrorType err = DNSServiceRegister(&dnssref, 0, 0, record.serviceName.toUtf8().constData(),
|
|
||||||
record.registeredType.toUtf8().constData(),
|
|
||||||
(record.replyDomain.isEmpty() ? 0 : record.replyDomain.toUtf8().constData()),
|
|
||||||
0, bigEndianPort, TXTRecordGetLength(&txtRec), TXTRecordGetBytesPtr(&txtRec), bonjourRegisterService, this);
|
|
||||||
if (err != kDNSServiceErr_NoError)
|
|
||||||
{
|
|
||||||
emit error(err);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int sockfd = DNSServiceRefSockFD(dnssref);
|
|
||||||
if (sockfd == -1)
|
|
||||||
{
|
|
||||||
emit error(kDNSServiceErr_Invalid);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this);
|
|
||||||
connect(bonjourSocket, &QSocketNotifier::activated, this, &BonjourServiceRegister::bonjourSocketReadyRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TXTRecordDeallocate(&txtRec);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BonjourServiceRegister::bonjourSocketReadyRead()
|
|
||||||
{
|
|
||||||
DNSServiceErrorType err = DNSServiceProcessResult(dnssref);
|
|
||||||
if (err != kDNSServiceErr_NoError)
|
|
||||||
emit error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BonjourServiceRegister::bonjourRegisterService(DNSServiceRef, DNSServiceFlags,
|
|
||||||
DNSServiceErrorType errorCode, const char *name,
|
|
||||||
const char *regtype, const char *domain,
|
|
||||||
void *data)
|
|
||||||
{
|
|
||||||
BonjourServiceRegister *serviceRegister = static_cast<BonjourServiceRegister *>(data);
|
|
||||||
if (errorCode != kDNSServiceErr_NoError)
|
|
||||||
{
|
|
||||||
emit serviceRegister->error(errorCode);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
serviceRegister->finalRecord = BonjourRecord(QString::fromUtf8(name),
|
|
||||||
QString::fromUtf8(regtype),
|
|
||||||
QString::fromUtf8(domain));
|
|
||||||
emit serviceRegister->serviceRegistered(serviceRegister->finalRecord);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2007, Trenton Schulz
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. The name of the author may not be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
||||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <QtCore/QSocketNotifier>
|
|
||||||
#include <QtNetwork/QHostInfo>
|
|
||||||
|
|
||||||
#include "bonjour/bonjourrecord.h"
|
|
||||||
#include "bonjour/bonjourserviceresolver.h"
|
|
||||||
|
|
||||||
BonjourServiceResolver::BonjourServiceResolver(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, dnssref(0)
|
|
||||||
, bonjourSocket(0)
|
|
||||||
, bonjourPort(-1)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
BonjourServiceResolver::~BonjourServiceResolver()
|
|
||||||
{
|
|
||||||
cleanupResolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourServiceResolver::cleanupResolve()
|
|
||||||
{
|
|
||||||
if (dnssref)
|
|
||||||
{
|
|
||||||
DNSServiceRefDeallocate(dnssref);
|
|
||||||
dnssref = 0;
|
|
||||||
delete bonjourSocket;
|
|
||||||
bonjourPort = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BonjourServiceResolver::resolveBonjourRecord(const BonjourRecord &record)
|
|
||||||
{
|
|
||||||
if (dnssref)
|
|
||||||
{
|
|
||||||
//qWarning("resolve in process, aborting");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DNSServiceErrorType err = DNSServiceResolve(&dnssref, 0, 0,
|
|
||||||
record.serviceName.toUtf8().constData(),
|
|
||||||
record.registeredType.toUtf8().constData(),
|
|
||||||
record.replyDomain.toUtf8().constData(),
|
|
||||||
(DNSServiceResolveReply)bonjourResolveReply, this);
|
|
||||||
if (err != kDNSServiceErr_NoError)
|
|
||||||
{
|
|
||||||
emit error(err);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int sockfd = DNSServiceRefSockFD(dnssref);
|
|
||||||
if (sockfd == -1)
|
|
||||||
{
|
|
||||||
emit error(kDNSServiceErr_Invalid);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this);
|
|
||||||
connect(bonjourSocket, &QSocketNotifier::activated, this, &BonjourServiceResolver::bonjourSocketReadyRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourServiceResolver::bonjourSocketReadyRead()
|
|
||||||
{
|
|
||||||
DNSServiceErrorType err = DNSServiceProcessResult(dnssref);
|
|
||||||
if (err != kDNSServiceErr_NoError)
|
|
||||||
emit error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourServiceResolver::bonjourResolveReply(DNSServiceRef sdRef, DNSServiceFlags ,
|
|
||||||
quint32 , DNSServiceErrorType errorCode,
|
|
||||||
const char *, const char *hosttarget, quint16 port,
|
|
||||||
quint16 , const char *, void *context)
|
|
||||||
{
|
|
||||||
BonjourServiceResolver *serviceResolver = static_cast<BonjourServiceResolver *>(context);
|
|
||||||
if (errorCode != kDNSServiceErr_NoError) {
|
|
||||||
emit serviceResolver->error(errorCode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
|
||||||
{
|
|
||||||
port = 0 | ((port & 0x00ff) << 8) | ((port & 0xff00) >> 8);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
serviceResolver->bonjourPort = port;
|
|
||||||
|
|
||||||
QHostInfo::lookupHost(QString::fromUtf8(hosttarget), serviceResolver, SLOT(finishConnect(const QHostInfo &)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonjourServiceResolver::finishConnect(const QHostInfo &hostInfo)
|
|
||||||
{
|
|
||||||
emit bonjourRecordResolved(hostInfo, bonjourPort);
|
|
||||||
QMetaObject::invokeMethod(this, "cleanupResolve", Qt::QueuedConnection);
|
|
||||||
}
|
|
@ -8,6 +8,8 @@
|
|||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
/* Enable to turn on detailed CEC logs */
|
/* Enable to turn on detailed CEC logs */
|
||||||
// #define VERBOSE_CEC
|
// #define VERBOSE_CEC
|
||||||
@ -34,15 +36,16 @@ bool CECHandler::start()
|
|||||||
if (_cecAdapter)
|
if (_cecAdapter)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Info(_logger, "Starting CEC handler");
|
std::string library = std::string("" CEC_LIBRARY);
|
||||||
|
_cecAdapter = LibCecInitialise(&_cecConfig, QFile::exists(QString::fromStdString(library)) ? library.c_str() : nullptr);
|
||||||
_cecAdapter = LibCecInitialise(&_cecConfig);
|
|
||||||
if(!_cecAdapter)
|
if(!_cecAdapter)
|
||||||
{
|
{
|
||||||
Error(_logger, "Failed loading libcec.so");
|
Error(_logger, "Failed to loading libcec.so");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Info(_logger, "CEC handler started");
|
||||||
|
|
||||||
auto adapters = getAdapters();
|
auto adapters = getAdapters();
|
||||||
if (adapters.isEmpty())
|
if (adapters.isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -5,13 +5,14 @@ SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/cec)
|
|||||||
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/cec)
|
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/cec)
|
||||||
|
|
||||||
FILE (GLOB CEC_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp")
|
FILE (GLOB CEC_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp")
|
||||||
|
|
||||||
add_library(cechandler ${CEC_SOURCES})
|
add_library(cechandler ${CEC_SOURCES})
|
||||||
|
add_definitions(-DCEC_LIBRARY="${CEC_LIBRARIES}")
|
||||||
|
|
||||||
include_directories(${CEC_INCLUDE_DIRS})
|
include_directories(${CEC_INCLUDE_DIRS})
|
||||||
|
|
||||||
target_link_libraries(cechandler
|
target_link_libraries(cechandler
|
||||||
dl
|
|
||||||
${CEC_LIBRARIES}
|
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
|
${CMAKE_DL_LIBS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,5 +60,10 @@ flatbuffers
|
|||||||
Qt${QT_VERSION_MAJOR}::Network
|
Qt${QT_VERSION_MAJOR}::Network
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(ENABLE_MDNS)
|
||||||
|
target_link_libraries(flatbufserver mdns)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ FlatBufferConnection::FlatBufferConnection(const QString& origin, const QString&
|
|||||||
|
|
||||||
FlatBufferConnection::~FlatBufferConnection()
|
FlatBufferConnection::~FlatBufferConnection()
|
||||||
{
|
{
|
||||||
|
Debug(_log, "Closing connection to: %s:%u", QSTRING_CSTR(_host), _port);
|
||||||
_timer.stop();
|
_timer.stop();
|
||||||
_socket.close();
|
_socket.close();
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,18 @@
|
|||||||
#include <utils/NetOrigin.h>
|
#include <utils/NetOrigin.h>
|
||||||
#include <utils/GlobalSignals.h>
|
#include <utils/GlobalSignals.h>
|
||||||
|
|
||||||
// bonjour
|
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
#include <bonjour/bonjourserviceregister.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// qt
|
// qt
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char SERVICE_TYPE[] = "flatbuffer";
|
||||||
|
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
FlatBufferServer::FlatBufferServer(const QJsonDocument& config, QObject* parent)
|
FlatBufferServer::FlatBufferServer(const QJsonDocument& config, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, _server(new QTcpServer(this))
|
, _server(new QTcpServer(this))
|
||||||
@ -106,19 +108,8 @@ void FlatBufferServer::startServer()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Info(_log,"Started on port %d", _port);
|
Info(_log,"Started on port %d", _port);
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
if(_serviceRegister == nullptr)
|
emit publishService(SERVICE_TYPE, _port);
|
||||||
{
|
|
||||||
_serviceRegister = new BonjourServiceRegister(this);
|
|
||||||
_serviceRegister->registerService("_hyperiond-flatbuf._tcp", _port);
|
|
||||||
}
|
|
||||||
else if(_serviceRegister->getPort() != _port)
|
|
||||||
{
|
|
||||||
delete _serviceRegister;
|
|
||||||
_serviceRegister = new BonjourServiceRegister(this);
|
|
||||||
_serviceRegister->registerService("_hyperiond-flatbuf._tcp", _port);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// STL includes
|
// STL includes
|
||||||
#include <stdexcept>
|
#include <chrono>
|
||||||
|
|
||||||
// project includes
|
// project includes
|
||||||
#include <forwarder/MessageForwarder.h>
|
#include <forwarder/MessageForwarder.h>
|
||||||
@ -12,23 +12,46 @@
|
|||||||
#include <utils/NetUtils.h>
|
#include <utils/NetUtils.h>
|
||||||
|
|
||||||
// qt includes
|
// qt includes
|
||||||
#include <QTcpServer>
|
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QHostInfo>
|
#include <QHostInfo>
|
||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include <flatbufserver/FlatBufferConnection.h>
|
#include <flatbufserver/FlatBufferConnection.h>
|
||||||
|
|
||||||
|
// mDNS discover
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
#include <mdns/MdnsBrowser.h>
|
||||||
|
#include <mdns/MdnsServiceRegister.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const int DEFAULT_FORWARDER_FLATBUFFFER_PRIORITY = 140;
|
||||||
|
|
||||||
|
constexpr std::chrono::milliseconds CONNECT_TIMEOUT{500}; // JSON-socket connect timeout in ms
|
||||||
|
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
MessageForwarder::MessageForwarder(Hyperion* hyperion)
|
MessageForwarder::MessageForwarder(Hyperion* hyperion)
|
||||||
: _hyperion(hyperion)
|
: _hyperion(hyperion)
|
||||||
, _log(nullptr)
|
, _log(nullptr)
|
||||||
, _muxer(_hyperion->getMuxerInstance())
|
, _muxer(_hyperion->getMuxerInstance())
|
||||||
, _forwarder_enabled(true)
|
, _forwarder_enabled(false)
|
||||||
, _priority(140)
|
, _priority(DEFAULT_FORWARDER_FLATBUFFFER_PRIORITY)
|
||||||
|
, _messageForwarderFlatBufHelper(nullptr)
|
||||||
{
|
{
|
||||||
QString subComponent = hyperion->property("instance").toString();
|
QString subComponent = hyperion->property("instance").toString();
|
||||||
_log= Logger::getInstance("NETFORWARDER", subComponent);
|
_log= Logger::getInstance("NETFORWARDER", subComponent);
|
||||||
|
|
||||||
|
qRegisterMetaType<TargetHost>("TargetHost");
|
||||||
|
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||||
|
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType("jsonapi")));
|
||||||
|
#endif
|
||||||
|
|
||||||
// get settings updates
|
// get settings updates
|
||||||
connect(_hyperion, &Hyperion::settingsChanged, this, &MessageForwarder::handleSettingsUpdate);
|
connect(_hyperion, &Hyperion::settingsChanged, this, &MessageForwarder::handleSettingsUpdate);
|
||||||
|
|
||||||
@ -37,82 +60,23 @@ MessageForwarder::MessageForwarder(Hyperion* hyperion)
|
|||||||
|
|
||||||
// connect with Muxer visible priority changes
|
// connect with Muxer visible priority changes
|
||||||
connect(_muxer, &PriorityMuxer::visiblePriorityChanged, this, &MessageForwarder::handlePriorityChanges);
|
connect(_muxer, &PriorityMuxer::visiblePriorityChanged, this, &MessageForwarder::handlePriorityChanges);
|
||||||
|
|
||||||
// init
|
|
||||||
handleSettingsUpdate(settings::NETFORWARD, _hyperion->getSetting(settings::NETFORWARD));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageForwarder::~MessageForwarder()
|
MessageForwarder::~MessageForwarder()
|
||||||
{
|
{
|
||||||
while (!_forwardClients.isEmpty())
|
stopJsonTargets();
|
||||||
{
|
stopFlatbufferTargets();
|
||||||
delete _forwardClients.takeFirst();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MessageForwarder::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
|
void MessageForwarder::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
|
||||||
{
|
{
|
||||||
if (type == settings::NETFORWARD)
|
if (type == settings::NETFORWARD)
|
||||||
{
|
{
|
||||||
// clear the current targets
|
|
||||||
_jsonTargets.clear();
|
|
||||||
_flatbufferTargets.clear();
|
|
||||||
while (!_forwardClients.isEmpty())
|
|
||||||
{
|
|
||||||
delete _forwardClients.takeFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
// build new one
|
|
||||||
const QJsonObject& obj = config.object();
|
const QJsonObject& obj = config.object();
|
||||||
if (!obj["json"].isNull())
|
|
||||||
{
|
|
||||||
const QJsonArray& addr = obj["json"].toArray();
|
|
||||||
for (const auto& entry : addr)
|
|
||||||
{
|
|
||||||
addJsonTarget(entry.toObject());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!obj["flat"].isNull())
|
|
||||||
{
|
|
||||||
const QJsonArray& addr = obj["flat"].toArray();
|
|
||||||
for (const auto& entry : addr)
|
|
||||||
{
|
|
||||||
addFlatbufferTarget(entry.toObject());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isForwarderEnabledinSettings = obj["enable"].toBool(false);
|
bool isForwarderEnabledinSettings = obj["enable"].toBool(false);
|
||||||
|
enableTargets(isForwarderEnabledinSettings, obj);
|
||||||
if (!_jsonTargets.isEmpty() && isForwarderEnabledinSettings && _forwarder_enabled)
|
|
||||||
{
|
|
||||||
for (const auto& targetHost : qAsConst(_jsonTargets))
|
|
||||||
{
|
|
||||||
InfoIf(isForwarderEnabledinSettings, _log, "Forwarding now to JSON-target host: %s port: %u", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(_hyperion, &Hyperion::forwardJsonMessage, this, &MessageForwarder::forwardJsonMessage, Qt::UniqueConnection);
|
|
||||||
}
|
|
||||||
else if (_jsonTargets.isEmpty() || !isForwarderEnabledinSettings || !_forwarder_enabled)
|
|
||||||
{
|
|
||||||
disconnect(_hyperion, &Hyperion::forwardJsonMessage, nullptr, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_flatbufferTargets.isEmpty() && isForwarderEnabledinSettings && _forwarder_enabled)
|
|
||||||
{
|
|
||||||
for (const auto& targetHost : qAsConst(_flatbufferTargets))
|
|
||||||
{
|
|
||||||
InfoIf(isForwarderEnabledinSettings, _log, "Forwarding now to Flatbuffer-target host: %s port: %u", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_flatbufferTargets.isEmpty() || !isForwarderEnabledinSettings || !_forwarder_enabled)
|
|
||||||
{
|
|
||||||
disconnect(_hyperion, &Hyperion::forwardSystemProtoMessage, nullptr, nullptr);
|
|
||||||
disconnect(_hyperion, &Hyperion::forwardV4lProtoMessage, nullptr, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update comp state
|
|
||||||
_hyperion->setNewComponentState(hyperion::COMP_FORWARDER, isForwarderEnabledinSettings);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,30 +84,59 @@ void MessageForwarder::handleCompStateChangeRequest(hyperion::Components compone
|
|||||||
{
|
{
|
||||||
if (component == hyperion::COMP_FORWARDER && _forwarder_enabled != enable)
|
if (component == hyperion::COMP_FORWARDER && _forwarder_enabled != enable)
|
||||||
{
|
{
|
||||||
_forwarder_enabled = enable;
|
Info(_log, "Forwarder is %s", (enable ? "enabled" : "disabled"));
|
||||||
handleSettingsUpdate(settings::NETFORWARD, _hyperion->getSetting(settings::NETFORWARD));
|
QJsonDocument config {_hyperion->getSetting(settings::type::NETFORWARD)};
|
||||||
Info(_log, "Forwarder change state to %s", (_forwarder_enabled ? "enabled" : "disabled"));
|
enableTargets(enable, config.object());
|
||||||
_hyperion->setNewComponentState(component, _forwarder_enabled);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageForwarder::enableTargets(bool enable, const QJsonObject& config)
|
||||||
|
{
|
||||||
|
if (!enable)
|
||||||
|
{
|
||||||
|
_forwarder_enabled = false;
|
||||||
|
stopJsonTargets();
|
||||||
|
stopFlatbufferTargets();
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int jsonTargetNum = startJsonTargets(config);
|
||||||
|
int flatbufTargetNum = startFlatbufferTargets(config);
|
||||||
|
|
||||||
|
if (flatbufTargetNum > 0)
|
||||||
|
{
|
||||||
|
hyperion::Components activeCompId = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority()).componentId;
|
||||||
|
if (activeCompId == hyperion::COMP_GRABBER)
|
||||||
|
{
|
||||||
|
connect(_hyperion, &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage, Qt::UniqueConnection);
|
||||||
|
}
|
||||||
|
else if (activeCompId == hyperion::COMP_V4L)
|
||||||
|
{
|
||||||
|
connect(_hyperion, &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage, Qt::UniqueConnection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonTargetNum > 0 || flatbufTargetNum > 0)
|
||||||
|
{
|
||||||
|
_forwarder_enabled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_forwarder_enabled = false;
|
||||||
|
Warning(_log,"No JSON- nor Flatbuffer-Forwarder configured -> Forwarding disabled", _forwarder_enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_hyperion->setNewComponentState(hyperion::COMP_FORWARDER, _forwarder_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
void MessageForwarder::handlePriorityChanges(int priority)
|
void MessageForwarder::handlePriorityChanges(int priority)
|
||||||
{
|
{
|
||||||
const QJsonObject obj = _hyperion->getSetting(settings::NETFORWARD).object();
|
if (priority != 0 && _forwarder_enabled)
|
||||||
if (priority != 0 && _forwarder_enabled && obj["enable"].toBool())
|
|
||||||
{
|
{
|
||||||
hyperion::Components activeCompId = _hyperion->getPriorityInfo(priority).componentId;
|
hyperion::Components activeCompId = _hyperion->getPriorityInfo(priority).componentId;
|
||||||
if (activeCompId == hyperion::COMP_GRABBER || activeCompId == hyperion::COMP_V4L)
|
if (activeCompId == hyperion::COMP_GRABBER || activeCompId == hyperion::COMP_V4L)
|
||||||
{
|
{
|
||||||
if (!obj["flat"].isNull())
|
|
||||||
{
|
|
||||||
const QJsonArray& addr = obj["flat"].toArray();
|
|
||||||
for (const auto& entry : addr)
|
|
||||||
{
|
|
||||||
addFlatbufferTarget(entry.toObject());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (activeCompId)
|
switch (activeCompId)
|
||||||
{
|
{
|
||||||
case hyperion::COMP_GRABBER:
|
case hyperion::COMP_GRABBER:
|
||||||
@ -177,69 +170,131 @@ void MessageForwarder::addJsonTarget(const QJsonObject& targetConfig)
|
|||||||
{
|
{
|
||||||
TargetHost targetHost;
|
TargetHost targetHost;
|
||||||
|
|
||||||
QString config_host = targetConfig["host"].toString();
|
QString hostName = targetConfig["host"].toString();
|
||||||
if (NetUtils::resolveHostAddress(_log, config_host, targetHost.host))
|
int port = targetConfig["port"].toInt();
|
||||||
{
|
|
||||||
int config_port = targetConfig["port"].toInt();
|
|
||||||
if (NetUtils::isValidPort(_log, config_port, config_host))
|
|
||||||
{
|
|
||||||
targetHost.port = static_cast<quint16>(config_port);
|
|
||||||
|
|
||||||
// verify loop with JSON-server
|
if (!hostName.isEmpty())
|
||||||
const QJsonObject& obj = _hyperion->getSetting(settings::JSONSERVER).object();
|
{
|
||||||
if ((QNetworkInterface::allAddresses().indexOf(targetHost.host) != -1) && targetHost.port == static_cast<quint16>(obj["port"].toInt()))
|
if (NetUtils::resolveHostToAddress(_log, hostName, targetHost.host, port))
|
||||||
|
{
|
||||||
|
QString address = targetHost.host.toString();
|
||||||
|
if (hostName != address)
|
||||||
{
|
{
|
||||||
Error(_log, "Loop between JSON-Server and Forwarder! Configuration for host: %s, port: %d is ignored.", QSTRING_CSTR(config_host), config_port);
|
Info(_log, "Resolved hostname [%s] to address [%s]", QSTRING_CSTR(hostName), QSTRING_CSTR(address));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (NetUtils::isValidPort(_log, port, targetHost.host.toString()))
|
||||||
{
|
{
|
||||||
if (_forwarder_enabled)
|
targetHost.port = static_cast<quint16>(port);
|
||||||
|
|
||||||
|
// verify loop with JSON-server
|
||||||
|
const QJsonObject& obj = _hyperion->getSetting(settings::JSONSERVER).object();
|
||||||
|
if ((QNetworkInterface::allAddresses().indexOf(targetHost.host) != -1) && targetHost.port == static_cast<quint16>(obj["port"].toInt()))
|
||||||
|
{
|
||||||
|
Error(_log, "Loop between JSON-Server and Forwarder! Configuration for host: %s, port: %d is ignored.", QSTRING_CSTR(targetHost.host.toString()), port);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (_jsonTargets.indexOf(targetHost) == -1)
|
if (_jsonTargets.indexOf(targetHost) == -1)
|
||||||
{
|
{
|
||||||
Info(_log, "JSON-Forwarder settings: Adding target host: %s port: %u", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
Debug(_log, "JSON-Forwarder settings: Adding target host: %s port: %u", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
||||||
_jsonTargets << targetHost;
|
_jsonTargets << targetHost;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Warning(_log, "JSON Forwarder settings: Duplicate target host configuration! Configuration for host: %s, port: %d is ignored.", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
Warning(_log, "JSON-Forwarder settings: Duplicate target host configuration! Configuration for host: %s, port: %d is ignored.", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MessageForwarder::startJsonTargets(const QJsonObject& config)
|
||||||
|
{
|
||||||
|
if (!config["jsonapi"].isNull())
|
||||||
|
{
|
||||||
|
_jsonTargets.clear();
|
||||||
|
const QJsonArray& addr = config["jsonapi"].toArray();
|
||||||
|
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
if (!addr.isEmpty())
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||||
|
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType("jsonapi")));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (const auto& entry : addr)
|
||||||
|
{
|
||||||
|
addJsonTarget(entry.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_jsonTargets.isEmpty())
|
||||||
|
{
|
||||||
|
for (const auto& targetHost : qAsConst(_jsonTargets))
|
||||||
|
{
|
||||||
|
Info(_log, "Forwarding now to JSON-target host: %s port: %u", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(_hyperion, &Hyperion::forwardJsonMessage, this, &MessageForwarder::forwardJsonMessage, Qt::UniqueConnection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _jsonTargets.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MessageForwarder::stopJsonTargets()
|
||||||
|
{
|
||||||
|
if (!_jsonTargets.isEmpty())
|
||||||
|
{
|
||||||
|
disconnect(_hyperion, &Hyperion::forwardJsonMessage, nullptr, nullptr);
|
||||||
|
for (const auto& targetHost : qAsConst(_jsonTargets))
|
||||||
|
{
|
||||||
|
Info(_log, "Stopped forwarding to JSON-target host: %s port: %u", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
||||||
|
}
|
||||||
|
_jsonTargets.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MessageForwarder::addFlatbufferTarget(const QJsonObject& targetConfig)
|
void MessageForwarder::addFlatbufferTarget(const QJsonObject& targetConfig)
|
||||||
{
|
{
|
||||||
TargetHost targetHost;
|
TargetHost targetHost;
|
||||||
|
|
||||||
QString config_host = targetConfig["host"].toString();
|
QString hostName = targetConfig["host"].toString();
|
||||||
if (NetUtils::resolveHostAddress(_log, config_host, targetHost.host))
|
int port = targetConfig["port"].toInt();
|
||||||
{
|
|
||||||
int config_port = targetConfig["port"].toInt();
|
|
||||||
if (NetUtils::isValidPort(_log, config_port, config_host))
|
|
||||||
{
|
|
||||||
targetHost.port = static_cast<quint16>(config_port);
|
|
||||||
|
|
||||||
// verify loop with Flatbuffer-server
|
if (!hostName.isEmpty())
|
||||||
const QJsonObject& obj = _hyperion->getSetting(settings::FLATBUFSERVER).object();
|
{
|
||||||
if ((QNetworkInterface::allAddresses().indexOf(targetHost.host) != -1) && targetHost.port == static_cast<quint16>(obj["port"].toInt()))
|
if (NetUtils::resolveHostToAddress(_log, hostName, targetHost.host, port))
|
||||||
|
{
|
||||||
|
QString address = targetHost.host.toString();
|
||||||
|
if (hostName != address)
|
||||||
{
|
{
|
||||||
Error(_log, "Loop between Flatbuffer-Server and Forwarder! Configuration for host: %s, port: %d is ignored.", QSTRING_CSTR(config_host), config_port);
|
Info(_log, "Resolved hostname [%s] to address [%s]", QSTRING_CSTR(hostName), QSTRING_CSTR(address));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (NetUtils::isValidPort(_log, port, targetHost.host.toString()))
|
||||||
{
|
{
|
||||||
if (_forwarder_enabled)
|
targetHost.port = static_cast<quint16>(port);
|
||||||
|
|
||||||
|
// verify loop with Flatbuffer-server
|
||||||
|
const QJsonObject& obj = _hyperion->getSetting(settings::FLATBUFSERVER).object();
|
||||||
|
if ((QNetworkInterface::allAddresses().indexOf(targetHost.host) != -1) && targetHost.port == static_cast<quint16>(obj["port"].toInt()))
|
||||||
|
{
|
||||||
|
Error(_log, "Loop between Flatbuffer-Server and Forwarder! Configuration for host: %s, port: %d is ignored.", QSTRING_CSTR(targetHost.host.toString()), port);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (_flatbufferTargets.indexOf(targetHost) == -1)
|
if (_flatbufferTargets.indexOf(targetHost) == -1)
|
||||||
{
|
{
|
||||||
Info(_log, "Flatbuffer-Forwarder settings: Adding target host: %s port: %u", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
Debug(_log, "Flatbuffer-Forwarder settings: Adding target host: %s port: %u", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
||||||
_flatbufferTargets << targetHost;
|
_flatbufferTargets << targetHost;
|
||||||
|
|
||||||
FlatBufferConnection* flatbuf = new FlatBufferConnection("Forwarder", targetHost.host.toString(), _priority, false, targetHost.port);
|
if (_messageForwarderFlatBufHelper != nullptr)
|
||||||
_forwardClients << flatbuf;
|
{
|
||||||
|
emit _messageForwarderFlatBufHelper->addClient("Forwarder", targetHost, _priority, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -251,6 +306,66 @@ void MessageForwarder::addFlatbufferTarget(const QJsonObject& targetConfig)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MessageForwarder::startFlatbufferTargets(const QJsonObject& config)
|
||||||
|
{
|
||||||
|
if (!config["flatbuffer"].isNull())
|
||||||
|
{
|
||||||
|
if (_messageForwarderFlatBufHelper == nullptr)
|
||||||
|
{
|
||||||
|
_messageForwarderFlatBufHelper = new MessageForwarderFlatbufferClientsHelper();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit _messageForwarderFlatBufHelper->clearClients();
|
||||||
|
}
|
||||||
|
_flatbufferTargets.clear();
|
||||||
|
|
||||||
|
const QJsonArray& addr = config["flatbuffer"].toArray();
|
||||||
|
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
if (!addr.isEmpty())
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||||
|
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType("flatbuffer")));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (const auto& entry : addr)
|
||||||
|
{
|
||||||
|
addFlatbufferTarget(entry.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_flatbufferTargets.isEmpty())
|
||||||
|
{
|
||||||
|
for (const auto& targetHost : qAsConst(_flatbufferTargets))
|
||||||
|
{
|
||||||
|
Info(_log, "Forwarding now to Flatbuffer-target host: %s port: %u", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _flatbufferTargets.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageForwarder::stopFlatbufferTargets()
|
||||||
|
{
|
||||||
|
if (!_flatbufferTargets.isEmpty())
|
||||||
|
{
|
||||||
|
disconnect(_hyperion, &Hyperion::forwardSystemProtoMessage, nullptr, nullptr);
|
||||||
|
disconnect(_hyperion, &Hyperion::forwardV4lProtoMessage, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (_messageForwarderFlatBufHelper != nullptr)
|
||||||
|
{
|
||||||
|
delete _messageForwarderFlatBufHelper;
|
||||||
|
_messageForwarderFlatBufHelper = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& targetHost : qAsConst(_flatbufferTargets))
|
||||||
|
{
|
||||||
|
Info(_log, "Stopped forwarding to Flatbuffer-target host: %s port: %u", QSTRING_CSTR(targetHost.host.toString()), targetHost.port);
|
||||||
|
}
|
||||||
|
_flatbufferTargets.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MessageForwarder::forwardJsonMessage(const QJsonObject& message)
|
void MessageForwarder::forwardJsonMessage(const QJsonObject& message)
|
||||||
{
|
{
|
||||||
if (_forwarder_enabled)
|
if (_forwarder_enabled)
|
||||||
@ -259,7 +374,7 @@ void MessageForwarder::forwardJsonMessage(const QJsonObject& message)
|
|||||||
for (const auto& targetHost : qAsConst(_jsonTargets))
|
for (const auto& targetHost : qAsConst(_jsonTargets))
|
||||||
{
|
{
|
||||||
client.connectToHost(targetHost.host, targetHost.port);
|
client.connectToHost(targetHost.host, targetHost.port);
|
||||||
if (client.waitForConnected(500))
|
if (client.waitForConnected(CONNECT_TIMEOUT.count()))
|
||||||
{
|
{
|
||||||
sendJsonMessage(message, &client);
|
sendJsonMessage(message, &client);
|
||||||
client.close();
|
client.close();
|
||||||
@ -270,11 +385,13 @@ void MessageForwarder::forwardJsonMessage(const QJsonObject& message)
|
|||||||
|
|
||||||
void MessageForwarder::forwardFlatbufferMessage(const QString& /*name*/, const Image<ColorRgb>& image)
|
void MessageForwarder::forwardFlatbufferMessage(const QString& /*name*/, const Image<ColorRgb>& image)
|
||||||
{
|
{
|
||||||
if (_forwarder_enabled)
|
if (_messageForwarderFlatBufHelper != nullptr)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _forwardClients.size(); i++)
|
bool isfree = _messageForwarderFlatBufHelper->isFree();
|
||||||
|
|
||||||
|
if (isfree && _forwarder_enabled)
|
||||||
{
|
{
|
||||||
_forwardClients.at(i)->setImage(image);
|
QMetaObject::invokeMethod(_messageForwarderFlatBufHelper, "forwardImage", Qt::QueuedConnection, Q_ARG(Image<ColorRgb>, image));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,12 +433,72 @@ void MessageForwarder::sendJsonMessage(const QJsonObject& message, QTcpSocket* s
|
|||||||
|
|
||||||
// parse reply data
|
// parse reply data
|
||||||
QJsonParseError error;
|
QJsonParseError error;
|
||||||
QJsonDocument::fromJson(serializedReply, &error);
|
/* QJsonDocument reply = */ QJsonDocument::fromJson(serializedReply, &error);
|
||||||
|
|
||||||
if (error.error != QJsonParseError::NoError)
|
if (error.error != QJsonParseError::NoError)
|
||||||
{
|
{
|
||||||
Error(_log, "Error while parsing reply: invalid json");
|
Error(_log, "Error while parsing reply: invalid JSON");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessageForwarderFlatbufferClientsHelper::MessageForwarderFlatbufferClientsHelper()
|
||||||
|
{
|
||||||
|
QThread* mainThread = new QThread();
|
||||||
|
mainThread->setObjectName("ForwarderHelperThread");
|
||||||
|
this->moveToThread(mainThread);
|
||||||
|
mainThread->start();
|
||||||
|
|
||||||
|
_free = true;
|
||||||
|
connect(this, &MessageForwarderFlatbufferClientsHelper::addClient, this, &MessageForwarderFlatbufferClientsHelper::addClientHandler);
|
||||||
|
connect(this, &MessageForwarderFlatbufferClientsHelper::clearClients, this, &MessageForwarderFlatbufferClientsHelper::clearClientsHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageForwarderFlatbufferClientsHelper::~MessageForwarderFlatbufferClientsHelper()
|
||||||
|
{
|
||||||
|
_free=false;
|
||||||
|
while (!_forwardClients.isEmpty())
|
||||||
|
{
|
||||||
|
_forwardClients.takeFirst()->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QThread* oldThread = this->thread();
|
||||||
|
disconnect(oldThread, nullptr, nullptr, nullptr);
|
||||||
|
oldThread->quit();
|
||||||
|
oldThread->wait();
|
||||||
|
delete oldThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageForwarderFlatbufferClientsHelper::addClientHandler(const QString& origin, const TargetHost& targetHost, int priority, bool skipReply)
|
||||||
|
{
|
||||||
|
FlatBufferConnection* flatbuf = new FlatBufferConnection(origin, targetHost.host.toString(), priority, skipReply, targetHost.port);
|
||||||
|
_forwardClients << flatbuf;
|
||||||
|
_free = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageForwarderFlatbufferClientsHelper::clearClientsHandler()
|
||||||
|
{
|
||||||
|
while (!_forwardClients.isEmpty())
|
||||||
|
{
|
||||||
|
delete _forwardClients.takeFirst();
|
||||||
|
}
|
||||||
|
_free = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageForwarderFlatbufferClientsHelper::isFree() const
|
||||||
|
{
|
||||||
|
return _free;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageForwarderFlatbufferClientsHelper::forwardImage(const Image<ColorRgb>& image)
|
||||||
|
{
|
||||||
|
_free = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < _forwardClients.size(); i++)
|
||||||
|
{
|
||||||
|
_forwardClients.at(i)->setImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
_free = true;
|
||||||
|
}
|
||||||
|
@ -41,7 +41,3 @@ endif()
|
|||||||
if(ENABLE_FORWARDER)
|
if(ENABLE_FORWARDER)
|
||||||
target_link_libraries(hyperion forwarder)
|
target_link_libraries(hyperion forwarder)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_AVAHI)
|
|
||||||
target_link_libraries(hyperion bonjour)
|
|
||||||
endif ()
|
|
||||||
|
@ -149,6 +149,7 @@ void Hyperion::start()
|
|||||||
if (_instIndex == 0)
|
if (_instIndex == 0)
|
||||||
{
|
{
|
||||||
_messageForwarder = new MessageForwarder(this);
|
_messageForwarder = new MessageForwarder(this);
|
||||||
|
_messageForwarder->handleSettingsUpdate(settings::NETFORWARD, getSetting(settings::NETFORWARD));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -698,7 +699,6 @@ void Hyperion::update()
|
|||||||
// Smoothing is disabled
|
// Smoothing is disabled
|
||||||
if (! _deviceSmooth->enabled())
|
if (! _deviceSmooth->enabled())
|
||||||
{
|
{
|
||||||
//std::cout << "Hyperion::update()> Non-Smoothing - "; LedDevice::printLedValues ( _ledBuffer);
|
|
||||||
emit ledDeviceData(_ledBuffer);
|
emit ledDeviceData(_ledBuffer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -710,11 +710,4 @@ void Hyperion::update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//LEDDevice is disabled
|
|
||||||
Debug(_log, "LEDDevice is disabled - no update required");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,16 @@ HyperionIManager::HyperionIManager(const QString& rootPath, QObject* parent, boo
|
|||||||
|
|
||||||
Hyperion* HyperionIManager::getHyperionInstance(quint8 instance)
|
Hyperion* HyperionIManager::getHyperionInstance(quint8 instance)
|
||||||
{
|
{
|
||||||
|
Hyperion* pInstance {nullptr};
|
||||||
if(_runningInstances.contains(instance))
|
if(_runningInstances.contains(instance))
|
||||||
return _runningInstances.value(instance);
|
return _runningInstances.value(instance);
|
||||||
|
|
||||||
Warning(_log,"The requested instance index '%d' with name '%s' isn't running, return main instance", instance, QSTRING_CSTR(_instanceTable->getNamebyIndex(instance)));
|
if (!_runningInstances.isEmpty())
|
||||||
return _runningInstances.value(0);
|
{
|
||||||
|
Warning(_log,"The requested instance index '%d' with name '%s' isn't running, return main instance", instance, QSTRING_CSTR(_instanceTable->getNamebyIndex(instance)));
|
||||||
|
pInstance = _runningInstances.value(0);
|
||||||
|
}
|
||||||
|
return pInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QVariantMap> HyperionIManager::getInstanceData() const
|
QVector<QVariantMap> HyperionIManager::getInstanceData() const
|
||||||
|
@ -22,15 +22,15 @@ const int PriorityMuxer::ENDLESS = -1;
|
|||||||
|
|
||||||
PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, _log(nullptr)
|
, _log(nullptr)
|
||||||
, _currentPriority(PriorityMuxer::LOWEST_PRIORITY)
|
, _currentPriority(PriorityMuxer::LOWEST_PRIORITY)
|
||||||
, _previousPriority(_currentPriority)
|
, _previousPriority(_currentPriority)
|
||||||
, _manualSelectedPriority(MANUAL_SELECTED_PRIORITY)
|
, _manualSelectedPriority(MANUAL_SELECTED_PRIORITY)
|
||||||
, _prevVisComp (hyperion::Components::COMP_COLOR)
|
, _prevVisComp (hyperion::Components::COMP_COLOR)
|
||||||
, _sourceAutoSelectEnabled(true)
|
, _sourceAutoSelectEnabled(true)
|
||||||
, _updateTimer(new QTimer(this))
|
, _updateTimer(new QTimer(this))
|
||||||
, _timer(new QTimer(this))
|
, _timer(new QTimer(this))
|
||||||
, _blockTimer(new QTimer(this))
|
, _blockTimer(new QTimer(this))
|
||||||
{
|
{
|
||||||
QString subComponent = parent->property("instance").toString();
|
QString subComponent = parent->property("instance").toString();
|
||||||
_log= Logger::getInstance("MUXER", subComponent);
|
_log= Logger::getInstance("MUXER", subComponent);
|
||||||
|
@ -41,6 +41,33 @@
|
|||||||
},
|
},
|
||||||
"access": "advanced",
|
"access": "advanced",
|
||||||
"propertyOrder": 4
|
"propertyOrder": 4
|
||||||
|
},
|
||||||
|
"enableAttempts": {
|
||||||
|
"type": "integer",
|
||||||
|
"title": "edt_dev_general_enableAttempts_title",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 120,
|
||||||
|
"default": 12,
|
||||||
|
"required": true,
|
||||||
|
"options": {
|
||||||
|
"infoText": "edt_dev_general_enableAttempts_title_info"
|
||||||
|
},
|
||||||
|
"access": "advanced",
|
||||||
|
"propertyOrder": 5
|
||||||
|
},
|
||||||
|
"enableAttemptsInterval": {
|
||||||
|
"type": "integer",
|
||||||
|
"title": "edt_dev_general_enableAttemptsInterval_title",
|
||||||
|
"minimum": 5,
|
||||||
|
"maximum": 120,
|
||||||
|
"default": 15,
|
||||||
|
"required": true,
|
||||||
|
"append": "edt_append_s",
|
||||||
|
"options": {
|
||||||
|
"infoText": "edt_dev_general_enableAttemptsInterval_title_info"
|
||||||
|
},
|
||||||
|
"access": "advanced",
|
||||||
|
"propertyOrder": 6
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,77 +1,106 @@
|
|||||||
{
|
{
|
||||||
"type" : "object",
|
"type": "object",
|
||||||
"title" : "edt_conf_fw_heading_title",
|
"title": "edt_conf_fw_heading_title",
|
||||||
"required" : true,
|
"required": true,
|
||||||
"properties": {
|
"properties": {
|
||||||
"enable": {
|
"enable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"title": "edt_conf_general_enable_title",
|
"title": "edt_conf_general_enable_title",
|
||||||
"required": true,
|
"required": true,
|
||||||
"default": false,
|
"default": false,
|
||||||
"propertyOrder": 1
|
"propertyOrder": 1
|
||||||
},
|
},
|
||||||
"json": {
|
"jsonapiselect": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"title": "edt_conf_fw_json_title",
|
"uniqueItems": true,
|
||||||
"propertyOrder": 2,
|
"format": "select",
|
||||||
"uniqueItems": true,
|
"title": "edt_conf_fw_json_services_discovered_title",
|
||||||
"items": {
|
"propertyOrder": 2
|
||||||
"type": "object",
|
},
|
||||||
"title": "edt_conf_fw_json_itemtitle",
|
"jsonapi": {
|
||||||
"required": true,
|
"type": "array",
|
||||||
"properties": {
|
"title": "edt_conf_fw_json_title",
|
||||||
"host": {
|
"uniqueItems": true,
|
||||||
"type": "string",
|
"access": "expert",
|
||||||
"format": "hostname_or_ip",
|
"items": {
|
||||||
"minLength": 7,
|
"type": "object",
|
||||||
"title": "edt_dev_spec_targetIpHost_title",
|
"title": "edt_conf_fw_json_itemtitle",
|
||||||
"required": true,
|
"properties": {
|
||||||
"propertyOrder": 1
|
"name": {
|
||||||
},
|
"type": "string",
|
||||||
"port": {
|
"title": "edt_conf_fw_service_name_title",
|
||||||
"type": "integer",
|
"required": true,
|
||||||
"minimum": 1,
|
"access": "expert",
|
||||||
"maximum": 65535,
|
"propertyOrder": 1
|
||||||
"default": 19444,
|
},
|
||||||
"title": "edt_dev_spec_port_title",
|
"host": {
|
||||||
"required": true,
|
"type": "string",
|
||||||
"access": "expert",
|
"format": "hostname_or_ip",
|
||||||
"propertyOrder": 2
|
"minLength": 7,
|
||||||
}
|
"title": "edt_dev_spec_targetIpHost_title",
|
||||||
}
|
"required": true,
|
||||||
}
|
"access": "expert",
|
||||||
},
|
"propertyOrder": 2
|
||||||
"flat": {
|
},
|
||||||
"type": "array",
|
"port": {
|
||||||
"title": "edt_conf_fw_flat_title",
|
"type": "integer",
|
||||||
"propertyOrder": 3,
|
"minimum": 1,
|
||||||
"uniqueItems": true,
|
"maximum": 65535,
|
||||||
"items": {
|
"title": "edt_dev_spec_port_title",
|
||||||
"type": "object",
|
"required": true,
|
||||||
"title": "edt_conf_fw_flat_itemtitle",
|
"access": "expert",
|
||||||
"required": true,
|
"propertyOrder": 3
|
||||||
"properties": {
|
}
|
||||||
"host": {
|
}
|
||||||
"type": "string",
|
},
|
||||||
"format": "hostname_or_ip",
|
"propertyOrder": 3
|
||||||
"minLength": 7,
|
},
|
||||||
"title": "edt_dev_spec_targetIpHost_title",
|
"flatbufferselect": {
|
||||||
"required": true,
|
"type": "array",
|
||||||
"propertyOrder": 1
|
"uniqueItems": true,
|
||||||
},
|
"format": "select",
|
||||||
"port": {
|
"title": "edt_conf_fw_flat_services_discovered_title",
|
||||||
"type": "integer",
|
"propertyOrder": 4
|
||||||
"minimum": 1,
|
},
|
||||||
"maximum": 65535,
|
"flatbuffer": {
|
||||||
"default": 19400,
|
"type": "array",
|
||||||
"title": "edt_dev_spec_port_title",
|
"title": "edt_conf_fw_flat_title",
|
||||||
"required": true,
|
"uniqueItems": true,
|
||||||
"access": "expert",
|
"access": "expert",
|
||||||
"propertyOrder": 2
|
"items": {
|
||||||
}
|
"type": "object",
|
||||||
}
|
"title": "edt_conf_fw_flat_itemtitle",
|
||||||
}
|
"properties": {
|
||||||
}
|
"name": {
|
||||||
},
|
"type": "string",
|
||||||
"additionalProperties": false
|
"title": "edt_conf_fw_service_name_title",
|
||||||
}
|
"access": "expert",
|
||||||
|
"propertyOrder": 1
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "hostname_or_ip",
|
||||||
|
"minLength": 7,
|
||||||
|
"title": "edt_dev_spec_targetIpHost_title",
|
||||||
|
"required": true,
|
||||||
|
"access": "expert",
|
||||||
|
"propertyOrder": 2
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 65535,
|
||||||
|
"default": 19400,
|
||||||
|
"title": "edt_dev_spec_port_title",
|
||||||
|
"required": true,
|
||||||
|
"access": "expert",
|
||||||
|
"propertyOrder": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"propertyOrder": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -13,3 +13,8 @@ target_link_libraries(jsonserver
|
|||||||
Qt${QT_VERSION_MAJOR}::Network
|
Qt${QT_VERSION_MAJOR}::Network
|
||||||
Qt${QT_VERSION_MAJOR}::Gui
|
Qt${QT_VERSION_MAJOR}::Gui
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(ENABLE_MDNS)
|
||||||
|
target_link_libraries(jsonserver mdns)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
@ -1,37 +1,35 @@
|
|||||||
// system includes
|
// system includes
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
// project includes
|
|
||||||
#include "HyperionConfig.h"
|
|
||||||
#include <jsonserver/JsonServer.h>
|
|
||||||
#include "JsonClientConnection.h"
|
|
||||||
|
|
||||||
// bonjour include
|
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
#include <bonjour/bonjourserviceregister.h>
|
|
||||||
#endif
|
|
||||||
#include <utils/NetOrigin.h>
|
|
||||||
|
|
||||||
// qt includes
|
// qt includes
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
|
||||||
|
// project includes
|
||||||
|
#include "HyperionConfig.h"
|
||||||
|
#include <jsonserver/JsonServer.h>
|
||||||
|
#include "JsonClientConnection.h"
|
||||||
|
|
||||||
|
#include <utils/NetOrigin.h>
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char SERVICE_TYPE[] = "jsonapi";
|
||||||
|
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
JsonServer::JsonServer(const QJsonDocument& config)
|
JsonServer::JsonServer(const QJsonDocument& config)
|
||||||
: QObject()
|
: QObject()
|
||||||
, _server(new QTcpServer(this))
|
, _server(new QTcpServer(this))
|
||||||
, _openConnections()
|
, _openConnections()
|
||||||
, _log(Logger::getInstance("JSONSERVER"))
|
, _log(Logger::getInstance("JSONSERVER"))
|
||||||
, _netOrigin(NetOrigin::getInstance())
|
, _netOrigin(NetOrigin::getInstance())
|
||||||
|
, _config(config)
|
||||||
{
|
{
|
||||||
Debug(_log, "Created instance");
|
Debug(_log, "Created instance");
|
||||||
|
|
||||||
// Set trigger for incoming connections
|
|
||||||
connect(_server, &QTcpServer::newConnection, this, &JsonServer::newConnection);
|
|
||||||
|
|
||||||
// init
|
|
||||||
handleSettingsUpdate(settings::JSONSERVER, config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonServer::~JsonServer()
|
JsonServer::~JsonServer()
|
||||||
@ -39,31 +37,29 @@ JsonServer::~JsonServer()
|
|||||||
qDeleteAll(_openConnections);
|
qDeleteAll(_openConnections);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JsonServer::initServer()
|
||||||
|
{
|
||||||
|
// Set trigger for incoming connections
|
||||||
|
connect(_server, &QTcpServer::newConnection, this, &JsonServer::newConnection);
|
||||||
|
|
||||||
|
// init
|
||||||
|
handleSettingsUpdate(settings::JSONSERVER, _config);
|
||||||
|
}
|
||||||
|
|
||||||
void JsonServer::start()
|
void JsonServer::start()
|
||||||
{
|
{
|
||||||
if(_server->isListening())
|
if(!_server->isListening())
|
||||||
return;
|
|
||||||
|
|
||||||
if (!_server->listen(QHostAddress::Any, _port))
|
|
||||||
{
|
{
|
||||||
Error(_log,"Could not bind to port '%d', please use an available port", _port);
|
if (!_server->listen(QHostAddress::Any, _port))
|
||||||
return;
|
{
|
||||||
|
Error(_log,"Could not bind to port '%d', please use an available port", _port);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info(_log, "Started on port %d", _port);
|
||||||
|
emit publishService(SERVICE_TYPE, _port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Info(_log, "Started on port %d", _port);
|
|
||||||
|
|
||||||
#ifdef ENABLE_AVAHI
|
|
||||||
if(_serviceRegister == nullptr)
|
|
||||||
{
|
|
||||||
_serviceRegister = new BonjourServiceRegister(this);
|
|
||||||
_serviceRegister->registerService("_hyperiond-json._tcp", _port);
|
|
||||||
}
|
|
||||||
else if( _serviceRegister->getPort() != _port)
|
|
||||||
{
|
|
||||||
delete _serviceRegister;
|
|
||||||
_serviceRegister = new BonjourServiceRegister(this);
|
|
||||||
_serviceRegister->registerService("_hyperiond-json._tcp", _port);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonServer::stop()
|
void JsonServer::stop()
|
||||||
|
@ -141,3 +141,6 @@ if (ENABLE_DEV_USB_HID)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_MDNS)
|
||||||
|
target_link_libraries(leddevice mdns)
|
||||||
|
endif()
|
||||||
|
@ -15,84 +15,91 @@
|
|||||||
//std includes
|
//std includes
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Configuration settings
|
// Configuration settings
|
||||||
const char CONFIG_CURRENT_LED_COUNT[] = "currentLedCount";
|
const char CONFIG_CURRENT_LED_COUNT[] = "currentLedCount";
|
||||||
const char CONFIG_COLOR_ORDER[] = "colorOrder";
|
const char CONFIG_COLOR_ORDER[] = "colorOrder";
|
||||||
const char CONFIG_AUTOSTART[] = "autoStart";
|
const char CONFIG_AUTOSTART[] = "autoStart";
|
||||||
const char CONFIG_LATCH_TIME[] = "latchTime";
|
const char CONFIG_LATCH_TIME[] = "latchTime";
|
||||||
const char CONFIG_REWRITE_TIME[] = "rewriteTime";
|
const char CONFIG_REWRITE_TIME[] = "rewriteTime";
|
||||||
|
|
||||||
int DEFAULT_LED_COUNT = 1;
|
int DEFAULT_LED_COUNT{ 1 };
|
||||||
const char DEFAULT_COLOR_ORDER[] = "RGB";
|
const char DEFAULT_COLOR_ORDER[]{ "RGB" };
|
||||||
const bool DEFAULT_IS_AUTOSTART = true;
|
const bool DEFAULT_IS_AUTOSTART{ true };
|
||||||
|
|
||||||
|
const char CONFIG_ENABLE_ATTEMPTS[] = "enableAttempts";
|
||||||
|
const char CONFIG_ENABLE_ATTEMPTS_INTERVALL[] = "enableAttemptsInterval";
|
||||||
|
|
||||||
|
const int DEFAULT_MAX_ENABLE_ATTEMPTS{ 5 };
|
||||||
|
constexpr std::chrono::seconds DEFAULT_ENABLE_ATTEMPTS_INTERVAL{ 5 };
|
||||||
|
|
||||||
} //End of constants
|
} //End of constants
|
||||||
|
|
||||||
LedDevice::LedDevice(const QJsonObject& deviceConfig, QObject* parent)
|
LedDevice::LedDevice(const QJsonObject& deviceConfig, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, _devConfig(deviceConfig)
|
, _devConfig(deviceConfig)
|
||||||
, _log(Logger::getInstance("LEDDEVICE"))
|
, _log(Logger::getInstance("LEDDEVICE"))
|
||||||
, _ledBuffer(0)
|
, _ledBuffer(0)
|
||||||
, _refreshTimer(nullptr)
|
, _refreshTimer(nullptr)
|
||||||
, _refreshTimerInterval_ms(0)
|
, _enableAttemptsTimer(nullptr)
|
||||||
, _latchTime_ms(0)
|
, _refreshTimerInterval_ms(0)
|
||||||
, _ledCount(0)
|
, _enableAttemptTimerInterval(DEFAULT_ENABLE_ATTEMPTS_INTERVAL)
|
||||||
, _isRestoreOrigState(false)
|
, _enableAttempts(0)
|
||||||
, _isEnabled(false)
|
, _maxEnableAttempts(DEFAULT_MAX_ENABLE_ATTEMPTS)
|
||||||
, _isDeviceInitialised(false)
|
, _latchTime_ms(0)
|
||||||
, _isDeviceReady(false)
|
, _ledCount(0)
|
||||||
, _isOn(false)
|
, _isRestoreOrigState(false)
|
||||||
, _isDeviceInError(false)
|
, _isEnabled(false)
|
||||||
, _isInSwitchOff (false)
|
, _isDeviceInitialised(false)
|
||||||
, _lastWriteTime(QDateTime::currentDateTime())
|
, _isDeviceReady(false)
|
||||||
, _isRefreshEnabled (false)
|
, _isOn(false)
|
||||||
, _isAutoStart(true)
|
, _isDeviceInError(false)
|
||||||
|
, _lastWriteTime(QDateTime::currentDateTime())
|
||||||
|
, _isRefreshEnabled(false)
|
||||||
|
, _isAutoStart(true)
|
||||||
{
|
{
|
||||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
LedDevice::~LedDevice()
|
LedDevice::~LedDevice()
|
||||||
{
|
{
|
||||||
delete _refreshTimer;
|
this->stopEnableAttemptsTimer();
|
||||||
|
this->stopRefreshTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedDevice::start()
|
void LedDevice::start()
|
||||||
{
|
{
|
||||||
Info(_log, "Start LedDevice '%s'.", QSTRING_CSTR(_activeDeviceType));
|
Info(_log, "Start LedDevice '%s'.", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
|
||||||
// setup refreshTimer
|
|
||||||
if ( _refreshTimer == nullptr )
|
|
||||||
{
|
|
||||||
_refreshTimer = new QTimer(this);
|
|
||||||
_refreshTimer->setTimerType(Qt::PreciseTimer);
|
|
||||||
_refreshTimer->setInterval( _refreshTimerInterval_ms );
|
|
||||||
connect(_refreshTimer, &QTimer::timeout, this, &LedDevice::rewriteLEDs );
|
|
||||||
}
|
|
||||||
|
|
||||||
close();
|
close();
|
||||||
|
|
||||||
_isDeviceInitialised = false;
|
_isDeviceInitialised = false;
|
||||||
// General initialisation and configuration of LedDevice
|
|
||||||
if ( init(_devConfig) )
|
if (init(_devConfig))
|
||||||
{
|
{
|
||||||
// Everything is OK -> enable device
|
// Everything is OK -> enable device
|
||||||
_isDeviceInitialised = true;
|
_isDeviceInitialised = true;
|
||||||
|
|
||||||
if (_isAutoStart)
|
if (_isAutoStart)
|
||||||
{
|
{
|
||||||
this->enable();
|
if (!_isEnabled)
|
||||||
|
{
|
||||||
|
Debug(_log, "Not enabled -> enable device");
|
||||||
|
enable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedDevice::stop()
|
void LedDevice::stop()
|
||||||
{
|
{
|
||||||
|
Debug(_log, "Stop device");
|
||||||
this->disable();
|
this->disable();
|
||||||
this->stopRefreshTimer();
|
this->stopRefreshTimer();
|
||||||
Info(_log, " Stopped LedDevice '%s'", QSTRING_CSTR(_activeDeviceType) );
|
Info(_log, " Stopped LedDevice '%s'", QSTRING_CSTR(_activeDeviceType));
|
||||||
}
|
}
|
||||||
|
|
||||||
int LedDevice::open()
|
int LedDevice::open()
|
||||||
@ -113,6 +120,7 @@ int LedDevice::close()
|
|||||||
|
|
||||||
void LedDevice::setInError(const QString& errorMsg)
|
void LedDevice::setInError(const QString& errorMsg)
|
||||||
{
|
{
|
||||||
|
_isOn = false;
|
||||||
_isDeviceInError = true;
|
_isDeviceInError = true;
|
||||||
_isDeviceReady = false;
|
_isDeviceReady = false;
|
||||||
_isEnabled = false;
|
_isEnabled = false;
|
||||||
@ -124,21 +132,53 @@ void LedDevice::setInError(const QString& errorMsg)
|
|||||||
|
|
||||||
void LedDevice::enable()
|
void LedDevice::enable()
|
||||||
{
|
{
|
||||||
if ( !_isEnabled )
|
Debug(_log, "Enable device %s'", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
|
||||||
|
if (!_isEnabled)
|
||||||
{
|
{
|
||||||
|
if (_enableAttemptsTimer != nullptr && _enableAttemptsTimer->isActive())
|
||||||
|
{
|
||||||
|
_enableAttemptsTimer->stop();
|
||||||
|
}
|
||||||
|
|
||||||
_isDeviceInError = false;
|
_isDeviceInError = false;
|
||||||
|
|
||||||
if ( ! _isDeviceReady )
|
if (!_isDeviceInitialised)
|
||||||
|
{
|
||||||
|
_isDeviceInitialised = init(_devConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_isDeviceReady)
|
||||||
{
|
{
|
||||||
open();
|
open();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( _isDeviceReady )
|
bool isEnableFailed(true);
|
||||||
|
|
||||||
|
if (_isDeviceReady)
|
||||||
{
|
{
|
||||||
_isEnabled = true;
|
if (switchOn())
|
||||||
if ( switchOn() )
|
|
||||||
{
|
{
|
||||||
|
stopEnableAttemptsTimer();
|
||||||
|
_isEnabled = true;
|
||||||
|
isEnableFailed = false;
|
||||||
emit enableStateChanged(_isEnabled);
|
emit enableStateChanged(_isEnabled);
|
||||||
|
Info(_log, "LedDevice '%s' enabled", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEnableFailed)
|
||||||
|
{
|
||||||
|
emit enableStateChanged(false);
|
||||||
|
|
||||||
|
if (_maxEnableAttempts > 0)
|
||||||
|
{
|
||||||
|
Debug(_log, "Device's enablement failed - Start retry timer. Retried already done [%d], isEnabled: [%d]", _enableAttempts, _isEnabled);
|
||||||
|
startEnableAttemptsTimer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug(_log, "Device's enablement failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,9 +186,11 @@ void LedDevice::enable()
|
|||||||
|
|
||||||
void LedDevice::disable()
|
void LedDevice::disable()
|
||||||
{
|
{
|
||||||
if ( _isEnabled )
|
Debug(_log, "Disable device %s'", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
if (_isEnabled)
|
||||||
{
|
{
|
||||||
_isEnabled = false;
|
_isEnabled = false;
|
||||||
|
this->stopEnableAttemptsTimer();
|
||||||
this->stopRefreshTimer();
|
this->stopRefreshTimer();
|
||||||
|
|
||||||
switchOff();
|
switchOff();
|
||||||
@ -163,47 +205,110 @@ void LedDevice::setActiveDeviceType(const QString& deviceType)
|
|||||||
_activeDeviceType = deviceType;
|
_activeDeviceType = deviceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LedDevice::init(const QJsonObject &deviceConfig)
|
bool LedDevice::init(const QJsonObject& deviceConfig)
|
||||||
{
|
{
|
||||||
Debug(_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
Debug(_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
_colorOrder = deviceConfig[CONFIG_COLOR_ORDER].toString(DEFAULT_COLOR_ORDER);
|
setLedCount(deviceConfig[CONFIG_CURRENT_LED_COUNT].toInt(DEFAULT_LED_COUNT)); // property injected to reflect real led count
|
||||||
_isAutoStart = deviceConfig[CONFIG_AUTOSTART].toBool(DEFAULT_IS_AUTOSTART);
|
setColorOrder(deviceConfig[CONFIG_COLOR_ORDER].toString(DEFAULT_COLOR_ORDER));
|
||||||
|
setLatchTime(deviceConfig[CONFIG_LATCH_TIME].toInt(_latchTime_ms));
|
||||||
setLedCount( deviceConfig[CONFIG_CURRENT_LED_COUNT].toInt(DEFAULT_LED_COUNT) ); // property injected to reflect real led count
|
setRewriteTime(deviceConfig[CONFIG_REWRITE_TIME].toInt(_refreshTimerInterval_ms));
|
||||||
setLatchTime( deviceConfig[CONFIG_LATCH_TIME].toInt( _latchTime_ms ) );
|
setAutoStart(deviceConfig[CONFIG_AUTOSTART].toBool(DEFAULT_IS_AUTOSTART));
|
||||||
setRewriteTime ( deviceConfig[CONFIG_REWRITE_TIME].toInt( _refreshTimerInterval_ms) );
|
setEnableAttempts(deviceConfig[CONFIG_ENABLE_ATTEMPTS].toInt(DEFAULT_MAX_ENABLE_ATTEMPTS),
|
||||||
|
std::chrono::seconds(deviceConfig[CONFIG_ENABLE_ATTEMPTS_INTERVALL].toInt(DEFAULT_ENABLE_ATTEMPTS_INTERVAL.count()))
|
||||||
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedDevice::startRefreshTimer()
|
void LedDevice::startRefreshTimer()
|
||||||
{
|
{
|
||||||
if ( _isDeviceReady && _isEnabled )
|
if (_refreshTimerInterval_ms > 0)
|
||||||
{
|
{
|
||||||
_refreshTimer->start();
|
if (_isDeviceReady && _isOn)
|
||||||
|
{
|
||||||
|
// setup refreshTimer
|
||||||
|
if (_refreshTimer == nullptr)
|
||||||
|
{
|
||||||
|
_refreshTimer = new QTimer(this);
|
||||||
|
_refreshTimer->setTimerType(Qt::PreciseTimer);
|
||||||
|
connect(_refreshTimer, &QTimer::timeout, this, &LedDevice::rewriteLEDs);
|
||||||
|
}
|
||||||
|
_refreshTimer->setInterval(_refreshTimerInterval_ms);
|
||||||
|
|
||||||
|
//Debug(_log, "Start refresh timer with interval = %ims", _refreshTimer->interval());
|
||||||
|
_refreshTimer->start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug(_log, "Device is not ready to start a refresh timer");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedDevice::stopRefreshTimer()
|
void LedDevice::stopRefreshTimer()
|
||||||
{
|
{
|
||||||
if ( _refreshTimer != nullptr )
|
if (_refreshTimer != nullptr)
|
||||||
{
|
{
|
||||||
|
//Debug(_log, "Stopping refresh timer");
|
||||||
_refreshTimer->stop();
|
_refreshTimer->stop();
|
||||||
|
delete _refreshTimer;
|
||||||
|
_refreshTimer = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
|
void LedDevice::startEnableAttemptsTimer()
|
||||||
|
{
|
||||||
|
++_enableAttempts;
|
||||||
|
|
||||||
|
if (_enableAttempts <= _maxEnableAttempts)
|
||||||
|
{
|
||||||
|
if (_enableAttemptTimerInterval.count() > 0)
|
||||||
|
{
|
||||||
|
// setup enable retry timer
|
||||||
|
if (_enableAttemptsTimer == nullptr)
|
||||||
|
{
|
||||||
|
_enableAttemptsTimer = new QTimer(this);
|
||||||
|
_enableAttemptsTimer->setTimerType(Qt::PreciseTimer);
|
||||||
|
connect(_enableAttemptsTimer, &QTimer::timeout, this, &LedDevice::enable);
|
||||||
|
}
|
||||||
|
_enableAttemptsTimer->setInterval(static_cast<int>(_enableAttemptTimerInterval.count() * 1000)); //NOLINT
|
||||||
|
|
||||||
|
Info(_log, "Start %d. attempt of %d to enable the device in %d seconds", _enableAttempts, _maxEnableAttempts, _enableAttemptTimerInterval.count());
|
||||||
|
_enableAttemptsTimer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error(_log, "Device disabled. Maximum number of %d attempts enabling the device reached. Tried for %d seconds.", _maxEnableAttempts, _enableAttempts * _enableAttemptTimerInterval.count());
|
||||||
|
_enableAttempts = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LedDevice::stopEnableAttemptsTimer()
|
||||||
|
{
|
||||||
|
if (_enableAttemptsTimer != nullptr)
|
||||||
|
{
|
||||||
|
Debug(_log, "Stopping enable retry timer");
|
||||||
|
_enableAttemptsTimer->stop();
|
||||||
|
delete _enableAttemptsTimer;
|
||||||
|
_enableAttemptsTimer = nullptr;
|
||||||
|
_enableAttempts = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDevice::updateLeds(std::vector<ColorRgb> ledValues)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
if ( !_isEnabled || !_isOn || !_isDeviceReady || _isDeviceInError )
|
if (!_isEnabled || !_isOn || !_isDeviceReady || _isDeviceInError)
|
||||||
{
|
{
|
||||||
//std::cout << "LedDevice::updateLeds(), LedDevice NOT ready! ";
|
//std::cout << "LedDevice::updateLeds(), LedDevice NOT ready! ";
|
||||||
retval = -1;
|
retval = -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qint64 elapsedTimeMs = _lastWriteTime.msecsTo( QDateTime::currentDateTime() );
|
qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
|
||||||
if (_latchTime_ms == 0 || elapsedTimeMs >= _latchTime_ms)
|
if (_latchTime_ms == 0 || elapsedTimeMs >= _latchTime_ms)
|
||||||
{
|
{
|
||||||
//std::cout << "LedDevice::updateLeds(), Elapsed time since last write (" << elapsedTimeMs << ") ms > _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
|
//std::cout << "LedDevice::updateLeds(), Elapsed time since last write (" << elapsedTimeMs << ") ms > _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
|
||||||
@ -211,16 +316,16 @@ int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
|
|||||||
_lastWriteTime = QDateTime::currentDateTime();
|
_lastWriteTime = QDateTime::currentDateTime();
|
||||||
|
|
||||||
// if device requires refreshing, save Led-Values and restart the timer
|
// if device requires refreshing, save Led-Values and restart the timer
|
||||||
if ( _isRefreshEnabled && _isEnabled )
|
if (_isRefreshEnabled && _isEnabled)
|
||||||
{
|
{
|
||||||
this->startRefreshTimer();
|
|
||||||
_lastLedValues = ledValues;
|
_lastLedValues = ledValues;
|
||||||
|
this->startRefreshTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//std::cout << "LedDevice::updateLeds(), Skip write. elapsedTime (" << elapsedTimeMs << ") ms < _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
|
//std::cout << "LedDevice::updateLeds(), Skip write. elapsedTime (" << elapsedTimeMs << ") ms < _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
|
||||||
if ( _isRefreshEnabled )
|
if (_isRefreshEnabled)
|
||||||
{
|
{
|
||||||
//Stop timer to allow for next non-refresh update
|
//Stop timer to allow for next non-refresh update
|
||||||
this->stopRefreshTimer();
|
this->stopRefreshTimer();
|
||||||
@ -234,18 +339,21 @@ int LedDevice::rewriteLEDs()
|
|||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if ( _isDeviceReady && _isEnabled )
|
if (_isEnabled && _isOn && _isDeviceReady && !_isDeviceInError)
|
||||||
{
|
{
|
||||||
// qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
|
// qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
|
||||||
// std::cout << "LedDevice::rewriteLEDs(): Rewrite LEDs now, elapsedTime [" << elapsedTimeMs << "] ms" << std::endl;
|
// std::cout << "LedDevice::rewriteLEDs(): Rewrite LEDs now, elapsedTime [" << elapsedTimeMs << "] ms" << std::endl;
|
||||||
// //:TESTING: Inject "white" output records to differentiate from normal writes
|
// //:TESTING: Inject "white" output records to differentiate from normal writes
|
||||||
// _lastLedValues.clear();
|
// _lastLedValues.clear();
|
||||||
// _lastLedValues.resize(static_cast<unsigned long>(_ledCount), ColorRgb::WHITE);
|
// _lastLedValues.resize(static_cast<unsigned long>(_ledCount), ColorRgb::WHITE);
|
||||||
// printLedValues(_lastLedValues);
|
// printLedValues(_lastLedValues);
|
||||||
// //:TESTING:
|
// //:TESTING:
|
||||||
|
|
||||||
retval = write(_lastLedValues);
|
if (!_lastLedValues.empty())
|
||||||
_lastWriteTime = QDateTime::currentDateTime();
|
{
|
||||||
|
retval = write(_lastLedValues);
|
||||||
|
_lastWriteTime = QDateTime::currentDateTime();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -257,6 +365,7 @@ int LedDevice::rewriteLEDs()
|
|||||||
|
|
||||||
int LedDevice::writeBlack(int numberOfWrites)
|
int LedDevice::writeBlack(int numberOfWrites)
|
||||||
{
|
{
|
||||||
|
Debug(_log, "Set LED strip to black to switch of LEDs");
|
||||||
return writeColor(ColorRgb::BLACK, numberOfWrites);
|
return writeColor(ColorRgb::BLACK, numberOfWrites);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,7 +382,7 @@ int LedDevice::writeColor(const ColorRgb& color, int numberOfWrites)
|
|||||||
QTimer::singleShot(_latchTime_ms, &loop, &QEventLoop::quit);
|
QTimer::singleShot(_latchTime_ms, &loop, &QEventLoop::quit);
|
||||||
loop.exec();
|
loop.exec();
|
||||||
}
|
}
|
||||||
_lastLedValues = std::vector<ColorRgb>(static_cast<unsigned long>(_ledCount),color);
|
_lastLedValues = std::vector<ColorRgb>(static_cast<unsigned long>(_ledCount), color);
|
||||||
rc = write(_lastLedValues);
|
rc = write(_lastLedValues);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
@ -281,24 +390,31 @@ int LedDevice::writeColor(const ColorRgb& color, int numberOfWrites)
|
|||||||
|
|
||||||
bool LedDevice::switchOn()
|
bool LedDevice::switchOn()
|
||||||
{
|
{
|
||||||
bool rc = false;
|
bool rc{ false };
|
||||||
|
|
||||||
if ( _isOn )
|
if (_isOn)
|
||||||
{
|
{
|
||||||
|
Debug(_log, "Device %s is already on. Skipping.", QSTRING_CSTR(_activeDeviceType));
|
||||||
rc = true;
|
rc = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( _isEnabled &&_isDeviceInitialised )
|
if (_isDeviceReady)
|
||||||
{
|
{
|
||||||
if ( storeState() )
|
Info(_log, "Switching device %s ON", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
if (storeState())
|
||||||
{
|
{
|
||||||
if ( powerOn() )
|
if (powerOn())
|
||||||
{
|
{
|
||||||
|
Info(_log, "Device %s is ON", QSTRING_CSTR(_activeDeviceType));
|
||||||
_isOn = true;
|
_isOn = true;
|
||||||
_isInSwitchOff = false;
|
emit enableStateChanged(_isEnabled);
|
||||||
rc = true;
|
rc = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Warning(_log, "Failed switching device %s ON", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,32 +423,40 @@ bool LedDevice::switchOn()
|
|||||||
|
|
||||||
bool LedDevice::switchOff()
|
bool LedDevice::switchOff()
|
||||||
{
|
{
|
||||||
bool rc = false;
|
bool rc{ false };
|
||||||
|
|
||||||
if ( !_isOn )
|
if (!_isOn)
|
||||||
{
|
{
|
||||||
rc = true;
|
rc = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( _isDeviceInitialised )
|
if (_isDeviceInitialised)
|
||||||
{
|
{
|
||||||
// Disable device to ensure no standard Led updates are written/processed
|
Info(_log, "Switching device %s OFF", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
|
||||||
|
// Disable device to ensure no standard LED updates are written/processed
|
||||||
_isOn = false;
|
_isOn = false;
|
||||||
_isInSwitchOff = true;
|
|
||||||
|
|
||||||
rc = true;
|
rc = true;
|
||||||
|
|
||||||
if ( _isDeviceReady )
|
if (_isDeviceReady)
|
||||||
{
|
{
|
||||||
if ( _isRestoreOrigState )
|
if (_isRestoreOrigState)
|
||||||
{
|
{
|
||||||
//Restore devices state
|
//Restore devices state
|
||||||
restoreState();
|
restoreState();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
powerOff();
|
if (powerOff())
|
||||||
|
{
|
||||||
|
Info(_log, "Device %s is OFF", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Warning(_log, "Failed switching device %s OFF", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -342,10 +466,12 @@ bool LedDevice::switchOff()
|
|||||||
|
|
||||||
bool LedDevice::powerOff()
|
bool LedDevice::powerOff()
|
||||||
{
|
{
|
||||||
bool rc = false;
|
bool rc{ false };
|
||||||
|
|
||||||
|
Debug(_log, "Power Off: %s", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
|
||||||
// Simulate power-off by writing a final "Black" to have a defined outcome
|
// Simulate power-off by writing a final "Black" to have a defined outcome
|
||||||
if ( writeBlack() >= 0 )
|
if (writeBlack() >= 0)
|
||||||
{
|
{
|
||||||
rc = true;
|
rc = true;
|
||||||
}
|
}
|
||||||
@ -354,15 +480,18 @@ bool LedDevice::powerOff()
|
|||||||
|
|
||||||
bool LedDevice::powerOn()
|
bool LedDevice::powerOn()
|
||||||
{
|
{
|
||||||
bool rc = true;
|
bool rc{ true };
|
||||||
|
|
||||||
|
Debug(_log, "Power On: %s", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LedDevice::storeState()
|
bool LedDevice::storeState()
|
||||||
{
|
{
|
||||||
bool rc = true;
|
bool rc{ true };
|
||||||
|
|
||||||
if ( _isRestoreOrigState )
|
if (_isRestoreOrigState)
|
||||||
{
|
{
|
||||||
// Save device's original state
|
// Save device's original state
|
||||||
// _originalStateValues = get device's state;
|
// _originalStateValues = get device's state;
|
||||||
@ -373,9 +502,9 @@ bool LedDevice::storeState()
|
|||||||
|
|
||||||
bool LedDevice::restoreState()
|
bool LedDevice::restoreState()
|
||||||
{
|
{
|
||||||
bool rc = true;
|
bool rc{ true };
|
||||||
|
|
||||||
if ( _isRestoreOrigState )
|
if (_isRestoreOrigState)
|
||||||
{
|
{
|
||||||
// Restore device's original state
|
// Restore device's original state
|
||||||
// update device using _originalStateValues
|
// update device using _originalStateValues
|
||||||
@ -393,7 +522,7 @@ QJsonObject LedDevice::discover(const QJsonObject& /*params*/)
|
|||||||
QJsonArray deviceList;
|
QJsonArray deviceList;
|
||||||
devicesDiscovered.insert("devices", deviceList);
|
devicesDiscovered.insert("devices", deviceList);
|
||||||
|
|
||||||
Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
return devicesDiscovered;
|
return devicesDiscovered;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,75 +530,98 @@ QString LedDevice::discoverFirst()
|
|||||||
{
|
{
|
||||||
QString deviceDiscovered;
|
QString deviceDiscovered;
|
||||||
|
|
||||||
Debug(_log, "deviceDiscovered: [%s]", QSTRING_CSTR(deviceDiscovered) );
|
Debug(_log, "deviceDiscovered: [%s]", QSTRING_CSTR(deviceDiscovered));
|
||||||
return deviceDiscovered;
|
return deviceDiscovered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QJsonObject LedDevice::getProperties(const QJsonObject& params)
|
QJsonObject LedDevice::getProperties(const QJsonObject& params)
|
||||||
{
|
{
|
||||||
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
QJsonObject properties;
|
QJsonObject properties;
|
||||||
|
|
||||||
QJsonObject deviceProperties;
|
QJsonObject deviceProperties;
|
||||||
properties.insert("properties", deviceProperties);
|
properties.insert("properties", deviceProperties);
|
||||||
|
|
||||||
Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LedDevice::setLogger(Logger* log)
|
||||||
|
{
|
||||||
|
_log = log;
|
||||||
|
}
|
||||||
|
|
||||||
void LedDevice::setLedCount(int ledCount)
|
void LedDevice::setLedCount(int ledCount)
|
||||||
{
|
{
|
||||||
assert(ledCount >= 0);
|
assert(ledCount >= 0);
|
||||||
_ledCount = ledCount;
|
_ledCount = static_cast<uint>(ledCount);
|
||||||
_ledRGBCount = _ledCount * sizeof(ColorRgb);
|
_ledRGBCount = _ledCount * sizeof(ColorRgb);
|
||||||
_ledRGBWCount = _ledCount * sizeof(ColorRgbw);
|
_ledRGBWCount = _ledCount * sizeof(ColorRgbw);
|
||||||
|
Debug(_log, "LedCount set to %d", _ledCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedDevice::setLatchTime( int latchTime_ms )
|
void LedDevice::setColorOrder(const QString& colorOrder)
|
||||||
|
{
|
||||||
|
_colorOrder = colorOrder;
|
||||||
|
Debug(_log, "ColorOrder set to %s", QSTRING_CSTR(_colorOrder.toUpper()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LedDevice::setLatchTime(int latchTime_ms)
|
||||||
{
|
{
|
||||||
assert(latchTime_ms >= 0);
|
assert(latchTime_ms >= 0);
|
||||||
_latchTime_ms = latchTime_ms;
|
_latchTime_ms = latchTime_ms;
|
||||||
Debug(_log, "LatchTime updated to %dms", _latchTime_ms);
|
Debug(_log, "LatchTime set to %dms", _latchTime_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedDevice::setRewriteTime( int rewriteTime_ms )
|
void LedDevice::setAutoStart(bool isAutoStart)
|
||||||
{
|
{
|
||||||
assert(rewriteTime_ms >= 0);
|
_isAutoStart = isAutoStart;
|
||||||
|
Debug(_log, "AutoStart %s", (_isAutoStart ? "enabled" : "disabled"));
|
||||||
|
}
|
||||||
|
|
||||||
//Check, if refresh timer was not initialised due to getProperties/identify sceanrios
|
void LedDevice::setRewriteTime(int rewriteTime_ms)
|
||||||
if (_refreshTimer != nullptr)
|
{
|
||||||
|
_refreshTimerInterval_ms = qMax(rewriteTime_ms, 0);
|
||||||
|
|
||||||
|
if (_refreshTimerInterval_ms > 0)
|
||||||
{
|
{
|
||||||
_refreshTimerInterval_ms = rewriteTime_ms;
|
_isRefreshEnabled = true;
|
||||||
|
|
||||||
if (_refreshTimerInterval_ms > 0)
|
if (_refreshTimerInterval_ms <= _latchTime_ms)
|
||||||
{
|
{
|
||||||
|
int new_refresh_timer_interval = _latchTime_ms + 10; //NOLINT
|
||||||
_isRefreshEnabled = true;
|
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;
|
||||||
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, "RewriteTime updated to %dms", _refreshTimerInterval_ms);
|
Debug(_log, "Refresh interval = %dms", _refreshTimerInterval_ms);
|
||||||
|
startRefreshTimer();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_isRefreshEnabled = false;
|
||||||
|
stopRefreshTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LedDevice::setEnableAttempts(int maxEnableRetries, std::chrono::seconds enableRetryTimerInterval)
|
||||||
|
{
|
||||||
|
stopEnableAttemptsTimer();
|
||||||
|
maxEnableRetries = qMax(maxEnableRetries, 0);
|
||||||
|
|
||||||
|
_enableAttempts = 0;
|
||||||
|
_maxEnableAttempts = maxEnableRetries;
|
||||||
|
_enableAttemptTimerInterval = enableRetryTimerInterval;
|
||||||
|
|
||||||
|
Debug(_log, "Max enable retries: %d, enable retry interval = %llds", _maxEnableAttempts, static_cast<int>(_enableAttemptTimerInterval.count()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues)
|
void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues)
|
||||||
{
|
{
|
||||||
std::cout << "LedValues [" << ledValues.size() <<"] [";
|
std::cout << "LedValues [" << ledValues.size() << "] [";
|
||||||
for (const ColorRgb& color : ledValues)
|
for (const ColorRgb& color : ledValues)
|
||||||
{
|
{
|
||||||
std::cout << color;
|
std::cout << color;
|
||||||
@ -477,24 +629,24 @@ void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues)
|
|||||||
std::cout << "]" << std::endl;
|
std::cout << "]" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LedDevice::uint8_t_to_hex_string(const uint8_t * data, const int size, int number) const
|
QString LedDevice::uint8_t_to_hex_string(const uint8_t* data, const int size, int number)
|
||||||
{
|
{
|
||||||
if ( number <= 0 || number > size)
|
if (number <= 0 || number > size)
|
||||||
{
|
{
|
||||||
number = size;
|
number = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray bytes (reinterpret_cast<const char*>(data), number);
|
QByteArray bytes(reinterpret_cast<const char*>(data), number);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||||
return bytes.toHex(':');
|
return bytes.toHex(':');
|
||||||
#else
|
#else
|
||||||
return bytes.toHex();
|
return bytes.toHex();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LedDevice::toHex(const QByteArray& data, int number) const
|
QString LedDevice::toHex(const QByteArray& data, int number)
|
||||||
{
|
{
|
||||||
if ( number <= 0 || number > data.size())
|
if (number <= 0 || number > data.size())
|
||||||
{
|
{
|
||||||
number = data.size();
|
number = data.size();
|
||||||
}
|
}
|
||||||
@ -505,3 +657,47 @@ QString LedDevice::toHex(const QByteArray& data, int number) const
|
|||||||
return data.left(number).toHex();
|
return data.left(number).toHex();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
bool LedDevice::isInitialised() const
|
||||||
|
{
|
||||||
|
return _isDeviceInitialised;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LedDevice::isReady() const
|
||||||
|
{
|
||||||
|
return _isDeviceReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LedDevice::isInError() const
|
||||||
|
{
|
||||||
|
return _isDeviceInError;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDevice::getLatchTime() const
|
||||||
|
{
|
||||||
|
return _latchTime_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDevice::getRewriteTime() const
|
||||||
|
{
|
||||||
|
return _refreshTimerInterval_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDevice::getLedCount() const
|
||||||
|
{
|
||||||
|
return static_cast<int>(_ledCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LedDevice::getActiveDeviceType() const
|
||||||
|
{
|
||||||
|
return _activeDeviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LedDevice::getColorOrder() const
|
||||||
|
{
|
||||||
|
return _colorOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LedDevice::componentState() const {
|
||||||
|
return _isEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
<file alias="schema-udpartnet">schemas/schema-artnet.json</file>
|
<file alias="schema-udpartnet">schemas/schema-artnet.json</file>
|
||||||
<file alias="schema-udph801">schemas/schema-h801.json</file>
|
<file alias="schema-udph801">schemas/schema-h801.json</file>
|
||||||
<file alias="schema-udpraw">schemas/schema-udpraw.json</file>
|
<file alias="schema-udpraw">schemas/schema-udpraw.json</file>
|
||||||
|
<file alias="schema-udpddp">schemas/schema-udpddp.json</file>
|
||||||
<file alias="schema-ws2801">schemas/schema-ws2801.json</file>
|
<file alias="schema-ws2801">schemas/schema-ws2801.json</file>
|
||||||
<file alias="schema-ws2812spi">schemas/schema-ws2812spi.json</file>
|
<file alias="schema-ws2812spi">schemas/schema-ws2812spi.json</file>
|
||||||
<file alias="schema-apa104">schemas/schema-apa104.json</file>
|
<file alias="schema-apa104">schemas/schema-apa104.json</file>
|
||||||
|
@ -67,9 +67,6 @@ void LedDeviceWrapper::createLedDevice(const QJsonObject& config)
|
|||||||
// further signals
|
// further signals
|
||||||
connect(this, &LedDeviceWrapper::updateLeds, _ledDevice, &LedDevice::updateLeds, Qt::QueuedConnection);
|
connect(this, &LedDeviceWrapper::updateLeds, _ledDevice, &LedDevice::updateLeds, Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(this, &LedDeviceWrapper::enable, _ledDevice, &LedDevice::enable);
|
|
||||||
connect(this, &LedDeviceWrapper::disable, _ledDevice, &LedDevice::disable);
|
|
||||||
|
|
||||||
connect(this, &LedDeviceWrapper::switchOn, _ledDevice, &LedDevice::switchOn);
|
connect(this, &LedDeviceWrapper::switchOn, _ledDevice, &LedDevice::switchOn);
|
||||||
connect(this, &LedDeviceWrapper::switchOff, _ledDevice, &LedDevice::switchOff);
|
connect(this, &LedDeviceWrapper::switchOff, _ledDevice, &LedDevice::switchOff);
|
||||||
|
|
||||||
@ -81,6 +78,100 @@ void LedDeviceWrapper::createLedDevice(const QJsonObject& config)
|
|||||||
thread->start();
|
thread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LedDeviceWrapper::handleComponentState(hyperion::Components component, bool state)
|
||||||
|
{
|
||||||
|
if (component == hyperion::COMP_LEDDEVICE)
|
||||||
|
{
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(_ledDevice, "enable", Qt::BlockingQueuedConnection);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(_ledDevice, "disable", Qt::BlockingQueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(_ledDevice, "componentState", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, _enabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LedDeviceWrapper::handleInternalEnableState(bool newState)
|
||||||
|
{
|
||||||
|
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, newState);
|
||||||
|
_enabled = newState;
|
||||||
|
|
||||||
|
if (_enabled)
|
||||||
|
{
|
||||||
|
_hyperion->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LedDeviceWrapper::stopDeviceThread()
|
||||||
|
{
|
||||||
|
// turns the LEDs off & stop refresh timers
|
||||||
|
emit stopLedDevice();
|
||||||
|
|
||||||
|
// get current thread
|
||||||
|
QThread* oldThread = _ledDevice->thread();
|
||||||
|
disconnect(oldThread, nullptr, nullptr, nullptr);
|
||||||
|
oldThread->quit();
|
||||||
|
oldThread->wait();
|
||||||
|
delete oldThread;
|
||||||
|
|
||||||
|
disconnect(_ledDevice, nullptr, nullptr, nullptr);
|
||||||
|
delete _ledDevice;
|
||||||
|
_ledDevice = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LedDeviceWrapper::getActiveDeviceType() const
|
||||||
|
{
|
||||||
|
QString value = 0;
|
||||||
|
QMetaObject::invokeMethod(_ledDevice, "getActiveDeviceType", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int LedDeviceWrapper::getLedCount() const
|
||||||
|
{
|
||||||
|
int value = 0;
|
||||||
|
QMetaObject::invokeMethod(_ledDevice, "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LedDeviceWrapper::getColorOrder() const
|
||||||
|
{
|
||||||
|
QString value;
|
||||||
|
QMetaObject::invokeMethod(_ledDevice, "getColorOrder", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDeviceWrapper::getLatchTime() const
|
||||||
|
{
|
||||||
|
int value = 0;
|
||||||
|
QMetaObject::invokeMethod(_ledDevice, "getLatchTime", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LedDeviceWrapper::enabled() const
|
||||||
|
{
|
||||||
|
return _enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDeviceWrapper::addToDeviceMap(QString name, LedDeviceCreateFuncType funcPtr)
|
||||||
|
{
|
||||||
|
QMutexLocker lock(&_ledDeviceMapLock);
|
||||||
|
|
||||||
|
_ledDeviceMap.emplace(name,funcPtr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LedDeviceRegistry& LedDeviceWrapper::getDeviceMap()
|
||||||
|
{
|
||||||
|
QMutexLocker lock(&_ledDeviceMapLock);
|
||||||
|
|
||||||
|
return _ledDeviceMap;
|
||||||
|
}
|
||||||
|
|
||||||
QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
|
QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
|
||||||
{
|
{
|
||||||
// make sure the resources are loaded (they may be left out after static linking)
|
// make sure the resources are loaded (they may be left out after static linking)
|
||||||
@ -115,101 +206,3 @@ QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LedDeviceWrapper::addToDeviceMap(QString name, LedDeviceCreateFuncType funcPtr)
|
|
||||||
{
|
|
||||||
QMutexLocker lock(&_ledDeviceMapLock);
|
|
||||||
|
|
||||||
_ledDeviceMap.emplace(name,funcPtr);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LedDeviceRegistry& LedDeviceWrapper::getDeviceMap()
|
|
||||||
{
|
|
||||||
QMutexLocker lock(&_ledDeviceMapLock);
|
|
||||||
|
|
||||||
return _ledDeviceMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LedDeviceWrapper::getLatchTime() const
|
|
||||||
{
|
|
||||||
int value = 0;
|
|
||||||
QMetaObject::invokeMethod(_ledDevice, "getLatchTime", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, value));
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString LedDeviceWrapper::getActiveDeviceType() const
|
|
||||||
{
|
|
||||||
QString value = 0;
|
|
||||||
QMetaObject::invokeMethod(_ledDevice, "getActiveDeviceType", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, value));
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString LedDeviceWrapper::getColorOrder() const
|
|
||||||
{
|
|
||||||
QString value;
|
|
||||||
QMetaObject::invokeMethod(_ledDevice, "getColorOrder", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, value));
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int LedDeviceWrapper::getLedCount() const
|
|
||||||
{
|
|
||||||
int value = 0;
|
|
||||||
QMetaObject::invokeMethod(_ledDevice, "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, value));
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LedDeviceWrapper::enabled() const
|
|
||||||
{
|
|
||||||
return _enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LedDeviceWrapper::handleComponentState(hyperion::Components component, bool state)
|
|
||||||
{
|
|
||||||
if(component == hyperion::COMP_LEDDEVICE)
|
|
||||||
{
|
|
||||||
if ( state )
|
|
||||||
{
|
|
||||||
emit enable();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
emit disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get device's state, considering situations where it is not ready
|
|
||||||
bool deviceState = false;
|
|
||||||
QMetaObject::invokeMethod(_ledDevice, "componentState", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, deviceState));
|
|
||||||
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, deviceState);
|
|
||||||
_enabled = deviceState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LedDeviceWrapper::handleInternalEnableState(bool newState)
|
|
||||||
{
|
|
||||||
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, newState);
|
|
||||||
_enabled = newState;
|
|
||||||
|
|
||||||
if (_enabled)
|
|
||||||
{
|
|
||||||
_hyperion->update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LedDeviceWrapper::stopDeviceThread()
|
|
||||||
{
|
|
||||||
// turns the LEDs off & stop refresh timers
|
|
||||||
emit stopLedDevice();
|
|
||||||
|
|
||||||
// get current thread
|
|
||||||
QThread* oldThread = _ledDevice->thread();
|
|
||||||
disconnect(oldThread, nullptr, nullptr, nullptr);
|
|
||||||
oldThread->quit();
|
|
||||||
oldThread->wait();
|
|
||||||
delete oldThread;
|
|
||||||
|
|
||||||
disconnect(_ledDevice, nullptr, nullptr, nullptr);
|
|
||||||
delete _ledDevice;
|
|
||||||
_ledDevice = nullptr;
|
|
||||||
}
|
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// Sets configuration
|
/// Sets configuration
|
||||||
///
|
///
|
||||||
/// @para#endif // LEDEVICETEMPLATE_Hm deviceConfig the json device config
|
/// @param deviceConfig the json device config
|
||||||
/// @return true if success
|
/// @return true if success
|
||||||
bool init(const QJsonObject &deviceConfig) override;
|
bool init(const QJsonObject &deviceConfig) override;
|
||||||
|
|
||||||
|
@ -45,23 +45,16 @@ LedDeviceAtmoOrb::~LedDeviceAtmoOrb()
|
|||||||
|
|
||||||
bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
|
bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK {false};
|
||||||
|
|
||||||
if ( LedDevice::init(deviceConfig) )
|
if ( LedDevice::init(deviceConfig) )
|
||||||
{
|
{
|
||||||
|
|
||||||
_multicastGroup = deviceConfig["host"].toString(MULTICAST_GROUP_DEFAULT_ADDRESS);
|
_multicastGroup = deviceConfig["host"].toString(MULTICAST_GROUP_DEFAULT_ADDRESS);
|
||||||
_multiCastGroupPort = static_cast<quint16>(deviceConfig["port"].toInt(MULTICAST_GROUP_DEFAULT_PORT));
|
_multiCastGroupPort = static_cast<quint16>(deviceConfig["port"].toInt(MULTICAST_GROUP_DEFAULT_PORT));
|
||||||
_useOrbSmoothing = deviceConfig["useOrbSmoothing"].toBool(false);
|
_useOrbSmoothing = deviceConfig["useOrbSmoothing"].toBool(false);
|
||||||
_skipSmoothingDiff = deviceConfig["skipSmoothingDiff"].toInt(0);
|
_skipSmoothingDiff = deviceConfig["skipSmoothingDiff"].toInt(0);
|
||||||
QStringList orbIds = QStringUtils::split(deviceConfig["orbIds"].toString().simplified().remove(" "),",", QStringUtils::SplitBehavior::SkipEmptyParts);
|
QStringList orbIds = QStringUtils::split(deviceConfig["orbIds"].toString().simplified().remove(" "),",", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||||
|
|
||||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
|
||||||
Debug(_log, "LedCount : %d", this->getLedCount());
|
|
||||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
|
||||||
Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
|
|
||||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
|
||||||
|
|
||||||
Debug(_log, "MulticastGroup : %s", QSTRING_CSTR(_multicastGroup));
|
Debug(_log, "MulticastGroup : %s", QSTRING_CSTR(_multicastGroup));
|
||||||
Debug(_log, "MulticastGroupPort: %d", _multiCastGroupPort);
|
Debug(_log, "MulticastGroupPort: %d", _multiCastGroupPort);
|
||||||
Debug(_log, "Orb ID list : %s", QSTRING_CSTR(deviceConfig["orbIds"].toString()));
|
Debug(_log, "Orb ID list : %s", QSTRING_CSTR(deviceConfig["orbIds"].toString()));
|
||||||
|
@ -8,21 +8,27 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
// mDNS discover
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
#include <mdns/MdnsBrowser.h>
|
||||||
|
#include <mdns/MdnsServiceRegister.h>
|
||||||
|
#endif
|
||||||
|
#include <utils/NetUtils.h>
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
namespace {
|
namespace {
|
||||||
const bool verbose = false;
|
const bool verbose = false;
|
||||||
const bool verbose3 = false;
|
const bool verbose3 = false;
|
||||||
|
|
||||||
// Configuration settings
|
// Configuration settings
|
||||||
|
const char CONFIG_HOST[] = "host";
|
||||||
const char CONFIG_HW_LED_COUNT[] = "hardwareLedCount";
|
const char CONFIG_HW_LED_COUNT[] = "hardwareLedCount";
|
||||||
|
|
||||||
const int COLOLIGHT_BEADS_PER_MODULE = 19;
|
const int COLOLIGHT_BEADS_PER_MODULE = 19;
|
||||||
|
|
||||||
|
const int STREAM_DEFAULT_PORT = 8900;
|
||||||
|
|
||||||
// Cololight discovery service
|
// Cololight discovery service
|
||||||
|
|
||||||
const int API_DEFAULT_PORT = 8900;
|
|
||||||
|
|
||||||
const char DISCOVERY_ADDRESS[] = "255.255.255.255";
|
const char DISCOVERY_ADDRESS[] = "255.255.255.255";
|
||||||
const quint16 DISCOVERY_PORT = 12345;
|
const quint16 DISCOVERY_PORT = 12345;
|
||||||
const char DISCOVERY_MESSAGE[] = "Z-SEARCH * \r\n";
|
const char DISCOVERY_MESSAGE[] = "Z-SEARCH * \r\n";
|
||||||
@ -46,6 +52,11 @@ LedDeviceCololight::LedDeviceCololight(const QJsonObject& deviceConfig)
|
|||||||
, _distance(0)
|
, _distance(0)
|
||||||
, _sequenceNumber(1)
|
, _sequenceNumber(1)
|
||||||
{
|
{
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||||
|
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
|
||||||
|
#endif
|
||||||
|
|
||||||
_packetFixPart.append(reinterpret_cast<const char*>(PACKET_HEADER), sizeof(PACKET_HEADER));
|
_packetFixPart.append(reinterpret_cast<const char*>(PACKET_HEADER), sizeof(PACKET_HEADER));
|
||||||
_packetFixPart.append(reinterpret_cast<const char*>(PACKET_SECU), sizeof(PACKET_SECU));
|
_packetFixPart.append(reinterpret_cast<const char*>(PACKET_SECU), sizeof(PACKET_SECU));
|
||||||
}
|
}
|
||||||
@ -57,22 +68,13 @@ LedDevice* LedDeviceCololight::construct(const QJsonObject& deviceConfig)
|
|||||||
|
|
||||||
bool LedDeviceCololight::init(const QJsonObject& deviceConfig)
|
bool LedDeviceCololight::init(const QJsonObject& deviceConfig)
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK {false};
|
||||||
|
|
||||||
_port = API_DEFAULT_PORT;
|
if ( ProviderUdp::init(deviceConfig) )
|
||||||
|
|
||||||
if (ProviderUdp::init(deviceConfig))
|
|
||||||
{
|
{
|
||||||
// Initialise LedDevice configuration and execution environment
|
_hostName = _devConfig[ CONFIG_HOST ].toString();
|
||||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR(this->getActiveDeviceType()));
|
_port = STREAM_DEFAULT_PORT;
|
||||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR(this->getColorOrder()));
|
isInitOK = true;
|
||||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
|
||||||
|
|
||||||
if (initLedsConfiguration())
|
|
||||||
{
|
|
||||||
initDirectColorCmdTemplate();
|
|
||||||
isInitOK = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
@ -161,6 +163,27 @@ void LedDeviceCololight::initDirectColorCmdTemplate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LedDeviceCololight::open()
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
_isDeviceReady = false;
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||||
|
{
|
||||||
|
if (ProviderUdp::open() == 0)
|
||||||
|
{
|
||||||
|
if (initLedsConfiguration())
|
||||||
|
{
|
||||||
|
initDirectColorCmdTemplate();
|
||||||
|
// Everything is OK, device is ready
|
||||||
|
_isDeviceReady = true;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
bool LedDeviceCololight::getInfo()
|
bool LedDeviceCololight::getInfo()
|
||||||
{
|
{
|
||||||
bool isCmdOK = false;
|
bool isCmdOK = false;
|
||||||
@ -652,10 +675,19 @@ QJsonObject LedDeviceCololight::discover(const QJsonObject& /*params*/)
|
|||||||
QJsonObject devicesDiscovered;
|
QJsonObject devicesDiscovered;
|
||||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType);
|
devicesDiscovered.insert("ledDeviceType", _activeDeviceType);
|
||||||
|
|
||||||
QString discoveryMethod("ssdp");
|
|
||||||
QJsonArray deviceList;
|
QJsonArray deviceList;
|
||||||
|
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
QString discoveryMethod("mDNS");
|
||||||
|
deviceList = MdnsBrowser::getInstance().getServicesDiscoveredJson(
|
||||||
|
MdnsServiceRegister::getServiceType(_activeDeviceType),
|
||||||
|
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
|
||||||
|
DEFAULT_DISCOVER_TIMEOUT
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
QString discoveryMethod("ssdp");
|
||||||
deviceList = discover();
|
deviceList = discover();
|
||||||
|
#endif
|
||||||
|
|
||||||
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
||||||
devicesDiscovered.insert("devices", deviceList);
|
devicesDiscovered.insert("devices", deviceList);
|
||||||
@ -669,19 +701,16 @@ QJsonObject LedDeviceCololight::getProperties(const QJsonObject& params)
|
|||||||
{
|
{
|
||||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
QJsonObject properties;
|
QJsonObject properties;
|
||||||
|
|
||||||
QString hostName = params["host"].toString("");
|
|
||||||
quint16 apiPort = static_cast<quint16>(params["port"].toInt(API_DEFAULT_PORT));
|
|
||||||
|
|
||||||
QJsonObject propertiesDetails;
|
QJsonObject propertiesDetails;
|
||||||
if (!hostName.isEmpty())
|
|
||||||
|
_hostName = params[CONFIG_HOST].toString("");
|
||||||
|
_port = STREAM_DEFAULT_PORT;
|
||||||
|
|
||||||
|
Info(_log, "Get properties for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||||
{
|
{
|
||||||
QJsonObject deviceConfig;
|
if (ProviderUdp::open() == 0)
|
||||||
|
|
||||||
deviceConfig.insert("host", hostName);
|
|
||||||
deviceConfig.insert("port", apiPort);
|
|
||||||
|
|
||||||
if (ProviderUdp::init(deviceConfig))
|
|
||||||
{
|
{
|
||||||
if (getInfo())
|
if (getInfo())
|
||||||
{
|
{
|
||||||
@ -717,16 +746,14 @@ void LedDeviceCololight::identify(const QJsonObject& params)
|
|||||||
{
|
{
|
||||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
QString hostName = params["host"].toString("");
|
_hostName = params[CONFIG_HOST].toString("");
|
||||||
quint16 apiPort = static_cast<quint16>(params["port"].toInt(API_DEFAULT_PORT));
|
_port = STREAM_DEFAULT_PORT;
|
||||||
|
|
||||||
if (!hostName.isEmpty())
|
Info(_log, "Identify %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||||
{
|
{
|
||||||
QJsonObject deviceConfig;
|
if (ProviderUdp::open() == 0)
|
||||||
|
|
||||||
deviceConfig.insert("host", hostName);
|
|
||||||
deviceConfig.insert("port", apiPort);
|
|
||||||
if (ProviderUdp::init(deviceConfig))
|
|
||||||
{
|
{
|
||||||
if (setStateDirect(false) && setState(true))
|
if (setStateDirect(false) && setState(true))
|
||||||
{
|
{
|
||||||
|
@ -161,6 +161,13 @@ protected:
|
|||||||
///
|
///
|
||||||
bool init(const QJsonObject& deviceConfig) override;
|
bool init(const QJsonObject& deviceConfig) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Opens the output device.
|
||||||
|
///
|
||||||
|
/// @return Zero on success (i.e. device is ready), else negative
|
||||||
|
///
|
||||||
|
int open() override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Writes the RGB-Color values to the LEDs.
|
/// @brief Writes the RGB-Color values to the LEDs.
|
||||||
///
|
///
|
||||||
|
@ -18,15 +18,20 @@ const int MAX_NUM_LEDS = 10000; // OPC can handle 21845 LEDs - in theory, fadeca
|
|||||||
const int OPC_SET_PIXELS = 0; // OPC command codes
|
const int OPC_SET_PIXELS = 0; // OPC command codes
|
||||||
const int OPC_SYS_EX = 255; // OPC command codes
|
const int OPC_SYS_EX = 255; // OPC command codes
|
||||||
const int OPC_HEADER_SIZE = 4; // OPC header size
|
const int OPC_HEADER_SIZE = 4; // OPC header size
|
||||||
} //End of constants
|
|
||||||
|
|
||||||
// TCP elements
|
// TCP elements
|
||||||
|
const char CONFIG_HOST[] = "host";
|
||||||
|
const char CONFIG_PORT[] = "port";
|
||||||
|
|
||||||
|
const char DEFAULT_HOST[] = "127.0.0.1";
|
||||||
const int STREAM_DEFAULT_PORT = 7890;
|
const int STREAM_DEFAULT_PORT = 7890;
|
||||||
|
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
LedDeviceFadeCandy::LedDeviceFadeCandy(const QJsonObject& deviceConfig)
|
LedDeviceFadeCandy::LedDeviceFadeCandy(const QJsonObject& deviceConfig)
|
||||||
: LedDevice(deviceConfig)
|
: LedDevice(deviceConfig)
|
||||||
, _client(nullptr)
|
, _client(nullptr)
|
||||||
, _host()
|
, _hostName()
|
||||||
, _port(STREAM_DEFAULT_PORT)
|
, _port(STREAM_DEFAULT_PORT)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -43,7 +48,7 @@ LedDevice* LedDeviceFadeCandy::construct(const QJsonObject& deviceConfig)
|
|||||||
|
|
||||||
bool LedDeviceFadeCandy::init(const QJsonObject& deviceConfig)
|
bool LedDeviceFadeCandy::init(const QJsonObject& deviceConfig)
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK {false};
|
||||||
|
|
||||||
if (LedDevice::init(deviceConfig))
|
if (LedDevice::init(deviceConfig))
|
||||||
{
|
{
|
||||||
@ -55,11 +60,11 @@ bool LedDeviceFadeCandy::init(const QJsonObject& deviceConfig)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_host = deviceConfig["host"].toString("127.0.0.1");
|
_hostName = _devConfig[ CONFIG_HOST ].toString(DEFAULT_HOST);
|
||||||
_port = deviceConfig["port"].toInt(STREAM_DEFAULT_PORT);
|
_port = deviceConfig[CONFIG_PORT].toInt(STREAM_DEFAULT_PORT);
|
||||||
|
|
||||||
//If host not configured the init fails
|
//If host not configured the init fails
|
||||||
if (_host.isEmpty())
|
if (_hostName.isEmpty())
|
||||||
{
|
{
|
||||||
this->setInError("No target hostname nor IP defined");
|
this->setInError("No target hostname nor IP defined");
|
||||||
}
|
}
|
||||||
@ -90,10 +95,7 @@ bool LedDeviceFadeCandy::init(const QJsonObject& deviceConfig)
|
|||||||
_opc_data[1] = OPC_SET_PIXELS;
|
_opc_data[1] = OPC_SET_PIXELS;
|
||||||
qToBigEndian<quint16>(static_cast<quint16>(_ledRGBCount), _opc_data.data() + 2);
|
qToBigEndian<quint16>(static_cast<quint16>(_ledRGBCount), _opc_data.data() + 2);
|
||||||
|
|
||||||
if (initNetwork())
|
isInitOK = true;
|
||||||
{
|
|
||||||
isInitOK = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,12 +104,11 @@ bool LedDeviceFadeCandy::init(const QJsonObject& deviceConfig)
|
|||||||
|
|
||||||
bool LedDeviceFadeCandy::initNetwork()
|
bool LedDeviceFadeCandy::initNetwork()
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK = true;
|
||||||
|
|
||||||
if (_client == nullptr)
|
if (_client == nullptr)
|
||||||
{
|
{
|
||||||
_client = new QTcpSocket(this);
|
_client = new QTcpSocket(this);
|
||||||
isInitOK = true;
|
|
||||||
}
|
}
|
||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
@ -118,17 +119,20 @@ int LedDeviceFadeCandy::open()
|
|||||||
QString errortext;
|
QString errortext;
|
||||||
_isDeviceReady = false;
|
_isDeviceReady = false;
|
||||||
|
|
||||||
|
if (initNetwork())
|
||||||
|
{
|
||||||
// Try to open the LedDevice
|
// Try to open the LedDevice
|
||||||
if (!tryConnect())
|
if (!tryConnect())
|
||||||
{
|
{
|
||||||
errortext = QString("Failed to open device.");
|
errortext = QString("Failed to open device.");
|
||||||
this->setInError(errortext);
|
this->setInError(errortext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Everything is OK, device is ready
|
// Everything is OK, device is ready
|
||||||
_isDeviceReady = true;
|
_isDeviceReady = true;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -162,10 +166,10 @@ bool LedDeviceFadeCandy::tryConnect()
|
|||||||
if (_client != nullptr)
|
if (_client != nullptr)
|
||||||
{
|
{
|
||||||
if (_client->state() == QAbstractSocket::UnconnectedState) {
|
if (_client->state() == QAbstractSocket::UnconnectedState) {
|
||||||
_client->connectToHost(_host, static_cast<quint16>(_port));
|
_client->connectToHost(_hostName, static_cast<quint16>(_port));
|
||||||
if (_client->waitForConnected(CONNECT_TIMEOUT.count()))
|
if (_client->waitForConnected(CONNECT_TIMEOUT.count()))
|
||||||
{
|
{
|
||||||
Info(_log, "fadecandy/opc: connected to %s:%d on channel %d", QSTRING_CSTR(_host), _port, _channel);
|
Info(_log, "fadecandy/opc: connected to %s:%d on channel %d", QSTRING_CSTR(_hostName), _port, _channel);
|
||||||
if (_setFcConfig)
|
if (_setFcConfig)
|
||||||
{
|
{
|
||||||
sendFadeCandyConfiguration();
|
sendFadeCandyConfiguration();
|
||||||
|
@ -130,7 +130,7 @@ private:
|
|||||||
void sendFadeCandyConfiguration();
|
void sendFadeCandyConfiguration();
|
||||||
|
|
||||||
QTcpSocket* _client;
|
QTcpSocket* _client;
|
||||||
QString _host;
|
QString _hostName;
|
||||||
int _port;
|
int _port;
|
||||||
int _channel;
|
int _channel;
|
||||||
QByteArray _opc_data;
|
QByteArray _opc_data;
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
// Local-Hyperion includes
|
// Local-Hyperion includes
|
||||||
#include "LedDeviceNanoleaf.h"
|
#include "LedDeviceNanoleaf.h"
|
||||||
|
|
||||||
#include <ssdp/SSDPDiscover.h>
|
//std includes
|
||||||
#include <utils/QStringUtils.h>
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QtEndian>
|
#include <QtEndian>
|
||||||
|
|
||||||
//std includes
|
#include <ssdp/SSDPDiscover.h>
|
||||||
#include <sstream>
|
#include <utils/QStringUtils.h>
|
||||||
#include <iomanip>
|
|
||||||
|
// mDNS discover
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
#include <mdns/MdnsBrowser.h>
|
||||||
|
#include <mdns/MdnsServiceRegister.h>
|
||||||
|
#endif
|
||||||
|
#include <utils/NetUtils.h>
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
namespace {
|
namespace {
|
||||||
@ -18,7 +25,7 @@ const bool verbose = false;
|
|||||||
const bool verbose3 = false;
|
const bool verbose3 = false;
|
||||||
|
|
||||||
// Configuration settings
|
// Configuration settings
|
||||||
const char CONFIG_ADDRESS[] = "host";
|
const char CONFIG_HOST[] = "host";
|
||||||
const char CONFIG_AUTH_TOKEN[] = "token";
|
const char CONFIG_AUTH_TOKEN[] = "token";
|
||||||
const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
|
const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
|
||||||
const char CONFIG_BRIGHTNESS[] = "brightness";
|
const char CONFIG_BRIGHTNESS[] = "brightness";
|
||||||
@ -115,6 +122,10 @@ LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject& deviceConfig)
|
|||||||
, _extControlVersion(EXTCTRLVER_V2)
|
, _extControlVersion(EXTCTRLVER_V2)
|
||||||
, _panelLedCount(0)
|
, _panelLedCount(0)
|
||||||
{
|
{
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||||
|
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
LedDevice* LedDeviceNanoleaf::construct(const QJsonObject& deviceConfig)
|
LedDevice* LedDeviceNanoleaf::construct(const QJsonObject& deviceConfig)
|
||||||
@ -130,6 +141,8 @@ LedDeviceNanoleaf::~LedDeviceNanoleaf()
|
|||||||
|
|
||||||
bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
||||||
{
|
{
|
||||||
|
bool isInitOK {false};
|
||||||
|
|
||||||
// Overwrite non supported/required features
|
// Overwrite non supported/required features
|
||||||
setLatchTime(0);
|
setLatchTime(0);
|
||||||
setRewriteTime(0);
|
setRewriteTime(0);
|
||||||
@ -141,21 +154,19 @@ bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
|||||||
|
|
||||||
DebugIf(verbose,_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose,_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
bool isInitOK = false;
|
if ( ProviderUdp::init(deviceConfig) )
|
||||||
|
|
||||||
if (LedDevice::init(deviceConfig))
|
|
||||||
{
|
{
|
||||||
int configuredLedCount = this->getLedCount();
|
//Set hostname as per configuration and default port
|
||||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR(this->getActiveDeviceType()));
|
_hostName = deviceConfig[CONFIG_HOST].toString();
|
||||||
Debug(_log, "LedCount : %d", configuredLedCount);
|
_port = STREAM_CONTROL_DEFAULT_PORT;
|
||||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR(this->getColorOrder()));
|
_apiPort = API_DEFAULT_PORT;
|
||||||
Debug(_log, "RewriteTime : %d", this->getRewriteTime());
|
_authToken = deviceConfig[CONFIG_AUTH_TOKEN].toString();
|
||||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
|
||||||
|
|
||||||
_isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(DEFAULT_IS_RESTORE_STATE);
|
_isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(DEFAULT_IS_RESTORE_STATE);
|
||||||
_isBrightnessOverwrite = _devConfig[CONFIG_BRIGHTNESS_OVERWRITE].toBool(DEFAULT_IS_BRIGHTNESS_OVERWRITE);
|
_isBrightnessOverwrite = _devConfig[CONFIG_BRIGHTNESS_OVERWRITE].toBool(DEFAULT_IS_BRIGHTNESS_OVERWRITE);
|
||||||
_brightness = _devConfig[CONFIG_BRIGHTNESS].toInt(BRI_MAX);
|
_brightness = _devConfig[CONFIG_BRIGHTNESS].toInt(BRI_MAX);
|
||||||
|
|
||||||
|
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostName) );
|
||||||
Debug(_log, "RestoreOrigState : %d", _isRestoreOrigState);
|
Debug(_log, "RestoreOrigState : %d", _isRestoreOrigState);
|
||||||
Debug(_log, "Overwrite Brightn.: %d", _isBrightnessOverwrite);
|
Debug(_log, "Overwrite Brightn.: %d", _isBrightnessOverwrite);
|
||||||
Debug(_log, "Set Brightness to : %d", _brightness);
|
Debug(_log, "Set Brightness to : %d", _brightness);
|
||||||
@ -178,37 +189,9 @@ bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
|||||||
{
|
{
|
||||||
_leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toInt() == 0;
|
_leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toInt() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_startPos = deviceConfig[CONFIG_PANEL_START_POS].toInt(0);
|
_startPos = deviceConfig[CONFIG_PANEL_START_POS].toInt(0);
|
||||||
|
|
||||||
//Set hostname as per configuration and_defaultHost default port
|
isInitOK = true;
|
||||||
_hostName = deviceConfig[CONFIG_ADDRESS].toString();
|
|
||||||
_apiPort = API_DEFAULT_PORT;
|
|
||||||
_authToken = deviceConfig[CONFIG_AUTH_TOKEN].toString();
|
|
||||||
|
|
||||||
//If host not configured the init failed
|
|
||||||
if (_hostName.isEmpty())
|
|
||||||
{
|
|
||||||
this->setInError("No target hostname nor IP defined");
|
|
||||||
isInitOK = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (initRestAPI(_hostName, _apiPort, _authToken))
|
|
||||||
{
|
|
||||||
// Read LedDevice configuration and validate against device configuration
|
|
||||||
if (initLedsConfiguration())
|
|
||||||
{
|
|
||||||
// Set UDP streaming host and port
|
|
||||||
_devConfig["host"] = _hostName;
|
|
||||||
_devConfig["port"] = STREAM_CONTROL_DEFAULT_PORT;
|
|
||||||
|
|
||||||
isInitOK = ProviderUdp::init(_devConfig);
|
|
||||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostName));
|
|
||||||
Debug(_log, "Port : %d", _port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
@ -358,18 +341,17 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
|||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LedDeviceNanoleaf::initRestAPI(const QString& hostname, int port, const QString& token)
|
bool LedDeviceNanoleaf::openRestAPI()
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK {true};
|
||||||
|
|
||||||
if (_restApi == nullptr)
|
if (_restApi == nullptr)
|
||||||
{
|
{
|
||||||
_restApi = new ProviderRestApi(hostname, port);
|
_restApi = new ProviderRestApi(_address.toString(), _apiPort);
|
||||||
|
_restApi->setLogger(_log);
|
||||||
|
|
||||||
//Base-path is api-path + authentication token
|
//Base-path is api-path + authentication token
|
||||||
_restApi->setBasePath(QString(API_BASE_PATH).arg(token));
|
_restApi->setBasePath(QString(API_BASE_PATH).arg(_authToken));
|
||||||
|
|
||||||
isInitOK = true;
|
|
||||||
}
|
}
|
||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
@ -379,13 +361,27 @@ int LedDeviceNanoleaf::open()
|
|||||||
int retval = -1;
|
int retval = -1;
|
||||||
_isDeviceReady = false;
|
_isDeviceReady = false;
|
||||||
|
|
||||||
if (ProviderUdp::open() == 0)
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||||
{
|
{
|
||||||
// Everything is OK, device is ready
|
if ( openRestAPI() )
|
||||||
_isDeviceReady = true;
|
{
|
||||||
retval = 0;
|
// Read LedDevice configuration and validate against device configuration
|
||||||
|
if (initLedsConfiguration())
|
||||||
|
{
|
||||||
|
if (ProviderUdp::open() == 0)
|
||||||
|
{
|
||||||
|
// Everything is OK, device is ready
|
||||||
|
_isDeviceReady = true;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_restApi->setHost(_address.toString());
|
||||||
|
_restApi->setPort(_apiPort);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,13 +410,23 @@ QJsonObject LedDeviceNanoleaf::discover(const QJsonObject& /*params*/)
|
|||||||
QJsonObject devicesDiscovered;
|
QJsonObject devicesDiscovered;
|
||||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType);
|
devicesDiscovered.insert("ledDeviceType", _activeDeviceType);
|
||||||
|
|
||||||
QString discoveryMethod("ssdp");
|
|
||||||
QJsonArray deviceList;
|
QJsonArray deviceList;
|
||||||
|
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
QString discoveryMethod("mDNS");
|
||||||
|
deviceList = MdnsBrowser::getInstance().getServicesDiscoveredJson(
|
||||||
|
MdnsServiceRegister::getServiceType(_activeDeviceType),
|
||||||
|
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
|
||||||
|
DEFAULT_DISCOVER_TIMEOUT
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
QString discoveryMethod("ssdp");
|
||||||
deviceList = discover();
|
deviceList = discover();
|
||||||
|
#endif
|
||||||
|
|
||||||
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
||||||
devicesDiscovered.insert("devices", deviceList);
|
devicesDiscovered.insert("devices", deviceList);
|
||||||
|
|
||||||
DebugIf(verbose,_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose,_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
return devicesDiscovered;
|
return devicesDiscovered;
|
||||||
@ -431,27 +437,29 @@ QJsonObject LedDeviceNanoleaf::getProperties(const QJsonObject& params)
|
|||||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
QJsonObject properties;
|
QJsonObject properties;
|
||||||
|
|
||||||
// Get Nanoleaf device properties
|
_hostName = params[CONFIG_HOST].toString("");
|
||||||
QString hostName = params["host"].toString("");
|
_apiPort = API_DEFAULT_PORT;
|
||||||
|
_authToken = params["token"].toString("");
|
||||||
|
|
||||||
if (!hostName.isEmpty())
|
Info(_log, "Get properties for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||||
{
|
{
|
||||||
QString authToken = params["token"].toString("");
|
if ( openRestAPI() )
|
||||||
QString filter = params["filter"].toString("");
|
|
||||||
|
|
||||||
initRestAPI(hostName, API_DEFAULT_PORT, authToken);
|
|
||||||
_restApi->setPath(filter);
|
|
||||||
|
|
||||||
// Perform request
|
|
||||||
httpResponse response = _restApi->get();
|
|
||||||
if (response.error())
|
|
||||||
{
|
{
|
||||||
Warning(_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
QString filter = params["filter"].toString("");
|
||||||
|
_restApi->setPath(filter);
|
||||||
|
|
||||||
|
// Perform request
|
||||||
|
httpResponse response = _restApi->get();
|
||||||
|
if (response.error())
|
||||||
|
{
|
||||||
|
Warning(_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||||
|
}
|
||||||
|
properties.insert("properties", response.getBody().object());
|
||||||
}
|
}
|
||||||
|
|
||||||
properties.insert("properties", response.getBody().object());
|
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
DebugIf(verbose,_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
|
||||||
}
|
}
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
@ -460,19 +468,24 @@ void LedDeviceNanoleaf::identify(const QJsonObject& params)
|
|||||||
{
|
{
|
||||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
QString hostName = params["host"].toString("");
|
_hostName = params[CONFIG_HOST].toString("");
|
||||||
if (!hostName.isEmpty())
|
_apiPort = API_DEFAULT_PORT;if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||||
|
_authToken = params["token"].toString("");
|
||||||
|
|
||||||
|
Info(_log, "Identify %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||||
{
|
{
|
||||||
QString authToken = params["token"].toString("");
|
if ( openRestAPI() )
|
||||||
|
|
||||||
initRestAPI(hostName, API_DEFAULT_PORT, authToken);
|
|
||||||
_restApi->setPath("identify");
|
|
||||||
|
|
||||||
// Perform request
|
|
||||||
httpResponse response = _restApi->put();
|
|
||||||
if (response.error())
|
|
||||||
{
|
{
|
||||||
Warning(_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
_restApi->setPath("identify");
|
||||||
|
|
||||||
|
// Perform request
|
||||||
|
httpResponse response = _restApi->put();
|
||||||
|
if (response.error())
|
||||||
|
{
|
||||||
|
Warning(_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -662,7 +675,7 @@ bool LedDeviceNanoleaf::restoreState()
|
|||||||
Warning (_log, "%s restoring effect failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
Warning (_log, "%s restoring effect failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Warning (_log, "%s restoring effect failed with error: Cannot restore dynamic or solid effect. Turning device off", QSTRING_CSTR(_activeDeviceType));
|
Warning (_log, "%s restoring effect failed with error: Cannot restore dynamic or solid effect. Device is switched off", QSTRING_CSTR(_activeDeviceType));
|
||||||
_originalIsOn = false;
|
_originalIsOn = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -150,13 +150,9 @@ private:
|
|||||||
///
|
///
|
||||||
/// @brief Initialise the access to the REST-API wrapper
|
/// @brief Initialise the access to the REST-API wrapper
|
||||||
///
|
///
|
||||||
/// @param[in] host
|
|
||||||
/// @param[in] port
|
|
||||||
/// @param[in] authentication token
|
|
||||||
///
|
|
||||||
/// @return True, if success
|
/// @return True, if success
|
||||||
///
|
///
|
||||||
bool initRestAPI(const QString& hostname, int port, const QString& token);
|
bool openRestAPI();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get Nanoleaf device details and configuration
|
/// @brief Get Nanoleaf device details and configuration
|
||||||
@ -188,9 +184,7 @@ private:
|
|||||||
|
|
||||||
///REST-API wrapper
|
///REST-API wrapper
|
||||||
ProviderRestApi* _restApi;
|
ProviderRestApi* _restApi;
|
||||||
|
int _apiPort;
|
||||||
QString _hostName;
|
|
||||||
int _apiPort;
|
|
||||||
QString _authToken;
|
QString _authToken;
|
||||||
|
|
||||||
bool _topDown;
|
bool _topDown;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QEventLoop>
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QtCore/qmath.h>
|
#include <QtCore/qmath.h>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
@ -85,7 +84,7 @@ struct CiColor
|
|||||||
///
|
///
|
||||||
/// @return color point
|
/// @return color point
|
||||||
///
|
///
|
||||||
static CiColor rgbToCiColor(double red, double green, double blue, const CiColorTriangle &colorSpace);
|
static CiColor rgbToCiColor(double red, double green, double blue, const CiColorTriangle& colorSpace, bool candyGamma);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @param p the color point to check
|
/// @param p the color point to check
|
||||||
@ -149,8 +148,9 @@ public:
|
|||||||
/// @param bridge the bridge
|
/// @param bridge the bridge
|
||||||
/// @param id the light id
|
/// @param id the light id
|
||||||
///
|
///
|
||||||
PhilipsHueLight(Logger* log, unsigned int id, QJsonObject values, unsigned int ledidx);
|
PhilipsHueLight(Logger* log, int id, QJsonObject values, int ledidx,
|
||||||
~PhilipsHueLight();
|
int onBlackTimeToPowerOff,
|
||||||
|
int onBlackTimeToPowerOn);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @param on
|
/// @param on
|
||||||
@ -167,11 +167,12 @@ public:
|
|||||||
///
|
///
|
||||||
void setColor(const CiColor& color);
|
void setColor(const CiColor& color);
|
||||||
|
|
||||||
unsigned int getId() const;
|
int getId() const;
|
||||||
|
|
||||||
bool getOnOffState() const;
|
bool getOnOffState() const;
|
||||||
int getTransitionTime() const;
|
int getTransitionTime() const;
|
||||||
CiColor getColor() const;
|
CiColor getColor() const;
|
||||||
|
bool hasColor() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @return the color space of the light determined by the model id reported by the bridge.
|
/// @return the color space of the light determined by the model id reported by the bridge.
|
||||||
@ -180,15 +181,21 @@ public:
|
|||||||
void saveOriginalState(const QJsonObject& values);
|
void saveOriginalState(const QJsonObject& values);
|
||||||
QString getOriginalState() const;
|
QString getOriginalState() const;
|
||||||
|
|
||||||
|
bool isBusy();
|
||||||
|
bool isBlack(bool isBlack);
|
||||||
|
bool isWhite(bool isWhite);
|
||||||
|
void setBlack();
|
||||||
|
void blackScreenTriggered();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Logger* _log;
|
Logger* _log;
|
||||||
/// light id
|
/// light id
|
||||||
unsigned int _id;
|
int _id;
|
||||||
unsigned int _ledidx;
|
int _ledidx;
|
||||||
bool _on;
|
bool _on;
|
||||||
int _transitionTime;
|
int _transitionTime;
|
||||||
CiColor _color;
|
CiColor _color;
|
||||||
|
bool _hasColor;
|
||||||
/// darkes blue color in hue lamp GAMUT = black
|
/// darkes blue color in hue lamp GAMUT = black
|
||||||
CiColor _colorBlack;
|
CiColor _colorBlack;
|
||||||
/// The model id of the hue lamp which is used to determine the color space.
|
/// The model id of the hue lamp which is used to determine the color space.
|
||||||
@ -201,6 +208,12 @@ private:
|
|||||||
|
|
||||||
QString _originalState;
|
QString _originalState;
|
||||||
CiColor _originalColor;
|
CiColor _originalColor;
|
||||||
|
qint64 _lastSendColorTime;
|
||||||
|
qint64 _lastBlackTime;
|
||||||
|
qint64 _lastWhiteTime;
|
||||||
|
bool _blackScreenTriggered;
|
||||||
|
qint64 _onBlackTimeToPowerOff;
|
||||||
|
qint64 _onBlackTimeToPowerOn;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LedDevicePhilipsHueBridge : public ProviderUdpSSL
|
class LedDevicePhilipsHueBridge : public ProviderUdpSSL
|
||||||
@ -215,13 +228,9 @@ public:
|
|||||||
///
|
///
|
||||||
/// @brief Initialise the access to the REST-API wrapper
|
/// @brief Initialise the access to the REST-API wrapper
|
||||||
///
|
///
|
||||||
/// @param[in] host
|
|
||||||
/// @param[in] port
|
|
||||||
/// @param[in] authentication token
|
|
||||||
///
|
|
||||||
/// @return True, if success
|
/// @return True, if success
|
||||||
///
|
///
|
||||||
bool initRestAPI(const QString &hostname, int port, const QString &token );
|
bool openRestAPI();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Perform a REST-API GET
|
/// @brief Perform a REST-API GET
|
||||||
@ -238,20 +247,18 @@ public:
|
|||||||
/// @param route the route of the POST request.
|
/// @param route the route of the POST request.
|
||||||
/// @param content the content of the POST request.
|
/// @param content the content of the POST request.
|
||||||
///
|
///
|
||||||
QJsonDocument post(const QString& route, const QString& content);
|
QJsonDocument put(const QString& route, const QString& content, bool supressError = false);
|
||||||
|
|
||||||
QJsonDocument getLightState(unsigned int lightId);
|
QJsonDocument getLightState( int lightId);
|
||||||
void setLightState(unsigned int lightId = 0, const QString &state = "");
|
void setLightState( int lightId = 0, const QString &state = "");
|
||||||
|
|
||||||
QMap<quint16,QJsonObject> getLightMap() const;
|
QMap<int,QJsonObject> getLightMap() const;
|
||||||
|
|
||||||
QMap<quint16,QJsonObject> getGroupMap() const;
|
QMap<int,QJsonObject> getGroupMap() const;
|
||||||
|
|
||||||
QString getGroupName(quint16 groupId = 0) const;
|
|
||||||
|
|
||||||
QJsonArray getGroupLights(quint16 groupId = 0) const;
|
|
||||||
|
|
||||||
|
QString getGroupName(int groupId = 0) const;
|
||||||
|
|
||||||
|
QJsonArray getGroupLights(int groupId = 0) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@ -281,23 +288,66 @@ protected:
|
|||||||
/// @brief Check, if Hue API response indicate error
|
/// @brief Check, if Hue API response indicate error
|
||||||
///
|
///
|
||||||
/// @param[in] response from Hue-Bridge in JSON-format
|
/// @param[in] response from Hue-Bridge in JSON-format
|
||||||
|
/// @param[in] suppressError Treat an error as a warning
|
||||||
|
///
|
||||||
/// return True, Hue Bridge reports error
|
/// return True, Hue Bridge reports error
|
||||||
///
|
///
|
||||||
bool checkApiError(const QJsonDocument &response );
|
bool checkApiError(const QJsonDocument& response, bool supressError = false);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Discover devices of this type available (for configuration).
|
||||||
|
/// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
|
||||||
|
///
|
||||||
|
/// @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;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Get the Hue Bridge device's resource properties
|
||||||
|
///
|
||||||
|
/// Following parameters are required
|
||||||
|
/// @code
|
||||||
|
/// {
|
||||||
|
/// "host" : "hostname or IP",
|
||||||
|
/// "port" : port
|
||||||
|
/// "user" : "username",
|
||||||
|
/// "filter": "resource to query", root "/" is used, if empty
|
||||||
|
/// }
|
||||||
|
///@endcode
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters to query device
|
||||||
|
/// @return A JSON structure holding the device's properties
|
||||||
|
///
|
||||||
|
QJsonObject getProperties(const QJsonObject& params) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Add an authorization/client-key to the Hue Bridge device
|
||||||
|
///
|
||||||
|
/// Following parameters are required
|
||||||
|
/// @code
|
||||||
|
/// {
|
||||||
|
/// "host" : "hostname or IP",
|
||||||
|
/// "port" : port
|
||||||
|
/// }
|
||||||
|
///@endcode
|
||||||
|
///
|
||||||
|
/// @param[in] params Parameters to query device
|
||||||
|
/// @return A JSON structure holding the authorization keys
|
||||||
|
///
|
||||||
|
QJsonObject addAuthorization(const QJsonObject& params) override;
|
||||||
|
|
||||||
///REST-API wrapper
|
///REST-API wrapper
|
||||||
ProviderRestApi* _restApi;
|
ProviderRestApi* _restApi;
|
||||||
|
|
||||||
/// Ip address of the bridge
|
|
||||||
QString _hostname;
|
|
||||||
int _apiPort;
|
int _apiPort;
|
||||||
/// User name for the API ("newdeveloper")
|
/// User name for the API ("newdeveloper")
|
||||||
QString _username;
|
QString _authToken;
|
||||||
|
|
||||||
bool _useHueEntertainmentAPI;
|
bool _useHueEntertainmentAPI;
|
||||||
|
|
||||||
QJsonDocument getGroupState( unsigned int groupId );
|
QJsonDocument getGroupState( int groupId );
|
||||||
QJsonDocument setGroupState( unsigned int groupId, bool state);
|
QJsonDocument setGroupState( int groupId, bool state);
|
||||||
|
|
||||||
bool isStreamOwner(const QString &streamOwner) const;
|
bool isStreamOwner(const QString &streamOwner) const;
|
||||||
bool initMaps();
|
bool initMaps();
|
||||||
@ -308,6 +358,14 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Discover Philips-Hue devices available (for configuration).
|
||||||
|
/// Philips-Hue specific ssdp discovery
|
||||||
|
///
|
||||||
|
/// @return A JSON structure holding a list of devices found
|
||||||
|
///
|
||||||
|
QJsonArray discover();
|
||||||
|
|
||||||
QJsonDocument getAllBridgeInfos();
|
QJsonDocument getAllBridgeInfos();
|
||||||
void setBridgeConfig( const QJsonDocument &doc );
|
void setBridgeConfig( const QJsonDocument &doc );
|
||||||
void setLightsMap( const QJsonDocument &doc );
|
void setLightsMap( const QJsonDocument &doc );
|
||||||
@ -324,8 +382,8 @@ private:
|
|||||||
|
|
||||||
bool _isHueEntertainmentReady;
|
bool _isHueEntertainmentReady;
|
||||||
|
|
||||||
QMap<quint16,QJsonObject> _lightsMap;
|
QMap<int,QJsonObject> _lightsMap;
|
||||||
QMap<quint16,QJsonObject> _groupsMap;
|
QMap<int,QJsonObject> _groupsMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -360,34 +418,6 @@ public:
|
|||||||
/// @return LedDevice constructed
|
/// @return LedDevice constructed
|
||||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Discover devices of this type available (for configuration).
|
|
||||||
/// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
|
|
||||||
///
|
|
||||||
/// @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;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Get the Hue Bridge device's resource properties
|
|
||||||
///
|
|
||||||
/// Following parameters are required
|
|
||||||
/// @code
|
|
||||||
/// {
|
|
||||||
/// "host" : "hostname or IP
|
|
||||||
/// "port" : port
|
|
||||||
/// "user" : "username",
|
|
||||||
/// "filter": "resource to query", root "/" is used, if empty
|
|
||||||
/// }
|
|
||||||
///@endcode
|
|
||||||
///
|
|
||||||
/// @param[in] params Parameters to query device
|
|
||||||
/// @return A JSON structure holding the device's properties
|
|
||||||
///
|
|
||||||
QJsonObject getProperties(const QJsonObject& params) override;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Send an update to the device to identify it.
|
/// @brief Send an update to the device to identify it.
|
||||||
///
|
///
|
||||||
@ -412,7 +442,7 @@ public:
|
|||||||
///
|
///
|
||||||
unsigned int getLightsCount() const { return _lightsCount; }
|
unsigned int getLightsCount() const { return _lightsCount; }
|
||||||
|
|
||||||
void setOnOffState(PhilipsHueLight& light, bool on);
|
void setOnOffState(PhilipsHueLight& light, bool on, bool force = false);
|
||||||
void setTransitionTime(PhilipsHueLight& light);
|
void setTransitionTime(PhilipsHueLight& light);
|
||||||
void setColor(PhilipsHueLight& light, CiColor& color);
|
void setColor(PhilipsHueLight& light, CiColor& color);
|
||||||
void setState(PhilipsHueLight& light, bool on, const CiColor& color);
|
void setState(PhilipsHueLight& light, bool on, const CiColor& color);
|
||||||
@ -443,13 +473,6 @@ protected:
|
|||||||
///
|
///
|
||||||
int open() override;
|
int open() override;
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Closes the output device.
|
|
||||||
///
|
|
||||||
/// @return Zero on success (i.e. device is closed), else negative
|
|
||||||
///
|
|
||||||
int close() override;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Writes the RGB-Color values to the LEDs.
|
/// @brief Writes the RGB-Color values to the LEDs.
|
||||||
///
|
///
|
||||||
@ -465,7 +488,7 @@ protected:
|
|||||||
/// Depending on the configuration, the device may store its current state for later restore.
|
/// Depending on the configuration, the device may store its current state for later restore.
|
||||||
/// @see powerOn, storeState
|
/// @see powerOn, storeState
|
||||||
///
|
///
|
||||||
/// @return True if success
|
/// @return True, if success
|
||||||
///
|
///
|
||||||
bool switchOn() override;
|
bool switchOn() override;
|
||||||
|
|
||||||
@ -518,28 +541,17 @@ protected:
|
|||||||
///
|
///
|
||||||
bool restoreState() override;
|
bool restoreState() override;
|
||||||
|
|
||||||
private slots:
|
|
||||||
|
|
||||||
void noSignalTimeout();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool initLeds();
|
bool initLeds();
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
|
||||||
///
|
|
||||||
/// @param map Map of lightid/value pairs of bridge
|
|
||||||
///
|
|
||||||
void newLights(QMap<quint16, QJsonObject> map);
|
|
||||||
|
|
||||||
bool setLights();
|
bool setLights();
|
||||||
|
|
||||||
/// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
/// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
||||||
///
|
///
|
||||||
/// @param map Map of lightid/value pairs of bridge
|
/// @param map Map of lightid/value pairs of bridge
|
||||||
///
|
///
|
||||||
bool updateLights(const QMap<quint16, QJsonObject> &map);
|
bool updateLights(const QMap<int, QJsonObject> &map);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Set the number of LEDs supported by the device.
|
/// @brief Set the number of LEDs supported by the device.
|
||||||
@ -554,13 +566,9 @@ private:
|
|||||||
bool startStream();
|
bool startStream();
|
||||||
bool stopStream();
|
bool stopStream();
|
||||||
|
|
||||||
void writeStream();
|
void writeStream(bool flush = false);
|
||||||
int writeSingleLights(const std::vector<ColorRgb>& ledValues);
|
int writeSingleLights(const std::vector<ColorRgb>& ledValues);
|
||||||
|
|
||||||
bool noSignalDetection();
|
|
||||||
|
|
||||||
void stopBlackTimeoutTimer();
|
|
||||||
|
|
||||||
QByteArray prepareStreamData() const;
|
QByteArray prepareStreamData() const;
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -574,32 +582,28 @@ private:
|
|||||||
bool _isInitLeds;
|
bool _isInitLeds;
|
||||||
|
|
||||||
/// Array of the light ids.
|
/// Array of the light ids.
|
||||||
std::vector<quint16> _lightIds;
|
std::vector<int> _lightIds;
|
||||||
/// Array to save the lamps.
|
/// Array to save the lamps.
|
||||||
std::vector<PhilipsHueLight> _lights;
|
std::vector<PhilipsHueLight> _lights;
|
||||||
|
|
||||||
unsigned int _lightsCount;
|
int _lightsCount;
|
||||||
quint16 _groupId;
|
int _groupId;
|
||||||
|
|
||||||
double _brightnessMin;
|
|
||||||
double _brightnessMax;
|
|
||||||
|
|
||||||
bool _allLightsBlack;
|
|
||||||
|
|
||||||
QTimer* _blackLightsTimer;
|
|
||||||
int _blackLightsTimeout;
|
int _blackLightsTimeout;
|
||||||
double _brightnessThreshold;
|
double _blackLevel;
|
||||||
|
int _onBlackTimeToPowerOff;
|
||||||
int _handshake_timeout_min;
|
int _onBlackTimeToPowerOn;
|
||||||
int _handshake_timeout_max;
|
bool _candyGamma;
|
||||||
int _ssl_read_timeout;
|
|
||||||
|
|
||||||
|
// TODO: Check what is the correct class
|
||||||
|
uint32_t _handshake_timeout_min;
|
||||||
|
uint32_t _handshake_timeout_max;
|
||||||
bool _stopConnection;
|
bool _stopConnection;
|
||||||
|
|
||||||
QString _groupName;
|
QString _groupName;
|
||||||
QString _streamOwner;
|
QString _streamOwner;
|
||||||
|
|
||||||
int start_retry_left;
|
qint64 _lastConfirm;
|
||||||
int stop_retry_left;
|
int _lastId;
|
||||||
|
bool _groupStreamState;
|
||||||
};
|
};
|
||||||
|
@ -65,13 +65,6 @@ bool LedDeviceRazer::init(const QJsonObject& deviceConfig)
|
|||||||
// Initialise sub-class
|
// Initialise sub-class
|
||||||
if (LedDevice::init(deviceConfig))
|
if (LedDevice::init(deviceConfig))
|
||||||
{
|
{
|
||||||
// Initialise LedDevice configuration and execution environment
|
|
||||||
uint configuredLedCount = this->getLedCount();
|
|
||||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR(this->getActiveDeviceType()));
|
|
||||||
Debug(_log, "LedCount : %u", configuredLedCount);
|
|
||||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR(this->getColorOrder()));
|
|
||||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
|
||||||
Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
|
|
||||||
|
|
||||||
//Razer Chroma SDK allows localhost connection only
|
//Razer Chroma SDK allows localhost connection only
|
||||||
_hostname = API_DEFAULT_HOST;
|
_hostname = API_DEFAULT_HOST;
|
||||||
@ -86,6 +79,7 @@ bool LedDeviceRazer::init(const QJsonObject& deviceConfig)
|
|||||||
Debug(_log, "Razer Device : %s", QSTRING_CSTR(_razerDeviceType));
|
Debug(_log, "Razer Device : %s", QSTRING_CSTR(_razerDeviceType));
|
||||||
Debug(_log, "Single Color : %d", _isSingleColor);
|
Debug(_log, "Single Color : %d", _isSingleColor);
|
||||||
|
|
||||||
|
int configuredLedCount = this->getLedCount();
|
||||||
if (resolveDeviceProperties(_razerDeviceType))
|
if (resolveDeviceProperties(_razerDeviceType))
|
||||||
{
|
{
|
||||||
if (_isSingleColor && configuredLedCount > 1)
|
if (_isSingleColor && configuredLedCount > 1)
|
||||||
@ -125,6 +119,8 @@ bool LedDeviceRazer::initRestAPI(const QString& hostname, int port)
|
|||||||
if (_restApi == nullptr)
|
if (_restApi == nullptr)
|
||||||
{
|
{
|
||||||
_restApi = new ProviderRestApi(hostname, port);
|
_restApi = new ProviderRestApi(hostname, port);
|
||||||
|
_restApi->setLogger(_log);
|
||||||
|
|
||||||
_restApi->setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
_restApi->setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
|
|
||||||
isInitOK = true;
|
isInitOK = true;
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
#include "LedDeviceTpm2net.h"
|
#include "LedDeviceTpm2net.h"
|
||||||
|
#include <utils/NetUtils.h>
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char CONFIG_HOST[] = "host";
|
||||||
|
const char CONFIG_PORT[] = "port";
|
||||||
const ushort TPM2_DEFAULT_PORT = 65506;
|
const ushort TPM2_DEFAULT_PORT = 65506;
|
||||||
|
}
|
||||||
|
|
||||||
LedDeviceTpm2net::LedDeviceTpm2net(const QJsonObject &deviceConfig)
|
LedDeviceTpm2net::LedDeviceTpm2net(const QJsonObject &deviceConfig)
|
||||||
: ProviderUdp(deviceConfig)
|
: ProviderUdp(deviceConfig)
|
||||||
@ -20,13 +27,14 @@ LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
|
|||||||
|
|
||||||
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
|
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK {false};
|
||||||
|
|
||||||
_port = TPM2_DEFAULT_PORT;
|
|
||||||
|
|
||||||
// Initialise sub-class
|
// Initialise sub-class
|
||||||
if ( ProviderUdp::init(deviceConfig) )
|
if ( ProviderUdp::init(deviceConfig) )
|
||||||
{
|
{
|
||||||
|
_hostName = _devConfig[ CONFIG_HOST ].toString();
|
||||||
|
_port = deviceConfig[CONFIG_PORT].toInt(TPM2_DEFAULT_PORT);
|
||||||
|
|
||||||
_tpm2_max = deviceConfig["max-packet"].toInt(170);
|
_tpm2_max = deviceConfig["max-packet"].toInt(170);
|
||||||
_tpm2ByteCount = 3 * _ledCount;
|
_tpm2ByteCount = 3 * _ledCount;
|
||||||
_tpm2TotalPackets = (_tpm2ByteCount / _tpm2_max) + ((_tpm2ByteCount % _tpm2_max) != 0);
|
_tpm2TotalPackets = (_tpm2ByteCount / _tpm2_max) + ((_tpm2ByteCount % _tpm2_max) != 0);
|
||||||
@ -38,6 +46,23 @@ bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
|
|||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LedDeviceTpm2net::open()
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
_isDeviceReady = false;
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||||
|
{
|
||||||
|
if (ProviderUdp::open() == 0)
|
||||||
|
{
|
||||||
|
// Everything is OK, device is ready
|
||||||
|
_isDeviceReady = true;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int LedDeviceTpm2net::write(const std::vector<ColorRgb> &ledValues)
|
int LedDeviceTpm2net::write(const std::vector<ColorRgb> &ledValues)
|
||||||
{
|
{
|
||||||
int retVal = 0;
|
int retVal = 0;
|
||||||
|
@ -41,6 +41,13 @@ private:
|
|||||||
///
|
///
|
||||||
bool init(const QJsonObject &deviceConfig) override;
|
bool init(const QJsonObject &deviceConfig) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Opens the output device.
|
||||||
|
///
|
||||||
|
/// @return Zero on success (i.e. device is ready), else negative
|
||||||
|
///
|
||||||
|
int open() override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Writes the RGB-Color values to the LEDs.
|
/// @brief Writes the RGB-Color values to the LEDs.
|
||||||
///
|
///
|
||||||
|
@ -9,7 +9,16 @@
|
|||||||
|
|
||||||
#include <QHostInfo>
|
#include <QHostInfo>
|
||||||
|
|
||||||
|
#include <utils/NetUtils.h>
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char CONFIG_HOST[] = "host";
|
||||||
|
const char CONFIG_PORT[] = "port";
|
||||||
|
|
||||||
const ushort ARTNET_DEFAULT_PORT = 6454;
|
const ushort ARTNET_DEFAULT_PORT = 6454;
|
||||||
|
}
|
||||||
|
|
||||||
LedDeviceUdpArtNet::LedDeviceUdpArtNet(const QJsonObject &deviceConfig)
|
LedDeviceUdpArtNet::LedDeviceUdpArtNet(const QJsonObject &deviceConfig)
|
||||||
: ProviderUdp(deviceConfig)
|
: ProviderUdp(deviceConfig)
|
||||||
@ -23,13 +32,14 @@ LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
|
|||||||
|
|
||||||
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
|
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK {false};
|
||||||
|
|
||||||
_port = ARTNET_DEFAULT_PORT;
|
|
||||||
|
|
||||||
// Initialise sub-class
|
// Initialise sub-class
|
||||||
if ( ProviderUdp::init(deviceConfig) )
|
if ( ProviderUdp::init(deviceConfig) )
|
||||||
{
|
{
|
||||||
|
_hostName = _devConfig[ CONFIG_HOST ].toString();
|
||||||
|
_port = deviceConfig[CONFIG_PORT].toInt(ARTNET_DEFAULT_PORT);
|
||||||
|
|
||||||
_artnet_universe = deviceConfig["universe"].toInt(1);
|
_artnet_universe = deviceConfig["universe"].toInt(1);
|
||||||
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
|
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
|
||||||
|
|
||||||
@ -38,6 +48,23 @@ bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
|
|||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LedDeviceUdpArtNet::open()
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
_isDeviceReady = false;
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||||
|
{
|
||||||
|
if (ProviderUdp::open() == 0)
|
||||||
|
{
|
||||||
|
// Everything is OK, device is ready
|
||||||
|
_isDeviceReady = true;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
// populates the headers
|
// populates the headers
|
||||||
void LedDeviceUdpArtNet::prepare(unsigned this_universe, unsigned this_sequence, unsigned this_dmxChannelCount)
|
void LedDeviceUdpArtNet::prepare(unsigned this_universe, unsigned this_sequence, unsigned this_dmxChannelCount)
|
||||||
{
|
{
|
||||||
|
@ -69,6 +69,13 @@ private:
|
|||||||
///
|
///
|
||||||
bool init(const QJsonObject &deviceConfig) override;
|
bool init(const QJsonObject &deviceConfig) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Opens the output device.
|
||||||
|
///
|
||||||
|
/// @return Zero on success (i.e. device is ready), else negative
|
||||||
|
///
|
||||||
|
int open() override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Writes the RGB-Color values to the LEDs.
|
/// @brief Writes the RGB-Color values to the LEDs.
|
||||||
///
|
///
|
||||||
|
163
libsrc/leddevice/dev_net/LedDeviceUdpDdp.cpp
Normal file
163
libsrc/leddevice/dev_net/LedDeviceUdpDdp.cpp
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#include "LedDeviceUdpDdp.h"
|
||||||
|
|
||||||
|
#include <QtEndian>
|
||||||
|
|
||||||
|
#include <utils/NetUtils.h>
|
||||||
|
|
||||||
|
// DDP header format
|
||||||
|
// header is 10 bytes (14 if TIME flag used)
|
||||||
|
struct ddp_hdr_struct {
|
||||||
|
uint8_t flags1;
|
||||||
|
uint8_t flags2;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t id;
|
||||||
|
uint32_t offset;
|
||||||
|
uint16_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char CONFIG_HOST[] = "host";
|
||||||
|
const char CONFIG_PORT[] = "port";
|
||||||
|
|
||||||
|
const ushort DDP_DEFAULT_PORT = 4048;
|
||||||
|
|
||||||
|
namespace DDP {
|
||||||
|
|
||||||
|
// DDP protocol header definitions
|
||||||
|
struct Header {
|
||||||
|
uint8_t flags1;
|
||||||
|
uint8_t flags2;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t id;
|
||||||
|
uint8_t offset[4];
|
||||||
|
uint8_t len[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr int HEADER_LEN = (sizeof(struct Header)); // header is 10 bytes (14 if TIME flag used)
|
||||||
|
static constexpr int MAX_LEDS = 480;
|
||||||
|
static constexpr int CHANNELS_PER_PACKET = MAX_LEDS*3;
|
||||||
|
|
||||||
|
namespace flags1 {
|
||||||
|
static constexpr auto VER_MASK = 0xc0;
|
||||||
|
static constexpr auto VER1 = 0x40;
|
||||||
|
static constexpr auto PUSH = 0x01;
|
||||||
|
static constexpr auto QUERY = 0x02;
|
||||||
|
static constexpr auto REPLY = 0x04;
|
||||||
|
static constexpr auto STORAGE = 0x08;
|
||||||
|
static constexpr auto TIME = 0x10;
|
||||||
|
} // namespace flags1
|
||||||
|
|
||||||
|
namespace id {
|
||||||
|
static constexpr auto DISPLAY = 1;
|
||||||
|
static constexpr auto CONTROL = 246;
|
||||||
|
static constexpr auto CONFIG = 250;
|
||||||
|
static constexpr auto STATUS = 251;
|
||||||
|
static constexpr auto DMXTRANSIT = 254;
|
||||||
|
static constexpr auto ALLDEVICES = 255;
|
||||||
|
} // namespace id
|
||||||
|
|
||||||
|
} // namespace DDP
|
||||||
|
|
||||||
|
} //End of constants
|
||||||
|
|
||||||
|
LedDeviceUdpDdp::LedDeviceUdpDdp(const QJsonObject &deviceConfig)
|
||||||
|
: ProviderUdp(deviceConfig)
|
||||||
|
,_packageSequenceNumber(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LedDevice* LedDeviceUdpDdp::construct(const QJsonObject &deviceConfig)
|
||||||
|
{
|
||||||
|
return new LedDeviceUdpDdp(deviceConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LedDeviceUdpDdp::init(const QJsonObject &deviceConfig)
|
||||||
|
{
|
||||||
|
bool isInitOK {false};
|
||||||
|
|
||||||
|
if ( ProviderUdp::init(deviceConfig) )
|
||||||
|
{
|
||||||
|
_hostName = _devConfig[ CONFIG_HOST ].toString();
|
||||||
|
_port = deviceConfig[CONFIG_PORT].toInt(DDP_DEFAULT_PORT);
|
||||||
|
|
||||||
|
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostName) );
|
||||||
|
Debug(_log, "Port : %d", _port );
|
||||||
|
|
||||||
|
_ddpData.resize(DDP::HEADER_LEN + DDP::CHANNELS_PER_PACKET);
|
||||||
|
_ddpData[0] = DDP::flags1::VER1; // flags1
|
||||||
|
_ddpData[1] = 0; // flags2
|
||||||
|
_ddpData[2] = 1; // type
|
||||||
|
_ddpData[3] = DDP::id::DISPLAY; // id
|
||||||
|
|
||||||
|
isInitOK = true;
|
||||||
|
}
|
||||||
|
return isInitOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDeviceUdpDdp::open()
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
_isDeviceReady = false;
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||||
|
{
|
||||||
|
if (ProviderUdp::open() == 0)
|
||||||
|
{
|
||||||
|
// Everything is OK, device is ready
|
||||||
|
_isDeviceReady = true;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDeviceUdpDdp::write(const std::vector<ColorRgb> &ledValues)
|
||||||
|
{
|
||||||
|
int rc {0};
|
||||||
|
|
||||||
|
int channelCount = static_cast<int>(_ledCount) * 3; // 1 channel for every R,G,B value
|
||||||
|
int packetCount = ((channelCount-1) / DDP::CHANNELS_PER_PACKET) + 1;
|
||||||
|
int channel = 0;
|
||||||
|
|
||||||
|
_ddpData[0] = DDP::flags1::VER1;
|
||||||
|
|
||||||
|
for (int currentPacket = 0; currentPacket < packetCount; currentPacket++)
|
||||||
|
{
|
||||||
|
if (_packageSequenceNumber > 15)
|
||||||
|
{
|
||||||
|
_packageSequenceNumber = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int packetSize = DDP::CHANNELS_PER_PACKET;
|
||||||
|
|
||||||
|
if (currentPacket == (packetCount - 1))
|
||||||
|
{
|
||||||
|
// last packet, set the push flag
|
||||||
|
/*0*/_ddpData[0] = DDP::flags1::VER1 | DDP::flags1::PUSH;
|
||||||
|
|
||||||
|
if (channelCount % DDP::CHANNELS_PER_PACKET != 0)
|
||||||
|
{
|
||||||
|
packetSize = channelCount % DDP::CHANNELS_PER_PACKET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*1*/_ddpData[1] = static_cast<char>(_packageSequenceNumber++ & 0x0F);
|
||||||
|
/*4*/qToBigEndian<quint32>(static_cast<quint32>(channel), _ddpData.data() + 4);
|
||||||
|
/*8*/qToBigEndian<quint16>(static_cast<quint16>(packetSize), _ddpData.data() + 8);
|
||||||
|
|
||||||
|
_ddpData.replace(DDP::HEADER_LEN, channel, reinterpret_cast<const char*>(ledValues.data())+channel, packetSize);
|
||||||
|
_ddpData.resize(DDP::HEADER_LEN + packetSize);
|
||||||
|
|
||||||
|
rc = writeBytes(_ddpData);
|
||||||
|
|
||||||
|
if (rc != 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
channel += packetSize;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
62
libsrc/leddevice/dev_net/LedDeviceUdpDdp.h
Normal file
62
libsrc/leddevice/dev_net/LedDeviceUdpDdp.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#ifndef LEDEVICEUDPDDP_H
|
||||||
|
#define LEDEVICEUDPDDP_H
|
||||||
|
|
||||||
|
// hyperion includes
|
||||||
|
#include "ProviderUdp.h"
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Implementation of the LedDevice interface for sending LED colors via UDP and the Distributed Display Protocol (DDP)
|
||||||
|
/// http://www.3waylabs.com/ddp/#Data%20Types
|
||||||
|
///
|
||||||
|
class LedDeviceUdpDdp : public virtual ProviderUdp
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Constructs a LED-device fed via DDP
|
||||||
|
///
|
||||||
|
/// @param deviceConfig Device's configuration as JSON-Object
|
||||||
|
///
|
||||||
|
explicit LedDeviceUdpDdp(const QJsonObject &deviceConfig);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Constructs the LED-device
|
||||||
|
///
|
||||||
|
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||||
|
/// @return LedDevice constructed
|
||||||
|
///
|
||||||
|
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Initialise the device's configuration
|
||||||
|
///
|
||||||
|
/// @param[in] deviceConfig the JSON device configuration
|
||||||
|
/// @return True, if success
|
||||||
|
///
|
||||||
|
bool init(const QJsonObject &deviceConfig) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Opens the output device.
|
||||||
|
///
|
||||||
|
/// @return Zero on success (i.e. device is ready), else negative
|
||||||
|
///
|
||||||
|
int open() override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Writes the RGB-Color values to the LEDs.
|
||||||
|
///
|
||||||
|
/// @param[in] ledValues The RGB-color per LED
|
||||||
|
/// @return Zero on success, else negative
|
||||||
|
///
|
||||||
|
int write(const std::vector<ColorRgb> & ledValues) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QByteArray _ddpData;
|
||||||
|
|
||||||
|
int _packageSequenceNumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LEDEVICEUDPDDP_H
|
@ -8,6 +8,13 @@
|
|||||||
|
|
||||||
// hyperion local includes
|
// hyperion local includes
|
||||||
#include "LedDeviceUdpE131.h"
|
#include "LedDeviceUdpE131.h"
|
||||||
|
#include <utils/NetUtils.h>
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char CONFIG_HOST[] = "host";
|
||||||
|
const char CONFIG_PORT[] = "port";
|
||||||
|
|
||||||
const ushort E131_DEFAULT_PORT = 5568;
|
const ushort E131_DEFAULT_PORT = 5568;
|
||||||
|
|
||||||
@ -23,6 +30,7 @@ const uint32_t VECTOR_E131_DATA_PACKET = 0x00000002;
|
|||||||
//#define E131_NETWORK_DATA_LOSS_TIMEOUT 2500 // milli econds
|
//#define E131_NETWORK_DATA_LOSS_TIMEOUT 2500 // milli econds
|
||||||
//#define E131_DISCOVERY_UNIVERSE 64214
|
//#define E131_DISCOVERY_UNIVERSE 64214
|
||||||
const int DMX_MAX = 512; // 512 usable slots
|
const int DMX_MAX = 512; // 512 usable slots
|
||||||
|
}
|
||||||
|
|
||||||
LedDeviceUdpE131::LedDeviceUdpE131(const QJsonObject &deviceConfig)
|
LedDeviceUdpE131::LedDeviceUdpE131(const QJsonObject &deviceConfig)
|
||||||
: ProviderUdp(deviceConfig)
|
: ProviderUdp(deviceConfig)
|
||||||
@ -36,13 +44,14 @@ LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
|
|||||||
|
|
||||||
bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
|
bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK {false};
|
||||||
|
|
||||||
_port = E131_DEFAULT_PORT;
|
|
||||||
|
|
||||||
// Initialise sub-class
|
// Initialise sub-class
|
||||||
if ( ProviderUdp::init(deviceConfig) )
|
if ( ProviderUdp::init(deviceConfig) )
|
||||||
{
|
{
|
||||||
|
_hostName = _devConfig[ CONFIG_HOST ].toString();
|
||||||
|
_port = deviceConfig[CONFIG_PORT].toInt(E131_DEFAULT_PORT);
|
||||||
|
|
||||||
_e131_universe = deviceConfig["universe"].toInt(1);
|
_e131_universe = deviceConfig["universe"].toInt(1);
|
||||||
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
|
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
|
||||||
QString _json_cid = deviceConfig["cid"].toString("");
|
QString _json_cid = deviceConfig["cid"].toString("");
|
||||||
@ -70,6 +79,23 @@ bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
|
|||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LedDeviceUdpE131::open()
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
_isDeviceReady = false;
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||||
|
{
|
||||||
|
if (ProviderUdp::open() == 0)
|
||||||
|
{
|
||||||
|
// Everything is OK, device is ready
|
||||||
|
_isDeviceReady = true;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
// populates the headers
|
// populates the headers
|
||||||
void LedDeviceUdpE131::prepare(unsigned this_universe, unsigned this_dmxChannelCount)
|
void LedDeviceUdpE131::prepare(unsigned this_universe, unsigned this_dmxChannelCount)
|
||||||
{
|
{
|
||||||
|
@ -114,6 +114,13 @@ private:
|
|||||||
///
|
///
|
||||||
bool init(const QJsonObject &deviceConfig) override;
|
bool init(const QJsonObject &deviceConfig) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Opens the output device.
|
||||||
|
///
|
||||||
|
/// @return Zero on success (i.e. device is ready), else negative
|
||||||
|
///
|
||||||
|
int open() override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Writes the RGB-Color values to the LEDs.
|
/// @brief Writes the RGB-Color values to the LEDs.
|
||||||
///
|
///
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
#include "LedDeviceUdpH801.h"
|
#include "LedDeviceUdpH801.h"
|
||||||
|
#include <utils/NetUtils.h>
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
const char CONFIG_HOST[] = "host";
|
||||||
|
const char CONFIG_PORT[] = "port";
|
||||||
|
|
||||||
const ushort H801_DEFAULT_PORT = 30977;
|
const ushort H801_DEFAULT_PORT = 30977;
|
||||||
const char H801_DEFAULT_HOST[] = "255.255.255.255";
|
const char H801_DEFAULT_HOST[] = "255.255.255.255";
|
||||||
|
|
||||||
@ -20,16 +24,17 @@ LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
|
|||||||
|
|
||||||
bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
|
bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK {false};
|
||||||
|
|
||||||
/* The H801 port is fixed */
|
/* The H801 port is fixed */
|
||||||
_latchTime_ms = 10;
|
_latchTime_ms = 10;
|
||||||
_port = H801_DEFAULT_PORT;
|
|
||||||
_defaultHost = H801_DEFAULT_HOST;
|
|
||||||
|
|
||||||
// Initialise sub-class
|
// Initialise sub-class
|
||||||
if ( ProviderUdp::init(deviceConfig) )
|
if ( ProviderUdp::init(deviceConfig) )
|
||||||
{
|
{
|
||||||
|
_hostName = _devConfig[ CONFIG_HOST ].toString(H801_DEFAULT_HOST);
|
||||||
|
_port = deviceConfig[CONFIG_PORT].toInt(H801_DEFAULT_PORT);
|
||||||
|
|
||||||
_ids.clear();
|
_ids.clear();
|
||||||
QJsonArray lArray = deviceConfig["lightIds"].toArray();
|
QJsonArray lArray = deviceConfig["lightIds"].toArray();
|
||||||
for (int i = 0; i < lArray.size(); i++)
|
for (int i = 0; i < lArray.size(); i++)
|
||||||
@ -47,14 +52,28 @@ bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
|
|||||||
_message[_prefix_size + _colors + i * _id_size + 1] = (_ids[i] >> 0x08) & 0xFF;
|
_message[_prefix_size + _colors + i * _id_size + 1] = (_ids[i] >> 0x08) & 0xFF;
|
||||||
_message[_prefix_size + _colors + i * _id_size + 2] = (_ids[i] >> 0x10) & 0xFF;
|
_message[_prefix_size + _colors + i * _id_size + 2] = (_ids[i] >> 0x10) & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug(_log, "H801 using %s:%d", _address.toString().toStdString().c_str(), _port);
|
|
||||||
|
|
||||||
isInitOK = true;
|
isInitOK = true;
|
||||||
}
|
}
|
||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LedDeviceUdpH801::open()
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
_isDeviceReady = false;
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||||
|
{
|
||||||
|
if (ProviderUdp::open() == 0)
|
||||||
|
{
|
||||||
|
// Everything is OK, device is ready
|
||||||
|
_isDeviceReady = true;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int LedDeviceUdpH801::write(const std::vector<ColorRgb> &ledValues)
|
int LedDeviceUdpH801::write(const std::vector<ColorRgb> &ledValues)
|
||||||
{
|
{
|
||||||
ColorRgb color = ledValues[0];
|
ColorRgb color = ledValues[0];
|
||||||
|
@ -37,6 +37,13 @@ private:
|
|||||||
///
|
///
|
||||||
bool init(const QJsonObject &deviceConfig) override;
|
bool init(const QJsonObject &deviceConfig) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Opens the output device.
|
||||||
|
///
|
||||||
|
/// @return Zero on success (i.e. device is ready), else negative
|
||||||
|
///
|
||||||
|
int open() override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Writes the RGB-Color values to the LEDs.
|
/// @brief Writes the RGB-Color values to the LEDs.
|
||||||
///
|
///
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
#include "LedDeviceUdpRaw.h"
|
#include "LedDeviceUdpRaw.h"
|
||||||
|
|
||||||
|
#include <utils/NetUtils.h>
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const bool verbose = false;
|
const bool verbose = false;
|
||||||
|
|
||||||
|
const char CONFIG_HOST[] = "host";
|
||||||
|
const char CONFIG_PORT[] = "port";
|
||||||
const ushort RAW_DEFAULT_PORT=5568;
|
const ushort RAW_DEFAULT_PORT=5568;
|
||||||
const int UDP_MAX_LED_NUM = 490;
|
const int UDP_MAX_LED_NUM = 490;
|
||||||
|
|
||||||
@ -22,33 +26,46 @@ LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
|
|||||||
|
|
||||||
bool LedDeviceUdpRaw::init(const QJsonObject &deviceConfig)
|
bool LedDeviceUdpRaw::init(const QJsonObject &deviceConfig)
|
||||||
{
|
{
|
||||||
_port = RAW_DEFAULT_PORT;
|
bool isInitOK {false};
|
||||||
|
|
||||||
bool isInitOK = false;
|
if ( ProviderUdp::init(deviceConfig) )
|
||||||
if ( LedDevice::init(deviceConfig) )
|
|
||||||
{
|
{
|
||||||
// Initialise LedDevice configuration and execution environment
|
if (this->getLedCount() > UDP_MAX_LED_NUM)
|
||||||
int configuredLedCount = this->getLedCount();
|
|
||||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
|
||||||
Debug(_log, "LedCount : %d", configuredLedCount);
|
|
||||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
|
||||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
|
||||||
|
|
||||||
if (configuredLedCount > UDP_MAX_LED_NUM)
|
|
||||||
{
|
{
|
||||||
QString errorReason = QString("Device type %1 can only be run with maximum %2 LEDs!").arg(this->getActiveDeviceType()).arg(UDP_MAX_LED_NUM);
|
QString errorReason = QString("Device type %1 can only be run with maximum %2 LEDs for streaming protocol = UDP-RAW!").arg(this->getActiveDeviceType()).arg(UDP_MAX_LED_NUM);
|
||||||
this->setInError ( errorReason );
|
this->setInError ( errorReason );
|
||||||
isInitOK = false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Initialise sub-class
|
_hostName = deviceConfig[ CONFIG_HOST ].toString();
|
||||||
isInitOK = ProviderUdp::init(deviceConfig);
|
_port = deviceConfig[CONFIG_PORT].toInt(RAW_DEFAULT_PORT);
|
||||||
|
|
||||||
|
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostName) );
|
||||||
|
Debug(_log, "Port : %d", _port );
|
||||||
|
|
||||||
|
isInitOK = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LedDeviceUdpRaw::open()
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
_isDeviceReady = false;
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||||
|
{
|
||||||
|
if (ProviderUdp::open() == 0)
|
||||||
|
{
|
||||||
|
// Everything is OK, device is ready
|
||||||
|
_isDeviceReady = true;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
|
int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
|
||||||
{
|
{
|
||||||
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
|
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
|
||||||
@ -59,8 +76,11 @@ int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
|
|||||||
QJsonObject LedDeviceUdpRaw::getProperties(const QJsonObject& params)
|
QJsonObject LedDeviceUdpRaw::getProperties(const QJsonObject& params)
|
||||||
{
|
{
|
||||||
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||||
|
|
||||||
QJsonObject properties;
|
QJsonObject properties;
|
||||||
|
|
||||||
|
Info(_log, "Get properties for %s", QSTRING_CSTR(_activeDeviceType));
|
||||||
|
|
||||||
QJsonObject propertiesDetails;
|
QJsonObject propertiesDetails;
|
||||||
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
///
|
///
|
||||||
/// Implementation of the LedDevice interface for sending LED colors via UDP
|
/// Implementation of the LedDevice interface for sending LED colors via UDP
|
||||||
///
|
///
|
||||||
class LedDeviceUdpRaw : public ProviderUdp
|
class LedDeviceUdpRaw : public virtual ProviderUdp
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -44,6 +44,13 @@ protected:
|
|||||||
///
|
///
|
||||||
bool init(const QJsonObject &deviceConfig) override;
|
bool init(const QJsonObject &deviceConfig) override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Opens the output device.
|
||||||
|
///
|
||||||
|
/// @return Zero on success (i.e. device is ready), else negative
|
||||||
|
///
|
||||||
|
int open() override;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Writes the RGB-Color values to the LEDs.
|
/// @brief Writes the RGB-Color values to the LEDs.
|
||||||
///
|
///
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
// Local-Hyperion includes
|
// Local-Hyperion includes
|
||||||
#include "LedDeviceWled.h"
|
#include "LedDeviceWled.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
#include <utils/QStringUtils.h>
|
#include <utils/QStringUtils.h>
|
||||||
#include <utils/WaitTime.h>
|
#include <utils/WaitTime.h>
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
#include <chrono>
|
// mDNS discover
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
#include <mdns/MdnsBrowser.h>
|
||||||
|
#include <mdns/MdnsServiceRegister.h>
|
||||||
|
#endif
|
||||||
|
#include <utils/NetUtils.h>
|
||||||
|
#include <utils/version.hpp>
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
namespace {
|
namespace {
|
||||||
@ -13,16 +20,22 @@ namespace {
|
|||||||
const bool verbose = false;
|
const bool verbose = false;
|
||||||
|
|
||||||
// Configuration settings
|
// Configuration settings
|
||||||
const char CONFIG_ADDRESS[] = "host";
|
const char CONFIG_HOST[] = "host";
|
||||||
|
const char CONFIG_STREAM_PROTOCOL[] = "streamProtocol";
|
||||||
const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
|
const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
|
||||||
const char CONFIG_BRIGHTNESS[] = "brightness";
|
const char CONFIG_BRIGHTNESS[] = "brightness";
|
||||||
const char CONFIG_BRIGHTNESS_OVERWRITE[] = "overwriteBrightness";
|
const char CONFIG_BRIGHTNESS_OVERWRITE[] = "overwriteBrightness";
|
||||||
const char CONFIG_SYNC_OVERWRITE[] = "overwriteSync";
|
const char CONFIG_SYNC_OVERWRITE[] = "overwriteSync";
|
||||||
|
|
||||||
// UDP elements
|
const char DEFAULT_STREAM_PROTOCOL[] = "DDP";
|
||||||
const quint16 STREAM_DEFAULT_PORT = 19446;
|
|
||||||
|
// UDP-RAW
|
||||||
|
const int UDP_STREAM_DEFAULT_PORT = 19446;
|
||||||
const int UDP_MAX_LED_NUM = 490;
|
const int UDP_MAX_LED_NUM = 490;
|
||||||
|
|
||||||
|
// DDP
|
||||||
|
const char WLED_VERSION_DDP[] = "0.11.0";
|
||||||
|
|
||||||
// WLED JSON-API elements
|
// WLED JSON-API elements
|
||||||
const int API_DEFAULT_PORT = -1; //Use default port per communication scheme
|
const int API_DEFAULT_PORT = -1; //Use default port per communication scheme
|
||||||
|
|
||||||
@ -46,7 +59,7 @@ constexpr std::chrono::milliseconds DEFAULT_IDENTIFY_TIME{ 2000 };
|
|||||||
} //End of constants
|
} //End of constants
|
||||||
|
|
||||||
LedDeviceWled::LedDeviceWled(const QJsonObject &deviceConfig)
|
LedDeviceWled::LedDeviceWled(const QJsonObject &deviceConfig)
|
||||||
: ProviderUdp(deviceConfig)
|
: ProviderUdp(deviceConfig), LedDeviceUdpDdp(deviceConfig), LedDeviceUdpRaw(deviceConfig)
|
||||||
,_restApi(nullptr)
|
,_restApi(nullptr)
|
||||||
,_apiPort(API_DEFAULT_PORT)
|
,_apiPort(API_DEFAULT_PORT)
|
||||||
,_isBrightnessOverwrite(DEFAULT_IS_BRIGHTNESS_OVERWRITE)
|
,_isBrightnessOverwrite(DEFAULT_IS_BRIGHTNESS_OVERWRITE)
|
||||||
@ -54,7 +67,12 @@ LedDeviceWled::LedDeviceWled(const QJsonObject &deviceConfig)
|
|||||||
,_isSyncOverwrite(DEFAULT_IS_SYNC_OVERWRITE)
|
,_isSyncOverwrite(DEFAULT_IS_SYNC_OVERWRITE)
|
||||||
,_originalStateUdpnSend(false)
|
,_originalStateUdpnSend(false)
|
||||||
,_originalStateUdpnRecv(true)
|
,_originalStateUdpnRecv(true)
|
||||||
|
,_isStreamDDP(true)
|
||||||
{
|
{
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||||
|
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
LedDeviceWled::~LedDeviceWled()
|
LedDeviceWled::~LedDeviceWled()
|
||||||
@ -70,25 +88,30 @@ LedDevice* LedDeviceWled::construct(const QJsonObject &deviceConfig)
|
|||||||
|
|
||||||
bool LedDeviceWled::init(const QJsonObject &deviceConfig)
|
bool LedDeviceWled::init(const QJsonObject &deviceConfig)
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK {false};
|
||||||
|
|
||||||
// Initialise LedDevice sub-class, ProviderUdp::init will be executed later, if connectivity is defined
|
QString streamProtocol = _devConfig[CONFIG_STREAM_PROTOCOL].toString(DEFAULT_STREAM_PROTOCOL);
|
||||||
if ( LedDevice::init(deviceConfig) )
|
|
||||||
|
if (streamProtocol != DEFAULT_STREAM_PROTOCOL)
|
||||||
{
|
{
|
||||||
// Initialise LedDevice configuration and execution environment
|
_isStreamDDP = false;
|
||||||
int configuredLedCount = this->getLedCount();
|
}
|
||||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
Debug(_log, "Stream protocol : %s", QSTRING_CSTR(streamProtocol));
|
||||||
Debug(_log, "LedCount : %d", configuredLedCount);
|
Debug(_log, "Stream DDP : %d", _isStreamDDP);
|
||||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
|
||||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
|
||||||
|
|
||||||
if (configuredLedCount > UDP_MAX_LED_NUM)
|
if (_isStreamDDP)
|
||||||
{
|
{
|
||||||
QString errorReason = QString("Device type %1 can only be run with maximum %2 LEDs!").arg(this->getActiveDeviceType()).arg(UDP_MAX_LED_NUM);
|
LedDeviceUdpDdp::init(deviceConfig);
|
||||||
this->setInError ( errorReason );
|
}
|
||||||
return false;
|
else
|
||||||
}
|
{
|
||||||
|
_devConfig["port"] = UDP_STREAM_DEFAULT_PORT;
|
||||||
|
LedDeviceUdpRaw::init(_devConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_isDeviceInError)
|
||||||
|
{
|
||||||
|
_apiPort = API_DEFAULT_PORT;
|
||||||
_isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(DEFAULT_IS_RESTORE_STATE);
|
_isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(DEFAULT_IS_RESTORE_STATE);
|
||||||
_isSyncOverwrite = _devConfig[CONFIG_SYNC_OVERWRITE].toBool(DEFAULT_IS_SYNC_OVERWRITE);
|
_isSyncOverwrite = _devConfig[CONFIG_SYNC_OVERWRITE].toBool(DEFAULT_IS_SYNC_OVERWRITE);
|
||||||
_isBrightnessOverwrite = _devConfig[CONFIG_BRIGHTNESS_OVERWRITE].toBool(DEFAULT_IS_BRIGHTNESS_OVERWRITE);
|
_isBrightnessOverwrite = _devConfig[CONFIG_BRIGHTNESS_OVERWRITE].toBool(DEFAULT_IS_BRIGHTNESS_OVERWRITE);
|
||||||
@ -99,57 +122,78 @@ bool LedDeviceWled::init(const QJsonObject &deviceConfig)
|
|||||||
Debug(_log, "Overwrite Brightn.: %d", _isBrightnessOverwrite);
|
Debug(_log, "Overwrite Brightn.: %d", _isBrightnessOverwrite);
|
||||||
Debug(_log, "Set Brightness to : %d", _brightness);
|
Debug(_log, "Set Brightness to : %d", _brightness);
|
||||||
|
|
||||||
//Set hostname as per configuration
|
isInitOK = true;
|
||||||
QString hostName = deviceConfig[ CONFIG_ADDRESS ].toString();
|
|
||||||
|
|
||||||
//If host not configured the init fails
|
|
||||||
if ( hostName.isEmpty() )
|
|
||||||
{
|
|
||||||
this->setInError("No target hostname nor IP defined");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QStringList addressparts = QStringUtils::split(hostName,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
|
||||||
_hostname = addressparts[0];
|
|
||||||
if ( addressparts.size() > 1 )
|
|
||||||
{
|
|
||||||
_apiPort = addressparts[1].toInt();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_apiPort = API_DEFAULT_PORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( initRestAPI( _hostname, _apiPort ) )
|
|
||||||
{
|
|
||||||
// Update configuration with hostname without port
|
|
||||||
_devConfig["host"] = _hostname;
|
|
||||||
_devConfig["port"] = STREAM_DEFAULT_PORT;
|
|
||||||
|
|
||||||
isInitOK = ProviderUdp::init(_devConfig);
|
|
||||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
|
|
||||||
Debug(_log, "Port : %d", _port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LedDeviceWled::initRestAPI(const QString &hostname, int port)
|
bool LedDeviceWled::openRestAPI()
|
||||||
{
|
{
|
||||||
bool isInitOK = false;
|
bool isInitOK {true};
|
||||||
|
|
||||||
if ( _restApi == nullptr )
|
if ( _restApi == nullptr )
|
||||||
{
|
{
|
||||||
_restApi = new ProviderRestApi(hostname, port);
|
_restApi = new ProviderRestApi(_address.toString(), _apiPort);
|
||||||
_restApi->setBasePath( API_BASE_PATH );
|
_restApi->setLogger(_log);
|
||||||
|
|
||||||
isInitOK = true;
|
_restApi->setBasePath( API_BASE_PATH );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_restApi->setHost(_address.toString());
|
||||||
|
_restApi->setPort(_apiPort);
|
||||||
|
}
|
||||||
|
|
||||||
return isInitOK;
|
return isInitOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int LedDeviceWled::open()
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
_isDeviceReady = false;
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||||
|
{
|
||||||
|
if ( openRestAPI() )
|
||||||
|
{
|
||||||
|
if (_isStreamDDP)
|
||||||
|
{
|
||||||
|
if (LedDeviceUdpDdp::open() == 0)
|
||||||
|
{
|
||||||
|
// Everything is OK, device is ready
|
||||||
|
_isDeviceReady = true;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (LedDeviceUdpRaw::open() == 0)
|
||||||
|
{
|
||||||
|
// Everything is OK, device is ready
|
||||||
|
_isDeviceReady = true;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDeviceWled::close()
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
if (_isStreamDDP)
|
||||||
|
{
|
||||||
|
retval = LedDeviceUdpDdp::close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval = LedDeviceUdpRaw::close();
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
QString LedDeviceWled::getOnOffRequest(bool isOn) const
|
QString LedDeviceWled::getOnOffRequest(bool isOn) const
|
||||||
{
|
{
|
||||||
QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
|
QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
|
||||||
@ -316,6 +360,16 @@ QJsonObject LedDeviceWled::discover(const QJsonObject& /*params*/)
|
|||||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
|
devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
|
||||||
|
|
||||||
QJsonArray deviceList;
|
QJsonArray deviceList;
|
||||||
|
|
||||||
|
#ifdef ENABLE_MDNS
|
||||||
|
QString discoveryMethod("mDNS");
|
||||||
|
deviceList = MdnsBrowser::getInstance().getServicesDiscoveredJson(
|
||||||
|
MdnsServiceRegister::getServiceType(_activeDeviceType),
|
||||||
|
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
|
||||||
|
DEFAULT_DISCOVER_TIMEOUT
|
||||||
|
);
|
||||||
|
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
||||||
|
#endif
|
||||||
devicesDiscovered.insert("devices", deviceList);
|
devicesDiscovered.insert("devices", deviceList);
|
||||||
DebugIf(verbose, _log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
DebugIf(verbose, _log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||||
|
|
||||||
@ -327,41 +381,45 @@ QJsonObject LedDeviceWled::getProperties(const QJsonObject& params)
|
|||||||
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||||
QJsonObject properties;
|
QJsonObject properties;
|
||||||
|
|
||||||
QString hostName = params["host"].toString("");
|
_hostName = params[CONFIG_HOST].toString("");
|
||||||
|
_apiPort = API_DEFAULT_PORT;
|
||||||
|
|
||||||
if ( !hostName.isEmpty() )
|
Info(_log, "Get properties for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||||
{
|
{
|
||||||
QString filter = params["filter"].toString("");
|
if ( openRestAPI() )
|
||||||
|
|
||||||
// Resolve hostname and port (or use default API port)
|
|
||||||
QStringList addressparts = QStringUtils::split(hostName,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
|
||||||
QString apiHost = addressparts[0];
|
|
||||||
int apiPort;
|
|
||||||
|
|
||||||
if ( addressparts.size() > 1)
|
|
||||||
{
|
{
|
||||||
apiPort = addressparts[1].toInt();
|
QString filter = params["filter"].toString("");
|
||||||
}
|
_restApi->setPath(filter);
|
||||||
else
|
|
||||||
{
|
|
||||||
apiPort = API_DEFAULT_PORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
initRestAPI(apiHost, apiPort);
|
httpResponse response = _restApi->get();
|
||||||
_restApi->setPath(filter);
|
if ( response.error() )
|
||||||
|
{
|
||||||
|
Warning (_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||||
|
}
|
||||||
|
|
||||||
httpResponse response = _restApi->get();
|
QJsonObject propertiesDetails = response.getBody().object();
|
||||||
if ( response.error() )
|
|
||||||
{
|
|
||||||
Warning (_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject propertiesDetails = response.getBody().object();
|
semver::version currentVersion {""};
|
||||||
if (!propertiesDetails.isEmpty())
|
if (currentVersion.setVersion(propertiesDetails.value("ver").toString().toStdString()))
|
||||||
{
|
{
|
||||||
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
semver::version ddpVersion{WLED_VERSION_DDP};
|
||||||
|
if (currentVersion < ddpVersion)
|
||||||
|
{
|
||||||
|
Warning(_log, "DDP streaming not supported by your WLED device version [%s], minimum version expected [%s]. Fall back to UDP-Streaming (%d LEDs max)", currentVersion.getVersion().c_str(), ddpVersion.getVersion().c_str(), UDP_MAX_LED_NUM);
|
||||||
|
if (!propertiesDetails.isEmpty())
|
||||||
|
{
|
||||||
|
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info(_log, "DDP streaming is supported by your WLED device version [%s]. No limitation in number of LEDs.", currentVersion.getVersion().c_str(), ddpVersion.getVersion().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
properties.insert("properties", propertiesDetails);
|
||||||
}
|
}
|
||||||
properties.insert("properties", propertiesDetails);
|
|
||||||
|
|
||||||
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||||
}
|
}
|
||||||
@ -372,41 +430,40 @@ void LedDeviceWled::identify(const QJsonObject& params)
|
|||||||
{
|
{
|
||||||
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
QString hostName = params["host"].toString("");
|
_hostName = params[CONFIG_HOST].toString("");
|
||||||
|
_apiPort = API_DEFAULT_PORT;
|
||||||
|
|
||||||
if ( !hostName.isEmpty() )
|
Info(_log, "Identify %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||||
|
|
||||||
|
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||||
{
|
{
|
||||||
// Resolve hostname and port (or use default API port)
|
if ( openRestAPI() )
|
||||||
QStringList addressparts = QStringUtils::split(hostName,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
|
||||||
QString apiHost = addressparts[0];
|
|
||||||
int apiPort;
|
|
||||||
|
|
||||||
if ( addressparts.size() > 1)
|
|
||||||
{
|
{
|
||||||
apiPort = addressparts[1].toInt();
|
_isRestoreOrigState = true;
|
||||||
|
storeState();
|
||||||
|
|
||||||
|
QString request = getOnOffRequest(true) + "," + getLorRequest(1) + "," + getEffectRequest(25);
|
||||||
|
sendStateUpdateRequest(request);
|
||||||
|
|
||||||
|
wait(DEFAULT_IDENTIFY_TIME);
|
||||||
|
|
||||||
|
restoreState();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
apiPort = API_DEFAULT_PORT;
|
|
||||||
}
|
|
||||||
|
|
||||||
initRestAPI(apiHost, apiPort);
|
|
||||||
|
|
||||||
_isRestoreOrigState = true;
|
|
||||||
storeState();
|
|
||||||
|
|
||||||
QString request = getOnOffRequest(true) + "," + getLorRequest(1) + "," + getEffectRequest(25);
|
|
||||||
sendStateUpdateRequest(request);
|
|
||||||
|
|
||||||
wait(DEFAULT_IDENTIFY_TIME);
|
|
||||||
|
|
||||||
restoreState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int LedDeviceWled::write(const std::vector<ColorRgb> &ledValues)
|
int LedDeviceWled::write(const std::vector<ColorRgb> &ledValues)
|
||||||
{
|
{
|
||||||
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
|
int rc {0};
|
||||||
|
|
||||||
return writeBytes( _ledRGBCount, dataPtr);
|
if (_isStreamDDP)
|
||||||
|
{
|
||||||
|
rc = LedDeviceUdpDdp::write(ledValues);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = LedDeviceUdpRaw::write(ledValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user