Merge PR #199: Solax: Update to networkdevice interface
commit
6816b5b5e5
|
|
@ -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.
|
||||||
|
|
@ -63,20 +63,23 @@ void IntegrationPluginSolax::discoverThings(ThingDiscoveryInfo *info)
|
||||||
if (!result.serialNumber.isEmpty())
|
if (!result.serialNumber.isEmpty())
|
||||||
title.append(" " + result.serialNumber);
|
title.append(" " + result.serialNumber);
|
||||||
|
|
||||||
ThingDescriptor descriptor(solaxInverterTcpThingClassId, title, result.networkDeviceInfo.address().toString() + " " + result.networkDeviceInfo.macAddress());
|
ThingDescriptor descriptor(solaxInverterTcpThingClassId, title, result.networkDeviceInfo.address().toString());
|
||||||
qCInfo(dcSolax()) << "Discovered:" << descriptor.title() << descriptor.description();
|
qCInfo(dcSolax()) << "Discovered:" << descriptor.title() << descriptor.description();
|
||||||
|
|
||||||
// Check if we already have set up this device
|
|
||||||
Things existingThings = myThings().filterByParam(solaxInverterTcpThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress());
|
|
||||||
if (existingThings.count() == 1) {
|
|
||||||
qCDebug(dcSolax()) << "This solax inverter already exists in the system:" << result.networkDeviceInfo;
|
|
||||||
descriptor.setThingId(existingThings.first()->id());
|
|
||||||
}
|
|
||||||
|
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params << Param(solaxInverterTcpThingMacAddressParamTypeId, result.networkDeviceInfo.macAddress());
|
params << Param(solaxInverterTcpThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress());
|
||||||
|
params << Param(solaxInverterTcpThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName());
|
||||||
|
params << Param(solaxInverterTcpThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress());
|
||||||
// Note: if we discover also the port and modbusaddress, we must fill them in from the discovery here, for now everywhere the defaults...
|
// Note: if we discover also the port and modbusaddress, we must fill them in from the discovery here, for now everywhere the defaults...
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
|
|
||||||
|
// Check if we already have set up this device
|
||||||
|
Thing *existingThing = myThings().findByParams(params);
|
||||||
|
if (existingThing) {
|
||||||
|
qCDebug(dcSolax()) << "This thing already exists in the system:" << result.networkDeviceInfo;
|
||||||
|
descriptor.setThingId(existingThing->id());
|
||||||
|
}
|
||||||
|
|
||||||
info->addThingDescriptor(descriptor);
|
info->addThingDescriptor(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,16 +107,16 @@ void IntegrationPluginSolax::setupThing(ThingSetupInfo *info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MacAddress macAddress = MacAddress(thing->paramValue(solaxInverterTcpThingMacAddressParamTypeId).toString());
|
// Create the monitor
|
||||||
if (!macAddress.isValid()) {
|
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
|
||||||
qCWarning(dcSolax()) << "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(dcSolax()) << "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)) {
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,25 @@
|
||||||
"id": "fa1a559a-12a6-416f-ab77-a431a38bc3c2",
|
"id": "fa1a559a-12a6-416f-ab77-a431a38bc3c2",
|
||||||
"createMethods": ["discovery"],
|
"createMethods": ["discovery"],
|
||||||
"discoveryType": "weak",
|
"discoveryType": "weak",
|
||||||
"interfaces": ["solarinverter", "connectable"],
|
"interfaces": ["solarinverter", "connectable", "networkdevice"],
|
||||||
"providedInterfaces": [ "energymeter", "energystorage"],
|
"providedInterfaces": [ "energymeter", "energystorage"],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
|
{
|
||||||
|
"id": "a736047f-ba25-4c47-b2b8-7caca790e5fe",
|
||||||
|
"name": "address",
|
||||||
|
"displayName": "Host address",
|
||||||
|
"type": "QString",
|
||||||
|
"inputType": "IPv4Address",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "58fd35e1-fef7-497c-8cdf-91358fd6b0be",
|
||||||
|
"name": "hostName",
|
||||||
|
"displayName": "Host name",
|
||||||
|
"type": "QString",
|
||||||
|
"inputType": "TextLine",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "acdee28d-4c73-4ed9-ad1b-d5d1440164c0",
|
"id": "acdee28d-4c73-4ed9-ad1b-d5d1440164c0",
|
||||||
"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.
|
||||||
|
|
@ -46,10 +46,11 @@ void SolaxDiscovery::startDiscovery()
|
||||||
m_startDateTime = QDateTime::currentDateTime();
|
m_startDateTime = QDateTime::currentDateTime();
|
||||||
|
|
||||||
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
|
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
|
||||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &SolaxDiscovery::checkNetworkDevice);
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &SolaxDiscovery::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, [this, discoveryReply](){
|
||||||
qCDebug(dcSolax()) << "Discovery: Network discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices";
|
qCDebug(dcSolax()) << "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,19 +65,19 @@ QList<SolaxDiscovery::SolaxDiscoveryResult> SolaxDiscovery::discoveryResults() c
|
||||||
return m_discoveryResults;
|
return m_discoveryResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SolaxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo)
|
void SolaxDiscovery::checkNetworkDevice(const QHostAddress &address)
|
||||||
{
|
{
|
||||||
// Create a Solax connection and try to initialize it.
|
// Create a Solax 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).
|
||||||
// We cloud tough also filter the result only for certain software versions, manufactueres or whatever...
|
// We cloud tough also filter the result only for certain software versions, manufactueres or whatever...
|
||||||
|
|
||||||
SolaxModbusTcpConnection *connection = new SolaxModbusTcpConnection(networkDeviceInfo.address(), m_port, m_modbusAddress, this);
|
SolaxModbusTcpConnection *connection = new SolaxModbusTcpConnection(address, m_port, m_modbusAddress, this);
|
||||||
connection->modbusTcpMaster()->setTimeout(500);
|
connection->modbusTcpMaster()->setTimeout(500);
|
||||||
connection->modbusTcpMaster()->setNumberOfRetries(0);
|
connection->modbusTcpMaster()->setNumberOfRetries(0);
|
||||||
m_connections.append(connection);
|
m_connections.append(connection);
|
||||||
|
|
||||||
connect(connection, &SolaxModbusTcpConnection::reachableChanged, this, [=](bool reachable){
|
connect(connection, &SolaxModbusTcpConnection::reachableChanged, this, [this, connection, address](bool reachable){
|
||||||
if (!reachable) {
|
if (!reachable) {
|
||||||
// Disconnected ... done with this connection
|
// Disconnected ... done with this connection
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
|
|
@ -84,14 +85,14 @@ void SolaxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceIn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modbus TCP connected and reachable call successed, let's try to initialize it!
|
// Modbus TCP connected and reachable call successed, let's try to initialize it!
|
||||||
connect(connection, &SolaxModbusTcpConnection::initializationFinished, this, [=](bool success){
|
connect(connection, &SolaxModbusTcpConnection::initializationFinished, this, [this, connection, address](bool success){
|
||||||
if (!success) {
|
if (!success) {
|
||||||
qCDebug(dcSolax()) << "Discovery: Initialization failed on" << networkDeviceInfo.address().toString() << "Continue...";;
|
qCDebug(dcSolax()) << "Discovery: Initialization failed on" << address.toString() << "Continue...";;
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCInfo(dcSolax()) << "Discovery: Initialized successfully" << networkDeviceInfo << connection->factoryName() << connection->serialNumber();
|
qCInfo(dcSolax()) << "Discovery: Initialized successfully" << address.toString() << connection->factoryName() << connection->serialNumber();
|
||||||
|
|
||||||
// Let's make sure the information are correct
|
// Let's make sure the information are correct
|
||||||
if (connection->factoryName().toLower().contains("solax")) {
|
if (connection->factoryName().toLower().contains("solax")) {
|
||||||
|
|
@ -99,7 +100,7 @@ void SolaxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceIn
|
||||||
result.productName = connection->moduleName();
|
result.productName = connection->moduleName();
|
||||||
result.manufacturerName = connection->factoryName();
|
result.manufacturerName = connection->factoryName();
|
||||||
result.serialNumber = connection->serialNumber();
|
result.serialNumber = connection->serialNumber();
|
||||||
result.networkDeviceInfo = networkDeviceInfo;
|
result.address = address;
|
||||||
m_discoveryResults.append(result);
|
m_discoveryResults.append(result);
|
||||||
|
|
||||||
qCInfo(dcSolax()) << "Discovery: --> Found" << result.manufacturerName << result.productName
|
qCInfo(dcSolax()) << "Discovery: --> Found" << result.manufacturerName << result.productName
|
||||||
|
|
@ -110,31 +111,31 @@ void SolaxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceIn
|
||||||
connection->disconnectDevice();
|
connection->disconnectDevice();
|
||||||
});
|
});
|
||||||
|
|
||||||
qCDebug(dcSolax()) << "Discovery: The host" << networkDeviceInfo << "is reachable, trying to initialize...";
|
qCDebug(dcSolax()) << "Discovery: The host" << address << "is reachable, trying to initialize...";
|
||||||
if (!connection->initialize()) {
|
if (!connection->initialize()) {
|
||||||
qCDebug(dcSolax()) << "Discovery: Unable to initialize connection on" << networkDeviceInfo.address().toString() << "Continue...";;
|
qCDebug(dcSolax()) << "Discovery: Unable to initialize connection on" << address.toString() << "Continue...";;
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// If we get any error...skip this host...
|
// If we get any error...skip this host...
|
||||||
connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionStateChanged, this, [=](bool connected){
|
connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionStateChanged, this, [this, address](bool connected){
|
||||||
if (connected) {
|
if (connected) {
|
||||||
qCDebug(dcSolax()) << "Discovery: Connected with" << networkDeviceInfo.address().toString() << m_port;
|
qCDebug(dcSolax()) << "Discovery: Connected with" << address.toString() << m_port;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 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, [this, connection, address](QModbusDevice::Error error){
|
||||||
if (error != QModbusDevice::NoError) {
|
if (error != QModbusDevice::NoError) {
|
||||||
qCDebug(dcSolax()) << "Discovery: Connection error on" << networkDeviceInfo.address().toString() << "Continue...";;
|
qCDebug(dcSolax()) << "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, &SolaxModbusTcpConnection::checkReachabilityFailed, this, [=](){
|
connect(connection, &SolaxModbusTcpConnection::checkReachabilityFailed, this, [this, connection, address](){
|
||||||
qCDebug(dcSolax()) << "Discovery: Check reachability failed on" << networkDeviceInfo.address().toString() << "Continue...";;
|
qCDebug(dcSolax()) << "Discovery: Check reachability failed on" << address.toString() << "Continue...";;
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -154,10 +155,15 @@ void SolaxDiscovery::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 (SolaxModbusTcpConnection *connection, m_connections)
|
foreach (SolaxModbusTcpConnection *connection, m_connections)
|
||||||
cleanupConnection(connection);
|
cleanupConnection(connection);
|
||||||
|
|
||||||
qCInfo(dcSolax()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count() << "Solax Inverters in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz");
|
qCInfo(dcSolax()) << "Discovery: Finished the discovery process. Found" << m_discoveryResults.count()
|
||||||
|
<< "Solax Inverters in" << QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz");
|
||||||
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.
|
||||||
|
|
@ -47,6 +47,7 @@ public:
|
||||||
QString productName;
|
QString productName;
|
||||||
QString manufacturerName;
|
QString manufacturerName;
|
||||||
QString serialNumber;
|
QString serialNumber;
|
||||||
|
QHostAddress address;
|
||||||
NetworkDeviceInfo networkDeviceInfo;
|
NetworkDeviceInfo networkDeviceInfo;
|
||||||
} SolaxDiscoveryResult;
|
} SolaxDiscoveryResult;
|
||||||
|
|
||||||
|
|
@ -61,13 +62,12 @@ 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;
|
||||||
|
|
||||||
QList<SolaxModbusTcpConnection *> m_connections;
|
QList<SolaxModbusTcpConnection *> m_connections;
|
||||||
QList<SolaxDiscoveryResult> m_discoveryResults;
|
QList<SolaxDiscoveryResult> m_discoveryResults;
|
||||||
|
NetworkDeviceInfos m_networkDeviceInfos;
|
||||||
|
|
||||||
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
|
void checkNetworkDevice(const QHostAddress &address);
|
||||||
void cleanupConnection(SolaxModbusTcpConnection *connection);
|
void cleanupConnection(SolaxModbusTcpConnection *connection);
|
||||||
|
|
||||||
void finishDiscovery();
|
void finishDiscovery();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue