From 1aea8bd64ef2b64c6bb515ef40124a98a641eeae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 10 Dec 2024 16:43:42 +0100 Subject: [PATCH] Fronius: Update to networkdevice interface --- fronius/froniusdiscovery.cpp | 34 +++++++----- fronius/froniusdiscovery.h | 4 +- fronius/integrationpluginfronius.cpp | 80 ++++++++++++--------------- fronius/integrationpluginfronius.json | 11 +++- 4 files changed, 66 insertions(+), 63 deletions(-) diff --git a/fronius/froniusdiscovery.cpp b/fronius/froniusdiscovery.cpp index 997ce59b0..614ea47e4 100644 --- a/fronius/froniusdiscovery.cpp +++ b/fronius/froniusdiscovery.cpp @@ -46,7 +46,6 @@ FroniusDiscovery::FroniusDiscovery(NetworkAccessManager *networkManager, Network qCDebug(dcFronius()) << "Discovery: Grace period timer triggered."; finishDiscovery(); }); - } void FroniusDiscovery::startDiscovery() @@ -55,10 +54,14 @@ void FroniusDiscovery::startDiscovery() m_startDateTime = QDateTime::currentDateTime(); NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover(); - connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &FroniusDiscovery::checkNetworkDevice); - connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ + connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &FroniusDiscovery::checkHostAddress); + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [this, discoveryReply](){ + + m_networkDeviceInfos = discoveryReply->networkDeviceInfos(); + qCDebug(dcFronius()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices"; m_gracePeriodTimer.start(); + discoveryReply->deleteLater(); }); } @@ -68,11 +71,11 @@ QList FroniusDiscovery::discoveryResults() const return m_discoveryResults; } -void FroniusDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo) +void FroniusDiscovery::checkHostAddress(const QHostAddress &address) { - qCDebug(dcFronius()) << "Discovery: Checking network device:" << networkDeviceInfo; + qCDebug(dcFronius()) << "Discovery: Checking host address" << address.toString(); - FroniusSolarConnection *connection = new FroniusSolarConnection(m_networkManager, networkDeviceInfo.address(), this); + FroniusSolarConnection *connection = new FroniusSolarConnection(m_networkManager, address, this); m_connections.append(connection); FroniusNetworkReply *reply = connection->getVersion(); @@ -80,9 +83,9 @@ void FroniusDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice QByteArray data = reply->networkReply()->readAll(); if (reply->networkReply()->error() != QNetworkReply::NoError) { if (reply->networkReply()->error() == QNetworkReply::ContentNotFoundError) { - qCInfo(dcFronius()) << "Discovery: The device on" << networkDeviceInfo.address().toString() << "does not reply to our requests. Please verify that the Fronius Solar API is enabled on the device."; + qCInfo(dcFronius()) << "Discovery: The device on" << address.toString() << "does not reply to our requests. Please verify that the Fronius Solar API is enabled on the device."; } else { - qCDebug(dcFronius()) << "Discovery: Reply finished with error on" << networkDeviceInfo.address().toString() << reply->networkReply()->errorString(); + qCDebug(dcFronius()) << "Discovery: Reply finished with error on" << address.toString() << reply->networkReply()->errorString(); } cleanupConnection(connection); return; @@ -91,14 +94,14 @@ void FroniusDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) { - qCDebug(dcFronius()) << "Discovery: Failed to parse JSON data from" << networkDeviceInfo.address().toString() << ":" << error.errorString() << data; + qCDebug(dcFronius()) << "Discovery: Failed to parse JSON data from" << address.toString() << ":" << error.errorString() << data; cleanupConnection(connection); return; } QVariantMap versionResponseMap = jsonDoc.toVariant().toMap(); if (!versionResponseMap.contains("CompatibilityRange")) { - qCDebug(dcFronius()) << "Discovery: Unexpected JSON reply from" << networkDeviceInfo.address().toString() << "Probably not a Fronius device."; + qCDebug(dcFronius()) << "Discovery: Unexpected JSON reply from" << address.toString() << "Probably not a Fronius device."; cleanupConnection(connection); return; } @@ -109,7 +112,7 @@ void FroniusDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice qCWarning(dcFronius()) << "Discovery: The Fronius data logger has a version which is known to have a broken JSON API firmware."; } - m_discoveryResults.append(networkDeviceInfo); + m_discoveredAddresses.append(address); cleanupConnection(connection); }); } @@ -124,14 +127,15 @@ void FroniusDiscovery::finishDiscovery() { qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch(); - foreach (FroniusSolarConnection *connection, m_connections) { + foreach (FroniusSolarConnection *connection, m_connections) cleanupConnection(connection); - } + + foreach (const QHostAddress &address, m_discoveredAddresses) + m_discoveryResults.append(m_networkDeviceInfos.get(address)); qCDebug(dcFronius()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count() - << "Fronius devices in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); + << "Fronius devices in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); m_gracePeriodTimer.stop(); emit discoveryFinished(); - } diff --git a/fronius/froniusdiscovery.h b/fronius/froniusdiscovery.h index 6b7b3249a..856ddda90 100644 --- a/fronius/froniusdiscovery.h +++ b/fronius/froniusdiscovery.h @@ -59,9 +59,11 @@ class FroniusDiscovery : public QObject QList m_connections; + NetworkDeviceInfos m_networkDeviceInfos; + QList m_discoveredAddresses; QList m_discoveryResults; - void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo); + void checkHostAddress(const QHostAddress &address); void cleanupConnection(FroniusSolarConnection *connection); void finishDiscovery(); diff --git a/fronius/integrationpluginfronius.cpp b/fronius/integrationpluginfronius.cpp index 425e70370..9e5ab8361 100644 --- a/fronius/integrationpluginfronius.cpp +++ b/fronius/integrationpluginfronius.cpp @@ -62,8 +62,6 @@ void IntegrationPluginFronius::discoverThings(ThingDiscoveryInfo *info) qCInfo(dcFronius()) << "Discovery finished. Found" << discovery->discoveryResults().count() << "devices"; foreach (const NetworkDeviceInfo &networkDeviceInfo, discovery->discoveryResults()) { qCInfo(dcFronius()) << "Discovered Fronius on" << networkDeviceInfo; - if (networkDeviceInfo.macAddress().isNull()) - continue; QString title; if (networkDeviceInfo.hostName().isEmpty()) { @@ -73,24 +71,29 @@ void IntegrationPluginFronius::discoverThings(ThingDiscoveryInfo *info) } QString description; - if (networkDeviceInfo.macAddressManufacturer().isEmpty()) { - description = networkDeviceInfo.macAddress(); - } else { - description = networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")"; + if (networkDeviceInfo.macAddressInfos().count() == 1) { + MacAddressInfo macInfo = networkDeviceInfo.macAddressInfos().constFirst(); + if (macInfo.vendorName().isEmpty()) { + description = macInfo.macAddress().toString(); + } else { + description = macInfo.macAddress().toString() + " (" + macInfo.vendorName() + ")"; + } } ThingDescriptor descriptor(connectionThingClassId, title, description); + ParamList params; + params.append(Param(connectionThingMacAddressParamTypeId, networkDeviceInfo.thingParamValueMacAddress())); + params.append(Param(connectionThingHostNameParamTypeId, networkDeviceInfo.thingParamValueHostName())); + params.append(Param(connectionThingAddressParamTypeId, networkDeviceInfo.thingParamValueAddress())); + descriptor.setParams(params); // Check if we already have set up this device - Things existingThings = myThings().filterByParam(connectionThingMacParamTypeId, networkDeviceInfo.macAddress()); - if (existingThings.count() == 1) { - qCDebug(dcFronius()) << "This thing already exists in the system." << existingThings.first() << networkDeviceInfo; - descriptor.setThingId(existingThings.first()->id()); + Thing *existingThing = myThings().findByParams(params); + if (existingThing) { + qCDebug(dcFronius()) << "This thing already exists in the system." << existingThing; + descriptor.setThingId(existingThing->id()); } - ParamList params; - params << Param(connectionThingMacParamTypeId, networkDeviceInfo.macAddress()); - descriptor.setParams(params); info->addThingDescriptor(descriptor); } info->finish(Thing::ThingErrorNoError); @@ -113,42 +116,30 @@ void IntegrationPluginFronius::setupThing(ThingSetupInfo *info) connection->deleteLater(); } - if (m_monitors.contains(thing)) { + if (m_monitors.contains(thing)) hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing)); - } - - // Set up depending on the available params, mac can only be filled in by discovery (ro param), - // the ip could be used as static manual config for VPN networks or WAN IP's - QHostAddress address(thing->paramValue(connectionThingAddressParamTypeId).toString()); - MacAddress mac(thing->paramValue(connectionThingMacParamTypeId).toString()); - - // Create the connection - FroniusSolarConnection *connection = nullptr; - - if (mac.isValid() && !mac.isNull()) { - qCInfo(dcFronius()) << "Setting up network device monitor for Fronius connection using MAC address" << mac.toString(); - NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(mac); - m_monitors.insert(thing, monitor); - connection = new FroniusSolarConnection(hardwareManager()->networkManager(), monitor->networkDeviceInfo().address(), thing); - connect(monitor, &NetworkDeviceMonitor::networkDeviceInfoChanged, this, [=](const NetworkDeviceInfo &networkDeviceInfo){ - qCDebug(dcFronius()) << "Network device info changed for" << thing << networkDeviceInfo; - if (networkDeviceInfo.isValid()) { - connection->setAddress(networkDeviceInfo.address()); - refreshConnection(connection); - } else { - connection->setAddress(QHostAddress()); - } - }); - } else if (!address.isNull()) { - qCInfo(dcFronius()) << "Setting up Fronius connection based on IP address" << address.toString() << "without monitoring. Any IP changed will not be recognized and the device will be disconnected."; - connection = new FroniusSolarConnection(hardwareManager()->networkManager(), address, thing); - } else { - qCWarning(dcFronius()) << "Unable to set up thing" << thing << ", neither IP nor MAC is valid." << thing->params(); - info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("Please reconfigure the device.")); + NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing); + if (!monitor) { + qCWarning(dcFronius()) << "Unable to register monitor with the given params" << thing->params(); + info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("Unable to set up the connection with this configuration, please reconfigure the connection.")); return; } + qCInfo(dcFronius()) << "Set up Fronius connection " << monitor; + m_monitors.insert(thing, monitor); + + FroniusSolarConnection *connection = new FroniusSolarConnection(hardwareManager()->networkManager(), monitor->networkDeviceInfo().address(), thing); + connect(monitor, &NetworkDeviceMonitor::networkDeviceInfoChanged, this, [=](const NetworkDeviceInfo &networkDeviceInfo){ + qCDebug(dcFronius()) << "Network device info changed for" << thing << networkDeviceInfo; + if (networkDeviceInfo.isValid()) { + connection->setAddress(networkDeviceInfo.address()); + refreshConnection(connection); + } else { + connection->setAddress(QHostAddress()); + } + }); + connect(connection, &FroniusSolarConnection::availableChanged, this, [=](bool available){ qCDebug(dcFronius()) << thing << "Available changed" << available; thing->setStateValue("connected", available); @@ -168,7 +159,6 @@ void IntegrationPluginFronius::setupThing(ThingSetupInfo *info) } }); - if (info->isInitialSetup()) { // Verify the version FroniusNetworkReply *reply = connection->getVersion(); diff --git a/fronius/integrationpluginfronius.json b/fronius/integrationpluginfronius.json index ed0e59354..c8f93aadd 100644 --- a/fronius/integrationpluginfronius.json +++ b/fronius/integrationpluginfronius.json @@ -13,7 +13,7 @@ "name": "connection", "displayName": "Fronius Solar", "createMethods": ["discovery", "user"], - "interfaces": ["gateway"], + "interfaces": ["gateway", "networkdevice"], "providedInterfaces": ["energymeter", "solarinverter", "energystorage"], "paramTypes": [ { @@ -24,9 +24,16 @@ "inputType": "IPv4Address", "defaultValue": "" }, + { + "id": "05d05a5f-7da1-4198-b281-5199dc660acc", + "name": "hostName", + "displayName": "Host name", + "type": "QString", + "defaultValue": "" + }, { "id": "2237972e-385b-4458-b5d3-1d1fb4ae8756", - "name": "mac", + "name": "macAddress", "displayName": "Mac address", "type": "QString", "readOnly": true,