From 5503d82daefa0cee63d40976fbc45d340e732676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 10 Dec 2024 16:22:28 +0100 Subject: [PATCH] Bosswerk: Update to networkdevice interface --- bosswerk/integrationpluginbosswerk.cpp | 79 +++++++++++++++++-------- bosswerk/integrationpluginbosswerk.h | 5 +- bosswerk/integrationpluginbosswerk.json | 21 ++++++- 3 files changed, 76 insertions(+), 29 deletions(-) diff --git a/bosswerk/integrationpluginbosswerk.cpp b/bosswerk/integrationpluginbosswerk.cpp index 9856b9a13..4ef9f9c33 100644 --- a/bosswerk/integrationpluginbosswerk.cpp +++ b/bosswerk/integrationpluginbosswerk.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2022, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -33,6 +33,7 @@ #include "plugininfo.h" #include +#include #include #include #include @@ -50,10 +51,13 @@ IntegrationPluginBosswerk::IntegrationPluginBosswerk() IntegrationPluginBosswerk::~IntegrationPluginBosswerk() { + } void IntegrationPluginBosswerk::discoverThings(ThingDiscoveryInfo *info) -{ +{ + m_discoveryCache.clear(); + NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover(); // This device doesn't give much information without login credentials. In order to identify it we'll @@ -62,31 +66,47 @@ void IntegrationPluginBosswerk::discoverThings(ThingDiscoveryInfo *info) // If this proves to not be reliable enough, one more option would be to connect to TCP port 8899 which is open // and responds to a proprietary binary protocol which would need to be reverse engineered first. connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater); - connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, info, [=](const NetworkDeviceInfo &networkDeviceInfo){ - qCDebug(dcBosswerk()) << "Probing device" << networkDeviceInfo.address(); + connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, info, [this, info](const QHostAddress &address){ + qCDebug(dcBosswerk()) << "Probing device" << address.toString(); - QUrl url("http://" + networkDeviceInfo.address().toString() + "/status.html"); + QUrl url("http://" + address.toString() + "/status.html"); QNetworkRequest request(url); QNetworkReply *probeReply = hardwareManager()->networkManager()->get(QNetworkRequest(url)); connect(probeReply, &QNetworkReply::finished, probeReply, &QNetworkReply::deleteLater); - connect(probeReply, &QNetworkReply::finished, info, [=](){ + connect(probeReply, &QNetworkReply::finished, info, [probeReply, address, this](){ QByteArray data = probeReply->readAll(); - qCDebug(dcBosswerk()) << "Probe reply from" << networkDeviceInfo.address() << ":" << probeReply->rawHeaderPairs() << data; + qCDebug(dcBosswerk()) << "Probe reply from" << address.toString() << ":" << probeReply->rawHeaderPairs() << data; if (probeReply->header(QNetworkRequest::ServerHeader) == "HTTPD" && data == "401 Unauthorized\n

401 Unauthorized

