Razor Chroma Support - Initial version

This commit is contained in:
LordGrey 2020-10-16 00:03:49 +02:00
parent 9d2e442d42
commit 8476553448
9 changed files with 588 additions and 76 deletions

View File

@ -492,6 +492,7 @@
"edt_dev_spec_printTimeStamp_title": "Add timestamp", "edt_dev_spec_printTimeStamp_title": "Add timestamp",
"edt_dev_spec_pwmChannel_title": "PWM channel", "edt_dev_spec_pwmChannel_title": "PWM channel",
"edt_dev_spec_restoreOriginalState_title": "Restore lights' original state when disabled", "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_serial_title": "Serial number",
"edt_dev_spec_spipath_title": "SPI path", "edt_dev_spec_spipath_title": "SPI path",
"edt_dev_spec_sslHSTimeoutMax_title": "Streamer handshake timeout maximum", "edt_dev_spec_sslHSTimeoutMax_title": "Streamer handshake timeout maximum",

View File

@ -571,8 +571,8 @@ $(document).ready(function() {
var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'sk9822', 'ws2812spi']; var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'sk9822', 'ws2812spi'];
var devRPiPWM = ['ws281x']; var devRPiPWM = ['ws281x'];
var devRPiGPIO = ['piblaster']; var devRPiGPIO = ['piblaster'];
var devNET = ['atmoorb', 'fadecandy', 'philipshue', 'nanoleaf', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw', 'wled', 'yeelight']; var devNET = ['atmoorb', 'fadecandy', 'philipshue', 'nanoleaf', 'razer', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw', 'wled', 'yeelight'];
var devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'multilightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2', 'karate']; var devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2', 'karate'];
var optArr = [[]]; var optArr = [[]];
optArr[1]=[]; optArr[1]=[];

View File

@ -414,14 +414,14 @@ protected slots:
/// ///
/// @return Zero on success else negative /// @return Zero on success else negative
/// ///
int rewriteLEDs(); virtual int rewriteLEDs();
/// ///
/// @brief Set device in error state /// @brief Set device in error state
/// ///
/// @param[in] errorMsg The error message to be logged /// @param[in] errorMsg The error message to be logged
/// ///
virtual void setInError( const QString& errorMsg); virtual void setInError( const QString& errorMsg);
private: private:

View File

@ -11,7 +11,6 @@
<file alias="schema-lightpack">schemas/schema-lightpack.json</file> <file alias="schema-lightpack">schemas/schema-lightpack.json</file>
<file alias="schema-lpd6803">schemas/schema-lpd6803.json</file> <file alias="schema-lpd6803">schemas/schema-lpd6803.json</file>
<file alias="schema-lpd8806">schemas/schema-lpd8806.json</file> <file alias="schema-lpd8806">schemas/schema-lpd8806.json</file>
<file alias="schema-multilightpack">schemas/schema-multilightpack.json</file>
<file alias="schema-p9813">schemas/schema-p9813.json</file> <file alias="schema-p9813">schemas/schema-p9813.json</file>
<file alias="schema-paintpack">schemas/schema-paintpack.json</file> <file alias="schema-paintpack">schemas/schema-paintpack.json</file>
<file alias="schema-philipshue">schemas/schema-philipshue.json</file> <file alias="schema-philipshue">schemas/schema-philipshue.json</file>
@ -36,5 +35,6 @@
<file alias="schema-nanoleaf">schemas/schema-nanoleaf.json</file> <file alias="schema-nanoleaf">schemas/schema-nanoleaf.json</file>
<file alias="schema-wled">schemas/schema-wled.json</file> <file alias="schema-wled">schemas/schema-wled.json</file>
<file alias="schema-yeelight">schemas/schema-yeelight.json</file> <file alias="schema-yeelight">schemas/schema-yeelight.json</file>
<file alias="schema-razer">schemas/schema-razer.json</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -0,0 +1,254 @@
#include "LedDeviceRazer.h"
#include <utils/QStringUtils.h>
#if _WIN32
#include <windows.h>
#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<ColorRgb>& 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;
}

