SMA: Update to networkdevice interface

This commit is contained in:
Simon Stürz 2024-12-18 15:04:52 +01:00
parent 36f9f3c512
commit f3b51cae4d
14 changed files with 295 additions and 207 deletions

View File

@ -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<quint32>(thing->paramValue(speedwireInverterThingSerialNumberParamTypeId).toUInt());
quint16 modelId = static_cast<quint16>(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();

View File

@ -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",

View File

@ -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<SmaModbusBatteryInverterDiscovery::Result> 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();

View File

@ -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<SmaBatteryInverterModbusTcpConnection *> m_connections;
QList<Result> m_discoveryResults;
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
void checkNetworkDevice(const QHostAddress &address);
void cleanupConnection(SmaBatteryInverterModbusTcpConnection *connection);
void finishDiscovery();

View File

@ -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<SmaModbusSolarInverterDiscovery::SmaModbusDiscoveryResult> 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();
}

View File

@ -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<SmaSolarInverterModbusTcpConnection *> m_connections;
QList<SmaModbusDiscoveryResult> m_discoveryResults;
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
void checkNetworkDevice(const QHostAddress &address);
void cleanupConnection(SmaSolarInverterModbusTcpConnection *connection);
void finishDiscovery();

View File

@ -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();

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, nymea GmbH
* Copyright 2013 - 2024, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.

View File

@ -33,17 +33,43 @@
#include <QDateTime>
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;

View File

@ -34,12 +34,15 @@
#include <QObject>
#include <QQueue>
#include <network/networkdevicemonitor.h>
#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;

View File

@ -31,9 +31,9 @@
#include "sunnywebbox.h"
#include "extern-plugininfo.h"
#include "QJsonDocument"
#include "QJsonObject"
#include "QJsonArray"
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
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 &params, const QString &requestId)
{
qCDebug(dcSma()) << "SunnyWebBox: Send message to" << address.toString() << "Procedure:" << procedure << "Params:" << params;

View File

@ -31,8 +31,8 @@
#ifndef SUNNYWEBBOX_H
#define SUNNYWEBBOX_H
#include "integrations/thing.h"
#include "network/networkaccessmanager.h"
#include <integrations/thing.h>
#include <network/networkaccessmanager.h>
#include <QObject>
#include <QJsonObject>
@ -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 &params = 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);

View File

@ -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");

View File

@ -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<QHostAddress> m_discoveredHosts;
NetworkDeviceInfos m_discoveryResults;
NetworkDeviceInfos m_discoveredNetworkDeviceInfos;
NetworkDeviceInfos m_verifiedNetworkDeviceInfos;
NetworkDeviceInfos m_networkDeviceInfos;
QDateTime m_startDateTime;
QList<QNetworkReply *> m_pendingReplies;