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

Vestel: Update to networkdevice interface #203

Open
wants to merge 1 commit into
base: improve-vestel-discovery
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
38 changes: 21 additions & 17 deletions vestel/evc04discovery.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2023, nymea GmbH
* Copyright 2013 - 2024, nymea GmbH
* Contact: [email protected]
*
* This file is part of nymea.
Expand Down Expand Up @@ -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();
});
}

Expand All @@ -63,13 +64,13 @@ QList<EVC04Discovery::Result> 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){
Expand All @@ -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;
}
Expand All @@ -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);
});

Expand All @@ -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();
Expand Down
8 changes: 5 additions & 3 deletions vestel/evc04discovery.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Copyright 2013 - 2024, nymea GmbH
* Contact: [email protected]
*
* This file is part of nymea.
Expand Down Expand Up @@ -49,6 +49,7 @@ class EVC04Discovery : public QObject
QString firmwareVersion;
QString brand;
QString model;
QHostAddress address;
NetworkDeviceInfo networkDeviceInfo;
};

Expand All @@ -66,11 +67,12 @@ class EVC04Discovery : public QObject
QTimer m_gracePeriodTimer;
QDateTime m_startDateTime;

QList<EVC04ModbusTcpConnection*> m_connections;
NetworkDeviceInfos m_networkDeviceInfos;
QList<EVC04ModbusTcpConnection *> m_connections;

QList<Result> m_discoveryResults;

void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
void checkNetworkDevice(const QHostAddress &address);
void cleanupConnection(EVC04ModbusTcpConnection *connection);

void finishDiscovery();
Expand Down
65 changes: 39 additions & 26 deletions vestel/integrationpluginvestel.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Copyright 2013 - 2024, nymea GmbH
* Contact: [email protected]
*
* This file is part of nymea.
Expand Down Expand Up @@ -58,29 +58,33 @@ 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();
}
}

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) {

Expand All @@ -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;
}
}

Expand Down
21 changes: 19 additions & 2 deletions vestel/integrationpluginvestel.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": ""
}
],
Expand Down