From 9665bab2347adb7c0671f16abbbb8bec55f151fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 18 Dec 2024 15:19:41 +0100 Subject: [PATCH] Solax: Update to networkdevice interface --- solax/integrationpluginsolax.cpp | 35 +++++++++++++----------- solax/integrationpluginsolax.json | 18 ++++++++++++- solax/solaxdiscovery.cpp | 44 ++++++++++++++++++------------- solax/solaxdiscovery.h | 8 +++--- 4 files changed, 65 insertions(+), 40 deletions(-) diff --git a/solax/integrationpluginsolax.cpp b/solax/integrationpluginsolax.cpp index 85c23b9..819df01 100644 --- a/solax/integrationpluginsolax.cpp +++ b/solax/integrationpluginsolax.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2023, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -63,20 +63,23 @@ void IntegrationPluginSolax::discoverThings(ThingDiscoveryInfo *info) if (!result.serialNumber.isEmpty()) title.append(" " + result.serialNumber); - ThingDescriptor descriptor(solaxInverterTcpThingClassId, title, result.networkDeviceInfo.address().toString() + " " + result.networkDeviceInfo.macAddress()); + ThingDescriptor descriptor(solaxInverterTcpThingClassId, title, result.networkDeviceInfo.address().toString()); qCInfo(dcSolax()) << "Discovered:" << descriptor.title() << descriptor.description(); - // Check if we already have set up this device - Things existingThings = myThings().filterByParam(solaxInverterTcpThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress()); - if (existingThings.count() == 1) { - qCDebug(dcSolax()) << "This solax inverter already exists in the system:" << result.networkDeviceInfo; - descriptor.setThingId(existingThings.first()->id()); - } - ParamList params; - params << Param(solaxInverterTcpThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress()); + params << Param(solaxInverterTcpThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress()); + params << Param(solaxInverterTcpThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName()); + params << Param(solaxInverterTcpThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress()); // Note: if we discover also the port and modbusaddress, we must fill them in from the discovery here, for now everywhere the defaults... descriptor.setParams(params); + + // Check if we already have set up this device + Thing *existingThing = myThings().findByParams(params); + if (existingThing) { + qCDebug(dcSolax()) << "This thing already exists in the system:" << result.networkDeviceInfo; + descriptor.setThingId(existingThing->id()); + } + info->addThingDescriptor(descriptor); } @@ -104,16 +107,16 @@ void IntegrationPluginSolax::setupThing(ThingSetupInfo *info) } } - MacAddress macAddress = MacAddress(thing->paramValue(solaxInverterTcpThingMacAddressParamTypeId).toString()); - if (!macAddress.isValid()) { - qCWarning(dcSolax()) << "The configured mac address is not valid" << thing->params(); - info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The MAC address is not known. Please reconfigure the thing.")); + // Create the monitor + NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing); + if (!monitor) { + qCWarning(dcSolax()) << "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; } - // Create the monitor - NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress); m_monitors.insert(thing, monitor); + connect(info, &ThingSetupInfo::aborted, monitor, [=](){ // Clean up in case the setup gets aborted if (m_monitors.contains(thing)) { diff --git a/solax/integrationpluginsolax.json b/solax/integrationpluginsolax.json index 0850a22..455adc2 100644 --- a/solax/integrationpluginsolax.json +++ b/solax/integrationpluginsolax.json @@ -14,9 +14,25 @@ "id": "fa1a559a-12a6-416f-ab77-a431a38bc3c2", "createMethods": ["discovery"], "discoveryType": "weak", - "interfaces": ["solarinverter", "connectable"], + "interfaces": ["solarinverter", "connectable", "networkdevice"], "providedInterfaces": [ "energymeter", "energystorage"], "paramTypes": [ + { + "id": "a736047f-ba25-4c47-b2b8-7caca790e5fe", + "name": "address", + "displayName": "Host address", + "type": "QString", + "inputType": "IPv4Address", + "defaultValue": "" + }, + { + "id": "58fd35e1-fef7-497c-8cdf-91358fd6b0be", + "name": "hostName", + "displayName": "Host name", + "type": "QString", + "inputType": "TextLine", + "defaultValue": "" + }, { "id": "acdee28d-4c73-4ed9-ad1b-d5d1440164c0", "name":"macAddress", diff --git a/solax/solaxdiscovery.cpp b/solax/solaxdiscovery.cpp index 1464015..6e7ff42 100644 --- a/solax/solaxdiscovery.cpp +++ b/solax/solaxdiscovery.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2023, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -46,10 +46,11 @@ void SolaxDiscovery::startDiscovery() m_startDateTime = QDateTime::currentDateTime(); NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover(); - connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &SolaxDiscovery::checkNetworkDevice); + connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &SolaxDiscovery::checkNetworkDevice); connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater); - connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [this, discoveryReply](){ qCDebug(dcSolax()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices"; + m_networkDeviceInfos = discoveryReply->networkDeviceInfos(); // Give the last connections added right before the network discovery finished a chance to check the device... QTimer::singleShot(3000, this, [this](){ @@ -64,19 +65,19 @@ QList SolaxDiscovery::discoveryResults() c return m_discoveryResults; } -void SolaxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo) +void SolaxDiscovery::checkNetworkDevice(const QHostAddress &address) { // Create a Solax connection and try to initialize it. // Only if initialized successfully and all information have been fetched correctly from // the device we can assume this is what we are locking for (ip, port, modbus address, correct registers). // We cloud tough also filter the result only for certain software versions, manufactueres or whatever... - SolaxModbusTcpConnection *connection = new SolaxModbusTcpConnection(networkDeviceInfo.address(), m_port, m_modbusAddress, this); + SolaxModbusTcpConnection *connection = new SolaxModbusTcpConnection(address, m_port, m_modbusAddress, this); connection->modbusTcpMaster()->setTimeout(500); connection->modbusTcpMaster()->setNumberOfRetries(0); m_connections.append(connection); - connect(connection, &SolaxModbusTcpConnection::reachableChanged, this, [=](bool reachable){ + connect(connection, &SolaxModbusTcpConnection::reachableChanged, this, [this, connection, address](bool reachable){ if (!reachable) { // Disconnected ... done with this connection cleanupConnection(connection); @@ -84,14 +85,14 @@ void SolaxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceIn } // Modbus TCP connected and reachable call successed, let's try to initialize it! - connect(connection, &SolaxModbusTcpConnection::initializationFinished, this, [=](bool success){ + connect(connection, &SolaxModbusTcpConnection::initializationFinished, this, [this, connection, address](bool success){ if (!success) { - qCDebug(dcSolax()) << "Discovery: Initialization failed on" << networkDeviceInfo.address().toString() << "Continue...";; + qCDebug(dcSolax()) << "Discovery: Initialization failed on" << address.toString() << "Continue...";; cleanupConnection(connection); return; } - qCInfo(dcSolax()) << "Discovery: Initialized successfully" << networkDeviceInfo << connection->factoryName() << connection->serialNumber(); + qCInfo(dcSolax()) << "Discovery: Initialized successfully" << address.toString() << connection->factoryName() << connection->serialNumber(); // Let's make sure the information are correct if (connection->factoryName().toLower().contains("solax")) { @@ -99,7 +100,7 @@ void SolaxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceIn result.productName = connection->moduleName(); result.manufacturerName = connection->factoryName(); result.serialNumber = connection->serialNumber(); - result.networkDeviceInfo = networkDeviceInfo; + result.address = address; m_discoveryResults.append(result); qCInfo(dcSolax()) << "Discovery: --> Found" << result.manufacturerName << result.productName @@ -110,31 +111,31 @@ void SolaxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceIn connection->disconnectDevice(); }); - qCDebug(dcSolax()) << "Discovery: The host" << networkDeviceInfo << "is reachable, trying to initialize..."; + qCDebug(dcSolax()) << "Discovery: The host" << address << "is reachable, trying to initialize..."; if (!connection->initialize()) { - qCDebug(dcSolax()) << "Discovery: Unable to initialize connection on" << networkDeviceInfo.address().toString() << "Continue...";; + qCDebug(dcSolax()) << "Discovery: Unable to initialize connection on" << address.toString() << "Continue...";; cleanupConnection(connection); } }); // If we get any error...skip this host... - connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionStateChanged, this, [=](bool connected){ + connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionStateChanged, this, [this, address](bool connected){ if (connected) { - qCDebug(dcSolax()) << "Discovery: Connected with" << networkDeviceInfo.address().toString() << m_port; + qCDebug(dcSolax()) << "Discovery: Connected with" << address.toString() << m_port; } }); // If we get any error...skip this host... - connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionErrorOccurred, this, [=](QModbusDevice::Error error){ + connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionErrorOccurred, this, [this, connection, address](QModbusDevice::Error error){ if (error != QModbusDevice::NoError) { - qCDebug(dcSolax()) << "Discovery: Connection error on" << networkDeviceInfo.address().toString() << "Continue...";; + qCDebug(dcSolax()) << "Discovery: Connection error on" << address.toString() << "Continue...";; cleanupConnection(connection); } }); // If check reachability failed...skip this host... - connect(connection, &SolaxModbusTcpConnection::checkReachabilityFailed, this, [=](){ - qCDebug(dcSolax()) << "Discovery: Check reachability failed on" << networkDeviceInfo.address().toString() << "Continue...";; + connect(connection, &SolaxModbusTcpConnection::checkReachabilityFailed, this, [this, connection, address](){ + qCDebug(dcSolax()) << "Discovery: Check reachability failed on" << address.toString() << "Continue...";; cleanupConnection(connection); }); @@ -154,10 +155,15 @@ void SolaxDiscovery::finishDiscovery() { qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch(); + // Fill in all network device infos we have + for (int i = 0; i < m_discoveryResults.count(); i++) + m_discoveryResults[i].networkDeviceInfo = m_networkDeviceInfos.get(m_discoveryResults.at(i).address); + // Cleanup any leftovers...we don't care any more foreach (SolaxModbusTcpConnection *connection, m_connections) cleanupConnection(connection); - qCInfo(dcSolax()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count() << "Solax Inverters in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); + qCInfo(dcSolax()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count() + << "Solax Inverters in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); emit discoveryFinished(); } diff --git a/solax/solaxdiscovery.h b/solax/solaxdiscovery.h index b4561cb..9a95bbc 100644 --- a/solax/solaxdiscovery.h +++ b/solax/solaxdiscovery.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2023, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -47,6 +47,7 @@ public: QString productName; QString manufacturerName; QString serialNumber; + QHostAddress address; NetworkDeviceInfo networkDeviceInfo; } SolaxDiscoveryResult; @@ -61,13 +62,12 @@ private: NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr; quint16 m_port; quint16 m_modbusAddress; - QDateTime m_startDateTime; - QList m_connections; QList m_discoveryResults; + NetworkDeviceInfos m_networkDeviceInfos; - void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo); + void checkNetworkDevice(const QHostAddress &address); void cleanupConnection(SolaxModbusTcpConnection *connection); void finishDiscovery();