Merge PR #201: Sungrow: Update to networkdevice interface

sunspec-fix-storage-charging-enabled-action
jenkins 2025-03-30 20:37:29 +02:00
commit 94d84d7bca
4 changed files with 54 additions and 29 deletions

View File

@ -50,7 +50,6 @@ void IntegrationPluginSungrow::discoverThings(ThingDiscoveryInfo *info)
// Create a discovery with the info as parent for auto deleting the object once the discovery info is done // Create a discovery with the info as parent for auto deleting the object once the discovery info is done
SungrowDiscovery *discovery = new SungrowDiscovery(hardwareManager()->networkDeviceDiscovery(), m_modbusTcpPort, m_modbusSlaveAddress, info); SungrowDiscovery *discovery = new SungrowDiscovery(hardwareManager()->networkDeviceDiscovery(), m_modbusTcpPort, m_modbusSlaveAddress, info);
connect(discovery, &SungrowDiscovery::discoveryFinished, discovery, &SungrowDiscovery::deleteLater);
connect(discovery, &SungrowDiscovery::discoveryFinished, info, [=](){ connect(discovery, &SungrowDiscovery::discoveryFinished, info, [=](){
foreach (const SungrowDiscovery::SungrowDiscoveryResult &result, discovery->discoveryResults()) { foreach (const SungrowDiscovery::SungrowDiscoveryResult &result, discovery->discoveryResults()) {
QString title = "Sungrow " + QString::number(result.nominalOutputPower) + "kW Inverter"; QString title = "Sungrow " + QString::number(result.nominalOutputPower) + "kW Inverter";
@ -58,19 +57,22 @@ void IntegrationPluginSungrow::discoverThings(ThingDiscoveryInfo *info)
if (!result.serialNumber.isEmpty()) if (!result.serialNumber.isEmpty())
title.append(" " + result.serialNumber); title.append(" " + result.serialNumber);
ThingDescriptor descriptor(sungrowInverterTcpThingClassId, title, result.networkDeviceInfo.address().toString() + " " + result.networkDeviceInfo.macAddress()); ThingDescriptor descriptor(sungrowInverterTcpThingClassId, title, result.networkDeviceInfo.address().toString());
qCInfo(dcSungrow()) << "Discovered:" << descriptor.title() << descriptor.description(); qCInfo(dcSungrow()) << "Discovered:" << descriptor.title() << descriptor.description();
ParamList params;
params << Param(sungrowInverterTcpThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress());
params << Param(sungrowInverterTcpThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName());
params << Param(sungrowInverterTcpThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress());
descriptor.setParams(params);
// Check if we already have set up this device // Check if we already have set up this device
Things existingThings = myThings().filterByParam(sungrowInverterTcpThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress()); Thing *existingThing = myThings().findByParams(params);
if (existingThings.count() == 1) { if (existingThing) {
qCDebug(dcSungrow()) << "This Sungrow inverter already exists in the system:" << result.networkDeviceInfo; qCDebug(dcSungrow()) << "This thing already exists in the system:" << result.networkDeviceInfo;
descriptor.setThingId(existingThings.first()->id()); descriptor.setThingId(existingThing->id());
} }
ParamList params;
params << Param(sungrowInverterTcpThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress());
descriptor.setParams(params);
info->addThingDescriptor(descriptor); info->addThingDescriptor(descriptor);
} }
@ -97,16 +99,16 @@ void IntegrationPluginSungrow::setupThing(ThingSetupInfo *info)
} }
} }
MacAddress macAddress = MacAddress(thing->paramValue(sungrowInverterTcpThingMacAddressParamTypeId).toString()); // Create the monitor
if (!macAddress.isValid()) { NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
qCWarning(dcSungrow()) << "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 this inverter.")); qCWarning(dcSungrow()) << "Unable to register monitor with the given params" << thing->params();
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("Unable to set up the connection with this configuration, please reconfigure the connection."));
return; return;
} }
// Create the monitor
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress);
m_monitors.insert(thing, monitor); m_monitors.insert(thing, monitor);
connect(info, &ThingSetupInfo::aborted, monitor, [=](){ connect(info, &ThingSetupInfo::aborted, monitor, [=](){
// Clean up in case the setup gets aborted // Clean up in case the setup gets aborted
if (m_monitors.contains(thing)) { if (m_monitors.contains(thing)) {

View File

@ -14,9 +14,25 @@
"id": "59cb2da4-da07-11ee-adea-7397f8a9afe9", "id": "59cb2da4-da07-11ee-adea-7397f8a9afe9",
"createMethods": ["discovery"], "createMethods": ["discovery"],
"discoveryType": "weak", "discoveryType": "weak",
"interfaces": ["solarinverter", "connectable"], "interfaces": ["solarinverter", "connectable", "networkdevice"],
"providedInterfaces": [ "energymeter", "energystorage"], "providedInterfaces": [ "energymeter", "energystorage"],
"paramTypes": [ "paramTypes": [
{
"id": "311c0038-0134-4d91-878d-57526c3eec11",
"name": "address",
"displayName": "Host address",
"type": "QString",
"inputType": "IPv4Address",
"defaultValue": ""
},
{
"id": "6676fcea-1f3a-4241-ae03-18dae96c5d8d",
"name": "hostName",
"displayName": "Host name",
"type": "QString",
"inputType": "TextLine",
"defaultValue": ""
},
{ {
"id": "62137142-da07-11ee-9522-2f74f3b1fc5d", "id": "62137142-da07-11ee-9522-2f74f3b1fc5d",
"name":"macAddress", "name":"macAddress",

View File

@ -46,10 +46,11 @@ void SungrowDiscovery::startDiscovery()
m_startDateTime = QDateTime::currentDateTime(); m_startDateTime = QDateTime::currentDateTime();
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover(); NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &SungrowDiscovery::checkNetworkDevice); connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &SungrowDiscovery::checkNetworkDevice);
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater); connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=] () { connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=] () {
qCDebug(dcSungrow()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices"; qCDebug(dcSungrow()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices";
m_networkDeviceInfos = discoveryReply->networkDeviceInfos();
// Give the last connections added right before the network discovery finished a chance to check the device... // 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] () {
@ -64,15 +65,15 @@ QList<SungrowDiscovery::SungrowDiscoveryResult> SungrowDiscovery::discoveryResul
return m_discoveryResults; return m_discoveryResults;
} }
void SungrowDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo) void SungrowDiscovery::checkNetworkDevice(const QHostAddress &address)
{ {
/* Create a Sungrow connection and try to initialize it. /* Create a Sungrow connection and try to initialize it.
* Only if initialized successfully and all information have been fetched correctly from * 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). * the device we can assume this is what we are locking for (ip, port, modbus address, correct registers).
*/ */
qCDebug(dcSungrow()) << "Creating Sungrow Modbus TCP connection for" << networkDeviceInfo.address() << "Port:" << m_port << "Slave Address" << m_modbusAddress; qCDebug(dcSungrow()) << "Creating Sungrow Modbus TCP connection for" << address << "Port:" << m_port << "Slave Address" << m_modbusAddress;
SungrowModbusTcpConnection *connection = new SungrowModbusTcpConnection(networkDeviceInfo.address(), m_port, m_modbusAddress, this); SungrowModbusTcpConnection *connection = new SungrowModbusTcpConnection(address, m_port, m_modbusAddress, this);
connection->modbusTcpMaster()->setTimeout(5000); connection->modbusTcpMaster()->setTimeout(5000);
connection->modbusTcpMaster()->setNumberOfRetries(0); connection->modbusTcpMaster()->setNumberOfRetries(0);
m_connections.append(connection); m_connections.append(connection);
@ -87,12 +88,12 @@ void SungrowDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
connect(connection, &SungrowModbusTcpConnection::initializationFinished, this, [=](bool success){ connect(connection, &SungrowModbusTcpConnection::initializationFinished, this, [=](bool success){
if (!success) { if (!success) {
qCDebug(dcSungrow()) << "Discovery: Initialization failed on" << networkDeviceInfo.address().toString() << "Continue..."; qCDebug(dcSungrow()) << "Discovery: Initialization failed on" << address.toString() << "Continue...";
cleanupConnection(connection); cleanupConnection(connection);
return; return;
} }
qCDebug(dcSungrow()) << "Discovery: Initialized successfully" << networkDeviceInfo << connection->serialNumber(); qCDebug(dcSungrow()) << "Discovery: Initialized successfully" << address.toString() << connection->serialNumber();
qCDebug(dcSungrow()) << " - Protocol number:" << connection->protocolNumber(); qCDebug(dcSungrow()) << " - Protocol number:" << connection->protocolNumber();
qCDebug(dcSungrow()) << " - Protocol version:" << connection->protocolVersion(); qCDebug(dcSungrow()) << " - Protocol version:" << connection->protocolVersion();
qCDebug(dcSungrow()) << " - ARM software version:" << connection->armSoftwareVersion(); qCDebug(dcSungrow()) << " - ARM software version:" << connection->armSoftwareVersion();
@ -100,7 +101,7 @@ void SungrowDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
if (connection->deviceTypeCode() >= 0xd00 && connection->deviceTypeCode() <= 0xeff) { if (connection->deviceTypeCode() >= 0xd00 && connection->deviceTypeCode() <= 0xeff) {
SungrowDiscoveryResult result; SungrowDiscoveryResult result;
result.networkDeviceInfo = networkDeviceInfo; result.address = address;
result.serialNumber = connection->serialNumber(); result.serialNumber = connection->serialNumber();
result.nominalOutputPower = connection->nominalOutputPower(); result.nominalOutputPower = connection->nominalOutputPower();
result.deviceType = connection->deviceTypeCode(); result.deviceType = connection->deviceTypeCode();
@ -110,9 +111,9 @@ void SungrowDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
connection->disconnectDevice(); connection->disconnectDevice();
}); });
qCDebug(dcSungrow()) << "Discovery: The host" << networkDeviceInfo << "is reachable. Starting with initialization."; qCDebug(dcSungrow()) << "Discovery: The host" << address << "is reachable. Starting with initialization.";
if (!connection->initialize()) { if (!connection->initialize()) {
qCDebug(dcSungrow()) << "Discovery: Unable to initialize connection on" << networkDeviceInfo.address().toString() << "Continue..."; qCDebug(dcSungrow()) << "Discovery: Unable to initialize connection on" << address.toString() << "Continue...";
cleanupConnection(connection); cleanupConnection(connection);
} }
}); });
@ -120,21 +121,21 @@ void SungrowDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
// In case of an error skip the host // In case of an error skip the host
connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionStateChanged, this, [=](bool connected){ connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionStateChanged, this, [=](bool connected){
if (connected) { if (connected) {
qCDebug(dcSungrow()) << "Discovery: Connected with" << networkDeviceInfo.address().toString() << m_port; qCDebug(dcSungrow()) << "Discovery: Connected with" << address.toString() << m_port;
} }
}); });
// In case of an error skip the host // In case of an error skip the 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(dcSungrow()) << "Discovery: Connection error on" << networkDeviceInfo.address().toString() << "Continue..."; qCDebug(dcSungrow()) << "Discovery: Connection error on" << address.toString() << "Continue...";
cleanupConnection(connection); cleanupConnection(connection);
} }
}); });
// If the reachability check failed skip the host // If the reachability check failed skip the host
connect(connection, &SungrowModbusTcpConnection::checkReachabilityFailed, this, [=](){ connect(connection, &SungrowModbusTcpConnection::checkReachabilityFailed, this, [=](){
qCDebug(dcSungrow()) << "Discovery: Check reachability failed on" << networkDeviceInfo.address().toString() << "Continue..."; qCDebug(dcSungrow()) << "Discovery: Check reachability failed on" << address.toString() << "Continue...";
cleanupConnection(connection); cleanupConnection(connection);
}); });
@ -153,6 +154,10 @@ void SungrowDiscovery::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);
foreach (SungrowModbusTcpConnection *connection, m_connections) foreach (SungrowModbusTcpConnection *connection, m_connections)
cleanupConnection(connection); cleanupConnection(connection);

