From 45de9c1e5bcdd8b4feb0e2503589a0c8587096e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 23 Mar 2022 08:56:34 +0100 Subject: [PATCH 01/42] Update modbus tool structure and extend functionality --- modbus/tools/README.md | 7 +- modbus/tools/connectiontool/__init__.py | 0 modbus/tools/connectiontool/modbusrtu.py | 381 ++++++++ modbus/tools/connectiontool/modbustcp.py | 385 ++++++++ modbus/tools/connectiontool/toolcommon.py | 496 ++++++++++ modbus/tools/generate-connection.py | 1071 +++------------------ 6 files changed, 1404 insertions(+), 936 deletions(-) create mode 100644 modbus/tools/connectiontool/__init__.py create mode 100644 modbus/tools/connectiontool/modbusrtu.py create mode 100644 modbus/tools/connectiontool/modbustcp.py create mode 100644 modbus/tools/connectiontool/toolcommon.py diff --git a/modbus/tools/README.md b/modbus/tools/README.md index 72b0309..e1e2e1e 100644 --- a/modbus/tools/README.md +++ b/modbus/tools/README.md @@ -23,6 +23,7 @@ The basic structure of the modbus register JSON looks like following example: ``` { + "protocol": "TCP", "endianness": "BigEndian", "enums": [ { @@ -71,7 +72,7 @@ The basic structure of the modbus register JSON looks like following example: ## Endianness -When converting multiple registers to one data type (i.e. 2 registers uint16 values to one uint32), the order of the registers are important to align with the endiness of the data receiving. +When converting multiple registers to one data type (i.e. 2 registers uint16 values to one uint32), the order of the registers are important to align with the endianness of the data receiving. There are 2 possibilities: @@ -133,9 +134,9 @@ Earch register will be defined as a property in the resulting class modbus TCP c On many device it is possible to read multiple registers in one modbus call. This can improve speed significantly when reading many register addresses which are in a row. -> Important: all registers within the block must exist, be in a row with no gaps inbetween! +> Important: all registers within the block must exist, be in a row with no gaps inbetween and from the same function type! -A block sequence looks like this and will define a read method for reading the entwire block. Writing multiple blocks is currently not supported since not needed so far, but could be added to. In any case, all registers must be read or written, never have combinations. +A block sequence looks like this and will define a read method for reading the entwire block. Writing multiple blocks is currently not supported since not needed so far, but could be added too. In any case, all registers must be read or written, never have combinations. * `id`: Mandatory. The id defines the name of the block used in the resulting class. * `readSchedule`: Optional. Defines when the register needs to be fetched. If no read schedule has been defined, the class will provide only the update methods, but will not read the value during `initialize()` or `update()` calls. Possible values are: diff --git a/modbus/tools/connectiontool/__init__.py b/modbus/tools/connectiontool/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modbus/tools/connectiontool/modbusrtu.py b/modbus/tools/connectiontool/modbusrtu.py new file mode 100644 index 0000000..cdddf40 --- /dev/null +++ b/modbus/tools/connectiontool/modbusrtu.py @@ -0,0 +1,381 @@ +# Copyright (C) 2021 - 2022 nymea GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from .toolcommon import * + +############################################################## + +def writePropertyGetSetMethodDeclarationsRtu(fileDescriptor, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + if 'unit' in registerDefinition and registerDefinition['unit'] != '': + writeLine(fileDescriptor, ' /* %s [%s] - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) + else: + writeLine(fileDescriptor, ' /* %s - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + + writeLine(fileDescriptor, ' %s %s() const;' % (propertyTyp, propertyName)) + + # Check if we require a set method + if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO': + writeLine(fileDescriptor, ' ModbusRtuReply *set%s(%s %s);' % (propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName)) + + writeLine(fileDescriptor) + + +def writePropertyGetSetMethodImplementationsRtu(fileDescriptor, className, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + # Get + if 'enum' in registerDefinition: + writeLine(fileDescriptor, '%s::%s %s::%s() const' % (className, propertyTyp, className, propertyName)) + else: + writeLine(fileDescriptor, '%s %s::%s() const' % (propertyTyp, className, propertyName)) + + writeLine(fileDescriptor, '{') + writeLine(fileDescriptor, ' return m_%s;' % propertyName) + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + + # Check if we require a set method + if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO': + writeLine(fileDescriptor, 'ModbusRtuReply *%s::set%s(%s %s)' % (className, propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName)) + writeLine(fileDescriptor, '{') + + writeLine(fileDescriptor, ' QVector values = %s;' % getConversionToValueMethod(registerDefinition)) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Write \\"%s\\" register:" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + if registerDefinition['registerType'] == 'holdingRegister': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeHoldingRegisters(m_slaveId, %s, values);' % (registerDefinition['address'])) + elif registerDefinition['registerType'] == 'coils': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeCoils(m_slaveId, %s, values);' % (registerDefinition['address'])) + else: + print('Error: invalid register type for writing.') + exit(1) + + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + +############################################################## + + +def writePropertyUpdateMethodImplementationsRtu(fileDescriptor, className, registerDefinitions): + for registerDefinition in registerDefinitions: + if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': + continue + + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + writeLine(fileDescriptor, 'void %s::update%s()' % (className, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, '{') + writeLine(fileDescriptor, ' // Update registers from %s' % registerDefinition['description']) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read \\"%s\\" register:" << %s << "size:" << %s;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' ModbusRtuReply *reply = read%s();' % (propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' if (reply) {') + writeLine(fileDescriptor, ' if (!reply->isFinished()) {') + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') + writeLine(fileDescriptor, ' QVector values = reply->result();') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' process%sRegisterValues(values);' % (propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating \\"%s\\" registers" << error << reply->errorString();' % (className, registerDefinition['description'])) + writeLine(fileDescriptor, ' emit reply->finished();') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers";' % (className, registerDefinition['description'])) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + +############################################################## + +def writeBlockUpdateMethodImplementationsRtu(fileDescriptor, className, blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerType = blockRegister['registerType'] + + registerCount += 1 + blockSize += blockRegister['size'] + + writeLine(fileDescriptor, 'void %s::update%sBlock()' % (className, blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor, '{') + writeLine(fileDescriptor, ' // Update register block \"%s\"' % blockName) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read block \\"%s\\" registers from:" << %s << "size:" << %s;' % (className, blockName, blockStartAddress, blockSize)) + + + # Build request depending on the register type + if registerType == 'inputRegister': + writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + elif registerType == 'discreteInputs': + writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readDiscreteInput(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + elif registerType == 'coils': + writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readCoil(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + else: + #Default to holdingRegister + writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + + writeLine(fileDescriptor, ' if (reply) {') + writeLine(fileDescriptor, ' if (!reply->isFinished()) {') + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') + writeLine(fileDescriptor, ' QVector blockValues = reply->result();') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize)) + + # Start parsing the registers using offsets + offset = 0 + for i, blockRegister in enumerate(blockRegisters): + propertyName = blockRegister['id'] + writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size'])) + offset += blockRegister['size'] + + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName)) + writeLine(fileDescriptor, ' emit reply->finished();') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName)) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + +############################################################## + +def writeInternalPropertyReadMethodDeclarationsRtu(fileDescriptor, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + writeLine(fileDescriptor, ' ModbusRtuReply *read%s();' % (propertyName[0].upper() + propertyName[1:])) + + +def writeInternalPropertyReadMethodImplementationsRtu(fileDescriptor, className, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + writeLine(fileDescriptor, 'ModbusRtuReply *%s::read%s()' % (className, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, '{') + + # Build request depending on the register type + if registerDefinition['registerType'] == 'inputRegister': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readInputRegister(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + elif registerDefinition['registerType'] == 'discreteInputs': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readDiscreteInput(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + elif registerDefinition['registerType'] == 'coils': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readCoil(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + else: + #Default to holdingRegister + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readHoldingRegister(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + +############################################################## + +def writeInternalBlockReadMethodDeclarationsRtu(fileDescriptor, blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerType = blockRegister['registerType'] + + registerCount += 1 + blockSize += blockRegister['size'] + + writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount)) + for i, registerDefinition in enumerate(blockRegisters): + if 'unit' in registerDefinition and registerDefinition['unit'] != '': + writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) + else: + writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' */ ' ) + writeLine(fileDescriptor, ' ModbusRtuReply *readBlock%s();' % (blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor) + + +def writeInternalBlockReadMethodImplementationsRtu(fileDescriptor, className, blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerType = blockRegister['registerType'] + + registerCount += 1 + blockSize += blockRegister['size'] + + + writeLine(fileDescriptor, 'ModbusRtuReply *%s::readBlock%s()' % (className, blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor, '{') + + # Build request depending on the register type + if registerType == 'inputRegister': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readInputRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + elif registerType == 'discreteInputs': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readDiscreteInput(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + elif registerType == 'coils': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readCoil(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + else: + #Default to holdingRegister + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readHoldingRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + +############################################################## + +def writeInitMethodImplementationRtu(fileDescriptor, className, registerDefinitions, blockDefinitions): + writeLine(fileDescriptor, 'void %s::initialize()' % (className)) + writeLine(fileDescriptor, '{') + + # First check if there are any init registers + initRequired = False + for registerDefinition in registerDefinitions: + if registerDefinition['readSchedule'] == 'init': + initRequired = True + break + + for blockDefinition in blockDefinitions: + if 'readSchedule' in blockDefinition and blockDefinition['readSchedule'] == 'init': + initRequired = True + break + + if initRequired: + writeLine(fileDescriptor, ' ModbusRtuReply *reply = nullptr;') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' if (!m_pendingInitReplies.isEmpty()) {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Tried to initialize but there are still some init replies pending.";' % className) + writeLine(fileDescriptor, ' return;') + writeLine(fileDescriptor, ' }') + + # Read individual registers + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + + if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' // Read %s' % registerDefinition['description']) + writeLine(fileDescriptor, ' reply = read%s();' % (propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' if (reply) {') + writeLine(fileDescriptor, ' if (!reply->isFinished()) {') + writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);') + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') + writeLine(fileDescriptor, ' QVector values = reply->result();') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' process%sRegisterValues(values);' % (propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);') + writeLine(fileDescriptor, ' verifyInitFinished();') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating \\"%s\\" registers" << error << reply->errorString();' % (className, registerDefinition['description'])) + writeLine(fileDescriptor, ' emit reply->finished();') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers";' % (className, registerDefinition['description'])) + writeLine(fileDescriptor, ' }') + + # Read init blocks + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + + if 'readSchedule' in blockDefinition and blockDefinition['readSchedule'] == 'init': + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerType = blockRegister['registerType'] + + registerCount += 1 + blockSize += blockRegister['size'] + + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' // Read %s' % blockName) + writeLine(fileDescriptor, ' reply = readBlock%s();' % (blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor, ' if (reply) {') + writeLine(fileDescriptor, ' if (!reply->isFinished()) {') + writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);') + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') + writeLine(fileDescriptor, ' QVector blockValues = reply->result();') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize)) + + # Start parsing the registers using offsets + offset = 0 + for i, blockRegister in enumerate(blockRegisters): + propertyName = blockRegister['id'] + propertyTyp = getCppDataType(blockRegister) + writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size'])) + offset += blockRegister['size'] + + writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);') + writeLine(fileDescriptor, ' verifyInitFinished();') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName)) + writeLine(fileDescriptor, ' emit reply->finished();') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName)) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor) + + else: + writeLine(fileDescriptor, ' // No init registers defined. Nothing to be done and we are finished.') + writeLine(fileDescriptor, ' emit initializationFinished();') + + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) diff --git a/modbus/tools/connectiontool/modbustcp.py b/modbus/tools/connectiontool/modbustcp.py new file mode 100644 index 0000000..fb2b8e5 --- /dev/null +++ b/modbus/tools/connectiontool/modbustcp.py @@ -0,0 +1,385 @@ +# Copyright (C) 2021 - 2022 nymea GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from .toolcommon import * + +############################################################## + +def writePropertyGetSetMethodDeclarationsTcp(fileDescriptor, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + if 'unit' in registerDefinition and registerDefinition['unit'] != '': + writeLine(fileDescriptor, ' /* %s [%s] - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) + else: + writeLine(fileDescriptor, ' /* %s - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + + writeLine(fileDescriptor, ' %s %s() const;' % (propertyTyp, propertyName)) + + # Check if we require a set method + if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO': + writeLine(fileDescriptor, ' QModbusReply *set%s(%s %s);' % (propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName)) + + writeLine(fileDescriptor) + + +def writePropertyGetSetMethodImplementationsTcp(fileDescriptor, className, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + # Get + if 'enum' in registerDefinition: + writeLine(fileDescriptor, '%s::%s %s::%s() const' % (className, propertyTyp, className, propertyName)) + else: + writeLine(fileDescriptor, '%s %s::%s() const' % (propertyTyp, className, propertyName)) + + writeLine(fileDescriptor, '{') + writeLine(fileDescriptor, ' return m_%s;' % propertyName) + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + + # Check if we require a set method + if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO': + writeLine(fileDescriptor, 'QModbusReply *%s::set%s(%s %s)' % (className, propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName)) + writeLine(fileDescriptor, '{') + + writeLine(fileDescriptor, ' QVector values = %s;' % getConversionToValueMethod(registerDefinition)) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Write \\"%s\\" register:" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + if registerDefinition['registerType'] == 'holdingRegister': + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, values.count());' % (registerDefinition['address'])) + elif registerDefinition['registerType'] == 'coils': + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, values.count());' % (registerDefinition['address'])) + else: + print('Error: invalid register type for writing.') + exit(1) + + writeLine(fileDescriptor, ' request.setValues(values);') + writeLine(fileDescriptor, ' return sendWriteRequest(request, m_slaveId);') + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + +############################################################## + +def writePropertyUpdateMethodImplementationsTcp(fileDescriptor, className, registerDefinitions): + for registerDefinition in registerDefinitions: + if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': + continue + + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + writeLine(fileDescriptor, 'void %s::update%s()' % (className, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, '{') + writeLine(fileDescriptor, ' // Update registers from %s' % registerDefinition['description']) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read \\"%s\\" register:" << %s << "size:" << %s;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' QModbusReply *reply = read%s();' % (propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' if (reply) {') + writeLine(fileDescriptor, ' if (!reply->isFinished()) {') + writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);') + writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {') + writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating \\"%s\\" registers from" << hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description'])) + writeLine(fileDescriptor, ' emit reply->finished(); // To make sure it will be deleted') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' delete reply; // Broadcast reply returns immediatly') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers from" << hostAddress().toString() << errorString();' % (className, registerDefinition['description'])) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + +############################################################## + +def writeBlockUpdateMethodImplementationsTcp(fileDescriptor, className, blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerType = blockRegister['registerType'] + + registerCount += 1 + blockSize += blockRegister['size'] + + writeLine(fileDescriptor, 'void %s::update%sBlock()' % (className, blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor, '{') + writeLine(fileDescriptor, ' // Update register block \"%s\"' % blockName) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read block \\"%s\\" registers from:" << %s << "size:" << %s;' % (className, blockName, blockStartAddress, blockSize)) + writeLine(fileDescriptor, ' QModbusReply *reply = readBlock%s();' % (blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor, ' if (reply) {') + writeLine(fileDescriptor, ' if (!reply->isFinished()) {') + writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {') + writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();') + writeLine(fileDescriptor, ' const QVector blockValues = unit.values();') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize)) + + # Start parsing the registers using offsets + offset = 0 + for i, blockRegister in enumerate(blockRegisters): + propertyName = blockRegister['id'] + propertyTyp = getCppDataType(blockRegister) + writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size'])) + offset += blockRegister['size'] + + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName)) + writeLine(fileDescriptor, ' emit reply->finished();') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName)) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + +############################################################## + +def writeInternalPropertyReadMethodDeclarationsTcp(fileDescriptor, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + writeLine(fileDescriptor, ' QModbusReply *read%s();' % (propertyName[0].upper() + propertyName[1:])) + + +def writeInternalPropertyReadMethodImplementationsTcp(fileDescriptor, className, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + writeLine(fileDescriptor, 'QModbusReply *%s::read%s()' % (className, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, '{') + + # Build request depending on the register type + if registerDefinition['registerType'] == 'inputRegister': + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + elif registerDefinition['registerType'] == 'discreteInputs': + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + elif registerDefinition['registerType'] == 'coils': + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + else: + #Default to holdingRegister + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + + writeLine(fileDescriptor, ' return sendReadRequest(request, m_slaveId);') + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + + +############################################################## + +def writeInternalBlockReadMethodDeclarationsTcp(fileDescriptor, blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerType = blockRegister['registerType'] + + registerCount += 1 + blockSize += blockRegister['size'] + + writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount)) + for i, registerDefinition in enumerate(blockRegisters): + if 'unit' in registerDefinition and registerDefinition['unit'] != '': + writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) + else: + writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' */ ' ) + writeLine(fileDescriptor, ' QModbusReply *readBlock%s();' % (blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor) + + +def writeInternalBlockReadMethodImplementationsTcp(fileDescriptor, className, blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerType = blockRegister['registerType'] + + registerCount += 1 + blockSize += blockRegister['size'] + + + writeLine(fileDescriptor, 'QModbusReply *%s::readBlock%s()' % (className, blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor, '{') + + # Build request depending on the register type + if registerType == 'inputRegister': + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, %s, %s);' % (blockStartAddress, blockSize)) + elif registerType == 'discreteInputs': + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, %s, %s);' % (blockStartAddress, blockSize)) + elif registerType == 'coils': + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, %s);' % (blockStartAddress, blockSize)) + else: + #Default to holdingRegister + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, %s);' % (blockStartAddress, blockSize)) + + writeLine(fileDescriptor, ' return sendReadRequest(request, m_slaveId);') + + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + +############################################################## + +def writeInitMethodImplementationTcp(fileDescriptor, className, registerDefinitions, blockDefinitions): + writeLine(fileDescriptor, 'void %s::initialize()' % (className)) + writeLine(fileDescriptor, '{') + + # First check if there are any init registers + initRequired = False + for registerDefinition in registerDefinitions: + if registerDefinition['readSchedule'] == 'init': + initRequired = True + break + + for blockDefinition in blockDefinitions: + if 'readSchedule' in blockDefinition and blockDefinition['readSchedule'] == 'init': + initRequired = True + break + + if initRequired: + writeLine(fileDescriptor, ' QModbusReply *reply = nullptr;') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' if (!m_pendingInitReplies.isEmpty()) {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Tried to initialize but there are still some init replies pending.";' % className) + writeLine(fileDescriptor, ' return;') + writeLine(fileDescriptor, ' }') + + # Read individual registers + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + + if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' // Read %s' % registerDefinition['description']) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read init \\"%s\\" register:" << %s << "size:" << %s;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' reply = read%s();' % (propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' if (reply) {') + writeLine(fileDescriptor, ' if (!reply->isFinished()) {') + writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);') + writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);') + writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {') + writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from init \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);') + writeLine(fileDescriptor, ' verifyInitFinished();') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while reading \\"%s\\" registers from" << hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description'])) + writeLine(fileDescriptor, ' emit reply->finished(); // To make sure it will be deleted') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' delete reply; // Broadcast reply returns immediatly') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers from" << hostAddress().toString() << errorString();' % (className, registerDefinition['description'])) + writeLine(fileDescriptor, ' }') + + # Read init blocks + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + + if 'readSchedule' in blockDefinition and blockDefinition['readSchedule'] == 'init': + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerType = blockRegister['registerType'] + + registerCount += 1 + blockSize += blockRegister['size'] + + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' // Read %s' % blockName) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read init block \\"%s\\" registers from:" << %s << "size:" << %s;' % (className, blockName, blockStartAddress, blockSize)) + writeLine(fileDescriptor, ' reply = readBlock%s();' % (blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor, ' if (reply) {') + writeLine(fileDescriptor, ' if (!reply->isFinished()) {') + writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);') + writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {') + writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();') + writeLine(fileDescriptor, ' const QVector blockValues = unit.values();') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading init block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize)) + + # Start parsing the registers using offsets + offset = 0 + for i, blockRegister in enumerate(blockRegisters): + propertyName = blockRegister['id'] + propertyTyp = getCppDataType(blockRegister) + writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size'])) + offset += blockRegister['size'] + + writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);') + writeLine(fileDescriptor, ' verifyInitFinished();') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName)) + writeLine(fileDescriptor, ' emit reply->finished();') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName)) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor) + + else: + writeLine(fileDescriptor, ' // No init registers defined. Nothing to be done and we are finished.') + writeLine(fileDescriptor, ' emit initializationFinished();') + + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) diff --git a/modbus/tools/connectiontool/toolcommon.py b/modbus/tools/connectiontool/toolcommon.py new file mode 100644 index 0000000..749e1ff --- /dev/null +++ b/modbus/tools/connectiontool/toolcommon.py @@ -0,0 +1,496 @@ +# Copyright (C) 2021 - 2022 nymea GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import os +import re +import sys +import json +import shutil +import argparse +import datetime + +def convertToAlphaNumeric(text): + finalText = '' + for character in text: + if character.isalnum(): + finalText += character + else: + finalText += ' ' + return finalText + + +def splitCamelCase(text): + return re.sub('([A-Z][a-z]+)', r' \1', re.sub('([A-Z]+)', r' \1', text)).split() + + +def convertToCamelCase(text, capitalize = False): + s = convertToAlphaNumeric(text) + s = s.replace("-", " ").replace("_", " ") + words = s.split() + #print('--> words', words) + finalWords = [] + + for i in range(len(words)): + camelCaseSplit = splitCamelCase(words[i]) + if len(camelCaseSplit) == 0: + finalWords.append(words[i]) + else: + #print('--> camel split words', camelCaseSplit) + for j in range(len(camelCaseSplit)): + finalWords.append(camelCaseSplit[j]) + + if len(finalWords) == 0: + return text + + finalText = '' + if capitalize: + finalText = finalWords[0].capitalize() + ''.join(i.capitalize() for i in finalWords[1:]) + else: + finalText = finalWords[0].lower() + ''.join(i.capitalize() for i in finalWords[1:]) + #print('Convert camel case:', text, '-->', finalText) + return finalText + + +def loadJsonFile(filePath): + print('--> Loading JSON file', filePath) + jsonFile = open(filePath, 'r') + return json.load(jsonFile) + + +def writeLine(fileDescriptor, line = ''): + fileDescriptor.write(line + '\n') + + +def writeLicenseHeader(fileDescriptor): + writeLine(fileDescriptor, '/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *') + writeLine(fileDescriptor, '*') + writeLine(fileDescriptor, '* Copyright 2013 - %s, nymea GmbH' % datetime.datetime.now().year) + writeLine(fileDescriptor, '* Contact: contact@nymea.io') + writeLine(fileDescriptor, '*') + writeLine(fileDescriptor, '* This fileDescriptor is part of nymea.') + writeLine(fileDescriptor, '* This project including source code and documentation is protected by') + writeLine(fileDescriptor, '* copyright law, and remains the property of nymea GmbH. All rights, including') + writeLine(fileDescriptor, '* reproduction, publication, editing and translation, are reserved. The use of') + writeLine(fileDescriptor, '* this project is subject to the terms of a license agreement to be concluded') + writeLine(fileDescriptor, '* with nymea GmbH in accordance with the terms of use of nymea GmbH, available') + writeLine(fileDescriptor, '* under https://nymea.io/license') + writeLine(fileDescriptor, '*') + writeLine(fileDescriptor, '* GNU Lesser General Public License Usage') + writeLine(fileDescriptor, '* Alternatively, this project may be redistributed and/or modified under the') + writeLine(fileDescriptor, '* terms of the GNU Lesser General Public License as published by the Free') + writeLine(fileDescriptor, '* Software Foundation; version 3. This project is distributed in the hope that') + writeLine(fileDescriptor, '* it will be useful, but WITHOUT ANY WARRANTY; without even the implied') + writeLine(fileDescriptor, '* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU') + writeLine(fileDescriptor, '* Lesser General Public License for more details.') + writeLine(fileDescriptor, '*') + writeLine(fileDescriptor, '* You should have received a copy of the GNU Lesser General Public License') + writeLine(fileDescriptor, '* along with this project. If not, see .') + writeLine(fileDescriptor, '*') + writeLine(fileDescriptor, '* For any further details and any questions please contact us under') + writeLine(fileDescriptor, '* contact@nymea.io or see our FAQ/Licensing Information on') + writeLine(fileDescriptor, '* https://nymea.io/license/faq') + writeLine(fileDescriptor, '*') + writeLine(fileDescriptor, '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */') + writeLine(fileDescriptor) + writeLine(fileDescriptor, '/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *') + writeLine(fileDescriptor, '*') + writeLine(fileDescriptor, '* WARNING') + writeLine(fileDescriptor, '*') + writeLine(fileDescriptor, '* This file has been autogenerated. Any changes in this file may be overwritten.') + writeLine(fileDescriptor, '* If you want to change something, update the register json or the tool.') + writeLine(fileDescriptor, '*') + writeLine(fileDescriptor, '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */') + writeLine(fileDescriptor) + + +def writeRegistersEnum(fileDescriptor, registerJson): + print('Writing enum for all registers') + + registerEnums = {} + + # Read all register names and addresses + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + blockRegisters = blockDefinition['registers'] + for blockRegister in blockRegisters: + registerName = blockRegister['id'] + registerAddress = blockRegister['address'] + registerEnums[registerAddress] = registerName + + for registerDefinition in registerJson['registers']: + registerName = registerDefinition['id'] + registerAddress = registerDefinition['address'] + registerEnums[registerAddress] = registerName + + + # Sort the enum map + registersKeys = registerEnums.keys() + sortedRegistersKeys = sorted(registersKeys) + sortedRegisterEnumList = [] + + print('Sorted registers') + for registerAddress in sortedRegistersKeys: + print('--> %s : %s' % (registerAddress, registerEnums[registerAddress])) + enumData = {} + enumData['key'] = registerEnums[registerAddress] + enumData['value'] = registerAddress + sortedRegisterEnumList.append(enumData) + + enumName = 'Registers' + writeLine(fileDescriptor, ' enum %s {' % enumName) + for i in range(len(sortedRegisterEnumList)): + enumData = sortedRegisterEnumList[i] + line = (' Register%s = %s' % (enumData['key'][0].upper() + enumData['key'][1:] , enumData['value'])) + if i < (len(sortedRegisterEnumList) - 1): + line += ',' + + writeLine(fileDescriptor, line) + + writeLine(fileDescriptor, ' };') + writeLine(fileDescriptor, ' Q_ENUM(%s)' % enumName) + writeLine(fileDescriptor) + + +def writeEnumDefinition(fileDescriptor, enumDefinition): + print('Writing enum', enumDefinition) + enumName = enumDefinition['name'] + enumValues = enumDefinition['values'] + writeLine(fileDescriptor, ' enum %s {' % enumName) + for i in range(len(enumValues)): + enumData = enumValues[i] + line = (' %s%s = %s' % (enumName, enumData['key'], enumData['value'])) + if i < (len(enumValues) - 1): + line += ',' + + writeLine(fileDescriptor, line) + + writeLine(fileDescriptor, ' };') + writeLine(fileDescriptor, ' Q_ENUM(%s)' % enumName) + writeLine(fileDescriptor) + + +def getCppDataType(registerDefinition, rawType = False): + if not rawType: + if 'enum' in registerDefinition: + return registerDefinition['enum'] + + if 'scaleFactor' in registerDefinition or 'staticScaleFactor' in registerDefinition: + return 'float' + + if registerDefinition['type'] == 'uint16': + return 'quint16' + + if registerDefinition['type'] == 'int16': + return 'qint16' + + if registerDefinition['type'] == 'uint32': + return 'quint32' + + if registerDefinition['type'] == 'int32': + return 'qint32' + + if registerDefinition['type'] == 'uint64': + return 'quint64' + + if registerDefinition['type'] == 'int64': + return 'qint64' + + if registerDefinition['type'] == 'float': + return 'float' + + if registerDefinition['type'] == 'float64': + return 'double' + + if registerDefinition['type'] == 'string': + return 'QString' + + +def getConversionToValueMethod(registerDefinition): + # Handle enums + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition, True) + + if 'enum' in registerDefinition: + enumName = registerDefinition['enum'] + if registerDefinition['type'] == 'uint16': + return ('ModbusDataUtils::convertFromUInt16(static_cast<%s>(%s))' % (propertyTyp, propertyName)) + elif registerDefinition['type'] == 'int16': + return ('ModbusDataUtils::convertFromInt16(static_cast<%s>(%s))' % (propertyTyp, propertyName)) + elif registerDefinition['type'] == 'uint32': + return ('ModbusDataUtils::convertFromUInt32(static_cast<%s>(%s), m_endianness)' % (propertyTyp, propertyName)) + elif registerDefinition['type'] == 'int32': + return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s), m_endianness)' % (propertyTyp, propertyName)) + + # Handle scale factors + if 'scaleFactor' in registerDefinition: + scaleFactorProperty = 'm_%s' % registerDefinition['scaleFactor'] + if registerDefinition['type'] == 'uint16': + return ('ModbusDataUtils::convertFromUInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactorProperty)) + elif registerDefinition['type'] == 'int16': + return ('ModbusDataUtils::convertFromInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactorProperty)) + elif registerDefinition['type'] == 'uint32': + return ('ModbusDataUtils::convertFromUInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), m_endianness)' % (propertyTyp, propertyName, scaleFactorProperty)) + elif registerDefinition['type'] == 'int32': + return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), m_endianness)' % (propertyTyp, propertyName, scaleFactorProperty)) + + elif 'staticScaleFactor' in registerDefinition: + scaleFactor = registerDefinition['staticScaleFactor'] + if registerDefinition['type'] == 'uint16': + return ('ModbusDataUtils::convertFromUInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactor)) + elif registerDefinition['type'] == 'int16': + return ('ModbusDataUtils::convertFromInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactor)) + elif registerDefinition['type'] == 'uint32': + return ('ModbusDataUtils::convertFromUInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), m_endianness)' % (propertyTyp, propertyName, scaleFactor)) + elif registerDefinition['type'] == 'int32': + return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), m_endianness)' % (propertyTyp, propertyName, scaleFactor)) + + # Handle default types + elif registerDefinition['type'] == 'uint16': + return ('ModbusDataUtils::convertFromUInt16(%s)' % propertyName) + elif registerDefinition['type'] == 'int16': + return ('ModbusDataUtils::convertFromInt16(%s)' % propertyName) + elif registerDefinition['type'] == 'uint32': + return ('ModbusDataUtils::convertFromUInt32(%s, m_endianness)' % (propertyName)) + elif registerDefinition['type'] == 'int32': + return ('ModbusDataUtils::convertFromInt32(%s, m_endianness)' % (propertyName)) + elif registerDefinition['type'] == 'uint64': + return ('ModbusDataUtils::convertFromUInt64(%s, m_endianness)' % (propertyName)) + elif registerDefinition['type'] == 'int64': + return ('ModbusDataUtils::convertFromInt64(%s, m_endianness)' % (propertyName)) + elif registerDefinition['type'] == 'float': + return ('ModbusDataUtils::convertFromFloat32(%s, m_endianness)' % propertyName) + elif registerDefinition['type'] == 'float64': + return ('ModbusDataUtils::convertFromFloat64(%s, m_endianness)' % propertyName) + elif registerDefinition['type'] == 'string': + return ('ModbusDataUtils::convertFromString(%s)' % propertyName) + + +def getValueConversionMethod(registerDefinition): + # Handle enums + if 'enum' in registerDefinition: + enumName = registerDefinition['enum'] + if registerDefinition['type'] == 'uint16': + return ('static_cast<%s>(ModbusDataUtils::convertToUInt16(values))' % (enumName)) + elif registerDefinition['type'] == 'int16': + return ('static_cast<%s>(ModbusDataUtils::convertToInt16(values))' % (enumName)) + elif registerDefinition['type'] == 'uint32': + return ('static_cast<%s>(ModbusDataUtils::convertToUInt32(values, m_endianness))' % (enumName)) + elif registerDefinition['type'] == 'int32': + return ('static_cast<%s>(ModbusDataUtils::convertToInt32(values, m_endianness))' % (enumName)) + + # Handle scale factors + if 'scaleFactor' in registerDefinition: + scaleFactorProperty = 'm_%s' % registerDefinition['scaleFactor'] + if registerDefinition['type'] == 'uint16': + return ('ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, %s)' % (scaleFactorProperty)) + elif registerDefinition['type'] == 'int16': + return ('ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, %s)' % (scaleFactorProperty)) + elif registerDefinition['type'] == 'uint32': + return ('ModbusDataUtils::convertToUInt32(values, m_endianness) * 1.0 * pow(10, %s)' % (scaleFactorProperty)) + elif registerDefinition['type'] == 'int32': + return ('ModbusDataUtils::convertToInt32(values, m_endianness) * 1.0 * pow(10, %s)' % (scaleFactorProperty)) + + elif 'staticScaleFactor' in registerDefinition: + scaleFactor = registerDefinition['staticScaleFactor'] + if registerDefinition['type'] == 'uint16': + return ('ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, %s)' % (scaleFactor)) + elif registerDefinition['type'] == 'int16': + return ('ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, %s)' % (scaleFactor)) + elif registerDefinition['type'] == 'uint32': + return ('ModbusDataUtils::convertToUInt32(values, m_endianness) * 1.0 * pow(10, %s)' % (scaleFactor)) + elif registerDefinition['type'] == 'int32': + return ('ModbusDataUtils::convertToInt32(values, m_endianness) * 1.0 * pow(10, %s)' % (scaleFactor)) + + # Handle default types + elif registerDefinition['type'] == 'uint16': + return ('ModbusDataUtils::convertToUInt16(values)') + elif registerDefinition['type'] == 'int16': + return ('ModbusDataUtils::convertToInt16(values)') + elif registerDefinition['type'] == 'uint32': + return ('ModbusDataUtils::convertToUInt32(values, m_endianness)') + elif registerDefinition['type'] == 'int32': + return ('ModbusDataUtils::convertToInt32(values, m_endianness)') + elif registerDefinition['type'] == 'uint64': + return ('ModbusDataUtils::convertToUInt64(values, m_endianness)') + elif registerDefinition['type'] == 'int64': + return ('ModbusDataUtils::convertToInt64(values, m_endianness)') + elif registerDefinition['type'] == 'float': + return ('ModbusDataUtils::convertToFloat32(values, m_endianness)') + elif registerDefinition['type'] == 'float64': + return ('ModbusDataUtils::convertToFloat64(values, m_endianness)') + elif registerDefinition['type'] == 'string': + return ('ModbusDataUtils::convertToString(values)') + + +def writeBlockGetMethodDeclarations(fileDescriptor, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + if 'unit' in registerDefinition and registerDefinition['unit'] != '': + writeLine(fileDescriptor, ' /* %s [%s] - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) + else: + writeLine(fileDescriptor, ' /* %s - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + + writeLine(fileDescriptor, ' %s %s() const;' % (propertyTyp, propertyName)) + writeLine(fileDescriptor) + + +def writePropertyUpdateMethodDeclarations(fileDescriptor, registerDefinitions): + for registerDefinition in registerDefinitions: + if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': + continue + + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + writeLine(fileDescriptor, ' void update%s();' % (propertyName[0].upper() + propertyName[1:])) + + +def validateBlocks(blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerAccess = "" + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerAccess = blockRegister['access'] + registerType = blockRegister['registerType'] + else: + previouseRegisterAddress = blockRegisters[i - 1]['address'] + previouseRegisterSize = blockRegisters[i - 1]['size'] + previouseRegisterType = blockRegisters[i - 1]['registerType'] + if previouseRegisterAddress + previouseRegisterSize != blockRegister['address']: + print('Error: block %s has invalid register order in register %s. There seems to be a gap between the registers.' % (blockName, blockRegister['id'])) + exit(1) + + if blockRegister['access'] != registerAccess: + print('Error: block %s has inconsistent register access in register %s. The block registers dont seem to have the same access rights.' % (blockName, blockRegister['id'])) + exit(1) + + if blockRegister['registerType'] != registerType: + print('Error: block %s has inconsistent register type in register %s. The block registers dont seem to be from the same type.' % (blockName, blockRegister['id'])) + exit(1) + + registerCount += 1 + blockSize += blockRegister['size'] + + print('Define valid block \"%s\" starting at %s with length %s containing %s properties to read.' % (blockName, blockStartAddress, blockSize, registerCount)) + + +def writeBlocksUpdateMethodDeclarations(fileDescriptor, blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + blockStartAddress = 0 + blockSize = 0 + registerCount = 0 + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + + registerCount += 1 + blockSize += blockRegister['size'] + + # Write the block update method + writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount)) + for i, registerDefinition in enumerate(blockRegisters): + if 'unit' in registerDefinition and registerDefinition['unit'] != '': + writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) + else: + writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' */ ' ) + writeLine(fileDescriptor, ' void update%sBlock();' % (blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor) + + +def writeRegistersDebugLine(fileDescriptor, debugObjectParamName, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + line = ('" - %s:" << %s->%s()' % (registerDefinition['description'], debugObjectParamName, propertyName)) + if 'unit' in registerDefinition and registerDefinition['unit'] != '': + line += (' << " [%s]"' % registerDefinition['unit']) + writeLine(fileDescriptor, ' debug.nospace().noquote() << %s << "\\n";' % (line)) + + +def writeUpdateMethod(fileDescriptor, className, registerDefinitions, blockDefinitions): + writeLine(fileDescriptor, 'void %s::update()' % (className)) + writeLine(fileDescriptor, '{') + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'update': + writeLine(fileDescriptor, ' update%s();' % (propertyName[0].upper() + propertyName[1:])) + + # Add the update block methods + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + writeLine(fileDescriptor, ' update%sBlock();' % (blockName[0].upper() + blockName[1:])) + + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + + +def writePropertyChangedSignals(fileDescriptor, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + if propertyTyp == 'QString': + writeLine(fileDescriptor, ' void %sChanged(const %s &%s);' % (propertyName, propertyTyp, propertyName)) + else: + writeLine(fileDescriptor, ' void %sChanged(%s %s);' % (propertyName, propertyTyp, propertyName)) + + +def writeProtectedPropertyMembers(fileDescriptor, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + if 'defaultValue' in registerDefinition: + writeLine(fileDescriptor, ' %s m_%s = %s;' % (propertyTyp, propertyName, registerDefinition['defaultValue'])) + else: + writeLine(fileDescriptor, ' %s m_%s;' % (propertyTyp, propertyName)) + + +def writePropertyProcessMethodDeclaration(fileDescriptor, registerDefinitions): + propertyVariables = [] + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + writeLine(fileDescriptor, ' void process%sRegisterValues(const QVector values);' % (propertyName[0].upper() + propertyName[1:])) + + writeLine(fileDescriptor) + + +def writePropertyProcessMethodImplementations(fileDescriptor, className, registerDefinitions): + propertyVariables = [] + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + + writeLine(fileDescriptor, 'void %s::process%sRegisterValues(const QVector values)' % (className, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, '{') + writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(registerDefinition))) + writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName)) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) diff --git a/modbus/tools/generate-connection.py b/modbus/tools/generate-connection.py index 39c0969..6c0d1f7 100644 --- a/modbus/tools/generate-connection.py +++ b/modbus/tools/generate-connection.py @@ -26,909 +26,9 @@ import shutil import argparse import datetime -def convertToAlphaNumeric(text): - finalText = '' - for character in text: - if character.isalnum(): - finalText += character - else: - finalText += ' ' - return finalText - - -def splitCamelCase(text): - return re.sub('([A-Z][a-z]+)', r' \1', re.sub('([A-Z]+)', r' \1', text)).split() - - -def convertToCamelCase(text, capitalize = False): - s = convertToAlphaNumeric(text) - s = s.replace("-", " ").replace("_", " ") - words = s.split() - #print('--> words', words) - finalWords = [] - - for i in range(len(words)): - camelCaseSplit = splitCamelCase(words[i]) - if len(camelCaseSplit) == 0: - finalWords.append(words[i]) - else: - #print('--> camel split words', camelCaseSplit) - for j in range(len(camelCaseSplit)): - finalWords.append(camelCaseSplit[j]) - - if len(finalWords) == 0: - return text - - finalText = '' - if capitalize: - finalText = finalWords[0].capitalize() + ''.join(i.capitalize() for i in finalWords[1:]) - else: - finalText = finalWords[0].lower() + ''.join(i.capitalize() for i in finalWords[1:]) - #print('Convert camel case:', text, '-->', finalText) - return finalText - - -def loadJsonFile(filePath): - print('--> Loading JSON file', filePath) - jsonFile = open(filePath, 'r') - return json.load(jsonFile) - - -def writeLine(fileDescriptor, line = ''): - fileDescriptor.write(line + '\n') - - -def writeLicenseHeader(fileDescriptor): - writeLine(fileDescriptor, '/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *') - writeLine(fileDescriptor, '*') - writeLine(fileDescriptor, '* Copyright 2013 - %s, nymea GmbH' % datetime.datetime.now().year) - writeLine(fileDescriptor, '* Contact: contact@nymea.io') - writeLine(fileDescriptor, '*') - writeLine(fileDescriptor, '* This fileDescriptor is part of nymea.') - writeLine(fileDescriptor, '* This project including source code and documentation is protected by') - writeLine(fileDescriptor, '* copyright law, and remains the property of nymea GmbH. All rights, including') - writeLine(fileDescriptor, '* reproduction, publication, editing and translation, are reserved. The use of') - writeLine(fileDescriptor, '* this project is subject to the terms of a license agreement to be concluded') - writeLine(fileDescriptor, '* with nymea GmbH in accordance with the terms of use of nymea GmbH, available') - writeLine(fileDescriptor, '* under https://nymea.io/license') - writeLine(fileDescriptor, '*') - writeLine(fileDescriptor, '* GNU Lesser General Public License Usage') - writeLine(fileDescriptor, '* Alternatively, this project may be redistributed and/or modified under the') - writeLine(fileDescriptor, '* terms of the GNU Lesser General Public License as published by the Free') - writeLine(fileDescriptor, '* Software Foundation; version 3. This project is distributed in the hope that') - writeLine(fileDescriptor, '* it will be useful, but WITHOUT ANY WARRANTY; without even the implied') - writeLine(fileDescriptor, '* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU') - writeLine(fileDescriptor, '* Lesser General Public License for more details.') - writeLine(fileDescriptor, '*') - writeLine(fileDescriptor, '* You should have received a copy of the GNU Lesser General Public License') - writeLine(fileDescriptor, '* along with this project. If not, see .') - writeLine(fileDescriptor, '*') - writeLine(fileDescriptor, '* For any further details and any questions please contact us under') - writeLine(fileDescriptor, '* contact@nymea.io or see our FAQ/Licensing Information on') - writeLine(fileDescriptor, '* https://nymea.io/license/faq') - writeLine(fileDescriptor, '*') - writeLine(fileDescriptor, '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */') - writeLine(fileDescriptor) - - -def writeRegistersEnum(fileDescriptor, registerJson): - print('Writing enum for all registers') - - registerEnums = {} - - # Read all register names and addresses - if 'blocks' in registerJson: - for blockDefinition in registerJson['blocks']: - blockRegisters = blockDefinition['registers'] - for blockRegister in blockRegisters: - registerName = blockRegister['id'] - registerAddress = blockRegister['address'] - registerEnums[registerAddress] = registerName - - for registerDefinition in registerJson['registers']: - registerName = registerDefinition['id'] - registerAddress = registerDefinition['address'] - registerEnums[registerAddress] = registerName - - - # Sort the enum map - registersKeys = registerEnums.keys() - sortedRegistersKeys = sorted(registersKeys) - sortedRegisterEnumList = [] - - print('Sorted registers') - for registerAddress in sortedRegistersKeys: - print('--> %s : %s' % (registerAddress, registerEnums[registerAddress])) - enumData = {} - enumData['key'] = registerEnums[registerAddress] - enumData['value'] = registerAddress - sortedRegisterEnumList.append(enumData) - - enumName = 'Registers' - writeLine(fileDescriptor, ' enum %s {' % enumName) - for i in range(len(sortedRegisterEnumList)): - enumData = sortedRegisterEnumList[i] - line = (' Register%s = %s' % (enumData['key'][0].upper() + enumData['key'][1:] , enumData['value'])) - if i < (len(sortedRegisterEnumList) - 1): - line += ',' - - writeLine(fileDescriptor, line) - - writeLine(fileDescriptor, ' };') - writeLine(fileDescriptor, ' Q_ENUM(%s)' % enumName) - writeLine(fileDescriptor) - - -def writeEnumDefinition(fileDescriptor, enumDefinition): - print('Writing enum', enumDefinition) - enumName = enumDefinition['name'] - enumValues = enumDefinition['values'] - writeLine(fileDescriptor, ' enum %s {' % enumName) - for i in range(len(enumValues)): - enumData = enumValues[i] - line = (' %s%s = %s' % (enumName, enumData['key'], enumData['value'])) - if i < (len(enumValues) - 1): - line += ',' - - writeLine(fileDescriptor, line) - - writeLine(fileDescriptor, ' };') - writeLine(fileDescriptor, ' Q_ENUM(%s)' % enumName) - writeLine(fileDescriptor) - - -def getCppDataType(registerDefinition, rawType = False): - if not rawType: - if 'enum' in registerDefinition: - return registerDefinition['enum'] - - if 'scaleFactor' in registerDefinition or 'staticScaleFactor' in registerDefinition: - return 'float' - - if registerDefinition['type'] == 'uint16': - return 'quint16' - - if registerDefinition['type'] == 'int16': - return 'qint16' - - if registerDefinition['type'] == 'uint32': - return 'quint32' - - if registerDefinition['type'] == 'int32': - return 'qint32' - - if registerDefinition['type'] == 'uint64': - return 'quint64' - - if registerDefinition['type'] == 'int64': - return 'qint64' - - if registerDefinition['type'] == 'float': - return 'float' - - if registerDefinition['type'] == 'float64': - return 'double' - - if registerDefinition['type'] == 'string': - return 'QString' - - -def getConversionToValueMethod(registerDefinition): - # Handle enums - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition, True) - - if 'enum' in registerDefinition: - enumName = registerDefinition['enum'] - if registerDefinition['type'] == 'uint16': - return ('ModbusDataUtils::convertFromUInt16(static_cast<%s>(%s))' % (propertyTyp, propertyName)) - elif registerDefinition['type'] == 'int16': - return ('ModbusDataUtils::convertFromInt16(static_cast<%s>(%s))' % (propertyTyp, propertyName)) - elif registerDefinition['type'] == 'uint32': - return ('ModbusDataUtils::convertFromUInt32(static_cast<%s>(%s), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, endianness)) - elif registerDefinition['type'] == 'int32': - return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, endianness)) - - # Handle scale factors - if 'scaleFactor' in registerDefinition: - scaleFactorProperty = 'm_%s' % registerDefinition['scaleFactor'] - if registerDefinition['type'] == 'uint16': - return ('ModbusDataUtils::convertFromUInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactorProperty)) - elif registerDefinition['type'] == 'int16': - return ('ModbusDataUtils::convertFromInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactorProperty)) - elif registerDefinition['type'] == 'uint32': - return ('ModbusDataUtils::convertFromUInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, scaleFactorProperty, endianness)) - elif registerDefinition['type'] == 'int32': - return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, scaleFactorProperty, endianness)) - - elif 'staticScaleFactor' in registerDefinition: - scaleFactor = registerDefinition['staticScaleFactor'] - if registerDefinition['type'] == 'uint16': - return ('ModbusDataUtils::convertFromUInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactor)) - elif registerDefinition['type'] == 'int16': - return ('ModbusDataUtils::convertFromInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactor)) - elif registerDefinition['type'] == 'uint32': - return ('ModbusDataUtils::convertFromUInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, scaleFactor, endianness)) - elif registerDefinition['type'] == 'int32': - return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, scaleFactor, endianness)) - - # Handle default types - elif registerDefinition['type'] == 'uint16': - return ('ModbusDataUtils::convertFromUInt16(%s)' % propertyName) - elif registerDefinition['type'] == 'int16': - return ('ModbusDataUtils::convertFromInt16(%s)' % propertyName) - elif registerDefinition['type'] == 'uint32': - return ('ModbusDataUtils::convertFromUInt32(%s, ModbusDataUtils::ByteOrder%s)' % (propertyName, endianness)) - elif registerDefinition['type'] == 'int32': - return ('ModbusDataUtils::convertFromInt32(%s, ModbusDataUtils::ByteOrder%s)' % (propertyName, endianness)) - elif registerDefinition['type'] == 'uint64': - return ('ModbusDataUtils::convertFromUInt64(%s, ModbusDataUtils::ByteOrder%s)' % (propertyName, endianness)) - elif registerDefinition['type'] == 'int64': - return ('ModbusDataUtils::convertFromInt64(%s, ModbusDataUtils::ByteOrder%s)' % (propertyName, endianness)) - elif registerDefinition['type'] == 'float': - return ('ModbusDataUtils::convertFromFloat32(%s, ModbusDataUtils::ByteOrder%s)' % propertyName, endianness) - elif registerDefinition['type'] == 'float64': - return ('ModbusDataUtils::convertFromFloat64(%s, ModbusDataUtils::ByteOrder%s)' % propertyName, endianness) - elif registerDefinition['type'] == 'string': - return ('ModbusDataUtils::convertFromString(%s)' % propertyName) - - -def getValueConversionMethod(registerDefinition): - # Handle enums - if 'enum' in registerDefinition: - enumName = registerDefinition['enum'] - if registerDefinition['type'] == 'uint16': - return ('static_cast<%s>(ModbusDataUtils::convertToUInt16(values))' % (enumName)) - elif registerDefinition['type'] == 'int16': - return ('static_cast<%s>(ModbusDataUtils::convertToInt16(values))' % (enumName)) - elif registerDefinition['type'] == 'uint32': - return ('static_cast<%s>(ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrder%s))' % (enumName, endianness)) - elif registerDefinition['type'] == 'int32': - return ('static_cast<%s>(ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrder%s))' % (enumName, endianness)) - - # Handle scale factors - if 'scaleFactor' in registerDefinition: - scaleFactorProperty = 'm_%s' % registerDefinition['scaleFactor'] - if registerDefinition['type'] == 'uint16': - return ('ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, %s)' % (scaleFactorProperty)) - elif registerDefinition['type'] == 'int16': - return ('ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, %s)' % (scaleFactorProperty)) - elif registerDefinition['type'] == 'uint32': - return ('ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactorProperty)) - elif registerDefinition['type'] == 'int32': - return ('ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactorProperty)) - - elif 'staticScaleFactor' in registerDefinition: - scaleFactor = registerDefinition['staticScaleFactor'] - if registerDefinition['type'] == 'uint16': - return ('ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, %s)' % (scaleFactor)) - elif registerDefinition['type'] == 'int16': - return ('ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, %s)' % (scaleFactor)) - elif registerDefinition['type'] == 'uint32': - return ('ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactor)) - elif registerDefinition['type'] == 'int32': - return ('ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactor)) - - # Handle default types - elif registerDefinition['type'] == 'uint16': - return ('ModbusDataUtils::convertToUInt16(values)') - elif registerDefinition['type'] == 'int16': - return ('ModbusDataUtils::convertToInt16(values)') - elif registerDefinition['type'] == 'uint32': - return ('ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrder%s)' % endianness) - elif registerDefinition['type'] == 'int32': - return ('ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrder%s)' % endianness) - elif registerDefinition['type'] == 'uint64': - return ('ModbusDataUtils::convertToUInt64(values, ModbusDataUtils::ByteOrder%s)' % endianness) - elif registerDefinition['type'] == 'int64': - return ('ModbusDataUtils::convertToInt64(values, ModbusDataUtils::ByteOrder%s)' % endianness) - elif registerDefinition['type'] == 'float': - return ('ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrder%s)' % endianness) - elif registerDefinition['type'] == 'float64': - return ('ModbusDataUtils::convertToFloat64(values, ModbusDataUtils::ByteOrder%s)' % endianness) - elif registerDefinition['type'] == 'string': - return ('ModbusDataUtils::convertToString(values)') - - -def writePropertyGetSetMethodDeclarationsTcp(fileDescriptor, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - if 'unit' in registerDefinition and registerDefinition['unit'] != '': - writeLine(fileDescriptor, ' /* %s [%s] - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) - else: - writeLine(fileDescriptor, ' /* %s - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - - writeLine(fileDescriptor, ' %s %s() const;' % (propertyTyp, propertyName)) - - # Check if we require a set method - if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO': - writeLine(fileDescriptor, ' QModbusReply *set%s(%s %s);' % (propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName)) - - writeLine(fileDescriptor) - - - -def writePropertyGetSetMethodDeclarationsRtu(fileDescriptor, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - if 'unit' in registerDefinition and registerDefinition['unit'] != '': - writeLine(fileDescriptor, ' /* %s [%s] - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) - else: - writeLine(fileDescriptor, ' /* %s - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - - writeLine(fileDescriptor, ' %s %s() const;' % (propertyTyp, propertyName)) - - # Check if we require a set method - if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO': - writeLine(fileDescriptor, ' ModbusRtuReply *set%s(%s %s);' % (propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName)) - - writeLine(fileDescriptor) - - -def writeBlockGetMethodDeclarations(fileDescriptor, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - if 'unit' in registerDefinition and registerDefinition['unit'] != '': - writeLine(fileDescriptor, ' /* %s [%s] - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) - else: - writeLine(fileDescriptor, ' /* %s - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - - writeLine(fileDescriptor, ' %s %s() const;' % (propertyTyp, propertyName)) - writeLine(fileDescriptor) - - -def writePropertyGetSetMethodImplementationsTcp(fileDescriptor, className, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - # Get - if 'enum' in registerDefinition: - writeLine(fileDescriptor, '%s::%s %s::%s() const' % (className, propertyTyp, className, propertyName)) - else: - writeLine(fileDescriptor, '%s %s::%s() const' % (propertyTyp, className, propertyName)) - - writeLine(fileDescriptor, '{') - writeLine(fileDescriptor, ' return m_%s;' % propertyName) - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - # Check if we require a set method - if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO': - writeLine(fileDescriptor, 'QModbusReply *%s::set%s(%s %s)' % (className, propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName)) - writeLine(fileDescriptor, '{') - - writeLine(fileDescriptor, ' QVector values = %s;' % getConversionToValueMethod(registerDefinition)) - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Write \\"%s\\" register:" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - if registerDefinition['registerType'] == 'holdingRegister': - writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, values.count());' % (registerDefinition['address'])) - elif registerDefinition['registerType'] == 'coils': - writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, values.count());' % (registerDefinition['address'])) - else: - print('Error: invalid register type for writing.') - exit(1) - - writeLine(fileDescriptor, ' request.setValues(values);') - writeLine(fileDescriptor, ' return sendWriteRequest(request, m_slaveId);') - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - -def writePropertyGetSetMethodImplementationsRtu(fileDescriptor, className, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - # Get - if 'enum' in registerDefinition: - writeLine(fileDescriptor, '%s::%s %s::%s() const' % (className, propertyTyp, className, propertyName)) - else: - writeLine(fileDescriptor, '%s %s::%s() const' % (propertyTyp, className, propertyName)) - - writeLine(fileDescriptor, '{') - writeLine(fileDescriptor, ' return m_%s;' % propertyName) - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - # Check if we require a set method - if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO': - writeLine(fileDescriptor, 'ModbusRtuReply *%s::set%s(%s %s)' % (className, propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName)) - writeLine(fileDescriptor, '{') - - writeLine(fileDescriptor, ' QVector values = %s;' % getConversionToValueMethod(registerDefinition)) - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Write \\"%s\\" register:" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - if registerDefinition['registerType'] == 'holdingRegister': - writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeHoldingRegisters(m_slaveId, %s, values);' % (registerDefinition['address'])) - elif registerDefinition['registerType'] == 'coils': - writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeCoils(m_slaveId, %s, values);' % (registerDefinition['address'])) - else: - print('Error: invalid register type for writing.') - exit(1) - - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - -def writePropertyUpdateMethodDeclarations(fileDescriptor, registerDefinitions): - for registerDefinition in registerDefinitions: - if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': - continue - - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - writeLine(fileDescriptor, ' void update%s();' % (propertyName[0].upper() + propertyName[1:])) - - -def validateBlocks(blockDefinitions): - for blockDefinition in blockDefinitions: - blockName = blockDefinition['id'] - blockRegisters = blockDefinition['registers'] - - blockStartAddress = 0 - registerCount = 0 - blockSize = 0 - registerAccess = "" - registerType = "" - - for i, blockRegister in enumerate(blockRegisters): - if i == 0: - blockStartAddress = blockRegister['address'] - registerAccess = blockRegister['access'] - registerType = blockRegister['registerType'] - else: - previouseRegisterAddress = blockRegisters[i - 1]['address'] - previouseRegisterSize = blockRegisters[i - 1]['size'] - previouseRegisterType = blockRegisters[i - 1]['registerType'] - if previouseRegisterAddress + previouseRegisterSize != blockRegister['address']: - print('Error: block %s has invalid register order in register %s. There seems to be a gap between the registers.' % (blockName, blockRegister['id'])) - exit(1) - - if blockRegister['access'] != registerAccess: - print('Error: block %s has inconsistent register access in register %s. The block registers dont seem to have the same access rights.' % (blockName, blockRegister['id'])) - exit(1) - - if blockRegister['registerType'] != registerType: - print('Error: block %s has inconsistent register type in register %s. The block registers dont seem to be from the same type.' % (blockName, blockRegister['id'])) - exit(1) - - registerCount += 1 - blockSize += blockRegister['size'] - - print('Define valid block \"%s\" starting at %s with length %s containing %s properties to read.' % (blockName, blockStartAddress, blockSize, registerCount)) - - -def writeBlocksUpdateMethodDeclarations(fileDescriptor, blockDefinitions): - for blockDefinition in blockDefinitions: - blockName = blockDefinition['id'] - blockRegisters = blockDefinition['registers'] - - # Write the property get / set methods for the block registers - writeBlockGetMethodDeclarations(fileDescriptor, blockRegisters) - - blockStartAddress = 0 - blockSize = 0 - registerCount = 0 - - for i, blockRegister in enumerate(blockRegisters): - if i == 0: - blockStartAddress = blockRegister['address'] - - registerCount += 1 - blockSize += blockRegister['size'] - - # Write the block update method - writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount)) - for i, registerDefinition in enumerate(blockRegisters): - if 'unit' in registerDefinition and registerDefinition['unit'] != '': - writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) - else: - writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - writeLine(fileDescriptor, ' */ ' ) - writeLine(fileDescriptor, ' void update%sBlock();' % (blockName[0].upper() + blockName[1:])) - writeLine(fileDescriptor) - - -def writePropertyUpdateMethodImplementationsTcp(fileDescriptor, className, registerDefinitions): - for registerDefinition in registerDefinitions: - if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': - continue - - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - writeLine(fileDescriptor, 'void %s::update%s()' % (className, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, '{') - writeLine(fileDescriptor, ' // Update registers from %s' % registerDefinition['description']) - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read \\"%s\\" register:" << %s << "size:" << %s;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - writeLine(fileDescriptor, ' QModbusReply *reply = read%s();' % (propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' if (reply) {') - writeLine(fileDescriptor, ' if (!reply->isFinished()) {') - writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);') - writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){') - writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {') - writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();') - writeLine(fileDescriptor, ' const QVector values = unit.values();') - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(registerDefinition))) - writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName)) - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' });') - writeLine(fileDescriptor) - writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating \\"%s\\" registers from" << hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description'])) - writeLine(fileDescriptor, ' emit reply->finished(); // To make sure it will be deleted') - writeLine(fileDescriptor, ' });') - writeLine(fileDescriptor, ' } else {') - writeLine(fileDescriptor, ' delete reply; // Broadcast reply returns immediatly') - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' } else {') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers from" << hostAddress().toString() << errorString();' % (className, registerDefinition['description'])) - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - -def writePropertyUpdateMethodImplementationsRtu(fileDescriptor, className, registerDefinitions): - for registerDefinition in registerDefinitions: - if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': - continue - - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - writeLine(fileDescriptor, 'void %s::update%s()' % (className, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, '{') - writeLine(fileDescriptor, ' // Update registers from %s' % registerDefinition['description']) - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read \\"%s\\" register:" << %s << "size:" << %s;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - writeLine(fileDescriptor, ' ModbusRtuReply *reply = read%s();' % (propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' if (reply) {') - writeLine(fileDescriptor, ' if (!reply->isFinished()) {') - writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){') - writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') - writeLine(fileDescriptor, ' QVector values = reply->result();') - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - - # FIXME: introduce bool and check register type for parsing - writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(registerDefinition))) - writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName)) - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' });') - writeLine(fileDescriptor) - writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating \\"%s\\" registers" << error << reply->errorString();' % (className, registerDefinition['description'])) - writeLine(fileDescriptor, ' emit reply->finished();') - writeLine(fileDescriptor, ' });') - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' } else {') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers";' % (className, registerDefinition['description'])) - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - -def writeBlockUpdateMethodImplementationsRtu(fileDescriptor, className, blockDefinitions): - for blockDefinition in blockDefinitions: - blockName = blockDefinition['id'] - blockRegisters = blockDefinition['registers'] - blockStartAddress = 0 - registerCount = 0 - blockSize = 0 - registerType = "" - - for i, blockRegister in enumerate(blockRegisters): - if i == 0: - blockStartAddress = blockRegister['address'] - registerType = blockRegister['registerType'] - - registerCount += 1 - blockSize += blockRegister['size'] - - writeLine(fileDescriptor, 'void %s::update%sBlock()' % (className, blockName[0].upper() + blockName[1:])) - writeLine(fileDescriptor, '{') - writeLine(fileDescriptor, ' // Update register block \"%s\"' % blockName) - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read block \\"%s\\" registers from:" << %s << "size:" << %s;' % (className, blockName, blockStartAddress, blockSize)) - - - # Build request depending on the register type - if registerType == 'inputRegister': - writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) - elif registerType == 'discreteInputs': - writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readDiscreteInput(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) - elif registerType == 'coils': - writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readCoil(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) - else: - #Default to holdingRegister - writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) - - writeLine(fileDescriptor, ' if (reply) {') - writeLine(fileDescriptor, ' if (!reply->isFinished()) {') - writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){') - writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') - writeLine(fileDescriptor, ' QVector blockValues = reply->result();') - writeLine(fileDescriptor, ' QVector values;') - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize)) - - # Start parsing the registers using offsets - offset = 0 - for i, blockRegister in enumerate(blockRegisters): - propertyName = blockRegister['id'] - propertyTyp = getCppDataType(blockRegister) - writeLine(fileDescriptor, ' values = blockValues.mid(%s, %s);' % (offset, blockRegister['size'])) - writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(blockRegister))) - writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName)) - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor) - offset += blockRegister['size'] - - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' });') - writeLine(fileDescriptor) - writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName)) - writeLine(fileDescriptor, ' emit reply->finished();') - writeLine(fileDescriptor, ' });') - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' } else {') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName)) - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - -def writeBlockUpdateMethodImplementationsTcp(fileDescriptor, className, blockDefinitions): - for blockDefinition in blockDefinitions: - blockName = blockDefinition['id'] - blockRegisters = blockDefinition['registers'] - blockStartAddress = 0 - registerCount = 0 - blockSize = 0 - registerType = "" - - for i, blockRegister in enumerate(blockRegisters): - if i == 0: - blockStartAddress = blockRegister['address'] - registerType = blockRegister['registerType'] - - registerCount += 1 - blockSize += blockRegister['size'] - - writeLine(fileDescriptor, 'void %s::update%sBlock()' % (className, blockName[0].upper() + blockName[1:])) - writeLine(fileDescriptor, '{') - writeLine(fileDescriptor, ' // Update register block \"%s\"' % blockName) - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read block \\"%s\\" registers from:" << %s << "size:" << %s;' % (className, blockName, blockStartAddress, blockSize)) - - # Build request depending on the register type - # Build request depending on the register type - if registerType == 'inputRegister': - writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, %s, %s);' % (blockStartAddress, blockSize)) - elif registerType == 'discreteInputs': - writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, %s, %s);' % (blockStartAddress, blockSize)) - elif registerType == 'coils': - writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, %s);' % (blockStartAddress, blockSize)) - else: - #Default to holdingRegister - writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, %s);' % (blockStartAddress, blockSize)) - - writeLine(fileDescriptor, ' QModbusReply *reply = sendReadRequest(request, m_slaveId);') - - writeLine(fileDescriptor, ' if (reply) {') - writeLine(fileDescriptor, ' if (!reply->isFinished()) {') - writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){') - writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {') - writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();') - writeLine(fileDescriptor, ' const QVector blockValues = unit.values();') - writeLine(fileDescriptor, ' QVector values;') - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize)) - - # Start parsing the registers using offsets - offset = 0 - for i, blockRegister in enumerate(blockRegisters): - propertyName = blockRegister['id'] - propertyTyp = getCppDataType(blockRegister) - writeLine(fileDescriptor, ' values = blockValues.mid(%s, %s);' % (offset, blockRegister['size'])) - writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(blockRegister))) - writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName)) - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor) - offset += blockRegister['size'] - - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' });') - writeLine(fileDescriptor) - writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName)) - writeLine(fileDescriptor, ' emit reply->finished();') - writeLine(fileDescriptor, ' });') - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' } else {') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName)) - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - -def writeInternalPropertyReadMethodDeclarationsTcp(fileDescriptor, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - writeLine(fileDescriptor, ' QModbusReply *read%s();' % (propertyName[0].upper() + propertyName[1:])) - - -def writeInternalPropertyReadMethodDeclarationsRtu(fileDescriptor, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - writeLine(fileDescriptor, ' ModbusRtuReply *read%s();' % (propertyName[0].upper() + propertyName[1:])) - - -def writeInternalPropertyReadMethodImplementationsTcp(fileDescriptor, className, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - writeLine(fileDescriptor, 'QModbusReply *%s::read%s()' % (className, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, '{') - - # Build request depending on the register type - if registerDefinition['registerType'] == 'inputRegister': - writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) - elif registerDefinition['registerType'] == 'discreteInputs': - writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) - elif registerDefinition['registerType'] == 'coils': - writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) - else: - #Default to holdingRegister - writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) - - writeLine(fileDescriptor, ' return sendReadRequest(request, m_slaveId);') - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - -def writeInternalPropertyReadMethodImplementationsRtu(fileDescriptor, className, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - writeLine(fileDescriptor, 'ModbusRtuReply *%s::read%s()' % (className, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, '{') - - # Build request depending on the register type - if registerDefinition['registerType'] == 'inputRegister': - writeLine(fileDescriptor, ' return m_modbusRtuMaster->readInputRegister(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) - elif registerDefinition['registerType'] == 'discreteInputs': - writeLine(fileDescriptor, ' return m_modbusRtuMaster->readDiscreteInput(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) - elif registerDefinition['registerType'] == 'coils': - writeLine(fileDescriptor, ' return m_modbusRtuMaster->readCoil(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) - else: - #Default to holdingRegister - writeLine(fileDescriptor, ' return m_modbusRtuMaster->readHoldingRegister(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) - - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - - -def writePropertyChangedSignals(fileDescriptor, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - if propertyTyp == 'QString': - writeLine(fileDescriptor, ' void %sChanged(const %s &%s);' % (propertyName, propertyTyp, propertyName)) - else: - writeLine(fileDescriptor, ' void %sChanged(%s %s);' % (propertyName, propertyTyp, propertyName)) - - -def writePrivatePropertyMembers(fileDescriptor, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - if 'defaultValue' in registerDefinition: - writeLine(fileDescriptor, ' %s m_%s = %s;' % (propertyTyp, propertyName, registerDefinition['defaultValue'])) - else: - writeLine(fileDescriptor, ' %s m_%s;' % (propertyTyp, propertyName)) - - -def writeInitializeMethod(fileDescriptor, className, registerDefinitions): - writeLine(fileDescriptor, 'void %s::initialize()' % (className)) - writeLine(fileDescriptor, '{') - - # First check if there are any init registers - initRequired = False - for registerDefinition in registerDefinitions: - if registerDefinition['readSchedule'] == 'init': - initRequired = True - break - - if initRequired: - if protocol == 'TCP': - # Init implementation for TCP - writeLine(fileDescriptor, ' QModbusReply *reply = nullptr;') - writeLine(fileDescriptor) - writeLine(fileDescriptor, ' if (!m_pendingInitReplies.isEmpty()) {') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Tried to initialize but there are still some init replies pending.";' % className) - writeLine(fileDescriptor, ' return;') - writeLine(fileDescriptor, ' }') - - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - - if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': - writeLine(fileDescriptor) - writeLine(fileDescriptor, ' // Read %s' % registerDefinition['description']) - writeLine(fileDescriptor, ' reply = read%s();' % (propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' if (reply) {') - writeLine(fileDescriptor, ' if (!reply->isFinished()) {') - writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);') - writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);') - writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){') - writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {') - writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();') - writeLine(fileDescriptor, ' const QVector values = unit.values();') - writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(registerDefinition))) - writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:])) - writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName)) - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor) - writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);') - writeLine(fileDescriptor, ' verifyInitFinished();') - writeLine(fileDescriptor, ' });') - writeLine(fileDescriptor) - writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while reading \\"%s\\" registers from" << hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description'])) - writeLine(fileDescriptor, ' emit reply->finished(); // To make sure it will be deleted') - writeLine(fileDescriptor, ' });') - writeLine(fileDescriptor, ' } else {') - writeLine(fileDescriptor, ' delete reply; // Broadcast reply returns immediatly') - writeLine(fileDescriptor, ' }') - writeLine(fileDescriptor, ' } else {') - writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers from" << hostAddress().toString() << errorString();' % (className, registerDefinition['description'])) - writeLine(fileDescriptor, ' }') - - else: - print('TODO: this has not been implemented yet for RTU') - exit(1) - - else: - writeLine(fileDescriptor, ' // No init registers defined. Nothing to be done and we are finished.') - writeLine(fileDescriptor, ' emit initializationFinished();') - - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - -def writeUpdateMethod(fileDescriptor, className, registerDefinitions): - writeLine(fileDescriptor, 'void %s::update()' % (className)) - writeLine(fileDescriptor, '{') - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'update': - writeLine(fileDescriptor, ' update%s();' % (propertyName[0].upper() + propertyName[1:])) - - # Add the update block methods - if 'blocks' in registerJson: - for blockDefinition in registerJson['blocks']: - blockName = blockDefinition['id'] - writeLine(fileDescriptor, ' update%sBlock();' % (blockName[0].upper() + blockName[1:])) - - writeLine(fileDescriptor, '}') - writeLine(fileDescriptor) - - -def writeRegistersDebugLine(fileDescriptor, debugObjectParamName, registerDefinitions): - for registerDefinition in registerDefinitions: - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - line = ('" - %s:" << %s->%s()' % (registerDefinition['description'], debugObjectParamName, propertyName)) - if 'unit' in registerDefinition and registerDefinition['unit'] != '': - line += (' << " [%s]"' % registerDefinition['unit']) - writeLine(fileDescriptor, ' debug.nospace().noquote() << %s << "\\n";' % (line)) - +from connectiontool.toolcommon import * +from connectiontool.modbusrtu import * +from connectiontool.modbustcp import * def writeTcpHeaderFile(): print('Writing modbus TCP hader file %s' % headerFilePath) @@ -965,12 +65,17 @@ def writeTcpHeaderFile(): writeLine(headerFile, ' explicit %s(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr);' % className) writeLine(headerFile, ' ~%s() = default;' % className) writeLine(headerFile) + writeLine(headerFile, ' ModbusDataUtils::ByteOrder endianness() const;') + writeLine(headerFile, ' void setEndianness(ModbusDataUtils::ByteOrder endianness);') + writeLine(headerFile) # Write registers get method declarations writePropertyGetSetMethodDeclarationsTcp(headerFile, registerJson['registers']) - - # Write block get/set method declarations if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writePropertyGetSetMethodDeclarationsTcp(headerFile, blockDefinition['registers']) + + # Write block get/set method declarations writeBlocksUpdateMethodDeclarations(headerFile, registerJson['blocks']) # Write init and update method declarations @@ -980,12 +85,19 @@ def writeTcpHeaderFile(): writePropertyUpdateMethodDeclarations(headerFile, registerJson['registers']) writeLine(headerFile) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writePropertyUpdateMethodDeclarations(headerFile, blockDefinition['registers']) + + writeLine(headerFile) # Write registers value changed signals writeLine(headerFile, 'signals:') writeLine(headerFile, ' void initializationFinished();') + writeLine(headerFile, ' void endiannessChanged(ModbusDataUtils::ByteOrder endianness);') writeLine(headerFile) writePropertyChangedSignals(headerFile, registerJson['registers']) + writeLine(headerFile) if 'blocks' in registerJson: for blockDefinition in registerJson['blocks']: writePropertyChangedSignals(headerFile, blockDefinition['registers']) @@ -995,11 +107,26 @@ def writeTcpHeaderFile(): # Protected members writeLine(headerFile, 'protected:') writeInternalPropertyReadMethodDeclarationsTcp(headerFile, registerJson['registers']) - writeLine(headerFile) - writePrivatePropertyMembers(headerFile, registerJson['registers']) if 'blocks' in registerJson: for blockDefinition in registerJson['blocks']: - writePrivatePropertyMembers(headerFile, blockDefinition['registers']) + writeInternalPropertyReadMethodDeclarationsTcp(headerFile, blockDefinition['registers']) + + writeLine(headerFile) + writeInternalBlockReadMethodDeclarationsTcp(headerFile, registerJson['blocks']) + + + writeLine(headerFile) + writeProtectedPropertyMembers(headerFile, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writeProtectedPropertyMembers(headerFile, blockDefinition['registers']) + + writeLine(headerFile) + + writePropertyProcessMethodDeclaration(headerFile, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writePropertyProcessMethodDeclaration(headerFile, blockDefinition['registers']) writeLine(headerFile) @@ -1007,6 +134,7 @@ def writeTcpHeaderFile(): writeLine(headerFile, 'private:') writeLine(headerFile, ' quint16 m_slaveId = 1;') writeLine(headerFile, ' QVector m_pendingInitReplies;') + writeLine(headerFile, ' ModbusDataUtils::ByteOrder m_endianness = ModbusDataUtils::ByteOrder%s;' % endianness) writeLine(headerFile) writeLine(headerFile, ' void verifyInitFinished();') writeLine(headerFile) @@ -1042,27 +170,54 @@ def writeTcpSourceFile(): writeLine(sourceFile, '}') writeLine(sourceFile) + writeLine(sourceFile, 'ModbusDataUtils::ByteOrder %s::endianness() const' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' return m_endianness;') + writeLine(sourceFile, '}') + writeLine(sourceFile) + + writeLine(sourceFile, 'void %s::setEndianness(ModbusDataUtils::ByteOrder endianness)' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' if (m_endianness == endianness)') + writeLine(sourceFile, ' return;') + writeLine(sourceFile,) + writeLine(sourceFile, ' m_endianness = endianness;') + writeLine(sourceFile, ' emit endiannessChanged(m_endianness);') + writeLine(sourceFile, '}') + writeLine(sourceFile) + # Property get methods writePropertyGetSetMethodImplementationsTcp(sourceFile, className, registerJson['registers']) - - # Block property get methods if 'blocks' in registerJson: for blockDefinition in registerJson['blocks']: writePropertyGetSetMethodImplementationsTcp(sourceFile, className, blockDefinition['registers']) # Write init and update method implementation - writeInitializeMethod(sourceFile, className, registerJson['registers']) - writeUpdateMethod(sourceFile, className, registerJson['registers']) + writeInitMethodImplementationTcp(sourceFile, className, registerJson['registers'], registerJson['blocks']) + writeUpdateMethod(sourceFile, className, registerJson['registers'], registerJson['blocks']) # Write update methods writePropertyUpdateMethodImplementationsTcp(sourceFile, className, registerJson['registers']) - - # Write block update method if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writePropertyUpdateMethodImplementationsTcp(sourceFile, className, blockDefinition['registers']) + + # Write block update method writeBlockUpdateMethodImplementationsTcp(sourceFile, className, registerJson['blocks']) # Write internal protected property read method implementations writeInternalPropertyReadMethodImplementationsTcp(sourceFile, className, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writeInternalPropertyReadMethodImplementationsTcp(sourceFile, className, blockDefinition['registers']) + + writeInternalBlockReadMethodImplementationsTcp(sourceFile, className, registerJson['blocks']) + + # Write internal processors of properties + writePropertyProcessMethodImplementations(sourceFile, className, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writePropertyProcessMethodImplementations(sourceFile, className, blockDefinition['registers']) writeLine(sourceFile, 'void %s::verifyInitFinished()' % (className)) writeLine(sourceFile, '{') @@ -1079,7 +234,6 @@ def writeTcpSourceFile(): writeLine(sourceFile, '{') writeLine(sourceFile, ' debug.nospace().noquote() << "%s(" << %s->hostAddress().toString() << ":" << %s->port() << ")" << "\\n";' % (className, debugObjectParamName, debugObjectParamName)) writeRegistersDebugLine(sourceFile, debugObjectParamName, registerJson['registers']) - if 'blocks' in registerJson: for blockDefinition in registerJson['blocks']: writeRegistersDebugLine(sourceFile, debugObjectParamName, blockDefinition['registers']) @@ -1131,40 +285,66 @@ def writeRtuHeaderFile(): writeLine(headerFile, ' ModbusRtuMaster *modbusRtuMaster() const;') writeLine(headerFile, ' quint16 slaveId() const;') writeLine(headerFile) - - # Write registers get/set method declarations - writePropertyGetSetMethodDeclarationsRtu(headerFile, registerJson['registers']) - - # Write block get/set method declarations - if 'blocks' in registerJson: - writeBlocksUpdateMethodDeclarations(headerFile, registerJson['blocks']) - - writePropertyUpdateMethodDeclarations(headerFile, registerJson['registers']) + writeLine(headerFile, ' ModbusDataUtils::ByteOrder endianness() const;') + writeLine(headerFile, ' void setEndianness(ModbusDataUtils::ByteOrder endianness);') writeLine(headerFile) + # Write registers get method declarations + writePropertyGetSetMethodDeclarationsRtu(headerFile, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writePropertyGetSetMethodDeclarationsRtu(headerFile, blockDefinition['registers']) + + # Write block get/set method declarations + writeBlocksUpdateMethodDeclarations(headerFile, registerJson['blocks']) + # Write init and update method declarations writeLine(headerFile, ' virtual void initialize();') writeLine(headerFile, ' virtual void update();') writeLine(headerFile) + writePropertyUpdateMethodDeclarations(headerFile, registerJson['registers']) + writeLine(headerFile) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writePropertyUpdateMethodDeclarations(headerFile, blockDefinition['registers']) + + writeLine(headerFile) + # Write registers value changed signals writeLine(headerFile, 'signals:') writeLine(headerFile, ' void initializationFinished();') + writeLine(headerFile, ' void endiannessChanged(ModbusDataUtils::ByteOrder endianness);') writeLine(headerFile) writePropertyChangedSignals(headerFile, registerJson['registers']) if 'blocks' in registerJson: for blockDefinition in registerJson['blocks']: writePropertyChangedSignals(headerFile, blockDefinition['registers']) + writeLine(headerFile) # Protected members writeLine(headerFile, 'protected:') writeInternalPropertyReadMethodDeclarationsRtu(headerFile, registerJson['registers']) - writeLine(headerFile) - writePrivatePropertyMembers(headerFile, registerJson['registers']) if 'blocks' in registerJson: for blockDefinition in registerJson['blocks']: - writePrivatePropertyMembers(headerFile, blockDefinition['registers']) + writeInternalPropertyReadMethodDeclarationsRtu(headerFile, blockDefinition['registers']) + + writeLine(headerFile) + writeInternalBlockReadMethodDeclarationsRtu(headerFile, registerJson['blocks']) + + + writeProtectedPropertyMembers(headerFile, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writeProtectedPropertyMembers(headerFile, blockDefinition['registers']) + + writeLine(headerFile) + + writePropertyProcessMethodDeclaration(headerFile, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writePropertyProcessMethodDeclaration(headerFile, blockDefinition['registers']) writeLine(headerFile) @@ -1173,6 +353,7 @@ def writeRtuHeaderFile(): writeLine(headerFile, ' ModbusRtuMaster *m_modbusRtuMaster = nullptr;') writeLine(headerFile, ' quint16 m_slaveId = 1;') writeLine(headerFile, ' QVector m_pendingInitReplies;') + writeLine(headerFile, ' ModbusDataUtils::ByteOrder m_endianness = ModbusDataUtils::ByteOrder%s;' % endianness) writeLine(headerFile) writeLine(headerFile, ' void verifyInitFinished();') writeLine(headerFile) @@ -1219,28 +400,52 @@ def writeRtuSourceFile(): writeLine(sourceFile, ' return m_slaveId;') writeLine(sourceFile, '}') + writeLine(sourceFile, 'ModbusDataUtils::ByteOrder %s::endianness() const' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' return m_endianness;') + writeLine(sourceFile, '}') + + writeLine(sourceFile, 'void %s::setEndianness(ModbusDataUtils::ByteOrder endianness)' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' if (m_endianness == endianness)') + writeLine(sourceFile, ' return;') + writeLine(sourceFile,) + writeLine(sourceFile, ' m_endianness = endianness;') + writeLine(sourceFile, ' emit endiannessChanged(m_endianness);') + writeLine(sourceFile, '}') # Property get methods writePropertyGetSetMethodImplementationsRtu(sourceFile, className, registerJson['registers']) - - # Block property get methods if 'blocks' in registerJson: for blockDefinition in registerJson['blocks']: writePropertyGetSetMethodImplementationsRtu(sourceFile, className, blockDefinition['registers']) # Write init and update method implementation - writeInitializeMethod(sourceFile, className, registerJson['registers']) - writeUpdateMethod(sourceFile, className, registerJson['registers']) + writeInitMethodImplementationRtu(sourceFile, className, registerJson['registers'], registerJson['blocks']) + writeUpdateMethod(sourceFile, className, registerJson['registers'], registerJson['blocks']) # Write update methods writePropertyUpdateMethodImplementationsRtu(sourceFile, className, registerJson['registers']) - - # Write block update method if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writePropertyUpdateMethodImplementationsRtu(sourceFile, className, blockDefinition['registers']) + + # Write block update method writeBlockUpdateMethodImplementationsRtu(sourceFile, className, registerJson['blocks']) # Write internal protected property read method implementations writeInternalPropertyReadMethodImplementationsRtu(sourceFile, className, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writeInternalPropertyReadMethodImplementationsRtu(sourceFile, className, blockDefinition['registers']) + + writeInternalBlockReadMethodImplementationsRtu(sourceFile, className, registerJson['blocks']) + + # Write internal processors of properties + writePropertyProcessMethodImplementations(sourceFile, className, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writePropertyProcessMethodImplementations(sourceFile, className, blockDefinition['registers']) writeLine(sourceFile, 'void %s::verifyInitFinished()' % (className)) writeLine(sourceFile, '{') From 6e6261b839a14a43794d09dc8192b3eb463e05ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 23 Mar 2022 17:00:48 +0100 Subject: [PATCH 02/42] Update debug printes and make read methods public --- modbus/tools/connectiontool/modbustcp.py | 4 ++-- modbus/tools/connectiontool/toolcommon.py | 7 ++++--- modbus/tools/generate-connection.py | 18 ++++++++++-------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/modbus/tools/connectiontool/modbustcp.py b/modbus/tools/connectiontool/modbustcp.py index fb2b8e5..aef6b00 100644 --- a/modbus/tools/connectiontool/modbustcp.py +++ b/modbus/tools/connectiontool/modbustcp.py @@ -215,9 +215,9 @@ def writeInternalBlockReadMethodDeclarationsTcp(fileDescriptor, blockDefinitions writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount)) for i, registerDefinition in enumerate(blockRegisters): if 'unit' in registerDefinition and registerDefinition['unit'] != '': - writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) else: - writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) writeLine(fileDescriptor, ' */ ' ) writeLine(fileDescriptor, ' QModbusReply *readBlock%s();' % (blockName[0].upper() + blockName[1:])) writeLine(fileDescriptor) diff --git a/modbus/tools/connectiontool/toolcommon.py b/modbus/tools/connectiontool/toolcommon.py index 749e1ff..caccae2 100644 --- a/modbus/tools/connectiontool/toolcommon.py +++ b/modbus/tools/connectiontool/toolcommon.py @@ -417,10 +417,10 @@ def writeBlocksUpdateMethodDeclarations(fileDescriptor, blockDefinitions): if 'unit' in registerDefinition and registerDefinition['unit'] != '': writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) else: - writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) writeLine(fileDescriptor, ' */ ' ) writeLine(fileDescriptor, ' void update%sBlock();' % (blockName[0].upper() + blockName[1:])) - writeLine(fileDescriptor) + writeLine(fileDescriptor) def writeRegistersDebugLine(fileDescriptor, debugObjectParamName, registerDefinitions): @@ -444,7 +444,8 @@ def writeUpdateMethod(fileDescriptor, className, registerDefinitions, blockDefin # Add the update block methods for blockDefinition in blockDefinitions: blockName = blockDefinition['id'] - writeLine(fileDescriptor, ' update%sBlock();' % (blockName[0].upper() + blockName[1:])) + if 'readSchedule' in blockDefinition and blockDefinition['readSchedule'] == 'update': + writeLine(fileDescriptor, ' update%sBlock();' % (blockName[0].upper() + blockName[1:])) writeLine(fileDescriptor, '}') writeLine(fileDescriptor) diff --git a/modbus/tools/generate-connection.py b/modbus/tools/generate-connection.py index 6c0d1f7..c5d7742 100644 --- a/modbus/tools/generate-connection.py +++ b/modbus/tools/generate-connection.py @@ -91,6 +91,16 @@ def writeTcpHeaderFile(): writeLine(headerFile) + writeInternalPropertyReadMethodDeclarationsTcp(headerFile, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writeInternalPropertyReadMethodDeclarationsTcp(headerFile, blockDefinition['registers']) + + writeLine(headerFile) + writeInternalBlockReadMethodDeclarationsTcp(headerFile, registerJson['blocks']) + + writeLine(headerFile) + # Write registers value changed signals writeLine(headerFile, 'signals:') writeLine(headerFile, ' void initializationFinished();') @@ -106,14 +116,6 @@ def writeTcpHeaderFile(): # Protected members writeLine(headerFile, 'protected:') - writeInternalPropertyReadMethodDeclarationsTcp(headerFile, registerJson['registers']) - if 'blocks' in registerJson: - for blockDefinition in registerJson['blocks']: - writeInternalPropertyReadMethodDeclarationsTcp(headerFile, blockDefinition['registers']) - - writeLine(headerFile) - writeInternalBlockReadMethodDeclarationsTcp(headerFile, registerJson['blocks']) - writeLine(headerFile) writeProtectedPropertyMembers(headerFile, registerJson['registers']) From 3ae84f28cd41b88cee460a9e016615a389a751b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 4 Apr 2022 15:00:18 +0200 Subject: [PATCH 03/42] Fix modbus connection header file --- modbus/tools/generate-connection.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/modbus/tools/generate-connection.py b/modbus/tools/generate-connection.py index c5d7742..dd971bc 100644 --- a/modbus/tools/generate-connection.py +++ b/modbus/tools/generate-connection.py @@ -313,6 +313,15 @@ def writeRtuHeaderFile(): writeLine(headerFile) + writeInternalPropertyReadMethodDeclarationsRtu(headerFile, registerJson['registers']) + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + writeInternalPropertyReadMethodDeclarationsRtu(headerFile, blockDefinition['registers']) + + writeLine(headerFile) + writeInternalBlockReadMethodDeclarationsRtu(headerFile, registerJson['blocks']) + + # Write registers value changed signals writeLine(headerFile, 'signals:') writeLine(headerFile, ' void initializationFinished();') @@ -327,14 +336,6 @@ def writeRtuHeaderFile(): # Protected members writeLine(headerFile, 'protected:') - writeInternalPropertyReadMethodDeclarationsRtu(headerFile, registerJson['registers']) - if 'blocks' in registerJson: - for blockDefinition in registerJson['blocks']: - writeInternalPropertyReadMethodDeclarationsRtu(headerFile, blockDefinition['registers']) - - writeLine(headerFile) - writeInternalBlockReadMethodDeclarationsRtu(headerFile, registerJson['blocks']) - writeProtectedPropertyMembers(headerFile, registerJson['registers']) if 'blocks' in registerJson: @@ -378,6 +379,7 @@ def writeRtuSourceFile(): writeLine(sourceFile, '#include "%s"' % headerFileName) writeLine(sourceFile, '#include "loggingcategories.h"') + writeLine(sourceFile, '#include "math.h"') writeLine(sourceFile) writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className)) writeLine(sourceFile) From 03c77ef3a371b3f27caa5f4dd9787df3f9ea56c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 4 Apr 2022 15:04:26 +0200 Subject: [PATCH 04/42] Fix math.h include --- modbus/tools/generate-connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modbus/tools/generate-connection.py b/modbus/tools/generate-connection.py index dd971bc..a6314fd 100644 --- a/modbus/tools/generate-connection.py +++ b/modbus/tools/generate-connection.py @@ -379,7 +379,7 @@ def writeRtuSourceFile(): writeLine(sourceFile, '#include "%s"' % headerFileName) writeLine(sourceFile, '#include "loggingcategories.h"') - writeLine(sourceFile, '#include "math.h"') + writeLine(sourceFile, '#include ') writeLine(sourceFile) writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className)) writeLine(sourceFile) From 62f78f5e90fc3183f1feff1c361b8b8cbeda7840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 4 May 2022 12:14:40 +0200 Subject: [PATCH 05/42] Introduce libnymea-modbus Improve tool and prepare autogeneration of connection classes --- .gitignore | 1 + debian/control | 30 +++- debian/libnymea-modbus-dev.install.in | 4 + debian/libnymea-modbus.install.in | 4 + debian/rules | 1 + libnymea-modbus/libnymea-modbus.pro | 57 ++++++++ libnymea-modbus/modbus-tool.pri | 56 ++++++++ .../modbusdatautils.cpp | 0 {modbus => libnymea-modbus}/modbusdatautils.h | 0 .../modbustcpmaster.cpp | 51 ++++--- {modbus => libnymea-modbus}/modbustcpmaster.h | 10 +- {modbus => libnymea-modbus}/tools/README.md | 74 ++++++++-- .../tools/connectiontool/__init__.py | 0 .../tools/connectiontool/modbusrtu.py | 6 +- .../tools/connectiontool/modbustcp.py | 4 +- .../tools/connectiontool/toolcommon.py | 30 ++-- .../tools/examples/example-registers.json | 114 ++++++++++++++++ .../tools/generate-connection.py | 129 ++++++++++++++---- modbus.pri | 12 ++ nymea-plugins-modbus.pro | 2 +- 20 files changed, 496 insertions(+), 89 deletions(-) create mode 100644 debian/libnymea-modbus-dev.install.in create mode 100644 debian/libnymea-modbus.install.in create mode 100644 libnymea-modbus/libnymea-modbus.pro create mode 100644 libnymea-modbus/modbus-tool.pri rename {modbus => libnymea-modbus}/modbusdatautils.cpp (100%) rename {modbus => libnymea-modbus}/modbusdatautils.h (100%) rename {modbus => libnymea-modbus}/modbustcpmaster.cpp (87%) rename {modbus => libnymea-modbus}/modbustcpmaster.h (97%) rename {modbus => libnymea-modbus}/tools/README.md (85%) rename {modbus => libnymea-modbus}/tools/connectiontool/__init__.py (100%) rename {modbus => libnymea-modbus}/tools/connectiontool/modbusrtu.py (99%) rename {modbus => libnymea-modbus}/tools/connectiontool/modbustcp.py (99%) rename {modbus => libnymea-modbus}/tools/connectiontool/toolcommon.py (94%) create mode 100644 libnymea-modbus/tools/examples/example-registers.json rename {modbus => libnymea-modbus}/tools/generate-connection.py (82%) create mode 100644 modbus.pri diff --git a/.gitignore b/.gitignore index d73d76c..9e237a7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ builddir doc/html *.qm +__pycache__ diff --git a/debian/control b/debian/control index 0ab3eb2..a9eea5a 100644 --- a/debian/control +++ b/debian/control @@ -2,6 +2,7 @@ Source: nymea-plugins-modbus Section: utils Priority: options Maintainer: nymea GmbH +Standards-Version: 3.9.3 Build-depends: debhelper (>= 9.0.0), libnymea-dev (>= 0.17), libnymea-gpio-dev, @@ -10,8 +11,8 @@ Build-depends: debhelper (>= 9.0.0), nymea-dev-tools:native, pkg-config, qtbase5-dev, - libi2c-dev -Standards-Version: 3.9.3 + libi2c-dev, + python3:native Package: libnymea-sunspec1 @@ -22,6 +23,7 @@ Depends: ${shlibs:Depends}, Description: nymea.io sunspec library This package contains the nymea sunspec library. + Package: libnymea-sunspec-dev Section: libdevel Architecture: any @@ -34,6 +36,30 @@ Depends: ${shlibs:Depends}, Description: The main libraries and header files for developing with nymea sunspec. This package contains the nymea sunspec library - development files. + +Package: libnymea-modbus +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends} +Description: nymea modbus integration plugins library + This package contains the nymea modbus library for integration plugins. + + +Package: libnymea-modbus-dev +Section: libdevel +Architecture: any +Multi-Arch: same +Depends: ${shlibs:Depends}, + ${misc:Depends}, + libnymea-modbus (= ${binary:Version}), + pkg-config, + qtbase5-dev, + python3, +Description: The main libraries and header files for developing with modbus based nymea integration plugins. + This package contains the nymea modbus integration plugin library - development files. + + Package: nymea-plugin-alphainnotec Architecture: any Section: libs diff --git a/debian/libnymea-modbus-dev.install.in b/debian/libnymea-modbus-dev.install.in new file mode 100644 index 0000000..d743d89 --- /dev/null +++ b/debian/libnymea-modbus-dev.install.in @@ -0,0 +1,4 @@ +usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so +usr/include/nymea-modbus/ +usr/lib/@DEB_HOST_MULTIARCH@/pkgconfig/nymea-modbus.pc + diff --git a/debian/libnymea-modbus.install.in b/debian/libnymea-modbus.install.in new file mode 100644 index 0000000..a180f98 --- /dev/null +++ b/debian/libnymea-modbus.install.in @@ -0,0 +1,4 @@ +usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so.1 +usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so.1.0 +usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so.1.0.0 + diff --git a/debian/rules b/debian/rules index 7a8679f..dcdbe2b 100755 --- a/debian/rules +++ b/debian/rules @@ -21,5 +21,6 @@ override_dh_auto_clean: dh_auto_clean find -name *plugininfo.h -exec rm {} \; find -name *.qm -exec rm {} \; + find -name "autogenerated" -type d -exec rm -rvf {} + rm -rf $(PREPROCESS_FILES:.in=) diff --git a/libnymea-modbus/libnymea-modbus.pro b/libnymea-modbus/libnymea-modbus.pro new file mode 100644 index 0000000..61d8b3b --- /dev/null +++ b/libnymea-modbus/libnymea-modbus.pro @@ -0,0 +1,57 @@ +QMAKE_CXXFLAGS += -Werror -std=c++11 -z defs +QMAKE_LFLAGS += -std=c++11 -z defs + +QT += network serialbus + +CONFIG += link_pkgconfig +PKGCONFIG += nymea + +TARGET = nymea-modbus +TEMPLATE = lib + +gcc { + COMPILER_VERSION = $$system($$QMAKE_CXX " -dumpversion") + COMPILER_MAJOR_VERSION = $$str_member($$COMPILER_VERSION) + greaterThan(COMPILER_MAJOR_VERSION, 7): QMAKE_CXXFLAGS += -Wno-deprecated-copy +} + +HEADERS += \ + modbusdatautils.h \ + modbustcpmaster.h + +SOURCES += \ + modbusdatautils.cpp \ + modbustcpmaster.cpp + + +# define install target +target.path = $$[QT_INSTALL_LIBS] +INSTALLS += target + +# install modbustool for external plugins +modbustoolpri.files = modbus-tool.pri +modbustoolpri.path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/ +modbustool.files = tools/generate-connection.py +modbustool.path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/tools/ +modbustoolmodules.files = tools/connectiontool/*.py +modbustoolmodules.path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/tools/connectiontool/ +INSTALLS += modbustoolpri modbustool modbustoolmodules + +# install header file with relative subdirectory +for (header, HEADERS) { + path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/$${dirname(header)} + eval(headers_$${path}.files += $${header}) + eval(headers_$${path}.path = $${path}) + eval(INSTALLS *= headers_$${path}) +} + +# Create pkgconfig file +CONFIG += create_pc create_prl no_install_prl +QMAKE_PKGCONFIG_NAME = libnymea-modbus +QMAKE_PKGCONFIG_DESCRIPTION = nymea modbus integrations development library +QMAKE_PKGCONFIG_PREFIX = $$[QT_INSTALL_PREFIX] +QMAKE_PKGCONFIG_INCDIR = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/ +QMAKE_PKGCONFIG_LIBDIR = $$target.path +QMAKE_PKGCONFIG_VERSION = 1.0.0 +QMAKE_PKGCONFIG_FILE = nymea-modbus +QMAKE_PKGCONFIG_DESTDIR = pkgconfig diff --git a/libnymea-modbus/modbus-tool.pri b/libnymea-modbus/modbus-tool.pri new file mode 100644 index 0000000..c507b6f --- /dev/null +++ b/libnymea-modbus/modbus-tool.pri @@ -0,0 +1,56 @@ +# Copyright 2013 - 2021, nymea GmbH +# Contact: contact@nymea.io +# +# This file is part of nymea. +# This project including source code and documentation is protected by +# copyright law, and remains the property of nymea GmbH. All rights, including +# reproduction, publication, editing and translation, are reserved. The use of +# this project is subject to the terms of a license agreement to be concluded +# with nymea GmbH in accordance with the terms of use of nymea GmbH, available +# under https://nymea.io/license +# +# GNU Lesser General Public License Usage +# Alternatively, this project may be redistributed and/or modified under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; version 3. This project is distributed in the hope that +# it will be useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this project. If not, see . +# +# For any further details and any questions please contact us under +# contact@nymea.io or see our FAQ/Licensing Information on +# https://nymea.io/license/faq + +# This project include file is meant to be used by nymea modbus integration plugins. +# For external plugins you can generate connection by including this project like following: + +# # Generate modbus connection +# MODBUS_CONNECTIONS += modbus-registers.json +# MODBUS_TOOLS_CONFIG += VERBOSE +# include($$[QT_INSTALL_PREFIX]/include/nymea-modbus/modbus-tool.pri) + +# On each qmake run the classes will be generated in the build directory. + +GENERATE_MODBUS_CONNECTION_BINARY=$${PWD}/tools/generate-connection.py + +for(registerDefinition, MODBUS_CONNECTIONS) { + contains(MODBUS_TOOLS_CONFIG, VERBOSE) { + message("Generating modbus connection class for $${registerDefinition} (verbose)") + system(python3 $${GENERATE_MODBUS_CONNECTION_BINARY} -j $${_PRO_FILE_PWD_}/$${registerDefinition} -o $${OUT_PWD}/autogenerated -v) + } else { + message("Generating class for $${registerDefinition}") + system(python3 $${GENERATE_MODBUS_CONNECTION_BINARY} -j $${_PRO_FILE_PWD_}/$${registerDefinition} -o $${OUT_PWD}/autogenerated) + } +} + +# Add all generated pri files to the project +MODBUS_CONNECTIONS_INCLUDES = $$files($${OUT_PWD}/autogenerated/*.pri) +for(MODBUS_CONNECTION, MODBUS_CONNECTIONS_INCLUDES) { + message("Adding generated connection to project $${MODBUS_CONNECTION}") + include($${MODBUS_CONNECTION}) + INCLUDEPATH += $${OUT_PWD}/autogenerated +} + diff --git a/modbus/modbusdatautils.cpp b/libnymea-modbus/modbusdatautils.cpp similarity index 100% rename from modbus/modbusdatautils.cpp rename to libnymea-modbus/modbusdatautils.cpp diff --git a/modbus/modbusdatautils.h b/libnymea-modbus/modbusdatautils.h similarity index 100% rename from modbus/modbusdatautils.h rename to libnymea-modbus/modbusdatautils.h diff --git a/modbus/modbustcpmaster.cpp b/libnymea-modbus/modbustcpmaster.cpp similarity index 87% rename from modbus/modbustcpmaster.cpp rename to libnymea-modbus/modbustcpmaster.cpp index 880f4c6..8c6a448 100644 --- a/modbus/modbustcpmaster.cpp +++ b/libnymea-modbus/modbustcpmaster.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2021, nymea GmbH +* Copyright 2013 - 2022, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -30,8 +30,7 @@ #include "modbustcpmaster.h" -#include -NYMEA_LOGGING_CATEGORY(dcModbusTCP, "ModbusTCP") +Q_LOGGING_CATEGORY(dcModbusTcpMaster, "ModbusTcpMaster") ModbusTCPMaster::ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QObject *parent) : QObject(parent), @@ -91,7 +90,7 @@ bool ModbusTCPMaster::connectDevice() { // Only connect if we are in the unconnected state if (m_modbusTcpClient->state() == QModbusDevice::UnconnectedState) { - qCDebug(dcModbusTCP()) << "Connecting modbus TCP client to" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port); + qCDebug(dcModbusTcpMaster()) << "Connecting modbus TCP client to" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port); m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, m_port); m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, m_hostAddress.toString()); m_modbusTcpClient->setTimeout(m_timeout); @@ -101,7 +100,7 @@ bool ModbusTCPMaster::connectDevice() { // Restart the timer in case of connecting not finished yet or closing m_reconnectTimer->start(); } else { - qCWarning(dcModbusTCP()) << "Connect modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port) << "called, but the socket is currently in the" << m_modbusTcpClient->state(); + qCWarning(dcModbusTcpMaster()) << "Connect modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port) << "called, but the socket is currently in the" << m_modbusTcpClient->state(); } return false; @@ -119,7 +118,7 @@ void ModbusTCPMaster::disconnectDevice() bool ModbusTCPMaster::reconnectDevice() { - qCWarning(dcModbusTCP()) << "Reconnecting modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port); + qCWarning(dcModbusTcpMaster()) << "Reconnecting modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port); if (!m_modbusTcpClient) return false; @@ -184,12 +183,12 @@ QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress, uint si emit receivedCoil(reply->serverAddress(), modbusAddress, unit.values()); } else { emit readRequestExecuted(requestId, false); - qCWarning(dcModbusTCP()) << "Read response error:" << reply->error(); + qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error(); } }); connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - qCWarning(dcModbusTCP()) << "Modbus reply error:" << error; + qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error; emit readRequestError(requestId, reply->errorString()); emit reply->finished(); // To make sure it will be deleted }); @@ -200,7 +199,7 @@ QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress, uint si return QUuid(); } } else { - qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString(); + qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString(); return QUuid(); } return requestId; @@ -226,13 +225,13 @@ QUuid ModbusTCPMaster::writeHoldingRegisters(uint slaveAddress, uint registerAdd emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.values()); } else { emit writeRequestExecuted(requestId, false); - qCWarning(dcModbusTCP()) << "Read response error:" << reply->error(); + qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error(); } reply->deleteLater(); }); connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - qCWarning(dcModbusTCP()) << "Modbus replay error:" << error; + qCWarning(dcModbusTcpMaster()) << "Modbus replay error:" << error; emit writeRequestError(requestId, reply->errorString()); emit reply->finished(); // To make sure it will be deleted }); @@ -243,7 +242,7 @@ QUuid ModbusTCPMaster::writeHoldingRegisters(uint slaveAddress, uint registerAdd return QUuid(); } } else { - qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString(); + qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString(); return QUuid(); } return requestId; @@ -289,12 +288,12 @@ QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress emit receivedDiscreteInput(reply->serverAddress(), modbusAddress, unit.values()); } else { emit readRequestExecuted(requestId, false); - qCWarning(dcModbusTCP()) << "Read response error:" << reply->error(); + qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error(); } }); connect(reply, &QModbusReply::errorOccurred, this, [requestId, this] (QModbusDevice::Error error){ - qCWarning(dcModbusTCP()) << "Modbus replay error:" << error; + qCWarning(dcModbusTcpMaster()) << "Modbus replay error:" << error; QModbusReply *reply = qobject_cast(sender()); emit readRequestError(requestId, reply->errorString()); emit reply->finished(); // To make sure it will be deleted @@ -306,7 +305,7 @@ QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress return QUuid(); } } else { - qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString(); + qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString(); return QUuid(); } return requestId; @@ -333,12 +332,12 @@ QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress emit receivedInputRegister(reply->serverAddress(), modbusAddress, unit.values()); } else { emit readRequestExecuted(requestId, false); - qCWarning(dcModbusTCP()) << "Read response error:" << reply->error(); + qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error(); } }); connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - qCWarning(dcModbusTCP()) << "Modbus reply error:" << error; + qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error; emit readRequestError(requestId, reply->errorString()); emit reply->finished(); // To make sure it will be deleted }); @@ -350,7 +349,7 @@ QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress return QUuid(); } } else { - qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString(); + qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString(); return QUuid(); } return requestId; @@ -378,7 +377,7 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre } else { emit writeRequestExecuted(requestId, false); - qCWarning(dcModbusTCP()) << "Read response error:" << reply->error(); + qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error(); emit readRequestError(requestId, reply->errorString()); } reply->deleteLater(); @@ -386,7 +385,7 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - qCWarning(dcModbusTCP()) << "Modbus reply error:" << error; + qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error; emit readRequestError(requestId, reply->errorString()); emit reply->finished(); // To make sure it will be deleted }); @@ -397,7 +396,7 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre return QUuid(); } } else { - qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString(); + qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString(); return QUuid(); } return requestId; @@ -431,13 +430,13 @@ QUuid ModbusTCPMaster::writeCoils(uint slaveAddress, uint registerAddress, const } else { emit writeRequestExecuted(requestId, false); - qCWarning(dcModbusTCP()) << "Write response error:" << reply->error(); + qCWarning(dcModbusTcpMaster()) << "Write response error:" << reply->error(); } reply->deleteLater(); }); connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - qCWarning(dcModbusTCP()) << "Modbus reply error:" << error; + qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error; emit writeRequestError(requestId, reply->errorString()); emit reply->finished(); // To make sure it will be deleted }); @@ -448,7 +447,7 @@ QUuid ModbusTCPMaster::writeCoils(uint slaveAddress, uint registerAddress, const return QUuid(); } } else { - qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString(); + qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString(); return QUuid(); } return requestId; @@ -461,12 +460,12 @@ QUuid ModbusTCPMaster::writeHoldingRegister(uint slaveAddress, uint registerAddr void ModbusTCPMaster::onModbusErrorOccurred(QModbusDevice::Error error) { - qCWarning(dcModbusTCP()) << "An error occured" << error; + qCWarning(dcModbusTcpMaster()) << "An error occured" << error; } void ModbusTCPMaster::onModbusStateChanged(QModbusDevice::State state) { - qCDebug(dcModbusTCP()) << "Connection state changed for" << m_hostAddress << state; + qCDebug(dcModbusTcpMaster()) << "Connection state changed for" << m_hostAddress << state; bool connected = (state == QModbusDevice::ConnectedState); if (m_connected != connected) { m_connected = connected; diff --git a/modbus/modbustcpmaster.h b/libnymea-modbus/modbustcpmaster.h similarity index 97% rename from modbus/modbustcpmaster.h rename to libnymea-modbus/modbustcpmaster.h index 7857922..4b456ee 100644 --- a/modbus/modbustcpmaster.h +++ b/libnymea-modbus/modbustcpmaster.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2021, nymea GmbH +* Copyright 2013 - 2022, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. @@ -31,11 +31,14 @@ #ifndef MODBUSTCPMASTER_H #define MODBUSTCPMASTER_H +#include +#include #include #include #include -#include -#include +#include + +Q_DECLARE_LOGGING_CATEGORY(dcModbusTcpMaster) class ModbusTCPMaster : public QObject { @@ -112,6 +115,7 @@ signals: void receivedDiscreteInput(uint slaveAddress, uint modbusRegister, const QVector &values); void receivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector &values); void receivedInputRegister(uint slaveAddress, uint modbusRegister, const QVector &values); + }; #endif // MODBUSTCPMASTER_H diff --git a/modbus/tools/README.md b/libnymea-modbus/tools/README.md similarity index 85% rename from modbus/tools/README.md rename to libnymea-modbus/tools/README.md index e1e2e1e..939fd4a 100644 --- a/modbus/tools/README.md +++ b/libnymea-modbus/tools/README.md @@ -14,7 +14,7 @@ The class will provide 2 main methods for fetching information from the modbus d * `initialize()` will read all registers with `"readSchedule": "init"` and emits the signal `initializationFinished()` once all replies returned. * `update()` can be used to update all registers with `"readSchedule": "update"`. The class will then fetch each register and update the specified value internally. If the value has changed, the `Changed()` signal will be emitted. -The reulting class will inhert from the `ModbusTCPMaster` class, providing easy access to all possible modbus operations and inform about the connected state. +The resulting class will inhert from the `ModbusTCPMaster` class, providing easy access to all possible modbus operations and inform about the connected state. # JSON format @@ -23,7 +23,8 @@ The basic structure of the modbus register JSON looks like following example: ``` { - "protocol": "TCP", + "className": "MyConnection", + "protocols": [ "TCP" ], "endianness": "BigEndian", "enums": [ { @@ -65,11 +66,65 @@ The basic structure of the modbus register JSON looks like following example: "access": "RO" }, ... + ], + "blocks": [ + { + "id": "blockName", + "readSchedule": "update", + "registers": [ + { + "id": "registerOne", + "address": 0, + "size": 2, + ... + }, + { + "id": "registerOne", + "address": 0, + "size": 2, + ... + }, + ... + ] + } ] } ``` +## Class name + +If no name class name has been passed to the generator script, the classname defined in the JSON file will be used. + +The naming convention for the classname and the resulting source code files looks like this: + +The class will be defined as + + * `Connection`. + +The source code files will be calld: + + * `classnameprotocolconnection.h` + * `classnameprotocolconnection.cpp` + + + +## Protocol + +Depending on the communication protocol, a different base class will be used for the resulting output class. + +There are 2 protocol types: + +* `RTU`: a communication based on the RS485 serial RTU transport protocol +* `TCP`: a communication based on the TCP transport protocol + +If the modbus device supports both protocols and you want to generate a class for each protocol you can set the protocol to `BOTH` and a class for `RTU` and one for `TCP` will be generated. + + ... + "protocol": "TCP", + ... + + ## Endianness When converting multiple registers to one data type (i.e. 2 registers uint16 values to one uint32), the order of the registers are important to align with the endianness of the data receiving. @@ -79,15 +134,6 @@ There are 2 possibilities: * `BigEndian`: default if not specified: register bytes come in following order `[0, 1, 2, 3]`: `ABCD` * `LittleEndian`: register bytes come in following order `[0, 1, 2, 3]`: `CDAB` -## Protocol - -Depending on the communication protocol, a different base class will be used for the resulting output class. - -There are 2 possibilities: - -* `RTU`: a communication based on the RS485 serial RTU transport protocol -* `TCP`: a communication based on the TCP transport protocol - ## Enums Many modbus devices provide inforation using `Enums`, indicating a special state trough a defined list of values. If a register implements an enum, you can define it in the `enums` section. The `name` property defines the name of the enum, and the script will generate a c++ enum definition from this section. Each enum value will then be generated using ` = `. @@ -179,12 +225,12 @@ Example block: Change into your plugin sub directory. Assuming you wrote the registers.json file you can run now following command to generate your modbus class: -`$ python3 ../modbus/tools/generate-connection.py -j registers.json -o . -c MyModbusConnection` +`$ python3 ../modbus/tools/generate-connection.py -j registers.json -o . -c MyModbus` You the result will be a header and a source file called: -* `mymodbusconnection.h` -* `mymodbusconnection.cpp` +* `mymodbustcpconnection.h` +* `mymodbustcpconnection.cpp` You can include this class in your project and provide one connection per thing. diff --git a/modbus/tools/connectiontool/__init__.py b/libnymea-modbus/tools/connectiontool/__init__.py similarity index 100% rename from modbus/tools/connectiontool/__init__.py rename to libnymea-modbus/tools/connectiontool/__init__.py diff --git a/modbus/tools/connectiontool/modbusrtu.py b/libnymea-modbus/tools/connectiontool/modbusrtu.py similarity index 99% rename from modbus/tools/connectiontool/modbusrtu.py rename to libnymea-modbus/tools/connectiontool/modbusrtu.py index cdddf40..2d490c6 100644 --- a/modbus/tools/connectiontool/modbusrtu.py +++ b/libnymea-modbus/tools/connectiontool/modbusrtu.py @@ -14,6 +14,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +import logging + from .toolcommon import * ############################################################## @@ -63,7 +65,7 @@ def writePropertyGetSetMethodImplementationsRtu(fileDescriptor, className, regis elif registerDefinition['registerType'] == 'coils': writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeCoils(m_slaveId, %s, values);' % (registerDefinition['address'])) else: - print('Error: invalid register type for writing.') + logger.warning('Error: invalid register type for writing.') exit(1) writeLine(fileDescriptor, '}') @@ -222,7 +224,7 @@ def writeInternalBlockReadMethodDeclarationsRtu(fileDescriptor, blockDefinitions writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) else: writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - writeLine(fileDescriptor, ' */ ' ) + writeLine(fileDescriptor, ' */' ) writeLine(fileDescriptor, ' ModbusRtuReply *readBlock%s();' % (blockName[0].upper() + blockName[1:])) writeLine(fileDescriptor) diff --git a/modbus/tools/connectiontool/modbustcp.py b/libnymea-modbus/tools/connectiontool/modbustcp.py similarity index 99% rename from modbus/tools/connectiontool/modbustcp.py rename to libnymea-modbus/tools/connectiontool/modbustcp.py index aef6b00..1fbd057 100644 --- a/modbus/tools/connectiontool/modbustcp.py +++ b/libnymea-modbus/tools/connectiontool/modbustcp.py @@ -63,7 +63,7 @@ def writePropertyGetSetMethodImplementationsTcp(fileDescriptor, className, regis elif registerDefinition['registerType'] == 'coils': writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, values.count());' % (registerDefinition['address'])) else: - print('Error: invalid register type for writing.') + logger.warning('Error: invalid register type for writing.') exit(1) writeLine(fileDescriptor, ' request.setValues(values);') @@ -218,7 +218,7 @@ def writeInternalBlockReadMethodDeclarationsTcp(fileDescriptor, blockDefinitions writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) else: writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - writeLine(fileDescriptor, ' */ ' ) + writeLine(fileDescriptor, ' */' ) writeLine(fileDescriptor, ' QModbusReply *readBlock%s();' % (blockName[0].upper() + blockName[1:])) writeLine(fileDescriptor) diff --git a/modbus/tools/connectiontool/toolcommon.py b/libnymea-modbus/tools/connectiontool/toolcommon.py similarity index 94% rename from modbus/tools/connectiontool/toolcommon.py rename to libnymea-modbus/tools/connectiontool/toolcommon.py index caccae2..66cac9c 100644 --- a/modbus/tools/connectiontool/toolcommon.py +++ b/libnymea-modbus/tools/connectiontool/toolcommon.py @@ -19,8 +19,10 @@ import re import sys import json import shutil -import argparse import datetime +import logging + +logger = logging.getLogger('modbus-tools') def convertToAlphaNumeric(text): finalText = '' @@ -40,7 +42,7 @@ def convertToCamelCase(text, capitalize = False): s = convertToAlphaNumeric(text) s = s.replace("-", " ").replace("_", " ") words = s.split() - #print('--> words', words) + logger.debug('--> words', words) finalWords = [] for i in range(len(words)): @@ -48,7 +50,7 @@ def convertToCamelCase(text, capitalize = False): if len(camelCaseSplit) == 0: finalWords.append(words[i]) else: - #print('--> camel split words', camelCaseSplit) + logging.debug('Camel calse split words', camelCaseSplit) for j in range(len(camelCaseSplit)): finalWords.append(camelCaseSplit[j]) @@ -60,12 +62,12 @@ def convertToCamelCase(text, capitalize = False): finalText = finalWords[0].capitalize() + ''.join(i.capitalize() for i in finalWords[1:]) else: finalText = finalWords[0].lower() + ''.join(i.capitalize() for i in finalWords[1:]) - #print('Convert camel case:', text, '-->', finalText) + logging.debug('Convert camel case:', text, '-->', finalText) return finalText def loadJsonFile(filePath): - print('--> Loading JSON file', filePath) + logger.info('Loading JSON file %s', filePath) jsonFile = open(filePath, 'r') return json.load(jsonFile) @@ -117,7 +119,7 @@ def writeLicenseHeader(fileDescriptor): def writeRegistersEnum(fileDescriptor, registerJson): - print('Writing enum for all registers') + logger.debug('Writing enum for all registers') registerEnums = {} @@ -141,9 +143,9 @@ def writeRegistersEnum(fileDescriptor, registerJson): sortedRegistersKeys = sorted(registersKeys) sortedRegisterEnumList = [] - print('Sorted registers') + logger.debug('Sorted registers') for registerAddress in sortedRegistersKeys: - print('--> %s : %s' % (registerAddress, registerEnums[registerAddress])) + logger.debug('--> %s : %s' % (registerAddress, registerEnums[registerAddress])) enumData = {} enumData['key'] = registerEnums[registerAddress] enumData['value'] = registerAddress @@ -165,7 +167,7 @@ def writeRegistersEnum(fileDescriptor, registerJson): def writeEnumDefinition(fileDescriptor, enumDefinition): - print('Writing enum', enumDefinition) + logger.debug('Writing enum %s', enumDefinition) enumName = enumDefinition['name'] enumValues = enumDefinition['values'] writeLine(fileDescriptor, ' enum %s {' % enumName) @@ -379,21 +381,21 @@ def validateBlocks(blockDefinitions): previouseRegisterSize = blockRegisters[i - 1]['size'] previouseRegisterType = blockRegisters[i - 1]['registerType'] if previouseRegisterAddress + previouseRegisterSize != blockRegister['address']: - print('Error: block %s has invalid register order in register %s. There seems to be a gap between the registers.' % (blockName, blockRegister['id'])) + logger.warning('Error: block %s has invalid register order in register %s. There seems to be a gap between the registers.' % (blockName, blockRegister['id'])) exit(1) if blockRegister['access'] != registerAccess: - print('Error: block %s has inconsistent register access in register %s. The block registers dont seem to have the same access rights.' % (blockName, blockRegister['id'])) + logger.warning('Error: block %s has inconsistent register access in register %s. The block registers dont seem to have the same access rights.' % (blockName, blockRegister['id'])) exit(1) if blockRegister['registerType'] != registerType: - print('Error: block %s has inconsistent register type in register %s. The block registers dont seem to be from the same type.' % (blockName, blockRegister['id'])) + logger.warning('Error: block %s has inconsistent register type in register %s. The block registers dont seem to be from the same type.' % (blockName, blockRegister['id'])) exit(1) registerCount += 1 blockSize += blockRegister['size'] - print('Define valid block \"%s\" starting at %s with length %s containing %s properties to read.' % (blockName, blockStartAddress, blockSize, registerCount)) + logger.debug('Define valid block \"%s\" starting at %s with length %s containing %s properties to read.' % (blockName, blockStartAddress, blockSize, registerCount)) def writeBlocksUpdateMethodDeclarations(fileDescriptor, blockDefinitions): @@ -418,7 +420,7 @@ def writeBlocksUpdateMethodDeclarations(fileDescriptor, blockDefinitions): writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) else: writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - writeLine(fileDescriptor, ' */ ' ) + writeLine(fileDescriptor, ' */' ) writeLine(fileDescriptor, ' void update%sBlock();' % (blockName[0].upper() + blockName[1:])) writeLine(fileDescriptor) diff --git a/libnymea-modbus/tools/examples/example-registers.json b/libnymea-modbus/tools/examples/example-registers.json new file mode 100644 index 0000000..3bb0b08 --- /dev/null +++ b/libnymea-modbus/tools/examples/example-registers.json @@ -0,0 +1,114 @@ +{ + "className": "Example", + "protocol": "BOTH", + "endianness": "BigEndian", + "enums": [ + { + "name": "NameOfEnum", + "values": [ + { + "key": "EnumValue1", + "value": 0 + }, + { + "key": "EnumValue2", + "value": 1 + } + ] + } + ], + "registers": [ + { + "id": "foo", + "address": 10, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Foo register", + "unit": "ValueUnit", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "bar", + "address": 20, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Bar register", + "unit": "ValueUnit", + "defaultValue": "0", + "access": "RO" + } + ], + "blocks": [ + { + "id": "testBlock", + "readSchedule": "update", + "registers": [ + { + "id": "A", + "address": 0, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "A register", + "unit": "X", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "B", + "address": 2, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "B register", + "unit": "X", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "C", + "address": 4, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "C register", + "unit": "X", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "D", + "address": 6, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "D register", + "unit": "X", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "E", + "address": 8, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "E register", + "unit": "X", + "defaultValue": "0", + "access": "RO" + } + ] + } + ] +} diff --git a/modbus/tools/generate-connection.py b/libnymea-modbus/tools/generate-connection.py similarity index 82% rename from modbus/tools/generate-connection.py rename to libnymea-modbus/tools/generate-connection.py index a6314fd..0fc7c07 100644 --- a/modbus/tools/generate-connection.py +++ b/libnymea-modbus/tools/generate-connection.py @@ -25,13 +25,14 @@ import json import shutil import argparse import datetime +import logging from connectiontool.toolcommon import * from connectiontool.modbusrtu import * from connectiontool.modbustcp import * def writeTcpHeaderFile(): - print('Writing modbus TCP hader file %s' % headerFilePath) + logger.info('Writing modbus TCP header file %s' % headerFilePath) headerFile = open(headerFilePath, 'w') writeLicenseHeader(headerFile) @@ -40,8 +41,8 @@ def writeTcpHeaderFile(): writeLine(headerFile) writeLine(headerFile, '#include ') writeLine(headerFile) - writeLine(headerFile, '#include "../modbus/modbusdatautils.h"') - writeLine(headerFile, '#include "../modbus/modbustcpmaster.h"') + writeLine(headerFile, '#include ') + writeLine(headerFile, '#include ') writeLine(headerFile) @@ -153,12 +154,12 @@ def writeTcpHeaderFile(): def writeTcpSourceFile(): - print('Writing modbus TCP source file %s' % sourceFilePath) + logger.info('Writing modbus TCP source file %s' % sourceFilePath) sourceFile = open(sourceFilePath, 'w') writeLicenseHeader(sourceFile) writeLine(sourceFile) writeLine(sourceFile, '#include "%s"' % headerFileName) - writeLine(sourceFile, '#include "loggingcategories.h"') + writeLine(sourceFile, '#include ') writeLine(sourceFile) writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className)) writeLine(sourceFile) @@ -249,7 +250,7 @@ def writeTcpSourceFile(): ########################################################################################################## def writeRtuHeaderFile(): - print('Writing modbus TCP hader file %s' % headerFilePath) + logger.info('Writing modbus RTU header file %s' % headerFilePath) headerFile = open(headerFilePath, 'w') writeLicenseHeader(headerFile) @@ -258,7 +259,7 @@ def writeRtuHeaderFile(): writeLine(headerFile) writeLine(headerFile, '#include ') writeLine(headerFile) - writeLine(headerFile, '#include "../modbus/modbusdatautils.h"') + writeLine(headerFile, '#include ') writeLine(headerFile, '#include ') writeLine(headerFile) @@ -373,12 +374,12 @@ def writeRtuHeaderFile(): def writeRtuSourceFile(): - print('Writing modbus RTU source file %s' % sourceFilePath) + logger.info('Writing modbus RTU source file %s' % sourceFilePath) sourceFile = open(sourceFilePath, 'w') writeLicenseHeader(sourceFile) writeLine(sourceFile, '#include "%s"' % headerFileName) - writeLine(sourceFile, '#include "loggingcategories.h"') + writeLine(sourceFile, '#include ') writeLine(sourceFile, '#include ') writeLine(sourceFile) writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className)) @@ -466,7 +467,6 @@ def writeRtuSourceFile(): writeLine(sourceFile, '{') writeLine(sourceFile, ' debug.nospace().noquote() << "%s(" << %s->modbusRtuMaster()->modbusUuid().toString() << ", " << %s->modbusRtuMaster()->serialPort() << ", slave ID:" << %s->slaveId() << ")" << "\\n";' % (className, debugObjectParamName, debugObjectParamName, debugObjectParamName)) writeRegistersDebugLine(sourceFile, debugObjectParamName, registerJson['registers']) - if 'blocks' in registerJson: for blockDefinition in registerJson['blocks']: writeRegistersDebugLine(sourceFile, debugObjectParamName, blockDefinition['registers']) @@ -482,35 +482,49 @@ def writeRtuSourceFile(): # Main ############################################################################################ +logger = logging.getLogger('modbus-tools') +logger.setLevel(logging.INFO) +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(logging.INFO) +formatter = logging.Formatter('%(name)s: %(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + parser = argparse.ArgumentParser(description='Generate modbus tcp connection class from JSON register definitions file.') parser.add_argument('-j', '--json', metavar='', help='The JSON file containing the register definitions.') parser.add_argument('-o', '--output-directory', metavar='', help='The output directory for the resulting class.') -parser.add_argument('-c', '--class-name', metavar='', help='The name of the resulting class.') +parser.add_argument('-v', '--verbose', dest='verboseOutput', action='store_true', help='More verbose output.') args = parser.parse_args() registerJson = loadJsonFile(args.json) scriptPath = os.path.dirname(os.path.realpath(sys.argv[0])) outputDirectory = os.path.realpath(args.output_directory) -className = args.class_name -headerFileName = className.lower() + '.h' -sourceFileName = className.lower() + '.cpp' +if not os.path.exists(outputDirectory): + logger.debug("Output directory does not exist. Creating directory %s", outputDirectory) + os.makedirs(outputDirectory) -headerFilePath = os.path.join(outputDirectory, headerFileName) -sourceFilePath = os.path.join(outputDirectory, sourceFileName) +if args.verboseOutput: + logger.setLevel(logging.DEBUG) + ch.setLevel(logging.DEBUG) -print('Scrip path: %s' % scriptPath) -print('Output directory: %s' % outputDirectory) -print('Class name: %s' % className) -print('Header file: %s' % headerFileName) -print('Source file: %s' % sourceFileName) -print('Header file path: %s' % headerFilePath) -print('Source file path: %s' % sourceFilePath) +logger.debug("Verbose output enabled") + +if not 'className' in registerJson: + logger.warning('Classname missing. Please specify the classname in the json file or pass it to the generatori using -c .') + exit(1) + +classNamePrefix = registerJson['className'] endianness = 'BigEndian' if 'endianness' in registerJson: endianness = registerJson['endianness'] +logger.debug('Scrip path: %s' % scriptPath) +logger.debug('Output directory: %s' % outputDirectory) +logger.debug('Class name prefix: %s' % classNamePrefix) +logger.debug('Endianness: %s' % endianness) + protocol = 'TCP' if 'protocol' in registerJson: protocol = registerJson['protocol'] @@ -518,12 +532,77 @@ if 'protocol' in registerJson: if 'blocks' in registerJson: validateBlocks(registerJson['blocks']) +# Create classes depending on the protocol +writeTcp = True +writeRtu = False + if protocol == 'TCP': + writeTcp = True + writeRtu = False +elif protocol == 'RTU': + writeTcp = False + writeRtu = True +else: + # Any other value generates both classes + writeTcp = True + writeRtu = True + +headerFiles = [] +sourceFiles = [] + +if writeTcp: + className = classNamePrefix + 'ModbusTcpConnection' + headerFileName = className.lower() + '.h' + headerFiles.append(headerFileName) + sourceFileName = className.lower() + '.cpp' + sourceFiles.append(sourceFileName) + + headerFilePath = os.path.join(outputDirectory, headerFileName) + sourceFilePath = os.path.join(outputDirectory, sourceFileName) + logger.debug('=======================================================') + logger.debug('Class name: %s' % className) + logger.debug('Header file: %s' % headerFileName) + logger.debug('Source file: %s' % sourceFileName) + logger.debug('Header file path: %s' % headerFilePath) + logger.debug('Source file path: %s' % sourceFilePath) writeTcpHeaderFile() writeTcpSourceFile() -else: + +if writeRtu: + className = classNamePrefix + 'ModbusRtuConnection' + headerFileName = className.lower() + '.h' + headerFiles.append(headerFileName) + sourceFileName = className.lower() + '.cpp' + sourceFiles.append(sourceFileName) + headerFilePath = os.path.join(outputDirectory, headerFileName) + sourceFilePath = os.path.join(outputDirectory, sourceFileName) + logger.debug('=======================================================') + logger.debug('Class name: %s' % className) + logger.debug('Header file: %s' % headerFileName) + logger.debug('Source file: %s' % sourceFileName) + logger.debug('Header file path: %s' % headerFilePath) + logger.debug('Source file path: %s' % sourceFilePath) writeRtuHeaderFile() writeRtuSourceFile() +# Write pri file +projectIncludeFileName = classNamePrefix.lower() + '.pri' +projectIncludeFilePath = os.path.join(outputDirectory, projectIncludeFileName) - +logger.info('Writing connection project include file %s' % projectIncludeFileName) +projectIncludeFile = open(projectIncludeFilePath, 'w') +writeLine(projectIncludeFile, '# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #') +writeLine(projectIncludeFile, '#') +writeLine(projectIncludeFile, '# This file has been autogenerated.') +writeLine(projectIncludeFile, '# Any changes in this file may be overwritten from qmake.') +writeLine(projectIncludeFile, '#') +writeLine(projectIncludeFile, '# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #') +writeLine(projectIncludeFile) +writeLine(projectIncludeFile, 'HEADERS = \\') +for generatedHeaderFileName in headerFiles: + writeLine(projectIncludeFile, ' $${PWD}/%s \\' % generatedHeaderFileName) + +writeLine(projectIncludeFile) +writeLine(projectIncludeFile, "SOURCES = \\") +for generatedSourceFileName in sourceFiles: + writeLine(projectIncludeFile, ' $${PWD}/%s \\' % generatedSourceFileName) diff --git a/modbus.pri b/modbus.pri new file mode 100644 index 0000000..840bcb4 --- /dev/null +++ b/modbus.pri @@ -0,0 +1,12 @@ +QT += network serialport serialbus + +top_srcdir=$$PWD +top_builddir=$$shadowed($$PWD) + +INCLUDEPATH += $$top_srcdir/libnymea-modbus +LIBS += -L$$top_builddir/libnymea-modbus/ -lnymea-modbus + +OTHER_FILES += $${MODBUS_CONNECTIONS} + +include(libnymea-modbus/modbus-tool.pri) + diff --git a/nymea-plugins-modbus.pro b/nymea-plugins-modbus.pro index 6124d5c..2e60263 100644 --- a/nymea-plugins-modbus.pro +++ b/nymea-plugins-modbus.pro @@ -2,7 +2,7 @@ TEMPLATE = subdirs # Note keep it ordered so the lib will be built first CONFIG += ordered -SUBDIRS += libnymea-sunspec +SUBDIRS += libnymea-modbus libnymea-sunspec PLUGIN_DIRS = \ alphainnotec \ From 70dc99a33f1ae34dd27815bf37d87a21507af28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 3 Jun 2022 08:46:35 +0200 Subject: [PATCH 06/42] Update readme for modbus tool --- libnymea-modbus/tools/README.md | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/libnymea-modbus/tools/README.md b/libnymea-modbus/tools/README.md index 939fd4a..a3fc623 100644 --- a/libnymea-modbus/tools/README.md +++ b/libnymea-modbus/tools/README.md @@ -24,7 +24,7 @@ The basic structure of the modbus register JSON looks like following example: ``` { "className": "MyConnection", - "protocols": [ "TCP" ], + "protocol": "BOTH", "endianness": "BigEndian", "enums": [ { @@ -108,7 +108,6 @@ The source code files will be calld: * `classnameprotocolconnection.cpp` - ## Protocol Depending on the communication protocol, a different base class will be used for the resulting output class. @@ -220,20 +219,16 @@ Example block: ] -# Example +# Autogenerate modbus classes -Change into your plugin sub directory. -Assuming you wrote the registers.json file you can run now following command to generate your modbus class: - -`$ python3 ../modbus/tools/generate-connection.py -j registers.json -o . -c MyModbus` - -You the result will be a header and a source file called: - -* `mymodbustcpconnection.h` -* `mymodbustcpconnection.cpp` - -You can include this class in your project and provide one connection per thing. +In order to get always the latest generated code from this tool, the entire process can be automated. +Assuming you have defined the registers in the `my-registers.json` within your plugin directory, and following lines to your plugin project file and run `qmake`. + # Generate modbus connection + MODBUS_CONNECTIONS += my-registers.json + include(../modbus.pri) +If you want to get information about the autogenerating class process, you can add `MODBUS_TOOLS_CONFIG += VERBOSE` in order to get much more information of the process. +Once you run qmake, in the build directory the autogenerated classes can be found. Also in your project you can find the generated classes for inspection. From e1d3593dbceca21ede514d018729a41d0e58c6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 3 Jun 2022 09:28:18 +0200 Subject: [PATCH 07/42] Update protocol parsing logic and warn on invalid protocol --- libnymea-modbus/tools/generate-connection.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/libnymea-modbus/tools/generate-connection.py b/libnymea-modbus/tools/generate-connection.py index 0fc7c07..e385892 100644 --- a/libnymea-modbus/tools/generate-connection.py +++ b/libnymea-modbus/tools/generate-connection.py @@ -533,19 +533,11 @@ if 'blocks' in registerJson: validateBlocks(registerJson['blocks']) # Create classes depending on the protocol -writeTcp = True -writeRtu = False - -if protocol == 'TCP': - writeTcp = True - writeRtu = False -elif protocol == 'RTU': - writeTcp = False - writeRtu = True -else: - # Any other value generates both classes - writeTcp = True - writeRtu = True +writeTcp = protocol in ["TCP", "BOTH"] +writeRtu = protocol in ["RTU", "BOTH"] +if not writeTcp and not writeRtu: + logger.warning('Invalid protocol definition. Please use TCP, RTU or BOTH.') + exit(1) headerFiles = [] sourceFiles = [] From 5224831da6be16cd2ebe5d79a32d10e8aed0be26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 3 Jun 2022 09:43:57 +0200 Subject: [PATCH 08/42] Regenerate project file only if the JSON file has changed --- libnymea-modbus/tools/generate-connection.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/libnymea-modbus/tools/generate-connection.py b/libnymea-modbus/tools/generate-connection.py index e385892..13aa183 100644 --- a/libnymea-modbus/tools/generate-connection.py +++ b/libnymea-modbus/tools/generate-connection.py @@ -22,6 +22,7 @@ import os import re import sys import json +import time import shutil import argparse import datetime @@ -496,7 +497,8 @@ parser.add_argument('-o', '--output-directory', metavar='', help='The parser.add_argument('-v', '--verbose', dest='verboseOutput', action='store_true', help='More verbose output.') args = parser.parse_args() -registerJson = loadJsonFile(args.json) +registerJsonFilePath = os.path.realpath(args.json) +registerJson = loadJsonFile(registerJsonFilePath) scriptPath = os.path.dirname(os.path.realpath(sys.argv[0])) outputDirectory = os.path.realpath(args.output_directory) @@ -581,6 +583,22 @@ if writeRtu: projectIncludeFileName = classNamePrefix.lower() + '.pri' projectIncludeFilePath = os.path.join(outputDirectory, projectIncludeFileName) +# Note: we write the project file only if the registers +# file has been modified since the project has been modified the last time. +# This prevents qt-creator to retrigger qmake runs on it's own by changing the +# project file which retriggers a qmake run and so on... +if os.path.exists(projectIncludeFilePath): + timestampRegistersJson = os.path.getmtime(registerJsonFilePath) + timestampProjectInclude = os.path.getmtime(projectIncludeFilePath) + if timestampRegistersJson > timestampProjectInclude: + logger.debug('Registers modified %s' % time.ctime(timestampRegistersJson)) + logger.debug('Project file modified %s' % time.ctime(timestampProjectInclude)) + logger.debug('Register JSON file has changed since last project file update. %s' % time.ctime(timestampRegistersJson)) + logger.debug('Regenerating project file %s ...' % projectIncludeFileName) + else: + logger.debug('The register JSON file has not changed since the last run. Skip writing the project file %s ...' % projectIncludeFileName) + exit(0) + logger.info('Writing connection project include file %s' % projectIncludeFileName) projectIncludeFile = open(projectIncludeFilePath, 'w') writeLine(projectIncludeFile, '# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #') From 06cde7a4ecf70251f5084a8931a52321991822d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 10:32:37 +0200 Subject: [PATCH 09/42] Update alphainnotec plugin to libnyma-modbus --- .../alphaconnectmodbustcpconnection.cpp | 1273 ----------------- .../alphaconnectmodbustcpconnection.h | 273 ---- alphainnotec/alphainnotec-registers.json | 5 +- alphainnotec/alphainnotec.pro | 15 +- .../integrationpluginalphainnotec.cpp | 104 +- alphainnotec/integrationpluginalphainnotec.h | 4 +- 6 files changed, 64 insertions(+), 1610 deletions(-) delete mode 100644 alphainnotec/alphaconnectmodbustcpconnection.cpp delete mode 100644 alphainnotec/alphaconnectmodbustcpconnection.h diff --git a/alphainnotec/alphaconnectmodbustcpconnection.cpp b/alphainnotec/alphaconnectmodbustcpconnection.cpp deleted file mode 100644 index 9f6dd9b..0000000 --- a/alphainnotec/alphaconnectmodbustcpconnection.cpp +++ /dev/null @@ -1,1273 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -#include "alphaconnectmodbustcpconnection.h" -#include "loggingcategories.h" - -NYMEA_LOGGING_CATEGORY(dcAlphaConnectModbusTcpConnection, "AlphaConnectModbusTcpConnection") - -AlphaConnectModbusTcpConnection::AlphaConnectModbusTcpConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) : - ModbusTCPMaster(hostAddress, port, parent), - m_slaveId(slaveId) -{ - -} - -float AlphaConnectModbusTcpConnection::flowTemperature() const -{ - return m_flowTemperature; -} - -float AlphaConnectModbusTcpConnection::returnTemperature() const -{ - return m_returnTemperature; -} - -float AlphaConnectModbusTcpConnection::externalReturnTemperature() const -{ - return m_externalReturnTemperature; -} - -float AlphaConnectModbusTcpConnection::hotWaterTemperature() const -{ - return m_hotWaterTemperature; -} - -float AlphaConnectModbusTcpConnection::hotGasTemperature() const -{ - return m_hotGasTemperature; -} - -float AlphaConnectModbusTcpConnection::heatSourceInletTemperature() const -{ - return m_heatSourceInletTemperature; -} - -float AlphaConnectModbusTcpConnection::heatSourceOutletTemperature() const -{ - return m_heatSourceOutletTemperature; -} - -float AlphaConnectModbusTcpConnection::roomTemperature1() const -{ - return m_roomTemperature1; -} - -float AlphaConnectModbusTcpConnection::roomTemperature2() const -{ - return m_roomTemperature2; -} - -float AlphaConnectModbusTcpConnection::roomTemperature3() const -{ - return m_roomTemperature3; -} - -float AlphaConnectModbusTcpConnection::solarCollectorTemperature() const -{ - return m_solarCollectorTemperature; -} - -float AlphaConnectModbusTcpConnection::solarStorageTankTemperature() const -{ - return m_solarStorageTankTemperature; -} - -float AlphaConnectModbusTcpConnection::externalEnergySourceTemperature() const -{ - return m_externalEnergySourceTemperature; -} - -float AlphaConnectModbusTcpConnection::supplyAirTemperature() const -{ - return m_supplyAirTemperature; -} - -float AlphaConnectModbusTcpConnection::externalAirTemperature() const -{ - return m_externalAirTemperature; -} - -float AlphaConnectModbusTcpConnection::rbeRoomActualTemperature() const -{ - return m_rbeRoomActualTemperature; -} - -float AlphaConnectModbusTcpConnection::rbeRoomSetpointTemperature() const -{ - return m_rbeRoomSetpointTemperature; -} - -quint16 AlphaConnectModbusTcpConnection::heatingPumpOperatingHours() const -{ - return m_heatingPumpOperatingHours; -} - -AlphaConnectModbusTcpConnection::SystemStatus AlphaConnectModbusTcpConnection::systemStatus() const -{ - return m_systemStatus; -} - -float AlphaConnectModbusTcpConnection::heatingEnergy() const -{ - return m_heatingEnergy; -} - -float AlphaConnectModbusTcpConnection::waterHeatEnergy() const -{ - return m_waterHeatEnergy; -} - -float AlphaConnectModbusTcpConnection::totalHeatEnergy() const -{ - return m_totalHeatEnergy; -} - -float AlphaConnectModbusTcpConnection::outdoorTemperature() const -{ - return m_outdoorTemperature; -} - -QModbusReply *AlphaConnectModbusTcpConnection::setOutdoorTemperature(float outdoorTemperature) -{ - QVector values = ModbusDataUtils::convertFromUInt16(static_cast(outdoorTemperature * 1.0 / pow(10, -1))); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Write \"Outdoor temperature\" register:" << 0 << "size:" << 1 << values; - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 0, values.count()); - request.setValues(values); - return sendWriteRequest(request, m_slaveId); -} - -float AlphaConnectModbusTcpConnection::returnSetpointTemperature() const -{ - return m_returnSetpointTemperature; -} - -QModbusReply *AlphaConnectModbusTcpConnection::setReturnSetpointTemperature(float returnSetpointTemperature) -{ - QVector values = ModbusDataUtils::convertFromUInt16(static_cast(returnSetpointTemperature * 1.0 / pow(10, -1))); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Write \"Return setpoint temperature\" register:" << 1 << "size:" << 1 << values; - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 1, values.count()); - request.setValues(values); - return sendWriteRequest(request, m_slaveId); -} - -float AlphaConnectModbusTcpConnection::hotWaterSetpointTemperature() const -{ - return m_hotWaterSetpointTemperature; -} - -QModbusReply *AlphaConnectModbusTcpConnection::setHotWaterSetpointTemperature(float hotWaterSetpointTemperature) -{ - QVector values = ModbusDataUtils::convertFromUInt16(static_cast(hotWaterSetpointTemperature * 1.0 / pow(10, -1))); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Write \"Hot water setpoint temperature\" register:" << 5 << "size:" << 1 << values; - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 5, values.count()); - request.setValues(values); - return sendWriteRequest(request, m_slaveId); -} - -AlphaConnectModbusTcpConnection::SmartGridState AlphaConnectModbusTcpConnection::smartGrid() const -{ - return m_smartGrid; -} - -QModbusReply *AlphaConnectModbusTcpConnection::setSmartGrid(SmartGridState smartGrid) -{ - QVector values = ModbusDataUtils::convertFromUInt16(static_cast(smartGrid)); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Write \"Smart grid control\" register:" << 14 << "size:" << 1 << values; - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 14, values.count()); - request.setValues(values); - return sendWriteRequest(request, m_slaveId); -} - -void AlphaConnectModbusTcpConnection::initialize() -{ - // No init registers defined. Nothing to be done and we are finished. - emit initializationFinished(); -} - -void AlphaConnectModbusTcpConnection::update() -{ - updateFlowTemperature(); - updateReturnTemperature(); - updateExternalReturnTemperature(); - updateHotWaterTemperature(); - updateHotGasTemperature(); - updateHeatSourceInletTemperature(); - updateHeatSourceOutletTemperature(); - updateRoomTemperature1(); - updateRoomTemperature2(); - updateRoomTemperature3(); - updateSolarCollectorTemperature(); - updateSolarStorageTankTemperature(); - updateExternalEnergySourceTemperature(); - updateSupplyAirTemperature(); - updateExternalAirTemperature(); - updateRbeRoomActualTemperature(); - updateRbeRoomSetpointTemperature(); - updateHeatingPumpOperatingHours(); - updateSystemStatus(); - updateHeatingEnergy(); - updateWaterHeatEnergy(); - updateTotalHeatEnergy(); - updateOutdoorTemperature(); - updateReturnSetpointTemperature(); - updateHotWaterSetpointTemperature(); - updateSmartGrid(); -} - -void AlphaConnectModbusTcpConnection::updateFlowTemperature() -{ - // Update registers from Flow - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Flow\" register:" << 1 << "size:" << 1; - QModbusReply *reply = readFlowTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Flow\" register" << 1 << "size:" << 1 << unit.values(); - float receivedFlowTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_flowTemperature != receivedFlowTemperature) { - m_flowTemperature = receivedFlowTemperature; - emit flowTemperatureChanged(m_flowTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Flow\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Flow\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateReturnTemperature() -{ - // Update registers from Return - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Return\" register:" << 2 << "size:" << 1; - QModbusReply *reply = readReturnTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Return\" register" << 2 << "size:" << 1 << unit.values(); - float receivedReturnTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_returnTemperature != receivedReturnTemperature) { - m_returnTemperature = receivedReturnTemperature; - emit returnTemperatureChanged(m_returnTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Return\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Return\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateExternalReturnTemperature() -{ - // Update registers from External return - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"External return\" register:" << 3 << "size:" << 1; - QModbusReply *reply = readExternalReturnTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"External return\" register" << 3 << "size:" << 1 << unit.values(); - float receivedExternalReturnTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_externalReturnTemperature != receivedExternalReturnTemperature) { - m_externalReturnTemperature = receivedExternalReturnTemperature; - emit externalReturnTemperatureChanged(m_externalReturnTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"External return\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"External return\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateHotWaterTemperature() -{ - // Update registers from Hot water temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Hot water temperature\" register:" << 4 << "size:" << 1; - QModbusReply *reply = readHotWaterTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Hot water temperature\" register" << 4 << "size:" << 1 << unit.values(); - float receivedHotWaterTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_hotWaterTemperature != receivedHotWaterTemperature) { - m_hotWaterTemperature = receivedHotWaterTemperature; - emit hotWaterTemperatureChanged(m_hotWaterTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Hot water temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Hot water temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateHotGasTemperature() -{ - // Update registers from Hot gas temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Hot gas temperature\" register:" << 8 << "size:" << 1; - QModbusReply *reply = readHotGasTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Hot gas temperature\" register" << 8 << "size:" << 1 << unit.values(); - float receivedHotGasTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_hotGasTemperature != receivedHotGasTemperature) { - m_hotGasTemperature = receivedHotGasTemperature; - emit hotGasTemperatureChanged(m_hotGasTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Hot gas temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Hot gas temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateHeatSourceInletTemperature() -{ - // Update registers from Heat source inlet temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Heat source inlet temperature\" register:" << 9 << "size:" << 1; - QModbusReply *reply = readHeatSourceInletTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Heat source inlet temperature\" register" << 9 << "size:" << 1 << unit.values(); - float receivedHeatSourceInletTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_heatSourceInletTemperature != receivedHeatSourceInletTemperature) { - m_heatSourceInletTemperature = receivedHeatSourceInletTemperature; - emit heatSourceInletTemperatureChanged(m_heatSourceInletTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Heat source inlet temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Heat source inlet temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateHeatSourceOutletTemperature() -{ - // Update registers from Heat source outlet temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Heat source outlet temperature\" register:" << 10 << "size:" << 1; - QModbusReply *reply = readHeatSourceOutletTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Heat source outlet temperature\" register" << 10 << "size:" << 1 << unit.values(); - float receivedHeatSourceOutletTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_heatSourceOutletTemperature != receivedHeatSourceOutletTemperature) { - m_heatSourceOutletTemperature = receivedHeatSourceOutletTemperature; - emit heatSourceOutletTemperatureChanged(m_heatSourceOutletTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Heat source outlet temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Heat source outlet temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateRoomTemperature1() -{ - // Update registers from Room remote adjuster 1 temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Room remote adjuster 1 temperature\" register:" << 11 << "size:" << 1; - QModbusReply *reply = readRoomTemperature1(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Room remote adjuster 1 temperature\" register" << 11 << "size:" << 1 << unit.values(); - float receivedRoomTemperature1 = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_roomTemperature1 != receivedRoomTemperature1) { - m_roomTemperature1 = receivedRoomTemperature1; - emit roomTemperature1Changed(m_roomTemperature1); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Room remote adjuster 1 temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Room remote adjuster 1 temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateRoomTemperature2() -{ - // Update registers from Room remote adjuster 2 temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Room remote adjuster 2 temperature\" register:" << 12 << "size:" << 1; - QModbusReply *reply = readRoomTemperature2(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Room remote adjuster 2 temperature\" register" << 12 << "size:" << 1 << unit.values(); - float receivedRoomTemperature2 = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_roomTemperature2 != receivedRoomTemperature2) { - m_roomTemperature2 = receivedRoomTemperature2; - emit roomTemperature2Changed(m_roomTemperature2); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Room remote adjuster 2 temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Room remote adjuster 2 temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateRoomTemperature3() -{ - // Update registers from Room remote adjuster 3 temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Room remote adjuster 3 temperature\" register:" << 13 << "size:" << 1; - QModbusReply *reply = readRoomTemperature3(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Room remote adjuster 3 temperature\" register" << 13 << "size:" << 1 << unit.values(); - float receivedRoomTemperature3 = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_roomTemperature3 != receivedRoomTemperature3) { - m_roomTemperature3 = receivedRoomTemperature3; - emit roomTemperature3Changed(m_roomTemperature3); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Room remote adjuster 3 temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Room remote adjuster 3 temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateSolarCollectorTemperature() -{ - // Update registers from Solar collector temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Solar collector temperature\" register:" << 14 << "size:" << 1; - QModbusReply *reply = readSolarCollectorTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Solar collector temperature\" register" << 14 << "size:" << 1 << unit.values(); - float receivedSolarCollectorTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_solarCollectorTemperature != receivedSolarCollectorTemperature) { - m_solarCollectorTemperature = receivedSolarCollectorTemperature; - emit solarCollectorTemperatureChanged(m_solarCollectorTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Solar collector temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Solar collector temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateSolarStorageTankTemperature() -{ - // Update registers from Solar storage tank temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Solar storage tank temperature\" register:" << 15 << "size:" << 1; - QModbusReply *reply = readSolarStorageTankTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Solar storage tank temperature\" register" << 15 << "size:" << 1 << unit.values(); - float receivedSolarStorageTankTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_solarStorageTankTemperature != receivedSolarStorageTankTemperature) { - m_solarStorageTankTemperature = receivedSolarStorageTankTemperature; - emit solarStorageTankTemperatureChanged(m_solarStorageTankTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Solar storage tank temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Solar storage tank temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateExternalEnergySourceTemperature() -{ - // Update registers from External energy source temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"External energy source temperature\" register:" << 16 << "size:" << 1; - QModbusReply *reply = readExternalEnergySourceTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"External energy source temperature\" register" << 16 << "size:" << 1 << unit.values(); - float receivedExternalEnergySourceTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_externalEnergySourceTemperature != receivedExternalEnergySourceTemperature) { - m_externalEnergySourceTemperature = receivedExternalEnergySourceTemperature; - emit externalEnergySourceTemperatureChanged(m_externalEnergySourceTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"External energy source temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"External energy source temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateSupplyAirTemperature() -{ - // Update registers from Supply air temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Supply air temperature\" register:" << 17 << "size:" << 1; - QModbusReply *reply = readSupplyAirTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Supply air temperature\" register" << 17 << "size:" << 1 << unit.values(); - float receivedSupplyAirTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_supplyAirTemperature != receivedSupplyAirTemperature) { - m_supplyAirTemperature = receivedSupplyAirTemperature; - emit supplyAirTemperatureChanged(m_supplyAirTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Supply air temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Supply air temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateExternalAirTemperature() -{ - // Update registers from External air temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"External air temperature\" register:" << 18 << "size:" << 1; - QModbusReply *reply = readExternalAirTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"External air temperature\" register" << 18 << "size:" << 1 << unit.values(); - float receivedExternalAirTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_externalAirTemperature != receivedExternalAirTemperature) { - m_externalAirTemperature = receivedExternalAirTemperature; - emit externalAirTemperatureChanged(m_externalAirTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"External air temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"External air temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateRbeRoomActualTemperature() -{ - // Update registers from RBE actual room temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"RBE actual room temperature\" register:" << 24 << "size:" << 1; - QModbusReply *reply = readRbeRoomActualTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"RBE actual room temperature\" register" << 24 << "size:" << 1 << unit.values(); - float receivedRbeRoomActualTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_rbeRoomActualTemperature != receivedRbeRoomActualTemperature) { - m_rbeRoomActualTemperature = receivedRbeRoomActualTemperature; - emit rbeRoomActualTemperatureChanged(m_rbeRoomActualTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"RBE actual room temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"RBE actual room temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateRbeRoomSetpointTemperature() -{ - // Update registers from RBE room temperature setpoint - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"RBE room temperature setpoint\" register:" << 24 << "size:" << 1; - QModbusReply *reply = readRbeRoomSetpointTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"RBE room temperature setpoint\" register" << 24 << "size:" << 1 << unit.values(); - float receivedRbeRoomSetpointTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_rbeRoomSetpointTemperature != receivedRbeRoomSetpointTemperature) { - m_rbeRoomSetpointTemperature = receivedRbeRoomSetpointTemperature; - emit rbeRoomSetpointTemperatureChanged(m_rbeRoomSetpointTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"RBE room temperature setpoint\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"RBE room temperature setpoint\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateHeatingPumpOperatingHours() -{ - // Update registers from Heating pump operating hours - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Heating pump operating hours\" register:" << 33 << "size:" << 1; - QModbusReply *reply = readHeatingPumpOperatingHours(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Heating pump operating hours\" register" << 33 << "size:" << 1 << unit.values(); - quint16 receivedHeatingPumpOperatingHours = ModbusDataUtils::convertToUInt16(unit.values()); - if (m_heatingPumpOperatingHours != receivedHeatingPumpOperatingHours) { - m_heatingPumpOperatingHours = receivedHeatingPumpOperatingHours; - emit heatingPumpOperatingHoursChanged(m_heatingPumpOperatingHours); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Heating pump operating hours\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Heating pump operating hours\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateSystemStatus() -{ - // Update registers from System status - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"System status\" register:" << 37 << "size:" << 1; - QModbusReply *reply = readSystemStatus(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"System status\" register" << 37 << "size:" << 1 << unit.values(); - SystemStatus receivedSystemStatus = static_cast(ModbusDataUtils::convertToUInt16(unit.values())); - if (m_systemStatus != receivedSystemStatus) { - m_systemStatus = receivedSystemStatus; - emit systemStatusChanged(m_systemStatus); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"System status\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"System status\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateHeatingEnergy() -{ - // Update registers from Heating energy - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Heating energy\" register:" << 38 << "size:" << 2; - QModbusReply *reply = readHeatingEnergy(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Heating energy\" register" << 38 << "size:" << 2 << unit.values(); - float receivedHeatingEnergy = ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -1); - if (m_heatingEnergy != receivedHeatingEnergy) { - m_heatingEnergy = receivedHeatingEnergy; - emit heatingEnergyChanged(m_heatingEnergy); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Heating energy\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Heating energy\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateWaterHeatEnergy() -{ - // Update registers from Water heat energy - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Water heat energy\" register:" << 40 << "size:" << 2; - QModbusReply *reply = readWaterHeatEnergy(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Water heat energy\" register" << 40 << "size:" << 2 << unit.values(); - float receivedWaterHeatEnergy = ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -1); - if (m_waterHeatEnergy != receivedWaterHeatEnergy) { - m_waterHeatEnergy = receivedWaterHeatEnergy; - emit waterHeatEnergyChanged(m_waterHeatEnergy); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Water heat energy\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Water heat energy\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateTotalHeatEnergy() -{ - // Update registers from Total energy - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Total energy\" register:" << 44 << "size:" << 2; - QModbusReply *reply = readTotalHeatEnergy(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Total energy\" register" << 44 << "size:" << 2 << unit.values(); - float receivedTotalHeatEnergy = ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -1); - if (m_totalHeatEnergy != receivedTotalHeatEnergy) { - m_totalHeatEnergy = receivedTotalHeatEnergy; - emit totalHeatEnergyChanged(m_totalHeatEnergy); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Total energy\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Total energy\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateOutdoorTemperature() -{ - // Update registers from Outdoor temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Outdoor temperature\" register:" << 0 << "size:" << 1; - QModbusReply *reply = readOutdoorTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Outdoor temperature\" register" << 0 << "size:" << 1 << unit.values(); - float receivedOutdoorTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_outdoorTemperature != receivedOutdoorTemperature) { - m_outdoorTemperature = receivedOutdoorTemperature; - emit outdoorTemperatureChanged(m_outdoorTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Outdoor temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Outdoor temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateReturnSetpointTemperature() -{ - // Update registers from Return setpoint temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Return setpoint temperature\" register:" << 1 << "size:" << 1; - QModbusReply *reply = readReturnSetpointTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Return setpoint temperature\" register" << 1 << "size:" << 1 << unit.values(); - float receivedReturnSetpointTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_returnSetpointTemperature != receivedReturnSetpointTemperature) { - m_returnSetpointTemperature = receivedReturnSetpointTemperature; - emit returnSetpointTemperatureChanged(m_returnSetpointTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Return setpoint temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Return setpoint temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateHotWaterSetpointTemperature() -{ - // Update registers from Hot water setpoint temperature - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Hot water setpoint temperature\" register:" << 5 << "size:" << 1; - QModbusReply *reply = readHotWaterSetpointTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Hot water setpoint temperature\" register" << 5 << "size:" << 1 << unit.values(); - float receivedHotWaterSetpointTemperature = ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, -1); - if (m_hotWaterSetpointTemperature != receivedHotWaterSetpointTemperature) { - m_hotWaterSetpointTemperature = receivedHotWaterSetpointTemperature; - emit hotWaterSetpointTemperatureChanged(m_hotWaterSetpointTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Hot water setpoint temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Hot water setpoint temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void AlphaConnectModbusTcpConnection::updateSmartGrid() -{ - // Update registers from Smart grid control - qCDebug(dcAlphaConnectModbusTcpConnection()) << "--> Read \"Smart grid control\" register:" << 14 << "size:" << 1; - QModbusReply *reply = readSmartGrid(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - qCDebug(dcAlphaConnectModbusTcpConnection()) << "<-- Response from \"Smart grid control\" register" << 14 << "size:" << 1 << unit.values(); - SmartGridState receivedSmartGrid = static_cast(ModbusDataUtils::convertToUInt16(unit.values())); - if (m_smartGrid != receivedSmartGrid) { - m_smartGrid = receivedSmartGrid; - emit smartGridChanged(m_smartGrid); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Modbus reply error occurred while updating \"Smart grid control\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcAlphaConnectModbusTcpConnection()) << "Error occurred while reading \"Smart grid control\" registers from" << hostAddress().toString() << errorString(); - } -} - -QModbusReply *AlphaConnectModbusTcpConnection::readFlowTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 1, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readReturnTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 2, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readExternalReturnTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 3, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readHotWaterTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 4, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readHotGasTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 8, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readHeatSourceInletTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 9, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readHeatSourceOutletTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 10, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readRoomTemperature1() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 11, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readRoomTemperature2() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 12, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readRoomTemperature3() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 13, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readSolarCollectorTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 14, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readSolarStorageTankTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 15, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readExternalEnergySourceTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 16, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readSupplyAirTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 17, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readExternalAirTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 18, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readRbeRoomActualTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 24, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readRbeRoomSetpointTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 24, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readHeatingPumpOperatingHours() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 33, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readSystemStatus() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 37, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readHeatingEnergy() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 38, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readWaterHeatEnergy() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 40, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readTotalHeatEnergy() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 44, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readOutdoorTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 0, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readReturnSetpointTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 1, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readHotWaterSetpointTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 5, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *AlphaConnectModbusTcpConnection::readSmartGrid() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 14, 1); - return sendReadRequest(request, m_slaveId); -} - -void AlphaConnectModbusTcpConnection::verifyInitFinished() -{ - if (m_pendingInitReplies.isEmpty()) { - qCDebug(dcAlphaConnectModbusTcpConnection()) << "Initialization finished of AlphaConnectModbusTcpConnection" << hostAddress().toString(); - emit initializationFinished(); - } -} - -QDebug operator<<(QDebug debug, AlphaConnectModbusTcpConnection *alphaConnectModbusTcpConnection) -{ - debug.nospace().noquote() << "AlphaConnectModbusTcpConnection(" << alphaConnectModbusTcpConnection->hostAddress().toString() << ":" << alphaConnectModbusTcpConnection->port() << ")" << "\n"; - debug.nospace().noquote() << " - Flow:" << alphaConnectModbusTcpConnection->flowTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Return:" << alphaConnectModbusTcpConnection->returnTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - External return:" << alphaConnectModbusTcpConnection->externalReturnTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Hot water temperature:" << alphaConnectModbusTcpConnection->hotWaterTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Hot gas temperature:" << alphaConnectModbusTcpConnection->hotGasTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Heat source inlet temperature:" << alphaConnectModbusTcpConnection->heatSourceInletTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Heat source outlet temperature:" << alphaConnectModbusTcpConnection->heatSourceOutletTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Room remote adjuster 1 temperature:" << alphaConnectModbusTcpConnection->roomTemperature1() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Room remote adjuster 2 temperature:" << alphaConnectModbusTcpConnection->roomTemperature2() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Room remote adjuster 3 temperature:" << alphaConnectModbusTcpConnection->roomTemperature3() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Solar collector temperature:" << alphaConnectModbusTcpConnection->solarCollectorTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Solar storage tank temperature:" << alphaConnectModbusTcpConnection->solarStorageTankTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - External energy source temperature:" << alphaConnectModbusTcpConnection->externalEnergySourceTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Supply air temperature:" << alphaConnectModbusTcpConnection->supplyAirTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - External air temperature:" << alphaConnectModbusTcpConnection->externalAirTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - RBE actual room temperature:" << alphaConnectModbusTcpConnection->rbeRoomActualTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - RBE room temperature setpoint:" << alphaConnectModbusTcpConnection->rbeRoomSetpointTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Heating pump operating hours:" << alphaConnectModbusTcpConnection->heatingPumpOperatingHours() << " [h]" << "\n"; - debug.nospace().noquote() << " - System status:" << alphaConnectModbusTcpConnection->systemStatus() << "\n"; - debug.nospace().noquote() << " - Heating energy:" << alphaConnectModbusTcpConnection->heatingEnergy() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Water heat energy:" << alphaConnectModbusTcpConnection->waterHeatEnergy() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Total energy:" << alphaConnectModbusTcpConnection->totalHeatEnergy() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Outdoor temperature:" << alphaConnectModbusTcpConnection->outdoorTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Return setpoint temperature:" << alphaConnectModbusTcpConnection->returnSetpointTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Hot water setpoint temperature:" << alphaConnectModbusTcpConnection->hotWaterSetpointTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Smart grid control:" << alphaConnectModbusTcpConnection->smartGrid() << "\n"; - return debug.quote().space(); -} - diff --git a/alphainnotec/alphaconnectmodbustcpconnection.h b/alphainnotec/alphaconnectmodbustcpconnection.h deleted file mode 100644 index 4b27fd1..0000000 --- a/alphainnotec/alphaconnectmodbustcpconnection.h +++ /dev/null @@ -1,273 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef ALPHACONNECTMODBUSTCPCONNECTION_H -#define ALPHACONNECTMODBUSTCPCONNECTION_H - -#include - -#include "../modbus/modbusdatautils.h" -#include "../modbus/modbustcpmaster.h" - -class AlphaConnectModbusTcpConnection : public ModbusTCPMaster -{ - Q_OBJECT -public: - enum SystemStatus { - SystemStatusHeatingMode = 0, - SystemStatusDomesticHotWater = 1, - SystemStatusSwimmingPool = 2, - SystemStatusEVUOff = 3, - SystemStatusDefrost = 4, - SystemStatusOff = 5, - SystemStatusExternalEnergySource = 6, - SystemStatusCoolingMode = 7 - }; - Q_ENUM(SystemStatus) - - enum SmartGridState { - SmartGridStateOff = 0, - SmartGridStateLow = 1, - SmartGridStateStandard = 2, - SmartGridStateHigh = 3 - }; - Q_ENUM(SmartGridState) - - explicit AlphaConnectModbusTcpConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr); - ~AlphaConnectModbusTcpConnection() = default; - - /* Flow [°C] - Address: 1, Size: 1 */ - float flowTemperature() const; - - /* Return [°C] - Address: 2, Size: 1 */ - float returnTemperature() const; - - /* External return [°C] - Address: 3, Size: 1 */ - float externalReturnTemperature() const; - - /* Hot water temperature [°C] - Address: 4, Size: 1 */ - float hotWaterTemperature() const; - - /* Hot gas temperature [°C] - Address: 8, Size: 1 */ - float hotGasTemperature() const; - - /* Heat source inlet temperature [°C] - Address: 9, Size: 1 */ - float heatSourceInletTemperature() const; - - /* Heat source outlet temperature [°C] - Address: 10, Size: 1 */ - float heatSourceOutletTemperature() const; - - /* Room remote adjuster 1 temperature [°C] - Address: 11, Size: 1 */ - float roomTemperature1() const; - - /* Room remote adjuster 2 temperature [°C] - Address: 12, Size: 1 */ - float roomTemperature2() const; - - /* Room remote adjuster 3 temperature [°C] - Address: 13, Size: 1 */ - float roomTemperature3() const; - - /* Solar collector temperature [°C] - Address: 14, Size: 1 */ - float solarCollectorTemperature() const; - - /* Solar storage tank temperature [°C] - Address: 15, Size: 1 */ - float solarStorageTankTemperature() const; - - /* External energy source temperature [°C] - Address: 16, Size: 1 */ - float externalEnergySourceTemperature() const; - - /* Supply air temperature [°C] - Address: 17, Size: 1 */ - float supplyAirTemperature() const; - - /* External air temperature [°C] - Address: 18, Size: 1 */ - float externalAirTemperature() const; - - /* RBE actual room temperature [°C] - Address: 24, Size: 1 */ - float rbeRoomActualTemperature() const; - - /* RBE room temperature setpoint [°C] - Address: 24, Size: 1 */ - float rbeRoomSetpointTemperature() const; - - /* Heating pump operating hours [h] - Address: 33, Size: 1 */ - quint16 heatingPumpOperatingHours() const; - - /* System status - Address: 37, Size: 1 */ - SystemStatus systemStatus() const; - - /* Heating energy [kWh] - Address: 38, Size: 2 */ - float heatingEnergy() const; - - /* Water heat energy [kWh] - Address: 40, Size: 2 */ - float waterHeatEnergy() const; - - /* Total energy [kWh] - Address: 44, Size: 2 */ - float totalHeatEnergy() const; - - /* Outdoor temperature [°C] - Address: 0, Size: 1 */ - float outdoorTemperature() const; - QModbusReply *setOutdoorTemperature(float outdoorTemperature); - - /* Return setpoint temperature [°C] - Address: 1, Size: 1 */ - float returnSetpointTemperature() const; - QModbusReply *setReturnSetpointTemperature(float returnSetpointTemperature); - - /* Hot water setpoint temperature [°C] - Address: 5, Size: 1 */ - float hotWaterSetpointTemperature() const; - QModbusReply *setHotWaterSetpointTemperature(float hotWaterSetpointTemperature); - - /* Smart grid control - Address: 14, Size: 1 */ - SmartGridState smartGrid() const; - QModbusReply *setSmartGrid(SmartGridState smartGrid); - - virtual void initialize(); - virtual void update(); - - void updateFlowTemperature(); - void updateReturnTemperature(); - void updateExternalReturnTemperature(); - void updateHotWaterTemperature(); - void updateHotGasTemperature(); - void updateHeatSourceInletTemperature(); - void updateHeatSourceOutletTemperature(); - void updateRoomTemperature1(); - void updateRoomTemperature2(); - void updateRoomTemperature3(); - void updateSolarCollectorTemperature(); - void updateSolarStorageTankTemperature(); - void updateExternalEnergySourceTemperature(); - void updateSupplyAirTemperature(); - void updateExternalAirTemperature(); - void updateRbeRoomActualTemperature(); - void updateRbeRoomSetpointTemperature(); - void updateHeatingPumpOperatingHours(); - void updateSystemStatus(); - void updateHeatingEnergy(); - void updateWaterHeatEnergy(); - void updateTotalHeatEnergy(); - void updateOutdoorTemperature(); - void updateReturnSetpointTemperature(); - void updateHotWaterSetpointTemperature(); - void updateSmartGrid(); - -signals: - void initializationFinished(); - - void flowTemperatureChanged(float flowTemperature); - void returnTemperatureChanged(float returnTemperature); - void externalReturnTemperatureChanged(float externalReturnTemperature); - void hotWaterTemperatureChanged(float hotWaterTemperature); - void hotGasTemperatureChanged(float hotGasTemperature); - void heatSourceInletTemperatureChanged(float heatSourceInletTemperature); - void heatSourceOutletTemperatureChanged(float heatSourceOutletTemperature); - void roomTemperature1Changed(float roomTemperature1); - void roomTemperature2Changed(float roomTemperature2); - void roomTemperature3Changed(float roomTemperature3); - void solarCollectorTemperatureChanged(float solarCollectorTemperature); - void solarStorageTankTemperatureChanged(float solarStorageTankTemperature); - void externalEnergySourceTemperatureChanged(float externalEnergySourceTemperature); - void supplyAirTemperatureChanged(float supplyAirTemperature); - void externalAirTemperatureChanged(float externalAirTemperature); - void rbeRoomActualTemperatureChanged(float rbeRoomActualTemperature); - void rbeRoomSetpointTemperatureChanged(float rbeRoomSetpointTemperature); - void heatingPumpOperatingHoursChanged(quint16 heatingPumpOperatingHours); - void systemStatusChanged(SystemStatus systemStatus); - void heatingEnergyChanged(float heatingEnergy); - void waterHeatEnergyChanged(float waterHeatEnergy); - void totalHeatEnergyChanged(float totalHeatEnergy); - void outdoorTemperatureChanged(float outdoorTemperature); - void returnSetpointTemperatureChanged(float returnSetpointTemperature); - void hotWaterSetpointTemperatureChanged(float hotWaterSetpointTemperature); - void smartGridChanged(SmartGridState smartGrid); - -private: - quint16 m_slaveId = 1; - QVector m_pendingInitReplies; - - float m_flowTemperature = 0; - float m_returnTemperature = 0; - float m_externalReturnTemperature = 0; - float m_hotWaterTemperature = 0; - float m_hotGasTemperature = 0; - float m_heatSourceInletTemperature = 0; - float m_heatSourceOutletTemperature = 0; - float m_roomTemperature1 = 0; - float m_roomTemperature2 = 0; - float m_roomTemperature3 = 0; - float m_solarCollectorTemperature = 0; - float m_solarStorageTankTemperature = 0; - float m_externalEnergySourceTemperature = 0; - float m_supplyAirTemperature = 0; - float m_externalAirTemperature = 0; - float m_rbeRoomActualTemperature = 0; - float m_rbeRoomSetpointTemperature = 0; - quint16 m_heatingPumpOperatingHours = 0; - SystemStatus m_systemStatus = SystemStatusHeatingMode; - float m_heatingEnergy = 0; - float m_waterHeatEnergy = 0; - float m_totalHeatEnergy = 0; - float m_outdoorTemperature = 0; - float m_returnSetpointTemperature = 0; - float m_hotWaterSetpointTemperature = 0; - SmartGridState m_smartGrid = SmartGridStateStandard; - - void verifyInitFinished(); - - QModbusReply *readFlowTemperature(); - QModbusReply *readReturnTemperature(); - QModbusReply *readExternalReturnTemperature(); - QModbusReply *readHotWaterTemperature(); - QModbusReply *readHotGasTemperature(); - QModbusReply *readHeatSourceInletTemperature(); - QModbusReply *readHeatSourceOutletTemperature(); - QModbusReply *readRoomTemperature1(); - QModbusReply *readRoomTemperature2(); - QModbusReply *readRoomTemperature3(); - QModbusReply *readSolarCollectorTemperature(); - QModbusReply *readSolarStorageTankTemperature(); - QModbusReply *readExternalEnergySourceTemperature(); - QModbusReply *readSupplyAirTemperature(); - QModbusReply *readExternalAirTemperature(); - QModbusReply *readRbeRoomActualTemperature(); - QModbusReply *readRbeRoomSetpointTemperature(); - QModbusReply *readHeatingPumpOperatingHours(); - QModbusReply *readSystemStatus(); - QModbusReply *readHeatingEnergy(); - QModbusReply *readWaterHeatEnergy(); - QModbusReply *readTotalHeatEnergy(); - QModbusReply *readOutdoorTemperature(); - QModbusReply *readReturnSetpointTemperature(); - QModbusReply *readHotWaterSetpointTemperature(); - QModbusReply *readSmartGrid(); - - -}; - -QDebug operator<<(QDebug debug, AlphaConnectModbusTcpConnection *alphaConnectModbusTcpConnection); - -#endif // ALPHACONNECTMODBUSTCPCONNECTION_H diff --git a/alphainnotec/alphainnotec-registers.json b/alphainnotec/alphainnotec-registers.json index 1908e0d..2068ce0 100644 --- a/alphainnotec/alphainnotec-registers.json +++ b/alphainnotec/alphainnotec-registers.json @@ -1,4 +1,6 @@ { + "className": "AlphaInnotec", + "protocol": "TCP", "endianness": "BigEndian", "enums": [ { @@ -397,5 +399,6 @@ "defaultValue": "SmartGridStateStandard", "access": "RW" } - ] + ], + "blocks": [ ] } diff --git a/alphainnotec/alphainnotec.pro b/alphainnotec/alphainnotec.pro index b88c856..b2220a6 100644 --- a/alphainnotec/alphainnotec.pro +++ b/alphainnotec/alphainnotec.pro @@ -1,15 +1,12 @@ include(../plugins.pri) -QT += network serialbus +# Generate modbus connection +MODBUS_CONNECTIONS += alphainnotec-registers.json +MODBUS_TOOLS_CONFIG += VERBOSE +include(../modbus.pri) SOURCES += \ - integrationpluginalphainnotec.cpp \ - alphaconnectmodbustcpconnection.cpp \ - ../modbus/modbustcpmaster.cpp \ - ../modbus/modbusdatautils.cpp + integrationpluginalphainnotec.cpp HEADERS += \ - integrationpluginalphainnotec.h \ - alphaconnectmodbustcpconnection.h \ - ../modbus/modbustcpmaster.h \ - ../modbus/modbusdatautils.h + integrationpluginalphainnotec.h diff --git a/alphainnotec/integrationpluginalphainnotec.cpp b/alphainnotec/integrationpluginalphainnotec.cpp index 153d6b3..d6f5fb6 100644 --- a/alphainnotec/integrationpluginalphainnotec.cpp +++ b/alphainnotec/integrationpluginalphainnotec.cpp @@ -107,8 +107,8 @@ void IntegrationPluginAlphaInnotec::setupThing(ThingSetupInfo *info) uint port = thing->paramValue(alphaConnectThingPortParamTypeId).toUInt(); quint16 slaveId = thing->paramValue(alphaConnectThingSlaveIdParamTypeId).toUInt(); - AlphaConnectModbusTcpConnection *alphaConnectTcpConnection = new AlphaConnectModbusTcpConnection(hostAddress, port, slaveId, this); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::connectionStateChanged, this, [thing, alphaConnectTcpConnection](bool status){ + AlphaInnotecModbusTcpConnection *alphaConnectTcpConnection = new AlphaInnotecModbusTcpConnection(hostAddress, port, slaveId, this); + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::connectionStateChanged, this, [thing, alphaConnectTcpConnection](bool status){ qCDebug(dcAlphaInnotec()) << "Connected changed to" << status << "for" << thing; if (status) { alphaConnectTcpConnection->update(); @@ -119,181 +119,181 @@ void IntegrationPluginAlphaInnotec::setupThing(ThingSetupInfo *info) // Input registers -// connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::meanTemperatureChanged, this, [thing](float meanTemperature){ +// connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::meanTemperatureChanged, this, [thing](float meanTemperature){ // qCDebug(dcAlphaInnotec()) << thing << "mean temperature changed" << meanTemperature << "°C"; // thing->setStateValue(alphaConnectMeanTemperatureStateTypeId, meanTemperature); // }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::flowTemperatureChanged, this, [thing](float flowTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::flowTemperatureChanged, this, [thing](float flowTemperature){ qCDebug(dcAlphaInnotec()) << thing << "flow temperature changed" << flowTemperature << "°C"; thing->setStateValue(alphaConnectFlowTemperatureStateTypeId, flowTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::returnTemperatureChanged, this, [thing](float returnTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::returnTemperatureChanged, this, [thing](float returnTemperature){ qCDebug(dcAlphaInnotec()) << thing << "return temperature changed" << returnTemperature << "°C"; thing->setStateValue(alphaConnectReturnTemperatureStateTypeId, returnTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::externalReturnTemperatureChanged, this, [thing](float externalReturnTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::externalReturnTemperatureChanged, this, [thing](float externalReturnTemperature){ qCDebug(dcAlphaInnotec()) << thing << "external return temperature changed" << externalReturnTemperature << "°C"; thing->setStateValue(alphaConnectExternalReturnTemperatureStateTypeId, externalReturnTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::hotWaterTemperatureChanged, this, [thing](float hotWaterTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::hotWaterTemperatureChanged, this, [thing](float hotWaterTemperature){ qCDebug(dcAlphaInnotec()) << thing << "hot water temperature changed" << hotWaterTemperature << "°C"; thing->setStateValue(alphaConnectHotWaterTemperatureStateTypeId, hotWaterTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::hotGasTemperatureChanged, this, [thing](float hotGasTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::hotGasTemperatureChanged, this, [thing](float hotGasTemperature){ qCDebug(dcAlphaInnotec()) << thing << "hot gas temperature changed" << hotGasTemperature << "°C"; thing->setStateValue(alphaConnectHotGasTemperatureStateTypeId, hotGasTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::heatSourceInletTemperatureChanged, this, [thing](float heatSourceInletTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::heatSourceInletTemperatureChanged, this, [thing](float heatSourceInletTemperature){ qCDebug(dcAlphaInnotec()) << thing << "heat source inlet temperature changed" << heatSourceInletTemperature << "°C"; thing->setStateValue(alphaConnectHeatSourceInletTemperatureStateTypeId, heatSourceInletTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::heatSourceOutletTemperatureChanged, this, [thing](float heatSourceOutletTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::heatSourceOutletTemperatureChanged, this, [thing](float heatSourceOutletTemperature){ qCDebug(dcAlphaInnotec()) << thing << "heat source outlet temperature changed" << heatSourceOutletTemperature << "°C"; thing->setStateValue(alphaConnectHeatSourceOutletTemperatureStateTypeId, heatSourceOutletTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::roomTemperature1Changed, this, [thing](float roomTemperature1){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::roomTemperature1Changed, this, [thing](float roomTemperature1){ qCDebug(dcAlphaInnotec()) << thing << "room remote adjuster 1 temperature changed" << roomTemperature1 << "°C"; thing->setStateValue(alphaConnectRoomTemperature1StateTypeId, roomTemperature1); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::roomTemperature2Changed, this, [thing](float roomTemperature2){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::roomTemperature2Changed, this, [thing](float roomTemperature2){ qCDebug(dcAlphaInnotec()) << thing << "room remote adjuster 2 temperature changed" << roomTemperature2 << "°C"; thing->setStateValue(alphaConnectRoomTemperature2StateTypeId, roomTemperature2); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::roomTemperature3Changed, this, [thing](float roomTemperature3){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::roomTemperature3Changed, this, [thing](float roomTemperature3){ qCDebug(dcAlphaInnotec()) << thing << "room remote adjuster 3 temperature changed" << roomTemperature3 << "°C"; thing->setStateValue(alphaConnectRoomTemperature2StateTypeId, roomTemperature3); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::solarCollectorTemperatureChanged, this, [thing](float solarCollectorTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::solarCollectorTemperatureChanged, this, [thing](float solarCollectorTemperature){ qCDebug(dcAlphaInnotec()) << thing << "solar collector temperature changed" << solarCollectorTemperature << "°C"; thing->setStateValue(alphaConnectSolarCollectorTemperatureStateTypeId, solarCollectorTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::solarStorageTankTemperatureChanged, this, [thing](float solarStorageTankTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::solarStorageTankTemperatureChanged, this, [thing](float solarStorageTankTemperature){ qCDebug(dcAlphaInnotec()) << thing << "solar storage tank temperature changed" << solarStorageTankTemperature << "°C"; thing->setStateValue(alphaConnectSolarCollectorTemperatureStateTypeId, solarStorageTankTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::externalEnergySourceTemperatureChanged, this, [thing](float externalEnergySourceTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::externalEnergySourceTemperatureChanged, this, [thing](float externalEnergySourceTemperature){ qCDebug(dcAlphaInnotec()) << thing << "external energy source temperature changed" << externalEnergySourceTemperature << "°C"; thing->setStateValue(alphaConnectExternalEnergySourceTemperatureStateTypeId, externalEnergySourceTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::supplyAirTemperatureChanged, this, [thing](float supplyAirTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::supplyAirTemperatureChanged, this, [thing](float supplyAirTemperature){ qCDebug(dcAlphaInnotec()) << thing << "supply air temperature changed" << supplyAirTemperature << "°C"; thing->setStateValue(alphaConnectSupplyAirTemperatureStateTypeId, supplyAirTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::externalAirTemperatureChanged, this, [thing](float externalAirTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::externalAirTemperatureChanged, this, [thing](float externalAirTemperature){ qCDebug(dcAlphaInnotec()) << thing << "external air temperature changed" << externalAirTemperature << "°C"; thing->setStateValue(alphaConnectExternalAirTemperatureStateTypeId, externalAirTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::heatingPumpOperatingHoursChanged, this, [thing](quint16 heatingPumpOperatingHours){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::heatingPumpOperatingHoursChanged, this, [thing](quint16 heatingPumpOperatingHours){ qCDebug(dcAlphaInnotec()) << thing << "heating pump operating hours changed" << heatingPumpOperatingHours; thing->setStateValue(alphaConnectHeatingPumpOperatingHoursStateTypeId, heatingPumpOperatingHours); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::systemStatusChanged, this, [thing](AlphaConnectModbusTcpConnection::SystemStatus systemStatus){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::systemStatusChanged, this, [thing](AlphaInnotecModbusTcpConnection::SystemStatus systemStatus){ qCDebug(dcAlphaInnotec()) << thing << "system status changed" << systemStatus; switch (systemStatus) { - case AlphaConnectModbusTcpConnection::SystemStatusHeatingMode: + case AlphaInnotecModbusTcpConnection::SystemStatusHeatingMode: thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Heating mode"); break; - case AlphaConnectModbusTcpConnection::SystemStatusDomesticHotWater: + case AlphaInnotecModbusTcpConnection::SystemStatusDomesticHotWater: thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Domestic hot water"); break; - case AlphaConnectModbusTcpConnection::SystemStatusSwimmingPool: + case AlphaInnotecModbusTcpConnection::SystemStatusSwimmingPool: thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Swimming pool"); break; - case AlphaConnectModbusTcpConnection::SystemStatusEVUOff: + case AlphaInnotecModbusTcpConnection::SystemStatusEVUOff: thing->setStateValue(alphaConnectSystemStatusStateTypeId, "EUV off"); break; - case AlphaConnectModbusTcpConnection::SystemStatusDefrost: + case AlphaInnotecModbusTcpConnection::SystemStatusDefrost: thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Defrost"); break; - case AlphaConnectModbusTcpConnection::SystemStatusOff: + case AlphaInnotecModbusTcpConnection::SystemStatusOff: thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Off"); break; - case AlphaConnectModbusTcpConnection::SystemStatusExternalEnergySource: + case AlphaInnotecModbusTcpConnection::SystemStatusExternalEnergySource: thing->setStateValue(alphaConnectSystemStatusStateTypeId, "External energy source"); break; - case AlphaConnectModbusTcpConnection::SystemStatusCoolingMode: + case AlphaInnotecModbusTcpConnection::SystemStatusCoolingMode: thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Cooling mode"); break; } // Set heating and cooling states according to the system state - thing->setStateValue(alphaConnectHeatingOnStateTypeId, systemStatus == AlphaConnectModbusTcpConnection::SystemStatusHeatingMode); - thing->setStateValue(alphaConnectCoolingOnStateTypeId, systemStatus == AlphaConnectModbusTcpConnection::SystemStatusCoolingMode); + thing->setStateValue(alphaConnectHeatingOnStateTypeId, systemStatus == AlphaInnotecModbusTcpConnection::SystemStatusHeatingMode); + thing->setStateValue(alphaConnectCoolingOnStateTypeId, systemStatus == AlphaInnotecModbusTcpConnection::SystemStatusCoolingMode); }); // Energy - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::totalHeatEnergyChanged, this, [thing](float totalHeatEnergy){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::totalHeatEnergyChanged, this, [thing](float totalHeatEnergy){ qCDebug(dcAlphaInnotec()) << thing << "total heating energy changed" << totalHeatEnergy << "kWh"; thing->setStateValue(alphaConnectTotalEnergyStateTypeId, totalHeatEnergy); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::heatingEnergyChanged, this, [thing](float heatingEnergy){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::heatingEnergyChanged, this, [thing](float heatingEnergy){ qCDebug(dcAlphaInnotec()) << thing << "heating energy changed" << heatingEnergy << "kWh"; thing->setStateValue(alphaConnectHeatingEnergyStateTypeId, heatingEnergy); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::waterHeatEnergyChanged, this, [thing](float waterHeatEnergy){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::waterHeatEnergyChanged, this, [thing](float waterHeatEnergy){ qCDebug(dcAlphaInnotec()) << thing << "water heat energy changed" << waterHeatEnergy << "kWh"; thing->setStateValue(alphaConnectHotWaterEnergyStateTypeId, waterHeatEnergy); }); -// connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::swimmingPoolHeatEnergyChanged, this, [thing](float swimmingPoolHeatEnergy){ +// connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::swimmingPoolHeatEnergyChanged, this, [thing](float swimmingPoolHeatEnergy){ // qCDebug(dcAlphaInnotec()) << thing << "swimming pool heat energy changed" << swimmingPoolHeatEnergy << "kWh"; // thing->setStateValue(alphaConnectSwimmingPoolEnergyStateTypeId, swimmingPoolHeatEnergy); // }); // Holding registers - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::outdoorTemperatureChanged, this, [thing](float outdoorTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::outdoorTemperatureChanged, this, [thing](float outdoorTemperature){ qCDebug(dcAlphaInnotec()) << thing << "outdoor temperature changed" << outdoorTemperature << "°C"; thing->setStateValue(alphaConnectOutdoorTemperatureStateTypeId, outdoorTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::returnSetpointTemperatureChanged, this, [thing](float returnSetpointTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::returnSetpointTemperatureChanged, this, [thing](float returnSetpointTemperature){ qCDebug(dcAlphaInnotec()) << thing << "return setpoint temperature changed" << returnSetpointTemperature << "°C"; thing->setStateValue(alphaConnectReturnSetpointTemperatureStateTypeId, returnSetpointTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::hotWaterSetpointTemperatureChanged, this, [thing](float hotWaterSetpointTemperature){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::hotWaterSetpointTemperatureChanged, this, [thing](float hotWaterSetpointTemperature){ qCDebug(dcAlphaInnotec()) << thing << "hot water setpoint temperature changed" << hotWaterSetpointTemperature << "°C"; thing->setStateValue(alphaConnectHotWaterSetpointTemperatureStateTypeId, hotWaterSetpointTemperature); }); - connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::smartGridChanged, this, [thing](AlphaConnectModbusTcpConnection::SmartGridState smartGridState){ + connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::smartGridChanged, this, [thing](AlphaInnotecModbusTcpConnection::SmartGridState smartGridState){ qCDebug(dcAlphaInnotec()) << thing << "smart grid state changed" << smartGridState; switch (smartGridState) { - case AlphaConnectModbusTcpConnection::SmartGridStateOff: + case AlphaInnotecModbusTcpConnection::SmartGridStateOff: thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "Off"); break; - case AlphaConnectModbusTcpConnection::SmartGridStateLow: + case AlphaInnotecModbusTcpConnection::SmartGridStateLow: thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "Low"); break; - case AlphaConnectModbusTcpConnection::SmartGridStateStandard: + case AlphaInnotecModbusTcpConnection::SmartGridStateStandard: thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "Standard"); break; - case AlphaConnectModbusTcpConnection::SmartGridStateHigh: + case AlphaInnotecModbusTcpConnection::SmartGridStateHigh: thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "High"); break; } }); - m_alpaConnectTcpThings.insert(thing, alphaConnectTcpConnection); + m_connections.insert(thing, alphaConnectTcpConnection); alphaConnectTcpConnection->connectDevice(); // FIXME: make async and check if this is really an alpha connect @@ -308,7 +308,7 @@ void IntegrationPluginAlphaInnotec::postSetupThing(Thing *thing) qCDebug(dcAlphaInnotec()) << "Starting plugin timer..."; m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); connect(m_pluginTimer, &PluginTimer::timeout, this, [this] { - foreach (AlphaConnectModbusTcpConnection *connection, m_alpaConnectTcpThings) { + foreach (AlphaInnotecModbusTcpConnection *connection, m_connections) { if (connection->connected()) { connection->update(); } @@ -322,8 +322,8 @@ void IntegrationPluginAlphaInnotec::postSetupThing(Thing *thing) void IntegrationPluginAlphaInnotec::thingRemoved(Thing *thing) { - if (thing->thingClassId() == alphaConnectThingClassId && m_alpaConnectTcpThings.contains(thing)) { - AlphaConnectModbusTcpConnection *connection = m_alpaConnectTcpThings.take(thing); + if (thing->thingClassId() == alphaConnectThingClassId && m_connections.contains(thing)) { + AlphaInnotecModbusTcpConnection *connection = m_connections.take(thing); delete connection; } @@ -336,7 +336,7 @@ void IntegrationPluginAlphaInnotec::thingRemoved(Thing *thing) void IntegrationPluginAlphaInnotec::executeAction(ThingActionInfo *info) { Thing *thing = info->thing(); - AlphaConnectModbusTcpConnection *connection = m_alpaConnectTcpThings.value(thing); + AlphaInnotecModbusTcpConnection *connection = m_connections.value(thing); if (!connection->connected()) { qCWarning(dcAlphaInnotec()) << "Could not execute action. The modbus connection is currently not available."; @@ -430,15 +430,15 @@ void IntegrationPluginAlphaInnotec::executeAction(ThingActionInfo *info) } else if (info->action().actionTypeId() == alphaConnectSgReadyModeActionTypeId) { QString sgReadyModeString = info->action().paramValue(alphaConnectSgReadyModeActionSgReadyModeParamTypeId).toString(); qCDebug(dcAlphaInnotec()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params(); - AlphaConnectModbusTcpConnection::SmartGridState sgReadyState; + AlphaInnotecModbusTcpConnection::SmartGridState sgReadyState; if (sgReadyModeString == "Off") { - sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateOff; + sgReadyState = AlphaInnotecModbusTcpConnection::SmartGridStateOff; } else if (sgReadyModeString == "Low") { - sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateLow; + sgReadyState = AlphaInnotecModbusTcpConnection::SmartGridStateLow; } else if (sgReadyModeString == "High") { - sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateHigh; + sgReadyState = AlphaInnotecModbusTcpConnection::SmartGridStateHigh; } else { - sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateStandard; + sgReadyState = AlphaInnotecModbusTcpConnection::SmartGridStateStandard; } QModbusReply *reply = connection->setSmartGrid(sgReadyState); diff --git a/alphainnotec/integrationpluginalphainnotec.h b/alphainnotec/integrationpluginalphainnotec.h index 0f6a4cc..284f591 100644 --- a/alphainnotec/integrationpluginalphainnotec.h +++ b/alphainnotec/integrationpluginalphainnotec.h @@ -32,7 +32,7 @@ #define INTEGRATIONPLUGINALPHAINNOTEC_H #include "plugintimer.h" -#include "alphaconnectmodbustcpconnection.h" +#include "alphainnotecmodbustcpconnection.h" #include "integrations/integrationplugin.h" class IntegrationPluginAlphaInnotec: public IntegrationPlugin @@ -54,7 +54,7 @@ public: private: PluginTimer *m_pluginTimer = nullptr; - QHash m_alpaConnectTcpThings; + QHash m_connections; }; #endif // INTEGRATIONPLUGINALPHAINNOTEC_H From f3ea2c9c04c5d8eee0889bc0ee629287cd77d0f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 11:00:02 +0200 Subject: [PATCH 10/42] Update bgetech plugin to libnyma-modbus --- bgetech/bgetech.pro | 13 +- bgetech/sdm630-registers.json | 3 +- bgetech/sdm630modbusrtuconnection.cpp | 455 -------------------------- bgetech/sdm630modbusrtuconnection.h | 199 ----------- 4 files changed, 8 insertions(+), 662 deletions(-) delete mode 100644 bgetech/sdm630modbusrtuconnection.cpp delete mode 100644 bgetech/sdm630modbusrtuconnection.h diff --git a/bgetech/bgetech.pro b/bgetech/bgetech.pro index 080685d..bb12ae8 100644 --- a/bgetech/bgetech.pro +++ b/bgetech/bgetech.pro @@ -1,14 +1,13 @@ include(../plugins.pri) -QT += serialport serialbus +# Generate modbus connection +MODBUS_CONNECTIONS += sdm630-registers.json +#MODBUS_TOOLS_CONFIG += VERBOSE +include(../modbus.pri) HEADERS += \ - integrationpluginbgetech.h \ - sdm630modbusrtuconnection.h \ - ../modbus/modbusdatautils.h + integrationpluginbgetech.h SOURCES += \ - integrationpluginbgetech.cpp \ - sdm630modbusrtuconnection.cpp \ - ../modbus/modbusdatautils.cpp + integrationpluginbgetech.cpp diff --git a/bgetech/sdm630-registers.json b/bgetech/sdm630-registers.json index b4d9f0d..1bdbabf 100644 --- a/bgetech/sdm630-registers.json +++ b/bgetech/sdm630-registers.json @@ -1,4 +1,5 @@ { + "className": "Sdm630", "protocol": "RTU", "endianness": "BigEndian", "registers": [ @@ -257,4 +258,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/bgetech/sdm630modbusrtuconnection.cpp b/bgetech/sdm630modbusrtuconnection.cpp deleted file mode 100644 index 1134d2f..0000000 --- a/bgetech/sdm630modbusrtuconnection.cpp +++ /dev/null @@ -1,455 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -#include "sdm630modbusrtuconnection.h" -#include "loggingcategories.h" - -NYMEA_LOGGING_CATEGORY(dcSdm630ModbusRtuConnection, "Sdm630ModbusRtuConnection") - -Sdm630ModbusRtuConnection::Sdm630ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent) : - QObject(parent), - m_modbusRtuMaster(modbusRtuMaster), - m_slaveId(slaveId) -{ - -} - -ModbusRtuMaster *Sdm630ModbusRtuConnection::modbusRtuMaster() const -{ - return m_modbusRtuMaster; -} -quint16 Sdm630ModbusRtuConnection::slaveId() const -{ - return m_slaveId; -} -float Sdm630ModbusRtuConnection::totalCurrentPower() const -{ - return m_totalCurrentPower; -} - -float Sdm630ModbusRtuConnection::voltagePhaseA() const -{ - return m_voltagePhaseA; -} - -float Sdm630ModbusRtuConnection::voltagePhaseB() const -{ - return m_voltagePhaseB; -} - -float Sdm630ModbusRtuConnection::voltagePhaseC() const -{ - return m_voltagePhaseC; -} - -float Sdm630ModbusRtuConnection::currentPhaseA() const -{ - return m_currentPhaseA; -} - -float Sdm630ModbusRtuConnection::currentPhaseB() const -{ - return m_currentPhaseB; -} - -float Sdm630ModbusRtuConnection::currentPhaseC() const -{ - return m_currentPhaseC; -} - -float Sdm630ModbusRtuConnection::powerPhaseA() const -{ - return m_powerPhaseA; -} - -float Sdm630ModbusRtuConnection::powerPhaseB() const -{ - return m_powerPhaseB; -} - -float Sdm630ModbusRtuConnection::powerPhaseC() const -{ - return m_powerPhaseC; -} - -float Sdm630ModbusRtuConnection::frequency() const -{ - return m_frequency; -} - -float Sdm630ModbusRtuConnection::totalEnergyConsumed() const -{ - return m_totalEnergyConsumed; -} - -float Sdm630ModbusRtuConnection::totalEnergyProduced() const -{ - return m_totalEnergyProduced; -} - -float Sdm630ModbusRtuConnection::energyProducedPhaseA() const -{ - return m_energyProducedPhaseA; -} - -float Sdm630ModbusRtuConnection::energyProducedPhaseB() const -{ - return m_energyProducedPhaseB; -} - -float Sdm630ModbusRtuConnection::energyProducedPhaseC() const -{ - return m_energyProducedPhaseC; -} - -float Sdm630ModbusRtuConnection::energyConsumedPhaseA() const -{ - return m_energyConsumedPhaseA; -} - -float Sdm630ModbusRtuConnection::energyConsumedPhaseB() const -{ - return m_energyConsumedPhaseB; -} - -float Sdm630ModbusRtuConnection::energyConsumedPhaseC() const -{ - return m_energyConsumedPhaseC; -} - -void Sdm630ModbusRtuConnection::initialize() -{ - // No init registers defined. Nothing to be done and we are finished. - emit initializationFinished(); -} - -void Sdm630ModbusRtuConnection::update() -{ - updateTotalCurrentPower(); - updatePhaseVoltageAndCurrentBlock(); - updatePhasePowerBlock(); - updateFrequencyAndTotalEnergyBlock(); - updatePhaseEnergyEnergyBlock(); -} - -void Sdm630ModbusRtuConnection::updateTotalCurrentPower() -{ - // Update registers from Total system power - qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read \"Total system power\" register:" << 52 << "size:" << 2; - ModbusRtuReply *reply = readTotalCurrentPower(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from \"Total system power\" register" << 52 << "size:" << 2 << values; - float receivedTotalCurrentPower = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_totalCurrentPower != receivedTotalCurrentPower) { - m_totalCurrentPower = receivedTotalCurrentPower; - emit totalCurrentPowerChanged(m_totalCurrentPower); - } - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Total system power\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading \"Total system power\" registers"; - } -} - -void Sdm630ModbusRtuConnection::updatePhaseVoltageAndCurrentBlock() -{ - // Update register block "phaseVoltageAndCurrent" - qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"phaseVoltageAndCurrent\" registers from:" << 0 << "size:" << 12; - ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 0, 12); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - QVector values; - qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"phaseVoltageAndCurrent\" register" << 0 << "size:" << 12 << blockValues; - values = blockValues.mid(0, 2); - float receivedVoltagePhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_voltagePhaseA != receivedVoltagePhaseA) { - m_voltagePhaseA = receivedVoltagePhaseA; - emit voltagePhaseAChanged(m_voltagePhaseA); - } - - values = blockValues.mid(2, 2); - float receivedVoltagePhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_voltagePhaseB != receivedVoltagePhaseB) { - m_voltagePhaseB = receivedVoltagePhaseB; - emit voltagePhaseBChanged(m_voltagePhaseB); - } - - values = blockValues.mid(4, 2); - float receivedVoltagePhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_voltagePhaseC != receivedVoltagePhaseC) { - m_voltagePhaseC = receivedVoltagePhaseC; - emit voltagePhaseCChanged(m_voltagePhaseC); - } - - values = blockValues.mid(6, 2); - float receivedCurrentPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_currentPhaseA != receivedCurrentPhaseA) { - m_currentPhaseA = receivedCurrentPhaseA; - emit currentPhaseAChanged(m_currentPhaseA); - } - - values = blockValues.mid(8, 2); - float receivedCurrentPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_currentPhaseB != receivedCurrentPhaseB) { - m_currentPhaseB = receivedCurrentPhaseB; - emit currentPhaseBChanged(m_currentPhaseB); - } - - values = blockValues.mid(10, 2); - float receivedCurrentPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_currentPhaseC != receivedCurrentPhaseC) { - m_currentPhaseC = receivedCurrentPhaseC; - emit currentPhaseCChanged(m_currentPhaseC); - } - - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phaseVoltageAndCurrent\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"phaseVoltageAndCurrent\" registers"; - } -} - -void Sdm630ModbusRtuConnection::updatePhasePowerBlock() -{ - // Update register block "phasePower" - qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"phasePower\" registers from:" << 12 << "size:" << 6; - ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 12, 6); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - QVector values; - qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"phasePower\" register" << 12 << "size:" << 6 << blockValues; - values = blockValues.mid(0, 2); - float receivedPowerPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_powerPhaseA != receivedPowerPhaseA) { - m_powerPhaseA = receivedPowerPhaseA; - emit powerPhaseAChanged(m_powerPhaseA); - } - - values = blockValues.mid(2, 2); - float receivedPowerPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_powerPhaseB != receivedPowerPhaseB) { - m_powerPhaseB = receivedPowerPhaseB; - emit powerPhaseBChanged(m_powerPhaseB); - } - - values = blockValues.mid(4, 2); - float receivedPowerPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_powerPhaseC != receivedPowerPhaseC) { - m_powerPhaseC = receivedPowerPhaseC; - emit powerPhaseCChanged(m_powerPhaseC); - } - - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasePower\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"phasePower\" registers"; - } -} - -void Sdm630ModbusRtuConnection::updateFrequencyAndTotalEnergyBlock() -{ - // Update register block "frequencyAndTotalEnergy" - qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"frequencyAndTotalEnergy\" registers from:" << 70 << "size:" << 6; - ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 70, 6); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - QVector values; - qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"frequencyAndTotalEnergy\" register" << 70 << "size:" << 6 << blockValues; - values = blockValues.mid(0, 2); - float receivedFrequency = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_frequency != receivedFrequency) { - m_frequency = receivedFrequency; - emit frequencyChanged(m_frequency); - } - - values = blockValues.mid(2, 2); - float receivedTotalEnergyConsumed = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_totalEnergyConsumed != receivedTotalEnergyConsumed) { - m_totalEnergyConsumed = receivedTotalEnergyConsumed; - emit totalEnergyConsumedChanged(m_totalEnergyConsumed); - } - - values = blockValues.mid(4, 2); - float receivedTotalEnergyProduced = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_totalEnergyProduced != receivedTotalEnergyProduced) { - m_totalEnergyProduced = receivedTotalEnergyProduced; - emit totalEnergyProducedChanged(m_totalEnergyProduced); - } - - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"frequencyAndTotalEnergy\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"frequencyAndTotalEnergy\" registers"; - } -} - -void Sdm630ModbusRtuConnection::updatePhaseEnergyEnergyBlock() -{ - // Update register block "phaseEnergyEnergy" - qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"phaseEnergyEnergy\" registers from:" << 346 << "size:" << 12; - ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 346, 12); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - QVector values; - qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"phaseEnergyEnergy\" register" << 346 << "size:" << 12 << blockValues; - values = blockValues.mid(0, 2); - float receivedEnergyProducedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyProducedPhaseA != receivedEnergyProducedPhaseA) { - m_energyProducedPhaseA = receivedEnergyProducedPhaseA; - emit energyProducedPhaseAChanged(m_energyProducedPhaseA); - } - - values = blockValues.mid(2, 2); - float receivedEnergyProducedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyProducedPhaseB != receivedEnergyProducedPhaseB) { - m_energyProducedPhaseB = receivedEnergyProducedPhaseB; - emit energyProducedPhaseBChanged(m_energyProducedPhaseB); - } - - values = blockValues.mid(4, 2); - float receivedEnergyProducedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyProducedPhaseC != receivedEnergyProducedPhaseC) { - m_energyProducedPhaseC = receivedEnergyProducedPhaseC; - emit energyProducedPhaseCChanged(m_energyProducedPhaseC); - } - - values = blockValues.mid(6, 2); - float receivedEnergyConsumedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyConsumedPhaseA != receivedEnergyConsumedPhaseA) { - m_energyConsumedPhaseA = receivedEnergyConsumedPhaseA; - emit energyConsumedPhaseAChanged(m_energyConsumedPhaseA); - } - - values = blockValues.mid(8, 2); - float receivedEnergyConsumedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyConsumedPhaseB != receivedEnergyConsumedPhaseB) { - m_energyConsumedPhaseB = receivedEnergyConsumedPhaseB; - emit energyConsumedPhaseBChanged(m_energyConsumedPhaseB); - } - - values = blockValues.mid(10, 2); - float receivedEnergyConsumedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyConsumedPhaseC != receivedEnergyConsumedPhaseC) { - m_energyConsumedPhaseC = receivedEnergyConsumedPhaseC; - emit energyConsumedPhaseCChanged(m_energyConsumedPhaseC); - } - - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phaseEnergyEnergy\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"phaseEnergyEnergy\" registers"; - } -} - -ModbusRtuReply *Sdm630ModbusRtuConnection::readTotalCurrentPower() -{ - return m_modbusRtuMaster->readInputRegister(m_slaveId, 52, 2); -} - -void Sdm630ModbusRtuConnection::verifyInitFinished() -{ - if (m_pendingInitReplies.isEmpty()) { - qCDebug(dcSdm630ModbusRtuConnection()) << "Initialization finished of Sdm630ModbusRtuConnection"; - emit initializationFinished(); - } -} - -QDebug operator<<(QDebug debug, Sdm630ModbusRtuConnection *sdm630ModbusRtuConnection) -{ - debug.nospace().noquote() << "Sdm630ModbusRtuConnection(" << sdm630ModbusRtuConnection->modbusRtuMaster()->modbusUuid().toString() << ", " << sdm630ModbusRtuConnection->modbusRtuMaster()->serialPort() << ", slave ID:" << sdm630ModbusRtuConnection->slaveId() << ")" << "\n"; - debug.nospace().noquote() << " - Total system power:" << sdm630ModbusRtuConnection->totalCurrentPower() << " [W]" << "\n"; - debug.nospace().noquote() << " - Voltage phase L1:" << sdm630ModbusRtuConnection->voltagePhaseA() << " [V]" << "\n"; - debug.nospace().noquote() << " - Voltage phase L2:" << sdm630ModbusRtuConnection->voltagePhaseB() << " [V]" << "\n"; - debug.nospace().noquote() << " - Voltage phase L3:" << sdm630ModbusRtuConnection->voltagePhaseC() << " [V]" << "\n"; - debug.nospace().noquote() << " - Current phase L1:" << sdm630ModbusRtuConnection->currentPhaseA() << " [A]" << "\n"; - debug.nospace().noquote() << " - Current phase L2:" << sdm630ModbusRtuConnection->currentPhaseB() << " [A]" << "\n"; - debug.nospace().noquote() << " - Current phase L3:" << sdm630ModbusRtuConnection->currentPhaseC() << " [A]" << "\n"; - debug.nospace().noquote() << " - Power phase L1:" << sdm630ModbusRtuConnection->powerPhaseA() << " [W]" << "\n"; - debug.nospace().noquote() << " - Power phase L2:" << sdm630ModbusRtuConnection->powerPhaseB() << " [W]" << "\n"; - debug.nospace().noquote() << " - Power phase L3:" << sdm630ModbusRtuConnection->powerPhaseC() << " [W]" << "\n"; - debug.nospace().noquote() << " - Frequency:" << sdm630ModbusRtuConnection->frequency() << " [Hz]" << "\n"; - debug.nospace().noquote() << " - Total energy consumed:" << sdm630ModbusRtuConnection->totalEnergyConsumed() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Total energy produced:" << sdm630ModbusRtuConnection->totalEnergyProduced() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy produced phase A:" << sdm630ModbusRtuConnection->energyProducedPhaseA() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy produced phase B:" << sdm630ModbusRtuConnection->energyProducedPhaseB() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy produced phase C:" << sdm630ModbusRtuConnection->energyProducedPhaseC() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy consumed phase A:" << sdm630ModbusRtuConnection->energyConsumedPhaseA() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy consumed phase B:" << sdm630ModbusRtuConnection->energyConsumedPhaseB() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy consumed phase C:" << sdm630ModbusRtuConnection->energyConsumedPhaseC() << " [kWh]" << "\n"; - return debug.quote().space(); -} - diff --git a/bgetech/sdm630modbusrtuconnection.h b/bgetech/sdm630modbusrtuconnection.h deleted file mode 100644 index 649a667..0000000 --- a/bgetech/sdm630modbusrtuconnection.h +++ /dev/null @@ -1,199 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef SDM630MODBUSRTUCONNECTION_H -#define SDM630MODBUSRTUCONNECTION_H - -#include - -#include "../modbus/modbusdatautils.h" -#include - -class Sdm630ModbusRtuConnection : public QObject -{ - Q_OBJECT -public: - explicit Sdm630ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr); - ~Sdm630ModbusRtuConnection() = default; - - ModbusRtuMaster *modbusRtuMaster() const; - quint16 slaveId() const; - - /* Total system power [W] - Address: 52, Size: 2 */ - float totalCurrentPower() const; - - /* Voltage phase L1 [V] - Address: 0, Size: 2 */ - float voltagePhaseA() const; - - /* Voltage phase L2 [V] - Address: 2, Size: 2 */ - float voltagePhaseB() const; - - /* Voltage phase L3 [V] - Address: 4, Size: 2 */ - float voltagePhaseC() const; - - /* Current phase L1 [A] - Address: 6, Size: 2 */ - float currentPhaseA() const; - - /* Current phase L2 [A] - Address: 8, Size: 2 */ - float currentPhaseB() const; - - /* Current phase L3 [A] - Address: 10, Size: 2 */ - float currentPhaseC() const; - - /* Read block from start addess 0 with size of 12 registers containing following 6 properties: - - Voltage phase L1 [V] - Address: 0, Size: 2 - - Voltage phase L2 [V] - Address: 2, Size: 2 - - Voltage phase L3 [V] - Address: 4, Size: 2 - - Current phase L1 [A] - Address: 6, Size: 2 - - Current phase L2 [A] - Address: 8, Size: 2 - - Current phase L3 [A] - Address: 10, Size: 2 - */ - void updatePhaseVoltageAndCurrentBlock(); - /* Power phase L1 [W] - Address: 12, Size: 2 */ - float powerPhaseA() const; - - /* Power phase L2 [W] - Address: 14, Size: 2 */ - float powerPhaseB() const; - - /* Power phase L3 [W] - Address: 16, Size: 2 */ - float powerPhaseC() const; - - /* Read block from start addess 12 with size of 6 registers containing following 3 properties: - - Power phase L1 [W] - Address: 12, Size: 2 - - Power phase L2 [W] - Address: 14, Size: 2 - - Power phase L3 [W] - Address: 16, Size: 2 - */ - void updatePhasePowerBlock(); - /* Frequency [Hz] - Address: 70, Size: 2 */ - float frequency() const; - - /* Total energy consumed [kWh] - Address: 72, Size: 2 */ - float totalEnergyConsumed() const; - - /* Total energy produced [kWh] - Address: 74, Size: 2 */ - float totalEnergyProduced() const; - - /* Read block from start addess 70 with size of 6 registers containing following 3 properties: - - Frequency [Hz] - Address: 70, Size: 2 - - Total energy consumed [kWh] - Address: 72, Size: 2 - - Total energy produced [kWh] - Address: 74, Size: 2 - */ - void updateFrequencyAndTotalEnergyBlock(); - /* Energy produced phase A [kWh] - Address: 346, Size: 2 */ - float energyProducedPhaseA() const; - - /* Energy produced phase B [kWh] - Address: 348, Size: 2 */ - float energyProducedPhaseB() const; - - /* Energy produced phase C [kWh] - Address: 350, Size: 2 */ - float energyProducedPhaseC() const; - - /* Energy consumed phase A [kWh] - Address: 352, Size: 2 */ - float energyConsumedPhaseA() const; - - /* Energy consumed phase B [kWh] - Address: 354, Size: 2 */ - float energyConsumedPhaseB() const; - - /* Energy consumed phase C [kWh] - Address: 356, Size: 2 */ - float energyConsumedPhaseC() const; - - /* Read block from start addess 346 with size of 12 registers containing following 6 properties: - - Energy produced phase A [kWh] - Address: 346, Size: 2 - - Energy produced phase B [kWh] - Address: 348, Size: 2 - - Energy produced phase C [kWh] - Address: 350, Size: 2 - - Energy consumed phase A [kWh] - Address: 352, Size: 2 - - Energy consumed phase B [kWh] - Address: 354, Size: 2 - - Energy consumed phase C [kWh] - Address: 356, Size: 2 - */ - void updatePhaseEnergyEnergyBlock(); - - void updateTotalCurrentPower(); - - virtual void initialize(); - virtual void update(); - -signals: - void initializationFinished(); - - void totalCurrentPowerChanged(float totalCurrentPower); - void voltagePhaseAChanged(float voltagePhaseA); - void voltagePhaseBChanged(float voltagePhaseB); - void voltagePhaseCChanged(float voltagePhaseC); - void currentPhaseAChanged(float currentPhaseA); - void currentPhaseBChanged(float currentPhaseB); - void currentPhaseCChanged(float currentPhaseC); - void powerPhaseAChanged(float powerPhaseA); - void powerPhaseBChanged(float powerPhaseB); - void powerPhaseCChanged(float powerPhaseC); - void frequencyChanged(float frequency); - void totalEnergyConsumedChanged(float totalEnergyConsumed); - void totalEnergyProducedChanged(float totalEnergyProduced); - void energyProducedPhaseAChanged(float energyProducedPhaseA); - void energyProducedPhaseBChanged(float energyProducedPhaseB); - void energyProducedPhaseCChanged(float energyProducedPhaseC); - void energyConsumedPhaseAChanged(float energyConsumedPhaseA); - void energyConsumedPhaseBChanged(float energyConsumedPhaseB); - void energyConsumedPhaseCChanged(float energyConsumedPhaseC); - -private: - ModbusRtuMaster *m_modbusRtuMaster = nullptr; - quint16 m_slaveId = 1; - QVector m_pendingInitReplies; - - float m_totalCurrentPower = 0; - float m_voltagePhaseA = 0; - float m_voltagePhaseB = 0; - float m_voltagePhaseC = 0; - float m_currentPhaseA = 0; - float m_currentPhaseB = 0; - float m_currentPhaseC = 0; - float m_powerPhaseA = 0; - float m_powerPhaseB = 0; - float m_powerPhaseC = 0; - float m_frequency = 0; - float m_totalEnergyConsumed = 0; - float m_totalEnergyProduced = 0; - float m_energyProducedPhaseA = 0; - float m_energyProducedPhaseB = 0; - float m_energyProducedPhaseC = 0; - float m_energyConsumedPhaseA = 0; - float m_energyConsumedPhaseB = 0; - float m_energyConsumedPhaseC = 0; - - void verifyInitFinished(); - - ModbusRtuReply *readTotalCurrentPower(); - - -}; - -QDebug operator<<(QDebug debug, Sdm630ModbusRtuConnection *sdm630ModbusRtuConnection); - -#endif // SDM630MODBUSRTUCONNECTION_H From 6d794dd7b96cfb69e28dc85276a759888ce483dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 11:39:38 +0200 Subject: [PATCH 11/42] Update huawei plugin to libnyma-modbus --- huawei/huawei-registers.json | 1 + huawei/huawei.pro | 15 +- huawei/huaweifusionsolar.cpp | 71 +--- huawei/huaweimodbustcpconnection.cpp | 523 --------------------------- huawei/huaweimodbustcpconnection.h | 194 ---------- 5 files changed, 22 insertions(+), 782 deletions(-) delete mode 100644 huawei/huaweimodbustcpconnection.cpp delete mode 100644 huawei/huaweimodbustcpconnection.h diff --git a/huawei/huawei-registers.json b/huawei/huawei-registers.json index 0e559d1..e0b585d 100644 --- a/huawei/huawei-registers.json +++ b/huawei/huawei-registers.json @@ -1,4 +1,5 @@ { + "className": "Huawei", "protocol": "TCP", "endianness": "BigEndian", "enums": [ diff --git a/huawei/huawei.pro b/huawei/huawei.pro index 194853d..d5d9324 100644 --- a/huawei/huawei.pro +++ b/huawei/huawei.pro @@ -1,17 +1,14 @@ include(../plugins.pri) -QT += network serialbus +# Generate modbus connection +MODBUS_CONNECTIONS += huawei-registers.json +#MODBUS_TOOLS_CONFIG += VERBOSE +include(../modbus.pri) HEADERS += \ huaweifusionsolar.h \ - huaweimodbustcpconnection.h \ - integrationpluginhuawei.h \ - ../modbus/modbustcpmaster.h \ - ../modbus/modbusdatautils.h + integrationpluginhuawei.h SOURCES += \ huaweifusionsolar.cpp \ - huaweimodbustcpconnection.cpp \ - integrationpluginhuawei.cpp \ - ../modbus/modbustcpmaster.cpp \ - ../modbus/modbusdatautils.cpp + integrationpluginhuawei.cpp diff --git a/huawei/huaweifusionsolar.cpp b/huawei/huaweifusionsolar.cpp index 3374c2a..e11c9e7 100644 --- a/huawei/huaweifusionsolar.cpp +++ b/huawei/huaweifusionsolar.cpp @@ -98,11 +98,7 @@ void HuaweiFusionSolar::readNextRegister() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Inverter active power\" register" << 32080 << "size:" << 2 << values; - float receivedInverterActivePower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -3); - if (m_inverterActivePower != receivedInverterActivePower) { - m_inverterActivePower = receivedInverterActivePower; - emit inverterActivePowerChanged(m_inverterActivePower); - } + processInverterActivePowerRegisterValues(values); } finishRequest(); }); @@ -133,12 +129,8 @@ void HuaweiFusionSolar::readNextRegister() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Inverter device status\" register" << 32089 << "size:" << 1 << values; - InverterDeviceStatus receivedInverterDeviceStatus = static_cast(ModbusDataUtils::convertToUInt16(values)); - qCDebug(dcHuaweiFusionSolar()) << "Inverter status" << receivedInverterDeviceStatus; - if (m_inverterDeviceStatus != receivedInverterDeviceStatus) { - m_inverterDeviceStatus = receivedInverterDeviceStatus; - emit inverterDeviceStatusChanged(m_inverterDeviceStatus); - } + processInverterDeviceStatusRegisterValues(values); + qCDebug(dcHuaweiFusionSolar()) << "Inverter status" << inverterDeviceStatus(); } finishRequest(); }); @@ -169,11 +161,7 @@ void HuaweiFusionSolar::readNextRegister() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Inverter energy produced\" register" << 32106 << "size:" << 2 << values; - float receivedInverterEnergyProduced = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -2); - if (m_inverterEnergyProduced != receivedInverterEnergyProduced) { - m_inverterEnergyProduced = receivedInverterEnergyProduced; - emit inverterEnergyProducedChanged(m_inverterEnergyProduced); - } + processInverterEnergyProducedRegisterValues(values); } finishRequest(); }); @@ -204,18 +192,13 @@ void HuaweiFusionSolar::readNextRegister() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 1 status\" register" << 37000 << "size:" << 1 << values; - BatteryDeviceStatus receivedLunaBattery1Status = static_cast(ModbusDataUtils::convertToUInt16(values)); - qCDebug(dcHuaweiFusionSolar()) << "Battery 1 status" << receivedLunaBattery1Status; - if (receivedLunaBattery1Status == BatteryDeviceStatusOffline) { + processLunaBattery1StatusRegisterValues(values); + qCDebug(dcHuaweiFusionSolar()) << "Battery 1 status" << m_lunaBattery1Status; + if (m_lunaBattery1Status == BatteryDeviceStatusOffline) { m_battery1Available = false; } else { m_battery1Available = true; } - - if (m_lunaBattery1Status != receivedLunaBattery1Status) { - m_lunaBattery1Status = receivedLunaBattery1Status; - emit lunaBattery1StatusChanged(m_lunaBattery1Status); - } } finishRequest(); }); @@ -246,11 +229,7 @@ void HuaweiFusionSolar::readNextRegister() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 1 power\" register" << 37001 << "size:" << 2 << values; - qint32 receivedLunaBattery1Power = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_lunaBattery1Power != receivedLunaBattery1Power) { - m_lunaBattery1Power = receivedLunaBattery1Power; - emit lunaBattery1PowerChanged(m_lunaBattery1Power); - } + processLunaBattery1PowerRegisterValues(values); } finishRequest(); }); @@ -281,11 +260,7 @@ void HuaweiFusionSolar::readNextRegister() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 1 state of charge\" register" << 37004 << "size:" << 1 << values; - float receivedLunaBattery1Soc = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_lunaBattery1Soc != receivedLunaBattery1Soc) { - m_lunaBattery1Soc = receivedLunaBattery1Soc; - emit lunaBattery1SocChanged(m_lunaBattery1Soc); - } + processLunaBattery1SocRegisterValues(values); } finishRequest(); }); @@ -316,11 +291,7 @@ void HuaweiFusionSolar::readNextRegister() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Power meter active power\" register" << 37113 << "size:" << 2 << values; - qint32 receivedPowerMeterActivePower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_powerMeterActivePower != receivedPowerMeterActivePower) { - m_powerMeterActivePower = receivedPowerMeterActivePower; - emit powerMeterActivePowerChanged(m_powerMeterActivePower); - } + processPowerMeterActivePowerRegisterValues(values); } finishRequest(); }); @@ -351,17 +322,13 @@ void HuaweiFusionSolar::readNextRegister() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 2 status\" register" << 37741 << "size:" << 1 << values; - BatteryDeviceStatus receivedLunaBattery2Status = static_cast(ModbusDataUtils::convertToUInt16(values)); - qCDebug(dcHuaweiFusionSolar()) << "Battery 2 status" << receivedLunaBattery2Status; - if (receivedLunaBattery2Status == BatteryDeviceStatusOffline) { + processLunaBattery2StatusRegisterValues(values); + qCDebug(dcHuaweiFusionSolar()) << "Battery 2 status" << m_lunaBattery2Status; + if (m_lunaBattery2Status == BatteryDeviceStatusOffline) { m_battery2Available = false; } else { m_battery2Available = true; } - if (m_lunaBattery2Status != receivedLunaBattery2Status) { - m_lunaBattery2Status = receivedLunaBattery2Status; - emit lunaBattery2StatusChanged(m_lunaBattery2Status); - } } finishRequest(); }); @@ -392,11 +359,7 @@ void HuaweiFusionSolar::readNextRegister() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 2 power\" register" << 37743 << "size:" << 2 << values; - qint32 receivedLunaBattery2Power = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_lunaBattery2Power != receivedLunaBattery2Power) { - m_lunaBattery2Power = receivedLunaBattery2Power; - emit lunaBattery2PowerChanged(m_lunaBattery2Power); - } + processLunaBattery2PowerRegisterValues(values); } finishRequest(); }); @@ -427,11 +390,7 @@ void HuaweiFusionSolar::readNextRegister() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 2 state of charge\" register" << 37738 << "size:" << 1 << values; - float receivedLunaBattery2Soc = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_lunaBattery2Soc != receivedLunaBattery2Soc) { - m_lunaBattery2Soc = receivedLunaBattery2Soc; - emit lunaBattery2SocChanged(m_lunaBattery2Soc); - } + processLunaBattery2SocRegisterValues(values); } finishRequest(); }); diff --git a/huawei/huaweimodbustcpconnection.cpp b/huawei/huaweimodbustcpconnection.cpp deleted file mode 100644 index cca8e02..0000000 --- a/huawei/huaweimodbustcpconnection.cpp +++ /dev/null @@ -1,523 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2022, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -#include "huaweimodbustcpconnection.h" -#include "loggingcategories.h" - -NYMEA_LOGGING_CATEGORY(dcHuaweiModbusTcpConnection, "HuaweiModbusTcpConnection") - -HuaweiModbusTcpConnection::HuaweiModbusTcpConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) : - ModbusTCPMaster(hostAddress, port, parent), - m_slaveId(slaveId) -{ - -} - -float HuaweiModbusTcpConnection::inverterActivePower() const -{ - return m_inverterActivePower; -} - -HuaweiModbusTcpConnection::InverterDeviceStatus HuaweiModbusTcpConnection::inverterDeviceStatus() const -{ - return m_inverterDeviceStatus; -} - -float HuaweiModbusTcpConnection::inverterEnergyProduced() const -{ - return m_inverterEnergyProduced; -} - -qint32 HuaweiModbusTcpConnection::powerMeterActivePower() const -{ - return m_powerMeterActivePower; -} - -HuaweiModbusTcpConnection::BatteryDeviceStatus HuaweiModbusTcpConnection::lunaBattery1Status() const -{ - return m_lunaBattery1Status; -} - -qint32 HuaweiModbusTcpConnection::lunaBattery1Power() const -{ - return m_lunaBattery1Power; -} - -float HuaweiModbusTcpConnection::lunaBattery1Soc() const -{ - return m_lunaBattery1Soc; -} - -HuaweiModbusTcpConnection::BatteryDeviceStatus HuaweiModbusTcpConnection::lunaBattery2Status() const -{ - return m_lunaBattery2Status; -} - -qint32 HuaweiModbusTcpConnection::lunaBattery2Power() const -{ - return m_lunaBattery2Power; -} - -float HuaweiModbusTcpConnection::lunaBattery2Soc() const -{ - return m_lunaBattery2Soc; -} - -void HuaweiModbusTcpConnection::initialize() -{ - // No init registers defined. Nothing to be done and we are finished. - emit initializationFinished(); -} - -void HuaweiModbusTcpConnection::update() -{ - updateInverterActivePower(); - updateInverterDeviceStatus(); - updateInverterEnergyProduced(); - updatePowerMeterActivePower(); - updateLunaBattery1Status(); - updateLunaBattery1Power(); - updateLunaBattery1Soc(); - updateLunaBattery2Status(); - updateLunaBattery2Power(); - updateLunaBattery2Soc(); -} - -void HuaweiModbusTcpConnection::updateInverterActivePower() -{ - // Update registers from Inverter active power - qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Inverter active power\" register:" << 32080 << "size:" << 2; - QModbusReply *reply = readInverterActivePower(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Inverter active power\" register" << 32080 << "size:" << 2 << values; - float receivedInverterActivePower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -3); - if (m_inverterActivePower != receivedInverterActivePower) { - m_inverterActivePower = receivedInverterActivePower; - emit inverterActivePowerChanged(m_inverterActivePower); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Inverter active power\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Inverter active power\" registers from" << hostAddress().toString() << errorString(); - } -} - -void HuaweiModbusTcpConnection::updateInverterDeviceStatus() -{ - // Update registers from Inverter device status - qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Inverter device status\" register:" << 32089 << "size:" << 1; - QModbusReply *reply = readInverterDeviceStatus(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Inverter device status\" register" << 32089 << "size:" << 1 << values; - InverterDeviceStatus receivedInverterDeviceStatus = static_cast(ModbusDataUtils::convertToUInt16(values)); - if (m_inverterDeviceStatus != receivedInverterDeviceStatus) { - m_inverterDeviceStatus = receivedInverterDeviceStatus; - emit inverterDeviceStatusChanged(m_inverterDeviceStatus); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Inverter device status\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Inverter device status\" registers from" << hostAddress().toString() << errorString(); - } -} - -void HuaweiModbusTcpConnection::updateInverterEnergyProduced() -{ - // Update registers from Inverter energy produced - qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Inverter energy produced\" register:" << 32106 << "size:" << 2; - QModbusReply *reply = readInverterEnergyProduced(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Inverter energy produced\" register" << 32106 << "size:" << 2 << values; - float receivedInverterEnergyProduced = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -2); - if (m_inverterEnergyProduced != receivedInverterEnergyProduced) { - m_inverterEnergyProduced = receivedInverterEnergyProduced; - emit inverterEnergyProducedChanged(m_inverterEnergyProduced); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Inverter energy produced\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Inverter energy produced\" registers from" << hostAddress().toString() << errorString(); - } -} - -void HuaweiModbusTcpConnection::updatePowerMeterActivePower() -{ - // Update registers from Power meter active power - qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Power meter active power\" register:" << 37113 << "size:" << 2; - QModbusReply *reply = readPowerMeterActivePower(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Power meter active power\" register" << 37113 << "size:" << 2 << values; - qint32 receivedPowerMeterActivePower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_powerMeterActivePower != receivedPowerMeterActivePower) { - m_powerMeterActivePower = receivedPowerMeterActivePower; - emit powerMeterActivePowerChanged(m_powerMeterActivePower); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Power meter active power\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Power meter active power\" registers from" << hostAddress().toString() << errorString(); - } -} - -void HuaweiModbusTcpConnection::updateLunaBattery1Status() -{ - // Update registers from Luna 2000 Battery 1 status - qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 1 status\" register:" << 37000 << "size:" << 1; - QModbusReply *reply = readLunaBattery1Status(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 1 status\" register" << 37000 << "size:" << 1 << values; - BatteryDeviceStatus receivedLunaBattery1Status = static_cast(ModbusDataUtils::convertToUInt16(values)); - m_lunaBattery1Status = receivedLunaBattery1Status; - emit lunaBattery1StatusChanged(m_lunaBattery1Status); - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 1 status\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 1 status\" registers from" << hostAddress().toString() << errorString(); - } -} - -void HuaweiModbusTcpConnection::updateLunaBattery1Power() -{ - // Update registers from Luna 2000 Battery 1 power - qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 1 power\" register:" << 37001 << "size:" << 2; - QModbusReply *reply = readLunaBattery1Power(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 1 power\" register" << 37001 << "size:" << 2 << values; - qint32 receivedLunaBattery1Power = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_lunaBattery1Power != receivedLunaBattery1Power) { - m_lunaBattery1Power = receivedLunaBattery1Power; - emit lunaBattery1PowerChanged(m_lunaBattery1Power); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 1 power\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 1 power\" registers from" << hostAddress().toString() << errorString(); - } -} - -void HuaweiModbusTcpConnection::updateLunaBattery1Soc() -{ - // Update registers from Luna 2000 Battery 1 state of charge - qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 1 state of charge\" register:" << 37004 << "size:" << 1; - QModbusReply *reply = readLunaBattery1Soc(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 1 state of charge\" register" << 37004 << "size:" << 1 << values; - float receivedLunaBattery1Soc = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_lunaBattery1Soc != receivedLunaBattery1Soc) { - m_lunaBattery1Soc = receivedLunaBattery1Soc; - emit lunaBattery1SocChanged(m_lunaBattery1Soc); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 1 state of charge\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 1 state of charge\" registers from" << hostAddress().toString() << errorString(); - } -} - -void HuaweiModbusTcpConnection::updateLunaBattery2Status() -{ - // Update registers from Luna 2000 Battery 2 status - qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 2 status\" register:" << 37741 << "size:" << 1; - QModbusReply *reply = readLunaBattery2Status(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 2 status\" register" << 37741 << "size:" << 1 << values; - BatteryDeviceStatus receivedLunaBattery2Status = static_cast(ModbusDataUtils::convertToUInt16(values)); - m_lunaBattery2Status = receivedLunaBattery2Status; - emit lunaBattery2StatusChanged(m_lunaBattery2Status); - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 2 status\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 2 status\" registers from" << hostAddress().toString() << errorString(); - } -} - -void HuaweiModbusTcpConnection::updateLunaBattery2Power() -{ - // Update registers from Luna 2000 Battery 2 power - qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 2 power\" register:" << 37743 << "size:" << 2; - QModbusReply *reply = readLunaBattery2Power(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 2 power\" register" << 37743 << "size:" << 2 << values; - qint32 receivedLunaBattery2Power = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_lunaBattery2Power != receivedLunaBattery2Power) { - m_lunaBattery2Power = receivedLunaBattery2Power; - emit lunaBattery2PowerChanged(m_lunaBattery2Power); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 2 power\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 2 power\" registers from" << hostAddress().toString() << errorString(); - } -} - -void HuaweiModbusTcpConnection::updateLunaBattery2Soc() -{ - // Update registers from Luna 2000 Battery 2 state of charge - qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 2 state of charge\" register:" << 37738 << "size:" << 1; - QModbusReply *reply = readLunaBattery2Soc(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 2 state of charge\" register" << 37738 << "size:" << 1 << values; - float receivedLunaBattery2Soc = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_lunaBattery2Soc != receivedLunaBattery2Soc) { - m_lunaBattery2Soc = receivedLunaBattery2Soc; - emit lunaBattery2SocChanged(m_lunaBattery2Soc); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 2 state of charge\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 2 state of charge\" registers from" << hostAddress().toString() << errorString(); - } -} - -QModbusReply *HuaweiModbusTcpConnection::readInverterActivePower() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 32080, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *HuaweiModbusTcpConnection::readInverterDeviceStatus() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 32089, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *HuaweiModbusTcpConnection::readInverterEnergyProduced() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 32106, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *HuaweiModbusTcpConnection::readPowerMeterActivePower() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37113, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *HuaweiModbusTcpConnection::readLunaBattery1Status() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37000, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *HuaweiModbusTcpConnection::readLunaBattery1Power() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37001, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *HuaweiModbusTcpConnection::readLunaBattery1Soc() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37004, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *HuaweiModbusTcpConnection::readLunaBattery2Status() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37741, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *HuaweiModbusTcpConnection::readLunaBattery2Power() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37743, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *HuaweiModbusTcpConnection::readLunaBattery2Soc() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37738, 1); - return sendReadRequest(request, m_slaveId); -} - -void HuaweiModbusTcpConnection::verifyInitFinished() -{ - if (m_pendingInitReplies.isEmpty()) { - qCDebug(dcHuaweiModbusTcpConnection()) << "Initialization finished of HuaweiModbusTcpConnection" << hostAddress().toString(); - emit initializationFinished(); - } -} - -QDebug operator<<(QDebug debug, HuaweiModbusTcpConnection *huaweiModbusTcpConnection) -{ - debug.nospace().noquote() << "HuaweiModbusTcpConnection(" << huaweiModbusTcpConnection->hostAddress().toString() << ":" << huaweiModbusTcpConnection->port() << ")" << "\n"; - debug.nospace().noquote() << " - Inverter active power:" << huaweiModbusTcpConnection->inverterActivePower() << " [kW]" << "\n"; - debug.nospace().noquote() << " - Inverter device status:" << huaweiModbusTcpConnection->inverterDeviceStatus() << "\n"; - debug.nospace().noquote() << " - Inverter energy produced:" << huaweiModbusTcpConnection->inverterEnergyProduced() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Power meter active power:" << huaweiModbusTcpConnection->powerMeterActivePower() << " [W]" << "\n"; - debug.nospace().noquote() << " - Luna 2000 Battery 1 status:" << huaweiModbusTcpConnection->lunaBattery1Status() << "\n"; - debug.nospace().noquote() << " - Luna 2000 Battery 1 power:" << huaweiModbusTcpConnection->lunaBattery1Power() << " [W]" << "\n"; - debug.nospace().noquote() << " - Luna 2000 Battery 1 state of charge:" << huaweiModbusTcpConnection->lunaBattery1Soc() << " [%]" << "\n"; - debug.nospace().noquote() << " - Luna 2000 Battery 2 status:" << huaweiModbusTcpConnection->lunaBattery2Status() << "\n"; - debug.nospace().noquote() << " - Luna 2000 Battery 2 power:" << huaweiModbusTcpConnection->lunaBattery2Power() << " [W]" << "\n"; - debug.nospace().noquote() << " - Luna 2000 Battery 2 state of charge:" << huaweiModbusTcpConnection->lunaBattery2Soc() << " [%]" << "\n"; - return debug.quote().space(); -} - diff --git a/huawei/huaweimodbustcpconnection.h b/huawei/huaweimodbustcpconnection.h deleted file mode 100644 index 40ce1b3..0000000 --- a/huawei/huaweimodbustcpconnection.h +++ /dev/null @@ -1,194 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2022, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HUAWEIMODBUSTCPCONNECTION_H -#define HUAWEIMODBUSTCPCONNECTION_H - -#include - -#include "../modbus/modbusdatautils.h" -#include "../modbus/modbustcpmaster.h" - -class HuaweiModbusTcpConnection : public ModbusTCPMaster -{ - Q_OBJECT -public: - enum Registers { - RegisterInverterActivePower = 32080, - RegisterInverterDeviceStatus = 32089, - RegisterInverterEnergyProduced = 32106, - RegisterLunaBattery1Status = 37000, - RegisterLunaBattery1Power = 37001, - RegisterLunaBattery1Soc = 37004, - RegisterPowerMeterActivePower = 37113, - RegisterLunaBattery2Soc = 37738, - RegisterLunaBattery2Status = 37741, - RegisterLunaBattery2Power = 37743 - }; - Q_ENUM(Registers) - - enum InverterDeviceStatus { - InverterDeviceStatusStandbyInitializing = 0, - InverterDeviceStatusStandbyDetectingInsulationResistance = 1, - InverterDeviceStatusStandbyDetectingIrradiation = 2, - InverterDeviceStatusStandbyDridDetecting = 3, - InverterDeviceStatusStarting = 256, - InverterDeviceStatusOnGrid = 512, - InverterDeviceStatusPowerLimited = 513, - InverterDeviceStatusSelfDerating = 514, - InverterDeviceStatusShutdownFault = 768, - InverterDeviceStatusShutdownCommand = 769, - InverterDeviceStatusShutdownOVGR = 770, - InverterDeviceStatusShutdownCommunicationDisconnected = 771, - InverterDeviceStatusShutdownPowerLimit = 772, - InverterDeviceStatusShutdownManualStartupRequired = 773, - InverterDeviceStatusShutdownInputUnderpower = 774, - InverterDeviceStatusGridSchedulingPCurve = 1025, - InverterDeviceStatusGridSchedulingQUCurve = 1026, - InverterDeviceStatusGridSchedulingPFUCurve = 1027, - InverterDeviceStatusGridSchedulingDryContact = 1028, - InverterDeviceStatusGridSchedulingQPCurve = 1029, - InverterDeviceStatusSpotCheckReady = 1280, - InverterDeviceStatusSpotChecking = 1281, - InverterDeviceStatusInspecting = 1536, - InverterDeviceStatusAfciSelfCheck = 1792, - InverterDeviceStatusIVScanning = 2048, - InverterDeviceStatusDCInputDetection = 2304, - InverterDeviceStatusRunningOffGridCharging = 2560, - InverterDeviceStatusStandbyNoIrradiation = 40960 - }; - Q_ENUM(InverterDeviceStatus) - - enum BatteryDeviceStatus { - BatteryDeviceStatusOffline = 0, - BatteryDeviceStatusStandby = 1, - BatteryDeviceStatusRunning = 1, - BatteryDeviceStatusFault = 1, - BatteryDeviceStatusSleepMode = 1 - }; - Q_ENUM(BatteryDeviceStatus) - - explicit HuaweiModbusTcpConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr); - ~HuaweiModbusTcpConnection() = default; - - /* Inverter active power [kW] - Address: 32080, Size: 2 */ - float inverterActivePower() const; - - /* Inverter device status - Address: 32089, Size: 1 */ - InverterDeviceStatus inverterDeviceStatus() const; - - /* Inverter energy produced [kWh] - Address: 32106, Size: 2 */ - float inverterEnergyProduced() const; - - /* Power meter active power [W] - Address: 37113, Size: 2 */ - qint32 powerMeterActivePower() const; - - /* Luna 2000 Battery 1 status - Address: 37000, Size: 1 */ - BatteryDeviceStatus lunaBattery1Status() const; - - /* Luna 2000 Battery 1 power [W] - Address: 37001, Size: 2 */ - qint32 lunaBattery1Power() const; - - /* Luna 2000 Battery 1 state of charge [%] - Address: 37004, Size: 1 */ - float lunaBattery1Soc() const; - - /* Luna 2000 Battery 2 status - Address: 37741, Size: 1 */ - BatteryDeviceStatus lunaBattery2Status() const; - - /* Luna 2000 Battery 2 power [W] - Address: 37743, Size: 2 */ - qint32 lunaBattery2Power() const; - - /* Luna 2000 Battery 2 state of charge [%] - Address: 37738, Size: 1 */ - float lunaBattery2Soc() const; - - - virtual void initialize(); - virtual void update(); - - void updateInverterActivePower(); - void updateInverterDeviceStatus(); - void updateInverterEnergyProduced(); - void updatePowerMeterActivePower(); - void updateLunaBattery1Status(); - void updateLunaBattery1Power(); - void updateLunaBattery1Soc(); - void updateLunaBattery2Status(); - void updateLunaBattery2Power(); - void updateLunaBattery2Soc(); - -signals: - void initializationFinished(); - - void inverterActivePowerChanged(float inverterActivePower); - void inverterDeviceStatusChanged(InverterDeviceStatus inverterDeviceStatus); - void inverterEnergyProducedChanged(float inverterEnergyProduced); - void powerMeterActivePowerChanged(qint32 powerMeterActivePower); - void lunaBattery1StatusChanged(BatteryDeviceStatus lunaBattery1Status); - void lunaBattery1PowerChanged(qint32 lunaBattery1Power); - void lunaBattery1SocChanged(float lunaBattery1Soc); - void lunaBattery2StatusChanged(BatteryDeviceStatus lunaBattery2Status); - void lunaBattery2PowerChanged(qint32 lunaBattery2Power); - void lunaBattery2SocChanged(float lunaBattery2Soc); - -protected: - QModbusReply *readInverterActivePower(); - QModbusReply *readInverterDeviceStatus(); - QModbusReply *readInverterEnergyProduced(); - QModbusReply *readPowerMeterActivePower(); - QModbusReply *readLunaBattery1Status(); - QModbusReply *readLunaBattery1Power(); - QModbusReply *readLunaBattery1Soc(); - QModbusReply *readLunaBattery2Status(); - QModbusReply *readLunaBattery2Power(); - QModbusReply *readLunaBattery2Soc(); - - float m_inverterActivePower = 0; - InverterDeviceStatus m_inverterDeviceStatus = InverterDeviceStatusStandbyInitializing; - float m_inverterEnergyProduced = 0; - qint32 m_powerMeterActivePower = 0; - BatteryDeviceStatus m_lunaBattery1Status = BatteryDeviceStatusOffline; - qint32 m_lunaBattery1Power = 0; - float m_lunaBattery1Soc = 0; - BatteryDeviceStatus m_lunaBattery2Status = BatteryDeviceStatusOffline; - qint32 m_lunaBattery2Power = 0; - float m_lunaBattery2Soc = 0; - -private: - quint16 m_slaveId = 1; - QVector m_pendingInitReplies; - - void verifyInitFinished(); - - -}; - -QDebug operator<<(QDebug debug, HuaweiModbusTcpConnection *huaweiModbusTcpConnection); - -#endif // HUAWEIMODBUSTCPCONNECTION_H From c46c333a6856737197ee04ca1b47f61ba13518fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 11:43:35 +0200 Subject: [PATCH 12/42] Update idm plugin to libnyma-modbus --- idm/idm.cpp | 2 +- idm/idm.pro | 11 +++-------- {modbus => idm}/modbushelpers.cpp | 0 {modbus => idm}/modbushelpers.h | 0 4 files changed, 4 insertions(+), 9 deletions(-) rename {modbus => idm}/modbushelpers.cpp (100%) rename {modbus => idm}/modbushelpers.h (100%) diff --git a/idm/idm.cpp b/idm/idm.cpp index dc96863..9ea769e 100644 --- a/idm/idm.cpp +++ b/idm/idm.cpp @@ -30,7 +30,7 @@ #include "idm.h" #include "extern-plugininfo.h" -#include "../modbus/modbushelpers.h" +#include "modbushelpers.h" #include diff --git a/idm/idm.pro b/idm/idm.pro index 6bc6551..d8a1e12 100644 --- a/idm/idm.pro +++ b/idm/idm.pro @@ -1,19 +1,14 @@ include(../plugins.pri) - -QT += \ - network \ - serialbus \ +include(../modbus.pri) SOURCES += \ idm.cpp \ integrationpluginidm.cpp \ - ../modbus/modbustcpmaster.cpp \ - ../modbus/modbushelpers.cpp \ + modbushelpers.cpp HEADERS += \ idm.h \ idminfo.h \ integrationpluginidm.h \ - ../modbus/modbustcpmaster.h \ - ../modbus/modbushelpers.h \ + modbushelpers.h diff --git a/modbus/modbushelpers.cpp b/idm/modbushelpers.cpp similarity index 100% rename from modbus/modbushelpers.cpp rename to idm/modbushelpers.cpp diff --git a/modbus/modbushelpers.h b/idm/modbushelpers.h similarity index 100% rename from modbus/modbushelpers.h rename to idm/modbushelpers.h From 5d4d8beb56ce8a13e52225c38b4d34de285f18b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 11:44:12 +0200 Subject: [PATCH 13/42] Disable verbose generate connection for alphainnotec --- alphainnotec/alphainnotec.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alphainnotec/alphainnotec.pro b/alphainnotec/alphainnotec.pro index b2220a6..18fd540 100644 --- a/alphainnotec/alphainnotec.pro +++ b/alphainnotec/alphainnotec.pro @@ -2,7 +2,7 @@ include(../plugins.pri) # Generate modbus connection MODBUS_CONNECTIONS += alphainnotec-registers.json -MODBUS_TOOLS_CONFIG += VERBOSE +#MODBUS_TOOLS_CONFIG += VERBOSE include(../modbus.pri) SOURCES += \ From c947b510239ba24ea11e00a70da012dd30c23190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 11:47:09 +0200 Subject: [PATCH 14/42] Update inepro plugin to libnyma-modbus --- inepro/inepro.pro | 13 +- inepro/integrationplugininepro.cpp | 14 +- inepro/integrationplugininepro.h | 4 +- inepro/pro380-registers.json | 3 +- inepro/pro380modbusrtuconnection.cpp | 537 --------------------------- inepro/pro380modbusrtuconnection.h | 204 ---------- 6 files changed, 16 insertions(+), 759 deletions(-) delete mode 100644 inepro/pro380modbusrtuconnection.cpp delete mode 100644 inepro/pro380modbusrtuconnection.h diff --git a/inepro/inepro.pro b/inepro/inepro.pro index 4067273..d4395d8 100644 --- a/inepro/inepro.pro +++ b/inepro/inepro.pro @@ -1,14 +1,13 @@ include(../plugins.pri) -QT += serialport serialbus +# Generate modbus connection +MODBUS_CONNECTIONS += pro380-registers.json +#MODBUS_TOOLS_CONFIG += VERBOSE +include(../modbus.pri) HEADERS += \ - integrationplugininepro.h \ - pro380modbusrtuconnection.h \ - ../modbus/modbusdatautils.h + integrationplugininepro.h SOURCES += \ - integrationplugininepro.cpp \ - pro380modbusrtuconnection.cpp \ - ../modbus/modbusdatautils.cpp + integrationplugininepro.cpp diff --git a/inepro/integrationplugininepro.cpp b/inepro/integrationplugininepro.cpp index af5ff77..9d5cf2c 100644 --- a/inepro/integrationplugininepro.cpp +++ b/inepro/integrationplugininepro.cpp @@ -45,7 +45,7 @@ void IntegrationPluginInepro::init() qCWarning(dcInepro()) << "Modbus RTU hardware resource removed for" << thing << ". The thing will not be functional any more until a new resource has been configured for it."; thing->setStateValue(pro380ConnectedStateTypeId, false); - delete m_pro380Connections.take(thing); + delete m_connections.take(thing); } } }); @@ -101,9 +101,9 @@ void IntegrationPluginInepro::setupThing(ThingSetupInfo *info) return; } - if (m_pro380Connections.contains(thing)) { + if (m_connections.contains(thing)) { qCDebug(dcInepro()) << "Setup after rediscovery, cleaning up ..."; - m_pro380Connections.take(thing)->deleteLater(); + m_connections.take(thing)->deleteLater(); } Pro380ModbusRtuConnection *proConnection = new Pro380ModbusRtuConnection(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), address, this); @@ -194,7 +194,7 @@ void IntegrationPluginInepro::setupThing(ThingSetupInfo *info) // FIXME: try to read before setup success - m_pro380Connections.insert(thing, proConnection); + m_connections.insert(thing, proConnection); info->finish(Thing::ThingErrorNoError); } @@ -205,7 +205,7 @@ void IntegrationPluginInepro::postSetupThing(Thing *thing) m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(2); connect(m_refreshTimer, &PluginTimer::timeout, this, [this] { foreach (Thing *thing, myThings()) { - m_pro380Connections.value(thing)->update(); + m_connections.value(thing)->update(); } }); @@ -218,8 +218,8 @@ void IntegrationPluginInepro::thingRemoved(Thing *thing) { qCDebug(dcInepro()) << "Thing removed" << thing->name(); - if (m_pro380Connections.contains(thing)) - m_pro380Connections.take(thing)->deleteLater(); + if (m_connections.contains(thing)) + m_connections.take(thing)->deleteLater(); if (myThings().isEmpty() && m_refreshTimer) { qCDebug(dcInepro()) << "Stopping reconnect timer"; diff --git a/inepro/integrationplugininepro.h b/inepro/integrationplugininepro.h index dfd8ce0..f74a38b 100644 --- a/inepro/integrationplugininepro.h +++ b/inepro/integrationplugininepro.h @@ -37,8 +37,6 @@ #include "pro380modbusrtuconnection.h" -#include "extern-plugininfo.h" - #include #include @@ -59,8 +57,8 @@ public: private: PluginTimer *m_refreshTimer = nullptr; + QHash m_connections; - QHash m_pro380Connections; }; #endif // INTEGRATIONPLUGININEPRO_H diff --git a/inepro/pro380-registers.json b/inepro/pro380-registers.json index d9c189e..0c9fe50 100644 --- a/inepro/pro380-registers.json +++ b/inepro/pro380-registers.json @@ -1,4 +1,5 @@ { + "className": "Pro380", "protocol": "RTU", "endianness": "BigEndian", "blocks": [ @@ -263,4 +264,4 @@ "access": "RO" } ] -} \ No newline at end of file +} diff --git a/inepro/pro380modbusrtuconnection.cpp b/inepro/pro380modbusrtuconnection.cpp deleted file mode 100644 index 013b80c..0000000 --- a/inepro/pro380modbusrtuconnection.cpp +++ /dev/null @@ -1,537 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -#include "pro380modbusrtuconnection.h" -#include "loggingcategories.h" - -NYMEA_LOGGING_CATEGORY(dcPro380ModbusRtuConnection, "Pro380ModbusRtuConnection") - -Pro380ModbusRtuConnection::Pro380ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent) : - QObject(parent), - m_modbusRtuMaster(modbusRtuMaster), - m_slaveId(slaveId) -{ - -} - -ModbusRtuMaster *Pro380ModbusRtuConnection::modbusRtuMaster() const -{ - return m_modbusRtuMaster; -} -quint16 Pro380ModbusRtuConnection::slaveId() const -{ - return m_slaveId; -} -float Pro380ModbusRtuConnection::frequency() const -{ - return m_frequency; -} - -float Pro380ModbusRtuConnection::totalEnergyConsumed() const -{ - return m_totalEnergyConsumed; -} - -float Pro380ModbusRtuConnection::totalEnergyProduced() const -{ - return m_totalEnergyProduced; -} - -float Pro380ModbusRtuConnection::voltagePhaseA() const -{ - return m_voltagePhaseA; -} - -float Pro380ModbusRtuConnection::voltagePhaseB() const -{ - return m_voltagePhaseB; -} - -float Pro380ModbusRtuConnection::voltagePhaseC() const -{ - return m_voltagePhaseC; -} - -float Pro380ModbusRtuConnection::currentPhaseA() const -{ - return m_currentPhaseA; -} - -float Pro380ModbusRtuConnection::currentPhaseB() const -{ - return m_currentPhaseB; -} - -float Pro380ModbusRtuConnection::currentPhaseC() const -{ - return m_currentPhaseC; -} - -float Pro380ModbusRtuConnection::totalCurrentPower() const -{ - return m_totalCurrentPower; -} - -float Pro380ModbusRtuConnection::powerPhaseA() const -{ - return m_powerPhaseA; -} - -float Pro380ModbusRtuConnection::powerPhaseB() const -{ - return m_powerPhaseB; -} - -float Pro380ModbusRtuConnection::powerPhaseC() const -{ - return m_powerPhaseC; -} - -float Pro380ModbusRtuConnection::energyConsumedPhaseA() const -{ - return m_energyConsumedPhaseA; -} - -float Pro380ModbusRtuConnection::energyConsumedPhaseB() const -{ - return m_energyConsumedPhaseB; -} - -float Pro380ModbusRtuConnection::energyConsumedPhaseC() const -{ - return m_energyConsumedPhaseC; -} - -float Pro380ModbusRtuConnection::energyProducedPhaseA() const -{ - return m_energyProducedPhaseA; -} - -float Pro380ModbusRtuConnection::energyProducedPhaseB() const -{ - return m_energyProducedPhaseB; -} - -float Pro380ModbusRtuConnection::energyProducedPhaseC() const -{ - return m_energyProducedPhaseC; -} - -void Pro380ModbusRtuConnection::initialize() -{ - // No init registers defined. Nothing to be done and we are finished. - emit initializationFinished(); -} - -void Pro380ModbusRtuConnection::update() -{ - updateFrequency(); - updateTotalEnergyConsumed(); - updateTotalEnergyProduced(); - updatePhasesVoltageBlock(); - updatePhasesCurrentBlock(); - updateCurrentPowerBlock(); - updatePhasesEnergyConsumedBlock(); - updatePhasesEnergyProducedBlock(); -} - -void Pro380ModbusRtuConnection::updateFrequency() -{ - // Update registers from Frequency - qCDebug(dcPro380ModbusRtuConnection()) << "--> Read \"Frequency\" register:" << 20488 << "size:" << 2; - ModbusRtuReply *reply = readFrequency(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from \"Frequency\" register" << 20488 << "size:" << 2 << values; - float receivedFrequency = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_frequency != receivedFrequency) { - m_frequency = receivedFrequency; - emit frequencyChanged(m_frequency); - } - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Frequency\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading \"Frequency\" registers"; - } -} - -void Pro380ModbusRtuConnection::updateTotalEnergyConsumed() -{ - // Update registers from Total energy consumed (Forward active energy) - qCDebug(dcPro380ModbusRtuConnection()) << "--> Read \"Total energy consumed (Forward active energy)\" register:" << 24588 << "size:" << 2; - ModbusRtuReply *reply = readTotalEnergyConsumed(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from \"Total energy consumed (Forward active energy)\" register" << 24588 << "size:" << 2 << values; - float receivedTotalEnergyConsumed = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_totalEnergyConsumed != receivedTotalEnergyConsumed) { - m_totalEnergyConsumed = receivedTotalEnergyConsumed; - emit totalEnergyConsumedChanged(m_totalEnergyConsumed); - } - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Total energy consumed (Forward active energy)\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading \"Total energy consumed (Forward active energy)\" registers"; - } -} - -void Pro380ModbusRtuConnection::updateTotalEnergyProduced() -{ - // Update registers from Total energy produced (Reverse active energy) - qCDebug(dcPro380ModbusRtuConnection()) << "--> Read \"Total energy produced (Reverse active energy)\" register:" << 24600 << "size:" << 2; - ModbusRtuReply *reply = readTotalEnergyProduced(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from \"Total energy produced (Reverse active energy)\" register" << 24600 << "size:" << 2 << values; - float receivedTotalEnergyProduced = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_totalEnergyProduced != receivedTotalEnergyProduced) { - m_totalEnergyProduced = receivedTotalEnergyProduced; - emit totalEnergyProducedChanged(m_totalEnergyProduced); - } - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Total energy produced (Reverse active energy)\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading \"Total energy produced (Reverse active energy)\" registers"; - } -} - -void Pro380ModbusRtuConnection::updatePhasesVoltageBlock() -{ - // Update register block "phasesVoltage" - qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesVoltage\" registers from:" << 20482 << "size:" << 6; - ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20482, 6); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - QVector values; - qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesVoltage\" register" << 20482 << "size:" << 6 << blockValues; - values = blockValues.mid(0, 2); - float receivedVoltagePhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_voltagePhaseA != receivedVoltagePhaseA) { - m_voltagePhaseA = receivedVoltagePhaseA; - emit voltagePhaseAChanged(m_voltagePhaseA); - } - - values = blockValues.mid(2, 2); - float receivedVoltagePhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_voltagePhaseB != receivedVoltagePhaseB) { - m_voltagePhaseB = receivedVoltagePhaseB; - emit voltagePhaseBChanged(m_voltagePhaseB); - } - - values = blockValues.mid(4, 2); - float receivedVoltagePhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_voltagePhaseC != receivedVoltagePhaseC) { - m_voltagePhaseC = receivedVoltagePhaseC; - emit voltagePhaseCChanged(m_voltagePhaseC); - } - - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesVoltage\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesVoltage\" registers"; - } -} - -void Pro380ModbusRtuConnection::updatePhasesCurrentBlock() -{ - // Update register block "phasesCurrent" - qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesCurrent\" registers from:" << 20492 << "size:" << 6; - ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20492, 6); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - QVector values; - qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesCurrent\" register" << 20492 << "size:" << 6 << blockValues; - values = blockValues.mid(0, 2); - float receivedCurrentPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_currentPhaseA != receivedCurrentPhaseA) { - m_currentPhaseA = receivedCurrentPhaseA; - emit currentPhaseAChanged(m_currentPhaseA); - } - - values = blockValues.mid(2, 2); - float receivedCurrentPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_currentPhaseB != receivedCurrentPhaseB) { - m_currentPhaseB = receivedCurrentPhaseB; - emit currentPhaseBChanged(m_currentPhaseB); - } - - values = blockValues.mid(4, 2); - float receivedCurrentPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_currentPhaseC != receivedCurrentPhaseC) { - m_currentPhaseC = receivedCurrentPhaseC; - emit currentPhaseCChanged(m_currentPhaseC); - } - - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesCurrent\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesCurrent\" registers"; - } -} - -void Pro380ModbusRtuConnection::updateCurrentPowerBlock() -{ - // Update register block "currentPower" - qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"currentPower\" registers from:" << 20498 << "size:" << 8; - ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20498, 8); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - QVector values; - qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"currentPower\" register" << 20498 << "size:" << 8 << blockValues; - values = blockValues.mid(0, 2); - float receivedTotalCurrentPower = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_totalCurrentPower != receivedTotalCurrentPower) { - m_totalCurrentPower = receivedTotalCurrentPower; - emit totalCurrentPowerChanged(m_totalCurrentPower); - } - - values = blockValues.mid(2, 2); - float receivedPowerPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_powerPhaseA != receivedPowerPhaseA) { - m_powerPhaseA = receivedPowerPhaseA; - emit powerPhaseAChanged(m_powerPhaseA); - } - - values = blockValues.mid(4, 2); - float receivedPowerPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_powerPhaseB != receivedPowerPhaseB) { - m_powerPhaseB = receivedPowerPhaseB; - emit powerPhaseBChanged(m_powerPhaseB); - } - - values = blockValues.mid(6, 2); - float receivedPowerPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_powerPhaseC != receivedPowerPhaseC) { - m_powerPhaseC = receivedPowerPhaseC; - emit powerPhaseCChanged(m_powerPhaseC); - } - - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"currentPower\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"currentPower\" registers"; - } -} - -void Pro380ModbusRtuConnection::updatePhasesEnergyConsumedBlock() -{ - // Update register block "phasesEnergyConsumed" - qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesEnergyConsumed\" registers from:" << 24594 << "size:" << 6; - ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24594, 6); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - QVector values; - qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesEnergyConsumed\" register" << 24594 << "size:" << 6 << blockValues; - values = blockValues.mid(0, 2); - float receivedEnergyConsumedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyConsumedPhaseA != receivedEnergyConsumedPhaseA) { - m_energyConsumedPhaseA = receivedEnergyConsumedPhaseA; - emit energyConsumedPhaseAChanged(m_energyConsumedPhaseA); - } - - values = blockValues.mid(2, 2); - float receivedEnergyConsumedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyConsumedPhaseB != receivedEnergyConsumedPhaseB) { - m_energyConsumedPhaseB = receivedEnergyConsumedPhaseB; - emit energyConsumedPhaseBChanged(m_energyConsumedPhaseB); - } - - values = blockValues.mid(4, 2); - float receivedEnergyConsumedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyConsumedPhaseC != receivedEnergyConsumedPhaseC) { - m_energyConsumedPhaseC = receivedEnergyConsumedPhaseC; - emit energyConsumedPhaseCChanged(m_energyConsumedPhaseC); - } - - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesEnergyConsumed\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesEnergyConsumed\" registers"; - } -} - -void Pro380ModbusRtuConnection::updatePhasesEnergyProducedBlock() -{ - // Update register block "phasesEnergyProduced" - qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesEnergyProduced\" registers from:" << 24606 << "size:" << 6; - ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24606, 6); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - QVector values; - qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesEnergyProduced\" register" << 24606 << "size:" << 6 << blockValues; - values = blockValues.mid(0, 2); - float receivedEnergyProducedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyProducedPhaseA != receivedEnergyProducedPhaseA) { - m_energyProducedPhaseA = receivedEnergyProducedPhaseA; - emit energyProducedPhaseAChanged(m_energyProducedPhaseA); - } - - values = blockValues.mid(2, 2); - float receivedEnergyProducedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyProducedPhaseB != receivedEnergyProducedPhaseB) { - m_energyProducedPhaseB = receivedEnergyProducedPhaseB; - emit energyProducedPhaseBChanged(m_energyProducedPhaseB); - } - - values = blockValues.mid(4, 2); - float receivedEnergyProducedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_energyProducedPhaseC != receivedEnergyProducedPhaseC) { - m_energyProducedPhaseC = receivedEnergyProducedPhaseC; - emit energyProducedPhaseCChanged(m_energyProducedPhaseC); - } - - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesEnergyProduced\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesEnergyProduced\" registers"; - } -} - -ModbusRtuReply *Pro380ModbusRtuConnection::readFrequency() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20488, 2); -} - -ModbusRtuReply *Pro380ModbusRtuConnection::readTotalEnergyConsumed() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24588, 2); -} - -ModbusRtuReply *Pro380ModbusRtuConnection::readTotalEnergyProduced() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24600, 2); -} - -void Pro380ModbusRtuConnection::verifyInitFinished() -{ - if (m_pendingInitReplies.isEmpty()) { - qCDebug(dcPro380ModbusRtuConnection()) << "Initialization finished of Pro380ModbusRtuConnection"; - emit initializationFinished(); - } -} - -QDebug operator<<(QDebug debug, Pro380ModbusRtuConnection *pro380ModbusRtuConnection) -{ - debug.nospace().noquote() << "Pro380ModbusRtuConnection(" << pro380ModbusRtuConnection->modbusRtuMaster()->modbusUuid().toString() << ", " << pro380ModbusRtuConnection->modbusRtuMaster()->serialPort() << ", slave ID:" << pro380ModbusRtuConnection->slaveId() << ")" << "\n"; - debug.nospace().noquote() << " - Frequency:" << pro380ModbusRtuConnection->frequency() << " [Hz]" << "\n"; - debug.nospace().noquote() << " - Total energy consumed (Forward active energy):" << pro380ModbusRtuConnection->totalEnergyConsumed() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Total energy produced (Reverse active energy):" << pro380ModbusRtuConnection->totalEnergyProduced() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Voltage phase L1:" << pro380ModbusRtuConnection->voltagePhaseA() << " [V]" << "\n"; - debug.nospace().noquote() << " - Voltage phase L2:" << pro380ModbusRtuConnection->voltagePhaseB() << " [V]" << "\n"; - debug.nospace().noquote() << " - Voltage phase L3:" << pro380ModbusRtuConnection->voltagePhaseC() << " [V]" << "\n"; - debug.nospace().noquote() << " - Current phase L1:" << pro380ModbusRtuConnection->currentPhaseA() << " [A]" << "\n"; - debug.nospace().noquote() << " - Current phase L2:" << pro380ModbusRtuConnection->currentPhaseB() << " [A]" << "\n"; - debug.nospace().noquote() << " - Current phase L3:" << pro380ModbusRtuConnection->currentPhaseC() << " [A]" << "\n"; - debug.nospace().noquote() << " - Total system power:" << pro380ModbusRtuConnection->totalCurrentPower() << " [kW]" << "\n"; - debug.nospace().noquote() << " - Power phase L1:" << pro380ModbusRtuConnection->powerPhaseA() << " [kW]" << "\n"; - debug.nospace().noquote() << " - Power phase L2:" << pro380ModbusRtuConnection->powerPhaseB() << " [kW]" << "\n"; - debug.nospace().noquote() << " - Power phase L3:" << pro380ModbusRtuConnection->powerPhaseC() << " [kW]" << "\n"; - debug.nospace().noquote() << " - Energy consumed phase A:" << pro380ModbusRtuConnection->energyConsumedPhaseA() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy consumed phase B:" << pro380ModbusRtuConnection->energyConsumedPhaseB() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy consumed phase C:" << pro380ModbusRtuConnection->energyConsumedPhaseC() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy produced phase A:" << pro380ModbusRtuConnection->energyProducedPhaseA() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy produced phase B:" << pro380ModbusRtuConnection->energyProducedPhaseB() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Energy produced phase C:" << pro380ModbusRtuConnection->energyProducedPhaseC() << " [kWh]" << "\n"; - return debug.quote().space(); -} - diff --git a/inepro/pro380modbusrtuconnection.h b/inepro/pro380modbusrtuconnection.h deleted file mode 100644 index 3f26c0b..0000000 --- a/inepro/pro380modbusrtuconnection.h +++ /dev/null @@ -1,204 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef PRO380MODBUSRTUCONNECTION_H -#define PRO380MODBUSRTUCONNECTION_H - -#include - -#include "../modbus/modbusdatautils.h" -#include - -class Pro380ModbusRtuConnection : public QObject -{ - Q_OBJECT -public: - explicit Pro380ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr); - ~Pro380ModbusRtuConnection() = default; - - ModbusRtuMaster *modbusRtuMaster() const; - quint16 slaveId() const; - - /* Frequency [Hz] - Address: 20488, Size: 2 */ - float frequency() const; - - /* Total energy consumed (Forward active energy) [kWh] - Address: 24588, Size: 2 */ - float totalEnergyConsumed() const; - - /* Total energy produced (Reverse active energy) [kWh] - Address: 24600, Size: 2 */ - float totalEnergyProduced() const; - - /* Voltage phase L1 [V] - Address: 20482, Size: 2 */ - float voltagePhaseA() const; - - /* Voltage phase L2 [V] - Address: 20484, Size: 2 */ - float voltagePhaseB() const; - - /* Voltage phase L3 [V] - Address: 20486, Size: 2 */ - float voltagePhaseC() const; - - /* Read block from start addess 20482 with size of 6 registers containing following 3 properties: - - Voltage phase L1 [V] - Address: 20482, Size: 2 - - Voltage phase L2 [V] - Address: 20484, Size: 2 - - Voltage phase L3 [V] - Address: 20486, Size: 2 - */ - void updatePhasesVoltageBlock(); - /* Current phase L1 [A] - Address: 20492, Size: 2 */ - float currentPhaseA() const; - - /* Current phase L2 [A] - Address: 20494, Size: 2 */ - float currentPhaseB() const; - - /* Current phase L3 [A] - Address: 20496, Size: 2 */ - float currentPhaseC() const; - - /* Read block from start addess 20492 with size of 6 registers containing following 3 properties: - - Current phase L1 [A] - Address: 20492, Size: 2 - - Current phase L2 [A] - Address: 20494, Size: 2 - - Current phase L3 [A] - Address: 20496, Size: 2 - */ - void updatePhasesCurrentBlock(); - /* Total system power [kW] - Address: 20498, Size: 2 */ - float totalCurrentPower() const; - - /* Power phase L1 [kW] - Address: 20500, Size: 2 */ - float powerPhaseA() const; - - /* Power phase L2 [kW] - Address: 20502, Size: 2 */ - float powerPhaseB() const; - - /* Power phase L3 [kW] - Address: 20504, Size: 2 */ - float powerPhaseC() const; - - /* Read block from start addess 20498 with size of 8 registers containing following 4 properties: - - Total system power [kW] - Address: 20498, Size: 2 - - Power phase L1 [kW] - Address: 20500, Size: 2 - - Power phase L2 [kW] - Address: 20502, Size: 2 - - Power phase L3 [kW] - Address: 20504, Size: 2 - */ - void updateCurrentPowerBlock(); - /* Energy consumed phase A [kWh] - Address: 24594, Size: 2 */ - float energyConsumedPhaseA() const; - - /* Energy consumed phase B [kWh] - Address: 24596, Size: 2 */ - float energyConsumedPhaseB() const; - - /* Energy consumed phase C [kWh] - Address: 24598, Size: 2 */ - float energyConsumedPhaseC() const; - - /* Read block from start addess 24594 with size of 6 registers containing following 3 properties: - - Energy consumed phase A [kWh] - Address: 24594, Size: 2 - - Energy consumed phase B [kWh] - Address: 24596, Size: 2 - - Energy consumed phase C [kWh] - Address: 24598, Size: 2 - */ - void updatePhasesEnergyConsumedBlock(); - /* Energy produced phase A [kWh] - Address: 24606, Size: 2 */ - float energyProducedPhaseA() const; - - /* Energy produced phase B [kWh] - Address: 24608, Size: 2 */ - float energyProducedPhaseB() const; - - /* Energy produced phase C [kWh] - Address: 24610, Size: 2 */ - float energyProducedPhaseC() const; - - /* Read block from start addess 24606 with size of 6 registers containing following 3 properties: - - Energy produced phase A [kWh] - Address: 24606, Size: 2 - - Energy produced phase B [kWh] - Address: 24608, Size: 2 - - Energy produced phase C [kWh] - Address: 24610, Size: 2 - */ - void updatePhasesEnergyProducedBlock(); - - void updateFrequency(); - void updateTotalEnergyConsumed(); - void updateTotalEnergyProduced(); - - virtual void initialize(); - virtual void update(); - -signals: - void initializationFinished(); - - void frequencyChanged(float frequency); - void totalEnergyConsumedChanged(float totalEnergyConsumed); - void totalEnergyProducedChanged(float totalEnergyProduced); - void voltagePhaseAChanged(float voltagePhaseA); - void voltagePhaseBChanged(float voltagePhaseB); - void voltagePhaseCChanged(float voltagePhaseC); - void currentPhaseAChanged(float currentPhaseA); - void currentPhaseBChanged(float currentPhaseB); - void currentPhaseCChanged(float currentPhaseC); - void totalCurrentPowerChanged(float totalCurrentPower); - void powerPhaseAChanged(float powerPhaseA); - void powerPhaseBChanged(float powerPhaseB); - void powerPhaseCChanged(float powerPhaseC); - void energyConsumedPhaseAChanged(float energyConsumedPhaseA); - void energyConsumedPhaseBChanged(float energyConsumedPhaseB); - void energyConsumedPhaseCChanged(float energyConsumedPhaseC); - void energyProducedPhaseAChanged(float energyProducedPhaseA); - void energyProducedPhaseBChanged(float energyProducedPhaseB); - void energyProducedPhaseCChanged(float energyProducedPhaseC); - -private: - ModbusRtuMaster *m_modbusRtuMaster = nullptr; - quint16 m_slaveId = 1; - QVector m_pendingInitReplies; - - float m_frequency = 0; - float m_totalEnergyConsumed = 0; - float m_totalEnergyProduced = 0; - float m_voltagePhaseA = 0; - float m_voltagePhaseB = 0; - float m_voltagePhaseC = 0; - float m_currentPhaseA = 0; - float m_currentPhaseB = 0; - float m_currentPhaseC = 0; - float m_totalCurrentPower = 0; - float m_powerPhaseA = 0; - float m_powerPhaseB = 0; - float m_powerPhaseC = 0; - float m_energyConsumedPhaseA = 0; - float m_energyConsumedPhaseB = 0; - float m_energyConsumedPhaseC = 0; - float m_energyProducedPhaseA = 0; - float m_energyProducedPhaseB = 0; - float m_energyProducedPhaseC = 0; - - void verifyInitFinished(); - - ModbusRtuReply *readFrequency(); - ModbusRtuReply *readTotalEnergyConsumed(); - ModbusRtuReply *readTotalEnergyProduced(); - - -}; - -QDebug operator<<(QDebug debug, Pro380ModbusRtuConnection *pro380ModbusRtuConnection); - -#endif // PRO380MODBUSRTUCONNECTION_H From 43d1c1c41357c29f475b8f5b535fc4e34867ccce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 11:51:06 +0200 Subject: [PATCH 15/42] Update modbuscommander plugin to libnyma-modbus --- modbuscommander/integrationpluginmodbuscommander.cpp | 10 ++++------ modbuscommander/integrationpluginmodbuscommander.h | 12 ++++++------ modbuscommander/modbuscommander.pro | 12 +++--------- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/modbuscommander/integrationpluginmodbuscommander.cpp b/modbuscommander/integrationpluginmodbuscommander.cpp index 5889534..ec597f6 100644 --- a/modbuscommander/integrationpluginmodbuscommander.cpp +++ b/modbuscommander/integrationpluginmodbuscommander.cpp @@ -31,12 +31,10 @@ #include "integrationpluginmodbuscommander.h" #include "plugininfo.h" -#include "hardwaremanager.h" -#include "network/networkdevicediscovery.h" -#include "hardware/modbus/modbusrtumaster.h" -#include "hardware/modbus/modbusrtuhardwareresource.h" - -#include +#include +#include +#include +#include IntegrationPluginModbusCommander::IntegrationPluginModbusCommander() { diff --git a/modbuscommander/integrationpluginmodbuscommander.h b/modbuscommander/integrationpluginmodbuscommander.h index 54f6906..5736bdf 100644 --- a/modbuscommander/integrationpluginmodbuscommander.h +++ b/modbuscommander/integrationpluginmodbuscommander.h @@ -31,14 +31,15 @@ #ifndef INTEGRATIONPLUGINMODBUSCOMMANDER_H #define INTEGRATIONPLUGINMODBUSCOMMANDER_H -#include "plugintimer.h" -#include "integrations/integrationplugin.h" -#include "hardware/modbus/modbusrtumaster.h" +#include +#include +#include -#include "../modbus/modbustcpmaster.h" +#include -#include #include +#include +#include class IntegrationPluginModbusCommander: public IntegrationPlugin { @@ -60,7 +61,6 @@ public: private: PluginTimer *m_refreshTimer = nullptr; - //QHash m_modbusRTUMasters; QHash m_modbusTCPMasters; QHash m_modbusRtuMasters; QHash m_asyncActions; diff --git a/modbuscommander/modbuscommander.pro b/modbuscommander/modbuscommander.pro index ab4dfc1..5b2bc31 100644 --- a/modbuscommander/modbuscommander.pro +++ b/modbuscommander/modbuscommander.pro @@ -1,15 +1,9 @@ include(../plugins.pri) - -QT += \ - serialport \ - network \ - serialbus \ +include(../modbus.pri) SOURCES += \ - integrationpluginmodbuscommander.cpp \ - ../modbus/modbustcpmaster.cpp + integrationpluginmodbuscommander.cpp HEADERS += \ - integrationpluginmodbuscommander.h \ - ../modbus/modbustcpmaster.h + integrationpluginmodbuscommander.h From 2c56f37041803e7e597cba8d9644e57f5f2f0b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 11:53:49 +0200 Subject: [PATCH 16/42] Update mtec plugin to libnyma-modbus --- mtec/integrationpluginmtec.cpp | 3 ++- mtec/integrationpluginmtec.h | 4 ++-- mtec/mtec.h | 2 +- mtec/mtec.pro | 11 +++-------- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/mtec/integrationpluginmtec.cpp b/mtec/integrationpluginmtec.cpp index 858acd8..f0452ad 100644 --- a/mtec/integrationpluginmtec.cpp +++ b/mtec/integrationpluginmtec.cpp @@ -28,7 +28,8 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "network/networkdevicediscovery.h" +#include + #include "integrationpluginmtec.h" #include "plugininfo.h" diff --git a/mtec/integrationpluginmtec.h b/mtec/integrationpluginmtec.h index c1302a4..7a476ad 100644 --- a/mtec/integrationpluginmtec.h +++ b/mtec/integrationpluginmtec.h @@ -30,8 +30,8 @@ #ifndef INTEGRATIONPLUGINMTEC_H #define INTEGRATIONPLUGINMTEC_H -#include "integrations/integrationplugin.h" -#include "plugintimer.h" +#include +#include #include "mtec.h" diff --git a/mtec/mtec.h b/mtec/mtec.h index 50f1740..197ec5f 100644 --- a/mtec/mtec.h +++ b/mtec/mtec.h @@ -34,7 +34,7 @@ #include #include -#include "../modbus/modbustcpmaster.h" +#include class MTec : public QObject { diff --git a/mtec/mtec.pro b/mtec/mtec.pro index c68ed3b..30e501b 100644 --- a/mtec/mtec.pro +++ b/mtec/mtec.pro @@ -1,16 +1,11 @@ include(../plugins.pri) - -QT += \ - network \ - serialbus \ +include(../modbus.pri) SOURCES += \ mtec.cpp \ - integrationpluginmtec.cpp \ - ../modbus/modbustcpmaster.cpp + integrationpluginmtec.cpp HEADERS += \ mtec.h \ - integrationpluginmtec.h \ - ../modbus/modbustcpmaster.h \ + integrationpluginmtec.h From ccdfe3e0cdb000b50aee133b767ba7bab7c42582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 11:55:30 +0200 Subject: [PATCH 17/42] Update mypv plugin to libnyma-modbus --- mypv/integrationpluginmypv.h | 6 +++--- mypv/mypv.pro | 11 +++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/mypv/integrationpluginmypv.h b/mypv/integrationpluginmypv.h index 108feca..d5959cd 100644 --- a/mypv/integrationpluginmypv.h +++ b/mypv/integrationpluginmypv.h @@ -31,10 +31,10 @@ #ifndef INTEGRATIONPLUGINMYPV_H #define INTEGRATIONPLUGINMYPV_H -#include "integrations/integrationplugin.h" -#include "plugintimer.h" +#include +#include -#include "../modbus/modbustcpmaster.h" +#include #include #include diff --git a/mypv/mypv.pro b/mypv/mypv.pro index 808801a..29c146b 100644 --- a/mypv/mypv.pro +++ b/mypv/mypv.pro @@ -1,13 +1,8 @@ include(../plugins.pri) - -QT += \ - network \ - serialbus \ +include(../modbus.pri) SOURCES += \ - integrationpluginmypv.cpp \ - ../modbus/modbustcpmaster.cpp \ + integrationpluginmypv.cpp HEADERS += \ - integrationpluginmypv.h \ - ../modbus/modbustcpmaster.h \ + integrationpluginmypv.h From 86e19c8106b34fe357661182c89ee5a9cd3d5060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 11:58:58 +0200 Subject: [PATCH 18/42] Update wallbe plugin to libnyma-modbus --- wallbe/integrationpluginwallbe.cpp | 5 +++-- wallbe/integrationpluginwallbe.h | 6 +++--- wallbe/wallbe.pro | 11 +++-------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/wallbe/integrationpluginwallbe.cpp b/wallbe/integrationpluginwallbe.cpp index b95c67c..907aecd 100644 --- a/wallbe/integrationpluginwallbe.cpp +++ b/wallbe/integrationpluginwallbe.cpp @@ -30,8 +30,9 @@ #include "integrationpluginwallbe.h" #include "plugininfo.h" -#include "network/networkdevicediscovery.h" -#include "types/param.h" + +#include +#include #include #include diff --git a/wallbe/integrationpluginwallbe.h b/wallbe/integrationpluginwallbe.h index 4d3f545..2b24819 100644 --- a/wallbe/integrationpluginwallbe.h +++ b/wallbe/integrationpluginwallbe.h @@ -31,10 +31,10 @@ #ifndef INTEGRATIONPLUGINWALLBE_H #define INTEGRATIONPLUGINWALLBE_H -#include "integrations/integrationplugin.h" -#include "plugintimer.h" +#include +#include -#include "../modbus/modbustcpmaster.h" +#include #include #include diff --git a/wallbe/wallbe.pro b/wallbe/wallbe.pro index c0cd408..b204735 100644 --- a/wallbe/wallbe.pro +++ b/wallbe/wallbe.pro @@ -1,13 +1,8 @@ include(../plugins.pri) - -QT += \ - network \ - serialbus \ +include(../modbus.pri) SOURCES += \ - integrationpluginwallbe.cpp \ - ../modbus/modbustcpmaster.cpp + integrationpluginwallbe.cpp HEADERS += \ - integrationpluginwallbe.h \ - ../modbus/modbustcpmaster.h + integrationpluginwallbe.h From 82c6da394b483f7c3e3824b38592dd3504c22486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 12:01:53 +0200 Subject: [PATCH 19/42] Update webasto plugin to libnyma-modbus --- webasto/integrationpluginwebasto.cpp | 6 +++--- webasto/integrationpluginwebasto.h | 5 ++--- webasto/webasto.h | 2 +- webasto/webasto.pro | 9 +++------ 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/webasto/integrationpluginwebasto.cpp b/webasto/integrationpluginwebasto.cpp index dcf25be..7afc211 100644 --- a/webasto/integrationpluginwebasto.cpp +++ b/webasto/integrationpluginwebasto.cpp @@ -28,12 +28,12 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "network/networkdevicediscovery.h" +#include +#include + #include "integrationpluginwebasto.h" #include "plugininfo.h" -#include "types/param.h" - #include #include #include diff --git a/webasto/integrationpluginwebasto.h b/webasto/integrationpluginwebasto.h index 7822101..6d833aa 100644 --- a/webasto/integrationpluginwebasto.h +++ b/webasto/integrationpluginwebasto.h @@ -31,10 +31,9 @@ #ifndef INTEGRATIONPLUGINWEBASTO_H #define INTEGRATIONPLUGINWEBASTO_H -#include "integrations/integrationplugin.h" -#include "plugintimer.h" +#include +#include #include "webasto.h" -#include "../modbus/modbustcpmaster.h" #include #include diff --git a/webasto/webasto.h b/webasto/webasto.h index 49a093f..0beb557 100644 --- a/webasto/webasto.h +++ b/webasto/webasto.h @@ -36,7 +36,7 @@ #include #include -#include "../modbus/modbustcpmaster.h" +#include class Webasto : public QObject { diff --git a/webasto/webasto.pro b/webasto/webasto.pro index c39fc78..45b6235 100644 --- a/webasto/webasto.pro +++ b/webasto/webasto.pro @@ -1,13 +1,10 @@ include(../plugins.pri) - -QT += serialbus network +include(../modbus.pri) SOURCES += \ integrationpluginwebasto.cpp \ - webasto.cpp \ - ../modbus/modbustcpmaster.cpp + webasto.cpp HEADERS += \ integrationpluginwebasto.h \ - webasto.h \ - ../modbus/modbustcpmaster.h + webasto.h From 8b8992679276dd5fb7483c5a7f2b3c27b20a439b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 6 May 2022 12:31:40 +0200 Subject: [PATCH 20/42] Update includes --- alphainnotec/integrationpluginalphainnotec.cpp | 6 +++--- alphainnotec/integrationpluginalphainnotec.h | 5 +++-- drexelundweiss/integrationplugindrexelundweiss.cpp | 6 +++--- drexelundweiss/integrationplugindrexelundweiss.h | 7 ++++--- huawei/integrationpluginhuawei.cpp | 6 +++--- huawei/integrationpluginhuawei.h | 5 +++-- idm/idm.h | 2 +- idm/integrationpluginidm.cpp | 3 ++- idm/integrationpluginidm.h | 5 +++-- sunspec/integrationpluginsunspec.cpp | 5 +++-- sunspec/integrationpluginsunspec.h | 4 ++-- sunspec/sunspecthing.h | 3 ++- webasto/integrationpluginwebasto.cpp | 6 +++--- webasto/integrationpluginwebasto.h | 1 + 14 files changed, 36 insertions(+), 28 deletions(-) diff --git a/alphainnotec/integrationpluginalphainnotec.cpp b/alphainnotec/integrationpluginalphainnotec.cpp index d6f5fb6..96b6f96 100644 --- a/alphainnotec/integrationpluginalphainnotec.cpp +++ b/alphainnotec/integrationpluginalphainnotec.cpp @@ -29,11 +29,11 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "integrationpluginalphainnotec.h" - -#include "network/networkdevicediscovery.h" -#include "hardwaremanager.h" #include "plugininfo.h" +#include +#include + IntegrationPluginAlphaInnotec::IntegrationPluginAlphaInnotec() { diff --git a/alphainnotec/integrationpluginalphainnotec.h b/alphainnotec/integrationpluginalphainnotec.h index 284f591..8f94c4a 100644 --- a/alphainnotec/integrationpluginalphainnotec.h +++ b/alphainnotec/integrationpluginalphainnotec.h @@ -31,9 +31,10 @@ #ifndef INTEGRATIONPLUGINALPHAINNOTEC_H #define INTEGRATIONPLUGINALPHAINNOTEC_H -#include "plugintimer.h" +#include +#include + #include "alphainnotecmodbustcpconnection.h" -#include "integrations/integrationplugin.h" class IntegrationPluginAlphaInnotec: public IntegrationPlugin { diff --git a/drexelundweiss/integrationplugindrexelundweiss.cpp b/drexelundweiss/integrationplugindrexelundweiss.cpp index 493a8e0..c4eff29 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.cpp +++ b/drexelundweiss/integrationplugindrexelundweiss.cpp @@ -31,9 +31,9 @@ #include "integrationplugindrexelundweiss.h" #include "plugininfo.h" -#include "hardwaremanager.h" -#include "hardware/modbus/modbusrtumaster.h" -#include "hardware/modbus/modbusrtuhardwareresource.h" +#include +#include +#include IntegrationPluginDrexelUndWeiss::IntegrationPluginDrexelUndWeiss() { diff --git a/drexelundweiss/integrationplugindrexelundweiss.h b/drexelundweiss/integrationplugindrexelundweiss.h index 12235eb..a93d0ed 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.h +++ b/drexelundweiss/integrationplugindrexelundweiss.h @@ -31,9 +31,10 @@ #ifndef INTEGRATIONPLUGINDREXELUNDWEISS_H #define INTEGRATIONPLUGINDREXELUNDWEISS_H -#include "integrations/integrationplugin.h" -#include "hardware/modbus/modbusrtumaster.h" -#include "plugintimer.h" +#include +#include +#include + #include "modbusregisterdefinition.h" #include diff --git a/huawei/integrationpluginhuawei.cpp b/huawei/integrationpluginhuawei.cpp index fcdfee7..1c83ee2 100644 --- a/huawei/integrationpluginhuawei.cpp +++ b/huawei/integrationpluginhuawei.cpp @@ -29,11 +29,11 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "integrationpluginhuawei.h" - -#include "network/networkdevicediscovery.h" -#include "hardwaremanager.h" #include "plugininfo.h" +#include +#include + IntegrationPluginHuawei::IntegrationPluginHuawei() { diff --git a/huawei/integrationpluginhuawei.h b/huawei/integrationpluginhuawei.h index 5c05e09..8e5afe6 100644 --- a/huawei/integrationpluginhuawei.h +++ b/huawei/integrationpluginhuawei.h @@ -31,8 +31,9 @@ #ifndef INTEGRATIONPLUGINHUAWEI_H #define INTEGRATIONPLUGINHUAWEI_H -#include "plugintimer.h" -#include "integrations/integrationplugin.h" +#include +#include + #include "huaweifusionsolar.h" class IntegrationPluginHuawei: public IntegrationPlugin diff --git a/idm/idm.h b/idm/idm.h index 53f1d02..7c78d21 100644 --- a/idm/idm.h +++ b/idm/idm.h @@ -33,7 +33,7 @@ #include -#include "../modbus/modbustcpmaster.h" +#include #include "idminfo.h" diff --git a/idm/integrationpluginidm.cpp b/idm/integrationpluginidm.cpp index 7f92ed1..1f0790e 100644 --- a/idm/integrationpluginidm.cpp +++ b/idm/integrationpluginidm.cpp @@ -28,10 +28,11 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "network/networkdevicediscovery.h" #include "integrationpluginidm.h" #include "plugininfo.h" +#include + IntegrationPluginIdm::IntegrationPluginIdm() { diff --git a/idm/integrationpluginidm.h b/idm/integrationpluginidm.h index 058988e..860196c 100644 --- a/idm/integrationpluginidm.h +++ b/idm/integrationpluginidm.h @@ -31,8 +31,9 @@ #ifndef INTEGRATIONPLUGINIDM_H #define INTEGRATIONPLUGINIDM_H -#include "integrations/integrationplugin.h" -#include "plugintimer.h" +#include +#include + #include "idm.h" #include diff --git a/sunspec/integrationpluginsunspec.cpp b/sunspec/integrationpluginsunspec.cpp index 16b14b5..c4ad08d 100644 --- a/sunspec/integrationpluginsunspec.cpp +++ b/sunspec/integrationpluginsunspec.cpp @@ -28,9 +28,10 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "plugininfo.h" #include "integrationpluginsunspec.h" -#include "network/networkdevicediscovery.h" +#include "plugininfo.h" + +#include #include #include diff --git a/sunspec/integrationpluginsunspec.h b/sunspec/integrationpluginsunspec.h index f057d19..d4a5a40 100644 --- a/sunspec/integrationpluginsunspec.h +++ b/sunspec/integrationpluginsunspec.h @@ -31,8 +31,8 @@ #ifndef INTEGRATIONPLUGINSUNSPEC_H #define INTEGRATIONPLUGINSUNSPEC_H -#include "integrations/integrationplugin.h" -#include "plugintimer.h" +#include +#include #include #include diff --git a/sunspec/sunspecthing.h b/sunspec/sunspecthing.h index 211d522..ea22466 100644 --- a/sunspec/sunspecthing.h +++ b/sunspec/sunspecthing.h @@ -34,7 +34,8 @@ #include #include "extern-plugininfo.h" -#include "integrations/integrationplugin.h" + +#include #include #include diff --git a/webasto/integrationpluginwebasto.cpp b/webasto/integrationpluginwebasto.cpp index 7afc211..008c8e2 100644 --- a/webasto/integrationpluginwebasto.cpp +++ b/webasto/integrationpluginwebasto.cpp @@ -28,12 +28,12 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include -#include - #include "integrationpluginwebasto.h" #include "plugininfo.h" +#include +#include + #include #include #include diff --git a/webasto/integrationpluginwebasto.h b/webasto/integrationpluginwebasto.h index 6d833aa..eaed575 100644 --- a/webasto/integrationpluginwebasto.h +++ b/webasto/integrationpluginwebasto.h @@ -33,6 +33,7 @@ #include #include + #include "webasto.h" #include From a4e8038343bf18fe7b23115d60386edecb79b86e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 13 May 2022 08:15:30 +0200 Subject: [PATCH 21/42] Update schrack plugin to libnyma-modbus --- schrack/cion-registers.json | 1 + schrack/cionmodbusrtuconnection.cpp | 723 ---------------------------- schrack/cionmodbusrtuconnection.h | 231 --------- schrack/schrack.pro | 19 +- 4 files changed, 7 insertions(+), 967 deletions(-) delete mode 100644 schrack/cionmodbusrtuconnection.cpp delete mode 100644 schrack/cionmodbusrtuconnection.h diff --git a/schrack/cion-registers.json b/schrack/cion-registers.json index 779762d..a796b9b 100644 --- a/schrack/cion-registers.json +++ b/schrack/cion-registers.json @@ -1,4 +1,5 @@ { + "className": "Cion", "protocol": "RTU", "endianness": "LittleEndian", "blocks": [ diff --git a/schrack/cionmodbusrtuconnection.cpp b/schrack/cionmodbusrtuconnection.cpp deleted file mode 100644 index 7bb4349..0000000 --- a/schrack/cionmodbusrtuconnection.cpp +++ /dev/null @@ -1,723 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2022, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* WARNING -* -* This file has been autogenerated. Any changes in this file may be overwritten. -* If you want to change something, update the register json or the tool. -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "cionmodbusrtuconnection.h" -#include "loggingcategories.h" -#include "math.h" - -NYMEA_LOGGING_CATEGORY(dcCionModbusRtuConnection, "CionModbusRtuConnection") - -CionModbusRtuConnection::CionModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent) : - QObject(parent), - m_modbusRtuMaster(modbusRtuMaster), - m_slaveId(slaveId) -{ - -} - -ModbusRtuMaster *CionModbusRtuConnection::modbusRtuMaster() const -{ - return m_modbusRtuMaster; -} -quint16 CionModbusRtuConnection::slaveId() const -{ - return m_slaveId; -} -ModbusDataUtils::ByteOrder CionModbusRtuConnection::endianness() const -{ - return m_endianness; -} -void CionModbusRtuConnection::setEndianness(ModbusDataUtils::ByteOrder endianness) -{ - if (m_endianness == endianness) - return; - - m_endianness = endianness; - emit endiannessChanged(m_endianness); -} -quint16 CionModbusRtuConnection::chargingEnabled() const -{ - return m_chargingEnabled; -} - -ModbusRtuReply *CionModbusRtuConnection::setChargingEnabled(quint16 chargingEnabled) -{ - QVector values = ModbusDataUtils::convertFromUInt16(chargingEnabled); - qCDebug(dcCionModbusRtuConnection()) << "--> Write \"Charging enabled\" register:" << 100 << "size:" << 1 << values; - return m_modbusRtuMaster->writeHoldingRegisters(m_slaveId, 100, values); -} - -quint16 CionModbusRtuConnection::chargingCurrentSetpoint() const -{ - return m_chargingCurrentSetpoint; -} - -ModbusRtuReply *CionModbusRtuConnection::setChargingCurrentSetpoint(quint16 chargingCurrentSetpoint) -{ - QVector values = ModbusDataUtils::convertFromUInt16(chargingCurrentSetpoint); - qCDebug(dcCionModbusRtuConnection()) << "--> Write \"Charging current setpoint\" register:" << 101 << "size:" << 1 << values; - return m_modbusRtuMaster->writeHoldingRegisters(m_slaveId, 101, values); -} - -quint16 CionModbusRtuConnection::statusBits() const -{ - return m_statusBits; -} - -quint16 CionModbusRtuConnection::cpSignalState() const -{ - return m_cpSignalState; -} - -float CionModbusRtuConnection::u1Voltage() const -{ - return m_u1Voltage; -} - -float CionModbusRtuConnection::gridVoltage() const -{ - return m_gridVoltage; -} - -quint16 CionModbusRtuConnection::minChargingCurrent() const -{ - return m_minChargingCurrent; -} - -quint16 CionModbusRtuConnection::currentChargingCurrentE3() const -{ - return m_currentChargingCurrentE3; -} - -quint16 CionModbusRtuConnection::maxChargingCurrentE3() const -{ - return m_maxChargingCurrentE3; -} - -quint16 CionModbusRtuConnection::maxChargingCurrentCableE3() const -{ - return m_maxChargingCurrentCableE3; -} - -quint32 CionModbusRtuConnection::chargingDuration() const -{ - return m_chargingDuration; -} - -quint32 CionModbusRtuConnection::pluggedInDuration() const -{ - return m_pluggedInDuration; -} - -void CionModbusRtuConnection::initialize() -{ - // No init registers defined. Nothing to be done and we are finished. - emit initializationFinished(); -} - -void CionModbusRtuConnection::update() -{ - updateChargingEnabled(); - updateChargingCurrentSetpoint(); - updateStatusBits(); - updateCpSignalState(); - updateU1Voltage(); - updateGridVoltage(); - updateMinChargingCurrent(); - updateE3Block(); - updateDurationsBlock(); -} - -void CionModbusRtuConnection::updateChargingEnabled() -{ - // Update registers from Charging enabled - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Charging enabled\" register:" << 100 << "size:" << 1; - ModbusRtuReply *reply = readChargingEnabled(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Charging enabled\" register" << 100 << "size:" << 1 << values; - processChargingEnabledRegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Charging enabled\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Charging enabled\" registers"; - } -} - -void CionModbusRtuConnection::updateChargingCurrentSetpoint() -{ - // Update registers from Charging current setpoint - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Charging current setpoint\" register:" << 101 << "size:" << 1; - ModbusRtuReply *reply = readChargingCurrentSetpoint(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Charging current setpoint\" register" << 101 << "size:" << 1 << values; - processChargingCurrentSetpointRegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Charging current setpoint\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Charging current setpoint\" registers"; - } -} - -void CionModbusRtuConnection::updateStatusBits() -{ - // Update registers from Mode3-State A, B, C, D, U - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Mode3-State A, B, C, D, U\" register:" << 121 << "size:" << 1; - ModbusRtuReply *reply = readStatusBits(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Mode3-State A, B, C, D, U\" register" << 121 << "size:" << 1 << values; - processStatusBitsRegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Mode3-State A, B, C, D, U\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Mode3-State A, B, C, D, U\" registers"; - } -} - -void CionModbusRtuConnection::updateCpSignalState() -{ - // Update registers from Status bits - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Status bits\" register:" << 139 << "size:" << 1; - ModbusRtuReply *reply = readCpSignalState(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Status bits\" register" << 139 << "size:" << 1 << values; - processCpSignalStateRegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Status bits\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Status bits\" registers"; - } -} - -void CionModbusRtuConnection::updateU1Voltage() -{ - // Update registers from U1 voltage - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"U1 voltage\" register:" << 167 << "size:" << 1; - ModbusRtuReply *reply = readU1Voltage(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"U1 voltage\" register" << 167 << "size:" << 1 << values; - processU1VoltageRegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"U1 voltage\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"U1 voltage\" registers"; - } -} - -void CionModbusRtuConnection::updateGridVoltage() -{ - // Update registers from Voltage of the power supply grid - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Voltage of the power supply grid\" register:" << 302 << "size:" << 1; - ModbusRtuReply *reply = readGridVoltage(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Voltage of the power supply grid\" register" << 302 << "size:" << 1 << values; - processGridVoltageRegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Voltage of the power supply grid\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Voltage of the power supply grid\" registers"; - } -} - -void CionModbusRtuConnection::updateMinChargingCurrent() -{ - // Update registers from Minimum charging current - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Minimum charging current\" register:" << 507 << "size:" << 1; - ModbusRtuReply *reply = readMinChargingCurrent(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Minimum charging current\" register" << 507 << "size:" << 1 << values; - processMinChargingCurrentRegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Minimum charging current\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Minimum charging current\" registers"; - } -} - -void CionModbusRtuConnection::updateCurrentChargingCurrentE3() -{ - // Update registers from Current charging Ampere - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Current charging Ampere\" register:" << 126 << "size:" << 1; - ModbusRtuReply *reply = readCurrentChargingCurrentE3(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Current charging Ampere\" register" << 126 << "size:" << 1 << values; - processCurrentChargingCurrentE3RegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Current charging Ampere\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Current charging Ampere\" registers"; - } -} - -void CionModbusRtuConnection::updateMaxChargingCurrentE3() -{ - // Update registers from Maximum charging current - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Maximum charging current\" register:" << 127 << "size:" << 1; - ModbusRtuReply *reply = readMaxChargingCurrentE3(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Maximum charging current\" register" << 127 << "size:" << 1 << values; - processMaxChargingCurrentE3RegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Maximum charging current\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Maximum charging current\" registers"; - } -} - -void CionModbusRtuConnection::updateMaxChargingCurrentCableE3() -{ - // Update registers from Maximum charging current of connected cable - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Maximum charging current of connected cable\" register:" << 128 << "size:" << 1; - ModbusRtuReply *reply = readMaxChargingCurrentCableE3(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Maximum charging current of connected cable\" register" << 128 << "size:" << 1 << values; - processMaxChargingCurrentCableE3RegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Maximum charging current of connected cable\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Maximum charging current of connected cable\" registers"; - } -} - -void CionModbusRtuConnection::updateChargingDuration() -{ - // Update registers from Charging duration - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Charging duration\" register:" << 151 << "size:" << 2; - ModbusRtuReply *reply = readChargingDuration(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Charging duration\" register" << 151 << "size:" << 2 << values; - processChargingDurationRegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Charging duration\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Charging duration\" registers"; - } -} - -void CionModbusRtuConnection::updatePluggedInDuration() -{ - // Update registers from Plugged in duration - qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Plugged in duration\" register:" << 153 << "size:" << 2; - ModbusRtuReply *reply = readPluggedInDuration(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector values = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Plugged in duration\" register" << 153 << "size:" << 2 << values; - processPluggedInDurationRegisterValues(values); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Plugged in duration\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Plugged in duration\" registers"; - } -} - -void CionModbusRtuConnection::updateE3Block() -{ - // Update register block "e3" - qCDebug(dcCionModbusRtuConnection()) << "--> Read block \"e3\" registers from:" << 126 << "size:" << 3; - ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 126, 3); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from reading block \"e3\" register" << 126 << "size:" << 3 << blockValues; - processCurrentChargingCurrentE3RegisterValues(blockValues.mid(0, 1)); - processMaxChargingCurrentE3RegisterValues(blockValues.mid(1, 1)); - processMaxChargingCurrentCableE3RegisterValues(blockValues.mid(2, 1)); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"e3\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading block \"e3\" registers"; - } -} - -void CionModbusRtuConnection::updateDurationsBlock() -{ - // Update register block "durations" - qCDebug(dcCionModbusRtuConnection()) << "--> Read block \"durations\" registers from:" << 151 << "size:" << 4; - ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 151, 4); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ - if (reply->error() == ModbusRtuReply::NoError) { - QVector blockValues = reply->result(); - qCDebug(dcCionModbusRtuConnection()) << "<-- Response from reading block \"durations\" register" << 151 << "size:" << 4 << blockValues; - processChargingDurationRegisterValues(blockValues.mid(0, 2)); - processPluggedInDurationRegisterValues(blockValues.mid(2, 2)); - } - }); - - connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ - qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"durations\" registers" << error << reply->errorString(); - emit reply->finished(); - }); - } - } else { - qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading block \"durations\" registers"; - } -} - -ModbusRtuReply *CionModbusRtuConnection::readChargingEnabled() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 100, 1); -} - -ModbusRtuReply *CionModbusRtuConnection::readChargingCurrentSetpoint() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 101, 1); -} - -ModbusRtuReply *CionModbusRtuConnection::readStatusBits() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 121, 1); -} - -ModbusRtuReply *CionModbusRtuConnection::readCpSignalState() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 139, 1); -} - -ModbusRtuReply *CionModbusRtuConnection::readU1Voltage() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 167, 1); -} - -ModbusRtuReply *CionModbusRtuConnection::readGridVoltage() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 302, 1); -} - -ModbusRtuReply *CionModbusRtuConnection::readMinChargingCurrent() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 507, 1); -} - -ModbusRtuReply *CionModbusRtuConnection::readCurrentChargingCurrentE3() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 126, 1); -} - -ModbusRtuReply *CionModbusRtuConnection::readMaxChargingCurrentE3() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 127, 1); -} - -ModbusRtuReply *CionModbusRtuConnection::readMaxChargingCurrentCableE3() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 128, 1); -} - -ModbusRtuReply *CionModbusRtuConnection::readChargingDuration() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 151, 2); -} - -ModbusRtuReply *CionModbusRtuConnection::readPluggedInDuration() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 153, 2); -} - -ModbusRtuReply *CionModbusRtuConnection::readBlockE3() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 126, 3); -} - -ModbusRtuReply *CionModbusRtuConnection::readBlockDurations() -{ - return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 151, 4); -} - -void CionModbusRtuConnection::processChargingEnabledRegisterValues(const QVector values) -{ - quint16 receivedChargingEnabled = ModbusDataUtils::convertToUInt16(values); - if (m_chargingEnabled != receivedChargingEnabled) { - m_chargingEnabled = receivedChargingEnabled; - emit chargingEnabledChanged(m_chargingEnabled); - } -} - -void CionModbusRtuConnection::processChargingCurrentSetpointRegisterValues(const QVector values) -{ - quint16 receivedChargingCurrentSetpoint = ModbusDataUtils::convertToUInt16(values); - if (m_chargingCurrentSetpoint != receivedChargingCurrentSetpoint) { - m_chargingCurrentSetpoint = receivedChargingCurrentSetpoint; - emit chargingCurrentSetpointChanged(m_chargingCurrentSetpoint); - } -} - -void CionModbusRtuConnection::processStatusBitsRegisterValues(const QVector values) -{ - quint16 receivedStatusBits = ModbusDataUtils::convertToUInt16(values); - if (m_statusBits != receivedStatusBits) { - m_statusBits = receivedStatusBits; - emit statusBitsChanged(m_statusBits); - } -} - -void CionModbusRtuConnection::processCpSignalStateRegisterValues(const QVector values) -{ - quint16 receivedCpSignalState = ModbusDataUtils::convertToUInt16(values); - if (m_cpSignalState != receivedCpSignalState) { - m_cpSignalState = receivedCpSignalState; - emit cpSignalStateChanged(m_cpSignalState); - } -} - -void CionModbusRtuConnection::processU1VoltageRegisterValues(const QVector values) -{ - float receivedU1Voltage = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -2); - if (m_u1Voltage != receivedU1Voltage) { - m_u1Voltage = receivedU1Voltage; - emit u1VoltageChanged(m_u1Voltage); - } -} - -void CionModbusRtuConnection::processGridVoltageRegisterValues(const QVector values) -{ - float receivedGridVoltage = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -2); - if (m_gridVoltage != receivedGridVoltage) { - m_gridVoltage = receivedGridVoltage; - emit gridVoltageChanged(m_gridVoltage); - } -} - -void CionModbusRtuConnection::processMinChargingCurrentRegisterValues(const QVector values) -{ - quint16 receivedMinChargingCurrent = ModbusDataUtils::convertToUInt16(values); - if (m_minChargingCurrent != receivedMinChargingCurrent) { - m_minChargingCurrent = receivedMinChargingCurrent; - emit minChargingCurrentChanged(m_minChargingCurrent); - } -} - -void CionModbusRtuConnection::processCurrentChargingCurrentE3RegisterValues(const QVector values) -{ - quint16 receivedCurrentChargingCurrentE3 = ModbusDataUtils::convertToUInt16(values); - if (m_currentChargingCurrentE3 != receivedCurrentChargingCurrentE3) { - m_currentChargingCurrentE3 = receivedCurrentChargingCurrentE3; - emit currentChargingCurrentE3Changed(m_currentChargingCurrentE3); - } -} - -void CionModbusRtuConnection::processMaxChargingCurrentE3RegisterValues(const QVector values) -{ - quint16 receivedMaxChargingCurrentE3 = ModbusDataUtils::convertToUInt16(values); - if (m_maxChargingCurrentE3 != receivedMaxChargingCurrentE3) { - m_maxChargingCurrentE3 = receivedMaxChargingCurrentE3; - emit maxChargingCurrentE3Changed(m_maxChargingCurrentE3); - } -} - -void CionModbusRtuConnection::processMaxChargingCurrentCableE3RegisterValues(const QVector values) -{ - quint16 receivedMaxChargingCurrentCableE3 = ModbusDataUtils::convertToUInt16(values); - if (m_maxChargingCurrentCableE3 != receivedMaxChargingCurrentCableE3) { - m_maxChargingCurrentCableE3 = receivedMaxChargingCurrentCableE3; - emit maxChargingCurrentCableE3Changed(m_maxChargingCurrentCableE3); - } -} - -void CionModbusRtuConnection::processChargingDurationRegisterValues(const QVector values) -{ - quint32 receivedChargingDuration = ModbusDataUtils::convertToUInt32(values, m_endianness); - if (m_chargingDuration != receivedChargingDuration) { - m_chargingDuration = receivedChargingDuration; - emit chargingDurationChanged(m_chargingDuration); - } -} - -void CionModbusRtuConnection::processPluggedInDurationRegisterValues(const QVector values) -{ - quint32 receivedPluggedInDuration = ModbusDataUtils::convertToUInt32(values, m_endianness); - if (m_pluggedInDuration != receivedPluggedInDuration) { - m_pluggedInDuration = receivedPluggedInDuration; - emit pluggedInDurationChanged(m_pluggedInDuration); - } -} - -void CionModbusRtuConnection::verifyInitFinished() -{ - if (m_pendingInitReplies.isEmpty()) { - qCDebug(dcCionModbusRtuConnection()) << "Initialization finished of CionModbusRtuConnection"; - emit initializationFinished(); - } -} - -QDebug operator<<(QDebug debug, CionModbusRtuConnection *cionModbusRtuConnection) -{ - debug.nospace().noquote() << "CionModbusRtuConnection(" << cionModbusRtuConnection->modbusRtuMaster()->modbusUuid().toString() << ", " << cionModbusRtuConnection->modbusRtuMaster()->serialPort() << ", slave ID:" << cionModbusRtuConnection->slaveId() << ")" << "\n"; - debug.nospace().noquote() << " - Charging enabled:" << cionModbusRtuConnection->chargingEnabled() << "\n"; - debug.nospace().noquote() << " - Charging current setpoint:" << cionModbusRtuConnection->chargingCurrentSetpoint() << " [A]" << "\n"; - debug.nospace().noquote() << " - Mode3-State A, B, C, D, U:" << cionModbusRtuConnection->statusBits() << "\n"; - debug.nospace().noquote() << " - Status bits:" << cionModbusRtuConnection->cpSignalState() << "\n"; - debug.nospace().noquote() << " - U1 voltage:" << cionModbusRtuConnection->u1Voltage() << " [V]" << "\n"; - debug.nospace().noquote() << " - Voltage of the power supply grid:" << cionModbusRtuConnection->gridVoltage() << " [V]" << "\n"; - debug.nospace().noquote() << " - Minimum charging current:" << cionModbusRtuConnection->minChargingCurrent() << " [A]" << "\n"; - debug.nospace().noquote() << " - Current charging Ampere:" << cionModbusRtuConnection->currentChargingCurrentE3() << " [A]" << "\n"; - debug.nospace().noquote() << " - Maximum charging current:" << cionModbusRtuConnection->maxChargingCurrentE3() << " [A]" << "\n"; - debug.nospace().noquote() << " - Maximum charging current of connected cable:" << cionModbusRtuConnection->maxChargingCurrentCableE3() << " [A]" << "\n"; - debug.nospace().noquote() << " - Charging duration:" << cionModbusRtuConnection->chargingDuration() << " [ms]" << "\n"; - debug.nospace().noquote() << " - Plugged in duration:" << cionModbusRtuConnection->pluggedInDuration() << " [ms]" << "\n"; - return debug.quote().space(); -} - diff --git a/schrack/cionmodbusrtuconnection.h b/schrack/cionmodbusrtuconnection.h deleted file mode 100644 index a175aea..0000000 --- a/schrack/cionmodbusrtuconnection.h +++ /dev/null @@ -1,231 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2022, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* WARNING -* -* This file has been autogenerated. Any changes in this file may be overwritten. -* If you want to change something, update the register json or the tool. -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef CIONMODBUSRTUCONNECTION_H -#define CIONMODBUSRTUCONNECTION_H - -#include - -#include "../modbus/modbusdatautils.h" -#include - -class CionModbusRtuConnection : public QObject -{ - Q_OBJECT -public: - enum Registers { - RegisterChargingEnabled = 100, - RegisterChargingCurrentSetpoint = 101, - RegisterStatusBits = 121, - RegisterCurrentChargingCurrentE3 = 126, - RegisterMaxChargingCurrentE3 = 127, - RegisterMaxChargingCurrentCableE3 = 128, - RegisterCpSignalState = 139, - RegisterChargingDuration = 151, - RegisterPluggedInDuration = 153, - RegisterU1Voltage = 167, - RegisterGridVoltage = 302, - RegisterMinChargingCurrent = 507 - }; - Q_ENUM(Registers) - - explicit CionModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr); - ~CionModbusRtuConnection() = default; - - ModbusRtuMaster *modbusRtuMaster() const; - quint16 slaveId() const; - - ModbusDataUtils::ByteOrder endianness() const; - void setEndianness(ModbusDataUtils::ByteOrder endianness); - - /* Charging enabled - Address: 100, Size: 1 */ - quint16 chargingEnabled() const; - ModbusRtuReply *setChargingEnabled(quint16 chargingEnabled); - - /* Charging current setpoint [A] - Address: 101, Size: 1 */ - quint16 chargingCurrentSetpoint() const; - ModbusRtuReply *setChargingCurrentSetpoint(quint16 chargingCurrentSetpoint); - - /* Mode3-State A, B, C, D, U - Address: 121, Size: 1 */ - quint16 statusBits() const; - - /* Status bits - Address: 139, Size: 1 */ - quint16 cpSignalState() const; - - /* U1 voltage [V] - Address: 167, Size: 1 */ - float u1Voltage() const; - - /* Voltage of the power supply grid [V] - Address: 302, Size: 1 */ - float gridVoltage() const; - - /* Minimum charging current [A] - Address: 507, Size: 1 */ - quint16 minChargingCurrent() const; - - /* Current charging Ampere [A] - Address: 126, Size: 1 */ - quint16 currentChargingCurrentE3() const; - - /* Maximum charging current [A] - Address: 127, Size: 1 */ - quint16 maxChargingCurrentE3() const; - - /* Maximum charging current of connected cable [A] - Address: 128, Size: 1 */ - quint16 maxChargingCurrentCableE3() const; - - /* Charging duration [ms] - Address: 151, Size: 2 */ - quint32 chargingDuration() const; - - /* Plugged in duration [ms] - Address: 153, Size: 2 */ - quint32 pluggedInDuration() const; - - /* Read block from start addess 126 with size of 3 registers containing following 3 properties: - - Current charging Ampere [A] - Address: 126, Size: 1 - - Maximum charging current [A] - Address: 127, Size: 1 - - Maximum charging current of connected cable [A] - Address: 128, Size: 1 - */ - void updateE3Block(); - - /* Read block from start addess 151 with size of 4 registers containing following 2 properties: - - Charging duration [ms] - Address: 151, Size: 2 - - Plugged in duration [ms] - Address: 153, Size: 2 - */ - void updateDurationsBlock(); - - virtual void initialize(); - virtual void update(); - - void updateChargingEnabled(); - void updateChargingCurrentSetpoint(); - void updateStatusBits(); - void updateCpSignalState(); - void updateU1Voltage(); - void updateGridVoltage(); - void updateMinChargingCurrent(); - - void updateCurrentChargingCurrentE3(); - void updateMaxChargingCurrentE3(); - void updateMaxChargingCurrentCableE3(); - void updateChargingDuration(); - void updatePluggedInDuration(); - - ModbusRtuReply *readChargingEnabled(); - ModbusRtuReply *readChargingCurrentSetpoint(); - ModbusRtuReply *readStatusBits(); - ModbusRtuReply *readCpSignalState(); - ModbusRtuReply *readU1Voltage(); - ModbusRtuReply *readGridVoltage(); - ModbusRtuReply *readMinChargingCurrent(); - ModbusRtuReply *readCurrentChargingCurrentE3(); - ModbusRtuReply *readMaxChargingCurrentE3(); - ModbusRtuReply *readMaxChargingCurrentCableE3(); - ModbusRtuReply *readChargingDuration(); - ModbusRtuReply *readPluggedInDuration(); - - /* Read block from start addess 126 with size of 3 registers containing following 3 properties: - - Current charging Ampere [A] - Address: 126, Size: 1 - - Maximum charging current [A] - Address: 127, Size: 1 - - Maximum charging current of connected cable [A] - Address: 128, Size: 1 - */ - ModbusRtuReply *readBlockE3(); - - /* Read block from start addess 151 with size of 4 registers containing following 2 properties: - - Charging duration [ms] - Address: 151, Size: 2 - - Plugged in duration [ms] - Address: 153, Size: 2 - */ - ModbusRtuReply *readBlockDurations(); - -signals: - void initializationFinished(); - void endiannessChanged(ModbusDataUtils::ByteOrder endianness); - - void chargingEnabledChanged(quint16 chargingEnabled); - void chargingCurrentSetpointChanged(quint16 chargingCurrentSetpoint); - void statusBitsChanged(quint16 statusBits); - void cpSignalStateChanged(quint16 cpSignalState); - void u1VoltageChanged(float u1Voltage); - void gridVoltageChanged(float gridVoltage); - void minChargingCurrentChanged(quint16 minChargingCurrent); - void currentChargingCurrentE3Changed(quint16 currentChargingCurrentE3); - void maxChargingCurrentE3Changed(quint16 maxChargingCurrentE3); - void maxChargingCurrentCableE3Changed(quint16 maxChargingCurrentCableE3); - void chargingDurationChanged(quint32 chargingDuration); - void pluggedInDurationChanged(quint32 pluggedInDuration); - -protected: - quint16 m_chargingEnabled = 0; - quint16 m_chargingCurrentSetpoint = 6; - quint16 m_statusBits = 85; - quint16 m_cpSignalState = 0; - float m_u1Voltage = 32; - float m_gridVoltage = 0; - quint16 m_minChargingCurrent = 13; - quint16 m_currentChargingCurrentE3 = 6; - quint16 m_maxChargingCurrentE3 = 32; - quint16 m_maxChargingCurrentCableE3 = 32; - quint32 m_chargingDuration = 0; - quint32 m_pluggedInDuration = 0; - - void processChargingEnabledRegisterValues(const QVector values); - void processChargingCurrentSetpointRegisterValues(const QVector values); - void processStatusBitsRegisterValues(const QVector values); - void processCpSignalStateRegisterValues(const QVector values); - void processU1VoltageRegisterValues(const QVector values); - void processGridVoltageRegisterValues(const QVector values); - void processMinChargingCurrentRegisterValues(const QVector values); - - void processCurrentChargingCurrentE3RegisterValues(const QVector values); - void processMaxChargingCurrentE3RegisterValues(const QVector values); - void processMaxChargingCurrentCableE3RegisterValues(const QVector values); - - void processChargingDurationRegisterValues(const QVector values); - void processPluggedInDurationRegisterValues(const QVector values); - - -private: - ModbusRtuMaster *m_modbusRtuMaster = nullptr; - quint16 m_slaveId = 1; - QVector m_pendingInitReplies; - ModbusDataUtils::ByteOrder m_endianness = ModbusDataUtils::ByteOrderBigEndian; - - void verifyInitFinished(); - - -}; - -QDebug operator<<(QDebug debug, CionModbusRtuConnection *cionModbusRtuConnection); - -#endif // CIONMODBUSRTUCONNECTION_H diff --git a/schrack/schrack.pro b/schrack/schrack.pro index 88565a9..94fae58 100644 --- a/schrack/schrack.pro +++ b/schrack/schrack.pro @@ -1,20 +1,13 @@ include(../plugins.pri) -QT += serialport serialbus +# Generate modbus connection +MODBUS_CONNECTIONS += cion-registers.json +#MODBUS_TOOLS_CONFIG += VERBOSE +include(../modbus.pri) SOURCES += \ - integrationpluginschrack.cpp \ - cionmodbusrtuconnection.cpp \ - ../modbus/modbusdatautils.cpp + integrationpluginschrack.cpp HEADERS += \ - integrationpluginschrack.h \ - cionmodbusrtuconnection.h \ - ../modbus/modbusdatautils.h + integrationpluginschrack.h -OTHER_FILES += cion-registers.json - -modbusconnection.commands = python $${top_srcdir}/modbus/tools/generate-connection.py -j $${_PRO_FILE_PWD_}/cion-registers.json -o $${_PRO_FILE_PWD_} -c CionModbusRtuConnection -QMAKE_EXTRA_TARGETS += modbusconnection - -#target.depends += modbusconnection From e4a42817102e761c6d39b52faf761a853fcdd58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 3 Jun 2022 11:20:22 +0200 Subject: [PATCH 22/42] Get rid of ordered to build plugins and save a kitten --- nymea-plugins-modbus.pro | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/nymea-plugins-modbus.pro b/nymea-plugins-modbus.pro index 2e60263..c389e0a 100644 --- a/nymea-plugins-modbus.pro +++ b/nymea-plugins-modbus.pro @@ -1,7 +1,7 @@ TEMPLATE = subdirs -# Note keep it ordered so the lib will be built first -CONFIG += ordered +# Note: In the loop at the end of this file the plugin +# dependency on the libs will be defined SUBDIRS += libnymea-modbus libnymea-sunspec PLUGIN_DIRS = \ @@ -63,6 +63,12 @@ for(plugin, PLUGINS) { exists($${plugin}) { SUBDIRS*= $${plugin} message("- $${plugin}") + # Make sure the libs will be built before the plugins + equals(plugin, "sunspec") { + $${plugin}.depends += libnymea-sunspec + } else { + $${plugin}.depends += libnymea-modbus + } } else { error("Invalid plugin \"$${plugin}\".") } From eb56d176d365c5c44176a1268a5b610a0648e517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 2 Feb 2022 11:11:49 +0100 Subject: [PATCH 23/42] Add initial plugin structure for stiebel eltron --- nymea-plugins-modbus.pro | 1 + .../integrationpluginstiebeleltron.cpp | 154 ++++++++++++++++++ .../integrationpluginstiebeleltron.h | 65 ++++++++ .../integrationpluginstiebeleltron.json | 112 +++++++++++++ stiebeleltron/stiebel-eltron-registers.json | 19 +++ stiebeleltron/stiebeleltron.pro | 16 ++ .../stiebeleltronmodbusconnection.cpp | 113 +++++++++++++ stiebeleltron/stiebeleltronmodbusconnection.h | 79 +++++++++ 8 files changed, 559 insertions(+) create mode 100644 stiebeleltron/integrationpluginstiebeleltron.cpp create mode 100644 stiebeleltron/integrationpluginstiebeleltron.h create mode 100644 stiebeleltron/integrationpluginstiebeleltron.json create mode 100644 stiebeleltron/stiebel-eltron-registers.json create mode 100644 stiebeleltron/stiebeleltron.pro create mode 100644 stiebeleltron/stiebeleltronmodbusconnection.cpp create mode 100644 stiebeleltron/stiebeleltronmodbusconnection.h diff --git a/nymea-plugins-modbus.pro b/nymea-plugins-modbus.pro index c389e0a..636d847 100644 --- a/nymea-plugins-modbus.pro +++ b/nymea-plugins-modbus.pro @@ -15,6 +15,7 @@ PLUGIN_DIRS = \ mtec \ mypv \ schrack \ + stiebeleltron \ sunspec \ unipi \ wallbe \ diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp new file mode 100644 index 0000000..e772758 --- /dev/null +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -0,0 +1,154 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "integrationpluginstiebeleltron.h" + +#include "network/networkdevicediscovery.h" +#include "hardwaremanager.h" +#include "plugininfo.h" + +IntegrationPluginStiebelEltron::IntegrationPluginStiebelEltron() +{ + +} + +void IntegrationPluginStiebelEltron::discoverThings(ThingDiscoveryInfo *info) +{ + if (!hardwareManager()->networkDeviceDiscovery()->available()) { + qCWarning(dcStiebelEltron()) << "The network discovery is not available on this platform."; + info->finish(Thing::ThingErrorUnsupportedFeature, QT_TR_NOOP("The network device discovery is not available.")); + return; + } + + NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover(); + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ + foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) { + + qCDebug(dcStiebelEltron()) << "Found" << networkDeviceInfo; + + QString title; + if (networkDeviceInfo.hostName().isEmpty()) { + title = networkDeviceInfo.address().toString(); + } else { + title = networkDeviceInfo.hostName() + " (" + networkDeviceInfo.address().toString() + ")"; + } + + QString description; + if (networkDeviceInfo.macAddressManufacturer().isEmpty()) { + description = networkDeviceInfo.macAddress(); + } else { + description = networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")"; + } + + ThingDescriptor descriptor(stiebelEltronThingClassId, title, description); + ParamList params; + params << Param(stiebelEltronThingIpAddressParamTypeId, networkDeviceInfo.address().toString()); + params << Param(stiebelEltronThingMacAddressParamTypeId, networkDeviceInfo.macAddress()); + descriptor.setParams(params); + + // Check if we already have set up this device + Things existingThings = myThings().filterByParam(stiebelEltronThingMacAddressParamTypeId, networkDeviceInfo.macAddress()); + if (existingThings.count() == 1) { + qCDebug(dcStiebelEltron()) << "This connection already exists in the system:" << networkDeviceInfo; + descriptor.setThingId(existingThings.first()->id()); + } + + info->addThingDescriptor(descriptor); + } + + info->finish(Thing::ThingErrorNoError); + }); +} + +void IntegrationPluginStiebelEltron::startMonitoringAutoThings() +{ + +} + +void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) +{ + Thing *thing = info->thing(); + qCDebug(dcStiebelEltron()) << "Setup" << thing << thing->params(); + + if (thing->thingClassId() == stiebelEltronThingClassId) { + + QHostAddress address(thing->paramValue(stiebelEltronThingIpAddressParamTypeId).toString()); + quint16 port = thing->paramValue(stiebelEltronThingPortParamTypeId).toUInt(); + quint16 slaveId = thing->paramValue(stiebelEltronThingSlaveIdParamTypeId).toUInt(); + + StiebelEltronModbusConnection *connection = new StiebelEltronModbusConnection(address, port, slaveId, this); + + connection->connectDevice(); + + + m_connections.insert(thing, connection); + info->finish(Thing::ThingErrorNoError); + } + + +} + +void IntegrationPluginStiebelEltron::postSetupThing(Thing *thing) +{ + if (thing->thingClassId() == stiebelEltronThingClassId) { + if (!m_pluginTimer) { + qCDebug(dcStiebelEltron()) << "Starting plugin timer..."; + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); + connect(m_pluginTimer, &PluginTimer::timeout, this, [this] { + foreach (StiebelEltronModbusConnection *connection, m_connections) { + if (connection->connected()) { + connection->update(); + } + } + }); + + m_pluginTimer->start(); + } + } +} + +void IntegrationPluginStiebelEltron::thingRemoved(Thing *thing) +{ + if (thing->thingClassId() == stiebelEltronThingClassId && m_connections.contains(thing)) { + m_connections.take(thing)->deleteLater(); + } + + if (myThings().isEmpty() && m_pluginTimer) { + hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer); + m_pluginTimer = nullptr; + } +} + +void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) +{ + info->finish(Thing::ThingErrorNoError); +} + + diff --git a/stiebeleltron/integrationpluginstiebeleltron.h b/stiebeleltron/integrationpluginstiebeleltron.h new file mode 100644 index 0000000..0b81459 --- /dev/null +++ b/stiebeleltron/integrationpluginstiebeleltron.h @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef INTEGRATIONPLUGINSTIEBELELTRON_H +#define INTEGRATIONPLUGINSTIEBELELTRON_H + +#include "plugintimer.h" +#include "integrations/integrationplugin.h" +#include "stiebeleltronmodbusconnection.h" + +class IntegrationPluginStiebelEltron: public IntegrationPlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginstiebeleltron.json") + Q_INTERFACES(IntegrationPlugin) + +public: + explicit IntegrationPluginStiebelEltron(); + + void discoverThings(ThingDiscoveryInfo *info) override; + void startMonitoringAutoThings() override; + void setupThing(ThingSetupInfo *info) override; + void postSetupThing(Thing *thing) override; + void thingRemoved(Thing *thing) override; + void executeAction(ThingActionInfo *info) override; + +private: + PluginTimer *m_pluginTimer = nullptr; + + QHash m_connections; + + +}; + +#endif // INTEGRATIONPLUGINSTIEBELELTRON_H + + diff --git a/stiebeleltron/integrationpluginstiebeleltron.json b/stiebeleltron/integrationpluginstiebeleltron.json new file mode 100644 index 0000000..d7ae4e2 --- /dev/null +++ b/stiebeleltron/integrationpluginstiebeleltron.json @@ -0,0 +1,112 @@ +{ + "name": "StiebelEltron", + "displayName": "Stiebel Eltron", + "id": "956c848b-b538-4b8f-8cdb-7bbecfc9d361", + "vendors": [ + { + "name": "stiebelEltron", + "displayName": "Stiebel Eltron", + "id": "c8607f85-a81e-40e0-bc95-1b7199cd2d99", + "thingClasses": [ + { + "name": "stiebelEltron", + "displayName": "Stiebel Eltron Heatpump", + "id": "e02ecf61-7d28-43c2-b87e-e7e98a48fbfd", + "createMethods": ["discovery", "user"], + "interfaces": ["smartgridheatpump", "connectable"], + "paramTypes": [ + { + "id": "47d221fa-f6d2-400e-b80f-bb90abccb72c", + "name": "ipAddress", + "displayName": "IP address", + "type": "QString", + "inputType": "IPv4Address", + "defaultValue": "127.0.0.1" + }, + { + "id": "05cd59b8-3068-460f-b0d2-6d49f27458df", + "name":"macAddress", + "displayName": "MAC address", + "type": "QString", + "inputType": "MacAddress", + "defaultValue": "" + }, + { + "id": "6842321f-1f1a-47e2-b12d-59ee322eb8a6", + "name":"port", + "displayName": "Port", + "type": "int", + "defaultValue": 502 + }, + { + "id": "732de6da-bd0a-4215-b320-602117ebc75c", + "name":"slaveId", + "displayName": "Modbus slave ID", + "type": "int", + "defaultValue": 1 + } + ], + "stateTypes": [ + { + "id": "8d952a5e-87bd-492e-a213-277948521652", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "d6475acb-3a15-401b-8bad-8610eb056bf7", + "name": "flowTemperature", + "displayName": "Flow temperature", + "displayNameEvent": "Flow temperature changed", + "unit": "DegreeCelsius", + "type": "double", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "ce25e3fd-6544-40e9-bd39-032306553e32", + "name": "returnTemperature", + "displayName": "Return temperature", + "displayNameEvent": "Return temperature changed", + "unit": "DegreeCelsius", + "type": "double", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "7d474fb5-aa37-4f21-8166-b20f5bf84fb4", + "name": "sgReadyMode", + "displayName": "Smart grid mode", + "displayNameEvent": "Smart grid mode changed", + "displayNameAction": "Set smart grid mode", + "type": "QString", + "possibleValues": [ + "Off", + "Low", + "Standard", + "High" + ], + "writable": true, + "defaultValue": "Standard", + "suggestLogging": true + }, + { + "id": "f4abbd8d-14d6-4294-9b63-411a9721f946", + "name": "totalEnergy", + "displayName": "Total energy", + "displayNameEvent": "Total energy changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0, + "suggestLogging": true + } + ], + "actionTypes": [ ] + } + ] + } + ] +} diff --git a/stiebeleltron/stiebel-eltron-registers.json b/stiebeleltron/stiebel-eltron-registers.json new file mode 100644 index 0000000..cdcc2ed --- /dev/null +++ b/stiebeleltron/stiebel-eltron-registers.json @@ -0,0 +1,19 @@ +{ + "protocol": "TCP", + "endianness": "BigEndian", + "registers": [ + { + "id": "outdoorTemperature", + "address": 507, + "size": 1, + "type": "int16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Outdoor temperature", + "staticScaleFactor": -1, + "defaultValue": "0", + "unit": "°C", + "access": "RO" + } + ] +} \ No newline at end of file diff --git a/stiebeleltron/stiebeleltron.pro b/stiebeleltron/stiebeleltron.pro new file mode 100644 index 0000000..78483b0 --- /dev/null +++ b/stiebeleltron/stiebeleltron.pro @@ -0,0 +1,16 @@ +include(../plugins.pri) + +QT += network serialbus + +HEADERS += \ + integrationpluginstiebeleltron.h \ + stiebeleltronmodbusconnection.h \ + ../modbus/modbustcpmaster.h \ + ../modbus/modbusdatautils.h + +SOURCES += \ + integrationpluginstiebeleltron.cpp \ + stiebeleltronmodbusconnection.cpp \ + ../modbus/modbustcpmaster.cpp \ + ../modbus/modbusdatautils.cpp + diff --git a/stiebeleltron/stiebeleltronmodbusconnection.cpp b/stiebeleltron/stiebeleltronmodbusconnection.cpp new file mode 100644 index 0000000..15bd8e5 --- /dev/null +++ b/stiebeleltron/stiebeleltronmodbusconnection.cpp @@ -0,0 +1,113 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, nymea GmbH +* Contact: contact@nymea.io +* +* This fileDescriptor is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +#include "stiebeleltronmodbusconnection.h" +#include "loggingcategories.h" + +NYMEA_LOGGING_CATEGORY(dcStiebelEltronModbusConnection, "StiebelEltronModbusConnection") + +StiebelEltronModbusConnection::StiebelEltronModbusConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) : + ModbusTCPMaster(hostAddress, port, parent), + m_slaveId(slaveId) +{ + +} + +float StiebelEltronModbusConnection::outdoorTemperature() const +{ + return m_outdoorTemperature; +} + +void StiebelEltronModbusConnection::initialize() +{ + // No init registers defined. Nothing to be done and we are finished. + emit initializationFinished(); +} + +void StiebelEltronModbusConnection::update() +{ + updateOutdoorTemperature(); +} + +void StiebelEltronModbusConnection::updateOutdoorTemperature() +{ + // Update registers from Flow + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Flow\" register:" << 507 << "size:" << 1; + QModbusReply *reply = readOutdoorTemperature(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Flow\" register" << 507 << "size:" << 1 << values; + float receivedOutdoorTemperature = ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, -1); + if (m_outdoorTemperature != receivedOutdoorTemperature) { + m_outdoorTemperature = receivedOutdoorTemperature; + emit outdoorTemperatureChanged(m_outdoorTemperature); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Flow\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Flow\" registers from" << hostAddress().toString() << errorString(); + } +} + +QModbusReply *StiebelEltronModbusConnection::readOutdoorTemperature() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 507, 1); + return sendReadRequest(request, m_slaveId); +} + +void StiebelEltronModbusConnection::verifyInitFinished() +{ + if (m_pendingInitReplies.isEmpty()) { + qCDebug(dcStiebelEltronModbusConnection()) << "Initialization finished of StiebelEltronModbusConnection" << hostAddress().toString(); + emit initializationFinished(); + } +} + +QDebug operator<<(QDebug debug, StiebelEltronModbusConnection *stiebelEltronModbusConnection) +{ + debug.nospace().noquote() << "StiebelEltronModbusConnection(" << stiebelEltronModbusConnection->hostAddress().toString() << ":" << stiebelEltronModbusConnection->port() << ")" << "\n"; + debug.nospace().noquote() << " - Flow:" << stiebelEltronModbusConnection->outdoorTemperature() << " [°C]" << "\n"; + return debug.quote().space(); +} + diff --git a/stiebeleltron/stiebeleltronmodbusconnection.h b/stiebeleltron/stiebeleltronmodbusconnection.h new file mode 100644 index 0000000..942beb6 --- /dev/null +++ b/stiebeleltron/stiebeleltronmodbusconnection.h @@ -0,0 +1,79 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, nymea GmbH +* Contact: contact@nymea.io +* +* This fileDescriptor is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef STIEBELELTRONMODBUSCONNECTION_H +#define STIEBELELTRONMODBUSCONNECTION_H + +#include + +#include "../modbus/modbusdatautils.h" +#include "../modbus/modbustcpmaster.h" + +class StiebelEltronModbusConnection : public ModbusTCPMaster +{ + Q_OBJECT +public: + enum Registers { + RegisterOutdoorTemperature = 507 + }; + Q_ENUM(Registers) + + explicit StiebelEltronModbusConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr); + ~StiebelEltronModbusConnection() = default; + + /* Flow [°C] - Address: 507, Size: 1 */ + float outdoorTemperature() const; + + virtual void initialize(); + virtual void update(); + + void updateOutdoorTemperature(); + +signals: + void initializationFinished(); + + void outdoorTemperatureChanged(float outdoorTemperature); + +protected: + QModbusReply *readOutdoorTemperature(); + + float m_outdoorTemperature = 0; + +private: + quint16 m_slaveId = 1; + QVector m_pendingInitReplies; + + void verifyInitFinished(); + +}; + +QDebug operator<<(QDebug debug, StiebelEltronModbusConnection *stiebelEltronModbusConnection); + +#endif // STIEBELELTRONMODBUSCONNECTION_H From 92163a92dd857d20b21d348f8ff641d1202d4acc Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Thu, 3 Feb 2022 15:16:36 +0100 Subject: [PATCH 24/42] added debian package files --- debian/control | 10 ++++++++++ debian/nymea-plugin-stiebeleltron.install.in | 1 + debian/rules | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 debian/nymea-plugin-stiebeleltron.install.in diff --git a/debian/control b/debian/control index a9eea5a..4d26826 100644 --- a/debian/control +++ b/debian/control @@ -156,6 +156,16 @@ Description: nymea integration plugin for Schrack wallboxes This package contains the nymea integration plugin for Schrack wallboxes. +Package: nymea-plugin-stiebeleltron +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends}, + nymea-plugins-modbus-translations +Description: nymea.io plugin for Stiebel Eltron heat pumps + This package will install the nymea.io plugin for Stiebel Eltron heat pumps. + + Package: nymea-plugin-sunspec Architecture: any Depends: ${shlibs:Depends}, diff --git a/debian/nymea-plugin-stiebeleltron.install.in b/debian/nymea-plugin-stiebeleltron.install.in new file mode 100644 index 0000000..36bab22 --- /dev/null +++ b/debian/nymea-plugin-stiebeleltron.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginstiebeleltron.so diff --git a/debian/rules b/debian/rules index dcdbe2b..565f725 100755 --- a/debian/rules +++ b/debian/rules @@ -12,7 +12,7 @@ $(PREPROCESS_FILES:.in=): %: %.in override_dh_auto_build: dh_auto_build - make lrelease + #make lrelease override_dh_install: $(PREPROCESS_FILES:.in=) dh_install --fail-missing From eac316e6f8d33d6638623a9c64ea0cb372210ae9 Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Thu, 17 Feb 2022 14:16:53 +0100 Subject: [PATCH 25/42] Added registers and Thing states and connects --- .../integrationpluginstiebeleltron.cpp | 466 ++++++-- .../integrationpluginstiebeleltron.json | 269 ++++- stiebeleltron/stiebel-eltron-registers.json | 316 +++++- .../stiebeleltronmodbusconnection.cpp | 1007 ++++++++++++++++- stiebeleltron/stiebeleltronmodbusconnection.h | 194 +++- 5 files changed, 2126 insertions(+), 126 deletions(-) diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index e772758..46c1c13 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -1,128 +1,357 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * + * Copyright 2013 - 2021, nymea GmbH + * Contact: contact@nymea.io + * + * This file is part of nymea. + * This project including source code and documentation is protected by + * copyright law, and remains the property of nymea GmbH. All rights, including + * reproduction, publication, editing and translation, are reserved. The use of + * this project is subject to the terms of a license agreement to be concluded + * with nymea GmbH in accordance with the terms of use of nymea GmbH, available + * under https://nymea.io/license + * + * GNU Lesser General Public License Usage + * Alternatively, this project may be redistributed and/or modified under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; version 3. This project is distributed in the hope that + * it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this project. If not, see . + * + * For any further details and any questions please contact us under + * contact@nymea.io or see our FAQ/Licensing Information on + * https://nymea.io/license/faq + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "integrationpluginstiebeleltron.h" -#include "network/networkdevicediscovery.h" #include "hardwaremanager.h" +#include "network/networkdevicediscovery.h" #include "plugininfo.h" -IntegrationPluginStiebelEltron::IntegrationPluginStiebelEltron() -{ +IntegrationPluginStiebelEltron::IntegrationPluginStiebelEltron() {} -} - -void IntegrationPluginStiebelEltron::discoverThings(ThingDiscoveryInfo *info) -{ +void IntegrationPluginStiebelEltron::discoverThings(ThingDiscoveryInfo *info) { if (!hardwareManager()->networkDeviceDiscovery()->available()) { - qCWarning(dcStiebelEltron()) << "The network discovery is not available on this platform."; - info->finish(Thing::ThingErrorUnsupportedFeature, QT_TR_NOOP("The network device discovery is not available.")); + qCWarning(dcStiebelEltron()) + << "The network discovery is not available on this platform."; + info->finish( + Thing::ThingErrorUnsupportedFeature, + QT_TR_NOOP("The network device discovery is not available.")); return; } - NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover(); - connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ - foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) { + NetworkDeviceDiscoveryReply *discoveryReply = + hardwareManager()->networkDeviceDiscovery()->discover(); + connect( + discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=]() { + foreach (const NetworkDeviceInfo &networkDeviceInfo, + discoveryReply->networkDeviceInfos()) { + qCDebug(dcStiebelEltron()) << "Found" << networkDeviceInfo; - qCDebug(dcStiebelEltron()) << "Found" << networkDeviceInfo; + QString title; + if (networkDeviceInfo.hostName().isEmpty()) { + title = networkDeviceInfo.address().toString(); + } else { + title = networkDeviceInfo.hostName() + " (" + + networkDeviceInfo.address().toString() + ")"; + } - QString title; - if (networkDeviceInfo.hostName().isEmpty()) { - title = networkDeviceInfo.address().toString(); - } else { - title = networkDeviceInfo.hostName() + " (" + networkDeviceInfo.address().toString() + ")"; + QString description; + if (networkDeviceInfo.macAddressManufacturer().isEmpty()) { + description = networkDeviceInfo.macAddress(); + } else { + description = networkDeviceInfo.macAddress() + " (" + + networkDeviceInfo.macAddressManufacturer() + + ")"; + } + + ThingDescriptor descriptor(stiebelEltronThingClassId, title, + description); + ParamList params; + params << Param(stiebelEltronThingIpAddressParamTypeId, + networkDeviceInfo.address().toString()); + params << Param(stiebelEltronThingMacAddressParamTypeId, + networkDeviceInfo.macAddress()); + descriptor.setParams(params); + + // Check if we already have set up this device + Things existingThings = myThings().filterByParam( + stiebelEltronThingMacAddressParamTypeId, + networkDeviceInfo.macAddress()); + if (existingThings.count() == 1) { + qCDebug(dcStiebelEltron()) + << "This connection already exists in the system:" + << networkDeviceInfo; + descriptor.setThingId(existingThings.first()->id()); + } + + info->addThingDescriptor(descriptor); } - QString description; - if (networkDeviceInfo.macAddressManufacturer().isEmpty()) { - description = networkDeviceInfo.macAddress(); - } else { - description = networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")"; - } - - ThingDescriptor descriptor(stiebelEltronThingClassId, title, description); - ParamList params; - params << Param(stiebelEltronThingIpAddressParamTypeId, networkDeviceInfo.address().toString()); - params << Param(stiebelEltronThingMacAddressParamTypeId, networkDeviceInfo.macAddress()); - descriptor.setParams(params); - - // Check if we already have set up this device - Things existingThings = myThings().filterByParam(stiebelEltronThingMacAddressParamTypeId, networkDeviceInfo.macAddress()); - if (existingThings.count() == 1) { - qCDebug(dcStiebelEltron()) << "This connection already exists in the system:" << networkDeviceInfo; - descriptor.setThingId(existingThings.first()->id()); - } - - info->addThingDescriptor(descriptor); - } - - info->finish(Thing::ThingErrorNoError); - }); + info->finish(Thing::ThingErrorNoError); + }); } -void IntegrationPluginStiebelEltron::startMonitoringAutoThings() -{ +void IntegrationPluginStiebelEltron::startMonitoringAutoThings() {} -} - -void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) -{ +void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); qCDebug(dcStiebelEltron()) << "Setup" << thing << thing->params(); if (thing->thingClassId() == stiebelEltronThingClassId) { + QHostAddress address( + thing->paramValue(stiebelEltronThingIpAddressParamTypeId) + .toString()); + quint16 port = + thing->paramValue(stiebelEltronThingPortParamTypeId).toUInt(); + quint16 slaveId = + thing->paramValue(stiebelEltronThingSlaveIdParamTypeId).toUInt(); - QHostAddress address(thing->paramValue(stiebelEltronThingIpAddressParamTypeId).toString()); - quint16 port = thing->paramValue(stiebelEltronThingPortParamTypeId).toUInt(); - quint16 slaveId = thing->paramValue(stiebelEltronThingSlaveIdParamTypeId).toUInt(); + StiebelEltronModbusConnection *connection = + new StiebelEltronModbusConnection(address, port, slaveId, this); - StiebelEltronModbusConnection *connection = new StiebelEltronModbusConnection(address, port, slaveId, this); + connect( + connection, &StiebelEltronModbusConnection::connectionStateChanged, + this, [thing, connection](bool status) { + qCDebug(dcStiebelEltron()) + << "Connected changed to" << status << "for" << thing; + if (status) { + connection->update(); + } - connection->connectDevice(); + thing->setStateValue(stiebelEltronConnectedStateTypeId, status); + }); + connect(connection, + &StiebelEltronModbusConnection::outdoorTemperatureChanged, this, + [thing](float outdoorTemperature) { + qCDebug(dcStiebelEltron()) + << thing << "outdoor temperature changed" + << outdoorTemperature << "°C"; + thing->setStateValue( + stiebelEltronOutdoorTemperatureStateTypeId, + outdoorTemperature); + }); + + connect( + connection, &StiebelEltronModbusConnection::flowTemperatureChanged, + this, [thing](float flowTemperature) { + qCDebug(dcStiebelEltron()) + << thing << "flow temperature changed" << flowTemperature + << "°C"; + thing->setStateValue(stiebelEltronFlowTemperatureStateTypeId, + flowTemperature); + }); + + connect(connection, + &StiebelEltronModbusConnection::hotWaterTemperatureChanged, + this, [thing](float hotWaterTemperature) { + qCDebug(dcStiebelEltron()) + << thing << "hot water temperature changed" + << hotWaterTemperature << "°C"; + thing->setStateValue( + stiebelEltronHotWaterTemperatureStateTypeId, + hotWaterTemperature); + }); + connect(connection, + &StiebelEltronModbusConnection::storageTankTemperatureChanged, + this, [thing](float storageTankTemperature) { + qCDebug(dcStiebelEltron()) + << thing << "Storage tank temperature changed" + << storageTankTemperature << "°C"; + thing->setStateValue( + stiebelEltronStorageTankTemperatureStateTypeId, + storageTankTemperature); + }); + connect(connection, + &StiebelEltronModbusConnection::returnTemperatureChanged, this, + [thing](float returnTemperature) { + qCDebug(dcStiebelEltron()) + << thing << "return temperature changed" + << returnTemperature << "°C"; + thing->setStateValue( + stiebelEltronReturnTemperatureStateTypeId, + returnTemperature); + }); + connect( + connection, &StiebelEltronModbusConnection::heatingEnergyChanged, + this, [thing](quint32 heatingEnergy) { + // kWh and MWh of energy are stored in two registers an read as + // an uint32. The following arithmetic splits the uint32 into + // two uint16 and sums up the MWh and kWh values. + quint32 correctedEnergy = + (heatingEnergy >> 16) + (heatingEnergy & 0xFFFF) * 1000; + qCDebug(dcStiebelEltron()) << thing << "Heating energy changed" + << correctedEnergy << "kWh"; + thing->setStateValue(stiebelEltronHeatingEnergyStateTypeId, + correctedEnergy); + }); + connect(connection, + &StiebelEltronModbusConnection::hotWaterEnergyChanged, this, + [thing](quint32 hotWaterEnergy) { + // see comment in heatingEnergyChanged + quint32 correctedEnergy = (hotWaterEnergy >> 16) + + (hotWaterEnergy & 0xFFFF) * 1000; + qCDebug(dcStiebelEltron()) + << thing << "Hot Water energy changed" + << correctedEnergy << "kWh"; + thing->setStateValue(stiebelEltronHotWaterEnergyStateTypeId, + correctedEnergy); + }); + connect(connection, + &StiebelEltronModbusConnection::consumedEnergyHeatingChanged, + this, [thing](quint32 consumedEnergyHeatingEnergy) { + // see comment in heatingEnergyChanged + quint32 correctedEnergy = + (consumedEnergyHeatingEnergy >> 16) + + (consumedEnergyHeatingEnergy & 0xFFFF) * 1000; + qCDebug(dcStiebelEltron()) + << thing << "Consumed energy Heating changed" + << correctedEnergy << "kWh"; + thing->setStateValue( + stiebelEltronConsumedEnergyHeatingStateTypeId, + correctedEnergy); + }); + connect(connection, + &StiebelEltronModbusConnection::consumedEnergyHotWaterChanged, + this, [thing](quint32 consumedEnergyHotWaterEnergy) { + // see comment in heatingEnergyChanged + quint32 correctedEnergy = + (consumedEnergyHotWaterEnergy >> 16) + + (consumedEnergyHotWaterEnergy & 0xFFFF) * 1000; + qCDebug(dcStiebelEltron()) + << thing << "Consumed energy hot water changed" + << correctedEnergy << "kWh"; + thing->setStateValue( + stiebelEltronConsumedEnergyHotWaterStateTypeId, + correctedEnergy); + }); + + connect( + connection, &StiebelEltronModbusConnection::operatingModeChanged, + this, + [thing]( + StiebelEltronModbusConnection::OperatingMode operatingMode) { + qCDebug(dcStiebelEltron()) + << thing << "operating mode changed " << operatingMode; + switch (operatingMode) { + case StiebelEltronModbusConnection::OperatingModeEmergency: + thing->setStateValue( + stiebelEltronOperatingModeStateTypeId, "Emergency"); + break; + case StiebelEltronModbusConnection::OperatingModeStandby: + thing->setStateValue( + stiebelEltronOperatingModeStateTypeId, "Standby"); + break; + case StiebelEltronModbusConnection::OperatingModeProgram: + thing->setStateValue( + stiebelEltronOperatingModeStateTypeId, "Program"); + break; + case StiebelEltronModbusConnection::OperatingModeComfort: + thing->setStateValue( + stiebelEltronOperatingModeStateTypeId, "Comfort"); + break; + case StiebelEltronModbusConnection::OperatingModeEco: + thing->setStateValue( + stiebelEltronOperatingModeStateTypeId, "Eco"); + break; + case StiebelEltronModbusConnection::OperatingModeHotWater: + thing->setStateValue( + stiebelEltronOperatingModeStateTypeId, "Hot water"); + break; + } + }); + connect(connection, &StiebelEltronModbusConnection::systemStatusChanged, + this, [thing](uint16_t systemStatus) { + qCDebug(dcStiebelEltron()) + << thing << "System status changed " << systemStatus; + + thing->setStateValue(stiebelEltronPumpOneStateTypeId, + systemStatus & (1 << 0)); + + thing->setStateValue(stiebelEltronPumpTwoStateTypeId, + systemStatus & (1 << 1)); + thing->setStateValue(stiebelEltronHeatingUpStateTypeId, + systemStatus & (1 << 2)); + + thing->setStateValue(stiebelEltronAuxHeatingStateTypeId, + systemStatus & (1 << 3)); + thing->setStateValue(stiebelEltronHeatingStateTypeId, + systemStatus & (1 << 4)); + thing->setStateValue(stiebelEltronHotWaterStateTypeId, + systemStatus & (1 << 5)); + thing->setStateValue(stiebelEltronCompressorStateTypeId, + systemStatus & (1 << 6)); + thing->setStateValue(stiebelEltronSummerModeStateTypeId, + systemStatus & (1 << 7)); + thing->setStateValue(stiebelEltronCoolingModeStateTypeId, + systemStatus & (1 << 8)); + thing->setStateValue(stiebelEltronDefrostingStateTypeId, + systemStatus & (1 << 9)); + thing->setStateValue(stiebelEltronSilentModeStateTypeId, + systemStatus & (1 << 10)); + thing->setStateValue(stiebelEltronPowerStateTypeId, + systemStatus & (1 << 11)); + }); + + connect( + connection, &StiebelEltronModbusConnection::sgReadyStateChanged, + this, + [thing](StiebelEltronModbusConnection::SmartGridState + smartGridState) { + qCDebug(dcStiebelEltron()) + << thing << "SG Ready activation changed" << smartGridState; + switch (smartGridState) { + case StiebelEltronModbusConnection::SmartGridStateModeOne: + thing->setStateValue( + stiebelEltronSgReadyModeStateTypeId, "Mode 1"); + break; + case StiebelEltronModbusConnection::SmartGridStateModeTwo: + thing->setStateValue( + stiebelEltronSgReadyModeStateTypeId, "Mode 2"); + break; + case StiebelEltronModbusConnection::SmartGridStateModeThree: + thing->setStateValue( + stiebelEltronSgReadyModeStateTypeId, "Mode 3"); + break; + case StiebelEltronModbusConnection::SmartGridStateModeFour: + thing->setStateValue( + stiebelEltronSgReadyModeStateTypeId, "Mode 4"); + break; + } + }); + connect(connection, + &StiebelEltronModbusConnection::sgReadyActiveChanged, this, + [thing](bool smartGridActive) { + qCDebug(dcStiebelEltron()) + << thing << "SG Ready activation changed" + << smartGridActive; + thing->setStateValue(stiebelEltronSgReadyActiveStateTypeId, + smartGridActive); + }); m_connections.insert(thing, connection); + connection->connectDevice(); + info->finish(Thing::ThingErrorNoError); } - - } -void IntegrationPluginStiebelEltron::postSetupThing(Thing *thing) -{ +void IntegrationPluginStiebelEltron::postSetupThing(Thing *thing) { if (thing->thingClassId() == stiebelEltronThingClassId) { if (!m_pluginTimer) { qCDebug(dcStiebelEltron()) << "Starting plugin timer..."; - m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); + m_pluginTimer = + hardwareManager()->pluginTimerManager()->registerTimer(10); connect(m_pluginTimer, &PluginTimer::timeout, this, [this] { - foreach (StiebelEltronModbusConnection *connection, m_connections) { + foreach (StiebelEltronModbusConnection *connection, + m_connections) { if (connection->connected()) { connection->update(); } @@ -134,9 +363,9 @@ void IntegrationPluginStiebelEltron::postSetupThing(Thing *thing) } } -void IntegrationPluginStiebelEltron::thingRemoved(Thing *thing) -{ - if (thing->thingClassId() == stiebelEltronThingClassId && m_connections.contains(thing)) { +void IntegrationPluginStiebelEltron::thingRemoved(Thing *thing) { + if (thing->thingClassId() == stiebelEltronThingClassId && + m_connections.contains(thing)) { m_connections.take(thing)->deleteLater(); } @@ -146,9 +375,56 @@ void IntegrationPluginStiebelEltron::thingRemoved(Thing *thing) } } -void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) -{ - info->finish(Thing::ThingErrorNoError); +void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { + Thing *thing = info->thing(); + StiebelEltronModbusConnection *connection = m_connections.value(thing); + + + + if (!connection->connected()) { + qCWarning(dcStiebelEltron()) << "Could not execute action. The modbus connection is currently not available."; + info->finish(Thing::ThingErrorHardwareNotAvailable); + return; + } + + // Got this from StiebelEltron plugin, not sure if necessary + if (thing->thingClassId() != stiebelEltronThingClassId) { + info->finish(Thing::ThingErrorNoError); + } + + if (info->action().actionTypeId() == stiebelEltronSgReadyActiveActionTypeId) { + bool sgReadyActiveBool = info->action().paramValue(stiebelEltronSgReadyActiveActionSgReadyActiveParamTypeId).toBool(); + qCDebug(dcStiebelEltron()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params(); + qCDebug(dcStiebelEltron()) << "Value: " << sgReadyActiveBool; + + QModbusReply *reply = connection->setSgReadyActive(sgReadyActiveBool); + if (!reply) { + qCWarning(dcStiebelEltron()) << "Execute action failed because the reply could not be created."; + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, info, [info, reply, sgReadyActiveBool]{ + if (reply->error() != QModbusDevice::NoError) { + qCWarning(dcStiebelEltron()) << "Set SG ready activation finished with error" << reply->errorString(); + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + + qCDebug(dcStiebelEltron()) << "Execute action finished successfully" << info->action().actionTypeId().toString() << info->action().params(); + info->thing()->setStateValue(stiebelEltronSgReadyActiveStateTypeId, sgReadyActiveBool); + info->finish(Thing::ThingErrorNoError); + }); + + connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltron()) << "Modbus reply error occurred while execute action" << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } + + info->finish(Thing::ThingErrorNoError); } - diff --git a/stiebeleltron/integrationpluginstiebeleltron.json b/stiebeleltron/integrationpluginstiebeleltron.json index d7ae4e2..58e3088 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.json +++ b/stiebeleltron/integrationpluginstiebeleltron.json @@ -57,7 +57,7 @@ "cached": false }, { - "id": "d6475acb-3a15-401b-8bad-8610eb056bf7", + "id": "1ec958c8-7bf1-469e-b35e-b71fa2099e91", "name": "flowTemperature", "displayName": "Flow temperature", "displayNameEvent": "Flow temperature changed", @@ -76,32 +76,261 @@ "defaultValue": 0, "suggestLogging": true }, + { - "id": "7d474fb5-aa37-4f21-8166-b20f5bf84fb4", - "name": "sgReadyMode", - "displayName": "Smart grid mode", - "displayNameEvent": "Smart grid mode changed", - "displayNameAction": "Set smart grid mode", - "type": "QString", - "possibleValues": [ - "Off", - "Low", - "Standard", - "High" - ], - "writable": true, - "defaultValue": "Standard", + "id": "e86cbac5-c2c3-4fcf-8caa-dbfc0df2584d", + "name": "outdoorTemperature", + "displayName": "Outdoor temperature", + "displayNameEvent": "Outdoor temperature changed", + "unit": "DegreeCelsius", + "type": "double", + "defaultValue": 0, "suggestLogging": true }, { - "id": "f4abbd8d-14d6-4294-9b63-411a9721f946", - "name": "totalEnergy", - "displayName": "Total energy", - "displayNameEvent": "Total energy changed", + "id": "27c56897-75f1-45af-9a14-b0620053d2d2", + "name": "hotWaterTemperature", + "displayName": "Hot water temperature", + "displayNameEvent": "Hot water changed", + "unit": "DegreeCelsius", "type": "double", - "unit": "KiloWattHour", "defaultValue": 0, "suggestLogging": true + }, + { + "id": "5833ceb6-5e7c-437b-a44a-e9f5eb42b6ac", + "name": "sourceTemperature", + "displayName": "Source temperature", + "displayNameEvent": "Source temperature changed", + "unit": "DegreeCelsius", + "type": "double", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "d1959819-9e56-47f7-b619-a393ce50738a", + "name": "roomTemperature1", + "displayName": "Room temperature 1", + "displayNameEvent": "Room temperature 1 changed", + "unit": "DegreeCelsius", + "type": "double", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "04ac741c-5277-4806-be73-576a164ecb46", + "name": "roomTemperature2", + "displayName": "Room temperature 1", + "displayNameEvent": "Room temperature changed", + "unit": "DegreeCelsius", + "type": "double", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "43dd25b3-8782-4faa-a9e0-2fb10892fa0c", + "name": "storageTankTemperature", + "displayName": "Storage tank temperature", + "displayNameEvent": "Storage tank temperature changed", + "unit": "DegreeCelsius", + "type": "double", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "d0597f21-2c0e-4db6-92e0-4a3b66474f87", + "name": "heatingEnergy", + "displayName": "Heating energy", + "displayNameEvent": "Heating energy changed", + "unit": "KiloWattHour", + "type": "uint", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "9761060e-f364-466e-8661-d28f01b862fc", + "name": "hotWaterEnergy", + "displayName": "Hot water energy", + "displayNameEvent": "Hot water energy changed", + "unit": "KiloWattHour", + "type": "uint", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "11f91606-d550-4918-9fca-69e3303389c8", + "name": "consumedEnergyHotWater", + "displayName": "Consumed energy hot water", + "displayNameEvent": "Consumed energy hot water changed", + "unit": "KiloWattHour", + "type": "uint", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "6816dfef-3f54-4bf1-b0d5-641f06785991", + "name": "consumedEnergyHeating", + "displayName": "Consumed energy heating", + "displayNameEvent": "Consumed energy heating changed", + "unit": "KiloWattHour", + "type": "uint", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "932cc41e-53ae-48ae-baa2-6f385f5aa791", + "name": "operatingMode", + "displayName": "Operating mode", + "displayNameEvent": "Operating mode changed", + "displayNameAction": "Set operating mode", + "type": "QString", + "possibleValues": [ + "Emergency", + "Standby", + "Program", + "Comfort", + "Eco", + "Hot water" + ], + "writable": false, + "defaultValue": "Standby", + "suggestLogging": true + }, + { + "id": "0ad36f3e-96ff-49d0-8b12-b8c6fed1bf4b", + "name": "pumpOne", + "displayName": "Pump 1", + "displayNameEvent": "Pump 1 status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "1c211fb2-da78-41ad-b7d0-e404141a3dd5", + "name": "pumpTwo", + "displayName": "Pump 2", + "displayNameEvent": "Pump 2 status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "ad0b8df8-1eaa-409d-b5e2-a76d7c17c2b9", + "name": "heatingUp", + "displayName": "Heating up", + "displayNameEvent": "Heating up status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "44d5f18b-0389-4a7d-9cb8-f760ce06814e", + "name": "auxHeating", + "displayName": "Electric auxiliary heating", + "displayNameEvent": "Electric auxiliary heating status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "3e44e580-f515-47ae-984b-109b507a5db2", + "name": "heating", + "displayName": "Heating mode", + "displayNameEvent": "Heating mode status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "b6338cdb-863e-4191-adc4-bc6da5a67351", + "name": "hotWater", + "displayName": "Hot water mode", + "displayNameEvent": "Hot water mode status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "c957cef8-b3a7-4626-ab95-db5439fbdf7f", + "name": "compressor", + "displayName": "Compressor", + "displayNameEvent": "Compressor status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "7a287cfb-9088-4aad-a991-3e43714dc64e", + "name": "summerMode", + "displayName": "Summer mode", + "displayNameEvent": "Sommer mode status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "1bfd99ee-1477-4f70-8717-a3a2930b137f", + "name": "coolingMode", + "displayName": "Cooling mode", + "displayNameEvent": "Cooling mode status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "5c47d9bb-66de-48aa-b90e-caa3ca8d44a5", + "name": "defrosting", + "displayName": "Defrosting mode", + "displayNameEvent": "Defrosting mode status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "047fcb7d-9080-4b45-9a6e-5060fa43f7c2", + "name": "silentMode", + "displayName": "Silent mode", + "displayNameEvent": "Silent mode status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "d77a30d9-98f7-40ec-bc55-77c547f24145", + "name": "power", + "displayName": "Power", + "displayNameEvent": "Power status changed", + "type": "bool", + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "798458bb-d38e-4028-880a-6dcba409a2f5", + "name": "sgReadyActive", + "displayName": "SG Ready enabled", + "displayNameEvent": "SG Ready activation changed", + "displayNameAction": "Switch SG Ready on/off", + "type": "bool", + "writable": true, + "defaultValue": false, + "suggestLogging": true + }, + { + "id": "7d474fb5-aa37-4f21-8166-b20f5bf84fb4", + "name": "sgReadyMode", + "displayName": "SG Ready mode", + "displayNameEvent": "SG Ready mode changed", + "displayNameAction": "Set SG Ready mode", + "type": "QString", + "possibleValues": [ + "Mode 1", + "Mode 2", + "Mode 3", + "Mode 4" + ], + "writable": true, + "defaultValue": "Mode 3", + "suggestLogging": true } ], "actionTypes": [ ] diff --git a/stiebeleltron/stiebel-eltron-registers.json b/stiebeleltron/stiebel-eltron-registers.json index cdcc2ed..6fd0877 100644 --- a/stiebeleltron/stiebel-eltron-registers.json +++ b/stiebeleltron/stiebel-eltron-registers.json @@ -1,19 +1,331 @@ { "protocol": "TCP", "endianness": "BigEndian", + "enums": [ + { + "name": "OperatingMode", + "values": [ + { + "key": "Emergency", + "value": 0 + }, + { + "key": "Standby", + "value": 1 + }, + { + "key": "Program", + "value": 2 + }, + { + "key": "Comfort", + "value": 3 + }, + { + "key": "Eco", + "value": 4 + }, + { + "key": "HotWater", + "value": 5 + } + ] + }, + { + "name": "SmartGridState", + "values": [ + { + "key": "ModeOne", + "value": 1 + }, + { + "key": "ModeTwo", + "value": 2 + }, + { + "key": "ModeThree", + "value": 3 + }, + { + "key": "ModeFour", + "value": 4 + } + ] + } + ], "registers": [ { "id": "outdoorTemperature", - "address": 507, + "address": 506, "size": 1, "type": "int16", "registerType": "inputRegister", "readSchedule": "update", "description": "Outdoor temperature", "staticScaleFactor": -1, + "defaultValue": 0, + "unit": "°C", + "access": "RO" + }, + { + "id": "flowTemperature", + "address": 514, + "size": 1, + "type": "int16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Flow temperature", + "staticScaleFactor": -1, + "defaultValue": 0, + "unit": "°C", + "access": "RO" + }, + { + "id": "hotWaterTemperature", + "address": 521, + "size": 1, + "type": "uint16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Hot water temperature", + "staticScaleFactor": -1, "defaultValue": "0", "unit": "°C", "access": "RO" + }, + { + "id": "hotGasTemperature1", + "address": 543, + "size": 1, + "type": "uint16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Hot gas temperature HP 1", + "staticScaleFactor": -1, + "defaultValue": "0", + "unit": "°C", + "access": "RO" + }, + { + "id": "hotGasTemperature2", + "address": 550, + "size": 1, + "type": "uint16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Hot gas temperature HP 2", + "staticScaleFactor": -1, + "defaultValue": "0", + "unit": "°C", + "access": "RO" + }, + { + "id": "SourceTemperature", + "address": 562, + "size": 1, + "type": "uint16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Source temperature", + "staticScaleFactor": -1, + "defaultValue": "0", + "unit": "°C", + "access": "RO" + }, + { + "id": "roomTemperatureFEK", + "address": 502, + "size": 1, + "type": "uint16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Room temperature FEK", + "staticScaleFactor": -1, + "defaultValue": "0", + "unit": "°C", + "access": "RO" + }, + { + "id": "returnTemperature", + "address": 515, + "size": 1, + "type": "int16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Return temperature", + "staticScaleFactor": -1, + "defaultValue": 0, + "unit": "°C", + "access": "RO" + }, + { + "id": "solarCollectorTemperature", + "address": 527, + "size": 1, + "type": "uint16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Solar collector temperature", + "staticScaleFactor": -1, + "defaultValue": "0", + "unit": "°C", + "access": "RO" + }, + { + "id": "solarStorageTankTemperature", + "address": 528, + "size": 1, + "type": "uint16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Solar storage tank temperature", + "staticScaleFactor": -1, + "defaultValue": "0", + "unit": "°C", + "access": "RO" + }, + { + "id": "storageTankTemperature", + "address": 517, + "size": 1, + "type": "uint16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Storage tank temperature", + "staticScaleFactor": -1, + "defaultValue": "0", + "unit": "°C", + "access": "RO" + }, + { + "id": "externalHeatSourceTemperature", + "address": 530, + "size": 1, + "type": "uint16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "External heat source temperature", + "staticScaleFactor": -1, + "defaultValue": "0", + "unit": "°C", + "access": "RO" + }, + { + "id": "heatingEnergy", + "address": 3501, + "size": 2, + "type": "uint32", + "registerType": "inputRegister", + "readSchedule": "update", + "defaultValue": "0", + "unit": "kWh", + "description": "Heating energy", + "access": "RO" + }, + { + "id": "hotWaterEnergy", + "address": 3504, + "size": 2, + "type": "uint32", + "registerType": "inputRegister", + "readSchedule": "update", + "defaultValue": "0", + "unit": "kWh", + "description": "Hot water energy", + "access": "RO" + }, + { + "id": "consumedEnergyHeating", + "address": 3511, + "size": 2, + "type": "uint32", + "registerType": "inputRegister", + "readSchedule": "update", + "defaultValue": "0", + "unit": "kWh", + "description": "Consumed energy heating", + "access": "RO" + }, + { + "id": "consumedEnergyHotWater", + "address": 3514, + "size": 2, + "type": "uint32", + "registerType": "inputRegister", + "readSchedule": "update", + "defaultValue": "0", + "unit": "kWh", + "description": "Consumed energy hot water", + "access": "RO" + }, + { + "id": "operatingMode", + "address": 1500, + "size": 1, + "type": "uint16", + "enum": "OperatingMode", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Operating mode", + "defaultValue": "OperatingModeStandby", + "access": "RO" + }, + { + "id": "systemStatus", + "address": 2500, + "size": 1, + "type": "uint16", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "System status", + "defaultValue": 0, + "access": "RO" + }, + { + "id": "sgReadyState", + "address": 5000, + "size": 1, + "type": "uint16", + "enum": "SmartGridState", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Smart grid status", + "defaultValue": "SmartGridStateModeTwo", + "access": "RO" + }, + { + "id": "sgReadyActive", + "address": 4000, + "size": 1, + "type": "uint16", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "SG ready active", + "defaultValue": 0, + "access": "RW" + }, + { + "id": "sgReadyInputOne", + "address": 4001, + "size": 1, + "type": "uint16", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "SG Ready Input 1", + "defaultValue": 0, + "access": "RW" + }, + { + "id": "sgReadyInputTwo", + "address": 4002, + "size": 1, + "type": "uint16", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "SG Read Input 2", + "defaultValue": 0, + "access": "RW" } + ] -} \ No newline at end of file +} diff --git a/stiebeleltron/stiebeleltronmodbusconnection.cpp b/stiebeleltron/stiebeleltronmodbusconnection.cpp index 15bd8e5..a7bc246 100644 --- a/stiebeleltron/stiebeleltronmodbusconnection.cpp +++ b/stiebeleltron/stiebeleltronmodbusconnection.cpp @@ -46,6 +46,138 @@ float StiebelEltronModbusConnection::outdoorTemperature() const return m_outdoorTemperature; } +float StiebelEltronModbusConnection::flowTemperature() const +{ + return m_flowTemperature; +} + +float StiebelEltronModbusConnection::hotWaterTemperature() const +{ + return m_hotWaterTemperature; +} + +float StiebelEltronModbusConnection::hotGasTemperature1() const +{ + return m_hotGasTemperature1; +} + +float StiebelEltronModbusConnection::hotGasTemperature2() const +{ + return m_hotGasTemperature2; +} + +float StiebelEltronModbusConnection::SourceTemperature() const +{ + return m_SourceTemperature; +} + +float StiebelEltronModbusConnection::roomTemperatureFEK() const +{ + return m_roomTemperatureFEK; +} + +float StiebelEltronModbusConnection::returnTemperature() const +{ + return m_returnTemperature; +} + +float StiebelEltronModbusConnection::solarCollectorTemperature() const +{ + return m_solarCollectorTemperature; +} + +float StiebelEltronModbusConnection::solarStorageTankTemperature() const +{ + return m_solarStorageTankTemperature; +} + +float StiebelEltronModbusConnection::storageTankTemperature() const +{ + return m_storageTankTemperature; +} + +float StiebelEltronModbusConnection::externalHeatSourceTemperature() const +{ + return m_externalHeatSourceTemperature; +} + +quint32 StiebelEltronModbusConnection::heatingEnergy() const +{ + return m_heatingEnergy; +} + +quint32 StiebelEltronModbusConnection::hotWaterEnergy() const +{ + return m_hotWaterEnergy; +} + +quint32 StiebelEltronModbusConnection::consumedEnergyHeating() const +{ + return m_consumedEnergyHeating; +} + +quint32 StiebelEltronModbusConnection::consumedEnergyHotWater() const +{ + return m_consumedEnergyHotWater; +} + +StiebelEltronModbusConnection::OperatingMode StiebelEltronModbusConnection::operatingMode() const +{ + return m_operatingMode; +} + +quint16 StiebelEltronModbusConnection::systemStatus() const +{ + return m_systemStatus; +} + +StiebelEltronModbusConnection::SmartGridState StiebelEltronModbusConnection::sgReadyState() const +{ + return m_sgReadyState; +} + +quint16 StiebelEltronModbusConnection::sgReadyActive() const +{ + return m_sgReadyActive; +} + +QModbusReply *StiebelEltronModbusConnection::setSgReadyActive(quint16 sgReadyActive) +{ + QVector values = ModbusDataUtils::convertFromUInt16(sgReadyActive); + qCDebug(dcStiebelEltronModbusConnection()) << "--> Write \"SG ready active\" register:" << 4000 << "size:" << 1 << values; + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4000, values.count()); + request.setValues(values); + return sendWriteRequest(request, m_slaveId); +} + +quint16 StiebelEltronModbusConnection::sgReadyInputOne() const +{ + return m_sgReadyInputOne; +} + +QModbusReply *StiebelEltronModbusConnection::setSgReadyInputOne(quint16 sgReadyInputOne) +{ + QVector values = ModbusDataUtils::convertFromUInt16(sgReadyInputOne); + qCDebug(dcStiebelEltronModbusConnection()) << "--> Write \"SG Ready Input 1\" register:" << 4001 << "size:" << 1 << values; + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4001, values.count()); + request.setValues(values); + return sendWriteRequest(request, m_slaveId); +} + +quint16 StiebelEltronModbusConnection::sgReadyInputTwo() const +{ + return m_sgReadyInputTwo; +} + +QModbusReply *StiebelEltronModbusConnection::setSgReadyInputTwo(quint16 sgReadyInputTwo) +{ + QVector values = ModbusDataUtils::convertFromUInt16(sgReadyInputTwo); + qCDebug(dcStiebelEltronModbusConnection()) << "--> Write \"SG Read Input 2\" register:" << 4002 << "size:" << 1 << values; + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4002, values.count()); + request.setValues(values); + return sendWriteRequest(request, m_slaveId); +} + void StiebelEltronModbusConnection::initialize() { // No init registers defined. Nothing to be done and we are finished. @@ -55,12 +187,33 @@ void StiebelEltronModbusConnection::initialize() void StiebelEltronModbusConnection::update() { updateOutdoorTemperature(); + updateFlowTemperature(); + updateHotWaterTemperature(); + updateHotGasTemperature1(); + updateHotGasTemperature2(); + updateSourceTemperature(); + updateRoomTemperatureFEK(); + updateReturnTemperature(); + updateSolarCollectorTemperature(); + updateSolarStorageTankTemperature(); + updateStorageTankTemperature(); + updateExternalHeatSourceTemperature(); + updateHeatingEnergy(); + updateHotWaterEnergy(); + updateConsumedEnergyHeating(); + updateConsumedEnergyHotWater(); + updateOperatingMode(); + updateSystemStatus(); + updateSgReadyState(); + updateSgReadyActive(); + updateSgReadyInputOne(); + updateSgReadyInputTwo(); } void StiebelEltronModbusConnection::updateOutdoorTemperature() { - // Update registers from Flow - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Flow\" register:" << 507 << "size:" << 1; + // Update registers from Outdoor temperature + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Outdoor temperature\" register:" << 506 << "size:" << 1; QModbusReply *reply = readOutdoorTemperature(); if (reply) { if (!reply->isFinished()) { @@ -69,7 +222,7 @@ void StiebelEltronModbusConnection::updateOutdoorTemperature() if (reply->error() == QModbusDevice::NoError) { const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Flow\" register" << 507 << "size:" << 1 << values; + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Outdoor temperature\" register" << 506 << "size:" << 1 << values; float receivedOutdoorTemperature = ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, -1); if (m_outdoorTemperature != receivedOutdoorTemperature) { m_outdoorTemperature = receivedOutdoorTemperature; @@ -79,20 +232,839 @@ void StiebelEltronModbusConnection::updateOutdoorTemperature() }); connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Flow\" registers from" << hostAddress().toString() << error << reply->errorString(); + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Outdoor temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); emit reply->finished(); // To make sure it will be deleted }); } else { delete reply; // Broadcast reply returns immediatly } } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Flow\" registers from" << hostAddress().toString() << errorString(); + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Outdoor temperature\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateFlowTemperature() +{ + // Update registers from Flow temperature + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Flow temperature\" register:" << 514 << "size:" << 1; + QModbusReply *reply = readFlowTemperature(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Flow temperature\" register" << 514 << "size:" << 1 << values; + float receivedFlowTemperature = ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, -1); + if (m_flowTemperature != receivedFlowTemperature) { + m_flowTemperature = receivedFlowTemperature; + emit flowTemperatureChanged(m_flowTemperature); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Flow temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Flow temperature\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateHotWaterTemperature() +{ + // Update registers from Hot water temperature + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Hot water temperature\" register:" << 521 << "size:" << 1; + QModbusReply *reply = readHotWaterTemperature(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Hot water temperature\" register" << 521 << "size:" << 1 << values; + float receivedHotWaterTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); + if (m_hotWaterTemperature != receivedHotWaterTemperature) { + m_hotWaterTemperature = receivedHotWaterTemperature; + emit hotWaterTemperatureChanged(m_hotWaterTemperature); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Hot water temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Hot water temperature\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateHotGasTemperature1() +{ + // Update registers from Hot gas temperature HP 1 + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Hot gas temperature HP 1\" register:" << 543 << "size:" << 1; + QModbusReply *reply = readHotGasTemperature1(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Hot gas temperature HP 1\" register" << 543 << "size:" << 1 << values; + float receivedHotGasTemperature1 = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); + if (m_hotGasTemperature1 != receivedHotGasTemperature1) { + m_hotGasTemperature1 = receivedHotGasTemperature1; + emit hotGasTemperature1Changed(m_hotGasTemperature1); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Hot gas temperature HP 1\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Hot gas temperature HP 1\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateHotGasTemperature2() +{ + // Update registers from Hot gas temperature HP 2 + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Hot gas temperature HP 2\" register:" << 550 << "size:" << 1; + QModbusReply *reply = readHotGasTemperature2(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Hot gas temperature HP 2\" register" << 550 << "size:" << 1 << values; + float receivedHotGasTemperature2 = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); + if (m_hotGasTemperature2 != receivedHotGasTemperature2) { + m_hotGasTemperature2 = receivedHotGasTemperature2; + emit hotGasTemperature2Changed(m_hotGasTemperature2); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Hot gas temperature HP 2\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Hot gas temperature HP 2\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateSourceTemperature() +{ + // Update registers from Source temperature + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Source temperature\" register:" << 562 << "size:" << 1; + QModbusReply *reply = readSourceTemperature(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Source temperature\" register" << 562 << "size:" << 1 << values; + float receivedSourceTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); + if (m_SourceTemperature != receivedSourceTemperature) { + m_SourceTemperature = receivedSourceTemperature; + emit SourceTemperatureChanged(m_SourceTemperature); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Source temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Source temperature\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateRoomTemperatureFEK() +{ + // Update registers from Room temperature FEK + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Room temperature FEK\" register:" << 502 << "size:" << 1; + QModbusReply *reply = readRoomTemperatureFEK(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Room temperature FEK\" register" << 502 << "size:" << 1 << values; + float receivedRoomTemperatureFEK = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); + if (m_roomTemperatureFEK != receivedRoomTemperatureFEK) { + m_roomTemperatureFEK = receivedRoomTemperatureFEK; + emit roomTemperatureFEKChanged(m_roomTemperatureFEK); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Room temperature FEK\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Room temperature FEK\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateReturnTemperature() +{ + // Update registers from Return temperature + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Return temperature\" register:" << 515 << "size:" << 1; + QModbusReply *reply = readReturnTemperature(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Return temperature\" register" << 515 << "size:" << 1 << values; + float receivedReturnTemperature = ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, -1); + if (m_returnTemperature != receivedReturnTemperature) { + m_returnTemperature = receivedReturnTemperature; + emit returnTemperatureChanged(m_returnTemperature); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Return temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Return temperature\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateSolarCollectorTemperature() +{ + // Update registers from Solar collector temperature + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Solar collector temperature\" register:" << 527 << "size:" << 1; + QModbusReply *reply = readSolarCollectorTemperature(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Solar collector temperature\" register" << 527 << "size:" << 1 << values; + float receivedSolarCollectorTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); + if (m_solarCollectorTemperature != receivedSolarCollectorTemperature) { + m_solarCollectorTemperature = receivedSolarCollectorTemperature; + emit solarCollectorTemperatureChanged(m_solarCollectorTemperature); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Solar collector temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Solar collector temperature\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateSolarStorageTankTemperature() +{ + // Update registers from Solar storage tank temperature + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Solar storage tank temperature\" register:" << 528 << "size:" << 1; + QModbusReply *reply = readSolarStorageTankTemperature(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Solar storage tank temperature\" register" << 528 << "size:" << 1 << values; + float receivedSolarStorageTankTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); + if (m_solarStorageTankTemperature != receivedSolarStorageTankTemperature) { + m_solarStorageTankTemperature = receivedSolarStorageTankTemperature; + emit solarStorageTankTemperatureChanged(m_solarStorageTankTemperature); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Solar storage tank temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Solar storage tank temperature\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateStorageTankTemperature() +{ + // Update registers from Storage tank temperature + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Storage tank temperature\" register:" << 517 << "size:" << 1; + QModbusReply *reply = readStorageTankTemperature(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Storage tank temperature\" register" << 517 << "size:" << 1 << values; + float receivedStorageTankTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); + if (m_storageTankTemperature != receivedStorageTankTemperature) { + m_storageTankTemperature = receivedStorageTankTemperature; + emit storageTankTemperatureChanged(m_storageTankTemperature); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Storage tank temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Storage tank temperature\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateExternalHeatSourceTemperature() +{ + // Update registers from External heat source temperature + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"External heat source temperature\" register:" << 530 << "size:" << 1; + QModbusReply *reply = readExternalHeatSourceTemperature(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"External heat source temperature\" register" << 530 << "size:" << 1 << values; + float receivedExternalHeatSourceTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); + if (m_externalHeatSourceTemperature != receivedExternalHeatSourceTemperature) { + m_externalHeatSourceTemperature = receivedExternalHeatSourceTemperature; + emit externalHeatSourceTemperatureChanged(m_externalHeatSourceTemperature); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"External heat source temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"External heat source temperature\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateHeatingEnergy() +{ + // Update registers from Heating energy + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Heating energy\" register:" << 3501 << "size:" << 2; + QModbusReply *reply = readHeatingEnergy(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Heating energy\" register" << 3501 << "size:" << 2 << values; + quint32 receivedHeatingEnergy = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_heatingEnergy != receivedHeatingEnergy) { + m_heatingEnergy = receivedHeatingEnergy; + emit heatingEnergyChanged(m_heatingEnergy); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Heating energy\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Heating energy\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateHotWaterEnergy() +{ + // Update registers from Hot water energy + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Hot water energy\" register:" << 3504 << "size:" << 2; + QModbusReply *reply = readHotWaterEnergy(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Hot water energy\" register" << 3504 << "size:" << 2 << values; + quint32 receivedHotWaterEnergy = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_hotWaterEnergy != receivedHotWaterEnergy) { + m_hotWaterEnergy = receivedHotWaterEnergy; + emit hotWaterEnergyChanged(m_hotWaterEnergy); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Hot water energy\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Hot water energy\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateConsumedEnergyHeating() +{ + // Update registers from Consumed energy heating + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Consumed energy heating\" register:" << 3511 << "size:" << 2; + QModbusReply *reply = readConsumedEnergyHeating(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Consumed energy heating\" register" << 3511 << "size:" << 2 << values; + quint32 receivedConsumedEnergyHeating = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_consumedEnergyHeating != receivedConsumedEnergyHeating) { + m_consumedEnergyHeating = receivedConsumedEnergyHeating; + emit consumedEnergyHeatingChanged(m_consumedEnergyHeating); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Consumed energy heating\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Consumed energy heating\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateConsumedEnergyHotWater() +{ + // Update registers from Consumed energy hot water + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Consumed energy hot water\" register:" << 3514 << "size:" << 2; + QModbusReply *reply = readConsumedEnergyHotWater(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Consumed energy hot water\" register" << 3514 << "size:" << 2 << values; + quint32 receivedConsumedEnergyHotWater = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_consumedEnergyHotWater != receivedConsumedEnergyHotWater) { + m_consumedEnergyHotWater = receivedConsumedEnergyHotWater; + emit consumedEnergyHotWaterChanged(m_consumedEnergyHotWater); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Consumed energy hot water\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Consumed energy hot water\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateOperatingMode() +{ + // Update registers from Operating mode + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Operating mode\" register:" << 1500 << "size:" << 1; + QModbusReply *reply = readOperatingMode(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Operating mode\" register" << 1500 << "size:" << 1 << values; + OperatingMode receivedOperatingMode = static_cast(ModbusDataUtils::convertToUInt16(values)); + if (m_operatingMode != receivedOperatingMode) { + m_operatingMode = receivedOperatingMode; + emit operatingModeChanged(m_operatingMode); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Operating mode\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Operating mode\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateSystemStatus() +{ + // Update registers from System status + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"System status\" register:" << 2500 << "size:" << 1; + QModbusReply *reply = readSystemStatus(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"System status\" register" << 2500 << "size:" << 1 << values; + quint16 receivedSystemStatus = ModbusDataUtils::convertToUInt16(values); + if (m_systemStatus != receivedSystemStatus) { + m_systemStatus = receivedSystemStatus; + emit systemStatusChanged(m_systemStatus); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"System status\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"System status\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateSgReadyState() +{ + // Update registers from Smart grid status + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Smart grid status\" register:" << 5000 << "size:" << 1; + QModbusReply *reply = readSgReadyState(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Smart grid status\" register" << 5000 << "size:" << 1 << values; + SmartGridState receivedSgReadyState = static_cast(ModbusDataUtils::convertToUInt16(values)); + if (m_sgReadyState != receivedSgReadyState) { + m_sgReadyState = receivedSgReadyState; + emit sgReadyStateChanged(m_sgReadyState); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Smart grid status\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Smart grid status\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateSgReadyActive() +{ + // Update registers from SG ready active + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"SG ready active\" register:" << 4000 << "size:" << 1; + QModbusReply *reply = readSgReadyActive(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"SG ready active\" register" << 4000 << "size:" << 1 << values; + quint16 receivedSgReadyActive = ModbusDataUtils::convertToUInt16(values); + if (m_sgReadyActive != receivedSgReadyActive) { + m_sgReadyActive = receivedSgReadyActive; + emit sgReadyActiveChanged(m_sgReadyActive); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"SG ready active\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"SG ready active\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateSgReadyInputOne() +{ + // Update registers from SG Ready Input 1 + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"SG Ready Input 1\" register:" << 4001 << "size:" << 1; + QModbusReply *reply = readSgReadyInputOne(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"SG Ready Input 1\" register" << 4001 << "size:" << 1 << values; + quint16 receivedSgReadyInputOne = ModbusDataUtils::convertToUInt16(values); + if (m_sgReadyInputOne != receivedSgReadyInputOne) { + m_sgReadyInputOne = receivedSgReadyInputOne; + emit sgReadyInputOneChanged(m_sgReadyInputOne); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"SG Ready Input 1\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"SG Ready Input 1\" registers from" << hostAddress().toString() << errorString(); + } +} + +void StiebelEltronModbusConnection::updateSgReadyInputTwo() +{ + // Update registers from SG Read Input 2 + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"SG Read Input 2\" register:" << 4002 << "size:" << 1; + QModbusReply *reply = readSgReadyInputTwo(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector values = unit.values(); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"SG Read Input 2\" register" << 4002 << "size:" << 1 << values; + quint16 receivedSgReadyInputTwo = ModbusDataUtils::convertToUInt16(values); + if (m_sgReadyInputTwo != receivedSgReadyInputTwo) { + m_sgReadyInputTwo = receivedSgReadyInputTwo; + emit sgReadyInputTwoChanged(m_sgReadyInputTwo); + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"SG Read Input 2\" registers from" << hostAddress().toString() << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else { + delete reply; // Broadcast reply returns immediatly + } + } else { + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"SG Read Input 2\" registers from" << hostAddress().toString() << errorString(); } } QModbusReply *StiebelEltronModbusConnection::readOutdoorTemperature() { - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 507, 1); + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 506, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readFlowTemperature() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 514, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readHotWaterTemperature() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 521, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readHotGasTemperature1() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 543, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readHotGasTemperature2() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 550, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readSourceTemperature() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 562, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readRoomTemperatureFEK() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 502, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readReturnTemperature() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 515, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readSolarCollectorTemperature() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 527, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readSolarStorageTankTemperature() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 528, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readStorageTankTemperature() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 517, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readExternalHeatSourceTemperature() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 530, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readHeatingEnergy() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 3501, 2); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readHotWaterEnergy() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 3504, 2); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readConsumedEnergyHeating() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 3511, 2); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readConsumedEnergyHotWater() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 3514, 2); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readOperatingMode() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 1500, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readSystemStatus() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 2500, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readSgReadyState() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 5000, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readSgReadyActive() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4000, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readSgReadyInputOne() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4001, 1); + return sendReadRequest(request, m_slaveId); +} + +QModbusReply *StiebelEltronModbusConnection::readSgReadyInputTwo() +{ + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4002, 1); return sendReadRequest(request, m_slaveId); } @@ -107,7 +1079,28 @@ void StiebelEltronModbusConnection::verifyInitFinished() QDebug operator<<(QDebug debug, StiebelEltronModbusConnection *stiebelEltronModbusConnection) { debug.nospace().noquote() << "StiebelEltronModbusConnection(" << stiebelEltronModbusConnection->hostAddress().toString() << ":" << stiebelEltronModbusConnection->port() << ")" << "\n"; - debug.nospace().noquote() << " - Flow:" << stiebelEltronModbusConnection->outdoorTemperature() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Outdoor temperature:" << stiebelEltronModbusConnection->outdoorTemperature() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Flow temperature:" << stiebelEltronModbusConnection->flowTemperature() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Hot water temperature:" << stiebelEltronModbusConnection->hotWaterTemperature() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Hot gas temperature HP 1:" << stiebelEltronModbusConnection->hotGasTemperature1() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Hot gas temperature HP 2:" << stiebelEltronModbusConnection->hotGasTemperature2() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Source temperature:" << stiebelEltronModbusConnection->SourceTemperature() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Room temperature FEK:" << stiebelEltronModbusConnection->roomTemperatureFEK() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Return temperature:" << stiebelEltronModbusConnection->returnTemperature() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Solar collector temperature:" << stiebelEltronModbusConnection->solarCollectorTemperature() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Solar storage tank temperature:" << stiebelEltronModbusConnection->solarStorageTankTemperature() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Storage tank temperature:" << stiebelEltronModbusConnection->storageTankTemperature() << " [°C]" << "\n"; + debug.nospace().noquote() << " - External heat source temperature:" << stiebelEltronModbusConnection->externalHeatSourceTemperature() << " [°C]" << "\n"; + debug.nospace().noquote() << " - Heating energy:" << stiebelEltronModbusConnection->heatingEnergy() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Hot water energy:" << stiebelEltronModbusConnection->hotWaterEnergy() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Consumed energy heating:" << stiebelEltronModbusConnection->consumedEnergyHeating() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Consumed energy hot water:" << stiebelEltronModbusConnection->consumedEnergyHotWater() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Operating mode:" << stiebelEltronModbusConnection->operatingMode() << "\n"; + debug.nospace().noquote() << " - System status:" << stiebelEltronModbusConnection->systemStatus() << "\n"; + debug.nospace().noquote() << " - Smart grid status:" << stiebelEltronModbusConnection->sgReadyState() << "\n"; + debug.nospace().noquote() << " - SG ready active:" << stiebelEltronModbusConnection->sgReadyActive() << "\n"; + debug.nospace().noquote() << " - SG Ready Input 1:" << stiebelEltronModbusConnection->sgReadyInputOne() << "\n"; + debug.nospace().noquote() << " - SG Read Input 2:" << stiebelEltronModbusConnection->sgReadyInputTwo() << "\n"; return debug.quote().space(); } diff --git a/stiebeleltron/stiebeleltronmodbusconnection.h b/stiebeleltron/stiebeleltronmodbusconnection.h index 942beb6..d6a793e 100644 --- a/stiebeleltron/stiebeleltronmodbusconnection.h +++ b/stiebeleltron/stiebeleltronmodbusconnection.h @@ -41,30 +41,219 @@ class StiebelEltronModbusConnection : public ModbusTCPMaster Q_OBJECT public: enum Registers { - RegisterOutdoorTemperature = 507 + RegisterRoomTemperatureFEK = 502, + RegisterOutdoorTemperature = 506, + RegisterFlowTemperature = 514, + RegisterReturnTemperature = 515, + RegisterStorageTankTemperature = 517, + RegisterHotWaterTemperature = 521, + RegisterSolarCollectorTemperature = 527, + RegisterSolarStorageTankTemperature = 528, + RegisterExternalHeatSourceTemperature = 530, + RegisterHotGasTemperature1 = 543, + RegisterHotGasTemperature2 = 550, + RegisterSourceTemperature = 562, + RegisterOperatingMode = 1500, + RegisterSystemStatus = 2500, + RegisterHeatingEnergy = 3501, + RegisterHotWaterEnergy = 3504, + RegisterConsumedEnergyHeating = 3511, + RegisterConsumedEnergyHotWater = 3514, + RegisterSgReadyActive = 4000, + RegisterSgReadyInputOne = 4001, + RegisterSgReadyInputTwo = 4002, + RegisterSgReadyState = 5000 }; Q_ENUM(Registers) + enum OperatingMode { + OperatingModeEmergency = 0, + OperatingModeStandby = 1, + OperatingModeProgram = 2, + OperatingModeComfort = 3, + OperatingModeEco = 4, + OperatingModeHotWater = 5 + }; + Q_ENUM(OperatingMode) + + enum SmartGridState { + SmartGridStateModeOne = 1, + SmartGridStateModeTwo = 2, + SmartGridStateModeThree = 3, + SmartGridStateModeFour = 4 + }; + Q_ENUM(SmartGridState) + explicit StiebelEltronModbusConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr); ~StiebelEltronModbusConnection() = default; - /* Flow [°C] - Address: 507, Size: 1 */ + /* Outdoor temperature [°C] - Address: 506, Size: 1 */ float outdoorTemperature() const; + /* Flow temperature [°C] - Address: 514, Size: 1 */ + float flowTemperature() const; + + /* Hot water temperature [°C] - Address: 521, Size: 1 */ + float hotWaterTemperature() const; + + /* Hot gas temperature HP 1 [°C] - Address: 543, Size: 1 */ + float hotGasTemperature1() const; + + /* Hot gas temperature HP 2 [°C] - Address: 550, Size: 1 */ + float hotGasTemperature2() const; + + /* Source temperature [°C] - Address: 562, Size: 1 */ + float SourceTemperature() const; + + /* Room temperature FEK [°C] - Address: 502, Size: 1 */ + float roomTemperatureFEK() const; + + /* Return temperature [°C] - Address: 515, Size: 1 */ + float returnTemperature() const; + + /* Solar collector temperature [°C] - Address: 527, Size: 1 */ + float solarCollectorTemperature() const; + + /* Solar storage tank temperature [°C] - Address: 528, Size: 1 */ + float solarStorageTankTemperature() const; + + /* Storage tank temperature [°C] - Address: 517, Size: 1 */ + float storageTankTemperature() const; + + /* External heat source temperature [°C] - Address: 530, Size: 1 */ + float externalHeatSourceTemperature() const; + + /* Heating energy [kWh] - Address: 3501, Size: 2 */ + quint32 heatingEnergy() const; + + /* Hot water energy [kWh] - Address: 3504, Size: 2 */ + quint32 hotWaterEnergy() const; + + /* Consumed energy heating [kWh] - Address: 3511, Size: 2 */ + quint32 consumedEnergyHeating() const; + + /* Consumed energy hot water [kWh] - Address: 3514, Size: 2 */ + quint32 consumedEnergyHotWater() const; + + /* Operating mode - Address: 1500, Size: 1 */ + OperatingMode operatingMode() const; + + /* System status - Address: 2500, Size: 1 */ + quint16 systemStatus() const; + + /* Smart grid status - Address: 5000, Size: 1 */ + SmartGridState sgReadyState() const; + + /* SG ready active - Address: 4000, Size: 1 */ + quint16 sgReadyActive() const; + QModbusReply *setSgReadyActive(quint16 sgReadyActive); + + /* SG Ready Input 1 - Address: 4001, Size: 1 */ + quint16 sgReadyInputOne() const; + QModbusReply *setSgReadyInputOne(quint16 sgReadyInputOne); + + /* SG Read Input 2 - Address: 4002, Size: 1 */ + quint16 sgReadyInputTwo() const; + QModbusReply *setSgReadyInputTwo(quint16 sgReadyInputTwo); + virtual void initialize(); virtual void update(); void updateOutdoorTemperature(); + void updateFlowTemperature(); + void updateHotWaterTemperature(); + void updateHotGasTemperature1(); + void updateHotGasTemperature2(); + void updateSourceTemperature(); + void updateRoomTemperatureFEK(); + void updateReturnTemperature(); + void updateSolarCollectorTemperature(); + void updateSolarStorageTankTemperature(); + void updateStorageTankTemperature(); + void updateExternalHeatSourceTemperature(); + void updateHeatingEnergy(); + void updateHotWaterEnergy(); + void updateConsumedEnergyHeating(); + void updateConsumedEnergyHotWater(); + void updateOperatingMode(); + void updateSystemStatus(); + void updateSgReadyState(); + void updateSgReadyActive(); + void updateSgReadyInputOne(); + void updateSgReadyInputTwo(); signals: void initializationFinished(); void outdoorTemperatureChanged(float outdoorTemperature); + void flowTemperatureChanged(float flowTemperature); + void hotWaterTemperatureChanged(float hotWaterTemperature); + void hotGasTemperature1Changed(float hotGasTemperature1); + void hotGasTemperature2Changed(float hotGasTemperature2); + void SourceTemperatureChanged(float SourceTemperature); + void roomTemperatureFEKChanged(float roomTemperatureFEK); + void returnTemperatureChanged(float returnTemperature); + void solarCollectorTemperatureChanged(float solarCollectorTemperature); + void solarStorageTankTemperatureChanged(float solarStorageTankTemperature); + void storageTankTemperatureChanged(float storageTankTemperature); + void externalHeatSourceTemperatureChanged(float externalHeatSourceTemperature); + void heatingEnergyChanged(quint32 heatingEnergy); + void hotWaterEnergyChanged(quint32 hotWaterEnergy); + void consumedEnergyHeatingChanged(quint32 consumedEnergyHeating); + void consumedEnergyHotWaterChanged(quint32 consumedEnergyHotWater); + void operatingModeChanged(OperatingMode operatingMode); + void systemStatusChanged(quint16 systemStatus); + void sgReadyStateChanged(SmartGridState sgReadyState); + void sgReadyActiveChanged(quint16 sgReadyActive); + void sgReadyInputOneChanged(quint16 sgReadyInputOne); + void sgReadyInputTwoChanged(quint16 sgReadyInputTwo); protected: QModbusReply *readOutdoorTemperature(); + QModbusReply *readFlowTemperature(); + QModbusReply *readHotWaterTemperature(); + QModbusReply *readHotGasTemperature1(); + QModbusReply *readHotGasTemperature2(); + QModbusReply *readSourceTemperature(); + QModbusReply *readRoomTemperatureFEK(); + QModbusReply *readReturnTemperature(); + QModbusReply *readSolarCollectorTemperature(); + QModbusReply *readSolarStorageTankTemperature(); + QModbusReply *readStorageTankTemperature(); + QModbusReply *readExternalHeatSourceTemperature(); + QModbusReply *readHeatingEnergy(); + QModbusReply *readHotWaterEnergy(); + QModbusReply *readConsumedEnergyHeating(); + QModbusReply *readConsumedEnergyHotWater(); + QModbusReply *readOperatingMode(); + QModbusReply *readSystemStatus(); + QModbusReply *readSgReadyState(); + QModbusReply *readSgReadyActive(); + QModbusReply *readSgReadyInputOne(); + QModbusReply *readSgReadyInputTwo(); float m_outdoorTemperature = 0; + float m_flowTemperature = 0; + float m_hotWaterTemperature = 0; + float m_hotGasTemperature1 = 0; + float m_hotGasTemperature2 = 0; + float m_SourceTemperature = 0; + float m_roomTemperatureFEK = 0; + float m_returnTemperature = 0; + float m_solarCollectorTemperature = 0; + float m_solarStorageTankTemperature = 0; + float m_storageTankTemperature = 0; + float m_externalHeatSourceTemperature = 0; + quint32 m_heatingEnergy = 0; + quint32 m_hotWaterEnergy = 0; + quint32 m_consumedEnergyHeating = 0; + quint32 m_consumedEnergyHotWater = 0; + OperatingMode m_operatingMode = OperatingModeStandby; + quint16 m_systemStatus = 0; + SmartGridState m_sgReadyState = SmartGridStateModeTwo; + quint16 m_sgReadyActive = 0; + quint16 m_sgReadyInputOne = 0; + quint16 m_sgReadyInputTwo = 0; private: quint16 m_slaveId = 1; @@ -72,6 +261,7 @@ private: void verifyInitFinished(); + }; QDebug operator<<(QDebug debug, StiebelEltronModbusConnection *stiebelEltronModbusConnection); From 374b107c10bef2c465b315ce68c189d2a2fbfd62 Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Thu, 17 Feb 2022 15:10:38 +0100 Subject: [PATCH 26/42] Added SG Ready Support --- .../integrationpluginstiebeleltron.cpp | 146 ++++++++++++++---- stiebeleltron/stiebel-eltron-registers.json | 40 ++--- .../stiebeleltronmodbusconnection.cpp | 117 ++++---------- stiebeleltron/stiebeleltronmodbusconnection.h | 43 ++---- 4 files changed, 176 insertions(+), 170 deletions(-) diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index 46c1c13..985fec7 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -303,8 +303,8 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { connect( connection, &StiebelEltronModbusConnection::sgReadyStateChanged, this, - [thing](StiebelEltronModbusConnection::SmartGridState - smartGridState) { + [thing]( + StiebelEltronModbusConnection::SmartGridState smartGridState) { qCDebug(dcStiebelEltron()) << thing << "SG Ready activation changed" << smartGridState; switch (smartGridState) { @@ -379,52 +379,130 @@ void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { Thing *thing = info->thing(); StiebelEltronModbusConnection *connection = m_connections.value(thing); - - if (!connection->connected()) { - qCWarning(dcStiebelEltron()) << "Could not execute action. The modbus connection is currently not available."; + qCWarning(dcStiebelEltron()) + << "Could not execute action. The modbus connection is currently " + "not available."; info->finish(Thing::ThingErrorHardwareNotAvailable); return; } // Got this from StiebelEltron plugin, not sure if necessary - if (thing->thingClassId() != stiebelEltronThingClassId) { + if (thing->thingClassId() != stiebelEltronThingClassId) { info->finish(Thing::ThingErrorNoError); } - - if (info->action().actionTypeId() == stiebelEltronSgReadyActiveActionTypeId) { - bool sgReadyActiveBool = info->action().paramValue(stiebelEltronSgReadyActiveActionSgReadyActiveParamTypeId).toBool(); - qCDebug(dcStiebelEltron()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params(); - qCDebug(dcStiebelEltron()) << "Value: " << sgReadyActiveBool; - - QModbusReply *reply = connection->setSgReadyActive(sgReadyActiveBool); - if (!reply) { - qCWarning(dcStiebelEltron()) << "Execute action failed because the reply could not be created."; - info->finish(Thing::ThingErrorHardwareFailure); - return; - } + if (info->action().actionTypeId() == + stiebelEltronSgReadyActiveActionTypeId) { + bool sgReadyActiveBool = + info->action() + .paramValue( + stiebelEltronSgReadyActiveActionSgReadyActiveParamTypeId) + .toBool(); + qCDebug(dcStiebelEltron()) + << "Execute action" << info->action().actionTypeId().toString() + << info->action().params(); + qCDebug(dcStiebelEltron()) << "Value: " << sgReadyActiveBool; - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, info, [info, reply, sgReadyActiveBool]{ - if (reply->error() != QModbusDevice::NoError) { - qCWarning(dcStiebelEltron()) << "Set SG ready activation finished with error" << reply->errorString(); - info->finish(Thing::ThingErrorHardwareFailure); - return; - } + QModbusReply *reply = connection->setSgReadyActive(sgReadyActiveBool); + if (!reply) { + qCWarning(dcStiebelEltron()) << "Execute action failed because the " + "reply could not be created."; + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + connect(reply, &QModbusReply::finished, reply, + &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, info, + [info, reply, sgReadyActiveBool] { + if (reply->error() != QModbusDevice::NoError) { + qCWarning(dcStiebelEltron()) + << "Set SG ready activation finished with error" + << reply->errorString(); + info->finish(Thing::ThingErrorHardwareFailure); + return; + } - qCDebug(dcStiebelEltron()) << "Execute action finished successfully" << info->action().actionTypeId().toString() << info->action().params(); - info->thing()->setStateValue(stiebelEltronSgReadyActiveStateTypeId, sgReadyActiveBool); - info->finish(Thing::ThingErrorNoError); - }); + qCDebug(dcStiebelEltron()) + << "Execute action finished successfully" + << info->action().actionTypeId().toString() + << info->action().params(); + info->thing()->setStateValue( + stiebelEltronSgReadyActiveStateTypeId, + sgReadyActiveBool); + info->finish(Thing::ThingErrorNoError); + }); - connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltron()) << "Modbus reply error occurred while execute action" << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); + connect(reply, &QModbusReply::errorOccurred, this, + [reply](QModbusDevice::Error error) { + qCWarning(dcStiebelEltron()) + << "Modbus reply error occurred while execute action" + << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else if (info->action().actionTypeId() == + stiebelEltronSgReadyModeActionTypeId) { + QString sgReadyModeString = + info->action() + .paramValue( + stiebelEltronSgReadyModeActionSgReadyModeParamTypeId) + .toString(); + qCDebug(dcStiebelEltron()) + << "Execute action" << info->action().actionTypeId().toString() + << info->action().params(); + StiebelEltronModbusConnection::SmartGridState sgReadyState; + if (sgReadyModeString == "Mode 1") { + sgReadyState = + StiebelEltronModbusConnection::SmartGridStateModeOne; + } else if (sgReadyModeString == "Mode 2") { + sgReadyState = + StiebelEltronModbusConnection::SmartGridStateModeTwo; + } else if (sgReadyModeString == "Mode 3") { + sgReadyState = + StiebelEltronModbusConnection::SmartGridStateModeThree; + } else { + sgReadyState = + StiebelEltronModbusConnection::SmartGridStateModeFour; + } + + QModbusReply *reply = connection->setSgReadyState(sgReadyState); + if (!reply) { + qCWarning(dcStiebelEltron()) << "Execute action failed because the " + "reply could not be created."; + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + connect(reply, &QModbusReply::finished, reply, + &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, info, + [info, reply, sgReadyModeString] { + if (reply->error() != QModbusDevice::NoError) { + qCWarning(dcStiebelEltron()) + << "Set SG ready mode finished with error" + << reply->errorString(); + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + qCDebug(dcStiebelEltron()) + << "Execute action finished successfully" + << info->action().actionTypeId().toString() + << info->action().params(); + info->thing()->setStateValue( + stiebelEltronSgReadyModeStateTypeId, sgReadyModeString); + info->finish(Thing::ThingErrorNoError); + }); + + connect(reply, &QModbusReply::errorOccurred, this, + [reply](QModbusDevice::Error error) { + qCWarning(dcStiebelEltron()) + << "Modbus reply error occurred while execute action" + << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); } - info->finish(Thing::ThingErrorNoError); } diff --git a/stiebeleltron/stiebel-eltron-registers.json b/stiebeleltron/stiebel-eltron-registers.json index 6fd0877..ba53e04 100644 --- a/stiebeleltron/stiebel-eltron-registers.json +++ b/stiebeleltron/stiebel-eltron-registers.json @@ -36,19 +36,23 @@ "values": [ { "key": "ModeOne", - "value": 1 + "value": 1, + "comment": "0x00000001" }, { "key": "ModeTwo", - "value": 2 + "value": 0, + "comment": "0x00000000" }, { "key": "ModeThree", - "value": 3 + "value": 65536, + "comment": "0x00010000" }, { "key": "ModeFour", - "value": 4 + "value": 65537, + "comment": "0x00010001" } ] } @@ -282,15 +286,14 @@ "access": "RO" }, { - "id": "sgReadyState", + "id": "sgReadyStateRO", "address": 5000, "size": 1, "type": "uint16", - "enum": "SmartGridState", "registerType": "inputRegister", "readSchedule": "update", "description": "Smart grid status", - "defaultValue": "SmartGridStateModeTwo", + "defaultValue": 3, "access": "RO" }, { @@ -305,27 +308,16 @@ "access": "RW" }, { - "id": "sgReadyInputOne", + "id": "sgReadyState", "address": 4001, - "size": 1, - "type": "uint16", + "size": 2, + "type": "uint32", "registerType": "holdingRegister", + "enum": "SmartGridState", "readSchedule": "update", - "description": "SG Ready Input 1", - "defaultValue": 0, - "access": "RW" - }, - { - "id": "sgReadyInputTwo", - "address": 4002, - "size": 1, - "type": "uint16", - "registerType": "holdingRegister", - "readSchedule": "update", - "description": "SG Read Input 2", - "defaultValue": 0, + "description": "SG Ready mode", + "defaultValue": "SmartGridStateModeThree", "access": "RW" } - ] } diff --git a/stiebeleltron/stiebeleltronmodbusconnection.cpp b/stiebeleltron/stiebeleltronmodbusconnection.cpp index a7bc246..9b518b6 100644 --- a/stiebeleltron/stiebeleltronmodbusconnection.cpp +++ b/stiebeleltron/stiebeleltronmodbusconnection.cpp @@ -131,9 +131,9 @@ quint16 StiebelEltronModbusConnection::systemStatus() const return m_systemStatus; } -StiebelEltronModbusConnection::SmartGridState StiebelEltronModbusConnection::sgReadyState() const +quint16 StiebelEltronModbusConnection::sgReadyStateRO() const { - return m_sgReadyState; + return m_sgReadyStateRO; } quint16 StiebelEltronModbusConnection::sgReadyActive() const @@ -150,34 +150,20 @@ QModbusReply *StiebelEltronModbusConnection::setSgReadyActive(quint16 sgReadyAct return sendWriteRequest(request, m_slaveId); } -quint16 StiebelEltronModbusConnection::sgReadyInputOne() const +StiebelEltronModbusConnection::SmartGridState StiebelEltronModbusConnection::sgReadyState() const { - return m_sgReadyInputOne; + return m_sgReadyState; } -QModbusReply *StiebelEltronModbusConnection::setSgReadyInputOne(quint16 sgReadyInputOne) +QModbusReply *StiebelEltronModbusConnection::setSgReadyState(SmartGridState sgReadyState) { - QVector values = ModbusDataUtils::convertFromUInt16(sgReadyInputOne); - qCDebug(dcStiebelEltronModbusConnection()) << "--> Write \"SG Ready Input 1\" register:" << 4001 << "size:" << 1 << values; + QVector values = ModbusDataUtils::convertFromUInt32(static_cast(sgReadyState), ModbusDataUtils::ByteOrderBigEndian); + qCDebug(dcStiebelEltronModbusConnection()) << "--> Write \"SG Ready mode\" register:" << 4001 << "size:" << 2 << values; QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4001, values.count()); request.setValues(values); return sendWriteRequest(request, m_slaveId); } -quint16 StiebelEltronModbusConnection::sgReadyInputTwo() const -{ - return m_sgReadyInputTwo; -} - -QModbusReply *StiebelEltronModbusConnection::setSgReadyInputTwo(quint16 sgReadyInputTwo) -{ - QVector values = ModbusDataUtils::convertFromUInt16(sgReadyInputTwo); - qCDebug(dcStiebelEltronModbusConnection()) << "--> Write \"SG Read Input 2\" register:" << 4002 << "size:" << 1 << values; - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4002, values.count()); - request.setValues(values); - return sendWriteRequest(request, m_slaveId); -} - void StiebelEltronModbusConnection::initialize() { // No init registers defined. Nothing to be done and we are finished. @@ -204,10 +190,9 @@ void StiebelEltronModbusConnection::update() updateConsumedEnergyHotWater(); updateOperatingMode(); updateSystemStatus(); - updateSgReadyState(); + updateSgReadyStateRO(); updateSgReadyActive(); - updateSgReadyInputOne(); - updateSgReadyInputTwo(); + updateSgReadyState(); } void StiebelEltronModbusConnection::updateOutdoorTemperature() @@ -804,11 +789,11 @@ void StiebelEltronModbusConnection::updateSystemStatus() } } -void StiebelEltronModbusConnection::updateSgReadyState() +void StiebelEltronModbusConnection::updateSgReadyStateRO() { // Update registers from Smart grid status qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Smart grid status\" register:" << 5000 << "size:" << 1; - QModbusReply *reply = readSgReadyState(); + QModbusReply *reply = readSgReadyStateRO(); if (reply) { if (!reply->isFinished()) { connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); @@ -817,10 +802,10 @@ void StiebelEltronModbusConnection::updateSgReadyState() const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Smart grid status\" register" << 5000 << "size:" << 1 << values; - SmartGridState receivedSgReadyState = static_cast(ModbusDataUtils::convertToUInt16(values)); - if (m_sgReadyState != receivedSgReadyState) { - m_sgReadyState = receivedSgReadyState; - emit sgReadyStateChanged(m_sgReadyState); + quint16 receivedSgReadyStateRO = ModbusDataUtils::convertToUInt16(values); + if (m_sgReadyStateRO != receivedSgReadyStateRO) { + m_sgReadyStateRO = receivedSgReadyStateRO; + emit sgReadyStateROChanged(m_sgReadyStateRO); } } }); @@ -870,11 +855,11 @@ void StiebelEltronModbusConnection::updateSgReadyActive() } } -void StiebelEltronModbusConnection::updateSgReadyInputOne() +void StiebelEltronModbusConnection::updateSgReadyState() { - // Update registers from SG Ready Input 1 - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"SG Ready Input 1\" register:" << 4001 << "size:" << 1; - QModbusReply *reply = readSgReadyInputOne(); + // Update registers from SG Ready mode + qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"SG Ready mode\" register:" << 4001 << "size:" << 2; + QModbusReply *reply = readSgReadyState(); if (reply) { if (!reply->isFinished()) { connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); @@ -882,57 +867,24 @@ void StiebelEltronModbusConnection::updateSgReadyInputOne() if (reply->error() == QModbusDevice::NoError) { const QModbusDataUnit unit = reply->result(); const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"SG Ready Input 1\" register" << 4001 << "size:" << 1 << values; - quint16 receivedSgReadyInputOne = ModbusDataUtils::convertToUInt16(values); - if (m_sgReadyInputOne != receivedSgReadyInputOne) { - m_sgReadyInputOne = receivedSgReadyInputOne; - emit sgReadyInputOneChanged(m_sgReadyInputOne); + qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"SG Ready mode\" register" << 4001 << "size:" << 2 << values; + SmartGridState receivedSgReadyState = static_cast(ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian)); + if (m_sgReadyState != receivedSgReadyState) { + m_sgReadyState = receivedSgReadyState; + emit sgReadyStateChanged(m_sgReadyState); } } }); connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"SG Ready Input 1\" registers from" << hostAddress().toString() << error << reply->errorString(); + qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"SG Ready mode\" registers from" << hostAddress().toString() << error << reply->errorString(); emit reply->finished(); // To make sure it will be deleted }); } else { delete reply; // Broadcast reply returns immediatly } } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"SG Ready Input 1\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateSgReadyInputTwo() -{ - // Update registers from SG Read Input 2 - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"SG Read Input 2\" register:" << 4002 << "size:" << 1; - QModbusReply *reply = readSgReadyInputTwo(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"SG Read Input 2\" register" << 4002 << "size:" << 1 << values; - quint16 receivedSgReadyInputTwo = ModbusDataUtils::convertToUInt16(values); - if (m_sgReadyInputTwo != receivedSgReadyInputTwo) { - m_sgReadyInputTwo = receivedSgReadyInputTwo; - emit sgReadyInputTwoChanged(m_sgReadyInputTwo); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"SG Read Input 2\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"SG Read Input 2\" registers from" << hostAddress().toString() << errorString(); + qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"SG Ready mode\" registers from" << hostAddress().toString() << errorString(); } } @@ -1044,7 +996,7 @@ QModbusReply *StiebelEltronModbusConnection::readSystemStatus() return sendReadRequest(request, m_slaveId); } -QModbusReply *StiebelEltronModbusConnection::readSgReadyState() +QModbusReply *StiebelEltronModbusConnection::readSgReadyStateRO() { QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 5000, 1); return sendReadRequest(request, m_slaveId); @@ -1056,15 +1008,9 @@ QModbusReply *StiebelEltronModbusConnection::readSgReadyActive() return sendReadRequest(request, m_slaveId); } -QModbusReply *StiebelEltronModbusConnection::readSgReadyInputOne() +QModbusReply *StiebelEltronModbusConnection::readSgReadyState() { - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4001, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readSgReadyInputTwo() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4002, 1); + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4001, 2); return sendReadRequest(request, m_slaveId); } @@ -1097,10 +1043,9 @@ QDebug operator<<(QDebug debug, StiebelEltronModbusConnection *stiebelEltronModb debug.nospace().noquote() << " - Consumed energy hot water:" << stiebelEltronModbusConnection->consumedEnergyHotWater() << " [kWh]" << "\n"; debug.nospace().noquote() << " - Operating mode:" << stiebelEltronModbusConnection->operatingMode() << "\n"; debug.nospace().noquote() << " - System status:" << stiebelEltronModbusConnection->systemStatus() << "\n"; - debug.nospace().noquote() << " - Smart grid status:" << stiebelEltronModbusConnection->sgReadyState() << "\n"; + debug.nospace().noquote() << " - Smart grid status:" << stiebelEltronModbusConnection->sgReadyStateRO() << "\n"; debug.nospace().noquote() << " - SG ready active:" << stiebelEltronModbusConnection->sgReadyActive() << "\n"; - debug.nospace().noquote() << " - SG Ready Input 1:" << stiebelEltronModbusConnection->sgReadyInputOne() << "\n"; - debug.nospace().noquote() << " - SG Read Input 2:" << stiebelEltronModbusConnection->sgReadyInputTwo() << "\n"; + debug.nospace().noquote() << " - SG Ready mode:" << stiebelEltronModbusConnection->sgReadyState() << "\n"; return debug.quote().space(); } diff --git a/stiebeleltron/stiebeleltronmodbusconnection.h b/stiebeleltron/stiebeleltronmodbusconnection.h index d6a793e..e42c8b5 100644 --- a/stiebeleltron/stiebeleltronmodbusconnection.h +++ b/stiebeleltron/stiebeleltronmodbusconnection.h @@ -60,9 +60,8 @@ public: RegisterConsumedEnergyHeating = 3511, RegisterConsumedEnergyHotWater = 3514, RegisterSgReadyActive = 4000, - RegisterSgReadyInputOne = 4001, - RegisterSgReadyInputTwo = 4002, - RegisterSgReadyState = 5000 + RegisterSgReadyState = 4001, + RegisterSgReadyStateRO = 5000 }; Q_ENUM(Registers) @@ -78,9 +77,9 @@ public: enum SmartGridState { SmartGridStateModeOne = 1, - SmartGridStateModeTwo = 2, - SmartGridStateModeThree = 3, - SmartGridStateModeFour = 4 + SmartGridStateModeTwo = 0, + SmartGridStateModeThree = 65536, + SmartGridStateModeFour = 65537 }; Q_ENUM(SmartGridState) @@ -142,19 +141,15 @@ public: quint16 systemStatus() const; /* Smart grid status - Address: 5000, Size: 1 */ - SmartGridState sgReadyState() const; + quint16 sgReadyStateRO() const; /* SG ready active - Address: 4000, Size: 1 */ quint16 sgReadyActive() const; QModbusReply *setSgReadyActive(quint16 sgReadyActive); - /* SG Ready Input 1 - Address: 4001, Size: 1 */ - quint16 sgReadyInputOne() const; - QModbusReply *setSgReadyInputOne(quint16 sgReadyInputOne); - - /* SG Read Input 2 - Address: 4002, Size: 1 */ - quint16 sgReadyInputTwo() const; - QModbusReply *setSgReadyInputTwo(quint16 sgReadyInputTwo); + /* SG Ready mode - Address: 4001, Size: 2 */ + SmartGridState sgReadyState() const; + QModbusReply *setSgReadyState(SmartGridState sgReadyState); virtual void initialize(); virtual void update(); @@ -177,10 +172,9 @@ public: void updateConsumedEnergyHotWater(); void updateOperatingMode(); void updateSystemStatus(); - void updateSgReadyState(); + void updateSgReadyStateRO(); void updateSgReadyActive(); - void updateSgReadyInputOne(); - void updateSgReadyInputTwo(); + void updateSgReadyState(); signals: void initializationFinished(); @@ -203,10 +197,9 @@ signals: void consumedEnergyHotWaterChanged(quint32 consumedEnergyHotWater); void operatingModeChanged(OperatingMode operatingMode); void systemStatusChanged(quint16 systemStatus); - void sgReadyStateChanged(SmartGridState sgReadyState); + void sgReadyStateROChanged(quint16 sgReadyStateRO); void sgReadyActiveChanged(quint16 sgReadyActive); - void sgReadyInputOneChanged(quint16 sgReadyInputOne); - void sgReadyInputTwoChanged(quint16 sgReadyInputTwo); + void sgReadyStateChanged(SmartGridState sgReadyState); protected: QModbusReply *readOutdoorTemperature(); @@ -227,10 +220,9 @@ protected: QModbusReply *readConsumedEnergyHotWater(); QModbusReply *readOperatingMode(); QModbusReply *readSystemStatus(); - QModbusReply *readSgReadyState(); + QModbusReply *readSgReadyStateRO(); QModbusReply *readSgReadyActive(); - QModbusReply *readSgReadyInputOne(); - QModbusReply *readSgReadyInputTwo(); + QModbusReply *readSgReadyState(); float m_outdoorTemperature = 0; float m_flowTemperature = 0; @@ -250,10 +242,9 @@ protected: quint32 m_consumedEnergyHotWater = 0; OperatingMode m_operatingMode = OperatingModeStandby; quint16 m_systemStatus = 0; - SmartGridState m_sgReadyState = SmartGridStateModeTwo; + quint16 m_sgReadyStateRO = 3; quint16 m_sgReadyActive = 0; - quint16 m_sgReadyInputOne = 0; - quint16 m_sgReadyInputTwo = 0; + SmartGridState m_sgReadyState = SmartGridStateModeThree; private: quint16 m_slaveId = 1; From 06ef2eb01a23100d08baa641ad5b2e0582238c7a Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Thu, 17 Feb 2022 15:47:38 +0100 Subject: [PATCH 27/42] Renamed Silent mode and added meta.json --- .../integrationpluginstiebeleltron.cpp | 2 +- .../integrationpluginstiebeleltron.json | 58 ++++++++---------- stiebeleltron/meta.json | 14 +++++ stiebeleltron/stiebel-eltron.png | Bin 0 -> 3062 bytes 4 files changed, 39 insertions(+), 35 deletions(-) create mode 100644 stiebeleltron/meta.json create mode 100644 stiebeleltron/stiebel-eltron.png diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index 985fec7..2a425d3 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -296,7 +296,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { systemStatus & (1 << 9)); thing->setStateValue(stiebelEltronSilentModeStateTypeId, systemStatus & (1 << 10)); - thing->setStateValue(stiebelEltronPowerStateTypeId, + thing->setStateValue(stiebelEltronSilentMode2StateTypeId, systemStatus & (1 << 11)); }); diff --git a/stiebeleltron/integrationpluginstiebeleltron.json b/stiebeleltron/integrationpluginstiebeleltron.json index 58e3088..ad21a21 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.json +++ b/stiebeleltron/integrationpluginstiebeleltron.json @@ -96,37 +96,7 @@ "type": "double", "defaultValue": 0, "suggestLogging": true - }, - { - "id": "5833ceb6-5e7c-437b-a44a-e9f5eb42b6ac", - "name": "sourceTemperature", - "displayName": "Source temperature", - "displayNameEvent": "Source temperature changed", - "unit": "DegreeCelsius", - "type": "double", - "defaultValue": 0, - "suggestLogging": true - }, - { - "id": "d1959819-9e56-47f7-b619-a393ce50738a", - "name": "roomTemperature1", - "displayName": "Room temperature 1", - "displayNameEvent": "Room temperature 1 changed", - "unit": "DegreeCelsius", - "type": "double", - "defaultValue": 0, - "suggestLogging": true - }, - { - "id": "04ac741c-5277-4806-be73-576a164ecb46", - "name": "roomTemperature2", - "displayName": "Room temperature 1", - "displayNameEvent": "Room temperature changed", - "unit": "DegreeCelsius", - "type": "double", - "defaultValue": 0, - "suggestLogging": true - }, + }, { "id": "43dd25b3-8782-4faa-a9e0-2fb10892fa0c", "name": "storageTankTemperature", @@ -297,9 +267,9 @@ }, { "id": "d77a30d9-98f7-40ec-bc55-77c547f24145", - "name": "power", - "displayName": "Power", - "displayNameEvent": "Power status changed", + "name": "silentMode2", + "displayName": "Silent mode 2 (Off)", + "displayNameEvent": "Silent mode 2 status changed", "type": "bool", "defaultValue": false, "suggestLogging": true @@ -331,6 +301,26 @@ "writable": true, "defaultValue": "Mode 3", "suggestLogging": true + }, + { + "id": "5833ceb6-5e7c-437b-a44a-e9f5eb42b6ac", + "name": "sourceTemperature", + "displayName": "Source temperature (tbd)", + "displayNameEvent": "Source temperature changed", + "unit": "DegreeCelsius", + "type": "double", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "d1959819-9e56-47f7-b619-a393ce50738a", + "name": "roomTemperature1", + "displayName": "Room temperature (tbd)", + "displayNameEvent": "Room temperature changed", + "unit": "DegreeCelsius", + "type": "double", + "defaultValue": 0, + "suggestLogging": true } ], "actionTypes": [ ] diff --git a/stiebeleltron/meta.json b/stiebeleltron/meta.json new file mode 100644 index 0000000..80add71 --- /dev/null +++ b/stiebeleltron/meta.json @@ -0,0 +1,14 @@ +{ + "title": "Stiebel Eltron", + "tagline": "Integrate Stiebel Eltron heat pumps into nymea.", + "icon": "stiebel-eltron.png", + "stability": "community", + "offline": true, + "technologies": [ + "network", + "modbus" + ], + "categories": [ + "heating" + ] +} diff --git a/stiebeleltron/stiebel-eltron.png b/stiebeleltron/stiebel-eltron.png new file mode 100644 index 0000000000000000000000000000000000000000..2dfbe5c414b01f7f9b46986a04ced63e6052c3d6 GIT binary patch literal 3062 zcmb7`S5y<)5{82XjnY-52Ss}5pwdM_ic-Xalz@~_4n-h_qBNx`h;$H;P!$LP6@*X| zluiht2TTw}L&Ok3Vt|B_%em`5+=qJ}?!(ON^{>7DnTI`leb4M{%z2NA9RmOWyp|TG z_5c9a-2VCg(F6NgPAQGCUx2|DjxYd#ujlXJ%2nnQ2LO&&Tbi2Oig-nz(+~PiKGhZC z6s)0szzbM@CquRF=dz6Y)OACB>82Nlq#<&R@!DCq%3*HP@6INLABl>+q7!0sD+I^0E0@HO2L{H6zf*b~HD@qA%dre(x9)7w)(Z0{L9hDm_qu#qkhP!1(3=Q%c9~ z?v~ul=K`!PeRGT5nwW$F08!;q2mjg0VDC5KPxisM1cT+x?HU{auw`n<4X8|P;Q{!a zQ9XFc=_wA7A-tgZA1QJ&s+!hTPx}E{&o>}!$Nu5i^sHhzL3>^KYHodsz&MMxdQuQt zDD%twJSCmMaye^%x-mUpU4@>gYIQnP`v3Dr`#Ux8XA_pqE)`d@eiyYd4z;0Y9 zvYshNAd$a(tJ>#AeBy;p;2OZVb?uW|*`;2F?`KU+*E`yVe*MZKglvjMa;blZ@%O9)_f_nS*Vg3to@!hG7fg}Tho2%=uHogW*b0Cq% zEG2A06>yqYpUgDVLtCGRZ0_1)$#4jSnA+=MXJ>=|a`DOUr6s=)S@@M&b5<#b_VeL#pQ+mpoXRvDCjUq_h z9d|TKOZCY7O2Ue|n{X)87IN%shsoQWKvLhp6^ay4s&IR{$VDpyJg6K>&(0LHQUgvm?R+A0o(#F`* z4B1-CK8>Eqe5ew=bUDy2g+4p>ZgZx&j@hi1a+zHyGIY*ohfb&e#G>ZZ9cpvWI1?D; zj>OD^qu!08AIzx>I@YiUtRc~u=x7}*dEovxm{Ur53jy(BI+eccu#h8*V~`(as|g?P z<~Zrw>7CqLK2Le_!L?w4$()kNKLQ;ZuZT4&!Ho*Fn&-^tj!L{!!*OYQA-7Mp2B?W&V~|K_Gf{Zu0<#{!ZE zg%GEO`Cw#iAHU=uzz`=9AimJ)FtDOb(?t+z-WVP8{Oc)=_j6Yb`(z9A)o6{vPs{54 zY4;4SSSiPwpdKlvcwpy=@aT;inF|Bnjbl8=Z>@x6NT0%MG34rFUb0jgk`^Ci8Ii?H zZrzwDs#Z8=4Y`S+7A7ZzR>dEx0il23EOmY=&V^yXiwxGJ8DL~|at49V*Qu%1RM^a6 zJzC3|#X3(8zj7XoI8h=gofLDRt}zcs@s;Iz;j4tP{@+SjQ1bTY!$jBy>tzsX2fAHHxnkR+yB zVR6%kOKd2qy#njocj+S0Mc<(=V!g(%{FZjhk8tS@ghfvYT)2s)%knd+wF^i zwSHop63SBIi_>@HW}?&F|{P9X-y zfT;Yw;Y%}LICREDxJnhGGVS$=b2fyO$V^y16`svAXFx{5JF^@Yi`NIv$t-=~UAd2z z`kqy;5Y{eW(?H!(F4wY`$qksm5d8EG>ECzB zCe{=Eqes}d2y9z@czZE5{&lJrLmO2|m+kY=jcY_A4U}i=%Y7bu15%9w^`w$jY|o=r z$;om&_j z9SwR_(95L^t@G}#|oVcbUd$O}j9Vzs*C8;UiUMMz82tIFkQm5}~@hykT=b2n`dL zb*JAF@8C4F7NLDO6uaU;!|=+QcR0q*I5ED25n(Qt2alPI+in}&!zGi*^e}dcC(Ip1 zMIw=9{h>Whm(eFeH!<> zRwDA|wqGzwJ9Pw35Hh z`!dfYaFhF7q8A@b!(~H|Or*i* zF*+rL+$-*nO!UN*!@VHWKL&b3X6E`I-l(0jQa#$L`9pXdw3C+BEv2_=il7GhUwXBB zO7hd|?s`cvOf51rs6^y}RdkpaMg8ql+wf|W?Y|1WcN}bwWHAcgf(Ca~p_x!eOlPO! z+e^Tk@z)BVj(KUVdj;!}6YV1T{FdM_Uvh~T6HBV@Ujqq+YT;JCwfRcjO2Roe;AUWF zUl?zAj57LaISmDz($g1}Qx=rQmB~_2!m%p|WgVVO`?jcZOZJi8?z|Sq<`w zX59(ex{q0}UCVve$R5a2@+w61ln;)gxdpS-s^wd7k1}}kS~SQzup+xd|6bA=+zDG! zlv1|5v+?Z1v6T0?{sL0v+?fL7h>6yXa54NVIRZC*1TBPEN9PG8_w085tOPqdULVYyUzKXnU;m=e67Q$f?@RlYY+vKVV8IBU`vzV zpN~7!^P3qbH1B(17dDSpKv$AuxX+I0X6%X;H>7`I6Ey+-!$SKoDU&)AD+>4;_fJf? zwduB}2NwkZN~AcOB^(V;K^E72KX$wS-*D=&_c!Y@MgAKy{|9&eAJQH_ ZkH~EWLo?~0`ydanG_x_SzkKh>zW^~P510S| literal 0 HcmV?d00001 From 27cd789b7fcc5ef62a92ed995385ca57eec0b692 Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Thu, 17 Feb 2022 16:20:31 +0100 Subject: [PATCH 28/42] Clean code --- .../integrationpluginstiebeleltron.cpp | 530 +++++++----------- 1 file changed, 217 insertions(+), 313 deletions(-) diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index 2a425d3..2f0bac5 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -38,64 +38,56 @@ IntegrationPluginStiebelEltron::IntegrationPluginStiebelEltron() {} void IntegrationPluginStiebelEltron::discoverThings(ThingDiscoveryInfo *info) { if (!hardwareManager()->networkDeviceDiscovery()->available()) { - qCWarning(dcStiebelEltron()) - << "The network discovery is not available on this platform."; - info->finish( - Thing::ThingErrorUnsupportedFeature, - QT_TR_NOOP("The network device discovery is not available.")); + qCWarning(dcStiebelEltron()) << "The network discovery is not available on this platform."; + info->finish(Thing::ThingErrorUnsupportedFeature, + QT_TR_NOOP("The network device discovery is not available.")); return; } NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover(); - connect( - discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=]() { - foreach (const NetworkDeviceInfo &networkDeviceInfo, - discoveryReply->networkDeviceInfos()) { - qCDebug(dcStiebelEltron()) << "Found" << networkDeviceInfo; + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=]() { + foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) { + qCDebug(dcStiebelEltron()) << "Found" << networkDeviceInfo; - QString title; - if (networkDeviceInfo.hostName().isEmpty()) { - title = networkDeviceInfo.address().toString(); - } else { - title = networkDeviceInfo.hostName() + " (" + - networkDeviceInfo.address().toString() + ")"; - } - - QString description; - if (networkDeviceInfo.macAddressManufacturer().isEmpty()) { - description = networkDeviceInfo.macAddress(); - } else { - description = networkDeviceInfo.macAddress() + " (" + - networkDeviceInfo.macAddressManufacturer() + - ")"; - } - - ThingDescriptor descriptor(stiebelEltronThingClassId, title, - description); - ParamList params; - params << Param(stiebelEltronThingIpAddressParamTypeId, - networkDeviceInfo.address().toString()); - params << Param(stiebelEltronThingMacAddressParamTypeId, - networkDeviceInfo.macAddress()); - descriptor.setParams(params); - - // Check if we already have set up this device - Things existingThings = myThings().filterByParam( - stiebelEltronThingMacAddressParamTypeId, - networkDeviceInfo.macAddress()); - if (existingThings.count() == 1) { - qCDebug(dcStiebelEltron()) - << "This connection already exists in the system:" - << networkDeviceInfo; - descriptor.setThingId(existingThings.first()->id()); - } - - info->addThingDescriptor(descriptor); + QString title; + if (networkDeviceInfo.hostName().isEmpty()) { + title = networkDeviceInfo.address().toString(); + } else { + title = networkDeviceInfo.hostName() + " (" + + networkDeviceInfo.address().toString() + ")"; } - info->finish(Thing::ThingErrorNoError); - }); + QString description; + if (networkDeviceInfo.macAddressManufacturer().isEmpty()) { + description = networkDeviceInfo.macAddress(); + } else { + description = networkDeviceInfo.macAddress() + " (" + + networkDeviceInfo.macAddressManufacturer() + ")"; + } + + ThingDescriptor descriptor(stiebelEltronThingClassId, title, description); + ParamList params; + params << Param(stiebelEltronThingIpAddressParamTypeId, + networkDeviceInfo.address().toString()); + params << Param(stiebelEltronThingMacAddressParamTypeId, + networkDeviceInfo.macAddress()); + descriptor.setParams(params); + + // Check if we already have set up this device + Things existingThings = myThings().filterByParam( + stiebelEltronThingMacAddressParamTypeId, networkDeviceInfo.macAddress()); + if (existingThings.count() == 1) { + qCDebug(dcStiebelEltron()) + << "This connection already exists in the system:" << networkDeviceInfo; + descriptor.setThingId(existingThings.first()->id()); + } + + info->addThingDescriptor(descriptor); + } + + info->finish(Thing::ThingErrorNoError); + }); } void IntegrationPluginStiebelEltron::startMonitoringAutoThings() {} @@ -105,235 +97,175 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { qCDebug(dcStiebelEltron()) << "Setup" << thing << thing->params(); if (thing->thingClassId() == stiebelEltronThingClassId) { - QHostAddress address( - thing->paramValue(stiebelEltronThingIpAddressParamTypeId) - .toString()); - quint16 port = - thing->paramValue(stiebelEltronThingPortParamTypeId).toUInt(); - quint16 slaveId = - thing->paramValue(stiebelEltronThingSlaveIdParamTypeId).toUInt(); + QHostAddress address(thing->paramValue(stiebelEltronThingIpAddressParamTypeId).toString()); + quint16 port = thing->paramValue(stiebelEltronThingPortParamTypeId).toUInt(); + quint16 slaveId = thing->paramValue(stiebelEltronThingSlaveIdParamTypeId).toUInt(); StiebelEltronModbusConnection *connection = new StiebelEltronModbusConnection(address, port, slaveId, this); - connect( - connection, &StiebelEltronModbusConnection::connectionStateChanged, - this, [thing, connection](bool status) { - qCDebug(dcStiebelEltron()) - << "Connected changed to" << status << "for" << thing; - if (status) { - connection->update(); - } + connect(connection, &StiebelEltronModbusConnection::connectionStateChanged, this, + [thing, connection](bool status) { + qCDebug(dcStiebelEltron()) + << "Connected changed to" << status << "for" << thing; + if (status) { + connection->update(); + } - thing->setStateValue(stiebelEltronConnectedStateTypeId, status); - }); + thing->setStateValue(stiebelEltronConnectedStateTypeId, status); + }); - connect(connection, - &StiebelEltronModbusConnection::outdoorTemperatureChanged, this, + connect(connection, &StiebelEltronModbusConnection::outdoorTemperatureChanged, this, [thing](float outdoorTemperature) { qCDebug(dcStiebelEltron()) - << thing << "outdoor temperature changed" - << outdoorTemperature << "°C"; - thing->setStateValue( - stiebelEltronOutdoorTemperatureStateTypeId, - outdoorTemperature); + << thing << "outdoor temperature changed" << outdoorTemperature << "°C"; + thing->setStateValue(stiebelEltronOutdoorTemperatureStateTypeId, + outdoorTemperature); }); - connect( - connection, &StiebelEltronModbusConnection::flowTemperatureChanged, - this, [thing](float flowTemperature) { - qCDebug(dcStiebelEltron()) - << thing << "flow temperature changed" << flowTemperature - << "°C"; - thing->setStateValue(stiebelEltronFlowTemperatureStateTypeId, - flowTemperature); - }); + connect(connection, &StiebelEltronModbusConnection::flowTemperatureChanged, this, + [thing](float flowTemperature) { + qCDebug(dcStiebelEltron()) + << thing << "flow temperature changed" << flowTemperature << "°C"; + thing->setStateValue(stiebelEltronFlowTemperatureStateTypeId, flowTemperature); + }); - connect(connection, - &StiebelEltronModbusConnection::hotWaterTemperatureChanged, - this, [thing](float hotWaterTemperature) { + connect(connection, &StiebelEltronModbusConnection::hotWaterTemperatureChanged, this, + [thing](float hotWaterTemperature) { qCDebug(dcStiebelEltron()) - << thing << "hot water temperature changed" - << hotWaterTemperature << "°C"; - thing->setStateValue( - stiebelEltronHotWaterTemperatureStateTypeId, - hotWaterTemperature); + << thing << "hot water temperature changed" << hotWaterTemperature << "°C"; + thing->setStateValue(stiebelEltronHotWaterTemperatureStateTypeId, + hotWaterTemperature); }); - connect(connection, - &StiebelEltronModbusConnection::storageTankTemperatureChanged, - this, [thing](float storageTankTemperature) { - qCDebug(dcStiebelEltron()) - << thing << "Storage tank temperature changed" - << storageTankTemperature << "°C"; - thing->setStateValue( - stiebelEltronStorageTankTemperatureStateTypeId, - storageTankTemperature); + + connect(connection, &StiebelEltronModbusConnection::storageTankTemperatureChanged, this, + [thing](float storageTankTemperature) { + qCDebug(dcStiebelEltron()) << thing << "Storage tank temperature changed" + << storageTankTemperature << "°C"; + thing->setStateValue(stiebelEltronStorageTankTemperatureStateTypeId, + storageTankTemperature); }); - connect(connection, - &StiebelEltronModbusConnection::returnTemperatureChanged, this, + + connect(connection, &StiebelEltronModbusConnection::returnTemperatureChanged, this, [thing](float returnTemperature) { qCDebug(dcStiebelEltron()) - << thing << "return temperature changed" - << returnTemperature << "°C"; - thing->setStateValue( - stiebelEltronReturnTemperatureStateTypeId, - returnTemperature); + << thing << "return temperature changed" << returnTemperature << "°C"; + thing->setStateValue(stiebelEltronReturnTemperatureStateTypeId, + returnTemperature); }); - connect( - connection, &StiebelEltronModbusConnection::heatingEnergyChanged, - this, [thing](quint32 heatingEnergy) { - // kWh and MWh of energy are stored in two registers an read as - // an uint32. The following arithmetic splits the uint32 into - // two uint16 and sums up the MWh and kWh values. - quint32 correctedEnergy = - (heatingEnergy >> 16) + (heatingEnergy & 0xFFFF) * 1000; - qCDebug(dcStiebelEltron()) << thing << "Heating energy changed" - << correctedEnergy << "kWh"; - thing->setStateValue(stiebelEltronHeatingEnergyStateTypeId, - correctedEnergy); - }); - connect(connection, - &StiebelEltronModbusConnection::hotWaterEnergyChanged, this, + + connect(connection, &StiebelEltronModbusConnection::heatingEnergyChanged, this, + [thing](quint32 heatingEnergy) { + // kWh and MWh of energy are stored in two registers an read as + // an uint32. The following arithmetic splits the uint32 into + // two uint16 and sums up the MWh and kWh values. + quint32 correctedEnergy = + (heatingEnergy >> 16) + (heatingEnergy & 0xFFFF) * 1000; + qCDebug(dcStiebelEltron()) + << thing << "Heating energy changed" << correctedEnergy << "kWh"; + thing->setStateValue(stiebelEltronHeatingEnergyStateTypeId, correctedEnergy); + }); + + connect(connection, &StiebelEltronModbusConnection::hotWaterEnergyChanged, this, [thing](quint32 hotWaterEnergy) { // see comment in heatingEnergyChanged - quint32 correctedEnergy = (hotWaterEnergy >> 16) + - (hotWaterEnergy & 0xFFFF) * 1000; + quint32 correctedEnergy = + (hotWaterEnergy >> 16) + (hotWaterEnergy & 0xFFFF) * 1000; qCDebug(dcStiebelEltron()) - << thing << "Hot Water energy changed" - << correctedEnergy << "kWh"; - thing->setStateValue(stiebelEltronHotWaterEnergyStateTypeId, + << thing << "Hot Water energy changed" << correctedEnergy << "kWh"; + thing->setStateValue(stiebelEltronHotWaterEnergyStateTypeId, correctedEnergy); + }); + + connect(connection, &StiebelEltronModbusConnection::consumedEnergyHeatingChanged, this, + [thing](quint32 consumedEnergyHeatingEnergy) { + // see comment in heatingEnergyChanged + quint32 correctedEnergy = (consumedEnergyHeatingEnergy >> 16) + + (consumedEnergyHeatingEnergy & 0xFFFF) * 1000; + qCDebug(dcStiebelEltron()) + << thing << "Consumed energy Heating changed" << correctedEnergy << "kWh"; + thing->setStateValue(stiebelEltronConsumedEnergyHeatingStateTypeId, correctedEnergy); }); - connect(connection, - &StiebelEltronModbusConnection::consumedEnergyHeatingChanged, - this, [thing](quint32 consumedEnergyHeatingEnergy) { + + connect(connection, &StiebelEltronModbusConnection::consumedEnergyHotWaterChanged, this, + [thing](quint32 consumedEnergyHotWaterEnergy) { // see comment in heatingEnergyChanged - quint32 correctedEnergy = - (consumedEnergyHeatingEnergy >> 16) + - (consumedEnergyHeatingEnergy & 0xFFFF) * 1000; + quint32 correctedEnergy = (consumedEnergyHotWaterEnergy >> 16) + + (consumedEnergyHotWaterEnergy & 0xFFFF) * 1000; qCDebug(dcStiebelEltron()) - << thing << "Consumed energy Heating changed" - << correctedEnergy << "kWh"; - thing->setStateValue( - stiebelEltronConsumedEnergyHeatingStateTypeId, - correctedEnergy); - }); - connect(connection, - &StiebelEltronModbusConnection::consumedEnergyHotWaterChanged, - this, [thing](quint32 consumedEnergyHotWaterEnergy) { - // see comment in heatingEnergyChanged - quint32 correctedEnergy = - (consumedEnergyHotWaterEnergy >> 16) + - (consumedEnergyHotWaterEnergy & 0xFFFF) * 1000; - qCDebug(dcStiebelEltron()) - << thing << "Consumed energy hot water changed" - << correctedEnergy << "kWh"; - thing->setStateValue( - stiebelEltronConsumedEnergyHotWaterStateTypeId, - correctedEnergy); + << thing << "Consumed energy hot water changed" << correctedEnergy << "kWh"; + thing->setStateValue(stiebelEltronConsumedEnergyHotWaterStateTypeId, + correctedEnergy); }); connect( - connection, &StiebelEltronModbusConnection::operatingModeChanged, - this, - [thing]( - StiebelEltronModbusConnection::OperatingMode operatingMode) { - qCDebug(dcStiebelEltron()) - << thing << "operating mode changed " << operatingMode; + connection, &StiebelEltronModbusConnection::operatingModeChanged, this, + [thing](StiebelEltronModbusConnection::OperatingMode operatingMode) { + qCDebug(dcStiebelEltron()) << thing << "operating mode changed " << operatingMode; switch (operatingMode) { case StiebelEltronModbusConnection::OperatingModeEmergency: - thing->setStateValue( - stiebelEltronOperatingModeStateTypeId, "Emergency"); + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Emergency"); break; case StiebelEltronModbusConnection::OperatingModeStandby: - thing->setStateValue( - stiebelEltronOperatingModeStateTypeId, "Standby"); + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Standby"); break; case StiebelEltronModbusConnection::OperatingModeProgram: - thing->setStateValue( - stiebelEltronOperatingModeStateTypeId, "Program"); + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Program"); break; case StiebelEltronModbusConnection::OperatingModeComfort: - thing->setStateValue( - stiebelEltronOperatingModeStateTypeId, "Comfort"); + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Comfort"); break; case StiebelEltronModbusConnection::OperatingModeEco: - thing->setStateValue( - stiebelEltronOperatingModeStateTypeId, "Eco"); + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Eco"); break; case StiebelEltronModbusConnection::OperatingModeHotWater: - thing->setStateValue( - stiebelEltronOperatingModeStateTypeId, "Hot water"); + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Hot water"); break; } }); - connect(connection, &StiebelEltronModbusConnection::systemStatusChanged, - this, [thing](uint16_t systemStatus) { - qCDebug(dcStiebelEltron()) - << thing << "System status changed " << systemStatus; - - thing->setStateValue(stiebelEltronPumpOneStateTypeId, - systemStatus & (1 << 0)); - - thing->setStateValue(stiebelEltronPumpTwoStateTypeId, - systemStatus & (1 << 1)); - thing->setStateValue(stiebelEltronHeatingUpStateTypeId, - systemStatus & (1 << 2)); - - thing->setStateValue(stiebelEltronAuxHeatingStateTypeId, - systemStatus & (1 << 3)); - thing->setStateValue(stiebelEltronHeatingStateTypeId, - systemStatus & (1 << 4)); - thing->setStateValue(stiebelEltronHotWaterStateTypeId, - systemStatus & (1 << 5)); - thing->setStateValue(stiebelEltronCompressorStateTypeId, - systemStatus & (1 << 6)); - thing->setStateValue(stiebelEltronSummerModeStateTypeId, - systemStatus & (1 << 7)); - thing->setStateValue(stiebelEltronCoolingModeStateTypeId, - systemStatus & (1 << 8)); - thing->setStateValue(stiebelEltronDefrostingStateTypeId, - systemStatus & (1 << 9)); - thing->setStateValue(stiebelEltronSilentModeStateTypeId, - systemStatus & (1 << 10)); - thing->setStateValue(stiebelEltronSilentMode2StateTypeId, - systemStatus & (1 << 11)); - }); connect( - connection, &StiebelEltronModbusConnection::sgReadyStateChanged, - this, - [thing]( - StiebelEltronModbusConnection::SmartGridState smartGridState) { - qCDebug(dcStiebelEltron()) - << thing << "SG Ready activation changed" << smartGridState; - switch (smartGridState) { - case StiebelEltronModbusConnection::SmartGridStateModeOne: - thing->setStateValue( - stiebelEltronSgReadyModeStateTypeId, "Mode 1"); - break; - case StiebelEltronModbusConnection::SmartGridStateModeTwo: - thing->setStateValue( - stiebelEltronSgReadyModeStateTypeId, "Mode 2"); - break; - case StiebelEltronModbusConnection::SmartGridStateModeThree: - thing->setStateValue( - stiebelEltronSgReadyModeStateTypeId, "Mode 3"); - break; - case StiebelEltronModbusConnection::SmartGridStateModeFour: - thing->setStateValue( - stiebelEltronSgReadyModeStateTypeId, "Mode 4"); - break; - } + connection, &StiebelEltronModbusConnection::systemStatusChanged, this, + [thing](uint16_t systemStatus) { + qCDebug(dcStiebelEltron()) << thing << "System status changed " << systemStatus; + thing->setStateValue(stiebelEltronPumpOneStateTypeId, systemStatus & (1 << 0)); + thing->setStateValue(stiebelEltronPumpTwoStateTypeId, systemStatus & (1 << 1)); + thing->setStateValue(stiebelEltronHeatingUpStateTypeId, systemStatus & (1 << 2)); + thing->setStateValue(stiebelEltronAuxHeatingStateTypeId, systemStatus & (1 << 3)); + thing->setStateValue(stiebelEltronHeatingStateTypeId, systemStatus & (1 << 4)); + thing->setStateValue(stiebelEltronHotWaterStateTypeId, systemStatus & (1 << 5)); + thing->setStateValue(stiebelEltronCompressorStateTypeId, systemStatus & (1 << 6)); + thing->setStateValue(stiebelEltronSummerModeStateTypeId, systemStatus & (1 << 7)); + thing->setStateValue(stiebelEltronCoolingModeStateTypeId, systemStatus & (1 << 8)); + thing->setStateValue(stiebelEltronDefrostingStateTypeId, systemStatus & (1 << 9)); + thing->setStateValue(stiebelEltronSilentModeStateTypeId, systemStatus & (1 << 10)); + thing->setStateValue(stiebelEltronSilentMode2StateTypeId, systemStatus & (1 << 11)); }); - connect(connection, - &StiebelEltronModbusConnection::sgReadyActiveChanged, this, + + connect(connection, &StiebelEltronModbusConnection::sgReadyStateChanged, this, + [thing](StiebelEltronModbusConnection::SmartGridState smartGridState) { + qCDebug(dcStiebelEltron()) + << thing << "SG Ready activation changed" << smartGridState; + switch (smartGridState) { + case StiebelEltronModbusConnection::SmartGridStateModeOne: + thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Mode 1"); + break; + case StiebelEltronModbusConnection::SmartGridStateModeTwo: + thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Mode 2"); + break; + case StiebelEltronModbusConnection::SmartGridStateModeThree: + thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Mode 3"); + break; + case StiebelEltronModbusConnection::SmartGridStateModeFour: + thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Mode 4"); + break; + } + }); + connect(connection, &StiebelEltronModbusConnection::sgReadyActiveChanged, this, [thing](bool smartGridActive) { qCDebug(dcStiebelEltron()) - << thing << "SG Ready activation changed" - << smartGridActive; - thing->setStateValue(stiebelEltronSgReadyActiveStateTypeId, - smartGridActive); + << thing << "SG Ready activation changed" << smartGridActive; + thing->setStateValue(stiebelEltronSgReadyActiveStateTypeId, smartGridActive); }); m_connections.insert(thing, connection); @@ -347,11 +279,9 @@ void IntegrationPluginStiebelEltron::postSetupThing(Thing *thing) { if (thing->thingClassId() == stiebelEltronThingClassId) { if (!m_pluginTimer) { qCDebug(dcStiebelEltron()) << "Starting plugin timer..."; - m_pluginTimer = - hardwareManager()->pluginTimerManager()->registerTimer(10); + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); connect(m_pluginTimer, &PluginTimer::timeout, this, [this] { - foreach (StiebelEltronModbusConnection *connection, - m_connections) { + foreach (StiebelEltronModbusConnection *connection, m_connections) { if (connection->connected()) { connection->update(); } @@ -364,8 +294,7 @@ void IntegrationPluginStiebelEltron::postSetupThing(Thing *thing) { } void IntegrationPluginStiebelEltron::thingRemoved(Thing *thing) { - if (thing->thingClassId() == stiebelEltronThingClassId && - m_connections.contains(thing)) { + if (thing->thingClassId() == stiebelEltronThingClassId && m_connections.contains(thing)) { m_connections.take(thing)->deleteLater(); } @@ -392,16 +321,13 @@ void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { info->finish(Thing::ThingErrorNoError); } - if (info->action().actionTypeId() == - stiebelEltronSgReadyActiveActionTypeId) { + if (info->action().actionTypeId() == stiebelEltronSgReadyActiveActionTypeId) { bool sgReadyActiveBool = info->action() - .paramValue( - stiebelEltronSgReadyActiveActionSgReadyActiveParamTypeId) + .paramValue(stiebelEltronSgReadyActiveActionSgReadyActiveParamTypeId) .toBool(); - qCDebug(dcStiebelEltron()) - << "Execute action" << info->action().actionTypeId().toString() - << info->action().params(); + qCDebug(dcStiebelEltron()) << "Execute action" << info->action().actionTypeId().toString() + << info->action().params(); qCDebug(dcStiebelEltron()) << "Value: " << sgReadyActiveBool; QModbusReply *reply = connection->setSgReadyActive(sgReadyActiveBool); @@ -412,58 +338,43 @@ void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { return; } - connect(reply, &QModbusReply::finished, reply, - &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, info, - [info, reply, sgReadyActiveBool] { - if (reply->error() != QModbusDevice::NoError) { - qCWarning(dcStiebelEltron()) - << "Set SG ready activation finished with error" - << reply->errorString(); - info->finish(Thing::ThingErrorHardwareFailure); - return; - } + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, info, [info, reply, sgReadyActiveBool] { + if (reply->error() != QModbusDevice::NoError) { + qCWarning(dcStiebelEltron()) + << "Set SG ready activation finished with error" << reply->errorString(); + info->finish(Thing::ThingErrorHardwareFailure); + return; + } - qCDebug(dcStiebelEltron()) - << "Execute action finished successfully" - << info->action().actionTypeId().toString() - << info->action().params(); - info->thing()->setStateValue( - stiebelEltronSgReadyActiveStateTypeId, - sgReadyActiveBool); - info->finish(Thing::ThingErrorNoError); - }); + qCDebug(dcStiebelEltron()) + << "Execute action finished successfully" + << info->action().actionTypeId().toString() << info->action().params(); + info->thing()->setStateValue(stiebelEltronSgReadyActiveStateTypeId, sgReadyActiveBool); + info->finish(Thing::ThingErrorNoError); + }); - connect(reply, &QModbusReply::errorOccurred, this, - [reply](QModbusDevice::Error error) { - qCWarning(dcStiebelEltron()) - << "Modbus reply error occurred while execute action" - << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else if (info->action().actionTypeId() == - stiebelEltronSgReadyModeActionTypeId) { + connect(reply, &QModbusReply::errorOccurred, this, [reply](QModbusDevice::Error error) { + qCWarning(dcStiebelEltron()) << "Modbus reply error occurred while execute action" + << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); + } else if (info->action().actionTypeId() == stiebelEltronSgReadyModeActionTypeId) { QString sgReadyModeString = info->action() - .paramValue( - stiebelEltronSgReadyModeActionSgReadyModeParamTypeId) + .paramValue(stiebelEltronSgReadyModeActionSgReadyModeParamTypeId) .toString(); - qCDebug(dcStiebelEltron()) - << "Execute action" << info->action().actionTypeId().toString() - << info->action().params(); + qCDebug(dcStiebelEltron()) << "Execute action" << info->action().actionTypeId().toString() + << info->action().params(); StiebelEltronModbusConnection::SmartGridState sgReadyState; if (sgReadyModeString == "Mode 1") { - sgReadyState = - StiebelEltronModbusConnection::SmartGridStateModeOne; + sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeOne; } else if (sgReadyModeString == "Mode 2") { - sgReadyState = - StiebelEltronModbusConnection::SmartGridStateModeTwo; + sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeTwo; } else if (sgReadyModeString == "Mode 3") { - sgReadyState = - StiebelEltronModbusConnection::SmartGridStateModeThree; + sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeThree; } else { - sgReadyState = - StiebelEltronModbusConnection::SmartGridStateModeFour; + sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeFour; } QModbusReply *reply = connection->setSgReadyState(sgReadyState); @@ -474,34 +385,27 @@ void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { return; } - connect(reply, &QModbusReply::finished, reply, - &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, info, - [info, reply, sgReadyModeString] { - if (reply->error() != QModbusDevice::NoError) { - qCWarning(dcStiebelEltron()) - << "Set SG ready mode finished with error" - << reply->errorString(); - info->finish(Thing::ThingErrorHardwareFailure); - return; - } + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, info, [info, reply, sgReadyModeString] { + if (reply->error() != QModbusDevice::NoError) { + qCWarning(dcStiebelEltron()) + << "Set SG ready mode finished with error" << reply->errorString(); + info->finish(Thing::ThingErrorHardwareFailure); + return; + } - qCDebug(dcStiebelEltron()) - << "Execute action finished successfully" - << info->action().actionTypeId().toString() - << info->action().params(); - info->thing()->setStateValue( - stiebelEltronSgReadyModeStateTypeId, sgReadyModeString); - info->finish(Thing::ThingErrorNoError); - }); + qCDebug(dcStiebelEltron()) + << "Execute action finished successfully" + << info->action().actionTypeId().toString() << info->action().params(); + info->thing()->setStateValue(stiebelEltronSgReadyModeStateTypeId, sgReadyModeString); + info->finish(Thing::ThingErrorNoError); + }); - connect(reply, &QModbusReply::errorOccurred, this, - [reply](QModbusDevice::Error error) { - qCWarning(dcStiebelEltron()) - << "Modbus reply error occurred while execute action" - << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); + connect(reply, &QModbusReply::errorOccurred, this, [reply](QModbusDevice::Error error) { + qCWarning(dcStiebelEltron()) << "Modbus reply error occurred while execute action" + << error << reply->errorString(); + emit reply->finished(); // To make sure it will be deleted + }); } info->finish(Thing::ThingErrorNoError); } From 916469dcb6a903051f1af5f4e34f5ae5a5e2e77d Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Mon, 21 Feb 2022 09:33:40 +0100 Subject: [PATCH 29/42] Add Readme --- stiebeleltron/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 stiebeleltron/README.md diff --git a/stiebeleltron/README.md b/stiebeleltron/README.md new file mode 100644 index 0000000..7c287de --- /dev/null +++ b/stiebeleltron/README.md @@ -0,0 +1,21 @@ +# Stiebel Eltron + +Connect nymea to Stiebel Eltron heat pumps. + +This plugin communicates via Modbus/TCP with a Stiebel Eltron Internet-Service-Gateway (ISG). The ISG is usually connected to a WPM/WPM3/WPM3i heatpump controller which again is connected via CAN to the heatpump. +Make sure the ISG firmware is up to date to ensure the Modbus/TCP connection is working. Contact Stiebel Eltron service for a remote update of your ISG. + + +## Supported Things + +* Stiebel Eltron Heatpump + +## Requirements + +* The package 'nymea-plugin-stiebeleltron' must be installed +* Both devices must be in the same local area network. +* Modbus enabled (may conflict with an installed SMA EMI). + +## More + +https://www.stiebel-eltron.de/ From 31e3b0ca52b5c189d020d17a391c86a0af9541fb Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Mon, 21 Feb 2022 09:50:12 +0100 Subject: [PATCH 30/42] Updated Copyright header --- stiebeleltron/integrationpluginstiebeleltron.cpp | 2 +- stiebeleltron/integrationpluginstiebeleltron.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index 2f0bac5..08a8c33 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright 2013 - 2021, nymea GmbH + * Copyright 2013 - 2021, nymea GmbH, Consolinno Energy GmbH, L. Heizinger * Contact: contact@nymea.io * * This file is part of nymea. diff --git a/stiebeleltron/integrationpluginstiebeleltron.h b/stiebeleltron/integrationpluginstiebeleltron.h index 0b81459..769b641 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.h +++ b/stiebeleltron/integrationpluginstiebeleltron.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Copyright 2013 - 2020, nymea GmbH +* Copyright 2013 - 2021, nymea GmbH, Consolinno Energy GmbH, L. Heizinger * Contact: contact@nymea.io * * This file is part of nymea. From 5d3163911dc1914e95436cc6bc5a878aa46bfaef Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Mon, 21 Feb 2022 09:54:48 +0100 Subject: [PATCH 31/42] Add translations --- ...c848b-b538-4b8f-8cdb-7bbecfc9d361-en_US.ts | 477 ++++++++++++++++++ 1 file changed, 477 insertions(+) create mode 100644 stiebeleltron/translations/956c848b-b538-4b8f-8cdb-7bbecfc9d361-en_US.ts diff --git a/stiebeleltron/translations/956c848b-b538-4b8f-8cdb-7bbecfc9d361-en_US.ts b/stiebeleltron/translations/956c848b-b538-4b8f-8cdb-7bbecfc9d361-en_US.ts new file mode 100644 index 0000000..a2d2764 --- /dev/null +++ b/stiebeleltron/translations/956c848b-b538-4b8f-8cdb-7bbecfc9d361-en_US.ts @@ -0,0 +1,477 @@ + + + + + IntegrationPluginStiebelEltron + + + The network device discovery is not available. + + + + + StiebelEltron + + + + Compressor + The name of the ParamType (ThingClass: stiebelEltron, EventType: compressor, ID: {c957cef8-b3a7-4626-ab95-db5439fbdf7f}) +---------- +The name of the StateType ({c957cef8-b3a7-4626-ab95-db5439fbdf7f}) of ThingClass stiebelEltron + + + + + Compressor status changed + The name of the EventType ({c957cef8-b3a7-4626-ab95-db5439fbdf7f}) of ThingClass stiebelEltron + + + + + + Connected + The name of the ParamType (ThingClass: stiebelEltron, EventType: connected, ID: {8d952a5e-87bd-492e-a213-277948521652}) +---------- +The name of the StateType ({8d952a5e-87bd-492e-a213-277948521652}) of ThingClass stiebelEltron + + + + + Connected changed + The name of the EventType ({8d952a5e-87bd-492e-a213-277948521652}) of ThingClass stiebelEltron + + + + + + Consumed energy heating + The name of the ParamType (ThingClass: stiebelEltron, EventType: consumedEnergyHeating, ID: {6816dfef-3f54-4bf1-b0d5-641f06785991}) +---------- +The name of the StateType ({6816dfef-3f54-4bf1-b0d5-641f06785991}) of ThingClass stiebelEltron + + + + + Consumed energy heating changed + The name of the EventType ({6816dfef-3f54-4bf1-b0d5-641f06785991}) of ThingClass stiebelEltron + + + + + + Consumed energy hot water + The name of the ParamType (ThingClass: stiebelEltron, EventType: consumedEnergyHotWater, ID: {11f91606-d550-4918-9fca-69e3303389c8}) +---------- +The name of the StateType ({11f91606-d550-4918-9fca-69e3303389c8}) of ThingClass stiebelEltron + + + + + Consumed energy hot water changed + The name of the EventType ({11f91606-d550-4918-9fca-69e3303389c8}) of ThingClass stiebelEltron + + + + + + Cooling mode + The name of the ParamType (ThingClass: stiebelEltron, EventType: coolingMode, ID: {1bfd99ee-1477-4f70-8717-a3a2930b137f}) +---------- +The name of the StateType ({1bfd99ee-1477-4f70-8717-a3a2930b137f}) of ThingClass stiebelEltron + + + + + Cooling mode status changed + The name of the EventType ({1bfd99ee-1477-4f70-8717-a3a2930b137f}) of ThingClass stiebelEltron + + + + + + Defrosting mode + The name of the ParamType (ThingClass: stiebelEltron, EventType: defrosting, ID: {5c47d9bb-66de-48aa-b90e-caa3ca8d44a5}) +---------- +The name of the StateType ({5c47d9bb-66de-48aa-b90e-caa3ca8d44a5}) of ThingClass stiebelEltron + + + + + Defrosting mode status changed + The name of the EventType ({5c47d9bb-66de-48aa-b90e-caa3ca8d44a5}) of ThingClass stiebelEltron + + + + + + Electric auxiliary heating + The name of the ParamType (ThingClass: stiebelEltron, EventType: auxHeating, ID: {44d5f18b-0389-4a7d-9cb8-f760ce06814e}) +---------- +The name of the StateType ({44d5f18b-0389-4a7d-9cb8-f760ce06814e}) of ThingClass stiebelEltron + + + + + Electric auxiliary heating status changed + The name of the EventType ({44d5f18b-0389-4a7d-9cb8-f760ce06814e}) of ThingClass stiebelEltron + + + + + + Flow temperature + The name of the ParamType (ThingClass: stiebelEltron, EventType: flowTemperature, ID: {1ec958c8-7bf1-469e-b35e-b71fa2099e91}) +---------- +The name of the StateType ({1ec958c8-7bf1-469e-b35e-b71fa2099e91}) of ThingClass stiebelEltron + + + + + Flow temperature changed + The name of the EventType ({1ec958c8-7bf1-469e-b35e-b71fa2099e91}) of ThingClass stiebelEltron + + + + + + Heating energy + The name of the ParamType (ThingClass: stiebelEltron, EventType: heatingEnergy, ID: {d0597f21-2c0e-4db6-92e0-4a3b66474f87}) +---------- +The name of the StateType ({d0597f21-2c0e-4db6-92e0-4a3b66474f87}) of ThingClass stiebelEltron + + + + + Heating energy changed + The name of the EventType ({d0597f21-2c0e-4db6-92e0-4a3b66474f87}) of ThingClass stiebelEltron + + + + + + Heating mode + The name of the ParamType (ThingClass: stiebelEltron, EventType: heating, ID: {3e44e580-f515-47ae-984b-109b507a5db2}) +---------- +The name of the StateType ({3e44e580-f515-47ae-984b-109b507a5db2}) of ThingClass stiebelEltron + + + + + Heating mode status changed + The name of the EventType ({3e44e580-f515-47ae-984b-109b507a5db2}) of ThingClass stiebelEltron + + + + + + Heating up + The name of the ParamType (ThingClass: stiebelEltron, EventType: heatingUp, ID: {ad0b8df8-1eaa-409d-b5e2-a76d7c17c2b9}) +---------- +The name of the StateType ({ad0b8df8-1eaa-409d-b5e2-a76d7c17c2b9}) of ThingClass stiebelEltron + + + + + Heating up status changed + The name of the EventType ({ad0b8df8-1eaa-409d-b5e2-a76d7c17c2b9}) of ThingClass stiebelEltron + + + + + Hot water changed + The name of the EventType ({27c56897-75f1-45af-9a14-b0620053d2d2}) of ThingClass stiebelEltron + + + + + + Hot water energy + The name of the ParamType (ThingClass: stiebelEltron, EventType: hotWaterEnergy, ID: {9761060e-f364-466e-8661-d28f01b862fc}) +---------- +The name of the StateType ({9761060e-f364-466e-8661-d28f01b862fc}) of ThingClass stiebelEltron + + + + + Hot water energy changed + The name of the EventType ({9761060e-f364-466e-8661-d28f01b862fc}) of ThingClass stiebelEltron + + + + + + Hot water mode + The name of the ParamType (ThingClass: stiebelEltron, EventType: hotWater, ID: {b6338cdb-863e-4191-adc4-bc6da5a67351}) +---------- +The name of the StateType ({b6338cdb-863e-4191-adc4-bc6da5a67351}) of ThingClass stiebelEltron + + + + + Hot water mode status changed + The name of the EventType ({b6338cdb-863e-4191-adc4-bc6da5a67351}) of ThingClass stiebelEltron + + + + + + Hot water temperature + The name of the ParamType (ThingClass: stiebelEltron, EventType: hotWaterTemperature, ID: {27c56897-75f1-45af-9a14-b0620053d2d2}) +---------- +The name of the StateType ({27c56897-75f1-45af-9a14-b0620053d2d2}) of ThingClass stiebelEltron + + + + + IP address + The name of the ParamType (ThingClass: stiebelEltron, Type: thing, ID: {47d221fa-f6d2-400e-b80f-bb90abccb72c}) + + + + + MAC address + The name of the ParamType (ThingClass: stiebelEltron, Type: thing, ID: {05cd59b8-3068-460f-b0d2-6d49f27458df}) + + + + + Modbus slave ID + The name of the ParamType (ThingClass: stiebelEltron, Type: thing, ID: {732de6da-bd0a-4215-b320-602117ebc75c}) + + + + + + Operating mode + The name of the ParamType (ThingClass: stiebelEltron, EventType: operatingMode, ID: {932cc41e-53ae-48ae-baa2-6f385f5aa791}) +---------- +The name of the StateType ({932cc41e-53ae-48ae-baa2-6f385f5aa791}) of ThingClass stiebelEltron + + + + + Operating mode changed + The name of the EventType ({932cc41e-53ae-48ae-baa2-6f385f5aa791}) of ThingClass stiebelEltron + + + + + + Outdoor temperature + The name of the ParamType (ThingClass: stiebelEltron, EventType: outdoorTemperature, ID: {e86cbac5-c2c3-4fcf-8caa-dbfc0df2584d}) +---------- +The name of the StateType ({e86cbac5-c2c3-4fcf-8caa-dbfc0df2584d}) of ThingClass stiebelEltron + + + + + Outdoor temperature changed + The name of the EventType ({e86cbac5-c2c3-4fcf-8caa-dbfc0df2584d}) of ThingClass stiebelEltron + + + + + Port + The name of the ParamType (ThingClass: stiebelEltron, Type: thing, ID: {6842321f-1f1a-47e2-b12d-59ee322eb8a6}) + + + + + + Pump 1 + The name of the ParamType (ThingClass: stiebelEltron, EventType: pumpOne, ID: {0ad36f3e-96ff-49d0-8b12-b8c6fed1bf4b}) +---------- +The name of the StateType ({0ad36f3e-96ff-49d0-8b12-b8c6fed1bf4b}) of ThingClass stiebelEltron + + + + + Pump 1 status changed + The name of the EventType ({0ad36f3e-96ff-49d0-8b12-b8c6fed1bf4b}) of ThingClass stiebelEltron + + + + + + Pump 2 + The name of the ParamType (ThingClass: stiebelEltron, EventType: pumpTwo, ID: {1c211fb2-da78-41ad-b7d0-e404141a3dd5}) +---------- +The name of the StateType ({1c211fb2-da78-41ad-b7d0-e404141a3dd5}) of ThingClass stiebelEltron + + + + + Pump 2 status changed + The name of the EventType ({1c211fb2-da78-41ad-b7d0-e404141a3dd5}) of ThingClass stiebelEltron + + + + + + Return temperature + The name of the ParamType (ThingClass: stiebelEltron, EventType: returnTemperature, ID: {ce25e3fd-6544-40e9-bd39-032306553e32}) +---------- +The name of the StateType ({ce25e3fd-6544-40e9-bd39-032306553e32}) of ThingClass stiebelEltron + + + + + Return temperature changed + The name of the EventType ({ce25e3fd-6544-40e9-bd39-032306553e32}) of ThingClass stiebelEltron + + + + + + Room temperature (tbd) + The name of the ParamType (ThingClass: stiebelEltron, EventType: roomTemperature1, ID: {d1959819-9e56-47f7-b619-a393ce50738a}) +---------- +The name of the StateType ({d1959819-9e56-47f7-b619-a393ce50738a}) of ThingClass stiebelEltron + + + + + Room temperature changed + The name of the EventType ({d1959819-9e56-47f7-b619-a393ce50738a}) of ThingClass stiebelEltron + + + + + SG Ready activation changed + The name of the EventType ({798458bb-d38e-4028-880a-6dcba409a2f5}) of ThingClass stiebelEltron + + + + + + + SG Ready enabled + The name of the ParamType (ThingClass: stiebelEltron, ActionType: sgReadyActive, ID: {798458bb-d38e-4028-880a-6dcba409a2f5}) +---------- +The name of the ParamType (ThingClass: stiebelEltron, EventType: sgReadyActive, ID: {798458bb-d38e-4028-880a-6dcba409a2f5}) +---------- +The name of the StateType ({798458bb-d38e-4028-880a-6dcba409a2f5}) of ThingClass stiebelEltron + + + + + + + SG Ready mode + The name of the ParamType (ThingClass: stiebelEltron, ActionType: sgReadyMode, ID: {7d474fb5-aa37-4f21-8166-b20f5bf84fb4}) +---------- +The name of the ParamType (ThingClass: stiebelEltron, EventType: sgReadyMode, ID: {7d474fb5-aa37-4f21-8166-b20f5bf84fb4}) +---------- +The name of the StateType ({7d474fb5-aa37-4f21-8166-b20f5bf84fb4}) of ThingClass stiebelEltron + + + + + SG Ready mode changed + The name of the EventType ({7d474fb5-aa37-4f21-8166-b20f5bf84fb4}) of ThingClass stiebelEltron + + + + + Set SG Ready mode + The name of the ActionType ({7d474fb5-aa37-4f21-8166-b20f5bf84fb4}) of ThingClass stiebelEltron + + + + + + Silent mode + The name of the ParamType (ThingClass: stiebelEltron, EventType: silentMode, ID: {047fcb7d-9080-4b45-9a6e-5060fa43f7c2}) +---------- +The name of the StateType ({047fcb7d-9080-4b45-9a6e-5060fa43f7c2}) of ThingClass stiebelEltron + + + + + + Silent mode 2 (Off) + The name of the ParamType (ThingClass: stiebelEltron, EventType: silentMode2, ID: {d77a30d9-98f7-40ec-bc55-77c547f24145}) +---------- +The name of the StateType ({d77a30d9-98f7-40ec-bc55-77c547f24145}) of ThingClass stiebelEltron + + + + + Silent mode 2 status changed + The name of the EventType ({d77a30d9-98f7-40ec-bc55-77c547f24145}) of ThingClass stiebelEltron + + + + + Silent mode status changed + The name of the EventType ({047fcb7d-9080-4b45-9a6e-5060fa43f7c2}) of ThingClass stiebelEltron + + + + + Sommer mode status changed + The name of the EventType ({7a287cfb-9088-4aad-a991-3e43714dc64e}) of ThingClass stiebelEltron + + + + + + Source temperature (tbd) + The name of the ParamType (ThingClass: stiebelEltron, EventType: sourceTemperature, ID: {5833ceb6-5e7c-437b-a44a-e9f5eb42b6ac}) +---------- +The name of the StateType ({5833ceb6-5e7c-437b-a44a-e9f5eb42b6ac}) of ThingClass stiebelEltron + + + + + Source temperature changed + The name of the EventType ({5833ceb6-5e7c-437b-a44a-e9f5eb42b6ac}) of ThingClass stiebelEltron + + + + + + Stiebel Eltron + The name of the vendor ({c8607f85-a81e-40e0-bc95-1b7199cd2d99}) +---------- +The name of the plugin StiebelEltron ({956c848b-b538-4b8f-8cdb-7bbecfc9d361}) + + + + + Stiebel Eltron Heatpump + The name of the ThingClass ({e02ecf61-7d28-43c2-b87e-e7e98a48fbfd}) + + + + + + Storage tank temperature + The name of the ParamType (ThingClass: stiebelEltron, EventType: storageTankTemperature, ID: {43dd25b3-8782-4faa-a9e0-2fb10892fa0c}) +---------- +The name of the StateType ({43dd25b3-8782-4faa-a9e0-2fb10892fa0c}) of ThingClass stiebelEltron + + + + + Storage tank temperature changed + The name of the EventType ({43dd25b3-8782-4faa-a9e0-2fb10892fa0c}) of ThingClass stiebelEltron + + + + + + Summer mode + The name of the ParamType (ThingClass: stiebelEltron, EventType: summerMode, ID: {7a287cfb-9088-4aad-a991-3e43714dc64e}) +---------- +The name of the StateType ({7a287cfb-9088-4aad-a991-3e43714dc64e}) of ThingClass stiebelEltron + + + + + Switch SG Ready on/off + The name of the ActionType ({798458bb-d38e-4028-880a-6dcba409a2f5}) of ThingClass stiebelEltron + + + + From 3d3269b6e7f671d6a63c0440027a312b7424fdf8 Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Tue, 22 Feb 2022 10:13:31 +0100 Subject: [PATCH 32/42] Filter by hostname and fix Readme --- stiebeleltron/README.md | 2 +- .../integrationpluginstiebeleltron.cpp | 178 ++++++++---------- 2 files changed, 79 insertions(+), 101 deletions(-) diff --git a/stiebeleltron/README.md b/stiebeleltron/README.md index 7c287de..1187f20 100644 --- a/stiebeleltron/README.md +++ b/stiebeleltron/README.md @@ -12,7 +12,7 @@ Make sure the ISG firmware is up to date to ensure the Modbus/TCP connection is ## Requirements -* The package 'nymea-plugin-stiebeleltron' must be installed +* The package `nymea-plugin-stiebeleltron` must be installed * Both devices must be in the same local area network. * Modbus enabled (may conflict with an installed SMA EMI). diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index 08a8c33..739892a 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright 2013 - 2021, nymea GmbH, Consolinno Energy GmbH, L. Heizinger + * Copyright 2013 - 2021, nymea GmbH, Consolinno Energy GmbH, L. Heizinger * Contact: contact@nymea.io * * This file is part of nymea. @@ -44,8 +44,7 @@ void IntegrationPluginStiebelEltron::discoverThings(ThingDiscoveryInfo *info) { return; } - NetworkDeviceDiscoveryReply *discoveryReply = - hardwareManager()->networkDeviceDiscovery()->discover(); + NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover(); connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=]() { foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) { qCDebug(dcStiebelEltron()) << "Found" << networkDeviceInfo; @@ -54,29 +53,27 @@ void IntegrationPluginStiebelEltron::discoverThings(ThingDiscoveryInfo *info) { if (networkDeviceInfo.hostName().isEmpty()) { title = networkDeviceInfo.address().toString(); } else { - title = networkDeviceInfo.hostName() + " (" + - networkDeviceInfo.address().toString() + ")"; + if (!networkDeviceInfo.hostName().contains("StiebelEltronISG")) continue; + title = networkDeviceInfo.hostName() + " (" + networkDeviceInfo.address().toString() + ")"; } QString description; if (networkDeviceInfo.macAddressManufacturer().isEmpty()) { description = networkDeviceInfo.macAddress(); } else { - description = networkDeviceInfo.macAddress() + " (" + - networkDeviceInfo.macAddressManufacturer() + ")"; + description = + networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")"; } ThingDescriptor descriptor(stiebelEltronThingClassId, title, description); ParamList params; - params << Param(stiebelEltronThingIpAddressParamTypeId, - networkDeviceInfo.address().toString()); - params << Param(stiebelEltronThingMacAddressParamTypeId, - networkDeviceInfo.macAddress()); + params << Param(stiebelEltronThingIpAddressParamTypeId, networkDeviceInfo.address().toString()); + params << Param(stiebelEltronThingMacAddressParamTypeId, networkDeviceInfo.macAddress()); descriptor.setParams(params); // Check if we already have set up this device - Things existingThings = myThings().filterByParam( - stiebelEltronThingMacAddressParamTypeId, networkDeviceInfo.macAddress()); + Things existingThings = myThings().filterByParam(stiebelEltronThingMacAddressParamTypeId, + networkDeviceInfo.macAddress()); if (existingThings.count() == 1) { qCDebug(dcStiebelEltron()) << "This connection already exists in the system:" << networkDeviceInfo; @@ -106,8 +103,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { connect(connection, &StiebelEltronModbusConnection::connectionStateChanged, this, [thing, connection](bool status) { - qCDebug(dcStiebelEltron()) - << "Connected changed to" << status << "for" << thing; + qCDebug(dcStiebelEltron()) << "Connected changed to" << status << "for" << thing; if (status) { connection->update(); } @@ -119,8 +115,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { [thing](float outdoorTemperature) { qCDebug(dcStiebelEltron()) << thing << "outdoor temperature changed" << outdoorTemperature << "°C"; - thing->setStateValue(stiebelEltronOutdoorTemperatureStateTypeId, - outdoorTemperature); + thing->setStateValue(stiebelEltronOutdoorTemperatureStateTypeId, outdoorTemperature); }); connect(connection, &StiebelEltronModbusConnection::flowTemperatureChanged, this, @@ -134,14 +129,13 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { [thing](float hotWaterTemperature) { qCDebug(dcStiebelEltron()) << thing << "hot water temperature changed" << hotWaterTemperature << "°C"; - thing->setStateValue(stiebelEltronHotWaterTemperatureStateTypeId, - hotWaterTemperature); + thing->setStateValue(stiebelEltronHotWaterTemperatureStateTypeId, hotWaterTemperature); }); connect(connection, &StiebelEltronModbusConnection::storageTankTemperatureChanged, this, [thing](float storageTankTemperature) { - qCDebug(dcStiebelEltron()) << thing << "Storage tank temperature changed" - << storageTankTemperature << "°C"; + qCDebug(dcStiebelEltron()) + << thing << "Storage tank temperature changed" << storageTankTemperature << "°C"; thing->setStateValue(stiebelEltronStorageTankTemperatureStateTypeId, storageTankTemperature); }); @@ -150,8 +144,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { [thing](float returnTemperature) { qCDebug(dcStiebelEltron()) << thing << "return temperature changed" << returnTemperature << "°C"; - thing->setStateValue(stiebelEltronReturnTemperatureStateTypeId, - returnTemperature); + thing->setStateValue(stiebelEltronReturnTemperatureStateTypeId, returnTemperature); }); connect(connection, &StiebelEltronModbusConnection::heatingEnergyChanged, this, @@ -159,8 +152,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { // kWh and MWh of energy are stored in two registers an read as // an uint32. The following arithmetic splits the uint32 into // two uint16 and sums up the MWh and kWh values. - quint32 correctedEnergy = - (heatingEnergy >> 16) + (heatingEnergy & 0xFFFF) * 1000; + quint32 correctedEnergy = (heatingEnergy >> 16) + (heatingEnergy & 0xFFFF) * 1000; qCDebug(dcStiebelEltron()) << thing << "Heating energy changed" << correctedEnergy << "kWh"; thing->setStateValue(stiebelEltronHeatingEnergyStateTypeId, correctedEnergy); @@ -169,8 +161,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { connect(connection, &StiebelEltronModbusConnection::hotWaterEnergyChanged, this, [thing](quint32 hotWaterEnergy) { // see comment in heatingEnergyChanged - quint32 correctedEnergy = - (hotWaterEnergy >> 16) + (hotWaterEnergy & 0xFFFF) * 1000; + quint32 correctedEnergy = (hotWaterEnergy >> 16) + (hotWaterEnergy & 0xFFFF) * 1000; qCDebug(dcStiebelEltron()) << thing << "Hot Water energy changed" << correctedEnergy << "kWh"; thing->setStateValue(stiebelEltronHotWaterEnergyStateTypeId, correctedEnergy); @@ -179,73 +170,68 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { connect(connection, &StiebelEltronModbusConnection::consumedEnergyHeatingChanged, this, [thing](quint32 consumedEnergyHeatingEnergy) { // see comment in heatingEnergyChanged - quint32 correctedEnergy = (consumedEnergyHeatingEnergy >> 16) + - (consumedEnergyHeatingEnergy & 0xFFFF) * 1000; + quint32 correctedEnergy = + (consumedEnergyHeatingEnergy >> 16) + (consumedEnergyHeatingEnergy & 0xFFFF) * 1000; qCDebug(dcStiebelEltron()) << thing << "Consumed energy Heating changed" << correctedEnergy << "kWh"; - thing->setStateValue(stiebelEltronConsumedEnergyHeatingStateTypeId, - correctedEnergy); + thing->setStateValue(stiebelEltronConsumedEnergyHeatingStateTypeId, correctedEnergy); }); connect(connection, &StiebelEltronModbusConnection::consumedEnergyHotWaterChanged, this, [thing](quint32 consumedEnergyHotWaterEnergy) { // see comment in heatingEnergyChanged - quint32 correctedEnergy = (consumedEnergyHotWaterEnergy >> 16) + - (consumedEnergyHotWaterEnergy & 0xFFFF) * 1000; + quint32 correctedEnergy = + (consumedEnergyHotWaterEnergy >> 16) + (consumedEnergyHotWaterEnergy & 0xFFFF) * 1000; qCDebug(dcStiebelEltron()) << thing << "Consumed energy hot water changed" << correctedEnergy << "kWh"; - thing->setStateValue(stiebelEltronConsumedEnergyHotWaterStateTypeId, - correctedEnergy); + thing->setStateValue(stiebelEltronConsumedEnergyHotWaterStateTypeId, correctedEnergy); }); - connect( - connection, &StiebelEltronModbusConnection::operatingModeChanged, this, - [thing](StiebelEltronModbusConnection::OperatingMode operatingMode) { - qCDebug(dcStiebelEltron()) << thing << "operating mode changed " << operatingMode; - switch (operatingMode) { - case StiebelEltronModbusConnection::OperatingModeEmergency: - thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Emergency"); - break; - case StiebelEltronModbusConnection::OperatingModeStandby: - thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Standby"); - break; - case StiebelEltronModbusConnection::OperatingModeProgram: - thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Program"); - break; - case StiebelEltronModbusConnection::OperatingModeComfort: - thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Comfort"); - break; - case StiebelEltronModbusConnection::OperatingModeEco: - thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Eco"); - break; - case StiebelEltronModbusConnection::OperatingModeHotWater: - thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Hot water"); - break; - } - }); + connect(connection, &StiebelEltronModbusConnection::operatingModeChanged, this, + [thing](StiebelEltronModbusConnection::OperatingMode operatingMode) { + qCDebug(dcStiebelEltron()) << thing << "operating mode changed " << operatingMode; + switch (operatingMode) { + case StiebelEltronModbusConnection::OperatingModeEmergency: + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Emergency"); + break; + case StiebelEltronModbusConnection::OperatingModeStandby: + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Standby"); + break; + case StiebelEltronModbusConnection::OperatingModeProgram: + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Program"); + break; + case StiebelEltronModbusConnection::OperatingModeComfort: + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Comfort"); + break; + case StiebelEltronModbusConnection::OperatingModeEco: + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Eco"); + break; + case StiebelEltronModbusConnection::OperatingModeHotWater: + thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Hot water"); + break; + } + }); - connect( - connection, &StiebelEltronModbusConnection::systemStatusChanged, this, - [thing](uint16_t systemStatus) { - qCDebug(dcStiebelEltron()) << thing << "System status changed " << systemStatus; - thing->setStateValue(stiebelEltronPumpOneStateTypeId, systemStatus & (1 << 0)); - thing->setStateValue(stiebelEltronPumpTwoStateTypeId, systemStatus & (1 << 1)); - thing->setStateValue(stiebelEltronHeatingUpStateTypeId, systemStatus & (1 << 2)); - thing->setStateValue(stiebelEltronAuxHeatingStateTypeId, systemStatus & (1 << 3)); - thing->setStateValue(stiebelEltronHeatingStateTypeId, systemStatus & (1 << 4)); - thing->setStateValue(stiebelEltronHotWaterStateTypeId, systemStatus & (1 << 5)); - thing->setStateValue(stiebelEltronCompressorStateTypeId, systemStatus & (1 << 6)); - thing->setStateValue(stiebelEltronSummerModeStateTypeId, systemStatus & (1 << 7)); - thing->setStateValue(stiebelEltronCoolingModeStateTypeId, systemStatus & (1 << 8)); - thing->setStateValue(stiebelEltronDefrostingStateTypeId, systemStatus & (1 << 9)); - thing->setStateValue(stiebelEltronSilentModeStateTypeId, systemStatus & (1 << 10)); - thing->setStateValue(stiebelEltronSilentMode2StateTypeId, systemStatus & (1 << 11)); - }); + connect(connection, &StiebelEltronModbusConnection::systemStatusChanged, this, + [thing](uint16_t systemStatus) { + qCDebug(dcStiebelEltron()) << thing << "System status changed " << systemStatus; + thing->setStateValue(stiebelEltronPumpOneStateTypeId, systemStatus & (1 << 0)); + thing->setStateValue(stiebelEltronPumpTwoStateTypeId, systemStatus & (1 << 1)); + thing->setStateValue(stiebelEltronHeatingUpStateTypeId, systemStatus & (1 << 2)); + thing->setStateValue(stiebelEltronAuxHeatingStateTypeId, systemStatus & (1 << 3)); + thing->setStateValue(stiebelEltronHeatingStateTypeId, systemStatus & (1 << 4)); + thing->setStateValue(stiebelEltronHotWaterStateTypeId, systemStatus & (1 << 5)); + thing->setStateValue(stiebelEltronCompressorStateTypeId, systemStatus & (1 << 6)); + thing->setStateValue(stiebelEltronSummerModeStateTypeId, systemStatus & (1 << 7)); + thing->setStateValue(stiebelEltronCoolingModeStateTypeId, systemStatus & (1 << 8)); + thing->setStateValue(stiebelEltronDefrostingStateTypeId, systemStatus & (1 << 9)); + thing->setStateValue(stiebelEltronSilentModeStateTypeId, systemStatus & (1 << 10)); + thing->setStateValue(stiebelEltronSilentMode2StateTypeId, systemStatus & (1 << 11)); + }); connect(connection, &StiebelEltronModbusConnection::sgReadyStateChanged, this, [thing](StiebelEltronModbusConnection::SmartGridState smartGridState) { - qCDebug(dcStiebelEltron()) - << thing << "SG Ready activation changed" << smartGridState; + qCDebug(dcStiebelEltron()) << thing << "SG Ready activation changed" << smartGridState; switch (smartGridState) { case StiebelEltronModbusConnection::SmartGridStateModeOne: thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Mode 1"); @@ -263,8 +249,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { }); connect(connection, &StiebelEltronModbusConnection::sgReadyActiveChanged, this, [thing](bool smartGridActive) { - qCDebug(dcStiebelEltron()) - << thing << "SG Ready activation changed" << smartGridActive; + qCDebug(dcStiebelEltron()) << thing << "SG Ready activation changed" << smartGridActive; thing->setStateValue(stiebelEltronSgReadyActiveStateTypeId, smartGridActive); }); @@ -309,9 +294,8 @@ void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { StiebelEltronModbusConnection *connection = m_connections.value(thing); if (!connection->connected()) { - qCWarning(dcStiebelEltron()) - << "Could not execute action. The modbus connection is currently " - "not available."; + qCWarning(dcStiebelEltron()) << "Could not execute action. The modbus connection is currently " + "not available."; info->finish(Thing::ThingErrorHardwareNotAvailable); return; } @@ -323,9 +307,7 @@ void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { if (info->action().actionTypeId() == stiebelEltronSgReadyActiveActionTypeId) { bool sgReadyActiveBool = - info->action() - .paramValue(stiebelEltronSgReadyActiveActionSgReadyActiveParamTypeId) - .toBool(); + info->action().paramValue(stiebelEltronSgReadyActiveActionSgReadyActiveParamTypeId).toBool(); qCDebug(dcStiebelEltron()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params(); qCDebug(dcStiebelEltron()) << "Value: " << sgReadyActiveBool; @@ -347,23 +329,20 @@ void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { return; } - qCDebug(dcStiebelEltron()) - << "Execute action finished successfully" - << info->action().actionTypeId().toString() << info->action().params(); + qCDebug(dcStiebelEltron()) << "Execute action finished successfully" + << info->action().actionTypeId().toString() << info->action().params(); info->thing()->setStateValue(stiebelEltronSgReadyActiveStateTypeId, sgReadyActiveBool); info->finish(Thing::ThingErrorNoError); }); connect(reply, &QModbusReply::errorOccurred, this, [reply](QModbusDevice::Error error) { - qCWarning(dcStiebelEltron()) << "Modbus reply error occurred while execute action" - << error << reply->errorString(); + qCWarning(dcStiebelEltron()) + << "Modbus reply error occurred while execute action" << error << reply->errorString(); emit reply->finished(); // To make sure it will be deleted }); } else if (info->action().actionTypeId() == stiebelEltronSgReadyModeActionTypeId) { QString sgReadyModeString = - info->action() - .paramValue(stiebelEltronSgReadyModeActionSgReadyModeParamTypeId) - .toString(); + info->action().paramValue(stiebelEltronSgReadyModeActionSgReadyModeParamTypeId).toString(); qCDebug(dcStiebelEltron()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params(); StiebelEltronModbusConnection::SmartGridState sgReadyState; @@ -394,16 +373,15 @@ void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { return; } - qCDebug(dcStiebelEltron()) - << "Execute action finished successfully" - << info->action().actionTypeId().toString() << info->action().params(); + qCDebug(dcStiebelEltron()) << "Execute action finished successfully" + << info->action().actionTypeId().toString() << info->action().params(); info->thing()->setStateValue(stiebelEltronSgReadyModeStateTypeId, sgReadyModeString); info->finish(Thing::ThingErrorNoError); }); connect(reply, &QModbusReply::errorOccurred, this, [reply](QModbusDevice::Error error) { - qCWarning(dcStiebelEltron()) << "Modbus reply error occurred while execute action" - << error << reply->errorString(); + qCWarning(dcStiebelEltron()) + << "Modbus reply error occurred while execute action" << error << reply->errorString(); emit reply->finished(); // To make sure it will be deleted }); } From 662cb212c07e1742dac5ea86d59c2ef759df6479 Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Tue, 22 Feb 2022 10:17:18 +0100 Subject: [PATCH 33/42] Improve connects in setupThing --- .../integrationpluginstiebeleltron.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index 739892a..662d4d6 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -101,7 +101,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { StiebelEltronModbusConnection *connection = new StiebelEltronModbusConnection(address, port, slaveId, this); - connect(connection, &StiebelEltronModbusConnection::connectionStateChanged, this, + connect(connection, &StiebelEltronModbusConnection::connectionStateChanged, thing, [thing, connection](bool status) { qCDebug(dcStiebelEltron()) << "Connected changed to" << status << "for" << thing; if (status) { @@ -111,28 +111,28 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronConnectedStateTypeId, status); }); - connect(connection, &StiebelEltronModbusConnection::outdoorTemperatureChanged, this, + connect(connection, &StiebelEltronModbusConnection::outdoorTemperatureChanged, thing, [thing](float outdoorTemperature) { qCDebug(dcStiebelEltron()) << thing << "outdoor temperature changed" << outdoorTemperature << "°C"; thing->setStateValue(stiebelEltronOutdoorTemperatureStateTypeId, outdoorTemperature); }); - connect(connection, &StiebelEltronModbusConnection::flowTemperatureChanged, this, + connect(connection, &StiebelEltronModbusConnection::flowTemperatureChanged, thing, [thing](float flowTemperature) { qCDebug(dcStiebelEltron()) << thing << "flow temperature changed" << flowTemperature << "°C"; thing->setStateValue(stiebelEltronFlowTemperatureStateTypeId, flowTemperature); }); - connect(connection, &StiebelEltronModbusConnection::hotWaterTemperatureChanged, this, + connect(connection, &StiebelEltronModbusConnection::hotWaterTemperatureChanged, thing, [thing](float hotWaterTemperature) { qCDebug(dcStiebelEltron()) << thing << "hot water temperature changed" << hotWaterTemperature << "°C"; thing->setStateValue(stiebelEltronHotWaterTemperatureStateTypeId, hotWaterTemperature); }); - connect(connection, &StiebelEltronModbusConnection::storageTankTemperatureChanged, this, + connect(connection, &StiebelEltronModbusConnection::storageTankTemperatureChanged, thing, [thing](float storageTankTemperature) { qCDebug(dcStiebelEltron()) << thing << "Storage tank temperature changed" << storageTankTemperature << "°C"; @@ -140,14 +140,14 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { storageTankTemperature); }); - connect(connection, &StiebelEltronModbusConnection::returnTemperatureChanged, this, + connect(connection, &StiebelEltronModbusConnection::returnTemperatureChanged, thing, [thing](float returnTemperature) { qCDebug(dcStiebelEltron()) << thing << "return temperature changed" << returnTemperature << "°C"; thing->setStateValue(stiebelEltronReturnTemperatureStateTypeId, returnTemperature); }); - connect(connection, &StiebelEltronModbusConnection::heatingEnergyChanged, this, + connect(connection, &StiebelEltronModbusConnection::heatingEnergyChanged, thing, [thing](quint32 heatingEnergy) { // kWh and MWh of energy are stored in two registers an read as // an uint32. The following arithmetic splits the uint32 into @@ -158,7 +158,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronHeatingEnergyStateTypeId, correctedEnergy); }); - connect(connection, &StiebelEltronModbusConnection::hotWaterEnergyChanged, this, + connect(connection, &StiebelEltronModbusConnection::hotWaterEnergyChanged, thing, [thing](quint32 hotWaterEnergy) { // see comment in heatingEnergyChanged quint32 correctedEnergy = (hotWaterEnergy >> 16) + (hotWaterEnergy & 0xFFFF) * 1000; @@ -167,7 +167,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronHotWaterEnergyStateTypeId, correctedEnergy); }); - connect(connection, &StiebelEltronModbusConnection::consumedEnergyHeatingChanged, this, + connect(connection, &StiebelEltronModbusConnection::consumedEnergyHeatingChanged, thing, [thing](quint32 consumedEnergyHeatingEnergy) { // see comment in heatingEnergyChanged quint32 correctedEnergy = @@ -177,7 +177,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronConsumedEnergyHeatingStateTypeId, correctedEnergy); }); - connect(connection, &StiebelEltronModbusConnection::consumedEnergyHotWaterChanged, this, + connect(connection, &StiebelEltronModbusConnection::consumedEnergyHotWaterChanged, thing, [thing](quint32 consumedEnergyHotWaterEnergy) { // see comment in heatingEnergyChanged quint32 correctedEnergy = @@ -187,7 +187,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronConsumedEnergyHotWaterStateTypeId, correctedEnergy); }); - connect(connection, &StiebelEltronModbusConnection::operatingModeChanged, this, + connect(connection, &StiebelEltronModbusConnection::operatingModeChanged, thing, [thing](StiebelEltronModbusConnection::OperatingMode operatingMode) { qCDebug(dcStiebelEltron()) << thing << "operating mode changed " << operatingMode; switch (operatingMode) { @@ -212,7 +212,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { } }); - connect(connection, &StiebelEltronModbusConnection::systemStatusChanged, this, + connect(connection, &StiebelEltronModbusConnection::systemStatusChanged, thing, [thing](uint16_t systemStatus) { qCDebug(dcStiebelEltron()) << thing << "System status changed " << systemStatus; thing->setStateValue(stiebelEltronPumpOneStateTypeId, systemStatus & (1 << 0)); @@ -229,7 +229,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronSilentMode2StateTypeId, systemStatus & (1 << 11)); }); - connect(connection, &StiebelEltronModbusConnection::sgReadyStateChanged, this, + connect(connection, &StiebelEltronModbusConnection::sgReadyStateChanged, thing, [thing](StiebelEltronModbusConnection::SmartGridState smartGridState) { qCDebug(dcStiebelEltron()) << thing << "SG Ready activation changed" << smartGridState; switch (smartGridState) { @@ -247,7 +247,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { break; } }); - connect(connection, &StiebelEltronModbusConnection::sgReadyActiveChanged, this, + connect(connection, &StiebelEltronModbusConnection::sgReadyActiveChanged, thing, [thing](bool smartGridActive) { qCDebug(dcStiebelEltron()) << thing << "SG Ready activation changed" << smartGridActive; thing->setStateValue(stiebelEltronSgReadyActiveStateTypeId, smartGridActive); From 501556868b43a2460bec0b009b72f5648d4e08d1 Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Tue, 22 Feb 2022 10:22:24 +0100 Subject: [PATCH 34/42] Changed SG Ready values to Off, Low, Standard and High as required by nymea --- stiebeleltron/integrationpluginstiebeleltron.cpp | 8 ++++---- stiebeleltron/integrationpluginstiebeleltron.json | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index 662d4d6..36f0c2e 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -234,16 +234,16 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { qCDebug(dcStiebelEltron()) << thing << "SG Ready activation changed" << smartGridState; switch (smartGridState) { case StiebelEltronModbusConnection::SmartGridStateModeOne: - thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Mode 1"); + thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Off"); break; case StiebelEltronModbusConnection::SmartGridStateModeTwo: - thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Mode 2"); + thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Low"); break; case StiebelEltronModbusConnection::SmartGridStateModeThree: - thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Mode 3"); + thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Standard"); break; case StiebelEltronModbusConnection::SmartGridStateModeFour: - thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Mode 4"); + thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "High"); break; } }); diff --git a/stiebeleltron/integrationpluginstiebeleltron.json b/stiebeleltron/integrationpluginstiebeleltron.json index ad21a21..299a19a 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.json +++ b/stiebeleltron/integrationpluginstiebeleltron.json @@ -293,13 +293,13 @@ "displayNameAction": "Set SG Ready mode", "type": "QString", "possibleValues": [ - "Mode 1", - "Mode 2", - "Mode 3", - "Mode 4" + "Off", + "Low", + "Standard", + "High" ], "writable": true, - "defaultValue": "Mode 3", + "defaultValue": "Standard", "suggestLogging": true }, { From d36d3e2cef956371f9949968dddc2ad6a2350caf Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Tue, 22 Feb 2022 11:01:31 +0100 Subject: [PATCH 35/42] Install translation files and remove debian translations dependency --- debian/control | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/control b/debian/control index 4d26826..2b6c5b8 100644 --- a/debian/control +++ b/debian/control @@ -161,7 +161,6 @@ Architecture: any Section: libs Depends: ${shlibs:Depends}, ${misc:Depends}, - nymea-plugins-modbus-translations Description: nymea.io plugin for Stiebel Eltron heat pumps This package will install the nymea.io plugin for Stiebel Eltron heat pumps. From 3b994998315db16040733f7f3cfd719f76f53f2e Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Tue, 22 Feb 2022 11:02:25 +0100 Subject: [PATCH 36/42] Fix development leftover --- debian/rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index 565f725..dcdbe2b 100755 --- a/debian/rules +++ b/debian/rules @@ -12,7 +12,7 @@ $(PREPROCESS_FILES:.in=): %: %.in override_dh_auto_build: dh_auto_build - #make lrelease + make lrelease override_dh_install: $(PREPROCESS_FILES:.in=) dh_install --fail-missing From 67abb7b7553db6d454e1afaf751b28b0ede59a0c Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Tue, 22 Feb 2022 11:17:59 +0100 Subject: [PATCH 37/42] Added translations to debian .install file --- debian/nymea-plugin-stiebeleltron.install | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 debian/nymea-plugin-stiebeleltron.install diff --git a/debian/nymea-plugin-stiebeleltron.install b/debian/nymea-plugin-stiebeleltron.install new file mode 100644 index 0000000..c032153 --- /dev/null +++ b/debian/nymea-plugin-stiebeleltron.install @@ -0,0 +1,2 @@ +usr/lib/x86_64-linux-gnu/nymea/plugins/libnymea_integrationpluginstiebeleltron.so +stiebeleltron/translations/*qm usr/share/nymea/translations/ From 219e4fd279a9e170464d4b4e7a2e5958b3987029 Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Tue, 22 Feb 2022 11:35:48 +0100 Subject: [PATCH 38/42] Revert "Added translations to debian .install file" This reverts commit cdf69ff122b042ede56c5cb835233ee7f2400d51. --- debian/nymea-plugin-stiebeleltron.install | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 debian/nymea-plugin-stiebeleltron.install diff --git a/debian/nymea-plugin-stiebeleltron.install b/debian/nymea-plugin-stiebeleltron.install deleted file mode 100644 index c032153..0000000 --- a/debian/nymea-plugin-stiebeleltron.install +++ /dev/null @@ -1,2 +0,0 @@ -usr/lib/x86_64-linux-gnu/nymea/plugins/libnymea_integrationpluginstiebeleltron.so -stiebeleltron/translations/*qm usr/share/nymea/translations/ From 6bb2014be9e9f3aee0ec1dea74498e9ee8bea460 Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Tue, 22 Feb 2022 11:40:44 +0100 Subject: [PATCH 39/42] Fixed mix up of .install and .install.in --- debian/nymea-plugin-stiebeleltron.install.in | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/nymea-plugin-stiebeleltron.install.in b/debian/nymea-plugin-stiebeleltron.install.in index 36bab22..84035a8 100644 --- a/debian/nymea-plugin-stiebeleltron.install.in +++ b/debian/nymea-plugin-stiebeleltron.install.in @@ -1 +1,2 @@ usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginstiebeleltron.so +stiebeleltron/translations/*qm usr/share/nymea/translations/ From e8a8a060d09de1be34aa943bd298e5f4f8e2a12f Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Sat, 5 Mar 2022 13:59:23 +0100 Subject: [PATCH 40/42] Fix debug message for SG Ready mode change --- stiebeleltron/integrationpluginstiebeleltron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index 36f0c2e..6f8a7dc 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -231,7 +231,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { connect(connection, &StiebelEltronModbusConnection::sgReadyStateChanged, thing, [thing](StiebelEltronModbusConnection::SmartGridState smartGridState) { - qCDebug(dcStiebelEltron()) << thing << "SG Ready activation changed" << smartGridState; + qCDebug(dcStiebelEltron()) << thing << "SG Ready mode changed" << smartGridState; switch (smartGridState) { case StiebelEltronModbusConnection::SmartGridStateModeOne: thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Off"); From cb9f4a82364801529a303699dd4a93e37300c1cd Mon Sep 17 00:00:00 2001 From: "l.heizinger" Date: Sat, 5 Mar 2022 14:50:17 +0100 Subject: [PATCH 41/42] Fixed SG ready action --- stiebeleltron/integrationpluginstiebeleltron.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index 6f8a7dc..7d58501 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -346,14 +346,19 @@ void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { qCDebug(dcStiebelEltron()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params(); StiebelEltronModbusConnection::SmartGridState sgReadyState; - if (sgReadyModeString == "Mode 1") { + if (sgReadyModeString == "Off") { sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeOne; - } else if (sgReadyModeString == "Mode 2") { + } else if (sgReadyModeString == "Low") { sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeTwo; - } else if (sgReadyModeString == "Mode 3") { + } else if (sgReadyModeString == "Standard") { sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeThree; - } else { + } else if (sgReadyModeString == "High") { sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeFour; + } else { + qCWarning(dcStiebelEltron()) + << "Failed to set SG Ready mode. An unknown SG Ready mode was passed: " << sgReadyModeString; + info->finish(Thing::ThingErrorHardwareFailure); // TODO better matching error type? + return; } QModbusReply *reply = connection->setSgReadyState(sgReadyState); From 7bb000560dee5b6074f6eb7f0afe9f155d113e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 13 May 2022 08:30:56 +0200 Subject: [PATCH 42/42] Update stiebeleltron plugin to libnyma-modbus --- .../integrationpluginstiebeleltron.cpp | 76 +- .../integrationpluginstiebeleltron.h | 9 +- stiebeleltron/stiebel-eltron-registers.json | 4 +- stiebeleltron/stiebeleltron.pro | 15 +- .../stiebeleltronmodbusconnection.cpp | 1051 ----------------- stiebeleltron/stiebeleltronmodbusconnection.h | 260 ---- 6 files changed, 52 insertions(+), 1363 deletions(-) delete mode 100644 stiebeleltron/stiebeleltronmodbusconnection.cpp delete mode 100644 stiebeleltron/stiebeleltronmodbusconnection.h diff --git a/stiebeleltron/integrationpluginstiebeleltron.cpp b/stiebeleltron/integrationpluginstiebeleltron.cpp index 7d58501..086538a 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.cpp +++ b/stiebeleltron/integrationpluginstiebeleltron.cpp @@ -29,11 +29,11 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "integrationpluginstiebeleltron.h" - -#include "hardwaremanager.h" -#include "network/networkdevicediscovery.h" #include "plugininfo.h" +#include +#include + IntegrationPluginStiebelEltron::IntegrationPluginStiebelEltron() {} void IntegrationPluginStiebelEltron::discoverThings(ThingDiscoveryInfo *info) { @@ -98,10 +98,10 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { quint16 port = thing->paramValue(stiebelEltronThingPortParamTypeId).toUInt(); quint16 slaveId = thing->paramValue(stiebelEltronThingSlaveIdParamTypeId).toUInt(); - StiebelEltronModbusConnection *connection = - new StiebelEltronModbusConnection(address, port, slaveId, this); + StiebelEltronModbusTcpConnection *connection = + new StiebelEltronModbusTcpConnection(address, port, slaveId, this); - connect(connection, &StiebelEltronModbusConnection::connectionStateChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::connectionStateChanged, thing, [thing, connection](bool status) { qCDebug(dcStiebelEltron()) << "Connected changed to" << status << "for" << thing; if (status) { @@ -111,28 +111,28 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronConnectedStateTypeId, status); }); - connect(connection, &StiebelEltronModbusConnection::outdoorTemperatureChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::outdoorTemperatureChanged, thing, [thing](float outdoorTemperature) { qCDebug(dcStiebelEltron()) << thing << "outdoor temperature changed" << outdoorTemperature << "°C"; thing->setStateValue(stiebelEltronOutdoorTemperatureStateTypeId, outdoorTemperature); }); - connect(connection, &StiebelEltronModbusConnection::flowTemperatureChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::flowTemperatureChanged, thing, [thing](float flowTemperature) { qCDebug(dcStiebelEltron()) << thing << "flow temperature changed" << flowTemperature << "°C"; thing->setStateValue(stiebelEltronFlowTemperatureStateTypeId, flowTemperature); }); - connect(connection, &StiebelEltronModbusConnection::hotWaterTemperatureChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::hotWaterTemperatureChanged, thing, [thing](float hotWaterTemperature) { qCDebug(dcStiebelEltron()) << thing << "hot water temperature changed" << hotWaterTemperature << "°C"; thing->setStateValue(stiebelEltronHotWaterTemperatureStateTypeId, hotWaterTemperature); }); - connect(connection, &StiebelEltronModbusConnection::storageTankTemperatureChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::storageTankTemperatureChanged, thing, [thing](float storageTankTemperature) { qCDebug(dcStiebelEltron()) << thing << "Storage tank temperature changed" << storageTankTemperature << "°C"; @@ -140,14 +140,14 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { storageTankTemperature); }); - connect(connection, &StiebelEltronModbusConnection::returnTemperatureChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::returnTemperatureChanged, thing, [thing](float returnTemperature) { qCDebug(dcStiebelEltron()) << thing << "return temperature changed" << returnTemperature << "°C"; thing->setStateValue(stiebelEltronReturnTemperatureStateTypeId, returnTemperature); }); - connect(connection, &StiebelEltronModbusConnection::heatingEnergyChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::heatingEnergyChanged, thing, [thing](quint32 heatingEnergy) { // kWh and MWh of energy are stored in two registers an read as // an uint32. The following arithmetic splits the uint32 into @@ -158,7 +158,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronHeatingEnergyStateTypeId, correctedEnergy); }); - connect(connection, &StiebelEltronModbusConnection::hotWaterEnergyChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::hotWaterEnergyChanged, thing, [thing](quint32 hotWaterEnergy) { // see comment in heatingEnergyChanged quint32 correctedEnergy = (hotWaterEnergy >> 16) + (hotWaterEnergy & 0xFFFF) * 1000; @@ -167,7 +167,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronHotWaterEnergyStateTypeId, correctedEnergy); }); - connect(connection, &StiebelEltronModbusConnection::consumedEnergyHeatingChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::consumedEnergyHeatingChanged, thing, [thing](quint32 consumedEnergyHeatingEnergy) { // see comment in heatingEnergyChanged quint32 correctedEnergy = @@ -177,7 +177,7 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronConsumedEnergyHeatingStateTypeId, correctedEnergy); }); - connect(connection, &StiebelEltronModbusConnection::consumedEnergyHotWaterChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::consumedEnergyHotWaterChanged, thing, [thing](quint32 consumedEnergyHotWaterEnergy) { // see comment in heatingEnergyChanged quint32 correctedEnergy = @@ -187,32 +187,32 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronConsumedEnergyHotWaterStateTypeId, correctedEnergy); }); - connect(connection, &StiebelEltronModbusConnection::operatingModeChanged, thing, - [thing](StiebelEltronModbusConnection::OperatingMode operatingMode) { + connect(connection, &StiebelEltronModbusTcpConnection::operatingModeChanged, thing, + [thing](StiebelEltronModbusTcpConnection::OperatingMode operatingMode) { qCDebug(dcStiebelEltron()) << thing << "operating mode changed " << operatingMode; switch (operatingMode) { - case StiebelEltronModbusConnection::OperatingModeEmergency: + case StiebelEltronModbusTcpConnection::OperatingModeEmergency: thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Emergency"); break; - case StiebelEltronModbusConnection::OperatingModeStandby: + case StiebelEltronModbusTcpConnection::OperatingModeStandby: thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Standby"); break; - case StiebelEltronModbusConnection::OperatingModeProgram: + case StiebelEltronModbusTcpConnection::OperatingModeProgram: thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Program"); break; - case StiebelEltronModbusConnection::OperatingModeComfort: + case StiebelEltronModbusTcpConnection::OperatingModeComfort: thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Comfort"); break; - case StiebelEltronModbusConnection::OperatingModeEco: + case StiebelEltronModbusTcpConnection::OperatingModeEco: thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Eco"); break; - case StiebelEltronModbusConnection::OperatingModeHotWater: + case StiebelEltronModbusTcpConnection::OperatingModeHotWater: thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Hot water"); break; } }); - connect(connection, &StiebelEltronModbusConnection::systemStatusChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::systemStatusChanged, thing, [thing](uint16_t systemStatus) { qCDebug(dcStiebelEltron()) << thing << "System status changed " << systemStatus; thing->setStateValue(stiebelEltronPumpOneStateTypeId, systemStatus & (1 << 0)); @@ -229,25 +229,25 @@ void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) { thing->setStateValue(stiebelEltronSilentMode2StateTypeId, systemStatus & (1 << 11)); }); - connect(connection, &StiebelEltronModbusConnection::sgReadyStateChanged, thing, - [thing](StiebelEltronModbusConnection::SmartGridState smartGridState) { + connect(connection, &StiebelEltronModbusTcpConnection::sgReadyStateChanged, thing, + [thing](StiebelEltronModbusTcpConnection::SmartGridState smartGridState) { qCDebug(dcStiebelEltron()) << thing << "SG Ready mode changed" << smartGridState; switch (smartGridState) { - case StiebelEltronModbusConnection::SmartGridStateModeOne: + case StiebelEltronModbusTcpConnection::SmartGridStateModeOne: thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Off"); break; - case StiebelEltronModbusConnection::SmartGridStateModeTwo: + case StiebelEltronModbusTcpConnection::SmartGridStateModeTwo: thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Low"); break; - case StiebelEltronModbusConnection::SmartGridStateModeThree: + case StiebelEltronModbusTcpConnection::SmartGridStateModeThree: thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Standard"); break; - case StiebelEltronModbusConnection::SmartGridStateModeFour: + case StiebelEltronModbusTcpConnection::SmartGridStateModeFour: thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "High"); break; } }); - connect(connection, &StiebelEltronModbusConnection::sgReadyActiveChanged, thing, + connect(connection, &StiebelEltronModbusTcpConnection::sgReadyActiveChanged, thing, [thing](bool smartGridActive) { qCDebug(dcStiebelEltron()) << thing << "SG Ready activation changed" << smartGridActive; thing->setStateValue(stiebelEltronSgReadyActiveStateTypeId, smartGridActive); @@ -266,7 +266,7 @@ void IntegrationPluginStiebelEltron::postSetupThing(Thing *thing) { qCDebug(dcStiebelEltron()) << "Starting plugin timer..."; m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); connect(m_pluginTimer, &PluginTimer::timeout, this, [this] { - foreach (StiebelEltronModbusConnection *connection, m_connections) { + foreach (StiebelEltronModbusTcpConnection *connection, m_connections) { if (connection->connected()) { connection->update(); } @@ -291,7 +291,7 @@ void IntegrationPluginStiebelEltron::thingRemoved(Thing *thing) { void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { Thing *thing = info->thing(); - StiebelEltronModbusConnection *connection = m_connections.value(thing); + StiebelEltronModbusTcpConnection *connection = m_connections.value(thing); if (!connection->connected()) { qCWarning(dcStiebelEltron()) << "Could not execute action. The modbus connection is currently " @@ -345,15 +345,15 @@ void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) { info->action().paramValue(stiebelEltronSgReadyModeActionSgReadyModeParamTypeId).toString(); qCDebug(dcStiebelEltron()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params(); - StiebelEltronModbusConnection::SmartGridState sgReadyState; + StiebelEltronModbusTcpConnection::SmartGridState sgReadyState; if (sgReadyModeString == "Off") { - sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeOne; + sgReadyState = StiebelEltronModbusTcpConnection::SmartGridStateModeOne; } else if (sgReadyModeString == "Low") { - sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeTwo; + sgReadyState = StiebelEltronModbusTcpConnection::SmartGridStateModeTwo; } else if (sgReadyModeString == "Standard") { - sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeThree; + sgReadyState = StiebelEltronModbusTcpConnection::SmartGridStateModeThree; } else if (sgReadyModeString == "High") { - sgReadyState = StiebelEltronModbusConnection::SmartGridStateModeFour; + sgReadyState = StiebelEltronModbusTcpConnection::SmartGridStateModeFour; } else { qCWarning(dcStiebelEltron()) << "Failed to set SG Ready mode. An unknown SG Ready mode was passed: " << sgReadyModeString; diff --git a/stiebeleltron/integrationpluginstiebeleltron.h b/stiebeleltron/integrationpluginstiebeleltron.h index 769b641..260253d 100644 --- a/stiebeleltron/integrationpluginstiebeleltron.h +++ b/stiebeleltron/integrationpluginstiebeleltron.h @@ -31,9 +31,10 @@ #ifndef INTEGRATIONPLUGINSTIEBELELTRON_H #define INTEGRATIONPLUGINSTIEBELELTRON_H -#include "plugintimer.h" -#include "integrations/integrationplugin.h" -#include "stiebeleltronmodbusconnection.h" +#include +#include + +#include "stiebeleltronmodbustcpconnection.h" class IntegrationPluginStiebelEltron: public IntegrationPlugin { @@ -55,7 +56,7 @@ public: private: PluginTimer *m_pluginTimer = nullptr; - QHash m_connections; + QHash m_connections; }; diff --git a/stiebeleltron/stiebel-eltron-registers.json b/stiebeleltron/stiebel-eltron-registers.json index ba53e04..771e95b 100644 --- a/stiebeleltron/stiebel-eltron-registers.json +++ b/stiebeleltron/stiebel-eltron-registers.json @@ -1,4 +1,5 @@ { + "className": "StiebelEltron", "protocol": "TCP", "endianness": "BigEndian", "enums": [ @@ -319,5 +320,6 @@ "defaultValue": "SmartGridStateModeThree", "access": "RW" } - ] + ], + "blocks": [ ] } diff --git a/stiebeleltron/stiebeleltron.pro b/stiebeleltron/stiebeleltron.pro index 78483b0..95e34d7 100644 --- a/stiebeleltron/stiebeleltron.pro +++ b/stiebeleltron/stiebeleltron.pro @@ -1,16 +1,13 @@ include(../plugins.pri) -QT += network serialbus +# Generate modbus connection +MODBUS_CONNECTIONS += stiebel-eltron-registers.json +#MODBUS_TOOLS_CONFIG += VERBOSE +include(../modbus.pri) HEADERS += \ - integrationpluginstiebeleltron.h \ - stiebeleltronmodbusconnection.h \ - ../modbus/modbustcpmaster.h \ - ../modbus/modbusdatautils.h + integrationpluginstiebeleltron.h SOURCES += \ - integrationpluginstiebeleltron.cpp \ - stiebeleltronmodbusconnection.cpp \ - ../modbus/modbustcpmaster.cpp \ - ../modbus/modbusdatautils.cpp + integrationpluginstiebeleltron.cpp diff --git a/stiebeleltron/stiebeleltronmodbusconnection.cpp b/stiebeleltron/stiebeleltronmodbusconnection.cpp deleted file mode 100644 index 9b518b6..0000000 --- a/stiebeleltron/stiebeleltronmodbusconnection.cpp +++ /dev/null @@ -1,1051 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2022, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -#include "stiebeleltronmodbusconnection.h" -#include "loggingcategories.h" - -NYMEA_LOGGING_CATEGORY(dcStiebelEltronModbusConnection, "StiebelEltronModbusConnection") - -StiebelEltronModbusConnection::StiebelEltronModbusConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) : - ModbusTCPMaster(hostAddress, port, parent), - m_slaveId(slaveId) -{ - -} - -float StiebelEltronModbusConnection::outdoorTemperature() const -{ - return m_outdoorTemperature; -} - -float StiebelEltronModbusConnection::flowTemperature() const -{ - return m_flowTemperature; -} - -float StiebelEltronModbusConnection::hotWaterTemperature() const -{ - return m_hotWaterTemperature; -} - -float StiebelEltronModbusConnection::hotGasTemperature1() const -{ - return m_hotGasTemperature1; -} - -float StiebelEltronModbusConnection::hotGasTemperature2() const -{ - return m_hotGasTemperature2; -} - -float StiebelEltronModbusConnection::SourceTemperature() const -{ - return m_SourceTemperature; -} - -float StiebelEltronModbusConnection::roomTemperatureFEK() const -{ - return m_roomTemperatureFEK; -} - -float StiebelEltronModbusConnection::returnTemperature() const -{ - return m_returnTemperature; -} - -float StiebelEltronModbusConnection::solarCollectorTemperature() const -{ - return m_solarCollectorTemperature; -} - -float StiebelEltronModbusConnection::solarStorageTankTemperature() const -{ - return m_solarStorageTankTemperature; -} - -float StiebelEltronModbusConnection::storageTankTemperature() const -{ - return m_storageTankTemperature; -} - -float StiebelEltronModbusConnection::externalHeatSourceTemperature() const -{ - return m_externalHeatSourceTemperature; -} - -quint32 StiebelEltronModbusConnection::heatingEnergy() const -{ - return m_heatingEnergy; -} - -quint32 StiebelEltronModbusConnection::hotWaterEnergy() const -{ - return m_hotWaterEnergy; -} - -quint32 StiebelEltronModbusConnection::consumedEnergyHeating() const -{ - return m_consumedEnergyHeating; -} - -quint32 StiebelEltronModbusConnection::consumedEnergyHotWater() const -{ - return m_consumedEnergyHotWater; -} - -StiebelEltronModbusConnection::OperatingMode StiebelEltronModbusConnection::operatingMode() const -{ - return m_operatingMode; -} - -quint16 StiebelEltronModbusConnection::systemStatus() const -{ - return m_systemStatus; -} - -quint16 StiebelEltronModbusConnection::sgReadyStateRO() const -{ - return m_sgReadyStateRO; -} - -quint16 StiebelEltronModbusConnection::sgReadyActive() const -{ - return m_sgReadyActive; -} - -QModbusReply *StiebelEltronModbusConnection::setSgReadyActive(quint16 sgReadyActive) -{ - QVector values = ModbusDataUtils::convertFromUInt16(sgReadyActive); - qCDebug(dcStiebelEltronModbusConnection()) << "--> Write \"SG ready active\" register:" << 4000 << "size:" << 1 << values; - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4000, values.count()); - request.setValues(values); - return sendWriteRequest(request, m_slaveId); -} - -StiebelEltronModbusConnection::SmartGridState StiebelEltronModbusConnection::sgReadyState() const -{ - return m_sgReadyState; -} - -QModbusReply *StiebelEltronModbusConnection::setSgReadyState(SmartGridState sgReadyState) -{ - QVector values = ModbusDataUtils::convertFromUInt32(static_cast(sgReadyState), ModbusDataUtils::ByteOrderBigEndian); - qCDebug(dcStiebelEltronModbusConnection()) << "--> Write \"SG Ready mode\" register:" << 4001 << "size:" << 2 << values; - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4001, values.count()); - request.setValues(values); - return sendWriteRequest(request, m_slaveId); -} - -void StiebelEltronModbusConnection::initialize() -{ - // No init registers defined. Nothing to be done and we are finished. - emit initializationFinished(); -} - -void StiebelEltronModbusConnection::update() -{ - updateOutdoorTemperature(); - updateFlowTemperature(); - updateHotWaterTemperature(); - updateHotGasTemperature1(); - updateHotGasTemperature2(); - updateSourceTemperature(); - updateRoomTemperatureFEK(); - updateReturnTemperature(); - updateSolarCollectorTemperature(); - updateSolarStorageTankTemperature(); - updateStorageTankTemperature(); - updateExternalHeatSourceTemperature(); - updateHeatingEnergy(); - updateHotWaterEnergy(); - updateConsumedEnergyHeating(); - updateConsumedEnergyHotWater(); - updateOperatingMode(); - updateSystemStatus(); - updateSgReadyStateRO(); - updateSgReadyActive(); - updateSgReadyState(); -} - -void StiebelEltronModbusConnection::updateOutdoorTemperature() -{ - // Update registers from Outdoor temperature - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Outdoor temperature\" register:" << 506 << "size:" << 1; - QModbusReply *reply = readOutdoorTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Outdoor temperature\" register" << 506 << "size:" << 1 << values; - float receivedOutdoorTemperature = ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, -1); - if (m_outdoorTemperature != receivedOutdoorTemperature) { - m_outdoorTemperature = receivedOutdoorTemperature; - emit outdoorTemperatureChanged(m_outdoorTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Outdoor temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Outdoor temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateFlowTemperature() -{ - // Update registers from Flow temperature - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Flow temperature\" register:" << 514 << "size:" << 1; - QModbusReply *reply = readFlowTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Flow temperature\" register" << 514 << "size:" << 1 << values; - float receivedFlowTemperature = ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, -1); - if (m_flowTemperature != receivedFlowTemperature) { - m_flowTemperature = receivedFlowTemperature; - emit flowTemperatureChanged(m_flowTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Flow temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Flow temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateHotWaterTemperature() -{ - // Update registers from Hot water temperature - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Hot water temperature\" register:" << 521 << "size:" << 1; - QModbusReply *reply = readHotWaterTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Hot water temperature\" register" << 521 << "size:" << 1 << values; - float receivedHotWaterTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_hotWaterTemperature != receivedHotWaterTemperature) { - m_hotWaterTemperature = receivedHotWaterTemperature; - emit hotWaterTemperatureChanged(m_hotWaterTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Hot water temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Hot water temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateHotGasTemperature1() -{ - // Update registers from Hot gas temperature HP 1 - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Hot gas temperature HP 1\" register:" << 543 << "size:" << 1; - QModbusReply *reply = readHotGasTemperature1(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Hot gas temperature HP 1\" register" << 543 << "size:" << 1 << values; - float receivedHotGasTemperature1 = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_hotGasTemperature1 != receivedHotGasTemperature1) { - m_hotGasTemperature1 = receivedHotGasTemperature1; - emit hotGasTemperature1Changed(m_hotGasTemperature1); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Hot gas temperature HP 1\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Hot gas temperature HP 1\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateHotGasTemperature2() -{ - // Update registers from Hot gas temperature HP 2 - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Hot gas temperature HP 2\" register:" << 550 << "size:" << 1; - QModbusReply *reply = readHotGasTemperature2(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Hot gas temperature HP 2\" register" << 550 << "size:" << 1 << values; - float receivedHotGasTemperature2 = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_hotGasTemperature2 != receivedHotGasTemperature2) { - m_hotGasTemperature2 = receivedHotGasTemperature2; - emit hotGasTemperature2Changed(m_hotGasTemperature2); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Hot gas temperature HP 2\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Hot gas temperature HP 2\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateSourceTemperature() -{ - // Update registers from Source temperature - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Source temperature\" register:" << 562 << "size:" << 1; - QModbusReply *reply = readSourceTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Source temperature\" register" << 562 << "size:" << 1 << values; - float receivedSourceTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_SourceTemperature != receivedSourceTemperature) { - m_SourceTemperature = receivedSourceTemperature; - emit SourceTemperatureChanged(m_SourceTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Source temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Source temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateRoomTemperatureFEK() -{ - // Update registers from Room temperature FEK - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Room temperature FEK\" register:" << 502 << "size:" << 1; - QModbusReply *reply = readRoomTemperatureFEK(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Room temperature FEK\" register" << 502 << "size:" << 1 << values; - float receivedRoomTemperatureFEK = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_roomTemperatureFEK != receivedRoomTemperatureFEK) { - m_roomTemperatureFEK = receivedRoomTemperatureFEK; - emit roomTemperatureFEKChanged(m_roomTemperatureFEK); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Room temperature FEK\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Room temperature FEK\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateReturnTemperature() -{ - // Update registers from Return temperature - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Return temperature\" register:" << 515 << "size:" << 1; - QModbusReply *reply = readReturnTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Return temperature\" register" << 515 << "size:" << 1 << values; - float receivedReturnTemperature = ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, -1); - if (m_returnTemperature != receivedReturnTemperature) { - m_returnTemperature = receivedReturnTemperature; - emit returnTemperatureChanged(m_returnTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Return temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Return temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateSolarCollectorTemperature() -{ - // Update registers from Solar collector temperature - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Solar collector temperature\" register:" << 527 << "size:" << 1; - QModbusReply *reply = readSolarCollectorTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Solar collector temperature\" register" << 527 << "size:" << 1 << values; - float receivedSolarCollectorTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_solarCollectorTemperature != receivedSolarCollectorTemperature) { - m_solarCollectorTemperature = receivedSolarCollectorTemperature; - emit solarCollectorTemperatureChanged(m_solarCollectorTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Solar collector temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Solar collector temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateSolarStorageTankTemperature() -{ - // Update registers from Solar storage tank temperature - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Solar storage tank temperature\" register:" << 528 << "size:" << 1; - QModbusReply *reply = readSolarStorageTankTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Solar storage tank temperature\" register" << 528 << "size:" << 1 << values; - float receivedSolarStorageTankTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_solarStorageTankTemperature != receivedSolarStorageTankTemperature) { - m_solarStorageTankTemperature = receivedSolarStorageTankTemperature; - emit solarStorageTankTemperatureChanged(m_solarStorageTankTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Solar storage tank temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Solar storage tank temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateStorageTankTemperature() -{ - // Update registers from Storage tank temperature - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Storage tank temperature\" register:" << 517 << "size:" << 1; - QModbusReply *reply = readStorageTankTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Storage tank temperature\" register" << 517 << "size:" << 1 << values; - float receivedStorageTankTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_storageTankTemperature != receivedStorageTankTemperature) { - m_storageTankTemperature = receivedStorageTankTemperature; - emit storageTankTemperatureChanged(m_storageTankTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Storage tank temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Storage tank temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateExternalHeatSourceTemperature() -{ - // Update registers from External heat source temperature - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"External heat source temperature\" register:" << 530 << "size:" << 1; - QModbusReply *reply = readExternalHeatSourceTemperature(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"External heat source temperature\" register" << 530 << "size:" << 1 << values; - float receivedExternalHeatSourceTemperature = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1); - if (m_externalHeatSourceTemperature != receivedExternalHeatSourceTemperature) { - m_externalHeatSourceTemperature = receivedExternalHeatSourceTemperature; - emit externalHeatSourceTemperatureChanged(m_externalHeatSourceTemperature); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"External heat source temperature\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"External heat source temperature\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateHeatingEnergy() -{ - // Update registers from Heating energy - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Heating energy\" register:" << 3501 << "size:" << 2; - QModbusReply *reply = readHeatingEnergy(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Heating energy\" register" << 3501 << "size:" << 2 << values; - quint32 receivedHeatingEnergy = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_heatingEnergy != receivedHeatingEnergy) { - m_heatingEnergy = receivedHeatingEnergy; - emit heatingEnergyChanged(m_heatingEnergy); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Heating energy\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Heating energy\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateHotWaterEnergy() -{ - // Update registers from Hot water energy - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Hot water energy\" register:" << 3504 << "size:" << 2; - QModbusReply *reply = readHotWaterEnergy(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Hot water energy\" register" << 3504 << "size:" << 2 << values; - quint32 receivedHotWaterEnergy = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_hotWaterEnergy != receivedHotWaterEnergy) { - m_hotWaterEnergy = receivedHotWaterEnergy; - emit hotWaterEnergyChanged(m_hotWaterEnergy); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Hot water energy\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Hot water energy\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateConsumedEnergyHeating() -{ - // Update registers from Consumed energy heating - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Consumed energy heating\" register:" << 3511 << "size:" << 2; - QModbusReply *reply = readConsumedEnergyHeating(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Consumed energy heating\" register" << 3511 << "size:" << 2 << values; - quint32 receivedConsumedEnergyHeating = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_consumedEnergyHeating != receivedConsumedEnergyHeating) { - m_consumedEnergyHeating = receivedConsumedEnergyHeating; - emit consumedEnergyHeatingChanged(m_consumedEnergyHeating); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Consumed energy heating\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Consumed energy heating\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateConsumedEnergyHotWater() -{ - // Update registers from Consumed energy hot water - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Consumed energy hot water\" register:" << 3514 << "size:" << 2; - QModbusReply *reply = readConsumedEnergyHotWater(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Consumed energy hot water\" register" << 3514 << "size:" << 2 << values; - quint32 receivedConsumedEnergyHotWater = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian); - if (m_consumedEnergyHotWater != receivedConsumedEnergyHotWater) { - m_consumedEnergyHotWater = receivedConsumedEnergyHotWater; - emit consumedEnergyHotWaterChanged(m_consumedEnergyHotWater); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Consumed energy hot water\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Consumed energy hot water\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateOperatingMode() -{ - // Update registers from Operating mode - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Operating mode\" register:" << 1500 << "size:" << 1; - QModbusReply *reply = readOperatingMode(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Operating mode\" register" << 1500 << "size:" << 1 << values; - OperatingMode receivedOperatingMode = static_cast(ModbusDataUtils::convertToUInt16(values)); - if (m_operatingMode != receivedOperatingMode) { - m_operatingMode = receivedOperatingMode; - emit operatingModeChanged(m_operatingMode); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Operating mode\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Operating mode\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateSystemStatus() -{ - // Update registers from System status - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"System status\" register:" << 2500 << "size:" << 1; - QModbusReply *reply = readSystemStatus(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"System status\" register" << 2500 << "size:" << 1 << values; - quint16 receivedSystemStatus = ModbusDataUtils::convertToUInt16(values); - if (m_systemStatus != receivedSystemStatus) { - m_systemStatus = receivedSystemStatus; - emit systemStatusChanged(m_systemStatus); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"System status\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"System status\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateSgReadyStateRO() -{ - // Update registers from Smart grid status - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"Smart grid status\" register:" << 5000 << "size:" << 1; - QModbusReply *reply = readSgReadyStateRO(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"Smart grid status\" register" << 5000 << "size:" << 1 << values; - quint16 receivedSgReadyStateRO = ModbusDataUtils::convertToUInt16(values); - if (m_sgReadyStateRO != receivedSgReadyStateRO) { - m_sgReadyStateRO = receivedSgReadyStateRO; - emit sgReadyStateROChanged(m_sgReadyStateRO); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"Smart grid status\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"Smart grid status\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateSgReadyActive() -{ - // Update registers from SG ready active - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"SG ready active\" register:" << 4000 << "size:" << 1; - QModbusReply *reply = readSgReadyActive(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"SG ready active\" register" << 4000 << "size:" << 1 << values; - quint16 receivedSgReadyActive = ModbusDataUtils::convertToUInt16(values); - if (m_sgReadyActive != receivedSgReadyActive) { - m_sgReadyActive = receivedSgReadyActive; - emit sgReadyActiveChanged(m_sgReadyActive); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"SG ready active\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"SG ready active\" registers from" << hostAddress().toString() << errorString(); - } -} - -void StiebelEltronModbusConnection::updateSgReadyState() -{ - // Update registers from SG Ready mode - qCDebug(dcStiebelEltronModbusConnection()) << "--> Read \"SG Ready mode\" register:" << 4001 << "size:" << 2; - QModbusReply *reply = readSgReadyState(); - if (reply) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, this, [this, reply](){ - if (reply->error() == QModbusDevice::NoError) { - const QModbusDataUnit unit = reply->result(); - const QVector values = unit.values(); - qCDebug(dcStiebelEltronModbusConnection()) << "<-- Response from \"SG Ready mode\" register" << 4001 << "size:" << 2 << values; - SmartGridState receivedSgReadyState = static_cast(ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian)); - if (m_sgReadyState != receivedSgReadyState) { - m_sgReadyState = receivedSgReadyState; - emit sgReadyStateChanged(m_sgReadyState); - } - } - }); - - connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ - qCWarning(dcStiebelEltronModbusConnection()) << "Modbus reply error occurred while updating \"SG Ready mode\" registers from" << hostAddress().toString() << error << reply->errorString(); - emit reply->finished(); // To make sure it will be deleted - }); - } else { - delete reply; // Broadcast reply returns immediatly - } - } else { - qCWarning(dcStiebelEltronModbusConnection()) << "Error occurred while reading \"SG Ready mode\" registers from" << hostAddress().toString() << errorString(); - } -} - -QModbusReply *StiebelEltronModbusConnection::readOutdoorTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 506, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readFlowTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 514, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readHotWaterTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 521, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readHotGasTemperature1() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 543, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readHotGasTemperature2() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 550, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readSourceTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 562, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readRoomTemperatureFEK() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 502, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readReturnTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 515, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readSolarCollectorTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 527, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readSolarStorageTankTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 528, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readStorageTankTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 517, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readExternalHeatSourceTemperature() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 530, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readHeatingEnergy() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 3501, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readHotWaterEnergy() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 3504, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readConsumedEnergyHeating() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 3511, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readConsumedEnergyHotWater() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 3514, 2); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readOperatingMode() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 1500, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readSystemStatus() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 2500, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readSgReadyStateRO() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, 5000, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readSgReadyActive() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4000, 1); - return sendReadRequest(request, m_slaveId); -} - -QModbusReply *StiebelEltronModbusConnection::readSgReadyState() -{ - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 4001, 2); - return sendReadRequest(request, m_slaveId); -} - -void StiebelEltronModbusConnection::verifyInitFinished() -{ - if (m_pendingInitReplies.isEmpty()) { - qCDebug(dcStiebelEltronModbusConnection()) << "Initialization finished of StiebelEltronModbusConnection" << hostAddress().toString(); - emit initializationFinished(); - } -} - -QDebug operator<<(QDebug debug, StiebelEltronModbusConnection *stiebelEltronModbusConnection) -{ - debug.nospace().noquote() << "StiebelEltronModbusConnection(" << stiebelEltronModbusConnection->hostAddress().toString() << ":" << stiebelEltronModbusConnection->port() << ")" << "\n"; - debug.nospace().noquote() << " - Outdoor temperature:" << stiebelEltronModbusConnection->outdoorTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Flow temperature:" << stiebelEltronModbusConnection->flowTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Hot water temperature:" << stiebelEltronModbusConnection->hotWaterTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Hot gas temperature HP 1:" << stiebelEltronModbusConnection->hotGasTemperature1() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Hot gas temperature HP 2:" << stiebelEltronModbusConnection->hotGasTemperature2() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Source temperature:" << stiebelEltronModbusConnection->SourceTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Room temperature FEK:" << stiebelEltronModbusConnection->roomTemperatureFEK() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Return temperature:" << stiebelEltronModbusConnection->returnTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Solar collector temperature:" << stiebelEltronModbusConnection->solarCollectorTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Solar storage tank temperature:" << stiebelEltronModbusConnection->solarStorageTankTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Storage tank temperature:" << stiebelEltronModbusConnection->storageTankTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - External heat source temperature:" << stiebelEltronModbusConnection->externalHeatSourceTemperature() << " [°C]" << "\n"; - debug.nospace().noquote() << " - Heating energy:" << stiebelEltronModbusConnection->heatingEnergy() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Hot water energy:" << stiebelEltronModbusConnection->hotWaterEnergy() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Consumed energy heating:" << stiebelEltronModbusConnection->consumedEnergyHeating() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Consumed energy hot water:" << stiebelEltronModbusConnection->consumedEnergyHotWater() << " [kWh]" << "\n"; - debug.nospace().noquote() << " - Operating mode:" << stiebelEltronModbusConnection->operatingMode() << "\n"; - debug.nospace().noquote() << " - System status:" << stiebelEltronModbusConnection->systemStatus() << "\n"; - debug.nospace().noquote() << " - Smart grid status:" << stiebelEltronModbusConnection->sgReadyStateRO() << "\n"; - debug.nospace().noquote() << " - SG ready active:" << stiebelEltronModbusConnection->sgReadyActive() << "\n"; - debug.nospace().noquote() << " - SG Ready mode:" << stiebelEltronModbusConnection->sgReadyState() << "\n"; - return debug.quote().space(); -} - diff --git a/stiebeleltron/stiebeleltronmodbusconnection.h b/stiebeleltron/stiebeleltronmodbusconnection.h deleted file mode 100644 index e42c8b5..0000000 --- a/stiebeleltron/stiebeleltronmodbusconnection.h +++ /dev/null @@ -1,260 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2022, nymea GmbH -* Contact: contact@nymea.io -* -* This fileDescriptor is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef STIEBELELTRONMODBUSCONNECTION_H -#define STIEBELELTRONMODBUSCONNECTION_H - -#include - -#include "../modbus/modbusdatautils.h" -#include "../modbus/modbustcpmaster.h" - -class StiebelEltronModbusConnection : public ModbusTCPMaster -{ - Q_OBJECT -public: - enum Registers { - RegisterRoomTemperatureFEK = 502, - RegisterOutdoorTemperature = 506, - RegisterFlowTemperature = 514, - RegisterReturnTemperature = 515, - RegisterStorageTankTemperature = 517, - RegisterHotWaterTemperature = 521, - RegisterSolarCollectorTemperature = 527, - RegisterSolarStorageTankTemperature = 528, - RegisterExternalHeatSourceTemperature = 530, - RegisterHotGasTemperature1 = 543, - RegisterHotGasTemperature2 = 550, - RegisterSourceTemperature = 562, - RegisterOperatingMode = 1500, - RegisterSystemStatus = 2500, - RegisterHeatingEnergy = 3501, - RegisterHotWaterEnergy = 3504, - RegisterConsumedEnergyHeating = 3511, - RegisterConsumedEnergyHotWater = 3514, - RegisterSgReadyActive = 4000, - RegisterSgReadyState = 4001, - RegisterSgReadyStateRO = 5000 - }; - Q_ENUM(Registers) - - enum OperatingMode { - OperatingModeEmergency = 0, - OperatingModeStandby = 1, - OperatingModeProgram = 2, - OperatingModeComfort = 3, - OperatingModeEco = 4, - OperatingModeHotWater = 5 - }; - Q_ENUM(OperatingMode) - - enum SmartGridState { - SmartGridStateModeOne = 1, - SmartGridStateModeTwo = 0, - SmartGridStateModeThree = 65536, - SmartGridStateModeFour = 65537 - }; - Q_ENUM(SmartGridState) - - explicit StiebelEltronModbusConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr); - ~StiebelEltronModbusConnection() = default; - - /* Outdoor temperature [°C] - Address: 506, Size: 1 */ - float outdoorTemperature() const; - - /* Flow temperature [°C] - Address: 514, Size: 1 */ - float flowTemperature() const; - - /* Hot water temperature [°C] - Address: 521, Size: 1 */ - float hotWaterTemperature() const; - - /* Hot gas temperature HP 1 [°C] - Address: 543, Size: 1 */ - float hotGasTemperature1() const; - - /* Hot gas temperature HP 2 [°C] - Address: 550, Size: 1 */ - float hotGasTemperature2() const; - - /* Source temperature [°C] - Address: 562, Size: 1 */ - float SourceTemperature() const; - - /* Room temperature FEK [°C] - Address: 502, Size: 1 */ - float roomTemperatureFEK() const; - - /* Return temperature [°C] - Address: 515, Size: 1 */ - float returnTemperature() const; - - /* Solar collector temperature [°C] - Address: 527, Size: 1 */ - float solarCollectorTemperature() const; - - /* Solar storage tank temperature [°C] - Address: 528, Size: 1 */ - float solarStorageTankTemperature() const; - - /* Storage tank temperature [°C] - Address: 517, Size: 1 */ - float storageTankTemperature() const; - - /* External heat source temperature [°C] - Address: 530, Size: 1 */ - float externalHeatSourceTemperature() const; - - /* Heating energy [kWh] - Address: 3501, Size: 2 */ - quint32 heatingEnergy() const; - - /* Hot water energy [kWh] - Address: 3504, Size: 2 */ - quint32 hotWaterEnergy() const; - - /* Consumed energy heating [kWh] - Address: 3511, Size: 2 */ - quint32 consumedEnergyHeating() const; - - /* Consumed energy hot water [kWh] - Address: 3514, Size: 2 */ - quint32 consumedEnergyHotWater() const; - - /* Operating mode - Address: 1500, Size: 1 */ - OperatingMode operatingMode() const; - - /* System status - Address: 2500, Size: 1 */ - quint16 systemStatus() const; - - /* Smart grid status - Address: 5000, Size: 1 */ - quint16 sgReadyStateRO() const; - - /* SG ready active - Address: 4000, Size: 1 */ - quint16 sgReadyActive() const; - QModbusReply *setSgReadyActive(quint16 sgReadyActive); - - /* SG Ready mode - Address: 4001, Size: 2 */ - SmartGridState sgReadyState() const; - QModbusReply *setSgReadyState(SmartGridState sgReadyState); - - virtual void initialize(); - virtual void update(); - - void updateOutdoorTemperature(); - void updateFlowTemperature(); - void updateHotWaterTemperature(); - void updateHotGasTemperature1(); - void updateHotGasTemperature2(); - void updateSourceTemperature(); - void updateRoomTemperatureFEK(); - void updateReturnTemperature(); - void updateSolarCollectorTemperature(); - void updateSolarStorageTankTemperature(); - void updateStorageTankTemperature(); - void updateExternalHeatSourceTemperature(); - void updateHeatingEnergy(); - void updateHotWaterEnergy(); - void updateConsumedEnergyHeating(); - void updateConsumedEnergyHotWater(); - void updateOperatingMode(); - void updateSystemStatus(); - void updateSgReadyStateRO(); - void updateSgReadyActive(); - void updateSgReadyState(); - -signals: - void initializationFinished(); - - void outdoorTemperatureChanged(float outdoorTemperature); - void flowTemperatureChanged(float flowTemperature); - void hotWaterTemperatureChanged(float hotWaterTemperature); - void hotGasTemperature1Changed(float hotGasTemperature1); - void hotGasTemperature2Changed(float hotGasTemperature2); - void SourceTemperatureChanged(float SourceTemperature); - void roomTemperatureFEKChanged(float roomTemperatureFEK); - void returnTemperatureChanged(float returnTemperature); - void solarCollectorTemperatureChanged(float solarCollectorTemperature); - void solarStorageTankTemperatureChanged(float solarStorageTankTemperature); - void storageTankTemperatureChanged(float storageTankTemperature); - void externalHeatSourceTemperatureChanged(float externalHeatSourceTemperature); - void heatingEnergyChanged(quint32 heatingEnergy); - void hotWaterEnergyChanged(quint32 hotWaterEnergy); - void consumedEnergyHeatingChanged(quint32 consumedEnergyHeating); - void consumedEnergyHotWaterChanged(quint32 consumedEnergyHotWater); - void operatingModeChanged(OperatingMode operatingMode); - void systemStatusChanged(quint16 systemStatus); - void sgReadyStateROChanged(quint16 sgReadyStateRO); - void sgReadyActiveChanged(quint16 sgReadyActive); - void sgReadyStateChanged(SmartGridState sgReadyState); - -protected: - QModbusReply *readOutdoorTemperature(); - QModbusReply *readFlowTemperature(); - QModbusReply *readHotWaterTemperature(); - QModbusReply *readHotGasTemperature1(); - QModbusReply *readHotGasTemperature2(); - QModbusReply *readSourceTemperature(); - QModbusReply *readRoomTemperatureFEK(); - QModbusReply *readReturnTemperature(); - QModbusReply *readSolarCollectorTemperature(); - QModbusReply *readSolarStorageTankTemperature(); - QModbusReply *readStorageTankTemperature(); - QModbusReply *readExternalHeatSourceTemperature(); - QModbusReply *readHeatingEnergy(); - QModbusReply *readHotWaterEnergy(); - QModbusReply *readConsumedEnergyHeating(); - QModbusReply *readConsumedEnergyHotWater(); - QModbusReply *readOperatingMode(); - QModbusReply *readSystemStatus(); - QModbusReply *readSgReadyStateRO(); - QModbusReply *readSgReadyActive(); - QModbusReply *readSgReadyState(); - - float m_outdoorTemperature = 0; - float m_flowTemperature = 0; - float m_hotWaterTemperature = 0; - float m_hotGasTemperature1 = 0; - float m_hotGasTemperature2 = 0; - float m_SourceTemperature = 0; - float m_roomTemperatureFEK = 0; - float m_returnTemperature = 0; - float m_solarCollectorTemperature = 0; - float m_solarStorageTankTemperature = 0; - float m_storageTankTemperature = 0; - float m_externalHeatSourceTemperature = 0; - quint32 m_heatingEnergy = 0; - quint32 m_hotWaterEnergy = 0; - quint32 m_consumedEnergyHeating = 0; - quint32 m_consumedEnergyHotWater = 0; - OperatingMode m_operatingMode = OperatingModeStandby; - quint16 m_systemStatus = 0; - quint16 m_sgReadyStateRO = 3; - quint16 m_sgReadyActive = 0; - SmartGridState m_sgReadyState = SmartGridStateModeThree; - -private: - quint16 m_slaveId = 1; - QVector m_pendingInitReplies; - - void verifyInitFinished(); - - -}; - -QDebug operator<<(QDebug debug, StiebelEltronModbusConnection *stiebelEltronModbusConnection); - -#endif // STIEBELELTRONMODBUSCONNECTION_H