From 1bf4aa3f3903170e1dc2cfb6bc34e746c7ab5b2b Mon Sep 17 00:00:00 2001 From: Boernsman Date: Sun, 5 Jan 2020 00:15:15 +0100 Subject: [PATCH 01/12] added dynatrace ufo --- debian/control | 15 ++ debian/nymea-plugin-dynatrace.install.in | 1 + dynatrace/README.md | 20 ++ dynatrace/deviceplugindynatrace.cpp | 219 ++++++++++++++++++ dynatrace/deviceplugindynatrace.h | 66 ++++++ dynatrace/deviceplugindynatrace.json | 139 +++++++++++ dynatrace/dynatrace.pro | 13 ++ ...51bd7-69cb-4106-968f-1206a5736368-en_US.ts | 205 ++++++++++++++++ dynatrace/ufo.cpp | 159 +++++++++++++ dynatrace/ufo.h | 65 ++++++ nymea-plugins.pro | 1 + 11 files changed, 903 insertions(+) create mode 100644 debian/nymea-plugin-dynatrace.install.in create mode 100644 dynatrace/README.md create mode 100644 dynatrace/deviceplugindynatrace.cpp create mode 100644 dynatrace/deviceplugindynatrace.h create mode 100644 dynatrace/deviceplugindynatrace.json create mode 100644 dynatrace/dynatrace.pro create mode 100644 dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts create mode 100644 dynatrace/ufo.cpp create mode 100644 dynatrace/ufo.h diff --git a/debian/control b/debian/control index 6efef76e..8c06dd32 100644 --- a/debian/control +++ b/debian/control @@ -215,6 +215,21 @@ Description: nymea.io plugin for dweet.io This package will install the nymea.io plugin for dweet.io +Package: nymea-plugin-dynatrace +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + nymea-plugins-translations, +Description: nymea.io plugin for dynatrace + 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 dynatrace + + Package: nymea-plugin-elgato Architecture: any Depends: ${shlibs:Depends}, diff --git a/debian/nymea-plugin-dynatrace.install.in b/debian/nymea-plugin-dynatrace.install.in new file mode 100644 index 00000000..80cc26d7 --- /dev/null +++ b/debian/nymea-plugin-dynatrace.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_deviceplugindynatrace.so diff --git a/dynatrace/README.md b/dynatrace/README.md new file mode 100644 index 00000000..14d22069 --- /dev/null +++ b/dynatrace/README.md @@ -0,0 +1,20 @@ +# Dynatrace + +This plug-in enables nymea to control the Dynatrace Ufo. + + +## Device Setup + +An excerpt of the Ufo (Blog Post)[https://www.dynatrace.com/news/blog/using-dynatrace-devops-pipeline-state-ufo/] + +* Plug it in! +* Press the little black dot on the top. The UFO starts blinking blue and now offers a WiFi hotspot with the name “ufo” +* Connect to that hotspot, browse to http://192.168.4.1 +* Through the Web UI connect to your own WiFi. You can also do it via the REST API: http://192.168.4.1/api?ssid=&pwd= +* Remember: WPA2 works well where Enterprise WPA2 is currently not supported +* While it reboots itself it will blink yellow. Once it has its assigned IP Address it will start visualizing its IP Address through a special „blink code“ as explained in the Quick Start Guide! +* Remember: the UFO will also try to register its hostname as „ufo“ with your DHCP server. If that works you can simply browse to http://ufo + +More about the Dynatrace Ufo: +https://github.com/Dynatrace/ufo + diff --git a/dynatrace/deviceplugindynatrace.cpp b/dynatrace/deviceplugindynatrace.cpp new file mode 100644 index 00000000..3f9edb64 --- /dev/null +++ b/dynatrace/deviceplugindynatrace.cpp @@ -0,0 +1,219 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* This project may also contain libraries licensed under the open source software license GNU GPL v.3. +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project 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 project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "deviceplugindynatrace.h" +#include "devices/device.h" +#include "plugininfo.h" +#include "network/networkaccessmanager.h" + +#include +#include +#include +#include + +DevicePluginDynatrace::DevicePluginDynatrace() +{ + +} + +void DevicePluginDynatrace::discoverDevices(DeviceDiscoveryInfo *info) +{ + if (info->deviceClassId() == ufoDeviceClassId) { + + QHostInfo::lookupHost("ufo.home", this, [info, this](const QHostInfo &host){ + if (host.error() != QHostInfo::NoError) { + qCDebug(dcDynatrace()) << "Lookup failed:" << host.errorString(); + } + + foreach (QHostAddress address, host.addresses()) { + qCDebug(dcDynatrace()) << "Found IP address" << address.toString(); + + DeviceDescriptor descriptor(ufoDeviceClassId, "Ufo", address.toString()); + ParamList params; + + /*Device *existingDevice = myDevices().findByParams(ParamList() << Param(ufoDeviceIdParamTypeId, "")); + if (existingDevice) { + //For device re-discovery + descriptor.setDeviceId(existingDevice->id()); + }*/ + params << Param(ufoDeviceHostParamTypeId, address.toString()); + descriptor.setParams(params); + info->addDeviceDescriptor(descriptor); + } + info->finish(Device::DeviceErrorNoError); + }); + } +} + +void DevicePluginDynatrace::setupDevice(DeviceSetupInfo *info) +{ + + if (info->device()->deviceClassId() == ufoDeviceClassId) { + QHostAddress address = QHostAddress(info->device()->paramValue(ufoDeviceHostParamTypeId).toString()); + QString id = info->device()->paramValue(ufoDeviceIdParamTypeId).toString(); + if(id.isEmpty()) { //Probably a manual device setup + QUrl url; + url.setScheme("http"); + url.setHost(address.toString()); + url.setPath("/info", QUrl::ParsingMode::TolerantMode); + QNetworkRequest request; + request.setUrl(url); + QNetworkReply *reply = hardwareManager()->networkManager()->get(request); + connect(reply, &QNetworkReply::finished, this, [info, reply, this] { + reply->deleteLater(); + + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + info->finish(Device::DeviceErrorSetupFailed, error.errorString()); + } + + QString id = data.toVariant().toMap().value("ufoid").toString(); + info->device()->setParamValue(ufoDeviceIdParamTypeId, id); + info->finish(Device::DeviceErrorNoError); + }); + } else { + // Discovery device setup + info->finish(Device::DeviceErrorNoError); + } + } +} + +void DevicePluginDynatrace::postSetupDevice(Device *device) +{ + if (device->deviceClassId() == ufoDeviceClassId) { + QHostAddress address = QHostAddress(device->paramValue(ufoDeviceHostParamTypeId).toString()); + Ufo *ufo = new Ufo(hardwareManager()->networkManager(), address, this); + m_ufoConnections.insert(device->id(), ufo); + ufo->resetLogo(); + } + + if(!m_pluginTimer) { + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60); + connect(m_pluginTimer, &PluginTimer::timeout, this, [this]() { + //TODO check if device is reachable + }); + } +} + +void DevicePluginDynatrace::executeAction(DeviceActionInfo *info) +{ + Device *device = info->device(); + Action action = info->action(); + + if (device->deviceClassId() == ufoDeviceClassId) { + Ufo *ufo = m_ufoConnections.value(device->id()); + if (!ufo) + return; + if (action.actionTypeId() == ufoLogoActionTypeId) { + bool power = action.param(ufoLogoActionLogoParamTypeId).value().toBool(); + device->setStateValue(ufoLogoStateTypeId, power); + if (power) { + ufo->resetLogo(); + } else { + QColor color; + color.setRgb(0, 0, 0); + ufo->setLogo(color, color, color, color); + } + info->finish(Device::DeviceErrorNoError); + + } else if (action.actionTypeId() == ufoPowerActionTypeId) { + bool power = action.param(ufoPowerActionPowerParamTypeId).value().toBool(); + device->setStateValue(ufoPowerStateTypeId, power); + if (power) { + ufo->setBackgroundColor(true, true, QColor(Qt::white)); //#ffffff + } else { + ufo->setBackgroundColor(true, true, QColor(Qt::black)); //#000000 + } + info->finish(Device::DeviceErrorNoError); + + } else if (action.actionTypeId() == ufoBrightnessActionTypeId) { + int brightness = action.param(ufoBrightnessActionBrightnessParamTypeId).value().toInt(); + QColor color = QColor(device->stateValue(ufoColorStateTypeId).toString()); + color.setHsv(color.hue(), color.saturation(), brightness); + ufo->setBackgroundColor(true, true, color); + info->finish(Device::DeviceErrorNoError); + } else if (action.actionTypeId() == ufoColorActionTypeId) { + QColor color = QColor(action.param(ufoColorActionColorParamTypeId).value().toString()); + int brightness = device->stateValue(ufoBrightnessStateTypeId).toInt(); + device->setStateValue(ufoColorStateTypeId, color); + color.setHsv(color.hue(), color.saturation(), brightness); + ufo->setBackgroundColor(true, true, color); + info->finish(Device::DeviceErrorNoError); + } else { + qCWarning(dcDynatrace()) << "Execute action: Unhandled actionTypeId"; + } + } else { + qCWarning(dcDynatrace()) << "Execute action: Unhandled deviceClass"; + } +} + +void DevicePluginDynatrace::deviceRemoved(Device *device) +{ + if (device->deviceClassId() == ufoDeviceClassId) { + if (m_ufoConnections.contains(device->id())){ + Ufo *ufo = m_ufoConnections.take(device->id()); + ufo->deleteLater(); + } + } + + if (myDevices().isEmpty() && m_pluginTimer) { + m_pluginTimer->deleteLater(); + m_pluginTimer = nullptr; + } +} + +void DevicePluginDynatrace::getId(const QHostAddress &address) +{ + QUrl url; + url.setScheme("http"); + url.setHost(address.toString()); + url.setPath("/info", QUrl::ParsingMode::TolerantMode); + QNetworkRequest request; + request.setUrl(url); + QNetworkReply *reply = hardwareManager()->networkManager()->get(request); + connect(reply, &QNetworkReply::finished, this, [reply, this] { + reply->deleteLater(); + + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) + return; + + QString id = data.toVariant().toMap().value("ufoid").toString(); + if (m_asyncSetup.contains(reply->url().host())) { + DeviceSetupInfo *info = m_asyncSetup.value(reply->url().host()); + info->finish(Device::DeviceErrorNoError); + } + }); +} + +void DevicePluginDynatrace::onConnectionChanged(bool connected) +{ + Q_UNUSED(connected) +} diff --git a/dynatrace/deviceplugindynatrace.h b/dynatrace/deviceplugindynatrace.h new file mode 100644 index 00000000..f55f91a4 --- /dev/null +++ b/dynatrace/deviceplugindynatrace.h @@ -0,0 +1,66 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* This project may also contain libraries licensed under the open source software license GNU GPL v.3. +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project 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 project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DEVICEPLUGINDYNATRACE_H +#define DEVICEPLUGINDYNATRACE_H + +#include "plugintimer.h" +#include "devices/deviceplugin.h" +#include "network/oauth2.h" +#include "ufo.h" + +#include +#include + +class DevicePluginDynatrace : public DevicePlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "deviceplugindynatrace.json") + Q_INTERFACES(DevicePlugin) + +public: + explicit DevicePluginDynatrace(); + void discoverDevices(DeviceDiscoveryInfo *info) override; + void setupDevice(DeviceSetupInfo *info) override; + void postSetupDevice(Device *device) override; + void executeAction(DeviceActionInfo *info) override; + void deviceRemoved(Device *device) override; + +private: + PluginTimer *m_pluginTimer = nullptr; + QHash m_ufoConnections; + QHash m_asyncActions; + QHash m_asyncSetup; + + void getId(const QHostAddress &address); + +private slots: + void onConnectionChanged(bool connected); +}; + +#endif // DEVICEPLUGINDYNATRACE_H diff --git a/dynatrace/deviceplugindynatrace.json b/dynatrace/deviceplugindynatrace.json new file mode 100644 index 00000000..e2eac5e2 --- /dev/null +++ b/dynatrace/deviceplugindynatrace.json @@ -0,0 +1,139 @@ +{ + "displayName": "Dynatrace", + "name": "dynatrace", + "id": "a8451bd7-69cb-4106-968f-1206a5736368", + "vendors": [ + { + "name": "Dynatrace", + "displayName": "Dynatrace", + "id": "31b402be-1562-4335-aa83-d1c1166db570", + "deviceClasses": [ + { + "id": "6271f010-0b0a-4f29-b894-0611bb5f3dcc", + "name": "ufo", + "displayName": "ufo", + "createMethods": ["user", "discovery"], + "interfaces": ["colorlight", "alert", "connectable"], + "paramTypes": [ + { + "id": "3e14968b-954e-4e85-ae79-3de9ae4fe951", + "name": "host", + "displayName": "Host address", + "type" : "QString", + "inputType": "IPv4Address", + "readOnly": true + }, + { + "id": "142c25c0-03e3-478e-b5c3-3d072f668cc4", + "name": "id", + "displayName": "Id", + "type" : "QString", + "readOnly": true + } + ], + "actionTypes": [ + { + "id": "6efa52d9-527b-4ac7-8885-50f2b1786561", + "name": "alert", + "displayName": "flash", + "paramTypes": [ + { + "id": "e8d854ce-02d0-4ddd-a2bd-0c464cbb9182", + "name": "alert", + "displayName": "alert", + "type": "QString", + "defaultValue": "flash", + "allowedValues": [ + "flash", + "flash 15 [s]" + ] + } + ] + } + ], + "stateTypes": [ + { + "id": "1a439907-e810-4dea-b357-dd32281896e7", + "name": "connected", + "displayName": "Reachable", + "displayNameEvent": "Reachable changed", + "defaultValue": false, + "type": "bool" + }, + { + "id": "a9c123e2-db78-40d3-a422-7e4817d50984", + "name": "logo", + "displayName": "Logo", + "displayNameEvent": "Logo changed", + "displayNameAction": "Set logo", + "defaultValue": false, + "type": "bool", + "writable": true + }, + { + "id": "14ac8d16-72be-4530-a2ce-dd5589ce8dd7", + "name": "power", + "displayName": "Power", + "displayNameEvent": "Power changed", + "displayNameAction": "Set power", + "type": "bool", + "defaultValue": false, + "writable": true + }, + { + "id": "60fa917b-8702-4ff2-90b8-9c8c616bb21f", + "name": "colorTemperature", + "displayName": "Color temperature", + "displayNameEvent": "Color temperature changed", + "displayNameAction": "Set color temperature", + "type": "int", + "unit": "Mired", + "defaultValue": 170, + "minValue": 153, + "maxValue": 500, + "writable": true + }, + { + "id": "9535fd99-05c6-449f-80a2-8daf61d9b9b0", + "name": "color", + "displayName": "Color", + "displayNameEvent": "Color changed", + "displayNameAction": "Set color", + "type": "QColor", + "defaultValue": "#000000", + "writable": true + }, + { + "id": "1adb2df8-7ba1-48b8-b0da-d67085efe041", + "name": "brightness", + "displayName": "Brightness", + "displayNameEvent": "Brightness changed", + "displayNameAction": "Set brigtness", + "type": "int", + "unit": "Percentage", + "defaultValue": 0, + "minValue": 0, + "maxValue": 100, + "writable": true + }, + { + "id": "53da0021-974a-434a-94ac-3f187aad1480", + "name": "effect", + "displayName": "Effect", + "displayNameEvent": "Effect changed", + "displayNameAction": "Set effect", + "type": "QString", + "defaultValue": "None", + "possibleValues": [ + "None", + "Morph", + "Whirl" + ], + "writable": true + } + ] + } + ] + } + ] +} diff --git a/dynatrace/dynatrace.pro b/dynatrace/dynatrace.pro new file mode 100644 index 00000000..41ab4c98 --- /dev/null +++ b/dynatrace/dynatrace.pro @@ -0,0 +1,13 @@ +include(../plugins.pri) + +QT += network + +TARGET = $$qtLibraryTarget(nymea_deviceplugindynatrace) + +SOURCES += \ + deviceplugindynatrace.cpp \ + ufo.cpp + +HEADERS += \ + deviceplugindynatrace.h \ + ufo.h diff --git a/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts b/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts new file mode 100644 index 00000000..2d702e9c --- /dev/null +++ b/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts @@ -0,0 +1,205 @@ + + + + + dynatrace + + + + + Brightness + The name of the ParamType (DeviceClass: ufo, ActionType: brightness, ID: {1adb2df8-7ba1-48b8-b0da-d67085efe041}) +---------- +The name of the ParamType (DeviceClass: ufo, EventType: brightness, ID: {1adb2df8-7ba1-48b8-b0da-d67085efe041}) +---------- +The name of the StateType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of DeviceClass ufo + + + + + Brightness changed + The name of the EventType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of DeviceClass ufo + + + + + + + Color + The name of the ParamType (DeviceClass: ufo, ActionType: color, ID: {9535fd99-05c6-449f-80a2-8daf61d9b9b0}) +---------- +The name of the ParamType (DeviceClass: ufo, EventType: color, ID: {9535fd99-05c6-449f-80a2-8daf61d9b9b0}) +---------- +The name of the StateType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of DeviceClass ufo + + + + + Color changed + The name of the EventType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of DeviceClass ufo + + + + + + + Color temperature + The name of the ParamType (DeviceClass: ufo, ActionType: colorTemperature, ID: {60fa917b-8702-4ff2-90b8-9c8c616bb21f}) +---------- +The name of the ParamType (DeviceClass: ufo, EventType: colorTemperature, ID: {60fa917b-8702-4ff2-90b8-9c8c616bb21f}) +---------- +The name of the StateType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of DeviceClass ufo + + + + + Color temperature changed + The name of the EventType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of DeviceClass ufo + + + + + + Dynatrace + The name of the vendor ({31b402be-1562-4335-aa83-d1c1166db570}) +---------- +The name of the plugin dynatrace ({a8451bd7-69cb-4106-968f-1206a5736368}) + + + + + + + Effect + The name of the ParamType (DeviceClass: ufo, ActionType: effect, ID: {53da0021-974a-434a-94ac-3f187aad1480}) +---------- +The name of the ParamType (DeviceClass: ufo, EventType: effect, ID: {53da0021-974a-434a-94ac-3f187aad1480}) +---------- +The name of the StateType ({53da0021-974a-434a-94ac-3f187aad1480}) of DeviceClass ufo + + + + + Effect changed + The name of the EventType ({53da0021-974a-434a-94ac-3f187aad1480}) of DeviceClass ufo + + + + + Host address + The name of the ParamType (DeviceClass: ufo, Type: device, ID: {3e14968b-954e-4e85-ae79-3de9ae4fe951}) + + + + + Id + The name of the ParamType (DeviceClass: ufo, Type: device, ID: {142c25c0-03e3-478e-b5c3-3d072f668cc4}) + + + + + + + Logo + The name of the ParamType (DeviceClass: ufo, ActionType: logo, ID: {a9c123e2-db78-40d3-a422-7e4817d50984}) +---------- +The name of the ParamType (DeviceClass: ufo, EventType: logo, ID: {a9c123e2-db78-40d3-a422-7e4817d50984}) +---------- +The name of the StateType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of DeviceClass ufo + + + + + Logo changed + The name of the EventType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of DeviceClass ufo + + + + + + + Power + The name of the ParamType (DeviceClass: ufo, ActionType: power, ID: {14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) +---------- +The name of the ParamType (DeviceClass: ufo, EventType: power, ID: {14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) +---------- +The name of the StateType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of DeviceClass ufo + + + + + Power changed + The name of the EventType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of DeviceClass ufo + + + + + + Reachable + The name of the ParamType (DeviceClass: ufo, EventType: connected, ID: {1a439907-e810-4dea-b357-dd32281896e7}) +---------- +The name of the StateType ({1a439907-e810-4dea-b357-dd32281896e7}) of DeviceClass ufo + + + + + Reachable changed + The name of the EventType ({1a439907-e810-4dea-b357-dd32281896e7}) of DeviceClass ufo + + + + + Set brigtness + The name of the ActionType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of DeviceClass ufo + + + + + Set color + The name of the ActionType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of DeviceClass ufo + + + + + Set color temperature + The name of the ActionType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of DeviceClass ufo + + + + + Set effect + The name of the ActionType ({53da0021-974a-434a-94ac-3f187aad1480}) of DeviceClass ufo + + + + + Set logo + The name of the ActionType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of DeviceClass ufo + + + + + Set power + The name of the ActionType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of DeviceClass ufo + + + + + alert + The name of the ParamType (DeviceClass: ufo, ActionType: alert, ID: {e8d854ce-02d0-4ddd-a2bd-0c464cbb9182}) + + + + + flash + The name of the ActionType ({6efa52d9-527b-4ac7-8885-50f2b1786561}) of DeviceClass ufo + + + + + ufo + The name of the DeviceClass ({6271f010-0b0a-4f29-b894-0611bb5f3dcc}) + + + + diff --git a/dynatrace/ufo.cpp b/dynatrace/ufo.cpp new file mode 100644 index 00000000..ff9232d6 --- /dev/null +++ b/dynatrace/ufo.cpp @@ -0,0 +1,159 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* This project may also contain libraries licensed under the open source software license GNU GPL v.3. +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project 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 project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "ufo.h" +#include "extern-plugininfo.h" +#include + +Ufo::Ufo(NetworkAccessManager *networkManager, const QHostAddress &address, QObject *parent) : + QObject(parent), + m_networkManager(networkManager), + m_address(address) +{ + +} + +void Ufo::resetLogo() +{ + QUrl url; + url.setScheme("http"); + url.setHost(m_address.toString()); + url.setPath("/api"); + url.setQuery("logo_reset"); + QNetworkRequest request; + request.setUrl(url); + qCDebug(dcDynatrace()) << "Sending request" << url; + QNetworkReply *reply = m_networkManager->get(request); + connect(reply, &QNetworkReply::finished, this, [reply, this] { + reply->deleteLater(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + // Check HTTP status code + if (status != 200 || reply->error() != QNetworkReply::NoError) { + qCWarning(dcDynatrace()) << "Request error:" << status << reply->errorString(); + emit connectionChanged(false); + return; + } + emit connectionChanged(true); + }); + +} + +void Ufo::setLogo(QColor led1, QColor led2, QColor led3, QColor led4) +{ + QUrl url; + url.setScheme("http"); + url.setHost(m_address.toString()); + url.setPath("/api"); + QUrlQuery query; + query.addQueryItem("logo", led1.name().remove(0,1)+"|"+led2.name().remove(0,1)+"|"+led3.name().remove(0,1)+"|"+led4.name().remove(0,1)); + url.setQuery(query); + QNetworkRequest request; + request.setUrl(url); + + qCDebug(dcDynatrace()) << "Sending request" << url; + QNetworkReply *reply = m_networkManager->get(request); + connect(reply, &QNetworkReply::finished, this, [reply, this] { + reply->deleteLater(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + // Check HTTP status code + if (status != 200 || reply->error() != QNetworkReply::NoError) { + qCWarning(dcDynatrace()) << "Request error:" << status << reply->errorString(); + emit connectionChanged(false); + return; + } + emit connectionChanged(true); + }); +} + +void Ufo::initBackgroundColor(bool top, bool bottom) +{ + QUrl url; + url.setScheme("http"); + url.setHost(m_address.toString()); + url.setPath("/api"); + if (top) { + url.setQuery("top_init"); + } + if (bottom) { + url.setQuery("bottom_init"); + } + QNetworkRequest request; + request.setUrl(url); + + qCDebug(dcDynatrace()) << "Sending request" << url; + QNetworkReply *reply = m_networkManager->get(request); + connect(reply, &QNetworkReply::finished, this, [reply, this] { + reply->deleteLater(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + // Check HTTP status code + if (status != 200 || reply->error() != QNetworkReply::NoError) { + qCWarning(dcDynatrace()) << "Request error:" << status << reply->errorString(); + emit connectionChanged(false); + return; + } + emit connectionChanged(true); + }); +} + +void Ufo::setBackgroundColor(bool top, bool bottom, QColor color) +{ + QUrl url; + url.setScheme("http"); + url.setHost(m_address.toString()); + url.setPath("/api"); + QUrlQuery query; + if (top){ + query.addQueryItem("top_init", "0"); + query.addQueryItem("top_bg", color.name().remove(0,1)); + } + if (bottom) { + query.addQueryItem("bottom_init", "0"); + query.addQueryItem("bottom_bg", color.name().remove(0,1)); + } + url.setQuery(query); + QNetworkRequest request; + request.setUrl(url); + + qCDebug(dcDynatrace()) << "Sending request" << url; + QNetworkReply *reply = m_networkManager->get(request); + connect(reply, &QNetworkReply::finished, this, [reply, this] { + reply->deleteLater(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + // Check HTTP status code + if (status != 200 || reply->error() != QNetworkReply::NoError) { + qCWarning(dcDynatrace()) << "Request error:" << status << reply->errorString(); + emit connectionChanged(false); + return; + } + emit connectionChanged(true); + }); +} diff --git a/dynatrace/ufo.h b/dynatrace/ufo.h new file mode 100644 index 00000000..a2e1ebdc --- /dev/null +++ b/dynatrace/ufo.h @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by copyright law, and +* remains the property of nymea GmbH. All rights, including reproduction, publication, +* editing and translation, are reserved. The use of this project is subject to the terms of a +* license agreement to be concluded with nymea GmbH in accordance with the terms +* of use of nymea GmbH, available under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* This project may also contain libraries licensed under the open source software license GNU GPL v.3. +* Alternatively, this project may be redistributed and/or modified under the terms of the GNU +* Lesser General Public License as published by the Free Software Foundation; version 3. +* this project 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 project. +* If not, see . +* +* For any further details and any questions please contact us under contact@nymea.io +* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DYNATRACE_UFO_H +#define DYNATRACE_UFO_H + +#include "network/networkaccessmanager.h" +#include "devices/device.h" + +#include +#include +#include +#include + +class Ufo : public QObject +{ + Q_OBJECT +public: + explicit Ufo(NetworkAccessManager *networkManager, const QHostAddress &address, QObject *parent = nullptr); + + void resetLogo(); + void setLogo(QColor led1, QColor led2, QColor led3, QColor led4); + void initBackgroundColor(bool top, bool bottom); + void setBackgroundColor(bool top, bool bottom, QColor color); + void setLeds(bool top, int ledIndex, int numOfLeds, QColor color); + void startWhirl(bool top, bool bottom, int speed, bool clockwise); + void stopWhirl(bool top, bool bottom); + void startMorph(bool top, bool bottom, int speed, bool time); + void stopMorph(bool top, bool bottom); + + +private: + NetworkAccessManager *m_networkManager; + QHostAddress m_address; + +signals: + void connectionChanged(bool reachable); + +}; +#endif //DYNATRACE_UFO_H diff --git a/nymea-plugins.pro b/nymea-plugins.pro index 23d78cdf..7814a71b 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -13,6 +13,7 @@ PLUGIN_DIRS = \ daylightsensor \ denon \ dweetio \ + dynatrace \ elgato \ elro \ eq-3 \ From ff477cd2c7d53a2bee1606992f570b0d43185fe6 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Sun, 5 Jan 2020 11:49:00 +0100 Subject: [PATCH 02/12] added effects --- dynatrace/deviceplugindynatrace.cpp | 127 ++++++++++++++++++++++++--- dynatrace/deviceplugindynatrace.json | 75 ++++++++++------ dynatrace/ufo.cpp | 96 ++++++++++++++++++-- dynatrace/ufo.h | 6 +- 4 files changed, 257 insertions(+), 47 deletions(-) diff --git a/dynatrace/deviceplugindynatrace.cpp b/dynatrace/deviceplugindynatrace.cpp index 3f9edb64..e9a61b63 100644 --- a/dynatrace/deviceplugindynatrace.cpp +++ b/dynatrace/deviceplugindynatrace.cpp @@ -92,13 +92,12 @@ void DevicePluginDynatrace::setupDevice(DeviceSetupInfo *info) if (error.error != QJsonParseError::NoError) { info->finish(Device::DeviceErrorSetupFailed, error.errorString()); } - QString id = data.toVariant().toMap().value("ufoid").toString(); info->device()->setParamValue(ufoDeviceIdParamTypeId, id); info->finish(Device::DeviceErrorNoError); }); } else { - // Discovery device setup + // Discovery device setup or devices setup caused by nymea restart info->finish(Device::DeviceErrorNoError); } } @@ -107,10 +106,18 @@ void DevicePluginDynatrace::setupDevice(DeviceSetupInfo *info) void DevicePluginDynatrace::postSetupDevice(Device *device) { if (device->deviceClassId() == ufoDeviceClassId) { + device->setStateValue(ufoConnectedStateTypeId, true); //FIXME + device->setStateValue(ufoPowerStateTypeId, false); + device->setStateValue(ufoLogoStateTypeId, false); + device->setStateValue(ufoEffectTopStateTypeId, "None"); + device->setStateValue(ufoEffectBottomStateTypeId, "None"); + QHostAddress address = QHostAddress(device->paramValue(ufoDeviceHostParamTypeId).toString()); Ufo *ufo = new Ufo(hardwareManager()->networkManager(), address, this); m_ufoConnections.insert(device->id(), ufo); - ufo->resetLogo(); + // Set all off + ufo->setLogo(QColor(Qt::black), QColor(Qt::black), QColor(Qt::black), QColor(Qt::black)); + ufo->setBackgroundColor(true, true, true, true, QColor(Qt::black)); } if(!m_pluginTimer) { @@ -134,11 +141,12 @@ void DevicePluginDynatrace::executeAction(DeviceActionInfo *info) bool power = action.param(ufoLogoActionLogoParamTypeId).value().toBool(); device->setStateValue(ufoLogoStateTypeId, power); if (power) { - ufo->resetLogo(); - } else { - QColor color; - color.setRgb(0, 0, 0); + int brightness = device->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); + QColor color = QColor(device->stateValue(ufoLogoColorStateTypeId).toString()); + color.setHsv(color.hue(), color.saturation(), brightness*2.55); ufo->setLogo(color, color, color, color); + } else { + ufo->setLogo(QColor(Qt::black), QColor(Qt::black), QColor(Qt::black), QColor(Qt::black)); } info->finish(Device::DeviceErrorNoError); @@ -146,30 +154,123 @@ void DevicePluginDynatrace::executeAction(DeviceActionInfo *info) bool power = action.param(ufoPowerActionPowerParamTypeId).value().toBool(); device->setStateValue(ufoPowerStateTypeId, power); if (power) { - ufo->setBackgroundColor(true, true, QColor(Qt::white)); //#ffffff + int brightness = device->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); + QColor color = QColor(device->stateValue(ufoColorStateTypeId).toString()); + color.setHsv(color.hue(), color.saturation(), brightness*2.55); + device->setStateValue(ufoLogoStateTypeId, true); + ufo->setLogo(color, color, color, color); + ufo->setBackgroundColor(true, true, true, true, color); + device->setStateValue(ufoEffectTopStateTypeId, "None"); + device->setStateValue(ufoEffectBottomStateTypeId, "None"); + device->setStateValue(ufoLogoColorStateTypeId, color); + device->setStateValue(ufoTopColorStateTypeId, color); + device->setStateValue(ufoBottomColorStateTypeId, color); } else { - ufo->setBackgroundColor(true, true, QColor(Qt::black)); //#000000 + ufo->setLogo(QColor(Qt::black), QColor(Qt::black), QColor(Qt::black), QColor(Qt::black)); + device->setStateValue(ufoLogoStateTypeId, false); + ufo->setBackgroundColor(true, true, true, true, QColor(Qt::black)); + device->setStateValue(ufoEffectTopStateTypeId, "None"); + device->setStateValue(ufoEffectBottomStateTypeId, "None"); } info->finish(Device::DeviceErrorNoError); } else if (action.actionTypeId() == ufoBrightnessActionTypeId) { int brightness = action.param(ufoBrightnessActionBrightnessParamTypeId).value().toInt(); + device->setStateValue(ufoBrightnessStateTypeId, brightness); QColor color = QColor(device->stateValue(ufoColorStateTypeId).toString()); - color.setHsv(color.hue(), color.saturation(), brightness); - ufo->setBackgroundColor(true, true, color); + color.setHsv(color.hue(), color.saturation(), brightness*2.55); + if (device->stateValue(ufoLogoStateTypeId).toBool()) { + ufo->setLogo(color, color, color, color); + } + ufo->setBackgroundColor(true, false, true, false, color); info->finish(Device::DeviceErrorNoError); } else if (action.actionTypeId() == ufoColorActionTypeId) { QColor color = QColor(action.param(ufoColorActionColorParamTypeId).value().toString()); int brightness = device->stateValue(ufoBrightnessStateTypeId).toInt(); device->setStateValue(ufoColorStateTypeId, color); - color.setHsv(color.hue(), color.saturation(), brightness); - ufo->setBackgroundColor(true, true, color); + device->setStateValue(ufoLogoColorStateTypeId, color); + device->setStateValue(ufoTopColorStateTypeId, color); + device->setStateValue(ufoBottomColorStateTypeId, color); + color.setHsv(color.hue(), color.saturation(), brightness*2.55); + if (device->stateValue(ufoLogoStateTypeId).toBool()) { + ufo->setLogo(color, color, color, color); + } + ufo->setBackgroundColor(true, false, true, false, color); + info->finish(Device::DeviceErrorNoError); + } else if (action.actionTypeId() == ufoColorTemperatureActionTypeId) { + int mired= device->stateValue(ufoColorTemperatureActionColorTemperatureParamTypeId).toInt(); + device->setStateValue(ufoColorTemperatureStateTypeId, mired); + int brightness = device->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); + QColor color(Qt::white); + color.setBlue(static_cast((mired-153)*0.73)); + color.setHsv(color.hue(), color.saturation(), brightness*2.55); + if (device->stateValue(ufoLogoStateTypeId).toBool()) { + ufo->setLogo(color, color, color, color); + } + device->setStateValue(ufoColorStateTypeId, color); + device->setStateValue(ufoLogoColorStateTypeId, color); + device->setStateValue(ufoTopColorStateTypeId, color); + device->setStateValue(ufoBottomColorStateTypeId, color); + ufo->setBackgroundColor(true, false, true, false, color); + info->finish(Device::DeviceErrorNoError); + + } else if (action.actionTypeId() == ufoEffectTopActionTypeId) { + QString effect = action.param(ufoEffectTopActionEffectTopParamTypeId).value().toString(); + int brightness = device->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); + QColor color = QColor(device->stateValue(ufoColorStateTypeId).toString()); + color.setHsv(color.hue(), color.saturation(), brightness*2.55); + if (effect == "None") { + ufo->setBackgroundColor(true, true, false, false, color); + } else if (effect == "Whirl") { + ufo->startWhirl(true, false, color, 500, true); + } else if (effect == "Morph") { + ufo->startMorph(true, false, color, 250, 8); + } + info->finish(Device::DeviceErrorNoError); + } else if (action.actionTypeId() == ufoEffectBottomActionTypeId) { + QString effect = action.param(ufoEffectBottomActionEffectBottomParamTypeId).value().toString(); + int brightness = device->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); + QColor color = QColor(device->stateValue(ufoColorStateTypeId).toString()); + color.setHsv(color.hue(), color.saturation(), brightness*2.55); + if (effect == "None") { + ufo->setBackgroundColor(false, false, true, true, color); + } else if (effect == "Whirl") { + ufo->startWhirl(false, true, color, 500, true); + } else if (effect == "Morph") { + ufo->startMorph(false, true, color, 250, 8); + } + info->finish(Device::DeviceErrorNoError); + } else if (action.actionTypeId() == ufoLogoColorActionTypeId) { + QColor color = QColor(action.param(ufoLogoColorActionLogoColorParamTypeId).value().toString()); + int brightness = device->stateValue(ufoBrightnessStateTypeId).toInt(); + device->setStateValue(ufoLogoColorStateTypeId, color); + device->setStateValue(ufoLogoStateTypeId, true); + color.setHsv(color.hue(), color.saturation(), brightness*2.55); + ufo->setLogo(color, color, color, color); + info->finish(Device::DeviceErrorNoError); + } else if (action.actionTypeId() == ufoTopColorActionTypeId) { + QColor color = QColor(action.param(ufoTopColorActionTopColorParamTypeId).value().toString()); + int brightness = device->stateValue(ufoBrightnessStateTypeId).toInt(); + device->setStateValue(ufoTopColorStateTypeId, color); + device->setStateValue(ufoPowerStateTypeId, true); + color.setHsv(color.hue(), color.saturation(), brightness*2.55); + ufo->setBackgroundColor(true, false, false, false, color); + info->finish(Device::DeviceErrorNoError); + } else if (action.actionTypeId() == ufoBottomColorActionTypeId) { + QColor color = QColor(action.param(ufoBottomColorActionBottomColorParamTypeId).value().toString()); + int brightness = device->stateValue(ufoBrightnessStateTypeId).toInt(); + device->setStateValue(ufoBottomColorStateTypeId, color); + device->setStateValue(ufoPowerStateTypeId, true); + color.setHsv(color.hue(), color.saturation(), brightness*2.55); + ufo->setBackgroundColor(false, false, true, false, color); info->finish(Device::DeviceErrorNoError); } else { qCWarning(dcDynatrace()) << "Execute action: Unhandled actionTypeId"; + info->finish(Device::DeviceErrorHardwareFailure); } } else { qCWarning(dcDynatrace()) << "Execute action: Unhandled deviceClass"; + info->finish(Device::DeviceErrorHardwareFailure); } } diff --git a/dynatrace/deviceplugindynatrace.json b/dynatrace/deviceplugindynatrace.json index e2eac5e2..69347cd9 100644 --- a/dynatrace/deviceplugindynatrace.json +++ b/dynatrace/deviceplugindynatrace.json @@ -13,7 +13,7 @@ "name": "ufo", "displayName": "ufo", "createMethods": ["user", "discovery"], - "interfaces": ["colorlight", "alert", "connectable"], + "interfaces": ["colorlight", "connectable"], "paramTypes": [ { "id": "3e14968b-954e-4e85-ae79-3de9ae4fe951", @@ -31,26 +31,6 @@ "readOnly": true } ], - "actionTypes": [ - { - "id": "6efa52d9-527b-4ac7-8885-50f2b1786561", - "name": "alert", - "displayName": "flash", - "paramTypes": [ - { - "id": "e8d854ce-02d0-4ddd-a2bd-0c464cbb9182", - "name": "alert", - "displayName": "alert", - "type": "QString", - "defaultValue": "flash", - "allowedValues": [ - "flash", - "flash 15 [s]" - ] - } - ] - } - ], "stateTypes": [ { "id": "1a439907-e810-4dea-b357-dd32281896e7", @@ -118,10 +98,10 @@ }, { "id": "53da0021-974a-434a-94ac-3f187aad1480", - "name": "effect", - "displayName": "Effect", - "displayNameEvent": "Effect changed", - "displayNameAction": "Set effect", + "name": "effectTop", + "displayName": "Effect top", + "displayNameEvent": "Effect top changed", + "displayNameAction": "Set top effect", "type": "QString", "defaultValue": "None", "possibleValues": [ @@ -130,6 +110,51 @@ "Whirl" ], "writable": true + }, + { + "id": "0fab896b-9900-4375-96c0-0d38460cee65", + "name": "effectBottom", + "displayName": "Effect bottom", + "displayNameEvent": "Effect bottom changed", + "displayNameAction": "Set bottom effect", + "type": "QString", + "defaultValue": "None", + "possibleValues": [ + "None", + "Morph", + "Whirl" + ], + "writable": true + }, + { + "id": "d3eb4a99-20cc-4d47-af7d-33453aca2087", + "name": "logoColor", + "displayName": "Logo color", + "displayNameEvent": "Logo color changed", + "displayNameAction": "Set logo color", + "type": "QColor", + "defaultValue": "#000000", + "writable": true + }, + { + "id": "b378290a-468f-45ef-9d65-00546737ce9b", + "name": "topColor", + "displayName": "Top color", + "displayNameEvent": "Top color changed", + "displayNameAction": "Set top color", + "type": "QColor", + "defaultValue": "#000000", + "writable": true + }, + { + "id": "ef2a8d5b-82d4-43d5-b9ec-82ef5662b971", + "name": "bottomColor", + "displayName": "Bottom color", + "displayNameEvent": "Bottom color changed", + "displayNameAction": "Set bottom color", + "type": "QColor", + "defaultValue": "#000000", + "writable": true } ] } diff --git a/dynatrace/ufo.cpp b/dynatrace/ufo.cpp index ff9232d6..b558d694 100644 --- a/dynatrace/ufo.cpp +++ b/dynatrace/ufo.cpp @@ -98,15 +98,16 @@ void Ufo::initBackgroundColor(bool top, bool bottom) url.setScheme("http"); url.setHost(m_address.toString()); url.setPath("/api"); + QUrlQuery query; if (top) { - url.setQuery("top_init"); + query.addQueryItem("top_init", "0"); } if (bottom) { - url.setQuery("bottom_init"); + query.addQueryItem("bottom_init", "0"); } + url.setQuery(query); QNetworkRequest request; request.setUrl(url); - qCDebug(dcDynatrace()) << "Sending request" << url; QNetworkReply *reply = m_networkManager->get(request); connect(reply, &QNetworkReply::finished, this, [reply, this] { @@ -123,19 +124,23 @@ void Ufo::initBackgroundColor(bool top, bool bottom) }); } -void Ufo::setBackgroundColor(bool top, bool bottom, QColor color) +void Ufo::setBackgroundColor(bool top, bool initTop, bool bottom, bool initBottom, QColor color) { QUrl url; url.setScheme("http"); url.setHost(m_address.toString()); url.setPath("/api"); QUrlQuery query; - if (top){ + if (initTop){ query.addQueryItem("top_init", "0"); + } + if (initBottom){ + query.addQueryItem("bottom_init", "0"); + } + if (top){ query.addQueryItem("top_bg", color.name().remove(0,1)); } if (bottom) { - query.addQueryItem("bottom_init", "0"); query.addQueryItem("bottom_bg", color.name().remove(0,1)); } url.setQuery(query); @@ -157,3 +162,82 @@ void Ufo::setBackgroundColor(bool top, bool bottom, QColor color) emit connectionChanged(true); }); } + +void Ufo::startWhirl(bool top, bool bottom, QColor color, int speed, bool clockwise) +{ + Q_UNUSED(clockwise) + QUrl url; + url.setScheme("http"); + url.setHost(m_address.toString()); + url.setPath("/api"); + QUrlQuery query; + if (top){ + query.addQueryItem("top_init", "0"); + query.addQueryItem("top_bg", color.name().remove(0,1)); + query.addQueryItem("top", "0|8|000000"); + query.addQueryItem("top_whirl", QString::number(speed)); + } + if (bottom) { + query.addQueryItem("bottom_init", "0"); + query.addQueryItem("bottom_bg", color.name().remove(0,1)); + query.addQueryItem("bottom", "0|8|000000"); + query.addQueryItem("bottom_whirl", QString::number(speed)); + } + url.setQuery(query); + QNetworkRequest request; + request.setUrl(url); + + qCDebug(dcDynatrace()) << "Sending request" << url; + QNetworkReply *reply = m_networkManager->get(request); + connect(reply, &QNetworkReply::finished, this, [reply, this] { + reply->deleteLater(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + // Check HTTP status code + if (status != 200 || reply->error() != QNetworkReply::NoError) { + qCWarning(dcDynatrace()) << "Request error:" << status << reply->errorString(); + emit connectionChanged(false); + return; + } + emit connectionChanged(true); + }); +} + +void Ufo::startMorph(bool top, bool bottom, QColor color, int time, int speed) +{ + QUrl url; + url.setScheme("http"); + url.setHost(m_address.toString()); + url.setPath("/api"); + QUrlQuery query; + if (top){ + query.addQueryItem("top_init", "0"); + query.addQueryItem("top_bg", color.name().remove(0,1)); + query.addQueryItem("top", "0|16|000000"); + query.addQueryItem("top_morph", QString::number(time)+"|"+QString::number(speed)); + } + if (bottom) { + query.addQueryItem("bottom_init", "0"); + query.addQueryItem("bottom_bg", color.name().remove(0,1)); + query.addQueryItem("bottom", "0|16|000000"); + query.addQueryItem("bottom_morph", QString::number(time)+"|"+QString::number(speed)); + } + url.setQuery(query); + QNetworkRequest request; + request.setUrl(url); + + qCDebug(dcDynatrace()) << "Sending request" << url; + QNetworkReply *reply = m_networkManager->get(request); + connect(reply, &QNetworkReply::finished, this, [reply, this] { + reply->deleteLater(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + // Check HTTP status code + if (status != 200 || reply->error() != QNetworkReply::NoError) { + qCWarning(dcDynatrace()) << "Request error:" << status << reply->errorString(); + emit connectionChanged(false); + return; + } + emit connectionChanged(true); + }); +} diff --git a/dynatrace/ufo.h b/dynatrace/ufo.h index a2e1ebdc..b1427876 100644 --- a/dynatrace/ufo.h +++ b/dynatrace/ufo.h @@ -46,11 +46,11 @@ public: void resetLogo(); void setLogo(QColor led1, QColor led2, QColor led3, QColor led4); void initBackgroundColor(bool top, bool bottom); - void setBackgroundColor(bool top, bool bottom, QColor color); + void setBackgroundColor(bool top, bool initTop, bool bottom, bool initBottom, QColor color); //top and bottom flags are to select the ring, init is to reset a effect void setLeds(bool top, int ledIndex, int numOfLeds, QColor color); - void startWhirl(bool top, bool bottom, int speed, bool clockwise); + void startWhirl(bool top, bool bottom, QColor color, int speed, bool clockwise); //Speed: 0 (no movement) to about 510 (very fast) void stopWhirl(bool top, bool bottom); - void startMorph(bool top, bool bottom, int speed, bool time); + void startMorph(bool top, bool bottom, QColor color, int time, int speed); //time in ms, speed 0-10 void stopMorph(bool top, bool bottom); From e503c9bc8aca800119a0e4b56f22b7762645f603 Mon Sep 17 00:00:00 2001 From: "bernhard.trinnes" Date: Fri, 20 Mar 2020 09:13:44 +0100 Subject: [PATCH 03/12] devices to things --- dynatrace/dynatrace.pro | 6 +- ...ace.cpp => integrationplugindynatrace.cpp} | 211 +++++++++--------- ...natrace.h => integrationplugindynatrace.h} | 32 +-- ...e.json => integrationplugindynatrace.json} | 2 +- dynatrace/ufo.h | 2 +- 5 files changed, 126 insertions(+), 127 deletions(-) rename dynatrace/{deviceplugindynatrace.cpp => integrationplugindynatrace.cpp} (55%) rename dynatrace/{deviceplugindynatrace.h => integrationplugindynatrace.h} (70%) rename dynatrace/{deviceplugindynatrace.json => integrationplugindynatrace.json} (99%) diff --git a/dynatrace/dynatrace.pro b/dynatrace/dynatrace.pro index 41ab4c98..9ab1b668 100644 --- a/dynatrace/dynatrace.pro +++ b/dynatrace/dynatrace.pro @@ -2,12 +2,12 @@ include(../plugins.pri) QT += network -TARGET = $$qtLibraryTarget(nymea_deviceplugindynatrace) +TARGET = $$qtLibraryTarget(nymea_integrationplugindynatrace) SOURCES += \ - deviceplugindynatrace.cpp \ + integrationplugindynatrace.cpp \ ufo.cpp HEADERS += \ - deviceplugindynatrace.h \ + integrationplugindynatrace.h \ ufo.h diff --git a/dynatrace/deviceplugindynatrace.cpp b/dynatrace/integrationplugindynatrace.cpp similarity index 55% rename from dynatrace/deviceplugindynatrace.cpp rename to dynatrace/integrationplugindynatrace.cpp index e9a61b63..f4c95634 100644 --- a/dynatrace/deviceplugindynatrace.cpp +++ b/dynatrace/integrationplugindynatrace.cpp @@ -26,8 +26,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "deviceplugindynatrace.h" -#include "devices/device.h" +#include "integrationplugindynatrace.h" #include "plugininfo.h" #include "network/networkaccessmanager.h" @@ -36,16 +35,16 @@ #include #include -DevicePluginDynatrace::DevicePluginDynatrace() +IntegrationPluginDynatrace::IntegrationPluginDynatrace() { } -void DevicePluginDynatrace::discoverDevices(DeviceDiscoveryInfo *info) +void IntegrationPluginDynatrace::discoverThings(ThingDiscoveryInfo *info) { - if (info->deviceClassId() == ufoDeviceClassId) { + if (info->thingClassId() == ufoThingClassId) { - QHostInfo::lookupHost("ufo.home", this, [info, this](const QHostInfo &host){ + QHostInfo::lookupHost("ufo.home", this, [info](const QHostInfo &host){ if (host.error() != QHostInfo::NoError) { qCDebug(dcDynatrace()) << "Lookup failed:" << host.errorString(); } @@ -53,30 +52,30 @@ void DevicePluginDynatrace::discoverDevices(DeviceDiscoveryInfo *info) foreach (QHostAddress address, host.addresses()) { qCDebug(dcDynatrace()) << "Found IP address" << address.toString(); - DeviceDescriptor descriptor(ufoDeviceClassId, "Ufo", address.toString()); + ThingDescriptor descriptor(ufoThingClassId, "Ufo", address.toString()); ParamList params; - /*Device *existingDevice = myDevices().findByParams(ParamList() << Param(ufoDeviceIdParamTypeId, "")); - if (existingDevice) { - //For device re-discovery - descriptor.setDeviceId(existingDevice->id()); + /*Thing *existingThing = myThings().findByParams(ParamList() << Param(ufoThingIdParamTypeId, "")); + if (existingThing) { + //For Thing re-discovery + descriptor.setThingId(existingthing->id()); }*/ - params << Param(ufoDeviceHostParamTypeId, address.toString()); + params << Param(ufoThingHostParamTypeId, address.toString()); descriptor.setParams(params); - info->addDeviceDescriptor(descriptor); + info->addThingDescriptor(descriptor); } - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); }); } } -void DevicePluginDynatrace::setupDevice(DeviceSetupInfo *info) +void IntegrationPluginDynatrace::setupThing(ThingSetupInfo *info) { - if (info->device()->deviceClassId() == ufoDeviceClassId) { - QHostAddress address = QHostAddress(info->device()->paramValue(ufoDeviceHostParamTypeId).toString()); - QString id = info->device()->paramValue(ufoDeviceIdParamTypeId).toString(); - if(id.isEmpty()) { //Probably a manual device setup + if (info->thing()->thingClassId() == ufoThingClassId) { + QHostAddress address = QHostAddress(info->thing()->paramValue(ufoThingHostParamTypeId).toString()); + QString id = info->thing()->paramValue(ufoThingIdParamTypeId).toString(); + if(id.isEmpty()) { //Probably a manual Thing setup QUrl url; url.setScheme("http"); url.setHost(address.toString()); @@ -84,37 +83,37 @@ void DevicePluginDynatrace::setupDevice(DeviceSetupInfo *info) QNetworkRequest request; request.setUrl(url); QNetworkReply *reply = hardwareManager()->networkManager()->get(request); - connect(reply, &QNetworkReply::finished, this, [info, reply, this] { + connect(reply, &QNetworkReply::finished, this, [info, reply] { reply->deleteLater(); QJsonParseError error; QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); if (error.error != QJsonParseError::NoError) { - info->finish(Device::DeviceErrorSetupFailed, error.errorString()); + info->finish(Thing::ThingErrorSetupFailed, error.errorString()); } QString id = data.toVariant().toMap().value("ufoid").toString(); - info->device()->setParamValue(ufoDeviceIdParamTypeId, id); - info->finish(Device::DeviceErrorNoError); + info->thing()->setParamValue(ufoThingIdParamTypeId, id); + info->finish(Thing::ThingErrorNoError); }); } else { - // Discovery device setup or devices setup caused by nymea restart - info->finish(Device::DeviceErrorNoError); + // Discovery Thing setup or Things setup caused by nymea restart + info->finish(Thing::ThingErrorNoError); } } } -void DevicePluginDynatrace::postSetupDevice(Device *device) +void IntegrationPluginDynatrace::postSetupThing(Thing *thing) { - if (device->deviceClassId() == ufoDeviceClassId) { - device->setStateValue(ufoConnectedStateTypeId, true); //FIXME - device->setStateValue(ufoPowerStateTypeId, false); - device->setStateValue(ufoLogoStateTypeId, false); - device->setStateValue(ufoEffectTopStateTypeId, "None"); - device->setStateValue(ufoEffectBottomStateTypeId, "None"); + if (thing->thingClassId() == ufoThingClassId) { + thing->setStateValue(ufoConnectedStateTypeId, true); //FIXME + thing->setStateValue(ufoPowerStateTypeId, false); + thing->setStateValue(ufoLogoStateTypeId, false); + thing->setStateValue(ufoEffectTopStateTypeId, "None"); + thing->setStateValue(ufoEffectBottomStateTypeId, "None"); - QHostAddress address = QHostAddress(device->paramValue(ufoDeviceHostParamTypeId).toString()); + QHostAddress address = QHostAddress(thing->paramValue(ufoThingHostParamTypeId).toString()); Ufo *ufo = new Ufo(hardwareManager()->networkManager(), address, this); - m_ufoConnections.insert(device->id(), ufo); + m_ufoConnections.insert(thing->id(), ufo); // Set all off ufo->setLogo(QColor(Qt::black), QColor(Qt::black), QColor(Qt::black), QColor(Qt::black)); ufo->setBackgroundColor(true, true, true, true, QColor(Qt::black)); @@ -123,101 +122,101 @@ void DevicePluginDynatrace::postSetupDevice(Device *device) if(!m_pluginTimer) { m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60); connect(m_pluginTimer, &PluginTimer::timeout, this, [this]() { - //TODO check if device is reachable + //TODO check if Thing is reachable }); } } -void DevicePluginDynatrace::executeAction(DeviceActionInfo *info) +void IntegrationPluginDynatrace::executeAction(ThingActionInfo *info) { - Device *device = info->device(); + Thing *thing = info->thing(); Action action = info->action(); - if (device->deviceClassId() == ufoDeviceClassId) { - Ufo *ufo = m_ufoConnections.value(device->id()); + if (thing->thingClassId() == ufoThingClassId) { + Ufo *ufo = m_ufoConnections.value(thing->id()); if (!ufo) return; if (action.actionTypeId() == ufoLogoActionTypeId) { bool power = action.param(ufoLogoActionLogoParamTypeId).value().toBool(); - device->setStateValue(ufoLogoStateTypeId, power); + thing->setStateValue(ufoLogoStateTypeId, power); if (power) { - int brightness = device->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); - QColor color = QColor(device->stateValue(ufoLogoColorStateTypeId).toString()); + int brightness = thing->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); + QColor color = QColor(thing->stateValue(ufoLogoColorStateTypeId).toString()); color.setHsv(color.hue(), color.saturation(), brightness*2.55); ufo->setLogo(color, color, color, color); } else { ufo->setLogo(QColor(Qt::black), QColor(Qt::black), QColor(Qt::black), QColor(Qt::black)); } - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == ufoPowerActionTypeId) { bool power = action.param(ufoPowerActionPowerParamTypeId).value().toBool(); - device->setStateValue(ufoPowerStateTypeId, power); + thing->setStateValue(ufoPowerStateTypeId, power); if (power) { - int brightness = device->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); - QColor color = QColor(device->stateValue(ufoColorStateTypeId).toString()); + int brightness = thing->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); + QColor color = QColor(thing->stateValue(ufoColorStateTypeId).toString()); color.setHsv(color.hue(), color.saturation(), brightness*2.55); - device->setStateValue(ufoLogoStateTypeId, true); + thing->setStateValue(ufoLogoStateTypeId, true); ufo->setLogo(color, color, color, color); ufo->setBackgroundColor(true, true, true, true, color); - device->setStateValue(ufoEffectTopStateTypeId, "None"); - device->setStateValue(ufoEffectBottomStateTypeId, "None"); - device->setStateValue(ufoLogoColorStateTypeId, color); - device->setStateValue(ufoTopColorStateTypeId, color); - device->setStateValue(ufoBottomColorStateTypeId, color); + thing->setStateValue(ufoEffectTopStateTypeId, "None"); + thing->setStateValue(ufoEffectBottomStateTypeId, "None"); + thing->setStateValue(ufoLogoColorStateTypeId, color); + thing->setStateValue(ufoTopColorStateTypeId, color); + thing->setStateValue(ufoBottomColorStateTypeId, color); } else { ufo->setLogo(QColor(Qt::black), QColor(Qt::black), QColor(Qt::black), QColor(Qt::black)); - device->setStateValue(ufoLogoStateTypeId, false); + thing->setStateValue(ufoLogoStateTypeId, false); ufo->setBackgroundColor(true, true, true, true, QColor(Qt::black)); - device->setStateValue(ufoEffectTopStateTypeId, "None"); - device->setStateValue(ufoEffectBottomStateTypeId, "None"); + thing->setStateValue(ufoEffectTopStateTypeId, "None"); + thing->setStateValue(ufoEffectBottomStateTypeId, "None"); } - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == ufoBrightnessActionTypeId) { int brightness = action.param(ufoBrightnessActionBrightnessParamTypeId).value().toInt(); - device->setStateValue(ufoBrightnessStateTypeId, brightness); - QColor color = QColor(device->stateValue(ufoColorStateTypeId).toString()); + thing->setStateValue(ufoBrightnessStateTypeId, brightness); + QColor color = QColor(thing->stateValue(ufoColorStateTypeId).toString()); color.setHsv(color.hue(), color.saturation(), brightness*2.55); - if (device->stateValue(ufoLogoStateTypeId).toBool()) { + if (thing->stateValue(ufoLogoStateTypeId).toBool()) { ufo->setLogo(color, color, color, color); } ufo->setBackgroundColor(true, false, true, false, color); - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == ufoColorActionTypeId) { QColor color = QColor(action.param(ufoColorActionColorParamTypeId).value().toString()); - int brightness = device->stateValue(ufoBrightnessStateTypeId).toInt(); - device->setStateValue(ufoColorStateTypeId, color); - device->setStateValue(ufoLogoColorStateTypeId, color); - device->setStateValue(ufoTopColorStateTypeId, color); - device->setStateValue(ufoBottomColorStateTypeId, color); + int brightness = thing->stateValue(ufoBrightnessStateTypeId).toInt(); + thing->setStateValue(ufoColorStateTypeId, color); + thing->setStateValue(ufoLogoColorStateTypeId, color); + thing->setStateValue(ufoTopColorStateTypeId, color); + thing->setStateValue(ufoBottomColorStateTypeId, color); color.setHsv(color.hue(), color.saturation(), brightness*2.55); - if (device->stateValue(ufoLogoStateTypeId).toBool()) { + if (thing->stateValue(ufoLogoStateTypeId).toBool()) { ufo->setLogo(color, color, color, color); } ufo->setBackgroundColor(true, false, true, false, color); - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == ufoColorTemperatureActionTypeId) { - int mired= device->stateValue(ufoColorTemperatureActionColorTemperatureParamTypeId).toInt(); - device->setStateValue(ufoColorTemperatureStateTypeId, mired); - int brightness = device->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); + int mired= thing->stateValue(ufoColorTemperatureActionColorTemperatureParamTypeId).toInt(); + thing->setStateValue(ufoColorTemperatureStateTypeId, mired); + int brightness = thing->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); QColor color(Qt::white); color.setBlue(static_cast((mired-153)*0.73)); color.setHsv(color.hue(), color.saturation(), brightness*2.55); - if (device->stateValue(ufoLogoStateTypeId).toBool()) { + if (thing->stateValue(ufoLogoStateTypeId).toBool()) { ufo->setLogo(color, color, color, color); } - device->setStateValue(ufoColorStateTypeId, color); - device->setStateValue(ufoLogoColorStateTypeId, color); - device->setStateValue(ufoTopColorStateTypeId, color); - device->setStateValue(ufoBottomColorStateTypeId, color); + thing->setStateValue(ufoColorStateTypeId, color); + thing->setStateValue(ufoLogoColorStateTypeId, color); + thing->setStateValue(ufoTopColorStateTypeId, color); + thing->setStateValue(ufoBottomColorStateTypeId, color); ufo->setBackgroundColor(true, false, true, false, color); - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == ufoEffectTopActionTypeId) { QString effect = action.param(ufoEffectTopActionEffectTopParamTypeId).value().toString(); - int brightness = device->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); - QColor color = QColor(device->stateValue(ufoColorStateTypeId).toString()); + int brightness = thing->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); + QColor color = QColor(thing->stateValue(ufoColorStateTypeId).toString()); color.setHsv(color.hue(), color.saturation(), brightness*2.55); if (effect == "None") { ufo->setBackgroundColor(true, true, false, false, color); @@ -226,11 +225,11 @@ void DevicePluginDynatrace::executeAction(DeviceActionInfo *info) } else if (effect == "Morph") { ufo->startMorph(true, false, color, 250, 8); } - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == ufoEffectBottomActionTypeId) { QString effect = action.param(ufoEffectBottomActionEffectBottomParamTypeId).value().toString(); - int brightness = device->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); - QColor color = QColor(device->stateValue(ufoColorStateTypeId).toString()); + int brightness = thing->stateValue(ufoBrightnessActionBrightnessParamTypeId).toInt(); + QColor color = QColor(thing->stateValue(ufoColorStateTypeId).toString()); color.setHsv(color.hue(), color.saturation(), brightness*2.55); if (effect == "None") { ufo->setBackgroundColor(false, false, true, true, color); @@ -239,57 +238,57 @@ void DevicePluginDynatrace::executeAction(DeviceActionInfo *info) } else if (effect == "Morph") { ufo->startMorph(false, true, color, 250, 8); } - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == ufoLogoColorActionTypeId) { QColor color = QColor(action.param(ufoLogoColorActionLogoColorParamTypeId).value().toString()); - int brightness = device->stateValue(ufoBrightnessStateTypeId).toInt(); - device->setStateValue(ufoLogoColorStateTypeId, color); - device->setStateValue(ufoLogoStateTypeId, true); + int brightness = thing->stateValue(ufoBrightnessStateTypeId).toInt(); + thing->setStateValue(ufoLogoColorStateTypeId, color); + thing->setStateValue(ufoLogoStateTypeId, true); color.setHsv(color.hue(), color.saturation(), brightness*2.55); ufo->setLogo(color, color, color, color); - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == ufoTopColorActionTypeId) { QColor color = QColor(action.param(ufoTopColorActionTopColorParamTypeId).value().toString()); - int brightness = device->stateValue(ufoBrightnessStateTypeId).toInt(); - device->setStateValue(ufoTopColorStateTypeId, color); - device->setStateValue(ufoPowerStateTypeId, true); + int brightness = thing->stateValue(ufoBrightnessStateTypeId).toInt(); + thing->setStateValue(ufoTopColorStateTypeId, color); + thing->setStateValue(ufoPowerStateTypeId, true); color.setHsv(color.hue(), color.saturation(), brightness*2.55); ufo->setBackgroundColor(true, false, false, false, color); - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); } else if (action.actionTypeId() == ufoBottomColorActionTypeId) { QColor color = QColor(action.param(ufoBottomColorActionBottomColorParamTypeId).value().toString()); - int brightness = device->stateValue(ufoBrightnessStateTypeId).toInt(); - device->setStateValue(ufoBottomColorStateTypeId, color); - device->setStateValue(ufoPowerStateTypeId, true); + int brightness = thing->stateValue(ufoBrightnessStateTypeId).toInt(); + thing->setStateValue(ufoBottomColorStateTypeId, color); + thing->setStateValue(ufoPowerStateTypeId, true); color.setHsv(color.hue(), color.saturation(), brightness*2.55); ufo->setBackgroundColor(false, false, true, false, color); - info->finish(Device::DeviceErrorNoError); + info->finish(Thing::ThingErrorNoError); } else { qCWarning(dcDynatrace()) << "Execute action: Unhandled actionTypeId"; - info->finish(Device::DeviceErrorHardwareFailure); + info->finish(Thing::ThingErrorHardwareFailure); } } else { - qCWarning(dcDynatrace()) << "Execute action: Unhandled deviceClass"; - info->finish(Device::DeviceErrorHardwareFailure); + qCWarning(dcDynatrace()) << "Execute action: Unhandled ThingClass"; + info->finish(Thing::ThingErrorHardwareFailure); } } -void DevicePluginDynatrace::deviceRemoved(Device *device) +void IntegrationPluginDynatrace::thingRemoved(Thing *thing) { - if (device->deviceClassId() == ufoDeviceClassId) { - if (m_ufoConnections.contains(device->id())){ - Ufo *ufo = m_ufoConnections.take(device->id()); + if (thing->thingClassId() == ufoThingClassId) { + if (m_ufoConnections.contains(thing->id())){ + Ufo *ufo = m_ufoConnections.take(thing->id()); ufo->deleteLater(); } } - if (myDevices().isEmpty() && m_pluginTimer) { + if (myThings().isEmpty() && m_pluginTimer) { m_pluginTimer->deleteLater(); m_pluginTimer = nullptr; } } -void DevicePluginDynatrace::getId(const QHostAddress &address) +void IntegrationPluginDynatrace::getId(const QHostAddress &address) { QUrl url; url.setScheme("http"); @@ -308,13 +307,13 @@ void DevicePluginDynatrace::getId(const QHostAddress &address) QString id = data.toVariant().toMap().value("ufoid").toString(); if (m_asyncSetup.contains(reply->url().host())) { - DeviceSetupInfo *info = m_asyncSetup.value(reply->url().host()); - info->finish(Device::DeviceErrorNoError); + ThingSetupInfo *info = m_asyncSetup.value(reply->url().host()); + info->finish(Thing::ThingErrorNoError); } }); } -void DevicePluginDynatrace::onConnectionChanged(bool connected) +void IntegrationPluginDynatrace::onConnectionChanged(bool connected) { Q_UNUSED(connected) } diff --git a/dynatrace/deviceplugindynatrace.h b/dynatrace/integrationplugindynatrace.h similarity index 70% rename from dynatrace/deviceplugindynatrace.h rename to dynatrace/integrationplugindynatrace.h index f55f91a4..98aba7b9 100644 --- a/dynatrace/deviceplugindynatrace.h +++ b/dynatrace/integrationplugindynatrace.h @@ -26,36 +26,36 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef DEVICEPLUGINDYNATRACE_H -#define DEVICEPLUGINDYNATRACE_H +#ifndef INTEGRATIONPLUGINDYNATRACE_H +#define INTEGRATIONPLUGINDYNATRACE_H #include "plugintimer.h" -#include "devices/deviceplugin.h" +#include "integrations/integrationplugin.h" #include "network/oauth2.h" #include "ufo.h" #include #include -class DevicePluginDynatrace : public DevicePlugin +class IntegrationPluginDynatrace : public IntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "deviceplugindynatrace.json") - Q_INTERFACES(DevicePlugin) + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationplugindynatrace.json") + Q_INTERFACES(IntegrationPlugin) public: - explicit DevicePluginDynatrace(); - void discoverDevices(DeviceDiscoveryInfo *info) override; - void setupDevice(DeviceSetupInfo *info) override; - void postSetupDevice(Device *device) override; - void executeAction(DeviceActionInfo *info) override; - void deviceRemoved(Device *device) override; + explicit IntegrationPluginDynatrace(); + void discoverThings(ThingDiscoveryInfo *info) override; + void setupThing(ThingSetupInfo *info) override; + void postSetupThing(Thing *thing) override; + void executeAction(ThingActionInfo *info) override; + void thingRemoved(Thing *thing) override; private: PluginTimer *m_pluginTimer = nullptr; - QHash m_ufoConnections; - QHash m_asyncActions; - QHash m_asyncSetup; + QHash m_ufoConnections; + QHash m_asyncActions; + QHash m_asyncSetup; void getId(const QHostAddress &address); @@ -63,4 +63,4 @@ private slots: void onConnectionChanged(bool connected); }; -#endif // DEVICEPLUGINDYNATRACE_H +#endif // INTEGRATIONPLUGINDYNATRACE_H diff --git a/dynatrace/deviceplugindynatrace.json b/dynatrace/integrationplugindynatrace.json similarity index 99% rename from dynatrace/deviceplugindynatrace.json rename to dynatrace/integrationplugindynatrace.json index 69347cd9..92e1cb33 100644 --- a/dynatrace/deviceplugindynatrace.json +++ b/dynatrace/integrationplugindynatrace.json @@ -7,7 +7,7 @@ "name": "Dynatrace", "displayName": "Dynatrace", "id": "31b402be-1562-4335-aa83-d1c1166db570", - "deviceClasses": [ + "thingClasses": [ { "id": "6271f010-0b0a-4f29-b894-0611bb5f3dcc", "name": "ufo", diff --git a/dynatrace/ufo.h b/dynatrace/ufo.h index b1427876..9f07310a 100644 --- a/dynatrace/ufo.h +++ b/dynatrace/ufo.h @@ -30,7 +30,7 @@ #define DYNATRACE_UFO_H #include "network/networkaccessmanager.h" -#include "devices/device.h" +#include "integrations/integrationplugin.h" #include #include From 292bfee5161e6e6ee634d8f38115034d74e0abde Mon Sep 17 00:00:00 2001 From: "bernhard.trinnes" Date: Fri, 20 Mar 2020 09:21:21 +0100 Subject: [PATCH 04/12] updated README.md --- dynatrace/README.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/dynatrace/README.md b/dynatrace/README.md index 14d22069..379a2a36 100644 --- a/dynatrace/README.md +++ b/dynatrace/README.md @@ -2,8 +2,20 @@ This plug-in enables nymea to control the Dynatrace Ufo. +## Supported Things -## Device Setup +* Dynatrace UFO + * Auto discovery setup + * Light interface + * Control color of each ring + * Control logo color + * Set morph and rotate effect + +## Requirements + +* The UFO device must be in the same local are network as nymea. +* TCP sockets on port 80 must not be blocked by the router. +* The package "nymea-plugin-dynatrace" must be installed. An excerpt of the Ufo (Blog Post)[https://www.dynatrace.com/news/blog/using-dynatrace-devops-pipeline-state-ufo/] @@ -15,6 +27,8 @@ An excerpt of the Ufo (Blog Post)[https://www.dynatrace.com/news/blog/using-dyna * While it reboots itself it will blink yellow. Once it has its assigned IP Address it will start visualizing its IP Address through a special „blink code“ as explained in the Quick Start Guide! * Remember: the UFO will also try to register its hostname as „ufo“ with your DHCP server. If that works you can simply browse to http://ufo -More about the Dynatrace Ufo: -https://github.com/Dynatrace/ufo + +## More + +More about the Dynatrace Ufo: https://github.com/Dynatrace/ufo From 9bdbee4c4830d5c3912967289aadd21e9f9253f3 Mon Sep 17 00:00:00 2001 From: "bernhard.trinnes" Date: Fri, 20 Mar 2020 09:55:15 +0100 Subject: [PATCH 05/12] fixed connected state --- dynatrace/integrationplugindynatrace.cpp | 54 +++++++++++------- dynatrace/integrationplugindynatrace.h | 36 ++++++------ dynatrace/ufo.cpp | 70 ++++++++++++++++++------ dynatrace/ufo.h | 39 +++++++------ 4 files changed, 125 insertions(+), 74 deletions(-) diff --git a/dynatrace/integrationplugindynatrace.cpp b/dynatrace/integrationplugindynatrace.cpp index f4c95634..1dcf0d6a 100644 --- a/dynatrace/integrationplugindynatrace.cpp +++ b/dynatrace/integrationplugindynatrace.cpp @@ -1,30 +1,32 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2013 - 2020, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. -* This project including source code and documentation is protected by copyright law, and -* remains the property of nymea GmbH. All rights, including reproduction, publication, -* editing and translation, are reserved. The use of this project is subject to the terms of a -* license agreement to be concluded with nymea GmbH in accordance with the terms -* of use of nymea GmbH, available under https://nymea.io/license +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license * * GNU Lesser General Public License Usage -* This project may also contain libraries licensed under the open source software license GNU GPL v.3. -* Alternatively, this project may be redistributed and/or modified under the terms of the GNU -* Lesser General Public License as published by the Free Software Foundation; version 3. -* this project 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. +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project 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 project. -* If not, see . +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . * -* For any further details and any questions please contact us under contact@nymea.io -* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "integrationplugindynatrace.h" #include "plugininfo.h" @@ -54,7 +56,7 @@ void IntegrationPluginDynatrace::discoverThings(ThingDiscoveryInfo *info) ThingDescriptor descriptor(ufoThingClassId, "Ufo", address.toString()); ParamList params; - + //FIXME Rediscovery /*Thing *existingThing = myThings().findByParams(ParamList() << Param(ufoThingIdParamTypeId, "")); if (existingThing) { //For Thing re-discovery @@ -99,13 +101,16 @@ void IntegrationPluginDynatrace::setupThing(ThingSetupInfo *info) // Discovery Thing setup or Things setup caused by nymea restart info->finish(Thing::ThingErrorNoError); } + } else { + qCWarning(dcDynatrace()) << "Setup thing: Unhandled ThingClassId" << info->thing()->thingClassId(); + info->finish(Thing::ThingErrorSetupFailed); } } void IntegrationPluginDynatrace::postSetupThing(Thing *thing) { if (thing->thingClassId() == ufoThingClassId) { - thing->setStateValue(ufoConnectedStateTypeId, true); //FIXME + thing->setStateValue(ufoConnectedStateTypeId, true); thing->setStateValue(ufoPowerStateTypeId, false); thing->setStateValue(ufoLogoStateTypeId, false); thing->setStateValue(ufoEffectTopStateTypeId, "None"); @@ -113,6 +118,7 @@ void IntegrationPluginDynatrace::postSetupThing(Thing *thing) QHostAddress address = QHostAddress(thing->paramValue(ufoThingHostParamTypeId).toString()); Ufo *ufo = new Ufo(hardwareManager()->networkManager(), address, this); + connect(ufo, &Ufo::connectionChanged, this, &IntegrationPluginDynatrace::onConnectionChanged); m_ufoConnections.insert(thing->id(), ufo); // Set all off ufo->setLogo(QColor(Qt::black), QColor(Qt::black), QColor(Qt::black), QColor(Qt::black)); @@ -122,7 +128,9 @@ void IntegrationPluginDynatrace::postSetupThing(Thing *thing) if(!m_pluginTimer) { m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60); connect(m_pluginTimer, &PluginTimer::timeout, this, [this]() { - //TODO check if Thing is reachable + foreach (Ufo *ufo, m_ufoConnections.values()) { + ufo->getId(); + } }); } } @@ -315,5 +323,9 @@ void IntegrationPluginDynatrace::getId(const QHostAddress &address) void IntegrationPluginDynatrace::onConnectionChanged(bool connected) { - Q_UNUSED(connected) + Ufo *ufo = static_cast(sender()); + Thing *thing = myThings().findById(m_ufoConnections.key(ufo)); + if (!thing) + return; + thing->setStateValue(ufoConnectedStateTypeId, connected); } diff --git a/dynatrace/integrationplugindynatrace.h b/dynatrace/integrationplugindynatrace.h index 98aba7b9..0b77d6e1 100644 --- a/dynatrace/integrationplugindynatrace.h +++ b/dynatrace/integrationplugindynatrace.h @@ -1,30 +1,32 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2013 - 2020, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. -* This project including source code and documentation is protected by copyright law, and -* remains the property of nymea GmbH. All rights, including reproduction, publication, -* editing and translation, are reserved. The use of this project is subject to the terms of a -* license agreement to be concluded with nymea GmbH in accordance with the terms -* of use of nymea GmbH, available under https://nymea.io/license +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license * * GNU Lesser General Public License Usage -* This project may also contain libraries licensed under the open source software license GNU GPL v.3. -* Alternatively, this project may be redistributed and/or modified under the terms of the GNU -* Lesser General Public License as published by the Free Software Foundation; version 3. -* this project 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. +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project 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 project. -* If not, see . +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . * -* For any further details and any questions please contact us under contact@nymea.io -* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef INTEGRATIONPLUGINDYNATRACE_H #define INTEGRATIONPLUGINDYNATRACE_H diff --git a/dynatrace/ufo.cpp b/dynatrace/ufo.cpp index b558d694..28727bca 100644 --- a/dynatrace/ufo.cpp +++ b/dynatrace/ufo.cpp @@ -1,34 +1,38 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2013 - 2020, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. -* This project including source code and documentation is protected by copyright law, and -* remains the property of nymea GmbH. All rights, including reproduction, publication, -* editing and translation, are reserved. The use of this project is subject to the terms of a -* license agreement to be concluded with nymea GmbH in accordance with the terms -* of use of nymea GmbH, available under https://nymea.io/license +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license * * GNU Lesser General Public License Usage -* This project may also contain libraries licensed under the open source software license GNU GPL v.3. -* Alternatively, this project may be redistributed and/or modified under the terms of the GNU -* Lesser General Public License as published by the Free Software Foundation; version 3. -* this project 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. +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project 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 project. -* If not, see . +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . * -* For any further details and any questions please contact us under contact@nymea.io -* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "ufo.h" #include "extern-plugininfo.h" + #include +#include Ufo::Ufo(NetworkAccessManager *networkManager, const QHostAddress &address, QObject *parent) : QObject(parent), @@ -38,6 +42,37 @@ Ufo::Ufo(NetworkAccessManager *networkManager, const QHostAddress &address, QObj } +void Ufo::getId() +{ + QUrl url; + url.setScheme("http"); + url.setHost(m_address.toString()); + url.setPath("/info", QUrl::ParsingMode::TolerantMode); + QNetworkRequest request; + request.setUrl(url); + QNetworkReply *reply = m_networkManager->get(request); + connect(reply, &QNetworkReply::finished, this, [reply, this] { + reply->deleteLater(); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + // Check HTTP status code + if (status != 200 || reply->error() != QNetworkReply::NoError) { + qCWarning(dcDynatrace()) << "Request error:" << status << reply->errorString(); + emit connectionChanged(false); + return; + } + emit connectionChanged(true); + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError){ + qCWarning(dcDynatrace()) << "JSON parsing error:" << error.errorString(); + return; + } + + QString id = data.toVariant().toMap().value("ufoid").toString(); + emit idReceived(id); + }); +} + void Ufo::resetLogo() { QUrl url; @@ -61,7 +96,6 @@ void Ufo::resetLogo() } emit connectionChanged(true); }); - } void Ufo::setLogo(QColor led1, QColor led2, QColor led3, QColor led4) diff --git a/dynatrace/ufo.h b/dynatrace/ufo.h index 9f07310a..0d840ccc 100644 --- a/dynatrace/ufo.h +++ b/dynatrace/ufo.h @@ -1,30 +1,32 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2013 - 2020, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. -* This project including source code and documentation is protected by copyright law, and -* remains the property of nymea GmbH. All rights, including reproduction, publication, -* editing and translation, are reserved. The use of this project is subject to the terms of a -* license agreement to be concluded with nymea GmbH in accordance with the terms -* of use of nymea GmbH, available under https://nymea.io/license +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license * * GNU Lesser General Public License Usage -* This project may also contain libraries licensed under the open source software license GNU GPL v.3. -* Alternatively, this project may be redistributed and/or modified under the terms of the GNU -* Lesser General Public License as published by the Free Software Foundation; version 3. -* this project 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. +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project 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 project. -* If not, see . +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . * -* For any further details and any questions please contact us under contact@nymea.io -* or see our FAQ/Licensing Information on https://nymea.io/license/faq +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef DYNATRACE_UFO_H #define DYNATRACE_UFO_H @@ -43,6 +45,7 @@ class Ufo : public QObject public: explicit Ufo(NetworkAccessManager *networkManager, const QHostAddress &address, QObject *parent = nullptr); + void getId(); void resetLogo(); void setLogo(QColor led1, QColor led2, QColor led3, QColor led4); void initBackgroundColor(bool top, bool bottom); @@ -53,13 +56,13 @@ public: void startMorph(bool top, bool bottom, QColor color, int time, int speed); //time in ms, speed 0-10 void stopMorph(bool top, bool bottom); - private: NetworkAccessManager *m_networkManager; QHostAddress m_address; signals: void connectionChanged(bool reachable); + void idReceived(const QString &id); }; #endif //DYNATRACE_UFO_H From feeb42bd2a4302316db1458e958ba21d1c75984e Mon Sep 17 00:00:00 2001 From: "bernhard.trinnes" Date: Fri, 20 Mar 2020 09:56:28 +0100 Subject: [PATCH 06/12] updated translation files --- dynatrace/integrationplugindynatrace.json | 1 + ...51bd7-69cb-4106-968f-1206a5736368-en_US.ts | 342 +++++++++++------- 2 files changed, 214 insertions(+), 129 deletions(-) diff --git a/dynatrace/integrationplugindynatrace.json b/dynatrace/integrationplugindynatrace.json index 92e1cb33..2f768a2e 100644 --- a/dynatrace/integrationplugindynatrace.json +++ b/dynatrace/integrationplugindynatrace.json @@ -38,6 +38,7 @@ "displayName": "Reachable", "displayNameEvent": "Reachable changed", "defaultValue": false, + "cached": false, "type": "bool" }, { diff --git a/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts b/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts index 2d702e9c..73f9789c 100644 --- a/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts +++ b/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts @@ -4,62 +4,62 @@ dynatrace - - - - Brightness - The name of the ParamType (DeviceClass: ufo, ActionType: brightness, ID: {1adb2df8-7ba1-48b8-b0da-d67085efe041}) ----------- -The name of the ParamType (DeviceClass: ufo, EventType: brightness, ID: {1adb2df8-7ba1-48b8-b0da-d67085efe041}) ----------- -The name of the StateType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of DeviceClass ufo - - - - - Brightness changed - The name of the EventType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of DeviceClass ufo - - - - - - - Color - The name of the ParamType (DeviceClass: ufo, ActionType: color, ID: {9535fd99-05c6-449f-80a2-8daf61d9b9b0}) ----------- -The name of the ParamType (DeviceClass: ufo, EventType: color, ID: {9535fd99-05c6-449f-80a2-8daf61d9b9b0}) ----------- -The name of the StateType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of DeviceClass ufo - - - - - Color changed - The name of the EventType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of DeviceClass ufo - - - - - - Color temperature - The name of the ParamType (DeviceClass: ufo, ActionType: colorTemperature, ID: {60fa917b-8702-4ff2-90b8-9c8c616bb21f}) ----------- -The name of the ParamType (DeviceClass: ufo, EventType: colorTemperature, ID: {60fa917b-8702-4ff2-90b8-9c8c616bb21f}) ----------- -The name of the StateType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of DeviceClass ufo - - - - Color temperature changed - The name of the EventType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of DeviceClass ufo + + Brightness + The name of the ParamType (ThingClass: ufo, ActionType: brightness, ID: {1adb2df8-7ba1-48b8-b0da-d67085efe041}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: brightness, ID: {1adb2df8-7ba1-48b8-b0da-d67085efe041}) +---------- +The name of the StateType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of ThingClass ufo - + Brightness changed + The name of the EventType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of ThingClass ufo + + + + + + + Color + The name of the ParamType (ThingClass: ufo, ActionType: color, ID: {9535fd99-05c6-449f-80a2-8daf61d9b9b0}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: color, ID: {9535fd99-05c6-449f-80a2-8daf61d9b9b0}) +---------- +The name of the StateType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of ThingClass ufo + + + + + Color changed + The name of the EventType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of ThingClass ufo + + + + + + + Color temperature + The name of the ParamType (ThingClass: ufo, ActionType: colorTemperature, ID: {60fa917b-8702-4ff2-90b8-9c8c616bb21f}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: colorTemperature, ID: {60fa917b-8702-4ff2-90b8-9c8c616bb21f}) +---------- +The name of the StateType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of ThingClass ufo + + + + + Color temperature changed + The name of the EventType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of ThingClass ufo + + + + + Dynatrace The name of the vendor ({31b402be-1562-4335-aa83-d1c1166db570}) ---------- @@ -67,138 +67,222 @@ The name of the plugin dynatrace ({a8451bd7-69cb-4106-968f-1206a5736368}) - - - - Effect - The name of the ParamType (DeviceClass: ufo, ActionType: effect, ID: {53da0021-974a-434a-94ac-3f187aad1480}) + + + + Bottom color + The name of the ParamType (ThingClass: ufo, ActionType: bottomColor, ID: {ef2a8d5b-82d4-43d5-b9ec-82ef5662b971}) ---------- -The name of the ParamType (DeviceClass: ufo, EventType: effect, ID: {53da0021-974a-434a-94ac-3f187aad1480}) +The name of the ParamType (ThingClass: ufo, EventType: bottomColor, ID: {ef2a8d5b-82d4-43d5-b9ec-82ef5662b971}) ---------- -The name of the StateType ({53da0021-974a-434a-94ac-3f187aad1480}) of DeviceClass ufo +The name of the StateType ({ef2a8d5b-82d4-43d5-b9ec-82ef5662b971}) of ThingClass ufo - - Effect changed - The name of the EventType ({53da0021-974a-434a-94ac-3f187aad1480}) of DeviceClass ufo - - - - - Host address - The name of the ParamType (DeviceClass: ufo, Type: device, ID: {3e14968b-954e-4e85-ae79-3de9ae4fe951}) - - - - - Id - The name of the ParamType (DeviceClass: ufo, Type: device, ID: {142c25c0-03e3-478e-b5c3-3d072f668cc4}) - - - - - - - Logo - The name of the ParamType (DeviceClass: ufo, ActionType: logo, ID: {a9c123e2-db78-40d3-a422-7e4817d50984}) ----------- -The name of the ParamType (DeviceClass: ufo, EventType: logo, ID: {a9c123e2-db78-40d3-a422-7e4817d50984}) ----------- -The name of the StateType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of DeviceClass ufo - - - - - Logo changed - The name of the EventType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of DeviceClass ufo + + Bottom color changed + The name of the EventType ({ef2a8d5b-82d4-43d5-b9ec-82ef5662b971}) of ThingClass ufo - Power - The name of the ParamType (DeviceClass: ufo, ActionType: power, ID: {14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) + Effect bottom + The name of the ParamType (ThingClass: ufo, ActionType: effectBottom, ID: {0fab896b-9900-4375-96c0-0d38460cee65}) ---------- -The name of the ParamType (DeviceClass: ufo, EventType: power, ID: {14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) +The name of the ParamType (ThingClass: ufo, EventType: effectBottom, ID: {0fab896b-9900-4375-96c0-0d38460cee65}) ---------- -The name of the StateType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of DeviceClass ufo +The name of the StateType ({0fab896b-9900-4375-96c0-0d38460cee65}) of ThingClass ufo - Power changed - The name of the EventType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of DeviceClass ufo + Effect bottom changed + The name of the EventType ({0fab896b-9900-4375-96c0-0d38460cee65}) of ThingClass ufo - Reachable - The name of the ParamType (DeviceClass: ufo, EventType: connected, ID: {1a439907-e810-4dea-b357-dd32281896e7}) ----------- -The name of the StateType ({1a439907-e810-4dea-b357-dd32281896e7}) of DeviceClass ufo - - - - Reachable changed - The name of the EventType ({1a439907-e810-4dea-b357-dd32281896e7}) of DeviceClass ufo + Effect top + The name of the ParamType (ThingClass: ufo, ActionType: effectTop, ID: {53da0021-974a-434a-94ac-3f187aad1480}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: effectTop, ID: {53da0021-974a-434a-94ac-3f187aad1480}) +---------- +The name of the StateType ({53da0021-974a-434a-94ac-3f187aad1480}) of ThingClass ufo - Set brigtness - The name of the ActionType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of DeviceClass ufo + Effect top changed + The name of the EventType ({53da0021-974a-434a-94ac-3f187aad1480}) of ThingClass ufo - Set color - The name of the ActionType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of DeviceClass ufo + Host address + The name of the ParamType (ThingClass: ufo, Type: thing, ID: {3e14968b-954e-4e85-ae79-3de9ae4fe951}) - Set color temperature - The name of the ActionType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of DeviceClass ufo + Id + The name of the ParamType (ThingClass: ufo, Type: thing, ID: {142c25c0-03e3-478e-b5c3-3d072f668cc4}) - Set effect - The name of the ActionType ({53da0021-974a-434a-94ac-3f187aad1480}) of DeviceClass ufo - - - - Set logo - The name of the ActionType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of DeviceClass ufo - - - - Set power - The name of the ActionType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of DeviceClass ufo + Logo + The name of the ParamType (ThingClass: ufo, ActionType: logo, ID: {a9c123e2-db78-40d3-a422-7e4817d50984}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: logo, ID: {a9c123e2-db78-40d3-a422-7e4817d50984}) +---------- +The name of the StateType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of ThingClass ufo - alert - The name of the ParamType (DeviceClass: ufo, ActionType: alert, ID: {e8d854ce-02d0-4ddd-a2bd-0c464cbb9182}) + Logo changed + The name of the EventType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of ThingClass ufo - flash - The name of the ActionType ({6efa52d9-527b-4ac7-8885-50f2b1786561}) of DeviceClass ufo + + + Logo color + The name of the ParamType (ThingClass: ufo, ActionType: logoColor, ID: {d3eb4a99-20cc-4d47-af7d-33453aca2087}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: logoColor, ID: {d3eb4a99-20cc-4d47-af7d-33453aca2087}) +---------- +The name of the StateType ({d3eb4a99-20cc-4d47-af7d-33453aca2087}) of ThingClass ufo - + + Logo color changed + The name of the EventType ({d3eb4a99-20cc-4d47-af7d-33453aca2087}) of ThingClass ufo + + + + + + + Power + The name of the ParamType (ThingClass: ufo, ActionType: power, ID: {14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: power, ID: {14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) +---------- +The name of the StateType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of ThingClass ufo + + + + + Power changed + The name of the EventType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of ThingClass ufo + + + + + + Reachable + The name of the ParamType (ThingClass: ufo, EventType: connected, ID: {1a439907-e810-4dea-b357-dd32281896e7}) +---------- +The name of the StateType ({1a439907-e810-4dea-b357-dd32281896e7}) of ThingClass ufo + + + + + Reachable changed + The name of the EventType ({1a439907-e810-4dea-b357-dd32281896e7}) of ThingClass ufo + + + + + Set bottom color + The name of the ActionType ({ef2a8d5b-82d4-43d5-b9ec-82ef5662b971}) of ThingClass ufo + + + + + Set bottom effect + The name of the ActionType ({0fab896b-9900-4375-96c0-0d38460cee65}) of ThingClass ufo + + + + + Set brigtness + The name of the ActionType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of ThingClass ufo + + + + + Set color + The name of the ActionType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of ThingClass ufo + + + + + Set color temperature + The name of the ActionType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of ThingClass ufo + + + + + Set top color + The name of the ActionType ({b378290a-468f-45ef-9d65-00546737ce9b}) of ThingClass ufo + + + + + Set top effect + The name of the ActionType ({53da0021-974a-434a-94ac-3f187aad1480}) of ThingClass ufo + + + + + + + Top color + The name of the ParamType (ThingClass: ufo, ActionType: topColor, ID: {b378290a-468f-45ef-9d65-00546737ce9b}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: topColor, ID: {b378290a-468f-45ef-9d65-00546737ce9b}) +---------- +The name of the StateType ({b378290a-468f-45ef-9d65-00546737ce9b}) of ThingClass ufo + + + + + Top color changed + The name of the EventType ({b378290a-468f-45ef-9d65-00546737ce9b}) of ThingClass ufo + + + + + Set logo + The name of the ActionType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of ThingClass ufo + + + + + Set logo color + The name of the ActionType ({d3eb4a99-20cc-4d47-af7d-33453aca2087}) of ThingClass ufo + + + + + Set power + The name of the ActionType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of ThingClass ufo + + + + ufo - The name of the DeviceClass ({6271f010-0b0a-4f29-b894-0611bb5f3dcc}) + The name of the ThingClass ({6271f010-0b0a-4f29-b894-0611bb5f3dcc}) From d104acfc2e121b989322d1a304fd4414756b3692 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 24 Mar 2020 23:37:09 +0100 Subject: [PATCH 07/12] Fix discovery and add german translation --- dynatrace/README.md | 18 +- dynatrace/integrationplugindynatrace.cpp | 68 +++- dynatrace/integrationplugindynatrace.h | 4 + dynatrace/integrationplugindynatrace.json | 2 +- ...a8451bd7-69cb-4106-968f-1206a5736368-de.ts | 297 ++++++++++++++++++ ...51bd7-69cb-4106-968f-1206a5736368-en_US.ts | 20 +- 6 files changed, 372 insertions(+), 37 deletions(-) create mode 100644 dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-de.ts diff --git a/dynatrace/README.md b/dynatrace/README.md index 379a2a36..8f78c5b8 100644 --- a/dynatrace/README.md +++ b/dynatrace/README.md @@ -2,14 +2,12 @@ This plug-in enables nymea to control the Dynatrace Ufo. -## Supported Things +The Dynatrace UFO is a sophisticated status light by Dynatrace. More information about the the UFO can be found +(here)[https://www.dynatrace.com/news/blog/using-dynatrace-devops-pipeline-state-ufo/]. 3D print layouts and +build instructions for your own UFO are available at this (github page)[https://github.com/Dynatrace/ufo]. -* Dynatrace UFO - * Auto discovery setup - * Light interface - * Control color of each ring - * Control logo color - * Set morph and rotate effect +This nymea integration supports auto discovering UFOs in the network and set them up as a color light in nymea. +Each ring can as well as the top logo can be controlled individually and morph and rotate effects can be enabled. ## Requirements @@ -17,7 +15,6 @@ This plug-in enables nymea to control the Dynatrace Ufo. * TCP sockets on port 80 must not be blocked by the router. * The package "nymea-plugin-dynatrace" must be installed. -An excerpt of the Ufo (Blog Post)[https://www.dynatrace.com/news/blog/using-dynatrace-devops-pipeline-state-ufo/] * Plug it in! * Press the little black dot on the top. The UFO starts blinking blue and now offers a WiFi hotspot with the name “ufo” @@ -27,8 +24,3 @@ An excerpt of the Ufo (Blog Post)[https://www.dynatrace.com/news/blog/using-dyna * While it reboots itself it will blink yellow. Once it has its assigned IP Address it will start visualizing its IP Address through a special „blink code“ as explained in the Quick Start Guide! * Remember: the UFO will also try to register its hostname as „ufo“ with your DHCP server. If that works you can simply browse to http://ufo - -## More - -More about the Dynatrace Ufo: https://github.com/Dynatrace/ufo - diff --git a/dynatrace/integrationplugindynatrace.cpp b/dynatrace/integrationplugindynatrace.cpp index 1dcf0d6a..c9df22a2 100644 --- a/dynatrace/integrationplugindynatrace.cpp +++ b/dynatrace/integrationplugindynatrace.cpp @@ -36,44 +36,78 @@ #include #include #include +#include IntegrationPluginDynatrace::IntegrationPluginDynatrace() { - } void IntegrationPluginDynatrace::discoverThings(ThingDiscoveryInfo *info) { - if (info->thingClassId() == ufoThingClassId) { + QHostInfo::lookupHost("ufo.home", info, [this, info](const QHostInfo &host){ + if (host.error() != QHostInfo::NoError) { + qCDebug(dcDynatrace()) << "Lookup failed:" << host.errorString(); + info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("An error happened discovering the UFO in the network.")); + return; + } - QHostInfo::lookupHost("ufo.home", this, [info](const QHostInfo &host){ - if (host.error() != QHostInfo::NoError) { - qCDebug(dcDynatrace()) << "Lookup failed:" << host.errorString(); - } + // NOTE: QHostInfo::lookupHost apparently calls back from a different thread which breaks + // QNetworkAccessManager... Decouple it here with a QueuedConnection + QMetaObject::invokeMethod(this, "resolveIds", Qt::QueuedConnection, Q_ARG(ThingDiscoveryInfo*, info), Q_ARG(QHostInfo, host)); + }); +} - foreach (QHostAddress address, host.addresses()) { - qCDebug(dcDynatrace()) << "Found IP address" << address.toString(); +void IntegrationPluginDynatrace::resolveIds(ThingDiscoveryInfo *info, const QHostInfo &host) +{ + QList *pendingInfoRequests = new QList(); - ThingDescriptor descriptor(ufoThingClassId, "Ufo", address.toString()); + foreach (QHostAddress address, host.addresses()) { + qCDebug(dcDynatrace()) << "Found IP address" << address.toString(); + + QNetworkRequest infoRequest("http://" + address.toString() + "/info"); + QNetworkReply *reply = hardwareManager()->networkManager()->get(infoRequest); + + pendingInfoRequests->append(reply); + + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, info, [this, info, reply, address, pendingInfoRequests](){ + pendingInfoRequests->removeAll(reply); + + QJsonParseError error; + QJsonDocument data = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error == QJsonParseError::NoError) { + QString id = data.toVariant().toMap().value("ufoid").toString(); + + ThingDescriptor descriptor(ufoThingClassId, "UFO", address.toString()); ParamList params; - //FIXME Rediscovery - /*Thing *existingThing = myThings().findByParams(ParamList() << Param(ufoThingIdParamTypeId, "")); - if (existingThing) { - //For Thing re-discovery - descriptor.setThingId(existingthing->id()); - }*/ + params << Param(ufoThingIdParamTypeId, id); params << Param(ufoThingHostParamTypeId, address.toString()); descriptor.setParams(params); + + Things existingUfos = myThings().filterByParam(ufoThingIdParamTypeId, id); + if (!existingUfos.isEmpty()) { + descriptor.setThingId(existingUfos.first()->id()); + } + info->addThingDescriptor(descriptor); } - info->finish(Thing::ThingErrorNoError); + + if (pendingInfoRequests->isEmpty()) { + delete pendingInfoRequests; + info->finish(Thing::ThingErrorNoError); + } + }); } + + // In case we abort, make sure to clean up stuff + connect(info, &ThingDiscoveryInfo::aborted, this, [pendingInfoRequests](){ + delete pendingInfoRequests; + }); } void IntegrationPluginDynatrace::setupThing(ThingSetupInfo *info) { - if (info->thing()->thingClassId() == ufoThingClassId) { QHostAddress address = QHostAddress(info->thing()->paramValue(ufoThingHostParamTypeId).toString()); QString id = info->thing()->paramValue(ufoThingIdParamTypeId).toString(); diff --git a/dynatrace/integrationplugindynatrace.h b/dynatrace/integrationplugindynatrace.h index 0b77d6e1..a1e48051 100644 --- a/dynatrace/integrationplugindynatrace.h +++ b/dynatrace/integrationplugindynatrace.h @@ -38,6 +38,7 @@ #include #include +#include class IntegrationPluginDynatrace : public IntegrationPlugin { @@ -63,6 +64,9 @@ private: private slots: void onConnectionChanged(bool connected); + +private slots: + void resolveIds(ThingDiscoveryInfo *info, const QHostInfo &host); }; #endif // INTEGRATIONPLUGINDYNATRACE_H diff --git a/dynatrace/integrationplugindynatrace.json b/dynatrace/integrationplugindynatrace.json index 2f768a2e..54241891 100644 --- a/dynatrace/integrationplugindynatrace.json +++ b/dynatrace/integrationplugindynatrace.json @@ -11,7 +11,7 @@ { "id": "6271f010-0b0a-4f29-b894-0611bb5f3dcc", "name": "ufo", - "displayName": "ufo", + "displayName": "UFO", "createMethods": ["user", "discovery"], "interfaces": ["colorlight", "connectable"], "paramTypes": [ diff --git a/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-de.ts b/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-de.ts new file mode 100644 index 00000000..9119892e --- /dev/null +++ b/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-de.ts @@ -0,0 +1,297 @@ + + + + + IntegrationPluginDynatrace + + + An error happened discovering the UFO in the network. + Ein Netzwerkfehler ist beim Auffinden des UFOs aufgetreten. + + + + dynatrace + + + + + Brightness + The name of the ParamType (ThingClass: ufo, ActionType: brightness, ID: {1adb2df8-7ba1-48b8-b0da-d67085efe041}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: brightness, ID: {1adb2df8-7ba1-48b8-b0da-d67085efe041}) +---------- +The name of the StateType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of ThingClass ufo + Helligkeit + + + + Brightness changed + The name of the EventType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of ThingClass ufo + Helligkeit geändert + + + + + + Color + The name of the ParamType (ThingClass: ufo, ActionType: color, ID: {9535fd99-05c6-449f-80a2-8daf61d9b9b0}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: color, ID: {9535fd99-05c6-449f-80a2-8daf61d9b9b0}) +---------- +The name of the StateType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of ThingClass ufo + Farbe + + + + Color changed + The name of the EventType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of ThingClass ufo + Farbe geändert + + + + + + Color temperature + The name of the ParamType (ThingClass: ufo, ActionType: colorTemperature, ID: {60fa917b-8702-4ff2-90b8-9c8c616bb21f}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: colorTemperature, ID: {60fa917b-8702-4ff2-90b8-9c8c616bb21f}) +---------- +The name of the StateType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of ThingClass ufo + Farbtemperatur + + + + Color temperature changed + The name of the EventType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of ThingClass ufo + Farbtemperatur geändert + + + + + Dynatrace + The name of the vendor ({31b402be-1562-4335-aa83-d1c1166db570}) +---------- +The name of the plugin dynatrace ({a8451bd7-69cb-4106-968f-1206a5736368}) + Dynatrace + + + + + + Bottom color + The name of the ParamType (ThingClass: ufo, ActionType: bottomColor, ID: {ef2a8d5b-82d4-43d5-b9ec-82ef5662b971}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: bottomColor, ID: {ef2a8d5b-82d4-43d5-b9ec-82ef5662b971}) +---------- +The name of the StateType ({ef2a8d5b-82d4-43d5-b9ec-82ef5662b971}) of ThingClass ufo + Farbe unten + + + + Bottom color changed + The name of the EventType ({ef2a8d5b-82d4-43d5-b9ec-82ef5662b971}) of ThingClass ufo + Farbe unten geändert + + + + + + Effect bottom + The name of the ParamType (ThingClass: ufo, ActionType: effectBottom, ID: {0fab896b-9900-4375-96c0-0d38460cee65}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: effectBottom, ID: {0fab896b-9900-4375-96c0-0d38460cee65}) +---------- +The name of the StateType ({0fab896b-9900-4375-96c0-0d38460cee65}) of ThingClass ufo + Effekt unten + + + + Effect bottom changed + The name of the EventType ({0fab896b-9900-4375-96c0-0d38460cee65}) of ThingClass ufo + Effekt unten geändert + + + + + + Effect top + The name of the ParamType (ThingClass: ufo, ActionType: effectTop, ID: {53da0021-974a-434a-94ac-3f187aad1480}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: effectTop, ID: {53da0021-974a-434a-94ac-3f187aad1480}) +---------- +The name of the StateType ({53da0021-974a-434a-94ac-3f187aad1480}) of ThingClass ufo + Effekt oben + + + + Effect top changed + The name of the EventType ({53da0021-974a-434a-94ac-3f187aad1480}) of ThingClass ufo + Effekt oben geändert + + + + Host address + The name of the ParamType (ThingClass: ufo, Type: thing, ID: {3e14968b-954e-4e85-ae79-3de9ae4fe951}) + IP Adresse + + + + Id + The name of the ParamType (ThingClass: ufo, Type: thing, ID: {142c25c0-03e3-478e-b5c3-3d072f668cc4}) + ID + + + + + + Logo + The name of the ParamType (ThingClass: ufo, ActionType: logo, ID: {a9c123e2-db78-40d3-a422-7e4817d50984}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: logo, ID: {a9c123e2-db78-40d3-a422-7e4817d50984}) +---------- +The name of the StateType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of ThingClass ufo + Logo + + + + Logo changed + The name of the EventType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of ThingClass ufo + Logo geändert + + + + + + Logo color + The name of the ParamType (ThingClass: ufo, ActionType: logoColor, ID: {d3eb4a99-20cc-4d47-af7d-33453aca2087}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: logoColor, ID: {d3eb4a99-20cc-4d47-af7d-33453aca2087}) +---------- +The name of the StateType ({d3eb4a99-20cc-4d47-af7d-33453aca2087}) of ThingClass ufo + Logo-Farbe + + + + Logo color changed + The name of the EventType ({d3eb4a99-20cc-4d47-af7d-33453aca2087}) of ThingClass ufo + Logo-Farbe geändert + + + + + + Power + The name of the ParamType (ThingClass: ufo, ActionType: power, ID: {14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: power, ID: {14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) +---------- +The name of the StateType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of ThingClass ufo + Eingeschaltet + + + + Power changed + The name of the EventType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of ThingClass ufo + Ein- oder ausgeschaltet + + + + + Reachable + The name of the ParamType (ThingClass: ufo, EventType: connected, ID: {1a439907-e810-4dea-b357-dd32281896e7}) +---------- +The name of the StateType ({1a439907-e810-4dea-b357-dd32281896e7}) of ThingClass ufo + Erreichbar + + + + Reachable changed + The name of the EventType ({1a439907-e810-4dea-b357-dd32281896e7}) of ThingClass ufo + Erreichbarkeit geändert + + + + Set bottom color + The name of the ActionType ({ef2a8d5b-82d4-43d5-b9ec-82ef5662b971}) of ThingClass ufo + Setze Farbe unten + + + + Set bottom effect + The name of the ActionType ({0fab896b-9900-4375-96c0-0d38460cee65}) of ThingClass ufo + Setze Farbe oben + + + + Set brigtness + The name of the ActionType ({1adb2df8-7ba1-48b8-b0da-d67085efe041}) of ThingClass ufo + Setze Helligkeit + + + + Set color + The name of the ActionType ({9535fd99-05c6-449f-80a2-8daf61d9b9b0}) of ThingClass ufo + Setze Farbe + + + + Set color temperature + The name of the ActionType ({60fa917b-8702-4ff2-90b8-9c8c616bb21f}) of ThingClass ufo + Setze Farbtemperatur + + + + Set top color + The name of the ActionType ({b378290a-468f-45ef-9d65-00546737ce9b}) of ThingClass ufo + Setze Farbe oben + + + + Set top effect + The name of the ActionType ({53da0021-974a-434a-94ac-3f187aad1480}) of ThingClass ufo + Setze Effekt oben + + + + + + Top color + The name of the ParamType (ThingClass: ufo, ActionType: topColor, ID: {b378290a-468f-45ef-9d65-00546737ce9b}) +---------- +The name of the ParamType (ThingClass: ufo, EventType: topColor, ID: {b378290a-468f-45ef-9d65-00546737ce9b}) +---------- +The name of the StateType ({b378290a-468f-45ef-9d65-00546737ce9b}) of ThingClass ufo + Farbe oben + + + + Top color changed + The name of the EventType ({b378290a-468f-45ef-9d65-00546737ce9b}) of ThingClass ufo + Farbe oben geändert + + + + UFO + The name of the ThingClass ({6271f010-0b0a-4f29-b894-0611bb5f3dcc}) + UFO + + + + Set logo + The name of the ActionType ({a9c123e2-db78-40d3-a422-7e4817d50984}) of ThingClass ufo + Setze Logo + + + + Set logo color + The name of the ActionType ({d3eb4a99-20cc-4d47-af7d-33453aca2087}) of ThingClass ufo + Setze Logo-Farbe + + + + Set power + The name of the ActionType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of ThingClass ufo + Ein- oder ausschalten + + + diff --git a/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts b/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts index 73f9789c..a9ffb8f8 100644 --- a/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts +++ b/dynatrace/translations/a8451bd7-69cb-4106-968f-1206a5736368-en_US.ts @@ -1,6 +1,14 @@ + + IntegrationPluginDynatrace + + + An error happened discovering the UFO in the network. + + + dynatrace @@ -261,6 +269,12 @@ The name of the StateType ({b378290a-468f-45ef-9d65-00546737ce9b}) of ThingClass The name of the EventType ({b378290a-468f-45ef-9d65-00546737ce9b}) of ThingClass ufo + + + UFO + The name of the ThingClass ({6271f010-0b0a-4f29-b894-0611bb5f3dcc}) + + Set logo @@ -279,11 +293,5 @@ The name of the StateType ({b378290a-468f-45ef-9d65-00546737ce9b}) of ThingClass The name of the ActionType ({14ac8d16-72be-4530-a2ce-dd5589ce8dd7}) of ThingClass ufo - - - ufo - The name of the ThingClass ({6271f010-0b0a-4f29-b894-0611bb5f3dcc}) - - From 95955e968efddb9f0a5f210396e03e39da09be7b Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 24 Mar 2020 23:40:52 +0100 Subject: [PATCH 08/12] Add to maker plugins --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 8c06dd32..d6f3b5e8 100644 --- a/debian/control +++ b/debian/control @@ -1035,6 +1035,7 @@ Depends: nymea-plugin-boblight, nymea-plugin-serialportcommander, nymea-plugin-systemmonitor, nymea-plugin-onewire, + nymea-plugin-ufo, Replaces: guh-plugins-maker Description: Plugins for nymea IoT server - Meta package for makers, tinkers and hackers The nymea daemon is a plugin based IoT (Internet of Things) server. The From 066a0e07ea9f0545b3844d3e9abde2ef96b51497 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 25 Mar 2020 00:28:09 +0100 Subject: [PATCH 09/12] fix dpkg install file --- debian/nymea-plugin-dynatrace.install.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/nymea-plugin-dynatrace.install.in b/debian/nymea-plugin-dynatrace.install.in index 80cc26d7..428b30a2 100644 --- a/debian/nymea-plugin-dynatrace.install.in +++ b/debian/nymea-plugin-dynatrace.install.in @@ -1 +1 @@ -usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_deviceplugindynatrace.so +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationplugindynatrace.so From 506039ab0c16ace16f1d30081aeab2c68c8fec63 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 25 Mar 2020 13:39:13 +0100 Subject: [PATCH 10/12] Make it build with older Qt versions (< 5.9) --- dynatrace/integrationplugindynatrace.cpp | 29 +++++++++++++++--------- dynatrace/integrationplugindynatrace.h | 13 ++++++----- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/dynatrace/integrationplugindynatrace.cpp b/dynatrace/integrationplugindynatrace.cpp index c9df22a2..e071caa2 100644 --- a/dynatrace/integrationplugindynatrace.cpp +++ b/dynatrace/integrationplugindynatrace.cpp @@ -44,21 +44,28 @@ IntegrationPluginDynatrace::IntegrationPluginDynatrace() void IntegrationPluginDynatrace::discoverThings(ThingDiscoveryInfo *info) { - QHostInfo::lookupHost("ufo.home", info, [this, info](const QHostInfo &host){ - if (host.error() != QHostInfo::NoError) { - qCDebug(dcDynatrace()) << "Lookup failed:" << host.errorString(); - info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("An error happened discovering the UFO in the network.")); - return; - } + m_asyncDiscoveries.append(info); - // NOTE: QHostInfo::lookupHost apparently calls back from a different thread which breaks - // QNetworkAccessManager... Decouple it here with a QueuedConnection - QMetaObject::invokeMethod(this, "resolveIds", Qt::QueuedConnection, Q_ARG(ThingDiscoveryInfo*, info), Q_ARG(QHostInfo, host)); - }); + // NOTE: QHostInfo::lookupHost will call in from another thread using the Funtor syntax! + // https://bugreports.qt.io/browse/QTBUG-83073 + // Using the old school syntax... + QHostInfo::lookupHost("ufo.home", this, SLOT(resolveIds(const QHostInfo &))); } -void IntegrationPluginDynatrace::resolveIds(ThingDiscoveryInfo *info, const QHostInfo &host) +void IntegrationPluginDynatrace::resolveIds(const QHostInfo &host) { + if (m_asyncDiscoveries.isEmpty()) { + qCWarning(dcDynatrace()) << "Discvery result came in but request has vanished..."; + return; + } + + ThingDiscoveryInfo *info = m_asyncDiscoveries.takeFirst(); + if (host.error() != QHostInfo::NoError) { + qCDebug(dcDynatrace()) << "Lookup failed:" << host.errorString(); + info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("An error happened discovering the UFO in the network.")); + return; + } + QList *pendingInfoRequests = new QList(); foreach (QHostAddress address, host.addresses()) { diff --git a/dynatrace/integrationplugindynatrace.h b/dynatrace/integrationplugindynatrace.h index a1e48051..fae00132 100644 --- a/dynatrace/integrationplugindynatrace.h +++ b/dynatrace/integrationplugindynatrace.h @@ -54,19 +54,20 @@ public: void executeAction(ThingActionInfo *info) override; void thingRemoved(Thing *thing) override; + +private slots: + void onConnectionChanged(bool connected); + + void resolveIds(const QHostInfo &host); + private: PluginTimer *m_pluginTimer = nullptr; QHash m_ufoConnections; QHash m_asyncActions; QHash m_asyncSetup; + QList m_asyncDiscoveries; void getId(const QHostAddress &address); - -private slots: - void onConnectionChanged(bool connected); - -private slots: - void resolveIds(ThingDiscoveryInfo *info, const QHostInfo &host); }; #endif // INTEGRATIONPLUGINDYNATRACE_H From 130a7202aeb06888d28f820645914fef897602af Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 25 Mar 2020 13:44:16 +0100 Subject: [PATCH 11/12] Properly use the lookup id --- dynatrace/integrationplugindynatrace.cpp | 11 ++++++----- dynatrace/integrationplugindynatrace.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/dynatrace/integrationplugindynatrace.cpp b/dynatrace/integrationplugindynatrace.cpp index e071caa2..da646363 100644 --- a/dynatrace/integrationplugindynatrace.cpp +++ b/dynatrace/integrationplugindynatrace.cpp @@ -44,22 +44,23 @@ IntegrationPluginDynatrace::IntegrationPluginDynatrace() void IntegrationPluginDynatrace::discoverThings(ThingDiscoveryInfo *info) { - m_asyncDiscoveries.append(info); - // NOTE: QHostInfo::lookupHost will call in from another thread using the Funtor syntax! // https://bugreports.qt.io/browse/QTBUG-83073 // Using the old school syntax... - QHostInfo::lookupHost("ufo.home", this, SLOT(resolveIds(const QHostInfo &))); + int id = QHostInfo::lookupHost("ufo.home", this, SLOT(resolveIds(const QHostInfo &))); + m_asyncDiscoveries.insert(id, info); } void IntegrationPluginDynatrace::resolveIds(const QHostInfo &host) { - if (m_asyncDiscoveries.isEmpty()) { + int id = host.lookupId(); + + if (!m_asyncDiscoveries.contains(id)) { qCWarning(dcDynatrace()) << "Discvery result came in but request has vanished..."; return; } - ThingDiscoveryInfo *info = m_asyncDiscoveries.takeFirst(); + ThingDiscoveryInfo *info = m_asyncDiscoveries.take(id); if (host.error() != QHostInfo::NoError) { qCDebug(dcDynatrace()) << "Lookup failed:" << host.errorString(); info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("An error happened discovering the UFO in the network.")); diff --git a/dynatrace/integrationplugindynatrace.h b/dynatrace/integrationplugindynatrace.h index fae00132..cc7494be 100644 --- a/dynatrace/integrationplugindynatrace.h +++ b/dynatrace/integrationplugindynatrace.h @@ -65,7 +65,7 @@ private: QHash m_ufoConnections; QHash m_asyncActions; QHash m_asyncSetup; - QList m_asyncDiscoveries; + QHash m_asyncDiscoveries; void getId(const QHostAddress &address); }; From 8f7567abb2693aa622e2b93298806b246a7885ef Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 25 Mar 2020 19:11:24 +0100 Subject: [PATCH 12/12] Fix maker plugin deps --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index d6f3b5e8..e4cc6f32 100644 --- a/debian/control +++ b/debian/control @@ -1035,7 +1035,7 @@ Depends: nymea-plugin-boblight, nymea-plugin-serialportcommander, nymea-plugin-systemmonitor, nymea-plugin-onewire, - nymea-plugin-ufo, + nymea-plugin-dynatrace, Replaces: guh-plugins-maker Description: Plugins for nymea IoT server - Meta package for makers, tinkers and hackers The nymea daemon is a plugin based IoT (Internet of Things) server. The