View File

@ -45,6 +45,7 @@ public:
explicit SungrowDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, quint16 port = 502, quint16 modbusAddress = 1, QObject *parent = nullptr); explicit SungrowDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, quint16 port = 502, quint16 modbusAddress = 1, QObject *parent = nullptr);
typedef struct SungrowDiscoveryResult { typedef struct SungrowDiscoveryResult {
QString serialNumber; QString serialNumber;
QHostAddress address;
NetworkDeviceInfo networkDeviceInfo; NetworkDeviceInfo networkDeviceInfo;
float nominalOutputPower; float nominalOutputPower;
int deviceType; int deviceType;
@ -64,10 +65,11 @@ private:
QDateTime m_startDateTime; QDateTime m_startDateTime;
NetworkDeviceInfos m_networkDeviceInfos;
QList<SungrowModbusTcpConnection *> m_connections; QList<SungrowModbusTcpConnection *> m_connections;
QList<SungrowDiscoveryResult> m_discoveryResults; QList<SungrowDiscoveryResult> m_discoveryResults;
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo); void checkNetworkDevice(const QHostAddress &address);
void cleanupConnection(SungrowModbusTcpConnection *connection); void cleanupConnection(SungrowModbusTcpConnection *connection);
void finishDiscovery(); void finishDiscovery();