diff --git a/httpcommander/devicepluginhttpcommander.cpp b/httpcommander/devicepluginhttpcommander.cpp index 9d52ff91..13d4c211 100644 --- a/httpcommander/devicepluginhttpcommander.cpp +++ b/httpcommander/devicepluginhttpcommander.cpp @@ -1,6 +1,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2017 Bernhard Trinnes * + * Copyright (C) 2018 Simon Stürz * * * * This file is part of guh. * * * @@ -19,6 +20,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "devicepluginhttpcommander.h" +#include "network/networkaccessmanager.h" #include "plugininfo.h" @@ -26,18 +28,49 @@ DevicePluginHttpCommander::DevicePluginHttpCommander() { } -DeviceManager::HardwareResources DevicePluginHttpCommander::requiredHardware() const +DevicePluginHttpCommander::~DevicePluginHttpCommander() { - return DeviceManager::HardwareResourceNetworkManager | DeviceManager::HardwareResourceTimer; + hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer); } +void DevicePluginHttpCommander::init() +{ + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); + connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginHttpCommander::onPluginTimer); +} DeviceManager::DeviceSetupStatus DevicePluginHttpCommander::setupDevice(Device *device) { - if ((device->deviceClassId() == httpGetDeviceClassId) || (device->deviceClassId() == httpPostDeviceClassId) || (device->deviceClassId() == httpPutDeviceClassId)) { - QUrl url = device->paramValue(urlParamTypeId).toUrl(); + qDebug(dcHttpCommander()) << "Setup device" << device->name() << device->params(); + + // Get + if (device->deviceClassId() == httpGetCommanderDeviceClassId) { + QUrl url = device->paramValue(httpGetCommanderUrlParamTypeId).toUrl(); if (!url.isValid()) { qDebug(dcHttpCommander()) << "Given URL is not valid"; + return DeviceManager::DeviceSetupStatusFailure; + } + + return DeviceManager::DeviceSetupStatusSuccess; + } + + // Put + if (device->deviceClassId() == httpPutCommanderDeviceClassId) { + QUrl url = device->paramValue(httpPutCommanderUrlParamTypeId).toUrl(); + if (!url.isValid()) { + qDebug(dcHttpCommander()) << "Given URL is not valid"; + return DeviceManager::DeviceSetupStatusFailure; + } + + return DeviceManager::DeviceSetupStatusSuccess; + } + + // Post + if (device->deviceClassId() == httpPostCommanderDeviceClassId) { + QUrl url = device->paramValue(httpPostCommanderUrlParamTypeId).toUrl(); + if (!url.isValid()) { + qDebug(dcHttpCommander()) << "Given URL is not valid"; + return DeviceManager::DeviceSetupStatusFailure; } return DeviceManager::DeviceSetupStatusSuccess; @@ -49,33 +82,34 @@ DeviceManager::DeviceSetupStatus DevicePluginHttpCommander::setupDevice(Device * void DevicePluginHttpCommander::postSetupDevice(Device *device) { - if (device->deviceClassId() == httpGetDeviceClassId) { - QUrl url = device->paramValue(urlParamTypeId).toUrl(); - url.setPort(device->paramValue(portParamTypeId).toInt()); - QNetworkRequest request; - request.setUrl(url); - request.setRawHeader("User-Agent", "guhIO 1.0"); - QNetworkReply *reply = networkManagerGet(request);; - m_httpRequests.insert(reply, device); + if (device->deviceClassId() == httpGetCommanderDeviceClassId) { + makeGetCall(device); } - if ((device->deviceClassId() == httpPostDeviceClassId) || (device->deviceClassId() == httpPutDeviceClassId)) { + + if (device->deviceClassId() == httpPostCommanderDeviceClassId) { //TODO find a way to check it the URL is reachable - device->setStateValue(reachableStateTypeId, true); + device->setStateValue(httpPostCommanderConnectedStateTypeId, true); + } + + if (device->deviceClassId() == httpPutCommanderDeviceClassId) { + //TODO find a way to check it the URL is reachable + device->setStateValue(httpPutCommanderConnectedStateTypeId, true); } } DeviceManager::DeviceError DevicePluginHttpCommander::executeAction(Device *device, const Action &action) { - if (device->deviceClassId() == httpPostDeviceClassId) { + if (device->deviceClassId() == httpPostCommanderDeviceClassId) { - // check if this is the "press" action - if (action.actionTypeId() == postActionTypeId) { + if (action.actionTypeId() == httpPostCommanderPostActionTypeId) { + QUrl url = device->paramValue(httpPostCommanderUrlParamTypeId).toUrl(); + url.setPort(device->paramValue(httpPostCommanderPortParamTypeId).toInt()); + QByteArray payload = action.param(httpPostCommanderDataParamTypeId).value().toByteArray(); + + QNetworkReply *reply = hardwareManager()->networkManager()->post(QNetworkRequest(url), payload); + connect(reply, &QNetworkReply::finished, this, &DevicePluginHttpCommander::onPostRequestFinished); - QUrl url = device->paramValue(urlParamTypeId).toUrl(); - url.setPort(device->paramValue(portParamTypeId).toInt()); - QByteArray payload = action.param(postDataParamTypeId).value().toByteArray(); - QNetworkReply *reply = networkManagerPost(QNetworkRequest(url), payload); m_httpRequests.insert(reply, device); return DeviceManager::DeviceErrorNoError; @@ -83,15 +117,18 @@ DeviceManager::DeviceError DevicePluginHttpCommander::executeAction(Device *devi return DeviceManager::DeviceErrorActionTypeNotFound; } - if (device->deviceClassId() == httpPutDeviceClassId) { + + if (device->deviceClassId() == httpPutCommanderDeviceClassId) { // check if this is the "press" action - if (action.actionTypeId() == putActionTypeId) { + if (action.actionTypeId() == httpPutCommanderPutActionTypeId) { + + QUrl url = device->paramValue(httpPutCommanderUrlParamTypeId).toUrl(); + url.setPort(device->paramValue(httpPutCommanderPortParamTypeId).toInt()); + QByteArray payload = action.param(httpPutCommanderDataParamTypeId).value().toByteArray(); + QNetworkReply *reply = hardwareManager()->networkManager()->put(QNetworkRequest(url), payload); + connect(reply, &QNetworkReply::finished, this, &DevicePluginHttpCommander::onPutRequestFinished); - QUrl url = device->paramValue(urlParamTypeId).toUrl(); - url.setPort(device->paramValue(portParamTypeId).toInt()); - QByteArray payload = action.param(putDataParamTypeId).value().toByteArray(); - QNetworkReply *reply = networkManagerPut(QNetworkRequest(url), payload); m_httpRequests.insert(reply, device); return DeviceManager::DeviceErrorNoError; @@ -100,63 +137,117 @@ DeviceManager::DeviceError DevicePluginHttpCommander::executeAction(Device *devi return DeviceManager::DeviceErrorDeviceClassNotFound; } - -void DevicePluginHttpCommander::deviceRemoved(Device *device) +void DevicePluginHttpCommander::makeGetCall(Device *device) { - Q_UNUSED(device); + QUrl url = device->paramValue(httpGetCommanderUrlParamTypeId).toUrl(); + url.setPort(device->paramValue(httpGetCommanderPortParamTypeId).toInt()); + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("User-Agent", "guhIO 1.0"); + + QNetworkReply *reply = hardwareManager()->networkManager()->get(request); + connect(reply, &QNetworkReply::finished, this, &DevicePluginHttpCommander::onGetRequestFinished); + + m_httpRequests.insert(reply, device); } - -void DevicePluginHttpCommander::guhTimer() +void DevicePluginHttpCommander::onPluginTimer() { - foreach (Device *device, myDevices()) { - - if (device->deviceClassId() == httpGetDeviceClassId) { - QUrl url = device->paramValue(urlParamTypeId).toUrl(); - url.setPort(device->paramValue(portParamTypeId).toInt()); - QNetworkRequest request; - request.setUrl(url); - request.setRawHeader("User-Agent", "guhIO 1.0"); - QNetworkReply *reply = networkManagerGet(request);; - m_httpRequests.insert(reply, device); + if (device->deviceClassId() == httpGetCommanderDeviceClassId) { + makeGetCall(device); } } - } - -void DevicePluginHttpCommander::networkManagerReplyReady(QNetworkReply *reply) +void DevicePluginHttpCommander::onGetRequestFinished() { + QNetworkReply *reply = static_cast(sender()); + qDebug(dcHttpCommander()) << "GET reply finished"; QByteArray data = reply->readAll(); - qDebug(dcHttpCommander()) << "Reply received"; int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (m_httpRequests.contains(reply)) { - Device *device = m_httpRequests.take(reply); - - if (device->deviceClassId() == httpGetDeviceClassId) { - device->setStateValue(getDataStateTypeId, data); - // check HTTP status code - if (status != 200 || reply->error() != QNetworkReply::NoError) { - qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString(); - device->setStateValue(reachableStateTypeId, false); - reply->deleteLater(); - return; - } - device->setStateValue(reachableStateTypeId, true); - } else if ((device->deviceClassId() == httpPostDeviceClassId) || (device->deviceClassId() == httpPutDeviceClassId) ) { - device->setStateValue(httpResponseStateTypeId, data); - // check HTTP status code - if (status != 200 || reply->error() != QNetworkReply::NoError) { - qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString(); - device->setStateValue(reachableStateTypeId, false); - reply->deleteLater(); - return; - } - device->setStateValue(reachableStateTypeId, true); - } + if (!m_httpRequests.contains(reply)) { + reply->deleteLater(); + return; } + + Device *device = m_httpRequests.take(reply); + device->setStateValue(httpGetCommanderResponseStateTypeId, data); + + // Check HTTP status code + if (status != 200 || reply->error() != QNetworkReply::NoError) { + qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString(); + device->setStateValue(httpGetCommanderConnectedStateTypeId, false); + reply->deleteLater(); + return; + } + + device->setStateValue(httpGetCommanderConnectedStateTypeId, true); reply->deleteLater(); } +void DevicePluginHttpCommander::onPostRequestFinished() +{ + QNetworkReply *reply = static_cast(sender()); + qDebug(dcHttpCommander()) << "POST reply finished"; + QByteArray data = reply->readAll(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (!m_httpRequests.contains(reply)) { + reply->deleteLater(); + return; + } + + Device *device = m_httpRequests.take(reply); + device->setStateValue(httpPostCommanderResponseStateTypeId, data); + + // Check HTTP status code + if (status != 200 || reply->error() != QNetworkReply::NoError) { + qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString(); + device->setStateValue(httpPostCommanderConnectedStateTypeId, false); + reply->deleteLater(); + return; + } + + device->setStateValue(httpPostCommanderConnectedStateTypeId, true); + reply->deleteLater(); +} + +void DevicePluginHttpCommander::onPutRequestFinished() +{ + QNetworkReply *reply = static_cast(sender()); + qDebug(dcHttpCommander()) << "PUT reply finished"; + QByteArray data = reply->readAll(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (!m_httpRequests.contains(reply)) { + reply->deleteLater(); + return; + } + + Device *device = m_httpRequests.take(reply); + device->setStateValue(httpPutCommanderResponseStateTypeId, data); + + // Check HTTP status code + if (status != 200 || reply->error() != QNetworkReply::NoError) { + qCWarning(dcHttpCommander()) << "Request error:" << status << reply->errorString(); + device->setStateValue(httpPutCommanderConnectedStateTypeId, false); + reply->deleteLater(); + return; + } + + device->setStateValue(httpPutCommanderConnectedStateTypeId, true); + reply->deleteLater(); +} + + +void DevicePluginHttpCommander::deviceRemoved(Device *device) +{ + if (m_httpRequests.values().contains(device)) { + QNetworkReply *reply = m_httpRequests.key(device); + m_httpRequests.remove(reply); + // Note: will be deleted once finished + } +} + diff --git a/httpcommander/devicepluginhttpcommander.h b/httpcommander/devicepluginhttpcommander.h index 1cec6299..4bacfa95 100644 --- a/httpcommander/devicepluginhttpcommander.h +++ b/httpcommander/devicepluginhttpcommander.h @@ -1,6 +1,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2017 Bernhard Trinnes * + * Copyright (C) 2018 Simon Stürz * * * * This file is part of guh. * * * @@ -23,6 +24,9 @@ #include "plugin/deviceplugin.h" #include "devicemanager.h" +#include "plugintimer.h" + +#include class DevicePluginHttpCommander : public DevicePlugin { @@ -33,18 +37,26 @@ class DevicePluginHttpCommander : public DevicePlugin public: explicit DevicePluginHttpCommander(); + ~DevicePluginHttpCommander(); - DeviceManager::HardwareResources requiredHardware() const override; + void init() override; DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; void postSetupDevice(Device *device) override; void deviceRemoved(Device *device) override; - void networkManagerReplyReady(QNetworkReply *reply) override; - void guhTimer() override; - DeviceManager::DeviceError executeAction(Device *device, const Action &action) override; private: + PluginTimer *m_pluginTimer = nullptr; QHash m_httpRequests; + + void makeGetCall(Device *device); + +private slots: + void onPluginTimer(); + + void onGetRequestFinished(); + void onPostRequestFinished(); + void onPutRequestFinished(); }; #endif // DEVICEPLUGINHTTPCOMMANDER_H diff --git a/httpcommander/devicepluginhttpcommander.json b/httpcommander/devicepluginhttpcommander.json index 0ad28dc6..e400bc87 100644 --- a/httpcommander/devicepluginhttpcommander.json +++ b/httpcommander/devicepluginhttpcommander.json @@ -1,71 +1,70 @@ { - "name": "http commander", - "idName": "HttpCommander", + "name": "HttpCommander", + "displayName": "Http Commander", "id": "4e62670c-6268-4487-8dff-cccca498731a", "vendors": [ { - "name": "http commander", - "idName": "httpCommander", + "name": "httpCommander", + "displayName": "HTTP commander", "id": "45d7c941-7690-43c9-92fc-fab36e1cebd0", "deviceClasses": [ { "id": "b101abdf-86fd-4d2e-a657-ee76044235bd", - "idName": "httpPost", - "name": "http post", + "name": "httpPostCommander", + "displayName": "HTTP post commander", "deviceIcon": "Network", "createMethods": ["user"], "basicTags": [ "Service" ], - "criticalStateTypeId": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39", + "interfaces": ["connectable"], "paramTypes": [ { - "id": "1a3fcb23-931b-4ba1-b134-c49b656c76f7", - "idName": "url", - "name": "url or ipv4 address", + "id": "020f672e-cc9a-4b74-92dd-a92a93ab1d23", + "name": "url", + "displayName": "URL or IPv4 address", "type": "QString", "inputType": "None", - "defaultValue": "http://nymea.io" + "defaultValue": "https://nymea.io" }, { - "id": "bee8b151-815a-4159-9d8a-42b76e99b42c", - "idName": "port", + "id": "37830ea8-2249-46e6-aaca-12164928a81a", "name": "port", + "displayName": "port", "type": "int", - "defaultValue": "80" + "defaultValue": "443" } ], "stateTypes": [ { "id": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39", - "idName": "reachable", - "name": "reachable", + "name": "connected", + "displayName": "Reachable", + "displayNameEvent": "Reachability changed", "type": "bool", - "defaultValue": false, - "eventTypeName": "reachability changed" + "defaultValue": false }, { "id": "69f32ec8-114d-43f4-9241-1f6a57261f32", - "idName": "httpResponse", "name": "response", + "displayName": "response", + "displayNameEvent": "Response received", "type": "QString", - "defaultValue": "", - "eventTypeName": "response received" + "defaultValue": "" } ], "actionTypes": [ { "id": "5a97ca56-b334-411b-adba-116496ffe83d", - "idName": "post", "name": "post", + "displayName": "Post data", "paramTypes": [ { "id": "363119a3-c02c-4ed5-a915-11706198f3eb", - "idName": "postData", - "name": "post data", + "name": "data", + "displayName": "Data", "type": "QString", - "defaultValue": "", - "eventTypeName": "post data sent" + "defaultValue": "" } ] } @@ -73,62 +72,61 @@ }, { "id": "05bf65f5-ff13-43e3-b6ae-77019e79d8a1", - "idName": "httpPut", - "name": "http put", + "name": "httpPutCommander", + "displayName": "HTTP put commander", "deviceIcon": "Network", "createMethods": ["user"], + "interfaces": ["connectable"], "basicTags": [ "Service" ], - "criticalStateTypeId": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39", "paramTypes": [ { "id": "1a3fcb23-931b-4ba1-b134-c49b656c76f7", - "idName": "url", - "name": "url or ipv4 address", + "name": "url", + "displayName": "URL or IPv4 address", "type": "QString", "inputType": "None", - "defaultValue": "http://nymea.io" + "defaultValue": "https://nymea.io" }, { - "id": "bee8b151-815a-4159-9d8a-42b76e99b42c", - "idName": "port", + "id": "db994349-1105-4ce5-b6fe-6fd38fbc436a", "name": "port", + "displayName": "Port", "type": "int", - "defaultValue": "80" + "defaultValue": "443" } ], "stateTypes": [ { - "id": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39", - "idName": "reachable", - "name": "reachable", + "id": "d102ff86-b773-48e3-a7a5-e138cb541f49", + "name": "connected", + "displayName": "Reachable", + "displayNameEvent": "Reachability changed", "type": "bool", - "defaultValue": false, - "eventTypeName": "reachability changed" + "defaultValue": false }, { "id": "69f32ec8-114d-43f4-9241-1f6a57261f32", - "idName": "httpResponse", "name": "response", + "displayName": "Response", + "displayNameEvent": "Response received", "type": "QString", - "defaultValue": "", - "eventTypeName": "response received" + "defaultValue": "" } ], "actionTypes": [ { "id": "a9f165dc-cdf1-48f0-b4b6-7c24373cb77c", - "idName": "put", "name": "put", + "displayName": "put", "paramTypes": [ { "id": "7742d445-8fc1-4b20-87f2-1bb35929fce1", - "idName": "putData", - "name": "put data", + "name": "data", + "displayName": "Data", "type": "QString", - "defaultValue": "", - "eventTypeName": "post data sent" + "defaultValue": "" } ] } @@ -136,47 +134,47 @@ }, { "id": "8f3f6dde-9db3-4237-800b-bb7f804098c9", - "idName": "httpGet", - "name": "http get", + "name": "httpGetCommander", + "displayName": "HTTP get", "deviceIcon": "Network", "createMethods": ["user"], "basicTags": [ "Service" ], - "criticalStateTypeId": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39", + "interfaces": ["connectable"], "paramTypes": [ { - "id": "1a3fcb23-931b-4ba1-b134-c49b656c76f7", - "idName": "url", - "name": "Url or IPv4 Address", + "id": "477b544b-b631-4526-a4ef-c712ff5f955d", + "name": "url", + "displayName": "URL or IPv4 Address", "type": "QString", "inputType": "None", - "defaultValue": "http://nymea.io" + "defaultValue": "https://nymea.io" }, { "id": "bee8b151-815a-4159-9d8a-42b76e99b42c", - "idName": "port", - "name": "Port", + "name": "port", + "displayName": "Port", "type": "int", - "defaultValue": "80" + "defaultValue": "443" } ], "stateTypes":[ { - "id": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39", - "idName": "reachable", - "name": "reachable", + "id": "0d63f815-efd1-488a-9bfa-e9f6bda540d2", + "name": "connected", + "displayName": "Reachable", + "displayNameEvent": "Reachability changed", "type": "bool", - "defaultValue": false, - "eventTypeName": "reachability changed" + "defaultValue": false }, { "id": "d81f0644-b94e-48ed-ae48-1b8ff6cebc0c", - "idName": "getData", - "name": "data", + "name": "response", + "displayName": "Response", "type": "QString", "defaultValue": "", - "eventTypeName": "get data received" + "displayNameEvent": "Response data received" } ] } diff --git a/httpcommander/httpcommander.pro b/httpcommander/httpcommander.pro index b1b2b360..34f0ba80 100644 --- a/httpcommander/httpcommander.pro +++ b/httpcommander/httpcommander.pro @@ -1,7 +1,3 @@ -TRANSLATIONS = translations/en_US.ts \ - translations/de_DE.ts - -# Note: include after the TRANSLATIONS definition include(../plugins.pri) TARGET = $$qtLibraryTarget(guh_devicepluginhttpcommander)