View File

@ -0,0 +1,101 @@
#ifndef LEDEVICERAZER_H
#define LEDEVICERAZER_H
// LedDevice includes
#include <leddevice/LedDevice.h>
#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<ColorRgb>& 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

View File

@ -12,26 +12,25 @@
// Constants // Constants
namespace { namespace {
bool verbose = false;
const QChar ONE_SLASH = '/'; const QChar ONE_SLASH = '/';
} //End of constants } //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")) :_log(Logger::getInstance("LEDDEVICE"))
,_networkManager(nullptr) , _networkManager(nullptr)
,_scheme("http")
,_hostname(host)
,_port(port)
{ {
_networkManager = new QNetworkAccessManager(); _networkManager = new QNetworkAccessManager();
_apiUrl.setScheme(_scheme); _apiUrl.setScheme("http");
_apiUrl.setHost(host); _apiUrl.setHost(host);
_apiUrl.setPort(port); _apiUrl.setPort(port);
_basePath = basePath; _basePath = basePath;
} }
ProviderRestApi::ProviderRestApi(const QString &host, int port) ProviderRestApi::ProviderRestApi(const QString& host, int port)
: ProviderRestApi(host, port, "") {} : ProviderRestApi(host, port, "") {}
ProviderRestApi::ProviderRestApi() ProviderRestApi::ProviderRestApi()
@ -39,46 +38,52 @@ ProviderRestApi::ProviderRestApi()
ProviderRestApi::~ProviderRestApi() ProviderRestApi::~ProviderRestApi()
{ {
if ( _networkManager != nullptr ) if (_networkManager != nullptr)
{ {
delete _networkManager; 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(); _basePath.clear();
appendPath (_basePath, basePath ); appendPath(_basePath, basePath);
} }
void ProviderRestApi::setPath ( const QString &path ) void ProviderRestApi::setPath(const QString& path)
{ {
_path.clear(); _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(); path.clear();
if (appendPath[0] != ONE_SLASH ) if (appendPath[0] != ONE_SLASH)
{ {
path.push_back(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); 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); 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; _fragment = fragment;
} }
void ProviderRestApi::setQuery(const QUrlQuery &query) void ProviderRestApi::setQuery(const QUrlQuery& query)
{ {
_query = query; _query = query;
} }
@ -106,22 +111,22 @@ QUrl ProviderRestApi::getUrl() const
QUrl url = _apiUrl; QUrl url = _apiUrl;
QString fullPath = _basePath; QString fullPath = _basePath;
appendPath (fullPath, _path ); appendPath(fullPath, _path);
url.setPath(fullPath); url.setPath(fullPath);
url.setFragment( _fragment ); url.setFragment(_fragment);
url.setQuery( _query ); url.setQuery(_query);
return url; return url;
} }
httpResponse ProviderRestApi::get() 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 // Perform request
QNetworkRequest request(url); QNetworkRequest request(url);
@ -133,9 +138,9 @@ httpResponse ProviderRestApi::get(const QUrl &url)
loop.exec(); loop.exec();
httpResponse response; httpResponse response;
if(reply->operation() == QNetworkAccessManager::GetOperation) if (reply->operation() == QNetworkAccessManager::GetOperation)
{ {
response = getResponse(reply ); response = getResponse(reply);
} }
// Free space. // Free space.
reply->deleteLater(); reply->deleteLater();
@ -143,16 +148,18 @@ httpResponse ProviderRestApi::get(const QUrl &url)
return response; 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 // Perform request
QNetworkRequest request(url); QNetworkRequest request(_networkRequestHeaders);
request.setUrl(url);
QNetworkReply* reply = _networkManager->put(request, body.toUtf8()); QNetworkReply* reply = _networkManager->put(request, body.toUtf8());
// Connect requestFinished signal to quit slot of the loop. // Connect requestFinished signal to quit slot of the loop.
QEventLoop loop; QEventLoop loop;
@ -161,7 +168,7 @@ httpResponse ProviderRestApi::put(const QUrl &url, const QString &body)
loop.exec(); loop.exec();
httpResponse response; httpResponse response;
if(reply->operation() == QNetworkAccessManager::PutOperation) if (reply->operation() == QNetworkAccessManager::PutOperation)
{ {
response = getResponse(reply); response = getResponse(reply);
} }
@ -172,23 +179,80 @@ httpResponse ProviderRestApi::put(const QUrl &url, const QString &body)
return response; 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; httpResponse response;
int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt(); int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
response.setHttpStatusCode(httpStatusCode); 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()); response.setNetworkReplyError(reply->error());
if(reply->error() == QNetworkReply::NoError) if (reply->error() == QNetworkReply::NoError)
{ {
if ( httpStatusCode != 204 ){ if (httpStatusCode != 204) {
QByteArray replyData = reply->readAll(); QByteArray replyData = reply->readAll();
if ( !replyData.isEmpty()) if (!replyData.isEmpty())
{ {
QJsonParseError error; QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(replyData, &error); QJsonDocument jsonDoc = QJsonDocument::fromJson(replyData, &error);
@ -202,23 +266,23 @@ httpResponse ProviderRestApi::getResponse(QNetworkReply* const &reply)
} }
else else
{ {
//std::cout << "Response: [" << QString (jsonDoc.toJson(QJsonDocument::Compact)).toStdString() << "]" << std::endl; //std::cout << "Response: [" << QString(jsonDoc.toJson(QJsonDocument::Compact)).toStdString() << "]" << std::endl;
response.setBody( jsonDoc ); response.setBody(jsonDoc);
} }
} }
else else
{ // Create valid body which is empty { // Create valid body which is empty
response.setBody( QJsonDocument() ); response.setBody(QJsonDocument());
} }
} }
} }
else else
{ {
QString errorReason; QString errorReason;
if ( httpStatusCode > 0 ) { if (httpStatusCode > 0) {
QString httpReason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString(); QString httpReason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
QString advise; QString advise;
switch ( httpStatusCode ) { switch (httpStatusCode) {
case 400: case 400:
advise = "Check Request Body"; advise = "Check Request Body";
break; break;
@ -231,7 +295,7 @@ httpResponse ProviderRestApi::getResponse(QNetworkReply* const &reply)
default: default:
break; break;
} }
errorReason = QString ("[%3 %4] - %5").arg(QString(httpStatusCode) , httpReason, advise); errorReason = QString("[%3 %4] - %5").arg(QString(httpStatusCode), httpReason, advise);
} }
else { else {
errorReason = reply->errorString(); errorReason = reply->errorString();
@ -240,8 +304,23 @@ httpResponse ProviderRestApi::getResponse(QNetworkReply* const &reply)
response.setErrorReason(errorReason); response.setErrorReason(errorReason);
// Create valid body which is empty // Create valid body which is empty
response.setBody( QJsonDocument() ); response.setBody(QJsonDocument());
} }
return response; 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());
}
}
}

