Merge remote-tracking branch 'remotes/origin/add_effect_engine' into add_effect_engine

Former-commit-id: cdff98227a21a63cdd2d3cddb8002e34f564f272
This commit is contained in:
T. van der Zwan 2013-12-11 22:07:04 +01:00
commit 6bd7f5d951
25 changed files with 1025 additions and 471 deletions

View File

@ -331,6 +331,11 @@
}
],
"effects" :
{
"paths" : ["/home/pi/hyperion/effects"]
},
/// The black border configuration, contains the following items:
/// * enable : true if the detector should be activated
"blackborderdetector" :
@ -338,12 +343,10 @@
"enable" : true
},
/// The boot-sequence configuration, contains the following items:
/// * type : The type of the boot-sequence ('rainbow', 'knightrider', 'none')
/// * duration_ms : The length of the boot-sequence [ms]
"bootsequence" :
{
"type" : "Rainbow",
"effect" : "rainbow-swirl-fast.json",
"path" : "/home/pi/hyperion/effects",
"duration_ms" : 3000
},

9
effects/knight-rider.json Executable file
View File

@ -0,0 +1,9 @@
{
"name" : "Knight rider",
"script" : "knight-rider.py",
"args" :
{
"speed" : 1.0,
"fadeFactor" : 0.7
}
}

View File

@ -3,8 +3,8 @@ import time
import colorsys
# Get the rotation time
speed = hyperion.args.get('speed', 1.0)
fadeFactor = hyperion.args.get('fadeFactor', 0.7)
speed = float(hyperion.args.get('speed', 1.0))
fadeFactor = float(hyperion.args.get('fadeFactor', 0.7))
# Check parameters
speed = max(0.0001, speed)

12
effects/mood-blobs-blue.json Executable file
View File

@ -0,0 +1,12 @@
{
"name" : "Blue mood blobs",
"script" : "mood-blobs.py",
"args" :
{
"rotationTime" : 60.0,
"color" : [0,0,255],
"hueChange" : 60.0,
"blobs" : 5,
"reverse" : false
}
}

12
effects/mood-blobs-green.json Executable file
View File

@ -0,0 +1,12 @@
{
"name" : "Green mood blobs",
"script" : "mood-blobs.py",
"args" :
{
"rotationTime" : 60.0,
"color" : [0,255,0],
"hueChange" : 60.0,
"blobs" : 5,
"reverse" : false
}
}

12
effects/mood-blobs-red.json Executable file
View File

@ -0,0 +1,12 @@
{
"name" : "Red mood blobs",
"script" : "mood-blobs.py",
"args" :
{
"rotationTime" : 60.0,
"color" : [255,0,0],
"hueChange" : 60.0,
"blobs" : 5,
"reverse" : false
}
}

61
effects/mood-blobs.py Normal file
View File

@ -0,0 +1,61 @@
import hyperion
import time
import colorsys
import math
# Get the parameters
rotationTime = float(hyperion.args.get('rotationTime', 20.0))
color = hyperion.args.get('color', (0,0,255))
hueChange = float(hyperion.args.get('hueChange', 60.0)) / 360.0
blobs = int(hyperion.args.get('blobs', 5))
reverse = bool(hyperion.args.get('reverse', False))
# Check parameters
rotationTime = max(0.1, rotationTime)
hueChange = max(0.0, min(abs(hueChange), .5))
blobs = max(1, blobs)
# Calculate the color data
baseHsv = colorsys.rgb_to_hsv(color[0]/255.0, color[1]/255.0, color[2]/255.0)
colorData = bytearray()
for i in range(hyperion.ledCount):
hue = (baseHsv[0] + hueChange * math.sin(2*math.pi * i / hyperion.ledCount)) % 1.0
rgb = colorsys.hsv_to_rgb(hue, baseHsv[1], baseHsv[2])
colorData += bytearray((int(255*rgb[0]), int(255*rgb[1]), int(255*rgb[2])))
# Calculate the increments
sleepTime = 0.1
amplitudePhaseIncrement = blobs * math.pi * sleepTime / rotationTime
colorDataIncrement = 3
# Switch direction if needed
if reverse:
amplitudePhaseIncrement = -amplitudePhaseIncrement
colorDataIncrement = -colorDataIncrement
# create a Array for the colors
colors = bytearray(hyperion.ledCount * (0,0,0))
# Start the write data loop
amplitudePhase = 0.0
rotateColors = False
while not hyperion.abort():
# Calculate new colors
for i in range(hyperion.ledCount):
amplitude = max(0.0, math.sin(-amplitudePhase + 2*math.pi * blobs * i / hyperion.ledCount))
colors[3*i+0] = int(colorData[3*i+0] * amplitude)
colors[3*i+1] = int(colorData[3*i+1] * amplitude)
colors[3*i+2] = int(colorData[3*i+2] * amplitude)
# set colors
hyperion.setColor(colors)
# increment the phase
amplitudePhase = (amplitudePhase + amplitudePhaseIncrement) % (2*math.pi)
if rotateColors:
colorData = colorData[-colorDataIncrement:] + colorData[:-colorDataIncrement]
rotateColors = not rotateColors
# sleep for a while
time.sleep(sleepTime)

