Add backwards compatibility for modbus protocol

Add verification for new registers

Signed-off-by: Martin Lukas <martin.lukas@chargebyte.com>
pull/179/head
Martin Lukas 2024-08-06 07:09:22 +02:00
parent 5affe6614e
commit 5d15fc9e16
7 changed files with 615 additions and 41 deletions

View File

@ -8,8 +8,10 @@ include(../modbus.pri)
HEADERS += \
integrationplugininro.h \
pantabox.h \
pantaboxdiscovery.h
SOURCES += \
integrationplugininro.cpp \
pantabox.cpp \
pantaboxdiscovery.cpp

View File

@ -136,7 +136,7 @@ void IntegrationPluginInro::postSetupThing(Thing *thing)
if (!m_refreshTimer) {
m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(2);
connect(m_refreshTimer, &PluginTimer::timeout, this, [this] {
foreach (PantaboxModbusTcpConnection *connection, m_connections) {
foreach (Pantabox *connection, m_connections) {
if (connection->reachable()) {
connection->update();
}
@ -152,7 +152,7 @@ void IntegrationPluginInro::executeAction(ThingActionInfo *info)
{
if (info->thing()->thingClassId() == pantaboxThingClassId) {
PantaboxModbusTcpConnection *connection = m_connections.value(info->thing());
Pantabox *connection = m_connections.value(info->thing());
if (!connection->reachable()) {
qCWarning(dcInro()) << "Cannot execute action. The PANTABOX is not reachable";
@ -248,7 +248,7 @@ void IntegrationPluginInro::thingRemoved(Thing *thing)
qCDebug(dcInro()) << "Thing removed" << thing->name();
if (m_connections.contains(thing)) {
PantaboxModbusTcpConnection *connection = m_connections.take(thing);
Pantabox *connection = m_connections.take(thing);
connection->disconnectDevice();
connection->deleteLater();
}
@ -269,8 +269,8 @@ void IntegrationPluginInro::setupConnection(ThingSetupInfo *info)
Thing *thing = info->thing();
NetworkDeviceMonitor *monitor = m_monitors.value(thing);
PantaboxModbusTcpConnection *connection = new PantaboxModbusTcpConnection(monitor->networkDeviceInfo().address(), 502, 1, this);
connect(info, &ThingSetupInfo::aborted, connection, &PantaboxModbusTcpConnection::deleteLater);
Pantabox *connection = new Pantabox(monitor->networkDeviceInfo().address(), 502, 1, this);
connect(info, &ThingSetupInfo::aborted, connection, &Pantabox::deleteLater);
// Monitor reachability
connect(monitor, &NetworkDeviceMonitor::reachableChanged, thing, [=](bool reachable){
@ -289,7 +289,7 @@ void IntegrationPluginInro::setupConnection(ThingSetupInfo *info)
});
// Connection reachability
connect(connection, &PantaboxModbusTcpConnection::reachableChanged, thing, [thing, connection](bool reachable){
connect(connection, &Pantabox::reachableChanged, thing, [thing, connection](bool reachable){
qCInfo(dcInro()) << "Reachable changed to" << reachable << "for" << thing;
thing->setStateValue("connected", reachable);
@ -301,28 +301,28 @@ void IntegrationPluginInro::setupConnection(ThingSetupInfo *info)
}
});
connect(connection, &PantaboxModbusTcpConnection::updateFinished, thing, [thing, connection](){
connect(connection, &Pantabox::updateFinished, thing, [thing, connection](){
qCDebug(dcInro()) << "Update finished for" << thing;
qCDebug(dcInro()) << connection;
QString chargingStateString;
switch(connection->chargingState()) {
case PantaboxModbusTcpConnection::ChargingStateA:
case Pantabox::ChargingStateA:
chargingStateString = "A";
break;
case PantaboxModbusTcpConnection::ChargingStateB:
case Pantabox::ChargingStateB:
chargingStateString = "B";
break;
case PantaboxModbusTcpConnection::ChargingStateC:
case Pantabox::ChargingStateC:
chargingStateString = "C";
break;
case PantaboxModbusTcpConnection::ChargingStateD:
case Pantabox::ChargingStateD:
chargingStateString = "D";
break;
case PantaboxModbusTcpConnection::ChargingStateE:
case Pantabox::ChargingStateE:
chargingStateString = "E";
break;
case PantaboxModbusTcpConnection::ChargingStateF:
case Pantabox::ChargingStateF:
chargingStateString = "F";
break;
}
@ -333,8 +333,8 @@ void IntegrationPluginInro::setupConnection(ThingSetupInfo *info)
// C: connected, charging
// D: ventilation required
// E: F: fault/error
thing->setStateValue(pantaboxPluggedInStateTypeId, connection->chargingState() >= PantaboxModbusTcpConnection::ChargingStateB);
thing->setStateValue(pantaboxChargingStateTypeId, connection->chargingState() >= PantaboxModbusTcpConnection::ChargingStateC);
thing->setStateValue(pantaboxPluggedInStateTypeId, connection->chargingState() >= Pantabox::ChargingStateB);
thing->setStateValue(pantaboxChargingStateTypeId, connection->chargingState() >= Pantabox::ChargingStateC);
thing->setStateValue(pantaboxCurrentPowerStateTypeId, connection->currentPower()); // W
thing->setStateValue(pantaboxTotalEnergyConsumedStateTypeId, connection->chargedEnergy() / 1000.0); // Wh
thing->setStateMaxValue(pantaboxMaxChargingCurrentActionTypeId, connection->maxPossibleChargingCurrent());

View File

@ -36,7 +36,7 @@
#include <network/networkdevicemonitor.h>
#include "extern-plugininfo.h"
#include "pantaboxmodbustcpconnection.h"
#include "pantabox.h"
class IntegrationPluginInro: public IntegrationPlugin
{
@ -56,7 +56,7 @@ public:
private:
PluginTimer *m_refreshTimer = nullptr;
QHash<Thing *, PantaboxModbusTcpConnection *> m_connections;
QHash<Thing *, Pantabox *> m_connections;
QHash<Thing *, NetworkDeviceMonitor *> m_monitors;
void setupConnection(ThingSetupInfo *info);

540
inro/pantabox.cpp Normal file
View File

@ -0,0 +1,540 @@
#include "pantabox.h"
#include "loggingcategories.h"
NYMEA_LOGGING_CATEGORY(dcPantabox, "Pantabox")
Pantabox::Pantabox(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) :
PantaboxModbusTcpConnection(hostAddress, port, slaveId, parent)
{
// Note: sometimes right after the discovery / setup the check fails the first time due to server busy error,
// this is a very slow or busy device since it returns quiet often that error. Don't faile with the first busy error...
setCheckReachableRetries(3);
}
bool Pantabox::initialize() {
if (!m_reachable) {
qCWarning(dcPantabox()) << "Tried to initialize but the device is not to be reachable.";
return false;
}
if (m_initObject) {
qCWarning(dcPantabox()) << "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;
// Read Serial number (hex)
qCDebug(dcPantabox()) << "--> Read init \"Serial number (hex)\" register:" << 256 << "size:" << 2;
reply = readSerialNumber();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Serial number (hex)\" 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();
processSerialNumberRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Serial number (hex)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Serial number (hex)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read ModbusTCP version
qCDebug(dcPantabox()) << "--> Read init \"ModbusTCP version\" register:" << 258 << "size:" << 2;
reply = readModbusTcpVersion();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"ModbusTCP 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();
processModbusTcpVersionRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"ModbusTCP version\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"ModbusTCP version\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Following Modbus registers are available since ModbusTcpVersion 1.1
if (m_modbusTcpVersion < 257)
return true;
// Read Name of vendor
qCDebug(dcPantabox()) << "--> Read init \"Name of vendor\" register:" << 260 << "size:" << 2;
reply = readVendorName();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Name of vendor\" 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();
processVendorNameRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Name of vendor\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Name of vendor\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read Name of product
qCDebug(dcPantabox()) << "--> Read init \"Name of product\" register:" << 262 << "size:" << 4;
reply = readProductName();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Name of product\" 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();
processProductNameRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Name of product\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Name of product\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read Firmware version
qCDebug(dcPantabox()) << "--> Read init \"Firmware version\" register:" << 266 << "size:" << 16;
reply = readFirmwareVersion();
if (!reply) {
qCWarning(dcPantabox()) << "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();
processFirmwareVersionRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Firmware version\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Firmware version\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
return true;
}
bool Pantabox::update() {
if (!m_modbusTcpMaster->connected())
return false;
if (!m_pendingUpdateReplies.isEmpty()) {
qCDebug(dcPantabox()) << "Tried to update but there are still some update replies pending. Waiting for them to be finished...";
return true;
}
QModbusReply *reply = nullptr;
// Read Charging state
qCDebug(dcPantabox()) << "--> Read \"Charging state\" register:" << 512 << "size:" << 1;
reply = readChargingState();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Charging 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();
processChargingStateRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Charging state\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Charging state\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read Current charging power
qCDebug(dcPantabox()) << "--> Read \"Current charging power\" register:" << 513 << "size:" << 2;
reply = readCurrentPower();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Current charging power\" 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();
processCurrentPowerRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Current charging power\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Current charging power\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read Charged energy
qCDebug(dcPantabox()) << "--> Read \"Charged energy\" register:" << 515 << "size:" << 2;
reply = readChargedEnergy();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Charged energy\" 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();
processChargedEnergyRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Charged energy\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Charged energy\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read Maximal possible charging current (adapter)
qCDebug(dcPantabox()) << "--> Read \"Maximal possible charging current (adapter)\" register:" << 517 << "size:" << 1;
reply = readMaxPossibleChargingCurrent();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Maximal possible charging current (adapter)\" 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();
processMaxPossibleChargingCurrentRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Maximal possible charging current (adapter)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Maximal possible charging current (adapter)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read Actual charging current
qCDebug(dcPantabox()) << "--> Read \"Actual charging current\" register:" << 518 << "size:" << 1;
reply = readChargingCurrent();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Actual charging current\" 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();
processChargingCurrentRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Actual charging current\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Actual charging current\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// The Modbus register for absolute charged energy is available since Modbusversion 1.2
if (m_modbusTcpVersion < 258) {
// Read Absolute charged energy
qCDebug(dcPantabox()) << "--> Read \"Absolute charged energy\" register:" << 519 << "size:" << 2;
reply = readAbsoluteEnergy();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Absolute charged energy\" 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();
processAbsoluteEnergyRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Absolute charged energy\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Absolute charged energy\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
}
// Read Charging enabled (1) / disabled (0)
qCDebug(dcPantabox()) << "--> Read \"Charging enabled (1) / disabled (0)\" register:" << 768 << "size:" << 1;
reply = readChargingEnabled();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Charging enabled (1) / disabled (0)\" 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();
processChargingEnabledRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Charging enabled (1) / disabled (0)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Charging enabled (1) / disabled (0)\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
// Read Max charging current
qCDebug(dcPantabox()) << "--> Read \"Max charging current\" register:" << 769 << "size:" << 1;
reply = readMaxChargingCurrent();
if (!reply) {
qCWarning(dcPantabox()) << "Error occurred while reading \"Max charging current\" 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();
processMaxChargingCurrentRegisterValues(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(dcPantabox()) << "Modbus reply error occurred while reading \"Max charging current\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString() << ModbusDataUtils::exceptionCodeToString(response.exceptionCode());
} else {
qCWarning(dcPantabox()) << "Modbus reply error occurred while reading \"Max charging current\" registers from" << m_modbusTcpMaster->hostAddress().toString() << error << reply->errorString();
}
});
return true;
}

21
inro/pantabox.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef PANTABOX_H
#define PANTABOX_H
#include "pantaboxmodbustcpconnection.h"
class Pantabox : public PantaboxModbusTcpConnection
{
Q_OBJECT
public:
explicit Pantabox(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr);
explicit Pantabox(ModbusTcpMaster *modbusTcpMaster, quint16 slaveId, QObject *parent = nullptr);
~Pantabox() = default;
virtual bool update() override;
virtual bool initialize() override;
signals:
};
#endif // PANTABOX_H

View File

@ -69,10 +69,10 @@ void PantaboxDiscovery::startDiscovery()
void PantaboxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo)
{
PantaboxModbusTcpConnection *connection = new PantaboxModbusTcpConnection(networkDeviceInfo.address(), m_port, m_modbusAddress, this);
Pantabox *connection = new Pantabox(networkDeviceInfo.address(), m_port, m_modbusAddress, this);
m_connections.append(connection);
connect(connection, &PantaboxModbusTcpConnection::reachableChanged, this, [=](bool reachable){
connect(connection, &Pantabox::reachableChanged, this, [=](bool reachable){
if (!reachable) {
// Disconnected ... done with this connection
cleanupConnection(connection);
@ -80,30 +80,42 @@ void PantaboxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevic
}
// Modbus TCP connected...ok, let's try to initialize it!
connect(connection, &PantaboxModbusTcpConnection::initializationFinished, this, [=](bool success){
connect(connection, &Pantabox::initializationFinished, this, [=](bool success){
if (!success) {
qCDebug(dcInro()) << "Discovery: Initialization failed on" << networkDeviceInfo.address().toString() << "Continue...";
cleanupConnection(connection);
return;
}
// FIXME: find a better way to discover the device besides a valid init
qCDebug(dcInro()) << "Discovery: Connection initialized successfully" << connection->serialNumber();
// Modbus registers for vendor and product name are available since Modbus version 1.1
if (connection->modbusTcpVersion() > 257) {
Result result;
result.serialNumber = QString::number(connection->serialNumber(), 16).toUpper();
result.modbusTcpVersion = modbusVersionToString(connection->modbusTcpVersion());
result.networkDeviceInfo = networkDeviceInfo;
m_results.append(result);
// Only add device to result when correct device parameters were read
if (connection->vendorName() == "INRO" && connection->productName() == "PANTABOX") {
qCDebug(dcInro()) << "Discovery: Connection initialized successfully" << connection->serialNumber();
qCInfo(dcInro()) << "Discovery: --> Found"
<< "Serial number:" << result.serialNumber
<< "(" << connection->serialNumber() << ")"
<< "ModbusTCP version:" << result.modbusTcpVersion
<< result.networkDeviceInfo;
Result result;
result.serialNumber = QString::number(connection->serialNumber(), 16).toUpper();
result.modbusTcpVersion = modbusVersionToString(connection->modbusTcpVersion());
result.networkDeviceInfo = networkDeviceInfo;
m_results.append(result);
// Done with this connection
cleanupConnection(connection);
qCInfo(dcInro()) << "Discovery: --> Found"
<< "Serial number:" << result.serialNumber
<< "(" << connection->serialNumber() << ")"
<< "ModbusTCP version:" << result.modbusTcpVersion
<< result.networkDeviceInfo;
// Done with this connection
cleanupConnection(connection);
} else {
qCDebug(dcInro()) << "Discovery: Device not added to result because of wrong vendor or/and product name"
<< connection->vendorName()
<< connection->productName();
}
} else {
qCDebug(dcInro()) << "Discovery: Device not added to result because of wrong ModbusTcpVersion" << modbusVersionToString(connection->modbusTcpVersion());
}
});
// Initializing...
@ -122,7 +134,7 @@ void PantaboxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevic
});
// If check reachability failed...skip this host...
connect(connection, &PantaboxModbusTcpConnection::checkReachabilityFailed, this, [=](){
connect(connection, &Pantabox::checkReachabilityFailed, this, [=](){
qCDebug(dcInro()) << "Discovery: Check reachability failed on" << networkDeviceInfo.address().toString() << "Continue...";
cleanupConnection(connection);
});
@ -131,7 +143,7 @@ void PantaboxDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevic
connection->connectDevice();
}
void PantaboxDiscovery::cleanupConnection(PantaboxModbusTcpConnection *connection)
void PantaboxDiscovery::cleanupConnection(Pantabox *connection)
{
m_connections.removeAll(connection);
connection->disconnectDevice();
@ -143,7 +155,7 @@ void PantaboxDiscovery::finishDiscovery()
qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
// Cleanup any leftovers...we don't care any more
foreach (PantaboxModbusTcpConnection *connection, m_connections)
foreach (Pantabox *connection, m_connections)
cleanupConnection(connection);
qCInfo(dcInro()) << "Discovery: Finished the discovery process. Found" << m_results.count()

View File

@ -34,8 +34,7 @@
#include <QObject>
#include <network/networkdevicediscovery.h>
#include "pantaboxmodbustcpconnection.h"
#include "pantabox.h"
class PantaboxDiscovery : public QObject
{
@ -66,12 +65,12 @@ private:
QDateTime m_startDateTime;
QList<PantaboxModbusTcpConnection *> m_connections;
QList<Pantabox *> m_connections;
QList<Result> m_results;
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
void cleanupConnection(PantaboxModbusTcpConnection *connection);
void cleanupConnection(Pantabox *connection);
void finishDiscovery();
};