add orderbutton plugin
add coap to the libguh source for dev package
This commit is contained in:
parent
6c99736216
commit
e30aace156
1
debian/guh-plugins-merkur.install
vendored
1
debian/guh-plugins-merkur.install
vendored
@ -2,3 +2,4 @@ usr/lib/guh/plugins/libguh_devicepluginosdomotics.so
|
||||
usr/lib/guh/plugins/libguh_deviceplugindollhouse.so
|
||||
usr/lib/guh/plugins/libguh_devicepluginplantcare.so
|
||||
usr/lib/guh/plugins/libguh_devicepluginws2812.so
|
||||
usr/lib/guh/plugins/libguh_devicepluginorderbutton.so
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
include(../guh.pri)
|
||||
include(coap/coap.pri)
|
||||
|
||||
TARGET = guh
|
||||
TEMPLATE = lib
|
||||
@ -40,6 +39,15 @@ SOURCES += devicemanager.cpp \
|
||||
network/upnpdiscovery/upnpdiscoveryrequest.cpp \
|
||||
network/networkmanager.cpp \
|
||||
network/oauth2.cpp \
|
||||
coap/coap.cpp \
|
||||
coap/coappdu.cpp \
|
||||
coap/coapoption.cpp \
|
||||
coap/coaprequest.cpp \
|
||||
coap/coapreply.cpp \
|
||||
coap/coappdublock.cpp \
|
||||
coap/corelinkparser.cpp \
|
||||
coap/corelink.cpp \
|
||||
coap/coapobserveresource.cpp \
|
||||
types/action.cpp \
|
||||
types/actiontype.cpp \
|
||||
types/state.cpp \
|
||||
@ -55,6 +63,7 @@ SOURCES += devicemanager.cpp \
|
||||
types/ruleactionparam.cpp \
|
||||
types/statedescriptor.cpp \
|
||||
|
||||
|
||||
HEADERS += devicemanager.h \
|
||||
libguh.h \
|
||||
typeutils.h \
|
||||
@ -77,6 +86,15 @@ HEADERS += devicemanager.h \
|
||||
network/upnpdiscovery/upnpdiscoveryrequest.h \
|
||||
network/networkmanager.h \
|
||||
network/oauth2.h \
|
||||
coap/coap.h \
|
||||
coap/coappdu.h \
|
||||
coap/coapoption.h \
|
||||
coap/coaprequest.h \
|
||||
coap/coapreply.h \
|
||||
coap/coappdublock.h \
|
||||
coap/corelinkparser.h \
|
||||
coap/corelink.h \
|
||||
coap/coapobserveresource.h \
|
||||
types/action.h \
|
||||
types/actiontype.h \
|
||||
types/state.h \
|
||||
@ -92,6 +110,7 @@ HEADERS += devicemanager.h \
|
||||
types/ruleactionparam.h \
|
||||
types/statedescriptor.h \
|
||||
|
||||
|
||||
# install plugininfo python script for libguh-dev
|
||||
generateplugininfo.files = $$top_srcdir/plugins/guh-generateplugininfo
|
||||
generateplugininfo.path = /usr/bin
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
\title aWATTar
|
||||
|
||||
\ingroup plugins
|
||||
\ingroup network
|
||||
\ingroup guh-plugins
|
||||
|
||||
This plugin allows to receive the current energy market price from the \l{https://www.awattar.com/}{aWATTar GmbH}.
|
||||
In order to use this plugin you need to enter the access token from your energy provider. You can find more
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
\title Time
|
||||
|
||||
\ingroup plugins
|
||||
\ingroup services
|
||||
\ingroup guh-plugins
|
||||
|
||||
The time plugin allows you create rules based on the time, day, month, year, weekday or on weekend.
|
||||
|
||||
|
||||
@ -24,3 +24,4 @@ SUBDIRS += elro \
|
||||
plantcare \
|
||||
osdomotics \
|
||||
ws2812 \
|
||||
orderbutton \
|
||||
|
||||
@ -18,6 +18,31 @@
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/*!
|
||||
\page dollhouse.html
|
||||
\title Dollhouse
|
||||
|
||||
\ingroup plugins
|
||||
\ingroup guh-plugins-merkur
|
||||
|
||||
The plugin for the guh-dollhouse demo booth.
|
||||
|
||||
\chapter Plugin properties
|
||||
Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses}
|
||||
and \l{Vendor}{Vendors} of this \l{DevicePlugin}.
|
||||
|
||||
Each \l{DeviceClass} has a list of \l{ParamType}{paramTypes}, \l{ActionType}{actionTypes}, \l{StateType}{stateTypes}
|
||||
and \l{EventType}{eventTypes}. The \l{DeviceClass::CreateMethod}{createMethods} parameter describes how the \l{Device}
|
||||
will be created in the system. A device can have more than one \l{DeviceClass::CreateMethod}{CreateMethod}.
|
||||
The \l{DeviceClass::SetupMethod}{setupMethod} describes the setup method of the \l{Device}.
|
||||
The detailed implementation of each \l{DeviceClass} can be found in the source code.
|
||||
|
||||
\note If a \l{StateType} has the parameter \tt{"writable": {...}}, an \l{ActionType} with the same uuid and \l{ParamType}{ParamTypes}
|
||||
will be created automatically.
|
||||
|
||||
\quotefile plugins/deviceplugins/datetime/deviceplugindollhouse.json
|
||||
*/
|
||||
|
||||
#include "deviceplugindollhouse.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
|
||||
489
plugins/deviceplugins/orderbutton/devicepluginorderbutton.cpp
Normal file
489
plugins/deviceplugins/orderbutton/devicepluginorderbutton.cpp
Normal file
@ -0,0 +1,489 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
|
||||
* Copyright (C) 2016 Bernhard Trinnes <bernhard.trinnes@guh.guru> *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh 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 General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
|
||||
#include "devicepluginorderbutton.h"
|
||||
#include "plugin/device.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
DevicePluginOrderButton::DevicePluginOrderButton()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DeviceManager::HardwareResources DevicePluginOrderButton::requiredHardware() const
|
||||
{
|
||||
// We need the NetworkManager for node discovery and the timer for ping requests
|
||||
return DeviceManager::HardwareResourceNetworkManager | DeviceManager::HardwareResourceTimer;
|
||||
}
|
||||
|
||||
DeviceManager::DeviceSetupStatus DevicePluginOrderButton::setupDevice(Device *device)
|
||||
{
|
||||
qCDebug(dcOrderButton) << "Setup Plant Care" << device->name() << device->params();
|
||||
|
||||
// Check if device already added with this address
|
||||
if (deviceAlreadyAdded(QHostAddress(device->paramValue("host").toString()))) {
|
||||
qCWarning(dcOrderButton) << "Device with this address already added.";
|
||||
return DeviceManager::DeviceSetupStatusFailure;
|
||||
}
|
||||
|
||||
// Create the CoAP socket if not already created
|
||||
if (m_coap.isNull()) {
|
||||
m_coap = new Coap(this);
|
||||
connect(m_coap.data(), SIGNAL(replyFinished(CoapReply*)), this, SLOT(coapReplyFinished(CoapReply*)));
|
||||
connect(m_coap.data(), SIGNAL(notificationReceived(CoapObserveResource,int,QByteArray)), this, SLOT(onNotificationReceived(CoapObserveResource,int,QByteArray)));
|
||||
}
|
||||
|
||||
return DeviceManager::DeviceSetupStatusSuccess;
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::deviceRemoved(Device *device)
|
||||
{
|
||||
Q_UNUSED(device)
|
||||
|
||||
// Delete the CoAP socket if there are no devices left
|
||||
if (myDevices().isEmpty()) {
|
||||
m_coap->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
DeviceManager::DeviceError DevicePluginOrderButton::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
||||
{
|
||||
Q_UNUSED(params)
|
||||
|
||||
// Perform a HTTP GET on the RPL router address
|
||||
QHostAddress address(configuration().paramValue("RPL address").toString());
|
||||
qCDebug(dcOrderButton) << "Scan for new nodes on RPL" << address.toString();
|
||||
|
||||
QUrl url;
|
||||
url.setScheme("http");
|
||||
url.setHost(address.toString());
|
||||
|
||||
m_asyncNodeScans.insert(networkManagerGet(QNetworkRequest(url)), deviceClassId);
|
||||
return DeviceManager::DeviceErrorAsync;
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::networkManagerReplyReady(QNetworkReply *reply)
|
||||
{
|
||||
if (m_asyncNodeScans.keys().contains(reply)) {
|
||||
DeviceClassId deviceClassId = m_asyncNodeScans.take(reply);
|
||||
// Check HTTP status code
|
||||
if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
|
||||
qCWarning(dcOrderButton) << "Node scan reply HTTP error:" << reply->errorString();
|
||||
emit devicesDiscovered(deviceClassId, QList<DeviceDescriptor>());
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
qCDebug(dcOrderButton) << "Node discovery finished:" << endl << data;
|
||||
|
||||
QList<DeviceDescriptor> deviceDescriptors;
|
||||
QList<QByteArray> lines = data.split('\n');
|
||||
qCDebug(dcOrderButton) << lines;
|
||||
foreach (const QByteArray &line, lines) {
|
||||
if (line.isEmpty())
|
||||
continue;
|
||||
|
||||
QHostAddress address(QString(line.left(line.length() - 4)));
|
||||
if (address.isNull())
|
||||
continue;
|
||||
|
||||
qCDebug(dcOrderButton) << "Found node" << address.toString();
|
||||
// Create a deviceDescriptor for each found address
|
||||
DeviceDescriptor descriptor(deviceClassId, "Order Button", address.toString());
|
||||
ParamList params;
|
||||
params.append(Param("host", address.toString()));
|
||||
descriptor.setParams(params);
|
||||
deviceDescriptors.append(descriptor);
|
||||
}
|
||||
// Inform the user which devices were found
|
||||
emit devicesDiscovered(deviceClassId, deviceDescriptors);
|
||||
}
|
||||
|
||||
// Delete the HTTP reply
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::postSetupDevice(Device *device)
|
||||
{
|
||||
// Try to ping the device after a successful setup
|
||||
pingDevice(device);
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::guhTimer()
|
||||
{
|
||||
// Try to ping each device every 10 seconds to make sure it is still reachable
|
||||
foreach (Device *device, myDevices()) {
|
||||
if (device->deviceClassId() == orderbuttonDeviceClassId) {
|
||||
pingDevice(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeviceManager::DeviceError DevicePluginOrderButton::executeAction(Device *device, const Action &action)
|
||||
{
|
||||
if (device->deviceClassId() != orderbuttonDeviceClassId)
|
||||
return DeviceManager::DeviceErrorDeviceClassNotFound;
|
||||
|
||||
qCDebug(dcOrderButton) << "Execute action" << device->name() << action.params();
|
||||
|
||||
// Check if the device is reachable
|
||||
if (!device->stateValue(reachableStateTypeId).toBool()) {
|
||||
qCWarning(dcOrderButton) << "Device not reachable.";
|
||||
return DeviceManager::DeviceErrorHardwareNotAvailable;
|
||||
}
|
||||
|
||||
// Check which action sould be executed
|
||||
if (action.actionTypeId() == resetActionTypeId) {
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(device->paramValue("host").toString());
|
||||
url.setPath("/a/reset");
|
||||
|
||||
CoapReply *reply = m_coap->post(CoapRequest(url));
|
||||
if (reply->isFinished() && reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcOrderButton) << "CoAP reply finished with error" << reply->errorString();
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
return DeviceManager::DeviceErrorHardwareFailure;
|
||||
}
|
||||
|
||||
m_resetCounterRequests.insert(reply, action);
|
||||
m_asyncActions.insert(action.id(), device);
|
||||
return DeviceManager::DeviceErrorAsync;
|
||||
|
||||
} else if(action.actionTypeId() == ledActionTypeId) {
|
||||
bool led = action.param("led").value().toBool();
|
||||
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(device->paramValue("host").toString());
|
||||
url.setPath("/a/led");
|
||||
|
||||
QByteArray payload = QString("mode=%1").arg(QString::number((int)led)).toUtf8();
|
||||
qCDebug(dcOrderButton()) << "Sending" << payload;
|
||||
CoapReply *reply = m_coap->post(CoapRequest(url), payload);
|
||||
if (reply->isFinished() && reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcOrderButton) << "CoAP reply finished with error" << reply->errorString();
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
return DeviceManager::DeviceErrorHardwareFailure;
|
||||
}
|
||||
|
||||
m_setLedPower.insert(reply, action);
|
||||
m_asyncActions.insert(action.id(), device);
|
||||
return DeviceManager::DeviceErrorAsync;
|
||||
}
|
||||
return DeviceManager::DeviceErrorActionTypeNotFound;
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::pingDevice(Device *device)
|
||||
{
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(device->paramValue("host").toString());
|
||||
m_pingReplies.insert(m_coap->ping(CoapRequest(url)), device);
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::updateBattery(Device *device)
|
||||
{
|
||||
qCDebug(dcOrderButton) << "Update" << device->name() << "battery value";
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(device->paramValue("host").toString());
|
||||
url.setPath("/s/battery");
|
||||
CoapReply *reply = m_coap->get(CoapRequest(url));
|
||||
if (reply->isFinished() && reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcOrderButton) << "CoAP reply finished with error" << reply->errorString();
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
m_updateReplies.insert(reply, device);
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::updateCount(Device *device)
|
||||
{
|
||||
qCDebug(dcOrderButton) << "Update" << device->name() << "count value";
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(device->paramValue("host").toString());
|
||||
url.setPath("/s/count");
|
||||
CoapReply *reply = m_coap->get(CoapRequest(url));
|
||||
if (reply->isFinished() && reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcOrderButton) << "CoAP reply finished with error" << reply->errorString();
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
m_updateReplies.insert(reply, device);
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::updateButton(Device *device)
|
||||
{
|
||||
qCDebug(dcOrderButton) << "Update" << device->name() << "button value";
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(device->paramValue("host").toString());
|
||||
url.setPath("/s/button");
|
||||
CoapReply *reply = m_coap->get(CoapRequest(url));
|
||||
if (reply->isFinished() && reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcOrderButton) << "CoAP reply finished with error" << reply->errorString();
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
m_updateReplies.insert(reply, device);
|
||||
}
|
||||
|
||||
|
||||
void DevicePluginOrderButton::updateLed(Device *device)
|
||||
{
|
||||
qCDebug(dcOrderButton) << "Update" << device->name() << "led value";
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(device->paramValue("host").toString());
|
||||
url.setPath("/a/led");
|
||||
CoapReply *reply = m_coap->get(CoapRequest(url));
|
||||
if (reply->isFinished() && reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcOrderButton) << "CoAP reply finished with error" << reply->errorString();
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
m_updateReplies.insert(reply, device);
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::enableNotifications(Device *device)
|
||||
{
|
||||
qCDebug(dcOrderButton) << "Enable" << device->name() << "notifications";
|
||||
QUrl url;
|
||||
url.setScheme("coap");
|
||||
url.setHost(device->paramValue("host").toString());
|
||||
|
||||
url.setPath("/s/button");
|
||||
m_enableNotification.insert(m_coap->enableResourceNotifications(CoapRequest(url)), device);
|
||||
|
||||
url.setPath("/s/count");
|
||||
m_enableNotification.insert(m_coap->enableResourceNotifications(CoapRequest(url)), device);
|
||||
|
||||
url.setPath("/s/battery");
|
||||
m_enableNotification.insert(m_coap->enableResourceNotifications(CoapRequest(url)), device);
|
||||
|
||||
url.setPath("/a/led");
|
||||
m_enableNotification.insert(m_coap->enableResourceNotifications(CoapRequest(url)), device);
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::setReachable(Device *device, const bool &reachable)
|
||||
{
|
||||
if (device->stateValue(reachableStateTypeId).toBool() != reachable) {
|
||||
if (!reachable) {
|
||||
// Warn just once that the device is not reachable
|
||||
qCWarning(dcOrderButton()) << device->name() << "reachable changed" << reachable;
|
||||
} else {
|
||||
qCDebug(dcOrderButton()) << device->name() << "reachable changed" << reachable;
|
||||
|
||||
// Get current state values after a reconnect
|
||||
updateBattery(device);
|
||||
updateCount(device);
|
||||
updateButton(device);
|
||||
updateLed(device);
|
||||
|
||||
// Make sure the notifications are enabled
|
||||
enableNotifications(device);
|
||||
}
|
||||
}
|
||||
|
||||
device->setStateValue(reachableStateTypeId, reachable);
|
||||
}
|
||||
|
||||
bool DevicePluginOrderButton::deviceAlreadyAdded(const QHostAddress &address)
|
||||
{
|
||||
// Check if we already have a device with the given address
|
||||
foreach (Device *device, myDevices()) {
|
||||
if (device->paramValue("host").toString() == address.toString()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Device *DevicePluginOrderButton::findDevice(const QHostAddress &address)
|
||||
{
|
||||
// Return the device pointer with the given address (otherwise 0)
|
||||
foreach (Device *device, myDevices()) {
|
||||
if (device->paramValue("host").toString() == address.toString()) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::coapReplyFinished(CoapReply *reply)
|
||||
{
|
||||
if (m_pingReplies.contains(reply)) {
|
||||
Device *device = m_pingReplies.take(reply);
|
||||
|
||||
// Check CoAP reply error
|
||||
if (reply->error() != CoapReply::NoError) {
|
||||
if (device->stateValue(reachableStateTypeId).toBool())
|
||||
qCWarning(dcOrderButton) << "Ping device" << reply->request().url().toString() << "reply finished with error" << reply->errorString();
|
||||
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
setReachable(device, true);
|
||||
|
||||
} else if (m_updateReplies.contains(reply)) {
|
||||
Device *device = m_updateReplies.take(reply);
|
||||
QString urlPath = reply->request().url().path();
|
||||
|
||||
// Check CoAP reply error
|
||||
if (reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcOrderButton) << "Update resource" << urlPath << "reply finished with error" << reply->errorString();
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check CoAP status code
|
||||
if (reply->statusCode() != CoapPdu::Content) {
|
||||
qCWarning(dcOrderButton) << "Update resource" << urlPath << "status code error:" << reply;
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// Update corresponding device state
|
||||
if (urlPath == "/s/count") {
|
||||
qCDebug(dcOrderButton()) << "Updated count value:" << reply->payload();
|
||||
device->setStateValue(countStateTypeId, reply->payload().toInt());
|
||||
} else if (urlPath == "/s/button") {
|
||||
qCDebug(dcOrderButton()) << "Updated button value:" << reply->payload();
|
||||
//device->(buttonStateTypeId, QVariant(reply->payload().toInt()).toBool());
|
||||
emit emitEvent(Event(buttonEventTypeId, device->id()));
|
||||
} else if (urlPath == "/s/battery") {
|
||||
qCDebug(dcOrderButton()) << "Updated battery value:" << reply->payload();
|
||||
device->setStateValue(batteryStateTypeId, reply->payload().toDouble());
|
||||
} else if (urlPath == "/a/led") {
|
||||
qCDebug(dcOrderButton()) << "Updated led value:" << reply->payload();
|
||||
device->setStateValue(ledStateTypeId, QVariant(reply->payload().toInt()).toBool());
|
||||
}
|
||||
|
||||
} else if (m_resetCounterRequests.contains(reply)) {
|
||||
Action action = m_resetCounterRequests.take(reply);
|
||||
Device *device = m_asyncActions.take(action.id());
|
||||
|
||||
// Check CoAP reply error
|
||||
if (reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcOrderButton) << "CoAP reply reset counter finished with error" << reply->errorString();
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
emit actionExecutionFinished(action.id(), DeviceManager::DeviceErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check CoAP status code
|
||||
if (reply->statusCode() != CoapPdu::Content) {
|
||||
qCWarning(dcOrderButton) << "reset counter status code error:" << reply;
|
||||
reply->deleteLater();
|
||||
emit actionExecutionFinished(action.id(), DeviceManager::DeviceErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
// Tell the user about the action execution result
|
||||
emit actionExecutionFinished(action.id(), DeviceManager::DeviceErrorNoError);
|
||||
|
||||
}else if (m_setLedPower.contains(reply)) {
|
||||
Action action = m_setLedPower.take(reply);
|
||||
Device *device = m_asyncActions.take(action.id());
|
||||
|
||||
// check CoAP reply error
|
||||
if (reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcOrderButton) << "CoAP set led power reply finished with error" << reply->errorString();
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
emit actionExecutionFinished(action.id(), DeviceManager::DeviceErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check CoAP status code
|
||||
if (reply->statusCode() != CoapPdu::Content) {
|
||||
qCWarning(dcOrderButton) << "Set led power status code error:" << reply;
|
||||
reply->deleteLater();
|
||||
emit actionExecutionFinished(action.id(), DeviceManager::DeviceErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the state here, so we don't have to wait for the notification
|
||||
device->setStateValue(ledStateTypeId, action.param("led").value().toBool());
|
||||
// Tell the user about the action execution result
|
||||
emit actionExecutionFinished(action.id(), DeviceManager::DeviceErrorNoError);
|
||||
|
||||
} else if (m_enableNotification.contains(reply)) {
|
||||
Device *device = m_enableNotification.take(reply);
|
||||
|
||||
// check CoAP reply error
|
||||
if (reply->error() != CoapReply::NoError) {
|
||||
qCWarning(dcOrderButton) << "Enable notifications for" << reply->request().url().toString() << "reply finished with error" << reply->errorString();
|
||||
setReachable(device, false);
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check CoAP status code
|
||||
if (reply->statusCode() != CoapPdu::Content) {
|
||||
qCWarning(dcOrderButton) << "Enable notifications for" << reply->request().url().toString() << "reply status code error" << reply->errorString();
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcOrderButton()) << "Enabled successfully notifications for" << device->name() << reply->request().url().path();
|
||||
}
|
||||
|
||||
// Delete the CoAP reply
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void DevicePluginOrderButton::onNotificationReceived(const CoapObserveResource &resource, const int ¬ificationNumber, const QByteArray &payload)
|
||||
{
|
||||
qCDebug(dcOrderButton) << " --> Got notification nr." << notificationNumber << resource.url().toString() << payload;
|
||||
Device *device = findDevice(QHostAddress(resource.url().host()));
|
||||
if (!device) {
|
||||
qCWarning(dcOrderButton()) << "Could not find device for this notification";
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the corresponding device state
|
||||
if (resource.url().path() == "/s/button") {
|
||||
emit emitEvent(Event(buttonEventTypeId, device->id()));
|
||||
//device->setStateValue(buttonStateTypeId, QVariant(payload.toInt()).toBool());
|
||||
} else if (resource.url().path() == "/s/battery") {
|
||||
device->setStateValue(batteryStateTypeId, payload.toDouble());
|
||||
} else if (resource.url().path() == "/a/led") {
|
||||
device->setStateValue(ledStateTypeId, QVariant(payload.toInt()).toBool());
|
||||
} else if (resource.url().path() == "/s/count") {
|
||||
device->setStateValue(countStateTypeId, payload.toInt());
|
||||
}
|
||||
}
|
||||
86
plugins/deviceplugins/orderbutton/devicepluginorderbutton.h
Normal file
86
plugins/deviceplugins/orderbutton/devicepluginorderbutton.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
|
||||
* Copyright (C) 2015 Bernhard Trinnes <bernhard.trinnes@guh.guru> *
|
||||
* *
|
||||
* This file is part of guh. *
|
||||
* *
|
||||
* Guh is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* Guh 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 General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef DEVICEPLUGINORDERBUTTON_H
|
||||
#define DEVICEPLUGINORDERBUTTON_H
|
||||
|
||||
#include "plugin/deviceplugin.h"
|
||||
#include "types/action.h"
|
||||
#include "coap/coap.h"
|
||||
|
||||
#include <QHash>
|
||||
|
||||
class DevicePluginOrderButton : public DevicePlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "guru.guh.DevicePlugin" FILE "devicepluginorderbutton.json")
|
||||
Q_INTERFACES(DevicePlugin)
|
||||
|
||||
public:
|
||||
explicit DevicePluginOrderButton();
|
||||
|
||||
DeviceManager::HardwareResources requiredHardware() const override;
|
||||
DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override;
|
||||
DeviceManager::DeviceSetupStatus setupDevice(Device *device) override;
|
||||
void deviceRemoved(Device *device) override;
|
||||
void networkManagerReplyReady(QNetworkReply *reply) override;
|
||||
|
||||
void postSetupDevice(Device *device) override;
|
||||
|
||||
void guhTimer() override;
|
||||
DeviceManager::DeviceError executeAction(Device *device, const Action &action) override;
|
||||
|
||||
private:
|
||||
QPointer<Coap> m_coap;
|
||||
QHash<QNetworkReply *, DeviceClassId> m_asyncNodeScans;
|
||||
QHash<CoapReply *, Device *> m_enableNotification;
|
||||
QHash<CoapReply *, Device *> m_pingReplies;
|
||||
|
||||
// State updates
|
||||
QHash<CoapReply *, Device *> m_updateReplies;
|
||||
|
||||
// Actions
|
||||
QHash<ActionId, Device *> m_asyncActions;
|
||||
|
||||
QHash<CoapReply *, Action> m_resetCounterRequests;
|
||||
QHash<CoapReply *, Action> m_setCount;
|
||||
QHash<CoapReply *, Action> m_setLedPower;
|
||||
|
||||
void pingDevice(Device *device);
|
||||
|
||||
void updateBattery(Device *device);
|
||||
void updateCount(Device *device);
|
||||
void updateButton(Device *device);
|
||||
void updateLed(Device *device);
|
||||
|
||||
void enableNotifications(Device *device);
|
||||
|
||||
void setReachable(Device *device, const bool &reachable);
|
||||
|
||||
bool deviceAlreadyAdded(const QHostAddress &address);
|
||||
Device *findDevice(const QHostAddress &address);
|
||||
|
||||
private slots:
|
||||
void coapReplyFinished(CoapReply *reply);
|
||||
void onNotificationReceived(const CoapObserveResource &resource, const int ¬ificationNumber, const QByteArray &payload);
|
||||
};
|
||||
|
||||
#endif // DEVICEPLUGINORDERBUTTON_H
|
||||
@ -0,0 +1,85 @@
|
||||
{
|
||||
"name": "Order Button",
|
||||
"idName": "OrderButton",
|
||||
"id": "939a6557-649d-43de-990b-3484f972ad86",
|
||||
"paramTypes": [
|
||||
{
|
||||
"name": "RPL address",
|
||||
"type": "QString",
|
||||
"inputType": "TextLine",
|
||||
"defaultValue": "fdaa:e9b8:d03a::ff:fe00:1"
|
||||
}
|
||||
],
|
||||
"vendors": [
|
||||
{
|
||||
"name": "guh",
|
||||
"idName": "guh",
|
||||
"id": "76df1ad2-c179-4842-94ea-2da6e4796339",
|
||||
"deviceClasses": [
|
||||
{
|
||||
"deviceClassId": "af4df281-2b3b-490f-8352-2b99ff23fc15",
|
||||
"name": "OrderButton",
|
||||
"idName": "orderbutton",
|
||||
"createMethods": ["discovery"],
|
||||
"basicTags": [
|
||||
"Device",
|
||||
"Gateway"
|
||||
],
|
||||
"paramTypes": [
|
||||
{
|
||||
"name": "host",
|
||||
"type": "QString",
|
||||
"inputType": "TextLine"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "a4d83813-10f3-4830-be2e-60d4815906c4",
|
||||
"idName": "battery",
|
||||
"name": "battery voltage",
|
||||
"type": "double",
|
||||
"unit": "Volt",
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "2df871fc-1888-4b04-8f02-f17b26642534",
|
||||
"idName": "count",
|
||||
"name": "count",
|
||||
"type": "int",
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "783e74ee-ffd6-4dd7-ade5-3a961452cf15",
|
||||
"idName": "reachable",
|
||||
"name": "reachable",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "b184ccc8-e7d9-4e94-8683-07f81484bbda",
|
||||
"idName": "led",
|
||||
"name": "led",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"writable": true
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
{
|
||||
"id": "b8e5da6c-501c-493e-8b0f-8ef09efb9057",
|
||||
"idName": "reset",
|
||||
"name": "reset"
|
||||
}
|
||||
],
|
||||
"eventTypes": [
|
||||
{
|
||||
"id": "2077a9ad-7f4b-4dd4-ae1c-7ecbe0a92dc0",
|
||||
"idName": "button",
|
||||
"name": "button"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
9
plugins/deviceplugins/orderbutton/orderbutton.pro
Normal file
9
plugins/deviceplugins/orderbutton/orderbutton.pro
Normal file
@ -0,0 +1,9 @@
|
||||
include(../../plugins.pri)
|
||||
|
||||
TARGET = $$qtLibraryTarget(guh_devicepluginorderbutton)
|
||||
|
||||
SOURCES += \
|
||||
devicepluginorderbutton.cpp
|
||||
|
||||
HEADERS += \
|
||||
devicepluginorderbutton.h
|
||||
Reference in New Issue
Block a user