From bd1a45216a9b59f6da4a3133ef01708e7be99a06 Mon Sep 17 00:00:00 2001 From: RickDB Date: Mon, 14 Mar 2016 20:19:19 +0100 Subject: [PATCH 1/8] Initial AtmoOrb support including sample json config. Former-commit-id: 51ad57afd39695095b5886966e8c71c4e47f269e --- doc/datasheets/AtmoOrb_sample_config.json | 163 ++++++++++++++++++++++ libsrc/leddevice/CMakeLists.txt | 2 + libsrc/leddevice/LedDeviceAtmoOrb.cpp | 152 ++++++++++++++++++++ libsrc/leddevice/LedDeviceAtmoOrb.h | 111 +++++++++++++++ libsrc/leddevice/LedDeviceFactory.cpp | 16 +++ 5 files changed, 444 insertions(+) create mode 100644 doc/datasheets/AtmoOrb_sample_config.json create mode 100644 libsrc/leddevice/LedDeviceAtmoOrb.cpp create mode 100644 libsrc/leddevice/LedDeviceAtmoOrb.h diff --git a/doc/datasheets/AtmoOrb_sample_config.json b/doc/datasheets/AtmoOrb_sample_config.json new file mode 100644 index 00000000..51e330a4 --- /dev/null +++ b/doc/datasheets/AtmoOrb_sample_config.json @@ -0,0 +1,163 @@ +// Automatically generated configuration file for 'Hyperion daemon' +// Generated by: HyperCon (The Hyperion deamon configuration file builder) +// Created with HyperCon V1.00.0 (11.03.2016) + +{ + /// 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 + /// APA102, Adalight, AdalightAPA102, AmbiLed, Atmo, Hyperion-USBASP-WS2801, Hyperion-USBASP-WS2812, Lightberry, Lightpack, LPD6803, LPD8806, Multi-Lightpack, P9813, Paintpack, PhilipsHUE, PiBlaster, SEDU, Test, ThinkerForge, TPM2, WS2801, WS2812b, None) + /// * [device type specific configuration] + /// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.). + /// + /// * 'Specific of Philips Hue: + /// * 'username' : The name of user registred on the Philips Hue Bridge + /// * 'switchOffOnBlack': Define if Hue light switch off when black is detected + /// * 'transitiontime' : Set the time of transition between color of Hue light + "device" : + { + "name" : "MyPi", + "type" : "atmoorb", + "output" : "239.15.18.2", + "transitiontime" : 0, + "port" : 49692, + "numLeds" : 24, + "orbIds" : [1], + "switchOffOnBlack" : true, + "colorOrder" : "rgb" + }, + + /// Color manipulation configuration used to tune the output colors to specific surroundings. + /// The configuration contains a list of color-transforms. Each transform contains the + /// following fields: + /// * 'id' : The unique identifier of the color transformation (eg 'device_1') /// * 'leds' : The indices (or index ranges) of the leds to which this color transform applies + /// (eg '0-5, 9, 11, 12-17'). The indices are zero based. /// * '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) + /// + /// Next to the list with color transforms there is also a smoothing option. + /// * '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 + /// - 'updateDelay' The delay of the output to leds (in periods of smoothing) + "color" : + { + "transform" : + [ + { + "id" : "default", + "leds" : "*", + "hsv" : + { + "saturationGain" : 1.0000, + "valueGain" : 1.0000 + }, + "red" : + { + "threshold" : 0.0000, + "gamma" : 2.2000, + "blacklevel" : 0.0000, + "whitelevel" : 1.0000 + }, + "green" : + { + "threshold" : 0.0000, + "gamma" : 2.2000, + "blacklevel" : 0.0000, + "whitelevel" : 1.0000 + }, + "blue" : + { + "threshold" : 0.0000, + "gamma" : 2.2000, + "blacklevel" : 0.0000, + "whitelevel" : 1.0000 + } + } + ], + "smoothing" : + { + "type" : "linear", + "time_ms" : 100, + "updateFrequency" : 60.0000, + "updateDelay" : 0 + } + }, + + /// The black border configuration, contains the following items: + /// * enable : true if the detector should be activated + /// * threshold : Value below which a pixel is regarded as black (value between 0.0 and 1.0) + /// * unknownFrameCnt : Number of frames without any detection before the border is set to 0 (default 600) + /// * borderFrameCnt : Number of frames before a consistent detected border gets set (default 50) + /// * maxInconsistentCnt : Number of inconsistent frames that are ignored before a new border gets a chance to proof consistency + /// * blurRemoveCnt : Number of pixels that get removed from the detected border to cut away blur (default 1) + /// * mode : Border detection mode (values=default,classic,osd) + "blackborderdetector" : + { + "enable" : false, + "threshold" : 0.01, + "unknownFrameCnt" : 600, + "borderFrameCnt" : 50, + "maxInconsistentCnt" : 10, + "blurRemoveCnt" : 1, + "mode" : "default" + }, + + /// The configuration of the effect engine, contains the following items: + /// * paths : An array with absolute location(s) of directories with effects + /// * color : Set static color after boot -> set effect to "" (empty) and input the values [R,G,B] and set duration_ms NOT to 0 (use 1) instead + /// * effect : The effect selected as 'boot sequence' + /// * duration_ms : The duration of the selected effect (0=endless) + /// * priority : The priority of the selected effect/static color (default=990) HINT: lower value result in HIGHER priority! + "effects" : + { + "paths" : + [ + "/opt/hyperion/effects" + ] + }, + + /// The configuration of the Json server which enables the json remote interface + /// * port : Port at which the json server is started + "jsonServer" : + { + "port" : 19446 + }, + + /// The configuration of the Proto server which enables the protobuffer remote interface + /// * port : Port at which the protobuffer server is started + "protoServer" : + { + "port" : 19447 + }, + + /// 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.0000, "maximum" : 1.0000 }, + "vscan" : { "minimum" : 0.0000, "maximum" : 1.0000 } + } + ], + + "endOfJson" : "endOfJson" +} \ No newline at end of file diff --git a/libsrc/leddevice/CMakeLists.txt b/libsrc/leddevice/CMakeLists.txt index da1251ca..66d61efd 100755 --- a/libsrc/leddevice/CMakeLists.txt +++ b/libsrc/leddevice/CMakeLists.txt @@ -17,6 +17,7 @@ SET(Leddevice_QT_HEADERS ${CURRENT_SOURCE_DIR}/LedDeviceAdalight.h ${CURRENT_SOURCE_DIR}/LedDeviceAdalightApa102.h ${CURRENT_SOURCE_DIR}/LedDeviceAmbiLed.h + ${CURRENT_SOURCE_DIR}/LedDeviceAtmoOrb.h ${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.h ${CURRENT_SOURCE_DIR}/LedHIDDevice.h ${CURRENT_SOURCE_DIR}/LedDeviceRawHID.h @@ -50,6 +51,7 @@ SET(Leddevice_SOURCES ${CURRENT_SOURCE_DIR}/LedDeviceAdalight.cpp ${CURRENT_SOURCE_DIR}/LedDeviceAdalightApa102.cpp ${CURRENT_SOURCE_DIR}/LedDeviceAmbiLed.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceAtmoOrb.cpp ${CURRENT_SOURCE_DIR}/LedDeviceRawHID.cpp ${CURRENT_SOURCE_DIR}/LedDeviceLightpack.cpp ${CURRENT_SOURCE_DIR}/LedDeviceMultiLightpack.cpp diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.cpp b/libsrc/leddevice/LedDeviceAtmoOrb.cpp new file mode 100644 index 00000000..e99c864b --- /dev/null +++ b/libsrc/leddevice/LedDeviceAtmoOrb.cpp @@ -0,0 +1,152 @@ +// Local-Hyperion includes +#include "LedDeviceAtmoOrb.h" + +// qt includes +#include +#include +#include +#include +#include + +#include +#include +#include + +AtmoOrbLight::AtmoOrbLight(unsigned int id) { + // Not implemented +} + +LedDeviceAtmoOrb::LedDeviceAtmoOrb(const std::string& output, bool switchOffOnBlack, + int transitiontime, int port, int numLeds, std::vector orbIds) : + multicastGroup(output.c_str()), switchOffOnBlack(switchOffOnBlack), transitiontime(transitiontime), + multiCastGroupPort(port), numLeds(numLeds), orbIds(orbIds) { + manager = new QNetworkAccessManager(); + groupAddress = QHostAddress(multicastGroup); + + udpSocket = new QUdpSocket(this); + udpSocket->bind(multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint); + + if (!udpSocket->joinMulticastGroup(groupAddress)) + { + joinedMulticastgroup = false; + } + else + { + joinedMulticastgroup = true; + } +} + +int LedDeviceAtmoOrb::write(const std::vector & ledValues) { + + // If not in multicast group return + if (!joinedMulticastgroup) + { + return 0; + } + + // Iterate through colors and set Orb color. + unsigned int idx = 0; + for (const ColorRgb& color : ledValues) + { + // If color is identical skip color setter + if(color.red == lastRed && color.green == lastGreen && color.blue == lastBlue) + { + continue; + } + + // Options parameter: + // + // 1 = force off + // 2 = use lamp smoothing and validate by Orb ID + // 4 = validate by Orb ID + // + + if (switchOffOnBlack && color.red == 0 && color.green == 0 && color.blue == 0) { + // Force to black + for (int i = 0; i < orbIds.size(); i++) { + setColor(orbIds[i], color, 1); + } + } + else + { + // Default send color + for (int i = 0; i < orbIds.size(); i++) { + setColor(orbIds[i], color, 4); + } + } + + // Store current colors + lastRed = color.red; + lastGreen = color.green; + lastBlue = color.blue; + + // Next light id. + idx++; + } + return 0; +} + +void LedDeviceAtmoOrb::setColor(unsigned int orbId, const ColorRgb& color, int commandType) { + QByteArray bytes; + bytes.resize(5 + 24 * 3); + + // Command identifier: C0FFEE + bytes[0] = 0xC0; + bytes[1] = 0xFF; + bytes[2] = 0xEE; + + // Command type + bytes[3] = 2; + + // Orb ID + bytes[4] = orbId; + + // RED / GREEN / BLUE + bytes[5] = color.red; + bytes[6] = color.green; + bytes[7] = color.blue; + + sendCommand(bytes); +} + +void LedDeviceAtmoOrb::sendCommand(const QByteArray & bytes) { + QByteArray datagram = bytes; + udpSocket->writeDatagram(datagram.data(), datagram.size(), + groupAddress, multiCastGroupPort); +} + +int LedDeviceAtmoOrb::switchOff() { + + // Default send color + for (int i = 0; i < orbIds.size(); i++) { + + QByteArray bytes; + bytes.resize(5 + 24 * 3); + + // Command identifier: C0FFEE + bytes[0] = 0xC0; + bytes[1] = 0xFF; + bytes[2] = 0xEE; + + // Command type + bytes[3] = 1; + + // Orb ID + bytes[4] = orbIds[i]; + + // RED / GREEN / BLUE + bytes[5] = 0; + bytes[6] = 0; + bytes[7] = 0; + + sendCommand(bytes); + } + return 0; +} +void LedDeviceAtmoOrb::switchOn(unsigned int nLights) { + // Not implemented +} + +LedDeviceAtmoOrb::~LedDeviceAtmoOrb() { + delete manager; +} \ No newline at end of file diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.h b/libsrc/leddevice/LedDeviceAtmoOrb.h new file mode 100644 index 00000000..794600cd --- /dev/null +++ b/libsrc/leddevice/LedDeviceAtmoOrb.h @@ -0,0 +1,111 @@ +#pragma once + +// STL includes +#include + +// Qt includes +#include +#include +#include +#include +#include + +// Leddevice includes +#include + +class QUdpSocket; + +class AtmoOrbLight { +public: + unsigned int id; + + /// + /// Constructs the light. + /// + /// @param id the orb id + AtmoOrbLight(unsigned int id); +}; + +/** + * Implementation for the AtmoOrb + * + * To use set the device to "atmoorb". + * + * @author RickDB (github) + */ +class LedDeviceAtmoOrb : public QObject, public LedDevice { + Q_OBJECT +public: + // Last color sent + int lastRed; + int lastGreen; + int lastBlue; + + // Last command sent timer + QTime timer; + + // Multicast status + bool joinedMulticastgroup; + + /// + /// Constructs the device. + /// + /// @param output is the multicast address of Orbs + /// + /// @param switchOffOnBlack kill lights for black (default: false) + /// + /// @param transitiontime is optional and not used at the moment + /// + /// @param port is the multicast port. + /// + /// @param numLeds is the total amount of leds per Orb + /// + /// @param orb ids to control + /// + LedDeviceAtmoOrb(const std::string& output, bool switchOffOnBlack = + false, int transitiontime = 0, int port = 49692, int numLeds = 24, std::vector orbIds = std::vector()); + /// + /// Destructor of this device + /// + virtual ~LedDeviceAtmoOrb(); + + /// + /// Sends the given led-color values to the Orbs + /// + /// @param ledValues The color-value per led + /// + /// @return Zero on success else negative + /// + virtual int write(const std::vector & ledValues); + virtual int switchOff(); +private: + /// Array to save the lamps. + std::vector lights; + + /// QNetworkAccessManager object for sending requests. + QNetworkAccessManager* manager; + + QString multicastGroup; + bool switchOffOnBlack; + int transitiontime; + int multiCastGroupPort; + int numLeds; + QHostAddress groupAddress; + QUdpSocket *udpSocket; + + /// Array of the light ids. + std::vector orbIds; + + /// + /// Switches the leds on. + /// + /// @param nLights the number of lights + /// + void switchOn(unsigned int nLights); + + // Set color + void setColor(unsigned int orbId, const ColorRgb& color, int commandType); + + // Send color command + void sendCommand(const QByteArray & bytes); +}; diff --git a/libsrc/leddevice/LedDeviceFactory.cpp b/libsrc/leddevice/LedDeviceFactory.cpp index 6f24072b..83625fab 100755 --- a/libsrc/leddevice/LedDeviceFactory.cpp +++ b/libsrc/leddevice/LedDeviceFactory.cpp @@ -37,6 +37,7 @@ #include "LedDeviceTpm2.h" #include "LedDeviceAtmo.h" #include "LedDeviceAdalightApa102.h" +#include "LedDeviceAtmoOrb.h" #ifdef ENABLE_WS2812BPWM #include "LedDeviceWS2812b.h" @@ -245,6 +246,21 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig) } device = new LedDevicePhilipsHue(output, username, switchOffOnBlack, transitiontime, lightIds); } + else if (type == "atmoorb") + { + const std::string output = deviceConfig["output"].asString(); + const bool switchOffOnBlack = deviceConfig.get("switchOffOnBlack", true).asBool(); + const int transitiontime = deviceConfig.get("transitiontime", 1).asInt(); + const int port = deviceConfig.get("port", 1).asInt(); + const int numLeds = deviceConfig.get("numLeds", 1).asInt(); + + std::vector orbIds; + for (Json::Value::ArrayIndex i = 0; i < deviceConfig["orbIds"].size(); i++) { + orbIds.push_back(deviceConfig["orbIds"][i].asInt()); + } + + device = new LedDeviceAtmoOrb(output, switchOffOnBlack, transitiontime, port, numLeds, orbIds); + } else if (type == "test") { const std::string output = deviceConfig["output"].asString(); From 0d8c4ac5fb09f139e6b7003ec4f3608b37fe0f8b Mon Sep 17 00:00:00 2001 From: RickDB Date: Mon, 14 Mar 2016 21:19:47 +0100 Subject: [PATCH 2/8] Correctly set buffer size based on number of leds so that it works with non-standard AtmoOrb setups. Former-commit-id: 6aec2410d6e870c8489e565269f2990e3a9e1b85 --- libsrc/leddevice/LedDeviceAtmoOrb.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.cpp b/libsrc/leddevice/LedDeviceAtmoOrb.cpp index e99c864b..869cc932 100644 --- a/libsrc/leddevice/LedDeviceAtmoOrb.cpp +++ b/libsrc/leddevice/LedDeviceAtmoOrb.cpp @@ -88,7 +88,7 @@ int LedDeviceAtmoOrb::write(const std::vector & ledValues) { void LedDeviceAtmoOrb::setColor(unsigned int orbId, const ColorRgb& color, int commandType) { QByteArray bytes; - bytes.resize(5 + 24 * 3); + bytes.resize(5 + numLeds * 3); // Command identifier: C0FFEE bytes[0] = 0xC0; @@ -121,7 +121,7 @@ int LedDeviceAtmoOrb::switchOff() { for (int i = 0; i < orbIds.size(); i++) { QByteArray bytes; - bytes.resize(5 + 24 * 3); + bytes.resize(5 + numLeds * 3); // Command identifier: C0FFEE bytes[0] = 0xC0; From fdb164da0a2d1e9e2a9f477f0cee26648ebc7e7c Mon Sep 17 00:00:00 2001 From: RickDB Date: Mon, 14 Mar 2016 23:19:20 +0100 Subject: [PATCH 3/8] Added multi Orb support, Orb ID should match that of leds index with a +1 offset (index 0 = Orb id 1 etc..) Code cleanup. Former-commit-id: af8a6df876f334c9a65b1a936b5bb85b380d86d1 --- libsrc/leddevice/LedDeviceAtmoOrb.cpp | 34 ++++++++++++--------------- libsrc/leddevice/LedDeviceAtmoOrb.h | 2 +- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.cpp b/libsrc/leddevice/LedDeviceAtmoOrb.cpp index 869cc932..901ce2d8 100644 --- a/libsrc/leddevice/LedDeviceAtmoOrb.cpp +++ b/libsrc/leddevice/LedDeviceAtmoOrb.cpp @@ -8,6 +8,7 @@ #include #include +//#include #include #include #include @@ -44,16 +45,11 @@ int LedDeviceAtmoOrb::write(const std::vector & ledValues) { return 0; } - // Iterate through colors and set Orb color. - unsigned int idx = 0; + // Iterate through colors and set Orb color + // Start off with idx 1 as 0 is reserved for controlling all orbs at once + unsigned int idx = 1; for (const ColorRgb& color : ledValues) { - // If color is identical skip color setter - if(color.red == lastRed && color.green == lastGreen && color.blue == lastBlue) - { - continue; - } - // Options parameter: // // 1 = force off @@ -63,23 +59,24 @@ int LedDeviceAtmoOrb::write(const std::vector & ledValues) { if (switchOffOnBlack && color.red == 0 && color.green == 0 && color.blue == 0) { // Force to black - for (int i = 0; i < orbIds.size(); i++) { - setColor(orbIds[i], color, 1); + for (unsigned int i = 0; i < orbIds.size(); i++) { + if (orbIds[i] == idx) + { + setColor(idx, color, 1); + } } } else { // Default send color - for (int i = 0; i < orbIds.size(); i++) { - setColor(orbIds[i], color, 4); + for (unsigned int i = 0; i < orbIds.size(); i++) { + if (orbIds[i] == idx) + { + setColor(idx, color, 4); + } } } - // Store current colors - lastRed = color.red; - lastGreen = color.green; - lastBlue = color.blue; - // Next light id. idx++; } @@ -118,8 +115,7 @@ void LedDeviceAtmoOrb::sendCommand(const QByteArray & bytes) { int LedDeviceAtmoOrb::switchOff() { // Default send color - for (int i = 0; i < orbIds.size(); i++) { - + for (unsigned int i = 0; i < orbIds.size(); i++) { QByteArray bytes; bytes.resize(5 + numLeds * 3); diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.h b/libsrc/leddevice/LedDeviceAtmoOrb.h index 794600cd..0517ff0f 100644 --- a/libsrc/leddevice/LedDeviceAtmoOrb.h +++ b/libsrc/leddevice/LedDeviceAtmoOrb.h @@ -52,7 +52,7 @@ public: /// /// @param output is the multicast address of Orbs /// - /// @param switchOffOnBlack kill lights for black (default: false) + /// @param switchOffOnBlack turn off Orbs on black (default: false) /// /// @param transitiontime is optional and not used at the moment /// From 5be072be24e681ce0f024f09897b601ceab641de Mon Sep 17 00:00:00 2001 From: RickDB Date: Tue, 15 Mar 2016 11:10:04 +0100 Subject: [PATCH 4/8] Added more inline documentation. Simplified joinedMulticastgroup. Removed non-required functions and includes. Former-commit-id: 829b5c6f89ee1e9a4789dbe18f911b05e3b5d8e1 --- libsrc/leddevice/LedDeviceAtmoOrb.cpp | 16 +--------- libsrc/leddevice/LedDeviceAtmoOrb.h | 44 +++++++++++++++++---------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.cpp b/libsrc/leddevice/LedDeviceAtmoOrb.cpp index 901ce2d8..032d566f 100644 --- a/libsrc/leddevice/LedDeviceAtmoOrb.cpp +++ b/libsrc/leddevice/LedDeviceAtmoOrb.cpp @@ -6,9 +6,7 @@ #include #include #include -#include -//#include #include #include #include @@ -27,14 +25,7 @@ LedDeviceAtmoOrb::LedDeviceAtmoOrb(const std::string& output, bool switchOffOnBl udpSocket = new QUdpSocket(this); udpSocket->bind(multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint); - if (!udpSocket->joinMulticastGroup(groupAddress)) - { - joinedMulticastgroup = false; - } - else - { - joinedMulticastgroup = true; - } + joinedMulticastgroup = udpSocket->joinMulticastGroup(groupAddress); } int LedDeviceAtmoOrb::write(const std::vector & ledValues) { @@ -113,8 +104,6 @@ void LedDeviceAtmoOrb::sendCommand(const QByteArray & bytes) { } int LedDeviceAtmoOrb::switchOff() { - - // Default send color for (unsigned int i = 0; i < orbIds.size(); i++) { QByteArray bytes; bytes.resize(5 + numLeds * 3); @@ -139,9 +128,6 @@ int LedDeviceAtmoOrb::switchOff() { } return 0; } -void LedDeviceAtmoOrb::switchOn(unsigned int nLights) { - // Not implemented -} LedDeviceAtmoOrb::~LedDeviceAtmoOrb() { delete manager; diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.h b/libsrc/leddevice/LedDeviceAtmoOrb.h index 0517ff0f..3924023c 100644 --- a/libsrc/leddevice/LedDeviceAtmoOrb.h +++ b/libsrc/leddevice/LedDeviceAtmoOrb.h @@ -8,7 +8,6 @@ #include #include #include -#include // Leddevice includes #include @@ -41,9 +40,6 @@ public: int lastGreen; int lastBlue; - // Last command sent timer - QTime timer; - // Multicast status bool joinedMulticastgroup; @@ -60,7 +56,7 @@ public: /// /// @param numLeds is the total amount of leds per Orb /// - /// @param orb ids to control + /// @param array containing orb ids /// LedDeviceAtmoOrb(const std::string& output, bool switchOffOnBlack = false, int transitiontime = 0, int port = 49692, int numLeds = 24, std::vector orbIds = std::vector()); @@ -79,33 +75,49 @@ public: virtual int write(const std::vector & ledValues); virtual int switchOff(); private: - /// Array to save the lamps. - std::vector lights; - /// QNetworkAccessManager object for sending requests. QNetworkAccessManager* manager; + /// String containing multicast group IP address QString multicastGroup; + + /// Switch off when detecting black bool switchOffOnBlack; + + /// Transition time between colors (not implemented) int transitiontime; + + /// Multicast port to send data to int multiCastGroupPort; + + /// Number of leds in Orb, used to determine buffer size int numLeds; + + /// QHostAddress object of multicast group IP address QHostAddress groupAddress; + + /// QUdpSocket object used to send data over QUdpSocket *udpSocket; - /// Array of the light ids. + /// Array of the orb ids. std::vector orbIds; - + /// - /// Switches the leds on. + /// Set Orbcolor /// - /// @param nLights the number of lights + /// @param orbId the orb id + /// + /// @param color which color to set + /// + /// + /// @param commandType which type of command to send (off / smoothing / etc..) /// - void switchOn(unsigned int nLights); - - // Set color void setColor(unsigned int orbId, const ColorRgb& color, int commandType); - // Send color command + /// + /// Send Orb command + /// + /// @param bytes the byte array containing command to send over multicast + /// void sendCommand(const QByteArray & bytes); }; From dcc6a9b449ccb393297845b49d86ee7ba087f29d Mon Sep 17 00:00:00 2001 From: RickDB Date: Tue, 15 Mar 2016 11:45:25 +0100 Subject: [PATCH 5/8] Make sure the byte array is empty before filling it. Former-commit-id: 64f76fa358234e131377ecfabf196f3c7324e79f --- libsrc/leddevice/LedDeviceAtmoOrb.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.cpp b/libsrc/leddevice/LedDeviceAtmoOrb.cpp index 032d566f..62382ddf 100644 --- a/libsrc/leddevice/LedDeviceAtmoOrb.cpp +++ b/libsrc/leddevice/LedDeviceAtmoOrb.cpp @@ -76,7 +76,8 @@ int LedDeviceAtmoOrb::write(const std::vector & ledValues) { void LedDeviceAtmoOrb::setColor(unsigned int orbId, const ColorRgb& color, int commandType) { QByteArray bytes; - bytes.resize(5 + numLeds * 3); + bytes.resize(5 + numLeds * 3); + bytes.fill('\0'); // Command identifier: C0FFEE bytes[0] = 0xC0; @@ -106,7 +107,8 @@ void LedDeviceAtmoOrb::sendCommand(const QByteArray & bytes) { int LedDeviceAtmoOrb::switchOff() { for (unsigned int i = 0; i < orbIds.size(); i++) { QByteArray bytes; - bytes.resize(5 + numLeds * 3); + bytes.resize(5 + numLeds * 3); + bytes.fill('\0'); // Command identifier: C0FFEE bytes[0] = 0xC0; From e5545eaac0570ab50cd9178a5ae15a15096f253b Mon Sep 17 00:00:00 2001 From: RickDB Date: Tue, 15 Mar 2016 12:03:00 +0100 Subject: [PATCH 6/8] Code reformatted. Former-commit-id: 6f3688791602efb33389c3ba789e7a8a723ee290 --- libsrc/leddevice/LedDeviceAtmoOrb.cpp | 197 +++++++++++++------------- libsrc/leddevice/LedDeviceAtmoOrb.h | 176 ++++++++++++----------- 2 files changed, 187 insertions(+), 186 deletions(-) diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.cpp b/libsrc/leddevice/LedDeviceAtmoOrb.cpp index 62382ddf..4ef3486d 100644 --- a/libsrc/leddevice/LedDeviceAtmoOrb.cpp +++ b/libsrc/leddevice/LedDeviceAtmoOrb.cpp @@ -12,125 +12,120 @@ #include AtmoOrbLight::AtmoOrbLight(unsigned int id) { - // Not implemented + // Not implemented } -LedDeviceAtmoOrb::LedDeviceAtmoOrb(const std::string& output, bool switchOffOnBlack, - int transitiontime, int port, int numLeds, std::vector orbIds) : - multicastGroup(output.c_str()), switchOffOnBlack(switchOffOnBlack), transitiontime(transitiontime), - multiCastGroupPort(port), numLeds(numLeds), orbIds(orbIds) { - manager = new QNetworkAccessManager(); - groupAddress = QHostAddress(multicastGroup); +LedDeviceAtmoOrb::LedDeviceAtmoOrb(const std::string &output, bool switchOffOnBlack, + int transitiontime, int port, int numLeds, std::vector orbIds) : + multicastGroup(output.c_str()), switchOffOnBlack(switchOffOnBlack), transitiontime(transitiontime), + multiCastGroupPort(port), numLeds(numLeds), orbIds(orbIds) { + manager = new QNetworkAccessManager(); + groupAddress = QHostAddress(multicastGroup); - udpSocket = new QUdpSocket(this); - udpSocket->bind(multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint); + udpSocket = new QUdpSocket(this); + udpSocket->bind(multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint); - joinedMulticastgroup = udpSocket->joinMulticastGroup(groupAddress); + joinedMulticastgroup = udpSocket->joinMulticastGroup(groupAddress); } -int LedDeviceAtmoOrb::write(const std::vector & ledValues) { +int LedDeviceAtmoOrb::write(const std::vector &ledValues) { - // If not in multicast group return - if (!joinedMulticastgroup) - { + // If not in multicast group return + if (!joinedMulticastgroup) { + return 0; + } + + // Iterate through colors and set Orb color + // Start off with idx 1 as 0 is reserved for controlling all orbs at once + unsigned int idx = 1; + for (const ColorRgb &color : ledValues) { + // Options parameter: + // + // 1 = force off + // 2 = use lamp smoothing and validate by Orb ID + // 4 = validate by Orb ID + // + + if (switchOffOnBlack && color.red == 0 && color.green == 0 && color.blue == 0) { + // Force to black + for (unsigned int i = 0; i < orbIds.size(); i++) { + if (orbIds[i] == idx) { + setColor(idx, color, 1); + } + } + } + else { + // Default send color + for (unsigned int i = 0; i < orbIds.size(); i++) { + if (orbIds[i] == idx) { + setColor(idx, color, 4); + } + } + } + + // Next light id. + idx++; + } return 0; - } - - // Iterate through colors and set Orb color - // Start off with idx 1 as 0 is reserved for controlling all orbs at once - unsigned int idx = 1; - for (const ColorRgb& color : ledValues) - { - // Options parameter: - // - // 1 = force off - // 2 = use lamp smoothing and validate by Orb ID - // 4 = validate by Orb ID - // - - if (switchOffOnBlack && color.red == 0 && color.green == 0 && color.blue == 0) { - // Force to black - for (unsigned int i = 0; i < orbIds.size(); i++) { - if (orbIds[i] == idx) - { - setColor(idx, color, 1); - } - } - } - else - { - // Default send color - for (unsigned int i = 0; i < orbIds.size(); i++) { - if (orbIds[i] == idx) - { - setColor(idx, color, 4); - } - } - } - - // Next light id. - idx++; - } - return 0; } -void LedDeviceAtmoOrb::setColor(unsigned int orbId, const ColorRgb& color, int commandType) { - QByteArray bytes; - bytes.resize(5 + numLeds * 3); - bytes.fill('\0'); - - // Command identifier: C0FFEE - bytes[0] = 0xC0; - bytes[1] = 0xFF; - bytes[2] = 0xEE; - - // Command type - bytes[3] = 2; - - // Orb ID - bytes[4] = orbId; - - // RED / GREEN / BLUE - bytes[5] = color.red; - bytes[6] = color.green; - bytes[7] = color.blue; +void LedDeviceAtmoOrb::setColor(unsigned int orbId, const ColorRgb &color, int commandType) { + QByteArray bytes; + bytes.resize(5 + numLeds * 3); + bytes.fill('\0'); - sendCommand(bytes); + // Command identifier: C0FFEE + bytes[0] = 0xC0; + bytes[1] = 0xFF; + bytes[2] = 0xEE; + + // Command type + bytes[3] = 2; + + // Orb ID + bytes[4] = orbId; + + // RED / GREEN / BLUE + bytes[5] = color.red; + bytes[6] = color.green; + bytes[7] = color.blue; + + sendCommand(bytes); } -void LedDeviceAtmoOrb::sendCommand(const QByteArray & bytes) { - QByteArray datagram = bytes; - udpSocket->writeDatagram(datagram.data(), datagram.size(), - groupAddress, multiCastGroupPort); +void LedDeviceAtmoOrb::sendCommand(const QByteArray &bytes) { + QByteArray datagram = bytes; + udpSocket->writeDatagram(datagram.data(), datagram.size(), + groupAddress, multiCastGroupPort); } int LedDeviceAtmoOrb::switchOff() { - for (unsigned int i = 0; i < orbIds.size(); i++) { - QByteArray bytes; - bytes.resize(5 + numLeds * 3); - bytes.fill('\0'); - - // Command identifier: C0FFEE - bytes[0] = 0xC0; - bytes[1] = 0xFF; - bytes[2] = 0xEE; - - // Command type - bytes[3] = 1; - - // Orb ID - bytes[4] = orbIds[i]; - - // RED / GREEN / BLUE - bytes[5] = 0; - bytes[6] = 0; - bytes[7] = 0; + for (unsigned int i = 0; i < orbIds.size(); i++) { + QByteArray bytes; + bytes.resize(5 + numLeds * 3); + bytes.fill('\0'); - sendCommand(bytes); - } - return 0; + // Command identifier: C0FFEE + bytes[0] = 0xC0; + bytes[1] = 0xFF; + bytes[2] = 0xEE; + + // Command type + bytes[3] = 1; + + // Orb ID + bytes[4] = orbIds[i]; + + // RED / GREEN / BLUE + bytes[5] = 0; + bytes[6] = 0; + bytes[7] = 0; + + sendCommand(bytes); + } + return 0; } LedDeviceAtmoOrb::~LedDeviceAtmoOrb() { - delete manager; + delete manager; } \ No newline at end of file diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.h b/libsrc/leddevice/LedDeviceAtmoOrb.h index 3924023c..d425b06a 100644 --- a/libsrc/leddevice/LedDeviceAtmoOrb.h +++ b/libsrc/leddevice/LedDeviceAtmoOrb.h @@ -16,13 +16,13 @@ class QUdpSocket; class AtmoOrbLight { public: - unsigned int id; + unsigned int id; - /// - /// Constructs the light. - /// - /// @param id the orb id - AtmoOrbLight(unsigned int id); + /// + /// Constructs the light. + /// + /// @param id the orb id + AtmoOrbLight(unsigned int id); }; /** @@ -33,91 +33,97 @@ public: * @author RickDB (github) */ class LedDeviceAtmoOrb : public QObject, public LedDevice { - Q_OBJECT + Q_OBJECT public: - // Last color sent - int lastRed; - int lastGreen; - int lastBlue; + // Last color sent + int lastRed; + int lastGreen; + int lastBlue; - // Multicast status - bool joinedMulticastgroup; + // Multicast status + bool joinedMulticastgroup; - /// - /// Constructs the device. - /// - /// @param output is the multicast address of Orbs - /// - /// @param switchOffOnBlack turn off Orbs on black (default: false) - /// - /// @param transitiontime is optional and not used at the moment - /// - /// @param port is the multicast port. - /// - /// @param numLeds is the total amount of leds per Orb - /// - /// @param array containing orb ids - /// - LedDeviceAtmoOrb(const std::string& output, bool switchOffOnBlack = - false, int transitiontime = 0, int port = 49692, int numLeds = 24, std::vector orbIds = std::vector()); - /// - /// Destructor of this device - /// - virtual ~LedDeviceAtmoOrb(); + /// + /// Constructs the device. + /// + /// @param output is the multicast address of Orbs + /// + /// @param switchOffOnBlack turn off Orbs on black (default: false) + /// + /// @param transitiontime is optional and not used at the moment + /// + /// @param port is the multicast port. + /// + /// @param numLeds is the total amount of leds per Orb + /// + /// @param array containing orb ids + /// + LedDeviceAtmoOrb(const std::string &output, bool switchOffOnBlack = + false, int transitiontime = 0, int port = 49692, int numLeds = 24, + std::vector orbIds = std::vector < unsigned int + + >()); + + /// + /// Destructor of this device + /// + virtual ~LedDeviceAtmoOrb(); + + /// + /// Sends the given led-color values to the Orbs + /// + /// @param ledValues The color-value per led + /// + /// @return Zero on success else negative + /// + virtual int write(const std::vector &ledValues); + + virtual int switchOff(); - /// - /// Sends the given led-color values to the Orbs - /// - /// @param ledValues The color-value per led - /// - /// @return Zero on success else negative - /// - virtual int write(const std::vector & ledValues); - virtual int switchOff(); private: - /// QNetworkAccessManager object for sending requests. - QNetworkAccessManager* manager; + /// QNetworkAccessManager object for sending requests. + QNetworkAccessManager *manager; - /// String containing multicast group IP address - QString multicastGroup; - - /// Switch off when detecting black - bool switchOffOnBlack; - - /// Transition time between colors (not implemented) - int transitiontime; - - /// Multicast port to send data to - int multiCastGroupPort; - - /// Number of leds in Orb, used to determine buffer size - int numLeds; - - /// QHostAddress object of multicast group IP address - QHostAddress groupAddress; - - /// QUdpSocket object used to send data over - QUdpSocket *udpSocket; + /// String containing multicast group IP address + QString multicastGroup; - /// Array of the orb ids. - std::vector orbIds; - - /// - /// Set Orbcolor - /// - /// @param orbId the orb id - /// - /// @param color which color to set - /// - /// - /// @param commandType which type of command to send (off / smoothing / etc..) - /// - void setColor(unsigned int orbId, const ColorRgb& color, int commandType); + /// Switch off when detecting black + bool switchOffOnBlack; - /// - /// Send Orb command - /// - /// @param bytes the byte array containing command to send over multicast - /// - void sendCommand(const QByteArray & bytes); + /// Transition time between colors (not implemented) + int transitiontime; + + /// Multicast port to send data to + int multiCastGroupPort; + + /// Number of leds in Orb, used to determine buffer size + int numLeds; + + /// QHostAddress object of multicast group IP address + QHostAddress groupAddress; + + /// QUdpSocket object used to send data over + QUdpSocket *udpSocket; + + /// Array of the orb ids. + std::vector orbIds; + + /// + /// Set Orbcolor + /// + /// @param orbId the orb id + /// + /// @param color which color to set + /// + /// + /// @param commandType which type of command to send (off / smoothing / etc..) + /// + void setColor(unsigned int orbId, const ColorRgb &color, int commandType); + + /// + /// Send Orb command + /// + /// @param bytes the byte array containing command to send over multicast + /// + void sendCommand(const QByteArray &bytes); }; From f783c59185c3274b47923b8efaf0ee0e863f0357 Mon Sep 17 00:00:00 2001 From: RickDB Date: Tue, 15 Mar 2016 12:06:24 +0100 Subject: [PATCH 7/8] Corrected indenting in LedDeviceFactory.cpp. Former-commit-id: 31713a4a0ce9bd25fd1e39969bbb481363a80167 --- libsrc/leddevice/LedDeviceFactory.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libsrc/leddevice/LedDeviceFactory.cpp b/libsrc/leddevice/LedDeviceFactory.cpp index 83625fab..8d39ea30 100755 --- a/libsrc/leddevice/LedDeviceFactory.cpp +++ b/libsrc/leddevice/LedDeviceFactory.cpp @@ -248,15 +248,15 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig) } else if (type == "atmoorb") { - const std::string output = deviceConfig["output"].asString(); - const bool switchOffOnBlack = deviceConfig.get("switchOffOnBlack", true).asBool(); - const int transitiontime = deviceConfig.get("transitiontime", 1).asInt(); - const int port = deviceConfig.get("port", 1).asInt(); - const int numLeds = deviceConfig.get("numLeds", 1).asInt(); + const std::string output = deviceConfig["output"].asString(); + const bool switchOffOnBlack = deviceConfig.get("switchOffOnBlack", true).asBool(); + const int transitiontime = deviceConfig.get("transitiontime", 1).asInt(); + const int port = deviceConfig.get("port", 1).asInt(); + const int numLeds = deviceConfig.get("numLeds", 1).asInt(); - std::vector orbIds; - for (Json::Value::ArrayIndex i = 0; i < deviceConfig["orbIds"].size(); i++) { - orbIds.push_back(deviceConfig["orbIds"][i].asInt()); + std::vector orbIds; + for (Json::Value::ArrayIndex i = 0; i < deviceConfig["orbIds"].size(); i++) { + orbIds.push_back(deviceConfig["orbIds"][i].asInt()); } device = new LedDeviceAtmoOrb(output, switchOffOnBlack, transitiontime, port, numLeds, orbIds); From 7adb339deac67b67c796fac7838fe3293e0131b1 Mon Sep 17 00:00:00 2001 From: RickDB Date: Tue, 15 Mar 2016 18:37:55 +0100 Subject: [PATCH 8/8] Updated orbIds config setting and sample config. Former-commit-id: 350db40b53d04efbb43dc8c87c88bf2eb378fa6b --- doc/datasheets/AtmoOrb_sample_config.json | 12 +++++++----- libsrc/leddevice/LedDeviceFactory.cpp | 24 ++++++++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/doc/datasheets/AtmoOrb_sample_config.json b/doc/datasheets/AtmoOrb_sample_config.json index 51e330a4..1c81790a 100644 --- a/doc/datasheets/AtmoOrb_sample_config.json +++ b/doc/datasheets/AtmoOrb_sample_config.json @@ -10,10 +10,12 @@ /// * [device type specific configuration] /// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.). /// - /// * 'Specific of Philips Hue: - /// * 'username' : The name of user registred on the Philips Hue Bridge - /// * 'switchOffOnBlack': Define if Hue light switch off when black is detected - /// * 'transitiontime' : Set the time of transition between color of Hue light + /// * 'Specific for AtmoOrb: + /// * 'transitiontime' : Set the time of transition between color of Orb (not implemented) + /// * 'port' : Multicast UDP port + /// * 'numLeds' : Number of leds in Orb + /// * 'orbIds' : The Orb ids to use + /// * 'switchOffOnBlack': Define if Orb is to switch off when black is detected "device" : { "name" : "MyPi", @@ -22,7 +24,7 @@ "transitiontime" : 0, "port" : 49692, "numLeds" : 24, - "orbIds" : [1], + "orbIds" : "1", "switchOffOnBlack" : true, "colorOrder" : "rgb" }, diff --git a/libsrc/leddevice/LedDeviceFactory.cpp b/libsrc/leddevice/LedDeviceFactory.cpp index 8d39ea30..49b197f6 100755 --- a/libsrc/leddevice/LedDeviceFactory.cpp +++ b/libsrc/leddevice/LedDeviceFactory.cpp @@ -253,13 +253,27 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig) const int transitiontime = deviceConfig.get("transitiontime", 1).asInt(); const int port = deviceConfig.get("port", 1).asInt(); const int numLeds = deviceConfig.get("numLeds", 1).asInt(); - + const std::string orbId = deviceConfig["orbIds"].asString(); std::vector orbIds; - for (Json::Value::ArrayIndex i = 0; i < deviceConfig["orbIds"].size(); i++) { - orbIds.push_back(deviceConfig["orbIds"][i].asInt()); - } - device = new LedDeviceAtmoOrb(output, switchOffOnBlack, transitiontime, port, numLeds, orbIds); + // If we find multiple Orb ids separate them and add to list + const std::string separator (","); + if (orbId.find(separator) != std::string::npos) { + std::stringstream ss(orbId); + std::vector output; + unsigned int i; + while (ss >> i) { + orbIds.push_back(i); + if (ss.peek() == ',' || ss.peek() == ' ') + ss.ignore(); + } + } + else + { + orbIds.push_back(atoi(orbId.c_str())); + } + + device = new LedDeviceAtmoOrb(output, switchOffOnBlack, transitiontime, port, numLeds, orbIds); } else if (type == "test") {