implement origin for effects (#408)

* implement rigin for efx

* implement origin for effects and other components
add experimental adalight firmware for arduino with upto 5 pwm channels

* cleanup

* origin ip now with dns lookup

* fix compile

* move some code
This commit is contained in:
redPanther
2017-03-01 15:23:53 +01:00
committed by GitHub
parent 31f352e7ce
commit 221af075a4
24 changed files with 376 additions and 98 deletions

View File

@@ -12,6 +12,7 @@
// Qt includes
#include <QResource>
#include <QDateTime>
#include <QHostInfo>
// hyperion util includes
#include "hyperion/ImageProcessorFactory.h"
@@ -32,6 +33,7 @@ BoblightClientConnection::BoblightClientConnection(QTcpSocket *socket, const int
, _priority(priority)
, _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb::BLACK)
, _log(Logger::getInstance("BOBLIGHT"))
, _clientAddress(QHostInfo::fromName(socket->peerAddress().toString()).hostName())
{
// initalize the locale. Start with the default C-locale
_locale.setNumberOptions(QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
@@ -165,16 +167,16 @@ void BoblightClientConnection::handleMessage(const QString & message)
// send current color values to hyperion if this is the last led assuming leds values are send in order of id
if ((ledIndex == _ledColors.size() -1) && _priority < 255)
{
_hyperion->setColors(_priority, _ledColors, -1, hyperion::COMP_BOBLIGHTSERVER);
_hyperion->setColors(_priority, _ledColors, -1, true, hyperion::COMP_BOBLIGHTSERVER, _clientAddress);
}
return;
}
}
else if(messageParts[3] == "speed" ||
messageParts[3] == "interpolation" ||
messageParts[3] == "use" ||
messageParts[3] == "singlechange")
messageParts[3] == "interpolation" ||
messageParts[3] == "use" ||
messageParts[3] == "singlechange")
{
// these message are ignored by Hyperion
return;
@@ -203,38 +205,33 @@ void BoblightClientConnection::handleMessage(const QString & message)
// send current color values to hyperion
if (_priority < 255)
{
_hyperion->setColors(_priority, _ledColors, -1, hyperion::COMP_BOBLIGHTSERVER);
_hyperion->setColors(_priority, _ledColors, -1, true, hyperion::COMP_BOBLIGHTSERVER, _clientAddress);
}
return;
}
}
Debug(_log, "unknown boblight message: %s", message.toStdString().c_str());
Debug(_log, "unknown boblight message: %s", QSTRING_CSTR(message));
}
void BoblightClientConnection::sendMessage(const std::string & message)
void BoblightClientConnection::sendMessage(const QByteArray & message)
{
//std::cout << "send boblight message: " << message;
_socket->write(message.c_str(), message.size());
}
void BoblightClientConnection::sendMessage(const char * message, int size)
{
//std::cout << "send boblight message: " << std::string(message, size);
_socket->write(message, size);
_socket->write(message);
}
void BoblightClientConnection::sendLightMessage()
{
char buffer[256];
int n = snprintf(buffer, sizeof(buffer), "lights %d\n", _hyperion->getLedCount());
sendMessage(buffer, n);
int n = snprintf(buffer, sizeof(buffer), "lights %d\n", _hyperion->getLedCount());
sendMessage(QByteArray(buffer, n));
double h0, h1, v0, v1;
for (unsigned i = 0; i < _hyperion->getLedCount(); ++i)
{
double h0, h1, v0, v1;
_imageProcessor->getScanParameters(i, h0, h1, v0, v1);
n = snprintf(buffer, sizeof(buffer), "light %03d scan %f %f %f %f\n", i, 100*v0, 100*v1, 100*h0, 100*h1);
sendMessage(buffer, n);
sendMessage(QByteArray(buffer, n));
}
}

View File

