Merge remote-tracking branch 'origin/add-dweetio'

This commit is contained in:
Jenkins 2018-04-19 14:05:13 +02:00
commit 8ecfb48824
8 changed files with 499 additions and 0 deletions

15
debian/control vendored
View File

@ -108,6 +108,21 @@ Description: nymea.io plugin for denon
This package will install the nymea.io plugin for denon
Package: nymea-plugin-dweetio
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
nymea-plugins-translations,
Description: nymea.io plugin for dweet.io
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 dweet.io
Package: nymea-plugin-elro
Architecture: any
Depends: ${shlibs:Depends},

View File

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

View File

@ -0,0 +1,265 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Bernhard Trinnes <bernhard.trinnes@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 "deviceplugindweetio.h"
#include "plugininfo.h"
#include "hardwaremanager.h"
#include "network/networkaccessmanager.h"
#include <QUuid>
#include <QJsonDocument>
#include <QJsonObject>
#include <QUrl>
#include <QUrlQuery>
DevicePluginDweetio::DevicePluginDweetio()
{
}
DevicePluginDweetio::~DevicePluginDweetio()
{
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
}
void DevicePluginDweetio::init()
{
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60);
connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginDweetio::onPluginTimer);
}
DeviceManager::DeviceSetupStatus DevicePluginDweetio::setupDevice(Device *device)
{
if (device->deviceClassId() == postDeviceClassId) {
QString thing = device->paramValue(postThingParamTypeId).toString();
if (thing.isEmpty()){
qDebug(dcDweetio) << "No thing name given, creating one";
thing = QUuid::createUuid().toString();
}
return DeviceManager::DeviceSetupStatusSuccess;
} else if (device->deviceClassId() == getDeviceClassId) {
return DeviceManager::DeviceSetupStatusSuccess;
}
return DeviceManager::DeviceSetupStatusFailure;
}
void DevicePluginDweetio::postSetupDevice(Device *device)
{
if (device->deviceClassId() == getDeviceClassId){
getRequest(device);
}
}
void DevicePluginDweetio::deviceRemoved(Device *device)
{
if (device->deviceClassId() == getDeviceClassId) {
foreach(QNetworkReply *reply, m_getReplies.keys()){
if (m_getReplies.value(reply) == device) {
m_getReplies.remove(reply);
}
}
}
if (device->deviceClassId() == postDeviceClassId) {
foreach(QNetworkReply *reply, m_postReplies.keys()){
if (m_postReplies.value(reply) == device) {
m_postReplies.remove(reply);
}
}
}
}
DeviceManager::DeviceError DevicePluginDweetio::executeAction(Device *device, const Action &action)
{
qCDebug(dcDweetio) << "Execute action" << device->id() << action.id() << action.params();
if (device->deviceClassId() == postDeviceClassId) {
if (action.actionTypeId() == postContentDataActionTypeId) {
QString content = action.param(postContentDataAreaParamTypeId).value().toString();
postContent(content, device, action);
return DeviceManager::DeviceErrorAsync;
}
return DeviceManager::DeviceErrorActionTypeNotFound;
}
return DeviceManager::DeviceErrorDeviceClassNotFound;
}
void DevicePluginDweetio::postContent(const QString &content, Device *device, const Action &action)
{
QUrl url = QString("https://dweet.io:443/dweet/for/") + device->paramValue(postThingParamTypeId).toString();
QNetworkRequest request(url);
request.setRawHeader("Content-Type", QString("application/json").toLocal8Bit());
request.setRawHeader("Accept", QString("application/json").toLocal8Bit());
request.setSslConfiguration(QSslConfiguration::defaultConfiguration());
QString key = device->paramValue(postKeyParamTypeId).toString();
if (!(key.isEmpty()) || !(key == "none")) {
QUrlQuery query;
query.addQueryItem("key", key);
url.setQuery(query);
}
QVariantMap contentMap;
contentMap.insert(device->paramValue(postContentNameParamTypeId).toString(), content);
QByteArray data = QJsonDocument::fromVariant(contentMap).toJson(QJsonDocument::Compact);
qDebug(dcDweetio) << "Dweet: " << data << "Url: " << url;
QNetworkReply *reply = hardwareManager()->networkManager()->post(request, data);
m_asyncActions.insert(reply, action.id());
connect(reply, &QNetworkReply::finished, this, &DevicePluginDweetio::onNetworkReplyFinished);
m_postReplies.insert(reply, device);
}
void DevicePluginDweetio::setConnectionStatus(bool status, Device *device)
{
// Set connection status
device->setStateValue(postConnectedStateTypeId, status);
}
void DevicePluginDweetio::processPostReply(const QVariantMap &data, Device *device)
{
QString message = data.value("this").toString();
qDebug(dcDweetio) << "Access Reply: " << message << "Device: " << device->name();
}
void DevicePluginDweetio::processGetReply(const QVariantMap &data, Device *device)
{
QVariantList withList = data.value("with").toList();
QVariantMap contentMap = withList.first().toMap().value("content").toMap();
QString content = contentMap.value(device->paramValue(getContentNameParamTypeId).toString()).toString();
device->setStateValue(getContentStateTypeId, content);
qDebug(dcDweetio) << "Data: " << data << "Device: " << device->name();
}
void DevicePluginDweetio::onNetworkReplyFinished()
{
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (m_postReplies.contains(reply)) {
Device *device = m_postReplies.value(reply);
m_postReplies.remove(reply);
ActionId actionId = m_asyncActions.value(reply);
// check HTTP status code
if ((status != 200) && (status != 204)) {
qCWarning(dcDweetio) << "Update reply HTTP error:" << status << reply->errorString() << reply->readAll();
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorMissingParameter);
setConnectionStatus(false, device);
reply->deleteLater();
return;
}
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorNoError);
setConnectionStatus(true, device);
if (status == 204){
reply->deleteLater();
return;
}
// check JSON file
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcDweetio) << "Update reply JSON error:" << error.errorString();
reply->deleteLater();
return;
}
processPostReply(jsonDoc.toVariant().toMap(), device);
} else if (m_getReplies.contains(reply)) {
Device *device = m_getReplies.value(reply);
m_getReplies.remove(reply);
// check HTTP status code
if ((status != 200) && (status != 204)) {
qCWarning(dcDweetio) << "Update reply HTTP error:" << status << reply->errorString() << reply->readAll();
setConnectionStatus(false, device);
reply->deleteLater();
return;
}
setConnectionStatus(true, device);
if (status == 204){
reply->deleteLater();
return;
}
// check JSON file
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcDweetio) << "Update reply JSON error:" << error.errorString();
reply->deleteLater();
return;
}
processGetReply(jsonDoc.toVariant().toMap(), device);
}
}
void DevicePluginDweetio::getRequest(Device *device)
{
qCDebug(dcDweetio()) << "Refresh data for" << device->name();
QUrl url = QString("https://dweet.io:443/get/latest/dweet/for/") + device->paramValue(postThingParamTypeId).toString();
QNetworkRequest request(url);
request.setRawHeader("Content-Type", QString("application/json").toLocal8Bit());
request.setRawHeader("Accept", QString("application/json").toLocal8Bit());
request.setSslConfiguration(QSslConfiguration::defaultConfiguration());
QString key = device->paramValue(getKeyParamTypeId).toString();
if (!(key.isEmpty()) || !(key == "none")) {
QUrlQuery query;
query.addQueryItem("key", key);
url.setQuery(query);
}
QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(url));
connect(reply, &QNetworkReply::finished, this, &DevicePluginDweetio::onNetworkReplyFinished);
m_getReplies.insert(reply, device);
}
void DevicePluginDweetio::onPluginTimer()
{
foreach (Device *device, myDevices()) {
if (device->deviceClassId() == getDeviceClassId) {
getRequest(device);
}
}
}