10
effects/rainbow-mood.json Executable file
View File

@ -0,0 +1,10 @@
{
"name" : "Rainbow mood",
"script" : "rainbow-mood.py",
"args" :
{
"rotation-time" : 60.0,
"brightness" : 1.0,
"reverse" : false
}
}

View File

@ -3,10 +3,10 @@ import time
import colorsys
# Get the parameters
rotationTime = hyperion.args.get('rotation-time', 3.0)
brightness = hyperion.args.get('brightness', 1.0)
saturation = hyperion.args.get('saturation', 1.0)
reverse = hyperion.args.get('reverse', False)
rotationTime = float(hyperion.args.get('rotation-time', 30.0))
brightness = float(hyperion.args.get('brightness', 1.0))
saturation = float(hyperion.args.get('saturation', 1.0))
reverse = bool(hyperion.args.get('reverse', False))
# Check parameters
rotationTime = max(0.1, rotationTime)

10
effects/rainbow-swirl-fast.json Executable file
View File

@ -0,0 +1,10 @@
{
"name" : "Rainbow swirl fast",
"script" : "rainbow-swirl.py",
"args" :
{
"rotation-time" : 3.0,
"brightness" : 1.0,
"reverse" : false
}
}

10
effects/rainbow-swirl.json Executable file
View File

@ -0,0 +1,10 @@
{
"name" : "Rainbow swirl",
"script" : "rainbow-swirl.py",
"args" :
{
"rotation-time" : 20.0,
"brightness" : 1.0,
"reverse" : false
}
}

View File

@ -3,10 +3,10 @@ import time
import colorsys
# Get the parameters
rotationTime = hyperion.args.get('rotation-time', 3.0)
brightness = hyperion.args.get('brightness', 1.0)
saturation = hyperion.args.get('saturation', 1.0)
reverse = hyperion.args.get('reverse', False)
rotationTime = float(hyperion.args.get('rotation-time', 3.0))
brightness = float(hyperion.args.get('brightness', 1.0))
saturation = float(hyperion.args.get('saturation', 1.0))
reverse = bool(hyperion.args.get('reverse', False))
# Check parameters
rotationTime = max(0.1, rotationTime)

View File

@ -26,6 +26,8 @@ public:
const std::list<EffectDefinition> & getEffects() const;
static bool loadEffectDefinition(const std::string & path, const std::string & effectConfigFile, EffectDefinition &effectDefinition);
public slots:
/// Run the specified effect on the given priority channel and optionally specify a timeout
int runEffect(const std::string &effectName, int priority, int timeout = -1);

View File

@ -105,7 +105,7 @@ public slots:
/// @param[in] ledColor The color to write to the leds
/// @param[in] timeout_ms The time the leds are set to the given color [ms]
///
void setColor(int priority, const ColorRgb &ledColor, const int timeout_ms);
void setColor(int priority, const ColorRgb &ledColor, const int timeout_ms, bool clearEffects = true);
///
/// Writes the given colors to all leds for the given time and priority
@ -114,7 +114,7 @@ public slots:
/// @param[in] ledColors The colors to write to the leds
/// @param[in] timeout_ms The time the leds are set to the given colors [ms]
///
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms);
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects = true);
///
/// Returns the list with unique transform identifiers

View File

