Merge PR #204: Webasto: Update to networkdevice interface
This commit is contained in:
commit
c3ed7f481b
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Copyright 2013 - 2024, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -67,7 +67,7 @@ void IntegrationPluginWebasto::discoverThings(ThingDiscoveryInfo *info)
|
||||
qCInfo(dcWebasto()) << "Start discovering webasto live in the local network...";
|
||||
NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover();
|
||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
|
||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
|
||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [this, discoveryReply, info](){
|
||||
ThingDescriptors descriptors;
|
||||
qCDebug(dcWebasto()) << "Discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "devices";
|
||||
foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) {
|
||||
@ -83,25 +83,38 @@ void IntegrationPluginWebasto::discoverThings(ThingDiscoveryInfo *info)
|
||||
}
|
||||
|
||||
QString description;
|
||||
if (networkDeviceInfo.macAddressManufacturer().isEmpty()) {
|
||||
description = networkDeviceInfo.macAddress();
|
||||
} else {
|
||||
description = networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")";
|
||||
MacAddressInfo macInfo;
|
||||
switch (networkDeviceInfo.monitorMode()) {
|
||||
case NetworkDeviceInfo::MonitorModeMac:
|
||||
macInfo = networkDeviceInfo.macAddressInfos().constFirst();
|
||||
description = macInfo.macAddress().toString();
|
||||
if (!macInfo.vendorName().isEmpty())
|
||||
description += " - " + macInfo.vendorName();
|
||||
|
||||
break;
|
||||
case NetworkDeviceInfo::MonitorModeHostName:
|
||||
description = networkDeviceInfo.hostName();
|
||||
break;
|
||||
case NetworkDeviceInfo::MonitorModeIp:
|
||||
description = "Interface: " + networkDeviceInfo.networkInterface().name();
|
||||
break;
|
||||
}
|
||||
|
||||
ThingDescriptor descriptor(webastoLiveThingClassId, title, description);
|
||||
|
||||
ParamList params;
|
||||
params << Param(webastoLiveThingMacAddressParamTypeId, networkDeviceInfo.thingParamValueMacAddress());
|
||||
params << Param(webastoLiveThingAddressParamTypeId, networkDeviceInfo.thingParamValueAddress());
|
||||
params << Param(webastoLiveThingHostNameParamTypeId, networkDeviceInfo.thingParamValueHostName());
|
||||
descriptor.setParams(params);
|
||||
|
||||
// Check if we already have set up this device
|
||||
Things existingThings = myThings().filterByParam(webastoLiveThingIpAddressParamTypeId, networkDeviceInfo.address().toString());
|
||||
if (existingThings.count() == 1) {
|
||||
qCDebug(dcWebasto()) << "This thing already exists in the system." << existingThings.first() << networkDeviceInfo;
|
||||
descriptor.setThingId(existingThings.first()->id());
|
||||
Thing *existingThing = myThings().findByParams(params);
|
||||
if (existingThing) {
|
||||
qCDebug(dcWebasto()) << "This thing already exists in the system:" << networkDeviceInfo;
|
||||
descriptor.setThingId(existingThing->id());
|
||||
}
|
||||
|
||||
ParamList params;
|
||||
params << Param(webastoLiveThingIpAddressParamTypeId, networkDeviceInfo.address().toString());
|
||||
params << Param(webastoLiveThingMacAddressParamTypeId, networkDeviceInfo.macAddress());
|
||||
descriptor.setParams(params);
|
||||
info->addThingDescriptor(descriptor);
|
||||
}
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
@ -117,7 +130,7 @@ void IntegrationPluginWebasto::discoverThings(ThingDiscoveryInfo *info)
|
||||
|
||||
// Create a discovery with the info as parent for auto deleting the object once the discovery info is done
|
||||
WebastoDiscovery *discovery = new WebastoDiscovery(hardwareManager()->networkDeviceDiscovery(), info);
|
||||
connect(discovery, &WebastoDiscovery::discoveryFinished, info, [=](){
|
||||
connect(discovery, &WebastoDiscovery::discoveryFinished, info, [this, discovery, info](){
|
||||
foreach (const WebastoDiscovery::Result &result, discovery->results()) {
|
||||
|
||||
QString title = "Webasto Next";
|
||||
@ -125,25 +138,39 @@ void IntegrationPluginWebasto::discoverThings(ThingDiscoveryInfo *info)
|
||||
title.append(" (" + result.networkDeviceInfo.hostName() + ")");
|
||||
}
|
||||
|
||||
QString description = result.networkDeviceInfo.address().toString();
|
||||
if (result.networkDeviceInfo.macAddressManufacturer().isEmpty()) {
|
||||
description += " " + result.networkDeviceInfo.macAddress();
|
||||
} else {
|
||||
description += " " + result.networkDeviceInfo.macAddress() + " (" + result.networkDeviceInfo.macAddressManufacturer() + ")";
|
||||
QString description;
|
||||
MacAddressInfo macInfo;
|
||||
switch (result.networkDeviceInfo.monitorMode()) {
|
||||
case NetworkDeviceInfo::MonitorModeMac:
|
||||
macInfo = result.networkDeviceInfo.macAddressInfos().constFirst();
|
||||
description = macInfo.macAddress().toString();
|
||||
if (!macInfo.vendorName().isEmpty())
|
||||
description += " - " + macInfo.vendorName();
|
||||
|
||||
break;
|
||||
case NetworkDeviceInfo::MonitorModeHostName:
|
||||
description = result.networkDeviceInfo.hostName();
|
||||
break;
|
||||
case NetworkDeviceInfo::MonitorModeIp:
|
||||
description = "Interface: " + result.networkDeviceInfo.networkInterface().name();
|
||||
break;
|
||||
}
|
||||
|
||||
ThingDescriptor descriptor(webastoNextThingClassId, title, description);
|
||||
|
||||
ParamList params;
|
||||
params << Param(webastoNextThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress());
|
||||
params << Param(webastoNextThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName());
|
||||
params << Param(webastoNextThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress());
|
||||
descriptor.setParams(params);
|
||||
|
||||
// Check if we already have set up this device
|
||||
Things existingThings = myThings().filterByParam(webastoNextThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress());
|
||||
if (existingThings.count() == 1) {
|
||||
qCDebug(dcWebasto()) << "This thing already exists in the system." << existingThings.first() << result.networkDeviceInfo;
|
||||
descriptor.setThingId(existingThings.first()->id());
|
||||
Thing *existingThing = myThings().findByParams(params);
|
||||
if (existingThing) {
|
||||
qCDebug(dcWebasto()) << "This thing already exists in the system:" << result.networkDeviceInfo;
|
||||
descriptor.setThingId(existingThing->id());
|
||||
}
|
||||
|
||||
ParamList params;
|
||||
params << Param(webastoNextThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress());
|
||||
descriptor.setParams(params);
|
||||
info->addThingDescriptor(descriptor);
|
||||
}
|
||||
|
||||
@ -168,24 +195,29 @@ void IntegrationPluginWebasto::discoverThings(ThingDiscoveryInfo *info)
|
||||
ThingDescriptor descriptor(webastoUniteThingClassId, name, description);
|
||||
qCDebug(dcWebasto()) << "Discovered:" << descriptor.title() << descriptor.description();
|
||||
|
||||
ParamList params;
|
||||
params << Param(webastoUniteThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress());
|
||||
params << Param(webastoUniteThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName());
|
||||
params << Param(webastoUniteThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress());
|
||||
descriptor.setParams(params);
|
||||
|
||||
// Check if we already have set up this device
|
||||
Things existingThings = myThings().filterByParam(webastoUniteThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress());
|
||||
if (existingThings.count() == 1) {
|
||||
qCDebug(dcWebasto()) << "This wallbox already exists in the system:" << result.networkDeviceInfo;
|
||||
descriptor.setThingId(existingThings.first()->id());
|
||||
Thing *existingThing = myThings().findByParams(params);
|
||||
if (existingThing) {
|
||||
qCDebug(dcWebasto()) << "This thing already exists in the system:" << result.networkDeviceInfo;
|
||||
descriptor.setThingId(existingThing->id());
|
||||
}
|
||||
|
||||
ParamList params;
|
||||
params << Param(webastoUniteThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress());
|
||||
descriptor.setParams(params);
|
||||
info->addThingDescriptor(descriptor);
|
||||
}
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
});
|
||||
discovery->startDiscovery();
|
||||
|
||||
discovery->startDiscovery();
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT_X(false, "discoverThings", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8());
|
||||
}
|
||||
|
||||
@ -199,25 +231,73 @@ void IntegrationPluginWebasto::setupThing(ThingSetupInfo *info)
|
||||
if (m_webastoLiveConnections.contains(thing)) {
|
||||
// Clean up after reconfiguration
|
||||
m_webastoLiveConnections.take(thing)->deleteLater();
|
||||
|
||||
if (m_monitors.contains(thing)) {
|
||||
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
|
||||
}
|
||||
}
|
||||
|
||||
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
|
||||
if (!monitor) {
|
||||
qCWarning(dcWebasto()) << "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;
|
||||
}
|
||||
|
||||
m_monitors.insert(thing, monitor);
|
||||
|
||||
connect(info, &ThingSetupInfo::aborted, monitor, [this, thing](){
|
||||
if (m_monitors.contains(thing)) {
|
||||
qCDebug(dcWebasto()) << "Unregistering monitor because setup has been aborted.";
|
||||
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
|
||||
}
|
||||
|
||||
if (m_webastoLiveConnections.contains(thing)) {
|
||||
qCDebug(dcWebasto()) << "Clean up connection because setup has been aborted.";
|
||||
m_webastoLiveConnections.take(thing)->deleteLater();
|
||||
}
|
||||
});
|
||||
|
||||
QHostAddress address = monitor->networkDeviceInfo().address();
|
||||
if (address.isNull()) {
|
||||
qCWarning(dcWebasto()) << "Cannot set up thing. The host address is not known yet. Maybe it will be available in the next run...";
|
||||
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
|
||||
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("The host address is not known yet. Trying later again."));
|
||||
return;
|
||||
}
|
||||
|
||||
QHostAddress address = QHostAddress(thing->paramValue(webastoLiveThingIpAddressParamTypeId).toString());
|
||||
Webasto *webasto = new Webasto(address, 502, thing);
|
||||
m_webastoLiveConnections.insert(thing, webasto);
|
||||
connect(webasto, &Webasto::destroyed, this, [thing, this] {m_webastoLiveConnections.remove(thing);});
|
||||
connect(webasto, &Webasto::connectionStateChanged, this, &IntegrationPluginWebasto::onConnectionChanged);
|
||||
|
||||
connect(monitor, &NetworkDeviceMonitor::reachableChanged, thing, [monitor, webasto, thing](bool reachable){
|
||||
qCDebug(dcWebasto()) << "Network device monitor reachable changed for" << thing->name() << reachable;
|
||||
if (!thing->setupComplete())
|
||||
return;
|
||||
|
||||
if (reachable && !thing->stateValue("connected").toBool()) {
|
||||
webasto->modbusTcpMaster()->setHostAddress(monitor->networkDeviceInfo().address());
|
||||
webasto->connectDevice();
|
||||
} else if (!reachable) {
|
||||
// Note: We disable autoreconnect explicitly and we will
|
||||
// connect the device once the monitor says it is reachable again
|
||||
webasto->modbusTcpMaster()->disconnectDevice();
|
||||
}
|
||||
});
|
||||
|
||||
connect(webasto, &Webasto::connectionStateChanged, this, [thing](bool state){
|
||||
thing->setStateValue(webastoLiveConnectedStateTypeId, state);
|
||||
});
|
||||
|
||||
connect(webasto, &Webasto::receivedRegister, this, &IntegrationPluginWebasto::onReceivedRegister);
|
||||
connect(webasto, &Webasto::writeRequestError, this, &IntegrationPluginWebasto::onWriteRequestError);
|
||||
connect(webasto, &Webasto::writeRequestExecuted, this, &IntegrationPluginWebasto::onWriteRequestExecuted);
|
||||
|
||||
if (!webasto->connectDevice()) {
|
||||
qCWarning(dcWebasto()) << "Could not connect to device";
|
||||
info->finish(Thing::ThingErrorSetupFailed);
|
||||
}
|
||||
connect(webasto, &Webasto::connectionStateChanged, info, [info] (bool connected) {
|
||||
if (connected)
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
});
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -233,15 +313,14 @@ void IntegrationPluginWebasto::setupThing(ThingSetupInfo *info)
|
||||
}
|
||||
}
|
||||
|
||||
MacAddress macAddress = MacAddress(thing->paramValue(webastoNextThingMacAddressParamTypeId).toString());
|
||||
if (!macAddress.isValid()) {
|
||||
qCWarning(dcWebasto()) << "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(dcWebasto()) << "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);
|
||||
|
||||
QHostAddress address = monitor->networkDeviceInfo().address();
|
||||
@ -294,14 +373,13 @@ void IntegrationPluginWebasto::setupThing(ThingSetupInfo *info)
|
||||
}
|
||||
}
|
||||
|
||||
MacAddress macAddress = MacAddress(thing->paramValue(webastoUniteThingMacAddressParamTypeId).toString());
|
||||
if (!macAddress.isValid()) {
|
||||
qCWarning(dcWebasto()) << "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(dcWebasto()) << "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, [=](){
|
||||
@ -311,23 +389,28 @@ void IntegrationPluginWebasto::setupThing(ThingSetupInfo *info)
|
||||
}
|
||||
});
|
||||
|
||||
if (monitor->reachable()) {
|
||||
setupEVC04Connection(info);
|
||||
// If this is the first setup, the monitor must become reachable before we finish the setup
|
||||
if (info->isInitialSetup()) {
|
||||
// Wait for the monitor to be ready
|
||||
if (monitor->reachable()) {
|
||||
setupEVC04Connection(info);
|
||||
} else {
|
||||
qCDebug(dcWebasto()) << "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(dcWebasto()) << "The monitor for thing setup" << thing->name() << "is now reachable. Continuing setup on" << monitor->networkDeviceInfo().address().toString();
|
||||
setupEVC04Connection(info);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCDebug(dcWebasto()) << "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(dcWebasto()) << "The monitor for thing setup" << thing->name() << "is now reachable. Continuing setup on" << monitor->networkDeviceInfo().address().toString();
|
||||
setupEVC04Connection(info);
|
||||
}
|
||||
});
|
||||
// Not the first setup, just add and let the monitor do the check reachable work
|
||||
setupEVC04Connection(info);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
||||
|
||||
}
|
||||
|
||||
void IntegrationPluginWebasto::postSetupThing(Thing *thing)
|
||||
@ -936,17 +1019,6 @@ void IntegrationPluginWebasto::executeWebastoNextPowerAction(ThingActionInfo *in
|
||||
});
|
||||
}
|
||||
|
||||
void IntegrationPluginWebasto::onConnectionChanged(bool connected)
|
||||
{
|
||||
Webasto *connection = static_cast<Webasto *>(sender());
|
||||
Thing *thing = m_webastoLiveConnections.key(connection);
|
||||
if (!thing) {
|
||||
qCWarning(dcWebasto()) << "On connection changed, thing not found for connection";
|
||||
return;
|
||||
}
|
||||
thing->setStateValue(webastoLiveConnectedStateTypeId, connected);
|
||||
}
|
||||
|
||||
void IntegrationPluginWebasto::onWriteRequestExecuted(const QUuid &requestId, bool success)
|
||||
{
|
||||
if (m_asyncActions.contains(requestId)) {
|
||||
@ -1258,21 +1330,21 @@ void IntegrationPluginWebasto::setupEVC04Connection(ThingSetupInfo *info)
|
||||
|
||||
connect(evc04Connection, &EVC04ModbusTcpConnection::chargepointStateChanged, thing, [thing](EVC04ModbusTcpConnection::ChargePointState chargePointState) {
|
||||
qCDebug(dcWebasto()) << "Chargepoint state changed" << thing->name() << chargePointState;
|
||||
// switch (chargePointState) {
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateAvailable:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStatePreparing:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateReserved:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateUnavailable:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateFaulted:
|
||||
// thing->setStateValue(evc04PluggedInStateTypeId, false);
|
||||
// break;
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateCharging:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateSuspendedEVSE:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateSuspendedEV:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateFinishing:
|
||||
// thing->setStateValue(evc04PluggedInStateTypeId, true);
|
||||
// break;
|
||||
// }
|
||||
// switch (chargePointState) {
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateAvailable:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStatePreparing:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateReserved:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateUnavailable:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateFaulted:
|
||||
// thing->setStateValue(evc04PluggedInStateTypeId, false);
|
||||
// break;
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateCharging:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateSuspendedEVSE:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateSuspendedEV:
|
||||
// case EVC04ModbusTcpConnection::ChargePointStateFinishing:
|
||||
// thing->setStateValue(evc04PluggedInStateTypeId, true);
|
||||
// break;
|
||||
// }
|
||||
});
|
||||
connect(evc04Connection, &EVC04ModbusTcpConnection::chargingStateChanged, thing, [thing](EVC04ModbusTcpConnection::ChargingState chargingState) {
|
||||
qCDebug(dcWebasto()) << "Charging state changed:" << chargingState;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Copyright 2013 - 2024, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -69,6 +69,7 @@ private:
|
||||
QHash<Thing *, Webasto *> m_webastoLiveConnections;
|
||||
QHash<Thing *, WebastoNextModbusTcpConnection *> m_webastoNextConnections;
|
||||
QHash<Thing *, EVC04ModbusTcpConnection *> m_evc04Connections;
|
||||
|
||||
QHash<Thing *, NetworkDeviceMonitor *> m_monitors;
|
||||
|
||||
void setupWebastoNextConnection(ThingSetupInfo *info);
|
||||
@ -88,7 +89,6 @@ private:
|
||||
void executeWebastoUnitePhaseCountAction(ThingActionInfo *info);
|
||||
|
||||
private slots:
|
||||
void onConnectionChanged(bool connected);
|
||||
void onWriteRequestExecuted(const QUuid &requestId, bool success);
|
||||
void onWriteRequestError(const QUuid &requestId, const QString &error);
|
||||
|
||||
|
||||
@ -12,23 +12,33 @@
|
||||
"id": "48472124-3199-4827-990a-b72069bd5658",
|
||||
"displayName": "Webasto Live",
|
||||
"name": "webastoLive",
|
||||
"createMethods": ["discovery"],
|
||||
"interfaces": ["evcharger", "smartmeterconsumer", "connectable"],
|
||||
"createMethods": ["discovery", "user"],
|
||||
"interfaces": ["evcharger", "smartmeterconsumer", "connectable", "networkdevice"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "51fa3ea8-e819-46ca-b975-1bee6285441c",
|
||||
"name": "ipAddress",
|
||||
"name": "address",
|
||||
"displayName": "IP address",
|
||||
"type": "QString",
|
||||
"defaultValue": "0.0.0.0"
|
||||
"inputType": "IPv4Address",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "8ff1cc86-e0b4-4887-ae2a-95de0f9cb24c",
|
||||
"name": "hostName",
|
||||
"displayName": "Host name",
|
||||
"type": "QString",
|
||||
"inputType": "TextLine",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "4aa97965-fc1c-488a-92a6-848c214564bc",
|
||||
"name": "macAddress",
|
||||
"displayName": "MAC address",
|
||||
"type": "QString",
|
||||
"defaultValue": "",
|
||||
"readOnly": true
|
||||
"inputType": "MacAddress",
|
||||
"readOnly": true,
|
||||
"defaultValue": ""
|
||||
}
|
||||
],
|
||||
"stateTypes":[
|
||||
@ -200,8 +210,8 @@
|
||||
"id": "1dddfbf4-a49d-4e28-8cbc-108547a369a2",
|
||||
"displayName": "Webasto NEXT",
|
||||
"name": "webastoNext",
|
||||
"createMethods": ["discovery"],
|
||||
"interfaces": ["evcharger", "smartmeterconsumer", "connectable"],
|
||||
"createMethods": ["discovery", "user"],
|
||||
"interfaces": ["evcharger", "smartmeterconsumer", "connectable", "networkdevice"],
|
||||
"settingsTypes": [
|
||||
{
|
||||
"id": "5292e079-515c-47ae-9117-6a70d5c02566",
|
||||
@ -224,13 +234,30 @@
|
||||
}
|
||||
],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "3e971569-dd28-4031-a5bc-86b58c9b9096",
|
||||
"name": "address",
|
||||
"displayName": "IP address",
|
||||
"type": "QString",
|
||||
"inputType": "IPv4Address",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "eddebfc7-28ee-479d-b528-6837ed974d27",
|
||||
"name": "hostName",
|
||||
"displayName": "Host name",
|
||||
"type": "QString",
|
||||
"inputType": "TextLine",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "882b662f-ec7c-4134-be31-5d36567b9fc2",
|
||||
"name": "macAddress",
|
||||
"displayName": "MAC address",
|
||||
"type": "QString",
|
||||
"defaultValue": "",
|
||||
"readOnly": true
|
||||
"readOnly": true,
|
||||
"inputType": "MacAddress",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "be5a0c50-f3ba-4562-b6c0-a0208e2ab118",
|
||||
@ -437,8 +464,24 @@
|
||||
"displayName": "Webasto Unite",
|
||||
"id": "f7598439-a794-44d4-ae51-47ab40189d61",
|
||||
"createMethods": ["discovery", "user"],
|
||||
"interfaces": ["evcharger", "smartmeterconsumer", "connectable"],
|
||||
"interfaces": ["evcharger", "smartmeterconsumer", "connectable", "networkdevice"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "41d713fb-4658-4797-ab0f-a978f5677eb9",
|
||||
"name": "address",
|
||||
"displayName": "IP address",
|
||||
"type": "QString",
|
||||
"inputType": "IPv4Address",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "fb98c75c-fb6b-4043-8794-d941017d471e",
|
||||
"name": "hostName",
|
||||
"displayName": "Host name",
|
||||
"type": "QString",
|
||||
"inputType": "TextLine",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "99aedef2-1b23-4ab8-bee4-7e8b57b8fa18",
|
||||
"name":"macAddress",
|
||||
|
||||
@ -50,15 +50,9 @@ Webasto::Webasto(const QHostAddress &address, uint port, QObject *parent) :
|
||||
});
|
||||
}
|
||||
|
||||
void Webasto::setAddress(const QHostAddress &address)
|
||||
ModbusTcpMaster *Webasto::modbusTcpMaster() const
|
||||
{
|
||||
qCDebug(dcWebasto()) << "Webasto: set address" << address;
|
||||
m_modbusConnection->setHostAddress(address);
|
||||
}
|
||||
|
||||
QHostAddress Webasto::address() const
|
||||
{
|
||||
return m_modbusConnection->hostAddress();
|
||||
return m_modbusConnection;
|
||||
}
|
||||
|
||||
bool Webasto::connected()
|
||||
|
||||
@ -114,8 +114,8 @@ public:
|
||||
|
||||
explicit Webasto(const QHostAddress &address, uint port = 502, QObject *parent = nullptr);
|
||||
|
||||
void setAddress(const QHostAddress &address);
|
||||
QHostAddress address() const;
|
||||
ModbusTcpMaster *modbusTcpMaster() const;
|
||||
|
||||
bool connected();
|
||||
bool connectDevice();
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Copyright 2013 - 2024, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -40,21 +40,24 @@ WebastoDiscovery::WebastoDiscovery(NetworkDeviceDiscovery *networkDeviceDiscover
|
||||
|
||||
void WebastoDiscovery::startDiscovery()
|
||||
{
|
||||
// TODO: add parameter for searching WebastoNext or WebastoLive, for now the discovery searches only for WebastoNext
|
||||
|
||||
// TODO: add parameter for searching WebastoNext or WebastoLive, for now the discovery searches only for WebastoNext
|
||||
qCInfo(dcWebasto()) << "Discovery: Starting to search for WebastoNext wallboxes in the network...";
|
||||
m_startDateTime = QDateTime::currentDateTime();
|
||||
|
||||
qCInfo(dcWebasto()) << "Discovery: Starting to search for WebastoNext wallboxes in the network...";
|
||||
m_networkDeviceInfos.clear();
|
||||
m_temporaryResults.clear();
|
||||
m_results.clear();
|
||||
|
||||
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
|
||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &WebastoDiscovery::checkNetworkDevice);
|
||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &WebastoDiscovery::checkNetworkDevice);
|
||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
|
||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
|
||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [this, discoveryReply](){
|
||||
qCDebug(dcWebasto()) << "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](){
|
||||
qCDebug(dcWebasto()) << "Discovery: Grace period timer triggered.";
|
||||
finishDiscovery();
|
||||
});
|
||||
QTimer::singleShot(3000, this, &WebastoDiscovery::finishDiscovery);
|
||||
});
|
||||
}
|
||||
|
||||
@ -63,9 +66,9 @@ QList<WebastoDiscovery::Result> WebastoDiscovery::results() const
|
||||
return m_results;
|
||||
}
|
||||
|
||||
void WebastoDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo)
|
||||
void WebastoDiscovery::checkNetworkDevice(const QHostAddress &address)
|
||||
{
|
||||
WebastoNextModbusTcpConnection *connection = new WebastoNextModbusTcpConnection(networkDeviceInfo.address(), 502, 1, this);
|
||||
WebastoNextModbusTcpConnection *connection = new WebastoNextModbusTcpConnection(address, 502, 1, this);
|
||||
m_connections.append(connection);
|
||||
|
||||
connect(connection, &WebastoNextModbusTcpConnection::reachableChanged, this, [=](bool reachable){
|
||||
@ -77,7 +80,7 @@ void WebastoDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
|
||||
|
||||
// Read some well known registers to verify if the register exist and make sense...
|
||||
QModbusReply *reply = connection->readCableState();
|
||||
connect(reply, &QModbusReply::finished, this, [=](){
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply, connection, address](){
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
@ -92,12 +95,12 @@ void WebastoDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
|
||||
quint16 rawValue = ModbusDataUtils::convertToUInt16(unit.values());
|
||||
QMetaEnum valueEnum = WebastoNextModbusTcpConnection::staticMetaObject.enumerator(WebastoNextModbusTcpConnection::staticMetaObject.indexOfEnumerator("CableState"));
|
||||
if (!valueEnum.valueToKey(rawValue)) {
|
||||
qCDebug(dcWebasto()) << "Discovery: invalid enum value for cable state on connection on" << networkDeviceInfo.address().toString() << "Continue...";;
|
||||
qCDebug(dcWebasto()) << "Discovery: invalid enum value for cable state on connection on" << address.toString() << "Continue...";;
|
||||
cleanupConnection(connection);
|
||||
}
|
||||
|
||||
QModbusReply *reply = connection->readChargerState();
|
||||
connect(reply, &QModbusReply::finished, this, [=](){
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply, connection, address](){
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
@ -112,15 +115,14 @@ void WebastoDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
|
||||
quint16 rawValue = ModbusDataUtils::convertToUInt16(unit.values());
|
||||
QMetaEnum valueEnum = WebastoNextModbusTcpConnection::staticMetaObject.enumerator(WebastoNextModbusTcpConnection::staticMetaObject.indexOfEnumerator("ChargerState"));
|
||||
if (!valueEnum.valueToKey(rawValue)) {
|
||||
qCDebug(dcWebasto()) << "Discovery: invalid enum value for charger state on connection on" << networkDeviceInfo.address().toString() << "Continue...";;
|
||||
qCDebug(dcWebasto()) << "Discovery: invalid enum value for charger state on connection on" << address.toString() << "Continue...";;
|
||||
cleanupConnection(connection);
|
||||
}
|
||||
|
||||
|
||||
// Read some registers distributed over the range...
|
||||
|
||||
QModbusReply *reply = connection->readTotalActivePower();
|
||||
connect(reply, &QModbusReply::finished, this, [=](){
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply, connection, address](){
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
@ -143,28 +145,13 @@ void WebastoDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
|
||||
|
||||
// All values good so far, let's assume this is a Webasto NEXT
|
||||
|
||||
// Final check if there is a hostname available for this network device, if so it shouls contain the string "NEXT_".
|
||||
// This is neccessary since Wallboxes from Vestel EVC04 aka. Webasto Unite wallboxes would also match
|
||||
// the creteria up to here get detected as positiv Webasto NEXT.
|
||||
|
||||
// Example hostname: NEXT-WS10XXXX
|
||||
|
||||
if (!networkDeviceInfo.hostName().isEmpty() &&
|
||||
(!networkDeviceInfo.hostName().contains("NEXT_") || networkDeviceInfo.hostName().contains("VESTEL"))) {
|
||||
qCDebug(dcWebasto()) << "Discovery: network device has a hostname and it does match kriteria for Webasto next:" << networkDeviceInfo.hostName() << "on" << networkDeviceInfo.address().toString() << "Continue...";;
|
||||
cleanupConnection(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
// Hostname verification also OK, let's assume this is a Webasto NEXT
|
||||
// The final check regarding the hostname will be done when all network device infos are available in the finishDiscovery slot
|
||||
|
||||
Result result;
|
||||
result.productName = "Webasto NEXT";
|
||||
result.type = TypeWebastoNext;
|
||||
result.networkDeviceInfo = networkDeviceInfo;
|
||||
m_results.append(result);
|
||||
|
||||
qCDebug(dcWebasto()) << "Discovery: --> Found" << result.productName << result.networkDeviceInfo;
|
||||
result.address = address;
|
||||
m_temporaryResults.append(result);
|
||||
|
||||
// Done with this connection
|
||||
cleanupConnection(connection);
|
||||
@ -177,14 +164,14 @@ void WebastoDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
|
||||
// If we get any error...skip this host...
|
||||
connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionErrorOccurred, this, [=](QModbusDevice::Error error){
|
||||
if (error != QModbusDevice::NoError) {
|
||||
qCDebug(dcWebasto()) << "Discovery: Connection error on" << networkDeviceInfo.address().toString() << "Continue...";;
|
||||
qCDebug(dcWebasto()) << "Discovery: Connection error on" << address.toString() << "Continue...";;
|
||||
cleanupConnection(connection);
|
||||
}
|
||||
});
|
||||
|
||||
// If check reachability failed...skip this host...
|
||||
connect(connection, &WebastoNextModbusTcpConnection::checkReachabilityFailed, this, [=](){
|
||||
qCDebug(dcWebasto()) << "Discovery: Check reachability failed on" << networkDeviceInfo.address().toString() << "Continue...";;
|
||||
qCDebug(dcWebasto()) << "Discovery: Check reachability failed on" << address.toString() << "Continue...";;
|
||||
cleanupConnection(connection);
|
||||
});
|
||||
|
||||
@ -203,6 +190,27 @@ void WebastoDiscovery::finishDiscovery()
|
||||
{
|
||||
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
|
||||
|
||||
for (int i = 0; i < m_temporaryResults.count(); i++) {
|
||||
// Fill in all network device infos we have
|
||||
m_temporaryResults[i].networkDeviceInfo = m_networkDeviceInfos.get(m_temporaryResults.at(i).address);
|
||||
|
||||
// Final check if there is a hostname available for this network device, if so it shouls contain the string "NEXT_".
|
||||
// This is neccessary since Wallboxes from Vestel EVC04 aka. Webasto Unite wallboxes would also match
|
||||
// the creteria up to here get detected as positiv Webasto NEXT.
|
||||
|
||||
// Example hostname: NEXT-WS10XXXX
|
||||
QString hostName = m_temporaryResults.at(i).networkDeviceInfo.hostName();
|
||||
if (!hostName.isEmpty() && (!hostName.contains("NEXT_") || hostName.contains("VESTEL"))) {
|
||||
qCDebug(dcWebasto()) << "Discovery: network device has a hostname and it does match kriteria for Webasto next:" << hostName << "on" << m_temporaryResults.at(i).networkDeviceInfo.address().toString() << "Continue...";;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Hostname verification also OK, let's assume this is a Webasto NEXT
|
||||
|
||||
qCDebug(dcWebasto()) << "Discovery: --> Found" << m_temporaryResults.at(i).productName << m_temporaryResults.at(i).networkDeviceInfo;
|
||||
m_results.append(m_temporaryResults.at(i));
|
||||
}
|
||||
|
||||
// Cleanup any leftovers...we don't care any more
|
||||
foreach (WebastoNextModbusTcpConnection *connection, m_connections)
|
||||
cleanupConnection(connection);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2023, nymea GmbH
|
||||
* Copyright 2013 - 2024, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -34,7 +34,6 @@
|
||||
#include <QObject>
|
||||
|
||||
#include <network/networkdevicediscovery.h>
|
||||
|
||||
#include "webastonextmodbustcpconnection.h"
|
||||
|
||||
class WebastoDiscovery : public QObject
|
||||
@ -50,6 +49,7 @@ public:
|
||||
typedef struct Result {
|
||||
QString productName;
|
||||
Type type;
|
||||
QHostAddress address;
|
||||
NetworkDeviceInfo networkDeviceInfo;
|
||||
} Result;
|
||||
|
||||
@ -64,14 +64,14 @@ signals:
|
||||
|
||||
private:
|
||||
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
|
||||
|
||||
QList<WebastoNextModbusTcpConnection *> m_connections;
|
||||
|
||||
QList<Result> m_results;
|
||||
|
||||
QDateTime m_startDateTime;
|
||||
|
||||
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
|
||||
NetworkDeviceInfos m_networkDeviceInfos;
|
||||
QList<WebastoNextModbusTcpConnection *> m_connections;
|
||||
QList<Result> m_temporaryResults;
|
||||
QList<Result> m_results;
|
||||
|
||||
void checkNetworkDevice(const QHostAddress &address);
|
||||
void cleanupConnection(WebastoNextModbusTcpConnection *connection);
|
||||
|
||||
void finishDiscovery();
|
||||
|
||||
Reference in New Issue
Block a user