From 0537fdc741f04b51df7d94c643c9ef32c2752e48 Mon Sep 17 00:00:00 2001 From: johan Date: Wed, 11 Dec 2013 21:58:59 +0100 Subject: [PATCH] Moved effect configurations from the config file to effect directory Former-commit-id: b8db13f25b93a0007adf613f0310a1cfbb6b8224 --- config/hyperion.config.json | 765 +++++++++--------- effects/knight-rider.json | 9 + effects/mood-blobs-blue.json | 12 + effects/mood-blobs-green.json | 12 + effects/mood-blobs-red.json | 12 + effects/rainbow-mood.json | 10 + effects/rainbow-swirl-fast.json | 10 + effects/rainbow-swirl.json | 10 + include/effectengine/EffectEngine.h | 2 + libsrc/bootsequence/BootSequenceFactory.cpp | 17 +- libsrc/bootsequence/EffectBootSequence.cpp | 7 +- libsrc/bootsequence/EffectBootSequence.h | 8 +- libsrc/effectengine/CMakeLists.txt | 6 + .../effectengine/EffectDefinition.schema.json | 342 ++++++++ libsrc/effectengine/EffectEngine.cpp | 77 +- libsrc/effectengine/EffectEngine.qrc | 5 + libsrc/hyperion/hyperion.schema.json | 34 +- 17 files changed, 919 insertions(+), 419 deletions(-) create mode 100755 effects/knight-rider.json create mode 100755 effects/mood-blobs-blue.json create mode 100755 effects/mood-blobs-green.json create mode 100755 effects/mood-blobs-red.json create mode 100755 effects/rainbow-mood.json create mode 100755 effects/rainbow-swirl-fast.json create mode 100755 effects/rainbow-swirl.json create mode 100644 libsrc/effectengine/EffectDefinition.schema.json create mode 100644 libsrc/effectengine/EffectEngine.qrc diff --git a/config/hyperion.config.json b/config/hyperion.config.json index 5f569a43..facc714e 100644 --- a/config/hyperion.config.json +++ b/config/hyperion.config.json @@ -2,399 +2,402 @@ // Generated by: HyperCon (The Hyperion deamon configuration file builder { - /// Device configuration contains the following fields: - /// * 'name' : The user friendly name of the device (only used for display purposes) - /// * 'type' : The type of the device or leds (known types for now are 'ws2801', 'ldp8806', - /// 'lpd6803', 'sedu', 'adalight', 'lightpack', 'test' and 'none') - /// * 'output' : The output specification depends on selected device. This can for example be the - /// device specifier, device serial number, or the output file name - /// * 'rate' : The baudrate of the output to the device - /// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.). - "device" : - { - "name" : "MyPi", - "type" : "ws2801", - "output" : "/dev/spidev0.0", - "rate" : 500000, - "colorOrder" : "rgb" - }, + /// Device configuration contains the following fields: + /// * 'name' : The user friendly name of the device (only used for display purposes) + /// * 'type' : The type of the device or leds (known types for now are 'ws2801', 'ldp8806', + /// 'lpd6803', 'sedu', 'adalight', 'lightpack', 'test' and 'none') + /// * 'output' : The output specification depends on selected device. This can for example be the + /// device specifier, device serial number, or the output file name + /// * 'rate' : The baudrate of the output to the device + /// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.). + "device" : + { + "name" : "MyPi", + "type" : "ws2801", + "output" : "/dev/spidev0.0", + "rate" : 500000, + "colorOrder" : "rgb" + }, - /// Color manipulation configuration used to tune the output colors to specific surroundings. Contains the following fields: - /// * 'hsv' : The manipulation in the Hue-Saturation-Value color domain with the following tuning parameters: - /// - 'saturationGain' The gain adjustement of the saturation - /// - 'valueGain' The gain adjustement of the value - /// * 'red'/'green'/'blue' : The manipulation in the Red-Green-Blue color domain with the following tuning parameters for each channel: - /// - 'threshold' The minimum required input value for the channel to be on (else zero) - /// - 'gamma' The gamma-curve correction factor - /// - 'blacklevel' The lowest possible value (when the channel is black) - /// - 'whitelevel' The highest possible value (when the channel is white) - /// * 'smoothing' : Smoothing of the colors in the time-domain with the following tuning parameters: - /// - 'type' The type of smoothing algorithm ('linear' or 'none') - /// - 'time_ms' The time constant for smoothing algorithm in milliseconds - /// - 'updateFrequency' The update frequency of the leds in Hz - "color" : - { - "hsv" : - { - "saturationGain" : 1.0000, - "valueGain" : 1.5000 - }, - "red" : - { - "threshold" : 0.1000, - "gamma" : 2.0000, - "blacklevel" : 0.0000, - "whitelevel" : 0.8000 - }, - "green" : - { - "threshold" : 0.1000, - "gamma" : 2.0000, - "blacklevel" : 0.0000, - "whitelevel" : 1.0000 - }, - "blue" : - { - "threshold" : 0.1000, - "gamma" : 2.0000, - "blacklevel" : 0.0000, - "whitelevel" : 1.0000 - }, - "smoothing" : - { - "type" : "none", - "time_ms" : 200, - "updateFrequency" : 20.0000 - } - }, + /// Color manipulation configuration used to tune the output colors to specific surroundings. Contains the following fields: + /// * 'hsv' : The manipulation in the Hue-Saturation-Value color domain with the following tuning parameters: + /// - 'saturationGain' The gain adjustement of the saturation + /// - 'valueGain' The gain adjustement of the value + /// * 'red'/'green'/'blue' : The manipulation in the Red-Green-Blue color domain with the following tuning parameters for each channel: + /// - 'threshold' The minimum required input value for the channel to be on (else zero) + /// - 'gamma' The gamma-curve correction factor + /// - 'blacklevel' The lowest possible value (when the channel is black) + /// - 'whitelevel' The highest possible value (when the channel is white) + /// * 'smoothing' : Smoothing of the colors in the time-domain with the following tuning parameters: + /// - 'type' The type of smoothing algorithm ('linear' or 'none') + /// - 'time_ms' The time constant for smoothing algorithm in milliseconds + /// - 'updateFrequency' The update frequency of the leds in Hz + "color" : + { + "hsv" : + { + "saturationGain" : 1.0000, + "valueGain" : 1.5000 + }, + "red" : + { + "threshold" : 0.1000, + "gamma" : 2.0000, + "blacklevel" : 0.0000, + "whitelevel" : 0.8000 + }, + "green" : + { + "threshold" : 0.1000, + "gamma" : 2.0000, + "blacklevel" : 0.0000, + "whitelevel" : 1.0000 + }, + "blue" : + { + "threshold" : 0.1000, + "gamma" : 2.0000, + "blacklevel" : 0.0000, + "whitelevel" : 1.0000 + }, + "smoothing" : + { + "type" : "none", + "time_ms" : 200, + "updateFrequency" : 20.0000 + } + }, - /// The configuration for each individual led. This contains the specification of the area - /// averaged of an input image for each led to determine its color. Each item in the list - /// contains the following fields: - /// * index: The index of the led. This determines its location in the string of leds; zero - /// being the first led. - /// * hscan: The fractional part of the image along the horizontal used for the averaging - /// (minimum and maximum inclusive) - /// * vscan: The fractional part of the image along the vertical used for the averaging - /// (minimum and maximum inclusive) - "leds" : - [ - { - "index" : 0, - "hscan" : { "minimum" : 0.4375, "maximum" : 0.5000 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 1, - "hscan" : { "minimum" : 0.3750, "maximum" : 0.4375 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 2, - "hscan" : { "minimum" : 0.3125, "maximum" : 0.3750 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 3, - "hscan" : { "minimum" : 0.2500, "maximum" : 0.3125 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 4, - "hscan" : { "minimum" : 0.1875, "maximum" : 0.2500 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 5, - "hscan" : { "minimum" : 0.1250, "maximum" : 0.1875 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 6, - "hscan" : { "minimum" : 0.0625, "maximum" : 0.1250 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 7, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0625 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 8, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 9, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, - "vscan" : { "minimum" : 0.8571, "maximum" : 1.0000 } - }, - { - "index" : 10, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, - "vscan" : { "minimum" : 0.7143, "maximum" : 0.8571 } - }, - { - "index" : 11, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, - "vscan" : { "minimum" : 0.5714, "maximum" : 0.7143 } - }, - { - "index" : 12, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, - "vscan" : { "minimum" : 0.4286, "maximum" : 0.5714 } - }, - { - "index" : 13, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, - "vscan" : { "minimum" : 0.2857, "maximum" : 0.4286 } - }, - { - "index" : 14, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, - "vscan" : { "minimum" : 0.1429, "maximum" : 0.2857 } - }, - { - "index" : 15, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.1429 } - }, - { - "index" : 16, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 17, - "hscan" : { "minimum" : 0.0000, "maximum" : 0.0625 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 18, - "hscan" : { "minimum" : 0.0625, "maximum" : 0.1250 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 19, - "hscan" : { "minimum" : 0.1250, "maximum" : 0.1875 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 20, - "hscan" : { "minimum" : 0.1875, "maximum" : 0.2500 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 21, - "hscan" : { "minimum" : 0.2500, "maximum" : 0.3125 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 22, - "hscan" : { "minimum" : 0.3125, "maximum" : 0.3750 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 23, - "hscan" : { "minimum" : 0.3750, "maximum" : 0.4375 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 24, - "hscan" : { "minimum" : 0.4375, "maximum" : 0.5000 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 25, - "hscan" : { "minimum" : 0.5000, "maximum" : 0.5625 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 26, - "hscan" : { "minimum" : 0.5625, "maximum" : 0.6250 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 27, - "hscan" : { "minimum" : 0.6250, "maximum" : 0.6875 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 28, - "hscan" : { "minimum" : 0.6875, "maximum" : 0.7500 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 29, - "hscan" : { "minimum" : 0.7500, "maximum" : 0.8125 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 30, - "hscan" : { "minimum" : 0.8125, "maximum" : 0.8750 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 31, - "hscan" : { "minimum" : 0.8750, "maximum" : 0.9375 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 32, - "hscan" : { "minimum" : 0.9375, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 33, - "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } - }, - { - "index" : 34, - "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.0000, "maximum" : 0.1429 } - }, - { - "index" : 35, - "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.1429, "maximum" : 0.2857 } - }, - { - "index" : 36, - "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.2857, "maximum" : 0.4286 } - }, - { - "index" : 37, - "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.4286, "maximum" : 0.5714 } - }, - { - "index" : 38, - "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.5714, "maximum" : 0.7143 } - }, - { - "index" : 39, - "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.7143, "maximum" : 0.8571 } - }, - { - "index" : 40, - "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.8571, "maximum" : 1.0000 } - }, - { - "index" : 41, - "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 42, - "hscan" : { "minimum" : 0.9375, "maximum" : 1.0000 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 43, - "hscan" : { "minimum" : 0.8750, "maximum" : 0.9375 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 44, - "hscan" : { "minimum" : 0.8125, "maximum" : 0.8750 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 45, - "hscan" : { "minimum" : 0.7500, "maximum" : 0.8125 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 46, - "hscan" : { "minimum" : 0.6875, "maximum" : 0.7500 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 47, - "hscan" : { "minimum" : 0.6250, "maximum" : 0.6875 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 48, - "hscan" : { "minimum" : 0.5625, "maximum" : 0.6250 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - }, - { - "index" : 49, - "hscan" : { "minimum" : 0.5000, "maximum" : 0.5625 }, - "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } - } - ], + /// The configuration for each individual led. This contains the specification of the area + /// averaged of an input image for each led to determine its color. Each item in the list + /// contains the following fields: + /// * index: The index of the led. This determines its location in the string of leds; zero + /// being the first led. + /// * hscan: The fractional part of the image along the horizontal used for the averaging + /// (minimum and maximum inclusive) + /// * vscan: The fractional part of the image along the vertical used for the averaging + /// (minimum and maximum inclusive) + "leds" : + [ + { + "index" : 0, + "hscan" : { "minimum" : 0.4375, "maximum" : 0.5000 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 1, + "hscan" : { "minimum" : 0.3750, "maximum" : 0.4375 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 2, + "hscan" : { "minimum" : 0.3125, "maximum" : 0.3750 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 3, + "hscan" : { "minimum" : 0.2500, "maximum" : 0.3125 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 4, + "hscan" : { "minimum" : 0.1875, "maximum" : 0.2500 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 5, + "hscan" : { "minimum" : 0.1250, "maximum" : 0.1875 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 6, + "hscan" : { "minimum" : 0.0625, "maximum" : 0.1250 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 7, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0625 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 8, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 9, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, + "vscan" : { "minimum" : 0.8571, "maximum" : 1.0000 } + }, + { + "index" : 10, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, + "vscan" : { "minimum" : 0.7143, "maximum" : 0.8571 } + }, + { + "index" : 11, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, + "vscan" : { "minimum" : 0.5714, "maximum" : 0.7143 } + }, + { + "index" : 12, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, + "vscan" : { "minimum" : 0.4286, "maximum" : 0.5714 } + }, + { + "index" : 13, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, + "vscan" : { "minimum" : 0.2857, "maximum" : 0.4286 } + }, + { + "index" : 14, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, + "vscan" : { "minimum" : 0.1429, "maximum" : 0.2857 } + }, + { + "index" : 15, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.1429 } + }, + { + "index" : 16, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 17, + "hscan" : { "minimum" : 0.0000, "maximum" : 0.0625 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 18, + "hscan" : { "minimum" : 0.0625, "maximum" : 0.1250 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 19, + "hscan" : { "minimum" : 0.1250, "maximum" : 0.1875 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 20, + "hscan" : { "minimum" : 0.1875, "maximum" : 0.2500 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 21, + "hscan" : { "minimum" : 0.2500, "maximum" : 0.3125 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 22, + "hscan" : { "minimum" : 0.3125, "maximum" : 0.3750 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 23, + "hscan" : { "minimum" : 0.3750, "maximum" : 0.4375 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 24, + "hscan" : { "minimum" : 0.4375, "maximum" : 0.5000 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 25, + "hscan" : { "minimum" : 0.5000, "maximum" : 0.5625 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 26, + "hscan" : { "minimum" : 0.5625, "maximum" : 0.6250 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 27, + "hscan" : { "minimum" : 0.6250, "maximum" : 0.6875 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 28, + "hscan" : { "minimum" : 0.6875, "maximum" : 0.7500 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 29, + "hscan" : { "minimum" : 0.7500, "maximum" : 0.8125 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 30, + "hscan" : { "minimum" : 0.8125, "maximum" : 0.8750 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 31, + "hscan" : { "minimum" : 0.8750, "maximum" : 0.9375 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 32, + "hscan" : { "minimum" : 0.9375, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 33, + "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 } + }, + { + "index" : 34, + "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 0.1429 } + }, + { + "index" : 35, + "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.1429, "maximum" : 0.2857 } + }, + { + "index" : 36, + "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.2857, "maximum" : 0.4286 } + }, + { + "index" : 37, + "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.4286, "maximum" : 0.5714 } + }, + { + "index" : 38, + "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.5714, "maximum" : 0.7143 } + }, + { + "index" : 39, + "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.7143, "maximum" : 0.8571 } + }, + { + "index" : 40, + "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.8571, "maximum" : 1.0000 } + }, + { + "index" : 41, + "hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 42, + "hscan" : { "minimum" : 0.9375, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 43, + "hscan" : { "minimum" : 0.8750, "maximum" : 0.9375 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 44, + "hscan" : { "minimum" : 0.8125, "maximum" : 0.8750 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 45, + "hscan" : { "minimum" : 0.7500, "maximum" : 0.8125 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 46, + "hscan" : { "minimum" : 0.6875, "maximum" : 0.7500 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 47, + "hscan" : { "minimum" : 0.6250, "maximum" : 0.6875 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 48, + "hscan" : { "minimum" : 0.5625, "maximum" : 0.6250 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + }, + { + "index" : 49, + "hscan" : { "minimum" : 0.5000, "maximum" : 0.5625 }, + "vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 } + } + ], - /// The black border configuration, contains the following items: - /// * enable : true if the detector should be activated - "blackborderdetector" : - { - "enable" : true - }, + "effects" : + { + "paths" : ["/home/pi/hyperion/effects"] + }, - /// 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", - "duration_ms" : 3000 - }, + /// The black border configuration, contains the following items: + /// * enable : true if the detector should be activated + "blackborderdetector" : + { + "enable" : true + }, - /// The configuration for the frame-grabber, contains the following items: - /// * width : The width of the grabbed frames [pixels] - /// * height : The height of the grabbed frames [pixels] - /// * frequency_Hz : The frequency of the frame grab [Hz] - "framegrabber" : - { - "width" : 64, - "height" : 64, - "frequency_Hz" : 10.0 - }, + "bootsequence" : + { + "effect" : "rainbow-swirl-fast.json", + "path" : "/home/pi/hyperion/effects", + "duration_ms" : 3000 + }, - /// The configuration of the XBMC connection used to enable and disable the frame-grabber. Contains the following fields: - /// * xbmcAddress : The IP address of the XBMC-host - /// * xbmcTcpPort : The TCP-port of the XBMC-server - /// * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback - /// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show - /// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback - /// * grabMenu : Flag indicating that the frame-grabber is on(true) in the XBMC menu - "xbmcVideoChecker" : - { - "xbmcAddress" : "127.0.0.1", - "xbmcTcpPort" : 9090, - "grabVideo" : true, - "grabPictures" : true, - "grabAudio" : true, - "grabMenu" : false - }, + /// The configuration for the frame-grabber, contains the following items: + /// * width : The width of the grabbed frames [pixels] + /// * height : The height of the grabbed frames [pixels] + /// * frequency_Hz : The frequency of the frame grab [Hz] + "framegrabber" : + { + "width" : 64, + "height" : 64, + "frequency_Hz" : 10.0 + }, - /// The configuration of the Json server which enables the json remote interface - /// * port : Port at which the json server is started - "jsonServer" : - { - "port" : 19444 - }, + /// The configuration of the XBMC connection used to enable and disable the frame-grabber. Contains the following fields: + /// * xbmcAddress : The IP address of the XBMC-host + /// * xbmcTcpPort : The TCP-port of the XBMC-server + /// * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback + /// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show + /// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback + /// * grabMenu : Flag indicating that the frame-grabber is on(true) in the XBMC menu + "xbmcVideoChecker" : + { + "xbmcAddress" : "127.0.0.1", + "xbmcTcpPort" : 9090, + "grabVideo" : true, + "grabPictures" : true, + "grabAudio" : true, + "grabMenu" : false + }, - /// The configuration of the Proto server which enables the protobuffer remote interface - /// * port : Port at which the protobuffer server is started - "protoServer" : - { - "port" : 19445 - }, + /// The configuration of the Json server which enables the json remote interface + /// * port : Port at which the json server is started + "jsonServer" : + { + "port" : 19444 + }, - /// The configuration of the boblight server which enables the boblight remote interface - /// * port : Port at which the boblight server is started + /// The configuration of the Proto server which enables the protobuffer remote interface + /// * port : Port at which the protobuffer server is started + "protoServer" : + { + "port" : 19445 + }, + + /// The configuration of the boblight server which enables the boblight remote interface + /// * port : Port at which the boblight server is started // "boblightServer" : // { // "port" : 19333 // }, - "end-of-json" : "end-of-json" + "end-of-json" : "end-of-json" } diff --git a/effects/knight-rider.json b/effects/knight-rider.json new file mode 100755 index 00000000..bf83f897 --- /dev/null +++ b/effects/knight-rider.json @@ -0,0 +1,9 @@ +{ + "name" : "Knight rider", + "script" : "knight-rider.py", + "args" : + { + "speed" : 1.0, + "fadeFactor" : 0.7 + } +} diff --git a/effects/mood-blobs-blue.json b/effects/mood-blobs-blue.json new file mode 100755 index 00000000..1aa188ab --- /dev/null +++ b/effects/mood-blobs-blue.json @@ -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 + } +} diff --git a/effects/mood-blobs-green.json b/effects/mood-blobs-green.json new file mode 100755 index 00000000..c0c104fe --- /dev/null +++ b/effects/mood-blobs-green.json @@ -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 + } +} diff --git a/effects/mood-blobs-red.json b/effects/mood-blobs-red.json new file mode 100755 index 00000000..3272dded --- /dev/null +++ b/effects/mood-blobs-red.json @@ -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 + } +} diff --git a/effects/rainbow-mood.json b/effects/rainbow-mood.json new file mode 100755 index 00000000..fe754287 --- /dev/null +++ b/effects/rainbow-mood.json @@ -0,0 +1,10 @@ +{ + "name" : "Rainbow mood", + "script" : "rainbow-mood.py", + "args" : + { + "rotation-time" : 60.0, + "brightness" : 1.0, + "reverse" : false + } +} diff --git a/effects/rainbow-swirl-fast.json b/effects/rainbow-swirl-fast.json new file mode 100755 index 00000000..19fec89c --- /dev/null +++ b/effects/rainbow-swirl-fast.json @@ -0,0 +1,10 @@ +{ + "name" : "Rainbow swirl fast", + "script" : "rainbow-swirl.py", + "args" : + { + "rotation-time" : 3.0, + "brightness" : 1.0, + "reverse" : false + } +} diff --git a/effects/rainbow-swirl.json b/effects/rainbow-swirl.json new file mode 100755 index 00000000..3f7b7243 --- /dev/null +++ b/effects/rainbow-swirl.json @@ -0,0 +1,10 @@ +{ + "name" : "Rainbow swirl", + "script" : "rainbow-swirl.py", + "args" : + { + "rotation-time" : 20.0, + "brightness" : 1.0, + "reverse" : false + } +} diff --git a/include/effectengine/EffectEngine.h b/include/effectengine/EffectEngine.h index 2bf73d6b..bf33ef3a 100644 --- a/include/effectengine/EffectEngine.h +++ b/include/effectengine/EffectEngine.h @@ -26,6 +26,8 @@ public: const std::list & 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); diff --git a/libsrc/bootsequence/BootSequenceFactory.cpp b/libsrc/bootsequence/BootSequenceFactory.cpp index a7979a09..c319c884 100644 --- a/libsrc/bootsequence/BootSequenceFactory.cpp +++ b/libsrc/bootsequence/BootSequenceFactory.cpp @@ -5,13 +5,24 @@ // Bootsequence includes #include +// Effect engine includes +#include + // 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; } diff --git a/libsrc/bootsequence/EffectBootSequence.cpp b/libsrc/bootsequence/EffectBootSequence.cpp index b40d8d02..9005a269 100644 --- a/libsrc/bootsequence/EffectBootSequence.cpp +++ b/libsrc/bootsequence/EffectBootSequence.cpp @@ -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); } diff --git a/libsrc/bootsequence/EffectBootSequence.h b/libsrc/bootsequence/EffectBootSequence.h index 2d4be069..a0a9eae2 100644 --- a/libsrc/bootsequence/EffectBootSequence.h +++ b/libsrc/bootsequence/EffectBootSequence.h @@ -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; diff --git a/libsrc/effectengine/CMakeLists.txt b/libsrc/effectengine/CMakeLists.txt index 92afce2e..98edfa5c 100644 --- a/libsrc/effectengine/CMakeLists.txt +++ b/libsrc/effectengine/CMakeLists.txt @@ -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} ) diff --git a/libsrc/effectengine/EffectDefinition.schema.json b/libsrc/effectengine/EffectDefinition.schema.json new file mode 100644 index 00000000..44733252 --- /dev/null +++ b/libsrc/effectengine/EffectDefinition.schema.json @@ -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 +} diff --git a/libsrc/effectengine/EffectEngine.cpp b/libsrc/effectengine/EffectEngine.cpp index c01809b5..a343ae4e 100644 --- a/libsrc/effectengine/EffectEngine.cpp +++ b/libsrc/effectengine/EffectEngine.cpp @@ -1,8 +1,17 @@ // Python includes #include +// Stl includes +#include + // Qt includes +#include #include +#include +#include + +// hyperion util includes +#include // effect engine includes #include @@ -21,11 +30,26 @@ EffectEngine::EffectEngine(Hyperion * hyperion, const Json::Value & jsonEffectCo connect(_hyperion, SIGNAL(allChannelsCleared()), this, SLOT(allChannelsCleared())); // read all effects - std::vector 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 &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(schemaData.data()), reinterpret_cast(schemaData.data()) + schemaData.size(), schema, false); + schemaChecker.setSchema(schema); + if (!schemaChecker.validate(config)) + { + const std::list & 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); diff --git a/libsrc/effectengine/EffectEngine.qrc b/libsrc/effectengine/EffectEngine.qrc new file mode 100644 index 00000000..2f4ef03e --- /dev/null +++ b/libsrc/effectengine/EffectEngine.qrc @@ -0,0 +1,5 @@ + + + EffectDefinition.schema.json + + diff --git a/libsrc/hyperion/hyperion.schema.json b/libsrc/hyperion/hyperion.schema.json index 57d6b63f..44733252 100644 --- a/libsrc/hyperion/hyperion.schema.json +++ b/libsrc/hyperion/hyperion.schema.json @@ -204,22 +204,16 @@ { "type" : "object", "required" : false, - "additionalProperties" : - { - "type" : "object", - "required" : false, - "properties" : - { - "script" : { - "type" : "string", - "required" : true - }, - "args" : { - "type" : "object", - "required" : false + "properties" : { + "paths" : { + "type" : "array", + "required" : false, + "items" : { + "type" : "string" } } - } + }, + "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