mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	Initial AtmoOrb support including sample json config.
Former-commit-id: 51ad57afd39695095b5886966e8c71c4e47f269e
This commit is contained in:
		
							
								
								
									
										163
									
								
								doc/datasheets/AtmoOrb_sample_config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								doc/datasheets/AtmoOrb_sample_config.json
									
									
									
									
									
										Normal file
									
								
							| @@ -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" | ||||
| } | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										152
									
								
								libsrc/leddevice/LedDeviceAtmoOrb.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								libsrc/leddevice/LedDeviceAtmoOrb.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| // Local-Hyperion includes | ||||
| #include "LedDeviceAtmoOrb.h" | ||||
|  | ||||
| // qt includes | ||||
| #include <QtCore/qmath.h> | ||||
| #include <QEventLoop> | ||||
| #include <QtNetwork> | ||||
| #include <QNetworkReply> | ||||
| #include <QTime>  | ||||
|  | ||||
| #include <stdexcept> | ||||
| #include <string> | ||||
| #include <set> | ||||
|  | ||||
| AtmoOrbLight::AtmoOrbLight(unsigned int id) { | ||||
| 	// Not implemented | ||||
| } | ||||
|  | ||||
| LedDeviceAtmoOrb::LedDeviceAtmoOrb(const std::string& output, bool switchOffOnBlack, | ||||
| 		int transitiontime, int port, int numLeds, std::vector<unsigned int> 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<ColorRgb> & 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; | ||||
| } | ||||
							
								
								
									
										111
									
								
								libsrc/leddevice/LedDeviceAtmoOrb.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								libsrc/leddevice/LedDeviceAtmoOrb.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| #pragma once | ||||
|  | ||||
| // STL includes | ||||
| #include <string> | ||||
|  | ||||
| // Qt includes | ||||
| #include <QObject> | ||||
| #include <QString> | ||||
| #include <QNetworkAccessManager> | ||||
| #include <QHostAddress> | ||||
| #include <QTime>  | ||||
|  | ||||
| // Leddevice includes | ||||
| #include <leddevice/LedDevice.h> | ||||
|  | ||||
| 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<unsigned int> 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<ColorRgb> & ledValues); | ||||
|   virtual int switchOff(); | ||||
| private: | ||||
|   /// Array to save the lamps. | ||||
|   std::vector<AtmoOrbLight> 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<unsigned int> 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); | ||||
| }; | ||||
| @@ -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<unsigned int> 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(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user