From e30aace156f9fc78766d5cabc58003a1d5c90652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 11 Apr 2016 13:13:50 +0200 Subject: [PATCH] add orderbutton plugin add coap to the libguh source for dev package --- debian/guh-plugins-merkur.install | 1 + libguh/libguh.pro | 21 +- .../awattar/devicepluginawattar.cpp | 2 +- .../datetime/deviceplugindatetime.cpp | 2 +- plugins/deviceplugins/deviceplugins.pro | 1 + .../dollhouse/deviceplugindollhouse.cpp | 25 + .../orderbutton/devicepluginorderbutton.cpp | 489 ++++++++++++++++++ .../orderbutton/devicepluginorderbutton.h | 86 +++ .../orderbutton/devicepluginorderbutton.json | 85 +++ .../deviceplugins/orderbutton/orderbutton.pro | 9 + 10 files changed, 718 insertions(+), 3 deletions(-) create mode 100644 plugins/deviceplugins/orderbutton/devicepluginorderbutton.cpp create mode 100644 plugins/deviceplugins/orderbutton/devicepluginorderbutton.h create mode 100644 plugins/deviceplugins/orderbutton/devicepluginorderbutton.json create mode 100644 plugins/deviceplugins/orderbutton/orderbutton.pro diff --git a/debian/guh-plugins-merkur.install b/debian/guh-plugins-merkur.install index 17ce7d38..98b26a30 100644 --- a/debian/guh-plugins-merkur.install +++ b/debian/guh-plugins-merkur.install @@ -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 diff --git a/libguh/libguh.pro b/libguh/libguh.pro index 1bf717ec..6f3a308f 100644 --- a/libguh/libguh.pro +++ b/libguh/libguh.pro @@ -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 diff --git a/plugins/deviceplugins/awattar/devicepluginawattar.cpp b/plugins/deviceplugins/awattar/devicepluginawattar.cpp index 668c0fd2..dc37f8f4 100644 --- a/plugins/deviceplugins/awattar/devicepluginawattar.cpp +++ b/plugins/deviceplugins/awattar/devicepluginawattar.cpp @@ -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 diff --git a/plugins/deviceplugins/datetime/deviceplugindatetime.cpp b/plugins/deviceplugins/datetime/deviceplugindatetime.cpp index c6d0e67e..509488e1 100644 --- a/plugins/deviceplugins/datetime/deviceplugindatetime.cpp +++ b/plugins/deviceplugins/datetime/deviceplugindatetime.cpp @@ -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. diff --git a/plugins/deviceplugins/deviceplugins.pro b/plugins/deviceplugins/deviceplugins.pro index a6207372..9e79917e 100644 --- a/plugins/deviceplugins/deviceplugins.pro +++ b/plugins/deviceplugins/deviceplugins.pro @@ -24,3 +24,4 @@ SUBDIRS += elro \ plantcare \ osdomotics \ ws2812 \ + orderbutton \ diff --git a/plugins/deviceplugins/dollhouse/deviceplugindollhouse.cpp b/plugins/deviceplugins/dollhouse/deviceplugindollhouse.cpp index 59be1248..2b89c42b 100644 --- a/plugins/deviceplugins/dollhouse/deviceplugindollhouse.cpp +++ b/plugins/deviceplugins/dollhouse/deviceplugindollhouse.cpp @@ -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" diff --git a/plugins/deviceplugins/orderbutton/devicepluginorderbutton.cpp b/plugins/deviceplugins/orderbutton/devicepluginorderbutton.cpp new file mode 100644 index 00000000..9f173a48 --- /dev/null +++ b/plugins/deviceplugins/orderbutton/devicepluginorderbutton.cpp @@ -0,0 +1,489 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * Copyright (C) 2016 Bernhard Trinnes * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +#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()); + reply->deleteLater(); + return; + } + + QByteArray data = reply->readAll(); + qCDebug(dcOrderButton) << "Node discovery finished:" << endl << data; + + QList deviceDescriptors; + QList 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()); + } +} diff --git a/plugins/deviceplugins/orderbutton/devicepluginorderbutton.h b/plugins/deviceplugins/orderbutton/devicepluginorderbutton.h new file mode 100644 index 00000000..d140dbaa --- /dev/null +++ b/plugins/deviceplugins/orderbutton/devicepluginorderbutton.h @@ -0,0 +1,86 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * Copyright (C) 2015 Bernhard Trinnes * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DEVICEPLUGINORDERBUTTON_H +#define DEVICEPLUGINORDERBUTTON_H + +#include "plugin/deviceplugin.h" +#include "types/action.h" +#include "coap/coap.h" + +#include + +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 m_coap; + QHash m_asyncNodeScans; + QHash m_enableNotification; + QHash m_pingReplies; + + // State updates + QHash m_updateReplies; + + // Actions + QHash m_asyncActions; + + QHash m_resetCounterRequests; + QHash m_setCount; + QHash 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 diff --git a/plugins/deviceplugins/orderbutton/devicepluginorderbutton.json b/plugins/deviceplugins/orderbutton/devicepluginorderbutton.json new file mode 100644 index 00000000..ddb91d75 --- /dev/null +++ b/plugins/deviceplugins/orderbutton/devicepluginorderbutton.json @@ -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" + } + ] + } + ] + } + ] +} diff --git a/plugins/deviceplugins/orderbutton/orderbutton.pro b/plugins/deviceplugins/orderbutton/orderbutton.pro new file mode 100644 index 00000000..5c0b8164 --- /dev/null +++ b/plugins/deviceplugins/orderbutton/orderbutton.pro @@ -0,0 +1,9 @@ +include(../../plugins.pri) + +TARGET = $$qtLibraryTarget(guh_devicepluginorderbutton) + +SOURCES += \ + devicepluginorderbutton.cpp + +HEADERS += \ + devicepluginorderbutton.h