@ -5,13 +5,24 @@
// Bootsequence includes
#include <bootsequence/BootSequenceFactory.h>
// Effect engine includes
#include <effectengine/EffectEngine.h>
// Local Bootsequence includes
#include "EffectBootSequence.h"
BootSequence * BootSequenceFactory::createBootSequence(Hyperion * hyperion, const Json::Value & jsonConfig)
{
const std::string script = jsonConfig["script"].asString();
const Json::Value args = jsonConfig.get("args", Json::Value(Json::objectValue));
const std::string path = jsonConfig["path"].asString();
const std::string effectFile = jsonConfig["effect"].asString();
const unsigned duration = jsonConfig["duration_ms"].asUInt();
return new EffectBootSequence(hyperion, script, args, duration);
EffectDefinition effect;
if (EffectEngine::loadEffectDefinition(path, effectFile, effect))
{
return new EffectBootSequence(hyperion, effect, duration);
}
std::cerr << "Boot sequence could not be loaded" << std::endl;
return nullptr;
}

View File

@ -1,10 +1,9 @@
#include "EffectBootSequence.h"
EffectBootSequence::EffectBootSequence(Hyperion *hyperion, const std::string &script, const Json::Value &args, const unsigned duration_ms) :
EffectBootSequence::EffectBootSequence(Hyperion *hyperion, const EffectDefinition &effect, const unsigned duration_ms) :
BootSequence(),
_hyperion(hyperion),
_script(script),
_args(args),
_effect(effect),
_duration_ms(duration_ms)
{
}
@ -15,5 +14,5 @@ EffectBootSequence::~EffectBootSequence()
void EffectBootSequence::start()
{
_hyperion->setEffectScript(_script, _args, 0, _duration_ms);
_hyperion->setEffectScript(_effect.script, _effect.args, 0, _duration_ms);
}

View File

@ -17,9 +17,10 @@ public:
/// duration is the length the effect will run.
///
/// @param[in] hyperion The Hyperion instance
/// @param[in] effect The effect definition
/// @param[in] duration_ms The length of the sequence [ms]
///
EffectBootSequence(Hyperion * hyperion, const std::string & script, const Json::Value & args, const unsigned duration_ms);
EffectBootSequence(Hyperion * hyperion, const EffectDefinition & effect, const unsigned duration_ms);
virtual ~EffectBootSequence();
virtual void start();
@ -29,10 +30,7 @@ private:
Hyperion * _hyperion;
/// The script to execute
const std::string _script;
/// The arguments of the script
const Json::Value _args;
const EffectDefinition _effect;
/// Duration of the boot sequence
const unsigned _duration_ms;

View File

@ -22,12 +22,18 @@ SET(EffectEngineSOURCES
${CURRENT_SOURCE_DIR}/Effect.cpp
)
set(EffectEngine_RESOURCES ${CURRENT_SOURCE_DIR}/EffectEngine.qrc)
QT4_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS})
qt4_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress")
add_library(effectengine
${EffectEngineHEADERS}
${EffectEngineQT_HEADERS}
${EffectEngineHEADERS_MOC}
${EffectEngine_RESOURCES_RCC}
${EffectEngineSOURCES}
)

View File

@ -29,8 +29,11 @@ Effect::Effect(int priority, int timeout, const std::string & script, const Json
_endTime(-1),
_interpreterThreadState(nullptr),
_abortRequested(false),
_imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor())
_imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()),
_colors()
{
_colors.resize(_imageProcessor->getLedCount(), ColorRgb::BLACK);
// connect the finished signal
connect(this, SIGNAL(finished()), this, SLOT(effectFinished()));
}
@ -170,7 +173,8 @@ PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args)
ColorRgb color;
if (PyArg_ParseTuple(args, "bbb", &color.red, &color.green, &color.blue))
{
effect->setColors(effect->_priority, std::vector<ColorRgb>(effect->_imageProcessor->getLedCount(), color), timeout);
std::fill(effect->_colors.begin(), effect->_colors.end(), color);
effect->setColors(effect->_priority, effect->_colors, timeout, false);
return Py_BuildValue("");
}
else
@ -189,16 +193,9 @@ PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args)
size_t length = PyByteArray_Size(bytearray);
if (length == 3 * effect->_imageProcessor->getLedCount())
{
std::vector<ColorRgb> colors(effect->_imageProcessor->getLedCount());
char * data = PyByteArray_AS_STRING(bytearray);
for (size_t i = 0; i < colors.size(); ++i)
{
ColorRgb & color = colors[i];
color.red = data [3*i];
color.green = data [3*i+1];
color.blue = data [3*i+2];
}
effect->setColors(effect->_priority, colors, timeout);
memcpy(effect->_colors.data(), data, length);
effect->setColors(effect->_priority, effect->_colors, timeout, false);
return Py_BuildValue("");
}
else
@ -265,21 +262,10 @@ PyObject* Effect::wrapSetImage(PyObject *self, PyObject *args)
{
Image<ColorRgb> image(width, height);
char * data = PyByteArray_AS_STRING(bytearray);
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
ColorRgb & color = image(x, y);
int index = x+width*y;
color.red = data [3*index];
color.green = data [3*index+1];
color.blue = data [3*index+2];
}
}
memcpy(image.memptr(), data, length);
std::vector<ColorRgb> colors(effect->_imageProcessor->getLedCount());
effect->_imageProcessor->process(image, colors);
effect->setColors(effect->_priority, colors, timeout);
effect->_imageProcessor->process(image, effect->_colors);
effect->setColors(effect->_priority, effect->_colors, timeout, false);
return Py_BuildValue("");
}
else
@ -307,13 +293,6 @@ PyObject* Effect::wrapSetImage(PyObject *self, PyObject *args)
PyObject* Effect::wrapAbort(PyObject *self, PyObject *)
{
Effect * effect = getEffect(self);
return Py_BuildValue("i", effect->_abortRequested ? 1 : 0);
}
Effect * Effect::getEffect(PyObject *self)
{
// Get the effect from the capsule in the self pointer
Effect * effect = reinterpret_cast<Effect *>(PyCapsule_GetPointer(self, nullptr));
// Test if the effect has reached it end time
if (effect->_timeout > 0 && QDateTime::currentMSecsSinceEpoch() > effect->_endTime)
@ -321,6 +300,11 @@ Effect * Effect::getEffect(PyObject *self)
effect->_abortRequested = true;
}
// return the effect
return effect;
return Py_BuildValue("i", effect->_abortRequested ? 1 : 0);
}
Effect * Effect::getEffect(PyObject *self)
{
// Get the effect from the capsule in the self pointer
return reinterpret_cast<Effect *>(PyCapsule_GetPointer(self, nullptr));
}

