switched to modbus rtu resource

This commit is contained in:
Boernsman 2021-05-02 11:27:57 +02:00 committed by Michael Zanetti
parent 47b661c2c9
commit 4d5911a098
9 changed files with 554 additions and 1138 deletions

View File

@ -6,9 +6,7 @@ QT += \
SOURCES += \
integrationplugindrexelundweiss.cpp \
../modbus/modbusrtumaster.cpp \
HEADERS += \
integrationplugindrexelundweiss.h \
modbusdegisterdefinition.h \
../modbus/modbusrtumaster.h \
modbusdegisterdefinition.h

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -30,50 +30,39 @@
#include "integrationplugindrexelundweiss.h"
#include "plugininfo.h"
#include "modbusdegisterdefinition.h"
#include "hardwaremanager.h"
#include "hardware/modbus/modbusrtumaster.h"
#include "hardware/modbus/modbusrtuhardwareresource.h"
IntegrationPluginDrexelUndWeiss::IntegrationPluginDrexelUndWeiss()
{
}
IntegrationPluginDrexelUndWeiss::~IntegrationPluginDrexelUndWeiss()
{
m_connectedStateTypeIds.insert(x2luThingClassId, x2luConnectedStateTypeId);
m_connectedStateTypeIds.insert(x2wpThingClassId, x2wpConnectedStateTypeId);
}
void IntegrationPluginDrexelUndWeiss::init()
{
connect(this, &IntegrationPluginDrexelUndWeiss::configValueChanged, this, &IntegrationPluginDrexelUndWeiss::onPluginConfigurationChanged);
connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=](const QUuid &modbusUuid){
qCDebug(dcDrexelUndWeiss()) << "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(dcDrexelUndWeiss()) << "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_connectedStateTypeIds[thing->thingClassId()], false);
}
}
});
}
void IntegrationPluginDrexelUndWeiss::discoverThings(ThingDiscoveryInfo *info)
{
// Create the list of available serial interfaces
QList<ThingDescriptor> thingDescriptors;
if (info->thingClassId() == modbusConnectionThingClassId) {
Q_FOREACH(QSerialPortInfo port, QSerialPortInfo::availablePorts()) {
if (m_usedSerialPorts.contains(port.systemLocation())){
//Thing already in use
qCDebug(dcDrexelUndWeiss()) << "Found serial port that is already used:" << port.portName();
} else {
//Serial port is not yet used, create now a new one
qCDebug(dcDrexelUndWeiss()) << "Found serial port:" << port.portName();
QString description = port.manufacturer() + " " + port.description();
ThingDescriptor descriptor(info->thingClassId(), port.portName(), description);
ParamList parameters;
parameters.append(Param(modbusConnectionThingSerialPortParamTypeId, port.systemLocation()));
descriptor.setParams(parameters);
info->addThingDescriptor(descriptor);
}
}
info->finish(Thing::ThingErrorNoError);
return;
} else if (info->thingClassId() == x2luThingClassId) {
info->finish(Thing::ThingErrorNoError);
return;
} else if (info->thingClassId() == x2wpThingClassId) {
if (info->thingClassId() == x2luThingClassId || info->thingClassId() == x2wpThingClassId) {
QList<ThingDescriptor> thingDescriptors;
info->finish(Thing::ThingErrorNoError);
return;
} else {
@ -84,26 +73,79 @@ void IntegrationPluginDrexelUndWeiss::discoverThings(ThingDiscoveryInfo *info)
void IntegrationPluginDrexelUndWeiss::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
qCDebug(dcDrexelUndWeiss()) << "Setup thing" << thing->name();
if (thing->thingClassId() == modbusConnectionThingClassId) {
if (thing->thingClassId() == x2luThingClassId) {
QString serialPort = thing->paramValue(modbusConnectionThingSerialPortParamTypeId).toString();
int baudRate = thing->paramValue(modbusConnectionThingBaudRateParamTypeId).toInt();
QUuid modbusMasterUuid = thing->paramValue(x2luThingModbusMasterUuidParamTypeId).toUuid();
uint slaveAddress = thing->paramValue(x2luThingSlaveAddressParamTypeId).toUInt();
ModbusRTUMaster *modbus = new ModbusRTUMaster(serialPort, baudRate, QSerialPort::Parity::NoParity, 8, 1, this);
connect(modbus, &ModbusRTUMaster::connectionStateChanged, this, &IntegrationPluginDrexelUndWeiss::onConnectionStateChanged);
connect(modbus, &ModbusRTUMaster::receivedHoldingRegister, this, &IntegrationPluginDrexelUndWeiss::onReceivedHoldingRegister);
if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(modbusMasterUuid)) {
return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface not available."));
}
ModbusRtuMaster *modbus = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(modbusMasterUuid);
if (!modbus->connected()) {
return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface is not connected."));
}
m_modbusRTUMasters.insert(thing, modbus);
m_usedSerialPorts.append(serialPort);
ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, ModbusRegisterX2::Geraetetyp);
connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater);
connect(reply, &ModbusRtuReply::finished, info, [reply, modbus, info, thing, this] {
if (reply->error() != ModbusRtuReply::Error::NoError) {
qCWarning(dcDrexelUndWeiss()) << "Setup failed, received modbus error" << reply->errorString();
return info->finish(Thing::ThingErrorHardwareNotAvailable);
}
if (reply->result().length() != 1) {
qCWarning(dcDrexelUndWeiss()) << "Setup failed, received reply has an illegal length";
return info->finish(Thing::ThingErrorHardwareNotAvailable);
}
if (reply->result().first() != DeviceType::X2_LU) {
qCWarning(dcDrexelUndWeiss()) << "Device on slave addresss" << reply->slaveAddress() << "is not a X2 ventilation unit";
return info->finish(Thing::ThingErrorHardwareNotAvailable);
}
info->finish(Thing::ThingErrorNoError);
m_modbusRtuMasters.insert(thing, modbus);
});
connect(modbus, &ModbusRtuMaster::connectedChanged, this, &IntegrationPluginDrexelUndWeiss::onConnectionStateChanged);
info->finish(Thing::ThingErrorNoError);
return;
} else if (thing->thingClassId() == x2luThingClassId) {
info->finish(Thing::ThingErrorNoError);
return;
} else if (thing->thingClassId() == x2wpThingClassId) {
QUuid modbusMasterUuid = thing->paramValue(x2wpThingModbusMasterUuidParamTypeId).toUuid();
uint slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt();
if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(modbusMasterUuid)) {
return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface not available."));
}
ModbusRtuMaster *modbus = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(modbusMasterUuid);
if (!modbus->connected()) {
return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface is not connected."));
}
ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, ModbusRegisterX2::Geraetetyp);
connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater);
connect(reply, &ModbusRtuReply::finished, info, [reply, modbus, info, thing, this] {
if (reply->error() != ModbusRtuReply::Error::NoError) {
qCWarning(dcDrexelUndWeiss()) << "Setup failed, received modbus error" << reply->errorString();
return info->finish(Thing::ThingErrorHardwareNotAvailable);
}
if (reply->result().length() != 1) {
qCWarning(dcDrexelUndWeiss()) << "Setup failed, received reply has an illegal length";
return info->finish(Thing::ThingErrorHardwareNotAvailable);
}
if (reply->result().first() != DeviceType::X2_WP) {
qCWarning(dcDrexelUndWeiss()) << "Device on slave addresss" << reply->slaveAddress() << "is not a X2 heat pump";
return info->finish(Thing::ThingErrorHardwareNotAvailable);
}
info->finish(Thing::ThingErrorNoError);
m_modbusRtuMasters.insert(thing, modbus);
});
connect(modbus, &ModbusRtuMaster::connectedChanged, this, &IntegrationPluginDrexelUndWeiss::onConnectionStateChanged);
info->finish(Thing::ThingErrorNoError);
return;
} else {
Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
}
@ -111,27 +153,21 @@ void IntegrationPluginDrexelUndWeiss::setupThing(ThingSetupInfo *info)
void IntegrationPluginDrexelUndWeiss::postSetupThing(Thing *thing)
{
qCDebug(dcDrexelUndWeiss()) << "Post setup thing" << thing->name();
if (!m_refreshTimer) {
// Refresh timer for TCP read
qCDebug(dcDrexelUndWeiss()) << "Creating refresh timer";
int refreshTime = configValue(drexelUndWeissPluginUpdateIntervalParamTypeId).toInt();
m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(refreshTime);
connect(m_refreshTimer, &PluginTimer::timeout, this, &IntegrationPluginDrexelUndWeiss::onRefreshTimer);
}
if (thing->thingClassId() == modbusConnectionThingClassId) {
// read Register 5000 and emit auto-Thing
ModbusRTUMaster *modbus = m_modbusRTUMasters.value(thing);
if (!modbus){
qCWarning(dcDrexelUndWeiss()) << "No modbus master available";
}
thing->setStateValue(modbusConnectionConnectedStateTypeId, true);
} else if ((thing->thingClassId() == x2luThingClassId) || (thing->thingClassId() == x2wpThingClassId)) {
if ((thing->thingClassId() == x2luThingClassId) || (thing->thingClassId() == x2wpThingClassId)) {
Thing *parentThing = myThings().findById(thing->parentId());
if (!parentThing) {
qCWarning(dcDrexelUndWeiss()) << "Could not find the parent Thing";
return;
}
ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parentThing);
ModbusRtuMaster *modbus = m_modbusRtuMasters.value(parentThing);
if (!modbus){
qCWarning(dcDrexelUndWeiss()) << "No modbus interface available";
}
@ -147,86 +183,40 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info)
Thing *thing = info->thing();
Action action = info->action();
if (thing->thingClassId() == modbusConnectionThingClassId) {
if (thing->thingClassId() == x2luThingClassId) {
ModbusRTUMaster *modbus = m_modbusRTUMasters.value(thing);
if (!modbus){
qCWarning(dcDrexelUndWeiss()) << "No modbus interface available";
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
if (action.actionTypeId() == modbusConnectionDiscoverDevicesActionTypeId) {
int slave = action.param(modbusConnectionDiscoverDevicesActionSlaveAddressParamTypeId).value().toInt();
discoverModbusSlaves(modbus, slave);
info->finish(Thing::ThingErrorNoError);
return;
} else {
Q_ASSERT_X(false, "executeAction", QString("Unhandled ActionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8());
}
} else if (thing->thingClassId() == x2luThingClassId) {
Thing *parentThing = myThings().findById(thing->parentId());
if (!parentThing) {
qWarning(dcDrexelUndWeiss()) << "Could not find the parent thing";
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parentThing);
int slave = thing->paramValue(x2luThingSlaveAddressParamTypeId).toInt();
if (!modbus){
qCWarning(dcDrexelUndWeiss()) << "No modbus interface available";
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
if (action.actionTypeId() == x2luVentilationModeActionTypeId) {
QString mode = action.param(x2luVentilationModeActionVentilationModeParamTypeId).value().toString();
int data = 0;
if (mode == "Manual level 0") {
data = VentialtionMode::ManuellStufe0;
} else if(mode == "Manual level 1") {
data = VentialtionMode::ManuellStufe1;
} else if(mode == "Manual level 2") {
data = VentialtionMode::ManuellStufe2;
}else if(mode == "Manual level 3") {
data = VentialtionMode::ManuellStufe3;
} else if(mode == "Automatic") {
data = VentialtionMode::Automatikbetrieb;
} else if(mode == "Party") {
data = VentialtionMode::Party;
uint slaveAddress = thing->paramValue(x2luThingSlaveAddressParamTypeId).toUInt();
if (action.actionTypeId() == x2luPowerActionTypeId) {
bool power = action.paramValue(x2luPowerActionPowerParamTypeId).toBool();
uint16_t data = 0;
if (power) {
data = getVentilationModeFromString(thing->stateValue(x2luVentilationModeStateTypeId).toString());
} else {
data = VentilationMode::ManuellStufe0;
}
m_pendingActions.insert(modbus->writeHoldingRegister(slave, ModbusRegisterX2::Betriebsart, data), info);
return;
sendWriteRequest(info, slaveAddress, ModbusRegisterX2::Betriebsart, data);
} else if (action.actionTypeId() == x2luVentilationModeActionTypeId) {
QString mode = action.param(x2luVentilationModeActionVentilationModeParamTypeId).value().toString();
uint16_t data = getVentilationModeFromString(mode);
sendWriteRequest(info, slaveAddress, ModbusRegisterX2::Betriebsart, data);
} else {
Q_ASSERT_X(false, "executeAction", QString("Unhandled ActionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8());
}
} else if (thing->thingClassId() == x2wpThingClassId) {
Thing *parentThing = myThings().findById(thing->parentId());
if (!parentThing) {
qWarning(dcDrexelUndWeiss()) << "Could not find modbus interface";
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parentThing);
int slave = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toInt();
if (!modbus){
qCWarning(dcDrexelUndWeiss()) << "No modbus master available";
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
uint slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt();
if (action.actionTypeId() == x2wpTargetTemperatureActionTypeId) {
qreal targetTemp = (action.param(x2wpTargetTemperatureActionTargetTemperatureParamTypeId).value().toDouble());
int data = static_cast<int>(qRound(targetTemp * 1000));
m_pendingActions.insert(modbus->writeHoldingRegister(slave,ModbusRegisterX2::RaumSoll, data), info);
return;
uint16_t data = static_cast<uint16_t>(qRound(targetTemp * 1000));
sendWriteRequest(info, slaveAddress, ModbusRegisterX2::RaumSoll, data);
} else if (action.actionTypeId() == x2wpTargetWaterTemperatureActionTypeId) {
qreal targetWaterTemp = action.param(x2wpTargetWaterTemperatureActionTargetWaterTemperatureParamTypeId).value().toDouble();
int data = static_cast<int>(qRound(targetWaterTemp * 1000));
m_pendingActions.insert(modbus->writeHoldingRegister(slave, ModbusRegisterX2::BrauchwasserSolltermperatur, data), info);
return;
sendWriteRequest(info, slaveAddress, ModbusRegisterX2::BrauchwasserSolltermperatur, data);
} else {
Q_ASSERT_X(false, "executeAction", QString("Unhandled ActionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8());
}
@ -235,18 +225,40 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info)
}
}
void IntegrationPluginDrexelUndWeiss::sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint16_t value)
{
ModbusRtuMaster *modbus = m_modbusRtuMasters.value(info->thing());
if (!modbus){
qCWarning(dcDrexelUndWeiss()) << "Modbus RTU interface available";
info->finish(Thing::ThingErrorHardwareFailure, tr("Modbus RTU interface not available."));
return;
}
if (!modbus->connected()) {
qCWarning(dcDrexelUndWeiss()) << "Modbus RTU interface not connected";
info->finish(Thing::ThingErrorHardwareFailure, tr("Modbus RTU interface not connected."));
return;
}
ModbusRtuReply *reply = modbus->writeHoldingRegisters(slaveAddress, modbusRegister, QVector<uint16_t>() << value);
connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater);
connect(reply, &ModbusRtuReply::finished, info, [info, reply] {
if (reply->error() != ModbusRtuReply::Error::NoError) {
return info->finish(Thing::ThingErrorHardwareFailure);
}
//TODO update thing state after successfull write requests
info->finish(Thing::ThingErrorNoError);
});
}
void IntegrationPluginDrexelUndWeiss::thingRemoved(Thing *thing)
{
if (thing->thingClassId() == modbusConnectionThingClassId) {
ModbusRTUMaster *modbus = m_modbusRTUMasters.take(thing);
if (!modbus){
qCWarning(dcDrexelUndWeiss()) << "No modbus interface available";
return;
}
m_usedSerialPorts.removeAll(modbus->serialPort());
modbus->deleteLater();
if (thing->thingClassId() == x2luThingClassId || thing->thingClassId() == x2luThingClassId) {
m_modbusRtuMasters.remove(thing);
}
if (myThings().isEmpty()) {
@ -258,15 +270,7 @@ void IntegrationPluginDrexelUndWeiss::thingRemoved(Thing *thing)
void IntegrationPluginDrexelUndWeiss::onRefreshTimer()
{
foreach (Thing *thing, myThings()) {
if (thing->thingClassId() == modbusConnectionThingClassId) {
ModbusRTUMaster *modbus = m_modbusRTUMasters.value(thing);
if (!modbus) {
qCWarning(dcDrexelUndWeiss()) << "No modbus master available";
return;
}
} else if (thing->thingClassId() == x2luThingClassId || thing->thingClassId() == x2wpThingClassId){
if (thing->thingClassId() == x2luThingClassId || thing->thingClassId() == x2wpThingClassId){
updateStates(thing);
}
}
@ -275,38 +279,279 @@ void IntegrationPluginDrexelUndWeiss::onRefreshTimer()
void IntegrationPluginDrexelUndWeiss::updateStates(Thing *thing)
{
if (thing->thingClassId() == x2luThingClassId) {
Thing *parent = myThings().findById(thing->parentId());
ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parent);
int slave = thing->paramValue(x2luThingSlaveAddressParamTypeId).toInt();
ModbusRtuMaster *modbus = m_modbusRtuMasters.value(thing);
if (!modbus) {
return;
}
uint slaveAddress = thing->paramValue(x2luThingSlaveAddressParamTypeId).toUInt();
modbus->readHoldingRegister(slave, ModbusRegisterX2::AktiveLuefterstufe);
modbus->readHoldingRegister(slave, ModbusRegisterX2::Betriebsart); // Ventilation mode
modbus->readHoldingRegister(slave, ModbusRegisterX2::CO2);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::AktiveLuefterstufe);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Betriebsart); // Ventilation mode
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::CO2);
}
if (thing->thingClassId() == x2wpThingClassId) {
Thing *parent = myThings().findById(thing->parentId());
ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parent);
int slave = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toInt();
ModbusRtuMaster *modbus = m_modbusRtuMasters.value(thing);
if (!modbus) {
return;
}
int slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt();
modbus->readHoldingRegister(slave, ModbusRegisterX2::Waermepumpe);
modbus->readHoldingRegister(slave, ModbusRegisterX2::RaumSoll);
modbus->readHoldingRegister(slave, ModbusRegisterX2::Raum);
modbus->readHoldingRegister(slave, ModbusRegisterX2::TemperaturWarmwasserspeicherUnten);
modbus->readHoldingRegister(slave, ModbusRegisterX2::BrauchwasserSolltermperatur);
modbus->readHoldingRegister(slave, ModbusRegisterX2::Auszenluft);
modbus->readHoldingRegister(slave, ModbusRegisterX2::Summenstoerung);
modbus->readHoldingRegister(slave, ModbusRegisterX2::LeistungKompressor);
modbus->readHoldingRegister(slave, ModbusRegisterX2::LeistungWarmwasser);
modbus->readHoldingRegister(slave, ModbusRegisterX2::LeistungRaumheizung);
modbus->readHoldingRegister(slave, ModbusRegisterX2::LeistungLuftvorwaermung);
modbus->readHoldingRegister(slave, ModbusRegisterX2::EnergieKompressor);
modbus->readHoldingRegister(slave, ModbusRegisterX2::EnergieWarmwasser);
modbus->readHoldingRegister(slave, ModbusRegisterX2::EnergieRaumheizung);
modbus->readHoldingRegister(slave, ModbusRegisterX2::EnergieLuftvorerwarrmung);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Waermepumpe);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::RaumSoll);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Raum);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::TemperaturWarmwasserspeicherUnten);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::BrauchwasserSolltermperatur);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Auszenluft);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Summenstoerung);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::LeistungKompressor);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::LeistungWarmwasser);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::LeistungRaumheizung);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::LeistungLuftvorwaermung);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::EnergieKompressor);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::EnergieWarmwasser);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::EnergieRaumheizung);
readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::EnergieLuftvorerwarrmung);
}
}
void IntegrationPluginDrexelUndWeiss::readHoldingRegister(Thing *thing, ModbusRtuMaster *modbus, uint slaveAddress, uint modbusRegister)
{
ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, modbusRegister);
connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater);
connect(reply, &ModbusRtuReply::finished, this, [reply, thing, this] {
if (reply->error() != ModbusRtuReply::Error::NoError) {
qCWarning(dcDrexelUndWeiss()) << "Modbus error" << reply->errorString();
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), false);
return;
}
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true);
QVector<uint16_t> values = reply->result();
if (thing->thingClassId() == x2luThingClassId) {
switch (reply->registerAddress()) {
case ModbusRegisterX2::Waermepumpe:
thing->setStateValue(x2wpPowerStateTypeId, values[0]);
break;
case ModbusRegisterX2::RaumSoll:
thing->setStateValue(x2wpTargetTemperatureStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::Raum:
thing->setStateValue(x2wpTemperatureStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::TemperaturWarmwasserspeicherUnten:
thing->setStateValue(x2wpWaterTemperatureStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::BrauchwasserSolltermperatur:
thing->setStateValue(x2wpTargetWaterTemperatureStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::Auszenluft:
thing->setStateValue(x2wpOutsideAirTemperatureStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::Summenstoerung:
if (values[0] != 0) {
//get actual error
} else {
thing->setStateValue(x2wpErrorStateTypeId, "No Error");
}
break;
case ModbusRegisterX2::StoerungAbluftventilator:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Exhaust fan");
break;
case ModbusRegisterX2::StoerungBoilerfuehlerElektroheizstab:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor electric heating element");
break;
case ModbusRegisterX2::StoerungBoilerfuehlerSolar:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor solar");
break;
case ModbusRegisterX2::StoerungBoilerfuehlerWaermepumpe:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor heat pump");
break;
case ModbusRegisterX2::StoerungBoileruebertemperatur:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Boiler overtemperature");
break;
case ModbusRegisterX2::StoerungCO2Sensor:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "CO2-Sensor");
break;
case ModbusRegisterX2::StoerungDruckverlustAbluftZuGrosz:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Pressure loss exhaust air too big");
break;
case ModbusRegisterX2::StoerungDruckverlustZuluftZuGrosz:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Pressure loss supply air too large");
break;
case ModbusRegisterX2::StoerungDurchflussmengeHeizgkreis:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Flow rate of heating circuit");
break;
case ModbusRegisterX2::StoerungDurchflussmengeSolekreis:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Flow rate brine circuit");
break;
case ModbusRegisterX2::StoerungTeilnehmerNichtErreichbar:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Participant not available");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerAuszenluft:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor outside air");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerHeizkreisVorlauf:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor heating circuit flow");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerRaum:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor room");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerSolarkollektor:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor solar collector");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerSole:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor brine");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerSoleAuszenluft:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor brine outside air");
break;
case ModbusRegisterX2::StoerungWaermepumpeHochdruck:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Heat pump high pressure");
break;
case ModbusRegisterX2::StoerungWaermepumpeNiederdruck:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Heat pump low pressure");
break;
case ModbusRegisterX2::StoerungWertNichtZulaessig:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Value not allowed");
break;
case ModbusRegisterX2::StoerungZuluftventilator:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Supply air fan");
break;
case ModbusRegisterX2::LeistungKompressor:
thing->setStateValue(x2wpPowerCompressorStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::LeistungWarmwasser:
thing->setStateValue(x2wpPowerWaterHeatingStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::LeistungRaumheizung:
thing->setStateValue(x2wpPowerRoomHeatingStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::LeistungLuftvorwaermung:
thing->setStateValue(x2wpPowerAirPreheatingStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::EnergieKompressor:
thing->setStateValue(x2wpEnergyCompressorStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::EnergieWarmwasser:
thing->setStateValue(x2wpEnergyWaterHeatingStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::EnergieRaumheizung:
thing->setStateValue(x2wpEnergyRoomHeatingStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::EnergieLuftvorerwarrmung:
thing->setStateValue(x2wpEnergyAirPreheatingStateTypeId, values[0]/1000.00);
break;
default:
break;
}
} else if (thing->thingClassId() == x2wpThingClassId) {
switch (reply->registerAddress()) {
case ModbusRegisterX2::Betriebsart:
if (values[0] == VentilationMode::ManuellStufe0) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 0");
} else if (values[0] == VentilationMode::ManuellStufe1) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 1");
} else if (values[0] == VentilationMode::ManuellStufe2) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 2");
} else if (values[0] == VentilationMode::ManuellStufe3) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 3");
} else if (values[0] == VentilationMode::Automatikbetrieb) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Automatic");
} else if (values[0] == VentilationMode::Party) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Party");
}
if (values[0] == VentilationMode::ManuellStufe0) {
thing->setStateValue(x2luPowerStateTypeId, false);
} else {
thing->setStateValue(x2luPowerStateTypeId, true);
}
break;
case ModbusRegisterX2::AktiveLuefterstufe:
thing->setStateValue(x2luActiveVentilationLevelStateTypeId, values[0]);
break;
case ModbusRegisterX2::CO2:
thing->setStateValue(x2luCo2StateTypeId, values[0]);
break;
}
}
});
}
VentilationMode IntegrationPluginDrexelUndWeiss::getVentilationModeFromString(const QString &modeString)
{
if (modeString == "Manual level 0") {
return VentilationMode::ManuellStufe0;
} else if(modeString == "Manual level 1") {
return VentilationMode::ManuellStufe1;
} else if(modeString == "Manual level 2") {
return VentilationMode::ManuellStufe2;
}else if(modeString == "Manual level 3") {
return VentilationMode::ManuellStufe3;
} else if(modeString == "Automatic") {
return VentilationMode::Automatikbetrieb;
} else if(modeString == "Party") {
return VentilationMode::Party;
} else {
qCWarning(dcDrexelUndWeiss()) << "Unknown ventilation mode string" << modeString;
}
return VentilationMode::ManuellStufe0;
}
void IntegrationPluginDrexelUndWeiss::onPluginConfigurationChanged(const ParamTypeId &paramTypeId, const QVariant &value)
{
@ -322,318 +567,9 @@ void IntegrationPluginDrexelUndWeiss::onPluginConfigurationChanged(const ParamTy
void IntegrationPluginDrexelUndWeiss::onConnectionStateChanged(bool status)
{
ModbusRTUMaster *modbusRtuMaster = static_cast<ModbusRTUMaster *>(sender());
Thing *thing = m_modbusRTUMasters.key(modbusRtuMaster);
ModbusRtuMaster *modbusRtuMaster = static_cast<ModbusRtuMaster *>(sender());
Thing *thing = m_modbusRtuMasters.key(modbusRtuMaster);
if (!thing)
return;
if (thing->thingClassId() == modbusConnectionThingClassId) {
thing->setStateValue(modbusConnectionConnectedStateTypeId, status);
}
}
void IntegrationPluginDrexelUndWeiss::onReceivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values)
{
ModbusRTUMaster *modbus = static_cast<ModbusRTUMaster *>(sender());
if (m_modbusRTUMasters.values().contains(modbus) ){
Thing *parentThing = m_modbusRTUMasters.key(static_cast<ModbusRTUMaster *>(modbus));
foreach(Thing *thing, myThings().filterByParentId(parentThing->id())) {
if (thing->thingClassId() == x2luThingClassId && thing->paramValue(x2luThingSlaveAddressParamTypeId) == slaveAddress) {
switch (modbusRegister) {
case ModbusRegisterX2::Waermepumpe:
thing->setStateValue(x2wpPowerStateTypeId, values[0]);
break;
case ModbusRegisterX2::RaumSoll:
thing->setStateValue(x2wpTargetTemperatureStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::Raum:
thing->setStateValue(x2wpTemperatureStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::TemperaturWarmwasserspeicherUnten:
thing->setStateValue(x2wpWaterTemperatureStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::BrauchwasserSolltermperatur:
thing->setStateValue(x2wpTargetWaterTemperatureStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::Auszenluft:
thing->setStateValue(x2wpOutsideAirTemperatureStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::Summenstoerung:
if (values[0] != 0) {
//get actual error
} else {
thing->setStateValue(x2wpErrorStateTypeId, "No Error");
}
break;
case ModbusRegisterX2::StoerungAbluftventilator:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Exhaust fan");
break;
case ModbusRegisterX2::StoerungBoilerfuehlerElektroheizstab:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor electric heating element");
break;
case ModbusRegisterX2::StoerungBoilerfuehlerSolar:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor solar");
break;
case ModbusRegisterX2::StoerungBoilerfuehlerWaermepumpe:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor heat pump");
break;
case ModbusRegisterX2::StoerungBoileruebertemperatur:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Boiler overtemperature");
break;
case ModbusRegisterX2::StoerungCO2Sensor:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "CO2-Sensor");
break;
case ModbusRegisterX2::StoerungDruckverlustAbluftZuGrosz:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Pressure loss exhaust air too big");
break;
case ModbusRegisterX2::StoerungDruckverlustZuluftZuGrosz:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Pressure loss supply air too large");
break;
case ModbusRegisterX2::StoerungDurchflussmengeHeizgkreis:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Flow rate of heating circuit");
break;
case ModbusRegisterX2::StoerungDurchflussmengeSolekreis:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Flow rate brine circuit");
break;
case ModbusRegisterX2::StoerungTeilnehmerNichtErreichbar:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Participant not available");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerAuszenluft:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor outside air");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerHeizkreisVorlauf:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor heating circuit flow");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerRaum:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor room");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerSolarkollektor:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor solar collector");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerSole:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor brine");
break;
case ModbusRegisterX2::StoerungTemperaturfuehlerSoleAuszenluft:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor brine outside air");
break;
case ModbusRegisterX2::StoerungWaermepumpeHochdruck:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Heat pump high pressure");
break;
case ModbusRegisterX2::StoerungWaermepumpeNiederdruck:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Heat pump low pressure");
break;
case ModbusRegisterX2::StoerungWertNichtZulaessig:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Value not allowed");
break;
case ModbusRegisterX2::StoerungZuluftventilator:
if (values[0] != 0)
thing->setStateValue(x2wpErrorStateTypeId, "Supply air fan");
break;
case ModbusRegisterX2::LeistungKompressor:
thing->setStateValue(x2wpPowerCompressorStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::LeistungWarmwasser:
thing->setStateValue(x2wpPowerWaterHeatingStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::LeistungRaumheizung:
thing->setStateValue(x2wpPowerRoomHeatingStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::LeistungLuftvorwaermung:
thing->setStateValue(x2wpPowerAirPreheatingStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::EnergieKompressor:
thing->setStateValue(x2wpEnergyCompressorStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::EnergieWarmwasser:
thing->setStateValue(x2wpEnergyWaterHeatingStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::EnergieRaumheizung:
thing->setStateValue(x2wpEnergyRoomHeatingStateTypeId, values[0]/1000.00);
break;
case ModbusRegisterX2::EnergieLuftvorerwarrmung:
thing->setStateValue(x2wpEnergyAirPreheatingStateTypeId, values[0]/1000.00);
break;
default:
break;
}
} else if (thing->thingClassId() == x2wpThingClassId && thing->paramValue(x2wpThingSlaveAddressParamTypeId) == slaveAddress) {
switch (modbusRegister) {
case ModbusRegisterX2::Betriebsart:
if (values[0] == VentialtionMode::ManuellStufe0) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 0");
} else if (values[0] == VentialtionMode::ManuellStufe1) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 1");
} else if (values[0] == VentialtionMode::ManuellStufe2) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 2");
} else if (values[0] == VentialtionMode::ManuellStufe3) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 3");
} else if (values[0] == VentialtionMode::Automatikbetrieb) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Automatic");
} else if (values[0] == VentialtionMode::Party) {
thing->setStateValue(x2luVentilationModeStateTypeId, "Party");
}
break;
case ModbusRegisterX2::AktiveLuefterstufe:
thing->setStateValue(x2luActiveVentilationLevelStateTypeId, values[0]);
break;
case ModbusRegisterX2::CO2:
thing->setStateValue(x2luCo2StateTypeId, values[0]);
break;
}
}
}
if (modbusRegister == ModbusRegisterX2::Geraetetyp) {
switch (values[0]) {
case DeviceType::X2_WP: {
qDebug(dcDrexelUndWeiss()) << "Discovered X2 heat pump";
QList<ThingDescriptor> thingDescriptors;
ThingDescriptor descriptor(x2wpThingClassId, "X2 WP", "Drexel und Weiss", parentThing->id());
ParamList params;
params.append(Param(x2wpThingSlaveAddressParamTypeId, slaveAddress));
descriptor.setParams(params);
thingDescriptors.append(descriptor);
emit autoThingsAppeared(thingDescriptors);
break;
}
case DeviceType::X2_LU: {
qDebug(dcDrexelUndWeiss()) << "Discovered X2 ventilation unit";
QList<ThingDescriptor> thingDescriptors;
ThingDescriptor descriptor(x2luThingClassId, "X2 LU", "Drexel und Weiss", parentThing->id());
ParamList params;
params.append(Param(x2luThingSlaveAddressParamTypeId, slaveAddress));
descriptor.setParams(params);
thingDescriptors.append(descriptor);
emit autoThingsAppeared(thingDescriptors);
break;
}
case DeviceType::AerosilentBianco:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosilent Bianco";
break;
case DeviceType::AerosilentBusiness:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosilent Business";
break;
case DeviceType::AerosilentCentro:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosilent Centro";
break;
case DeviceType::AerosilentMicro:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosilent Micro";
break;
case DeviceType::AerosilentPrimus:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosilent Primus";
break;
case DeviceType::AerosilentStratos:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosilent Stratos";
break;
case DeviceType::AerosilentTopo:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosmart Topo";
break;
case DeviceType::AerosmartL:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosmart L";
break;
case DeviceType::AerosmartM:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosmart M";
break;
case DeviceType::AerosmartMono:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosmart Mono";
break;
case DeviceType::AerosmartS:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosmart S";
break;
case DeviceType::AerosmartXls:
qDebug(dcDrexelUndWeiss()) << "Discovered Aerosmart Xls";
break;
}
}
}
}
void IntegrationPluginDrexelUndWeiss::onWriteRequestFinished(QUuid requestId, bool success)
{
if (m_pendingActions.contains(requestId)) {
ThingActionInfo *info = m_pendingActions.take(requestId);
if (!info)
return;
if (success) {
info->finish(Thing::ThingErrorNoError);
} else {
info->finish(Thing::ThingErrorHardwareFailure);
}
}
}
void IntegrationPluginDrexelUndWeiss::discoverModbusSlaves(ModbusRTUMaster *modbus, int slaveAddress)
{
foreach (Thing *thing, myThings()) {
if (thing->thingClassId() == x2luThingClassId) {
if (thing->paramValue(x2luThingSlaveAddressParamTypeId).toInt() == slaveAddress) {
qWarning(dcDrexelUndWeiss()) << "Thing with slave address" << slaveAddress << "already added";
return;
}
}
if (thing->thingClassId() == x2wpThingClassId) {
if (thing->paramValue(x2wpThingSlaveAddressParamTypeId).toInt() == slaveAddress) {
qWarning(dcDrexelUndWeiss()) << "Thing with slave address" << slaveAddress << "already added";
return;
}
}
}
modbus->readHoldingRegister(slaveAddress, ModbusRegisterX2::Geraetetyp);
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), status);
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -32,12 +32,11 @@
#define INTEGRATIONPLUGINDREXELUNDWEISS_H
#include "integrations/integrationplugin.h"
#include "hardware/modbus/modbusrtumaster.h"
#include "plugintimer.h"
#include "../modbus/modbusrtumaster.h"
#include "modbusdegisterdefinition.h"
#include <QDateTime>
#include <QSerialPortInfo>
class IntegrationPluginDrexelUndWeiss : public IntegrationPlugin
{
@ -48,9 +47,8 @@ class IntegrationPluginDrexelUndWeiss : public IntegrationPlugin
public:
explicit IntegrationPluginDrexelUndWeiss();
~IntegrationPluginDrexelUndWeiss() override;
void init() override;
void init() override;
void discoverThings(ThingDiscoveryInfo *info) override;
void setupThing(ThingSetupInfo *info) override;
void postSetupThing(Thing *thing) override;
@ -58,21 +56,21 @@ public:
void executeAction(ThingActionInfo *info) override;
private:
QList<QString> m_usedSerialPorts;
QHash<Thing *, ModbusRTUMaster *> m_modbusRTUMasters;
QHash<Thing *, ModbusRtuMaster *> m_modbusRtuMasters;
PluginTimer *m_refreshTimer = nullptr;
QHash<QUuid, ThingActionInfo *> m_pendingActions;
QHash<ThingClassId, StateTypeId> m_connectedStateTypeIds;
void sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint16_t value);
void updateStates(Thing *thing);
void discoverModbusSlaves(ModbusRTUMaster *modbus, int slaveAddress);
void discoverModbusSlaves(ModbusRtuMaster *modbus, uint slaveAddress);
void readHoldingRegister(Thing *thing, ModbusRtuMaster *modbus, uint slaveAddress, uint modbusRegister);
VentilationMode getVentilationModeFromString(const QString &modeString);
private slots:
void onRefreshTimer();
void onPluginConfigurationChanged(const ParamTypeId &paramTypeId, const QVariant &value);
void onConnectionStateChanged(bool status);
void onReceivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
void onWriteRequestFinished(QUuid requestId, bool success);
};
#endif // INTEGRATIONPLUGINDREXELUNDWEISS_H

View File

@ -18,81 +18,37 @@
"displayName": "Drexel und Weiss",
"id": "9f476e8b-7e95-448e-b03b-874747e8fb1f",
"thingClasses": [
{
"name": "modbusConnection",
"displayName": "Modbus connection",
"id": "06d04eec-ab5d-479a-b9e6-8c89efc18a8b",
"createMethods": ["discovery", "user"],
"interfaces": ["gateway"],
"paramTypes": [
{
"id": "ed49f7d8-ab18-4c37-9b80-1004b75dcb91",
"name": "serialPort",
"displayName": "Serial port",
"type": "QString",
"inputType": "TextLine",
"defaultValue": "ttyAMA0"
},
{
"id": "d0c04612-cc3e-4d38-b4c9-708e28dc4eb3",
"name": "baudRate",
"displayName": "Baud rate",
"type": "int",
"defaultValue": 9600
}
],
"stateTypes": [
{
"id": "181ce6e2-9c55-45c6-b329-adf379679e07a",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"defaultValue": false
}
],
"actionTypes": [
{
"id": "b9a24ecc-4433-4f31-99ba-596033bda421",
"name": "discoverDevices",
"displayName": "Discover devices",
"paramTypes": [
{
"id": "22413a22-31d4-4b8c-b855-8a29da5946bc",
"name": "slaveAddress",
"displayName": "Slave address",
"type": "int",
"minValue": 0,
"maxValue": 250,
"defaultValue": 0
}
]
}
]
},
{
"name": "x2lu",
"displayName": "X2 LU",
"id": "0de8e21e-392a-4790-a78a-b1a7eaa7571b",
"createMethods": ["auto"],
"interfaces": ["co2sensor", "connectable"],
"createMethods": ["discovery"],
"interfaces": ["ventilation", "co2sensor", "connectable"],
"discoveryParamTypes": [
{
"id": "8dd4ba9f-51f6-4711-a917-abac5e1aa82b",
"name": "slaveAddress",
"displayName": "Slave address",
"type": "int",
"defaultValue": 1
}
],
"paramTypes": [
{
"id": "28a72cb7-3cd0-4704-b604-44fb090d5a88",
"name": "slaveAddress",
"displayName": "Slave address",
"type": "int",
"type": "uint",
"minValue": 0,
"maxValue": 250,
"defaultValue": 0
},
{
"id": "91ef76cf-6c53-4a8a-a278-6f6e2ef68cc6",
"name": "sofwareVersion",
"displayName": "Software version",
"type": "QString",
"inputType": "TextLine",
"defaultValue": "-"
"id": "d25197d1-b1b9-45a9-b6fa-60583ed469fb",
"name": "modbusMasterUuid",
"displayName": "Modbus RTU master",
"type": "QUuid",
"defaultValue": ""
}
],
"stateTypes":[
@ -104,6 +60,16 @@
"type": "bool",
"defaultValue": false
},
{
"id": "c9df6349-2bf6-46cc-bce3-d4155836dbe5",
"name": "power",
"displayName": "Power",
"displayNameAction": "Set power",
"displayNameEvent": "Power changed",
"type": "bool",
"writable": true,
"defaultValue": false
},
{
"id": "0a6b44c8-e7af-4148-92ff-682ae717f3a8",
"name": "co2",
@ -145,25 +111,33 @@
"name": "x2wp",
"displayName": "X2 WP",
"id": "e548f962-92db-4110-8279-10fbcde35f93",
"createMethods": ["auto"],
"createMethods": ["discovery"],
"interfaces": ["thermostat", "heating", "temperaturesensor", "connectable"],
"discoveryParamTypes": [
{
"id": "d4923c90-22c8-477e-a37a-341858e59dcb",
"name": "slaveAddress",
"displayName": "Slave address",
"type": "int",
"defaultValue": 1
}
],
"paramTypes": [
{
"id": "b551d138-b006-4290-bfef-97072ff677c6",
"name": "slaveAddress",
"displayName": "Slave address",
"type": "int",
"type": "uint",
"minValue": 0,
"maxValue": 250,
"defaultValue": 0
},
{
"id": "1ffd72a9-7b3f-4287-b671-7f22e159f9b8",
"name": "sofwareVersion",
"displayName": "Software version",
"type": "QString",
"inputType": "TextLine",
"defaultValue": "-"
"id": "db8358f3-f573-44e3-b024-c4613ee3a270",
"name": "modbusMasterUuid",
"displayName": "Modbus RTU master",
"type": "QUuid",
"defaultValue": ""
}
],
"stateTypes":[

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -33,6 +33,8 @@
#endif // MODBUSDEGISTERDEFINITION
#include <QObject>
enum ModbusRegisterX2 {
AbsenkungderLuefterstufe1 = 5328,
AktiveLuefterstufe = 1066,
@ -241,7 +243,7 @@ enum HeatPumpStatus {
NachAbtauenAbtropfen
};
enum VentialtionMode {
enum VentilationMode {
ManuellStufe0 = 0,
ManuellStufe1,
ManuellStufe2,

View File

@ -35,11 +35,6 @@ The name of the StateType ({0a6b44c8-e7af-4148-92ff-682ae717f3a8}) of ThingClass
<extracomment>The name of the ActionType ({fb021cac-1236-4324-a45c-8d89ad069052}) of ThingClass x2wp</extracomment>
<translation>Setze Zielwassertemperatur</translation>
</message>
<message>
<source>Discover devices</source>
<extracomment>The name of the ActionType ({b9a24ecc-4433-4f31-99ba-596033bda421}) of ThingClass modbusConnection</extracomment>
<translation>Suche Geräte</translation>
</message>
<message>
<source>Drexel und Weiss</source>
<extracomment>The name of the vendor ({9f476e8b-7e95-448e-b03b-874747e8fb1f})
@ -137,12 +132,20 @@ The name of the StateType ({32378843-5478-4b86-9c0e-ccbf978c02be}) of ThingClass
----------
The name of the ParamType (ThingClass: x2wp, EventType: power, ID: {f2ce8389-c33f-4f10-8484-f2e993841762})
----------
The name of the StateType ({f2ce8389-c33f-4f10-8484-f2e993841762}) of ThingClass x2wp</extracomment>
The name of the StateType ({f2ce8389-c33f-4f10-8484-f2e993841762}) of ThingClass x2wp
----------
The name of the ParamType (ThingClass: x2lu, ActionType: power, ID: {c9df6349-2bf6-46cc-bce3-d4155836dbe5})
----------
The name of the ParamType (ThingClass: x2lu, EventType: power, ID: {c9df6349-2bf6-46cc-bce3-d4155836dbe5})
----------
The name of the StateType ({c9df6349-2bf6-46cc-bce3-d4155836dbe5}) of ThingClass x2lu</extracomment>
<translation>Eingeschalten</translation>
</message>
<message>
<source>Power changed</source>
<extracomment>The name of the EventType ({f2ce8389-c33f-4f10-8484-f2e993841762}) of ThingClass x2wp</extracomment>
<extracomment>The name of the EventType ({f2ce8389-c33f-4f10-8484-f2e993841762}) of ThingClass x2wp
----------
The name of the EventType ({c9df6349-2bf6-46cc-bce3-d4155836dbe5}) of ThingClass x2lu</extracomment>
<translation>Eingeschalten geändert</translation>
</message>
<message>
@ -205,27 +208,17 @@ The name of the StateType ({3ab2d609-1686-4fd7-84e3-580c8e0537d0}) of ThingClass
<extracomment>The name of the EventType ({3ab2d609-1686-4fd7-84e3-580c8e0537d0}) of ThingClass x2wp</extracomment>
<translation>Raumtemperatur geändert</translation>
</message>
<message>
<source>Serial port</source>
<extracomment>The name of the ParamType (ThingClass: modbusConnection, Type: thing, ID: {ed49f7d8-ab18-4c37-9b80-1004b75dcb91})</extracomment>
<translation>Serielle Schnittstelle</translation>
</message>
<message>
<source>Slave address</source>
<extracomment>The name of the ParamType (ThingClass: x2wp, Type: thing, ID: {b551d138-b006-4290-bfef-97072ff677c6})
<extracomment>The name of the ParamType (ThingClass: x2wp, Type: discovery, ID: {d4923c90-22c8-477e-a37a-341858e59dcb})
----------
The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {28a72cb7-3cd0-4704-b604-44fb090d5a88})
The name of the ParamType (ThingClass: x2wp, Type: thing, ID: {b551d138-b006-4290-bfef-97072ff677c6})
----------
The name of the ParamType (ThingClass: modbusConnection, ActionType: discoverDevices, ID: {22413a22-31d4-4b8c-b855-8a29da5946bc})</extracomment>
The name of the ParamType (ThingClass: x2lu, Type: discovery, ID: {8dd4ba9f-51f6-4711-a917-abac5e1aa82b})
----------
The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {28a72cb7-3cd0-4704-b604-44fb090d5a88})</extracomment>
<translation>Slave-Adresse</translation>
</message>
<message>
<source>Software version</source>
<extracomment>The name of the ParamType (ThingClass: x2wp, Type: thing, ID: {1ffd72a9-7b3f-4287-b671-7f22e159f9b8})
----------
The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {91ef76cf-6c53-4a8a-a278-6f6e2ef68cc6})</extracomment>
<translation>Softwareversion</translation>
</message>
<message>
<source>Target room temperature</source>
<extracomment>The name of the ParamType (ThingClass: x2wp, ActionType: targetTemperature, ID: {fb98754d-0fba-4163-9b74-3e5a07d71421})
@ -307,11 +300,6 @@ The name of the StateType ({77a96b57-fa0a-4946-af5b-39c3b66d9422}) of ThingClass
<extracomment>The name of the ThingClass ({e548f962-92db-4110-8279-10fbcde35f93})</extracomment>
<translation>X2 WP</translation>
</message>
<message>
<source>Baud rate</source>
<extracomment>The name of the ParamType (ThingClass: modbusConnection, Type: thing, ID: {d0c04612-cc3e-4d38-b4c9-708e28dc4eb3})</extracomment>
<translation>Baudrate</translation>
</message>
<message>
<source>Connected</source>
<extracomment>The name of the ParamType (ThingClass: x2wp, EventType: connected, ID: {baf203be-a391-4bfc-8198-53b4ecbcce80})
@ -320,26 +308,42 @@ The name of the StateType ({baf203be-a391-4bfc-8198-53b4ecbcce80}) of ThingClass
----------
The name of the ParamType (ThingClass: x2lu, EventType: connected, ID: {b4c4726f-d3d7-46e8-badb-0d590e7f5fac})
----------
The name of the StateType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu
----------
The name of the ParamType (ThingClass: modbusConnection, EventType: connected, ID: {181ce6e2-9c55-45c6-b329-adf379679e07})
----------
The name of the StateType ({181ce6e2-9c55-45c6-b329-adf379679e07}) of ThingClass modbusConnection</extracomment>
The name of the StateType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu</extracomment>
<translation>Verbunden</translation>
</message>
<message>
<source>Connected changed</source>
<extracomment>The name of the EventType ({baf203be-a391-4bfc-8198-53b4ecbcce80}) of ThingClass x2wp
----------
The name of the EventType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu
----------
The name of the EventType ({181ce6e2-9c55-45c6-b329-adf379679e07}) of ThingClass modbusConnection</extracomment>
The name of the EventType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu</extracomment>
<translation>Verbunden geändert</translation>
</message>
<message>
<source>Modbus connection</source>
<extracomment>The name of the ThingClass ({06d04eec-ab5d-479a-b9e6-8c89efc18a8b})</extracomment>
<translation>Modbusverbindung</translation>
<source>Modbus RTU master</source>
<extracomment>The name of the ParamType (ThingClass: x2wp, Type: thing, ID: {db8358f3-f573-44e3-b024-c4613ee3a270})
----------
The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {d25197d1-b1b9-45a9-b6fa-60583ed469fb})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set power</source>
<extracomment>The name of the ActionType ({c9df6349-2bf6-46cc-bce3-d4155836dbe5}) of ThingClass x2lu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>IntegrationPluginDrexelUndWeiss</name>
<message>
<source>Modbus RTU interface not available.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modbus RTU interface is not connected.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modbus RTU interface not connected.</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -35,11 +35,6 @@ The name of the StateType ({0a6b44c8-e7af-4148-92ff-682ae717f3a8}) of ThingClass
<extracomment>The name of the ActionType ({fb021cac-1236-4324-a45c-8d89ad069052}) of ThingClass x2wp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Discover devices</source>
<extracomment>The name of the ActionType ({b9a24ecc-4433-4f31-99ba-596033bda421}) of ThingClass modbusConnection</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Drexel und Weiss</source>
<extracomment>The name of the vendor ({9f476e8b-7e95-448e-b03b-874747e8fb1f})
@ -137,12 +132,20 @@ The name of the StateType ({32378843-5478-4b86-9c0e-ccbf978c02be}) of ThingClass
----------
The name of the ParamType (ThingClass: x2wp, EventType: power, ID: {f2ce8389-c33f-4f10-8484-f2e993841762})
----------
The name of the StateType ({f2ce8389-c33f-4f10-8484-f2e993841762}) of ThingClass x2wp</extracomment>
The name of the StateType ({f2ce8389-c33f-4f10-8484-f2e993841762}) of ThingClass x2wp
----------
The name of the ParamType (ThingClass: x2lu, ActionType: power, ID: {c9df6349-2bf6-46cc-bce3-d4155836dbe5})
----------
The name of the ParamType (ThingClass: x2lu, EventType: power, ID: {c9df6349-2bf6-46cc-bce3-d4155836dbe5})
----------
The name of the StateType ({c9df6349-2bf6-46cc-bce3-d4155836dbe5}) of ThingClass x2lu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power changed</source>
<extracomment>The name of the EventType ({f2ce8389-c33f-4f10-8484-f2e993841762}) of ThingClass x2wp</extracomment>
<extracomment>The name of the EventType ({f2ce8389-c33f-4f10-8484-f2e993841762}) of ThingClass x2wp
----------
The name of the EventType ({c9df6349-2bf6-46cc-bce3-d4155836dbe5}) of ThingClass x2lu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
@ -205,25 +208,15 @@ The name of the StateType ({3ab2d609-1686-4fd7-84e3-580c8e0537d0}) of ThingClass
<extracomment>The name of the EventType ({3ab2d609-1686-4fd7-84e3-580c8e0537d0}) of ThingClass x2wp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Serial port</source>
<extracomment>The name of the ParamType (ThingClass: modbusConnection, Type: thing, ID: {ed49f7d8-ab18-4c37-9b80-1004b75dcb91})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Slave address</source>
<extracomment>The name of the ParamType (ThingClass: x2wp, Type: thing, ID: {b551d138-b006-4290-bfef-97072ff677c6})
<extracomment>The name of the ParamType (ThingClass: x2wp, Type: discovery, ID: {d4923c90-22c8-477e-a37a-341858e59dcb})
----------
The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {28a72cb7-3cd0-4704-b604-44fb090d5a88})
The name of the ParamType (ThingClass: x2wp, Type: thing, ID: {b551d138-b006-4290-bfef-97072ff677c6})
----------
The name of the ParamType (ThingClass: modbusConnection, ActionType: discoverDevices, ID: {22413a22-31d4-4b8c-b855-8a29da5946bc})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Software version</source>
<extracomment>The name of the ParamType (ThingClass: x2wp, Type: thing, ID: {1ffd72a9-7b3f-4287-b671-7f22e159f9b8})
The name of the ParamType (ThingClass: x2lu, Type: discovery, ID: {8dd4ba9f-51f6-4711-a917-abac5e1aa82b})
----------
The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {91ef76cf-6c53-4a8a-a278-6f6e2ef68cc6})</extracomment>
The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {28a72cb7-3cd0-4704-b604-44fb090d5a88})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
@ -307,11 +300,6 @@ The name of the StateType ({77a96b57-fa0a-4946-af5b-39c3b66d9422}) of ThingClass
<extracomment>The name of the ThingClass ({e548f962-92db-4110-8279-10fbcde35f93})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Baud rate</source>
<extracomment>The name of the ParamType (ThingClass: modbusConnection, Type: thing, ID: {d0c04612-cc3e-4d38-b4c9-708e28dc4eb3})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Connected</source>
<extracomment>The name of the ParamType (ThingClass: x2wp, EventType: connected, ID: {baf203be-a391-4bfc-8198-53b4ecbcce80})
@ -320,25 +308,41 @@ The name of the StateType ({baf203be-a391-4bfc-8198-53b4ecbcce80}) of ThingClass
----------
The name of the ParamType (ThingClass: x2lu, EventType: connected, ID: {b4c4726f-d3d7-46e8-badb-0d590e7f5fac})
----------
The name of the StateType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu
----------
The name of the ParamType (ThingClass: modbusConnection, EventType: connected, ID: {181ce6e2-9c55-45c6-b329-adf379679e07})
----------
The name of the StateType ({181ce6e2-9c55-45c6-b329-adf379679e07}) of ThingClass modbusConnection</extracomment>
The name of the StateType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Connected changed</source>
<extracomment>The name of the EventType ({baf203be-a391-4bfc-8198-53b4ecbcce80}) of ThingClass x2wp
----------
The name of the EventType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu
----------
The name of the EventType ({181ce6e2-9c55-45c6-b329-adf379679e07}) of ThingClass modbusConnection</extracomment>
The name of the EventType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modbus connection</source>
<extracomment>The name of the ThingClass ({06d04eec-ab5d-479a-b9e6-8c89efc18a8b})</extracomment>
<source>Modbus RTU master</source>
<extracomment>The name of the ParamType (ThingClass: x2wp, Type: thing, ID: {db8358f3-f573-44e3-b024-c4613ee3a270})
----------
The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {d25197d1-b1b9-45a9-b6fa-60583ed469fb})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set power</source>
<extracomment>The name of the ActionType ({c9df6349-2bf6-46cc-bce3-d4155836dbe5}) of ThingClass x2lu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>IntegrationPluginDrexelUndWeiss</name>
<message>
<source>Modbus RTU interface not available.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modbus RTU interface is not connected.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Modbus RTU interface not connected.</source>
<translation type="unfinished"></translation>
</message>
</context>

