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}) - -