View File

@ -29,7 +29,7 @@ public slots:
signals:
void effectFinished(Effect * effect);
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms);
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects);
private slots:
void effectFinished();
@ -61,4 +61,7 @@ private:
/// The processor for translating images to led-values
ImageProcessor * _imageProcessor;
/// Buffer for colorData
std::vector<ColorRgb> _colors;
};

View File

@ -0,0 +1,342 @@
{
"type" : "object",
"required" : true,
"properties" : {
"device" : {
"type" : "object",
"required" : true,
"properties" : {
"name" : {
"type" : "string",
"required" : true
},
"type" : {
"type" : "string",
"required" : true
},
"output" : {
"type" : "string",
"required" : true
},
"rate" : {
"type" : "integer",
"required" : true,
"minimum" : 0
},
"colorOrder" : {
"type" : "string",
"required" : false
},
"bgr-output" : { // deprecated
"type" : "boolean",
"required" : false
}
},
"additionalProperties" : false
},
"color": {
"type":"object",
"required":false,
"properties": {
"hsv" : {
"type" : "object",
"required" : false,
"properties" : {
"saturationGain" : {
"type" : "number",
"required" : false,
"minimum" : 0.0
},
"valueGain" : {
"type" : "number",
"required" : false,
"minimum" : 0.0
}
},
"additionalProperties" : false
},
"red": {
"type":"object",
"required":false,
"properties":{
"gamma": {
"type":"number",
"required":false
},
"blacklevel": {
"type":"number",
"required":false
},
"whitelevel": {
"type":"number",
"required":false
},
"threshold": {
"type":"number",
"required":false,
"minimum" : 0.0,
"maximum" : 1.0
}
},
"additionalProperties" : false
},
"green": {
"type":"object",
"required":false,
"properties":{
"gamma": {
"type":"number",
"required":false
},
"blacklevel": {
"type":"number",
"required":false
},
"whitelevel": {
"type":"number",
"required":false
},
"threshold": {
"type":"number",
"required":false,
"minimum" : 0.0,
"maximum" : 1.0
}
},
"additionalProperties" : false
},
"blue": {
"type":"object",
"required":false,
"properties":{
"gamma": {
"type":"number",
"required":false
},
"whitelevel": {
"type":"number",
"required":false
},
"blacklevel": {
"type":"number",
"required":false
},
"threshold": {
"type":"number",
"required":false,
"minimum" : 0.0,
"maximum" : 1.0
}
},
"additionalProperties" : false
},
"smoothing" : {
"type" : "object",
"required" : false,
"properties" : {
"type" : {
"type" : "enum",
"required" : true,
"values" : ["none", "linear"]
},
"time_ms" : {
"type" : "integer",
"required" : false,
"minimum" : 10
},
"updateFrequency" : {
"type" : "number",
"required" : false,
"minimum" : 0.001
}
},
"additionalProperties" : false
}
},
"additionalProperties" : false
},
"leds": {
"type":"array",
"required":true,
"items": {
"type":"object",
"properties": {
"index": {
"type":"integer",
"required":true
},
"hscan": {
"type":"object",
"required":true,
"properties": {
"minimum": {
"type":"number",
"required":true
},
"maximum": {
"type":"number",
"required":true
}
},
"additionalProperties" : false
},
"vscan": {
"type":"object",
"required":true,
"properties": {
"minimum": {
"type":"number",
"required":true
},
"maximum": {
"type":"number",
"required":true
}
},
"additionalProperties" : false
}
},
"additionalProperties" : false
}
},
"effects" :
{
"type" : "object",
"required" : false,
"properties" : {
"paths" : {
"type" : "array",
"required" : false,
"items" : {
"type" : "string"
}
}
},
"additionalProperties" : false
},
"blackborderdetector" :
{
"type" : "object",
"required" : false,
"properties" : {
"enable" : {
"type" : "boolean",
"required" : true
}
},
"additionalProperties" : false
},
"xbmcVideoChecker" :
{
"type" : "object",
"required" : false,
"properties" : {
"xbmcAddress" : {
"type" : "string",
"required" : true
},
"xbmcTcpPort" : {
"type" : "integer",
"required" : true
},
"grabVideo" : {
"type" : "boolean",
"required" : true
},
"grabPictures" : {
"type" : "boolean",
"required" : true
},
"grabAudio" : {
"type" : "boolean",
"required" : true
},
"grabMenu" : {
"type" : "boolean",
"required" : true
}
},
"additionalProperties" : false
},
"bootsequence" :
{
"type" : "object",
"required" : false,
"properties" : {
"path" : {
"type" : "string",
"required" : true
},
"effect" : {
"type" : "string",
"required" : true
}
},
"additionalProperties" : false
},
"framegrabber" :
{
"type" : "object",
"required" : false,
"properties" : {
"width" : {
"type" : "integer",
"required" : true
},
"height" : {
"type" : "integer",
"required" : true
},
"frequency_Hz" : {
"type" : "integer",
"required" : true
}
},
"additionalProperties" : false
},
"jsonServer" :
{
"type" : "object",
"required" : false,
"properties" : {
"port" : {
"type" : "integer",
"required" : true,
"minimum" : 0,
"maximum" : 65535
}
},
"additionalProperties" : false
},
"protoServer" :
{
"type" : "object",
"required" : false,
"properties" : {
"port" : {
"type" : "integer",
"required" : true,
"minimum" : 0,
"maximum" : 65535
}
},
"additionalProperties" : false
},
"boblightServer" :
{
"type" : "object",
"required" : false,
"properties" : {
"port" : {
"type" : "integer",
"required" : true,
"minimum" : 0,
"maximum" : 65535
}
},
"additionalProperties" : false
}
},
"additionalProperties" : false
}

