SMA: Update to networkdevice interface
This commit is contained in:
parent
36f9f3c512
commit
f3b51cae4d
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2023, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -64,28 +64,39 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
webBoxDiscovery->deleteLater();
|
webBoxDiscovery->deleteLater();
|
||||||
ThingDescriptors descriptors;
|
ThingDescriptors descriptors;
|
||||||
foreach (const NetworkDeviceInfo &networkDeviceInfo, webBoxDiscovery->discoveryResults()) {
|
foreach (const NetworkDeviceInfo &networkDeviceInfo, webBoxDiscovery->discoveryResults()) {
|
||||||
QString title = "SMA Sunny WebBox (" + networkDeviceInfo.address().toString() + ")";
|
QString title = "SMA Sunny WebBox";
|
||||||
QString description;
|
QString description;
|
||||||
if (networkDeviceInfo.macAddressManufacturer().isEmpty()) {
|
MacAddressInfo macInfo;
|
||||||
description = networkDeviceInfo.macAddress();
|
switch (networkDeviceInfo.monitorMode()) {
|
||||||
} else {
|
case NetworkDeviceInfo::MonitorModeMac:
|
||||||
description = networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")";
|
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);
|
ThingDescriptor descriptor(sunnyWebBoxThingClassId, title, description);
|
||||||
|
|
||||||
// Check for reconfiguration
|
ParamList params;
|
||||||
foreach (Thing *existingThing, myThings()) {
|
params << Param(sunnyWebBoxThingAddressParamTypeId, networkDeviceInfo.thingParamValueAddress());
|
||||||
if (existingThing->paramValue(sunnyWebBoxThingMacAddressParamTypeId).toString() == networkDeviceInfo.macAddress()) {
|
params << Param(sunnyWebBoxThingHostNameParamTypeId, networkDeviceInfo.thingParamValueHostName());
|
||||||
descriptor.setThingId(existingThing->id());
|
params << Param(sunnyWebBoxThingMacAddressParamTypeId, networkDeviceInfo.thingParamValueMacAddress());
|
||||||
break;
|
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);
|
descriptors.append(descriptor);
|
||||||
}
|
}
|
||||||
info->addThingDescriptors(descriptors);
|
info->addThingDescriptors(descriptors);
|
||||||
@ -163,8 +174,6 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
connect(speedwireDiscovery, &SpeedwireDiscovery::discoveryFinished, this, [=](){
|
connect(speedwireDiscovery, &SpeedwireDiscovery::discoveryFinished, this, [=](){
|
||||||
qCDebug(dcSma()) << "Speed wire discovery finished.";
|
qCDebug(dcSma()) << "Speed wire discovery finished.";
|
||||||
speedwireDiscovery->deleteLater();
|
speedwireDiscovery->deleteLater();
|
||||||
|
|
||||||
ThingDescriptors descriptors;
|
|
||||||
foreach (const SpeedwireDiscovery::SpeedwireDiscoveryResult &result, speedwireDiscovery->discoveryResult()) {
|
foreach (const SpeedwireDiscovery::SpeedwireDiscoveryResult &result, speedwireDiscovery->discoveryResult()) {
|
||||||
|
|
||||||
if (result.deviceType != Speedwire::DeviceTypeInverter)
|
if (result.deviceType != Speedwire::DeviceTypeInverter)
|
||||||
@ -188,15 +197,16 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params << Param(speedwireInverterThingHostParamTypeId, result.address.toString());
|
params << Param(speedwireInverterThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress());
|
||||||
params << Param(speedwireInverterThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress());
|
params << Param(speedwireInverterThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName());
|
||||||
|
params << Param(speedwireInverterThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress());
|
||||||
params << Param(speedwireInverterThingSerialNumberParamTypeId, result.serialNumber);
|
params << Param(speedwireInverterThingSerialNumberParamTypeId, result.serialNumber);
|
||||||
params << Param(speedwireInverterThingModelIdParamTypeId, result.modelId);
|
params << Param(speedwireInverterThingModelIdParamTypeId, result.modelId);
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
descriptors.append(descriptor);
|
|
||||||
|
info->addThingDescriptor(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
info->addThingDescriptors(descriptors);
|
|
||||||
info->finish(Thing::ThingErrorNoError);
|
info->finish(Thing::ThingErrorNoError);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -225,7 +235,9 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ParamList params;
|
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(modbusSolarInverterThingPortParamTypeId, result.port);
|
||||||
params << Param(modbusSolarInverterThingSlaveIdParamTypeId, result.modbusAddress);
|
params << Param(modbusSolarInverterThingSlaveIdParamTypeId, result.modbusAddress);
|
||||||
params << Param(modbusSolarInverterThingSerialNumberParamTypeId, result.serialNumber);
|
params << Param(modbusSolarInverterThingSerialNumberParamTypeId, result.serialNumber);
|
||||||
@ -259,7 +271,9 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ParamList params;
|
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(modbusBatteryInverterThingPortParamTypeId, result.port);
|
||||||
params << Param(modbusBatteryInverterThingSlaveIdParamTypeId, result.modbusAddress);
|
params << Param(modbusBatteryInverterThingSlaveIdParamTypeId, result.modbusAddress);
|
||||||
params << Param(modbusBatteryInverterThingSerialNumberParamTypeId, result.serialNumber);
|
params << Param(modbusBatteryInverterThingSerialNumberParamTypeId, result.serialNumber);
|
||||||
@ -305,25 +319,42 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||||||
qCDebug(dcSma()) << "Setup thing" << thing << thing->params();
|
qCDebug(dcSma()) << "Setup thing" << thing << thing->params();
|
||||||
|
|
||||||
if (thing->thingClassId() == sunnyWebBoxThingClassId) {
|
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)) {
|
if (m_sunnyWebBoxes.contains(thing)) {
|
||||||
qCDebug(dcSma()) << "Setup after reconfiguration, cleaning up...";
|
qCDebug(dcSma()) << "Setup after reconfiguration, cleaning up...";
|
||||||
m_sunnyWebBoxes.take(thing)->deleteLater();
|
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);
|
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
|
||||||
sunnyWebBox->setMacAddress(thing->paramValue(sunnyWebBoxThingMacAddressParamTypeId).toString());
|
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(info, &ThingSetupInfo::aborted, sunnyWebBox, &SunnyWebBox::deleteLater);
|
||||||
connect(sunnyWebBox, &SunnyWebBox::destroyed, this, [thing, this] { m_sunnyWebBoxes.remove(thing);});
|
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();
|
QString requestId = sunnyWebBox->getPlantOverview();
|
||||||
connect(sunnyWebBox, &SunnyWebBox::plantOverviewReceived, info, [=] (const QString &messageId, SunnyWebBox::Overview overview) {
|
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) {
|
} 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());
|
quint32 serialNumber = static_cast<quint32>(thing->paramValue(speedwireInverterThingSerialNumberParamTypeId).toUInt());
|
||||||
quint16 modelId = static_cast<quint16>(thing->paramValue(speedwireInverterThingModelIdParamTypeId).toUInt());
|
quint16 modelId = static_cast<quint16>(thing->paramValue(speedwireInverterThingModelIdParamTypeId).toUInt());
|
||||||
|
|
||||||
if (m_speedwireInverters.contains(thing)) {
|
SpeedwireInverter *inverter = new SpeedwireInverter(getSpeedwireInterface(), monitor, modelId, serialNumber, this);
|
||||||
m_speedwireInverters.take(thing)->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
SpeedwireInverter *inverter = new SpeedwireInverter(getSpeedwireInterface(), address, modelId, serialNumber, this);
|
|
||||||
qCDebug(dcSma()) << "Inverter: Interface initialized successfully.";
|
qCDebug(dcSma()) << "Inverter: Interface initialized successfully.";
|
||||||
|
|
||||||
QString password;
|
QString password;
|
||||||
@ -519,15 +568,14 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MacAddress macAddress = MacAddress(thing->paramValue(modbusSolarInverterThingMacAddressParamTypeId).toString());
|
// Create the monitor
|
||||||
if (!macAddress.isValid()) {
|
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
|
||||||
qCWarning(dcSma()) << "The configured mac address is not valid" << thing->params();
|
if (!monitor) {
|
||||||
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The MAC address is not known. Please reconfigure the thing."));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the monitor
|
|
||||||
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress);
|
|
||||||
m_monitors.insert(thing, monitor);
|
m_monitors.insert(thing, monitor);
|
||||||
|
|
||||||
QHostAddress address = monitor->networkDeviceInfo().address();
|
QHostAddress address = monitor->networkDeviceInfo().address();
|
||||||
@ -571,15 +619,14 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MacAddress macAddress = MacAddress(thing->paramValue(modbusBatteryInverterThingMacAddressParamTypeId).toString());
|
// Create the monitor
|
||||||
if (!macAddress.isValid()) {
|
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
|
||||||
qCWarning(dcSma()) << "The configured mac address is not valid" << thing->params();
|
if (!monitor) {
|
||||||
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The MAC address is not known. Please reconfigure the thing."));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the monitor
|
|
||||||
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress);
|
|
||||||
m_monitors.insert(thing, monitor);
|
m_monitors.insert(thing, monitor);
|
||||||
|
|
||||||
QHostAddress address = monitor->networkDeviceInfo().address();
|
QHostAddress address = monitor->networkDeviceInfo().address();
|
||||||
|
|||||||
@ -13,15 +13,23 @@
|
|||||||
"name": "sunnyWebBox",
|
"name": "sunnyWebBox",
|
||||||
"displayName": "SMA Sunny WebBox",
|
"displayName": "SMA Sunny WebBox",
|
||||||
"createMethods": ["discovery", "user"],
|
"createMethods": ["discovery", "user"],
|
||||||
"interfaces": ["solarinverter"],
|
"interfaces": ["solarinverter", "connectable", "networkdevice"],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "864d4162-e3ce-48b8-b8ac-c1b971b52d42",
|
"id": "864d4162-e3ce-48b8-b8ac-c1b971b52d42",
|
||||||
"name": "host",
|
"name": "address",
|
||||||
"displayName": "Host address",
|
"displayName": "Host address",
|
||||||
"type": "QString",
|
"type": "QString",
|
||||||
"inputType": "IPv4Address",
|
"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",
|
"id": "03f32361-4e13-4597-a346-af8d16a986b3",
|
||||||
@ -30,7 +38,7 @@
|
|||||||
"type": "QString",
|
"type": "QString",
|
||||||
"inputType": "TextLine",
|
"inputType": "TextLine",
|
||||||
"readOnly": true,
|
"readOnly": true,
|
||||||
"defaultValue": "00:00:00:00:00:00"
|
"defaultValue": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stateTypes": [
|
"stateTypes": [
|
||||||
@ -286,15 +294,23 @@
|
|||||||
"displayName": "SMA Inverter",
|
"displayName": "SMA Inverter",
|
||||||
"createMethods": ["discovery", "user"],
|
"createMethods": ["discovery", "user"],
|
||||||
"setupMethod": "EnterPin",
|
"setupMethod": "EnterPin",
|
||||||
"interfaces": [ "solarinverter", "connectable"],
|
"interfaces": [ "solarinverter", "connectable", "networkdevice"],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "c8098d53-69eb-4d0b-9f07-e43c4a0ea9a9",
|
"id": "c8098d53-69eb-4d0b-9f07-e43c4a0ea9a9",
|
||||||
"name": "host",
|
"name": "address",
|
||||||
"displayName": "Host address",
|
"displayName": "Host address",
|
||||||
"type": "QString",
|
"type": "QString",
|
||||||
"inputType": "IPv4Address",
|
"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",
|
"id": "7df0ab60-0f11-4495-8e0d-508ba2b6d858",
|
||||||
@ -537,8 +553,24 @@
|
|||||||
"name": "modbusSolarInverter",
|
"name": "modbusSolarInverter",
|
||||||
"displayName": "SMA Solar Inverter (Modbus)",
|
"displayName": "SMA Solar Inverter (Modbus)",
|
||||||
"createMethods": ["discovery", "user"],
|
"createMethods": ["discovery", "user"],
|
||||||
"interfaces": [ "solarinverter" ],
|
"interfaces": [ "solarinverter", "connectable", "networkdevice" ],
|
||||||
"paramTypes": [
|
"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",
|
"id": "3cea46a0-9535-4612-9971-19167109e63c",
|
||||||
"name":"macAddress",
|
"name":"macAddress",
|
||||||
@ -699,8 +731,24 @@
|
|||||||
"name": "modbusBatteryInverter",
|
"name": "modbusBatteryInverter",
|
||||||
"displayName": "SMA Battery Inverter (Modbus)",
|
"displayName": "SMA Battery Inverter (Modbus)",
|
||||||
"createMethods": ["discovery", "user"],
|
"createMethods": ["discovery", "user"],
|
||||||
"interfaces": [ "energystorage", "connectable" ],
|
"interfaces": [ "energystorage", "connectable", "networkdevice" ],
|
||||||
"paramTypes": [
|
"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",
|
"id": "03a5a009-0edc-4370-924a-785e7fcee30a",
|
||||||
"name":"macAddress",
|
"name":"macAddress",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2023, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -45,20 +45,20 @@ SmaModbusBatteryInverterDiscovery::SmaModbusBatteryInverterDiscovery(NetworkDevi
|
|||||||
qCDebug(dcSma()) << "Discovery: Grace period timer triggered.";
|
qCDebug(dcSma()) << "Discovery: Grace period timer triggered.";
|
||||||
finishDiscovery();
|
finishDiscovery();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SmaModbusBatteryInverterDiscovery::startDiscovery()
|
void SmaModbusBatteryInverterDiscovery::startDiscovery()
|
||||||
{
|
{
|
||||||
qCInfo(dcSma()) << "Discovery: Searching for SMA battery inverters in the network...";
|
qCInfo(dcSma()) << "Discovery: Searching for SMA battery inverters in the network...";
|
||||||
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
|
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, [=](){
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
|
||||||
qCDebug(dcSma()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices";
|
qCDebug(dcSma()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices";
|
||||||
|
m_networkDeviceInfos = discoveryReply->networkDeviceInfos();
|
||||||
m_gracePeriodTimer.start();
|
m_gracePeriodTimer.start();
|
||||||
discoveryReply->deleteLater();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,11 +67,11 @@ QList<SmaModbusBatteryInverterDiscovery::Result> SmaModbusBatteryInverterDiscove
|
|||||||
return m_discoveryResults;
|
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);
|
m_connections.append(connection);
|
||||||
|
|
||||||
connect(connection, &SmaBatteryInverterModbusTcpConnection::reachableChanged, this, [=](bool reachable){
|
connect(connection, &SmaBatteryInverterModbusTcpConnection::reachableChanged, this, [=](bool reachable){
|
||||||
@ -82,13 +82,13 @@ void SmaModbusBatteryInverterDiscovery::checkNetworkDevice(const NetworkDeviceIn
|
|||||||
|
|
||||||
connect(connection, &SmaBatteryInverterModbusTcpConnection::initializationFinished, this, [=](bool success){
|
connect(connection, &SmaBatteryInverterModbusTcpConnection::initializationFinished, this, [=](bool success){
|
||||||
if (!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);
|
cleanupConnection(connection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection->deviceClass() != Sma::DeviceClassBatteryInverter) {
|
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);
|
cleanupConnection(connection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ void SmaModbusBatteryInverterDiscovery::checkNetworkDevice(const NetworkDeviceIn
|
|||||||
result.port = m_port;
|
result.port = m_port;
|
||||||
result.modbusAddress = m_modbusAddress;
|
result.modbusAddress = m_modbusAddress;
|
||||||
result.softwareVersion = Sma::buildSoftwareVersionString(connection->softwarePackage());
|
result.softwareVersion = Sma::buildSoftwareVersionString(connection->softwarePackage());
|
||||||
result.networkDeviceInfo = networkDeviceInfo;
|
result.address = address;
|
||||||
m_discoveryResults.append(result);
|
m_discoveryResults.append(result);
|
||||||
|
|
||||||
qCInfo(dcSma()) << "Discovery: --> Found";
|
qCInfo(dcSma()) << "Discovery: --> Found";
|
||||||
@ -112,18 +112,17 @@ void SmaModbusBatteryInverterDiscovery::checkNetworkDevice(const NetworkDeviceIn
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!connection->initialize()) {
|
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);
|
cleanupConnection(connection);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(connection, &SmaBatteryInverterModbusTcpConnection::checkReachabilityFailed, this, [=](){
|
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);
|
cleanupConnection(connection);
|
||||||
});
|
});
|
||||||
|
|
||||||
connection->connectDevice();
|
connection->connectDevice();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SmaModbusBatteryInverterDiscovery::cleanupConnection(SmaBatteryInverterModbusTcpConnection *connection)
|
void SmaModbusBatteryInverterDiscovery::cleanupConnection(SmaBatteryInverterModbusTcpConnection *connection)
|
||||||
@ -137,12 +136,16 @@ void SmaModbusBatteryInverterDiscovery::finishDiscovery()
|
|||||||
{
|
{
|
||||||
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
|
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
|
||||||
|
|
||||||
|
// Fill in all network device infos we have
|
||||||
|
for (int i = 0; i < m_discoveryResults.count(); i++)
|
||||||
|
m_discoveryResults[i].networkDeviceInfo = m_networkDeviceInfos.get(m_discoveryResults.at(i).address);
|
||||||
|
|
||||||
// Cleanup any leftovers...we don't care any more
|
// Cleanup any leftovers...we don't care any more
|
||||||
foreach (SmaBatteryInverterModbusTcpConnection *connection, m_connections)
|
foreach (SmaBatteryInverterModbusTcpConnection *connection, m_connections)
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
|
|
||||||
qCInfo(dcSma()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count()
|
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();
|
m_gracePeriodTimer.stop();
|
||||||
|
|
||||||
emit discoveryFinished();
|
emit discoveryFinished();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2023, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -49,6 +49,7 @@ public:
|
|||||||
int port;
|
int port;
|
||||||
int modbusAddress;
|
int modbusAddress;
|
||||||
QString softwareVersion;
|
QString softwareVersion;
|
||||||
|
QHostAddress address;
|
||||||
NetworkDeviceInfo networkDeviceInfo;
|
NetworkDeviceInfo networkDeviceInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,11 +68,11 @@ private:
|
|||||||
QTimer m_gracePeriodTimer;
|
QTimer m_gracePeriodTimer;
|
||||||
QDateTime m_startDateTime;
|
QDateTime m_startDateTime;
|
||||||
|
|
||||||
|
NetworkDeviceInfos m_networkDeviceInfos;
|
||||||
QList<SmaBatteryInverterModbusTcpConnection *> m_connections;
|
QList<SmaBatteryInverterModbusTcpConnection *> m_connections;
|
||||||
|
|
||||||
QList<Result> m_discoveryResults;
|
QList<Result> m_discoveryResults;
|
||||||
|
|
||||||
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
|
void checkNetworkDevice(const QHostAddress &address);
|
||||||
void cleanupConnection(SmaBatteryInverterModbusTcpConnection *connection);
|
void cleanupConnection(SmaBatteryInverterModbusTcpConnection *connection);
|
||||||
|
|
||||||
void finishDiscovery();
|
void finishDiscovery();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2022, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -36,9 +36,9 @@
|
|||||||
|
|
||||||
SmaModbusSolarInverterDiscovery::SmaModbusSolarInverterDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, quint16 port, quint16 modbusAddress,QObject *parent)
|
SmaModbusSolarInverterDiscovery::SmaModbusSolarInverterDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, quint16 port, quint16 modbusAddress,QObject *parent)
|
||||||
: QObject{parent},
|
: QObject{parent},
|
||||||
m_networkDeviceDiscovery{networkDeviceDiscovery},
|
m_networkDeviceDiscovery{networkDeviceDiscovery},
|
||||||
m_port{port},
|
m_port{port},
|
||||||
m_modbusAddress{modbusAddress}
|
m_modbusAddress{modbusAddress}
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -47,21 +47,14 @@ void SmaModbusSolarInverterDiscovery::startDiscovery()
|
|||||||
{
|
{
|
||||||
qCInfo(dcSma()) << "Discovery: Start searching for SMA modbus inverters in the network...";
|
qCInfo(dcSma()) << "Discovery: Start searching for SMA modbus inverters in the network...";
|
||||||
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
|
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
|
||||||
|
m_startDateTime = QDateTime::currentDateTime();
|
||||||
|
|
||||||
// Imedialty check any new device gets discovered
|
// Imedialty check any new device gets discovered
|
||||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &SmaModbusSolarInverterDiscovery::checkNetworkDevice);
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &SmaModbusSolarInverterDiscovery::checkNetworkDevice);
|
||||||
|
|
||||||
// Check what might be left on finished
|
|
||||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
|
||||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [this, discoveryReply](){
|
||||||
qCDebug(dcSma()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices";
|
qCDebug(dcSma()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices";
|
||||||
|
m_networkDeviceInfos = discoveryReply->networkDeviceInfos();
|
||||||
// Send a report request to nework device info not sent already...
|
|
||||||
foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) {
|
|
||||||
if (!m_verifiedNetworkDeviceInfos.contains(networkDeviceInfo)) {
|
|
||||||
checkNetworkDevice(networkDeviceInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Give the last connections added right before the network discovery finished a chance to check the device...
|
// Give the last connections added right before the network discovery finished a chance to check the device...
|
||||||
QTimer::singleShot(3000, this, [this](){
|
QTimer::singleShot(3000, this, [this](){
|
||||||
@ -76,19 +69,10 @@ QList<SmaModbusSolarInverterDiscovery::SmaModbusDiscoveryResult> SmaModbusSolarI
|
|||||||
return m_discoveryResults;
|
return m_discoveryResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo)
|
void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const QHostAddress &address)
|
||||||
{
|
{
|
||||||
// Create a kostal connection and try to initialize it.
|
SmaSolarInverterModbusTcpConnection *connection = new SmaSolarInverterModbusTcpConnection(address, m_port, m_modbusAddress, this);
|
||||||
// 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);
|
|
||||||
m_connections.append(connection);
|
m_connections.append(connection);
|
||||||
m_verifiedNetworkDeviceInfos.append(networkDeviceInfo);
|
|
||||||
|
|
||||||
connect(connection, &SmaSolarInverterModbusTcpConnection::reachableChanged, this, [=](bool reachable){
|
connect(connection, &SmaSolarInverterModbusTcpConnection::reachableChanged, this, [=](bool reachable){
|
||||||
if (!reachable) {
|
if (!reachable) {
|
||||||
@ -100,13 +84,13 @@ void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo
|
|||||||
// Modbus TCP connected...ok, let's try to initialize it!
|
// Modbus TCP connected...ok, let's try to initialize it!
|
||||||
connect(connection, &SmaSolarInverterModbusTcpConnection::initializationFinished, this, [=](bool success){
|
connect(connection, &SmaSolarInverterModbusTcpConnection::initializationFinished, this, [=](bool success){
|
||||||
if (!success) {
|
if (!success) {
|
||||||
qCDebug(dcSma()) << "Discovery: Initialization failed on" << networkDeviceInfo.address().toString() << "Continue...";;
|
qCDebug(dcSma()) << "Discovery: Initialization failed on" << address.toString() << "Continue...";;
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection->deviceClass() != Sma::DeviceClassSolarInverter) {
|
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);
|
cleanupConnection(connection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -118,14 +102,14 @@ void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo
|
|||||||
result.port = m_port;
|
result.port = m_port;
|
||||||
result.modbusAddress = m_modbusAddress;
|
result.modbusAddress = m_modbusAddress;
|
||||||
result.softwareVersion = Sma::buildSoftwareVersionString(connection->softwarePackage());
|
result.softwareVersion = Sma::buildSoftwareVersionString(connection->softwarePackage());
|
||||||
result.networkDeviceInfo = networkDeviceInfo;
|
result.address = address;
|
||||||
m_discoveryResults.append(result);
|
m_discoveryResults.append(result);
|
||||||
|
|
||||||
qCDebug(dcSma()) << "Discovery: --> Found" << result.productName;
|
qCDebug(dcSma()) << "Discovery: --> Found" << result.productName;
|
||||||
qCDebug(dcSma()) << "Discovery: Device name:" << result.deviceName;
|
qCDebug(dcSma()) << "Discovery: Device name:" << result.deviceName;
|
||||||
qCDebug(dcSma()) << "Discovery: Serial number:" << result.serialNumber;
|
qCDebug(dcSma()) << "Discovery: Serial number:" << result.serialNumber;
|
||||||
qCDebug(dcSma()) << "Discovery: Software version:" << result.softwareVersion;
|
qCDebug(dcSma()) << "Discovery: Software version:" << result.softwareVersion;
|
||||||
qCDebug(dcSma()) << "Discovery: " << result.networkDeviceInfo;
|
qCDebug(dcSma()) << "Discovery:" << result.networkDeviceInfo;
|
||||||
|
|
||||||
// Done with this connection
|
// Done with this connection
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
@ -133,7 +117,7 @@ void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo
|
|||||||
|
|
||||||
// Initializing...
|
// Initializing...
|
||||||
if (!connection->initialize()) {
|
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);
|
cleanupConnection(connection);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -141,14 +125,14 @@ void SmaModbusSolarInverterDiscovery::checkNetworkDevice(const NetworkDeviceInfo
|
|||||||
// If we get any error...skip this host...
|
// If we get any error...skip this host...
|
||||||
connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionErrorOccurred, this, [=](QModbusDevice::Error error){
|
connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionErrorOccurred, this, [=](QModbusDevice::Error error){
|
||||||
if (error != QModbusDevice::NoError) {
|
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);
|
cleanupConnection(connection);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// If check reachability failed...skip this host...
|
// If check reachability failed...skip this host...
|
||||||
connect(connection, &SmaSolarInverterModbusTcpConnection::checkReachabilityFailed, this, [=](){
|
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);
|
cleanupConnection(connection);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -167,10 +151,15 @@ void SmaModbusSolarInverterDiscovery::finishDiscovery()
|
|||||||
{
|
{
|
||||||
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
|
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
|
||||||
|
|
||||||
|
// Fill in all network device infos we have
|
||||||
|
for (int i = 0; i < m_discoveryResults.count(); i++)
|
||||||
|
m_discoveryResults[i].networkDeviceInfo = m_networkDeviceInfos.get(m_discoveryResults.at(i).address);
|
||||||
|
|
||||||
// Cleanup any leftovers...we don't care any more
|
// Cleanup any leftovers...we don't care any more
|
||||||
foreach (SmaSolarInverterModbusTcpConnection *connection, m_connections)
|
foreach (SmaSolarInverterModbusTcpConnection *connection, m_connections)
|
||||||
cleanupConnection(connection);
|
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();
|
emit discoveryFinished();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2022, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -50,6 +50,7 @@ public:
|
|||||||
quint16 port;
|
quint16 port;
|
||||||
quint16 modbusAddress;
|
quint16 modbusAddress;
|
||||||
QString softwareVersion;
|
QString softwareVersion;
|
||||||
|
QHostAddress address;
|
||||||
NetworkDeviceInfo networkDeviceInfo;
|
NetworkDeviceInfo networkDeviceInfo;
|
||||||
} SmaModbusDiscoveryResult;
|
} SmaModbusDiscoveryResult;
|
||||||
|
|
||||||
@ -64,15 +65,13 @@ private:
|
|||||||
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
|
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
|
||||||
quint16 m_port;
|
quint16 m_port;
|
||||||
quint16 m_modbusAddress;
|
quint16 m_modbusAddress;
|
||||||
|
|
||||||
QDateTime m_startDateTime;
|
QDateTime m_startDateTime;
|
||||||
NetworkDeviceInfos m_verifiedNetworkDeviceInfos;
|
|
||||||
|
|
||||||
|
NetworkDeviceInfos m_networkDeviceInfos;
|
||||||
QList<SmaSolarInverterModbusTcpConnection *> m_connections;
|
QList<SmaSolarInverterModbusTcpConnection *> m_connections;
|
||||||
|
|
||||||
QList<SmaModbusDiscoveryResult> m_discoveryResults;
|
QList<SmaModbusDiscoveryResult> m_discoveryResults;
|
||||||
|
|
||||||
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
|
void checkNetworkDevice(const QHostAddress &address);
|
||||||
void cleanupConnection(SmaSolarInverterModbusTcpConnection *connection);
|
void cleanupConnection(SmaSolarInverterModbusTcpConnection *connection);
|
||||||
|
|
||||||
void finishDiscovery();
|
void finishDiscovery();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2022, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -96,7 +96,6 @@ void SpeedwireDiscovery::startMulticastDiscovery()
|
|||||||
sendDiscoveryRequest();
|
sendDiscoveryRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SpeedwireDiscovery::startUnicastDiscovery()
|
void SpeedwireDiscovery::startUnicastDiscovery()
|
||||||
{
|
{
|
||||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Start discovering network...";
|
qCDebug(dcSma()) << "SpeedwireDiscovery: Start discovering network...";
|
||||||
@ -104,13 +103,12 @@ void SpeedwireDiscovery::startUnicastDiscovery()
|
|||||||
|
|
||||||
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
|
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
|
||||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
|
||||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, [this](const NetworkDeviceInfo &networkDeviceInfo){
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &SpeedwireDiscovery::sendUnicastDiscoveryRequest);
|
||||||
m_networkDeviceInfos.append(networkDeviceInfo);
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [this, discoveryReply](){
|
||||||
sendUnicastDiscoveryRequest(networkDeviceInfo.address());
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
|
|
||||||
qCDebug(dcSma()) << "Discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices for unicast requests.";
|
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.
|
// Wait some extra second in otder to give the last hosts joined some time to respond.
|
||||||
QTimer::singleShot(3000, this, [this](){
|
QTimer::singleShot(3000, this, [this](){
|
||||||
m_multicastSearchRequestTimer.stop();
|
m_multicastSearchRequestTimer.stop();
|
||||||
@ -178,10 +176,6 @@ void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quin
|
|||||||
m_resultMeters.insert(senderAddress, result);
|
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].modelId = modelId;
|
||||||
m_resultMeters[senderAddress].serialNumber = serialNumber;
|
m_resultMeters[senderAddress].serialNumber = serialNumber;
|
||||||
} else if (header.protocolId == Speedwire::ProtocolIdInverter) {
|
} else if (header.protocolId == Speedwire::ProtocolIdInverter) {
|
||||||
@ -196,10 +190,6 @@ void SpeedwireDiscovery::processDatagram(const QHostAddress &senderAddress, quin
|
|||||||
m_resultInverters.insert(senderAddress, result);
|
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].modelId = inverterPacket.sourceModelId;
|
||||||
m_resultInverters[senderAddress].serialNumber = inverterPacket.sourceSerialNumber;
|
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](){
|
connect(reply, &SpeedwireInverterReply::finished, this, [/*this, inverter,*/ senderAddress, reply](){
|
||||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Identify request finished from" << senderAddress.toString() << reply->error();
|
qCDebug(dcSma()) << "SpeedwireDiscovery: Identify request finished from" << senderAddress.toString() << reply->error();
|
||||||
|
|
||||||
// SpeedwireInverterReply *loginReply = inverter->sendLoginRequest();
|
// SpeedwireInverterReply *loginReply = inverter->sendLoginRequest();
|
||||||
// qCDebug(dcSma()) << "SpeedwireDiscovery: make login attempt using the default password.";
|
// qCDebug(dcSma()) << "SpeedwireDiscovery: make login attempt using the default password.";
|
||||||
// connect(loginReply, &SpeedwireInverterReply::finished, this, [loginReply, senderAddress](){
|
// connect(loginReply, &SpeedwireInverterReply::finished, this, [loginReply, senderAddress](){
|
||||||
// qCDebug(dcSma()) << "SpeedwireDiscovery: login attempt finished" << senderAddress.toString() << loginReply->error();
|
// qCDebug(dcSma()) << "SpeedwireDiscovery: login attempt finished" << senderAddress.toString() << loginReply->error();
|
||||||
// });
|
// });
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -248,6 +238,10 @@ void SpeedwireDiscovery::finishDiscovery()
|
|||||||
{
|
{
|
||||||
m_results = m_resultMeters.values() + m_resultInverters.values();
|
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";
|
qCDebug(dcSma()) << "SpeedwireDiscovery: Discovey finished. Found" << m_results.count() << "SMA devices in the network";
|
||||||
m_multicastSearchRequestTimer.stop();
|
m_multicastSearchRequestTimer.stop();
|
||||||
|
|
||||||
@ -255,13 +249,11 @@ void SpeedwireDiscovery::finishDiscovery()
|
|||||||
qCDebug(dcSma()) << "SpeedwireDiscovery: ============================================";
|
qCDebug(dcSma()) << "SpeedwireDiscovery: ============================================";
|
||||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Device type:" << result.deviceType;
|
qCDebug(dcSma()) << "SpeedwireDiscovery: Device type:" << result.deviceType;
|
||||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Address:" << result.address.toString();
|
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: Model ID:" << result.modelId;
|
||||||
qCDebug(dcSma()) << "SpeedwireDiscovery: Serial number:" << result.serialNumber;
|
qCDebug(dcSma()) << "SpeedwireDiscovery: Serial number:" << result.serialNumber;
|
||||||
|
if (result.networkDeviceInfo.isValid()) {
|
||||||
|
qCDebug(dcSma()) << "SpeedwireDiscovery:" << result.networkDeviceInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit discoveryFinished();
|
emit discoveryFinished();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2022, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
|
|||||||
@ -33,17 +33,43 @@
|
|||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
SpeedwireInverter::SpeedwireInverter(SpeedwireInterface *speedwireInterface, const QHostAddress &address, quint16 modelId, quint32 serialNumber, QObject *parent) :
|
SpeedwireInverter::SpeedwireInverter(SpeedwireInterface *speedwireInterface, NetworkDeviceMonitor *monitor, quint16 modelId, quint32 serialNumber, QObject *parent)
|
||||||
QObject(parent),
|
: QObject{parent},
|
||||||
m_speedwireInterface(speedwireInterface),
|
m_speedwireInterface{speedwireInterface},
|
||||||
m_address(address),
|
m_monitor{monitor},
|
||||||
m_modelId(modelId),
|
m_modelId{modelId},
|
||||||
m_serialNumber(serialNumber)
|
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();
|
qCDebug(dcSma()) << "Inverter: setup interface on" << m_address.toString();
|
||||||
connect(m_speedwireInterface, &SpeedwireInterface::dataReceived, this, &SpeedwireInverter::processData);
|
connect(m_speedwireInterface, &SpeedwireInterface::dataReceived, this, &SpeedwireInverter::processData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkDeviceMonitor *SpeedwireInverter::monitor() const
|
||||||
|
{
|
||||||
|
return m_monitor;
|
||||||
|
}
|
||||||
|
|
||||||
SpeedwireInverter::State SpeedwireInverter::state() const
|
SpeedwireInverter::State SpeedwireInverter::state() const
|
||||||
{
|
{
|
||||||
return m_state;
|
return m_state;
|
||||||
|
|||||||
@ -34,12 +34,15 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
|
|
||||||
|
#include <network/networkdevicemonitor.h>
|
||||||
|
|
||||||
#include "sma.h"
|
#include "sma.h"
|
||||||
#include "speedwire.h"
|
#include "speedwire.h"
|
||||||
#include "speedwireinterface.h"
|
#include "speedwireinterface.h"
|
||||||
#include "speedwireinverterreply.h"
|
#include "speedwireinverterreply.h"
|
||||||
#include "speedwireinverterrequest.h"
|
#include "speedwireinverterrequest.h"
|
||||||
|
|
||||||
|
|
||||||
class SpeedwireInverter : public QObject
|
class SpeedwireInverter : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -54,8 +57,11 @@ public:
|
|||||||
};
|
};
|
||||||
Q_ENUM(State)
|
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);
|
explicit SpeedwireInverter(SpeedwireInterface *speedwireInterface, const QHostAddress &address, quint16 modelId, quint32 serialNumber, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
NetworkDeviceMonitor *monitor() const;
|
||||||
|
|
||||||
State state() const;
|
State state() const;
|
||||||
|
|
||||||
bool reachable() const;
|
bool reachable() const;
|
||||||
@ -122,6 +128,7 @@ signals:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
SpeedwireInterface *m_speedwireInterface = nullptr;
|
SpeedwireInterface *m_speedwireInterface = nullptr;
|
||||||
|
NetworkDeviceMonitor *m_monitor = nullptr;
|
||||||
QHostAddress m_address;
|
QHostAddress m_address;
|
||||||
QString m_password;
|
QString m_password;
|
||||||
|
|
||||||
|
|||||||
@ -31,9 +31,9 @@
|
|||||||
#include "sunnywebbox.h"
|
#include "sunnywebbox.h"
|
||||||
#include "extern-plugininfo.h"
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
#include "QJsonDocument"
|
#include <QJsonDocument>
|
||||||
#include "QJsonObject"
|
#include <QJsonObject>
|
||||||
#include "QJsonArray"
|
#include <QJsonArray>
|
||||||
|
|
||||||
SunnyWebBox::SunnyWebBox(NetworkAccessManager *networkAccessManager, const QHostAddress &hostAddress, QObject *parrent) :
|
SunnyWebBox::SunnyWebBox(NetworkAccessManager *networkAccessManager, const QHostAddress &hostAddress, QObject *parrent) :
|
||||||
QObject(parrent),
|
QObject(parrent),
|
||||||
@ -142,16 +142,6 @@ void SunnyWebBox::setHostAddress(const QHostAddress &address)
|
|||||||
m_hostAddresss = 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)
|
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;
|
qCDebug(dcSma()) << "SunnyWebBox: Send message to" << address.toString() << "Procedure:" << procedure << "Params:" << params;
|
||||||
|
|||||||
@ -31,8 +31,8 @@
|
|||||||
#ifndef SUNNYWEBBOX_H
|
#ifndef SUNNYWEBBOX_H
|
||||||
#define SUNNYWEBBOX_H
|
#define SUNNYWEBBOX_H
|
||||||
|
|
||||||
#include "integrations/thing.h"
|
#include <integrations/thing.h>
|
||||||
#include "network/networkaccessmanager.h"
|
#include <network/networkaccessmanager.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
@ -88,9 +88,6 @@ public:
|
|||||||
QHostAddress hostAddress() const;
|
QHostAddress hostAddress() const;
|
||||||
void setHostAddress(const QHostAddress &address);
|
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());
|
QNetworkReply *sendRequest(const QHostAddress &address, const QString &procedure, const QJsonObject ¶ms = QJsonObject(), const QString &requestId = QString());
|
||||||
|
|
||||||
static QString generateRequestId();
|
static QString generateRequestId();
|
||||||
@ -99,7 +96,6 @@ private:
|
|||||||
NetworkAccessManager *m_networkManager = nullptr;
|
NetworkAccessManager *m_networkManager = nullptr;
|
||||||
bool m_connected = false;
|
bool m_connected = false;
|
||||||
QHostAddress m_hostAddresss;
|
QHostAddress m_hostAddresss;
|
||||||
QString m_macAddress;
|
|
||||||
QDateTime m_lastRequest;
|
QDateTime m_lastRequest;
|
||||||
|
|
||||||
QString sendMessage(const QHostAddress &address, const QString &procedure);
|
QString sendMessage(const QHostAddress &address, const QString &procedure);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2022, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -46,8 +46,8 @@ SunnyWebBoxDiscovery::SunnyWebBoxDiscovery(NetworkAccessManager *networkAccessMa
|
|||||||
void SunnyWebBoxDiscovery::startDiscovery()
|
void SunnyWebBoxDiscovery::startDiscovery()
|
||||||
{
|
{
|
||||||
// Clean up
|
// Clean up
|
||||||
|
m_discoveredHosts.clear();
|
||||||
m_discoveryResults.clear();
|
m_discoveryResults.clear();
|
||||||
m_verifiedNetworkDeviceInfos.clear();
|
|
||||||
|
|
||||||
m_startDateTime = QDateTime::currentDateTime();
|
m_startDateTime = QDateTime::currentDateTime();
|
||||||
|
|
||||||
@ -55,23 +55,14 @@ void SunnyWebBoxDiscovery::startDiscovery()
|
|||||||
m_discoveryReply = m_networkDeviceDiscovery->discover();
|
m_discoveryReply = m_networkDeviceDiscovery->discover();
|
||||||
|
|
||||||
// Test any network device beeing discovered
|
// Test any network device beeing discovered
|
||||||
connect(m_discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &SunnyWebBoxDiscovery::checkNetworkDevice);
|
connect(m_discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, 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::finished, this, [=](){
|
connect(m_discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
|
||||||
// The network device discovery is done
|
// The network device discovery is done
|
||||||
m_discoveredNetworkDeviceInfos = m_discoveryReply->networkDeviceInfos();
|
m_networkDeviceInfos = m_discoveryReply->networkDeviceInfos();
|
||||||
|
|
||||||
m_discoveryReply->deleteLater();
|
m_discoveryReply->deleteLater();
|
||||||
m_discoveryReply = nullptr;
|
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,
|
// 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...
|
// we don't care any more since there might just waiting for some timeouts...
|
||||||
// If there would be a device, if would have responded.
|
// If there would be a device, if would have responded.
|
||||||
@ -87,16 +78,11 @@ NetworkDeviceInfos SunnyWebBoxDiscovery::discoveryResults() const
|
|||||||
return m_discoveryResults;
|
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.
|
// Make a simple request and verify if it worked and the expected data gets returned.
|
||||||
SunnyWebBox webBox(m_networkAccessManager, networkDeviceInfo.address(), this);
|
SunnyWebBox webBox(m_networkAccessManager, address, this);
|
||||||
QNetworkReply *reply = webBox.sendRequest(networkDeviceInfo.address(), "GetPlantOverview");
|
QNetworkReply *reply = webBox.sendRequest(address, "GetPlantOverview");
|
||||||
m_pendingReplies.append(reply);
|
m_pendingReplies.append(reply);
|
||||||
connect(reply, &QNetworkReply::finished, this, [=](){
|
connect(reply, &QNetworkReply::finished, this, [=](){
|
||||||
m_pendingReplies.removeAll(reply);
|
m_pendingReplies.removeAll(reply);
|
||||||
@ -104,7 +90,7 @@ void SunnyWebBoxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDe
|
|||||||
|
|
||||||
// Check HTTP reply
|
// Check HTTP reply
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
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...";
|
<< "and a HTTP error occurred:" << reply->errorString() << "Continue...";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -115,28 +101,28 @@ void SunnyWebBoxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDe
|
|||||||
QJsonParseError error;
|
QJsonParseError error;
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
if (error.error != QJsonParseError::NoError) {
|
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...";
|
<< "and received invalid JSON data:" << error.errorString() << "Continue...";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!jsonDoc.isObject()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap map = jsonDoc.toVariant().toMap();
|
QVariantMap map = jsonDoc.toVariant().toMap();
|
||||||
if (map["version"] != "1.0") {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map.contains("proc") && map.contains("result")) {
|
if (map.contains("proc") && map.contains("result")) {
|
||||||
// Ok, seems to be a Sunny WebBox we are talking to...add to the discovery results...
|
// 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;
|
qCDebug(dcSma()) << "Discovery: SunnyWebBox: --> Found Sunny WebBox on" << address;
|
||||||
m_discoveryResults.append(networkDeviceInfo);
|
m_discoveredHosts.append(address);
|
||||||
} else {
|
} 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;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -152,6 +138,10 @@ void SunnyWebBoxDiscovery::cleanupPendingReplies()
|
|||||||
void SunnyWebBoxDiscovery::finishDiscovery()
|
void SunnyWebBoxDiscovery::finishDiscovery()
|
||||||
{
|
{
|
||||||
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
|
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()
|
qCInfo(dcSma()) << "Discovery: SunnyWebBox: Finished the discovery process. Found" << m_discoveryResults.count()
|
||||||
<< "Sunny WebBoxes in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz");
|
<< "Sunny WebBoxes in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz");
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2022, nymea GmbH
|
* Copyright 2013 - 2024, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -50,7 +50,7 @@ signals:
|
|||||||
void discoveryFinished();
|
void discoveryFinished();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
|
void checkNetworkDevice(const QHostAddress &address);
|
||||||
void cleanupPendingReplies();
|
void cleanupPendingReplies();
|
||||||
void finishDiscovery();
|
void finishDiscovery();
|
||||||
|
|
||||||
@ -59,9 +59,9 @@ private:
|
|||||||
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
|
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
|
||||||
NetworkDeviceDiscoveryReply *m_discoveryReply = nullptr;
|
NetworkDeviceDiscoveryReply *m_discoveryReply = nullptr;
|
||||||
|
|
||||||
|
QList<QHostAddress> m_discoveredHosts;
|
||||||
NetworkDeviceInfos m_discoveryResults;
|
NetworkDeviceInfos m_discoveryResults;
|
||||||
NetworkDeviceInfos m_discoveredNetworkDeviceInfos;
|
NetworkDeviceInfos m_networkDeviceInfos;
|
||||||
NetworkDeviceInfos m_verifiedNetworkDeviceInfos;
|
|
||||||
|
|
||||||
QDateTime m_startDateTime;
|
QDateTime m_startDateTime;
|
||||||
QList<QNetworkReply *> m_pendingReplies;
|
QList<QNetworkReply *> m_pendingReplies;
|
||||||
|
|||||||
Reference in New Issue
Block a user