@@ -1,8 +1,5 @@
#pragma once
// stl includes
#include <string>
// Qt includes
#include <QByteArray>
#include <QTcpSocket>
@@ -65,15 +62,7 @@ private:
///
/// @param message The boblight message to send
///
void sendMessage(const std::string &message);
///
/// Send a message to the connected client
///
/// @param message The boblight message to send
/// @param size The size of the message
///
void sendMessage(const char * message, int size);
void sendMessage(const QByteArray &message);
///
/// Send a lights message the to connected client
@@ -104,4 +93,7 @@ private:
/// logger instance
Logger * _log;
/// address of client
QString _clientAddress;
};

View File

@@ -66,7 +66,7 @@ void Effect::registerHyperionExtensionModule()
PyImport_AppendInittab("hyperion", &PyInit_hyperion);
}
Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args)
Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args, const QString & origin)
: QThread()
, _mainThreadState(mainThreadState)
, _priority(priority)
@@ -79,6 +79,7 @@ Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const
, _abortRequested(false)
, _imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor())
, _colors()
, _origin(origin)
{
_colors.resize(_imageProcessor->getLedCount(), ColorRgb::BLACK);
@@ -146,7 +147,7 @@ void Effect::run()
}
else
{
Error(Logger::getInstance("EFFECTENGINE"), "Unable to open script file %s", _script.toUtf8().constData());
Error(Logger::getInstance("EFFECTENGINE"), "Unable to open script file %s.", QSTRING_CSTR(_script));
}
file.close();
@@ -265,7 +266,7 @@ PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args)
if (PyArg_ParseTuple(args, "bbb", &color.red, &color.green, &color.blue))
{
std::fill(effect->_colors.begin(), effect->_colors.end(), color);
effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT);
effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT, effect->_origin);
return Py_BuildValue("");
}
else
@@ -286,7 +287,7 @@ PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args)
{
char * data = PyByteArray_AS_STRING(bytearray);
memcpy(effect->_colors.data(), data, length);
effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT);
effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT, effect->_origin);
return Py_BuildValue("");
}
else
@@ -356,7 +357,7 @@ PyObject* Effect::wrapSetImage(PyObject *self, PyObject *args)
memcpy(image.memptr(), data, length);
effect->_imageProcessor->process(image, effect->_colors);
effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT);
effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT, effect->_origin);
return Py_BuildValue("");
}
else
@@ -432,7 +433,7 @@ PyObject* Effect::wrapImageShow(PyObject *self, PyObject *args)
memcpy(image.memptr(), binaryImage.data(), binaryImage.size());
effect->_imageProcessor->process(image, effect->_colors);
effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT);
effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT, effect->_origin);
return Py_BuildValue("");
}

View File

@@ -18,7 +18,7 @@ class Effect : public QThread
Q_OBJECT
public:
Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args = QJsonObject());
Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args = QJsonObject(), const QString & origin="System");
virtual ~Effect();
virtual void run();
@@ -43,7 +43,7 @@ public slots:
signals:
void effectFinished(Effect * effect);
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects, hyperion::Components component);
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects, hyperion::Components componentconst, QString origin);
private slots:
void effectFinished();
@@ -102,5 +102,6 @@ private:
QImage * _image;
QPainter * _painter;
QString _origin;
};

View File

