Merge PR #221: SolarEdge: Update gateway thing classes and discovery
commit
4ab6647f9e
|
|
@ -70,6 +70,9 @@ IntegrationPluginSunSpec::IntegrationPluginSunSpec()
|
||||||
void IntegrationPluginSunSpec::init()
|
void IntegrationPluginSunSpec::init()
|
||||||
{
|
{
|
||||||
// SunSpec connection params
|
// SunSpec connection params
|
||||||
|
m_connectionDiscoverySlaveIdParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionDiscoverySlaveIdParamTypeId);
|
||||||
|
m_connectionDiscoverySlaveIdParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionDiscoverySlaveIdParamTypeId);
|
||||||
|
|
||||||
m_connectionMacAddressParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingMacAddressParamTypeId);
|
m_connectionMacAddressParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingMacAddressParamTypeId);
|
||||||
m_connectionMacAddressParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingMacAddressParamTypeId);
|
m_connectionMacAddressParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingMacAddressParamTypeId);
|
||||||
|
|
||||||
|
|
@ -139,13 +142,14 @@ void IntegrationPluginSunSpec::discoverThings(ThingDiscoveryInfo *info)
|
||||||
return;
|
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
|
// Note: we could add here more
|
||||||
connect(discovery, &SunSpecDiscovery::discoveryFinished, info, [this, info, discovery](){
|
connect(discovery, &SunSpecDiscovery::discoveryFinished, info, [this, info, discovery](){
|
||||||
foreach (const SunSpecDiscovery::Result &result, discovery->results()) {
|
foreach (const SunSpecDiscovery::Result &result, discovery->results()) {
|
||||||
|
|
@ -247,7 +251,6 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Create the monitor
|
// Create the monitor
|
||||||
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
|
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
|
||||||
if (!monitor) {
|
if (!monitor) {
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// SunSpec Connection params map
|
// SunSpec Connection params map
|
||||||
|
QHash<ThingClassId, ParamTypeId> m_connectionDiscoverySlaveIdParamTypeIds;
|
||||||
QHash<ThingClassId, ParamTypeId> m_connectionMacAddressParamTypeIds;
|
QHash<ThingClassId, ParamTypeId> m_connectionMacAddressParamTypeIds;
|
||||||
QHash<ThingClassId, ParamTypeId> m_connectionAddressParamTypeIds;
|
QHash<ThingClassId, ParamTypeId> m_connectionAddressParamTypeIds;
|
||||||
QHash<ThingClassId, ParamTypeId> m_connectionHostNameParamTypeIds;
|
QHash<ThingClassId, ParamTypeId> m_connectionHostNameParamTypeIds;
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,18 @@
|
||||||
"name": "sunspecConnection",
|
"name": "sunspecConnection",
|
||||||
"displayName": "SunSpec Generic",
|
"displayName": "SunSpec Generic",
|
||||||
"id": "f51853f3-8815-4cf3-b337-45cda1f3e6d5",
|
"id": "f51853f3-8815-4cf3-b337-45cda1f3e6d5",
|
||||||
"createMethods": [ "Discovery" ],
|
"createMethods": [ "discovery", "user" ],
|
||||||
"interfaces": [ "gateway", "networkdevice" ],
|
"interfaces": [ "gateway", "networkdevice" ],
|
||||||
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage"],
|
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage"],
|
||||||
|
"discoveryParamTypes": [
|
||||||
|
{
|
||||||
|
"id": "50e027aa-ab15-44df-80d3-71964aee44af",
|
||||||
|
"name":"slaveId",
|
||||||
|
"displayName": "Slave ID",
|
||||||
|
"type": "int",
|
||||||
|
"defaultValue": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "3567b389-9d42-48f9-a29b-d18388fb36a1",
|
"id": "3567b389-9d42-48f9-a29b-d18388fb36a1",
|
||||||
|
|
@ -1474,9 +1483,18 @@
|
||||||
"name": "solarEdgeConnection",
|
"name": "solarEdgeConnection",
|
||||||
"displayName": "SolarEdge",
|
"displayName": "SolarEdge",
|
||||||
"id": "7a92bf65-b443-4491-a012-2bec35eb5bf0",
|
"id": "7a92bf65-b443-4491-a012-2bec35eb5bf0",
|
||||||
"createMethods": [ "Discovery" ],
|
"createMethods": [ "discovery", "user" ],
|
||||||
"interfaces": [ "gateway", "networkdevice" ],
|
"interfaces": [ "gateway", "networkdevice" ],
|
||||||
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage" ],
|
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage" ],
|
||||||
|
"discoveryParamTypes": [
|
||||||
|
{
|
||||||
|
"id": "9025a4e9-d994-45c7-9a00-62f7abf47107",
|
||||||
|
"name":"slaveId",
|
||||||
|
"displayName": "Slave ID",
|
||||||
|
"type": "int",
|
||||||
|
"defaultValue": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "9c2bafd0-6d56-42e0-8ef3-c4940b4f18b5",
|
"id": "9c2bafd0-6d56-42e0-8ef3-c4940b4f18b5",
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@
|
||||||
#include <models/sunspecmodelfactory.h>
|
#include <models/sunspecmodelfactory.h>
|
||||||
#include <models/sunspeccommonmodel.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},
|
: QObject{parent},
|
||||||
m_networkDeviceDiscovery{networkDeviceDiscovery},
|
m_networkDeviceDiscovery{networkDeviceDiscovery},
|
||||||
m_slaveIds{slaveIds},
|
m_slaveId{slaveId},
|
||||||
m_byteOrder{byteOrder}
|
m_byteOrder{byteOrder}
|
||||||
{
|
{
|
||||||
m_scanPorts.append(502);
|
m_scanPorts.append(502);
|
||||||
|
|
@ -130,81 +130,79 @@ void SunSpecDiscovery::checkNetworkDevice(const QHostAddress &address)
|
||||||
// Check all ports for this host
|
// Check all ports for this host
|
||||||
foreach (quint16 port, m_scanPorts) {
|
foreach (quint16 port, m_scanPorts) {
|
||||||
|
|
||||||
foreach (quint16 slaveId, m_slaveIds) {
|
|
||||||
|
|
||||||
SunSpecConnection *connection = new SunSpecConnection(address, port, slaveId, m_byteOrder, this);
|
SunSpecConnection *connection = new SunSpecConnection(address, port, m_slaveId, m_byteOrder, this);
|
||||||
connection->setNumberOfRetries(1);
|
connection->setNumberOfRetries(1);
|
||||||
connection->setTimeout(500);
|
connection->setTimeout(500);
|
||||||
m_connections.append(connection);
|
m_connections.append(connection);
|
||||||
connectionQueue.enqueue(connection);
|
connectionQueue.enqueue(connection);
|
||||||
|
|
||||||
connect(connection, &SunSpecConnection::connectedChanged, this, [this, connection, connectionQueue, address](bool connected){
|
connect(connection, &SunSpecConnection::connectedChanged, this, [this, connection, connectionQueue, address](bool connected){
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
// Disconnected ... done with this connection
|
// 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);
|
cleanupConnection(connection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Successfully connected, we can stop the connection timer which takes care about blocking connection attempts
|
// Success, we found some sunspec models here, let's read some infomation from the models
|
||||||
if (m_connectionTimers.contains(connection)) {
|
|
||||||
QTimer *connectionTimer = m_connectionTimers.take(connection);
|
|
||||||
connectionTimer->stop();
|
|
||||||
connectionTimer->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modbus TCP connected, try to discovery sunspec models...
|
Result result;
|
||||||
connect(connection, &SunSpecConnection::discoveryFinished, this, [=](bool success){
|
result.address = address;
|
||||||
if (!success) {
|
result.port = connection->port();
|
||||||
qCDebug(dcSunSpec()) << "Discovery: SunSpec discovery failed on"
|
result.slaveId = connection->slaveId();
|
||||||
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
|
|
||||||
<< "slave ID:" << connection->slaveId() << "Continue...";
|
|
||||||
cleanupConnection(connection);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success, we found some sunspec models here, let's read some infomation from the models
|
qCDebug(dcSunSpec()) << "Discovery: --> Found SunSpec devices on" << result.networkDeviceInfo << "port" << result.port << "slave ID:" << result.slaveId;
|
||||||
|
foreach (SunSpecModel *model, connection->models()) {
|
||||||
Result result;
|
if (model->modelId() == SunSpecModelFactory::ModelIdCommon) {
|
||||||
result.address = address;
|
SunSpecCommonModel *commonModel = qobject_cast<SunSpecCommonModel *>(model);
|
||||||
result.port = connection->port();
|
QString manufacturer = commonModel->manufacturer();
|
||||||
result.slaveId = connection->slaveId();
|
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...
|
// Run SunSpec discovery on connection...
|
||||||
connect(connection->modbusTcpClient(), &QModbusTcpClient::errorOccurred, this, [=](QModbusDevice::Error error){
|
if (!connection->startDiscovery()) {
|
||||||
if (error != QModbusDevice::NoError) {
|
qCDebug(dcSunSpec()) << "Discovery: Unable to discover SunSpec data on connection"
|
||||||
qCDebug(dcSunSpec()) << "Discovery: Connection error on"
|
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
|
||||||
<< QString("%1:%2").arg(address.toString()).arg(connection->port())
|
<< "slave ID:" << connection->slaveId() << "Continue...";
|
||||||
<< "slave ID:" << connection->slaveId() << "Continue...";
|
cleanupConnection(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);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pendingConnectionAttempts[address] = connectionQueue;
|
m_pendingConnectionAttempts[address] = connectionQueue;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class SunSpecDiscovery : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
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 {
|
typedef struct Result {
|
||||||
QHostAddress address;
|
QHostAddress address;
|
||||||
NetworkDeviceInfo networkDeviceInfo;
|
NetworkDeviceInfo networkDeviceInfo;
|
||||||
|
|
@ -62,7 +62,7 @@ signals:
|
||||||
private:
|
private:
|
||||||
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
|
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
|
||||||
QList<quint16> m_scanPorts;
|
QList<quint16> m_scanPorts;
|
||||||
QList<quint16> m_slaveIds;
|
quint16 m_slaveId = 1;
|
||||||
SunSpecDataPoint::ByteOrder m_byteOrder;
|
SunSpecDataPoint::ByteOrder m_byteOrder;
|
||||||
|
|
||||||
QDateTime m_startDateTime;
|
QDateTime m_startDateTime;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue