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:
@@ -141,3 +141,6 @@ if (ENABLE_DEV_USB_HID)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_MDNS)
|
||||
target_link_libraries(leddevice mdns)
|
||||
endif()
|
||||
|
@@ -15,84 +15,91 @@
|
||||
//std includes
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
// Configuration settings
|
||||
const char CONFIG_CURRENT_LED_COUNT[] = "currentLedCount";
|
||||
const char CONFIG_COLOR_ORDER[] = "colorOrder";
|
||||
const char CONFIG_AUTOSTART[] = "autoStart";
|
||||
const char CONFIG_LATCH_TIME[] = "latchTime";
|
||||
const char CONFIG_REWRITE_TIME[] = "rewriteTime";
|
||||
// Configuration settings
|
||||
const char CONFIG_CURRENT_LED_COUNT[] = "currentLedCount";
|
||||
const char CONFIG_COLOR_ORDER[] = "colorOrder";
|
||||
const char CONFIG_AUTOSTART[] = "autoStart";
|
||||
const char CONFIG_LATCH_TIME[] = "latchTime";
|
||||
const char CONFIG_REWRITE_TIME[] = "rewriteTime";
|
||||
|
||||
int DEFAULT_LED_COUNT = 1;
|
||||
const char DEFAULT_COLOR_ORDER[] = "RGB";
|
||||
const bool DEFAULT_IS_AUTOSTART = true;
|
||||
int DEFAULT_LED_COUNT{ 1 };
|
||||
const char DEFAULT_COLOR_ORDER[]{ "RGB" };
|
||||
const bool DEFAULT_IS_AUTOSTART{ true };
|
||||
|
||||
const char CONFIG_ENABLE_ATTEMPTS[] = "enableAttempts";
|
||||
const char CONFIG_ENABLE_ATTEMPTS_INTERVALL[] = "enableAttemptsInterval";
|
||||
|
||||
const int DEFAULT_MAX_ENABLE_ATTEMPTS{ 5 };
|
||||
constexpr std::chrono::seconds DEFAULT_ENABLE_ATTEMPTS_INTERVAL{ 5 };
|
||||
|
||||
} //End of constants
|
||||
|
||||
LedDevice::LedDevice(const QJsonObject& deviceConfig, QObject* parent)
|
||||
: QObject(parent)
|
||||
, _devConfig(deviceConfig)
|
||||
, _log(Logger::getInstance("LEDDEVICE"))
|
||||
, _ledBuffer(0)
|
||||
, _refreshTimer(nullptr)
|
||||
, _refreshTimerInterval_ms(0)
|
||||
, _latchTime_ms(0)
|
||||
, _ledCount(0)
|
||||
, _isRestoreOrigState(false)
|
||||
, _isEnabled(false)
|
||||
, _isDeviceInitialised(false)
|
||||
, _isDeviceReady(false)
|
||||
, _isOn(false)
|
||||
, _isDeviceInError(false)
|
||||
, _isInSwitchOff (false)
|
||||
, _lastWriteTime(QDateTime::currentDateTime())
|
||||
, _isRefreshEnabled (false)
|
||||
, _isAutoStart(true)
|
||||
, _devConfig(deviceConfig)
|
||||
, _log(Logger::getInstance("LEDDEVICE"))
|
||||
, _ledBuffer(0)
|
||||
, _refreshTimer(nullptr)
|
||||
, _enableAttemptsTimer(nullptr)
|
||||
, _refreshTimerInterval_ms(0)
|
||||
, _enableAttemptTimerInterval(DEFAULT_ENABLE_ATTEMPTS_INTERVAL)
|
||||
, _enableAttempts(0)
|
||||
, _maxEnableAttempts(DEFAULT_MAX_ENABLE_ATTEMPTS)
|
||||
, _latchTime_ms(0)
|
||||
, _ledCount(0)
|
||||
, _isRestoreOrigState(false)
|
||||
, _isEnabled(false)
|
||||
, _isDeviceInitialised(false)
|
||||
, _isDeviceReady(false)
|
||||
, _isOn(false)
|
||||
, _isDeviceInError(false)
|
||||
, _lastWriteTime(QDateTime::currentDateTime())
|
||||
, _isRefreshEnabled(false)
|
||||
, _isAutoStart(true)
|
||||
{
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice::~LedDevice()
|
||||
{
|
||||
delete _refreshTimer;
|
||||
this->stopEnableAttemptsTimer();
|
||||
this->stopRefreshTimer();
|
||||
}
|
||||
|
||||
void LedDevice::start()
|
||||
{
|
||||
Info(_log, "Start LedDevice '%s'.", QSTRING_CSTR(_activeDeviceType));
|
||||
|
||||
// setup refreshTimer
|
||||
if ( _refreshTimer == nullptr )
|
||||
{
|
||||
_refreshTimer = new QTimer(this);
|
||||
_refreshTimer->setTimerType(Qt::PreciseTimer);
|
||||
_refreshTimer->setInterval( _refreshTimerInterval_ms );
|
||||
connect(_refreshTimer, &QTimer::timeout, this, &LedDevice::rewriteLEDs );
|
||||
}
|
||||
|
||||
close();
|
||||
|
||||
_isDeviceInitialised = false;
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
|
||||
if (init(_devConfig))
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_isDeviceInitialised = true;
|
||||
|
||||
if (_isAutoStart)
|
||||
{
|
||||
this->enable();
|
||||
if (!_isEnabled)
|
||||
{
|
||||
Debug(_log, "Not enabled -> enable device");
|
||||
enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LedDevice::stop()
|
||||
{
|
||||
Debug(_log, "Stop device");
|
||||
this->disable();
|
||||
this->stopRefreshTimer();
|
||||
Info(_log, " Stopped LedDevice '%s'", QSTRING_CSTR(_activeDeviceType) );
|
||||
Info(_log, " Stopped LedDevice '%s'", QSTRING_CSTR(_activeDeviceType));
|
||||
}
|
||||
|
||||
int LedDevice::open()
|
||||
@@ -113,6 +120,7 @@ int LedDevice::close()
|
||||
|
||||
void LedDevice::setInError(const QString& errorMsg)
|
||||
{
|
||||
_isOn = false;
|
||||
_isDeviceInError = true;
|
||||
_isDeviceReady = false;
|
||||
_isEnabled = false;
|
||||
@@ -124,21 +132,53 @@ void LedDevice::setInError(const QString& errorMsg)
|
||||
|
||||
void LedDevice::enable()
|
||||
{
|
||||
if ( !_isEnabled )
|
||||
Debug(_log, "Enable device %s'", QSTRING_CSTR(_activeDeviceType));
|
||||
|
||||
if (!_isEnabled)
|
||||
{
|
||||
if (_enableAttemptsTimer != nullptr && _enableAttemptsTimer->isActive())
|
||||
{
|
||||
_enableAttemptsTimer->stop();
|
||||
}
|
||||
|
||||
_isDeviceInError = false;
|
||||
|
||||
if ( ! _isDeviceReady )
|
||||
if (!_isDeviceInitialised)
|
||||
{
|
||||
_isDeviceInitialised = init(_devConfig);
|
||||
}
|
||||
|
||||
if (!_isDeviceReady)
|
||||
{
|
||||
open();
|
||||
}
|
||||
|
||||
if ( _isDeviceReady )
|
||||
bool isEnableFailed(true);
|
||||
|
||||
if (_isDeviceReady)
|
||||
{
|
||||
_isEnabled = true;
|
||||
if ( switchOn() )
|
||||
if (switchOn())
|
||||
{
|
||||
stopEnableAttemptsTimer();
|
||||
_isEnabled = true;
|
||||
isEnableFailed = false;
|
||||
emit enableStateChanged(_isEnabled);
|
||||
Info(_log, "LedDevice '%s' enabled", QSTRING_CSTR(_activeDeviceType));
|
||||
}
|
||||
}
|
||||
|
||||
if (isEnableFailed)
|
||||
{
|
||||
emit enableStateChanged(false);
|
||||
|
||||
if (_maxEnableAttempts > 0)
|
||||
{
|
||||
Debug(_log, "Device's enablement failed - Start retry timer. Retried already done [%d], isEnabled: [%d]", _enableAttempts, _isEnabled);
|
||||
startEnableAttemptsTimer();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug(_log, "Device's enablement failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,9 +186,11 @@ void LedDevice::enable()
|
||||
|
||||
void LedDevice::disable()
|
||||
{
|
||||
if ( _isEnabled )
|
||||
Debug(_log, "Disable device %s'", QSTRING_CSTR(_activeDeviceType));
|
||||
if (_isEnabled)
|
||||
{
|
||||
_isEnabled = false;
|
||||
this->stopEnableAttemptsTimer();
|
||||
this->stopRefreshTimer();
|
||||
|
||||
switchOff();
|
||||
@@ -163,47 +205,110 @@ void LedDevice::setActiveDeviceType(const QString& deviceType)
|
||||
_activeDeviceType = deviceType;
|
||||
}
|
||||
|
||||
bool LedDevice::init(const QJsonObject &deviceConfig)
|
||||
bool LedDevice::init(const QJsonObject& deviceConfig)
|
||||
{
|
||||
Debug(_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
Debug(_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
_colorOrder = deviceConfig[CONFIG_COLOR_ORDER].toString(DEFAULT_COLOR_ORDER);
|
||||
_isAutoStart = deviceConfig[CONFIG_AUTOSTART].toBool(DEFAULT_IS_AUTOSTART);
|
||||
|
||||
setLedCount( deviceConfig[CONFIG_CURRENT_LED_COUNT].toInt(DEFAULT_LED_COUNT) ); // property injected to reflect real led count
|
||||
setLatchTime( deviceConfig[CONFIG_LATCH_TIME].toInt( _latchTime_ms ) );
|
||||
setRewriteTime ( deviceConfig[CONFIG_REWRITE_TIME].toInt( _refreshTimerInterval_ms) );
|
||||
setLedCount(deviceConfig[CONFIG_CURRENT_LED_COUNT].toInt(DEFAULT_LED_COUNT)); // property injected to reflect real led count
|
||||
setColorOrder(deviceConfig[CONFIG_COLOR_ORDER].toString(DEFAULT_COLOR_ORDER));
|
||||
setLatchTime(deviceConfig[CONFIG_LATCH_TIME].toInt(_latchTime_ms));
|
||||
setRewriteTime(deviceConfig[CONFIG_REWRITE_TIME].toInt(_refreshTimerInterval_ms));
|
||||
setAutoStart(deviceConfig[CONFIG_AUTOSTART].toBool(DEFAULT_IS_AUTOSTART));
|
||||
setEnableAttempts(deviceConfig[CONFIG_ENABLE_ATTEMPTS].toInt(DEFAULT_MAX_ENABLE_ATTEMPTS),
|
||||
std::chrono::seconds(deviceConfig[CONFIG_ENABLE_ATTEMPTS_INTERVALL].toInt(DEFAULT_ENABLE_ATTEMPTS_INTERVAL.count()))
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LedDevice::startRefreshTimer()
|
||||
{
|
||||
if ( _isDeviceReady && _isEnabled )
|
||||
if (_refreshTimerInterval_ms > 0)
|
||||
{
|
||||
_refreshTimer->start();
|
||||
if (_isDeviceReady && _isOn)
|
||||
{
|
||||
// setup refreshTimer
|
||||
if (_refreshTimer == nullptr)
|
||||
{
|
||||
_refreshTimer = new QTimer(this);
|
||||
_refreshTimer->setTimerType(Qt::PreciseTimer);
|
||||
connect(_refreshTimer, &QTimer::timeout, this, &LedDevice::rewriteLEDs);
|
||||
}
|
||||
_refreshTimer->setInterval(_refreshTimerInterval_ms);
|
||||
|
||||
//Debug(_log, "Start refresh timer with interval = %ims", _refreshTimer->interval());
|
||||
_refreshTimer->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug(_log, "Device is not ready to start a refresh timer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LedDevice::stopRefreshTimer()
|
||||
{
|
||||
if ( _refreshTimer != nullptr )
|
||||
if (_refreshTimer != nullptr)
|
||||
{
|
||||
//Debug(_log, "Stopping refresh timer");
|
||||
_refreshTimer->stop();
|
||||
delete _refreshTimer;
|
||||
_refreshTimer = nullptr;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
|
||||
void LedDevice::startEnableAttemptsTimer()
|
||||
{
|
||||
++_enableAttempts;
|
||||
|
||||
if (_enableAttempts <= _maxEnableAttempts)
|
||||
{
|
||||
if (_enableAttemptTimerInterval.count() > 0)
|
||||
{
|
||||
// setup enable retry timer
|
||||
if (_enableAttemptsTimer == nullptr)
|
||||
{
|
||||
_enableAttemptsTimer = new QTimer(this);
|
||||
_enableAttemptsTimer->setTimerType(Qt::PreciseTimer);
|
||||
connect(_enableAttemptsTimer, &QTimer::timeout, this, &LedDevice::enable);
|
||||
}
|
||||
_enableAttemptsTimer->setInterval(static_cast<int>(_enableAttemptTimerInterval.count() * 1000)); //NOLINT
|
||||
|
||||
Info(_log, "Start %d. attempt of %d to enable the device in %d seconds", _enableAttempts, _maxEnableAttempts, _enableAttemptTimerInterval.count());
|
||||
_enableAttemptsTimer->start();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(_log, "Device disabled. Maximum number of %d attempts enabling the device reached. Tried for %d seconds.", _maxEnableAttempts, _enableAttempts * _enableAttemptTimerInterval.count());
|
||||
_enableAttempts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void LedDevice::stopEnableAttemptsTimer()
|
||||
{
|
||||
if (_enableAttemptsTimer != nullptr)
|
||||
{
|
||||
Debug(_log, "Stopping enable retry timer");
|
||||
_enableAttemptsTimer->stop();
|
||||
delete _enableAttemptsTimer;
|
||||
_enableAttemptsTimer = nullptr;
|
||||
_enableAttempts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int LedDevice::updateLeds(std::vector<ColorRgb> ledValues)
|
||||
{
|
||||
int retval = 0;
|
||||
if ( !_isEnabled || !_isOn || !_isDeviceReady || _isDeviceInError )
|
||||
if (!_isEnabled || !_isOn || !_isDeviceReady || _isDeviceInError)
|
||||
{
|
||||
//std::cout << "LedDevice::updateLeds(), LedDevice NOT ready! ";
|
||||
retval = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
qint64 elapsedTimeMs = _lastWriteTime.msecsTo( QDateTime::currentDateTime() );
|
||||
qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
|
||||
if (_latchTime_ms == 0 || elapsedTimeMs >= _latchTime_ms)
|
||||
{
|
||||
//std::cout << "LedDevice::updateLeds(), Elapsed time since last write (" << elapsedTimeMs << ") ms > _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
|
||||
@@ -211,16 +316,16 @@ int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
|
||||
_lastWriteTime = QDateTime::currentDateTime();
|
||||
|
||||
// if device requires refreshing, save Led-Values and restart the timer
|
||||
if ( _isRefreshEnabled && _isEnabled )
|
||||
if (_isRefreshEnabled && _isEnabled)
|
||||
{
|
||||
this->startRefreshTimer();
|
||||
_lastLedValues = ledValues;
|
||||
this->startRefreshTimer();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << "LedDevice::updateLeds(), Skip write. elapsedTime (" << elapsedTimeMs << ") ms < _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
|
||||
if ( _isRefreshEnabled )
|
||||
if (_isRefreshEnabled)
|
||||
{
|
||||
//Stop timer to allow for next non-refresh update
|
||||
this->stopRefreshTimer();
|
||||
@@ -234,18 +339,21 @@ int LedDevice::rewriteLEDs()
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
if ( _isDeviceReady && _isEnabled )
|
||||
if (_isEnabled && _isOn && _isDeviceReady && !_isDeviceInError)
|
||||
{
|
||||
// qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
|
||||
// std::cout << "LedDevice::rewriteLEDs(): Rewrite LEDs now, elapsedTime [" << elapsedTimeMs << "] ms" << std::endl;
|
||||
// //:TESTING: Inject "white" output records to differentiate from normal writes
|
||||
// _lastLedValues.clear();
|
||||
// _lastLedValues.resize(static_cast<unsigned long>(_ledCount), ColorRgb::WHITE);
|
||||
// printLedValues(_lastLedValues);
|
||||
// //:TESTING:
|
||||
// qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
|
||||
// std::cout << "LedDevice::rewriteLEDs(): Rewrite LEDs now, elapsedTime [" << elapsedTimeMs << "] ms" << std::endl;
|
||||
// //:TESTING: Inject "white" output records to differentiate from normal writes
|
||||
// _lastLedValues.clear();
|
||||
// _lastLedValues.resize(static_cast<unsigned long>(_ledCount), ColorRgb::WHITE);
|
||||
// printLedValues(_lastLedValues);
|
||||
// //:TESTING:
|
||||
|
||||
retval = write(_lastLedValues);
|
||||
_lastWriteTime = QDateTime::currentDateTime();
|
||||
if (!_lastLedValues.empty())
|
||||
{
|
||||
retval = write(_lastLedValues);
|
||||
_lastWriteTime = QDateTime::currentDateTime();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -257,6 +365,7 @@ int LedDevice::rewriteLEDs()
|
||||
|
||||
int LedDevice::writeBlack(int numberOfWrites)
|
||||
{
|
||||
Debug(_log, "Set LED strip to black to switch of LEDs");
|
||||
return writeColor(ColorRgb::BLACK, numberOfWrites);
|
||||
}
|
||||
|
||||
@@ -273,7 +382,7 @@ int LedDevice::writeColor(const ColorRgb& color, int numberOfWrites)
|
||||
QTimer::singleShot(_latchTime_ms, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
}
|
||||
_lastLedValues = std::vector<ColorRgb>(static_cast<unsigned long>(_ledCount),color);
|
||||
_lastLedValues = std::vector<ColorRgb>(static_cast<unsigned long>(_ledCount), color);
|
||||
rc = write(_lastLedValues);
|
||||
}
|
||||
return rc;
|
||||
@@ -281,24 +390,31 @@ int LedDevice::writeColor(const ColorRgb& color, int numberOfWrites)
|
||||
|
||||
bool LedDevice::switchOn()
|
||||
{
|
||||
bool rc = false;
|
||||
bool rc{ false };
|
||||
|
||||
if ( _isOn )
|
||||
if (_isOn)
|
||||
{
|
||||
Debug(_log, "Device %s is already on. Skipping.", QSTRING_CSTR(_activeDeviceType));
|
||||
rc = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( _isEnabled &&_isDeviceInitialised )
|
||||
if (_isDeviceReady)
|
||||
{
|
||||
if ( storeState() )
|
||||
Info(_log, "Switching device %s ON", QSTRING_CSTR(_activeDeviceType));
|
||||
if (storeState())
|
||||
{
|
||||
if ( powerOn() )
|
||||
if (powerOn())
|
||||
{
|
||||
Info(_log, "Device %s is ON", QSTRING_CSTR(_activeDeviceType));
|
||||
_isOn = true;
|
||||
_isInSwitchOff = false;
|
||||
emit enableStateChanged(_isEnabled);
|
||||
rc = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning(_log, "Failed switching device %s ON", QSTRING_CSTR(_activeDeviceType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,32 +423,40 @@ bool LedDevice::switchOn()
|
||||
|
||||
bool LedDevice::switchOff()
|
||||
{
|
||||
bool rc = false;
|
||||
bool rc{ false };
|
||||
|
||||
if ( !_isOn )
|
||||
if (!_isOn)
|
||||
{
|
||||
rc = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( _isDeviceInitialised )
|
||||
if (_isDeviceInitialised)
|
||||
{
|
||||
// Disable device to ensure no standard Led updates are written/processed
|
||||
Info(_log, "Switching device %s OFF", QSTRING_CSTR(_activeDeviceType));
|
||||
|
||||
// Disable device to ensure no standard LED updates are written/processed
|
||||
_isOn = false;
|
||||
_isInSwitchOff = true;
|
||||
|
||||
rc = true;
|
||||
|
||||
if ( _isDeviceReady )
|
||||
if (_isDeviceReady)
|
||||
{
|
||||
if ( _isRestoreOrigState )
|
||||
if (_isRestoreOrigState)
|
||||
{
|
||||
//Restore devices state
|
||||
restoreState();
|
||||
}
|
||||
else
|
||||
{
|
||||
powerOff();
|
||||
if (powerOff())
|
||||
{
|
||||
Info(_log, "Device %s is OFF", QSTRING_CSTR(_activeDeviceType));
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning(_log, "Failed switching device %s OFF", QSTRING_CSTR(_activeDeviceType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,10 +466,12 @@ bool LedDevice::switchOff()
|
||||
|
||||
bool LedDevice::powerOff()
|
||||
{
|
||||
bool rc = false;
|
||||
bool rc{ false };
|
||||
|
||||
Debug(_log, "Power Off: %s", QSTRING_CSTR(_activeDeviceType));
|
||||
|
||||
// Simulate power-off by writing a final "Black" to have a defined outcome
|
||||
if ( writeBlack() >= 0 )
|
||||
if (writeBlack() >= 0)
|
||||
{
|
||||
rc = true;
|
||||
}
|
||||
@@ -354,15 +480,18 @@ bool LedDevice::powerOff()
|
||||
|
||||
bool LedDevice::powerOn()
|
||||
{
|
||||
bool rc = true;
|
||||
bool rc{ true };
|
||||
|
||||
Debug(_log, "Power On: %s", QSTRING_CSTR(_activeDeviceType));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool LedDevice::storeState()
|
||||
{
|
||||
bool rc = true;
|
||||
bool rc{ true };
|
||||
|
||||
if ( _isRestoreOrigState )
|
||||
if (_isRestoreOrigState)
|
||||
{
|
||||
// Save device's original state
|
||||
// _originalStateValues = get device's state;
|
||||
@@ -373,9 +502,9 @@ bool LedDevice::storeState()
|
||||
|
||||
bool LedDevice::restoreState()
|
||||
{
|
||||
bool rc = true;
|
||||
bool rc{ true };
|
||||
|
||||
if ( _isRestoreOrigState )
|
||||
if (_isRestoreOrigState)
|
||||
{
|
||||
// Restore device's original state
|
||||
// update device using _originalStateValues
|
||||
@@ -393,7 +522,7 @@ QJsonObject LedDevice::discover(const QJsonObject& /*params*/)
|
||||
QJsonArray deviceList;
|
||||
devicesDiscovered.insert("devices", deviceList);
|
||||
|
||||
Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
return devicesDiscovered;
|
||||
}
|
||||
|
||||
@@ -401,75 +530,98 @@ QString LedDevice::discoverFirst()
|
||||
{
|
||||
QString deviceDiscovered;
|
||||
|
||||
Debug(_log, "deviceDiscovered: [%s]", QSTRING_CSTR(deviceDiscovered) );
|
||||
Debug(_log, "deviceDiscovered: [%s]", QSTRING_CSTR(deviceDiscovered));
|
||||
return deviceDiscovered;
|
||||
}
|
||||
|
||||
|
||||
QJsonObject LedDevice::getProperties(const QJsonObject& params)
|
||||
{
|
||||
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
QJsonObject properties;
|
||||
|
||||
QJsonObject deviceProperties;
|
||||
properties.insert("properties", deviceProperties);
|
||||
|
||||
Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
void LedDevice::setLogger(Logger* log)
|
||||
{
|
||||
_log = log;
|
||||
}
|
||||
|
||||
void LedDevice::setLedCount(int ledCount)
|
||||
{
|
||||
assert(ledCount >= 0);
|
||||
_ledCount = ledCount;
|
||||
_ledRGBCount = _ledCount * sizeof(ColorRgb);
|
||||
_ledCount = static_cast<uint>(ledCount);
|
||||
_ledRGBCount = _ledCount * sizeof(ColorRgb);
|
||||
_ledRGBWCount = _ledCount * sizeof(ColorRgbw);
|
||||
Debug(_log, "LedCount set to %d", _ledCount);
|
||||
}
|
||||
|
||||
void LedDevice::setLatchTime( int latchTime_ms )
|
||||
void LedDevice::setColorOrder(const QString& colorOrder)
|
||||
{
|
||||
_colorOrder = colorOrder;
|
||||
Debug(_log, "ColorOrder set to %s", QSTRING_CSTR(_colorOrder.toUpper()));
|
||||
}
|
||||
|
||||
void LedDevice::setLatchTime(int latchTime_ms)
|
||||
{
|
||||
assert(latchTime_ms >= 0);
|
||||
_latchTime_ms = latchTime_ms;
|
||||
Debug(_log, "LatchTime updated to %dms", _latchTime_ms);
|
||||
Debug(_log, "LatchTime set to %dms", _latchTime_ms);
|
||||
}
|
||||
|
||||
void LedDevice::setRewriteTime( int rewriteTime_ms )
|
||||
void LedDevice::setAutoStart(bool isAutoStart)
|
||||
{
|
||||
assert(rewriteTime_ms >= 0);
|
||||
_isAutoStart = isAutoStart;
|
||||
Debug(_log, "AutoStart %s", (_isAutoStart ? "enabled" : "disabled"));
|
||||
}
|
||||
|
||||
//Check, if refresh timer was not initialised due to getProperties/identify sceanrios
|
||||
if (_refreshTimer != nullptr)
|
||||
void LedDevice::setRewriteTime(int rewriteTime_ms)
|
||||
{
|
||||
_refreshTimerInterval_ms = qMax(rewriteTime_ms, 0);
|
||||
|
||||
if (_refreshTimerInterval_ms > 0)
|
||||
{
|
||||
_refreshTimerInterval_ms = rewriteTime_ms;
|
||||
_isRefreshEnabled = true;
|
||||
|
||||
if (_refreshTimerInterval_ms > 0)
|
||||
if (_refreshTimerInterval_ms <= _latchTime_ms)
|
||||
{
|
||||
|
||||
_isRefreshEnabled = true;
|
||||
|
||||
if (_refreshTimerInterval_ms <= _latchTime_ms)
|
||||
{
|
||||
int new_refresh_timer_interval = _latchTime_ms + 10;
|
||||
Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refreshTimerInterval_ms, new_refresh_timer_interval);
|
||||
_refreshTimerInterval_ms = new_refresh_timer_interval;
|
||||
_refreshTimer->setInterval(_refreshTimerInterval_ms);
|
||||
}
|
||||
|
||||
Debug(_log, "Refresh interval = %dms", _refreshTimerInterval_ms);
|
||||
_refreshTimer->setInterval(_refreshTimerInterval_ms);
|
||||
|
||||
_lastWriteTime = QDateTime::currentDateTime();
|
||||
int new_refresh_timer_interval = _latchTime_ms + 10; //NOLINT
|
||||
Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refreshTimerInterval_ms, new_refresh_timer_interval);
|
||||
_refreshTimerInterval_ms = new_refresh_timer_interval;
|
||||
}
|
||||
|
||||
Debug(_log, "RewriteTime updated to %dms", _refreshTimerInterval_ms);
|
||||
Debug(_log, "Refresh interval = %dms", _refreshTimerInterval_ms);
|
||||
startRefreshTimer();
|
||||
}
|
||||
else
|
||||
{
|
||||
_isRefreshEnabled = false;
|
||||
stopRefreshTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void LedDevice::setEnableAttempts(int maxEnableRetries, std::chrono::seconds enableRetryTimerInterval)
|
||||
{
|
||||
stopEnableAttemptsTimer();
|
||||
maxEnableRetries = qMax(maxEnableRetries, 0);
|
||||
|
||||
_enableAttempts = 0;
|
||||
_maxEnableAttempts = maxEnableRetries;
|
||||
_enableAttemptTimerInterval = enableRetryTimerInterval;
|
||||
|
||||
Debug(_log, "Max enable retries: %d, enable retry interval = %llds", _maxEnableAttempts, static_cast<int>(_enableAttemptTimerInterval.count()));
|
||||
}
|
||||
|
||||
void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues)
|
||||
{
|
||||
std::cout << "LedValues [" << ledValues.size() <<"] [";
|
||||
std::cout << "LedValues [" << ledValues.size() << "] [";
|
||||
for (const ColorRgb& color : ledValues)
|
||||
{
|
||||
std::cout << color;
|
||||
@@ -477,24 +629,24 @@ void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues)
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
|
||||
QString LedDevice::uint8_t_to_hex_string(const uint8_t * data, const int size, int number) const
|
||||
QString LedDevice::uint8_t_to_hex_string(const uint8_t* data, const int size, int number)
|
||||
{
|
||||
if ( number <= 0 || number > size)
|
||||
if (number <= 0 || number > size)
|
||||
{
|
||||
number = size;
|
||||
}
|
||||
|
||||
QByteArray bytes (reinterpret_cast<const char*>(data), number);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
return bytes.toHex(':');
|
||||
#else
|
||||
return bytes.toHex();
|
||||
#endif
|
||||
QByteArray bytes(reinterpret_cast<const char*>(data), number);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
return bytes.toHex(':');
|
||||
#else
|
||||
return bytes.toHex();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString LedDevice::toHex(const QByteArray& data, int number) const
|
||||
QString LedDevice::toHex(const QByteArray& data, int number)
|
||||
{
|
||||
if ( number <= 0 || number > data.size())
|
||||
if (number <= 0 || number > data.size())
|
||||
{
|
||||
number = data.size();
|
||||
}
|
||||
@@ -505,3 +657,47 @@ QString LedDevice::toHex(const QByteArray& data, int number) const
|
||||
return data.left(number).toHex();
|
||||
#endif
|
||||
}
|
||||
bool LedDevice::isInitialised() const
|
||||
{
|
||||
return _isDeviceInitialised;
|
||||
}
|
||||
|
||||
bool LedDevice::isReady() const
|
||||
{
|
||||
return _isDeviceReady;
|
||||
}
|
||||
|
||||
bool LedDevice::isInError() const
|
||||
{
|
||||
return _isDeviceInError;
|
||||
}
|
||||
|
||||
int LedDevice::getLatchTime() const
|
||||
{
|
||||
return _latchTime_ms;
|
||||
}
|
||||
|
||||
int LedDevice::getRewriteTime() const
|
||||
{
|
||||
return _refreshTimerInterval_ms;
|
||||
}
|
||||
|
||||
int LedDevice::getLedCount() const
|
||||
{
|
||||
return static_cast<int>(_ledCount);
|
||||
}
|
||||
|
||||
QString LedDevice::getActiveDeviceType() const
|
||||
{
|
||||
return _activeDeviceType;
|
||||
}
|
||||
|
||||
QString LedDevice::getColorOrder() const
|
||||
{
|
||||
return _colorOrder;
|
||||
}
|
||||
|
||||
bool LedDevice::componentState() const {
|
||||
return _isEnabled;
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
<file alias="schema-udpartnet">schemas/schema-artnet.json</file>
|
||||
<file alias="schema-udph801">schemas/schema-h801.json</file>
|
||||
<file alias="schema-udpraw">schemas/schema-udpraw.json</file>
|
||||
<file alias="schema-udpddp">schemas/schema-udpddp.json</file>
|
||||
<file alias="schema-ws2801">schemas/schema-ws2801.json</file>
|
||||
<file alias="schema-ws2812spi">schemas/schema-ws2812spi.json</file>
|
||||
<file alias="schema-apa104">schemas/schema-apa104.json</file>
|
||||
|
@@ -67,9 +67,6 @@ void LedDeviceWrapper::createLedDevice(const QJsonObject& config)
|
||||
// further signals
|
||||
connect(this, &LedDeviceWrapper::updateLeds, _ledDevice, &LedDevice::updateLeds, Qt::QueuedConnection);
|
||||
|
||||
connect(this, &LedDeviceWrapper::enable, _ledDevice, &LedDevice::enable);
|
||||
connect(this, &LedDeviceWrapper::disable, _ledDevice, &LedDevice::disable);
|
||||
|
||||
connect(this, &LedDeviceWrapper::switchOn, _ledDevice, &LedDevice::switchOn);
|
||||
connect(this, &LedDeviceWrapper::switchOff, _ledDevice, &LedDevice::switchOff);
|
||||
|
||||
@@ -81,6 +78,100 @@ void LedDeviceWrapper::createLedDevice(const QJsonObject& config)
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void LedDeviceWrapper::handleComponentState(hyperion::Components component, bool state)
|
||||
{
|
||||
if (component == hyperion::COMP_LEDDEVICE)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
QMetaObject::invokeMethod(_ledDevice, "enable", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMetaObject::invokeMethod(_ledDevice, "disable", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(_ledDevice, "componentState", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, _enabled));
|
||||
}
|
||||
}
|
||||
|
||||
void LedDeviceWrapper::handleInternalEnableState(bool newState)
|
||||
{
|
||||
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, newState);
|
||||
_enabled = newState;
|
||||
|
||||
if (_enabled)
|
||||
{
|
||||
_hyperion->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LedDeviceWrapper::stopDeviceThread()
|
||||
{
|
||||
// turns the LEDs off & stop refresh timers
|
||||
emit stopLedDevice();
|
||||
|
||||
// get current thread
|
||||
QThread* oldThread = _ledDevice->thread();
|
||||
disconnect(oldThread, nullptr, nullptr, nullptr);
|
||||
oldThread->quit();
|
||||
oldThread->wait();
|
||||
delete oldThread;
|
||||
|
||||
disconnect(_ledDevice, nullptr, nullptr, nullptr);
|
||||
delete _ledDevice;
|
||||
_ledDevice = nullptr;
|
||||
}
|
||||
|
||||
QString LedDeviceWrapper::getActiveDeviceType() const
|
||||
{
|
||||
QString value = 0;
|
||||
QMetaObject::invokeMethod(_ledDevice, "getActiveDeviceType", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned int LedDeviceWrapper::getLedCount() const
|
||||
{
|
||||
int value = 0;
|
||||
QMetaObject::invokeMethod(_ledDevice, "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
QString LedDeviceWrapper::getColorOrder() const
|
||||
{
|
||||
QString value;
|
||||
QMetaObject::invokeMethod(_ledDevice, "getColorOrder", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
int LedDeviceWrapper::getLatchTime() const
|
||||
{
|
||||
int value = 0;
|
||||
QMetaObject::invokeMethod(_ledDevice, "getLatchTime", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
bool LedDeviceWrapper::enabled() const
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
int LedDeviceWrapper::addToDeviceMap(QString name, LedDeviceCreateFuncType funcPtr)
|
||||
{
|
||||
QMutexLocker lock(&_ledDeviceMapLock);
|
||||
|
||||
_ledDeviceMap.emplace(name,funcPtr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const LedDeviceRegistry& LedDeviceWrapper::getDeviceMap()
|
||||
{
|
||||
QMutexLocker lock(&_ledDeviceMapLock);
|
||||
|
||||
return _ledDeviceMap;
|
||||
}
|
||||
|
||||
QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
|
||||
{
|
||||
// make sure the resources are loaded (they may be left out after static linking)
|
||||
@@ -115,101 +206,3 @@ QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int LedDeviceWrapper::addToDeviceMap(QString name, LedDeviceCreateFuncType funcPtr)
|
||||
{
|
||||
QMutexLocker lock(&_ledDeviceMapLock);
|
||||
|
||||
_ledDeviceMap.emplace(name,funcPtr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const LedDeviceRegistry& LedDeviceWrapper::getDeviceMap()
|
||||
{
|
||||
QMutexLocker lock(&_ledDeviceMapLock);
|
||||
|
||||
return _ledDeviceMap;
|
||||
}
|
||||
|
||||
int LedDeviceWrapper::getLatchTime() const
|
||||
{
|
||||
int value = 0;
|
||||
QMetaObject::invokeMethod(_ledDevice, "getLatchTime", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
QString LedDeviceWrapper::getActiveDeviceType() const
|
||||
{
|
||||
QString value = 0;
|
||||
QMetaObject::invokeMethod(_ledDevice, "getActiveDeviceType", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
QString LedDeviceWrapper::getColorOrder() const
|
||||
{
|
||||
QString value;
|
||||
QMetaObject::invokeMethod(_ledDevice, "getColorOrder", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned int LedDeviceWrapper::getLedCount() const
|
||||
{
|
||||
int value = 0;
|
||||
QMetaObject::invokeMethod(_ledDevice, "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, value));
|
||||
return value;
|
||||
}
|
||||
|
||||
bool LedDeviceWrapper::enabled() const
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void LedDeviceWrapper::handleComponentState(hyperion::Components component, bool state)
|
||||
{
|
||||
if(component == hyperion::COMP_LEDDEVICE)
|
||||
{
|
||||
if ( state )
|
||||
{
|
||||
emit enable();
|
||||
}
|
||||
else
|
||||
{
|
||||
emit disable();
|
||||
}
|
||||
|
||||
//Get device's state, considering situations where it is not ready
|
||||
bool deviceState = false;
|
||||
QMetaObject::invokeMethod(_ledDevice, "componentState", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, deviceState));
|
||||
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, deviceState);
|
||||
_enabled = deviceState;
|
||||
}
|
||||
}
|
||||
|
||||
void LedDeviceWrapper::handleInternalEnableState(bool newState)
|
||||
{
|
||||
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, newState);
|
||||
_enabled = newState;
|
||||
|
||||
if (_enabled)
|
||||
{
|
||||
_hyperion->update();
|
||||
}
|
||||
}
|
||||
|
||||
void LedDeviceWrapper::stopDeviceThread()
|
||||
{
|
||||
// turns the LEDs off & stop refresh timers
|
||||
emit stopLedDevice();
|
||||
|
||||
// get current thread
|
||||
QThread* oldThread = _ledDevice->thread();
|
||||
disconnect(oldThread, nullptr, nullptr, nullptr);
|
||||
oldThread->quit();
|
||||
oldThread->wait();
|
||||
delete oldThread;
|
||||
|
||||
disconnect(_ledDevice, nullptr, nullptr, nullptr);
|
||||
delete _ledDevice;
|
||||
_ledDevice = nullptr;
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ public:
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @para#endif // LEDEVICETEMPLATE_Hm deviceConfig the json device config
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -79,4 +79,4 @@ private:
|
||||
|
||||
};
|
||||
|
||||
#endif // LEDEVICETEMPLATE_H
|
||||
#endif // LEDEVICEPIBLASTER_H
|
||||
|
@@ -44,13 +44,6 @@ bool ProviderRs232::init(const QJsonObject &deviceConfig)
|
||||
// Initialise sub-class
|
||||
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, "RefreshTime : %d", _refreshTimerInterval_ms);
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
|
||||
_deviceName = deviceConfig["output"].toString("auto");
|
||||
_isAutoDeviceName = _deviceName.toLower() == "auto";
|
||||
|
||||
@@ -89,7 +82,6 @@ int ProviderRs232::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
_isInSwitchOff = false;
|
||||
|
||||
// open device physically
|
||||
if ( tryOpen(_delayAfterConnect_ms) )
|
||||
@@ -190,18 +182,6 @@ bool ProviderRs232::tryOpen(int delayAfterConnect_ms)
|
||||
{
|
||||
QString errortext = QString("Invalid serial device name: %1 %2!").arg(_deviceName, _location);
|
||||
this->setInError( errortext );
|
||||
|
||||
// List available device
|
||||
for (auto &port : QSerialPortInfo::availablePorts() ) {
|
||||
Debug(_log, "Avail. serial device: [%s]-(%s|%s), Manufacturer: %s, Description: %s",
|
||||
QSTRING_CSTR(port.portName()),
|
||||
QSTRING_CSTR(QString("0x%1").arg(port.vendorIdentifier(), 0, 16)),
|
||||
QSTRING_CSTR(QString("0x%1").arg(port.productIdentifier(), 0, 16)),
|
||||
QSTRING_CSTR(port.manufacturer()),
|
||||
QSTRING_CSTR(port.description())
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -295,17 +275,21 @@ QString ProviderRs232::discoverFirst()
|
||||
return "";
|
||||
}
|
||||
|
||||
QJsonObject ProviderRs232::discover(const QJsonObject& /*params*/)
|
||||
QJsonObject ProviderRs232::discover(const QJsonObject& params)
|
||||
{
|
||||
DebugIf(verbose,_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
QJsonObject devicesDiscovered;
|
||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
|
||||
|
||||
QJsonArray deviceList;
|
||||
|
||||
bool showAll = params["discoverAll"].toBool(false);
|
||||
|
||||
// Discover serial Devices
|
||||
for (auto &port : QSerialPortInfo::availablePorts() )
|
||||
{
|
||||
if ( !port.isNull() && port.vendorIdentifier() != 0)
|
||||
if ( !port.isNull() && (showAll || port.vendorIdentifier() != 0) )
|
||||
{
|
||||
QJsonObject portInfo;
|
||||
portInfo.insert("description", port.description());
|
||||
@@ -364,6 +348,8 @@ void ProviderRs232::identify(const QJsonObject& params)
|
||||
QString deviceName = params["output"].toString("");
|
||||
if (!deviceName.isEmpty())
|
||||
{
|
||||
Info(_log, "Identify %s, device: %s", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(deviceName) );
|
||||
|
||||
_devConfig = params;
|
||||
init(_devConfig);
|
||||
{
|
||||
|
@@ -74,12 +74,22 @@ protected:
|
||||
bool powerOff() override;
|
||||
|
||||
///
|
||||
/// @brief Discover first devices of a serial device available (for configuration)
|
||||
/// @brief Discover first device of serial devices available (for configuration)
|
||||
///
|
||||
/// @return A string of the device found
|
||||
///
|
||||
QString discoverFirst() override;
|
||||
|
||||
///
|
||||
/// @brief Discover serial devices available (for configuration).
|
||||
///
|
||||
/// Following parameters can be provided optional
|
||||
/// @code
|
||||
/// {
|
||||
/// "discoverAll" : true/false , "true", in case devices without vendor-id are to be included in the discovery result
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters used to overwrite discovery default behaviour
|
||||
///
|
||||
/// @return A JSON structure holding a list of devices found
|
||||
|
@@ -37,7 +37,6 @@ ProviderSpi::ProviderSpi(const QJsonObject &deviceConfig)
|
||||
{
|
||||
memset(&_spi, 0, sizeof(_spi));
|
||||
_latchTime_ms = 1;
|
||||
_isInSwitchOff = false;
|
||||
}
|
||||
|
||||
ProviderSpi::~ProviderSpi()
|
||||
@@ -69,7 +68,6 @@ int ProviderSpi::open()
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_isDeviceReady = false;
|
||||
_isInSwitchOff = false;
|
||||
|
||||
const int bitsPerWord = 8;
|
||||
|
||||
|
@@ -37,43 +37,74 @@
|
||||
},
|
||||
"useEntertainmentAPI": {
|
||||
"type": "boolean",
|
||||
"format": "checkbox",
|
||||
"title": "edt_dev_spec_useEntertainmentAPI_title",
|
||||
"default": true,
|
||||
"propertyOrder": 5
|
||||
},
|
||||
"transitiontime": {
|
||||
"type": "number",
|
||||
"title": "edt_dev_spec_transistionTime_title",
|
||||
"default": 1,
|
||||
"append": "x100ms",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": false
|
||||
}
|
||||
},
|
||||
"propertyOrder": 6
|
||||
},
|
||||
"switchOffOnBlack": {
|
||||
"type": "boolean",
|
||||
"format": "checkbox",
|
||||
"title": "edt_dev_spec_switchOffOnBlack_title",
|
||||
"default": false,
|
||||
"propertyOrder": 7
|
||||
"propertyOrder": 6
|
||||
},
|
||||
"restoreOriginalState": {
|
||||
"type": "boolean",
|
||||
"format": "checkbox",
|
||||
"title": "edt_dev_spec_restoreOriginalState_title",
|
||||
"default": true,
|
||||
"default": false,
|
||||
"propertyOrder": 7
|
||||
},
|
||||
"blackLevel": {
|
||||
"type": "number",
|
||||
"format": "stepper",
|
||||
"title": "edt_dev_spec_brightnessThreshold_title",
|
||||
"default": 0.009,
|
||||
"step": 0.01,
|
||||
"minimum": 0.001,
|
||||
"maximum": 1.0,
|
||||
"propertyOrder": 8
|
||||
},
|
||||
"onBlackTimeToPowerOff": {
|
||||
"type": "integer",
|
||||
"format": "stepper",
|
||||
"step": 50,
|
||||
"title": "edt_dev_spec_onBlackTimeToPowerOff",
|
||||
"append": "edt_append_ms",
|
||||
"minimum": 100,
|
||||
"maximum": 100000,
|
||||
"default": 600,
|
||||
"required": true,
|
||||
"propertyOrder": 9
|
||||
},
|
||||
"onBlackTimeToPowerOn": {
|
||||
"type": "integer",
|
||||
"format": "stepper",
|
||||
"step": 50,
|
||||
"title": "edt_dev_spec_onBlackTimeToPowerOn",
|
||||
"append": "edt_append_ms",
|
||||
"minimum": 100,
|
||||
"maximum": 100000,
|
||||
"default": 300,
|
||||
"required": true,
|
||||
"propertyOrder": 9
|
||||
},
|
||||
"candyGamma": {
|
||||
"type": "boolean",
|
||||
"format": "checkbox",
|
||||
"title": "edt_dev_spec_candyGamma_title",
|
||||
"default": true,
|
||||
"propertyOrder": 10
|
||||
},
|
||||
"lightIds": {
|
||||
"type": "array",
|
||||
"title": "edt_dev_spec_lightid_title",
|
||||
"minimum": 1,
|
||||
"minItems": 1,
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"required": true,
|
||||
"minimum": 0,
|
||||
"title": "edt_dev_spec_lightid_itemtitle"
|
||||
},
|
||||
"options": {
|
||||
@@ -81,10 +112,12 @@
|
||||
"useEntertainmentAPI": false
|
||||
}
|
||||
},
|
||||
"propertyOrder": 9
|
||||
"propertyOrder": 11
|
||||
},
|
||||
"groupId": {
|
||||
"type": "number",
|
||||
"format": "stepper",
|
||||
"step": 1,
|
||||
"title": "edt_dev_spec_groupId_title",
|
||||
"default": 0,
|
||||
"options": {
|
||||
@@ -92,41 +125,11 @@
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
},
|
||||
"propertyOrder": 10
|
||||
},
|
||||
"blackLightsTimeout": {
|
||||
"type": "number",
|
||||
"title": "edt_dev_spec_blackLightsTimeout_title",
|
||||
"default": 15000,
|
||||
"step": 500,
|
||||
"minimum": 10000,
|
||||
"maximum": 60000,
|
||||
"access": "advanced",
|
||||
"append": "edt_append_ms",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
},
|
||||
"propertyOrder": 11
|
||||
},
|
||||
"brightnessThreshold": {
|
||||
"type": "number",
|
||||
"title": "edt_dev_spec_brightnessThreshold_title",
|
||||
"default": 0,
|
||||
"step": 0.005,
|
||||
"minimum": 0,
|
||||
"maximum": 1.0,
|
||||
"access": "advanced",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
},
|
||||
"propertyOrder": 12
|
||||
},
|
||||
"brightnessFactor": {
|
||||
"type": "number",
|
||||
"format": "stepper",
|
||||
"title": "edt_dev_spec_brightnessFactor_title",
|
||||
"default": 1.0,
|
||||
"step": 0.25,
|
||||
@@ -135,6 +138,82 @@
|
||||
"access": "advanced",
|
||||
"propertyOrder": 13
|
||||
},
|
||||
"handshakeTimeoutMin": {
|
||||
"type": "number",
|
||||
"format": "stepper",
|
||||
"title": "edt_dev_spec_sslHSTimeoutMin_title",
|
||||
"default": 600,
|
||||
"step": 100,
|
||||
"minimum": 100,
|
||||
"maximum": 30000,
|
||||
"access": "expert",
|
||||
"append": "edt_append_ms",
|
||||
"required": true,
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
},
|
||||
"propertyOrder": 14
|
||||
},
|
||||
"handshakeTimeoutMax": {
|
||||
"type": "number",
|
||||
"format": "stepper",
|
||||
"title": "edt_dev_spec_sslHSTimeoutMax_title",
|
||||
"default": 1000,
|
||||
"step": 100,
|
||||
"minimum": 100,
|
||||
"maximum": 30000,
|
||||
"access": "expert",
|
||||
"append": "edt_append_ms",
|
||||
"required": true,
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
},
|
||||
"propertyOrder": 15
|
||||
},
|
||||
"verbose": {
|
||||
"type": "boolean",
|
||||
"format": "checkbox",
|
||||
"title": "edt_dev_spec_verbose_title",
|
||||
"default": false,
|
||||
"access": "expert",
|
||||
"propertyOrder": 16
|
||||
},
|
||||
"transitiontime": {
|
||||
"type": "number",
|
||||
"title": "edt_dev_spec_transistionTime_title",
|
||||
"default": 1,
|
||||
"minimum": 0,
|
||||
"maximum": 100000,
|
||||
"required": true,
|
||||
"append": "x100ms",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": false
|
||||
}
|
||||
},
|
||||
"propertyOrder": 17
|
||||
},
|
||||
"blackLightsTimeout": {
|
||||
"type": "number",
|
||||
"default": 5000,
|
||||
"options": {
|
||||
"hidden": true
|
||||
},
|
||||
"propertyOrder": 18
|
||||
},
|
||||
"brightnessThreshold": {
|
||||
"type": "number",
|
||||
"title": "edt_dev_spec_brightnessThreshold_title",
|
||||
"default": 0.0001,
|
||||
"options": {
|
||||
"hidden": true
|
||||
},
|
||||
"propertyOrder": 19
|
||||
},
|
||||
"brightnessMin": {
|
||||
"type": "number",
|
||||
"title": "edt_dev_spec_brightnessMin_title",
|
||||
@@ -144,11 +223,9 @@
|
||||
"maximum": 1.0,
|
||||
"access": "advanced",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
"hidden": true
|
||||
},
|
||||
"propertyOrder": 14
|
||||
"propertyOrder": 20
|
||||
},
|
||||
"brightnessMax": {
|
||||
"type": "number",
|
||||
@@ -159,93 +236,8 @@
|
||||
"maximum": 1.0,
|
||||
"access": "advanced",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
"hidden": true
|
||||
},
|
||||
"propertyOrder": 15
|
||||
},
|
||||
"sslReadTimeout": {
|
||||
"type": "number",
|
||||
"title": "edt_dev_spec_sslReadTimeout_title",
|
||||
"default": 0,
|
||||
"step": 100,
|
||||
"minimum": 0,
|
||||
"maximum": 30000,
|
||||
"access": "expert",
|
||||
"append": "edt_append_ms",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
},
|
||||
"propertyOrder": 16
|
||||
},
|
||||
"sslHSTimeoutMin": {
|
||||
"type": "number",
|
||||
"title": "edt_dev_spec_sslHSTimeoutMin_title",
|
||||
"default": 400,
|
||||
"step": 100,
|
||||
"minimum": 0,
|
||||
"maximum": 30000,
|
||||
"access": "expert",
|
||||
"append": "edt_append_ms",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
},
|
||||
"propertyOrder": 17
|
||||
},
|
||||
"sslHSTimeoutMax": {
|
||||
"type": "number",
|
||||
"title": "edt_dev_spec_sslHSTimeoutMax_title",
|
||||
"default": 1000,
|
||||
"step": 100,
|
||||
"minimum": 0,
|
||||
"maximum": 30000,
|
||||
"access": "expert",
|
||||
"append": "edt_append_ms",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
},
|
||||
"propertyOrder": 18
|
||||
},
|
||||
"verbose": {
|
||||
"type": "boolean",
|
||||
"title": "edt_dev_spec_verbose_title",
|
||||
"default": false,
|
||||
"access": "expert",
|
||||
"propertyOrder": 19
|
||||
},
|
||||
"debugStreamer": {
|
||||
"type": "boolean",
|
||||
"title": "edt_dev_spec_debugStreamer_title",
|
||||
"default": false,
|
||||
"access": "expert",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
},
|
||||
"propertyOrder": 20
|
||||
},
|
||||
"debugLevel": {
|
||||
"type": "string",
|
||||
"title": "edt_dev_spec_debugLevel_title",
|
||||
"enum": [ "0", "1", "2", "3", "4" ],
|
||||
"default": "0",
|
||||
"options": {
|
||||
"enum_titles": [ "edt_conf_enum_dl_nodebug", "edt_conf_enum_dl_error", "edt_conf_enum_dl_statechange", "edt_conf_enum_dl_informational", "edt_conf_enum_dl_verbose" ],
|
||||
"dependencies": {
|
||||
"useEntertainmentAPI": true
|
||||
}
|
||||
},
|
||||
"minimum": 0,
|
||||
"maximum": 4,
|
||||
"access": "expert",
|
||||
"propertyOrder": 21
|
||||
}
|
||||
},
|
||||
|
32
libsrc/leddevice/schemas/schema-udpddp.json
Normal file
32
libsrc/leddevice/schemas/schema-udpddp.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"type": "object",
|
||||
"required": true,
|
||||
"properties": {
|
||||
"host": {
|
||||
"type": "string",
|
||||
"title": "edt_dev_spec_targetIpHost_title",
|
||||
"format": "hostname_or_ip",
|
||||
"propertyOrder": 1
|
||||
},
|
||||
"port": {
|
||||
"type": "integer",
|
||||
"title": "edt_dev_spec_port_title",
|
||||
"default": 4048,
|
||||
"minimum": 0,
|
||||
"maximum": 65535,
|
||||
"access": "expert",
|
||||
"propertyOrder": 2
|
||||
},
|
||||
"latchTime": {
|
||||
"type": "integer",
|
||||
"title": "edt_dev_spec_latchtime_title",
|
||||
"default": 0,
|
||||
"append": "edt_append_ms",
|
||||
"minimum": 0,
|
||||
"maximum": 1000,
|
||||
"access": "expert",
|
||||
"propertyOrder": 3
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
@@ -24,6 +24,17 @@
|
||||
"required": true,
|
||||
"propertyOrder": 2
|
||||
},
|
||||
"streamProtocol": {
|
||||
"type": "string",
|
||||
"title": "edt_dev_spec_stream_protocol_title",
|
||||
"enum": [ "DDP", "RAW" ],
|
||||
"default": "DDP",
|
||||
"options": {
|
||||
"enum_titles": [ "edt_conf_enum_udp_ddp", "edt_conf_enum_udp_raw" ]
|
||||
},
|
||||
"access": "expert",
|
||||
"propertyOrder": 3
|
||||
},
|
||||
"restoreOriginalState": {
|
||||
"type": "boolean",
|
||||
"format": "checkbox",
|
||||
@@ -33,7 +44,7 @@
|
||||
"options": {
|
||||
"infoText": "edt_dev_spec_restoreOriginalState_title_info"
|
||||
},
|
||||
"propertyOrder": 3
|
||||
"propertyOrder": 4
|
||||
},
|
||||
"overwriteSync": {
|
||||
"type": "boolean",
|
||||
@@ -42,7 +53,7 @@
|
||||
"default": true,
|
||||
"required": true,
|
||||
"access": "advanced",
|
||||
"propertyOrder": 4
|
||||
"propertyOrder": 5
|
||||
},
|
||||
"overwriteBrightness": {
|
||||
"type": "boolean",
|
||||
@@ -51,7 +62,7 @@
|
||||
"default": true,
|
||||
"required": true,
|
||||
"access": "advanced",
|
||||
"propertyOrder": 5
|
||||
"propertyOrder": 6
|
||||
},
|
||||
"brightness": {
|
||||
"type": "integer",
|
||||
@@ -65,7 +76,7 @@
|
||||
}
|
||||
},
|
||||
"access": "advanced",
|
||||
"propertyOrder": 6
|
||||
"propertyOrder": 7
|
||||
},
|
||||
"latchTime": {
|
||||
"type": "integer",
|
||||
@@ -78,7 +89,7 @@
|
||||
"options": {
|
||||
"infoText": "edt_dev_spec_latchtime_title_info"
|
||||
},
|
||||
"propertyOrder": 7
|
||||
"propertyOrder": 8
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
|
Reference in New Issue
Block a user