Improved error handling logic to connect

master
Hermann Detz 2021-05-20 09:49:17 +02:00 committed by Michael Zanetti
parent a71b86f82e
commit 82dc46cd3b
6 changed files with 77 additions and 31 deletions

View File

@ -153,7 +153,7 @@ void IntegrationPluginMTec::update(Thing *thing)
} }
} }
void IntegrationPluginMTec::onConnectedChanged(bool connected) void IntegrationPluginMTec::onConnectedChanged(MTecHelpers::ConnectionState state)
{ {
MTec *mtec = qobject_cast<MTec *>(sender()); MTec *mtec = qobject_cast<MTec *>(sender());
Thing *thing = m_mtecConnections.key(mtec); Thing *thing = m_mtecConnections.key(mtec);
@ -163,7 +163,11 @@ void IntegrationPluginMTec::onConnectedChanged(bool connected)
if (!thing) if (!thing)
return; return;
thing->setStateValue(mtecConnectedStateTypeId, connected); if (state == MTecHelpers::ConnectionState::Online) {
thing->setStateValue(mtecConnectedStateTypeId, true);
}
thing->setStateValue(mtecStatusStateTypeId, MTecHelpers::connectionStateToString(state));
} }
void IntegrationPluginMTec::onStatusUpdated(const MTecInfo &info) void IntegrationPluginMTec::onStatusUpdated(const MTecInfo &info)

View File

@ -34,6 +34,7 @@
#include "plugintimer.h" #include "plugintimer.h"
#include "mtec.h" #include "mtec.h"
#include "mtechelpers.h"
#include <QUuid> #include <QUuid>
@ -62,7 +63,7 @@ private:
QHash<QUuid, ThingActionInfo *> m_asyncActions; QHash<QUuid, ThingActionInfo *> m_asyncActions;
private slots: private slots:
void onConnectedChanged(bool connected); void onConnectedChanged(MTecHelpers::ConnectionState state);
void onRefreshTimer(); void onRefreshTimer();
void onStatusUpdated(const MTecInfo &info); void onStatusUpdated(const MTecInfo &info);

View File