@@ -342,11 +342,16 @@ void EffectEngine::readEffects()
}
}
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, QString pythonScript)
int EffectEngine::runEffect(const QString &effectName, int priority, int timeout, const QString &origin)
{
return runEffect(effectName, QJsonObject(), priority, timeout, "", origin);
}
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin)
{
Info( _log, "run effect %s on channel %d", effectName.toUtf8().constData(), priority);
if (pythonScript == "")
if (pythonScript.isEmpty())
{
const EffectDefinition * effectDefinition = nullptr;
for (const EffectDefinition & e : _availableEffects)
@@ -364,24 +369,24 @@ int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args,
return -1;
}
return runEffectScript(effectDefinition->script, effectName, args.isEmpty() ? effectDefinition->args : args, priority, timeout);
} else
return runEffectScript(pythonScript, effectName, args, priority, timeout);
return runEffectScript(effectDefinition->script, effectName, (args.isEmpty() ? effectDefinition->args : args), priority, timeout, origin);
}
return runEffectScript(pythonScript, effectName, args, priority, timeout, origin);
}
int EffectEngine::runEffectScript(const QString &script, const QString &name, const QJsonObject &args, int priority, int timeout)
int EffectEngine::runEffectScript(const QString &script, const QString &name, const QJsonObject &args, int priority, int timeout, const QString & origin)
{
// clear current effect on the channel
channelCleared(priority);
// create the effect
Effect * effect = new Effect(_mainThreadState, priority, timeout, script, name, args);
connect(effect, SIGNAL(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components)), _hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components)), Qt::QueuedConnection);
Effect * effect = new Effect(_mainThreadState, priority, timeout, script, name, args, origin);
connect(effect, SIGNAL(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components,const QString)), _hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components,const QString)), Qt::QueuedConnection);
connect(effect, SIGNAL(effectFinished(Effect*)), this, SLOT(effectFinished(Effect*)));
_activeEffects.push_back(effect);
// start the effect
_hyperion->registerPriority(name.toStdString(), priority);
_hyperion->registerPriority(name, priority);
effect->start();
return 0;
@@ -426,5 +431,5 @@ void EffectEngine::effectFinished(Effect *effect)
// cleanup the effect
effect->deleteLater();
_hyperion->unRegisterPriority(effect->getName().toStdString());
_hyperion->unRegisterPriority(effect->getName());
}

View File

@@ -4,7 +4,6 @@
#include <hyperion/GrabberWrapper.h>
#include <HyperionConfig.h>
#define QSTRING_CSTR(str) str.toLocal8Bit().constData()
GrabberWrapper::GrabberWrapper(QString grabberName, const int priority, hyperion::Components grabberComponentId)
: _grabberName(grabberName)
, _hyperion(Hyperion::getInstance())
@@ -37,7 +36,7 @@ bool GrabberWrapper::start()
{
// Start the timer with the pre configured interval
_timer.start();
_hyperion->registerPriority(_grabberName.toStdString(), _priority);
_hyperion->registerPriority(_grabberName, _priority);
return _timer.isActive();
}
@@ -46,7 +45,7 @@ void GrabberWrapper::stop()
{
// Stop the timer, effectivly stopping the process
_timer.stop();
_hyperion->unRegisterPriority(_grabberName.toStdString());
_hyperion->unRegisterPriority(_grabberName);
}
void GrabberWrapper::componentStateChanged(const hyperion::Components component, bool enable)

View File

@@ -504,22 +504,22 @@ bool Hyperion::configWriteable()
}
void Hyperion::registerPriority(const std::string name, const int priority)
void Hyperion::registerPriority(const QString &name, const int priority/*, const QString &origin*/)
{
Info(_log, "Register new input source named '%s' for priority channel '%d'", name.c_str(), priority );
Info(_log, "Register new input source named '%s' for priority channel '%d'", QSTRING_CSTR(name), priority );
for(auto const &entry : _priorityRegister)
{
WarningIf( ( entry.first != name && entry.second == priority), _log,
"Input source '%s' uses same priority channel (%d) as '%s'.", name.c_str(), priority, entry.first.c_str());
"Input source '%s' uses same priority channel (%d) as '%s'.", QSTRING_CSTR(name), priority, QSTRING_CSTR(entry.first));
}
_priorityRegister.emplace(name,priority);
}
void Hyperion::unRegisterPriority(const std::string name)
void Hyperion::unRegisterPriority(const QString &name)
{
Info(_log, "Unregister input source named '%s' from priority register", name.c_str());
Info(_log, "Unregister input source named '%s' from priority register", QSTRING_CSTR(name));
_priorityRegister.erase(name);
}
@@ -688,14 +688,14 @@ const std::list<EffectSchema> & Hyperion::getEffectSchemas()
return _effectEngine->getEffectSchemas();
}
int Hyperion::setEffect(const QString &effectName, int priority, int timeout)
int Hyperion::setEffect(const QString &effectName, int priority, int timeout, const QString & origin)
{
return _effectEngine->runEffect(effectName, priority, timeout);
return _effectEngine->runEffect(effectName, priority, timeout, origin);
}
int Hyperion::setEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, QString pythonScript)
int Hyperion::setEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString & pythonScript, const QString & origin)
{
return _effectEngine->runEffect(effectName, args, priority, timeout, pythonScript);
return _effectEngine->runEffect(effectName, args, priority, timeout, pythonScript, origin);
}
void Hyperion::setLedMappingType(int mappingType)

