diff --git a/keba/integrationpluginkeba.cpp b/keba/integrationpluginkeba.cpp index 9e2c9183f..d96ef2edc 100644 --- a/keba/integrationpluginkeba.cpp +++ b/keba/integrationpluginkeba.cpp @@ -50,6 +50,12 @@ void IntegrationPluginKeba::init() m_macAddressParamTypeIds.insert(kebaThingClassId, kebaThingMacAddressParamTypeId); m_macAddressParamTypeIds.insert(kebaSimpleThingClassId, kebaSimpleThingMacAddressParamTypeId); + m_hostNameParamTypeIds.insert(kebaThingClassId, kebaThingHostNameParamTypeId); + m_hostNameParamTypeIds.insert(kebaSimpleThingClassId, kebaSimpleThingHostNameParamTypeId); + + m_addressParamTypeIds.insert(kebaThingClassId, kebaThingAddressParamTypeId); + m_addressParamTypeIds.insert(kebaSimpleThingClassId, kebaSimpleThingAddressParamTypeId); + m_modelParamTypeIds.insert(kebaThingClassId, kebaThingModelParamTypeId); m_modelParamTypeIds.insert(kebaSimpleThingClassId, kebaSimpleThingModelParamTypeId); @@ -104,14 +110,16 @@ void IntegrationPluginKeba::discoverThings(ThingDiscoveryInfo *info) qCDebug(dcKeba()) << "Discovered:" << descriptor.title() << descriptor.description(); // Check if we already have set up this device - Things existingThings = myThings().filterByParam(m_macAddressParamTypeIds.value(discoveredThingClassId), result.networkDeviceInfo.macAddress()); + Things existingThings = myThings().filterByParam(m_serialNumberParamTypeIds.value(discoveredThingClassId), result.serialNumber); if (existingThings.count() == 1) { qCDebug(dcKeba()) << "This keba already exists in the system!" << result.networkDeviceInfo; descriptor.setThingId(existingThings.first()->id()); } ParamList params; - params << Param(m_macAddressParamTypeIds.value(discoveredThingClassId), result.networkDeviceInfo.macAddress()); + params << Param(m_macAddressParamTypeIds.value(discoveredThingClassId), result.networkDeviceInfo.thingParamValueMacAddress()); + params << Param(m_hostNameParamTypeIds.value(discoveredThingClassId), result.networkDeviceInfo.thingParamValueHostName()); + params << Param(m_addressParamTypeIds.value(discoveredThingClassId), result.networkDeviceInfo.thingParamValueAddress()); params << Param(m_modelParamTypeIds.value(discoveredThingClassId), result.product); params << Param(m_serialNumberParamTypeIds.value(discoveredThingClassId), result.serialNumber); descriptor.setParams(params); @@ -156,16 +164,16 @@ void IntegrationPluginKeba::setupThing(ThingSetupInfo *info) } } + + // Create a monitor so we always get the correct IP in the network and see if the device is reachable without polling on our own + NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing); // Make sure we have a valid mac address, otherwise no monitor and not auto searching is possible - MacAddress macAddress = MacAddress(thing->paramValue(m_macAddressParamTypeIds.value(thing->thingClassId())).toString()); - if (macAddress.isNull()) { - qCWarning(dcKeba()) << "Failed to set up keba because the MAC address is not valid:" << thing->paramValue(m_macAddressParamTypeIds.value(thing->thingClassId())).toString() << macAddress.toString(); - info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The MAC address is not vaild. Please reconfigure the device to fix this.")); + if (!monitor) { + qCWarning(dcKeba()) << "Can not set up connection monitor with the given parameters:" << thing->params(); + info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("Unable to set up the connection with this configuration. Please reconfigure the connection.")); return; } - // Create a monitor so we always get the correct IP in the network and see if the device is reachable without polling on our own - NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress); connect(monitor, &NetworkDeviceMonitor::reachableChanged, thing, [=](bool reachable){ // Only if the setup has been finished KeContact *keba = m_kebaDevices.value(thing->id()); diff --git a/keba/integrationpluginkeba.h b/keba/integrationpluginkeba.h index 0e347a97a..a58cc2dbd 100644 --- a/keba/integrationpluginkeba.h +++ b/keba/integrationpluginkeba.h @@ -77,6 +77,8 @@ class IntegrationPluginKeba : public IntegrationPlugin KebaDiscovery *m_runningDiscovery = nullptr; QHash m_macAddressParamTypeIds; + QHash m_hostNameParamTypeIds; + QHash m_addressParamTypeIds; QHash m_modelParamTypeIds; QHash m_serialNumberParamTypeIds; diff --git a/keba/integrationpluginkeba.json b/keba/integrationpluginkeba.json index 44af0a971..260e61f8e 100644 --- a/keba/integrationpluginkeba.json +++ b/keba/integrationpluginkeba.json @@ -13,24 +13,40 @@ "name": "keba", "displayName": "Keba KeContact", "createMethods": ["discovery", "user"], - "interfaces": ["evcharger", "smartmeterconsumer", "connectable"], + "interfaces": ["evcharger", "smartmeterconsumer", "connectable", "networkdevice"], "paramTypes":[ { "id": "c2df921d-ff8b-411c-9b1d-04a437d7dfa6", "name": "macAddress", "displayName": "MAC address", "type": "QString", - "inputType": "TextLine", - "defaultValue":"", + "inputType": "MacAddress", + "defaultValue": "", "readOnly": true }, + { + "id": "0cc79bb7-3162-432c-a7bc-45f9b5542fbd", + "name": "hostName", + "displayName": "Host name", + "type": "QString", + "inputType": "TextLine", + "defaultValue": "" + }, + { + "id": "22f70789-33c2-4183-8bca-0d3108b1c80b", + "name": "address", + "displayName": "IP address", + "type": "QString", + "inputType": "IPv4Address", + "defaultValue": "" + }, { "id": "45255155-318b-4204-8ce6-2c106a56286d", "name": "serialNumber", "displayName": "Serial number", "type": "QString", "inputType": "TextLine", - "defaultValue":"", + "defaultValue": "", "readOnly": true }, { @@ -39,7 +55,7 @@ "displayName": "Product name", "type": "QString", "inputType": "TextLine", - "defaultValue":"", + "defaultValue": "", "readOnly": true } ], @@ -410,6 +426,22 @@ "defaultValue":"", "readOnly": true }, + { + "id": "96104d2b-2fd3-4f20-bc8c-7b873d0b0f9e", + "name": "hostName", + "displayName": "Host name", + "type": "QString", + "inputType": "TextLine", + "defaultValue": "" + }, + { + "id": "a0c60511-4082-4109-9a9f-383076680c4f", + "name": "address", + "displayName": "IP address", + "type": "QString", + "inputType": "IPv4Address", + "defaultValue": "" + }, { "id": "6f732eb9-1711-4da0-a9a4-abcfa19f5e34", "name": "serialNumber", diff --git a/keba/kebadiscovery.cpp b/keba/kebadiscovery.cpp index 054b2a57f..6af9a5353 100644 --- a/keba/kebadiscovery.cpp +++ b/keba/kebadiscovery.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2021, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -44,6 +44,12 @@ KebaDiscovery::KebaDiscovery(KeContactDataLayer *kebaDataLayer, NetworkDeviceDis m_responseTimer.setInterval(2000); m_responseTimer.setSingleShot(true); connect(&m_responseTimer, &QTimer::timeout, this, [=](){ + + // Fill in all network device infos we have + for (int i = 0; i < m_results.count(); i++) { + m_results[i].networkDeviceInfo = m_networkDeviceInfos.get(m_results.at(i).address); + } + qCInfo(dcKeba()) << "Discovery: Finished successfully. Found" << m_results.count() << "Keba Wallbox"; emit discoveryFinished(); }); @@ -51,12 +57,6 @@ KebaDiscovery::KebaDiscovery(KeContactDataLayer *kebaDataLayer, NetworkDeviceDis // Read data from the keba data layer and verify if it is a keba report connect (m_kebaDataLayer, &KeContactDataLayer::datagramReceived, this, [=](const QHostAddress &address, const QByteArray &datagram){ - // Just continue if this is a new address we have no result for - if (alreadyDiscovered(address)) { - qCDebug(dcKeba()) << "Discovery: Skipping datagram from already discovered Keba on" << address.toString(); - return; - } - // Try to convert the received data to a json document QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(datagram, &error); @@ -78,15 +78,23 @@ KebaDiscovery::KebaDiscovery(KeContactDataLayer *kebaDataLayer, NetworkDeviceDis } // We have received a report 1 datagram, let's add it to the result - NetworkDeviceInfo networkDeviceInfo = m_verifiedNetworkDeviceInfos.get(address); - if (networkDeviceInfo.isValid()) { - KebaDiscoveryResult result; - result.networkDeviceInfo = networkDeviceInfo; - result.product = dataMap.value("Product").toString(); - result.serialNumber = dataMap.value("Serial").toString(); - result.firmwareVersion = dataMap.value("Firmware").toString(); + KebaDiscoveryResult result; + result.address = address; + result.product = dataMap.value("Product").toString(); + result.serialNumber = dataMap.value("Serial").toString(); + result.firmwareVersion = dataMap.value("Firmware").toString(); + + bool alreadyDiscovered = false; + foreach (const KebaDiscoveryResult &r, m_results) { + if (r.serialNumber == result.serialNumber) { + alreadyDiscovered = true; + break; + } + } + + if (!alreadyDiscovered) { m_results.append(result); - qCDebug(dcKeba()) << "Discovery: -->" << networkDeviceInfo << networkDeviceInfo.macAddress() << result.product << result.serialNumber << result.firmwareVersion; + qCDebug(dcKeba()) << "Discovery: -->" << address.toString() << result.product << result.serialNumber << result.firmwareVersion; } }); } @@ -104,26 +112,16 @@ void KebaDiscovery::startDiscovery() qCInfo(dcKeba()) << "Discovery: Start searching for Keba wallboxes in the network..."; NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover(); - // Check any already discovered infos.. - foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) { - sendReportRequest(networkDeviceInfo); - } - // Imedialty check any new device gets discovered - connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &KebaDiscovery::sendReportRequest); + connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &KebaDiscovery::sendReportRequest); // Check what might be left on finished connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater); connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ qCDebug(dcKeba()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices"; m_networkDeviceInfos = discoveryReply->networkDeviceInfos(); + qCDebug(dcKeba()) << "Discovery: Network discovery finished. Start finishing discovery..."; - // Send a report request to nework device info not sent already... - foreach (const NetworkDeviceInfo &networkDeviceInfo, m_networkDeviceInfos) { - if (!m_verifiedNetworkDeviceInfos.contains(networkDeviceInfo)) { - sendReportRequest(networkDeviceInfo); - } - } m_responseTimer.start(); }); } @@ -133,27 +131,17 @@ QList KebaDiscovery::discoveryResults() cons return m_results; } -bool KebaDiscovery::alreadyDiscovered(const QHostAddress &address) +void KebaDiscovery::sendReportRequest(const QHostAddress &address) { - foreach (const KebaDiscoveryResult &result, m_results) { - if (result.networkDeviceInfo.address() == address) { - return true; - } - } - - return false; + m_verifiedAddresses.append(address); + m_kebaDataLayer->write(address, QByteArray("report 1\n")); } void KebaDiscovery::cleanup() { m_networkDeviceInfos.clear(); - m_verifiedNetworkDeviceInfos.clear(); + m_verifiedAddresses.clear(); m_results.clear(); } -void KebaDiscovery::sendReportRequest(const NetworkDeviceInfo &networkDeviceInfo) -{ - m_verifiedNetworkDeviceInfos.append(networkDeviceInfo); - m_kebaDataLayer->write(networkDeviceInfo.address(), QByteArray("report 1\n")); -} diff --git a/keba/kebadiscovery.h b/keba/kebadiscovery.h index df36c0dd1..eaead1ddc 100644 --- a/keba/kebadiscovery.h +++ b/keba/kebadiscovery.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2021, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -47,6 +47,7 @@ class KebaDiscovery : public QObject QString product; QString serialNumber; QString firmwareVersion; + QHostAddress address; NetworkDeviceInfo networkDeviceInfo; } KebaDiscoveryResult; @@ -60,22 +61,19 @@ class KebaDiscovery : public QObject signals: void discoveryFinished(); +private slots: + void sendReportRequest(const QHostAddress &address); + private: KeContactDataLayer *m_kebaDataLayer = nullptr; NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr; QTimer m_responseTimer; NetworkDeviceInfos m_networkDeviceInfos; - NetworkDeviceInfos m_verifiedNetworkDeviceInfos; + QList m_verifiedAddresses; QList m_results; - bool alreadyDiscovered(const QHostAddress &address); - void cleanup(); - -private slots: - void sendReportRequest(const NetworkDeviceInfo &networkDeviceInfo); - }; #endif // KEBADISCOVERY_H