\nAuthorization required.\n\n") { - qCDebug(dcBosswerk()) << "Found bosswerk MI-300/600:" << networkDeviceInfo.address(); - - ThingDescriptor descriptor(mix00ThingClassId, "MI-300/600", networkDeviceInfo.hostName()); - descriptor.setParams({Param(mix00ThingMacAddressParamTypeId, networkDeviceInfo.macAddress())}); - Thing *existingThing = myThings().findByParams({Param(mix00ThingMacAddressParamTypeId, networkDeviceInfo.macAddress())}); - if (existingThing) { - descriptor.setThingId(existingThing->id()); - } - info->addThingDescriptor(descriptor); + qCDebug(dcBosswerk()) << "Found bosswerk MI-300/600:" << address.toString(); + // We get the discovery info once the network device discovery is finished. + m_discoveryCache.append(address); } }); }); + + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, info, [this, info, discoveryReply](){ + foreach (const QHostAddress &address, m_discoveryCache) { + + NetworkDeviceInfo networkDeviceInfo = discoveryReply->networkDeviceInfos().get(address); + + ThingDescriptor descriptor(mix00ThingClassId, "MI-300/600", networkDeviceInfo.hostName()); + + ParamList params; + params.append(Param(mix00ThingMacAddressParamTypeId, networkDeviceInfo.thingParamValueMacAddress())); + params.append(Param(mix00ThingHostNameParamTypeId, networkDeviceInfo.thingParamValueHostName())); + params.append(Param(mix00ThingAddressParamTypeId, networkDeviceInfo.thingParamValueAddress())); + + Thing *existingThing = myThings().findByParams(params); + if (existingThing) + descriptor.setThingId(existingThing->id()); + + info->addThingDescriptor(descriptor); + } + m_discoveryCache.clear(); + }); + QTimer *timeout = new QTimer(info); timeout->start(28000); connect(timeout, &QTimer::timeout, info, [=](){ @@ -101,18 +121,24 @@ void IntegrationPluginBosswerk::startPairing(ThingPairingInfo *info) void IntegrationPluginBosswerk::confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret) { - MacAddress mac(info->params().paramValue(mix00ThingMacAddressParamTypeId).toString()); - - QHash cache = hardwareManager()->networkDeviceDiscovery()->cache(); - - if (!cache.contains(mac)) { - qCWarning(dcBosswerk()) << "MAC" << mac << "not found in network device cache."; + MacAddress macAddress(info->params().paramValue(mix00ThingMacAddressParamTypeId).toString()); + QString hostName(info->params().paramValue(mix00ThingHostNameParamTypeId).toString()); + QHostAddress address(info->params().paramValue(mix00ThingAddressParamTypeId).toString()); + + NetworkDeviceInfos cache = hardwareManager()->networkDeviceDiscovery()->cache(); + NetworkDeviceInfo networkDeviceInfo; + if (!macAddress.isNull()) { + networkDeviceInfo = cache.at(cache.indexFromMacAddress(macAddress).first()); + } else if (!hostName.isEmpty()) { + networkDeviceInfo = cache.at(cache.indexFromHostName(hostName)); + } else if (!address.isNull()) { + networkDeviceInfo = cache.get(address); + } else { + qCWarning(dcBosswerk()) << info->params() << "not found in network device cache."; info->finish(Thing::ThingErrorItemNotFound, QT_TR_NOOP("An error happened in the network communication.")); return; } - NetworkDeviceInfo networkDeviceInfo = cache.value(mac); - QUrl url("http://" + username + ":" + secret + "@" + networkDeviceInfo.address().toString() + "/status.html"); QNetworkRequest request(url); @@ -147,12 +173,13 @@ void IntegrationPluginBosswerk::setupThing(ThingSetupInfo *info) if (monitor) { hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(monitor); } + PluginTimer *timer = m_timers.take(thing); if (timer) { hardwareManager()->pluginTimerManager()->unregisterTimer(timer); } - monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(MacAddress(thing->paramValue(mix00ThingMacAddressParamTypeId).toString())); + monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing); m_deviceMonitors.insert(thing, monitor); timer = hardwareManager()->pluginTimerManager()->registerTimer(5); @@ -208,7 +235,7 @@ void IntegrationPluginBosswerk::pollDevice(Thing *thing) } QByteArray data = statusReply->readAll(); -// qCDebug(dcBosswerk) << "Status:" << qUtf8Printable(data); + // qCDebug(dcBosswerk) << "Status:" << qUtf8Printable(data); foreach (const QString &line, QString(data).split("\n")) { if (line.startsWith("var ")) { qCDebug(dcBosswerk()) << "Data line:" << line; diff --git a/bosswerk/integrationpluginbosswerk.h b/bosswerk/integrationpluginbosswerk.h index ba1a08f58..d2670bbdb 100644 --- a/bosswerk/integrationpluginbosswerk.h +++ b/bosswerk/integrationpluginbosswerk.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2022, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -34,6 +34,8 @@ #include "integrations/integrationplugin.h" #include "extern-plugininfo.h" +#include + class PluginTimer; class NetworkDeviceMonitor; class QNetworkReply; @@ -68,6 +70,7 @@ private slots: private: QHash m_deviceMonitors; QHash m_timers; + QList m_discoveryCache; }; #endif // INTEGRATIONPLUGINMEROSS_H diff --git a/bosswerk/integrationpluginbosswerk.json b/bosswerk/integrationpluginbosswerk.json index e0910f631..56849b7eb 100644 --- a/bosswerk/integrationpluginbosswerk.json +++ b/bosswerk/integrationpluginbosswerk.json @@ -14,13 +14,30 @@ "displayName": "MI-300/600", "createMethods": ["discovery"], "setupMethod": "userandpassword", - "interfaces": [ "solarinverter", "wirelessconnectable" ], + "interfaces": [ "solarinverter", "wirelessconnectable", "networkdevice" ], "paramTypes": [ + { + "id": "80f6972f-a2df-4cbb-beea-672bdcf05e45", + "name": "hostName", + "displayName": "Host name", + "type": "QString", + "defaultValue": "" + }, { "id": "6fbe5f08-3539-447d-9281-916abe9d8128", "name":"macAddress", "displayName": "MAC address", - "type": "QString" + "type": "QString", + "defaultValue": "00:00:00:00:00:00", + "readOnly": true + }, + { + "id": "f772600b-2a85-4459-a8a0-08b4e6adae2b", + "name": "address", + "displayName": "IP address", + "type": "QString", + "inputType": "IPv4Address", + "defaultValue": "" } ], "stateTypes": [