SunSpec: Update to networkdevice interface
This commit is contained in:
parent
36f9f3c512
commit
2a27534279
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2023, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -70,12 +70,18 @@ IntegrationPluginSunSpec::IntegrationPluginSunSpec()
|
|||||||
void IntegrationPluginSunSpec::init()
|
void IntegrationPluginSunSpec::init()
|
||||||
{
|
{
|
||||||
// SunSpec connection params
|
// SunSpec connection params
|
||||||
m_connectionPortParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingPortParamTypeId);
|
|
||||||
m_connectionPortParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingPortParamTypeId);
|
|
||||||
|
|
||||||
m_connectionMacAddressParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingMacAddressParamTypeId);
|
m_connectionMacAddressParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingMacAddressParamTypeId);
|
||||||
m_connectionMacAddressParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingMacAddressParamTypeId);
|
m_connectionMacAddressParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingMacAddressParamTypeId);
|
||||||
|
|
||||||
|
m_connectionHostNameParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingHostNameParamTypeId);
|
||||||
|
m_connectionHostNameParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingHostNameParamTypeId);
|
||||||
|
|
||||||
|
m_connectionAddressParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingAddressParamTypeId);
|
||||||
|
m_connectionAddressParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingAddressParamTypeId);
|
||||||
|
|
||||||
|
m_connectionPortParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingPortParamTypeId);
|
||||||
|
m_connectionPortParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingPortParamTypeId);
|
||||||
|
|
||||||
m_connectionSlaveIdParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingSlaveIdParamTypeId);
|
m_connectionSlaveIdParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingSlaveIdParamTypeId);
|
||||||
m_connectionSlaveIdParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingSlaveIdParamTypeId);
|
m_connectionSlaveIdParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingSlaveIdParamTypeId);
|
||||||
|
|
||||||
@ -141,7 +147,7 @@ void IntegrationPluginSunSpec::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
|
|
||||||
SunSpecDiscovery *discovery = new SunSpecDiscovery(hardwareManager()->networkDeviceDiscovery(), slaveIds, byteOrder, info);
|
SunSpecDiscovery *discovery = new SunSpecDiscovery(hardwareManager()->networkDeviceDiscovery(), slaveIds, byteOrder, info);
|
||||||
// Note: we could add here more
|
// Note: we could add here more
|
||||||
connect(discovery, &SunSpecDiscovery::discoveryFinished, info, [=](){
|
connect(discovery, &SunSpecDiscovery::discoveryFinished, info, [this, info, discovery](){
|
||||||
foreach (const SunSpecDiscovery::Result &result, discovery->results()) {
|
foreach (const SunSpecDiscovery::Result &result, discovery->results()) {
|
||||||
|
|
||||||
// Extract the manufacturer: we pick the first manufacturer name of the first common model having a manufacturer name for now
|
// Extract the manufacturer: we pick the first manufacturer name of the first common model having a manufacturer name for now
|
||||||
@ -166,6 +172,7 @@ void IntegrationPluginSunSpec::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
// Full support of meter, inverter and storage will be provided in the kostal plugin which makes
|
// Full support of meter, inverter and storage will be provided in the kostal plugin which makes
|
||||||
// use of the native modbus communication from kostal.
|
// use of the native modbus communication from kostal.
|
||||||
if (hasManufacturer(result.modelManufacturers, "kostal")) {
|
if (hasManufacturer(result.modelManufacturers, "kostal")) {
|
||||||
|
qCWarning(dcSunSpec()) << "Skipping Kostal manufacturer on SunSpec. Please use the native kostal integration plugin in order to add it to the system.";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,26 +184,40 @@ void IntegrationPluginSunSpec::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
title.append("SunSpec connection");
|
title.append("SunSpec connection");
|
||||||
|
|
||||||
QString description;
|
QString description;
|
||||||
if (result.networkDeviceInfo.macAddressManufacturer().isEmpty()) {
|
MacAddressInfo macInfo;
|
||||||
description = result.networkDeviceInfo.macAddress();
|
switch (result.networkDeviceInfo.monitorMode()) {
|
||||||
} else {
|
case NetworkDeviceInfo::MonitorModeMac:
|
||||||
description = result.networkDeviceInfo.macAddress() + " (" + result.networkDeviceInfo.macAddressManufacturer() + ")";
|
macInfo = result.networkDeviceInfo.macAddressInfos().constFirst();
|
||||||
|
description = result.networkDeviceInfo.address().toString();
|
||||||
|
if (!macInfo.vendorName().isEmpty())
|
||||||
|
description += " - " + result.networkDeviceInfo.macAddressInfos().constFirst().vendorName();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NetworkDeviceInfo::MonitorModeHostName:
|
||||||
|
description = result.networkDeviceInfo.hostName();
|
||||||
|
break;
|
||||||
|
case NetworkDeviceInfo::MonitorModeIp:
|
||||||
|
description = "Interface: " + result.networkDeviceInfo.networkInterface().name();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThingDescriptor descriptor(info->thingClassId(), title, description);
|
ThingDescriptor descriptor(info->thingClassId(), title, description);
|
||||||
|
|
||||||
// Check if we already have set up this device
|
|
||||||
Things existingThings = myThings().filterByParam(m_connectionMacAddressParamTypeIds.value(info->thingClassId()), result.networkDeviceInfo.macAddress());
|
|
||||||
if (existingThings.count() == 1) {
|
|
||||||
qCDebug(dcSunSpec()) << "This thing already exists in the system." << existingThings.first() << result.networkDeviceInfo;
|
|
||||||
descriptor.setThingId(existingThings.first()->id());
|
|
||||||
}
|
|
||||||
|
|
||||||
ParamList params;
|
ParamList params;
|
||||||
|
params << Param(m_connectionMacAddressParamTypeIds.value(info->thingClassId()), result.networkDeviceInfo.thingParamValueMacAddress());
|
||||||
|
params << Param(m_connectionHostNameParamTypeIds.value(info->thingClassId()), result.networkDeviceInfo.thingParamValueHostName());
|
||||||
|
params << Param(m_connectionAddressParamTypeIds.value(info->thingClassId()), result.networkDeviceInfo.thingParamValueAddress());
|
||||||
params << Param(m_connectionPortParamTypeIds.value(info->thingClassId()), result.port);
|
params << Param(m_connectionPortParamTypeIds.value(info->thingClassId()), result.port);
|
||||||
params << Param(m_connectionMacAddressParamTypeIds.value(info->thingClassId()), result.networkDeviceInfo.macAddress());
|
|
||||||
params << Param(m_connectionSlaveIdParamTypeIds.value(info->thingClassId()), result.slaveId);
|
params << Param(m_connectionSlaveIdParamTypeIds.value(info->thingClassId()), result.slaveId);
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
|
|
||||||
|
// Check if we already have set up this device
|
||||||
|
Thing *existingThing = myThings().findByParams(params);
|
||||||
|
if (existingThing) {
|
||||||
|
qCDebug(dcSunSpec()) << "This thing already exists in the system:" << result.networkDeviceInfo;
|
||||||
|
descriptor.setThingId(existingThing->id());
|
||||||
|
}
|
||||||
|
|
||||||
info->addThingDescriptor(descriptor);
|
info->addThingDescriptor(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +234,8 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||||||
qCDebug(dcSunSpec()) << "Setup thing" << thing;
|
qCDebug(dcSunSpec()) << "Setup thing" << thing;
|
||||||
qCDebug(dcSunSpec()) << thing->params();
|
qCDebug(dcSunSpec()) << thing->params();
|
||||||
|
|
||||||
if (thing->thingClassId() == sunspecConnectionThingClassId || thing->thingClassId() == solarEdgeConnectionThingClassId) {
|
if (thing->thingClassId() == sunspecConnectionThingClassId ||
|
||||||
|
thing->thingClassId() == solarEdgeConnectionThingClassId) {
|
||||||
|
|
||||||
// Handle reconfigure
|
// Handle reconfigure
|
||||||
if (m_sunSpecConnections.contains(thing->id())) {
|
if (m_sunSpecConnections.contains(thing->id())) {
|
||||||
@ -225,16 +247,17 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MacAddress macAddress = MacAddress(thing->paramValue(m_connectionMacAddressParamTypeIds.value(thing->thingClassId())).toString());
|
|
||||||
if (!macAddress.isValid()) {
|
// Create the monitor
|
||||||
qCWarning(dcSunSpec()) << "The configured mac address is not valid" << thing->params();
|
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
|
||||||
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The MAC address is not known. Please reconfigure the connection."));
|
if (!monitor) {
|
||||||
|
qCWarning(dcSunSpec()) << "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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the monitor
|
|
||||||
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress);
|
|
||||||
m_monitors.insert(thing, monitor);
|
m_monitors.insert(thing, monitor);
|
||||||
|
|
||||||
QHostAddress address = monitor->networkDeviceInfo().address();
|
QHostAddress address = monitor->networkDeviceInfo().address();
|
||||||
if (address.isNull() && info->isInitialSetup()) {
|
if (address.isNull() && info->isInitialSetup()) {
|
||||||
qCWarning(dcSunSpec()) << "Cannot set up thing. The host address is not known and this is an initial setup";
|
qCWarning(dcSunSpec()) << "Cannot set up thing. The host address is not known and this is an initial setup";
|
||||||
@ -305,9 +328,9 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (thing->thingClassId() == sunspecThreePhaseInverterThingClassId
|
} else if (thing->thingClassId() == sunspecThreePhaseInverterThingClassId ||
|
||||||
|| thing->thingClassId() == sunspecSplitPhaseInverterThingClassId
|
thing->thingClassId() == sunspecSplitPhaseInverterThingClassId ||
|
||||||
|| thing->thingClassId() == sunspecSinglePhaseInverterThingClassId ) {
|
thing->thingClassId() == sunspecSinglePhaseInverterThingClassId ) {
|
||||||
|
|
||||||
Thing *thing = info->thing();
|
Thing *thing = info->thing();
|
||||||
uint modelId = thing->paramValue(m_modelIdParamTypeIds.value(thing->thingClassId())).toInt();
|
uint modelId = thing->paramValue(m_modelIdParamTypeIds.value(thing->thingClassId())).toInt();
|
||||||
@ -420,9 +443,8 @@ void IntegrationPluginSunSpec::thingRemoved(Thing *thing)
|
|||||||
Q_ASSERT_X(false, "thingRemoved", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
Q_ASSERT_X(false, "thingRemoved", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_monitors.contains(thing)) {
|
if (m_monitors.contains(thing))
|
||||||
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
|
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
|
||||||
}
|
|
||||||
|
|
||||||
if (myThings().isEmpty()) {
|
if (myThings().isEmpty()) {
|
||||||
qCDebug(dcSunSpec()) << "Stopping refresh timer";
|
qCDebug(dcSunSpec()) << "Stopping refresh timer";
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2023, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -62,9 +62,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// SunSpec Connection params map
|
// SunSpec Connection params map
|
||||||
QHash<ThingClassId, ParamTypeId> m_connectionIpParamTypeIds;
|
|
||||||
QHash<ThingClassId, ParamTypeId> m_connectionPortParamTypeIds;
|
|
||||||
QHash<ThingClassId, ParamTypeId> m_connectionMacAddressParamTypeIds;
|
QHash<ThingClassId, ParamTypeId> m_connectionMacAddressParamTypeIds;
|
||||||
|
QHash<ThingClassId, ParamTypeId> m_connectionAddressParamTypeIds;
|
||||||
|
QHash<ThingClassId, ParamTypeId> m_connectionHostNameParamTypeIds;
|
||||||
|
QHash<ThingClassId, ParamTypeId> m_connectionPortParamTypeIds;
|
||||||
QHash<ThingClassId, ParamTypeId> m_connectionSlaveIdParamTypeIds;
|
QHash<ThingClassId, ParamTypeId> m_connectionSlaveIdParamTypeIds;
|
||||||
|
|
||||||
// SunSpec thing params map
|
// SunSpec thing params map
|
||||||
|
|||||||
@ -40,15 +40,32 @@
|
|||||||
"displayName": "SunSpec Generic",
|
"displayName": "SunSpec Generic",
|
||||||
"id": "f51853f3-8815-4cf3-b337-45cda1f3e6d5",
|
"id": "f51853f3-8815-4cf3-b337-45cda1f3e6d5",
|
||||||
"createMethods": [ "Discovery" ],
|
"createMethods": [ "Discovery" ],
|
||||||
"interfaces": ["gateway"],
|
"interfaces": [ "gateway", "networkdevice" ],
|
||||||
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage"],
|
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage"],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
|
{
|
||||||
|
"id": "3567b389-9d42-48f9-a29b-d18388fb36a1",
|
||||||
|
"name": "address",
|
||||||
|
"displayName": "Host address",
|
||||||
|
"type": "QString",
|
||||||
|
"inputType": "IPv4Address",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1667b0ed-9a2b-47c6-a01f-690caee55ffa",
|
||||||
|
"name": "hostName",
|
||||||
|
"displayName": "Host name",
|
||||||
|
"type": "QString",
|
||||||
|
"inputType": "TextLine",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "f65d6c36-1672-44cb-b52a-62d71837ae67",
|
"id": "f65d6c36-1672-44cb-b52a-62d71837ae67",
|
||||||
"name":"macAddress",
|
"name":"macAddress",
|
||||||
"displayName": "MAC address",
|
"displayName": "MAC address",
|
||||||
"type": "QString",
|
"type": "QString",
|
||||||
"defaultValue": "00:00:00:00:00:00"
|
"inputType": "MacAddress",
|
||||||
|
"defaultValue": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "1fa4fc9c-f6be-47c7-928a-bcefc1142eec",
|
"id": "1fa4fc9c-f6be-47c7-928a-bcefc1142eec",
|
||||||
@ -1458,15 +1475,32 @@
|
|||||||
"displayName": "SolarEdge",
|
"displayName": "SolarEdge",
|
||||||
"id": "7a92bf65-b443-4491-a012-2bec35eb5bf0",
|
"id": "7a92bf65-b443-4491-a012-2bec35eb5bf0",
|
||||||
"createMethods": [ "Discovery" ],
|
"createMethods": [ "Discovery" ],
|
||||||
"interfaces": ["gateway"],
|
"interfaces": [ "gateway", "networkdevice" ],
|
||||||
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage" ],
|
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage" ],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
|
{
|
||||||
|
"id": "9c2bafd0-6d56-42e0-8ef3-c4940b4f18b5",
|
||||||
|
"name": "address",
|
||||||
|
"displayName": "Host address",
|
||||||
|
"type": "QString",
|
||||||
|
"inputType": "IPv4Address",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2e22c369-8476-4908-9cdc-186472f4d472",
|
||||||
|
"name": "hostName",
|
||||||
|
"displayName": "Host name",
|
||||||
|
"type": "QString",
|
||||||
|
"inputType": "TextLine",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "bb395c12-54d6-4139-b0a6-e31b28bc4d2e",
|
"id": "bb395c12-54d6-4139-b0a6-e31b28bc4d2e",
|
||||||
"name":"macAddress",
|
"name":"macAddress",
|
||||||
"displayName": "MAC address",
|
"displayName": "MAC address",
|
||||||
"type": "QString",
|
"type": "QString",
|
||||||
"defaultValue": "00:00:00:00:00:00"
|
"inputType": "MacAddress",
|
||||||
|
"defaultValue": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "1bcede48-d167-4ced-8f1b-bea6302dd43f",
|
"id": "1bcede48-d167-4ced-8f1b-bea6302dd43f",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2023, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -65,16 +65,16 @@ void SunSpecDiscovery::startDiscovery()
|
|||||||
m_startDateTime = QDateTime::currentDateTime();
|
m_startDateTime = QDateTime::currentDateTime();
|
||||||
|
|
||||||
// Imedialty check any new device gets discovered
|
// Imedialty check any new device gets discovered
|
||||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &SunSpecDiscovery::checkNetworkDevice);
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &SunSpecDiscovery::checkNetworkDevice);
|
||||||
|
|
||||||
// Check what might be left on finished
|
// Check what might be left on finished
|
||||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
|
||||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [this, discoveryReply](){
|
||||||
qCDebug(dcSunSpec()) << "Discovery: Network discovery finished. Give some time for pending discovery checks to finish...";
|
qCDebug(dcSunSpec()) << "Discovery: Network discovery finished. Give some time for pending discovery checks to finish...";
|
||||||
|
m_networkDeviceInfos = discoveryReply->networkDeviceInfos();
|
||||||
|
|
||||||
// Give the last connections added right before the network discovery finished a chance to check the device...
|
// Give the last connections added right before the network discovery finished a chance to check the device...
|
||||||
QTimer::singleShot(3000, this, [this](){
|
QTimer::singleShot(3000, this, [this](){
|
||||||
qCDebug(dcSunSpec()) << "Discovery: Grace period timer triggered";
|
|
||||||
finishDiscovery();
|
finishDiscovery();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -121,7 +121,7 @@ void SunSpecDiscovery::testNextConnection(const QHostAddress &address)
|
|||||||
connectionTimer->start();
|
connectionTimer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo)
|
void SunSpecDiscovery::checkNetworkDevice(const QHostAddress &address)
|
||||||
{
|
{
|
||||||
// Create a connection queue for this network device
|
// Create a connection queue for this network device
|
||||||
|
|
||||||
@ -132,13 +132,13 @@ void SunSpecDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
|
|||||||
|
|
||||||
foreach (quint16 slaveId, m_slaveIds) {
|
foreach (quint16 slaveId, m_slaveIds) {
|
||||||
|
|
||||||
SunSpecConnection *connection = new SunSpecConnection(networkDeviceInfo.address(), port, slaveId, m_byteOrder, this);
|
SunSpecConnection *connection = new SunSpecConnection(address, port, slaveId, m_byteOrder, this);
|
||||||
connection->setNumberOfRetries(1);
|
connection->setNumberOfRetries(1);
|
||||||
connection->setTimeout(500);
|
connection->setTimeout(500);
|
||||||
m_connections.append(connection);
|
m_connections.append(connection);
|
||||||
connectionQueue.enqueue(connection);
|
connectionQueue.enqueue(connection);
|
||||||
|
|
||||||
connect(connection, &SunSpecConnection::connectedChanged, this, [=](bool connected){
|
connect(connection, &SunSpecConnection::connectedChanged, this, [this, connection, connectionQueue, address](bool connected){
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
// Disconnected ... done with this connection
|
// Disconnected ... done with this connection
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
@ -155,7 +155,9 @@ void SunSpecDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
|
|||||||
// Modbus TCP connected, try to discovery sunspec models...
|
// Modbus TCP connected, try to discovery sunspec models...
|
||||||
connect(connection, &SunSpecConnection::discoveryFinished, this, [=](bool success){
|
connect(connection, &SunSpecConnection::discoveryFinished, this, [=](bool success){
|
||||||
if (!success) {
|
if (!success) {
|
||||||
qCDebug(dcSunSpec()) << "Discovery: SunSpec discovery failed on" << QString("%1:%2").arg(networkDeviceInfo.address().toString()).arg(port) << "slave ID:" << slaveId << "Continue...";;
|
qCDebug(dcSunSpec()) << "Discovery: SunSpec discovery failed on"
|
||||||
|
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
|
||||||
|
<< "slave ID:" << connection->slaveId() << "Continue...";
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -163,7 +165,7 @@ void SunSpecDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
|
|||||||
// Success, we found some sunspec models here, let's read some infomation from the models
|
// Success, we found some sunspec models here, let's read some infomation from the models
|
||||||
|
|
||||||
Result result;
|
Result result;
|
||||||
result.networkDeviceInfo = networkDeviceInfo;
|
result.address = address;
|
||||||
result.port = connection->port();
|
result.port = connection->port();
|
||||||
result.slaveId = connection->slaveId();
|
result.slaveId = connection->slaveId();
|
||||||
|
|
||||||
@ -186,7 +188,9 @@ void SunSpecDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
|
|||||||
|
|
||||||
// Run SunSpec discovery on connection...
|
// Run SunSpec discovery on connection...
|
||||||
if (!connection->startDiscovery()) {
|
if (!connection->startDiscovery()) {
|
||||||
qCDebug(dcSunSpec()) << "Discovery: Unable to discover SunSpec data on connection" << QString("%1:%2").arg(networkDeviceInfo.address().toString()).arg(port) << "slave ID:" << slaveId << "Continue...";;
|
qCDebug(dcSunSpec()) << "Discovery: Unable to discover SunSpec data on connection"
|
||||||
|
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
|
||||||
|
<< "slave ID:" << connection->slaveId() << "Continue...";
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -194,15 +198,17 @@ void SunSpecDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
|
|||||||
// If we get any error...skip this host...
|
// If we get any error...skip this host...
|
||||||
connect(connection->modbusTcpClient(), &QModbusTcpClient::errorOccurred, this, [=](QModbusDevice::Error error){
|
connect(connection->modbusTcpClient(), &QModbusTcpClient::errorOccurred, this, [=](QModbusDevice::Error error){
|
||||||
if (error != QModbusDevice::NoError) {
|
if (error != QModbusDevice::NoError) {
|
||||||
qCDebug(dcSunSpec()) << "Discovery: Connection error on" << QString("%1:%2").arg(networkDeviceInfo.address().toString()).arg(port) << "slave ID:" << slaveId << "Continue...";;
|
qCDebug(dcSunSpec()) << "Discovery: Connection error on"
|
||||||
|
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
|
||||||
|
<< "slave ID:" << connection->slaveId() << "Continue...";
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pendingConnectionAttempts[networkDeviceInfo.address()] = connectionQueue;
|
m_pendingConnectionAttempts[address] = connectionQueue;
|
||||||
testNextConnection(networkDeviceInfo.address());
|
testNextConnection(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecDiscovery::cleanupConnection(SunSpecConnection *connection)
|
void SunSpecDiscovery::cleanupConnection(SunSpecConnection *connection)
|
||||||
@ -223,10 +229,15 @@ void SunSpecDiscovery::finishDiscovery()
|
|||||||
{
|
{
|
||||||
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
|
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
// Cleanup any leftovers...we don't care any more
|
// Cleanup any leftovers...we don't care any more
|
||||||
foreach (SunSpecConnection *connection, m_connections)
|
foreach (SunSpecConnection *connection, m_connections)
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
|
|
||||||
qCInfo(dcSunSpec()) << "Discovery: Finished the discovery process. Found" << m_results.count() << "SunSpec devices in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz");
|
qCInfo(dcSunSpec()) << "Discovery: Finished the discovery process. Found" << m_results.count()
|
||||||
|
<< "SunSpec devices in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz");
|
||||||
emit discoveryFinished();
|
emit discoveryFinished();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2023, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -44,6 +44,7 @@ class SunSpecDiscovery : public QObject
|
|||||||
public:
|
public:
|
||||||
explicit SunSpecDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, const QList<quint16> &slaveIds, SunSpecDataPoint::ByteOrder byteOrder = SunSpecDataPoint::ByteOrderLittleEndian, QObject *parent = nullptr);
|
explicit SunSpecDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, const QList<quint16> &slaveIds, SunSpecDataPoint::ByteOrder byteOrder = SunSpecDataPoint::ByteOrderLittleEndian, QObject *parent = nullptr);
|
||||||
typedef struct Result {
|
typedef struct Result {
|
||||||
|
QHostAddress address;
|
||||||
NetworkDeviceInfo networkDeviceInfo;
|
NetworkDeviceInfo networkDeviceInfo;
|
||||||
quint16 port;
|
quint16 port;
|
||||||
quint16 slaveId;
|
quint16 slaveId;
|
||||||
@ -67,13 +68,13 @@ private:
|
|||||||
QDateTime m_startDateTime;
|
QDateTime m_startDateTime;
|
||||||
QHash<QHostAddress, QQueue<SunSpecConnection *>> m_pendingConnectionAttempts;
|
QHash<QHostAddress, QQueue<SunSpecConnection *>> m_pendingConnectionAttempts;
|
||||||
QHash<SunSpecConnection *, QTimer *> m_connectionTimers;
|
QHash<SunSpecConnection *, QTimer *> m_connectionTimers;
|
||||||
|
|
||||||
QList<SunSpecConnection *> m_connections;
|
QList<SunSpecConnection *> m_connections;
|
||||||
|
NetworkDeviceInfos m_networkDeviceInfos;
|
||||||
QList<Result> m_results;
|
QList<Result> m_results;
|
||||||
|
|
||||||
void testNextConnection(const QHostAddress &address);
|
void testNextConnection(const QHostAddress &address);
|
||||||
|
|
||||||
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
|
void checkNetworkDevice(const QHostAddress &address);
|
||||||
void cleanupConnection(SunSpecConnection *connection);
|
void cleanupConnection(SunSpecConnection *connection);
|
||||||
|
|
||||||
void finishDiscovery();
|
void finishDiscovery();
|
||||||
|
|||||||
Reference in New Issue
Block a user