View File

@ -0,0 +1,72 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2018 Bernhard Trinnes <bernhard.trinnes@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 DEVICEPLUGINDWEETIO_H
#define DEVICEPLUGINDWEETIO_H
#include "devicemanager.h"
#include "plugin/deviceplugin.h"
#include <QHash>
#include <QObject>
#include <QPointer>
#include <QHostAddress>
#include <QNetworkReply>
#include "plugintimer.h"
class DevicePluginDweetio : public DevicePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "deviceplugindweetio.json")
Q_INTERFACES(DevicePlugin)
public:
explicit DevicePluginDweetio();
~DevicePluginDweetio();
void init() override;
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
void deviceRemoved(Device *device) override;
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
void postSetupDevice(Device *device) override;
private:
PluginTimer *m_pluginTimer = nullptr;
QHash<QNetworkReply *, Device *> m_postReplies;
QHash<QNetworkReply *, Device *> m_getReplies;
QHash<QNetworkReply *, ActionId> m_asyncActions;
void postContent(const QString &content, Device *device, const Action &action);
void processPostReply(const QVariantMap &data, Device *device);
void processGetReply(const QVariantMap &data, Device *device);
void setConnectionStatus(bool status, Device *device);
void getRequest(Device *device);
private slots:
void onNetworkReplyFinished();
void onPluginTimer();
};
#endif // DEVICEPLUGINDWEETIO_H