View File

@ -1,8 +1,17 @@
// Python includes
#include <Python.h>
// Stl includes
#include <fstream>
// Qt includes
#include <QResource>
#include <QMetaType>
#include <QFile>
#include <QDir>
// hyperion util includes
#include <utils/jsonschema/JsonSchemaChecker.h>
// effect engine includes
#include <effectengine/EffectEngine.h>
@ -21,11 +30,26 @@ EffectEngine::EffectEngine(Hyperion * hyperion, const Json::Value & jsonEffectCo
connect(_hyperion, SIGNAL(allChannelsCleared()), this, SLOT(allChannelsCleared()));
// read all effects
std::vector<std::string> effectNames = jsonEffectConfig.getMemberNames();
for (const std::string & name : effectNames)
const Json::Value & paths = jsonEffectConfig["paths"];
for (Json::UInt i = 0; i < paths.size(); ++i)
{
const Json::Value & info = jsonEffectConfig[name];
_availableEffects.push_back({name, info["script"].asString(), info["args"]});
const std::string & path = paths[i].asString();
QDir directory(QString::fromStdString(path));
if (!directory.exists())
{
std::cerr << "Effect directory can not be loaded: " << path << std::endl;
continue;
}
QStringList filenames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
foreach (const QString & filename, filenames)
{
EffectDefinition def;
if (loadEffectDefinition(path, filename.toStdString(), def))
{
_availableEffects.push_back(def);
}
}
}
// initialize the python interpreter
@ -48,6 +72,51 @@ const std::list<EffectDefinition> &EffectEngine::getEffects() const
return _availableEffects;
}
bool EffectEngine::loadEffectDefinition(const std::string &path, const std::string &effectConfigFile, EffectDefinition & effectDefinition)
{
std::string fileName = path + QDir::separator().toAscii() + effectConfigFile;
std::ifstream file(fileName.c_str());
if (!file.is_open())
{
std::cerr << "Effect file '" << fileName << "' could not be loaded" << std::endl;
return false;
}
// Read the json config file
Json::Reader jsonReader;
Json::Value config;
if (!jsonReader.parse(file, config, false))
{
std::cerr << "Error while reading effect '" << fileName << "': " << jsonReader.getFormattedErrorMessages() << std::endl;
return false;
}
// Read the json schema file
QResource schemaData(":effect-schema");
JsonSchemaChecker schemaChecker;
Json::Value schema;
Json::Reader().parse(reinterpret_cast<const char *>(schemaData.data()), reinterpret_cast<const char *>(schemaData.data()) + schemaData.size(), schema, false);
schemaChecker.setSchema(schema);
if (!schemaChecker.validate(config))
{
const std::list<std::string> & errors = schemaChecker.getMessages();
foreach (const std::string & error, errors) {
std::cerr << "Error while checking '" << fileName << "':" << error << std::endl;
}
return false;
}
// setup the definition
effectDefinition.name = config["name"].asString();
effectDefinition.script = path + QDir::separator().toAscii() + config["script"].asString();
effectDefinition.args = config["args"];
// return succes
std::cout << "Effect loaded: " + effectDefinition.name << std::endl;
return true;
}
int EffectEngine::runEffect(const std::string &effectName, int priority, int timeout)
{
return runEffect(effectName, Json::Value(Json::nullValue), priority, timeout);
@ -83,7 +152,7 @@ int EffectEngine::runEffectScript(const std::string &script, const Json::Value &
// create the effect
Effect * effect = new Effect(priority, timeout, script, args);
connect(effect, SIGNAL(setColors(int,std::vector<ColorRgb>,int)), _hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int)), Qt::QueuedConnection);
connect(effect, SIGNAL(setColors(int,std::vector<ColorRgb>,int,bool)), _hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int,bool)), Qt::QueuedConnection);
connect(effect, SIGNAL(effectFinished(Effect*)), this, SLOT(effectFinished(Effect*)));
_activeEffects.push_back(effect);

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file alias="effect-schema">EffectDefinition.schema.json</file>
</qresource>
</RCC>

