Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keba: Update to networkdevice interface #756

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions keba/integrationpluginkeba.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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());
Expand Down
2 changes: 2 additions & 0 deletions keba/integrationpluginkeba.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class IntegrationPluginKeba : public IntegrationPlugin
KebaDiscovery *m_runningDiscovery = nullptr;

QHash<ThingClassId, ParamTypeId> m_macAddressParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_hostNameParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_addressParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_modelParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_serialNumberParamTypeIds;

Expand Down
42 changes: 37 additions & 5 deletions keba/integrationpluginkeba.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
{
Expand All @@ -39,7 +55,7 @@
"displayName": "Product name",
"type": "QString",
"inputType": "TextLine",
"defaultValue":"",
"defaultValue": "",
"readOnly": true
}
],
Expand Down Expand Up @@ -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",
Expand Down
70 changes: 29 additions & 41 deletions keba/kebadiscovery.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Copyright 2013 - 2024, nymea GmbH
* Contact: [email protected]
*
* This file is part of nymea.
Expand Down Expand Up @@ -44,19 +44,19 @@ 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();
});

// 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);
Expand All @@ -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;
}
});
}
Expand All @@ -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();
});
}
Expand All @@ -133,27 +131,17 @@ QList<KebaDiscovery::KebaDiscoveryResult> 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"));
}

14 changes: 6 additions & 8 deletions keba/kebadiscovery.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Copyright 2013 - 2024, nymea GmbH
* Contact: [email protected]
*
* This file is part of nymea.
Expand Down Expand Up @@ -47,6 +47,7 @@ class KebaDiscovery : public QObject
QString product;
QString serialNumber;
QString firmwareVersion;
QHostAddress address;
NetworkDeviceInfo networkDeviceInfo;
} KebaDiscoveryResult;

Expand All @@ -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<QHostAddress> m_verifiedAddresses;
QList<KebaDiscoveryResult> m_results;

bool alreadyDiscovered(const QHostAddress &address);

void cleanup();

private slots:
void sendReportRequest(const NetworkDeviceInfo &networkDeviceInfo);

};

#endif // KEBADISCOVERY_H