Merge PR #221: SolarEdge: Update gateway thing classes and discovery

master
jenkins 2025-10-17 11:28:20 +02:00
commit 4ab6647f9e
5 changed files with 95 additions and 75 deletions

View File

@ -70,6 +70,9 @@ IntegrationPluginSunSpec::IntegrationPluginSunSpec()
void IntegrationPluginSunSpec::init()
{
// SunSpec connection params
m_connectionDiscoverySlaveIdParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionDiscoverySlaveIdParamTypeId);
m_connectionDiscoverySlaveIdParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionDiscoverySlaveIdParamTypeId);
m_connectionMacAddressParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingMacAddressParamTypeId);
m_connectionMacAddressParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingMacAddressParamTypeId);
@ -139,13 +142,14 @@ void IntegrationPluginSunSpec::discoverThings(ThingDiscoveryInfo *info)
return;
}
QList<quint16> slaveIds = {1, 2};
SunSpecDataPoint::ByteOrder byteOrder = SunSpecDataPoint::ByteOrderLittleEndian;
if (info->thingClassId() == solarEdgeConnectionThingClassId) {
byteOrder = SunSpecDataPoint::ByteOrderBigEndian;
}
SunSpecDiscovery *discovery = new SunSpecDiscovery(hardwareManager()->networkDeviceDiscovery(), slaveIds, byteOrder, info);
SunSpecDataPoint::ByteOrder byteOrder = SunSpecDataPoint::ByteOrderLittleEndian;
if (info->thingClassId() == solarEdgeConnectionThingClassId)
byteOrder = SunSpecDataPoint::ByteOrderBigEndian;
quint16 discoverySlaveId = info->params().paramValue(m_connectionDiscoverySlaveIdParamTypeIds.value(info->thingClassId())).toUInt();
SunSpecDiscovery *discovery = new SunSpecDiscovery(hardwareManager()->networkDeviceDiscovery(), discoverySlaveId, byteOrder, info);
// Note: we could add here more
connect(discovery, &SunSpecDiscovery::discoveryFinished, info, [this, info, discovery](){
foreach (const SunSpecDiscovery::Result &result, discovery->results()) {
@ -247,7 +251,6 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
}
}
// Create the monitor
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
if (!monitor) {

View File

@ -62,6 +62,7 @@ public:
private:
// SunSpec Connection params map
QHash<ThingClassId, ParamTypeId> m_connectionDiscoverySlaveIdParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_connectionMacAddressParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_connectionAddressParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_connectionHostNameParamTypeIds;

View File

@ -39,9 +39,18 @@
"name": "sunspecConnection",
"displayName": "SunSpec Generic",
"id": "f51853f3-8815-4cf3-b337-45cda1f3e6d5",
"createMethods": [ "Discovery" ],
"createMethods": [ "discovery", "user" ],
"interfaces": [ "gateway", "networkdevice" ],
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage"],
"discoveryParamTypes": [
{
"id": "50e027aa-ab15-44df-80d3-71964aee44af",
"name":"slaveId",
"displayName": "Slave ID",
"type": "int",
"defaultValue": 1
}
],
"paramTypes": [
{
"id": "3567b389-9d42-48f9-a29b-d18388fb36a1",
@ -1474,9 +1483,18 @@
"name": "solarEdgeConnection",
"displayName": "SolarEdge",
"id": "7a92bf65-b443-4491-a012-2bec35eb5bf0",
"createMethods": [ "Discovery" ],
"createMethods": [ "discovery", "user" ],
"interfaces": [ "gateway", "networkdevice" ],
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage" ],
"discoveryParamTypes": [
{
"id": "9025a4e9-d994-45c7-9a00-62f7abf47107",
"name":"slaveId",
"displayName": "Slave ID",
"type": "int",
"defaultValue": 1
}
],
"paramTypes": [
{
"id": "9c2bafd0-6d56-42e0-8ef3-c4940b4f18b5",

View File

@ -34,10 +34,10 @@
#include <models/sunspecmodelfactory.h>
#include <models/sunspeccommonmodel.h>
SunSpecDiscovery::SunSpecDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, const QList<quint16> &slaveIds, SunSpecDataPoint::ByteOrder byteOrder, QObject *parent)
SunSpecDiscovery::SunSpecDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, quint16 slaveId, SunSpecDataPoint::ByteOrder byteOrder, QObject *parent)
: QObject{parent},
m_networkDeviceDiscovery{networkDeviceDiscovery},
m_slaveIds{slaveIds},
m_slaveId{slaveId},
m_byteOrder{byteOrder}
{
m_scanPorts.append(502);
@ -130,81 +130,79 @@ void SunSpecDiscovery::checkNetworkDevice(const QHostAddress &address)
// Check all ports for this host
foreach (quint16 port, m_scanPorts) {
foreach (quint16 slaveId, m_slaveIds) {
SunSpecConnection *connection = new SunSpecConnection(address, port, slaveId, m_byteOrder, this);
connection->setNumberOfRetries(1);
connection->setTimeout(500);
m_connections.append(connection);
connectionQueue.enqueue(connection);
SunSpecConnection *connection = new SunSpecConnection(address, port, m_slaveId, m_byteOrder, this);
connection->setNumberOfRetries(1);
connection->setTimeout(500);
m_connections.append(connection);
connectionQueue.enqueue(connection);
connect(connection, &SunSpecConnection::connectedChanged, this, [this, connection, connectionQueue, address](bool connected){
if (!connected) {
// Disconnected ... done with this connection
connect(connection, &SunSpecConnection::connectedChanged, this, [this, connection, connectionQueue, address](bool connected){
if (!connected) {
// Disconnected ... done with this connection
cleanupConnection(connection);
return;
}
// Successfully connected, we can stop the connection timer which takes care about blocking connection attempts
if (m_connectionTimers.contains(connection)) {
QTimer *connectionTimer = m_connectionTimers.take(connection);
connectionTimer->stop();
connectionTimer->deleteLater();
}
// Modbus TCP connected, try to discovery sunspec models...
connect(connection, &SunSpecConnection::discoveryFinished, this, [=](bool success){
if (!success) {
qCDebug(dcSunSpec()) << "Discovery: SunSpec discovery failed on"
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
<< "slave ID:" << connection->slaveId() << "Continue...";
cleanupConnection(connection);
return;
}
// Successfully connected, we can stop the connection timer which takes care about blocking connection attempts
if (m_connectionTimers.contains(connection)) {
QTimer *connectionTimer = m_connectionTimers.take(connection);
connectionTimer->stop();
connectionTimer->deleteLater();
}
// Success, we found some sunspec models here, let's read some infomation from the models
// Modbus TCP connected, try to discovery sunspec models...
connect(connection, &SunSpecConnection::discoveryFinished, this, [=](bool success){
if (!success) {
qCDebug(dcSunSpec()) << "Discovery: SunSpec discovery failed on"
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
<< "slave ID:" << connection->slaveId() << "Continue...";
cleanupConnection(connection);
return;
}
Result result;
result.address = address;
result.port = connection->port();
result.slaveId = connection->slaveId();
// Success, we found some sunspec models here, let's read some infomation from the models
Result result;
result.address = address;
result.port = connection->port();
result.slaveId = connection->slaveId();
qCDebug(dcSunSpec()) << "Discovery: --> Found SunSpec devices on" << result.networkDeviceInfo << "port" << result.port << "slave ID:" << result.slaveId;
foreach (SunSpecModel *model, connection->models()) {
if (model->modelId() == SunSpecModelFactory::ModelIdCommon) {
SunSpecCommonModel *commonModel = qobject_cast<SunSpecCommonModel *>(model);
QString manufacturer = commonModel->manufacturer();
if (!manufacturer.isEmpty() && !result.modelManufacturers.contains(manufacturer)) {
result.modelManufacturers.append(manufacturer);
}
qCDebug(dcSunSpec()) << "Discovery: --> Found SunSpec devices on" << result.networkDeviceInfo << "port" << result.port << "slave ID:" << result.slaveId;
foreach (SunSpecModel *model, connection->models()) {
if (model->modelId() == SunSpecModelFactory::ModelIdCommon) {
SunSpecCommonModel *commonModel = qobject_cast<SunSpecCommonModel *>(model);
QString manufacturer = commonModel->manufacturer();
if (!manufacturer.isEmpty() && !result.modelManufacturers.contains(manufacturer)) {
result.modelManufacturers.append(manufacturer);
}
}
m_results.append(result);
// Done with this connection
cleanupConnection(connection);
});
// Run SunSpec discovery on connection...
if (!connection->startDiscovery()) {
qCDebug(dcSunSpec()) << "Discovery: Unable to discover SunSpec data on connection"
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
<< "slave ID:" << connection->slaveId() << "Continue...";
cleanupConnection(connection);
}
m_results.append(result);
// Done with this connection
cleanupConnection(connection);
});
// If we get any error...skip this host...
connect(connection->modbusTcpClient(), &QModbusTcpClient::errorOccurred, this, [=](QModbusDevice::Error error){
if (error != QModbusDevice::NoError) {
qCDebug(dcSunSpec()) << "Discovery: Connection error on"
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
<< "slave ID:" << connection->slaveId() << "Continue...";
cleanupConnection(connection);
}
});
}
// Run SunSpec discovery on connection...
if (!connection->startDiscovery()) {
qCDebug(dcSunSpec()) << "Discovery: Unable to discover SunSpec data on connection"
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
<< "slave ID:" << connection->slaveId() << "Continue...";
cleanupConnection(connection);
}
});
// If we get any error...skip this host...
connect(connection->modbusTcpClient(), &QModbusTcpClient::errorOccurred, this, [=](QModbusDevice::Error error){
if (error != QModbusDevice::NoError) {
qCDebug(dcSunSpec()) << "Discovery: Connection error on"
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
<< "slave ID:" << connection->slaveId() << "Continue...";
cleanupConnection(connection);
}
});
}
m_pendingConnectionAttempts[address] = connectionQueue;

View File

@ -42,7 +42,7 @@ class SunSpecDiscovery : public QObject
{
Q_OBJECT
public:
explicit SunSpecDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, const QList<quint16> &slaveIds, SunSpecDataPoint::ByteOrder byteOrder = SunSpecDataPoint::ByteOrderLittleEndian, QObject *parent = nullptr);
explicit SunSpecDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, quint16 slaveId, SunSpecDataPoint::ByteOrder byteOrder = SunSpecDataPoint::ByteOrderLittleEndian, QObject *parent = nullptr);
typedef struct Result {
QHostAddress address;
NetworkDeviceInfo networkDeviceInfo;
@ -62,7 +62,7 @@ signals:
private:
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
QList<quint16> m_scanPorts;
QList<quint16> m_slaveIds;
quint16 m_slaveId = 1;
SunSpecDataPoint::ByteOrder m_byteOrder;
QDateTime m_startDateTime;