View File

@ -392,17 +392,23 @@ unsigned Hyperion::getLedCount() const
return _ledString.leds().size();
}
void Hyperion::setColor(int priority, const ColorRgb &color, const int timeout_ms)
void Hyperion::setColor(int priority, const ColorRgb &color, const int timeout_ms, bool clearEffects)
{
// create led output
std::vector<ColorRgb> ledColors(_ledString.leds().size(), color);
// set colors
setColors(priority, ledColors, timeout_ms);
setColors(priority, ledColors, timeout_ms, clearEffects);
}
void Hyperion::setColors(int priority, const std::vector<ColorRgb>& ledColors, const int timeout_ms)
void Hyperion::setColors(int priority, const std::vector<ColorRgb>& ledColors, const int timeout_ms, bool clearEffects)
{
// clear effects if this call does not come from an effect
if (clearEffects)
{
_effectEngine->channelCleared(priority);
}
if (timeout_ms > 0)
{
const uint64_t timeoutTime = QDateTime::currentMSecsSinceEpoch() + timeout_ms;

View File

@ -204,22 +204,16 @@
{
"type" : "object",
"required" : false,
"additionalProperties" :
{
"type" : "object",
"properties" : {
"paths" : {
"type" : "array",
"required" : false,
"properties" :
{
"script" : {
"type" : "string",
"required" : true
"items" : {
"type" : "string"
}
}
},
"args" : {
"type" : "object",
"required" : false
}
}
}
"additionalProperties" : false
},
"blackborderdetector" :
{
@ -270,17 +264,13 @@
"type" : "object",
"required" : false,
"properties" : {
"duration_ms" : {
"type" : "integer",
"required" : true
},
"script" : {
"path" : {
"type" : "string",
"required" : true
},
"args" : {
"type" : "object",
"required" : false
"effect" : {
"type" : "string",
"required" : true
}
},
"additionalProperties" : false