View File

@ -1,410 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "modbusrtumaster.h"
#include <QSerialPortInfo>
#include <loggingcategories.h>
NYMEA_LOGGING_CATEGORY(dcModbusRTU, "ModbusRTU")
ModbusRTUMaster::ModbusRTUMaster(QString serialPort, uint baudrate, QSerialPort::Parity parity, uint dataBits, uint stopBits, QObject *parent) :
QObject(parent)
{
m_modbusRtuSerialMaster = new QModbusRtuSerialMaster(this);
m_modbusRtuSerialMaster->setConnectionParameter(QModbusDevice::SerialPortNameParameter, serialPort);
m_modbusRtuSerialMaster->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudrate);
m_modbusRtuSerialMaster->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, dataBits);
m_modbusRtuSerialMaster->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stopBits);
m_modbusRtuSerialMaster->setConnectionParameter(QModbusDevice::SerialParityParameter, parity);
connect(m_modbusRtuSerialMaster, &QModbusTcpClient::stateChanged, this, &ModbusRTUMaster::onModbusStateChanged);
connect(m_modbusRtuSerialMaster, &QModbusRtuSerialMaster::errorOccurred, this, &ModbusRTUMaster::onModbusErrorOccurred);
m_reconnectTimer = new QTimer(this);
m_reconnectTimer->setSingleShot(true);
connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusRTUMaster::onReconnectTimer);
}
ModbusRTUMaster::~ModbusRTUMaster()
{
if (!m_modbusRtuSerialMaster) {
m_modbusRtuSerialMaster->disconnectDevice();
m_modbusRtuSerialMaster->deleteLater();
}
if (!m_reconnectTimer) {
m_reconnectTimer->stop();
m_reconnectTimer->deleteLater();
}
}
bool ModbusRTUMaster::connectDevice()
{
qCDebug(dcModbusRTU()) << "Setting up RTU client connecion";
if (!m_modbusRtuSerialMaster)
return false;
return m_modbusRtuSerialMaster->connectDevice();
}
bool ModbusRTUMaster::connected()
{
return (m_modbusRtuSerialMaster->state() == QModbusDevice::State::ConnectedState);
}
void ModbusRTUMaster::setNumberOfRetries(int number)
{
m_modbusRtuSerialMaster->setNumberOfRetries(number);
}
void ModbusRTUMaster::setTimeout(int timeout)
{
m_modbusRtuSerialMaster->setTimeout(timeout);
}
int ModbusRTUMaster::timeout()
{
return m_modbusRtuSerialMaster->timeout();
}
int ModbusRTUMaster::numberOfRetries()
{
return m_modbusRtuSerialMaster->numberOfRetries();
}
QString ModbusRTUMaster::serialPort()
{
return m_modbusRtuSerialMaster->connectionParameter(QModbusDevice::SerialPortNameParameter).toString();
}
void ModbusRTUMaster::onReconnectTimer()
{
if(!m_modbusRtuSerialMaster->connectDevice()) {
m_reconnectTimer->start(10000);
}
}
QUuid ModbusRTUMaster::readCoil(uint slaveAddress, uint registerAddress, uint size)
{
if (!m_modbusRtuSerialMaster) {
return "";
}
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, size);
if (QModbusReply *reply = m_modbusRtuSerialMaster->sendReadRequest(request, slaveAddress)) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
if (reply->error() == QModbusDevice::NoError) {
requestExecuted(requestId, true);
const QModbusDataUnit unit = reply->result();
uint modbusAddress = unit.startAddress();
emit receivedCoil(reply->serverAddress(), modbusAddress, unit.values());
} else {
requestExecuted(requestId, false);
qCWarning(dcModbusRTU()) << "Read response error:" << reply->error();
}
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusRTU()) << "Modbus replay error:" << error;
emit requestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(200, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
}
} else {
qCWarning(dcModbusRTU()) << "Read error: " << m_modbusRtuSerialMaster->errorString();
return "";
}
return requestId;
}
QUuid ModbusRTUMaster::writeCoil(uint slaveAddress, uint registerAddress, bool value)
{
return writeCoils(slaveAddress, registerAddress, QVector<quint16>() << static_cast<quint16>(value));
}
QUuid ModbusRTUMaster::writeCoils(uint slaveAddress, uint registerAddress, const QVector<quint16> &values)
{
if (!m_modbusRtuSerialMaster) {
return "";
}
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, values.length());
request.setValues(values);
if (QModbusReply *reply = m_modbusRtuSerialMaster->sendWriteRequest(request, slaveAddress)) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
if (reply->error() == QModbusDevice::NoError) {
requestExecuted(requestId, true);
const QModbusDataUnit unit = reply->result();
uint modbusAddress = unit.startAddress();
emit receivedCoil(reply->serverAddress(), modbusAddress, unit.values());
} else {
requestExecuted(requestId, false);
qCWarning(dcModbusRTU()) << "Read response error:" << reply->error();
}
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusRTU()) << "Modbus replay error:" << error;
emit requestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(200, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
}
} else {
qCWarning(dcModbusRTU()) << "Read error: " << m_modbusRtuSerialMaster->errorString();
return "";
}
return requestId;
}
QUuid ModbusRTUMaster::writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value)
{
return writeHoldingRegisters(slaveAddress, registerAddress, QVector<quint16>() << value);
}
QUuid ModbusRTUMaster::writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector<quint16> &values)
{
if (!m_modbusRtuSerialMaster) {
return "";
}
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, values.length());
request.setValues(values);
if (QModbusReply *reply = m_modbusRtuSerialMaster->sendWriteRequest(request, slaveAddress)) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
if (reply->error() == QModbusDevice::NoError) {
requestExecuted(requestId, true);
const QModbusDataUnit unit = reply->result();
uint modbusAddress = unit.startAddress();
emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.values());
} else {
requestExecuted(requestId, false);
qCWarning(dcModbusRTU()) << "Read response error:" << reply->error();
}
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusRTU()) << "Modbus replay error:" << error;
emit requestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(200, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
}
} else {
qCWarning(dcModbusRTU()) << "Read error: " << m_modbusRtuSerialMaster->errorString();
return "";
}
return requestId;
}
QUuid ModbusRTUMaster::readDiscreteInput(uint slaveAddress, uint registerAddress, uint size)
{
if (!m_modbusRtuSerialMaster) {
return "";
}
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, registerAddress, size);
if (QModbusReply *reply = m_modbusRtuSerialMaster->sendReadRequest(request, slaveAddress)) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
if (reply->error() == QModbusDevice::NoError) {
requestExecuted(requestId, true);
const QModbusDataUnit unit = reply->result();
uint modbusAddress = unit.startAddress();
emit receivedDiscreteInput(reply->serverAddress(), modbusAddress, unit.values());
} else {
requestExecuted(requestId, false);
qCWarning(dcModbusRTU()) << "Read response error:" << reply->error();
}
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusRTU()) << "Modbus replay error:" << error;
emit requestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(200, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
}
} else {
qCWarning(dcModbusRTU()) << "Read error: " << m_modbusRtuSerialMaster->errorString();
return "";
}
return requestId;
}
QUuid ModbusRTUMaster::readInputRegister(uint slaveAddress, uint registerAddress, uint size)
{
if (!m_modbusRtuSerialMaster) {
return "";
}
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, registerAddress, size);
if (QModbusReply *reply = m_modbusRtuSerialMaster->sendReadRequest(request, slaveAddress)) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
if (reply->error() == QModbusDevice::NoError) {
requestExecuted(requestId, true);
const QModbusDataUnit unit = reply->result();
uint modbusAddress = unit.startAddress();
emit receivedInputRegister(reply->serverAddress(), modbusAddress, unit.values());
} else {
requestExecuted(requestId, false);
qCWarning(dcModbusRTU()) << "Read response error:" << reply->error();
}
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusRTU()) << "Modbus replay error:" << error;
emit requestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(200, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
}
} else {
qCWarning(dcModbusRTU()) << "Read error: " << m_modbusRtuSerialMaster->errorString();
return "";
}
return requestId;
}
QUuid ModbusRTUMaster::readHoldingRegister(uint slaveAddress, uint registerAddress, uint size)
{
if (!m_modbusRtuSerialMaster) {
return "";
}
QUuid requestId = QUuid::createUuid();
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, size);
if (QModbusReply *reply = m_modbusRtuSerialMaster->sendReadRequest(request, slaveAddress)) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
if (reply->error() == QModbusDevice::NoError) {
requestExecuted(requestId, true);
const QModbusDataUnit unit = reply->result();
uint modbusAddress = unit.startAddress();
emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.values());
} else {
requestExecuted(requestId, false);
qCWarning(dcModbusRTU()) << "Read response error:" << reply->error();
}
});
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
qCWarning(dcModbusRTU()) << "Modbus replay error:" << error;
emit requestError(requestId, reply->errorString());
reply->finished(); // To make sure it will be deleted
});
QTimer::singleShot(200, reply, &QModbusReply::deleteLater);
} else {
delete reply; // broadcast replies return immediately
return "";
}
} else {
qCWarning(dcModbusRTU()) << "Read error: " << m_modbusRtuSerialMaster->errorString();
return "";
}
return requestId;
}
void ModbusRTUMaster::onModbusErrorOccurred(QModbusDevice::Error error)
{
qCWarning(dcModbusRTU()) << "An error occured" << error;
if (error == QModbusDevice::Error::ConnectionError) {
emit connectionStateChanged(false);
}
}
void ModbusRTUMaster::onModbusStateChanged(QModbusDevice::State state)
{
qCWarning(dcModbusRTU()) << "State changed" << state;
if (state == QModbusDevice::UnconnectedState) {
//try to reconnect in 10 seconds
m_reconnectTimer->start(10000);
}
emit connectionStateChanged(state == QModbusDevice::ConnectedState);
}

