From ef86ece542f8912b22bf1648c9ead0b15b7845d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 19 Dec 2024 10:33:15 +0100 Subject: [PATCH] Vestel: Update to networkdevice interface --- vestel/evc04discovery.cpp | 38 +++++++++-------- vestel/evc04discovery.h | 8 ++-- vestel/integrationpluginvestel.cpp | 65 +++++++++++++++++------------ vestel/integrationpluginvestel.json | 21 +++++++++- 4 files changed, 84 insertions(+), 48 deletions(-) diff --git a/vestel/evc04discovery.cpp b/vestel/evc04discovery.cpp index 4764f2d2..35934939 100644 --- a/vestel/evc04discovery.cpp +++ b/vestel/evc04discovery.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. @@ -48,13 +48,14 @@ void EVC04Discovery::startDiscovery() { qCInfo(m_dc()) << "Discovery: Searching for Vestel EVC04 wallboxes in the network..."; NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover(); + m_startDateTime = QDateTime::currentDateTime(); - connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &EVC04Discovery::checkNetworkDevice); - + connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &EVC04Discovery::checkNetworkDevice); + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater); connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ qCDebug(m_dc()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices"; + m_networkDeviceInfos = discoveryReply->networkDeviceInfos(); m_gracePeriodTimer.start(); - discoveryReply->deleteLater(); }); } @@ -63,13 +64,13 @@ QList EVC04Discovery::discoveryResults() const return m_discoveryResults; } -void EVC04Discovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo) +void EVC04Discovery::checkNetworkDevice(const QHostAddress &address) { int port = 502; int slaveId = 0xff; - qCDebug(m_dc()) << "Checking network device:" << networkDeviceInfo << "Port:" << port << "Slave ID:" << slaveId; + qCDebug(m_dc()) << "Discovery: Checking network device:" << address << "Port:" << port << "Slave ID:" << slaveId; - EVC04ModbusTcpConnection *connection = new EVC04ModbusTcpConnection(networkDeviceInfo.address(), port, slaveId, this); + EVC04ModbusTcpConnection *connection = new EVC04ModbusTcpConnection(address, port, slaveId, this); m_connections.append(connection); connect(connection, &EVC04ModbusTcpConnection::reachableChanged, this, [=](bool reachable){ @@ -79,10 +80,10 @@ void EVC04Discovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceIn } connect(connection, &EVC04ModbusTcpConnection::initializationFinished, this, [=](bool success){ - qCDebug(m_dc()) << "Discovered device on" << networkDeviceInfo.address() << connection->brand() << connection->model() << connection->firmwareVersion(); + qCDebug(m_dc()) << "Discovery: Discovered device on" << address.toString() << connection->brand() << connection->model() << connection->firmwareVersion(); qCDebug(m_dc()) << connection; if (!success) { - qCDebug(m_dc()) << "Discovery: Initialization failed on" << networkDeviceInfo.address().toString(); + qCDebug(m_dc()) << "Discovery: Initialization failed on" << address.toString(); cleanupConnection(connection); return; } @@ -92,29 +93,28 @@ void EVC04Discovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceIn result.brand = QString(QString::fromUtf16(connection->brand().data(), connection->brand().length()).toUtf8()).trimmed(); result.model = QString(QString::fromUtf16(connection->model().data(), connection->model().length()).toUtf8()).trimmed(); result.firmwareVersion = QString(QString::fromUtf16(connection->firmwareVersion().data(), connection->firmwareVersion().length()).toUtf8()).trimmed(); - result.networkDeviceInfo = networkDeviceInfo; + result.address = address; if (result.chargepointId.isEmpty() && result.brand.isEmpty() && result.model.isEmpty() && result.firmwareVersion.isEmpty()) { - qCDebug(m_dc()) << "Discovery: Found modbus device with valid register set (initialized successfully), but the information seem not to be valid. This is probably some other device. Ignoring" << result.networkDeviceInfo; + qCDebug(m_dc()) << "Discovery: Found modbus device with valid register set (initialized successfully), but the information seem not to be valid. " + "This is probably some other device. Ignoring" << address.toString(); cleanupConnection(connection); return; } m_discoveryResults.append(result); - - qCDebug(m_dc()) << "Discovery: Found wallbox with firmware version:" << result.firmwareVersion << result.networkDeviceInfo; - + qCDebug(m_dc()) << "Discovery: Found wallbox with firmware version:" << result.firmwareVersion << address.toString(); cleanupConnection(connection); }); if (!connection->initialize()) { - qCDebug(m_dc()) << "Discovery: Unable to initialize connection on" << networkDeviceInfo.address().toString(); + qCDebug(m_dc()) << "Discovery: Unable to initialize connection on" << address.toString(); cleanupConnection(connection); } }); connect(connection, &EVC04ModbusTcpConnection::checkReachabilityFailed, this, [=](){ - qCDebug(m_dc()) << "Discovery: Checking reachability failed on" << networkDeviceInfo.address().toString(); + qCDebug(m_dc()) << "Discovery: Checking reachability failed on" << address.toString(); cleanupConnection(connection); }); @@ -132,12 +132,16 @@ void EVC04Discovery::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 (EVC04ModbusTcpConnection *connection, m_connections) cleanupConnection(connection); qCInfo(m_dc()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count() - << "Vestel EVC04 wallboxes in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); + << "EVC04 wallboxes in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); m_gracePeriodTimer.stop(); emit discoveryFinished(); diff --git a/vestel/evc04discovery.h b/vestel/evc04discovery.h index 15a47431..2590fbaf 100644 --- a/vestel/evc04discovery.h +++ b/vestel/evc04discovery.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. @@ -49,6 +49,7 @@ class EVC04Discovery : public QObject QString firmwareVersion; QString brand; QString model; + QHostAddress address; NetworkDeviceInfo networkDeviceInfo; }; @@ -66,11 +67,12 @@ class EVC04Discovery : public QObject QTimer m_gracePeriodTimer; QDateTime m_startDateTime; - QList m_connections; + NetworkDeviceInfos m_networkDeviceInfos; + QList m_connections; QList m_discoveryResults; - void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo); + void checkNetworkDevice(const QHostAddress &address); void cleanupConnection(EVC04ModbusTcpConnection *connection); void finishDiscovery(); diff --git a/vestel/integrationpluginvestel.cpp b/vestel/integrationpluginvestel.cpp index 226e9efe..249df623 100644 --- a/vestel/integrationpluginvestel.cpp +++ b/vestel/integrationpluginvestel.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. @@ -58,21 +58,25 @@ void IntegrationPluginVestel::discoverThings(ThingDiscoveryInfo *info) ThingDescriptor descriptor(evc04ThingClassId, name, description); qCDebug(dcVestel()) << "Discovered:" << descriptor.title() << descriptor.description(); + ParamList params; + params << Param(evc04ThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress()); + params << Param(evc04ThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName()); + params << Param(evc04ThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress()); + descriptor.setParams(params); + // Check if we already have set up this device - Things existingThings = myThings().filterByParam(evc04ThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress()); - if (existingThings.count() == 1) { - qCDebug(dcVestel()) << "This wallbox already exists in the system:" << result.networkDeviceInfo; - descriptor.setThingId(existingThings.first()->id()); + Thing *existingThing = myThings().findByParams(params); + if (existingThing) { + qCDebug(dcVestel()) << "This thing already exists in the system:" << existingThing << existingThing->params(); + descriptor.setThingId(existingThing->id()); } - ParamList params; - params << Param(evc04ThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress()); - descriptor.setParams(params); info->addThingDescriptor(descriptor); } info->finish(Thing::ThingErrorNoError); }); + discovery->startDiscovery(); } } @@ -80,7 +84,7 @@ void IntegrationPluginVestel::discoverThings(ThingDiscoveryInfo *info) void IntegrationPluginVestel::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); - qCDebug(dcVestel()) << "Setup" << thing << thing->params(); + qCDebug(dcVestel()) << "Setting up" << thing << thing->params(); if (thing->thingClassId() == evc04ThingClassId) { @@ -93,36 +97,45 @@ void IntegrationPluginVestel::setupThing(ThingSetupInfo *info) } } - MacAddress macAddress = MacAddress(thing->paramValue(evc04ThingMacAddressParamTypeId).toString()); - if (!macAddress.isValid()) { - qCWarning(dcVestel()) << "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.")); + NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing); + if (!monitor) { + qCWarning(dcVestel()) << "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; } - NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress); m_monitors.insert(thing, monitor); - connect(info, &ThingSetupInfo::aborted, monitor, [=](){ + connect(info, &ThingSetupInfo::aborted, monitor, [this, thing](){ if (m_monitors.contains(thing)) { qCDebug(dcVestel()) << "Unregistering monitor because setup has been aborted."; hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing)); } + + if (m_evc04Connections.contains(thing)) { + qCDebug(dcVestel()) << "Clean up connection because setup has been aborted."; + m_evc04Connections.take(thing)->deleteLater(); + } }); - if (monitor->reachable()) { - setupEVC04Connection(info); + // If this is the initial setup, wait for the monitor to be reachable and make sure + // we have an IP address, otherwise let the monitor do his work + if (info->isInitialSetup()) { + // Continue with setup only if we know that the network device is reachable + if (monitor->reachable()) { + setupEVC04Connection(info); + } else { + qCDebug(dcVestel()) << "Waiting for the network monitor to get reachable before continuing to set up the connection" << thing->name() << "..."; + connect(monitor, &NetworkDeviceMonitor::reachableChanged, info, [this, thing, info, monitor](bool reachable){ + if (reachable) { + qCDebug(dcVestel()) << "The monitor for thing setup" << thing->name() << "is now reachable. Continuing setup on" << monitor->networkDeviceInfo().address().toString(); + setupEVC04Connection(info); + } + }); + } } else { - qCDebug(dcVestel()) << "Waiting for the network monitor to get reachable before continuing to set up the connection" << thing->name() << "..."; - connect(monitor, &NetworkDeviceMonitor::reachableChanged, info, [=](bool reachable){ - if (reachable) { - qCDebug(dcVestel()) << "The monitor for thing setup" << thing->name() << "is now reachable. Continuing setup on" << monitor->networkDeviceInfo().address().toString(); - setupEVC04Connection(info); - } - }); + setupEVC04Connection(info); } - - return; } } diff --git a/vestel/integrationpluginvestel.json b/vestel/integrationpluginvestel.json index 5ac623f4..496f31c0 100644 --- a/vestel/integrationpluginvestel.json +++ b/vestel/integrationpluginvestel.json @@ -12,15 +12,32 @@ "name": "evc04", "displayName": "EVC04", "id": "396de19c-ef2b-4f32-b551-9d0d153304a4", - "createMethods": ["discovery", "user"], - "interfaces": ["evcharger", "smartmeterconsumer", "connectable"], + "createMethods": [ "discovery", "user" ], + "interfaces": [ "evcharger", "smartmeterconsumer", "connectable", "networkdevice" ], "paramTypes": [ + { + "id": "e7413345-6c69-4e41-8522-e0795949ef79", + "name": "hostName", + "displayName": "Host name", + "type": "QString", + "inputType": "TextLine", + "defaultValue": "" + }, + { + "id": "42a27ea2-e3dc-4568-bd17-f8779dc8c135", + "name": "address", + "displayName": "IP address", + "type": "QString", + "inputType": "IPv4Address", + "defaultValue": "" + }, { "id": "afdc55b7-b509-4d0c-ab79-176f2edf8488", "name":"macAddress", "displayName": "MAC address", "type": "QString", "inputType": "MacAddress", + "readOnly": true, "defaultValue": "" } ],