Add fronius discovery and broken API version check

master
Simon Stürz 2021-08-09 17:24:40 +02:00
parent 057251df08
commit 63d7ad0314
4 changed files with 80 additions and 10 deletions

View File

@ -65,8 +65,7 @@ void FroniusLogger::updateThingInfo(const QByteArray &data)
QVariantMap headMap = jsonDoc.toVariant().toMap().value("Head").toMap(); QVariantMap headMap = jsonDoc.toVariant().toMap().value("Head").toMap();
QVariantMap bodyMap = jsonDoc.toVariant().toMap().value("Body").toMap(); QVariantMap bodyMap = jsonDoc.toVariant().toMap().value("Body").toMap();
// print the fetched data in dataMap format to stdout //qCDebug(dcFronius()) << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented));
//qCDebug(dcFroniusSolar()) << dataMap;
// create LoggerInfo list Map // create LoggerInfo list Map
QVariantMap LoggerInfoMap = bodyMap.value("LoggerInfo").toMap(); QVariantMap LoggerInfoMap = bodyMap.value("LoggerInfo").toMap();

View File

@ -32,6 +32,7 @@
#include "integrationpluginfronius.h" #include "integrationpluginfronius.h"
#include "plugintimer.h" #include "plugintimer.h"
#include "network/networkaccessmanager.h" #include "network/networkaccessmanager.h"
#include "network/networkdevicediscovery.h"
#include <QUrl> #include <QUrl>
#include <QUrlQuery> #include <QUrlQuery>
@ -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) void IntegrationPluginFronius::setupThing(ThingSetupInfo *info)
{ {
qCDebug(dcFronius()) << "Setting up a new thing:" << info->thing()->name(); 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)); QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(requestUrl));
connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
connect(reply, &QNetworkReply::finished, info, [this, info, thing, reply] { connect(reply, &QNetworkReply::finished, info, [this, info, thing, reply] {
QByteArray data = reply->readAll(); QByteArray data = reply->readAll();
if (reply->error() != QNetworkReply::NoError) { 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")); info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Device not reachable"));
return; return;
} }
@ -87,13 +141,22 @@ void IntegrationPluginFronius::setupThing(ThingSetupInfo *info)
QJsonParseError error; QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) { 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")); info->finish(Thing::ThingErrorHardwareFailure, tr("Please try again"));
return; 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); 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()); newLogger->setHostAddress(thing->paramValue(dataloggerThingLoggerHostParamTypeId).toString());
m_froniusLoggers.insert(newLogger, thing); m_froniusLoggers.insert(newLogger, thing);

View File

@ -50,6 +50,7 @@ class IntegrationPluginFronius : public IntegrationPlugin
public: public:
explicit IntegrationPluginFronius(QObject *parent = nullptr); explicit IntegrationPluginFronius(QObject *parent = nullptr);
void discoverThings(ThingDiscoveryInfo *info) override;
void setupThing(ThingSetupInfo *thing) override; void setupThing(ThingSetupInfo *thing) override;
void postSetupThing(Thing* thing) override; void postSetupThing(Thing* thing) override;
void executeAction(ThingActionInfo *info) override; void executeAction(ThingActionInfo *info) override;

View File

@ -12,7 +12,7 @@
"id": "4fd79fed-42f1-4df9-be64-3df7b2e0bda2", "id": "4fd79fed-42f1-4df9-be64-3df7b2e0bda2",
"name": "datalogger", "name": "datalogger",
"displayName": "Fronius Solar Connection", "displayName": "Fronius Solar Connection",
"createMethods": ["user"], "createMethods": ["discovery", "user"],
"interfaces": ["gateway"], "interfaces": ["gateway"],
"paramTypes": [ "paramTypes": [
{ {
@ -22,6 +22,13 @@
"type": "QString", "type": "QString",
"inputType": "IPv4Address", "inputType": "IPv4Address",
"defaultValue": "88.117.152.99" "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": [ "stateTypes": [
@ -210,8 +217,8 @@
{ {
"id": "d6dbb879-4cbc-4db3-830e-b92ba91a13e5", "id": "d6dbb879-4cbc-4db3-830e-b92ba91a13e5",
"name": "totalEnergyProduced", "name": "totalEnergyProduced",
"displayName": "Energy total", "displayName": "Total produced energy",
"displayNameEvent": "Energy total changed", "displayNameEvent": "Total produced energy changed",
"type": "double", "type": "double",
"unit": "KiloWattHour", "unit": "KiloWattHour",
"defaultValue": "0" "defaultValue": "0"