Use new modbus RTU hardware resource for the modbus commander plugin

Use new modbus RTU hardware resource for the modbus commander plugin

Fix action abort for RTU actions and fix connected state fro child RTU things

Fix modbus rtu client and make it work with the basic resource component

Remove modbusrtu master from project file

Remove custom modbus rtu master include
This commit is contained in:
Simon Stürz 2021-02-08 16:22:32 +01:00 committed by Michael Zanetti
parent f0f9d7c245
commit 352413563f
5 changed files with 196 additions and 241 deletions

View File

@ -54,7 +54,6 @@ ModbusRTUMaster::ModbusRTUMaster(QString serialPort, uint baudrate, QSerialPort:
connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusRTUMaster::onReconnectTimer);
}
ModbusRTUMaster::~ModbusRTUMaster()
{
if (!m_modbusRtuSerialMaster) {

View File

@ -31,6 +31,10 @@
#include "integrationpluginmodbuscommander.h"
#include "plugininfo.h"
#include "hardwaremanager.h"
#include "hardware/modbus/modbusrtumaster.h"
#include "hardware/modbus/modbusrtuhardwareresource.h"
#include <QSerialPort>
IntegrationPluginModbusCommander::IntegrationPluginModbusCommander()
@ -39,8 +43,6 @@ IntegrationPluginModbusCommander::IntegrationPluginModbusCommander()
void IntegrationPluginModbusCommander::init()
{
connect(this, &IntegrationPluginModbusCommander::configValueChanged, this, &IntegrationPluginModbusCommander::onPluginConfigurationChanged);
m_slaveAddressParamTypeId.insert(coilThingClassId, coilThingSlaveAddressParamTypeId);
m_slaveAddressParamTypeId.insert(inputRegisterThingClassId, inputRegisterThingSlaveAddressParamTypeId);
m_slaveAddressParamTypeId.insert(discreteInputThingClassId, discreteInputThingSlaveAddressParamTypeId);
@ -62,46 +64,49 @@ void IntegrationPluginModbusCommander::init()
m_valueStateTypeId.insert(inputRegisterThingClassId, inputRegisterValueStateTypeId);
m_valueStateTypeId.insert(discreteInputThingClassId, discreteInputValueStateTypeId);
m_valueStateTypeId.insert(holdingRegisterThingClassId, holdingRegisterValueStateTypeId);
// Plugin configuration
connect(this, &IntegrationPluginModbusCommander::configValueChanged, this, &IntegrationPluginModbusCommander::onPluginConfigurationChanged);
// Modbus RTU hardware resource
connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=](const QUuid &modbusUuid){
qCDebug(dcModbusCommander()) << "Modbus RTU master has been removed" << modbusUuid.toString();
// Check if there is any device using this resource
foreach (Thing *thing, m_modbusRtuMasters.keys()) {
if (m_modbusRtuMasters.value(thing)->modbusUuid() == modbusUuid) {
qCWarning(dcModbusCommander()) << "Hardware resource removed for" << thing << ". The thing will not be functional any more until a new resource has been configured for it.";
m_modbusRtuMasters.remove(thing);
thing->setStateValue(m_connectedStateTypeId[thing->thingClassId()], false);
// Set all child things disconnected
foreach (Thing *childThing, myThings()) {
if (childThing->parentId() == thing->id()) {
thing->setStateValue(m_connectedStateTypeId[childThing->thingClassId()], false);
}
}
}
}
});
}
void IntegrationPluginModbusCommander::discoverThings(ThingDiscoveryInfo *info)
{
ThingClassId thingClassId = info->thingClassId();
if (thingClassId == modbusRTUClientThingClassId) {
Q_FOREACH(QSerialPortInfo port, QSerialPortInfo::availablePorts()) {
qCDebug(dcModbusCommander()) << "Found serial port:" << port.systemLocation() << "manufacturer" << port.manufacturer() << "description" << port.description() << "serial number" << port.serialNumber();
if (port.isBusy()) {
qCDebug(dcModbusCommander()) << "Serial port ist busy, skipping.";
continue;
foreach (ModbusRtuMaster *modbusMaster, hardwareManager()->modbusRtuResource()->modbusRtuMasters()) {
qCDebug(dcModbusCommander()) << "Found RTU master resource" << modbusMaster;
if (modbusMaster->connected()) {
ParamList parameters;
ThingDescriptor thingDescriptor(thingClassId, "Modbus RTU master", modbusMaster->serialPort());
parameters.append(Param(modbusRTUClientThingModbusMasterUuidParamTypeId, modbusMaster->modbusUuid()));
thingDescriptor.setParams(parameters);
info->addThingDescriptor(thingDescriptor);
} else {
qCWarning(dcModbusCommander()) << "Found configured resource" << modbusMaster << "but it is not connected. Skipping.";
}
QString manufacturer = port.manufacturer();
if (manufacturer.isEmpty()) {
manufacturer = "unknown";
}
QString description = port.description()+" Manufacturer: "+port.manufacturer();
ThingDescriptor thingDescriptor(thingClassId, "Modbus RTU interface", description);
ParamList parameters;
QString serialPort = port.systemLocation();
QString serialnumber = port.serialNumber();
if (serialnumber.isEmpty()) {
serialnumber = port.manufacturer()+QString::number(port.productIdentifier(), 16);
}
qCDebug(dcModbusCommander()) << " - Serial number" << serialnumber;
Q_FOREACH (Thing *exisingThing, myThings().filterByParam(modbusRTUClientThingClassId)) {
thingDescriptor.setThingId(exisingThing->id());
// Rediscovery is broken because of a missing unique device id
// This is a workaround and doesnt work if multiple uart converters are attached.
// ThingDiscoveryInfo may be extended to distinquish between discovery and rediscovery
break;
}
parameters.append(Param(modbusRTUClientThingSerialPortParamTypeId, serialPort));
parameters.append(Param(modbusRTUClientThingSerialnumberParamTypeId, serialnumber));
thingDescriptor.setParams(parameters);
info->addThingDescriptor(thingDescriptor);
}
//FIXME missing info if it is a rediscovery
info->finish(Thing::ThingErrorNoError);
return;
} else if (thingClassId == discreteInputThingClassId) {
@ -112,7 +117,7 @@ void IntegrationPluginModbusCommander::discoverThings(ThingDiscoveryInfo *info)
info->addThingDescriptor(descriptor);
}
if (clientThing->thingClassId() == modbusRTUClientThingClassId) {
ThingDescriptor descriptor(thingClassId, "Discrete input", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingSerialPortParamTypeId).toString());
ThingDescriptor descriptor(thingClassId, "Discrete input", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingModbusMasterUuidParamTypeId).toString());
descriptor.setParentId(clientThing->id());
info->addThingDescriptor(descriptor);
}
@ -128,7 +133,7 @@ void IntegrationPluginModbusCommander::discoverThings(ThingDiscoveryInfo *info)
info->addThingDescriptor(descriptor);
}
if (clientThing->thingClassId() == modbusRTUClientThingClassId) {
ThingDescriptor descriptor(thingClassId, "Coil", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingSerialPortParamTypeId).toString());
ThingDescriptor descriptor(thingClassId, "Coil", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingModbusMasterUuidParamTypeId).toString());
descriptor.setParentId(clientThing->id());
info->addThingDescriptor(descriptor);
}
@ -143,7 +148,7 @@ void IntegrationPluginModbusCommander::discoverThings(ThingDiscoveryInfo *info)
info->addThingDescriptor(descriptor);
}
if (clientThing->thingClassId() == modbusRTUClientThingClassId) {
ThingDescriptor descriptor(thingClassId, "Holding register", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingSerialPortParamTypeId).toString());
ThingDescriptor descriptor(thingClassId, "Holding register", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingModbusMasterUuidParamTypeId).toString());
descriptor.setParentId(clientThing->id());
info->addThingDescriptor(descriptor);
}
@ -159,7 +164,7 @@ void IntegrationPluginModbusCommander::discoverThings(ThingDiscoveryInfo *info)
info->addThingDescriptor(descriptor);
}
if (clientThing->thingClassId() == modbusRTUClientThingClassId) {
ThingDescriptor descriptor(thingClassId, "Input register", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingSerialPortParamTypeId).toString());
ThingDescriptor descriptor(thingClassId, "Input register", clientThing->name() + " " + clientThing->paramValue(modbusRTUClientThingModbusMasterUuidParamTypeId).toString());
descriptor.setParentId(clientThing->id());
info->addThingDescriptor(descriptor);
}
@ -215,74 +220,51 @@ void IntegrationPluginModbusCommander::setupThing(ThingSetupInfo *info)
}
});
connect(thing, &Thing::settingChanged, thing, [thing, modbusTCPMaster] (const ParamTypeId &paramTypeId, const QVariant &value) {
if (paramTypeId == modbusTCPClientSettingsNumberOfRetriesParamTypeId) {
qCDebug(dcModbusCommander()) << "Set number of retries" << thing->name() << value.toUInt();
modbusTCPMaster->setNumberOfRetries(value.toUInt());
} else if (paramTypeId == modbusTCPClientSettingsTimeoutParamTypeId) {
qCDebug(dcModbusCommander()) << "Set timeout " << thing->name() << value.toUInt();
modbusTCPMaster->setTimeout(value.toUInt());
}
});
if (paramTypeId == modbusTCPClientSettingsNumberOfRetriesParamTypeId) {
qCDebug(dcModbusCommander()) << "Set number of retries" << thing->name() << value.toUInt();
modbusTCPMaster->setNumberOfRetries(value.toUInt());
} else if (paramTypeId == modbusTCPClientSettingsTimeoutParamTypeId) {
qCDebug(dcModbusCommander()) << "Set timeout " << thing->name() << value.toUInt();
modbusTCPMaster->setTimeout(value.toUInt());
}
});
modbusTCPMaster->connectDevice();
} else if (thing->thingClassId() == modbusRTUClientThingClassId) {
QUuid modbusUuid = thing->paramValue(modbusRTUClientThingModbusMasterUuidParamTypeId).toUuid();
QString serialPort = thing->paramValue(modbusRTUClientThingSerialPortParamTypeId).toString();
uint baudrate = thing->paramValue(modbusRTUClientThingBaudRateParamTypeId).toUInt();
uint stopBits = thing->paramValue(modbusRTUClientThingStopBitsParamTypeId).toUInt();
uint dataBits = thing->paramValue(modbusRTUClientThingDataBitsParamTypeId).toUInt();
uint numberOfRetries = thing->setting(modbusRTUClientSettingsNumberOfRetriesParamTypeId).toUInt();
uint timeout = thing->setting(modbusRTUClientSettingsTimeoutParamTypeId).toUInt();
QSerialPort::Parity parity = QSerialPort::Parity::NoParity;
QString parityString = thing->paramValue(modbusRTUClientThingParityParamTypeId).toString();
if (parityString.contains("No")) {
parity = QSerialPort::Parity::NoParity;
} else if (parityString.contains("Even")) {
parity = QSerialPort::Parity::EvenParity;
} else if (parityString.contains("Odd")) {
parity = QSerialPort::Parity::OddParity;
}
qCDebug(dcModbusCommander()) << "Setting up RTU client" << thing->name();
qCDebug(dcModbusCommander()) << " baud:" << baudrate;
qCDebug(dcModbusCommander()) << " stop bits:" << stopBits;
qCDebug(dcModbusCommander()) << " data bits:" << dataBits;
qCDebug(dcModbusCommander()) << " parity:" << parityString;
qCDebug(dcModbusCommander()) << " number of retries:" << numberOfRetries;
qCDebug(dcModbusCommander()) << " timeout:" << timeout;
if (m_modbusRTUMasters.contains(thing)) {
// In case of a rediscovery
m_modbusRTUMasters.take(thing)->deleteLater();
if (!hardwareManager()->modbusRtuResource()->available()) {
qCWarning(dcModbusCommander()) << "Cannot set up thing" << thing << ". The modbus RTU hardware resource is not available.";
info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("The modbus RTU hardware resource is not available"));
return;
}
ModbusRTUMaster *modbusRTUMaster = new ModbusRTUMaster(serialPort, baudrate, parity, dataBits, stopBits, this);
modbusRTUMaster->setTimeout(timeout);
modbusRTUMaster->setNumberOfRetries(numberOfRetries);
connect(modbusRTUMaster, &ModbusRTUMaster::connectionStateChanged, this, &IntegrationPluginModbusCommander::onConnectionStateChanged);
connect(modbusRTUMaster, &ModbusRTUMaster::requestExecuted, this, &IntegrationPluginModbusCommander::onRequestExecuted);
connect(modbusRTUMaster, &ModbusRTUMaster::requestError, this, &IntegrationPluginModbusCommander::onRequestError);
connect(modbusRTUMaster, &ModbusRTUMaster::receivedCoil, this, &IntegrationPluginModbusCommander::onReceivedCoil);
connect(modbusRTUMaster, &ModbusRTUMaster::receivedDiscreteInput, this, &IntegrationPluginModbusCommander::onReceivedDiscreteInput);
connect(modbusRTUMaster, &ModbusRTUMaster::receivedHoldingRegister, this, &IntegrationPluginModbusCommander::onReceivedHoldingRegister);
connect(modbusRTUMaster, &ModbusRTUMaster::receivedInputRegister, this, &IntegrationPluginModbusCommander::onReceivedInputRegister);
connect(modbusRTUMaster, &ModbusRTUMaster::connectionStateChanged, info, [info, modbusRTUMaster, this] (bool connected) {
if (connected) {
info->finish(Thing::ThingErrorNoError);
m_modbusRTUMasters.insert(info->thing(), modbusRTUMaster);
if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(modbusUuid)) {
qCWarning(dcModbusCommander()) << "Cannot set up thing" << thing << ". The modbus RTU hardware resource" << modbusUuid.toString() << "does not exist any more. Reconfiguration required.";
info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("Configured modbus RTU master could not be found. Please reconfigure the client and assign a new valid modbus RTU master."));
return;
}
ModbusRtuMaster *modbusMaster = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(modbusUuid);
qCDebug(dcModbusCommander()) << "Setting up" << thing << "using" << modbusMaster;
m_modbusRtuMasters.insert(thing, modbusMaster);
connect(modbusMaster, &ModbusRtuMaster::connectedChanged, thing, [=](bool connected){
qCDebug(dcModbusCommander()) << "Modbus RTU client" << modbusMaster << "connected changed" << connected;
thing->setStateValue(modbusRTUClientConnectedStateTypeId, connected);
// Note: only set the connected state for the child things if disconnected.
// The child things will be evaluated upon read requests if the slave is connected or not.
if (!connected) {
foreach (Thing *childThing, myThings()) {
if (childThing->parentId() == thing->id()) {
thing->setStateValue(m_connectedStateTypeId[childThing->thingClassId()], connected);
}
}
}
});
connect(thing, &Thing::settingChanged, thing, [thing, modbusRTUMaster] (const ParamTypeId &paramTypeId, const QVariant &value) {
if (paramTypeId == modbusRTUClientSettingsNumberOfRetriesParamTypeId) {
qCDebug(dcModbusCommander()) << "Set number of retries" << thing->name() << value.toUInt();
modbusRTUMaster->setNumberOfRetries(value.toUInt());
} else if (paramTypeId == modbusRTUClientSettingsTimeoutParamTypeId) {
qCDebug(dcModbusCommander()) << "Set timeout " << thing->name() << value.toUInt();
modbusRTUMaster->setTimeout(value.toUInt());
}
});
modbusRTUMaster->connectDevice();
info->finish(Thing::ThingErrorNoError);
} else if ((thing->thingClassId() == coilThingClassId)
|| (thing->thingClassId() == discreteInputThingClassId)
|| (thing->thingClassId() == holdingRegisterThingClassId)
@ -362,9 +344,6 @@ void IntegrationPluginModbusCommander::thingRemoved(Thing *thing)
if (thing->thingClassId() == modbusTCPClientThingClassId) {
ModbusTCPMaster *modbus = m_modbusTCPMasters.take(thing);
modbus->deleteLater();
} else if (thing->thingClassId() == modbusRTUClientThingClassId) {
ModbusRTUMaster *modbus = m_modbusRTUMasters.take(thing);
modbus->deleteLater();
}
if (myThings().empty()) {
@ -392,12 +371,7 @@ void IntegrationPluginModbusCommander::onPluginConfigurationChanged(const ParamT
void IntegrationPluginModbusCommander::onConnectionStateChanged(bool status)
{
auto modbus = sender();
if (m_modbusRTUMasters.values().contains(static_cast<ModbusRTUMaster *>(modbus))) {
Thing *thing = m_modbusRTUMasters.key(static_cast<ModbusRTUMaster *>(modbus));
qCDebug(dcModbusCommander()) << "Connections state changed" << thing->name() << status;
thing->setStateValue(modbusRTUClientConnectedStateTypeId, status);
} else if (m_modbusTCPMasters.values().contains(static_cast<ModbusTCPMaster *>(modbus))) {
if (m_modbusTCPMasters.values().contains(static_cast<ModbusTCPMaster *>(modbus))) {
Thing *thing = m_modbusTCPMasters.key(static_cast<ModbusTCPMaster *>(modbus));
qCDebug(dcModbusCommander()) << "Connections state changed" << thing->name() << status;
thing->setStateValue(modbusTCPClientConnectedStateTypeId, status);
@ -439,20 +413,7 @@ void IntegrationPluginModbusCommander::onRequestError(QUuid requestId, const QSt
void IntegrationPluginModbusCommander::onReceivedCoil(quint32 slaveAddress, quint32 modbusRegister, const QVector<quint16> &values)
{
auto modbus = sender();
if (m_modbusRTUMasters.values().contains(static_cast<ModbusRTUMaster *>(modbus))) {
Thing *parent = m_modbusRTUMasters.key(static_cast<ModbusRTUMaster *>(modbus));
foreach (Thing *thing, myThings().filterByParentId(parent->id())) {
if (thing->thingClassId() == coilThingClassId) {
if ((thing->paramValue(m_slaveAddressParamTypeId.value(thing->thingClassId())) == slaveAddress)
&& (thing->paramValue(m_registerAddressParamTypeId.value(thing->thingClassId())) == modbusRegister)) {
thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), values[0]);
thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true);
return;
}
}
}
} else if (m_modbusTCPMasters.values().contains(static_cast<ModbusTCPMaster *>(modbus))) {
if (m_modbusTCPMasters.values().contains(static_cast<ModbusTCPMaster *>(modbus))) {
Thing *parent = m_modbusTCPMasters.key(static_cast<ModbusTCPMaster *>(modbus));
foreach (Thing *thing, myThings().filterByParentId(parent->id())) {
if (thing->thingClassId() == coilThingClassId) {
@ -471,19 +432,7 @@ void IntegrationPluginModbusCommander::onReceivedDiscreteInput(quint32 slaveAddr
{
auto modbus = sender();
if (m_modbusRTUMasters.values().contains(static_cast<ModbusRTUMaster *>(modbus))) {
Thing *parent = m_modbusRTUMasters.key(static_cast<ModbusRTUMaster *>(modbus));
foreach (Thing *thing, myThings().filterByParentId(parent->id())) {
if (thing->thingClassId() == discreteInputThingClassId) {
if ((thing->paramValue(m_slaveAddressParamTypeId.value(thing->thingClassId())) == slaveAddress)
&& (thing->paramValue(m_registerAddressParamTypeId.value(thing->thingClassId())) == modbusRegister)) {
thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), values[0]);
thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true);
return;
}
}
}
} else if (m_modbusTCPMasters.values().contains(static_cast<ModbusTCPMaster *>(modbus))) {
if (m_modbusTCPMasters.values().contains(static_cast<ModbusTCPMaster *>(modbus))) {
Thing *parent = m_modbusTCPMasters.key(static_cast<ModbusTCPMaster *>(modbus));
foreach (Thing *thing, myThings().filterByParentId(parent->id())) {
if (thing->thingClassId() == discreteInputThingClassId) {
@ -502,19 +451,7 @@ void IntegrationPluginModbusCommander::onReceivedHoldingRegister(uint slaveAddre
{
auto modbus = sender();
if (m_modbusRTUMasters.values().contains(static_cast<ModbusRTUMaster *>(modbus))) {
Thing *parent = m_modbusRTUMasters.key(static_cast<ModbusRTUMaster *>(modbus));
foreach (Thing *thing, myThings().filterByParentId(parent->id())) {
if (thing->thingClassId() == holdingRegisterThingClassId) {
if ((thing->paramValue(m_slaveAddressParamTypeId.value(thing->thingClassId())) == slaveAddress)
&& (thing->paramValue(m_registerAddressParamTypeId.value(thing->thingClassId())) == modbusRegister)) {
thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), values[0]);
thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true);
return;
}
}
}
} else if (m_modbusTCPMasters.values().contains(static_cast<ModbusTCPMaster *>(modbus))) {
if (m_modbusTCPMasters.values().contains(static_cast<ModbusTCPMaster *>(modbus))) {
Thing *parent = m_modbusTCPMasters.key(static_cast<ModbusTCPMaster *>(modbus));
foreach (Thing *thing, myThings().filterByParentId(parent->id())) {
if (thing->thingClassId() == holdingRegisterThingClassId) {
@ -533,19 +470,7 @@ void IntegrationPluginModbusCommander::onReceivedInputRegister(uint slaveAddress
{
auto modbus = sender();
if (m_modbusRTUMasters.values().contains(static_cast<ModbusRTUMaster *>(modbus))) {
Thing *parent = m_modbusRTUMasters.key(static_cast<ModbusRTUMaster *>(modbus));
foreach (Thing *thing, myThings().filterByParentId(parent->id())) {
if (thing->thingClassId() == inputRegisterThingClassId) {
if ((thing->paramValue(m_slaveAddressParamTypeId.value(thing->thingClassId())) == slaveAddress)
&& (thing->paramValue(m_registerAddressParamTypeId.value(thing->thingClassId())) == modbusRegister)) {
thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), values[0]);
thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true);
return;
}
}
}
} else if (m_modbusTCPMasters.values().contains(static_cast<ModbusTCPMaster *>(modbus))) {
if (m_modbusTCPMasters.values().contains(static_cast<ModbusTCPMaster *>(modbus))) {
Thing *parent = m_modbusTCPMasters.key(static_cast<ModbusTCPMaster *>(modbus));
foreach (Thing *thing, myThings().filterByParentId(parent->id())) {
if (thing->thingClassId() == inputRegisterThingClassId) {
@ -592,23 +517,76 @@ void IntegrationPluginModbusCommander::readRegister(Thing *thing)
}
} else if (parent->thingClassId() == modbusRTUClientThingClassId) {
ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parent);
if (!modbus)
ModbusRtuMaster *modbusMaster = m_modbusRtuMasters.value(parent);
if (!modbusMaster)
return;
if (!modbus->connected())
if (!modbusMaster->connected())
return; // Send requests only if the modbus interface is connected
if (thing->thingClassId() == coilThingClassId) {
requestId = modbus->readCoil(slaveAddress, registerAddress);
ModbusRtuReply *reply = modbusMaster->readCoil(slaveAddress, registerAddress);
connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){
if (reply->error() != ModbusRtuReply::NoError) {
qCWarning(dcModbusCommander()) << "Failed to read coil from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress;
thing->setStateValue(m_connectedStateTypeId[thing->thingClassId()], false);
return;
}
if (!reply->result().isEmpty()) {
thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), reply->result().at(0));
}
thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true);
});
} else if (thing->thingClassId() == discreteInputThingClassId) {
requestId = modbus->readDiscreteInput(slaveAddress, registerAddress);
ModbusRtuReply *reply = modbusMaster->readDiscreteInput(slaveAddress, registerAddress);
connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){
if (reply->error() != ModbusRtuReply::NoError) {
qCWarning(dcModbusCommander()) << "Failed to read discrete input from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress;
thing->setStateValue(m_connectedStateTypeId[thing->thingClassId()], false);
return;
}
if (!reply->result().isEmpty()) {
thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), reply->result().at(0));
}
thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true);
});
} else if (thing->thingClassId() == holdingRegisterThingClassId) {
requestId = modbus->readHoldingRegister(slaveAddress, registerAddress);
ModbusRtuReply *reply = modbusMaster->readHoldingRegister(slaveAddress, registerAddress);
connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){
if (reply->error() != ModbusRtuReply::NoError) {
qCWarning(dcModbusCommander()) << "Failed to read holding register from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress;
thing->setStateValue(m_connectedStateTypeId[thing->thingClassId()], false);
return;
}
if (!reply->result().isEmpty()) {
thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), reply->result().at(0));
}
thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true);
});
} else if (thing->thingClassId() == inputRegisterThingClassId) {
requestId = modbus->readInputRegister(slaveAddress, registerAddress);
ModbusRtuReply *reply = modbusMaster->readInputRegister(slaveAddress, registerAddress);
connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){
if (reply->error() != ModbusRtuReply::NoError) {
qCWarning(dcModbusCommander()) << "Failed to read input register from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress;
thing->setStateValue(m_connectedStateTypeId[thing->thingClassId()], false);
return;
}
if (!reply->result().isEmpty()) {
thing->setStateValue(m_valueStateTypeId.value(thing->thingClassId()), reply->result().at(0));
}
thing->setStateValue(m_connectedStateTypeId.value(thing->thingClassId()), true);
});
}
// Note: we don't want proceed with the method here, since we are not
// working with the requestId any more on RTU
return;
}
if (!requestId.isNull()) {
m_readRequests.insert(requestId, thing);
QTimer::singleShot(5000, this, [requestId, this] {m_readRequests.remove(requestId);});
@ -623,8 +601,10 @@ void IntegrationPluginModbusCommander::writeRegister(Thing *thing, ThingActionIn
Thing *parent = myThings().findById(thing->parentId());
if (!parent) {
qCWarning(dcModbusCommander()) << "Could not find parent device" << thing->name();
info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
uint registerAddress = thing->paramValue(m_registerAddressParamTypeId.value(thing->thingClassId())).toUInt();;
uint slaveAddress = thing->paramValue(m_slaveAddressParamTypeId.value(thing->thingClassId())).toUInt();
@ -633,8 +613,11 @@ void IntegrationPluginModbusCommander::writeRegister(Thing *thing, ThingActionIn
if (parent->thingClassId() == modbusTCPClientThingClassId) {
ModbusTCPMaster *modbus = m_modbusTCPMasters.value(parent);
if (!modbus)
if (!modbus) {
qCWarning(dcModbusCommander()) << "Could not find modbus TCP master for" << thing;
info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
if (thing->thingClassId() == coilThingClassId) {
requestId = modbus->writeCoil(slaveAddress, registerAddress, action.param(coilValueActionValueParamTypeId).value().toBool());
@ -643,15 +626,48 @@ void IntegrationPluginModbusCommander::writeRegister(Thing *thing, ThingActionIn
}
} else if (parent->thingClassId() == modbusRTUClientThingClassId) {
ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parent);
if (!modbus)
ModbusRtuMaster *modbusMaster = m_modbusRtuMasters.value(parent);
if (!modbusMaster) {
qCWarning(dcModbusCommander()) << "Could not find modbus RTU master for" << thing;
info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
if (thing->thingClassId() == coilThingClassId) {
requestId = modbus->writeCoil(slaveAddress, registerAddress, action.param(coilValueActionValueParamTypeId).value().toBool());
QVector<quint16> values;
values.append(static_cast<quint16>(action.param(coilValueActionValueParamTypeId).value().toBool()));
ModbusRtuReply *reply = modbusMaster->writeCoils(slaveAddress, registerAddress, values);
connect(info, &ThingActionInfo::aborted, reply, &ModbusRtuReply::deleteLater);
connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){
if (reply->error() != ModbusRtuReply::NoError) {
qCWarning(dcModbusCommander()) << "Failed to write coils from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress << values << reply->errorString();
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
info->finish(Thing::ThingErrorNoError);
});
} else if (thing->thingClassId() == holdingRegisterThingClassId) {
requestId = modbus->writeHoldingRegister(slaveAddress, registerAddress, action.param(holdingRegisterValueActionValueParamTypeId).value().toUInt());
QVector<quint16> values;
values.append(static_cast<quint16>(action.param(holdingRegisterValueActionValueParamTypeId).value().toUInt()));
ModbusRtuReply *reply = modbusMaster->writeHoldingRegisters(slaveAddress, registerAddress, values);
connect(info, &ThingActionInfo::aborted, reply, &ModbusRtuReply::deleteLater);
connect(reply, &ModbusRtuReply::finished, modbusMaster, [=](){
if (reply->error() != ModbusRtuReply::NoError) {
qCWarning(dcModbusCommander()) << "Failed to write holding registers from" << modbusMaster << "slave:" << slaveAddress << "register:" << registerAddress << values << reply->errorString();
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
info->finish(Thing::ThingErrorNoError);
});
}
// Note: we don't want proceed with the method here, since we are not
// working with the requestId any more on RTU
return;
}
if (requestId.toString().isNull()){

View File

@ -31,11 +31,11 @@
#ifndef INTEGRATIONPLUGINMODBUSCOMMANDER_H
#define INTEGRATIONPLUGINMODBUSCOMMANDER_H
#include "integrations/integrationplugin.h"
#include "plugintimer.h"
#include "integrations/integrationplugin.h"
#include "hardware/modbus/modbusrtumaster.h"
#include "../modbus/modbustcpmaster.h"
#include "../modbus/modbusrtumaster.h"
#include <QSerialPortInfo>
#include <QUuid>
@ -60,8 +60,9 @@ public:
private:
PluginTimer *m_refreshTimer = nullptr;
QHash<Thing*, ModbusRTUMaster*> m_modbusRTUMasters;
//QHash<Thing*, ModbusRTUMaster*> m_modbusRTUMasters;
QHash<Thing*, ModbusTCPMaster*> m_modbusTCPMasters;
QHash<Thing *, ModbusRtuMaster *> m_modbusRtuMasters;
QHash<QUuid, ThingActionInfo*> m_asyncActions;
QHash<QUuid, Thing*> m_readRequests;

View File

@ -72,74 +72,15 @@
"id": "776df314-6186-4eb5-b824-f0d916f6d9c3",
"name": "modbusRTUClient",
"displayName": "Modbus RTU client",
"createMethods": ["discovery", "user"],
"createMethods": ["discovery"],
"interfaces": ["connectable"],
"settingsTypes": [
{
"id": "b0af32f0-b8cc-4642-af5a-576732522b2c",
"name": "timeout",
"displayName": "Timeout",
"type": "uint",
"minValue": 10,
"defaultValue": 100
},
{
"id": "c4f16d6c-c1f2-4862-b0bd-6fae7193eaa8",
"name": "numberOfRetries",
"displayName": "Number of retries",
"type": "uint",
"defaultValue": 3
}
],
"paramTypes": [
{
"id": "ed49f7d8-ab18-4c37-9b80-1004b75dcb91",
"name": "serialPort",
"displayName": "Serial port",
"type": "QString",
"inputType": "TextLine",
"defaultValue": "ttyAMA0"
},
{
"id": "9908b01f-a76b-4b21-8242-b507c9252254",
"name": "serialnumber",
"displayName": "Serial number",
"type": "QString",
"name": "modbusMasterUuid",
"displayName": "Modbus RTU master",
"type": "QUuid",
"defaultValue": ""
},
{
"id": "45dfc828-f238-4263-89a3-9b35cf5dea39",
"name": "baudRate",
"displayName": "Baud rate",
"type": "uint",
"defaultValue": 9600
},
{
"id": "a27c664b-9f43-4573-a2cc-f65a8fa1a069",
"name": "dataBits",
"displayName": "Data bits",
"type": "uint",
"defaultValue": 8
},
{
"id": "4ea8bcdf-d4c5-45a4-a54f-f10ac3f08a78",
"name": "stopBits",
"displayName": "Stop bits",
"type": "uint",
"defaultValue": 1
},
{
"id": "72de1b08-2a27-49c5-90e0-8788c3ea1da3",
"name": "parity",
"displayName": "Parity",
"type": "QString",
"inputType": "TextLine",
"allowedValues": [
"No Parity",
"Even Parity",
"Odd Parity"
],
"defaultValue": "No Parity"
}
],
"stateTypes": [

View File

@ -7,11 +7,9 @@ QT += \
SOURCES += \
integrationpluginmodbuscommander.cpp \
../modbus/modbustcpmaster.cpp \
../modbus/modbusrtumaster.cpp \
../modbus/modbustcpmaster.cpp
HEADERS += \
integrationpluginmodbuscommander.h \
../modbus/modbustcpmaster.h \
../modbus/modbusrtumaster.h \
../modbus/modbustcpmaster.h