Fronius: Allow discovering alternate mac manufacturer

pull/712/head
Michael Zanetti 2023-07-20 20:10:04 +02:00 committed by Simon Stürz
parent c141467b24
commit 060ebeef98
4 changed files with 214 additions and 9 deletions

View File

@ -3,11 +3,13 @@ include(../plugins.pri)
QT += network
SOURCES += \
froniusdiscovery.cpp \
froniusnetworkreply.cpp \
froniussolarconnection.cpp \
integrationpluginfronius.cpp \
HEADERS += \
froniusdiscovery.h \
froniusnetworkreply.h \
froniussolarconnection.h \
integrationpluginfronius.h \

View File

@ -0,0 +1,137 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2023, 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
* 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 <https://www.gnu.org/licenses/>.
*
* 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 "froniusdiscovery.h"
#include "extern-plugininfo.h"
#include <QJsonDocument>
#include <QJsonParseError>
FroniusDiscovery::FroniusDiscovery(NetworkAccessManager *networkManager, NetworkDeviceDiscovery *networkDeviceDiscovery, QObject *parent):
QObject(parent),
m_networkManager(networkManager),
m_networkDeviceDiscovery{networkDeviceDiscovery}
{
m_gracePeriodTimer.setSingleShot(true);
m_gracePeriodTimer.setInterval(3000);
connect(&m_gracePeriodTimer, &QTimer::timeout, this, [this](){
qCDebug(dcFronius()) << "Discovery: Grace period timer triggered.";
finishDiscovery();
});
}
void FroniusDiscovery::startDiscovery()
{
qCInfo(dcFronius()) << "Discovery: Searching for Fronius solar devices in the network...";
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &FroniusDiscovery::checkNetworkDevice);
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
qCDebug(dcFronius()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices";
m_gracePeriodTimer.start();
discoveryReply->deleteLater();
});
}
QList<NetworkDeviceInfo> FroniusDiscovery::discoveryResults() const
{
return m_discoveryResults;
}
void FroniusDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo)
{
qCDebug(dcFronius()) << "Checking network device:" << networkDeviceInfo;
FroniusSolarConnection *connection = new FroniusSolarConnection(m_networkManager, networkDeviceInfo.address(), this);
m_connections.append(connection);
FroniusNetworkReply *reply = connection->getVersion();
connect(reply, &FroniusNetworkReply::finished, this, [=] {
QByteArray data = reply->networkReply()->readAll();
if (reply->networkReply()->error() != QNetworkReply::NoError) {
if (reply->networkReply()->error() == QNetworkReply::ContentNotFoundError) {
qCInfo(dcFronius()) << "The device does not reply to our requests. Please verify that the Fronius Solar API is enabled on the device.";
} else {
qCDebug(dcFronius()) << "device" << networkDeviceInfo.address() << "is not reachable.";
}
cleanupConnection(connection);
return;
}
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcFronius()) << "Failed to parse JSON data" << data << ":" << error.errorString() << data;
cleanupConnection(connection);
return;
}
QVariantMap versionResponseMap = jsonDoc.toVariant().toMap();
if (!versionResponseMap.contains("CompatibilityRange")) {
qCInfo(dcFronius()) << "Unexpected JSON reply. PRobably not a Fronius device.";
cleanupConnection(connection);
return;
}
qCDebug(dcFronius()) << "Compatibility version" << versionResponseMap.value("CompatibilityRange").toString();
// Knwon version with broken JSON API. Still allowing to discover so the user will get a proper error message during setup
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.";
}
m_discoveryResults.append(networkDeviceInfo);
cleanupConnection(connection);
});
}
void FroniusDiscovery::cleanupConnection(FroniusSolarConnection *connection)
{
m_connections.removeAll(connection);
connection->deleteLater();
}
void FroniusDiscovery::finishDiscovery()
{
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
foreach (FroniusSolarConnection *connection, m_connections) {
cleanupConnection(connection);
}
qCInfo(dcFronius()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count()
<< "Fronius devices in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz");
m_gracePeriodTimer.stop();
emit discoveryFinished();
}

View File

@ -0,0 +1,70 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2023, 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
* 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 <https://www.gnu.org/licenses/>.
*
* 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 FRONIUSDISCOVERY_H
#define FRONIUSDISCOVERY_H
#include <QObject>
#include <QTimer>
#include <network/networkdevicediscovery.h>
#include "froniussolarconnection.h"
class FroniusDiscovery : public QObject
{
Q_OBJECT
public:
explicit FroniusDiscovery(NetworkAccessManager *networkManager, NetworkDeviceDiscovery *networkDeviceDiscovery, QObject *parent = nullptr);
void startDiscovery();
QList<NetworkDeviceInfo> discoveryResults() const;
signals:
void discoveryFinished();
private:
NetworkAccessManager *m_networkManager = nullptr;
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
QTimer m_gracePeriodTimer;
QDateTime m_startDateTime;
QList<FroniusSolarConnection *> m_connections;
QList<NetworkDeviceInfo> m_discoveryResults;
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
void cleanupConnection(FroniusSolarConnection *connection);
void finishDiscovery();
};
#endif // FRONIUSDISCOVERY_H

View File

@ -31,6 +31,7 @@
#include "plugininfo.h"
#include "plugintimer.h"
#include "integrationpluginfronius.h"
#include "froniusdiscovery.h"
#include "network/networkaccessmanager.h"
#include "network/networkdevicediscovery.h"
@ -56,20 +57,15 @@ void IntegrationPluginFronius::discoverThings(ThingDiscoveryInfo *info)
}
qCInfo(dcFronius()) << "Starting network discovery...";
NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover();
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, info, [=](){
FroniusDiscovery *discovery = new FroniusDiscovery(hardwareManager()->networkManager(), hardwareManager()->networkDeviceDiscovery(), info);
connect(discovery, &FroniusDiscovery::discoveryFinished, info, [=](){
ThingDescriptors descriptors;
qCDebug(dcFronius()) << "Discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "devices";
foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) {
qCDebug(dcFronius()) << "Discovery finished. Found" << discovery->discoveryResults().count() << "devices";
foreach (const NetworkDeviceInfo &networkDeviceInfo, discovery->discoveryResults()) {
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 += "Fronius Solar";