View File

@ -1,90 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef MODBUSRTUMASTER_H
#define MODBUSRTUMASTER_H
#include <QObject>
#include <QtSerialBus>
#include <QSerialPort>
#include <QTimer>
#include <QUuid>
class ModbusRTUMaster : public QObject
{
Q_OBJECT
public:
explicit ModbusRTUMaster(QString serialPort, uint baudrate, QSerialPort::Parity parity, uint dataBits, uint stopBits, QObject *parent = nullptr);
~ModbusRTUMaster();
bool connectDevice();
bool connected();
void setNumberOfRetries(int number);
void setTimeout(int timeout);
int timeout();
int numberOfRetries();
QUuid readCoil(uint slaveAddress, uint registerAddress, uint size = 1);
QUuid readDiscreteInput(uint slaveAddress, uint registerAddress, uint size = 1);
QUuid readInputRegister(uint slaveAddress, uint registerAddress, uint size = 1);
QUuid readHoldingRegister(uint slaveAddress, uint registerAddress, uint size = 1);
QUuid writeCoil(uint slaveAddress, uint registerAddress, bool status);
QUuid writeCoils(uint slaveAddress, uint registerAddress, const QVector<quint16> &values);
QUuid writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value);
QUuid writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector<quint16> &values);
QString serialPort();
private:
QModbusRtuSerialMaster *m_modbusRtuSerialMaster;
QTimer *m_reconnectTimer = nullptr;
private slots:
void onReconnectTimer();
void onModbusErrorOccurred(QModbusDevice::Error error);
void onModbusStateChanged(QModbusDevice::State state);
signals:
void connectionStateChanged(bool status);
void requestExecuted(QUuid requestId, bool success);
void requestError(QUuid requestId, const QString &error);
void receivedCoil(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
void receivedDiscreteInput(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
void receivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
void receivedInputRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
};
#endif // MODBUSRTUMASTER_H