diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json
index 6f8d3816..df22f96a 100644
--- a/assets/webconfig/i18n/en.json
+++ b/assets/webconfig/i18n/en.json
@@ -492,6 +492,7 @@
"edt_dev_spec_printTimeStamp_title": "Add timestamp",
"edt_dev_spec_pwmChannel_title": "PWM channel",
"edt_dev_spec_restoreOriginalState_title": "Restore lights' original state when disabled",
+ "edt_dev_spec_razor_device_title": "Razor Chroma Device",
"edt_dev_spec_serial_title": "Serial number",
"edt_dev_spec_spipath_title": "SPI path",
"edt_dev_spec_sslHSTimeoutMax_title": "Streamer handshake timeout maximum",
diff --git a/assets/webconfig/js/content_leds.js b/assets/webconfig/js/content_leds.js
index 21b7f32f..56fd9d7a 100644
--- a/assets/webconfig/js/content_leds.js
+++ b/assets/webconfig/js/content_leds.js
@@ -571,8 +571,8 @@ $(document).ready(function() {
var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'sk9822', 'ws2812spi'];
var devRPiPWM = ['ws281x'];
var devRPiGPIO = ['piblaster'];
- var devNET = ['atmoorb', 'fadecandy', 'philipshue', 'nanoleaf', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw', 'wled', 'yeelight'];
- var devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'multilightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2', 'karate'];
+ var devNET = ['atmoorb', 'fadecandy', 'philipshue', 'nanoleaf', 'razer', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw', 'wled', 'yeelight'];
+ var devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2', 'karate'];
var optArr = [[]];
optArr[1]=[];
diff --git a/include/leddevice/LedDevice.h b/include/leddevice/LedDevice.h
index a9dcf0c5..03c2ddd7 100644
--- a/include/leddevice/LedDevice.h
+++ b/include/leddevice/LedDevice.h
@@ -414,14 +414,14 @@ protected slots:
///
/// @return Zero on success else negative
///
- int rewriteLEDs();
+ virtual int rewriteLEDs();
///
/// @brief Set device in error state
///
/// @param[in] errorMsg The error message to be logged
///
- virtual void setInError( const QString& errorMsg);
+ virtual void setInError( const QString& errorMsg);
private:
diff --git a/libsrc/leddevice/LedDeviceSchemas.qrc b/libsrc/leddevice/LedDeviceSchemas.qrc
index 8977d9ca..9ed5fc6f 100644
--- a/libsrc/leddevice/LedDeviceSchemas.qrc
+++ b/libsrc/leddevice/LedDeviceSchemas.qrc
@@ -11,7 +11,6 @@
schemas/schema-lightpack.json
schemas/schema-lpd6803.json
schemas/schema-lpd8806.json
- schemas/schema-multilightpack.json
schemas/schema-p9813.json
schemas/schema-paintpack.json
schemas/schema-philipshue.json
@@ -36,5 +35,6 @@
schemas/schema-nanoleaf.json
schemas/schema-wled.json
schemas/schema-yeelight.json
+ schemas/schema-razer.json
diff --git a/libsrc/leddevice/dev_net/LedDeviceRazer.cpp b/libsrc/leddevice/dev_net/LedDeviceRazer.cpp
new file mode 100644
index 00000000..36c10370
--- /dev/null
+++ b/libsrc/leddevice/dev_net/LedDeviceRazer.cpp
@@ -0,0 +1,254 @@
+#include "LedDeviceRazer.h"
+#include
+
+#if _WIN32
+#include
+#endif
+// Constants
+namespace {
+bool verbose = false;
+
+// Configuration settings
+const char CONFIG_ADDRESS[] = "host";
+const char RAZOR_DEVICE_TYPE[] = "razorDevice";
+
+// WLED JSON-API elements
+const char API_DEFAULT_HOST[] = "localhost";
+const int API_DEFAULT_PORT = 54235;
+
+const char API_BASE_PATH[] = "/razer/chromasdk";
+const char API_PATH_INFO[] = "info";
+const char API_PATH_STATE[] = "state";
+
+const char API_RESULT[] = "result";
+
+// List of State Information
+const char STATE_ON[] = "on";
+const char STATE_VALUE_TRUE[] = "true";
+const char STATE_VALUE_FALSE[] = "false";
+} //End of constants
+
+LedDeviceRazer::LedDeviceRazer(const QJsonObject& deviceConfig)
+ : LedDevice()
+ , _restApi(nullptr)
+ , _apiPort(API_DEFAULT_PORT)
+{
+ _devConfig = deviceConfig;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
+}
+
+LedDevice* LedDeviceRazer::construct(const QJsonObject& deviceConfig)
+{
+ return new LedDeviceRazer(deviceConfig);
+}
+
+bool LedDeviceRazer::init(const QJsonObject& deviceConfig)
+{
+ bool isInitOK = false;
+ setRewriteTime(1000);
+ connect(_refreshTimer, &QTimer::timeout, this, &LedDeviceRazer::rewriteLEDs);
+
+ // 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);
+
+ //Razor Chroma SDK allows localhost connection only
+ _hostname = API_DEFAULT_HOST;
+ _apiPort = API_DEFAULT_PORT;
+
+ Debug(_log, "Hostname : %s", QSTRING_CSTR(_hostname));
+ Debug(_log, "Port : %d", _apiPort);
+
+ _razerDeviceType = deviceConfig[RAZOR_DEVICE_TYPE].toString("keyboard");
+
+ Debug(_log, "Razer device : %s", QSTRING_CSTR(_razerDeviceType));
+
+ if (initRestAPI(_hostname, _apiPort))
+ {
+ isInitOK = true;
+ }
+ }
+
+ return isInitOK;
+}
+
+bool LedDeviceRazer::initRestAPI(const QString& hostname, int port)
+{
+ bool isInitOK = false;
+
+ if (_restApi == nullptr)
+ {
+ _restApi = new ProviderRestApi(hostname, port);
+ _restApi->setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ isInitOK = true;
+ }
+
+ return isInitOK;
+}
+
+bool LedDeviceRazer::checkApiError(const httpResponse& response)
+{
+ bool apiError = false;
+
+ if (response.error())
+ {
+ this->setInError(response.getErrorReason());
+ apiError = true;
+ }
+ else
+ {
+ QString errorReason;
+
+ QString strJson(response.getBody().toJson(QJsonDocument::Compact));
+ DebugIf(verbose, _log, "Reply: [%s]", strJson.toUtf8().constData());
+
+ QJsonObject jsonObj = response.getBody().object();
+
+ if (!jsonObj[API_RESULT].isNull())
+ {
+ int resultCode = jsonObj[API_RESULT].toInt();
+
+ if (resultCode != 0)
+ {
+ errorReason = QString("Chroma SDK error (%1)").arg(resultCode);
+ this->setInError(errorReason);
+ apiError = true;
+ }
+ }
+ }
+ return apiError;
+}
+
+int LedDeviceRazer::open()
+{
+ int retval = -1;
+ QString errortext;
+ _isDeviceReady = false;
+
+ // Try to open the LedDevice
+
+ QJsonObject obj;
+
+ obj.insert("title", "Hyperion - Razer Chroma");
+ obj.insert("description", "Hyperion to Razer Chroma interface");
+
+ QJsonObject authorDetails;
+ authorDetails.insert("name", "Hyperion Team");
+ authorDetails.insert("contact", "https://github.com/hyperion-project/hyperion.ng");
+
+ obj.insert("author", authorDetails);
+
+ QJsonArray deviceList = { "keyboard","mouse","headset","mousepad","keypad","chromalink" };
+ obj.insert("device_supported", deviceList);
+
+ obj.insert("category", "application");
+
+ QJsonDocument data = QJsonDocument(obj);
+
+ _restApi->setPort(API_DEFAULT_PORT);
+ _restApi->setBasePath(API_BASE_PATH);
+
+ httpResponse response = _restApi->post(data.toJson(QJsonDocument::Compact));
+ if (!checkApiError(response))
+ {
+ QJsonObject jsonObj = response.getBody().object();
+ if (jsonObj["uri"].isNull())
+ {
+ this->setInError("Chroma SDK error. No 'uri' received");
+ }
+ else
+ {
+ _uri = jsonObj.value("uri").toString();
+ _restApi->setUrl(_uri);
+
+ DebugIf(verbose, _log, "Session-ID: %d, uri [%s]", jsonObj.value("sessionid").toInt(), QSTRING_CSTR(_uri.toString()));
+
+ QJsonObject effectObj;
+ effectObj.insert("effect", "CHROMA_STATIC");
+ QJsonObject param;
+ param.insert("color", 255);
+ effectObj.insert("param", param);
+ data = QJsonDocument(effectObj);
+
+ _restApi->setPath(_razerDeviceType);
+ response = _restApi->put(data.toJson(QJsonDocument::Compact));
+
+ if (!checkApiError(response))
+ {
+ _restApi->setPath(_razerDeviceType);
+ response = _restApi->put(data.toJson(QJsonDocument::Compact));
+
+ if (!checkApiError(response))
+ {
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+int LedDeviceRazer::close()
+{
+ int retval = -1;
+ _isDeviceReady = false;
+
+ if (!_uri.isEmpty())
+ {
+ httpResponse response = _restApi->deleteResource(_uri);
+ if (!checkApiError(response))
+ {
+ // Everything is OK -> device is closed
+ retval = 0;
+ }
+ }
+ return retval;
+}
+
+int LedDeviceRazer::write(const std::vector& ledValues)
+{
+ int retval = -1;
+
+ ColorRgb color = ledValues[0];
+ int colorParam = (color.red * 65536) + (color.green * 256) + color.blue;
+
+ QJsonObject effectObj;
+ effectObj.insert("effect", "CHROMA_STATIC");
+ QJsonObject param;
+ param.insert("color", colorParam);
+ effectObj.insert("param", param);
+ QJsonDocument data = QJsonDocument(effectObj);
+
+ _restApi->setPath(_razerDeviceType);
+ httpResponse response = _restApi->put(data.toJson(QJsonDocument::Compact));
+ if (!checkApiError(response))
+ {
+ retval = 0;
+ }
+ return retval;
+}
+
+int LedDeviceRazer::rewriteLEDs()
+{
+ int retval = -1;
+
+ _restApi->setPath("heartbeat");
+ httpResponse response = _restApi->put();
+ if (!checkApiError(response))
+ {
+ retval = 0;
+ }
+ return retval;
+}
diff --git a/libsrc/leddevice/dev_net/LedDeviceRazer.h b/libsrc/leddevice/dev_net/LedDeviceRazer.h
new file mode 100644
index 00000000..dbbb673a
--- /dev/null
+++ b/libsrc/leddevice/dev_net/LedDeviceRazer.h
@@ -0,0 +1,101 @@
+#ifndef LEDEVICERAZER_H
+#define LEDEVICERAZER_H
+
+// LedDevice includes
+#include
+#include "ProviderRestApi.h"
+
+///
+/// Implementation of a Razer Chroma LedDevice
+/// Supported Razer Chroma device types: Keyboard, Mouse, Headset, Mousepad, Keypad, Chromalink
+///
+class LedDeviceRazer : public LedDevice
+{
+public:
+
+ ///
+ /// @brief Constructs a specific LED-device
+ ///
+ /// @param deviceConfig Device's configuration as JSON-Object
+ ///
+ explicit LedDeviceRazer(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 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.
+ ///
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
+ ///
+ int write(const std::vector& ledValues) override;
+
+protected slots:
+
+ ///
+ /// @brief Write the last data to the LEDs again.
+ ///
+ /// @return Zero on success else negative
+ ///
+ int rewriteLEDs() override;
+
+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);
+
+ ///
+ /// @brief Check, if Chroma SDK API response failed
+ ///
+ /// @param[in] http response, incl. the response by Chroma SDK in JSON-format
+ /// return True, API call failed
+ ///
+ bool checkApiError(const httpResponse& response);
+
+ ///REST-API wrapper
+ ProviderRestApi* _restApi;
+
+ QString _hostname;
+ int _apiPort;
+ QUrl _uri;
+
+ QString _razerDeviceType;
+};
+
+#endif // LEDEVICERAZER_H
diff --git a/libsrc/leddevice/dev_net/ProviderRestApi.cpp b/libsrc/leddevice/dev_net/ProviderRestApi.cpp
index 5ad71e90..2acd27a8 100644
--- a/libsrc/leddevice/dev_net/ProviderRestApi.cpp
+++ b/libsrc/leddevice/dev_net/ProviderRestApi.cpp
@@ -12,26 +12,25 @@
// Constants
namespace {
+bool verbose = false;
+
const QChar ONE_SLASH = '/';
} //End of constants
-ProviderRestApi::ProviderRestApi(const QString &host, int port, const QString &basePath)
+ProviderRestApi::ProviderRestApi(const QString& host, int port, const QString& basePath)
:_log(Logger::getInstance("LEDDEVICE"))
- ,_networkManager(nullptr)
- ,_scheme("http")
- ,_hostname(host)
- ,_port(port)
+ , _networkManager(nullptr)
{
_networkManager = new QNetworkAccessManager();
- _apiUrl.setScheme(_scheme);
+ _apiUrl.setScheme("http");
_apiUrl.setHost(host);
_apiUrl.setPort(port);
_basePath = basePath;
}
-ProviderRestApi::ProviderRestApi(const QString &host, int port)
+ProviderRestApi::ProviderRestApi(const QString& host, int port)
: ProviderRestApi(host, port, "") {}
ProviderRestApi::ProviderRestApi()
@@ -39,46 +38,52 @@ ProviderRestApi::ProviderRestApi()
ProviderRestApi::~ProviderRestApi()
{
- if ( _networkManager != nullptr )
+ if (_networkManager != nullptr)
{
delete _networkManager;
}
}
-void ProviderRestApi::setBasePath(const QString &basePath)
+void ProviderRestApi::setUrl(const QUrl& url)
+{
+ _apiUrl = url;
+ _basePath = url.path();
+}
+
+void ProviderRestApi::setBasePath(const QString& basePath)
{
_basePath.clear();
- appendPath (_basePath, basePath );
+ appendPath(_basePath, basePath);
}
-void ProviderRestApi::setPath ( const QString &path )
+void ProviderRestApi::setPath(const QString& path)
{
_path.clear();
- appendPath (_path, path );
+ appendPath(_path, path);
}
-void ProviderRestApi::appendPath ( const QString &path )
+void ProviderRestApi::appendPath(const QString& path)
{
- appendPath (_path, path );
+ appendPath(_path, path);
}
-void ProviderRestApi::appendPath ( QString& path, const QString &appendPath) const
+void ProviderRestApi::appendPath(QString& path, const QString& appendPath) const
{
- if ( !appendPath.isEmpty() && appendPath != ONE_SLASH )
+ if (!appendPath.isEmpty() && appendPath != ONE_SLASH)
{
- if (path.isEmpty() || path == ONE_SLASH )
+ if (path.isEmpty() || path == ONE_SLASH)
{
path.clear();
- if (appendPath[0] != ONE_SLASH )
+ if (appendPath[0] != ONE_SLASH)
{
path.push_back(ONE_SLASH);
}
}
- else if (path[path.size()-1] == ONE_SLASH && appendPath[0] == ONE_SLASH)
+ else if (path[path.size() - 1] == ONE_SLASH && appendPath[0] == ONE_SLASH)
{
path.chop(1);
}
- else if (path[path.size()-1] != ONE_SLASH && appendPath[0] != ONE_SLASH)
+ else if (path[path.size() - 1] != ONE_SLASH && appendPath[0] != ONE_SLASH)
{
path.push_back(ONE_SLASH);
}
@@ -91,12 +96,12 @@ void ProviderRestApi::appendPath ( QString& path, const QString &appendPath) con
}
}
-void ProviderRestApi::setFragment(const QString &fragment)
+void ProviderRestApi::setFragment(const QString& fragment)
{
_fragment = fragment;
}
-void ProviderRestApi::setQuery(const QUrlQuery &query)
+void ProviderRestApi::setQuery(const QUrlQuery& query)
{
_query = query;
}
@@ -106,22 +111,22 @@ QUrl ProviderRestApi::getUrl() const
QUrl url = _apiUrl;
QString fullPath = _basePath;
- appendPath (fullPath, _path );
+ appendPath(fullPath, _path);
url.setPath(fullPath);
- url.setFragment( _fragment );
- url.setQuery( _query );
+ url.setFragment(_fragment);
+ url.setQuery(_query);
return url;
}
httpResponse ProviderRestApi::get()
{
- return get( getUrl() );
+ return get(getUrl());
}
-httpResponse ProviderRestApi::get(const QUrl &url)
+httpResponse ProviderRestApi::get(const QUrl& url)
{
- Debug(_log, "GET: [%s]", QSTRING_CSTR( url.toString() ));
+ DebugIf(verbose,_log, "GET: [%s]", QSTRING_CSTR(url.toString()));
// Perform request
QNetworkRequest request(url);
@@ -133,9 +138,9 @@ httpResponse ProviderRestApi::get(const QUrl &url)
loop.exec();
httpResponse response;
- if(reply->operation() == QNetworkAccessManager::GetOperation)
+ if (reply->operation() == QNetworkAccessManager::GetOperation)
{
- response = getResponse(reply );
+ response = getResponse(reply);
}
// Free space.
reply->deleteLater();
@@ -143,16 +148,18 @@ httpResponse ProviderRestApi::get(const QUrl &url)
return response;
}
-httpResponse ProviderRestApi::put(const QString &body)
+httpResponse ProviderRestApi::put(const QString& body)
{
- return put( getUrl(), body );
+ return put(getUrl(), body);
}
-httpResponse ProviderRestApi::put(const QUrl &url, const QString &body)
+httpResponse ProviderRestApi::put(const QUrl& url, const QString& body)
{
- Debug(_log, "PUT: [%s] [%s]", QSTRING_CSTR( url.toString() ), QSTRING_CSTR( body ) );
+ DebugIf(verbose, _log, "PUT: [%s] [%s]", QSTRING_CSTR(url.toString()), QSTRING_CSTR(body));
// Perform request
- QNetworkRequest request(url);
+ QNetworkRequest request(_networkRequestHeaders);
+ request.setUrl(url);
+
QNetworkReply* reply = _networkManager->put(request, body.toUtf8());
// Connect requestFinished signal to quit slot of the loop.
QEventLoop loop;
@@ -161,7 +168,7 @@ httpResponse ProviderRestApi::put(const QUrl &url, const QString &body)
loop.exec();
httpResponse response;
- if(reply->operation() == QNetworkAccessManager::PutOperation)
+ if (reply->operation() == QNetworkAccessManager::PutOperation)
{
response = getResponse(reply);
}
@@ -172,23 +179,80 @@ httpResponse ProviderRestApi::put(const QUrl &url, const QString &body)
return response;
}
-httpResponse ProviderRestApi::getResponse(QNetworkReply* const &reply)
+httpResponse ProviderRestApi::post(const QString& body)
+{
+ return post(getUrl(), body);
+}
+
+httpResponse ProviderRestApi::post(const QUrl& url, const QString& body)
+{
+ DebugIf(verbose, _log, "POST: [%s] [%s]", QSTRING_CSTR(url.toString()), QSTRING_CSTR(body));
+ // Perform request
+ QNetworkRequest request(_networkRequestHeaders);
+ request.setUrl(url);
+
+ QNetworkReply* reply = _networkManager->post(request, body.toUtf8());
+ // Connect requestFinished signal to quit slot of the loop.
+ QEventLoop loop;
+ loop.connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
+ // Go into the loop until the request is finished.
+ loop.exec();
+
+ httpResponse response;
+ if (reply->operation() == QNetworkAccessManager::PostOperation)
+ {
+ response = getResponse(reply);
+ }
+ // Free space.
+ reply->deleteLater();
+
+ // Return response
+ return response;
+}
+
+httpResponse ProviderRestApi::deleteResource(const QUrl& url)
+{
+ DebugIf(verbose, _log, "DELETE: [%s]", QSTRING_CSTR(url.toString()));
+ // Perform request
+ QNetworkRequest request(_networkRequestHeaders);
+ request.setUrl(url);
+
+ QNetworkReply* reply = _networkManager->deleteResource(request);
+ // Connect requestFinished signal to quit slot of the loop.
+ QEventLoop loop;
+ loop.connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
+ // Go into the loop until the request is finished.
+ loop.exec();
+
+ httpResponse response;
+ if (reply->operation() == QNetworkAccessManager::DeleteOperation)
+ {
+ response = getResponse(reply);
+ }
+ // Free space.
+ reply->deleteLater();
+
+ // Return response
+ return response;
+}
+
+httpResponse ProviderRestApi::getResponse(QNetworkReply* const& reply)
{
httpResponse response;
- int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
+ int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
response.setHttpStatusCode(httpStatusCode);
- Debug(_log, "Reply.httpStatusCode [%d]", httpStatusCode );
+ DebugIf(verbose, _log, "Reply.error [%d], Reply.httpStatusCode [%d]", reply->error(), httpStatusCode);
response.setNetworkReplyError(reply->error());
- if(reply->error() == QNetworkReply::NoError)
+ if (reply->error() == QNetworkReply::NoError)
{
- if ( httpStatusCode != 204 ){
+ if (httpStatusCode != 204) {
QByteArray replyData = reply->readAll();
- if ( !replyData.isEmpty())
+ if (!replyData.isEmpty())
{
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(replyData, &error);
@@ -202,23 +266,23 @@ httpResponse ProviderRestApi::getResponse(QNetworkReply* const &reply)
}
else
{
- //std::cout << "Response: [" << QString (jsonDoc.toJson(QJsonDocument::Compact)).toStdString() << "]" << std::endl;
- response.setBody( jsonDoc );
+ //std::cout << "Response: [" << QString(jsonDoc.toJson(QJsonDocument::Compact)).toStdString() << "]" << std::endl;
+ response.setBody(jsonDoc);
}
}
else
{ // Create valid body which is empty
- response.setBody( QJsonDocument() );
+ response.setBody(QJsonDocument());
}
}
}
else
{
QString errorReason;
- if ( httpStatusCode > 0 ) {
- QString httpReason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
+ if (httpStatusCode > 0) {
+ QString httpReason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
QString advise;
- switch ( httpStatusCode ) {
+ switch (httpStatusCode) {
case 400:
advise = "Check Request Body";
break;
@@ -231,7 +295,7 @@ httpResponse ProviderRestApi::getResponse(QNetworkReply* const &reply)
default:
break;
}
- errorReason = QString ("[%3 %4] - %5").arg(QString(httpStatusCode) , httpReason, advise);
+ errorReason = QString("[%3 %4] - %5").arg(QString(httpStatusCode), httpReason, advise);
}
else {
errorReason = reply->errorString();
@@ -240,8 +304,23 @@ httpResponse ProviderRestApi::getResponse(QNetworkReply* const &reply)
response.setErrorReason(errorReason);
// Create valid body which is empty
- response.setBody( QJsonDocument() );
+ response.setBody(QJsonDocument());
}
return response;
}
+void ProviderRestApi::setHeader(QNetworkRequest::KnownHeaders header, const QVariant& value)
+{
+ QVariant headerValue = _networkRequestHeaders.header(header);
+ if (headerValue.isNull())
+ {
+ _networkRequestHeaders.setHeader(header, value);
+ }
+ else
+ {
+ if (!headerValue.toString().contains(value.toString()))
+ {
+ _networkRequestHeaders.setHeader(header, headerValue.toString() + "," + value.toString());
+ }
+ }
+}
diff --git a/libsrc/leddevice/dev_net/ProviderRestApi.h b/libsrc/leddevice/dev_net/ProviderRestApi.h
index 5a66bb20..5ab5500e 100644
--- a/libsrc/leddevice/dev_net/ProviderRestApi.h
+++ b/libsrc/leddevice/dev_net/ProviderRestApi.h
@@ -18,20 +18,20 @@ class httpResponse
public:
httpResponse() = default;
- bool error() const { return _hasError;}
+ bool error() const { return _hasError; }
void setError(const bool hasError) { _hasError = hasError; }
QJsonDocument getBody() const { return _responseBody; }
- void setBody(const QJsonDocument &body) { _responseBody = body; }
+ void setBody(const QJsonDocument& body) { _responseBody = body; }
QString getErrorReason() const { return _errorReason; }
- void setErrorReason(const QString &errorReason) { _errorReason = errorReason; }
+ void setErrorReason(const QString& errorReason) { _errorReason = errorReason; }
int getHttpStatusCode() const { return _httpStatusCode; }
void setHttpStatusCode(int httpStatusCode) { _httpStatusCode = httpStatusCode; }
QNetworkReply::NetworkError getNetworkReplyError() const { return _networkReplyError; }
- void setNetworkReplyError (const QNetworkReply::NetworkError networkReplyError) { _networkReplyError = networkReplyError; }
+ void setNetworkReplyError(const QNetworkReply::NetworkError networkReplyError) { _networkReplyError = networkReplyError; }
private:
@@ -77,7 +77,7 @@ public:
/// @param[in] host
/// @param[in] port
///
- explicit ProviderRestApi(const QString &host, int port);
+ explicit ProviderRestApi(const QString& host, int port);
///
/// @brief Constructor of the REST-API wrapper
@@ -86,13 +86,34 @@ public:
/// @param[in] port
/// @param[in] API base-path
///
- explicit ProviderRestApi(const QString &host, int port, const QString &basePath);
+ explicit ProviderRestApi(const QString& host, int port, const QString& basePath);
///
/// @brief Destructor of the REST-API wrapper
///
virtual ~ProviderRestApi();
+ ///
+ /// @brief Set an API's host
+ ///
+ /// @param[in] host
+ ///
+ void setHost(const QString& host) { _apiUrl.setHost(host); };
+
+ ///
+ /// @brief Set an API's port
+ ///
+ /// @param[in] port
+ ///
+ void setPort(const int port) { _apiUrl.setPort(port); };
+
+ ///
+ /// @brief Set an API's url
+ ///
+ /// @param[in] url, e.g. "http://locahost:60351/chromalink/"
+ ///
+ void setUrl(const QUrl& url);
+
///
/// @brief Get the URL as defined using scheme, host, port, API-basepath, path, query, fragment
///
@@ -105,35 +126,35 @@ public:
///
/// @param[in] basePath, e.g. "/api/v1/" or "/json"
///
- void setBasePath(const QString &basePath);
+ void setBasePath(const QString& basePath);
///
/// @brief Set an API's path to address resources
///
/// @param[in] path, e.g. "/lights/1/state/"
///
- void setPath ( const QString &path );
+ void setPath(const QString& path);
///
/// @brief Append an API's path element to path set before
///
/// @param[in] path
///
- void appendPath (const QString &appendPath);
+ void appendPath(const QString& appendPath);
///
/// @brief Set an API's fragment
///
/// @param[in] fragment, e.g. "question3"
///
- void setFragment(const QString&fragment);
+ void setFragment(const QString& fragment);
///
/// @brief Set an API's query string
///
/// @param[in] query, e.g. "&A=128&FX=0"
///
- void setQuery(const QUrlQuery &query);
+ void setQuery(const QUrlQuery& query);
///
/// @brief Execute GET request
@@ -148,7 +169,7 @@ public:
/// @param[in] url GET request for URL
/// @return Response The body of the response in JSON
///
- httpResponse get(const QUrl &url);
+ httpResponse get(const QUrl& url);
///
/// @brief Execute PUT request
@@ -156,7 +177,7 @@ public:
/// @param[in] body The body of the request in JSON
/// @return Response The body of the response in JSON
///
- httpResponse put(const QString &body = "");
+ httpResponse put(const QString& body = "");
///
/// @brief Execute PUT request
@@ -165,7 +186,7 @@ public:
/// @param[in] body The body of the request in JSON
/// @return Response The body of the response in JSON
///
- httpResponse put(const QUrl &url, const QString &body = "");
+ httpResponse put(const QUrl& url, const QString& body = "");
///
/// @brief Execute POST request
@@ -173,7 +194,24 @@ public:
/// @param[in] body The body of the request in JSON
/// @return Response The body of the response in JSON
///
- httpResponse post(QString body = "");
+ httpResponse post(const QString& body = "");
+
+ ///
+ /// @brief Execute POST request
+ ///
+ /// @param[in] URL for POST request
+ /// @param[in] body The body of the request in JSON
+ /// @return Response The body of the response in JSON
+ ///
+ httpResponse post(const QUrl& url, const QString& body = "");
+
+ ///
+ /// @brief Execute DELETE request
+ ///
+ /// @param[in] URL (Resource) for DELETE request
+ /// @return Response The body of the response in JSON
+ ///
+ httpResponse deleteResource(const QUrl& url);
///
/// @brief Handle responses for REST requests
@@ -181,7 +219,21 @@ public:
/// @param[in] reply Network reply
/// @return Response The body of the response in JSON
///
- httpResponse getResponse(QNetworkReply* const &reply);
+ httpResponse getResponse(QNetworkReply* const& reply);
+
+ ///
+ /// Adds a header field.
+ ///
+ /// @param[in] The type of the header field.
+ /// @param[in] The value of the header field.
+ /// If the header field exists, the value will be combined as comma separated string.
+
+ void setHeader(QNetworkRequest::KnownHeaders header, const QVariant& value);
+
+ ///
+ /// Remove all header fields.
+ ///
+ void removeAllHeaders() { _networkRequestHeaders = QNetworkRequest(); };
private:
@@ -191,7 +243,7 @@ private:
/// @param[in/out] path to be updated
/// @param[in] path, element to be appended
///
- void appendPath (QString &path, const QString &appendPath) const;
+ void appendPath(QString& path, const QString& appendPath) const;
Logger* _log;
@@ -200,16 +252,13 @@ private:
QUrl _apiUrl;
- QString _scheme;
- QString _hostname;
- int _port;
-
QString _basePath;
QString _path;
QString _fragment;
QUrlQuery _query;
+ QNetworkRequest _networkRequestHeaders;
};
#endif // PROVIDERRESTKAPI_H
diff --git a/libsrc/leddevice/schemas/schema-razer.json b/libsrc/leddevice/schemas/schema-razer.json
new file mode 100644
index 00000000..36ce16ea
--- /dev/null
+++ b/libsrc/leddevice/schemas/schema-razer.json
@@ -0,0 +1,28 @@
+{
+ "type": "object",
+ "required": true,
+ "properties": {
+ "razorDevice": {
+ "type": "string",
+ "title": "edt_dev_spec_razor_device_title",
+ "enum": [ "keyboard", "mouse", "headset", "mousepad", "keypad", "chromalink" ],
+ "default": "keyboard",
+ "options": {
+ "enum_titles": [ "Keyboard", "Mouse", "Headset", "Mousepad", "Keypad", "Chromalink" ]
+ },
+ "propertyOrder": 1
+ },
+ "latchTime": {
+ "type": "integer",
+ "title": "edt_dev_spec_latchtime_title",
+ "default": 0,
+ "append": "edt_append_ms",
+ "minimum": 0,
+ "maximum": 1000,
+ "access": "expert",
+ "propertyOrder": 2
+ }
+ },
+ "additionalProperties": true
+}
+