diff --git a/fronius/froniuslogger.cpp b/fronius/froniuslogger.cpp index e15651d5..c03bd0d8 100644 --- a/fronius/froniuslogger.cpp +++ b/fronius/froniuslogger.cpp @@ -65,8 +65,7 @@ void FroniusLogger::updateThingInfo(const QByteArray &data) QVariantMap headMap = jsonDoc.toVariant().toMap().value("Head").toMap(); QVariantMap bodyMap = jsonDoc.toVariant().toMap().value("Body").toMap(); - // print the fetched data in dataMap format to stdout - //qCDebug(dcFroniusSolar()) << dataMap; + //qCDebug(dcFronius()) << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented)); // create LoggerInfo list Map QVariantMap LoggerInfoMap = bodyMap.value("LoggerInfo").toMap(); diff --git a/fronius/integrationpluginfronius.cpp b/fronius/integrationpluginfronius.cpp index a8538f49..23be6595 100644 --- a/fronius/integrationpluginfronius.cpp +++ b/fronius/integrationpluginfronius.cpp @@ -32,6 +32,7 @@ #include "integrationpluginfronius.h" #include "plugintimer.h" #include "network/networkaccessmanager.h" +#include "network/networkdevicediscovery.h" #include #include @@ -46,6 +47,61 @@ IntegrationPluginFronius::IntegrationPluginFronius(QObject *parent): Integration } +void IntegrationPluginFronius::discoverThings(ThingDiscoveryInfo *info) +{ + if (!hardwareManager()->networkDeviceDiscovery()->available()) { + qCWarning(dcFronius()) << "Failed to discover network devices. The network device discovery is not available."; + info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("Unable to discovery devices in your network.")); + return; + } + + qCDebug(dcFronius()) << "Starting network discovery..."; + NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover(); + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ + ThingDescriptors descriptors; + qCDebug(dcFronius()) << "Discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "devices"; + foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) { + qCDebug(dcFronius()) << networkDeviceInfo; + if (networkDeviceInfo.macAddress().isNull()) + continue; + + // Hostname or MAC manufacturer must include Fronius + if (!(networkDeviceInfo.macAddressManufacturer().toLower().contains("fronius") || networkDeviceInfo.hostName().toLower().contains("fronius"))) + continue; + + QString title; + if (networkDeviceInfo.hostName().isEmpty()) { + title += networkDeviceInfo.address().toString(); + } else { + title += networkDeviceInfo.address().toString() + " (" + networkDeviceInfo.hostName() + ")"; + } + + QString description; + if (networkDeviceInfo.macAddressManufacturer().isEmpty()) { + description = networkDeviceInfo.macAddress(); + } else { + description = networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")"; + } + + ThingDescriptor descriptor(dataloggerThingClassId, title, description); + + // Check if we already have set up this device + Things existingThings = myThings().filterByParam(dataloggerThingLoggerMacParamTypeId, networkDeviceInfo.macAddress()); + if (existingThings.count() == 1) { + qCDebug(dcFronius()) << "This thing already exists in the system." << existingThings.first() << networkDeviceInfo; + descriptor.setThingId(existingThings.first()->id()); + } + + ParamList params; + params << Param(dataloggerThingLoggerHostParamTypeId, networkDeviceInfo.address().toString()); + params << Param(dataloggerThingLoggerMacParamTypeId, networkDeviceInfo.macAddress()); + descriptor.setParams(params); + info->addThingDescriptor(descriptor); + } + info->finish(Thing::ThingErrorNoError); + }); +} + void IntegrationPluginFronius::setupThing(ThingSetupInfo *info) { qCDebug(dcFronius()) << "Setting up a new thing:" << info->thing()->name(); @@ -74,11 +130,9 @@ void IntegrationPluginFronius::setupThing(ThingSetupInfo *info) QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(requestUrl)); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, info, [this, info, thing, reply] { - QByteArray data = reply->readAll(); - if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcFronius()) << "Fronius: Network request error:" << reply->error() << reply->errorString() << reply->url(); + qCWarning(dcFronius()) << "Network request error:" << reply->error() << reply->errorString() << reply->url(); info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Device not reachable")); return; } @@ -87,13 +141,22 @@ void IntegrationPluginFronius::setupThing(ThingSetupInfo *info) QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) { - qCWarning(dcFronius()) << "Fronius: Failed to parse JSON data" << data << ":" << error.errorString() << data; + qCWarning(dcFronius()) << "Failed to parse JSON data" << data << ":" << error.errorString() << data; info->finish(Thing::ThingErrorHardwareFailure, tr("Please try again")); return; } + QVariantMap versionResponseMap = jsonDoc.toVariant().toMap(); + + // Knwon version with broken JSON API + if (versionResponseMap.value("CompatibilityRange").toString() == "1.6-2") { + qCWarning(dcFronius()) << "The Fronius data logger has a version which is known to have a broken JSON API firmware."; + info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("The firmware version 1.6-2 of this Fronius data logger has a broken API. Please update your Fronius device.")); + return; + } + FroniusLogger *newLogger = new FroniusLogger(thing, this); - newLogger->setBaseUrl(jsonDoc.toVariant().toMap().value("BaseURL").toString()); + newLogger->setBaseUrl(versionResponseMap.value("BaseURL").toString()); newLogger->setHostAddress(thing->paramValue(dataloggerThingLoggerHostParamTypeId).toString()); m_froniusLoggers.insert(newLogger, thing); diff --git a/fronius/integrationpluginfronius.h b/fronius/integrationpluginfronius.h index a82f6c35..4662b8fd 100644 --- a/fronius/integrationpluginfronius.h +++ b/fronius/integrationpluginfronius.h @@ -50,6 +50,7 @@ class IntegrationPluginFronius : public IntegrationPlugin public: explicit IntegrationPluginFronius(QObject *parent = nullptr); + void discoverThings(ThingDiscoveryInfo *info) override; void setupThing(ThingSetupInfo *thing) override; void postSetupThing(Thing* thing) override; void executeAction(ThingActionInfo *info) override; diff --git a/fronius/integrationpluginfronius.json b/fronius/integrationpluginfronius.json index 917ab66f..97081adb 100644 --- a/fronius/integrationpluginfronius.json +++ b/fronius/integrationpluginfronius.json @@ -12,7 +12,7 @@ "id": "4fd79fed-42f1-4df9-be64-3df7b2e0bda2", "name": "datalogger", "displayName": "Fronius Solar Connection", - "createMethods": ["user"], + "createMethods": ["discovery", "user"], "interfaces": ["gateway"], "paramTypes": [ { @@ -22,6 +22,13 @@ "type": "QString", "inputType": "IPv4Address", "defaultValue": "88.117.152.99" + }, + { + "id": "2237972e-385b-4458-b5d3-1d1fb4ae8756", + "name": "loggerMac", + "displayName": "MAC address", + "type": "QString", + "defaultValue": "00:00:00:00:00:00" } ], "stateTypes": [ @@ -210,8 +217,8 @@ { "id": "d6dbb879-4cbc-4db3-830e-b92ba91a13e5", "name": "totalEnergyProduced", - "displayName": "Energy total", - "displayNameEvent": "Energy total changed", + "displayName": "Total produced energy", + "displayNameEvent": "Total produced energy changed", "type": "double", "unit": "KiloWattHour", "defaultValue": "0"