nymea-plugins-modbus/mennekes/amtronecu.cpp

641 lines
35 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright (C) 2013 - 2024, nymea GmbH
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
*
* This file is part of nymea-plugins-modbus.
*
* nymea-plugins-modbus 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 3 of the License, or
* (at your option) any later version.
*
* nymea-plugins-modbus 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 nymea-plugins-modbus. If not, see <https://www.gnu.org/licenses/>.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "amtronecu.h"
#include "extern-plugininfo.h"
Q_DECLARE_LOGGING_CATEGORY(dcAmtronECUModbusTcpConnection)
AmtronECU::AmtronECU(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent)
: AmtronECUModbusTcpConnection{hostAddress, port, slaveId, parent}
{
}
AmtronECU::AmtronECU(ModbusTcpMaster *modbusTcpMaster, quint16 slaveId, QObject *parent)
: AmtronECUModbusTcpConnection{modbusTcpMaster, slaveId, parent}
{
}
bool AmtronECU::initialize()
{
if (!m_reachable) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Tried to initialize but the device is not to be reachable.";
return false;
}
if (m_initObject) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Tried to initialize but the init process is already running.";
return false;
}
m_initializing = true;
// Parent object for the init process
m_initObject = new QObject(this);
QModbusReply *reply = nullptr;
// This is a 2 Step initialization. First read the firmware version, if the firmware version is smaller than 5.22 we are done
// otherwise read also the model since we use that for detecting the exact manufacturer.
// Some useres have to stay on 5.12 due to calibration law which is not available on 5.22
// Read Firmware version
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read init \"Firmware version\" register:" << 100 << "size:" << 2;
reply = readFirmwareVersion();
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading \"Firmware version\" registers from" << m_modbusTcpMaster->hostAddress().toString() << m_modbusTcpMaster->errorString();
finishInitialization(false);
return false;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return false;
}
m_pendingInitReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, m_initObject, [this, reply](){
handleModbusError(reply->error());
m_pendingInitReplies.removeAll(reply);
if (reply->error() != QModbusDevice::NoError) {
finishInitialization(false);
return;
}
const QModbusDataUnit unit = reply->result();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from init \"Firmware version\" register" << 100 << "size:" << 2 << unit.values();
if (unit.values().size() == 2) {
processFirmwareVersionRegisterValues(unit.values());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"Firmware version\" registers" << 100 << "size:" << 2 << "returned different size than requested. Ignoring incomplete data" << unit.values();
finishInitialization(false);
return;
}
// Make sure this is the correct firmware version format (0x-- 0x2e 0x-- 0x--)
if ((m_firmwareVersion & 0x00ff0000) != 0x002e0000) {
qCWarning(dcMennekes()) << "Invalid firmware version format. Could not determin the firmware format from uint32" << QByteArray::fromHex(QByteArray::number(m_firmwareVersion, 16));
m_detectedVersion = VersionUnknown;
finishInitialization(false);
return;
}
// If the firmware version is smaller than 5.22 (Ascii of the uint32 firmware version property),
// we are done since the model registers have been introduced in Version 5.22
if (m_firmwareVersion < 0x352e3232) {
qCDebug(dcMennekes()) << "Detected firmware version" << QByteArray::fromHex(QByteArray::number(m_firmwareVersion, 16)) << ". Some features are only available from version >= 5.22.";
m_detectedVersion = VersionOld;
} else {
qCDebug(dcMennekes()) << "Detected firmware version" << QByteArray::fromHex(QByteArray::number(m_firmwareVersion, 16)) << "All features available.";
m_detectedVersion = VersionNew;
// Read Device model (>= 5.22)
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read init \"Device model (>= 5.22)\" register:" << 142 << "size:" << 10;
QModbusReply *reply = readModel();
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading \"Device model (>= 5.22)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << m_modbusTcpMaster->errorString();
finishInitialization(false);
return;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return;
}
m_pendingInitReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, m_initObject, [this, reply](){
handleModbusError(reply->error());
m_pendingInitReplies.removeAll(reply);
if (reply->error() != QModbusDevice::NoError) {
finishInitialization(false);
return;
}
const QModbusDataUnit unit = reply->result();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from init \"Device model (>= 5.22)\" register" << 142 << "size:" << 10 << unit.values();
if (unit.values().size() == 10) {
processModelRegisterValues(unit.values());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"Device model (>= 5.22)\" registers" << 142 << "size:" << 10 << "returned different size than requested. Ignoring incomplete data" << unit.values();
}
verifyInitFinished();
});
connect(reply, &QModbusReply::errorOccurred, m_initObject, [this, reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Device model (>= 5.22)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Device model (>= 5.22)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
}
verifyInitFinished();
});
connect(reply, &QModbusReply::errorOccurred, m_initObject, [this, reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Firmware version\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Firmware version\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
return true;
}
bool AmtronECU::update()
{
if (!reachable()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Tried to update but the device is not to be reachable.";
return false;
}
if (!m_modbusTcpMaster->connected())
return false;
if (!m_pendingUpdateReplies.isEmpty()) {
qCDebug(dcAmtronECUModbusTcpConnection()) << "Tried to update but there are still some update replies pending. Waiting for them to be finished...";
return true;
}
// First update common registers
// Then update registers only available for > 5.22
QModbusReply *reply = nullptr;
// Read CP signal state
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read \"CP signal state\" register:" << 122 << "size:" << 1;
reply = readCpSignalState();
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading \"CP signal state\" registers from" << m_modbusTcpMaster->hostAddress().toString() << m_modbusTcpMaster->errorString();
return false;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return false;
}
m_pendingUpdateReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
m_pendingUpdateReplies.removeAll(reply);
handleModbusError(reply->error());
if (reply->error() != QModbusDevice::NoError) {
verifyUpdateFinished();
return;
}
const QModbusDataUnit unit = reply->result();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from \"CP signal state\" register" << 122 << "size:" << 1 << unit.values();
if (unit.values().size() == 1) {
processCpSignalStateRegisterValues(unit.values());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"CP signal state\" registers" << 122 << "size:" << 1 << "returned different size than requested. Ignoring incomplete data" << unit.values();
}
verifyUpdateFinished();
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"CP signal state\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"CP signal state\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read Signalled current to EV
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read \"Signalled current to EV\" register:" << 706 << "size:" << 1;
reply = readSignalledCurrent();
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading \"Signalled current to EV\" registers from" << m_modbusTcpMaster->hostAddress().toString() << m_modbusTcpMaster->errorString();
return false;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return false;
}
m_pendingUpdateReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
m_pendingUpdateReplies.removeAll(reply);
handleModbusError(reply->error());
if (reply->error() != QModbusDevice::NoError) {
verifyUpdateFinished();
return;
}
const QModbusDataUnit unit = reply->result();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from \"Signalled current to EV\" register" << 706 << "size:" << 1 << unit.values();
if (unit.values().size() == 1) {
processSignalledCurrentRegisterValues(unit.values());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"Signalled current to EV\" registers" << 706 << "size:" << 1 << "returned different size than requested. Ignoring incomplete data" << unit.values();
}
verifyUpdateFinished();
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Signalled current to EV\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Signalled current to EV\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read Minimum current limit
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read \"Minimum current limit\" register:" << 712 << "size:" << 1;
reply = readMinCurrentLimit();
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading \"Minimum current limit\" registers from" << m_modbusTcpMaster->hostAddress().toString() << m_modbusTcpMaster->errorString();
return false;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return false;
}
m_pendingUpdateReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
m_pendingUpdateReplies.removeAll(reply);
handleModbusError(reply->error());
if (reply->error() != QModbusDevice::NoError) {
verifyUpdateFinished();
return;
}
const QModbusDataUnit unit = reply->result();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from \"Minimum current limit\" register" << 712 << "size:" << 1 << unit.values();
if (unit.values().size() == 1) {
processMinCurrentLimitRegisterValues(unit.values());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"Minimum current limit\" registers" << 712 << "size:" << 1 << "returned different size than requested. Ignoring incomplete data" << unit.values();
}
verifyUpdateFinished();
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Minimum current limit\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Minimum current limit\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read consumptions
reply = readBlockConsumptions();
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read block \"consumptions\" registers from:" << 200 << "size:" << 18;
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading block \"consumptions\" registers";
return false;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return false;
}
m_pendingUpdateReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
m_pendingUpdateReplies.removeAll(reply);
handleModbusError(reply->error());
if (reply->error() != QModbusDevice::NoError) {
verifyUpdateFinished();
return;
}
const QModbusDataUnit unit = reply->result();
const QVector<quint16> blockValues = unit.values();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from reading block \"consumptions\" register" << 200 << "size:" << 18 << blockValues;
if (blockValues.size() == 18) {
processMeterEnergyL1RegisterValues(blockValues.mid(0, 2));
processMeterEnergyL2RegisterValues(blockValues.mid(2, 2));
processMeterEnergyL3RegisterValues(blockValues.mid(4, 2));
processMeterPowerL1RegisterValues(blockValues.mid(6, 2));
processMeterPowerL2RegisterValues(blockValues.mid(8, 2));
processMeterPowerL3RegisterValues(blockValues.mid(10, 2));
processMeterCurrentL1RegisterValues(blockValues.mid(12, 2));
processMeterCurrentL2RegisterValues(blockValues.mid(14, 2));
processMeterCurrentL3RegisterValues(blockValues.mid(16, 2));
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"consumptions\" block registers" << 200 << "size:" << 18 << "returned different size than requested. Ignoring incomplete data" << blockValues;
}
verifyUpdateFinished();
});
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while updating block \"consumptions\" registers" << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while updating block \"consumptions\" registers" << error << reply->errorString();
}
});
// Read Charge Point availability ( Version < 5.22: 0 available, 1 unavailable | Version >= 5.22 1 available, 0 unavailable )
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read \"Charge Point availability ( Version < 5.22: 0 available, 1 unavailable | Version >= 5.22 1 available, 0 unavailable )\" register:" << 124 << "size:" << 1;
reply = readCpAvailability();
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading \"Charge Point availability ( Version < 5.22: 0 available, 1 unavailable | Version >= 5.22 1 available, 0 unavailable )\" registers from" << m_modbusTcpMaster->hostAddress().toString() << m_modbusTcpMaster->errorString();
return false;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return false;
}
m_pendingUpdateReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
m_pendingUpdateReplies.removeAll(reply);
handleModbusError(reply->error());
if (reply->error() != QModbusDevice::NoError) {
verifyUpdateFinished();
return;
}
const QModbusDataUnit unit = reply->result();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from \"Charge Point availability ( Version < 5.22: 0 available, 1 unavailable | Version >= 5.22 1 available, 0 unavailable )\" register" << 124 << "size:" << 1 << unit.values();
if (unit.values().size() == 1) {
processCpAvailabilityRegisterValues(unit.values());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"Charge Point availability ( Version < 5.22: 0 available, 1 unavailable | Version >= 5.22 1 available, 0 unavailable )\" registers" << 124 << "size:" << 1 << "returned different size than requested. Ignoring incomplete data" << unit.values();
}
verifyUpdateFinished();
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Charge Point availability ( Version < 5.22: 0 available, 1 unavailable | Version >= 5.22 1 available, 0 unavailable )\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Charge Point availability ( Version < 5.22: 0 available, 1 unavailable | Version >= 5.22 1 available, 0 unavailable )\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read HEMS current limit
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read \"HEMS current limit\" register:" << 1000 << "size:" << 1;
reply = readHemsCurrentLimit();
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading \"HEMS current limit\" registers from" << m_modbusTcpMaster->hostAddress().toString() << m_modbusTcpMaster->errorString();
return false;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return false;
}
m_pendingUpdateReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
m_pendingUpdateReplies.removeAll(reply);
handleModbusError(reply->error());
if (reply->error() != QModbusDevice::NoError) {
verifyUpdateFinished();
return;
}
const QModbusDataUnit unit = reply->result();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from \"HEMS current limit\" register" << 1000 << "size:" << 1 << unit.values();
if (unit.values().size() == 1) {
processHemsCurrentLimitRegisterValues(unit.values());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"HEMS current limit\" registers" << 1000 << "size:" << 1 << "returned different size than requested. Ignoring incomplete data" << unit.values();
}
verifyUpdateFinished();
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"HEMS current limit\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"HEMS current limit\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Only available on >= 5.22
if (m_detectedVersion == VersionNew) {
// Read Maximum current limit (>= 5.22)
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read \"Maximum current limit (>= 5.22)\" register:" << 715 << "size:" << 1;
reply = readMaxCurrentLimit();
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading \"Maximum current limit (>= 5.22)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << m_modbusTcpMaster->errorString();
return false;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return false;
}
m_pendingUpdateReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
m_pendingUpdateReplies.removeAll(reply);
handleModbusError(reply->error());
if (reply->error() != QModbusDevice::NoError) {
verifyUpdateFinished();
return;
}
const QModbusDataUnit unit = reply->result();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from \"Maximum current limit (>= 5.22)\" register" << 715 << "size:" << 1 << unit.values();
if (unit.values().size() == 1) {
processMaxCurrentLimitRegisterValues(unit.values());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"Maximum current limit (>= 5.22)\" registers" << 715 << "size:" << 1 << "returned different size than requested. Ignoring incomplete data" << unit.values();
}
verifyUpdateFinished();
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Maximum current limit (>= 5.22)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Maximum current limit (>= 5.22)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read Charged energy for current session (>= 5.22)
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read \"Charged energy for current session (>= 5.22)\" register:" << 716 << "size:" << 2;
reply = readChargedEnergy();
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading \"Charged energy for current session (>= 5.22)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << m_modbusTcpMaster->errorString();
return false;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return false;
}
m_pendingUpdateReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
m_pendingUpdateReplies.removeAll(reply);
handleModbusError(reply->error());
if (reply->error() != QModbusDevice::NoError) {
verifyUpdateFinished();
return;
}
const QModbusDataUnit unit = reply->result();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from \"Charged energy for current session (>= 5.22)\" register" << 716 << "size:" << 2 << unit.values();
if (unit.values().size() == 2) {
processChargedEnergyRegisterValues(unit.values());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"Charged energy for current session (>= 5.22)\" registers" << 716 << "size:" << 2 << "returned different size than requested. Ignoring incomplete data" << unit.values();
}
verifyUpdateFinished();
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Charged energy for current session (>= 5.22)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while reading \"Charged energy for current session (>= 5.22)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read consumptionsTotals
reply = readBlockConsumptionsTotals();
qCDebug(dcAmtronECUModbusTcpConnection()) << "--> Read block \"consumptionsTotals\" registers from:" << 218 << "size:" << 10;
if (!reply) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Error occurred while reading block \"consumptionsTotals\" registers";
return false;
}
if (reply->isFinished()) {
reply->deleteLater(); // Broadcast reply returns immediatly
return false;
}
m_pendingUpdateReplies.append(reply);
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
m_pendingUpdateReplies.removeAll(reply);
handleModbusError(reply->error());
if (reply->error() != QModbusDevice::NoError) {
verifyUpdateFinished();
return;
}
const QModbusDataUnit unit = reply->result();
const QVector<quint16> blockValues = unit.values();
qCDebug(dcAmtronECUModbusTcpConnection()) << "<-- Response from reading block \"consumptionsTotals\" register" << 218 << "size:" << 10 << blockValues;
if (blockValues.size() == 10) {
processMeterTotoalEnergyRegisterValues(blockValues.mid(0, 2));
processMeterTotalPowerRegisterValues(blockValues.mid(2, 2));
processMeterVoltageL1RegisterValues(blockValues.mid(4, 2));
processMeterVoltageL2RegisterValues(blockValues.mid(6, 2));
processMeterVoltageL3RegisterValues(blockValues.mid(8, 2));
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Reading from \"consumptionsTotals\" block registers" << 218 << "size:" << 10 << "returned different size than requested. Ignoring incomplete data" << blockValues;
}
verifyUpdateFinished();
});
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){
QModbusResponse response = reply->rawResult();
if (reply->error() == QModbusDevice::ProtocolError && response.isException()) {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while updating block \"consumptionsTotals\" registers" << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcAmtronECUModbusTcpConnection()) << "Modbus reply error occurred while updating block \"consumptionsTotals\" registers" << error << reply->errorString();
}
});
}
return true;
}
AmtronECU::Version AmtronECU::detectedVersion() const
{
return m_detectedVersion;
}
QDebug operator<<(QDebug debug, AmtronECU *amtronECU)
{
debug.nospace().noquote() << "AmtronECU(" << amtronECU->modbusTcpMaster()->hostAddress().toString() << ":" << amtronECU->modbusTcpMaster()->port() << ")" << "\n";
debug.nospace().noquote() << " - holding 100 | Firmware version: " << amtronECU->firmwareVersion() << "\n";
debug.nospace().noquote() << " - holding 122 | CP signal state: " << amtronECU->cpSignalState() << "\n";
debug.nospace().noquote() << " - holding 124 | Charge Point availability ( Version < 5.22: 0 available, 1 unavailable | Version >= 5.22 1 available, 0 unavailable ): " << amtronECU->cpAvailability() << "\n";
debug.nospace().noquote() << " - holding 200 | Meter energy L1: " << amtronECU->meterEnergyL1() << " [Wh]" << "\n";
debug.nospace().noquote() << " - holding 202 | Meter energy L2: " << amtronECU->meterEnergyL2() << " [Wh]" << "\n";
debug.nospace().noquote() << " - holding 204 | Meter energy L3: " << amtronECU->meterEnergyL3() << " [Wh]" << "\n";
debug.nospace().noquote() << " - holding 206 | Meter power L1: " << amtronECU->meterPowerL1() << " [W]" << "\n";
debug.nospace().noquote() << " - holding 208 | Meter power L2: " << amtronECU->meterPowerL2() << " [W]" << "\n";
debug.nospace().noquote() << " - holding 210 | Meter power L3: " << amtronECU->meterPowerL3() << " [W]" << "\n";
debug.nospace().noquote() << " - holding 212 | Meter current L1: " << amtronECU->meterCurrentL1() << " [mA]" << "\n";
debug.nospace().noquote() << " - holding 214 | Meter current L2: " << amtronECU->meterCurrentL2() << " [mA]" << "\n";
debug.nospace().noquote() << " - holding 216 | Meter current L3: " << amtronECU->meterCurrentL3() << " [mA]" << "\n";
debug.nospace().noquote() << " - holding 706 | Signalled current to EV: " << amtronECU->signalledCurrent() << " [A]" << "\n";
debug.nospace().noquote() << " - holding 712 | Minimum current limit: " << amtronECU->minCurrentLimit() << " [A]" << "\n";
debug.nospace().noquote() << " - holding 1000 | HEMS current limit: " << amtronECU->hemsCurrentLimit() << " [A]" << "\n";
if (amtronECU->detectedVersion() == AmtronECU::VersionNew) {
debug.nospace().noquote() << " - holding 142 | Device model (>= 5.22): " << amtronECU->model() << "\n";
debug.nospace().noquote() << " - holding 218 | Meter total energy (>= 5.22): " << amtronECU->meterTotoalEnergy() << " [Wh]" << "\n";
debug.nospace().noquote() << " - holding 220 | Meter total power (>= 5.22): " << amtronECU->meterTotalPower() << " [W]" << "\n";
debug.nospace().noquote() << " - holding 222 | Meter voltage L1 (>= 5.22): " << amtronECU->meterVoltageL1() << " [V]" << "\n";
debug.nospace().noquote() << " - holding 224 | Meter voltage L2 (>= 5.22): " << amtronECU->meterVoltageL2() << " [V]" << "\n";
debug.nospace().noquote() << " - holding 226 | Meter voltage L3 (>= 5.22): " << amtronECU->meterVoltageL3() << " [V]" << "\n";
debug.nospace().noquote() << " - holding 715 | Maximum current limit (>= 5.22): " << amtronECU->maxCurrentLimit() << " [A]" << "\n";
debug.nospace().noquote() << " - holding 716 | Charged energy for current session (>= 5.22): " << amtronECU->chargedEnergy() << " [Wh]" << "\n";
}
return debug.quote().space();
}