Merge remote-tracking branch 'origin/add-http-commander'

This commit is contained in:
Jenkins 2018-03-15 11:51:52 +01:00
commit 10ef6d7d7d
8 changed files with 537 additions and 3 deletions

19
debian/control vendored
View File

@ -506,7 +506,21 @@ Description: nymea.io plugin for TCP commander
With the powerful rule engine you are able to connect any device available
in the system and create individual scenes and behaviors for your environment.
.
This package will install the nymea.io plugin for TCP commander
This package will install the nymea.io plugin for the TCP commander
Package: nymea-plugin-httpcommander
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
nymea-plugins-translations,
Description: nymea.io plugin for HTTP commander
The nymea daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and
allows them to interact.
With the powerful rule engine you are able to connect any device available
in the system and create individual scenes and behaviors for your environment.
.
This package will install the nymea.io plugin for the HTPP commander
Package: nymea-plugin-simulation
@ -589,7 +603,6 @@ Description: nymea.io plugin for keba
This package will install the nymea.io plugin for keba
Package: nymea-plugins-translations
Section: misc
Architecture: all
@ -605,7 +618,6 @@ Description: Translation files for nymea plugins - translations
This package provides the translation files for all nymea plugins.
Package: nymea-plugins
Section: libs
Architecture: all
@ -644,6 +656,7 @@ Architecture: all
Depends: nymea-plugin-commandlauncher,
nymea-plugin-udpcommander,
nymea-plugin-tcpcommander,
nymea-plugin-httpcommander,
nymea-plugin-genericelements,
nymea-plugin-avahimonitor,
nymea-plugin-gpio,

View File

@ -0,0 +1 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_devicepluginhttpcommander.so

View File

@ -0,0 +1,255 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> *
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "devicepluginhttpcommander.h"
#include "network/networkaccessmanager.h"
#include "plugininfo.h"
DevicePluginHttpCommander::DevicePluginHttpCommander()
{
}
DevicePluginHttpCommander::~DevicePluginHttpCommander()
{
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)
{
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;
}
return DeviceManager::DeviceSetupStatusFailure;
}
void DevicePluginHttpCommander::postSetupDevice(Device *device)
{
if (device->deviceClassId() == httpGetCommanderDeviceClassId) {
makeGetCall(device);
}
if (device->deviceClassId() == httpPostCommanderDeviceClassId) {
//TODO find a way to check it the URL is reachable
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() == httpPostCommanderDeviceClassId) {
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);
m_httpRequests.insert(reply, device);
return DeviceManager::DeviceErrorNoError;
}
return DeviceManager::DeviceErrorActionTypeNotFound;
}
if (device->deviceClassId() == httpPutCommanderDeviceClassId) {
// check if this is the "press" action
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);
m_httpRequests.insert(reply, device);
return DeviceManager::DeviceErrorNoError;
}
}
return DeviceManager::DeviceErrorDeviceClassNotFound;
}
void DevicePluginHttpCommander::makeGetCall(Device *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::onPluginTimer()
{
foreach (Device *device, myDevices()) {
if (device->deviceClassId() == httpGetCommanderDeviceClassId) {
makeGetCall(device);
}
}
}
void DevicePluginHttpCommander::onGetRequestFinished()
{
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
qDebug(dcHttpCommander()) << "GET 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(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<QNetworkReply *>(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<QNetworkReply *>(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
}
}

View File

@ -0,0 +1,64 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> *
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
* *
* This file is part of nymea. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; If not, see *
* <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef DEVICEPLUGINHTTPCOMMANDER_H
#define DEVICEPLUGINHTTPCOMMANDER_H
#include "plugin/deviceplugin.h"
#include "devicemanager.h"
#include "plugintimer.h"
#include <QNetworkReply>
class DevicePluginHttpCommander : public DevicePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "devicepluginhttpcommander.json")
Q_INTERFACES(DevicePlugin)
public:
explicit DevicePluginHttpCommander();
~DevicePluginHttpCommander();
void init() override;
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
void postSetupDevice(Device *device) override;
void deviceRemoved(Device *device) override;
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
private:
PluginTimer *m_pluginTimer = nullptr;
QHash<QNetworkReply *, Device *> m_httpRequests;
void makeGetCall(Device *device);
private slots:
void onPluginTimer();
void onGetRequestFinished();
void onPostRequestFinished();
void onPutRequestFinished();
};
#endif // DEVICEPLUGINHTTPCOMMANDER_H

View File