View File

@ -18,20 +18,20 @@ class httpResponse
public: public:
httpResponse() = default; httpResponse() = default;
bool error() const { return _hasError;} bool error() const { return _hasError; }
void setError(const bool hasError) { _hasError = hasError; } void setError(const bool hasError) { _hasError = hasError; }
QJsonDocument getBody() const { return _responseBody; } QJsonDocument getBody() const { return _responseBody; }
void setBody(const QJsonDocument &body) { _responseBody = body; } void setBody(const QJsonDocument& body) { _responseBody = body; }
QString getErrorReason() const { return _errorReason; } QString getErrorReason() const { return _errorReason; }
void setErrorReason(const QString &errorReason) { _errorReason = errorReason; } void setErrorReason(const QString& errorReason) { _errorReason = errorReason; }
int getHttpStatusCode() const { return _httpStatusCode; } int getHttpStatusCode() const { return _httpStatusCode; }
void setHttpStatusCode(int httpStatusCode) { _httpStatusCode = httpStatusCode; } void setHttpStatusCode(int httpStatusCode) { _httpStatusCode = httpStatusCode; }
QNetworkReply::NetworkError getNetworkReplyError() const { return _networkReplyError; } QNetworkReply::NetworkError getNetworkReplyError() const { return _networkReplyError; }
void setNetworkReplyError (const QNetworkReply::NetworkError networkReplyError) { _networkReplyError = networkReplyError; } void setNetworkReplyError(const QNetworkReply::NetworkError networkReplyError) { _networkReplyError = networkReplyError; }
private: private:
@ -77,7 +77,7 @@ public:
/// @param[in] host /// @param[in] host
/// @param[in] port /// @param[in] port
/// ///
explicit ProviderRestApi(const QString &host, int port); explicit ProviderRestApi(const QString& host, int port);
/// ///
/// @brief Constructor of the REST-API wrapper /// @brief Constructor of the REST-API wrapper
@ -86,13 +86,34 @@ public:
/// @param[in] port /// @param[in] port
/// @param[in] API base-path /// @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 /// @brief Destructor of the REST-API wrapper
/// ///
virtual ~ProviderRestApi(); 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 /// @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" /// @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 /// @brief Set an API's path to address resources
/// ///
/// @param[in] path, e.g. "/lights/1/state/" /// @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 /// @brief Append an API's path element to path set before
/// ///
/// @param[in] path /// @param[in] path
/// ///
void appendPath (const QString &appendPath); void appendPath(const QString& appendPath);
/// ///
/// @brief Set an API's fragment /// @brief Set an API's fragment
/// ///
/// @param[in] fragment, e.g. "question3" /// @param[in] fragment, e.g. "question3"
/// ///
void setFragment(const QString&fragment); void setFragment(const QString& fragment);
/// ///
/// @brief Set an API's query string /// @brief Set an API's query string
/// ///
/// @param[in] query, e.g. "&A=128&FX=0" /// @param[in] query, e.g. "&A=128&FX=0"
/// ///
void setQuery(const QUrlQuery &query); void setQuery(const QUrlQuery& query);
/// ///
/// @brief Execute GET request /// @brief Execute GET request
@ -148,7 +169,7 @@ public:
/// @param[in] url GET request for URL /// @param[in] url GET request for URL
/// @return Response The body of the response in JSON /// @return Response The body of the response in JSON
/// ///
httpResponse get(const QUrl &url); httpResponse get(const QUrl& url);
/// ///
/// @brief Execute PUT request /// @brief Execute PUT request
@ -156,7 +177,7 @@ public:
/// @param[in] body The body of the request in JSON /// @param[in] body The body of the request in JSON
/// @return Response The body of the response 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 /// @brief Execute PUT request
@ -165,7 +186,7 @@ public:
/// @param[in] body The body of the request in JSON /// @param[in] body The body of the request in JSON
/// @return Response The body of the response 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 /// @brief Execute POST request
@ -173,7 +194,24 @@ public:
/// @param[in] body The body of the request in JSON /// @param[in] body The body of the request in JSON
/// @return Response The body of the response 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 /// @brief Handle responses for REST requests
@ -181,7 +219,21 @@ public:
/// @param[in] reply Network reply /// @param[in] reply Network reply
/// @return Response The body of the response in JSON /// @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: private:
@ -191,7 +243,7 @@ private:
/// @param[in/out] path to be updated /// @param[in/out] path to be updated
/// @param[in] path, element to be appended /// @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; Logger* _log;
@ -200,16 +252,13 @@ private:
QUrl _apiUrl; QUrl _apiUrl;
QString _scheme;
QString _hostname;
int _port;
QString _basePath; QString _basePath;
QString _path; QString _path;
QString _fragment; QString _fragment;
QUrlQuery _query; QUrlQuery _query;
QNetworkRequest _networkRequestHeaders;
}; };
#endif // PROVIDERRESTKAPI_H #endif // PROVIDERRESTKAPI_H

View File

@ -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
}