mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
mDNS Support (#1452)
* Allow build, if no grabbers are enabled * Align available functions to right Qt version * Update to next development version * Align available functions to right Qt version * fix workflows (apt/nightly) * Disable QNetworkConfigurationManager deprecation warnings * Initial go on Smart Pointers * Add Deallocation * Correct QT_WARNING_DISABLE_DEPRECATED (available since 5.9) * Cluster Build Variables * Hyperion Light * Address build warnings * Hyperion Light - UI * Update Protobuf to latest master * Removed compiler warnings * Added restart ability to systray * Correct Protobuf * Ignore 'no-return' warning on protobuf build * hyperion-remote: Fix auto discovery of hyperion server * Fix Qt version override * Update changelog * Remove Grabber Components, if no Grabber exists * Standalone Grabber - Fix fps default * Remote Control - Have Source Selction accrosswhole screen * Enable Blackborder detection only, if relevant input sources available * Enable Blackborder detection only, if relevant input sources available * Remote UI - rearrange containers * Checkout * Fix compilation on windows * Re-added qmdnsengine template cmake * chrono added for linux * Removed existing AVAHI/Bonjour, allow to enable/disable mDNS * hyperiond macos typo fix * Fix macOS Bundle build * Fix macOS bundle info details * Correct CMake files * Removed existing AVAHI/Bonjour (2) * Share hyperion's services via mDNS * Add mDNS Browser and mDNS for LED-Devices * Support mDNS discovery for standalone grabbers * Remove ZLib Dependency & Cleanup * mDNS - hanle 2.local2 an ".local." domains equally * Hue - Link discovery to bridge class, workaround port 443 for mDNS discovery * Fix save button state when switching between devices * Removed sessions (of other hyperions) * mDNS Publisher - Simplify service naming * mDNS refactoring & Forwarder discovery * mDNS Updates to use device service name * Consistency of standalone grabbers with mDNS Service Registry * Merge branch 'hyperion-project:master' into mDNS * Start JSON and WebServers only after Instance 0 is available * Remove bespoke qDebug Output again * MDNS updates and refactor Forwarder * Minor updates * Upgrade to CMake 3.1 * typo * macOS fix * Correct merge * - Remove dynamic linker flag from standalone dispmanX Grabber - Added ability to use system qmdns libs * Cec handler library will load at runtime * typo fix * protobuf changes * mDNS changes for Windows/macOS * test window build qmdnsengine * absolute path to protobuf cmake dir * Rework Hue Wizard supporting mDNS * LED-Devices - Retry support + Refactoring (excl. Hue) * LED-Devices - Refactoring/Retry support Hue + additional alignments * Address LGTM findings * Fix CI-Build, revert test changes * Build Windows in Release mode to avoid python problem * Correct that WebServerObject is available earlier * Ensure that instance name in logs for one instance are presented * Update content LEDs * Rework mDNS Address lookup * Fix LED UI * Fix for non mDNS Services (ignore default port) * Disbale device when now input is available * Revert back some updates, ensure last color is updated when switched on * Handle reopening case and changed IP, port for API-calls * Add UPD-DDP Device * WLED support for DDP * Fix printout * LEDDevice - Allow more retries, udapte defaults * LED-Net Devices - Select Custom device, if configured Co-authored-by: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com> Co-authored-by: Paulchen Panther <Paulchen-Panter@protonmail.com>
This commit is contained in:
@@ -45,23 +45,16 @@ LedDeviceAtmoOrb::~LedDeviceAtmoOrb()
|
||||
|
||||
bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
bool isInitOK {false};
|
||||
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
|
||||
_multicastGroup = deviceConfig["host"].toString(MULTICAST_GROUP_DEFAULT_ADDRESS);
|
||||
_multiCastGroupPort = static_cast<quint16>(deviceConfig["port"].toInt(MULTICAST_GROUP_DEFAULT_PORT));
|
||||
_useOrbSmoothing = deviceConfig["useOrbSmoothing"].toBool(false);
|
||||
_skipSmoothingDiff = deviceConfig["skipSmoothingDiff"].toInt(0);
|
||||
QStringList orbIds = QStringUtils::split(deviceConfig["orbIds"].toString().simplified().remove(" "),",", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %d", this->getLedCount());
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
|
||||
Debug(_log, "MulticastGroup : %s", QSTRING_CSTR(_multicastGroup));
|
||||
Debug(_log, "MulticastGroupPort: %d", _multiCastGroupPort);
|
||||
Debug(_log, "Orb ID list : %s", QSTRING_CSTR(deviceConfig["orbIds"].toString()));
|
||||
|
@@ -8,21 +8,27 @@
|
||||
|
||||
#include <chrono>
|
||||
|
||||
// mDNS discover
|
||||
#ifdef ENABLE_MDNS
|
||||
#include <mdns/MdnsBrowser.h>
|
||||
#include <mdns/MdnsServiceRegister.h>
|
||||
#endif
|
||||
#include <utils/NetUtils.h>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
const bool verbose = false;
|
||||
const bool verbose3 = false;
|
||||
|
||||
// Configuration settings
|
||||
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_HW_LED_COUNT[] = "hardwareLedCount";
|
||||
|
||||
const int COLOLIGHT_BEADS_PER_MODULE = 19;
|
||||
|
||||
const int STREAM_DEFAULT_PORT = 8900;
|
||||
|
||||
// Cololight discovery service
|
||||
|
||||
const int API_DEFAULT_PORT = 8900;
|
||||
|
||||
const char DISCOVERY_ADDRESS[] = "255.255.255.255";
|
||||
const quint16 DISCOVERY_PORT = 12345;
|
||||
const char DISCOVERY_MESSAGE[] = "Z-SEARCH * \r\n";
|
||||
@@ -46,6 +52,11 @@ LedDeviceCololight::LedDeviceCololight(const QJsonObject& deviceConfig)
|
||||
, _distance(0)
|
||||
, _sequenceNumber(1)
|
||||
{
|
||||
#ifdef ENABLE_MDNS
|
||||
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
|
||||
#endif
|
||||
|
||||
_packetFixPart.append(reinterpret_cast<const char*>(PACKET_HEADER), sizeof(PACKET_HEADER));
|
||||
_packetFixPart.append(reinterpret_cast<const char*>(PACKET_SECU), sizeof(PACKET_SECU));
|
||||
}
|
||||
@@ -57,22 +68,13 @@ LedDevice* LedDeviceCololight::construct(const QJsonObject& deviceConfig)
|
||||
|
||||
bool LedDeviceCololight::init(const QJsonObject& deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
bool isInitOK {false};
|
||||
|
||||
_port = API_DEFAULT_PORT;
|
||||
|
||||
if (ProviderUdp::init(deviceConfig))
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
// Initialise LedDevice configuration and execution environment
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR(this->getActiveDeviceType()));
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR(this->getColorOrder()));
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
|
||||
if (initLedsConfiguration())
|
||||
{
|
||||
initDirectColorCmdTemplate();
|
||||
isInitOK = true;
|
||||
}
|
||||
_hostName = _devConfig[ CONFIG_HOST ].toString();
|
||||
_port = STREAM_DEFAULT_PORT;
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
@@ -161,6 +163,27 @@ void LedDeviceCololight::initDirectColorCmdTemplate()
|
||||
}
|
||||
}
|
||||
|
||||
int LedDeviceCololight::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||
{
|
||||
if (ProviderUdp::open() == 0)
|
||||
{
|
||||
if (initLedsConfiguration())
|
||||
{
|
||||
initDirectColorCmdTemplate();
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool LedDeviceCololight::getInfo()
|
||||
{
|
||||
bool isCmdOK = false;
|
||||
@@ -652,10 +675,19 @@ QJsonObject LedDeviceCololight::discover(const QJsonObject& /*params*/)
|
||||
QJsonObject devicesDiscovered;
|
||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType);
|
||||
|
||||
QString discoveryMethod("ssdp");
|
||||
QJsonArray deviceList;
|
||||
|
||||
#ifdef ENABLE_MDNS
|
||||
QString discoveryMethod("mDNS");
|
||||
deviceList = MdnsBrowser::getInstance().getServicesDiscoveredJson(
|
||||
MdnsServiceRegister::getServiceType(_activeDeviceType),
|
||||
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
|
||||
DEFAULT_DISCOVER_TIMEOUT
|
||||
);
|
||||
#else
|
||||
QString discoveryMethod("ssdp");
|
||||
deviceList = discover();
|
||||
#endif
|
||||
|
||||
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
||||
devicesDiscovered.insert("devices", deviceList);
|
||||
@@ -669,19 +701,16 @@ QJsonObject LedDeviceCololight::getProperties(const QJsonObject& params)
|
||||
{
|
||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
QJsonObject properties;
|
||||
|
||||
QString hostName = params["host"].toString("");
|
||||
quint16 apiPort = static_cast<quint16>(params["port"].toInt(API_DEFAULT_PORT));
|
||||
|
||||
QJsonObject propertiesDetails;
|
||||
if (!hostName.isEmpty())
|
||||
|
||||
_hostName = params[CONFIG_HOST].toString("");
|
||||
_port = STREAM_DEFAULT_PORT;
|
||||
|
||||
Info(_log, "Get properties for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||
{
|
||||
QJsonObject deviceConfig;
|
||||
|
||||
deviceConfig.insert("host", hostName);
|
||||
deviceConfig.insert("port", apiPort);
|
||||
|
||||
if (ProviderUdp::init(deviceConfig))
|
||||
if (ProviderUdp::open() == 0)
|
||||
{
|
||||
if (getInfo())
|
||||
{
|
||||
@@ -717,16 +746,14 @@ void LedDeviceCololight::identify(const QJsonObject& params)
|
||||
{
|
||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
QString hostName = params["host"].toString("");
|
||||
quint16 apiPort = static_cast<quint16>(params["port"].toInt(API_DEFAULT_PORT));
|
||||
_hostName = params[CONFIG_HOST].toString("");
|
||||
_port = STREAM_DEFAULT_PORT;
|
||||
|
||||
if (!hostName.isEmpty())
|
||||
Info(_log, "Identify %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||
{
|
||||
QJsonObject deviceConfig;
|
||||
|
||||
deviceConfig.insert("host", hostName);
|
||||
deviceConfig.insert("port", apiPort);
|
||||
if (ProviderUdp::init(deviceConfig))
|
||||
if (ProviderUdp::open() == 0)
|
||||
{
|
||||
if (setStateDirect(false) && setState(true))
|
||||
{
|
||||
|
@@ -161,6 +161,13 @@ protected:
|
||||
///
|
||||
bool init(const QJsonObject& deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
|
@@ -18,15 +18,20 @@ const int MAX_NUM_LEDS = 10000; // OPC can handle 21845 LEDs - in theory, fadeca
|
||||
const int OPC_SET_PIXELS = 0; // OPC command codes
|
||||
const int OPC_SYS_EX = 255; // OPC command codes
|
||||
const int OPC_HEADER_SIZE = 4; // OPC header size
|
||||
} //End of constants
|
||||
|
||||
// TCP elements
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_PORT[] = "port";
|
||||
|
||||
const char DEFAULT_HOST[] = "127.0.0.1";
|
||||
const int STREAM_DEFAULT_PORT = 7890;
|
||||
|
||||
} //End of constants
|
||||
|
||||
LedDeviceFadeCandy::LedDeviceFadeCandy(const QJsonObject& deviceConfig)
|
||||
: LedDevice(deviceConfig)
|
||||
, _client(nullptr)
|
||||
, _host()
|
||||
, _hostName()
|
||||
, _port(STREAM_DEFAULT_PORT)
|
||||
{
|
||||
}
|
||||
@@ -43,7 +48,7 @@ LedDevice* LedDeviceFadeCandy::construct(const QJsonObject& deviceConfig)
|
||||
|
||||
bool LedDeviceFadeCandy::init(const QJsonObject& deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
bool isInitOK {false};
|
||||
|
||||
if (LedDevice::init(deviceConfig))
|
||||
{
|
||||
@@ -55,11 +60,11 @@ bool LedDeviceFadeCandy::init(const QJsonObject& deviceConfig)
|
||||
}
|
||||
else
|
||||
{
|
||||
_host = deviceConfig["host"].toString("127.0.0.1");
|
||||
_port = deviceConfig["port"].toInt(STREAM_DEFAULT_PORT);
|
||||
_hostName = _devConfig[ CONFIG_HOST ].toString(DEFAULT_HOST);
|
||||
_port = deviceConfig[CONFIG_PORT].toInt(STREAM_DEFAULT_PORT);
|
||||
|
||||
//If host not configured the init fails
|
||||
if (_host.isEmpty())
|
||||
if (_hostName.isEmpty())
|
||||
{
|
||||
this->setInError("No target hostname nor IP defined");
|
||||
}
|
||||
@@ -90,10 +95,7 @@ bool LedDeviceFadeCandy::init(const QJsonObject& deviceConfig)
|
||||
_opc_data[1] = OPC_SET_PIXELS;
|
||||
qToBigEndian<quint16>(static_cast<quint16>(_ledRGBCount), _opc_data.data() + 2);
|
||||
|
||||
if (initNetwork())
|
||||
{
|
||||
isInitOK = true;
|
||||
}
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,12 +104,11 @@ bool LedDeviceFadeCandy::init(const QJsonObject& deviceConfig)
|
||||
|
||||
bool LedDeviceFadeCandy::initNetwork()
|
||||
{
|
||||
bool isInitOK = false;
|
||||
bool isInitOK = true;
|
||||
|
||||
if (_client == nullptr)
|
||||
{
|
||||
_client = new QTcpSocket(this);
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
@@ -118,17 +119,20 @@ int LedDeviceFadeCandy::open()
|
||||
QString errortext;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (initNetwork())
|
||||
{
|
||||
// Try to open the LedDevice
|
||||
if (!tryConnect())
|
||||
{
|
||||
errortext = QString("Failed to open device.");
|
||||
this->setInError(errortext);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
if (!tryConnect())
|
||||
{
|
||||
errortext = QString("Failed to open device.");
|
||||
this->setInError(errortext);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -162,10 +166,10 @@ bool LedDeviceFadeCandy::tryConnect()
|
||||
if (_client != nullptr)
|
||||
{
|
||||
if (_client->state() == QAbstractSocket::UnconnectedState) {
|
||||
_client->connectToHost(_host, static_cast<quint16>(_port));
|
||||
_client->connectToHost(_hostName, static_cast<quint16>(_port));
|
||||
if (_client->waitForConnected(CONNECT_TIMEOUT.count()))
|
||||
{
|
||||
Info(_log, "fadecandy/opc: connected to %s:%d on channel %d", QSTRING_CSTR(_host), _port, _channel);
|
||||
Info(_log, "fadecandy/opc: connected to %s:%d on channel %d", QSTRING_CSTR(_hostName), _port, _channel);
|
||||
if (_setFcConfig)
|
||||
{
|
||||
sendFadeCandyConfiguration();
|
||||
|
@@ -130,7 +130,7 @@ private:
|
||||
void sendFadeCandyConfiguration();
|
||||
|
||||
QTcpSocket* _client;
|
||||
QString _host;
|
||||
QString _hostName;
|
||||
int _port;
|
||||
int _channel;
|
||||
QByteArray _opc_data;
|
||||
|
@@ -1,16 +1,23 @@
|
||||
// Local-Hyperion includes
|
||||
#include "LedDeviceNanoleaf.h"
|
||||
|
||||
#include <ssdp/SSDPDiscover.h>
|
||||
#include <utils/QStringUtils.h>
|
||||
//std includes
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
// Qt includes
|
||||
#include <QNetworkReply>
|
||||
#include <QtEndian>
|
||||
|
||||
//std includes
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <ssdp/SSDPDiscover.h>
|
||||
#include <utils/QStringUtils.h>
|
||||
|
||||
// mDNS discover
|
||||
#ifdef ENABLE_MDNS
|
||||
#include <mdns/MdnsBrowser.h>
|
||||
#include <mdns/MdnsServiceRegister.h>
|
||||
#endif
|
||||
#include <utils/NetUtils.h>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
@@ -18,7 +25,7 @@ const bool verbose = false;
|
||||
const bool verbose3 = false;
|
||||
|
||||
// Configuration settings
|
||||
const char CONFIG_ADDRESS[] = "host";
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_AUTH_TOKEN[] = "token";
|
||||
const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
|
||||
const char CONFIG_BRIGHTNESS[] = "brightness";
|
||||
@@ -115,6 +122,10 @@ LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject& deviceConfig)
|
||||
, _extControlVersion(EXTCTRLVER_V2)
|
||||
, _panelLedCount(0)
|
||||
{
|
||||
#ifdef ENABLE_MDNS
|
||||
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
|
||||
#endif
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceNanoleaf::construct(const QJsonObject& deviceConfig)
|
||||
@@ -130,6 +141,8 @@ LedDeviceNanoleaf::~LedDeviceNanoleaf()
|
||||
|
||||
bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
||||
{
|
||||
bool isInitOK {false};
|
||||
|
||||
// Overwrite non supported/required features
|
||||
setLatchTime(0);
|
||||
setRewriteTime(0);
|
||||
@@ -141,21 +154,19 @@ bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
||||
|
||||
DebugIf(verbose,_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
bool isInitOK = false;
|
||||
|
||||
if (LedDevice::init(deviceConfig))
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
int configuredLedCount = this->getLedCount();
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR(this->getActiveDeviceType()));
|
||||
Debug(_log, "LedCount : %d", configuredLedCount);
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR(this->getColorOrder()));
|
||||
Debug(_log, "RewriteTime : %d", this->getRewriteTime());
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
//Set hostname as per configuration and default port
|
||||
_hostName = deviceConfig[CONFIG_HOST].toString();
|
||||
_port = STREAM_CONTROL_DEFAULT_PORT;
|
||||
_apiPort = API_DEFAULT_PORT;
|
||||
_authToken = deviceConfig[CONFIG_AUTH_TOKEN].toString();
|
||||
|
||||
_isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(DEFAULT_IS_RESTORE_STATE);
|
||||
_isBrightnessOverwrite = _devConfig[CONFIG_BRIGHTNESS_OVERWRITE].toBool(DEFAULT_IS_BRIGHTNESS_OVERWRITE);
|
||||
_brightness = _devConfig[CONFIG_BRIGHTNESS].toInt(BRI_MAX);
|
||||
|
||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostName) );
|
||||
Debug(_log, "RestoreOrigState : %d", _isRestoreOrigState);
|
||||
Debug(_log, "Overwrite Brightn.: %d", _isBrightnessOverwrite);
|
||||
Debug(_log, "Set Brightness to : %d", _brightness);
|
||||
@@ -178,37 +189,9 @@ bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
||||
{
|
||||
_leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toInt() == 0;
|
||||
}
|
||||
|
||||
_startPos = deviceConfig[CONFIG_PANEL_START_POS].toInt(0);
|
||||
|
||||
//Set hostname as per configuration and_defaultHost default port
|
||||
_hostName = deviceConfig[CONFIG_ADDRESS].toString();
|
||||
_apiPort = API_DEFAULT_PORT;
|
||||
_authToken = deviceConfig[CONFIG_AUTH_TOKEN].toString();
|
||||
|
||||
//If host not configured the init failed
|
||||
if (_hostName.isEmpty())
|
||||
{
|
||||
this->setInError("No target hostname nor IP defined");
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (initRestAPI(_hostName, _apiPort, _authToken))
|
||||
{
|
||||
// Read LedDevice configuration and validate against device configuration
|
||||
if (initLedsConfiguration())
|
||||
{
|
||||
// Set UDP streaming host and 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
@@ -358,18 +341,17 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::initRestAPI(const QString& hostname, int port, const QString& token)
|
||||
bool LedDeviceNanoleaf::openRestAPI()
|
||||
{
|
||||
bool isInitOK = false;
|
||||
bool isInitOK {true};
|
||||
|
||||
if (_restApi == nullptr)
|
||||
{
|
||||
_restApi = new ProviderRestApi(hostname, port);
|
||||
_restApi = new ProviderRestApi(_address.toString(), _apiPort);
|
||||
_restApi->setLogger(_log);
|
||||
|
||||
//Base-path is api-path + authentication token
|
||||
_restApi->setBasePath(QString(API_BASE_PATH).arg(token));
|
||||
|
||||
isInitOK = true;
|
||||
_restApi->setBasePath(QString(API_BASE_PATH).arg(_authToken));
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
@@ -379,13 +361,27 @@ int LedDeviceNanoleaf::open()
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (ProviderUdp::open() == 0)
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
if ( openRestAPI() )
|
||||
{
|
||||
// Read LedDevice configuration and validate against device configuration
|
||||
if (initLedsConfiguration())
|
||||
{
|
||||
if (ProviderUdp::open() == 0)
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_restApi->setHost(_address.toString());
|
||||
_restApi->setPort(_apiPort);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -414,13 +410,23 @@ QJsonObject LedDeviceNanoleaf::discover(const QJsonObject& /*params*/)
|
||||
QJsonObject devicesDiscovered;
|
||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType);
|
||||
|
||||
QString discoveryMethod("ssdp");
|
||||
QJsonArray deviceList;
|
||||
|
||||
#ifdef ENABLE_MDNS
|
||||
QString discoveryMethod("mDNS");
|
||||
deviceList = MdnsBrowser::getInstance().getServicesDiscoveredJson(
|
||||
MdnsServiceRegister::getServiceType(_activeDeviceType),
|
||||
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
|
||||
DEFAULT_DISCOVER_TIMEOUT
|
||||
);
|
||||
#else
|
||||
QString discoveryMethod("ssdp");
|
||||
deviceList = discover();
|
||||
#endif
|
||||
|
||||
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
||||
devicesDiscovered.insert("devices", deviceList);
|
||||
|
||||
DebugIf(verbose,_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
return devicesDiscovered;
|
||||
@@ -431,27 +437,29 @@ QJsonObject LedDeviceNanoleaf::getProperties(const QJsonObject& params)
|
||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
QJsonObject properties;
|
||||
|
||||
// Get Nanoleaf device properties
|
||||
QString hostName = params["host"].toString("");
|
||||
_hostName = params[CONFIG_HOST].toString("");
|
||||
_apiPort = API_DEFAULT_PORT;
|
||||
_authToken = params["token"].toString("");
|
||||
|
||||
if (!hostName.isEmpty())
|
||||
Info(_log, "Get properties for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||
{
|
||||
QString authToken = params["token"].toString("");
|
||||
QString filter = params["filter"].toString("");
|
||||
|
||||
initRestAPI(hostName, API_DEFAULT_PORT, authToken);
|
||||
_restApi->setPath(filter);
|
||||
|
||||
// Perform request
|
||||
httpResponse response = _restApi->get();
|
||||
if (response.error())
|
||||
if ( openRestAPI() )
|
||||
{
|
||||
Warning(_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
QString filter = params["filter"].toString("");
|
||||
_restApi->setPath(filter);
|
||||
|
||||
// Perform request
|
||||
httpResponse response = _restApi->get();
|
||||
if (response.error())
|
||||
{
|
||||
Warning(_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
}
|
||||
properties.insert("properties", response.getBody().object());
|
||||
}
|
||||
|
||||
properties.insert("properties", response.getBody().object());
|
||||
|
||||
DebugIf(verbose,_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
@@ -460,19 +468,24 @@ void LedDeviceNanoleaf::identify(const QJsonObject& params)
|
||||
{
|
||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
QString hostName = params["host"].toString("");
|
||||
if (!hostName.isEmpty())
|
||||
_hostName = params[CONFIG_HOST].toString("");
|
||||
_apiPort = API_DEFAULT_PORT;if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||
_authToken = params["token"].toString("");
|
||||
|
||||
Info(_log, "Identify %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||
{
|
||||
QString authToken = params["token"].toString("");
|
||||
|
||||
initRestAPI(hostName, API_DEFAULT_PORT, authToken);
|
||||
_restApi->setPath("identify");
|
||||
|
||||
// Perform request
|
||||
httpResponse response = _restApi->put();
|
||||
if (response.error())
|
||||
if ( openRestAPI() )
|
||||
{
|
||||
Warning(_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
_restApi->setPath("identify");
|
||||
|
||||
// Perform request
|
||||
httpResponse response = _restApi->put();
|
||||
if (response.error())
|
||||
{
|
||||
Warning(_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -662,7 +675,7 @@ bool LedDeviceNanoleaf::restoreState()
|
||||
Warning (_log, "%s restoring effect failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
}
|
||||
} else {
|
||||
Warning (_log, "%s restoring effect failed with error: Cannot restore dynamic or solid effect. Turning device off", QSTRING_CSTR(_activeDeviceType));
|
||||
Warning (_log, "%s restoring effect failed with error: Cannot restore dynamic or solid effect. Device is switched off", QSTRING_CSTR(_activeDeviceType));
|
||||
_originalIsOn = false;
|
||||
}
|
||||
break;
|
||||
|
@@ -150,13 +150,9 @@ private:
|
||||
///
|
||||
/// @brief Initialise the access to the REST-API wrapper
|
||||
///
|
||||
/// @param[in] host
|
||||
/// @param[in] port
|
||||
/// @param[in] authentication token
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool initRestAPI(const QString& hostname, int port, const QString& token);
|
||||
bool openRestAPI();
|
||||
|
||||
///
|
||||
/// @brief Get Nanoleaf device details and configuration
|
||||
@@ -188,9 +184,7 @@ private:
|
||||
|
||||
///REST-API wrapper
|
||||
ProviderRestApi* _restApi;
|
||||
|
||||
QString _hostName;
|
||||
int _apiPort;
|
||||
int _apiPort;
|
||||
QString _authToken;
|
||||
|
||||
bool _topDown;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,6 @@
|
||||
|
||||
// Qt includes
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkReply>
|
||||
#include <QtCore/qmath.h>
|
||||
#include <QStringList>
|
||||
@@ -85,7 +84,7 @@ struct CiColor
|
||||
///
|
||||
/// @return color point
|
||||
///
|
||||
static CiColor rgbToCiColor(double red, double green, double blue, const CiColorTriangle &colorSpace);
|
||||
static CiColor rgbToCiColor(double red, double green, double blue, const CiColorTriangle& colorSpace, bool candyGamma);
|
||||
|
||||
///
|
||||
/// @param p the color point to check
|
||||
@@ -149,8 +148,9 @@ public:
|
||||
/// @param bridge the bridge
|
||||
/// @param id the light id
|
||||
///
|
||||
PhilipsHueLight(Logger* log, unsigned int id, QJsonObject values, unsigned int ledidx);
|
||||
~PhilipsHueLight();
|
||||
PhilipsHueLight(Logger* log, int id, QJsonObject values, int ledidx,
|
||||
int onBlackTimeToPowerOff,
|
||||
int onBlackTimeToPowerOn);
|
||||
|
||||
///
|
||||
/// @param on
|
||||
@@ -167,11 +167,12 @@ public:
|
||||
///
|
||||
void setColor(const CiColor& color);
|
||||
|
||||
unsigned int getId() const;
|
||||
int getId() const;
|
||||
|
||||
bool getOnOffState() const;
|
||||
int getTransitionTime() const;
|
||||
CiColor getColor() const;
|
||||
bool hasColor() const;
|
||||
|
||||
///
|
||||
/// @return the color space of the light determined by the model id reported by the bridge.
|
||||
@@ -180,15 +181,21 @@ public:
|
||||
void saveOriginalState(const QJsonObject& values);
|
||||
QString getOriginalState() const;
|
||||
|
||||
bool isBusy();
|
||||
bool isBlack(bool isBlack);
|
||||
bool isWhite(bool isWhite);
|
||||
void setBlack();
|
||||
void blackScreenTriggered();
|
||||
private:
|
||||
|
||||
Logger* _log;
|
||||
/// light id
|
||||
unsigned int _id;
|
||||
unsigned int _ledidx;
|
||||
int _id;
|
||||
int _ledidx;
|
||||
bool _on;
|
||||
int _transitionTime;
|
||||
CiColor _color;
|
||||
bool _hasColor;
|
||||
/// darkes blue color in hue lamp GAMUT = black
|
||||
CiColor _colorBlack;
|
||||
/// The model id of the hue lamp which is used to determine the color space.
|
||||
@@ -201,6 +208,12 @@ private:
|
||||
|
||||
QString _originalState;
|
||||
CiColor _originalColor;
|
||||
qint64 _lastSendColorTime;
|
||||
qint64 _lastBlackTime;
|
||||
qint64 _lastWhiteTime;
|
||||
bool _blackScreenTriggered;
|
||||
qint64 _onBlackTimeToPowerOff;
|
||||
qint64 _onBlackTimeToPowerOn;
|
||||
};
|
||||
|
||||
class LedDevicePhilipsHueBridge : public ProviderUdpSSL
|
||||
@@ -215,13 +228,9 @@ public:
|
||||
///
|
||||
/// @brief Initialise the access to the REST-API wrapper
|
||||
///
|
||||
/// @param[in] host
|
||||
/// @param[in] port
|
||||
/// @param[in] authentication token
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool initRestAPI(const QString &hostname, int port, const QString &token );
|
||||
bool openRestAPI();
|
||||
|
||||
///
|
||||
/// @brief Perform a REST-API GET
|
||||
@@ -238,20 +247,18 @@ public:
|
||||
/// @param route the route of the POST request.
|
||||
/// @param content the content of the POST request.
|
||||
///
|
||||
QJsonDocument post(const QString& route, const QString& content);
|
||||
QJsonDocument put(const QString& route, const QString& content, bool supressError = false);
|
||||
|
||||
QJsonDocument getLightState(unsigned int lightId);
|
||||
void setLightState(unsigned int lightId = 0, const QString &state = "");
|
||||
QJsonDocument getLightState( int lightId);
|
||||
void setLightState( int lightId = 0, const QString &state = "");
|
||||
|
||||
QMap<quint16,QJsonObject> getLightMap() const;
|
||||
QMap<int,QJsonObject> getLightMap() const;
|
||||
|
||||
QMap<quint16,QJsonObject> getGroupMap() const;
|
||||
|
||||
QString getGroupName(quint16 groupId = 0) const;
|
||||
|
||||
QJsonArray getGroupLights(quint16 groupId = 0) const;
|
||||
QMap<int,QJsonObject> getGroupMap() const;
|
||||
|
||||
QString getGroupName(int groupId = 0) const;
|
||||
|
||||
QJsonArray getGroupLights(int groupId = 0) const;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -281,23 +288,66 @@ protected:
|
||||
/// @brief Check, if Hue API response indicate error
|
||||
///
|
||||
/// @param[in] response from Hue-Bridge in JSON-format
|
||||
/// @param[in] suppressError Treat an error as a warning
|
||||
///
|
||||
/// return True, Hue Bridge reports error
|
||||
///
|
||||
bool checkApiError(const QJsonDocument &response );
|
||||
bool checkApiError(const QJsonDocument& response, bool supressError = false);
|
||||
|
||||
///
|
||||
/// @brief Discover devices of this type available (for configuration).
|
||||
/// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
|
||||
///
|
||||
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||
///
|
||||
/// @return A JSON structure holding a list of devices found
|
||||
///
|
||||
QJsonObject discover(const QJsonObject& params) override;
|
||||
|
||||
///
|
||||
/// @brief Get the Hue Bridge device's resource properties
|
||||
///
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "host" : "hostname or IP",
|
||||
/// "port" : port
|
||||
/// "user" : "username",
|
||||
/// "filter": "resource to query", root "/" is used, if empty
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters to query device
|
||||
/// @return A JSON structure holding the device's properties
|
||||
///
|
||||
QJsonObject getProperties(const QJsonObject& params) override;
|
||||
|
||||
///
|
||||
/// @brief Add an authorization/client-key to the Hue Bridge device
|
||||
///
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "host" : "hostname or IP",
|
||||
/// "port" : port
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters to query device
|
||||
/// @return A JSON structure holding the authorization keys
|
||||
///
|
||||
QJsonObject addAuthorization(const QJsonObject& params) override;
|
||||
|
||||
///REST-API wrapper
|
||||
ProviderRestApi* _restApi;
|
||||
|
||||
/// Ip address of the bridge
|
||||
QString _hostname;
|
||||
int _apiPort;
|
||||
/// User name for the API ("newdeveloper")
|
||||
QString _username;
|
||||
QString _authToken;
|
||||
|
||||
bool _useHueEntertainmentAPI;
|
||||
|
||||
QJsonDocument getGroupState( unsigned int groupId );
|
||||
QJsonDocument setGroupState( unsigned int groupId, bool state);
|
||||
QJsonDocument getGroupState( int groupId );
|
||||
QJsonDocument setGroupState( int groupId, bool state);
|
||||
|
||||
bool isStreamOwner(const QString &streamOwner) const;
|
||||
bool initMaps();
|
||||
@@ -308,6 +358,14 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Discover Philips-Hue devices available (for configuration).
|
||||
/// Philips-Hue specific ssdp discovery
|
||||
///
|
||||
/// @return A JSON structure holding a list of devices found
|
||||
///
|
||||
QJsonArray discover();
|
||||
|
||||
QJsonDocument getAllBridgeInfos();
|
||||
void setBridgeConfig( const QJsonDocument &doc );
|
||||
void setLightsMap( const QJsonDocument &doc );
|
||||
@@ -324,8 +382,8 @@ private:
|
||||
|
||||
bool _isHueEntertainmentReady;
|
||||
|
||||
QMap<quint16,QJsonObject> _lightsMap;
|
||||
QMap<quint16,QJsonObject> _groupsMap;
|
||||
QMap<int,QJsonObject> _lightsMap;
|
||||
QMap<int,QJsonObject> _groupsMap;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -360,34 +418,6 @@ public:
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// @brief Discover devices of this type available (for configuration).
|
||||
/// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
|
||||
///
|
||||
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||
///
|
||||
/// @return A JSON structure holding a list of devices found
|
||||
///
|
||||
QJsonObject discover(const QJsonObject& params) override;
|
||||
|
||||
///
|
||||
/// @brief Get the Hue Bridge device's resource properties
|
||||
///
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "host" : "hostname or IP
|
||||
/// "port" : port
|
||||
/// "user" : "username",
|
||||
/// "filter": "resource to query", root "/" is used, if empty
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters to query device
|
||||
/// @return A JSON structure holding the device's properties
|
||||
///
|
||||
QJsonObject getProperties(const QJsonObject& params) override;
|
||||
|
||||
///
|
||||
/// @brief Send an update to the device to identify it.
|
||||
///
|
||||
@@ -412,7 +442,7 @@ public:
|
||||
///
|
||||
unsigned int getLightsCount() const { return _lightsCount; }
|
||||
|
||||
void setOnOffState(PhilipsHueLight& light, bool on);
|
||||
void setOnOffState(PhilipsHueLight& light, bool on, bool force = false);
|
||||
void setTransitionTime(PhilipsHueLight& light);
|
||||
void setColor(PhilipsHueLight& light, CiColor& color);
|
||||
void setState(PhilipsHueLight& light, bool on, const CiColor& color);
|
||||
@@ -443,13 +473,6 @@ protected:
|
||||
///
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
int close() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
@@ -465,7 +488,7 @@ protected:
|
||||
/// Depending on the configuration, the device may store its current state for later restore.
|
||||
/// @see powerOn, storeState
|
||||
///
|
||||
/// @return True if success
|
||||
/// @return True, if success
|
||||
///
|
||||
bool switchOn() override;
|
||||
|
||||
@@ -518,28 +541,17 @@ protected:
|
||||
///
|
||||
bool restoreState() override;
|
||||
|
||||
private slots:
|
||||
|
||||
void noSignalTimeout();
|
||||
|
||||
private:
|
||||
|
||||
bool initLeds();
|
||||
|
||||
///
|
||||
/// @brief Creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
||||
///
|
||||
/// @param map Map of lightid/value pairs of bridge
|
||||
///
|
||||
void newLights(QMap<quint16, QJsonObject> map);
|
||||
|
||||
bool setLights();
|
||||
|
||||
/// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
||||
///
|
||||
/// @param map Map of lightid/value pairs of bridge
|
||||
///
|
||||
bool updateLights(const QMap<quint16, QJsonObject> &map);
|
||||
bool updateLights(const QMap<int, QJsonObject> &map);
|
||||
|
||||
///
|
||||
/// @brief Set the number of LEDs supported by the device.
|
||||
@@ -554,13 +566,9 @@ private:
|
||||
bool startStream();
|
||||
bool stopStream();
|
||||
|
||||
void writeStream();
|
||||
void writeStream(bool flush = false);
|
||||
int writeSingleLights(const std::vector<ColorRgb>& ledValues);
|
||||
|
||||
bool noSignalDetection();
|
||||
|
||||
void stopBlackTimeoutTimer();
|
||||
|
||||
QByteArray prepareStreamData() const;
|
||||
|
||||
///
|
||||
@@ -574,32 +582,28 @@ private:
|
||||
bool _isInitLeds;
|
||||
|
||||
/// Array of the light ids.
|
||||
std::vector<quint16> _lightIds;
|
||||
std::vector<int> _lightIds;
|
||||
/// Array to save the lamps.
|
||||
std::vector<PhilipsHueLight> _lights;
|
||||
|
||||
unsigned int _lightsCount;
|
||||
quint16 _groupId;
|
||||
int _lightsCount;
|
||||
int _groupId;
|
||||
|
||||
double _brightnessMin;
|
||||
double _brightnessMax;
|
||||
|
||||
bool _allLightsBlack;
|
||||
|
||||
QTimer* _blackLightsTimer;
|
||||
int _blackLightsTimeout;
|
||||
double _brightnessThreshold;
|
||||
|
||||
int _handshake_timeout_min;
|
||||
int _handshake_timeout_max;
|
||||
int _ssl_read_timeout;
|
||||
double _blackLevel;
|
||||
int _onBlackTimeToPowerOff;
|
||||
int _onBlackTimeToPowerOn;
|
||||
bool _candyGamma;
|
||||
|
||||
// TODO: Check what is the correct class
|
||||
uint32_t _handshake_timeout_min;
|
||||
uint32_t _handshake_timeout_max;
|
||||
bool _stopConnection;
|
||||
|
||||
QString _groupName;
|
||||
QString _streamOwner;
|
||||
|
||||
int start_retry_left;
|
||||
int stop_retry_left;
|
||||
|
||||
qint64 _lastConfirm;
|
||||
int _lastId;
|
||||
bool _groupStreamState;
|
||||
};
|
||||
|
@@ -65,13 +65,6 @@ bool LedDeviceRazer::init(const QJsonObject& deviceConfig)
|
||||
// Initialise sub-class
|
||||
if (LedDevice::init(deviceConfig))
|
||||
{
|
||||
// Initialise LedDevice configuration and execution environment
|
||||
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, "LatchTime : %d", this->getLatchTime());
|
||||
Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
|
||||
|
||||
//Razer Chroma SDK allows localhost connection only
|
||||
_hostname = API_DEFAULT_HOST;
|
||||
@@ -86,6 +79,7 @@ bool LedDeviceRazer::init(const QJsonObject& deviceConfig)
|
||||
Debug(_log, "Razer Device : %s", QSTRING_CSTR(_razerDeviceType));
|
||||
Debug(_log, "Single Color : %d", _isSingleColor);
|
||||
|
||||
int configuredLedCount = this->getLedCount();
|
||||
if (resolveDeviceProperties(_razerDeviceType))
|
||||
{
|
||||
if (_isSingleColor && configuredLedCount > 1)
|
||||
@@ -125,6 +119,8 @@ bool LedDeviceRazer::initRestAPI(const QString& hostname, int port)
|
||||
if (_restApi == nullptr)
|
||||
{
|
||||
_restApi = new ProviderRestApi(hostname, port);
|
||||
_restApi->setLogger(_log);
|
||||
|
||||
_restApi->setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
isInitOK = true;
|
||||
|
@@ -1,6 +1,13 @@
|
||||
#include "LedDeviceTpm2net.h"
|
||||
#include <utils/NetUtils.h>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_PORT[] = "port";
|
||||
const ushort TPM2_DEFAULT_PORT = 65506;
|
||||
}
|
||||
|
||||
LedDeviceTpm2net::LedDeviceTpm2net(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp(deviceConfig)
|
||||
@@ -20,13 +27,14 @@ LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
_port = TPM2_DEFAULT_PORT;
|
||||
bool isInitOK {false};
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
_hostName = _devConfig[ CONFIG_HOST ].toString();
|
||||
_port = deviceConfig[CONFIG_PORT].toInt(TPM2_DEFAULT_PORT);
|
||||
|
||||
_tpm2_max = deviceConfig["max-packet"].toInt(170);
|
||||
_tpm2ByteCount = 3 * _ledCount;
|
||||
_tpm2TotalPackets = (_tpm2ByteCount / _tpm2_max) + ((_tpm2ByteCount % _tpm2_max) != 0);
|
||||
@@ -38,6 +46,23 @@ bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceTpm2net::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||
{
|
||||
if (ProviderUdp::open() == 0)
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceTpm2net::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
int retVal = 0;
|
||||
|
@@ -41,6 +41,13 @@ private:
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
|
@@ -9,7 +9,16 @@
|
||||
|
||||
#include <QHostInfo>
|
||||
|
||||
#include <utils/NetUtils.h>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_PORT[] = "port";
|
||||
|
||||
const ushort ARTNET_DEFAULT_PORT = 6454;
|
||||
}
|
||||
|
||||
LedDeviceUdpArtNet::LedDeviceUdpArtNet(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp(deviceConfig)
|
||||
@@ -23,13 +32,14 @@ LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
_port = ARTNET_DEFAULT_PORT;
|
||||
bool isInitOK {false};
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
_hostName = _devConfig[ CONFIG_HOST ].toString();
|
||||
_port = deviceConfig[CONFIG_PORT].toInt(ARTNET_DEFAULT_PORT);
|
||||
|
||||
_artnet_universe = deviceConfig["universe"].toInt(1);
|
||||
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
|
||||
|
||||
@@ -38,6 +48,23 @@ bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceUdpArtNet::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||
{
|
||||
if (ProviderUdp::open() == 0)
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// populates the headers
|
||||
void LedDeviceUdpArtNet::prepare(unsigned this_universe, unsigned this_sequence, unsigned this_dmxChannelCount)
|
||||
{
|
||||
|
@@ -69,6 +69,13 @@ private:
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
|
163
libsrc/leddevice/dev_net/LedDeviceUdpDdp.cpp
Normal file
163
libsrc/leddevice/dev_net/LedDeviceUdpDdp.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#include "LedDeviceUdpDdp.h"
|
||||
|
||||
#include <QtEndian>
|
||||
|
||||
#include <utils/NetUtils.h>
|
||||
|
||||
// DDP header format
|
||||
// header is 10 bytes (14 if TIME flag used)
|
||||
struct ddp_hdr_struct {
|
||||
uint8_t flags1;
|
||||
uint8_t flags2;
|
||||
uint8_t type;
|
||||
uint8_t id;
|
||||
uint32_t offset;
|
||||
uint16_t len;
|
||||
};
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_PORT[] = "port";
|
||||
|
||||
const ushort DDP_DEFAULT_PORT = 4048;
|
||||
|
||||
namespace DDP {
|
||||
|
||||
// DDP protocol header definitions
|
||||
struct Header {
|
||||
uint8_t flags1;
|
||||
uint8_t flags2;
|
||||
uint8_t type;
|
||||
uint8_t id;
|
||||
uint8_t offset[4];
|
||||
uint8_t len[2];
|
||||
};
|
||||
|
||||
static constexpr int HEADER_LEN = (sizeof(struct Header)); // header is 10 bytes (14 if TIME flag used)
|
||||
static constexpr int MAX_LEDS = 480;
|
||||
static constexpr int CHANNELS_PER_PACKET = MAX_LEDS*3;
|
||||
|
||||
namespace flags1 {
|
||||
static constexpr auto VER_MASK = 0xc0;
|
||||
static constexpr auto VER1 = 0x40;
|
||||
static constexpr auto PUSH = 0x01;
|
||||
static constexpr auto QUERY = 0x02;
|
||||
static constexpr auto REPLY = 0x04;
|
||||
static constexpr auto STORAGE = 0x08;
|
||||
static constexpr auto TIME = 0x10;
|
||||
} // namespace flags1
|
||||
|
||||
namespace id {
|
||||
static constexpr auto DISPLAY = 1;
|
||||
static constexpr auto CONTROL = 246;
|
||||
static constexpr auto CONFIG = 250;
|
||||
static constexpr auto STATUS = 251;
|
||||
static constexpr auto DMXTRANSIT = 254;
|
||||
static constexpr auto ALLDEVICES = 255;
|
||||
} // namespace id
|
||||
|
||||
} // namespace DDP
|
||||
|
||||
} //End of constants
|
||||
|
||||
LedDeviceUdpDdp::LedDeviceUdpDdp(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp(deviceConfig)
|
||||
,_packageSequenceNumber(0)
|
||||
{
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpDdp::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceUdpDdp(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceUdpDdp::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK {false};
|
||||
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
_hostName = _devConfig[ CONFIG_HOST ].toString();
|
||||
_port = deviceConfig[CONFIG_PORT].toInt(DDP_DEFAULT_PORT);
|
||||
|
||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostName) );
|
||||
Debug(_log, "Port : %d", _port );
|
||||
|
||||
_ddpData.resize(DDP::HEADER_LEN + DDP::CHANNELS_PER_PACKET);
|
||||
_ddpData[0] = DDP::flags1::VER1; // flags1
|
||||
_ddpData[1] = 0; // flags2
|
||||
_ddpData[2] = 1; // type
|
||||
_ddpData[3] = DDP::id::DISPLAY; // id
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceUdpDdp::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||
{
|
||||
if (ProviderUdp::open() == 0)
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceUdpDdp::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
int rc {0};
|
||||
|
||||
int channelCount = static_cast<int>(_ledCount) * 3; // 1 channel for every R,G,B value
|
||||
int packetCount = ((channelCount-1) / DDP::CHANNELS_PER_PACKET) + 1;
|
||||
int channel = 0;
|
||||
|
||||
_ddpData[0] = DDP::flags1::VER1;
|
||||
|
||||
for (int currentPacket = 0; currentPacket < packetCount; currentPacket++)
|
||||
{
|
||||
if (_packageSequenceNumber > 15)
|
||||
{
|
||||
_packageSequenceNumber = 0;
|
||||
}
|
||||
|
||||
int packetSize = DDP::CHANNELS_PER_PACKET;
|
||||
|
||||
if (currentPacket == (packetCount - 1))
|
||||
{
|
||||
// last packet, set the push flag
|
||||
/*0*/_ddpData[0] = DDP::flags1::VER1 | DDP::flags1::PUSH;
|
||||
|
||||
if (channelCount % DDP::CHANNELS_PER_PACKET != 0)
|
||||
{
|
||||
packetSize = channelCount % DDP::CHANNELS_PER_PACKET;
|
||||
}
|
||||
}
|
||||
|
||||
/*1*/_ddpData[1] = static_cast<char>(_packageSequenceNumber++ & 0x0F);
|
||||
/*4*/qToBigEndian<quint32>(static_cast<quint32>(channel), _ddpData.data() + 4);
|
||||
/*8*/qToBigEndian<quint16>(static_cast<quint16>(packetSize), _ddpData.data() + 8);
|
||||
|
||||
_ddpData.replace(DDP::HEADER_LEN, channel, reinterpret_cast<const char*>(ledValues.data())+channel, packetSize);
|
||||
_ddpData.resize(DDP::HEADER_LEN + packetSize);
|
||||
|
||||
rc = writeBytes(_ddpData);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
channel += packetSize;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
62
libsrc/leddevice/dev_net/LedDeviceUdpDdp.h
Normal file
62
libsrc/leddevice/dev_net/LedDeviceUdpDdp.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef LEDEVICEUDPDDP_H
|
||||
#define LEDEVICEUDPDDP_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending LED colors via UDP and the Distributed Display Protocol (DDP)
|
||||
/// http://www.3waylabs.com/ddp/#Data%20Types
|
||||
///
|
||||
class LedDeviceUdpDdp : public virtual ProviderUdp
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// @brief Constructs a LED-device fed via DDP
|
||||
///
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceUdpDdp(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
private:
|
||||
|
||||
QByteArray _ddpData;
|
||||
|
||||
int _packageSequenceNumber;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEUDPDDP_H
|
@@ -8,6 +8,13 @@
|
||||
|
||||
// hyperion local includes
|
||||
#include "LedDeviceUdpE131.h"
|
||||
#include <utils/NetUtils.h>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_PORT[] = "port";
|
||||
|
||||
const ushort E131_DEFAULT_PORT = 5568;
|
||||
|
||||
@@ -23,6 +30,7 @@ const uint32_t VECTOR_E131_DATA_PACKET = 0x00000002;
|
||||
//#define E131_NETWORK_DATA_LOSS_TIMEOUT 2500 // milli econds
|
||||
//#define E131_DISCOVERY_UNIVERSE 64214
|
||||
const int DMX_MAX = 512; // 512 usable slots
|
||||
}
|
||||
|
||||
LedDeviceUdpE131::LedDeviceUdpE131(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp(deviceConfig)
|
||||
@@ -36,13 +44,14 @@ LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
_port = E131_DEFAULT_PORT;
|
||||
bool isInitOK {false};
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
_hostName = _devConfig[ CONFIG_HOST ].toString();
|
||||
_port = deviceConfig[CONFIG_PORT].toInt(E131_DEFAULT_PORT);
|
||||
|
||||
_e131_universe = deviceConfig["universe"].toInt(1);
|
||||
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
|
||||
QString _json_cid = deviceConfig["cid"].toString("");
|
||||
@@ -70,6 +79,23 @@ bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceUdpE131::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||
{
|
||||
if (ProviderUdp::open() == 0)
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// populates the headers
|
||||
void LedDeviceUdpE131::prepare(unsigned this_universe, unsigned this_dmxChannelCount)
|
||||
{
|
||||
|
@@ -114,6 +114,13 @@ private:
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
|
@@ -1,8 +1,12 @@
|
||||
#include "LedDeviceUdpH801.h"
|
||||
#include <utils/NetUtils.h>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_PORT[] = "port";
|
||||
|
||||
const ushort H801_DEFAULT_PORT = 30977;
|
||||
const char H801_DEFAULT_HOST[] = "255.255.255.255";
|
||||
|
||||
@@ -20,16 +24,17 @@ LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
bool isInitOK {false};
|
||||
|
||||
/* The H801 port is fixed */
|
||||
_latchTime_ms = 10;
|
||||
_port = H801_DEFAULT_PORT;
|
||||
_defaultHost = H801_DEFAULT_HOST;
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
_hostName = _devConfig[ CONFIG_HOST ].toString(H801_DEFAULT_HOST);
|
||||
_port = deviceConfig[CONFIG_PORT].toInt(H801_DEFAULT_PORT);
|
||||
|
||||
_ids.clear();
|
||||
QJsonArray lArray = deviceConfig["lightIds"].toArray();
|
||||
for (int i = 0; i < lArray.size(); i++)
|
||||
@@ -47,14 +52,28 @@ bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
|
||||
_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);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceUdpH801::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||
{
|
||||
if (ProviderUdp::open() == 0)
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceUdpH801::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
ColorRgb color = ledValues[0];
|
||||
|
@@ -37,6 +37,13 @@ private:
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
|
@@ -1,10 +1,14 @@
|
||||
#include "LedDeviceUdpRaw.h"
|
||||
|
||||
#include <utils/NetUtils.h>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
const bool verbose = false;
|
||||
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_PORT[] = "port";
|
||||
const ushort RAW_DEFAULT_PORT=5568;
|
||||
const int UDP_MAX_LED_NUM = 490;
|
||||
|
||||
@@ -22,33 +26,46 @@ LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceUdpRaw::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = RAW_DEFAULT_PORT;
|
||||
bool isInitOK {false};
|
||||
|
||||
bool isInitOK = false;
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
// Initialise LedDevice configuration and execution environment
|
||||
int configuredLedCount = this->getLedCount();
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %d", configuredLedCount);
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
|
||||
if (configuredLedCount > UDP_MAX_LED_NUM)
|
||||
if (this->getLedCount() > UDP_MAX_LED_NUM)
|
||||
{
|
||||
QString errorReason = QString("Device type %1 can only be run with maximum %2 LEDs!").arg(this->getActiveDeviceType()).arg(UDP_MAX_LED_NUM);
|
||||
QString errorReason = QString("Device type %1 can only be run with maximum %2 LEDs for streaming protocol = UDP-RAW!").arg(this->getActiveDeviceType()).arg(UDP_MAX_LED_NUM);
|
||||
this->setInError ( errorReason );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialise sub-class
|
||||
isInitOK = ProviderUdp::init(deviceConfig);
|
||||
_hostName = deviceConfig[ CONFIG_HOST ].toString();
|
||||
_port = deviceConfig[CONFIG_PORT].toInt(RAW_DEFAULT_PORT);
|
||||
|
||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostName) );
|
||||
Debug(_log, "Port : %d", _port );
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceUdpRaw::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address))
|
||||
{
|
||||
if (ProviderUdp::open() == 0)
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
|
||||
@@ -59,8 +76,11 @@ int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
|
||||
QJsonObject LedDeviceUdpRaw::getProperties(const QJsonObject& params)
|
||||
{
|
||||
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
QJsonObject properties;
|
||||
|
||||
Info(_log, "Get properties for %s", QSTRING_CSTR(_activeDeviceType));
|
||||
|
||||
QJsonObject propertiesDetails;
|
||||
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending LED colors via UDP
|
||||
///
|
||||
class LedDeviceUdpRaw : public ProviderUdp
|
||||
class LedDeviceUdpRaw : public virtual ProviderUdp
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -44,6 +44,13 @@ protected:
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
|
@@ -1,11 +1,18 @@
|
||||
// Local-Hyperion includes
|
||||
#include "LedDeviceWled.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <utils/QStringUtils.h>
|
||||
#include <utils/WaitTime.h>
|
||||
#include <QThread>
|
||||
|
||||
#include <chrono>
|
||||
// mDNS discover
|
||||
#ifdef ENABLE_MDNS
|
||||
#include <mdns/MdnsBrowser.h>
|
||||
#include <mdns/MdnsServiceRegister.h>
|
||||
#endif
|
||||
#include <utils/NetUtils.h>
|
||||
#include <utils/version.hpp>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
@@ -13,16 +20,22 @@ namespace {
|
||||
const bool verbose = false;
|
||||
|
||||
// Configuration settings
|
||||
const char CONFIG_ADDRESS[] = "host";
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_STREAM_PROTOCOL[] = "streamProtocol";
|
||||
const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
|
||||
const char CONFIG_BRIGHTNESS[] = "brightness";
|
||||
const char CONFIG_BRIGHTNESS_OVERWRITE[] = "overwriteBrightness";
|
||||
const char CONFIG_SYNC_OVERWRITE[] = "overwriteSync";
|
||||
|
||||
// UDP elements
|
||||
const quint16 STREAM_DEFAULT_PORT = 19446;
|
||||
const char DEFAULT_STREAM_PROTOCOL[] = "DDP";
|
||||
|
||||
// UDP-RAW
|
||||
const int UDP_STREAM_DEFAULT_PORT = 19446;
|
||||
const int UDP_MAX_LED_NUM = 490;
|
||||
|
||||
// DDP
|
||||
const char WLED_VERSION_DDP[] = "0.11.0";
|
||||
|
||||
// WLED JSON-API elements
|
||||
const int API_DEFAULT_PORT = -1; //Use default port per communication scheme
|
||||
|
||||
@@ -46,7 +59,7 @@ constexpr std::chrono::milliseconds DEFAULT_IDENTIFY_TIME{ 2000 };
|
||||
} //End of constants
|
||||
|
||||
LedDeviceWled::LedDeviceWled(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp(deviceConfig)
|
||||
: ProviderUdp(deviceConfig), LedDeviceUdpDdp(deviceConfig), LedDeviceUdpRaw(deviceConfig)
|
||||
,_restApi(nullptr)
|
||||
,_apiPort(API_DEFAULT_PORT)
|
||||
,_isBrightnessOverwrite(DEFAULT_IS_BRIGHTNESS_OVERWRITE)
|
||||
@@ -54,7 +67,12 @@ LedDeviceWled::LedDeviceWled(const QJsonObject &deviceConfig)
|
||||
,_isSyncOverwrite(DEFAULT_IS_SYNC_OVERWRITE)
|
||||
,_originalStateUdpnSend(false)
|
||||
,_originalStateUdpnRecv(true)
|
||||
,_isStreamDDP(true)
|
||||
{
|
||||
#ifdef ENABLE_MDNS
|
||||
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
|
||||
#endif
|
||||
}
|
||||
|
||||
LedDeviceWled::~LedDeviceWled()
|
||||
@@ -70,25 +88,30 @@ LedDevice* LedDeviceWled::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceWled::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
bool isInitOK {false};
|
||||
|
||||
// Initialise LedDevice sub-class, ProviderUdp::init will be executed later, if connectivity is defined
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
QString streamProtocol = _devConfig[CONFIG_STREAM_PROTOCOL].toString(DEFAULT_STREAM_PROTOCOL);
|
||||
|
||||
if (streamProtocol != DEFAULT_STREAM_PROTOCOL)
|
||||
{
|
||||
// Initialise LedDevice configuration and execution environment
|
||||
int configuredLedCount = this->getLedCount();
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %d", configuredLedCount);
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
_isStreamDDP = false;
|
||||
}
|
||||
Debug(_log, "Stream protocol : %s", QSTRING_CSTR(streamProtocol));
|
||||
Debug(_log, "Stream DDP : %d", _isStreamDDP);
|
||||
|
||||
if (configuredLedCount > UDP_MAX_LED_NUM)
|
||||
{
|
||||
QString errorReason = QString("Device type %1 can only be run with maximum %2 LEDs!").arg(this->getActiveDeviceType()).arg(UDP_MAX_LED_NUM);
|
||||
this->setInError ( errorReason );
|
||||
return false;
|
||||
}
|
||||
if (_isStreamDDP)
|
||||
{
|
||||
LedDeviceUdpDdp::init(deviceConfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
_devConfig["port"] = UDP_STREAM_DEFAULT_PORT;
|
||||
LedDeviceUdpRaw::init(_devConfig);
|
||||
}
|
||||
|
||||
if (!_isDeviceInError)
|
||||
{
|
||||
_apiPort = API_DEFAULT_PORT;
|
||||
_isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(DEFAULT_IS_RESTORE_STATE);
|
||||
_isSyncOverwrite = _devConfig[CONFIG_SYNC_OVERWRITE].toBool(DEFAULT_IS_SYNC_OVERWRITE);
|
||||
_isBrightnessOverwrite = _devConfig[CONFIG_BRIGHTNESS_OVERWRITE].toBool(DEFAULT_IS_BRIGHTNESS_OVERWRITE);
|
||||
@@ -99,57 +122,78 @@ bool LedDeviceWled::init(const QJsonObject &deviceConfig)
|
||||
Debug(_log, "Overwrite Brightn.: %d", _isBrightnessOverwrite);
|
||||
Debug(_log, "Set Brightness to : %d", _brightness);
|
||||
|
||||
//Set hostname as per configuration
|
||||
QString hostName = deviceConfig[ CONFIG_ADDRESS ].toString();
|
||||
|
||||
//If host not configured the init fails
|
||||
if ( hostName.isEmpty() )
|
||||
{
|
||||
this->setInError("No target hostname nor IP defined");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
QStringList addressparts = QStringUtils::split(hostName,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
_hostname = addressparts[0];
|
||||
if ( addressparts.size() > 1 )
|
||||
{
|
||||
_apiPort = addressparts[1].toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
_apiPort = API_DEFAULT_PORT;
|
||||
}
|
||||
|
||||
if ( initRestAPI( _hostname, _apiPort ) )
|
||||
{
|
||||
// Update configuration with hostname without port
|
||||
_devConfig["host"] = _hostname;
|
||||
_devConfig["port"] = STREAM_DEFAULT_PORT;
|
||||
|
||||
isInitOK = ProviderUdp::init(_devConfig);
|
||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
|
||||
Debug(_log, "Port : %d", _port);
|
||||
}
|
||||
}
|
||||
isInitOK = true;
|
||||
}
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceWled::initRestAPI(const QString &hostname, int port)
|
||||
bool LedDeviceWled::openRestAPI()
|
||||
{
|
||||
bool isInitOK = false;
|
||||
bool isInitOK {true};
|
||||
|
||||
if ( _restApi == nullptr )
|
||||
{
|
||||
_restApi = new ProviderRestApi(hostname, port);
|
||||
_restApi->setBasePath( API_BASE_PATH );
|
||||
_restApi = new ProviderRestApi(_address.toString(), _apiPort);
|
||||
_restApi->setLogger(_log);
|
||||
|
||||
isInitOK = true;
|
||||
_restApi->setBasePath( API_BASE_PATH );
|
||||
}
|
||||
else
|
||||
{
|
||||
_restApi->setHost(_address.toString());
|
||||
_restApi->setPort(_apiPort);
|
||||
}
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceWled::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||
{
|
||||
if ( openRestAPI() )
|
||||
{
|
||||
if (_isStreamDDP)
|
||||
{
|
||||
if (LedDeviceUdpDdp::open() == 0)
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LedDeviceUdpRaw::open() == 0)
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceWled::close()
|
||||
{
|
||||
int retval = -1;
|
||||
if (_isStreamDDP)
|
||||
{
|
||||
retval = LedDeviceUdpDdp::close();
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = LedDeviceUdpRaw::close();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
QString LedDeviceWled::getOnOffRequest(bool isOn) const
|
||||
{
|
||||
QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
|
||||
@@ -316,6 +360,16 @@ QJsonObject LedDeviceWled::discover(const QJsonObject& /*params*/)
|
||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
|
||||
|
||||
QJsonArray deviceList;
|
||||
|
||||
#ifdef ENABLE_MDNS
|
||||
QString discoveryMethod("mDNS");
|
||||
deviceList = MdnsBrowser::getInstance().getServicesDiscoveredJson(
|
||||
MdnsServiceRegister::getServiceType(_activeDeviceType),
|
||||
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
|
||||
DEFAULT_DISCOVER_TIMEOUT
|
||||
);
|
||||
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
||||
#endif
|
||||
devicesDiscovered.insert("devices", deviceList);
|
||||
DebugIf(verbose, _log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
@@ -327,41 +381,45 @@ QJsonObject LedDeviceWled::getProperties(const QJsonObject& params)
|
||||
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
QJsonObject properties;
|
||||
|
||||
QString hostName = params["host"].toString("");
|
||||
_hostName = params[CONFIG_HOST].toString("");
|
||||
_apiPort = API_DEFAULT_PORT;
|
||||
|
||||
if ( !hostName.isEmpty() )
|
||||
Info(_log, "Get properties for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||
{
|
||||
QString filter = params["filter"].toString("");
|
||||
|
||||
// Resolve hostname and port (or use default API port)
|
||||
QStringList addressparts = QStringUtils::split(hostName,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
QString apiHost = addressparts[0];
|
||||
int apiPort;
|
||||
|
||||
if ( addressparts.size() > 1)
|
||||
if ( openRestAPI() )
|
||||
{
|
||||
apiPort = addressparts[1].toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
apiPort = API_DEFAULT_PORT;
|
||||
}
|
||||
QString filter = params["filter"].toString("");
|
||||
_restApi->setPath(filter);
|
||||
|
||||
initRestAPI(apiHost, apiPort);
|
||||
_restApi->setPath(filter);
|
||||
httpResponse response = _restApi->get();
|
||||
if ( response.error() )
|
||||
{
|
||||
Warning (_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
}
|
||||
|
||||
httpResponse response = _restApi->get();
|
||||
if ( response.error() )
|
||||
{
|
||||
Warning (_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
}
|
||||
QJsonObject propertiesDetails = response.getBody().object();
|
||||
|
||||
QJsonObject propertiesDetails = response.getBody().object();
|
||||
if (!propertiesDetails.isEmpty())
|
||||
{
|
||||
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
||||
semver::version currentVersion {""};
|
||||
if (currentVersion.setVersion(propertiesDetails.value("ver").toString().toStdString()))
|
||||
{
|
||||
semver::version ddpVersion{WLED_VERSION_DDP};
|
||||
if (currentVersion < ddpVersion)
|
||||
{
|
||||
Warning(_log, "DDP streaming not supported by your WLED device version [%s], minimum version expected [%s]. Fall back to UDP-Streaming (%d LEDs max)", currentVersion.getVersion().c_str(), ddpVersion.getVersion().c_str(), UDP_MAX_LED_NUM);
|
||||
if (!propertiesDetails.isEmpty())
|
||||
{
|
||||
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log, "DDP streaming is supported by your WLED device version [%s]. No limitation in number of LEDs.", currentVersion.getVersion().c_str(), ddpVersion.getVersion().c_str());
|
||||
}
|
||||
}
|
||||
properties.insert("properties", propertiesDetails);
|
||||
}
|
||||
properties.insert("properties", propertiesDetails);
|
||||
|
||||
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
}
|
||||
@@ -372,41 +430,40 @@ void LedDeviceWled::identify(const QJsonObject& params)
|
||||
{
|
||||
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
QString hostName = params["host"].toString("");
|
||||
_hostName = params[CONFIG_HOST].toString("");
|
||||
_apiPort = API_DEFAULT_PORT;
|
||||
|
||||
if ( !hostName.isEmpty() )
|
||||
Info(_log, "Identify %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(_hostName) );
|
||||
|
||||
if (NetUtils::resolveHostToAddress(_log, _hostName, _address, _apiPort))
|
||||
{
|
||||
// Resolve hostname and port (or use default API port)
|
||||
QStringList addressparts = QStringUtils::split(hostName,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
QString apiHost = addressparts[0];
|
||||
int apiPort;
|
||||
|
||||
if ( addressparts.size() > 1)
|
||||
if ( openRestAPI() )
|
||||
{
|
||||
apiPort = addressparts[1].toInt();
|
||||
_isRestoreOrigState = true;
|
||||
storeState();
|
||||
|
||||
QString request = getOnOffRequest(true) + "," + getLorRequest(1) + "," + getEffectRequest(25);
|
||||
sendStateUpdateRequest(request);
|
||||
|
||||
wait(DEFAULT_IDENTIFY_TIME);
|
||||
|
||||
restoreState();
|
||||
}
|
||||
else
|
||||
{
|
||||
apiPort = API_DEFAULT_PORT;
|
||||
}
|
||||
|
||||
initRestAPI(apiHost, apiPort);
|
||||
|
||||
_isRestoreOrigState = true;
|
||||
storeState();
|
||||
|
||||
QString request = getOnOffRequest(true) + "," + getLorRequest(1) + "," + getEffectRequest(25);
|
||||
sendStateUpdateRequest(request);
|
||||
|
||||
wait(DEFAULT_IDENTIFY_TIME);
|
||||
|
||||
restoreState();
|
||||
}
|
||||
}
|
||||
|
||||
int LedDeviceWled::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
|
||||
int rc {0};
|
||||
|
||||
return writeBytes( _ledRGBCount, dataPtr);
|
||||
if (_isStreamDDP)
|
||||
{
|
||||
rc = LedDeviceUdpDdp::write(ledValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = LedDeviceUdpRaw::write(ledValues);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@@ -4,12 +4,13 @@
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include "ProviderRestApi.h"
|
||||
#include "ProviderUdp.h"
|
||||
#include "LedDeviceUdpDdp.h"
|
||||
#include "LedDeviceUdpRaw.h"
|
||||
|
||||
///
|
||||
/// Implementation of a WLED-device
|
||||
///
|
||||
class LedDeviceWled : public ProviderUdp
|
||||
class LedDeviceWled : public LedDeviceUdpDdp, LedDeviceUdpRaw
|
||||
{
|
||||
|
||||
public:
|
||||
@@ -81,6 +82,20 @@ protected:
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the UDP device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
int close() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
@@ -127,11 +142,9 @@ private:
|
||||
///
|
||||
/// @brief Initialise the access to the REST-API wrapper
|
||||
///
|
||||
/// @param[in] host
|
||||
/// @param[in] port
|
||||
/// @return True, if success
|
||||
///
|
||||
bool initRestAPI(const QString &hostname, int port );
|
||||
bool openRestAPI();
|
||||
|
||||
///
|
||||
/// @brief Get command to power WLED-device on or off
|
||||
@@ -148,10 +161,12 @@ private:
|
||||
|
||||
bool sendStateUpdateRequest(const QString &request);
|
||||
|
||||
QString resolveAddress (const QString& hostName);
|
||||
|
||||
///REST-API wrapper
|
||||
ProviderRestApi* _restApi;
|
||||
|
||||
QString _hostname;
|
||||
QString _hostAddress;
|
||||
int _apiPort;
|
||||
|
||||
QJsonObject _originalStateProperties;
|
||||
@@ -162,6 +177,8 @@ private:
|
||||
bool _isSyncOverwrite;
|
||||
bool _originalStateUdpnSend;
|
||||
bool _originalStateUdpnRecv;
|
||||
|
||||
bool _isStreamDDP;
|
||||
};
|
||||
|
||||
#endif // LEDDEVICEWLED_H
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#include "LedDeviceYeelight.h"
|
||||
#include "LedDeviceYeelight.h"
|
||||
|
||||
#include <ssdp/SSDPDiscover.h>
|
||||
#include <utils/QStringUtils.h>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
// Qt includes
|
||||
#include <QEventLoop>
|
||||
@@ -11,8 +11,15 @@
|
||||
#include <QColor>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <ssdp/SSDPDiscover.h>
|
||||
#include <utils/QStringUtils.h>
|
||||
|
||||
// mDNS discover
|
||||
#ifdef ENABLE_MDNS
|
||||
#include <mdns/MdnsBrowser.h>
|
||||
#include <mdns/MdnsServiceRegister.h>
|
||||
#endif
|
||||
#include <utils/NetUtils.h>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
@@ -28,6 +35,9 @@ constexpr std::chrono::milliseconds CONNECT_STREAM_TIMEOUT{1000}; // device stre
|
||||
const bool TEST_CORRELATION_IDS = false; //Ignore, if yeelight sends responses in different order as request commands
|
||||
|
||||
// Configuration settings
|
||||
const char CONFIG_HOST[] = "host";
|
||||
const char CONFIG_PORT[] = "port";
|
||||
|
||||
const char CONFIG_LIGHTS [] = "lights";
|
||||
|
||||
const char CONFIG_COLOR_MODEL [] = "colorModel";
|
||||
@@ -111,7 +121,6 @@ YeelightLight::YeelightLight( Logger *log, const QString &hostname, quint16 port
|
||||
,_isInMusicMode(false)
|
||||
{
|
||||
_name = hostname;
|
||||
|
||||
}
|
||||
|
||||
YeelightLight::~YeelightLight()
|
||||
@@ -151,25 +160,29 @@ bool YeelightLight::open()
|
||||
}
|
||||
else
|
||||
{
|
||||
_tcpSocket->connectToHost( _host, _port);
|
||||
|
||||
if ( _tcpSocket->waitForConnected( CONNECT_TIMEOUT.count() ) )
|
||||
QHostAddress address;
|
||||
if (NetUtils::resolveHostToAddress(_log, _host, address))
|
||||
{
|
||||
if ( _tcpSocket->state() != QAbstractSocket::ConnectedState )
|
||||
_tcpSocket->connectToHost( address.toString(), _port);
|
||||
|
||||
if ( _tcpSocket->waitForConnected( CONNECT_TIMEOUT.count() ) )
|
||||
{
|
||||
if ( _tcpSocket->state() != QAbstractSocket::ConnectedState )
|
||||
{
|
||||
this->setInError( _tcpSocket->errorString() );
|
||||
rc = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
log (2,"open()","Successfully opened Yeelight: %s", QSTRING_CSTR(_host));
|
||||
rc = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setInError( _tcpSocket->errorString() );
|
||||
rc = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
log (2,"open()","Successfully opened Yeelight: %s", QSTRING_CSTR(_host));
|
||||
rc = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setInError( _tcpSocket->errorString() );
|
||||
rc = false;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@@ -1006,6 +1019,10 @@ LedDeviceYeelight::LedDeviceYeelight(const QJsonObject &deviceConfig)
|
||||
,_debuglevel(0)
|
||||
,_musicModeServerPort(-1)
|
||||
{
|
||||
#ifdef ENABLE_MDNS
|
||||
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "browseForServiceType",
|
||||
Qt::QueuedConnection, Q_ARG(QByteArray, MdnsServiceRegister::getServiceType(_activeDeviceType)));
|
||||
#endif
|
||||
}
|
||||
|
||||
LedDeviceYeelight::~LedDeviceYeelight()
|
||||
@@ -1034,12 +1051,6 @@ bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
|
||||
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %d", this->getLedCount());
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "RewriteTime : %d", this->getRewriteTime());
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
|
||||
//Get device specific configuration
|
||||
|
||||
if ( deviceConfig[ CONFIG_COLOR_MODEL ].isString() )
|
||||
@@ -1102,8 +1113,9 @@ bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
|
||||
int configuredYeelightsCount = 0;
|
||||
for (const QJsonValueRef light : configuredYeelightLights)
|
||||
{
|
||||
QString hostName = light.toObject().value("host").toString();
|
||||
int port = light.toObject().value("port").toInt(API_DEFAULT_PORT);
|
||||
QString hostName = light.toObject().value(CONFIG_HOST).toString();
|
||||
int port = light.toObject().value(CONFIG_PORT).toInt(API_DEFAULT_PORT);
|
||||
|
||||
if ( !hostName.isEmpty() )
|
||||
{
|
||||
QString name = light.toObject().value("name").toString();
|
||||
@@ -1133,9 +1145,8 @@ bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
|
||||
_lightsAddressList.clear();
|
||||
for (int j = 0; j < static_cast<int>( configuredLedCount ); ++j)
|
||||
{
|
||||
QString hostName = configuredYeelightLights[j].toObject().value("host").toString();
|
||||
int port = configuredYeelightLights[j].toObject().value("port").toInt(API_DEFAULT_PORT);
|
||||
|
||||
QString hostName = configuredYeelightLights[j].toObject().value(CONFIG_HOST).toString();
|
||||
int port = configuredYeelightLights[j].toObject().value(CONFIG_PORT).toInt(API_DEFAULT_PORT);
|
||||
_lightsAddressList.append( { hostName, port} );
|
||||
}
|
||||
|
||||
@@ -1160,13 +1171,10 @@ bool LedDeviceYeelight::startMusicModeServer()
|
||||
|
||||
if ( ! _tcpMusicModeServer->isListening() )
|
||||
{
|
||||
if (! _tcpMusicModeServer->listen())
|
||||
if (! _tcpMusicModeServer->listen(QHostAddress::AnyIPv4))
|
||||
{
|
||||
QString errorReason = QString ("(%1) %2").arg(_tcpMusicModeServer->serverError()).arg( _tcpMusicModeServer->errorString());
|
||||
Error( _log, "Error: MusicModeServer: %s", QSTRING_CSTR(errorReason));
|
||||
QString errorReason = QString ("Failed to start music mode server: (%1) %2").arg(_tcpMusicModeServer->serverError()).arg( _tcpMusicModeServer->errorString());
|
||||
this->setInError ( errorReason );
|
||||
|
||||
Error( _log, "Failed to start music mode server");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1182,12 +1190,14 @@ bool LedDeviceYeelight::startMusicModeServer()
|
||||
}
|
||||
if (_musicModeServerAddress.isNull())
|
||||
{
|
||||
Error(_log, "Failed to resolve IP for music mode server");
|
||||
_tcpMusicModeServer->close();
|
||||
QString errorReason = QString ("Network error - failed to resolve IP for music mode server");
|
||||
this->setInError ( errorReason );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( _tcpMusicModeServer->isListening() )
|
||||
if ( !_isDeviceInError && _tcpMusicModeServer->isListening() )
|
||||
{
|
||||
_musicModeServerPort = _tcpMusicModeServer->serverPort();
|
||||
Debug (_log, "The music mode server is running at %s:%d", QSTRING_CSTR(_musicModeServerAddress.toString()), _musicModeServerPort);
|
||||
@@ -1391,10 +1401,21 @@ QJsonObject LedDeviceYeelight::discover(const QJsonObject& /*params*/)
|
||||
QJsonObject devicesDiscovered;
|
||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
|
||||
|
||||
QString discoveryMethod("ssdp");
|
||||
QJsonArray deviceList;
|
||||
deviceList = discover();
|
||||
|
||||
#ifdef ENABLE_MDNS
|
||||
QString discoveryMethod("mDNS");
|
||||
deviceList = MdnsBrowser::getInstance().getServicesDiscoveredJson(
|
||||
MdnsServiceRegister::getServiceType(_activeDeviceType),
|
||||
MdnsServiceRegister::getServiceNameFilter(_activeDeviceType),
|
||||
DEFAULT_DISCOVER_TIMEOUT
|
||||
);
|
||||
#else
|
||||
QString discoveryMethod("ssdp");
|
||||
deviceList = discover();
|
||||
#endif
|
||||
|
||||
devicesDiscovered.insert("discoveryMethod", discoveryMethod);
|
||||
devicesDiscovered.insert("devices", deviceList);
|
||||
|
||||
DebugIf(verbose,_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
@@ -1407,21 +1428,22 @@ QJsonObject LedDeviceYeelight::getProperties(const QJsonObject& params)
|
||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
QJsonObject properties;
|
||||
|
||||
QString hostName = params["hostname"].toString("");
|
||||
quint16 apiPort = static_cast<quint16>( params["port"].toInt(API_DEFAULT_PORT) );
|
||||
QString hostName = params[CONFIG_HOST].toString("");
|
||||
quint16 apiPort = static_cast<quint16>( params[CONFIG_PORT].toInt(API_DEFAULT_PORT) );
|
||||
|
||||
if ( !hostName.isEmpty() )
|
||||
Info(_log, "Get properties for %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(hostName) );
|
||||
|
||||
QHostAddress address;
|
||||
if (NetUtils::resolveHostToAddress(_log, hostName, address))
|
||||
{
|
||||
YeelightLight yeelight(_log, hostName, apiPort);
|
||||
|
||||
//yeelight.setDebuglevel(3);
|
||||
YeelightLight yeelight(_log, address.toString(), apiPort);
|
||||
if ( yeelight.open() )
|
||||
{
|
||||
properties.insert("properties", yeelight.getProperties());
|
||||
yeelight.close();
|
||||
}
|
||||
}
|
||||
Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
return properties;
|
||||
}
|
||||
@@ -1430,15 +1452,15 @@ void LedDeviceYeelight::identify(const QJsonObject& params)
|
||||
{
|
||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
QString hostName = params["hostname"].toString("");
|
||||
quint16 apiPort = static_cast<quint16>( params["port"].toInt(API_DEFAULT_PORT) );
|
||||
Debug (_log, "apiHost [%s], apiPort [%d]", QSTRING_CSTR(hostName), apiPort);
|
||||
QString hostName = params[CONFIG_HOST].toString("");
|
||||
quint16 apiPort = static_cast<quint16>( params[CONFIG_PORT].toInt(API_DEFAULT_PORT) );
|
||||
|
||||
if ( !hostName.isEmpty() )
|
||||
Info(_log, "Identify %s, hostname (%s)", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(hostName) );
|
||||
|
||||
QHostAddress address;
|
||||
if (NetUtils::resolveHostToAddress(_log, hostName, address))
|
||||
{
|
||||
YeelightLight yeelight(_log, hostName, apiPort);
|
||||
//yeelight.setDebuglevel(3);
|
||||
|
||||
YeelightLight yeelight(_log, address.toString(), apiPort);
|
||||
if ( yeelight.open() )
|
||||
{
|
||||
yeelight.identify();
|
||||
|
@@ -449,8 +449,8 @@ public:
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "hostname" : "hostname or IP",
|
||||
/// "port" : port, default port 55443 is used when not provided
|
||||
/// "host" : "hostname or IP",
|
||||
/// "port" : port, default port 55443 is used when not provided
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
@@ -465,8 +465,8 @@ public:
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "hostname" : "hostname or IP",
|
||||
/// "port" : port, default port 55443 is used when not provided
|
||||
/// "host" : "hostname or IP",
|
||||
/// "port" : port, default port 55443 is used when not provided
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
|
@@ -136,13 +136,19 @@ httpResponse ProviderRestApi::get(const QUrl& url)
|
||||
QNetworkRequest request(_networkRequestHeaders);
|
||||
request.setUrl(url);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
_networkManager->setTransferTimeout(DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
QNetworkReply* reply = _networkManager->get(request);
|
||||
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
QEventLoop::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
ReplyTimeout::set(reply, DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
@@ -178,12 +184,18 @@ httpResponse ProviderRestApi::put(const QUrl &url, const QByteArray &body)
|
||||
QNetworkRequest request(_networkRequestHeaders);
|
||||
request.setUrl(url);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
_networkManager->setTransferTimeout(DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
QNetworkReply* reply = _networkManager->put(request, body);
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
QEventLoop::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
ReplyTimeout::set(reply, DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
@@ -220,10 +232,19 @@ httpResponse ProviderRestApi::post(const QUrl& url, const QByteArray& body)
|
||||
QNetworkRequest request(_networkRequestHeaders);
|
||||
request.setUrl(url);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
_networkManager->setTransferTimeout(DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
QNetworkReply* reply = _networkManager->post(request, body);
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
QEventLoop::connect(reply,&QNetworkReply::finished,&loop,&QEventLoop::quit);
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
ReplyTimeout::set(reply, DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
|
||||
@@ -249,6 +270,10 @@ httpResponse ProviderRestApi::deleteResource(const QUrl& url)
|
||||
QNetworkRequest request(_networkRequestHeaders);
|
||||
request.setUrl(url);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
_networkManager->setTransferTimeout(DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
QNetworkReply* reply = _networkManager->deleteResource(request);
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
@@ -256,6 +281,10 @@ httpResponse ProviderRestApi::deleteResource(const QUrl& url)
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
ReplyTimeout::set(reply, DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
httpResponse response;
|
||||
if (reply->operation() == QNetworkAccessManager::DeleteOperation)
|
||||
{
|
||||
@@ -331,16 +360,9 @@ httpResponse ProviderRestApi::getResponse(QNetworkReply* const& reply)
|
||||
}
|
||||
errorReason = QString ("[%3 %4] - %5").arg(httpStatusCode).arg(httpReason, advise);
|
||||
}
|
||||
else {
|
||||
|
||||
else
|
||||
{
|
||||
errorReason = reply->errorString();
|
||||
|
||||
if ( reply->error() == QNetworkReply::OperationCanceledError )
|
||||
{
|
||||
//Do not report errors caused by request cancellation because of timeouts
|
||||
Debug(_log, "Reply: [%s]", QSTRING_CSTR(errorReason) );
|
||||
}
|
||||
else
|
||||
{
|
||||
response.setError(true);
|
||||
response.setErrorReason(errorReason);
|
||||
|
@@ -77,12 +77,12 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
QJsonDocument _responseBody;
|
||||
QJsonDocument _responseBody {};
|
||||
bool _hasError = false;
|
||||
QString _errorReason;
|
||||
|
||||
int _httpStatusCode = 0;
|
||||
QNetworkReply::NetworkError _networkReplyError = QNetworkReply::NoError;
|
||||
QNetworkReply::NetworkError _networkReplyError { QNetworkReply::NoError };
|
||||
};
|
||||
|
||||
///
|
||||
@@ -291,6 +291,13 @@ public:
|
||||
///
|
||||
void removeAllHeaders() { _networkRequestHeaders = QNetworkRequest(); }
|
||||
|
||||
///
|
||||
/// @brief Set the common logger for LED-devices.
|
||||
///
|
||||
/// @param[in] log The logger to be used
|
||||
///
|
||||
void setLogger(Logger* log) { _log = log; }
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
|
@@ -10,16 +10,19 @@
|
||||
#include <QUdpSocket>
|
||||
#include <QHostInfo>
|
||||
|
||||
// mDNS discover
|
||||
#ifdef ENABLE_MDNS
|
||||
#include <mdns/MdnsBrowser.h>
|
||||
#endif
|
||||
#include <utils/NetUtils.h>
|
||||
|
||||
// Local Hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
const ushort MAX_PORT = 65535;
|
||||
|
||||
ProviderUdp::ProviderUdp(const QJsonObject& deviceConfig)
|
||||
: LedDevice(deviceConfig)
|
||||
, _udpSocket(nullptr)
|
||||
, _port(1)
|
||||
, _defaultHost("127.0.0.1")
|
||||
, _port(-1)
|
||||
{
|
||||
_latchTime_ms = 0;
|
||||
}
|
||||
@@ -29,83 +32,38 @@ ProviderUdp::~ProviderUdp()
|
||||
delete _udpSocket;
|
||||
}
|
||||
|
||||
bool ProviderUdp::init(const QJsonObject& deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise sub-class
|
||||
if (LedDevice::init(deviceConfig))
|
||||
{
|
||||
QString host = deviceConfig["host"].toString(_defaultHost);
|
||||
|
||||
if (_address.setAddress(host))
|
||||
{
|
||||
Debug(_log, "Successfully parsed %s as an IP-address.", QSTRING_CSTR(_address.toString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
QHostInfo hostInfo = QHostInfo::fromName(host);
|
||||
if (hostInfo.error() == QHostInfo::NoError)
|
||||
{
|
||||
_address = hostInfo.addresses().first();
|
||||
Debug(_log, "Successfully resolved IP-address (%s) for hostname (%s).", QSTRING_CSTR(_address.toString()), QSTRING_CSTR(host));
|
||||
}
|
||||
else
|
||||
{
|
||||
QString errortext = QString("Failed resolving IP-address for [%1], (%2) %3").arg(host).arg(hostInfo.error()).arg(hostInfo.errorString());
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isDeviceInError)
|
||||
{
|
||||
int config_port = deviceConfig["port"].toInt(_port);
|
||||
if (config_port <= 0 || config_port > MAX_PORT)
|
||||
{
|
||||
QString errortext = QString("Invalid target port [%1]!").arg(config_port);
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_port = static_cast<quint16>(config_port);
|
||||
Debug(_log, "UDP socket will write to %s port: %u", QSTRING_CSTR(_address.toString()), _port);
|
||||
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int ProviderUdp::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// Try to bind the UDP-Socket
|
||||
if (_udpSocket != nullptr)
|
||||
if (!_isDeviceInError)
|
||||
{
|
||||
if (_udpSocket->state() != QAbstractSocket::BoundState)
|
||||
{
|
||||
QHostAddress localAddress = QHostAddress::Any;
|
||||
quint16 localPort = 0;
|
||||
if (!_udpSocket->bind(localAddress, localPort))
|
||||
if (_udpSocket == nullptr)
|
||||
{
|
||||
QString warntext = QString("Could not bind local address: %1, (%2) %3").arg(localAddress.toString()).arg(_udpSocket->error()).arg(_udpSocket->errorString());
|
||||
Warning(_log, "%s", QSTRING_CSTR(warntext));
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
}
|
||||
|
||||
// Try to bind the UDP-Socket
|
||||
if (_udpSocket != nullptr)
|
||||
{
|
||||
Info(_log, "Stream UDP data to %s port: %d", QSTRING_CSTR(_address.toString()), _port);
|
||||
if (_udpSocket->state() != QAbstractSocket::BoundState)
|
||||
{
|
||||
QHostAddress localAddress = QHostAddress::Any;
|
||||
quint16 localPort = 0;
|
||||
if (!_udpSocket->bind(localAddress, localPort))
|
||||
{
|
||||
QString warntext = QString("Could not bind local address: %1, (%2) %3").arg(localAddress.toString()).arg(_udpSocket->error()).arg(_udpSocket->errorString());
|
||||
Warning(_log, "%s", QSTRING_CSTR(warntext));
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setInError(" Open error. UDP Socket not initialised!");
|
||||
}
|
||||
}
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setInError(" Open error. UDP Socket not initialised!");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -131,7 +89,7 @@ int ProviderUdp::close()
|
||||
int ProviderUdp::writeBytes(const unsigned size, const uint8_t* data)
|
||||
{
|
||||
int rc = 0;
|
||||
qint64 bytesWritten = _udpSocket->writeDatagram(reinterpret_cast<const char*>(data), size, _address, _port);
|
||||
qint64 bytesWritten = _udpSocket->writeDatagram(reinterpret_cast<const char*>(data), size, _address, static_cast<quint16>(_port));
|
||||
|
||||
if (bytesWritten == -1 || bytesWritten != size)
|
||||
{
|
||||
@@ -144,7 +102,7 @@ int ProviderUdp::writeBytes(const unsigned size, const uint8_t* data)
|
||||
int ProviderUdp::writeBytes(const QByteArray& bytes)
|
||||
{
|
||||
int rc = 0;
|
||||
qint64 bytesWritten = _udpSocket->writeDatagram(bytes, _address, _port);
|
||||
qint64 bytesWritten = _udpSocket->writeDatagram(bytes, _address, static_cast<quint16>(_port));
|
||||
|
||||
if (bytesWritten == -1 || bytesWritten != bytes.size())
|
||||
{
|
||||
|
@@ -32,14 +32,6 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// @brief Initialise the UDP device's configuration and network address details
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
bool init(const QJsonObject& deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
@@ -74,10 +66,10 @@ protected:
|
||||
int writeBytes(const QByteArray& bytes);
|
||||
|
||||
///
|
||||
QUdpSocket* _udpSocket;
|
||||
QUdpSocket* _udpSocket;
|
||||
QString _hostName;
|
||||
QHostAddress _address;
|
||||
quint16 _port;
|
||||
QString _defaultHost;
|
||||
int _port;
|
||||
};
|
||||
|
||||
#endif // PROVIDERUDP_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -23,19 +23,6 @@
|
||||
|
||||
#if defined(MBEDTLS_PLATFORM_C)
|
||||
#include <mbedtls/platform.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define mbedtls_time time
|
||||
#define mbedtls_time_t time_t
|
||||
#define mbedtls_printf printf
|
||||
#define mbedtls_fprintf fprintf
|
||||
#define mbedtls_snprintf snprintf
|
||||
#define mbedtls_calloc calloc
|
||||
#define mbedtls_free free
|
||||
#define mbedtls_exit exit
|
||||
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
|
||||
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
@@ -50,12 +37,6 @@
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/debug.h>
|
||||
|
||||
//----------- END mbedtls
|
||||
|
||||
constexpr std::chrono::milliseconds STREAM_SSL_HANDSHAKE_TIMEOUT_MIN{400};
|
||||
constexpr std::chrono::milliseconds STREAM_SSL_HANDSHAKE_TIMEOUT_MAX{1000};
|
||||
constexpr std::chrono::milliseconds STREAM_SSL_READ_TIMEOUT{0};
|
||||
|
||||
class ProviderUdpSSL : public LedDevice
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -71,6 +52,11 @@ public:
|
||||
///
|
||||
~ProviderUdpSSL() override;
|
||||
|
||||
///
|
||||
QString _hostName;
|
||||
QHostAddress _address;
|
||||
int _port;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
@@ -102,6 +88,18 @@ protected:
|
||||
///
|
||||
bool initNetwork();
|
||||
|
||||
///
|
||||
/// @brief Start astreaming connection
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool startConnection();
|
||||
|
||||
///
|
||||
/// @brief Stop the streaming connection
|
||||
///
|
||||
void stopConnection();
|
||||
|
||||
///
|
||||
/// Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
|
||||
/// values are latched.
|
||||
@@ -109,7 +107,7 @@ protected:
|
||||
/// @param[in] size The length of the data
|
||||
/// @param[in] data The data
|
||||
///
|
||||
void writeBytes(unsigned int size, const uint8_t *data);
|
||||
void writeBytes(unsigned int size, const uint8_t* data, bool flush = false);
|
||||
|
||||
///
|
||||
/// get ciphersuites list from mbedtls_ssl_list_ciphersuites
|
||||
@@ -118,36 +116,16 @@ protected:
|
||||
///
|
||||
virtual const int * getCiphersuites() const;
|
||||
|
||||
void sslLog(const QString &msg, const char* errorType = "debug");
|
||||
void sslLog(const char* msg, const char* errorType = "debug");
|
||||
void configLog(const char* msg, const char* type, ...);
|
||||
|
||||
/**
|
||||
* Debug callback for mbed TLS
|
||||
* Just prints on the USB serial port
|
||||
*/
|
||||
static void ProviderUdpSSLDebug(void* ctx, int level, const char* file, int line, const char* str);
|
||||
|
||||
/**
|
||||
* Certificate verification callback for mbed TLS
|
||||
* Here we only use it to display information on each cert in the chain
|
||||
*/
|
||||
static int ProviderUdpSSLVerify(void* data, mbedtls_x509_crt* crt, int depth, uint32_t* flags);
|
||||
|
||||
///
|
||||
/// closeSSLNotify and freeSSLConnection
|
||||
///
|
||||
void closeSSLConnection();
|
||||
|
||||
private:
|
||||
|
||||
bool initConnection();
|
||||
|
||||
bool seedingRNG();
|
||||
bool setupStructure();
|
||||
bool startUPDConnection();
|
||||
|
||||
bool setupPSK();
|
||||
bool startSSLHandshake();
|
||||
void handleReturn(int ret);
|
||||
|
||||
QString errorMsg(int ret);
|
||||
void closeSSLNotify();
|
||||
void freeSSLConnection();
|
||||
@@ -160,24 +138,19 @@ private:
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_timing_delay_context timer;
|
||||
|
||||
QMutex _hueMutex;
|
||||
QString _transport_type;
|
||||
QString _custom;
|
||||
QHostAddress _address;
|
||||
QString _defaultHost;
|
||||
int _port;
|
||||
int _ssl_port;
|
||||
QString _server_name;
|
||||
QString _psk;
|
||||
QString _psk_identity;
|
||||
uint32_t _read_timeout;
|
||||
|
||||
int _handshake_attempts;
|
||||
uint32_t _handshake_timeout_min;
|
||||
uint32_t _handshake_timeout_max;
|
||||
unsigned int _handshake_attempts;
|
||||
int _retry_left;
|
||||
bool _stopConnection;
|
||||
bool _debugStreamer;
|
||||
int _debugLevel;
|
||||
|
||||
bool _streamReady;
|
||||
bool _streamPaused;
|
||||
};
|
||||
|
||||
#endif // PROVIDERUDPSSL_H
|
||||
|
Reference in New Issue
Block a user