@ -0,0 +1,185 @@
{
"name": "HttpCommander",
"displayName": "Http Commander",
"id": "4e62670c-6268-4487-8dff-cccca498731a",
"vendors": [
{
"name": "httpCommander",
"displayName": "HTTP commander",
"id": "45d7c941-7690-43c9-92fc-fab36e1cebd0",
"deviceClasses": [
{
"id": "b101abdf-86fd-4d2e-a657-ee76044235bd",
"name": "httpPostCommander",
"displayName": "HTTP post commander",
"deviceIcon": "Network",
"createMethods": ["user"],
"basicTags": [
"Service"
],
"interfaces": ["connectable"],
"paramTypes": [
{
"id": "020f672e-cc9a-4b74-92dd-a92a93ab1d23",
"name": "url",
"displayName": "Address",
"type": "QString",
"inputType": "None",
"defaultValue": "https://nymea.io"
},
{
"id": "37830ea8-2249-46e6-aaca-12164928a81a",
"name": "port",
"displayName": "Port",
"type": "int",
"defaultValue": "443"
}
],
"stateTypes": [
{
"id": "8daac0e7-4c2f-4cdf-b528-02cfe04c6b39",
"name": "connected",
"displayName": "Reachable",
"displayNameEvent": "Reachability changed",
"type": "bool",
"defaultValue": false
},
{
"id": "69f32ec8-114d-43f4-9241-1f6a57261f32",
"name": "response",
"displayName": "response",
"displayNameEvent": "Response received",
"type": "QString",
"defaultValue": ""
}
],
"actionTypes": [
{
"id": "5a97ca56-b334-411b-adba-116496ffe83d",
"name": "post",
"displayName": "Post data",
"paramTypes": [
{
"id": "363119a3-c02c-4ed5-a915-11706198f3eb",
"name": "data",
"displayName": "Data",
"type": "QString",
"defaultValue": ""
}
]
}
]
},
{
"id": "05bf65f5-ff13-43e3-b6ae-77019e79d8a1",
"name": "httpPutCommander",
"displayName": "HTTP put commander",
"deviceIcon": "Network",
"createMethods": ["user"],
"interfaces": ["connectable"],
"basicTags": [
"Service"
],
"paramTypes": [
{
"id": "1a3fcb23-931b-4ba1-b134-c49b656c76f7",
"name": "url",
"displayName": "Address",
"type": "QString",
"inputType": "None",
"defaultValue": "https://nymea.io"
},
{
"id": "db994349-1105-4ce5-b6fe-6fd38fbc436a",
"name": "port",
"displayName": "Port",
"type": "int",
"defaultValue": "443"
}
],
"stateTypes": [
{
"id": "d102ff86-b773-48e3-a7a5-e138cb541f49",
"name": "connected",
"displayName": "Reachable",
"displayNameEvent": "Reachability changed",
"type": "bool",
"defaultValue": false
},
{
"id": "69f32ec8-114d-43f4-9241-1f6a57261f32",
"name": "response",
"displayName": "Response",
"displayNameEvent": "Response received",
"type": "QString",
"defaultValue": ""
}
],
"actionTypes": [
{
"id": "a9f165dc-cdf1-48f0-b4b6-7c24373cb77c",
"name": "put",
"displayName": "put",
"paramTypes": [
{
"id": "7742d445-8fc1-4b20-87f2-1bb35929fce1",
"name": "data",
"displayName": "Data",
"type": "QString",
"defaultValue": ""
}
]
}
]
},
{
"id": "8f3f6dde-9db3-4237-800b-bb7f804098c9",
"name": "httpGetCommander",
"displayName": "HTTP get",
"deviceIcon": "Network",
"createMethods": ["user"],
"basicTags": [
"Service"
],
"interfaces": ["connectable"],
"paramTypes": [
{
"id": "477b544b-b631-4526-a4ef-c712ff5f955d",
"name": "url",
"displayName": "URL or IPv4 Address",
"type": "QString",
"inputType": "None",
"defaultValue": "https://nymea.io"
},
{
"id": "bee8b151-815a-4159-9d8a-42b76e99b42c",
"name": "port",
"displayName": "Port",
"type": "int",
"defaultValue": "443"
}
],
"stateTypes":[
{
"id": "0d63f815-efd1-488a-9bfa-e9f6bda540d2",
"name": "connected",
"displayName": "Reachable",
"displayNameEvent": "Reachability changed",
"type": "bool",
"defaultValue": false
},
{
"id": "d81f0644-b94e-48ed-ae48-1b8ff6cebc0c",
"name": "response",
"displayName": "Response",
"type": "QString",
"defaultValue": "",
"displayNameEvent": "Response data received"
}
]
}
]
}
]
}

View File

@ -0,0 +1,11 @@
include(../plugins.pri)
TARGET = $$qtLibraryTarget(nymea_devicepluginhttpcommander)
SOURCES += \
devicepluginhttpcommander.cpp \
HEADERS += \
devicepluginhttpcommander.h \

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -19,6 +19,7 @@ PLUGIN_DIRS = \
leynew \
udpcommander \
tcpcommander \
httpcommander \
kodi \
elgato \
senic \