diff --git a/sma/integrationpluginsma.cpp b/sma/integrationpluginsma.cpp index 672ba86..b9316fe 100644 --- a/sma/integrationpluginsma.cpp +++ b/sma/integrationpluginsma.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2023, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -64,28 +64,39 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info) webBoxDiscovery->deleteLater(); ThingDescriptors descriptors; foreach (const NetworkDeviceInfo &networkDeviceInfo, webBoxDiscovery->discoveryResults()) { - QString title = "SMA Sunny WebBox (" + networkDeviceInfo.address().toString() + ")"; + QString title = "SMA Sunny WebBox"; 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 = networkDeviceInfo.address().toString(); + if (!macInfo.vendorName().isEmpty()) + description += " - " + networkDeviceInfo.macAddressInfos().constFirst().vendorName(); + break; + case NetworkDeviceInfo::MonitorModeHostName: + description = networkDeviceInfo.address().toString(); + break; + case NetworkDeviceInfo::MonitorModeIp: + description = "Interface: " + networkDeviceInfo.networkInterface().name(); + break; } ThingDescriptor descriptor(sunnyWebBoxThingClassId, title, description); - // Check for reconfiguration - foreach (Thing *existingThing, myThings()) { - if (existingThing->paramValue(sunnyWebBoxThingMacAddressParamTypeId).toString() == networkDeviceInfo.macAddress()) { - descriptor.setThingId(existingThing->id()); - break; - } + ParamList params; + params << Param(sunnyWebBoxThingAddressParamTypeId, networkDeviceInfo.thingParamValueAddress()); + params << Param(sunnyWebBoxThingHostNameParamTypeId, networkDeviceInfo.thingParamValueHostName()); + params << Param(sunnyWebBoxThingMacAddressParamTypeId, networkDeviceInfo.thingParamValueMacAddress()); + descriptor.setParams(params); + + // Check if we already have set up this device + Thing *existingThing = myThings().findByParams(params); + if (existingThing) { + qCDebug(dcSma()) << "This thing already exists in the system:" << networkDeviceInfo; + descriptor.setThingId(existingThing->id()); } - ParamList params; - params << Param(sunnyWebBoxThingHostParamTypeId, networkDeviceInfo.address().toString()); - params << Param(sunnyWebBoxThingMacAddressParamTypeId, networkDeviceInfo.macAddress()); - descriptor.setParams(params); descriptors.append(descriptor); } info->addThingDescriptors(descriptors); @@ -163,8 +174,6 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info) connect(speedwireDiscovery, &SpeedwireDiscovery::discoveryFinished, this, [=](){ qCDebug(dcSma()) << "Speed wire discovery finished."; speedwireDiscovery->deleteLater(); - - ThingDescriptors descriptors; foreach (const SpeedwireDiscovery::SpeedwireDiscoveryResult &result, speedwireDiscovery->discoveryResult()) { if (result.deviceType != Speedwire::DeviceTypeInverter) @@ -188,15 +197,16 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info) } ParamList params; - params << Param(speedwireInverterThingHostParamTypeId, result.address.toString()); - params << Param(speedwireInverterThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress()); + params << Param(speedwireInverterThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress()); + params << Param(speedwireInverterThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName()); + params << Param(speedwireInverterThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress()); params << Param(speedwireInverterThingSerialNumberParamTypeId, result.serialNumber); params << Param(speedwireInverterThingModelIdParamTypeId, result.modelId); descriptor.setParams(params); - descriptors.append(descriptor); + + info->addThingDescriptor(descriptor); } - info->addThingDescriptors(descriptors); info->finish(Thing::ThingErrorNoError); }); @@ -225,7 +235,9 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info) } ParamList params; - params << Param(modbusSolarInverterThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress()); + params << Param(modbusSolarInverterThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress()); + params << Param(modbusSolarInverterThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName()); + params << Param(modbusSolarInverterThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress()); params << Param(modbusSolarInverterThingPortParamTypeId, result.port); params << Param(modbusSolarInverterThingSlaveIdParamTypeId, result.modbusAddress); params << Param(modbusSolarInverterThingSerialNumberParamTypeId, result.serialNumber); @@ -259,7 +271,9 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info) } ParamList params; - params << Param(modbusBatteryInverterThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress()); + params << Param(modbusBatteryInverterThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress()); + params << Param(modbusBatteryInverterThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress()); + params << Param(modbusBatteryInverterThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName()); params << Param(modbusBatteryInverterThingPortParamTypeId, result.port); params << Param(modbusBatteryInverterThingSlaveIdParamTypeId, result.modbusAddress); params << Param(modbusBatteryInverterThingSerialNumberParamTypeId, result.serialNumber); @@ -305,25 +319,42 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info) qCDebug(dcSma()) << "Setup thing" << thing << thing->params(); if (thing->thingClassId() == sunnyWebBoxThingClassId) { - // Check if a Sunny WebBox is already added with this mac address - foreach (SunnyWebBox *sunnyWebBox, m_sunnyWebBoxes.values()) { - if (sunnyWebBox->macAddress() == thing->paramValue(sunnyWebBoxThingMacAddressParamTypeId).toString()){ - qCWarning(dcSma()) << "Thing with mac address" << thing->paramValue(sunnyWebBoxThingMacAddressParamTypeId).toString() << " already added!"; - info->finish(Thing::ThingErrorThingInUse); - return; - } - } if (m_sunnyWebBoxes.contains(thing)) { qCDebug(dcSma()) << "Setup after reconfiguration, cleaning up..."; m_sunnyWebBoxes.take(thing)->deleteLater(); + + if (m_monitors.contains(thing)) { + hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing)); + } } - SunnyWebBox *sunnyWebBox = new SunnyWebBox(hardwareManager()->networkManager(), QHostAddress(thing->paramValue(sunnyWebBoxThingHostParamTypeId).toString()), this); - sunnyWebBox->setMacAddress(thing->paramValue(sunnyWebBoxThingMacAddressParamTypeId).toString()); + NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing); + if (!monitor) { + qCWarning(dcSma()) << "Unable to register monitor with the given params" << thing << 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); + + // Make sure the monitor gets cleaned up when setup gets aborted + connect(info, &ThingSetupInfo::aborted, monitor, [this, thing](){ + if (m_monitors.contains(thing)) { + qCDebug(dcSma()) << "Unregistering monitor because setup has been aborted."; + hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing)); + } + }); + + SunnyWebBox *sunnyWebBox = new SunnyWebBox(hardwareManager()->networkManager(), monitor->networkDeviceInfo().address(), this); connect(info, &ThingSetupInfo::aborted, sunnyWebBox, &SunnyWebBox::deleteLater); connect(sunnyWebBox, &SunnyWebBox::destroyed, this, [thing, this] { m_sunnyWebBoxes.remove(thing);}); + connect(monitor, &NetworkDeviceMonitor::reachableChanged, this, [sunnyWebBox, monitor](bool reachable){ + qCDebug(dcSma()) << "SunnyWebBox: monitor reachable changed" << monitor; + if (reachable) { + sunnyWebBox->setHostAddress(monitor->networkDeviceInfo().address()); + } + }); QString requestId = sunnyWebBox->getPlantOverview(); connect(sunnyWebBox, &SunnyWebBox::plantOverviewReceived, info, [=] (const QString &messageId, SunnyWebBox::Overview overview) { @@ -388,18 +419,36 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info) } else if (thing->thingClassId() == speedwireInverterThingClassId) { - QHostAddress address = QHostAddress(thing->paramValue(speedwireInverterThingHostParamTypeId).toString()); + if (m_speedwireInverters.contains(thing)) { + qCDebug(dcSma()) << "Reconfiguring existing thing" << thing->name(); + m_speedwireInverters.take(thing)->deleteLater(); - // FIXME: use the monitor here since the IP might change + if (m_monitors.contains(thing)) { + hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing)); + } + } + + NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing); + if (!monitor) { + qCWarning(dcSma()) << "Unable to register monitor with the given params" << thing << 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); + + // Make sure the monitor gets cleaned up when setup gets aborted + connect(info, &ThingSetupInfo::aborted, monitor, [this, thing](){ + if (m_monitors.contains(thing)) { + qCDebug(dcSma()) << "Unregistering monitor because setup has been aborted."; + hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing)); + } + }); quint32 serialNumber = static_cast(thing->paramValue(speedwireInverterThingSerialNumberParamTypeId).toUInt()); quint16 modelId = static_cast(thing->paramValue(speedwireInverterThingModelIdParamTypeId).toUInt()); - if (m_speedwireInverters.contains(thing)) { - m_speedwireInverters.take(thing)->deleteLater(); - } - - SpeedwireInverter *inverter = new SpeedwireInverter(getSpeedwireInterface(), address, modelId, serialNumber, this); + SpeedwireInverter *inverter = new SpeedwireInverter(getSpeedwireInterface(), monitor, modelId, serialNumber, this); qCDebug(dcSma()) << "Inverter: Interface initialized successfully."; QString password; @@ -519,15 +568,14 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info) } } - MacAddress macAddress = MacAddress(thing->paramValue(modbusSolarInverterThingMacAddressParamTypeId).toString()); - if (!macAddress.isValid()) { - qCWarning(dcSma()) << "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(dcSma()) << "Unable to register monitor with the given params" << thing << 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(); @@ -571,15 +619,14 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info) } } - MacAddress macAddress = MacAddress(thing->paramValue(modbusBatteryInverterThingMacAddressParamTypeId).toString()); - if (!macAddress.isValid()) { - qCWarning(dcSma()) << "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(dcSma()) << "Unable to register monitor with the given params" << thing << 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(); diff --git a/sma/integrationpluginsma.json b/sma/integrationpluginsma.json index a939ae2..8addaa6 100644 --- a/sma/integrationpluginsma.json +++ b/sma/integrationpluginsma.json @@ -13,15 +13,23 @@ "name": "sunnyWebBox", "displayName": "SMA Sunny WebBox", "createMethods": ["discovery", "user"], - "interfaces": ["solarinverter"], + "interfaces": ["solarinverter", "connectable", "networkdevice"], "paramTypes": [ { "id": "864d4162-e3ce-48b8-b8ac-c1b971b52d42", - "name": "host", + "name": "address", "displayName": "Host address", "type": "QString", "inputType": "IPv4Address", - "defaultValue": "192.168.0.168" + "defaultValue": "" + }, + { + "id": "19e1f60a-f7c3-4e40-b971-7cae25db1def", + "name": "hostName", + "displayName": "Host name", + "type": "QString", + "inputType": "TextLine", + "defaultValue": "" }, { "id": "03f32361-4e13-4597-a346-af8d16a986b3", @@ -30,7 +38,7 @@ "type": "QString", "inputType": "TextLine", "readOnly": true, - "defaultValue": "00:00:00:00:00:00" + "defaultValue": "" } ], "stateTypes": [ @@ -286,15 +294,23 @@ "displayName": "SMA Inverter", "createMethods": ["discovery", "user"], "setupMethod": "EnterPin", - "interfaces": [ "solarinverter", "connectable"], + "interfaces": [ "solarinverter", "connectable", "networkdevice"], "paramTypes": [ { "id": "c8098d53-69eb-4d0b-9f07-e43c4a0ea9a9", - "name": "host", + "name": "address", "displayName": "Host address", "type": "QString", "inputType": "IPv4Address", - "defaultValue": "192.168.0.168" + "defaultValue": "" + }, + { + "id": "d72e1831-04f2-4bd6-a86d-d767e92868ef", + "name": "hostName", + "displayName": "Host name", + "type": "QString", + "inputType": "TextLine", + "defaultValue": "" }, { "id": "7df0ab60-0f11-4495-8e0d-508ba2b6d858", @@ -537,8 +553,24 @@ "name": "modbusSolarInverter", "displayName": "SMA Solar Inverter (Modbus)", "createMethods": ["discovery", "user"], - "interfaces": [ "solarinverter" ], + "interfaces": [ "solarinverter", "connectable", "networkdevice" ], "paramTypes": [ + { + "id": "07720ebe-2e4b-4d8e-a0c0-88ad21879375", + "name": "address", + "displayName": "Host address", + "type": "QString", + "inputType": "IPv4Address", + "defaultValue": "" + }, + { + "id": "e5e420c7-eb99-45c4-bb44-06218ebec8a2", + "name": "hostName", + "displayName": "Host name", + "type": "QString", + "inputType": "TextLine", + "defaultValue": "" + }, { "id": "3cea46a0-9535-4612-9971-19167109e63c", "name":"macAddress", @@ -699,8 +731,24 @@ "name": "modbusBatteryInverter", "displayName": "SMA Battery Inverter (Modbus)", "createMethods": ["discovery", "user"], - "interfaces": [ "energystorage", "connectable" ], + "interfaces": [ "energystorage", "connectable", "networkdevice" ], "paramTypes": [ + { + "id": "75d5d4ec-6f0c-44e8-bc30-a533f4a1001a", + "name": "address", + "displayName": "Host address", + "type": "QString", + "inputType": "IPv4Address", + "defaultValue": "" + }, + { + "id": "8a8a17aa-5e10-4232-bab6-77cc386d59e6", + "name": "hostName", + "displayName": "Host name", + "type": "QString", + "inputType": "TextLine", + "defaultValue": "" + }, { "id": "03a5a009-0edc-4370-924a-785e7fcee30a", "name":"macAddress", diff --git a/sma/modbus/smamodbusbatteryinverterdiscovery.cpp b/sma/modbus/smamodbusbatteryinverterdiscovery.cpp index 94612f6..187603e 100644 --- a/sma/modbus/smamodbusbatteryinverterdiscovery.cpp +++ b/sma/modbus/smamodbusbatteryinverterdiscovery.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2023, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -45,20 +45,20 @@ SmaModbusBatteryInverterDiscovery::SmaModbusBatteryInverterDiscovery(NetworkDevi qCDebug(dcSma()) << "Discovery: Grace period timer triggered."; finishDiscovery(); }); - } void SmaModbusBatteryInverterDiscovery::startDiscovery() { qCInfo(dcSma()) << "Discovery: Searching for SMA battery inverters in the network..."; NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover(); + m_startDateTime = QDateTime::currentDateTime(); - connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &SmaModbusBatteryInverterDiscovery::checkNetworkDevice); - + connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &SmaModbusBatteryInverterDiscovery::checkNetworkDevice); + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater); connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ qCDebug(dcSma()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices"; + m_networkDeviceInfos = discoveryReply->networkDeviceInfos(); m_gracePeriodTimer.start(); - discoveryReply->deleteLater(); }); } @@ -67,11 +67,11 @@ QList SmaModbusBatteryInverterDiscove return m_discoveryResults; } -void SmaModbusBatteryInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo) +void SmaModbusBatteryInverterDiscovery::checkNetworkDevice(const QHostAddress &address) { - qCInfo(dcSma()) << "Checking network device:" << networkDeviceInfo << "Port:" << m_port << "Slave ID:" << m_modbusAddress; + qCInfo(dcSma()) << "Checking network device:" << address << "Port:" << m_port << "Slave ID:" << m_modbusAddress; - SmaBatteryInverterModbusTcpConnection *connection = new SmaBatteryInverterModbusTcpConnection(networkDeviceInfo.address(), m_port, m_modbusAddress, this); + SmaBatteryInverterModbusTcpConnection *connection = new SmaBatteryInverterModbusTcpConnection(address, m_port, m_modbusAddress, this); m_connections.append(connection); connect(connection, &SmaBatteryInverterModbusTcpConnection::reachableChanged, this, [=](bool reachable){ @@ -82,13 +82,13 @@ void SmaModbusBatteryInverterDiscovery::checkNetworkDevice(const NetworkDeviceIn connect(connection, &SmaBatteryInverterModbusTcpConnection::initializationFinished, this, [=](bool success){ if (!success) { - qCInfo(dcSma()) << "Discovery: Initialization failed on" << networkDeviceInfo.address().toString() << "Skipping result...";; + qCInfo(dcSma()) << "Discovery: Initialization failed on" << address.toString() << "Skipping result...";; cleanupConnection(connection); return; } if (connection->deviceClass() != Sma::DeviceClassBatteryInverter) { - qCInfo(dcSma()) << "Discovery: Initialization successful for" << networkDeviceInfo.address().toString() << "but the device class is not a battery inverter. Skipping result...";; + qCInfo(dcSma()) << "Discovery: Initialization successful for" << address.toString() << "but the device class is not a battery inverter. Skipping result...";; cleanupConnection(connection); return; } @@ -99,7 +99,7 @@ void SmaModbusBatteryInverterDiscovery::checkNetworkDevice(const NetworkDeviceIn result.port = m_port; result.modbusAddress = m_modbusAddress; result.softwareVersion = Sma::buildSoftwareVersionString(connection->softwarePackage()); - result.networkDeviceInfo = networkDeviceInfo; + result.address = address; m_discoveryResults.append(result); qCInfo(dcSma()) << "Discovery: --> Found"; @@ -112,18 +112,17 @@ void SmaModbusBatteryInverterDiscovery::checkNetworkDevice(const NetworkDeviceIn }); if (!connection->initialize()) { - qCDebug(dcSma()) << "Discovery: Unable to initialize connection on" << networkDeviceInfo.address().toString(); + qCDebug(dcSma()) << "Discovery: Unable to initialize connection on" << address.toString(); cleanupConnection(connection); } }); connect(connection, &SmaBatteryInverterModbusTcpConnection::checkReachabilityFailed, this, [=](){ - qCDebug(dcSma()) << "Discovery: Checking reachability failed on" << networkDeviceInfo.address().toString(); + qCDebug(dcSma()) << "Discovery: Checking reachability failed on" << address.toString(); cleanupConnection(connection); }); connection->connectDevice(); - } void SmaModbusBatteryInverterDiscovery::cleanupConnection(SmaBatteryInverterModbusTcpConnection *connection) @@ -137,12 +136,16 @@ void SmaModbusBatteryInverterDiscovery::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 (SmaBatteryInverterModbusTcpConnection *connection, m_connections) cleanupConnection(connection); qCInfo(dcSma()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count() - << "SMA battery inverters in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); + << "SMA battery inverters in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); m_gracePeriodTimer.stop(); emit discoveryFinished(); diff --git a/sma/modbus/smamodbusbatteryinverterdiscovery.h b/sma/modbus/smamodbusbatteryinverterdiscovery.h index 053ff9a..e46b6dc 100644 --- a/sma/modbus/smamodbusbatteryinverterdiscovery.h +++ b/sma/modbus/smamodbusbatteryinverterdiscovery.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2023, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -49,6 +49,7 @@ public: int port; int modbusAddress; QString softwareVersion; + QHostAddress address; NetworkDeviceInfo networkDeviceInfo; }; @@ -67,11 +68,11 @@ private: QTimer m_gracePeriodTimer; QDateTime m_startDateTime; + NetworkDeviceInfos m_networkDeviceInfos; QList m_connections; - QList m_discoveryResults; - void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo); + void checkNetworkDevice(const QHostAddress &address); void cleanupConnection(SmaBatteryInverterModbusTcpConnection *connection); void finishDiscovery(); diff --git a/sma/modbus/smamodbussolarinverterdiscovery.cpp b/sma/modbus/smamodbussolarinverterdiscovery.cpp index c7150a1..3bc8b74 100644 --- a/sma/modbus/smamodbussolarinverterdiscovery.cpp +++ b/sma/modbus/smamodbussolarinverterdiscovery.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2022, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -36,9 +36,9 @@ SmaModbusSolarInverterDiscovery::SmaModbusSolarInverterDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, quint16 port, quint16 modbusAddress,QObject *parent) : QObject{parent}, - m_networkDeviceDiscovery{networkDeviceDiscovery}, - m_port{port}, - m_modbusAddress{modbusAddress} + m_networkDeviceDiscovery{networkDeviceDiscovery}, + m_port{port}, + m_modbusAddress{modbusAddress} { } @@ -47,21 +47,14 @@ void SmaModbusSolarInverterDiscovery::startDiscovery() { qCInfo(dcSma()) << "Discovery: Start searching for SMA modbus inverters in the network..."; NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover(); + m_startDateTime = QDateTime::currentDateTime(); // Imedialty check any new device gets discovered - connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &SmaModbusSolarInverterDiscovery::checkNetworkDevice); - - // Check what might be left on finished + connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &SmaModbusSolarInverterDiscovery::checkNetworkDevice); connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater); - connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [this, discoveryReply](){ qCDebug(dcSma()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices"; - - // Send a report request to nework device info not sent already... - foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) { - if (!m_verifiedNetworkDeviceInfos.contains(networkDeviceInfo)) { - checkNetworkDevice(networkDeviceInfo); - } - } + 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](){ @@ -76,19 +69,10 @@ QList SmaModbusSolarI return m_discoveryResults; } -void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo) +void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const QHostAddress &address) { - // Create a kostal connection and try to initialize it. - // Only if initialized successfully and all information have been fetched correctly from - // the device we can assume this is what we are locking for (ip, port, modbus address, correct registers). - // We cloud tough also filter the result only for certain software versions, manufactueres or whatever... - - if (m_verifiedNetworkDeviceInfos.contains(networkDeviceInfo)) - return; - - SmaSolarInverterModbusTcpConnection *connection = new SmaSolarInverterModbusTcpConnection(networkDeviceInfo.address(), m_port, m_modbusAddress, this); + SmaSolarInverterModbusTcpConnection *connection = new SmaSolarInverterModbusTcpConnection(address, m_port, m_modbusAddress, this); m_connections.append(connection); - m_verifiedNetworkDeviceInfos.append(networkDeviceInfo); connect(connection, &SmaSolarInverterModbusTcpConnection::reachableChanged, this, [=](bool reachable){ if (!reachable) { @@ -100,13 +84,13 @@ void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo // Modbus TCP connected...ok, let's try to initialize it! connect(connection, &SmaSolarInverterModbusTcpConnection::initializationFinished, this, [=](bool success){ if (!success) { - qCDebug(dcSma()) << "Discovery: Initialization failed on" << networkDeviceInfo.address().toString() << "Continue...";; + qCDebug(dcSma()) << "Discovery: Initialization failed on" << address.toString() << "Continue...";; cleanupConnection(connection); return; } if (connection->deviceClass() != Sma::DeviceClassSolarInverter) { - qCDebug(dcSma()) << "Discovery: Initialization successfull for" << networkDeviceInfo.address().toString() << "but the device class is not an inverter. Continue...";; + qCDebug(dcSma()) << "Discovery: Initialization successfull for" << address.toString() << "but the device class is not an inverter. Continue...";; cleanupConnection(connection); return; } @@ -118,14 +102,14 @@ void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo result.port = m_port; result.modbusAddress = m_modbusAddress; result.softwareVersion = Sma::buildSoftwareVersionString(connection->softwarePackage()); - result.networkDeviceInfo = networkDeviceInfo; + result.address = address; m_discoveryResults.append(result); qCDebug(dcSma()) << "Discovery: --> Found" << result.productName; - qCDebug(dcSma()) << "Discovery: Device name:" << result.deviceName; - qCDebug(dcSma()) << "Discovery: Serial number:" << result.serialNumber; - qCDebug(dcSma()) << "Discovery: Software version:" << result.softwareVersion; - qCDebug(dcSma()) << "Discovery: " << result.networkDeviceInfo; + qCDebug(dcSma()) << "Discovery: Device name:" << result.deviceName; + qCDebug(dcSma()) << "Discovery: Serial number:" << result.serialNumber; + qCDebug(dcSma()) << "Discovery: Software version:" << result.softwareVersion; + qCDebug(dcSma()) << "Discovery:" << result.networkDeviceInfo; // Done with this connection cleanupConnection(connection); @@ -133,7 +117,7 @@ void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo // Initializing... if (!connection->initialize()) { - qCDebug(dcSma()) << "Discovery: Unable to initialize connection on" << networkDeviceInfo.address().toString() << "Continue...";; + qCDebug(dcSma()) << "Discovery: Unable to initialize connection on" << address.toString() << "Continue...";; cleanupConnection(connection); } }); @@ -141,14 +125,14 @@ void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo // If we get any error...skip this host... connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionErrorOccurred, this, [=](QModbusDevice::Error error){ if (error != QModbusDevice::NoError) { - qCDebug(dcSma()) << "Discovery: Connection error on" << networkDeviceInfo.address().toString() << "Continue...";; + qCDebug(dcSma()) << "Discovery: Connection error on" << address.toString() << "Continue...";; cleanupConnection(connection); } }); // If check reachability failed...skip this host... connect(connection, &SmaSolarInverterModbusTcpConnection::checkReachabilityFailed, this, [=](){ - qCDebug(dcSma()) << "Discovery: Check reachability failed on" << networkDeviceInfo.address().toString() << "Continue...";; + qCDebug(dcSma()) << "Discovery: Check reachability failed on" << address.toString() << "Continue...";; cleanupConnection(connection); }); @@ -167,10 +151,15 @@ void SmaModbusSolarInverterDiscovery::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 (SmaSolarInverterModbusTcpConnection *connection, m_connections) cleanupConnection(connection); - qCInfo(dcSma()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count() << "SMA inverters in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); + qCInfo(dcSma()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count() + << "SMA inverters in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); emit discoveryFinished(); } diff --git a/sma/modbus/smamodbussolarinverterdiscovery.h b/sma/modbus/smamodbussolarinverterdiscovery.h index e79de9e..a6f242a 100644 --- a/sma/modbus/smamodbussolarinverterdiscovery.h +++ b/sma/modbus/smamodbussolarinverterdiscovery.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2022, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -50,6 +50,7 @@ public: quint16 port; quint16 modbusAddress; QString softwareVersion; + QHostAddress address; NetworkDeviceInfo networkDeviceInfo; } SmaModbusDiscoveryResult; @@ -64,15 +65,13 @@ private: NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr; quint16 m_port; quint16 m_modbusAddress; - QDateTime m_startDateTime; - NetworkDeviceInfos m_verifiedNetworkDeviceInfos; + NetworkDeviceInfos m_networkDeviceInfos; QList m_connections; - QList m_discoveryResults; - void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo); + void checkNetworkDevice(const QHostAddress &address); void cleanupConnection(SmaSolarInverterModbusTcpConnection *connection); void finishDiscovery(); diff --git a/sma/speedwire/speedwirediscovery.cpp b/sma/speedwire/speedwirediscovery.cpp index 023836d..d6693a3 100644 --- a/sma/speedwire/speedwirediscovery.cpp +++ b/sma/speedwire/speedwirediscovery.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2022, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -96,7 +96,6 @@ void SpeedwireDiscovery::startMulticastDiscovery() sendDiscoveryRequest(); } - void SpeedwireDiscovery::startUnicastDiscovery() { qCDebug(dcSma()) << "SpeedwireDiscovery: Start discovering network..."; @@ -104,13 +103,12 @@ void SpeedwireDiscovery::startUnicastDiscovery() NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover(); connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater); - connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, [this](const NetworkDeviceInfo &networkDeviceInfo){ - m_networkDeviceInfos.append(networkDeviceInfo); - sendUnicastDiscoveryRequest(networkDeviceInfo.address()); - }); - - connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ + connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &SpeedwireDiscovery::sendUnicastDiscoveryRequest); + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [this, discoveryReply](){ qCDebug(dcSma()) << "Discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices for unicast requests."; + + m_networkDeviceInfos = discoveryReply->networkDeviceInfos(); + // Wait some extra second in otder to give the last hosts joined some time to respond. QTimer::singleShot(3000, this, [this](){ m_multicastSearchRequestTimer.stop(); @@ -178,10 +176,6 @@ void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quin m_resultMeters.insert(senderAddress, result); } - if (m_networkDeviceInfos.hasHostAddress(senderAddress)) { - m_resultMeters[senderAddress].networkDeviceInfo = m_networkDeviceInfos.get(senderAddress); - } - m_resultMeters[senderAddress].modelId = modelId; m_resultMeters[senderAddress].serialNumber = serialNumber; } else if (header.protocolId == Speedwire::ProtocolIdInverter) { @@ -196,10 +190,6 @@ void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quin m_resultInverters.insert(senderAddress, result); } - if (m_networkDeviceInfos.hasHostAddress(senderAddress)) { - m_resultInverters[senderAddress].networkDeviceInfo = m_networkDeviceInfos.get(senderAddress); - } - m_resultInverters[senderAddress].modelId = inverterPacket.sourceModelId; m_resultInverters[senderAddress].serialNumber = inverterPacket.sourceSerialNumber; @@ -218,11 +208,11 @@ void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quin connect(reply, &SpeedwireInverterReply::finished, this, [/*this, inverter,*/ senderAddress, reply](){ qCDebug(dcSma()) << "SpeedwireDiscovery: Identify request finished from" << senderAddress.toString() << reply->error(); -// SpeedwireInverterReply *loginReply = inverter->sendLoginRequest(); -// qCDebug(dcSma()) << "SpeedwireDiscovery: make login attempt using the default password."; -// connect(loginReply, &SpeedwireInverterReply::finished, this, [loginReply, senderAddress](){ -// qCDebug(dcSma()) << "SpeedwireDiscovery: login attempt finished" << senderAddress.toString() << loginReply->error(); -// }); + // SpeedwireInverterReply *loginReply = inverter->sendLoginRequest(); + // qCDebug(dcSma()) << "SpeedwireDiscovery: make login attempt using the default password."; + // connect(loginReply, &SpeedwireInverterReply::finished, this, [loginReply, senderAddress](){ + // qCDebug(dcSma()) << "SpeedwireDiscovery: login attempt finished" << senderAddress.toString() << loginReply->error(); + // }); }); } else { @@ -248,6 +238,10 @@ void SpeedwireDiscovery::finishDiscovery() { m_results = m_resultMeters.values() + m_resultInverters.values(); + // 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); + qCDebug(dcSma()) << "SpeedwireDiscovery: Discovey finished. Found" << m_results.count() << "SMA devices in the network"; m_multicastSearchRequestTimer.stop(); @@ -255,13 +249,11 @@ void SpeedwireDiscovery::finishDiscovery() qCDebug(dcSma()) << "SpeedwireDiscovery: ============================================"; qCDebug(dcSma()) << "SpeedwireDiscovery: Device type:" << result.deviceType; qCDebug(dcSma()) << "SpeedwireDiscovery: Address:" << result.address.toString(); - if (result.networkDeviceInfo.isValid()) { - qCDebug(dcSma()) << "SpeedwireDiscovery: Hostname:" << result.networkDeviceInfo.hostName(); - qCDebug(dcSma()) << "SpeedwireDiscovery: MAC:" << result.networkDeviceInfo.macAddress(); - qCDebug(dcSma()) << "SpeedwireDiscovery: MAC manufacturer:" << result.networkDeviceInfo.macAddressManufacturer(); - } qCDebug(dcSma()) << "SpeedwireDiscovery: Model ID:" << result.modelId; qCDebug(dcSma()) << "SpeedwireDiscovery: Serial number:" << result.serialNumber; + if (result.networkDeviceInfo.isValid()) { + qCDebug(dcSma()) << "SpeedwireDiscovery:" << result.networkDeviceInfo; + } } emit discoveryFinished(); diff --git a/sma/speedwire/speedwirediscovery.h b/sma/speedwire/speedwirediscovery.h index d9ef586..72083d6 100644 --- a/sma/speedwire/speedwirediscovery.h +++ b/sma/speedwire/speedwirediscovery.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2022, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. diff --git a/sma/speedwire/speedwireinverter.cpp b/sma/speedwire/speedwireinverter.cpp index 3024026..d36eb0e 100644 --- a/sma/speedwire/speedwireinverter.cpp +++ b/sma/speedwire/speedwireinverter.cpp @@ -33,17 +33,43 @@ #include -SpeedwireInverter::SpeedwireInverter(SpeedwireInterface *speedwireInterface, const QHostAddress &address, quint16 modelId, quint32 serialNumber, QObject *parent) : - QObject(parent), - m_speedwireInterface(speedwireInterface), - m_address(address), - m_modelId(modelId), - m_serialNumber(serialNumber) +SpeedwireInverter::SpeedwireInverter(SpeedwireInterface *speedwireInterface, NetworkDeviceMonitor *monitor, quint16 modelId, quint32 serialNumber, QObject *parent) + : QObject{parent}, + m_speedwireInterface{speedwireInterface}, + m_monitor{monitor}, + m_modelId{modelId}, + m_serialNumber{serialNumber} +{ + if (!m_monitor->networkDeviceInfo().address().isNull()) + m_address = m_monitor->networkDeviceInfo().address(); + + qCDebug(dcSma()) << "Inverter: setup interface on" << m_monitor; + connect(m_monitor, &NetworkDeviceMonitor::reachableChanged, this, [this](bool reachable){ + qCDebug(dcSma()) << "Inverter: reachable changed" << m_monitor; + if (reachable) { + m_address = m_monitor->networkDeviceInfo().address(); + } + }); + + connect(m_speedwireInterface, &SpeedwireInterface::dataReceived, this, &SpeedwireInverter::processData); +} + +SpeedwireInverter::SpeedwireInverter(SpeedwireInterface *speedwireInterface, const QHostAddress &address, quint16 modelId, quint32 serialNumber, QObject *parent) + : QObject{parent}, + m_speedwireInterface{speedwireInterface}, + m_address{address}, + m_modelId{modelId}, + m_serialNumber{serialNumber} { qCDebug(dcSma()) << "Inverter: setup interface on" << m_address.toString(); connect(m_speedwireInterface, &SpeedwireInterface::dataReceived, this, &SpeedwireInverter::processData); } +NetworkDeviceMonitor *SpeedwireInverter::monitor() const +{ + return m_monitor; +} + SpeedwireInverter::State SpeedwireInverter::state() const { return m_state; diff --git a/sma/speedwire/speedwireinverter.h b/sma/speedwire/speedwireinverter.h index b6b0ed6..624cae5 100644 --- a/sma/speedwire/speedwireinverter.h +++ b/sma/speedwire/speedwireinverter.h @@ -34,12 +34,15 @@ #include #include +#include + #include "sma.h" #include "speedwire.h" #include "speedwireinterface.h" #include "speedwireinverterreply.h" #include "speedwireinverterrequest.h" + class SpeedwireInverter : public QObject { Q_OBJECT @@ -54,8 +57,11 @@ public: }; Q_ENUM(State) + explicit SpeedwireInverter(SpeedwireInterface *speedwireInterface, NetworkDeviceMonitor *monitor, quint16 modelId, quint32 serialNumber, QObject *parent = nullptr); explicit SpeedwireInverter(SpeedwireInterface *speedwireInterface, const QHostAddress &address, quint16 modelId, quint32 serialNumber, QObject *parent = nullptr); + NetworkDeviceMonitor *monitor() const; + State state() const; bool reachable() const; @@ -122,6 +128,7 @@ signals: private: SpeedwireInterface *m_speedwireInterface = nullptr; + NetworkDeviceMonitor *m_monitor = nullptr; QHostAddress m_address; QString m_password; diff --git a/sma/sunnywebbox/sunnywebbox.cpp b/sma/sunnywebbox/sunnywebbox.cpp index 3f59d9a..d6d4db2 100644 --- a/sma/sunnywebbox/sunnywebbox.cpp +++ b/sma/sunnywebbox/sunnywebbox.cpp @@ -31,9 +31,9 @@ #include "sunnywebbox.h" #include "extern-plugininfo.h" -#include "QJsonDocument" -#include "QJsonObject" -#include "QJsonArray" +#include +#include +#include SunnyWebBox::SunnyWebBox(NetworkAccessManager *networkAccessManager, const QHostAddress &hostAddress, QObject *parrent) : QObject(parrent), @@ -142,16 +142,6 @@ void SunnyWebBox::setHostAddress(const QHostAddress &address) m_hostAddresss = address; } -QString SunnyWebBox::macAddress() const -{ - return m_macAddress; -} - -void SunnyWebBox::setMacAddress(const QString &macAddress) -{ - m_macAddress = macAddress; -} - QNetworkReply *SunnyWebBox::sendRequest(const QHostAddress &address, const QString &procedure, const QJsonObject ¶ms, const QString &requestId) { qCDebug(dcSma()) << "SunnyWebBox: Send message to" << address.toString() << "Procedure:" << procedure << "Params:" << params; diff --git a/sma/sunnywebbox/sunnywebbox.h b/sma/sunnywebbox/sunnywebbox.h index da28985..552b06d 100644 --- a/sma/sunnywebbox/sunnywebbox.h +++ b/sma/sunnywebbox/sunnywebbox.h @@ -31,8 +31,8 @@ #ifndef SUNNYWEBBOX_H #define SUNNYWEBBOX_H -#include "integrations/thing.h" -#include "network/networkaccessmanager.h" +#include +#include #include #include @@ -88,9 +88,6 @@ public: QHostAddress hostAddress() const; void setHostAddress(const QHostAddress &address); - QString macAddress() const; - void setMacAddress(const QString &macAddress); - QNetworkReply *sendRequest(const QHostAddress &address, const QString &procedure, const QJsonObject ¶ms = QJsonObject(), const QString &requestId = QString()); static QString generateRequestId(); @@ -99,7 +96,6 @@ private: NetworkAccessManager *m_networkManager = nullptr; bool m_connected = false; QHostAddress m_hostAddresss; - QString m_macAddress; QDateTime m_lastRequest; QString sendMessage(const QHostAddress &address, const QString &procedure); diff --git a/sma/sunnywebbox/sunnywebboxdiscovery.cpp b/sma/sunnywebbox/sunnywebboxdiscovery.cpp index f9a1f76..575781b 100644 --- a/sma/sunnywebbox/sunnywebboxdiscovery.cpp +++ b/sma/sunnywebbox/sunnywebboxdiscovery.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2022, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -46,8 +46,8 @@ SunnyWebBoxDiscovery::SunnyWebBoxDiscovery(NetworkAccessManager *networkAccessMa void SunnyWebBoxDiscovery::startDiscovery() { // Clean up + m_discoveredHosts.clear(); m_discoveryResults.clear(); - m_verifiedNetworkDeviceInfos.clear(); m_startDateTime = QDateTime::currentDateTime(); @@ -55,23 +55,14 @@ void SunnyWebBoxDiscovery::startDiscovery() m_discoveryReply = m_networkDeviceDiscovery->discover(); // Test any network device beeing discovered - connect(m_discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &SunnyWebBoxDiscovery::checkNetworkDevice); - - // When the network discovery has finished, we process the rest and give some time to finish the pending replies + connect(m_discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &SunnyWebBoxDiscovery::checkNetworkDevice); connect(m_discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ // The network device discovery is done - m_discoveredNetworkDeviceInfos = m_discoveryReply->networkDeviceInfos(); + m_networkDeviceInfos = m_discoveryReply->networkDeviceInfos(); + m_discoveryReply->deleteLater(); m_discoveryReply = nullptr; - // Check if all network device infos have been verified - foreach (const NetworkDeviceInfo &networkDeviceInfo, m_discoveredNetworkDeviceInfos) { - if (m_verifiedNetworkDeviceInfos.contains(networkDeviceInfo)) - continue; - - checkNetworkDevice(networkDeviceInfo); - } - // If there might be some response after the grace period time, // we don't care any more since there might just waiting for some timeouts... // If there would be a device, if would have responded. @@ -87,16 +78,11 @@ NetworkDeviceInfos SunnyWebBoxDiscovery::discoveryResults() const return m_discoveryResults; } -void SunnyWebBoxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo) +void SunnyWebBoxDiscovery::checkNetworkDevice(const QHostAddress &address) { - if (m_verifiedNetworkDeviceInfos.contains(networkDeviceInfo)) - return; - - m_verifiedNetworkDeviceInfos.append(networkDeviceInfo); - // Make a simple request and verify if it worked and the expected data gets returned. - SunnyWebBox webBox(m_networkAccessManager, networkDeviceInfo.address(), this); - QNetworkReply *reply = webBox.sendRequest(networkDeviceInfo.address(), "GetPlantOverview"); + SunnyWebBox webBox(m_networkAccessManager, address, this); + QNetworkReply *reply = webBox.sendRequest(address, "GetPlantOverview"); m_pendingReplies.append(reply); connect(reply, &QNetworkReply::finished, this, [=](){ m_pendingReplies.removeAll(reply); @@ -104,7 +90,7 @@ void SunnyWebBoxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDe // Check HTTP reply if (reply->error() != QNetworkReply::NoError) { - qCDebug(dcSma()) << "Discovery: SunnyWebBox: Checked" << networkDeviceInfo.address().toString() + qCDebug(dcSma()) << "Discovery: SunnyWebBox: Checked" << address.toString() << "and a HTTP error occurred:" << reply->errorString() << "Continue..."; return; } @@ -115,28 +101,28 @@ void SunnyWebBoxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDe QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) { - qCDebug(dcSma()) << "Discovery: SunnyWebBox: Checked" << networkDeviceInfo.address().toString() + qCDebug(dcSma()) << "Discovery: SunnyWebBox: Checked" << address.toString() << "and received invalid JSON data:" << error.errorString() << "Continue..."; return; } if (!jsonDoc.isObject()) { - qCDebug(dcSma()) << "Discovery: SunnyWebBox: Response JSON is not an Object" << networkDeviceInfo.address().toString() << "Continue..."; + qCDebug(dcSma()) << "Discovery: SunnyWebBox: Response JSON is not an Object" << address.toString() << "Continue..."; return; } QVariantMap map = jsonDoc.toVariant().toMap(); if (map["version"] != "1.0") { - qCDebug(dcSma()) << "Discovery: SunnyWebBox: API version not supported on" << networkDeviceInfo.address().toString() << "Continue...";; + qCDebug(dcSma()) << "Discovery: SunnyWebBox: API version not supported on" << address.toString() << "Continue...";; return; } if (map.contains("proc") && map.contains("result")) { // Ok, seems to be a Sunny WebBox we are talking to...add to the discovery results... - qCDebug(dcSma()) << "Discovery: SunnyWebBox: --> Found Sunny WebBox on" << networkDeviceInfo; - m_discoveryResults.append(networkDeviceInfo); + qCDebug(dcSma()) << "Discovery: SunnyWebBox: --> Found Sunny WebBox on" << address; + m_discoveredHosts.append(address); } else { - qCDebug(dcSma()) << "Discovery: SunnyWebBox: Missing proc or result value in response from" << networkDeviceInfo.address().toString() << "Continue..."; + qCDebug(dcSma()) << "Discovery: SunnyWebBox: Missing proc or result value in response from" << address.toString() << "Continue..."; return; } }); @@ -152,6 +138,10 @@ void SunnyWebBoxDiscovery::cleanupPendingReplies() void SunnyWebBoxDiscovery::finishDiscovery() { qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch(); + + foreach (const QHostAddress &address, m_discoveredHosts) + m_discoveryResults.append(m_networkDeviceInfos.get(address)); + qCInfo(dcSma()) << "Discovery: SunnyWebBox: Finished the discovery process. Found" << m_discoveryResults.count() << "Sunny WebBoxes in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz"); diff --git a/sma/sunnywebbox/sunnywebboxdiscovery.h b/sma/sunnywebbox/sunnywebboxdiscovery.h index 066e4cd..512e06c 100644 --- a/sma/sunnywebbox/sunnywebboxdiscovery.h +++ b/sma/sunnywebbox/sunnywebboxdiscovery.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2022, nymea GmbH +* Copyright 2013 - 2024, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -50,7 +50,7 @@ signals: void discoveryFinished(); private slots: - void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo); + void checkNetworkDevice(const QHostAddress &address); void cleanupPendingReplies(); void finishDiscovery(); @@ -59,9 +59,9 @@ private: NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr; NetworkDeviceDiscoveryReply *m_discoveryReply = nullptr; + QList m_discoveredHosts; NetworkDeviceInfos m_discoveryResults; - NetworkDeviceInfos m_discoveredNetworkDeviceInfos; - NetworkDeviceInfos m_verifiedNetworkDeviceInfos; + NetworkDeviceInfos m_networkDeviceInfos; QDateTime m_startDateTime; QList m_pendingReplies;