mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Disentangle LedDevice/LinearColorSmoothing, Bug Fixes & Test support (#654)
* Handle Exceptions in main & Pythoninit * Have SSDPDiscover generic again * Have SSDPDiscover generic again * Change Info- to Debug logs as technical service messages * Nanoleaf - When switched on, ensure UDP mode * Include SQL Database in Cross-Compile instructions * Fix Clazy (QT code checker) and clang Warnings * Stop LedDevice:write for disabled device * Nanoleaf: Fix uint printfs * NanoLeaf: Fix indents to tabs * NanoLeaf - Add debug verbosity switches * Device switchability support, FileDevice with timestamp support * Nanoleaf Light Panels now support External Control V2 * Enhance LedDeviceFile by Timestamp + fix readyness * Stop color stream, if LedDevice disabled * Nanoleaf - remove switchability * Fix MultiColorAdjustment, if led-range is greater lednum * Fix logging * LedFileDevice/LedDevice - add testing support * New "Led Test" effect * LedDeviceFile - Add chrono include + Allow Led rewrites for testing * Stabilize Effects for LedDevices where latchtime = 0 * Update LedDeviceFile, allow latchtime = 0 * Distangle LinearColorSmoothing and LEDDevice, Fix Effect configuration updates * Updates LedDeviceFile - Initialize via Open * Updates LedDeviceNanoleaf - Initialize via Open, Remove throwing exceptions * Updates ProviderUDP - Remove throwing exceptions * Framebuffer - Use precise timer * TestSpi - Align to LedDevice updates * Pretty Print CrossCompileHowTo as markdown-file * Ensure that output is only written when LedDevice is ready * Align APA102 Device to new device staging * Logger - Remove clang warnings on extra semicolon * Devices SPI - Align to Device stages and methods * Fix cppcheck and clang findings * Add Code-Template for new Devices * Align devices to stages and methods, clean-up some code * Allow to reopen LedDevice without restart * Revert change "Remove Connect (PriorityMuxer::visiblePriorityChanged -> Hyperion::update) due to double writes" * Remove visiblePriorityChanged from LedDevice to decouple LedDevice from hyperion logic * Expose LedDevice getLedCount and align signedness
This commit is contained in:
@@ -2,58 +2,105 @@
|
||||
#include "LedDeviceAtmoOrb.h"
|
||||
|
||||
// qt includes
|
||||
#include <QtCore/qmath.h>
|
||||
#include <QEventLoop>
|
||||
#include <QtNetwork>
|
||||
#include <QNetworkReply>
|
||||
#include <QStringList>
|
||||
|
||||
AtmoOrbLight::AtmoOrbLight(unsigned int id)
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
LedDeviceAtmoOrb::LedDeviceAtmoOrb(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
, _networkmanager (nullptr)
|
||||
, _udpSocket (nullptr)
|
||||
, _multiCastGroupPort (49692)
|
||||
, joinedMulticastgroup (false)
|
||||
, _useOrbSmoothing (false)
|
||||
, _transitiontime (0)
|
||||
, _skipSmoothingDiff (0)
|
||||
, _numLeds (24)
|
||||
|
||||
{
|
||||
init(deviceConfig);
|
||||
_manager = new QNetworkAccessManager();
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceAtmoOrb::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceAtmoOrb(deviceConfig);
|
||||
}
|
||||
|
||||
LedDeviceAtmoOrb::~LedDeviceAtmoOrb()
|
||||
{
|
||||
_networkmanager->deleteLater();
|
||||
_udpSocket->deleteLater();
|
||||
}
|
||||
|
||||
bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
if ( isInitOK )
|
||||
{
|
||||
|
||||
_multicastGroup = deviceConfig["output"].toString().toStdString().c_str();
|
||||
_useOrbSmoothing = deviceConfig["useOrbSmoothing"].toBool(false);
|
||||
_transitiontime = deviceConfig["transitiontime"].toInt(0);
|
||||
_skipSmoothingDiff = deviceConfig["skipSmoothingDiff"].toInt(0);
|
||||
_multiCastGroupPort = static_cast<quint16>(deviceConfig["port"].toInt(49692));
|
||||
_numLeds = deviceConfig["numLeds"].toInt(24);
|
||||
|
||||
const QStringList orbIds = deviceConfig["orbIds"].toString().simplified().remove(" ").split(",", QString::SkipEmptyParts);
|
||||
_orbIds.clear();
|
||||
|
||||
foreach(auto & id_str, orbIds)
|
||||
{
|
||||
bool ok;
|
||||
int id = id_str.toInt(&ok);
|
||||
if (ok)
|
||||
_orbIds.append(id);
|
||||
else
|
||||
Error(_log, "orb id '%s' is not a number", QSTRING_CSTR(id_str));
|
||||
}
|
||||
|
||||
if ( _orbIds.size() == 0 )
|
||||
{
|
||||
this->setInError("No valid OrbIds found!");
|
||||
isInitOK = false;
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceAtmoOrb::initNetwork()
|
||||
{
|
||||
bool isInitOK = true;
|
||||
|
||||
// TODO: Add Network-Error handling
|
||||
_networkmanager = new QNetworkAccessManager();
|
||||
_groupAddress = QHostAddress(_multicastGroup);
|
||||
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
_udpSocket->bind(QHostAddress::AnyIPv4, _multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
|
||||
|
||||
joinedMulticastgroup = _udpSocket->joinMulticastGroup(_groupAddress);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
|
||||
int LedDeviceAtmoOrb::open()
|
||||
{
|
||||
_multicastGroup = deviceConfig["output"].toString().toStdString().c_str();
|
||||
_useOrbSmoothing = deviceConfig["useOrbSmoothing"].toBool(false);
|
||||
_transitiontime = deviceConfig["transitiontime"].toInt(0);
|
||||
_skipSmoothingDiff = deviceConfig["skipSmoothingDiff"].toInt(0);
|
||||
_multiCastGroupPort = deviceConfig["port"].toInt(49692);
|
||||
_numLeds = deviceConfig["numLeds"].toInt(24);
|
||||
|
||||
const QStringList orbIds = deviceConfig["orbIds"].toString().simplified().remove(" ").split(",", QString::SkipEmptyParts);
|
||||
_orbIds.clear();
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
|
||||
foreach(auto & id_str, orbIds)
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
bool ok;
|
||||
int id = id_str.toInt(&ok);
|
||||
if (ok)
|
||||
_orbIds.append(id);
|
||||
if ( !initNetwork() )
|
||||
{
|
||||
this->setInError( "Network error!" );
|
||||
}
|
||||
else
|
||||
Error(_log, "orb id '%s' is not a number", QSTRING_CSTR(id_str));
|
||||
{
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return _orbIds.size() > 0;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceAtmoOrb::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceAtmoOrb(deviceConfig);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
|
||||
@@ -79,7 +126,7 @@ int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
|
||||
|
||||
// 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;
|
||||
int idx = 1;
|
||||
|
||||
for (const ColorRgb &color : ledValues)
|
||||
{
|
||||
@@ -125,7 +172,7 @@ int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LedDeviceAtmoOrb::setColor(unsigned int orbId, const ColorRgb &color, int commandType)
|
||||
void LedDeviceAtmoOrb::setColor(int orbId, const ColorRgb &color, int commandType)
|
||||
{
|
||||
QByteArray bytes;
|
||||
bytes.resize(5 + _numLeds * 3);
|
||||
@@ -155,17 +202,3 @@ void LedDeviceAtmoOrb::sendCommand(const QByteArray &bytes)
|
||||
QByteArray datagram = bytes;
|
||||
_udpSocket->writeDatagram(datagram.data(), datagram.size(), _groupAddress, _multiCastGroupPort);
|
||||
}
|
||||
|
||||
int LedDeviceAtmoOrb::switchOff()
|
||||
{
|
||||
for (auto orbId : _orbIds)
|
||||
{
|
||||
setColor(orbId, ColorRgb::BLACK, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LedDeviceAtmoOrb::~LedDeviceAtmoOrb()
|
||||
{
|
||||
delete _manager;
|
||||
}
|
||||
|
@@ -5,25 +5,13 @@
|
||||
#include <QString>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QHostAddress>
|
||||
#include <QMap>
|
||||
#include <QVector>
|
||||
|
||||
// Leddevice includes
|
||||
// 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
|
||||
*
|
||||
@@ -35,52 +23,87 @@ class LedDeviceAtmoOrb : public LedDevice
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// Last send color map
|
||||
QMap<int, int> lastColorRedMap;
|
||||
QMap<int, int> lastColorGreenMap;
|
||||
QMap<int, int> lastColorBlueMap;
|
||||
|
||||
// Multicast status
|
||||
bool joinedMulticastgroup;
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceAtmoOrb(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceAtmoOrb(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Destructor of this device
|
||||
///
|
||||
virtual ~LedDeviceAtmoOrb();
|
||||
virtual ~LedDeviceAtmoOrb() override;
|
||||
|
||||
virtual int switchOff();
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
///
|
||||
/// @return True if success
|
||||
bool initNetwork();
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// 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 write(const std::vector <ColorRgb> &ledValues) override;
|
||||
|
||||
///
|
||||
/// 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(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);
|
||||
|
||||
/// QNetworkAccessManager object for sending requests.
|
||||
QNetworkAccessManager *_manager;
|
||||
QNetworkAccessManager *_networkmanager;
|
||||
|
||||
/// QUdpSocket object used to send data over
|
||||
QUdpSocket * _udpSocket;
|
||||
|
||||
/// QHostAddress object of multicast group IP address
|
||||
QHostAddress _groupAddress;
|
||||
|
||||
/// String containing multicast group IP address
|
||||
QString _multicastGroup;
|
||||
|
||||
/// Multicast port to send data to
|
||||
quint16 _multiCastGroupPort;
|
||||
|
||||
// Multicast status
|
||||
bool joinedMulticastgroup;
|
||||
|
||||
/// use Orbs own (external) smoothing algorithm
|
||||
bool _useOrbSmoothing;
|
||||
|
||||
@@ -90,34 +113,21 @@ private:
|
||||
// Maximum allowed color difference, will skip Orb (external) smoothing once reached
|
||||
int _skipSmoothingDiff;
|
||||
|
||||
/// 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.
|
||||
QVector<unsigned int> _orbIds;
|
||||
QVector<int> _orbIds;
|
||||
|
||||
// Last send color map
|
||||
QMap<int, int> lastColorRedMap;
|
||||
QMap<int, int> lastColorGreenMap;
|
||||
QMap<int, int> lastColorBlueMap;
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// 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);
|
||||
};
|
||||
|
@@ -9,13 +9,13 @@ LedDeviceFadeCandy::LedDeviceFadeCandy(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
, _client(nullptr)
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_client = new QTcpSocket(this);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDeviceFadeCandy::~LedDeviceFadeCandy()
|
||||
{
|
||||
_client->close();
|
||||
_client->deleteLater();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
|
||||
@@ -25,45 +25,90 @@ LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
if (_ledCount > MAX_NUM_LEDS)
|
||||
if ( isInitOK )
|
||||
{
|
||||
Error(_log, "fadecandy/opc: Invalid attempt to write led values. Not more than %d leds are allowed.", MAX_NUM_LEDS);
|
||||
return false;
|
||||
if (_ledCount > MAX_NUM_LEDS)
|
||||
{
|
||||
//Error(_log, "fadecandy/opc: Invalid attempt to write led values. Not more than %d leds are allowed.", MAX_NUM_LEDS);
|
||||
QString errortext = QString ("More LED configured than allowed (%1)").arg(MAX_NUM_LEDS);
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_host = deviceConfig["output"].toString("127.0.0.1");
|
||||
_port = deviceConfig["port"].toInt(7890);
|
||||
_channel = deviceConfig["channel"].toInt(0);
|
||||
_gamma = deviceConfig["gamma"].toDouble(1.0);
|
||||
_noDither = ! deviceConfig["dither"].toBool(false);
|
||||
_noInterp = ! deviceConfig["interpolation"].toBool(false);
|
||||
_manualLED = deviceConfig["manualLed"].toBool(false);
|
||||
_ledOnOff = deviceConfig["ledOn"].toBool(false);
|
||||
_setFcConfig = deviceConfig["setFcConfig"].toBool(false);
|
||||
|
||||
_whitePoint_r = 1.0;
|
||||
_whitePoint_g = 1.0;
|
||||
_whitePoint_b = 1.0;
|
||||
|
||||
const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray();
|
||||
if ( !whitePointConfig.isEmpty() && whitePointConfig.size() == 3 )
|
||||
{
|
||||
_whitePoint_r = whitePointConfig[0].toDouble() / 255.0;
|
||||
_whitePoint_g = whitePointConfig[1].toDouble() / 255.0;
|
||||
_whitePoint_b = whitePointConfig[2].toDouble() / 255.0;
|
||||
}
|
||||
|
||||
_opc_data.resize( _ledRGBCount + OPC_HEADER_SIZE );
|
||||
_opc_data[0] = _channel;
|
||||
_opc_data[1] = OPC_SET_PIXELS;
|
||||
_opc_data[2] = _ledRGBCount >> 8;
|
||||
_opc_data[3] = _ledRGBCount & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
_host = deviceConfig["output"].toString("127.0.0.1");
|
||||
_port = deviceConfig["port"].toInt(7890);
|
||||
_channel = deviceConfig["channel"].toInt(0);
|
||||
_gamma = deviceConfig["gamma"].toDouble(1.0);
|
||||
_noDither = ! deviceConfig["dither"].toBool(false);
|
||||
_noInterp = ! deviceConfig["interpolation"].toBool(false);
|
||||
_manualLED = deviceConfig["manualLed"].toBool(false);
|
||||
_ledOnOff = deviceConfig["ledOn"].toBool(false);
|
||||
_setFcConfig = deviceConfig["setFcConfig"].toBool(false);
|
||||
|
||||
_whitePoint_r = 1.0;
|
||||
_whitePoint_g = 1.0;
|
||||
_whitePoint_b = 1.0;
|
||||
|
||||
const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray();
|
||||
if ( !whitePointConfig.isEmpty() && whitePointConfig.size() == 3 )
|
||||
{
|
||||
_whitePoint_r = whitePointConfig[0].toDouble() / 255.0;
|
||||
_whitePoint_g = whitePointConfig[1].toDouble() / 255.0;
|
||||
_whitePoint_b = whitePointConfig[2].toDouble() / 255.0;
|
||||
}
|
||||
|
||||
_opc_data.resize( _ledRGBCount + OPC_HEADER_SIZE );
|
||||
_opc_data[0] = _channel;
|
||||
_opc_data[1] = OPC_SET_PIXELS;
|
||||
_opc_data[2] = _ledRGBCount >> 8;
|
||||
_opc_data[3] = _ledRGBCount & 0xff;
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceFadeCandy::initNetwork()
|
||||
{
|
||||
bool isInitOK = true;
|
||||
|
||||
// TODO: Add Network-Error handling
|
||||
_client = new QTcpSocket(this);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceFadeCandy::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
if ( !initNetwork() )
|
||||
{
|
||||
this->setInError( "Network error!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceFadeCandy::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
_client->close();
|
||||
}
|
||||
|
||||
|
||||
bool LedDeviceFadeCandy::isConnected()
|
||||
{
|
||||
return _client->state() == QAbstractSocket::ConnectedState;
|
||||
|
@@ -39,7 +39,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json config for fadecandy
|
||||
///
|
||||
LedDeviceFadeCandy(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceFadeCandy(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the tcp client
|
||||
@@ -54,7 +54,30 @@ public:
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
///
|
||||
/// @return True if success
|
||||
bool initNetwork();
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
private:
|
||||
///
|
||||
@@ -63,25 +86,7 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues);
|
||||
|
||||
protected:
|
||||
QTcpSocket* _client;
|
||||
QString _host;
|
||||
uint16_t _port;
|
||||
unsigned _channel;
|
||||
QByteArray _opc_data;
|
||||
|
||||
// fadecandy sysEx
|
||||
bool _setFcConfig;
|
||||
double _gamma;
|
||||
double _whitePoint_r;
|
||||
double _whitePoint_g;
|
||||
double _whitePoint_b;
|
||||
bool _noDither;
|
||||
bool _noInterp;
|
||||
bool _manualLED;
|
||||
bool _ledOnOff;
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) override;
|
||||
|
||||
/// try to establish connection to opc server, if not connected yet
|
||||
///
|
||||
@@ -112,4 +117,21 @@ protected:
|
||||
/// sends the configuration to fcserver
|
||||
void sendFadeCandyConfiguration();
|
||||
|
||||
QTcpSocket* _client;
|
||||
QString _host;
|
||||
uint16_t _port;
|
||||
unsigned _channel;
|
||||
QByteArray _opc_data;
|
||||
|
||||
// fadecandy sysEx
|
||||
bool _setFcConfig;
|
||||
double _gamma;
|
||||
double _whitePoint_r;
|
||||
double _whitePoint_g;
|
||||
double _whitePoint_b;
|
||||
bool _noDither;
|
||||
bool _noInterp;
|
||||
bool _manualLED;
|
||||
bool _ledOnOff;
|
||||
|
||||
};
|
||||
|
@@ -17,7 +17,7 @@ static const bool verbose = false;
|
||||
static const bool verbose3 = false;
|
||||
|
||||
// Controller configuration settings
|
||||
static const char CONFIG_ADDRESS[] = "output";
|
||||
static const char CONFIG_ADDRESS[] = "host";
|
||||
//static const char CONFIG_PORT[] = "port";
|
||||
static const char CONFIG_AUTH_TOKEN[] ="token";
|
||||
|
||||
@@ -85,120 +85,189 @@ LedDevice* LedDeviceNanoleaf::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceNanoleaf(deviceConfig);
|
||||
}
|
||||
|
||||
LedDeviceNanoleaf::~LedDeviceNanoleaf()
|
||||
{
|
||||
_networkmanager->deleteLater();
|
||||
}
|
||||
|
||||
LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_networkmanager = nullptr;
|
||||
_extControlVersion = EXTCTRLVER_V2;
|
||||
_panelLedCount = 0;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig) {
|
||||
bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
// Overwrite non supported/required features
|
||||
_devConfig["latchTime"] = 0;
|
||||
if (deviceConfig["rewriteTime"].toInt(0) > 0)
|
||||
{
|
||||
Info (_log, "Device Nanoleaf does not require rewrites. Refresh time is ignored.");
|
||||
_devConfig["rewriteTime"] = 0;
|
||||
}
|
||||
|
||||
LedDevice::init(deviceConfig);
|
||||
DebugIf(verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
uint configuredLedCount = static_cast<uint>(this->getLedCount());
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %u", configuredLedCount);
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
//Set hostname as per configuration and default port
|
||||
_hostname = deviceConfig[ CONFIG_ADDRESS ].toString();
|
||||
_api_port = API_DEFAULT_PORT;
|
||||
_auth_token = deviceConfig[ CONFIG_AUTH_TOKEN ].toString();
|
||||
if ( isInitOK )
|
||||
{
|
||||
uint configuredLedCount = this->getLedCount();
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %u", configuredLedCount);
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "RefreshTime : %d", _refresh_timer_interval);
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
|
||||
//If host not configured then discover device
|
||||
if ( _hostname.isEmpty() )
|
||||
//Discover Nanoleaf device
|
||||
if ( !discoverNanoleafDevice() ) {
|
||||
throw std::runtime_error("No target IP defined nor Nanoleaf device discovered");
|
||||
//Set hostname as per configuration and_defaultHost default port
|
||||
_hostname = deviceConfig[ CONFIG_ADDRESS ].toString();
|
||||
_api_port = API_DEFAULT_PORT;
|
||||
_auth_token = deviceConfig[ CONFIG_AUTH_TOKEN ].toString();
|
||||
|
||||
//If host not configured then discover device
|
||||
if ( _hostname.isEmpty() )
|
||||
{
|
||||
//Discover Nanoleaf device
|
||||
if ( !discoverNanoleafDevice() )
|
||||
{
|
||||
this->setInError("No target IP defined nor Nanoleaf device was discovered");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set UDP streaming port
|
||||
_devConfig["host"] = _hostname;
|
||||
_devConfig["port"] = STREAM_CONTROL_DEFAULT_PORT;
|
||||
isInitOK = ProviderUdp::init(_devConfig);
|
||||
|
||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
|
||||
Debug(_log, "Port : %d", _port);
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::initLeds()
|
||||
{
|
||||
bool isInitOK = true;
|
||||
|
||||
//Get Nanoleaf device details and configuration
|
||||
_networkmanager = new QNetworkAccessManager();
|
||||
|
||||
// Read Panel count and panel Ids
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_ROOT );
|
||||
QJsonDocument doc = getJson( url );
|
||||
if ( this->isInError() )
|
||||
{
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
QJsonObject jsonAllPanelInfo = doc.object();
|
||||
|
||||
QJsonObject jsonAllPanelInfo = doc.object();
|
||||
QString deviceName = jsonAllPanelInfo[DEV_DATA_NAME].toString();
|
||||
_deviceModel = jsonAllPanelInfo[DEV_DATA_MODEL].toString();
|
||||
QString deviceManufacturer = jsonAllPanelInfo[DEV_DATA_MANUFACTURER].toString();
|
||||
_deviceFirmwareVersion = jsonAllPanelInfo[DEV_DATA_FIRMWAREVERSION].toString();
|
||||
|
||||
QString deviceName = jsonAllPanelInfo[DEV_DATA_NAME].toString();
|
||||
_deviceModel = jsonAllPanelInfo[DEV_DATA_MODEL].toString();
|
||||
QString deviceManufacturer = jsonAllPanelInfo[DEV_DATA_MANUFACTURER].toString();
|
||||
_deviceFirmwareVersion = jsonAllPanelInfo[DEV_DATA_FIRMWAREVERSION].toString();
|
||||
Debug(_log, "Name : %s", QSTRING_CSTR( deviceName ));
|
||||
Debug(_log, "Model : %s", QSTRING_CSTR( _deviceModel ));
|
||||
Debug(_log, "Manufacturer : %s", QSTRING_CSTR( deviceManufacturer ));
|
||||
Debug(_log, "FirmwareVersion: %s", QSTRING_CSTR( _deviceFirmwareVersion));
|
||||
|
||||
Debug(_log, "Name : %s", QSTRING_CSTR( deviceName ));
|
||||
Debug(_log, "Model : %s", QSTRING_CSTR( _deviceModel ));
|
||||
Debug(_log, "Manufacturer : %s", QSTRING_CSTR( deviceManufacturer ));
|
||||
Debug(_log, "FirmwareVersion: %s", QSTRING_CSTR( _deviceFirmwareVersion));
|
||||
// Get panel details from /panelLayout/layout
|
||||
QJsonObject jsonPanelLayout = jsonAllPanelInfo[API_PANELLAYOUT].toObject();
|
||||
QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject();
|
||||
|
||||
// Get panel details from /panelLayout/layout
|
||||
QJsonObject jsonPanelLayout = jsonAllPanelInfo[API_PANELLAYOUT].toObject();
|
||||
QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject();
|
||||
uint panelNum = static_cast<uint>(jsonLayout[PANEL_NUM].toInt());
|
||||
QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
|
||||
|
||||
uint panelNum = static_cast<uint>(jsonLayout[PANEL_NUM].toInt());
|
||||
QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
|
||||
std::map<uint, std::map<uint, uint>> panelMap;
|
||||
|
||||
std::map<uint, std::map<uint, uint>> panelMap;
|
||||
// Loop over all children.
|
||||
foreach (const QJsonValue & value, positionData)
|
||||
{
|
||||
QJsonObject panelObj = value.toObject();
|
||||
|
||||
// Loop over all children.
|
||||
foreach (const QJsonValue & value, positionData) {
|
||||
QJsonObject panelObj = value.toObject();
|
||||
uint panelId = static_cast<uint>(panelObj[PANEL_ID].toInt());
|
||||
uint panelX = static_cast<uint>(panelObj[PANEL_POS_X].toInt());
|
||||
uint panelY = static_cast<uint>(panelObj[PANEL_POS_Y].toInt());
|
||||
uint panelshapeType = static_cast<uint>(panelObj[PANEL_SHAPE_TYPE].toInt());
|
||||
//uint panelOrientation = static_cast<uint>(panelObj[PANEL_ORIENTATION].toInt());
|
||||
|
||||
uint panelId = static_cast<uint>(panelObj[PANEL_ID].toInt());
|
||||
uint panelX = static_cast<uint>(panelObj[PANEL_POS_X].toInt());
|
||||
uint panelY = static_cast<uint>(panelObj[PANEL_POS_Y].toInt());
|
||||
uint panelshapeType = static_cast<uint>(panelObj[PANEL_SHAPE_TYPE].toInt());
|
||||
//uint panelOrientation = static_cast<uint>(panelObj[PANEL_ORIENTATION].toInt());
|
||||
DebugIf(verbose, _log, "Panel [%u] (%u,%u) - Type: [%u]", panelId, panelX, panelY, panelshapeType );
|
||||
|
||||
DebugIf(verbose, _log, "Panel [%u] (%u,%u) - Type: [%u]", panelId, panelX, panelY, panelshapeType );
|
||||
// Skip Rhythm panels
|
||||
if ( panelshapeType != RHYTM )
|
||||
{
|
||||
panelMap[panelY][panelX] = panelId;
|
||||
}
|
||||
else
|
||||
{ // Reset non support/required features
|
||||
Info(_log, "Rhythm panel skipped.");
|
||||
}
|
||||
}
|
||||
|
||||
// Skip Rhythm panels
|
||||
if ( panelshapeType != RHYTM ) {
|
||||
panelMap[panelY][panelX] = panelId;
|
||||
} else {
|
||||
Info(_log, "Rhythm panel skipped.");
|
||||
// Sort panels top down, left right
|
||||
for(auto posY = panelMap.crbegin(); posY != panelMap.crend(); ++posY)
|
||||
{
|
||||
// posY.first is the first key
|
||||
for(auto const &posX : posY->second)
|
||||
{
|
||||
// posX.first is the second key, posX.second is the data
|
||||
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX.first, posX.second );
|
||||
_panelIds.push_back(posX.second);
|
||||
}
|
||||
}
|
||||
this->_panelLedCount = static_cast<uint>(_panelIds.size());
|
||||
_devConfig["hardwareLedCount"] = static_cast<int>(_panelLedCount);
|
||||
|
||||
Debug(_log, "PanelsNum : %u", panelNum);
|
||||
Debug(_log, "PanelLedCount : %u", _panelLedCount);
|
||||
|
||||
// Check. if enough panelds were found.
|
||||
uint configuredLedCount = this->getLedCount();
|
||||
if (_panelLedCount < configuredLedCount )
|
||||
{
|
||||
QString errorReason = QString("Not enough panels [%1] for configured LEDs [%2] found!")
|
||||
.arg(_panelLedCount)
|
||||
.arg(configuredLedCount);
|
||||
this->setInError(errorReason);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( _panelLedCount > this->getLedCount() )
|
||||
{
|
||||
Warning(_log, "Nanoleaf: More panels [%u] than configured LEDs [%u].", _panelLedCount, configuredLedCount );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort panels top down, left right
|
||||
for(auto posY = panelMap.crbegin(); posY != panelMap.crend(); ++posY) {
|
||||
// posY.first is the first key
|
||||
for(auto const &posX : posY->second) {
|
||||
// posX.first is the second key, posX.second is the data
|
||||
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX.first, posX.second );
|
||||
_panelIds.push_back(posX.second);
|
||||
}
|
||||
}
|
||||
this->_panelLedCount = static_cast<uint>(_panelIds.size());
|
||||
|
||||
|
||||
Debug(_log, "PanelsNum : %u", panelNum);
|
||||
Debug(_log, "PanelLedCount : %u", _panelLedCount);
|
||||
|
||||
// Check. if enough panelds were found.
|
||||
if (_panelLedCount < configuredLedCount) {
|
||||
|
||||
throw std::runtime_error ( (QString ("Not enough panels [%1] for configured LEDs [%2] found!").arg(_panelLedCount).arg(configuredLedCount)).toStdString() );
|
||||
} else {
|
||||
if ( _panelLedCount > static_cast<uint>(this->getLedCount()) ) {
|
||||
Warning(_log, "Nanoleaf: More panels [%u] than configured LEDs [%u].", _panelLedCount, configuredLedCount );
|
||||
}
|
||||
}
|
||||
|
||||
// Set UDP streaming port
|
||||
_port = STREAM_CONTROL_DEFAULT_PORT;
|
||||
_defaultHost = _hostname;
|
||||
|
||||
switchOn();
|
||||
|
||||
ProviderUdp::init(deviceConfig);
|
||||
|
||||
Debug(_log, "Started successfully" );
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::discoverNanoleafDevice() {
|
||||
int LedDeviceNanoleaf::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
if ( initLeds() )
|
||||
{
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::discoverNanoleafDevice()
|
||||
{
|
||||
|
||||
bool isDeviceFound (false);
|
||||
// device searching by ssdp
|
||||
@@ -229,7 +298,9 @@ bool LedDeviceNanoleaf::discoverNanoleafDevice() {
|
||||
return isDeviceFound;
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode() {
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode()
|
||||
{
|
||||
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_EFFECT );
|
||||
QJsonDocument jsonDoc;
|
||||
@@ -245,7 +316,8 @@ QString LedDeviceNanoleaf::getUrl(QString host, QString port, QString auth_token
|
||||
return QString(API_URL_FORMAT).arg(host, port, auth_token, endpoint);
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::getJson(QString url) const {
|
||||
QJsonDocument LedDeviceNanoleaf::getJson(QString url)
|
||||
{
|
||||
|
||||
Debug(_log, "GET: [%s]", QSTRING_CSTR( url ));
|
||||
|
||||
@@ -269,7 +341,8 @@ QJsonDocument LedDeviceNanoleaf::getJson(QString url) const {
|
||||
return jsonDoc;
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json) const {
|
||||
QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json)
|
||||
{
|
||||
|
||||
Debug(_log, "PUT: [%s] [%s]", QSTRING_CSTR( url ), QSTRING_CSTR( json ) );
|
||||
// Perfrom request
|
||||
@@ -293,15 +366,15 @@ QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json) const {
|
||||
return jsonDoc;
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply ) const {
|
||||
QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply )
|
||||
{
|
||||
|
||||
QJsonDocument jsonDoc;
|
||||
|
||||
int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
|
||||
Debug(_log, "Reply.httpStatusCode [%d]", httpStatusCode );
|
||||
|
||||
if(reply->error() ==
|
||||
QNetworkReply::NoError)
|
||||
if(reply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
if ( httpStatusCode != 204 ){
|
||||
QByteArray response = reply->readAll();
|
||||
@@ -309,8 +382,7 @@ QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply ) const
|
||||
jsonDoc = QJsonDocument::fromJson(response, &error);
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
{
|
||||
Error (_log, "Got invalid response");
|
||||
throw std::runtime_error("");
|
||||
this->setInError ( "Got invalid response" );
|
||||
}
|
||||
else {
|
||||
//Debug
|
||||
@@ -326,35 +398,30 @@ QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply ) const
|
||||
QString httpReason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
|
||||
QString advise;
|
||||
switch ( httpStatusCode ) {
|
||||
case 400:
|
||||
advise = "Check Request Body";
|
||||
break;
|
||||
case 401:
|
||||
advise = "Check Authentication Token (API Key)";
|
||||
break;
|
||||
case 404:
|
||||
advise = "Check Resource given";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case 400:
|
||||
advise = "Check Request Body";
|
||||
break;
|
||||
case 401:
|
||||
advise = "Check Authentication Token (API Key)";
|
||||
break;
|
||||
case 404:
|
||||
advise = "Check Resource given";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
errorReason = QString ("%1:%2 [%3 %4] - %5").arg(_hostname, _api_port, QString(httpStatusCode) , httpReason);
|
||||
errorReason = QString ("%1:%2 [%3 %4] - %5").arg(_hostname, _api_port, QString(httpStatusCode) , httpReason, advise);
|
||||
}
|
||||
else {
|
||||
errorReason = QString ("%1:%2 - %3").arg(_hostname, _api_port, reply->errorString());
|
||||
}
|
||||
Error (_log, "%s", QSTRING_CSTR( errorReason ));
|
||||
throw std::runtime_error("Network Error");
|
||||
this->setInError ( errorReason );
|
||||
}
|
||||
// Return response
|
||||
return jsonDoc;
|
||||
}
|
||||
|
||||
|
||||
LedDeviceNanoleaf::~LedDeviceNanoleaf()
|
||||
{
|
||||
delete _networkmanager;
|
||||
}
|
||||
|
||||
int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
@@ -396,7 +463,7 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
|
||||
lowByte = static_cast<uchar>(panelID & 0xFF);
|
||||
|
||||
// Set panels configured
|
||||
if( panelCounter < static_cast<uint>(this->getLedCount()) ) {
|
||||
if( panelCounter < this->getLedCount() ) {
|
||||
color = static_cast<ColorRgb>(ledValues.at(panelCounter));
|
||||
}
|
||||
else
|
||||
@@ -437,40 +504,43 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
|
||||
return retVal;
|
||||
}
|
||||
|
||||
QString LedDeviceNanoleaf::getOnOffRequest (bool isOn ) const {
|
||||
QString LedDeviceNanoleaf::getOnOffRequest (bool isOn ) const
|
||||
{
|
||||
QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
|
||||
return QString( "{\"%1\":{\"%2\":%3}}" ).arg(STATE_ON, STATE_ONOFF_VALUE, state);
|
||||
}
|
||||
|
||||
int LedDeviceNanoleaf::switchOn() {
|
||||
Debug(_log, "switchOn()");
|
||||
int LedDeviceNanoleaf::switchOn()
|
||||
{
|
||||
if ( _deviceReady)
|
||||
{
|
||||
// Set Nanoleaf to External Control (UDP) mode
|
||||
Debug(_log, "Set Nanoleaf to External Control (UDP) streaming mode");
|
||||
QJsonDocument responseDoc = changeToExternalControlMode();
|
||||
// Resolve port for Ligh Panels
|
||||
QJsonObject jsonStreamControllInfo = responseDoc.object();
|
||||
if ( ! jsonStreamControllInfo.isEmpty() ) {
|
||||
_port = static_cast<uchar>(jsonStreamControllInfo[STREAM_CONTROL_PORT].toInt());
|
||||
}
|
||||
|
||||
// Set Nanoleaf to External Control (UDP) mode
|
||||
Debug(_log, "Set Nanoleaf to External Control (UDP) streaming mode");
|
||||
QJsonDocument responseDoc = changeToExternalControlMode();
|
||||
// Resolve port for Ligh Panels
|
||||
QJsonObject jsonStreamControllInfo = responseDoc.object();
|
||||
if ( ! jsonStreamControllInfo.isEmpty() ) {
|
||||
_port = static_cast<uchar>(jsonStreamControllInfo[STREAM_CONTROL_PORT].toInt());
|
||||
//Switch on Nanoleaf device
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
|
||||
putJson(url, this->getOnOffRequest(true) );
|
||||
}
|
||||
|
||||
//Switch on Nanoleaf device
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
|
||||
putJson(url, this->getOnOffRequest(true) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LedDeviceNanoleaf::switchOff() {
|
||||
Debug(_log, "switchOff()");
|
||||
|
||||
int LedDeviceNanoleaf::switchOff()
|
||||
{
|
||||
//Set all LEDs to Black
|
||||
int rc = writeBlack();
|
||||
|
||||
//Switch off Nanoleaf device physically
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
|
||||
putJson(url, getOnOffRequest(false) );
|
||||
int rc = LedDevice::switchOff();
|
||||
|
||||
if ( _deviceReady)
|
||||
{
|
||||
//Switch off Nanoleaf device physically
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
|
||||
putJson(url, getOnOffRequest(false) );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -480,7 +550,7 @@ std::string LedDeviceNanoleaf:: uint8_vector_to_hex_string( const std::vector<ui
|
||||
ss << std::hex << std::setfill('0');
|
||||
std::vector<uint8_t>::const_iterator it;
|
||||
|
||||
for (it = buffer.begin(); it != buffer.end(); it++)
|
||||
for (it = buffer.begin(); it != buffer.end(); ++it)
|
||||
{
|
||||
ss << " " << std::setw(2) << static_cast<unsigned>(*it);
|
||||
}
|
||||
|
@@ -18,134 +18,143 @@
|
||||
class LedDeviceNanoleaf : public ProviderUdp
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Constructs the LedDevice for Nanoleaf LightPanels (aka Aurora) or Canvas
|
||||
///
|
||||
/// following code shows all config options
|
||||
/// @code
|
||||
/// "device" :
|
||||
/// {
|
||||
/// "type" : "nanoleaf"
|
||||
/// "output" : "hostname or IP", // Optional. If empty, device is tried to be discovered
|
||||
/// "token" : "Authentication Token",
|
||||
/// },
|
||||
///@endcode
|
||||
///
|
||||
/// @param deviceConfig json config for nanoleaf
|
||||
///
|
||||
LedDeviceNanoleaf(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Constructs the LedDevice for Nanoleaf LightPanels (aka Aurora) or Canvas
|
||||
///
|
||||
/// following code shows all config options
|
||||
/// @code
|
||||
/// "device" :
|
||||
/// {
|
||||
/// "type" : "nanoleaf"
|
||||
/// "output" : "hostname or IP", // Optional. If empty, device is tried to be discovered
|
||||
/// "token" : "Authentication Token",
|
||||
/// },
|
||||
///@endcode
|
||||
///
|
||||
/// @param deviceConfig json config for nanoleaf
|
||||
///
|
||||
explicit LedDeviceNanoleaf(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the tcp client
|
||||
///
|
||||
virtual ~LedDeviceNanoleaf();
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the tcp client
|
||||
///
|
||||
virtual ~LedDeviceNanoleaf() override;
|
||||
|
||||
/// Constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
/// Constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
/// Switch the leds on
|
||||
virtual int switchOn();
|
||||
/// Switch the device on
|
||||
virtual int switchOn() override;
|
||||
|
||||
/// Switch the leds off
|
||||
virtual int switchOff();
|
||||
/// Switch the device off
|
||||
virtual int switchOff() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues);
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
///
|
||||
/// Identifies a Nanoleaf device's panel configuration,
|
||||
/// sets device into External Control (UDP) mode
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
/// @exception runtime_error in case device cannot be initialised
|
||||
/// e.g. more LEDs configured than device has panels or network problems
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Initialise Nanoleaf device's configuration and network address details
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return True if success
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// Get Nanoleaf device details and configuration
|
||||
///
|
||||
/// @return True, if Nanoleaf device capabilities fit configuration
|
||||
///
|
||||
bool initLeds();
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
private:
|
||||
// QNetworkAccessManager object for sending requests.
|
||||
QNetworkAccessManager* _networkmanager;
|
||||
// QNetworkAccessManager object for sending requests.
|
||||
QNetworkAccessManager* _networkmanager;
|
||||
|
||||
QString _hostname;
|
||||
QString _api_port;
|
||||
QString _auth_token;
|
||||
QString _hostname;
|
||||
QString _api_port;
|
||||
QString _auth_token;
|
||||
|
||||
//Nanoleaf device details
|
||||
QString _deviceModel;
|
||||
QString _deviceFirmwareVersion;
|
||||
ushort _extControlVersion;
|
||||
/// The number of panels with leds
|
||||
//Nanoleaf device details
|
||||
QString _deviceModel;
|
||||
QString _deviceFirmwareVersion;
|
||||
ushort _extControlVersion;
|
||||
/// The number of panels with leds
|
||||
uint _panelLedCount;
|
||||
/// Array of the pannel ids.
|
||||
std::vector<uint> _panelIds;
|
||||
/// Array of the pannel ids.
|
||||
std::vector<uint> _panelIds;
|
||||
|
||||
///
|
||||
/// Discover Nanoleaf device via SSDP identifiers
|
||||
///
|
||||
/// @return True, if Nanoleaf device was found
|
||||
///
|
||||
bool discoverNanoleafDevice();
|
||||
///
|
||||
/// Discover Nanoleaf device via SSDP identifiers
|
||||
///
|
||||
/// @return True, if Nanoleaf device was found
|
||||
///
|
||||
bool discoverNanoleafDevice();
|
||||
|
||||
///
|
||||
/// Change Nanoleaf device to External Control (UDP) mode
|
||||
///
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument changeToExternalControlMode();
|
||||
///
|
||||
/// Change Nanoleaf device to External Control (UDP) mode
|
||||
///
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument changeToExternalControlMode();
|
||||
|
||||
///
|
||||
/// Get command to switch Nanoleaf device on or off
|
||||
///
|
||||
/// @param isOn True, if to switch on device
|
||||
/// @return Command to switch device on/off
|
||||
///
|
||||
QString getOnOffRequest (bool isOn ) const;
|
||||
///
|
||||
/// Get command to switch Nanoleaf device on or off
|
||||
///
|
||||
/// @param isOn True, if to switch on device
|
||||
/// @return Command to switch device on/off
|
||||
///
|
||||
QString getOnOffRequest (bool isOn ) const;
|
||||
|
||||
///
|
||||
/// Get command as url
|
||||
///
|
||||
/// @param host Hostname or IP
|
||||
/// @param port IP-Port
|
||||
/// @param _auth_token Authorization token
|
||||
/// @param Endpoint command for request
|
||||
/// @return Url to execute endpoint/command
|
||||
///
|
||||
QString getUrl(QString host, QString port, QString auth_token, QString endpoint) const;
|
||||
///
|
||||
/// Get command as url
|
||||
///
|
||||
/// @param host Hostname or IP
|
||||
/// @param port IP-Port
|
||||
/// @param _auth_token Authorization token
|
||||
/// @param Endpoint command for request
|
||||
/// @return Url to execute endpoint/command
|
||||
///
|
||||
QString getUrl(QString host, QString port, QString auth_token, QString endpoint) const;
|
||||
|
||||
///
|
||||
/// Execute GET request
|
||||
///
|
||||
/// @param url GET request for url
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument getJson(QString url) const;
|
||||
///
|
||||
/// Execute GET request
|
||||
///
|
||||
/// @param url GET request for url
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument getJson(QString url);
|
||||
|
||||
///
|
||||
/// Execute PUT request
|
||||
///
|
||||
/// @param Url for PUT request
|
||||
/// @param json Command for request
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument putJson(QString url, QString json) const;
|
||||
|
||||
///
|
||||
/// Handle replys for GET and PUT requests
|
||||
///
|
||||
/// @param reply Network reply
|
||||
/// @return Response for request, if no error
|
||||
/// @exception runtime_error for network or request errors
|
||||
///
|
||||
QJsonDocument handleReply(QNetworkReply* const &reply ) const;
|
||||
///
|
||||
/// Execute PUT request
|
||||
///
|
||||
/// @param Url for PUT request
|
||||
/// @param json Command for request
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument putJson(QString url, QString json);
|
||||
|
||||
///
|
||||
/// Handle replys for GET and PUT requests
|
||||
///
|
||||
/// @param reply Network reply
|
||||
/// @return Response for request, if no error
|
||||
///
|
||||
QJsonDocument handleReply(QNetworkReply* const &reply );
|
||||
|
||||
///
|
||||
/// convert vector to hex string
|
||||
|
@@ -217,7 +217,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDevicePhilipsHue(const QJsonObject &deviceConfig);
|
||||
explicit LedDevicePhilipsHue(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of this device
|
||||
@@ -229,7 +229,7 @@ public:
|
||||
|
||||
public slots:
|
||||
/// thread start
|
||||
virtual void start();
|
||||
virtual void start() override;
|
||||
|
||||
private slots:
|
||||
/// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
||||
@@ -248,8 +248,8 @@ protected:
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues);
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
/// bridge class
|
||||
|
@@ -3,18 +3,8 @@
|
||||
LedDeviceTpm2net::LedDeviceTpm2net(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = TPM2_DEFAULT_PORT;
|
||||
ProviderUdp::init(deviceConfig);
|
||||
_tpm2_max = deviceConfig["max-packet"].toInt(170);
|
||||
_tpm2ByteCount = 3 * _ledCount;
|
||||
_tpm2TotalPackets = 1 + _tpm2ByteCount / _tpm2_max;
|
||||
|
||||
return true;
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
|
||||
@@ -22,8 +12,17 @@ LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceTpm2net(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = TPM2_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
|
||||
// populates the headers
|
||||
_tpm2_max = deviceConfig["max-packet"].toInt(170);
|
||||
_tpm2ByteCount = 3 * _ledCount;
|
||||
_tpm2TotalPackets = 1 + _tpm2ByteCount / _tpm2_max;
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceTpm2net::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
|
@@ -3,7 +3,7 @@
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
#define TPM2_DEFAULT_PORT 65506
|
||||
const ushort TPM2_DEFAULT_PORT = 65506;
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp tpm2.net packets
|
||||
@@ -16,17 +16,17 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceTpm2net(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceTpm2net(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@@ -35,7 +35,7 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
int _tpm2_max;
|
||||
int _tpm2ByteCount;
|
||||
|
@@ -7,17 +7,8 @@
|
||||
LedDeviceUdpArtNet::LedDeviceUdpArtNet(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = 6454;
|
||||
ProviderUdp::init(deviceConfig);
|
||||
_artnet_universe = deviceConfig["universe"].toInt(1);
|
||||
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
|
||||
|
||||
return true;
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
|
||||
@@ -25,6 +16,16 @@ LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceUdpArtNet(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = ARTNET_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
|
||||
_artnet_universe = deviceConfig["universe"].toInt(1);
|
||||
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
// populates the headers
|
||||
void LedDeviceUdpArtNet::prepare(const unsigned this_universe, const unsigned this_sequence, unsigned this_dmxChannelCount)
|
||||
@@ -66,7 +67,7 @@ The Sequence field is set to 0x00 to disable this feature.
|
||||
int dmxIdx = 0; // offset into the current dmx packet
|
||||
|
||||
memset(artnet_packet.raw, 0, sizeof(artnet_packet.raw));
|
||||
for (int ledIdx = 0; ledIdx < _ledRGBCount; ledIdx++)
|
||||
for (unsigned int ledIdx = 0; ledIdx < _ledRGBCount; ledIdx++)
|
||||
{
|
||||
|
||||
artnet_packet.Data[dmxIdx++] = rawdata[ledIdx];
|
||||
@@ -90,4 +91,3 @@ The Sequence field is set to 0x00 to disable this feature.
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@@ -13,7 +13,7 @@
|
||||
*
|
||||
**/
|
||||
|
||||
#define ArtNet_DEFAULT_PORT 5568
|
||||
const ushort ARTNET_DEFAULT_PORT = 6454;
|
||||
|
||||
#define DMX_MAX 512 // 512 usable slots
|
||||
|
||||
@@ -47,18 +47,17 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceUdpArtNet(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceUdpArtNet(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@@ -67,13 +66,13 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
void prepare(const unsigned this_universe, const unsigned this_sequence, const unsigned this_dmxChannelCount);
|
||||
|
||||
|
||||
artnet_packet_t artnet_packet;
|
||||
uint8_t _artnet_seq = 1;
|
||||
uint8_t _artnet_channelsPerFixture = 3;
|
||||
unsigned _artnet_universe = 1;
|
||||
int _artnet_channelsPerFixture = 3;
|
||||
int _artnet_universe = 1;
|
||||
};
|
||||
|
@@ -7,27 +7,32 @@
|
||||
LedDeviceUdpE131::LedDeviceUdpE131(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = 5568;
|
||||
ProviderUdp::init(deviceConfig);
|
||||
_e131_universe = deviceConfig["universe"].toInt(1);
|
||||
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
|
||||
QString _json_cid = deviceConfig["cid"].toString("");
|
||||
|
||||
if (_json_cid.isEmpty())
|
||||
_port = E131_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
_e131_cid = QUuid::createUuid();
|
||||
Debug( _log, "e131 no cid found, generated %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
} else {
|
||||
_e131_cid = QUuid(_json_cid);
|
||||
Debug( _log, "e131 cid found, using %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
}
|
||||
_e131_universe = deviceConfig["universe"].toInt(1);
|
||||
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
|
||||
QString _json_cid = deviceConfig["cid"].toString("");
|
||||
|
||||
return true;
|
||||
if (_json_cid.isEmpty())
|
||||
{
|
||||
_e131_cid = QUuid::createUuid();
|
||||
Debug( _log, "e131 no cid found, generated %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
_e131_cid = QUuid(_json_cid);
|
||||
Debug( _log, "e131 cid found, using %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
|
||||
@@ -35,7 +40,6 @@ LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceUdpE131(deviceConfig);
|
||||
}
|
||||
|
||||
|
||||
// populates the headers
|
||||
void LedDeviceUdpE131::prepare(const unsigned this_universe, const unsigned this_dmxChannelCount)
|
||||
{
|
||||
|
@@ -18,7 +18,7 @@
|
||||
*
|
||||
**/
|
||||
|
||||
#define E131_DEFAULT_PORT 5568
|
||||
const ushort E131_DEFAULT_PORT = 5568;
|
||||
|
||||
/* E1.31 Packet Offsets */
|
||||
#define E131_ROOT_PREAMBLE_SIZE 0
|
||||
@@ -105,18 +105,17 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceUdpE131(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceUdpE131(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@@ -125,7 +124,7 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
void prepare(const unsigned this_universe, const unsigned this_dmxChannelCount);
|
||||
|
||||
|
@@ -3,43 +3,46 @@
|
||||
LedDeviceUdpH801::LedDeviceUdpH801(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceUdpH801(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
/* The H801 port is fixed */
|
||||
_latchTime_ms = 10;
|
||||
_port = 30977;
|
||||
_defaultHost = "255.255.255.255";
|
||||
ProviderUdp::init(deviceConfig);
|
||||
_port = H801_DEFAULT_PORT;
|
||||
_defaultHost = H801_DEFAULT_HOST;
|
||||
|
||||
_ids.clear();
|
||||
QJsonArray lArray = deviceConfig["lightIds"].toArray();
|
||||
for (int i = 0; i < lArray.size(); i++)
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
QString id = lArray[i].toString();
|
||||
_ids.push_back(id.toInt(nullptr, 16));
|
||||
_ids.clear();
|
||||
QJsonArray lArray = deviceConfig["lightIds"].toArray();
|
||||
for (int i = 0; i < lArray.size(); i++)
|
||||
{
|
||||
QString id = lArray[i].toString();
|
||||
_ids.push_back(id.toInt(nullptr, 16));
|
||||
}
|
||||
|
||||
_message = QByteArray(_prefix_size + _colors + _id_size * _ids.size() + _suffix_size, 0x00);
|
||||
_message[0] = 0xFB;
|
||||
_message[1] = 0xEB;
|
||||
|
||||
for (int i = 0; i < _ids.length(); i++) {
|
||||
_message[_prefix_size + _colors + i * _id_size + 0] = (_ids[i] >> 0x00) & 0xFF;
|
||||
_message[_prefix_size + _colors + i * _id_size + 1] = (_ids[i] >> 0x08) & 0xFF;
|
||||
_message[_prefix_size + _colors + i * _id_size + 2] = (_ids[i] >> 0x10) & 0xFF;
|
||||
}
|
||||
|
||||
Debug(_log, "H801 using %s:%d", _address.toString().toStdString().c_str(), _port);
|
||||
}
|
||||
|
||||
_message = QByteArray(_prefix_size + _colors + _id_size * _ids.size() + _suffix_size, 0x00);
|
||||
_message[0] = 0xFB;
|
||||
_message[1] = 0xEB;
|
||||
|
||||
for (int i = 0; i < _ids.length(); i++) {
|
||||
_message[_prefix_size + _colors + i * _id_size + 0] = (_ids[i] >> 0x00) & 0xFF;
|
||||
_message[_prefix_size + _colors + i * _id_size + 1] = (_ids[i] >> 0x08) & 0xFF;
|
||||
_message[_prefix_size + _colors + i * _id_size + 2] = (_ids[i] >> 0x10) & 0xFF;
|
||||
}
|
||||
|
||||
Debug(_log, "H801 using %s:%d", _address.toString().toStdString().c_str(), _port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceUdpH801(deviceConfig);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceUdpH801::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@@ -6,6 +6,11 @@
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp.
|
||||
///
|
||||
///
|
||||
|
||||
const ushort H801_DEFAULT_PORT = 30977;
|
||||
static const char H801_DEFAULT_HOST[] = "255.255.255.255";
|
||||
|
||||
class LedDeviceUdpH801: public ProviderUdp
|
||||
{
|
||||
protected:
|
||||
@@ -22,17 +27,16 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceUdpH801(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceUdpH801(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@@ -41,5 +45,5 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@@ -3,8 +3,8 @@
|
||||
LedDeviceUdpRaw::LedDeviceUdpRaw(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_port = 5568;
|
||||
init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
|
||||
@@ -12,6 +12,13 @@ LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceUdpRaw(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceUdpRaw::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = RAW_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
|
||||
|
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
#define RAW_DEFAULT_PORT 5568
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp.
|
||||
///
|
||||
@@ -14,16 +16,24 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceUdpRaw(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceUdpRaw(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@@ -17,21 +17,22 @@
|
||||
|
||||
ProviderUdp::ProviderUdp()
|
||||
: LedDevice()
|
||||
, _port(1)
|
||||
, _defaultHost("127.0.0.1")
|
||||
, _udpSocket (nullptr)
|
||||
, _port(1)
|
||||
, _defaultHost("127.0.0.1")
|
||||
{
|
||||
_deviceReady = false;
|
||||
_latchTime_ms = 1;
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
}
|
||||
|
||||
ProviderUdp::~ProviderUdp()
|
||||
{
|
||||
_udpSocket->close();
|
||||
_udpSocket->deleteLater();
|
||||
}
|
||||
|
||||
bool ProviderUdp::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
QString host = deviceConfig["host"].toString(_defaultHost);
|
||||
|
||||
@@ -41,36 +42,86 @@ bool ProviderUdp::init(const QJsonObject &deviceConfig)
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Failed to parse %s as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
Debug( _log, "Failed to parse [%s] as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
QHostInfo info = QHostInfo::fromName(host);
|
||||
if (info.addresses().isEmpty())
|
||||
{
|
||||
Debug( _log, "Failed to parse %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
throw std::runtime_error("invalid target address");
|
||||
Debug( _log, "Failed to parse [%s] as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
QString errortext = QString ("Invalid target address [%1]!").arg(host);
|
||||
this->setInError ( errortext );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Successfully parsed %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
_address = info.addresses().first();
|
||||
}
|
||||
Debug( _log, "Successfully parsed %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
_address = info.addresses().first();
|
||||
}
|
||||
|
||||
_port = deviceConfig["port"].toInt(_port);
|
||||
if ( (_port <= 0) || (_port > MAX_PORT) )
|
||||
int config_port = deviceConfig["port"].toInt(_port);
|
||||
if ( config_port <= 0 || config_port > MAX_PORT )
|
||||
{
|
||||
throw std::runtime_error("invalid target port");
|
||||
QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
|
||||
this->setInError ( errortext );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_port = static_cast<int>(config_port);
|
||||
Debug( _log, "UDP using %s:%d", _address.toString().toStdString().c_str() , _port );
|
||||
}
|
||||
|
||||
Debug( _log, "UDP using %s:%d", _address.toString().toStdString().c_str() , _port );
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
return true;
|
||||
bool ProviderUdp::initNetwork()
|
||||
{
|
||||
bool isInitOK = true;
|
||||
|
||||
// TODO: Add Network-Error handling
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int ProviderUdp::open()
|
||||
{
|
||||
QHostAddress localAddress = QHostAddress::Any;
|
||||
quint16 localPort = 0;
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
WarningIf( !_udpSocket->bind(localAddress, localPort), _log, "Could not bind local address: %s", strerror(errno));
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
if ( ! initNetwork())
|
||||
{
|
||||
this->setInError( "Network error!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
QHostAddress localAddress = QHostAddress::Any;
|
||||
quint16 localPort = 0;
|
||||
|
||||
return 0;
|
||||
if ( !_udpSocket->bind(localAddress, localPort) )
|
||||
{
|
||||
Warning ( _log, "Could not bind local address: %s", strerror(errno));
|
||||
}
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ProviderUdp::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
if ( _udpSocket != nullptr)
|
||||
{
|
||||
_udpSocket->close();
|
||||
}
|
||||
}
|
||||
|
||||
int ProviderUdp::writeBytes(const unsigned size, const uint8_t * data)
|
||||
|
@@ -9,7 +9,7 @@
|
||||
|
||||
class QUdpSocket;
|
||||
|
||||
#define MAX_PORT 65535
|
||||
const ushort MAX_PORT = 65535;
|
||||
|
||||
///
|
||||
/// The ProviderUdp implements an abstract base-class for LedDevices using UDP packets.
|
||||
@@ -25,23 +25,37 @@ public:
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
///
|
||||
virtual ~ProviderUdp();
|
||||
virtual ~ProviderUdp() override;
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
///
|
||||
/// @return True if success
|
||||
bool initNetwork();
|
||||
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open();
|
||||
int open() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
|
||||
/// values are latched.
|
||||
|
Reference in New Issue
Block a user