@ -41,7 +41,10 @@ MTec::MTec(const QHostAddress &address, QObject *parent) :
m_modbusMaster = new ModbusTCPMaster(address, 502, this); m_modbusMaster = new ModbusTCPMaster(address, 502, this);
qCDebug(dcMTec()) << "created ModbusTCPMaster"; qCDebug(dcMTec()) << "created ModbusTCPMaster";
m_connected = m_modbusMaster->connectDevice();
if (m_modbusMaster->connectDevice()) {
emit connectedChanged(MTecHelpers::ConnectionState::Connecting);
}
connect(m_modbusMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &MTec::onReceivedHoldingRegister); connect(m_modbusMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &MTec::onReceivedHoldingRegister);
connect(m_modbusMaster, &ModbusTCPMaster::readRequestError, this, &MTec::onModbusError); connect(m_modbusMaster, &ModbusTCPMaster::readRequestError, this, &MTec::onModbusError);
@ -56,19 +59,22 @@ void MTec::onModbusError()
{ {
qCWarning(dcMTec()) << "MTec: Received modbus error"; qCWarning(dcMTec()) << "MTec: Received modbus error";
emit connectedChanged(false); /* Only emit connected changed signal, if a soft connection
* had already been established.
* This avoids a series of possibly fake connection state changes,
* while the modbus server in the heatpump is starting up. */
if (m_softConnection) {
m_softConnection = false;
emit connectedChanged(MTecHelpers::ConnectionState::Offline);
}
} }
void MTec::onRequestStatus() void MTec::onRequestStatus()
{ {
if ((m_connected) && (!m_firstTimeout.isValid())) { if ((m_softConnection) ||
/* No timestamp for timeout of first telegram defined, ((m_connected) && (m_requestsSent < MTec::ConnectionRetries))) {
* -> first request has not yet been sent
* -> do it now */
/* Note: m_firstRequest is set to false in if (m_requestsSent < MTec::ConnectionRetries) {
* the onReceivedHoldingRegister function */
if (m_firstRequest == true) {
m_firstTimeout = QDateTime::currentDateTime(); m_firstTimeout = QDateTime::currentDateTime();
m_firstTimeout = m_firstTimeout.addSecs(MTec::FirstConnectionTimeout); m_firstTimeout = m_firstTimeout.addSecs(MTec::FirstConnectionTimeout);
@ -83,17 +89,14 @@ void MTec::onRequestStatus()
/* Set back original modbus timeout */ /* Set back original modbus timeout */
m_modbusMaster->setTimeout(m_modbusTimeout); m_modbusMaster->setTimeout(m_modbusTimeout);
} }
} else {
QDateTime now = QDateTime::currentDateTime();
if (m_firstTimeout.msecsTo(now) < MTec::FirstConnectionTimeout) { } else {
/* Timeout of first request not yet reached qCDebug(dcMTec()) << "Max number of modbus connects reached, giving up";
* -> return without sending another request */ return;
return;
}
} }
m_modbusMaster->readHoldingRegister(MTec::ModbusUnitID, MTec::ActualPowerConsumption, 1); m_modbusMaster->readHoldingRegister(MTec::ModbusUnitID, MTec::ActualPowerConsumption, 1);
m_requestsSent ++;
} }
void MTec::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector<quint16> &value) void MTec::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector<quint16> &value)
@ -102,7 +105,8 @@ void MTec::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const
/* Some response was received, so the modbus communication is /* Some response was received, so the modbus communication is
* established. */ * established. */
m_firstRequest = false; m_softConnection = true;
emit connectedChanged(MTecHelpers::ConnectionState::Online);
switch (modbusRegister) { switch (modbusRegister) {
case ActualPowerConsumption: case ActualPowerConsumption:

View File

@ -37,6 +37,7 @@
#include "../modbus/modbustcpmaster.h" #include "../modbus/modbustcpmaster.h"
#include "mtecinfo.h" #include "mtecinfo.h"
#include "mtechelpers.h"
class MTec : public QObject class MTec : public QObject
{ {
@ -62,6 +63,9 @@ private:
/** Modbus Unit ID (undocumented, guessing 1 for now) */ /** Modbus Unit ID (undocumented, guessing 1 for now) */
static const quint16 ModbusUnitID = 1; static const quint16 ModbusUnitID = 1;
/** Number of retries to establish a modbus connection with the heat pump */
static const int ConnectionRetries = 3;
/** The following modbus addresses can be read: */ /** The following modbus addresses can be read: */
enum RegisterList { enum RegisterList {
/** /**
@ -108,15 +112,16 @@ private:
/** This structure is filled by the receivedStatus... functions */ /** This structure is filled by the receivedStatus... functions */
MTecInfo m_info ; MTecInfo m_info ;
bool m_firstRequest = true; int m_requestsSent = 0;
bool m_connected = false; bool m_connected = false;
bool m_softConnection = false;
QDateTime m_firstTimeout; QDateTime m_firstTimeout;
int m_modbusTimeout; int m_modbusTimeout;
signals: signals:
void connectedChanged(bool connected); void connectedChanged(MTecHelpers::ConnectionState state);
void statusUpdated(const MTecInfo &info); void statusUpdated(const MTecInfo &info);
public slots: public slots:

View File

@ -44,19 +44,41 @@ void MTecHelpers::convertFloatToRegister(quint16 &reg, float value)
reg = qRound(value * 100.0); reg = qRound(value * 100.0);
} }
QString MTecHelpers::externalHeatSourceRequestToString(quint16 value) QString MTecHelpers::connectionStateToString(ConnectionState state)
{ {
QString str{}; QString str{};
switch (value) { switch (state) {
case 0: case Offline:
str = "No request, external heat source must be turned off"; str = QT_TR_NOOP("Off");
break; break;
case 1: case Connecting:
str = "External heat source is released and can be switched on"; str = QT_TR_NOOP("Connecting");
break; break;
case 2: case Online:
str = "External heat source is required and must be turned on"; str = QT_TR_NOOP("Connected");
break;
case Error:
str = QT_TR_NOOP("Error");
break;
}
return str;
}
QString MTecHelpers::externalHeatSourceRequestToString(quint16 value)
{
QString str{};
switch (value) {
case 0:
str = QT_TR_NOOP("No request, external heat source must be turned off");
break;
case 1:
str = QT_TR_NOOP("External heat source is released and can be switched on");
break;
case 2:
str = QT_TR_NOOP("External heat source is required and must be turned on");
break; break;
} }

View File

@ -32,13 +32,23 @@
#define MTECHELPERS_H #define MTECHELPERS_H
#include <QtGlobal> #include <QtGlobal>
#include <QObject>
#include <QString> #include <QString>
class MTecHelpers { class MTecHelpers : public QObject {
public: public:
enum ConnectionState {
Offline,
Connecting,
Online,
Error
};
Q_ENUM(ConnectionState);
static float convertRegisterToFloat(quint16 reg); static float convertRegisterToFloat(quint16 reg);
static void convertFloatToRegister(quint16 &reg, float value); static void convertFloatToRegister(quint16 &reg, float value);
static QString connectionStateToString(ConnectionState state);
static QString externalHeatSourceRequestToString(quint16 value); static QString externalHeatSourceRequestToString(quint16 value);
}; };