View File

@ -0,0 +1,130 @@
{
"displayName": "Dweetio",
"name": "Dweetio",
"id": "9338f22c-df47-414e-a33c-9b6d40c953c9",
"vendors": [
{
"id": "23ff381d-c580-4ba1-85bd-30598f893a43",
"displayName": "Dweetio",
"name": "dweetio",
"deviceClasses": [
{
"id": "5036030e-adc7-403b-b9b6-a27a4a5afea8",
"name": "post",
"displayName": "Post",
"createMethods": ["user"],
"criticalStateTypeId": "4d1790bf-28c6-4c1f-8892-ba1a0ef140f5",
"deviceIcon": "Network",
"interfaces": [],
"basicTags": [
"Service"
],
"paramTypes": [
{
"id": "b50b3682-fb2e-4185-b7aa-31741648d9bb",
"name": "thing",
"displayName": "Thing",
"type" : "QString",
"inputType": "TextLine"
},
{
"id": "892b7323-ee85-4520-9160-f206f11b344e",
"name": "key",
"displayName": "key",
"defaultValue": "none",
"type" : "QString",
"inputType": "TextLine"
},
{
"id": "f2b2c3ae-a915-4dd9-a9dd-9545d9dd3d4e",
"name": "contentName",
"displayName": "Content Name",
"type": "QString",
"inputType": "TextLine"
}
],
"stateTypes": [
{
"id": "4d1790bf-28c6-4c1f-8892-ba1a0ef140f5",
"name": "connected",
"displayName": "connected",
"displayNameEvent": "connected changed",
"defaultValue": false,
"type": "bool"
}
],
"actionTypes": [
{
"id": "76472328-dbaa-458f-90c9-0b46968af511",
"name": "contentData",
"displayName": "Send Content",
"paramTypes": [
{
"id": "13760d36-26eb-40b5-85b3-450ca7937666",
"name": "contentDataArea",
"displayName": "Content",
"type": "QString",
"inputType": "TextArea"
}
]
}
]
},
{
"id": "8318f86c-061a-450f-978d-f42e3513ca8c",
"name": "get",
"displayName": "Get",
"createMethods": ["user"],
"criticalStateTypeId": "4d1790bf-28c6-4c1f-8892-ba1a0ef140f5",
"deviceIcon": "Network",
"interfaces": [],
"basicTags": [
"Service"
],
"paramTypes": [
{
"id": "b50b3682-fb2e-4185-b7aa-31741648d9bb",
"name": "thing",
"displayName": "Thing",
"type" : "QString",
"inputType": "TextLine"
},
{
"id": "892b7323-ee85-4520-9160-f206f11b344e",
"name": "key",
"displayName": "Key",
"type" : "QString",
"defaultValue": "none",
"inputType": "TextLine"
},
{
"id": "f2b2c3ae-a915-4dd9-a9dd-9545d9dd3d4e",
"name": "contentName",
"displayName": "Content name",
"type": "QString",
"inputType": "TextLine"
}
],
"stateTypes": [
{
"id": "4d1790bf-28c6-4c1f-8892-ba1a0ef140f5",
"name": "connected",
"displayName": "connected",
"displayNameEvent": "connected changed",
"defaultValue": false,
"type": "bool"
},
{
"id": "53dfe2bc-792d-420e-bc1f-2890ad715b27",
"name": "content",
"displayName": "Content",
"displayNameEvent": "content changed",
"defaultValue": "",
"type": "QString"
}
]
}
]
}
]
}

11
dweetio/dweetio.pro Normal file
View File

@ -0,0 +1,11 @@
include(../plugins.pri)
QT += network
TARGET = $$qtLibraryTarget(nymea_deviceplugindweetio)
SOURCES += \
deviceplugindweetio.cpp \
HEADERS += \
deviceplugindweetio.h \

View File

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

View File

@ -39,6 +39,7 @@ PLUGIN_DIRS = \
simulation \
keba \
remotessh \
dweetio \
CONFIG+=all