View File

@@ -27,6 +27,7 @@
#include <QByteArray>
#include <QIODevice>
#include <QDateTime>
#include <QHostInfo>
// hyperion util includes
#include <hyperion/ImageProcessorFactory.h>
@@ -57,6 +58,7 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket)
, _forwarder_enabled(true)
, _streaming_logging_activated(false)
, _image_stream_timeout(0)
, _clientAddress(socket->peerAddress())
{
// connect internal signals and slots
connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
@@ -365,7 +367,7 @@ void JsonClientConnection::handleColorCommand(const QJsonObject& message, const
// extract parameters
int priority = message["priority"].toInt();
int duration = message["duration"].toInt(-1);
QString origin = message["origin"].toString();
QString origin = message["origin"].toString() + "@"+QHostInfo::fromName(_clientAddress.toString()).hostName();
std::vector<ColorRgb> colorData(_hyperion->getLedCount());
const QJsonArray & jsonColor = message["color"].toArray();
@@ -438,18 +440,19 @@ void JsonClientConnection::handleEffectCommand(const QJsonObject& message, const
// extract parameters
int priority = message["priority"].toInt();
int duration = message["duration"].toInt(-1);
QString pythonScript = message["pythonScript"].toString("");
QString pythonScript = message["pythonScript"].toString();
QString origin = message["origin"].toString() + "@"+_clientAddress.toString();
const QJsonObject & effect = message["effect"].toObject();
const QString & effectName = effect["name"].toString();
// set output
if (effect.contains("args"))
{
_hyperion->setEffect(effectName, effect["args"].toObject(), priority, duration, pythonScript);
_hyperion->setEffect(effectName, effect["args"].toObject(), priority, duration, pythonScript, origin);
}
else
{
_hyperion->setEffect(effectName, priority, duration);
_hyperion->setEffect(effectName, priority, duration, origin);
}
// send reply
@@ -607,7 +610,7 @@ void JsonClientConnection::handleServerInfoCommand(const QJsonObject&, const QSt
{
if (entry.second == priority)
{
item["owner"] = QString::fromStdString(entry.first);
item["owner"] = entry.first;
priorityRegister.erase(entry.first);
break;
}
@@ -665,7 +668,7 @@ void JsonClientConnection::handleServerInfoCommand(const QJsonObject&, const QSt
item["priority"] = entry.second;
item["active"] = false;
item["visible"] = false;
item["owner"] = QString::fromStdString(entry.first);
item["owner"] = entry.first;
priorities.append(item);
}

View File

@@ -7,6 +7,7 @@
#include <QByteArray>
#include <QTcpSocket>
#include <QMutex>
#include <QHostAddress>
// Hyperion includes
#include <hyperion/Hyperion.h>
@@ -348,7 +349,10 @@ private:
/// timeout for live video refresh
volatile qint64 _image_stream_timeout;
/// address of client
QHostAddress _clientAddress;
// masks for fields in the basic header
static uint8_t const BHB0_OPCODE = 0x0F;
static uint8_t const BHB0_RSV3 = 0x10;

View File

@@ -16,6 +16,10 @@
"maximum" : 253,
"required": true
},
"origin": {
"type": "string",
"required": true
},
"duration": {
"type": "integer",
"required": false

View File

@@ -11,6 +11,7 @@
#include <QRgb>
#include <QResource>
#include <QDateTime>
#include <QHostInfo>
// hyperion util includes
#include "hyperion/ImageProcessorFactory.h"
@@ -27,13 +28,13 @@ ProtoClientConnection::ProtoClientConnection(QTcpSocket *socket)
, _hyperion(Hyperion::getInstance())
, _receiveBuffer()
, _priority(-1)
, _priorityChannelName("Proto-Server")
, _clientAddress(QHostInfo::fromName(socket->peerAddress().toString()).hostName())
{
// connect internal signals and slots
connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
connect(_socket, SIGNAL(readyRead()), this, SLOT(readData()));
connect(_hyperion, SIGNAL(imageToLedsMappingChanged(int)), _imageProcessor, SLOT(setLedMappingType(int)));
_priorityChannelName = "proto@"+ _socket->peerAddress().toString().toStdString();
}
ProtoClientConnection::~ProtoClientConnection()
@@ -198,7 +199,7 @@ void ProtoClientConnection::handleImageCommand(const proto::ImageRequest &messag
// process the image
std::vector<ColorRgb> ledColors = _imageProcessor->process(image);
_hyperion->setColors(_priority, ledColors, duration);
_hyperion->setColors(_priority, ledColors, duration, true, hyperion::COMP_PROTOSERVER , "proto@"+_clientAddress);
_hyperion->setImage(_priority, image, duration);
// send reply

View File

@@ -7,6 +7,7 @@
#include <QByteArray>
#include <QTcpSocket>
#include <QStringList>
#include <QString>
// Hyperion includes
#include <hyperion/Hyperion.h>
@@ -140,5 +141,8 @@ private:
int _priority;
std::string _priorityChannelName;
QString _priorityChannelName;
/// address of client
QString _clientAddress;
};

View File

@@ -109,27 +109,29 @@ void UDPListener::readPendingDatagrams()
_server->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
processTheDatagram(&datagram);
processTheDatagram(&datagram, &sender);
}
}
void UDPListener::processTheDatagram(const QByteArray * datagram)
void UDPListener::processTheDatagram(const QByteArray * datagram, const QHostAddress * sender)
{
int packetLedCount = datagram->size()/3;
int hyperionLedCount = Hyperion::getInstance()->getLedCount();
DebugIf( (packetLedCount != hyperionLedCount), _log, "packetLedCount (%d) != hyperionLedCount (%d)", packetLedCount, hyperionLedCount);
std::vector<ColorRgb> _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb::BLACK);
std::vector<ColorRgb> _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb::BLACK);
for (int ledIndex=0; ledIndex < std::min(packetLedCount, hyperionLedCount); ledIndex++) {
for (int ledIndex=0; ledIndex < std::min(packetLedCount, hyperionLedCount); ledIndex++) {
ColorRgb & rgb = _ledColors[ledIndex];
rgb.red = datagram->at(ledIndex*3+0);
rgb.red = datagram->at(ledIndex*3+0);
rgb.green = datagram->at(ledIndex*3+1);
rgb.blue = datagram->at(ledIndex*3+2);
rgb.blue = datagram->at(ledIndex*3+2);
}
_hyperion->setColors(_priority, _ledColors, _timeout, -1, hyperion::COMP_UDPLISTENER);
_hyperion->setColors(_priority, _ledColors, _timeout, -1, hyperion::COMP_UDPLISTENER, sender->toString());
}

View File

@@ -25,6 +25,7 @@ SET(Utils_HEADERS
${CURRENT_HEADER_DIR}/RgbToRgbw.h
${CURRENT_HEADER_DIR}/jsonschema/QJsonFactory.h
${CURRENT_HEADER_DIR}/jsonschema/QJsonSchemaChecker.h
${CURRENT_HEADER_DIR}/global_defines.h
)
SET(Utils_SOURCES

View File

@@ -18,6 +18,7 @@ LoggerManager* LoggerManager::_instance = nullptr;
Logger* Logger::getInstance(QString name, Logger::LogLevel minLevel)
{
qRegisterMetaType<Logger::T_LOG_MESSAGE>();
std::string loggerName = name.toStdString();
Logger* log = nullptr;
if (LoggerMap == nullptr)