mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
update
This commit is contained in:
parent
0e3ddb7eca
commit
d6b2cfaf9d
@ -276,6 +276,9 @@ if (ENABLE_TESTS)
|
|||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
# Add resources directory
|
||||||
|
add_subdirectory(resources)
|
||||||
|
|
||||||
# Add the doxygen generation directory
|
# Add the doxygen generation directory
|
||||||
add_subdirectory(doc)
|
add_subdirectory(doc)
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,9 +1,10 @@
|
|||||||
|
|
||||||
execute_process( COMMAND git log -1 --format=%cn-%t/%h-%ct WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE BUILD_ID ERROR_QUIET )
|
execute_process( COMMAND git log -1 --format=%cn-%t/%h-%ct WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE BUILD_ID ERROR_QUIET )
|
||||||
execute_process( COMMAND sh -c "git branch | grep '^*' | sed 's;^*;;g' " WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE VERSION_ID ERROR_QUIET )
|
execute_process( COMMAND sh -c "git branch | grep '^*' | sed 's;^*;;g' " WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE VERSION_ID ERROR_QUIET )
|
||||||
|
execute_process( COMMAND sh -c "git remote --verbose | grep origin | grep fetch | cut -f2 | cut -d' ' -f1" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_REMOTE_PATH ERROR_QUIET )
|
||||||
|
|
||||||
STRING ( STRIP "${BUILD_ID}" BUILD_ID )
|
STRING ( STRIP "${BUILD_ID}" BUILD_ID )
|
||||||
STRING ( STRIP "${VERSION_ID}" VERSION_ID )
|
STRING ( STRIP "${VERSION_ID}" VERSION_ID )
|
||||||
SET ( HYPERION_BUILD_ID "${VERSION_ID} (${BUILD_ID})" )
|
STRING ( STRIP "${GIT_REMOTE_PATH}" GIT_REMOTE_PATH )
|
||||||
|
SET ( HYPERION_BUILD_ID "${VERSION_ID} (${BUILD_ID}) Git Remote: ${GIT_REMOTE_PATH}" )
|
||||||
message ( STATUS "Current Version: ${HYPERION_BUILD_ID}" )
|
message ( STATUS "Current Version: ${HYPERION_BUILD_ID}" )
|
||||||
|
|
||||||
|
5
cmake/osxbundle/launch.sh
Normal file
5
cmake/osxbundle/launch.sh
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
# Path to hyperiond!?
|
||||||
|
cd ../Resources/bin
|
||||||
|
exec ./hyperiond "$@"
|
@ -1,38 +1,63 @@
|
|||||||
# cmake file for generating distribution packages
|
# cmake file for generating distribution packages
|
||||||
|
|
||||||
IF (APPLE)
|
IF (APPLE)
|
||||||
SET ( CPACK_GENERATOR "TGZ" "Bundle") # "RPM"
|
SET ( CPACK_GENERATOR "TGZ" "Bundle")
|
||||||
ELSE()
|
ELSEIF (UNIX)
|
||||||
SET ( CPACK_GENERATOR "DEB" "TGZ" "STGZ") # "RPM"
|
SET ( CPACK_GENERATOR "DEB" "TGZ" "STGZ") # "RPM"
|
||||||
|
ELSEIF (WIN32)
|
||||||
|
SET ( CPACK_GENERATOR "ZIP" "NSIS")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
SET ( CPACK_PACKAGE_NAME "hyperion" )
|
# Apply to all packages, some of these can be overwritten with generator specific content
|
||||||
|
# https://cmake.org/cmake/help/v3.0/module/CPack.html
|
||||||
|
|
||||||
|
SET ( CPACK_PACKAGE_NAME "Hyperion" )
|
||||||
SET ( CPACK_PACKAGE_DESCRIPTION_SUMMARY "Hyperion is an open source ambient light implementation" )
|
SET ( CPACK_PACKAGE_DESCRIPTION_SUMMARY "Hyperion is an open source ambient light implementation" )
|
||||||
SET ( CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md" )
|
SET ( CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md" )
|
||||||
SET ( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" )
|
SET ( CPACK_PACKAGE_FILE_NAME "Hyperion-${HYPERION_VERSION_MAJOR}.${HYPERION_VERSION_MINOR}.${HYPERION_VERSION_PATCH}")
|
||||||
|
SET ( CPACK_PACKAGE_CONTACT "packages@hyperion-project.org")
|
||||||
SET ( CPACK_DEBIAN_PACKAGE_MAINTAINER "Hyperion Team")
|
SET ( CPACK_PACKAGE_EXECUTABLES "hyperiond;Hyperion" )
|
||||||
SET ( CPACK_DEBIAN_PACKAGE_NAME "Hyperion" )
|
SET ( CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/icons/hyperion-icon-32px.png")
|
||||||
SET ( CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/cmake/debian/preinst;${CMAKE_CURRENT_SOURCE_DIR}/cmake/debian/postinst;${CMAKE_CURRENT_SOURCE_DIR}/cmake/debian/prerm" )
|
|
||||||
SET ( CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://www.hyperion-project.org" )
|
|
||||||
SET ( CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5core5a (>= 5.5.0), libqt5network5 (>= 5.5.0), libqt5gui5 (>= 5.5.0), libqt5serialport5 (>= 5.5.0), libqt5sql5 (>= 5.5.0), libavahi-core7 (>= 0.6.31), libavahi-compat-libdnssd1 (>= 0.6.31), libusb-1.0-0, libpython3.5, libc6" )
|
|
||||||
SET ( CPACK_DEBIAN_PACKAGE_SECTION "Miscellaneous" )
|
|
||||||
|
|
||||||
SET ( CPACK_RPM_PACKAGE_NAME "Hyperion" )
|
|
||||||
SET ( CPACK_RPM_PACKAGE_URL "https://github.com/hyperion-project/hyperion.ng" )
|
|
||||||
SET ( CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/rpm/postinst" )
|
|
||||||
|
|
||||||
SET ( CPACK_PACKAGE_FILE_NAME "Hyperion")
|
|
||||||
SET ( CPACK_PACKAGE_ICON ${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/Hyperion.icns )
|
|
||||||
SET ( CPACK_BUNDLE_NAME "Hyperion" )
|
|
||||||
SET ( CPACK_BUNDLE_ICON ${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/Hyperion.icns )
|
|
||||||
SET ( CPACK_BUNDLE_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/cmake/macos/Info.plist )
|
|
||||||
#SET ( CPACK_BUNDLE_STARTUP_COMMAND - path to a file that will be executed when the user opens the bundle. Could be a shell-script or a binary. )
|
|
||||||
|
|
||||||
SET ( CPACK_PACKAGE_VERSION_MAJOR "${HYPERION_VERSION_MAJOR}")
|
SET ( CPACK_PACKAGE_VERSION_MAJOR "${HYPERION_VERSION_MAJOR}")
|
||||||
SET ( CPACK_PACKAGE_VERSION_MINOR "${HYPERION_VERSION_MINOR}")
|
SET ( CPACK_PACKAGE_VERSION_MINOR "${HYPERION_VERSION_MINOR}")
|
||||||
SET ( CPACK_PACKAGE_VERSION_PATCH "${HYPERION_VERSION_PATCH}")
|
SET ( CPACK_PACKAGE_VERSION_PATCH "${HYPERION_VERSION_PATCH}")
|
||||||
|
SET ( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" )
|
||||||
|
SET ( CPACK_CREATE_DESKTOP_LINKS "hyperiond;Hyperion" )
|
||||||
|
|
||||||
|
|
||||||
|
# Specific CPack Package Generators
|
||||||
|
# https://cmake.org/Wiki/CMake:CPackPackageGenerators
|
||||||
|
# .deb files for dpkg
|
||||||
|
|
||||||
|
SET ( CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/cmake/debian/preinst;${CMAKE_CURRENT_SOURCE_DIR}/cmake/debian/postinst;${CMAKE_CURRENT_SOURCE_DIR}/cmake/debian/prerm" )
|
||||||
|
SET ( CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5core5a (>= 5.5.0), libqt5network5 (>= 5.5.0), libqt5gui5 (>= 5.5.0), libqt5serialport5 (>= 5.5.0), libqt5sql5 (>= 5.5.0), libqt5sql5-sqlite (>= 5.5.0), libavahi-core7 (>= 0.6.31), libavahi-compat-libdnssd1 (>= 0.6.31), libusb-1.0-0, libpython3.5, libc6" )
|
||||||
|
SET ( CPACK_DEBIAN_PACKAGE_SECTION "Miscellaneous" )
|
||||||
|
|
||||||
|
# .rpm for rpm
|
||||||
|
SET ( CPACK_RPM_PACKAGE_RELEASE 1)
|
||||||
|
SET ( CPACK_RPM_PACKAGE_LICENSE "unknown")
|
||||||
|
SET ( CPACK_RPM_PACKAGE_GROUP "unknown")
|
||||||
|
SET ( CPACK_RPM_PACKAGE_REQUIRES "libqt5core5a >= 5.5.0, libqt5network5 >= 5.5.0, libqt5gui5 >= 5.5.0, libqt5serialport5 >= 5.5.0, libqt5sql5 >= 5.5.0, libqt5sql5-sqlite >= 5.5.0, libavahi-core7 >= 0.6.31, libavahi-compat-libdnssd1 >= 0.6.31, libusb-1.0-0, libpython3.5, libc6")
|
||||||
|
SET ( CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/rpm/postinst" )
|
||||||
|
|
||||||
|
# OSX "Bundle" generator TODO Add more osx generators
|
||||||
|
# https://cmake.org/cmake/help/v3.10/module/CPackBundle.html
|
||||||
|
SET ( CPACK_BUNDLE_NAME "Hyperion" )
|
||||||
|
SET ( CPACK_BUNDLE_ICON ${CMAKE_CURRENT_SOURCE_DIR}/cmake/osxbundle/Hyperion.icns )
|
||||||
|
SET ( CPACK_BUNDLE_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/cmake/osxbundle/Info.plist )
|
||||||
|
SET ( CPACK_BUNDLE_STARTUP_COMMAND "${CMAKE_SOURCE_DIR}/cmake/osxbundle/launch.sh" )
|
||||||
|
|
||||||
|
# NSIS for windows, requires NSIS TODO finish
|
||||||
|
SET ( CPACK_NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}/cmake/nsis/installer.ico")
|
||||||
|
SET ( CPACK_NSIS_MUI_UNIICON "${CMAKE_CURRENT_SOURCE_DIR}/cmake/nsis/uninstaller.ico")
|
||||||
|
#SET ( CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/cmake/nsis/installer.bmp") #bmp required? If so, wrap in WIN32 check else: Use default icon instead
|
||||||
|
SET ( CPACK_NSIS_MODIFY_PATH ON)
|
||||||
|
SET ( CPACK_NSIS_DISPLAY_NAME "Hyperion Installer")
|
||||||
|
SET ( CPACK_NSIS_INSTALLED_ICON_NAME "Link to .exe")
|
||||||
|
SET ( CPACK_NSIS_HELP_LINK "https://www.hyperion-project.org")
|
||||||
|
SET ( CPACK_NSIS_URL_INFO_ABOUT "https://www.hyperion-project.org")
|
||||||
|
|
||||||
|
# define the install components
|
||||||
SET ( CPACK_COMPONENTS_ALL "${PLATFORM}" )
|
SET ( CPACK_COMPONENTS_ALL "${PLATFORM}" )
|
||||||
SET ( CPACK_ARCHIVE_COMPONENT_INSTALL ON )
|
SET ( CPACK_ARCHIVE_COMPONENT_INSTALL ON )
|
||||||
SET ( CPACK_DEB_COMPONENT_INSTALL ON )
|
SET ( CPACK_DEB_COMPONENT_INSTALL ON )
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#define _BSD_SOURCE // for usleep from unistd.h
|
#define _DEFAULT_SOURCE // for usleep from unistd.h
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -7,33 +7,10 @@
|
|||||||
#include <hyperion/Hyperion.h>
|
#include <hyperion/Hyperion.h>
|
||||||
|
|
||||||
// qt includess
|
// qt includess
|
||||||
#include <QTimer>
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
// createEffect helper
|
|
||||||
struct find_schema: std::unary_function<EffectSchema, bool>
|
|
||||||
{
|
|
||||||
QString pyFile;
|
|
||||||
find_schema(QString pyFile):pyFile(pyFile) { }
|
|
||||||
bool operator()(EffectSchema const& schema) const
|
|
||||||
{
|
|
||||||
return schema.pyFile == pyFile;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// deleteEffect helper
|
|
||||||
struct find_effect: std::unary_function<EffectDefinition, bool>
|
|
||||||
{
|
|
||||||
QString effectName;
|
|
||||||
find_effect(QString effectName) :effectName(effectName) { }
|
|
||||||
bool operator()(EffectDefinition const& effectDefinition) const
|
|
||||||
{
|
|
||||||
return effectDefinition.name == effectName;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class JsonCB;
|
class JsonCB;
|
||||||
|
|
||||||
class JsonAPI : public QObject
|
class JsonAPI : public QObject
|
||||||
@ -59,8 +36,11 @@ public:
|
|||||||
void handleMessage(const QString & message);
|
void handleMessage(const QString & message);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/// _timer_ledcolors requests ledcolor updates (if enabled)
|
///
|
||||||
void streamLedcolorsUpdate();
|
/// @brief is called whenever the current Hyperion instance pushes new led raw values (if enabled)
|
||||||
|
/// @param ledColors The current ledColors
|
||||||
|
///
|
||||||
|
void streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors);
|
||||||
|
|
||||||
/// push images whenever hyperion emits (if enabled)
|
/// push images whenever hyperion emits (if enabled)
|
||||||
void setImage(const Image<ColorRgb> & image);
|
void setImage(const Image<ColorRgb> & image);
|
||||||
@ -80,11 +60,9 @@ signals:
|
|||||||
void forwardJsonMessage(QJsonObject);
|
void forwardJsonMessage(QJsonObject);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// The JsonCB instance which handles data subscription/notifications
|
|
||||||
JsonCB* _jsonCB;
|
|
||||||
// true if further callbacks are forbidden (http)
|
// true if further callbacks are forbidden (http)
|
||||||
bool _noListener;
|
bool _noListener;
|
||||||
|
|
||||||
/// The peer address of the client
|
/// The peer address of the client
|
||||||
QString _peerAddress;
|
QString _peerAddress;
|
||||||
|
|
||||||
@ -94,8 +72,8 @@ private:
|
|||||||
/// Hyperion instance
|
/// Hyperion instance
|
||||||
Hyperion* _hyperion;
|
Hyperion* _hyperion;
|
||||||
|
|
||||||
/// timer for ledcolors streaming
|
// The JsonCB instance which handles data subscription/notifications
|
||||||
QTimer _timer_ledcolors;
|
JsonCB* _jsonCB;
|
||||||
|
|
||||||
// streaming buffers
|
// streaming buffers
|
||||||
QJsonObject _streaming_leds_reply;
|
QJsonObject _streaming_leds_reply;
|
||||||
@ -108,9 +86,15 @@ private:
|
|||||||
/// mutex to determine state of image streaming
|
/// mutex to determine state of image streaming
|
||||||
QMutex _image_stream_mutex;
|
QMutex _image_stream_mutex;
|
||||||
|
|
||||||
|
/// mutex to determine state of image streaming
|
||||||
|
QMutex _led_stream_mutex;
|
||||||
|
|
||||||
/// timeout for live video refresh
|
/// timeout for live video refresh
|
||||||
volatile qint64 _image_stream_timeout;
|
volatile qint64 _image_stream_timeout;
|
||||||
|
|
||||||
|
/// timeout for led color refresh
|
||||||
|
volatile qint64 _led_stream_timeout;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Handle an incoming JSON Color message
|
/// Handle an incoming JSON Color message
|
||||||
///
|
///
|
||||||
|
@ -17,30 +17,43 @@
|
|||||||
#include <effectengine/EffectSchema.h>
|
#include <effectengine/EffectSchema.h>
|
||||||
#include <utils/Logger.h>
|
#include <utils/Logger.h>
|
||||||
|
|
||||||
// pre-declarioation
|
// pre-declaration
|
||||||
class Effect;
|
class Effect;
|
||||||
|
class EffectFileHandler;
|
||||||
|
|
||||||
class EffectEngine : public QObject
|
class EffectEngine : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EffectEngine(Hyperion * hyperion, const QJsonObject & jsonEffectConfig);
|
EffectEngine(Hyperion * hyperion);
|
||||||
virtual ~EffectEngine();
|
virtual ~EffectEngine();
|
||||||
|
|
||||||
void readEffects();
|
const std::list<EffectDefinition> & getEffects() const { return _availableEffects; };
|
||||||
|
|
||||||
const std::list<EffectDefinition> & getEffects() const
|
|
||||||
{
|
|
||||||
return _availableEffects;
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::list<ActiveEffectDefinition> & getActiveEffects();
|
const std::list<ActiveEffectDefinition> & getActiveEffects();
|
||||||
|
|
||||||
const std::list<EffectSchema> & getEffectSchemas()
|
///
|
||||||
{
|
/// Get available schemas from EffectFileHandler
|
||||||
return _effectSchemas;
|
/// @return all schemas
|
||||||
};
|
///
|
||||||
|
const std::list<EffectSchema> & getEffectSchemas();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Save an effect with EffectFileHandler
|
||||||
|
/// @param obj The effect args
|
||||||
|
/// @param[out] resultMsg The feedback message
|
||||||
|
/// @return True on success else false
|
||||||
|
///
|
||||||
|
const bool saveEffect(const QJsonObject& obj, QString& resultMsg);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Delete an effect by name.
|
||||||
|
/// @param[in] effectName The effect name to delete
|
||||||
|
/// @param[out] resultMsg The message on error
|
||||||
|
/// @return True on success else false
|
||||||
|
///
|
||||||
|
const bool deleteEffect(const QString& effectName, QString& resultMsg);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get all init data of the running effects and stop them
|
/// @brief Get all init data of the running effects and stop them
|
||||||
@ -72,19 +85,18 @@ public slots:
|
|||||||
private slots:
|
private slots:
|
||||||
void effectFinished();
|
void effectFinished();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief is called whenever the EffectFileHandler emits updated effect list
|
||||||
|
///
|
||||||
|
void handleUpdatedEffectList();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool loadEffectDefinition(const QString & path, const QString & effectConfigFile, EffectDefinition &effectDefinition);
|
|
||||||
|
|
||||||
bool loadEffectSchema(const QString & path, const QString & effectSchemaFile, EffectSchema &effectSchema);
|
|
||||||
|
|
||||||
/// Run the specified effect on the given priority channel and optionally specify a timeout
|
/// Run the specified effect on the given priority channel and optionally specify a timeout
|
||||||
int runEffectScript(const QString &script, const QString &name, const QJsonObject & args, int priority, int timeout = -1, const QString & origin="System", unsigned smoothCfg=0);
|
int runEffectScript(const QString &script, const QString &name, const QJsonObject & args, int priority, int timeout = -1, const QString & origin="System", unsigned smoothCfg=0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Hyperion * _hyperion;
|
Hyperion * _hyperion;
|
||||||
|
|
||||||
QJsonObject _effectConfig;
|
|
||||||
|
|
||||||
std::list<EffectDefinition> _availableEffects;
|
std::list<EffectDefinition> _availableEffects;
|
||||||
|
|
||||||
std::list<Effect *> _activeEffects;
|
std::list<Effect *> _activeEffects;
|
||||||
@ -93,7 +105,8 @@ private:
|
|||||||
|
|
||||||
std::list<ActiveEffectDefinition> _cachedActiveEffects;
|
std::list<ActiveEffectDefinition> _cachedActiveEffects;
|
||||||
|
|
||||||
std::list<EffectSchema> _effectSchemas;
|
|
||||||
|
|
||||||
Logger * _log;
|
Logger * _log;
|
||||||
|
|
||||||
|
// The global effect file handler
|
||||||
|
EffectFileHandler* _effectFileHandler;
|
||||||
};
|
};
|
||||||
|
86
include/effectengine/EffectFileHandler.h
Normal file
86
include/effectengine/EffectFileHandler.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// util
|
||||||
|
#include <utils/Logger.h>
|
||||||
|
#include <effectengine/EffectDefinition.h>
|
||||||
|
#include <effectengine/EffectSchema.h>
|
||||||
|
#include <utils/settings.h>
|
||||||
|
|
||||||
|
class EffectFileHandler : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
friend class HyperionDaemon;
|
||||||
|
EffectFileHandler(const QString& rootPath, const QJsonDocument& effectConfig, QObject* parent = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static EffectFileHandler* efhInstance;
|
||||||
|
static EffectFileHandler* getInstance() { return efhInstance; };
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Get all available effects
|
||||||
|
///
|
||||||
|
const std::list<EffectDefinition> & getEffects() const { return _availableEffects; };
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Get all available schemas
|
||||||
|
///
|
||||||
|
const std::list<EffectSchema> & getEffectSchemas() { return _effectSchemas; };
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Save an effect
|
||||||
|
/// @param obj The effect args
|
||||||
|
/// @param[out] resultMsg The feedback message
|
||||||
|
/// @return True on success else false
|
||||||
|
///
|
||||||
|
const bool saveEffect(const QJsonObject& obj, QString& resultMsg);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Delete an effect by name.
|
||||||
|
/// @param[in] effectName The effect name to delete
|
||||||
|
/// @param[out] resultMsg The message on error
|
||||||
|
/// @return True on success else false
|
||||||
|
///
|
||||||
|
const bool deleteEffect(const QString& effectName, QString& resultMsg);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
///
|
||||||
|
/// @brief Handle settings update from Hyperion Settingsmanager emit
|
||||||
|
/// @param type settingyType from enum
|
||||||
|
/// @param config configuration object
|
||||||
|
///
|
||||||
|
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
///
|
||||||
|
/// @brief Emits whenever the data changes for an effect
|
||||||
|
///
|
||||||
|
void effectListChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
///
|
||||||
|
/// @brief refresh available schemas and effects
|
||||||
|
///
|
||||||
|
void updateEffects();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Load the effect definition, called by updateEffects()
|
||||||
|
///
|
||||||
|
bool loadEffectDefinition(const QString & path, const QString & effectConfigFile, EffectDefinition &effectDefinition);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief load effect schemas, called by updateEffects()
|
||||||
|
///
|
||||||
|
bool loadEffectSchema(const QString & path, const QString & effectSchemaFile, EffectSchema &effectSchema);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QJsonObject _effectConfig;
|
||||||
|
Logger* _log;
|
||||||
|
const QString _rootPath;
|
||||||
|
|
||||||
|
// available effects
|
||||||
|
std::list<EffectDefinition> _availableEffects;
|
||||||
|
|
||||||
|
// all schemas
|
||||||
|
std::list<EffectSchema> _effectSchemas;
|
||||||
|
};
|
@ -54,6 +54,11 @@ private slots:
|
|||||||
///
|
///
|
||||||
void setV4lInactive();
|
void setV4lInactive();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Is called from _systemInactiveTimer to set source after specific time to inactive
|
||||||
|
///
|
||||||
|
void setSystemInactive();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Hyperion instance
|
/// Hyperion instance
|
||||||
Hyperion* _hyperion;
|
Hyperion* _hyperion;
|
||||||
@ -61,6 +66,7 @@ private:
|
|||||||
/// Reflect state of System capture and prio
|
/// Reflect state of System capture and prio
|
||||||
bool _systemCaptEnabled;
|
bool _systemCaptEnabled;
|
||||||
quint8 _systemCaptPrio;
|
quint8 _systemCaptPrio;
|
||||||
|
QTimer* _systemInactiveTimer;
|
||||||
|
|
||||||
/// Reflect state of v4l capture and prio
|
/// Reflect state of v4l capture and prio
|
||||||
bool _v4lCaptEnabled;
|
bool _v4lCaptEnabled;
|
||||||
|
@ -163,8 +163,21 @@ public:
|
|||||||
///
|
///
|
||||||
const InputInfo getPriorityInfo(const int priority) const;
|
const InputInfo getPriorityInfo(const int priority) const;
|
||||||
|
|
||||||
/// Reload the list of available effects
|
///
|
||||||
void reloadEffects();
|
/// @brief Save an effect
|
||||||
|
/// @param obj The effect args
|
||||||
|
/// @param[out] resultMsg The feedback message
|
||||||
|
/// @return True on success else false
|
||||||
|
///
|
||||||
|
const bool saveEffect(const QJsonObject& obj, QString& resultMsg);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Delete an effect by name.
|
||||||
|
/// @param[in] effectName The effect name to delete
|
||||||
|
/// @param[out] resultMsg The message on error
|
||||||
|
/// @return True on success else false
|
||||||
|
///
|
||||||
|
const bool deleteEffect(const QString& effectName, QString& resultMsg);
|
||||||
|
|
||||||
/// Get the list of available effects
|
/// Get the list of available effects
|
||||||
/// @return The list of available effects
|
/// @return The list of available effects
|
||||||
@ -215,12 +228,6 @@ public:
|
|||||||
/// @return the state
|
/// @return the state
|
||||||
bool sourceAutoSelectEnabled();
|
bool sourceAutoSelectEnabled();
|
||||||
|
|
||||||
///
|
|
||||||
/// @brief Get the last untransformed/unadjusted led colors
|
|
||||||
/// @return The _rawLedBuffer leds
|
|
||||||
///
|
|
||||||
const std::vector<ColorRgb>& getRawLedBuffer() { return _rawLedBuffer; };
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Enable/Disable components during runtime, called from external API (requests)
|
/// @brief Enable/Disable components during runtime, called from external API (requests)
|
||||||
///
|
///
|
||||||
@ -433,6 +440,11 @@ signals:
|
|||||||
///
|
///
|
||||||
void v4lImage(const Image<ColorRgb> & image);
|
void v4lImage(const Image<ColorRgb> & image);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Emits whenever new untransformed ledColos data is available, reflects the current visible device
|
||||||
|
///
|
||||||
|
void rawLedColors(const std::vector<ColorRgb>& ledValues);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
///
|
///
|
||||||
/// Updates the priority muxer with the current time and (re)writes the led color with applied
|
/// Updates the priority muxer with the current time and (re)writes the led color with applied
|
||||||
@ -548,8 +560,6 @@ private:
|
|||||||
|
|
||||||
/// buffer for leds (with adjustment)
|
/// buffer for leds (with adjustment)
|
||||||
std::vector<ColorRgb> _ledBuffer;
|
std::vector<ColorRgb> _ledBuffer;
|
||||||
/// buffer for leds (without adjustment)
|
|
||||||
std::vector<ColorRgb> _rawLedBuffer;
|
|
||||||
|
|
||||||
/// Boblight instance
|
/// Boblight instance
|
||||||
BoblightServer* _boblightServer;
|
BoblightServer* _boblightServer;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
class Hyperion;
|
class Hyperion;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Manage the settings read write from/to database, on settings changed will emit a signal to update components accordingly
|
/// @brief Manage the settings read write from/to config file, on settings changed will emit a signal to update components accordingly
|
||||||
///
|
///
|
||||||
class SettingsManager : public QObject
|
class SettingsManager : public QObject
|
||||||
{
|
{
|
||||||
@ -37,7 +37,7 @@ public:
|
|||||||
const bool saveSettings(QJsonObject config, const bool& correct = false);
|
const bool saveSettings(QJsonObject config, const bool& correct = false);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief get a single setting json from database
|
/// @brief get a single setting json from config
|
||||||
/// @param type The settings::type from enum
|
/// @param type The settings::type from enum
|
||||||
/// @return The requested json data as QJsonDocument
|
/// @return The requested json data as QJsonDocument
|
||||||
///
|
///
|
||||||
@ -51,7 +51,7 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
///
|
///
|
||||||
/// @brief Emits whenever a config part changed. Comparison of database and new data to prevent false positive
|
/// @brief Emits whenever a config part changed.
|
||||||
/// @param type The settings type from enum
|
/// @param type The settings type from enum
|
||||||
/// @param data The data as QJsonDocument
|
/// @param data The data as QJsonDocument
|
||||||
///
|
///
|
||||||
@ -60,10 +60,13 @@ signals:
|
|||||||
private:
|
private:
|
||||||
/// Hyperion instance
|
/// Hyperion instance
|
||||||
Hyperion* _hyperion;
|
Hyperion* _hyperion;
|
||||||
|
|
||||||
/// Logger instance
|
/// Logger instance
|
||||||
Logger* _log;
|
Logger* _log;
|
||||||
|
|
||||||
/// the schema
|
/// the schema
|
||||||
static QJsonObject schemaJson;
|
static QJsonObject schemaJson;
|
||||||
|
|
||||||
/// the current config of this instance
|
/// the current config of this instance
|
||||||
QJsonObject _qconfig;
|
QJsonObject _qconfig;
|
||||||
};
|
};
|
||||||
|
@ -12,9 +12,9 @@
|
|||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QFileInfo>
|
// #include <QFileInfo>
|
||||||
#include <QDir>
|
// #include <QDir>
|
||||||
#include <QIODevice>
|
// #include <QIODevice>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
// hyperion includes
|
// hyperion includes
|
||||||
@ -41,13 +41,14 @@ using namespace hyperion;
|
|||||||
|
|
||||||
JsonAPI::JsonAPI(QString peerAddress, Logger* log, QObject* parent, bool noListener)
|
JsonAPI::JsonAPI(QString peerAddress, Logger* log, QObject* parent, bool noListener)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, _jsonCB(new JsonCB(this))
|
|
||||||
, _noListener(noListener)
|
, _noListener(noListener)
|
||||||
, _peerAddress(peerAddress)
|
, _peerAddress(peerAddress)
|
||||||
, _log(log)
|
, _log(log)
|
||||||
, _hyperion(Hyperion::getInstance())
|
, _hyperion(Hyperion::getInstance())
|
||||||
|
, _jsonCB(new JsonCB(this))
|
||||||
, _streaming_logging_activated(false)
|
, _streaming_logging_activated(false)
|
||||||
, _image_stream_timeout(0)
|
, _image_stream_timeout(0)
|
||||||
|
, _led_stream_timeout(0)
|
||||||
{
|
{
|
||||||
// the JsonCB creates json messages you can subscribe to e.g. data change events; forward them to the parent client
|
// the JsonCB creates json messages you can subscribe to e.g. data change events; forward them to the parent client
|
||||||
connect(_jsonCB, &JsonCB::newCallback, this, &JsonAPI::callbackMessage);
|
connect(_jsonCB, &JsonCB::newCallback, this, &JsonAPI::callbackMessage);
|
||||||
@ -55,9 +56,8 @@ JsonAPI::JsonAPI(QString peerAddress, Logger* log, QObject* parent, bool noListe
|
|||||||
// notify hyperion about a jsonMessageForward
|
// notify hyperion about a jsonMessageForward
|
||||||
connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage);
|
connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage);
|
||||||
|
|
||||||
// led color stream update timer
|
|
||||||
connect(&_timer_ledcolors, SIGNAL(timeout()), this, SLOT(streamLedcolorsUpdate()));
|
|
||||||
_image_stream_mutex.unlock();
|
_image_stream_mutex.unlock();
|
||||||
|
_led_stream_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleMessage(const QString& messageString)
|
void JsonAPI::handleMessage(const QString& messageString)
|
||||||
@ -207,105 +207,20 @@ void JsonAPI::handleEffectCommand(const QJsonObject& message, const QString& com
|
|||||||
|
|
||||||
void JsonAPI::handleCreateEffectCommand(const QJsonObject& message, const QString &command, const int tan)
|
void JsonAPI::handleCreateEffectCommand(const QJsonObject& message, const QString &command, const int tan)
|
||||||
{
|
{
|
||||||
if (!message["args"].toObject().isEmpty())
|
QString resultMsg;
|
||||||
{
|
if(_hyperion->saveEffect(message, resultMsg))
|
||||||
QString scriptName;
|
|
||||||
(message["script"].toString().mid(0, 1) == ":" )
|
|
||||||
? scriptName = ":/effects//" + message["script"].toString().mid(1)
|
|
||||||
: scriptName = message["script"].toString();
|
|
||||||
|
|
||||||
std::list<EffectSchema> effectsSchemas = _hyperion->getEffectSchemas();
|
|
||||||
std::list<EffectSchema>::iterator it = std::find_if(effectsSchemas.begin(), effectsSchemas.end(), find_schema(scriptName));
|
|
||||||
|
|
||||||
if (it != effectsSchemas.end())
|
|
||||||
{
|
|
||||||
if(!JsonUtils::validate("JsonRpc@"+_peerAddress, message["args"].toObject(), it->schemaFile, _log))
|
|
||||||
{
|
|
||||||
sendErrorReply("Error during arg validation against schema, please consult the Hyperion Log", command, tan);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject effectJson;
|
|
||||||
QJsonArray effectArray;
|
|
||||||
effectArray = _hyperion->getQJsonConfig()["effects"].toObject()["paths"].toArray();
|
|
||||||
|
|
||||||
if (effectArray.size() > 0)
|
|
||||||
{
|
|
||||||
if (message["name"].toString().trimmed().isEmpty() || message["name"].toString().trimmed().startsWith("."))
|
|
||||||
{
|
|
||||||
sendErrorReply("Can't save new effect. Effect name is empty or begins with a dot.", command, tan);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
effectJson["name"] = message["name"].toString();
|
|
||||||
effectJson["script"] = message["script"].toString();
|
|
||||||
effectJson["args"] = message["args"].toObject();
|
|
||||||
|
|
||||||
std::list<EffectDefinition> availableEffects = _hyperion->getEffects();
|
|
||||||
std::list<EffectDefinition>::iterator iter = std::find_if(availableEffects.begin(), availableEffects.end(), find_effect(message["name"].toString()));
|
|
||||||
|
|
||||||
QFileInfo newFileName;
|
|
||||||
if (iter != availableEffects.end())
|
|
||||||
{
|
|
||||||
newFileName.setFile(iter->file);
|
|
||||||
if (newFileName.absoluteFilePath().mid(0, 1) == ":")
|
|
||||||
{
|
|
||||||
sendErrorReply("The effect name '" + message["name"].toString() + "' is assigned to an internal effect. Please rename your effekt.", command, tan);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
QString f = FileUtils::convertPath(effectArray[0].toString() + "/" + message["name"].toString().replace(QString(" "), QString("")) + QString(".json"));
|
|
||||||
newFileName.setFile(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!JsonUtils::write(newFileName.absoluteFilePath(), effectJson, _log))
|
|
||||||
{
|
|
||||||
sendErrorReply("Error while saving effect, please check the Hyperion Log", command, tan);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Info(_log, "Reload effect list");
|
|
||||||
_hyperion->reloadEffects();
|
|
||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
} else
|
else
|
||||||
{
|
sendErrorReply(resultMsg, command, tan);
|
||||||
sendErrorReply("Can't save new effect. Effect path empty", command, tan);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
sendErrorReply("Missing schema file for Python script " + message["script"].toString(), command, tan);
|
|
||||||
} else
|
|
||||||
sendErrorReply("Missing or empty Object 'args'", command, tan);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleDeleteEffectCommand(const QJsonObject& message, const QString& command, const int tan)
|
void JsonAPI::handleDeleteEffectCommand(const QJsonObject& message, const QString& command, const int tan)
|
||||||
{
|
{
|
||||||
QString effectName = message["name"].toString();
|
QString resultMsg;
|
||||||
std::list<EffectDefinition> effectsDefinition = _hyperion->getEffects();
|
if(_hyperion->deleteEffect(message["name"].toString(), resultMsg))
|
||||||
std::list<EffectDefinition>::iterator it = std::find_if(effectsDefinition.begin(), effectsDefinition.end(), find_effect(effectName));
|
|
||||||
|
|
||||||
if (it != effectsDefinition.end())
|
|
||||||
{
|
|
||||||
QFileInfo effectConfigurationFile(it->file);
|
|
||||||
if (effectConfigurationFile.absoluteFilePath().mid(0, 1) != ":" )
|
|
||||||
{
|
|
||||||
if (effectConfigurationFile.exists())
|
|
||||||
{
|
|
||||||
bool result = QFile::remove(effectConfigurationFile.absoluteFilePath());
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
Info(_log, "Reload effect list");
|
|
||||||
_hyperion->reloadEffects();
|
|
||||||
sendSuccessReply(command, tan);
|
sendSuccessReply(command, tan);
|
||||||
} else
|
else
|
||||||
sendErrorReply("Can't delete effect configuration file: " + effectConfigurationFile.absoluteFilePath() + ". Please check permissions", command, tan);
|
sendErrorReply(resultMsg, command, tan);
|
||||||
} else
|
|
||||||
sendErrorReply("Can't find effect configuration file: " + effectConfigurationFile.absoluteFilePath(), command, tan);
|
|
||||||
} else
|
|
||||||
sendErrorReply("Can't delete internal effect: " + message["name"].toString(), command, tan);
|
|
||||||
} else
|
|
||||||
sendErrorReply("Effect " + message["name"].toString() + " not found", command, tan);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::handleSysInfoCommand(const QJsonObject&, const QString& command, const int tan)
|
void JsonAPI::handleSysInfoCommand(const QJsonObject&, const QString& command, const int tan)
|
||||||
@ -358,10 +273,9 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString&
|
|||||||
const Hyperion::InputInfo & priorityInfo = _hyperion->getPriorityInfo(priority);
|
const Hyperion::InputInfo & priorityInfo = _hyperion->getPriorityInfo(priority);
|
||||||
QJsonObject item;
|
QJsonObject item;
|
||||||
item["priority"] = priority;
|
item["priority"] = priority;
|
||||||
if (int(priorityInfo.timeoutTime_ms - now) > -1 )
|
if (priorityInfo.timeoutTime_ms > 0 )
|
||||||
{
|
|
||||||
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
||||||
}
|
|
||||||
// owner has optional informations to the component
|
// owner has optional informations to the component
|
||||||
if(!priorityInfo.owner.isEmpty())
|
if(!priorityInfo.owner.isEmpty())
|
||||||
item["owner"] = priorityInfo.owner;
|
item["owner"] = priorityInfo.owner;
|
||||||
@ -861,12 +775,11 @@ void JsonAPI::handleLedColorsCommand(const QJsonObject& message, const QString &
|
|||||||
_streaming_leds_reply["success"] = true;
|
_streaming_leds_reply["success"] = true;
|
||||||
_streaming_leds_reply["command"] = command+"-ledstream-update";
|
_streaming_leds_reply["command"] = command+"-ledstream-update";
|
||||||
_streaming_leds_reply["tan"] = tan;
|
_streaming_leds_reply["tan"] = tan;
|
||||||
_timer_ledcolors.setInterval(125);
|
connect(_hyperion, &Hyperion::rawLedColors, this, &JsonAPI::streamLedcolorsUpdate, Qt::UniqueConnection);
|
||||||
_timer_ledcolors.start(125);
|
|
||||||
}
|
}
|
||||||
else if (subcommand == "ledstream-stop")
|
else if (subcommand == "ledstream-stop")
|
||||||
{
|
{
|
||||||
_timer_ledcolors.stop();
|
disconnect(_hyperion, &Hyperion::rawLedColors, this, &JsonAPI::streamLedcolorsUpdate);
|
||||||
}
|
}
|
||||||
else if (subcommand == "imagestream-start")
|
else if (subcommand == "imagestream-start")
|
||||||
{
|
{
|
||||||
@ -984,12 +897,14 @@ void JsonAPI::sendErrorReply(const QString &error, const QString &command, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void JsonAPI::streamLedcolorsUpdate()
|
void JsonAPI::streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors)
|
||||||
{
|
{
|
||||||
|
if ( (_led_stream_timeout+100) < QDateTime::currentMSecsSinceEpoch() && _led_stream_mutex.tryLock(0) )
|
||||||
|
{
|
||||||
|
_led_stream_timeout = QDateTime::currentMSecsSinceEpoch();
|
||||||
QJsonObject result;
|
QJsonObject result;
|
||||||
QJsonArray leds;
|
QJsonArray leds;
|
||||||
|
|
||||||
const std::vector<ColorRgb> & ledColors = _hyperion->getRawLedBuffer();
|
|
||||||
for(auto color = ledColors.begin(); color != ledColors.end(); ++color)
|
for(auto color = ledColors.begin(); color != ledColors.end(); ++color)
|
||||||
{
|
{
|
||||||
QJsonObject item;
|
QJsonObject item;
|
||||||
@ -1005,11 +920,14 @@ void JsonAPI::streamLedcolorsUpdate()
|
|||||||
|
|
||||||
// send the result
|
// send the result
|
||||||
emit callbackMessage(_streaming_leds_reply);
|
emit callbackMessage(_streaming_leds_reply);
|
||||||
|
|
||||||
|
_led_stream_mutex.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::setImage(const Image<ColorRgb> & image)
|
void JsonAPI::setImage(const Image<ColorRgb> & image)
|
||||||
{
|
{
|
||||||
if ( (_image_stream_timeout+250) < QDateTime::currentMSecsSinceEpoch() && _image_stream_mutex.tryLock(0) )
|
if ( (_image_stream_timeout+100) < QDateTime::currentMSecsSinceEpoch() && _image_stream_mutex.tryLock(0) )
|
||||||
{
|
{
|
||||||
_image_stream_timeout = QDateTime::currentMSecsSinceEpoch();
|
_image_stream_timeout = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
|
||||||
|
@ -139,10 +139,9 @@ void JsonCB::handlePriorityUpdate()
|
|||||||
const Hyperion::InputInfo priorityInfo = _prioMuxer->getInputInfo(priority);
|
const Hyperion::InputInfo priorityInfo = _prioMuxer->getInputInfo(priority);
|
||||||
QJsonObject item;
|
QJsonObject item;
|
||||||
item["priority"] = priority;
|
item["priority"] = priority;
|
||||||
if (int(priorityInfo.timeoutTime_ms - now) > -1 )
|
if (priorityInfo.timeoutTime_ms > 0 )
|
||||||
{
|
|
||||||
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
||||||
}
|
|
||||||
// owner has optional informations to the component
|
// owner has optional informations to the component
|
||||||
if(!priorityInfo.owner.isEmpty())
|
if(!priorityInfo.owner.isEmpty())
|
||||||
item["owner"] = priorityInfo.owner;
|
item["owner"] = priorityInfo.owner;
|
||||||
|
@ -18,33 +18,46 @@
|
|||||||
#include <effectengine/EffectEngine.h>
|
#include <effectengine/EffectEngine.h>
|
||||||
#include <effectengine/Effect.h>
|
#include <effectengine/Effect.h>
|
||||||
#include <effectengine/EffectModule.h>
|
#include <effectengine/EffectModule.h>
|
||||||
|
#include <effectengine/EffectFileHandler.h>
|
||||||
#include "HyperionConfig.h"
|
#include "HyperionConfig.h"
|
||||||
|
|
||||||
EffectEngine::EffectEngine(Hyperion * hyperion, const QJsonObject & jsonEffectConfig)
|
EffectEngine::EffectEngine(Hyperion * hyperion)
|
||||||
: _hyperion(hyperion)
|
: _hyperion(hyperion)
|
||||||
, _effectConfig(jsonEffectConfig)
|
|
||||||
, _availableEffects()
|
, _availableEffects()
|
||||||
, _activeEffects()
|
, _activeEffects()
|
||||||
, _log(Logger::getInstance("EFFECTENGINE"))
|
, _log(Logger::getInstance("EFFECTENGINE"))
|
||||||
|
, _effectFileHandler(EffectFileHandler::getInstance())
|
||||||
{
|
{
|
||||||
|
|
||||||
Q_INIT_RESOURCE(EffectEngine);
|
Q_INIT_RESOURCE(EffectEngine);
|
||||||
qRegisterMetaType<std::vector<ColorRgb>>("std::vector<ColorRgb>");
|
qRegisterMetaType<std::vector<ColorRgb>>("std::vector<ColorRgb>");
|
||||||
qRegisterMetaType<Image<ColorRgb>>("Image<ColorRgb>");
|
|
||||||
qRegisterMetaType<hyperion::Components>("hyperion::Components");
|
qRegisterMetaType<hyperion::Components>("hyperion::Components");
|
||||||
|
|
||||||
// connect the Hyperion channel clear feedback
|
// connect the Hyperion channel clear feedback
|
||||||
connect(_hyperion, SIGNAL(channelCleared(int)), this, SLOT(channelCleared(int)));
|
connect(_hyperion, SIGNAL(channelCleared(int)), this, SLOT(channelCleared(int)));
|
||||||
connect(_hyperion, SIGNAL(allChannelsCleared()), this, SLOT(allChannelsCleared()));
|
connect(_hyperion, SIGNAL(allChannelsCleared()), this, SLOT(allChannelsCleared()));
|
||||||
|
|
||||||
// read all effects
|
// get notifications about refreshed effect list
|
||||||
readEffects();
|
connect(_effectFileHandler, &EffectFileHandler::effectListChanged, this, &EffectEngine::handleUpdatedEffectList);
|
||||||
|
|
||||||
|
// register smooth cfgs and fill available effects
|
||||||
|
handleUpdatedEffectList();
|
||||||
}
|
}
|
||||||
|
|
||||||
EffectEngine::~EffectEngine()
|
EffectEngine::~EffectEngine()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool EffectEngine::saveEffect(const QJsonObject& obj, QString& resultMsg)
|
||||||
|
{
|
||||||
|
return _effectFileHandler->saveEffect(obj, resultMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool EffectEngine::deleteEffect(const QString& effectName, QString& resultMsg)
|
||||||
|
{
|
||||||
|
return _effectFileHandler->deleteEffect(effectName, resultMsg);
|
||||||
|
}
|
||||||
|
|
||||||
const std::list<ActiveEffectDefinition> &EffectEngine::getActiveEffects()
|
const std::list<ActiveEffectDefinition> &EffectEngine::getActiveEffects()
|
||||||
{
|
{
|
||||||
_availableActiveEffects.clear();
|
_availableActiveEffects.clear();
|
||||||
@ -63,6 +76,11 @@ const std::list<ActiveEffectDefinition> &EffectEngine::getActiveEffects()
|
|||||||
return _availableActiveEffects;
|
return _availableActiveEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::list<EffectSchema> & EffectEngine::getEffectSchemas()
|
||||||
|
{
|
||||||
|
return _effectFileHandler->getEffectSchemas();
|
||||||
|
}
|
||||||
|
|
||||||
void EffectEngine::cacheRunningEffects()
|
void EffectEngine::cacheRunningEffects()
|
||||||
{
|
{
|
||||||
_cachedActiveEffects.clear();
|
_cachedActiveEffects.clear();
|
||||||
@ -90,175 +108,26 @@ void EffectEngine::startCachedEffects()
|
|||||||
_cachedActiveEffects.clear();
|
_cachedActiveEffects.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effectConfigFile, EffectDefinition & effectDefinition)
|
void EffectEngine::handleUpdatedEffectList()
|
||||||
{
|
{
|
||||||
QString fileName = path + QDir::separator() + effectConfigFile;
|
_availableEffects.clear();
|
||||||
|
|
||||||
// Read and parse the effect json config file
|
for (auto def : _effectFileHandler->getEffects())
|
||||||
QJsonObject configEffect;
|
|
||||||
if(!JsonUtils::readFile(fileName, configEffect, _log))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Q_INIT_RESOURCE(EffectEngine);
|
|
||||||
// validate effect config with effect schema(path)
|
|
||||||
if(!JsonUtils::validate(fileName, configEffect, ":effect-schema", _log))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// setup the definition
|
|
||||||
effectDefinition.file = fileName;
|
|
||||||
QJsonObject config = configEffect;
|
|
||||||
QString scriptName = config["script"].toString();
|
|
||||||
effectDefinition.name = config["name"].toString();
|
|
||||||
if (scriptName.isEmpty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QFile fileInfo(scriptName);
|
|
||||||
|
|
||||||
if (scriptName.mid(0, 1) == ":" )
|
|
||||||
{
|
{
|
||||||
(!fileInfo.exists())
|
// add smoothing configs to Hyperion
|
||||||
? effectDefinition.script = ":/effects/"+scriptName.mid(1)
|
if (def.args["smoothing-custom-settings"].toBool())
|
||||||
: effectDefinition.script = scriptName;
|
|
||||||
} else
|
|
||||||
{
|
{
|
||||||
(!fileInfo.exists())
|
def.smoothCfg = _hyperion->addSmoothingConfig(
|
||||||
? effectDefinition.script = path + QDir::separator() + scriptName
|
def.args["smoothing-time_ms"].toInt(),
|
||||||
: effectDefinition.script = scriptName;
|
def.args["smoothing-updateFrequency"].toDouble(),
|
||||||
}
|
|
||||||
|
|
||||||
effectDefinition.args = config["args"].toObject();
|
|
||||||
effectDefinition.smoothCfg = SMOOTHING_MODE_PAUSE;
|
|
||||||
if (effectDefinition.args["smoothing-custom-settings"].toBool())
|
|
||||||
{
|
|
||||||
effectDefinition.smoothCfg = _hyperion->addSmoothingConfig(
|
|
||||||
effectDefinition.args["smoothing-time_ms"].toInt(),
|
|
||||||
effectDefinition.args["smoothing-updateFrequency"].toDouble(),
|
|
||||||
0 );
|
0 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
effectDefinition.smoothCfg = _hyperion->addSmoothingConfig(true);
|
def.smoothCfg = _hyperion->addSmoothingConfig(true);
|
||||||
}
|
}
|
||||||
return true;
|
_availableEffects.push_back(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectEngine::loadEffectSchema(const QString &path, const QString &effectSchemaFile, EffectSchema & effectSchema)
|
|
||||||
{
|
|
||||||
QString fileName = path + "schema/" + QDir::separator() + effectSchemaFile;
|
|
||||||
|
|
||||||
// Read and parse the effect schema file
|
|
||||||
QJsonObject schemaEffect;
|
|
||||||
if(!JsonUtils::readFile(fileName, schemaEffect, _log))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// setup the definition
|
|
||||||
QString scriptName = schemaEffect["script"].toString();
|
|
||||||
effectSchema.schemaFile = fileName;
|
|
||||||
fileName = path + QDir::separator() + scriptName;
|
|
||||||
QFile pyFile(fileName);
|
|
||||||
|
|
||||||
if (scriptName.isEmpty() || !pyFile.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
fileName = path + "schema/" + QDir::separator() + effectSchemaFile;
|
|
||||||
Error( _log, "Python script '%s' in effect schema '%s' could not be loaded", QSTRING_CSTR(scriptName), QSTRING_CSTR(fileName));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pyFile.close();
|
|
||||||
|
|
||||||
effectSchema.pyFile = (scriptName.mid(0, 1) == ":" ) ? ":/effects/"+scriptName.mid(1) : path + QDir::separator() + scriptName;
|
|
||||||
effectSchema.pySchema = schemaEffect;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EffectEngine::readEffects()
|
|
||||||
{
|
|
||||||
// clear all lists
|
|
||||||
_availableEffects.clear();
|
|
||||||
_effectSchemas.clear();
|
|
||||||
|
|
||||||
// read all effects
|
|
||||||
const QJsonArray & paths = _effectConfig["paths"].toArray();
|
|
||||||
const QJsonArray & disabledEfx = _effectConfig["disable"].toArray();
|
|
||||||
|
|
||||||
QStringList efxPathList;
|
|
||||||
efxPathList << ":/effects/";
|
|
||||||
QStringList disableList;
|
|
||||||
|
|
||||||
for(auto p : paths)
|
|
||||||
{
|
|
||||||
efxPathList << p.toString().replace("$ROOT",_hyperion->getRootPath());
|
|
||||||
}
|
|
||||||
for(auto efx : disabledEfx)
|
|
||||||
{
|
|
||||||
disableList << efx.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QMap<QString, EffectDefinition> availableEffects;
|
|
||||||
for (const QString & path : efxPathList )
|
|
||||||
{
|
|
||||||
QDir directory(path);
|
|
||||||
if (!directory.exists())
|
|
||||||
{
|
|
||||||
if(directory.mkpath(path))
|
|
||||||
{
|
|
||||||
Warning(_log, "New Effect path \"%s\" created successfull", QSTRING_CSTR(path) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Warning(_log, "Failed to create Effect path \"%s\", please check permissions", QSTRING_CSTR(path) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int efxCount = 0;
|
|
||||||
QStringList filenames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
|
|
||||||
for (const QString & filename : filenames)
|
|
||||||
{
|
|
||||||
EffectDefinition def;
|
|
||||||
if (loadEffectDefinition(path, filename, def))
|
|
||||||
{
|
|
||||||
InfoIf(availableEffects.find(def.name) != availableEffects.end(), _log,
|
|
||||||
"effect overload effect '%s' is now taken from '%s'", QSTRING_CSTR(def.name), QSTRING_CSTR(path) );
|
|
||||||
|
|
||||||
if ( disableList.contains(def.name) )
|
|
||||||
{
|
|
||||||
Info(_log, "effect '%s' not loaded, because it is disabled in hyperion config", QSTRING_CSTR(def.name));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
availableEffects[def.name] = def;
|
|
||||||
efxCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Info(_log, "%d effects loaded from directory %s", efxCount, QSTRING_CSTR(path));
|
|
||||||
|
|
||||||
// collect effect schemas
|
|
||||||
efxCount = 0;
|
|
||||||
directory = path.endsWith("/") ? (path + "schema/") : (path + "/schema/");
|
|
||||||
QStringList pynames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
|
|
||||||
for (const QString & pyname : pynames)
|
|
||||||
{
|
|
||||||
EffectSchema pyEffect;
|
|
||||||
if (loadEffectSchema(path, pyname, pyEffect))
|
|
||||||
{
|
|
||||||
_effectSchemas.push_back(pyEffect);
|
|
||||||
efxCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InfoIf(efxCount > 0, _log, "%d effect schemas loaded from directory %s", efxCount, QSTRING_CSTR((path + "schema/")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto item : availableEffects)
|
|
||||||
{
|
|
||||||
_availableEffects.push_back(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorIf(_availableEffects.size()==0, _log, "no effects found, check your effect directories");
|
|
||||||
|
|
||||||
emit effectListUpdated();
|
emit effectListUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
322
libsrc/effectengine/EffectFileHandler.cpp
Normal file
322
libsrc/effectengine/EffectFileHandler.cpp
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
#include <effectengine/EffectFileHandler.h>
|
||||||
|
|
||||||
|
// util
|
||||||
|
#include <utils/JsonUtils.h>
|
||||||
|
|
||||||
|
// qt
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
// createEffect helper
|
||||||
|
struct find_schema: std::unary_function<EffectSchema, bool>
|
||||||
|
{
|
||||||
|
QString pyFile;
|
||||||
|
find_schema(QString pyFile):pyFile(pyFile) { }
|
||||||
|
bool operator()(EffectSchema const& schema) const
|
||||||
|
{
|
||||||
|
return schema.pyFile == pyFile;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// deleteEffect helper
|
||||||
|
struct find_effect: std::unary_function<EffectDefinition, bool>
|
||||||
|
{
|
||||||
|
QString effectName;
|
||||||
|
find_effect(QString effectName) :effectName(effectName) { }
|
||||||
|
bool operator()(EffectDefinition const& effectDefinition) const
|
||||||
|
{
|
||||||
|
return effectDefinition.name == effectName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EffectFileHandler* EffectFileHandler::efhInstance;
|
||||||
|
|
||||||
|
EffectFileHandler::EffectFileHandler(const QString& rootPath, const QJsonDocument& effectConfig, QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, _effectConfig()
|
||||||
|
, _log(Logger::getInstance("EFFECTFILES"))
|
||||||
|
, _rootPath(rootPath)
|
||||||
|
{
|
||||||
|
EffectFileHandler::efhInstance = this;
|
||||||
|
|
||||||
|
Q_INIT_RESOURCE(EffectEngine);
|
||||||
|
|
||||||
|
// init
|
||||||
|
handleSettingsUpdate(settings::EFFECTS, effectConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectFileHandler::handleSettingsUpdate(const settings::type& type, const QJsonDocument& config)
|
||||||
|
{
|
||||||
|
if(type == settings::EFFECTS)
|
||||||
|
{
|
||||||
|
_effectConfig = config.object();
|
||||||
|
// update effects and schemas
|
||||||
|
updateEffects();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool EffectFileHandler::deleteEffect(const QString& effectName, QString& resultMsg)
|
||||||
|
{
|
||||||
|
std::list<EffectDefinition> effectsDefinition = getEffects();
|
||||||
|
std::list<EffectDefinition>::iterator it = std::find_if(effectsDefinition.begin(), effectsDefinition.end(), find_effect(effectName));
|
||||||
|
|
||||||
|
if (it != effectsDefinition.end())
|
||||||
|
{
|
||||||
|
QFileInfo effectConfigurationFile(it->file);
|
||||||
|
if (effectConfigurationFile.absoluteFilePath().mid(0, 1) != ":" )
|
||||||
|
{
|
||||||
|
if (effectConfigurationFile.exists())
|
||||||
|
{
|
||||||
|
bool result = QFile::remove(effectConfigurationFile.absoluteFilePath());
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
updateEffects();
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
resultMsg = "Can't delete effect configuration file: " + effectConfigurationFile.absoluteFilePath() + ". Please check permissions";
|
||||||
|
} else
|
||||||
|
resultMsg = "Can't find effect configuration file: " + effectConfigurationFile.absoluteFilePath();
|
||||||
|
} else
|
||||||
|
resultMsg = "Can't delete internal effect: " + effectName;
|
||||||
|
} else
|
||||||
|
resultMsg = "Effect " + effectName + " not found";
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool EffectFileHandler::saveEffect(const QJsonObject& message, QString& resultMsg)
|
||||||
|
{
|
||||||
|
if (!message["args"].toObject().isEmpty())
|
||||||
|
{
|
||||||
|
QString scriptName;
|
||||||
|
(message["script"].toString().mid(0, 1) == ":" )
|
||||||
|
? scriptName = ":/effects//" + message["script"].toString().mid(1)
|
||||||
|
: scriptName = message["script"].toString();
|
||||||
|
|
||||||
|
std::list<EffectSchema> effectsSchemas = getEffectSchemas();
|
||||||
|
std::list<EffectSchema>::iterator it = std::find_if(effectsSchemas.begin(), effectsSchemas.end(), find_schema(scriptName));
|
||||||
|
|
||||||
|
if (it != effectsSchemas.end())
|
||||||
|
{
|
||||||
|
if(!JsonUtils::validate("EffectFileHandler", message["args"].toObject(), it->schemaFile, _log))
|
||||||
|
{
|
||||||
|
resultMsg = "Error during arg validation against schema, please consult the Hyperion Log";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject effectJson;
|
||||||
|
QJsonArray effectArray;
|
||||||
|
effectArray = _effectConfig["paths"].toArray();
|
||||||
|
|
||||||
|
if (effectArray.size() > 0)
|
||||||
|
{
|
||||||
|
if (message["name"].toString().trimmed().isEmpty() || message["name"].toString().trimmed().startsWith("."))
|
||||||
|
{
|
||||||
|
resultMsg = "Can't save new effect. Effect name is empty or begins with a dot.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
effectJson["name"] = message["name"].toString();
|
||||||
|
effectJson["script"] = message["script"].toString();
|
||||||
|
effectJson["args"] = message["args"].toObject();
|
||||||
|
|
||||||
|
std::list<EffectDefinition> availableEffects = getEffects();
|
||||||
|
std::list<EffectDefinition>::iterator iter = std::find_if(availableEffects.begin(), availableEffects.end(), find_effect(message["name"].toString()));
|
||||||
|
|
||||||
|
QFileInfo newFileName;
|
||||||
|
if (iter != availableEffects.end())
|
||||||
|
{
|
||||||
|
newFileName.setFile(iter->file);
|
||||||
|
if (newFileName.absoluteFilePath().mid(0, 1) == ":")
|
||||||
|
{
|
||||||
|
resultMsg = "The effect name '" + message["name"].toString() + "' is assigned to an internal effect. Please rename your effekt.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// TODO global special keyword handling
|
||||||
|
QString f = effectArray[0].toString().replace("$ROOT",_rootPath) + "/" + message["name"].toString().replace(QString(" "), QString("")) + QString(".json");
|
||||||
|
newFileName.setFile(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!JsonUtils::write(newFileName.absoluteFilePath(), effectJson, _log))
|
||||||
|
{
|
||||||
|
resultMsg = "Error while saving effect, please check the Hyperion Log";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info(_log, "Reload effect list");
|
||||||
|
updateEffects();
|
||||||
|
resultMsg = "";
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
resultMsg = "Can't save new effect. Effect path empty";
|
||||||
|
} else
|
||||||
|
resultMsg = "Missing schema file for Python script " + message["script"].toString();
|
||||||
|
} else
|
||||||
|
resultMsg = "Missing or empty Object 'args'";
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectFileHandler::updateEffects()
|
||||||
|
{
|
||||||
|
// clear all lists
|
||||||
|
_availableEffects.clear();
|
||||||
|
_effectSchemas.clear();
|
||||||
|
|
||||||
|
// read all effects
|
||||||
|
const QJsonArray & paths = _effectConfig["paths"].toArray();
|
||||||
|
const QJsonArray & disabledEfx = _effectConfig["disable"].toArray();
|
||||||
|
|
||||||
|
QStringList efxPathList;
|
||||||
|
efxPathList << ":/effects/";
|
||||||
|
QStringList disableList;
|
||||||
|
|
||||||
|
for(auto p : paths)
|
||||||
|
{
|
||||||
|
efxPathList << p.toString().replace("$ROOT",_rootPath);
|
||||||
|
}
|
||||||
|
for(auto efx : disabledEfx)
|
||||||
|
{
|
||||||
|
disableList << efx.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, EffectDefinition> availableEffects;
|
||||||
|
for (const QString & path : efxPathList )
|
||||||
|
{
|
||||||
|
QDir directory(path);
|
||||||
|
if (!directory.exists())
|
||||||
|
{
|
||||||
|
if(directory.mkpath(path))
|
||||||
|
{
|
||||||
|
Info(_log, "New Effect path \"%s\" created successfull", QSTRING_CSTR(path) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Warning(_log, "Failed to create Effect path \"%s\", please check permissions", QSTRING_CSTR(path) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int efxCount = 0;
|
||||||
|
QStringList filenames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
|
||||||
|
for (const QString & filename : filenames)
|
||||||
|
{
|
||||||
|
EffectDefinition def;
|
||||||
|
if (loadEffectDefinition(path, filename, def))
|
||||||
|
{
|
||||||
|
InfoIf(availableEffects.find(def.name) != availableEffects.end(), _log,
|
||||||
|
"effect overload effect '%s' is now taken from '%s'", QSTRING_CSTR(def.name), QSTRING_CSTR(path) );
|
||||||
|
|
||||||
|
if ( disableList.contains(def.name) )
|
||||||
|
{
|
||||||
|
Info(_log, "effect '%s' not loaded, because it is disabled in hyperion config", QSTRING_CSTR(def.name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
availableEffects[def.name] = def;
|
||||||
|
efxCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Info(_log, "%d effects loaded from directory %s", efxCount, QSTRING_CSTR(path));
|
||||||
|
|
||||||
|
// collect effect schemas
|
||||||
|
efxCount = 0;
|
||||||
|
directory = path.endsWith("/") ? (path + "schema/") : (path + "/schema/");
|
||||||
|
QStringList pynames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
|
||||||
|
for (const QString & pyname : pynames)
|
||||||
|
{
|
||||||
|
EffectSchema pyEffect;
|
||||||
|
if (loadEffectSchema(path, pyname, pyEffect))
|
||||||
|
{
|
||||||
|
_effectSchemas.push_back(pyEffect);
|
||||||
|
efxCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InfoIf(efxCount > 0, _log, "%d effect schemas loaded from directory %s", efxCount, QSTRING_CSTR((path + "schema/")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto item : availableEffects)
|
||||||
|
{
|
||||||
|
_availableEffects.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorIf(_availableEffects.size()==0, _log, "no effects found, check your effect directories");
|
||||||
|
|
||||||
|
emit effectListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EffectFileHandler::loadEffectDefinition(const QString &path, const QString &effectConfigFile, EffectDefinition & effectDefinition)
|
||||||
|
{
|
||||||
|
QString fileName = path + QDir::separator() + effectConfigFile;
|
||||||
|
|
||||||
|
// Read and parse the effect json config file
|
||||||
|
QJsonObject configEffect;
|
||||||
|
if(!JsonUtils::readFile(fileName, configEffect, _log))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// validate effect config with effect schema(path)
|
||||||
|
if(!JsonUtils::validate(fileName, configEffect, ":effect-schema", _log))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// setup the definition
|
||||||
|
effectDefinition.file = fileName;
|
||||||
|
QJsonObject config = configEffect;
|
||||||
|
QString scriptName = config["script"].toString();
|
||||||
|
effectDefinition.name = config["name"].toString();
|
||||||
|
if (scriptName.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QFile fileInfo(scriptName);
|
||||||
|
|
||||||
|
if (scriptName.mid(0, 1) == ":" )
|
||||||
|
{
|
||||||
|
(!fileInfo.exists())
|
||||||
|
? effectDefinition.script = ":/effects/"+scriptName.mid(1)
|
||||||
|
: effectDefinition.script = scriptName;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
(!fileInfo.exists())
|
||||||
|
? effectDefinition.script = path + QDir::separator() + scriptName
|
||||||
|
: effectDefinition.script = scriptName;
|
||||||
|
}
|
||||||
|
|
||||||
|
effectDefinition.args = config["args"].toObject();
|
||||||
|
effectDefinition.smoothCfg = 1; // pause config
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EffectFileHandler::loadEffectSchema(const QString &path, const QString &effectSchemaFile, EffectSchema & effectSchema)
|
||||||
|
{
|
||||||
|
QString fileName = path + "schema/" + QDir::separator() + effectSchemaFile;
|
||||||
|
|
||||||
|
// Read and parse the effect schema file
|
||||||
|
QJsonObject schemaEffect;
|
||||||
|
if(!JsonUtils::readFile(fileName, schemaEffect, _log))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// setup the definition
|
||||||
|
QString scriptName = schemaEffect["script"].toString();
|
||||||
|
effectSchema.schemaFile = fileName;
|
||||||
|
fileName = path + QDir::separator() + scriptName;
|
||||||
|
QFile pyFile(fileName);
|
||||||
|
|
||||||
|
if (scriptName.isEmpty() || !pyFile.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
fileName = path + "schema/" + QDir::separator() + effectSchemaFile;
|
||||||
|
Error( _log, "Python script '%s' in effect schema '%s' could not be loaded", QSTRING_CSTR(scriptName), QSTRING_CSTR(fileName));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pyFile.close();
|
||||||
|
|
||||||
|
effectSchema.pyFile = (scriptName.mid(0, 1) == ":" ) ? ":/effects/"+scriptName.mid(1) : path + QDir::separator() + scriptName;
|
||||||
|
effectSchema.pySchema = schemaEffect;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include <effectengine/Effect.h>
|
#include <effectengine/Effect.h>
|
||||||
#include <effectengine/EffectModule.h>
|
#include <effectengine/EffectModule.h>
|
||||||
@ -44,10 +45,9 @@ PyObject *EffectModule::json2python(const QJsonValue &jsonData)
|
|||||||
return Py_BuildValue("");
|
return Py_BuildValue("");
|
||||||
case QJsonValue::Double:
|
case QJsonValue::Double:
|
||||||
{
|
{
|
||||||
if (std::rint(jsonData.toDouble()) != jsonData.toDouble())
|
if (std::round(jsonData.toDouble()) != jsonData.toDouble())
|
||||||
{
|
|
||||||
return Py_BuildValue("d", jsonData.toDouble());
|
return Py_BuildValue("d", jsonData.toDouble());
|
||||||
}
|
|
||||||
return Py_BuildValue("i", jsonData.toInt());
|
return Py_BuildValue("i", jsonData.toInt());
|
||||||
}
|
}
|
||||||
case QJsonValue::Bool:
|
case QJsonValue::Bool:
|
||||||
|
@ -7,6 +7,7 @@ CaptureCont::CaptureCont(Hyperion* hyperion)
|
|||||||
: QObject()
|
: QObject()
|
||||||
, _hyperion(hyperion)
|
, _hyperion(hyperion)
|
||||||
, _systemCaptEnabled(false)
|
, _systemCaptEnabled(false)
|
||||||
|
, _systemInactiveTimer(new QTimer(this))
|
||||||
, _v4lCaptEnabled(false)
|
, _v4lCaptEnabled(false)
|
||||||
, _v4lInactiveTimer(new QTimer(this))
|
, _v4lInactiveTimer(new QTimer(this))
|
||||||
{
|
{
|
||||||
@ -16,6 +17,11 @@ CaptureCont::CaptureCont(Hyperion* hyperion)
|
|||||||
// comp changes
|
// comp changes
|
||||||
connect(_hyperion, &Hyperion::componentStateChanged, this, &CaptureCont::componentStateChanged);
|
connect(_hyperion, &Hyperion::componentStateChanged, this, &CaptureCont::componentStateChanged);
|
||||||
|
|
||||||
|
// inactive timer system
|
||||||
|
connect(_systemInactiveTimer, &QTimer::timeout, this, &CaptureCont::setSystemInactive);
|
||||||
|
_systemInactiveTimer->setSingleShot(true);
|
||||||
|
_systemInactiveTimer->setInterval(5000);
|
||||||
|
|
||||||
// inactive timer v4l
|
// inactive timer v4l
|
||||||
connect(_v4lInactiveTimer, &QTimer::timeout, this, &CaptureCont::setV4lInactive);
|
connect(_v4lInactiveTimer, &QTimer::timeout, this, &CaptureCont::setV4lInactive);
|
||||||
_v4lInactiveTimer->setSingleShot(true);
|
_v4lInactiveTimer->setSingleShot(true);
|
||||||
@ -38,6 +44,7 @@ void CaptureCont::handleV4lImage(const Image<ColorRgb> & image)
|
|||||||
|
|
||||||
void CaptureCont::handleSystemImage(const Image<ColorRgb>& image)
|
void CaptureCont::handleSystemImage(const Image<ColorRgb>& image)
|
||||||
{
|
{
|
||||||
|
_systemInactiveTimer->start();
|
||||||
_hyperion->setInputImage(_systemCaptPrio, image);
|
_hyperion->setInputImage(_systemCaptPrio, image);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,3 +125,8 @@ void CaptureCont::setV4lInactive()
|
|||||||
{
|
{
|
||||||
_hyperion->setInputInactive(_v4lCaptPrio);
|
_hyperion->setInputInactive(_v4lCaptPrio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CaptureCont::setSystemInactive()
|
||||||
|
{
|
||||||
|
_hyperion->setInputInactive(_systemCaptPrio);
|
||||||
|
}
|
||||||
|
@ -95,9 +95,7 @@ Hyperion::Hyperion(HyperionDaemon* daemon, const quint8& instance, const QString
|
|||||||
, _ledBuffer(_ledString.leds().size(), ColorRgb::BLACK)
|
, _ledBuffer(_ledString.leds().size(), ColorRgb::BLACK)
|
||||||
{
|
{
|
||||||
if (!_raw2ledAdjustment->verifyAdjustments())
|
if (!_raw2ledAdjustment->verifyAdjustments())
|
||||||
{
|
|
||||||
Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!");
|
Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!");
|
||||||
}
|
|
||||||
|
|
||||||
// handle hwLedCount
|
// handle hwLedCount
|
||||||
_hwLedCount = qMax(unsigned(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount())), getLedCount());
|
_hwLedCount = qMax(unsigned(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount())), getLedCount());
|
||||||
@ -107,6 +105,7 @@ Hyperion::Hyperion(HyperionDaemon* daemon, const quint8& instance, const QString
|
|||||||
{
|
{
|
||||||
_ledStringColorOrder.push_back(led.colorOrder);
|
_ledStringColorOrder.push_back(led.colorOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Led& led : _ledStringClone.leds())
|
for (Led& led : _ledStringClone.leds())
|
||||||
{
|
{
|
||||||
_ledStringColorOrder.insert(_ledStringColorOrder.begin() + led.index, led.colorOrder);
|
_ledStringColorOrder.insert(_ledStringColorOrder.begin() + led.index, led.colorOrder);
|
||||||
@ -135,7 +134,7 @@ Hyperion::Hyperion(HyperionDaemon* daemon, const quint8& instance, const QString
|
|||||||
getComponentRegister().componentStateChanged(hyperion::COMP_LEDDEVICE, _device->componentState());
|
getComponentRegister().componentStateChanged(hyperion::COMP_LEDDEVICE, _device->componentState());
|
||||||
|
|
||||||
// create the effect engine and pipe the updateEmit; must be initialized after smoothing!
|
// create the effect engine and pipe the updateEmit; must be initialized after smoothing!
|
||||||
_effectEngine = new EffectEngine(this,getSetting(settings::EFFECTS).object());
|
_effectEngine = new EffectEngine(this);
|
||||||
connect(_effectEngine, &EffectEngine::effectListUpdated, this, &Hyperion::effectListUpdated);
|
connect(_effectEngine, &EffectEngine::effectListUpdated, this, &Hyperion::effectListUpdated);
|
||||||
|
|
||||||
// setup config state checks and initial shot
|
// setup config state checks and initial shot
|
||||||
@ -178,7 +177,6 @@ void Hyperion::freeObjects(bool emitCloseSignal)
|
|||||||
{
|
{
|
||||||
// switch off all leds
|
// switch off all leds
|
||||||
clearall(true);
|
clearall(true);
|
||||||
_device->switchOff();
|
|
||||||
|
|
||||||
if (emitCloseSignal)
|
if (emitCloseSignal)
|
||||||
{
|
{
|
||||||
@ -507,9 +505,14 @@ const Hyperion::InputInfo Hyperion::getPriorityInfo(const int priority) const
|
|||||||
return _muxer.getInputInfo(priority);
|
return _muxer.getInputInfo(priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hyperion::reloadEffects()
|
const bool Hyperion::saveEffect(const QJsonObject& obj, QString& resultMsg)
|
||||||
{
|
{
|
||||||
_effectEngine->readEffects();
|
return _effectEngine->saveEffect(obj, resultMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool Hyperion::deleteEffect(const QString& effectName, QString& resultMsg)
|
||||||
|
{
|
||||||
|
return _effectEngine->deleteEffect(effectName, resultMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::list<EffectDefinition> & Hyperion::getEffects() const
|
const std::list<EffectDefinition> & Hyperion::getEffects() const
|
||||||
@ -625,12 +628,14 @@ void Hyperion::update()
|
|||||||
{
|
{
|
||||||
_ledBuffer = priorityInfo.ledColors;
|
_ledBuffer = priorityInfo.ledColors;
|
||||||
}
|
}
|
||||||
// copy rawLedColors before adjustments
|
|
||||||
_rawLedBuffer = _ledBuffer;
|
// emit rawLedColors before transform
|
||||||
|
emit rawLedColors(_ledBuffer);
|
||||||
|
|
||||||
// apply adjustments
|
// apply adjustments
|
||||||
if(compChanged)
|
if(compChanged)
|
||||||
_raw2ledAdjustment->setBacklightEnabled((_prevCompId != hyperion::COMP_COLOR && _prevCompId != hyperion::COMP_EFFECT));
|
_raw2ledAdjustment->setBacklightEnabled((_prevCompId != hyperion::COMP_COLOR && _prevCompId != hyperion::COMP_EFFECT));
|
||||||
|
|
||||||
_raw2ledAdjustment->applyAdjustment(_ledBuffer);
|
_raw2ledAdjustment->applyAdjustment(_ledBuffer);
|
||||||
|
|
||||||
// insert cloned leds into buffer
|
// insert cloned leds into buffer
|
||||||
|
@ -302,11 +302,10 @@ void PriorityMuxer::setCurrentTime(void)
|
|||||||
if(infoIt->timeoutTime_ms >= -1)
|
if(infoIt->timeoutTime_ms >= -1)
|
||||||
newPriority = qMin(newPriority, infoIt->priority);
|
newPriority = qMin(newPriority, infoIt->priority);
|
||||||
|
|
||||||
// call timeTrigger when effect or color is running with timeout > -1, blacklist prio 255
|
// call timeTrigger when effect or color is running with timeout > 0, blacklist prio 255
|
||||||
if(infoIt->priority < 254 && infoIt->timeoutTime_ms > -1 && (infoIt->componentId == hyperion::COMP_EFFECT || infoIt->componentId == hyperion::COMP_COLOR))
|
if(infoIt->priority < 254 && infoIt->timeoutTime_ms > 0 && (infoIt->componentId == hyperion::COMP_EFFECT || infoIt->componentId == hyperion::COMP_COLOR))
|
||||||
{
|
|
||||||
emit signalTimeTrigger(); // as signal to prevent Threading issues
|
emit signalTimeTrigger(); // as signal to prevent Threading issues
|
||||||
}
|
|
||||||
++infoIt;
|
++infoIt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file alias="hyperion-icon.png">hyperion-icon_32px.png</file>
|
|
||||||
<file alias="hyperion-schema">hyperion.schema.json</file>
|
<file alias="hyperion-schema">hyperion.schema.json</file>
|
||||||
<file alias="hyperion_default.config">../../config/hyperion.config.json.default</file>
|
<file alias="hyperion_default.config">../../config/hyperion.config.json.default</file>
|
||||||
<file alias="schema-general.json">schema/schema-general.json</file>
|
<file alias="schema-general.json">schema/schema-general.json</file>
|
||||||
|
@ -171,7 +171,7 @@ int LedDeviceAurora::write(const std::vector<ColorRgb> & ledValues)
|
|||||||
udpbuffer[i++] = panelCount;
|
udpbuffer[i++] = panelCount;
|
||||||
for (const ColorRgb& color : ledValues)
|
for (const ColorRgb& color : ledValues)
|
||||||
{
|
{
|
||||||
if (i<udpBufferSize) {
|
if ((unsigned)i < udpBufferSize) {
|
||||||
udpbuffer[i++] = panelIds[panelCounter++ % panelCount];
|
udpbuffer[i++] = panelIds[panelCounter++ % panelCount];
|
||||||
udpbuffer[i++] = 1; // No of Frames
|
udpbuffer[i++] = 1; // No of Frames
|
||||||
udpbuffer[i++] = color.red;
|
udpbuffer[i++] = color.red;
|
||||||
@ -180,7 +180,7 @@ int LedDeviceAurora::write(const std::vector<ColorRgb> & ledValues)
|
|||||||
udpbuffer[i++] = 0; // W not set manually
|
udpbuffer[i++] = 0; // W not set manually
|
||||||
udpbuffer[i++] = 1; // currently fixed at value 1 which corresponds to 100ms
|
udpbuffer[i++] = 1; // currently fixed at value 1 which corresponds to 100ms
|
||||||
}
|
}
|
||||||
if(panelCounter > panelCount) {
|
if((unsigned)panelCounter > panelCount) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//printf ("c.red %d sz c.red %d\n", color.red, sizeof(color.red));
|
//printf ("c.red %d sz c.red %d\n", color.red, sizeof(color.red));
|
||||||
|
@ -88,7 +88,7 @@ const QString SSDPDiscover::getFirstService(const searchType& type, const QStrin
|
|||||||
//Info(_log, "Received msearch response from '%s:%d'. Search target: %s",QSTRING_CSTR(sender.toString()), senderPort, QSTRING_CSTR(headers.value("st")));
|
//Info(_log, "Received msearch response from '%s:%d'. Search target: %s",QSTRING_CSTR(sender.toString()), senderPort, QSTRING_CSTR(headers.value("st")));
|
||||||
if(type == STY_WEBSERVER)
|
if(type == STY_WEBSERVER)
|
||||||
{
|
{
|
||||||
Info(_log, "Found Hyperion server at: %s:%d", QSTRING_CSTR(url.host()), url.port());
|
Info(_log, "Found Hyperion server at: %s:%s", QSTRING_CSTR(url.host()), url.port());
|
||||||
|
|
||||||
return url.host()+":"+QString::number(url.port());
|
return url.host()+":"+QString::number(url.port());
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ const QString SSDPDiscover::getFirstService(const searchType& type, const QStrin
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Info(_log, "Found Hyperion server at: %s:%d", QSTRING_CSTR(url.host()), fbsport);
|
Info(_log, "Found Hyperion server at: %s:%s", QSTRING_CSTR(url.host()), QSTRING_CSTR(fbsport));
|
||||||
return url.host()+":"+fbsport;
|
return url.host()+":"+fbsport;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
#include "QtHttpServer.h"
|
#include "QtHttpServer.h"
|
||||||
#include "QtHttpRequest.h"
|
#include "QtHttpRequest.h"
|
||||||
#include "QtHttpReply.h"
|
#include "QtHttpReply.h"
|
||||||
@ -11,24 +10,25 @@ const QString & QtHttpServer::HTTP_VERSION = QStringLiteral ("HTTP/1.1");
|
|||||||
QtHttpServerWrapper::QtHttpServerWrapper (QObject * parent)
|
QtHttpServerWrapper::QtHttpServerWrapper (QObject * parent)
|
||||||
: QTcpServer (parent)
|
: QTcpServer (parent)
|
||||||
, m_useSsl (false)
|
, m_useSsl (false)
|
||||||
{ }
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QtHttpServerWrapper::~QtHttpServerWrapper (void) { }
|
QtHttpServerWrapper::~QtHttpServerWrapper (void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void QtHttpServerWrapper::setUseSecure (const bool ssl) {
|
void QtHttpServerWrapper::setUseSecure (const bool ssl) {
|
||||||
m_useSsl = ssl;
|
m_useSsl = ssl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServerWrapper::incomingConnection (qintptr handle) {
|
void QtHttpServerWrapper::incomingConnection (qintptr handle)
|
||||||
|
{
|
||||||
QTcpSocket * sock = (m_useSsl
|
QTcpSocket * sock = (m_useSsl
|
||||||
? new QSslSocket (this)
|
? new QSslSocket (this)
|
||||||
: new QTcpSocket (this));
|
: new QTcpSocket (this));
|
||||||
if (sock->setSocketDescriptor (handle)) {
|
(sock->setSocketDescriptor (handle))
|
||||||
addPendingConnection (sock);
|
? addPendingConnection (sock)
|
||||||
}
|
: delete sock;
|
||||||
else {
|
|
||||||
delete sock;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QtHttpServer::QtHttpServer (QObject * parent)
|
QtHttpServer::QtHttpServer (QObject * parent)
|
||||||
@ -40,60 +40,78 @@ QtHttpServer::QtHttpServer (QObject * parent)
|
|||||||
connect (m_sockServer, &QtHttpServerWrapper::newConnection, this, &QtHttpServer::onClientConnected);
|
connect (m_sockServer, &QtHttpServerWrapper::newConnection, this, &QtHttpServer::onClientConnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString & QtHttpServer::getServerName (void) const {
|
const QString & QtHttpServer::getServerName (void) const
|
||||||
|
{
|
||||||
return m_serverName;
|
return m_serverName;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint16 QtHttpServer::getServerPort (void) const {
|
quint16 QtHttpServer::getServerPort (void) const
|
||||||
|
{
|
||||||
return m_sockServer->serverPort ();
|
return m_sockServer->serverPort ();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QtHttpServer::getErrorString (void) const {
|
QString QtHttpServer::getErrorString (void) const
|
||||||
|
{
|
||||||
return m_sockServer->errorString ();
|
return m_sockServer->errorString ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::start (quint16 port) {
|
void QtHttpServer::start (quint16 port)
|
||||||
if(!m_sockServer->isListening())
|
|
||||||
{
|
{
|
||||||
if (m_sockServer->listen (QHostAddress::Any, port)) {
|
if(!m_sockServer->isListening())
|
||||||
emit started (m_sockServer->serverPort ());
|
(m_sockServer->listen (QHostAddress::Any, port))
|
||||||
}
|
? emit started (m_sockServer->serverPort ())
|
||||||
else {
|
: emit error (m_sockServer->errorString ());
|
||||||
emit error (m_sockServer->errorString ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::stop (void) {
|
void QtHttpServer::stop (void)
|
||||||
if (m_sockServer->isListening ()) {
|
{
|
||||||
|
if (m_sockServer->isListening ())
|
||||||
|
{
|
||||||
m_sockServer->close ();
|
m_sockServer->close ();
|
||||||
|
|
||||||
|
// disconnect clients
|
||||||
|
const QList<QTcpSocket*> socks = m_socksClientsHash.keys();
|
||||||
|
for(auto sock : socks)
|
||||||
|
{
|
||||||
|
sock->close();
|
||||||
|
}
|
||||||
|
|
||||||
emit stopped ();
|
emit stopped ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::setServerName (const QString & serverName) {
|
void QtHttpServer::setServerName (const QString & serverName)
|
||||||
|
{
|
||||||
m_serverName = serverName;
|
m_serverName = serverName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::setUseSecure (const bool ssl) {
|
void QtHttpServer::setUseSecure (const bool ssl)
|
||||||
|
{
|
||||||
m_useSsl = ssl;
|
m_useSsl = ssl;
|
||||||
m_sockServer->setUseSecure (m_useSsl);
|
m_sockServer->setUseSecure (m_useSsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::setPrivateKey (const QSslKey & key) {
|
void QtHttpServer::setPrivateKey (const QSslKey & key)
|
||||||
|
{
|
||||||
m_sslKey = key;
|
m_sslKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::setCertificates (const QList<QSslCertificate> & certs) {
|
void QtHttpServer::setCertificates (const QList<QSslCertificate> & certs)
|
||||||
|
{
|
||||||
m_sslCerts = certs;
|
m_sslCerts = certs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::onClientConnected (void) {
|
void QtHttpServer::onClientConnected (void)
|
||||||
while (m_sockServer->hasPendingConnections ()) {
|
{
|
||||||
if (QTcpSocket * sock = m_sockServer->nextPendingConnection ()) {
|
while (m_sockServer->hasPendingConnections ())
|
||||||
|
{
|
||||||
|
if (QTcpSocket * sock = m_sockServer->nextPendingConnection ())
|
||||||
|
{
|
||||||
connect (sock, &QTcpSocket::disconnected, this, &QtHttpServer::onClientDisconnected);
|
connect (sock, &QTcpSocket::disconnected, this, &QtHttpServer::onClientDisconnected);
|
||||||
if (m_useSsl) {
|
if (m_useSsl)
|
||||||
if (QSslSocket * ssl = qobject_cast<QSslSocket *> (sock)) {
|
{
|
||||||
|
if (QSslSocket * ssl = qobject_cast<QSslSocket *> (sock))
|
||||||
|
{
|
||||||
connect (ssl, SslErrorSignal (&QSslSocket::sslErrors), this, &QtHttpServer::onClientSslErrors);
|
connect (ssl, SslErrorSignal (&QSslSocket::sslErrors), this, &QtHttpServer::onClientSslErrors);
|
||||||
connect (ssl, &QSslSocket::encrypted, this, &QtHttpServer::onClientSslEncrypted);
|
connect (ssl, &QSslSocket::encrypted, this, &QtHttpServer::onClientSslEncrypted);
|
||||||
connect (ssl, &QSslSocket::peerVerifyError, this, &QtHttpServer::onClientSslPeerVerifyError);
|
connect (ssl, &QSslSocket::peerVerifyError, this, &QtHttpServer::onClientSslPeerVerifyError);
|
||||||
@ -111,23 +129,31 @@ void QtHttpServer::onClientConnected (void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::onClientSslEncrypted (void) { }
|
void QtHttpServer::onClientSslEncrypted (void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void QtHttpServer::onClientSslPeerVerifyError (const QSslError & err) {
|
void QtHttpServer::onClientSslPeerVerifyError (const QSslError & err)
|
||||||
|
{
|
||||||
Q_UNUSED (err)
|
Q_UNUSED (err)
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::onClientSslErrors (const QList<QSslError> & errors) {
|
void QtHttpServer::onClientSslErrors (const QList<QSslError> & errors)
|
||||||
|
{
|
||||||
Q_UNUSED (errors)
|
Q_UNUSED (errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::onClientSslModeChanged (QSslSocket::SslMode mode) {
|
void QtHttpServer::onClientSslModeChanged (QSslSocket::SslMode mode)
|
||||||
|
{
|
||||||
Q_UNUSED (mode)
|
Q_UNUSED (mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtHttpServer::onClientDisconnected (void) {
|
void QtHttpServer::onClientDisconnected (void)
|
||||||
if (QTcpSocket * sockClient = qobject_cast<QTcpSocket *> (sender ())) {
|
{
|
||||||
if (QtHttpClientWrapper * wrapper = m_socksClientsHash.value (sockClient, Q_NULLPTR)) {
|
if (QTcpSocket * sockClient = qobject_cast<QTcpSocket *> (sender ()))
|
||||||
|
{
|
||||||
|
if (QtHttpClientWrapper * wrapper = m_socksClientsHash.value (sockClient, Q_NULLPTR))
|
||||||
|
{
|
||||||
emit clientDisconnected (wrapper->getGuid ());
|
emit clientDisconnected (wrapper->getGuid ());
|
||||||
wrapper->deleteLater ();
|
wrapper->deleteLater ();
|
||||||
m_socksClientsHash.remove (sockClient);
|
m_socksClientsHash.remove (sockClient);
|
||||||
|
@ -18,7 +18,6 @@ WebServer::WebServer(const QJsonDocument& config, QObject * parent)
|
|||||||
, _log(Logger::getInstance("WEBSERVER"))
|
, _log(Logger::getInstance("WEBSERVER"))
|
||||||
, _server()
|
, _server()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebServer::~WebServer()
|
WebServer::~WebServer()
|
||||||
|
@ -227,8 +227,8 @@ void WebSocketClient::sendClose(int status, QString reason)
|
|||||||
|
|
||||||
void WebSocketClient::handleBinaryMessage(QByteArray &data)
|
void WebSocketClient::handleBinaryMessage(QByteArray &data)
|
||||||
{
|
{
|
||||||
uint8_t priority = data.at(0);
|
//uint8_t priority = data.at(0);
|
||||||
unsigned duration_s = data.at(1);
|
//unsigned duration_s = data.at(1);
|
||||||
unsigned imgSize = data.size() - 4;
|
unsigned imgSize = data.size() - 4;
|
||||||
unsigned width = ((data.at(2) << 8) & 0xFF00) | (data.at(3) & 0xFF);
|
unsigned width = ((data.at(2) << 8) & 0xFF00) | (data.at(3) & 0xFF);
|
||||||
unsigned height = imgSize / width;
|
unsigned height = imgSize / width;
|
||||||
@ -244,7 +244,7 @@ void WebSocketClient::handleBinaryMessage(QByteArray &data)
|
|||||||
|
|
||||||
memcpy(image.memptr(), data.data()+4, imgSize);
|
memcpy(image.memptr(), data.data()+4, imgSize);
|
||||||
//_hyperion->registerInput();
|
//_hyperion->registerInput();
|
||||||
_hyperion->setInputImage(priority, image, duration_s*1000);
|
//_hyperion->setInputImage(priority, image, duration_s*1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 WebSocketClient::sendMessage(QJsonObject obj)
|
qint64 WebSocketClient::sendMessage(QJsonObject obj)
|
||||||
|
22
resources/CMakeLists.txt
Normal file
22
resources/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Global resource file to embed static data into code, available as static lib 'resources'. File names needs to be unique in the /resources directory and below.
|
||||||
|
# All files are available with their file name by calling ":/FILENAME". Probably you need to call Q_INIT_RESOURCE("resources") once
|
||||||
|
#
|
||||||
|
# Define the current source locations
|
||||||
|
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/resources)
|
||||||
|
|
||||||
|
# catch all files
|
||||||
|
FILE ( GLOB Hyperion_RESFILES "${CURRENT_SOURCE_DIR}/icons/*" )
|
||||||
|
|
||||||
|
# fill resources.qrc with RESFILES
|
||||||
|
FOREACH( f ${Hyperion_RESFILES} )
|
||||||
|
get_filename_component(fname ${f} NAME)
|
||||||
|
SET(HYPERION_RES "${HYPERION_RES}\n\t\t<file alias=\"${fname}\">${f}</file>")
|
||||||
|
ENDFOREACH()
|
||||||
|
|
||||||
|
# prep file
|
||||||
|
CONFIGURE_FILE(${CURRENT_SOURCE_DIR}/resources.qrc.in ${CMAKE_BINARY_DIR}/resources.qrc )
|
||||||
|
SET(Hyperion_RES ${CMAKE_BINARY_DIR}/resources.qrc)
|
||||||
|
|
||||||
|
add_library(resources
|
||||||
|
${Hyperion_RES}
|
||||||
|
)
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
5
resources/resources.qrc.in
Normal file
5
resources/resources.qrc.in
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
${HYPERION_RES}
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
@ -1,7 +1,7 @@
|
|||||||
add_subdirectory(hyperiond)
|
add_subdirectory(hyperiond)
|
||||||
add_subdirectory(hyperion-remote)
|
add_subdirectory(hyperion-remote)
|
||||||
|
|
||||||
# The following clients depend on the protobuf library
|
# The following binaries are just compiled if requested
|
||||||
if (ENABLE_AMLOGIC)
|
if (ENABLE_AMLOGIC)
|
||||||
add_subdirectory(hyperion-aml)
|
add_subdirectory(hyperion-aml)
|
||||||
endif()
|
endif()
|
||||||
|
@ -23,9 +23,7 @@ add_executable(${PROJECT_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
effectengine
|
|
||||||
commandline
|
commandline
|
||||||
blackborder
|
|
||||||
hyperion-utils
|
hyperion-utils
|
||||||
flatbufserver
|
flatbufserver
|
||||||
flatbuffers
|
flatbuffers
|
||||||
|
@ -37,7 +37,7 @@ int main(int argc, char ** argv)
|
|||||||
// create the option parser and initialize all parser
|
// create the option parser and initialize all parser
|
||||||
Parser parser("AmLogic capture application for Hyperion. Will automatically search a Hyperion server if -a option isn't used. Please note that if you have more than one server running it's more or less random which one will be used.");
|
Parser parser("AmLogic capture application for Hyperion. Will automatically search a Hyperion server if -a option isn't used. Please note that if you have more than one server running it's more or less random which one will be used.");
|
||||||
|
|
||||||
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10");
|
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10", 1, 25);
|
||||||
IntOption & argWidth = parser.add<IntOption> (0x0, "width", "Width of the captured image [default: %1]", "160", 160, 4096);
|
IntOption & argWidth = parser.add<IntOption> (0x0, "width", "Width of the captured image [default: %1]", "160", 160, 4096);
|
||||||
IntOption & argHeight = parser.add<IntOption> (0x0, "height", "Height of the captured image [default: %1]", "160", 160, 4096);
|
IntOption & argHeight = parser.add<IntOption> (0x0, "height", "Height of the captured image [default: %1]", "160", 160, 4096);
|
||||||
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
||||||
|
@ -30,9 +30,7 @@ add_executable( ${PROJECT_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries( ${PROJECT_NAME}
|
target_link_libraries( ${PROJECT_NAME}
|
||||||
effectengine
|
|
||||||
commandline
|
commandline
|
||||||
blackborder
|
|
||||||
hyperion-utils
|
hyperion-utils
|
||||||
flatbufserver
|
flatbufserver
|
||||||
flatbuffers
|
flatbuffers
|
||||||
|
@ -36,9 +36,9 @@ int main(int argc, char ** argv)
|
|||||||
// create the option parser and initialize all parameters
|
// create the option parser and initialize all parameters
|
||||||
Parser parser("Dispmanx capture application for Hyperion. Will automatically search a Hyperion server if -a option isn't used. Please note that if you have more than one server running it's more or less random which one will be used.");
|
Parser parser("Dispmanx capture application for Hyperion. Will automatically search a Hyperion server if -a option isn't used. Please note that if you have more than one server running it's more or less random which one will be used.");
|
||||||
|
|
||||||
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10");
|
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10", 1, 25);
|
||||||
IntOption & argWidth = parser.add<IntOption> (0x0, "width", "Width of the captured image [default: %1]", "64", 32, 4096);
|
IntOption & argWidth = parser.add<IntOption> (0x0, "width", "Width of the captured image [default: %1]", "64", 64);
|
||||||
IntOption & argHeight = parser.add<IntOption> (0x0, "height", "Height of the captured image [default: %1]", "64", 32, 4096);
|
IntOption & argHeight = parser.add<IntOption> (0x0, "height", "Height of the captured image [default: %1]", "64", 64);
|
||||||
|
|
||||||
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
||||||
Option & argAddress = parser.add<Option> ('a', "address", "Set the address of the hyperion server [default: %1]", "127.0.0.1:19445");
|
Option & argAddress = parser.add<Option> ('a', "address", "Set the address of the hyperion server [default: %1]", "127.0.0.1:19445");
|
||||||
|
@ -23,9 +23,7 @@ add_executable( ${PROJECT_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries( ${PROJECT_NAME}
|
target_link_libraries( ${PROJECT_NAME}
|
||||||
effectengine
|
|
||||||
commandline
|
commandline
|
||||||
blackborder
|
|
||||||
hyperion-utils
|
hyperion-utils
|
||||||
flatbufserver
|
flatbufserver
|
||||||
flatbuffers
|
flatbuffers
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
// QT includes
|
// QT includes
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
@ -31,9 +29,9 @@ int main(int argc, char ** argv)
|
|||||||
Parser parser("FrameBuffer capture application for Hyperion. Will automatically search a Hyperion server if -a option isn't used. Please note that if you have more than one server running it's more or less random which one will be used.");
|
Parser parser("FrameBuffer capture application for Hyperion. Will automatically search a Hyperion server if -a option isn't used. Please note that if you have more than one server running it's more or less random which one will be used.");
|
||||||
|
|
||||||
Option & argDevice = parser.add<Option> ('d', "device", "Set the video device [default: %1]", "/dev/video0");
|
Option & argDevice = parser.add<Option> ('d', "device", "Set the video device [default: %1]", "/dev/video0");
|
||||||
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10");
|
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10", 1, 25);
|
||||||
IntOption & argWidth = parser.add<IntOption> (0x0, "width", "Width of the captured image [default: %1]", "160", 160, 4096);
|
IntOption & argWidth = parser.add<IntOption> (0x0, "width", "Width of the captured image [default: %1]", "160", 160);
|
||||||
IntOption & argHeight = parser.add<IntOption> (0x0, "height", "Height of the captured image [default: %1]", "160", 160, 4096);
|
IntOption & argHeight = parser.add<IntOption> (0x0, "height", "Height of the captured image [default: %1]", "160", 160);
|
||||||
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
||||||
Option & argAddress = parser.add<Option> ('a', "address", "Set the address of the hyperion server [default: %1]", "127.0.0.1:19445");
|
Option & argAddress = parser.add<Option> ('a', "address", "Set the address of the hyperion server [default: %1]", "127.0.0.1:19445");
|
||||||
IntOption & argPriority = parser.add<IntOption> ('p', "priority", "Use the provided priority channel (suggested 100-199) [default: %1]", "150");
|
IntOption & argPriority = parser.add<IntOption> ('p', "priority", "Use the provided priority channel (suggested 100-199) [default: %1]", "150");
|
||||||
|
@ -23,9 +23,7 @@ add_executable( ${PROJECT_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries( ${PROJECT_NAME}
|
target_link_libraries( ${PROJECT_NAME}
|
||||||
effectengine
|
|
||||||
commandline
|
commandline
|
||||||
blackborder
|
|
||||||
hyperion-utils
|
hyperion-utils
|
||||||
flatbufserver
|
flatbufserver
|
||||||
flatbuffers
|
flatbuffers
|
||||||
|
@ -30,10 +30,10 @@ int main(int argc, char ** argv)
|
|||||||
// create the option parser and initialize all parameters
|
// create the option parser and initialize all parameters
|
||||||
Parser parser("OSX capture application for Hyperion. Will automatically search a Hyperion server if -a option isn't used. Please note that if you have more than one server running it's more or less random which one will be used.");
|
Parser parser("OSX capture application for Hyperion. Will automatically search a Hyperion server if -a option isn't used. Please note that if you have more than one server running it's more or less random which one will be used.");
|
||||||
|
|
||||||
Option & argDisplay = parser.add<Option> ('d', "display", "Set the display to capture [default: %1]");
|
Option & argDisplay = parser.add<Option> ('d', "display", "Set the display to capture [default: %1]", "0");
|
||||||
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10", 1, 600);
|
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10", 1, 25);
|
||||||
IntOption & argWidth = parser.add<IntOption> (0x0, "width", "Width of the captured image [default: %1]", "160", 160, 4096);
|
IntOption & argWidth = parser.add<IntOption> (0x0, "width", "Width of the captured image [default: %1]", "160", 160);
|
||||||
IntOption & argHeight = parser.add<IntOption> (0x0, "height", "Height of the captured image [default: %1]", "160", 160, 4096);
|
IntOption & argHeight = parser.add<IntOption> (0x0, "height", "Height of the captured image [default: %1]", "160", 160);
|
||||||
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
||||||
Option & argAddress = parser.add<Option> ('a', "address", "Set the address of the hyperion server [default: %1]", "127.0.0.1:19445");
|
Option & argAddress = parser.add<Option> ('a', "address", "Set the address of the hyperion server [default: %1]", "127.0.0.1:19445");
|
||||||
IntOption & argPriority = parser.add<IntOption> ('p', "priority", "Use the provided priority channel (suggested 100-199) [default: %1]", "150");
|
IntOption & argPriority = parser.add<IntOption> ('p', "priority", "Use the provided priority channel (suggested 100-199) [default: %1]", "150");
|
||||||
|
@ -23,10 +23,8 @@ add_executable(${PROJECT_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
effectengine
|
|
||||||
v4l2-grabber
|
v4l2-grabber
|
||||||
commandline
|
commandline
|
||||||
blackborder
|
|
||||||
hyperion-utils
|
hyperion-utils
|
||||||
flatbufserver
|
flatbufserver
|
||||||
flatbuffers
|
flatbuffers
|
||||||
|
@ -67,7 +67,7 @@ int main(int argc, char** argv)
|
|||||||
IntOption & argCropRight = parser.add<IntOption> (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)");
|
IntOption & argCropRight = parser.add<IntOption> (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)");
|
||||||
IntOption & argCropTop = parser.add<IntOption> (0x0, "crop-top", "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)");
|
IntOption & argCropTop = parser.add<IntOption> (0x0, "crop-top", "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)");
|
||||||
IntOption & argCropBottom = parser.add<IntOption> (0x0, "crop-bottom", "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)");
|
IntOption & argCropBottom = parser.add<IntOption> (0x0, "crop-bottom", "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)");
|
||||||
IntOption & argSizeDecimation = parser.add<IntOption> ('s', "size-decimator", "Decimation factor for the output size [default=%1]", "1");
|
IntOption & argSizeDecimation = parser.add<IntOption> ('s', "size-decimator", "Decimation factor for the output size [default=%1]", "6", 1);
|
||||||
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
||||||
|
|
||||||
BooleanOption & argSignalDetection = parser.add<BooleanOption>('s', "signal-detection-disabled", "disable signal detection");
|
BooleanOption & argSignalDetection = parser.add<BooleanOption>('s', "signal-detection-disabled", "disable signal detection");
|
||||||
|
@ -25,8 +25,6 @@ add_executable(${PROJECT_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
effectengine
|
|
||||||
blackborder
|
|
||||||
commandline
|
commandline
|
||||||
hyperion-utils
|
hyperion-utils
|
||||||
flatbufserver
|
flatbufserver
|
||||||
|
@ -42,7 +42,7 @@ int main(int argc, char ** argv)
|
|||||||
IntOption & argCropRight = parser.add<IntOption> (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)");
|
IntOption & argCropRight = parser.add<IntOption> (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)");
|
||||||
IntOption & argCropTop = parser.add<IntOption> (0x0, "crop-top", "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)");
|
IntOption & argCropTop = parser.add<IntOption> (0x0, "crop-top", "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)");
|
||||||
IntOption & argCropBottom = parser.add<IntOption> (0x0, "crop-bottom", "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)");
|
IntOption & argCropBottom = parser.add<IntOption> (0x0, "crop-bottom", "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)");
|
||||||
IntOption & argSizeDecimation = parser.add<IntOption> ('s', "size-decimator", "Decimation factor for the output size [default=%1]", "8");
|
IntOption & argSizeDecimation = parser.add<IntOption> ('s', "size-decimator", "Decimation factor for the output size [default=%1]", "8", 1);
|
||||||
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
BooleanOption & argScreenshot = parser.add<BooleanOption>(0x0, "screenshot", "Take a single screenshot, save it to file and quit");
|
||||||
Option & argAddress = parser.add<Option> ('a', "address", "Set the address of the hyperion server [default: %1]", "127.0.0.1:19445");
|
Option & argAddress = parser.add<Option> ('a', "address", "Set the address of the hyperion server [default: %1]", "127.0.0.1:19445");
|
||||||
IntOption & argPriority = parser.add<IntOption> ('p', "priority", "Use the provided priority channel (suggested 100-199) [default: %1]", "150");
|
IntOption & argPriority = parser.add<IntOption> ('p', "priority", "Use the provided priority channel (suggested 100-199) [default: %1]", "150");
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
find_package(PythonLibs 3.5 REQUIRED)
|
find_package(PythonLibs 3.5 REQUIRED)
|
||||||
include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..)
|
include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..)
|
||||||
|
|
||||||
@ -21,6 +20,7 @@ target_link_libraries(hyperiond
|
|||||||
bonjour
|
bonjour
|
||||||
ssdp
|
ssdp
|
||||||
python
|
python
|
||||||
|
resources
|
||||||
${PYTHON_LIBRARIES}
|
${PYTHON_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -60,6 +60,7 @@ qt5_use_modules(hyperiond Core Gui Network Widgets)
|
|||||||
install ( TARGETS hyperiond DESTINATION "share/hyperion/bin/" COMPONENT "${PLATFORM}" )
|
install ( TARGETS hyperiond DESTINATION "share/hyperion/bin/" COMPONENT "${PLATFORM}" )
|
||||||
install ( DIRECTORY ${CMAKE_SOURCE_DIR}/bin/service DESTINATION "share/hyperion/" COMPONENT "${PLATFORM}" )
|
install ( DIRECTORY ${CMAKE_SOURCE_DIR}/bin/service DESTINATION "share/hyperion/" COMPONENT "${PLATFORM}" )
|
||||||
install ( FILES ${CMAKE_SOURCE_DIR}/effects/readme.txt DESTINATION "share/hyperion/effects" COMPONENT "${PLATFORM}" )
|
install ( FILES ${CMAKE_SOURCE_DIR}/effects/readme.txt DESTINATION "share/hyperion/effects" COMPONENT "${PLATFORM}" )
|
||||||
|
install ( FILES ${CMAKE_SOURCE_DIR}/resources/icons/hyperion-icon-32px.png DESTINATION "share/hyperion/icons" COMPONENT "${PLATFORM}" )
|
||||||
|
|
||||||
if(CMAKE_HOST_UNIX)
|
if(CMAKE_HOST_UNIX)
|
||||||
install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/hyperiond\" \"${CMAKE_BINARY_DIR}/symlink_hyperiond\" )" COMPONENT "${PLATFORM}" )
|
install(CODE "EXECUTE_PROCESS(COMMAND ln -sf \"../share/hyperion/bin/hyperiond\" \"${CMAKE_BINARY_DIR}/symlink_hyperiond\" )" COMPONENT "${PLATFORM}" )
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include <QResource>
|
#include <QResource>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QHostAddress>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
@ -42,6 +41,9 @@
|
|||||||
// Init Python
|
// Init Python
|
||||||
#include <python/PythonInit.h>
|
#include <python/PythonInit.h>
|
||||||
|
|
||||||
|
// EffectFileHandler
|
||||||
|
#include <effectengine/EffectFileHandler.h>
|
||||||
|
|
||||||
HyperionDaemon* HyperionDaemon::daemon = nullptr;
|
HyperionDaemon* HyperionDaemon::daemon = nullptr;
|
||||||
|
|
||||||
HyperionDaemon::HyperionDaemon(QString configFile, const QString rootPath, QObject *parent, const bool& logLvlOverwrite)
|
HyperionDaemon::HyperionDaemon(QString configFile, const QString rootPath, QObject *parent, const bool& logLvlOverwrite)
|
||||||
@ -79,6 +81,10 @@ HyperionDaemon::HyperionDaemon(QString configFile, const QString rootPath, QObje
|
|||||||
if(!logLvlOverwrite)
|
if(!logLvlOverwrite)
|
||||||
handleSettingsUpdate(settings::LOGGER, _settingsManager->getSetting(settings::LOGGER));
|
handleSettingsUpdate(settings::LOGGER, _settingsManager->getSetting(settings::LOGGER));
|
||||||
|
|
||||||
|
// init EffectFileHandler
|
||||||
|
EffectFileHandler* efh = new EffectFileHandler(rootPath, _settingsManager->getSetting(settings::EFFECTS), this);
|
||||||
|
connect(this, &HyperionDaemon::settingsChanged, efh, &EffectFileHandler::handleSettingsUpdate);
|
||||||
|
|
||||||
// spawn all Hyperion instances before network services
|
// spawn all Hyperion instances before network services
|
||||||
_hyperion = Hyperion::initInstance(this, 0, configFile, rootPath);
|
_hyperion = Hyperion::initInstance(this, 0, configFile, rootPath);
|
||||||
|
|
||||||
@ -201,7 +207,7 @@ void HyperionDaemon::startNetworkServices()
|
|||||||
connect(this, &HyperionDaemon::settingsChanged, _webserver, &WebServer::handleSettingsUpdate);
|
connect(this, &HyperionDaemon::settingsChanged, _webserver, &WebServer::handleSettingsUpdate);
|
||||||
wsThread->start();
|
wsThread->start();
|
||||||
|
|
||||||
// create SSDPHandler in thread
|
// create ssdp server in thread
|
||||||
_ssdp = new SSDPHandler(_webserver, getSetting(settings::FLATBUFSERVER).object()["port"].toInt());
|
_ssdp = new SSDPHandler(_webserver, getSetting(settings::FLATBUFSERVER).object()["port"].toInt());
|
||||||
QThread* ssdpThread = new QThread(this);
|
QThread* ssdpThread = new QThread(this);
|
||||||
_ssdp->moveToThread(ssdpThread);
|
_ssdp->moveToThread(ssdpThread);
|
||||||
@ -268,15 +274,72 @@ void HyperionDaemon::handleSettingsUpdate(const settings::type& type, const QJso
|
|||||||
{
|
{
|
||||||
type = "framebuffer";
|
type = "framebuffer";
|
||||||
}
|
}
|
||||||
Info( _log, "set screen capture device to '%s'", QSTRING_CSTR(type));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == "") { Info( _log, "screen capture device disabled"); }
|
if(_prevType != type)
|
||||||
else if (type == "framebuffer" && _fbGrabber == nullptr) createGrabberFramebuffer(grabberConfig);
|
{
|
||||||
else if (type == "dispmanx" && _dispmanx == nullptr) createGrabberDispmanx();
|
Info( _log, "set screen capture device to '%s'", QSTRING_CSTR(type));
|
||||||
else if (type == "amlogic" && _amlGrabber == nullptr) createGrabberAmlogic();
|
|
||||||
else if (type == "osx" && _osxGrabber == nullptr) createGrabberOsx(grabberConfig);
|
// stop all capture interfaces
|
||||||
else if (type == "x11" && _x11Grabber == nullptr) createGrabberX11(grabberConfig);
|
#ifdef ENABLE_FB
|
||||||
|
if(_fbGrabber != nullptr) _fbGrabber->stop();
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_DISPMANX
|
||||||
|
if(_dispmanx != nullptr) _dispmanx->stop();
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_AMLOGIC
|
||||||
|
if(_amlGrabber != nullptr) _amlGrabber->stop();
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_OSX
|
||||||
|
if(_osxGrabber != nullptr) _osxGrabber->stop();
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_X11
|
||||||
|
if(_x11Grabber != nullptr) _x11Grabber->stop();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// create/start capture interface
|
||||||
|
if(type == "framebuffer")
|
||||||
|
{
|
||||||
|
if(_fbGrabber == nullptr)
|
||||||
|
createGrabberFramebuffer(grabberConfig);
|
||||||
|
#ifdef ENABLE_FB
|
||||||
|
_fbGrabber->start();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(type == "dispmanx")
|
||||||
|
{
|
||||||
|
if(_dispmanx == nullptr)
|
||||||
|
createGrabberDispmanx();
|
||||||
|
#ifdef ENABLE_DISPMANX
|
||||||
|
_dispmanx->start();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(type == "amlogic")
|
||||||
|
{
|
||||||
|
if(_amlGrabber == nullptr)
|
||||||
|
createGrabberAmlogic();
|
||||||
|
#ifdef ENABLE_AMLOGIC
|
||||||
|
_amlGrabber->start();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(type == "osx")
|
||||||
|
{
|
||||||
|
if(_osxGrabber == nullptr)
|
||||||
|
createGrabberOsx(grabberConfig);
|
||||||
|
#ifdef ENABLE_OSX
|
||||||
|
_osxGrabber->start();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(type == "x11")
|
||||||
|
{
|
||||||
|
if(_x11Grabber == nullptr)
|
||||||
|
createGrabberX11(grabberConfig);
|
||||||
|
#ifdef ENABLE_X11
|
||||||
|
_x11Grabber->start();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
_prevType = type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(type == settings::V4L2)
|
else if(type == settings::V4L2)
|
||||||
{
|
{
|
||||||
@ -341,7 +404,7 @@ void HyperionDaemon::createGrabberDispmanx()
|
|||||||
|
|
||||||
_dispmanx->start();
|
_dispmanx->start();
|
||||||
|
|
||||||
Info(_log, "DISPMANX frame grabber created and started");
|
Info(_log, "DISPMANX frame grabber created");
|
||||||
#else
|
#else
|
||||||
Error( _log, "The dispmanx framegrabber can not be instantiated, because it has been left out from the build");
|
Error( _log, "The dispmanx framegrabber can not be instantiated, because it has been left out from the build");
|
||||||
#endif
|
#endif
|
||||||
@ -360,7 +423,7 @@ void HyperionDaemon::createGrabberAmlogic()
|
|||||||
connect(this, &HyperionDaemon::settingsChanged, _amlGrabber, &AmlogicWrapper::handleSettingsUpdate);
|
connect(this, &HyperionDaemon::settingsChanged, _amlGrabber, &AmlogicWrapper::handleSettingsUpdate);
|
||||||
|
|
||||||
_amlGrabber->start();
|
_amlGrabber->start();
|
||||||
Info(_log, "AMLOGIC grabber created and started");
|
Info(_log, "AMLOGIC grabber created");
|
||||||
#else
|
#else
|
||||||
Error( _log, "The AMLOGIC grabber can not be instantiated, because it has been left out from the build");
|
Error( _log, "The AMLOGIC grabber can not be instantiated, because it has been left out from the build");
|
||||||
#endif
|
#endif
|
||||||
@ -381,7 +444,7 @@ void HyperionDaemon::createGrabberX11(const QJsonObject & grabberConfig)
|
|||||||
connect(this, &HyperionDaemon::settingsChanged, _x11Grabber, &X11Wrapper::handleSettingsUpdate);
|
connect(this, &HyperionDaemon::settingsChanged, _x11Grabber, &X11Wrapper::handleSettingsUpdate);
|
||||||
|
|
||||||
_x11Grabber->start();
|
_x11Grabber->start();
|
||||||
Info(_log, "X11 grabber created and started");
|
Info(_log, "X11 grabber created");
|
||||||
#else
|
#else
|
||||||
Error(_log, "The X11 grabber can not be instantiated, because it has been left out from the build");
|
Error(_log, "The X11 grabber can not be instantiated, because it has been left out from the build");
|
||||||
#endif
|
#endif
|
||||||
@ -402,7 +465,7 @@ void HyperionDaemon::createGrabberFramebuffer(const QJsonObject & grabberConfig)
|
|||||||
connect(this, &HyperionDaemon::settingsChanged, _fbGrabber, &FramebufferWrapper::handleSettingsUpdate);
|
connect(this, &HyperionDaemon::settingsChanged, _fbGrabber, &FramebufferWrapper::handleSettingsUpdate);
|
||||||
|
|
||||||
_fbGrabber->start();
|
_fbGrabber->start();
|
||||||
Info(_log, "Framebuffer grabber created and started");
|
Info(_log, "Framebuffer grabber created");
|
||||||
#else
|
#else
|
||||||
Error(_log, "The framebuffer grabber can not be instantiated, because it has been left out from the build");
|
Error(_log, "The framebuffer grabber can not be instantiated, because it has been left out from the build");
|
||||||
#endif
|
#endif
|
||||||
@ -423,7 +486,7 @@ void HyperionDaemon::createGrabberOsx(const QJsonObject & grabberConfig)
|
|||||||
connect(this, &HyperionDaemon::settingsChanged, _osxGrabber, &OsxWrapper::handleSettingsUpdate);
|
connect(this, &HyperionDaemon::settingsChanged, _osxGrabber, &OsxWrapper::handleSettingsUpdate);
|
||||||
|
|
||||||
_osxGrabber->start();
|
_osxGrabber->start();
|
||||||
Info(_log, "OSX grabber created and started");
|
Info(_log, "OSX grabber created");
|
||||||
#else
|
#else
|
||||||
Error(_log, "The osx grabber can not be instantiated, because it has been left out from the build");
|
Error(_log, "The osx grabber can not be instantiated, because it has been left out from the build");
|
||||||
#endif
|
#endif
|
||||||
|
@ -158,6 +158,8 @@ private:
|
|||||||
unsigned _grabber_cropTop;
|
unsigned _grabber_cropTop;
|
||||||
unsigned _grabber_cropBottom;
|
unsigned _grabber_cropBottom;
|
||||||
|
|
||||||
|
QString _prevType;
|
||||||
|
|
||||||
VideoMode _currVideoMode;
|
VideoMode _currVideoMode;
|
||||||
SettingsManager* _settingsManager;
|
SettingsManager* _settingsManager;
|
||||||
};
|
};
|
||||||
|
@ -104,6 +104,7 @@ QCoreApplication* createApplication(int &argc, char *argv[])
|
|||||||
{
|
{
|
||||||
QApplication* app = new QApplication(argc, argv);
|
QApplication* app = new QApplication(argc, argv);
|
||||||
app->setApplicationDisplayName("Hyperion");
|
app->setApplicationDisplayName("Hyperion");
|
||||||
|
app->setWindowIcon(QIcon(":/hyperion-icon-32px.png"));
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ SysTray::SysTray(HyperionDaemon *hyperiond)
|
|||||||
, _hyperion(nullptr)
|
, _hyperion(nullptr)
|
||||||
, _webPort(8090)
|
, _webPort(8090)
|
||||||
{
|
{
|
||||||
Q_INIT_RESOURCE(resource);
|
Q_INIT_RESOURCE(resources);
|
||||||
|
|
||||||
// webserver port
|
// webserver port
|
||||||
WebServer* webserver = _hyperiond->getWebServerInstance();
|
WebServer* webserver = _hyperiond->getWebServerInstance();
|
||||||
@ -33,7 +33,7 @@ SysTray::SysTray(HyperionDaemon *hyperiond)
|
|||||||
|
|
||||||
connect(_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
|
connect(_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
|
||||||
connect(&_colorDlg, SIGNAL(currentColorChanged(const QColor&)), this, SLOT(setColor(const QColor &)));
|
connect(&_colorDlg, SIGNAL(currentColorChanged(const QColor&)), this, SLOT(setColor(const QColor &)));
|
||||||
QIcon icon(":/hyperion-icon.png");
|
QIcon icon(":/hyperion-icon-32px.png");
|
||||||
_trayIcon->setIcon(icon);
|
_trayIcon->setIcon(icon);
|
||||||
_trayIcon->show();
|
_trayIcon->show();
|
||||||
setWindowIcon(icon);
|
setWindowIcon(icon);
|
||||||
|
Loading…
Reference in New Issue
Block a user