// SPDX-License-Identifier: GPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of nymea-plugins-modbus. * * nymea-plugins-modbus is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * nymea-plugins-modbus is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with nymea-plugins-modbus. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "integrationplugindrexelundweiss.h" #include "plugininfo.h" #include #include #include IntegrationPluginDrexelUndWeiss::IntegrationPluginDrexelUndWeiss() { m_connectedStateTypeIds.insert(x2luThingClassId, x2luConnectedStateTypeId); m_connectedStateTypeIds.insert(x2wpThingClassId, x2wpConnectedStateTypeId); m_discoverySlaveAddressParamTypeIds.insert(x2luThingClassId, x2luDiscoverySlaveAddressParamTypeId); m_discoverySlaveAddressParamTypeIds.insert(x2wpThingClassId, x2wpDiscoverySlaveAddressParamTypeId); m_slaveIdParamTypeIds.insert(x2luThingClassId, x2luThingSlaveAddressParamTypeId); m_slaveIdParamTypeIds.insert(x2wpThingClassId, x2wpThingSlaveAddressParamTypeId); m_modbusUuidParamTypeIds.insert(x2luThingClassId, x2luThingModbusMasterUuidParamTypeId); m_modbusUuidParamTypeIds.insert(x2wpThingClassId, x2wpThingModbusMasterUuidParamTypeId); } 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) { qCDebug(dcDrexelUndWeiss()) << "Discover things"; if (hardwareManager()->modbusRtuResource()->modbusRtuMasters().isEmpty()) { info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("No Modbus RTU interface is available.")); return; } uint slaveAddress = info->params().paramValue(m_discoverySlaveAddressParamTypeIds.value(info->thingClassId())).toUInt(); if (slaveAddress > 254 || slaveAddress == 0) { info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The Modbus slave address must be between 1 and 254")); return; } Q_FOREACH(ModbusRtuMaster *modbusMaster, hardwareManager()->modbusRtuResource()->modbusRtuMasters()) { qCDebug(dcDrexelUndWeiss()) << "Found RTU master resource" << modbusMaster << "connected" << modbusMaster->connected(); if (!modbusMaster->connected()) { continue; } QString name; if (info->thingClassId() == x2wpThingClassId) { name = QT_TR_NOOP("X2 Heat pump"); } else if (info->thingClassId() == x2luThingClassId) { name = QT_TR_NOOP("X2 Ventilation unit"); } ThingDescriptor descriptor(info->thingClassId(), name, QT_TR_NOOP("Slave address ") +QString::number(slaveAddress)+" "+modbusMaster->serialPort()); ParamList params; params << Param(m_slaveIdParamTypeIds.value(info->thingClassId()), slaveAddress); params << Param(m_modbusUuidParamTypeIds.value(info->thingClassId()), modbusMaster->modbusUuid()); descriptor.setParams(params); info->addThingDescriptor(descriptor); } info->finish(Thing::ThingErrorNoError); return; } void IntegrationPluginDrexelUndWeiss::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); qCDebug(dcDrexelUndWeiss()) << "Setup thing" << thing->name(); if (!m_connectedStateTypeIds.contains(thing->thingClassId())) { Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); } QUuid modbusMasterUuid = thing->paramValue(m_modbusUuidParamTypeIds.value(thing->thingClassId())).toUuid(); uint slaveAddress = thing->paramValue(m_slaveIdParamTypeIds.value(thing->thingClassId())).toUInt(); if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(modbusMasterUuid)) { return info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("The Modbus RTU interface is not available.")); } ModbusRtuMaster *modbus = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(modbusMasterUuid); if (!modbus->connected()) { return info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("The Modbus RTU interface is not connected.")); } ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, ModbusRegisterX2::Geraetetyp, 2); connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); connect(reply, &ModbusRtuReply::finished, info, [reply, modbus, info, thing, this] { if (info->isFinished()) return; // ModbusRtuReply::finished is called for every retry if (reply->error() != ModbusRtuReply::Error::NoError) { qCWarning(dcDrexelUndWeiss()) << "Setup failed, received modbus error" << reply->errorString(); return info->finish(Thing::ThingErrorHardwareNotAvailable); } if (reply->result().length() != 2) { qCWarning(dcDrexelUndWeiss()) << "Setup failed, received reply has an illegal length"; return info->finish(Thing::ThingErrorHardwareNotAvailable); } if (thing->thingClassId() == x2luThingClassId && reply->result()[1] == DeviceType::X2_LU) { info->finish(Thing::ThingErrorNoError); m_modbusRtuMasters.insert(thing, modbus); } else if (thing->thingClassId() == x2wpThingClassId && reply->result()[1] == DeviceType::X2_WP) { info->finish(Thing::ThingErrorNoError); m_modbusRtuMasters.insert(thing, modbus); } else { qCWarning(dcDrexelUndWeiss()) << "Device on slave address" << reply->slaveAddress() << "is not the wanted one."; return info->finish(Thing::ThingErrorHardwareNotAvailable); } }); connect(modbus, &ModbusRtuMaster::connectedChanged, this, &IntegrationPluginDrexelUndWeiss::onConnectionStateChanged); } void IntegrationPluginDrexelUndWeiss::postSetupThing(Thing *thing) { qCDebug(dcDrexelUndWeiss()) << "Post setup thing" << thing->name(); if (!m_refreshTimer) { 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() == 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); if (!modbus){ qCWarning(dcDrexelUndWeiss()) << "No modbus interface available"; } updateStates(thing); } else { Q_ASSERT_X(false, "postSetupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); } } void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info) { Thing *thing = info->thing(); Action action = info->action(); if (thing->thingClassId() == x2luThingClassId) { uint slaveAddress = thing->paramValue(x2luThingSlaveAddressParamTypeId).toUInt(); if (action.actionTypeId() == x2luPowerActionTypeId) { bool power = action.paramValue(x2luPowerActionPowerParamTypeId).toBool(); uint32_t data = 0; if (power) { data = VentilationMode::Automatikbetrieb; } else { data = VentilationMode::ManuellStufe0; } sendWriteRequest(info, slaveAddress, ModbusRegisterX2::Betriebsart, data); } else if (action.actionTypeId() == x2luVentilationModeActionTypeId) { QString mode = action.param(x2luVentilationModeActionVentilationModeParamTypeId).value().toString(); uint32_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) { uint slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt(); if (action.actionTypeId() == x2wpTargetTemperatureActionTypeId) { double targetTemp = (action.param(x2wpTargetTemperatureActionTargetTemperatureParamTypeId).value().toDouble()); uint32_t data = static_cast(qRound(targetTemp * 1000)); sendWriteRequest(info, slaveAddress, ModbusRegisterX2::RaumSoll, data); } else if (action.actionTypeId() == x2wpTargetWaterTemperatureActionTypeId) { double targetWaterTemp = action.param(x2wpTargetWaterTemperatureActionTargetWaterTemperatureParamTypeId).value().toDouble(); uint32_t data = static_cast(qRound(targetWaterTemp * 1000)); sendWriteRequest(info, slaveAddress, ModbusRegisterX2::BrauchwasserSolltermperatur, data); } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled ActionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); } } void IntegrationPluginDrexelUndWeiss::sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint32_t value) { ModbusRtuMaster *modbus = m_modbusRtuMasters.value(info->thing()); if (!modbus){ qCWarning(dcDrexelUndWeiss()) << "Modbus RTU interface available"; info->finish(Thing::ThingErrorHardwareFailure, tr("The Modbus RTU interface is not available.")); return; } if (!modbus->connected()) { qCWarning(dcDrexelUndWeiss()) << "Modbus RTU interface not connected"; info->finish(Thing::ThingErrorHardwareFailure, tr("The Modbus RTU interface is not connected.")); return; } QVector values; values.append(static_cast(value>>16)); values.append(static_cast(value&0xffff)); ModbusRtuReply *reply = modbus->writeHoldingRegisters(slaveAddress, modbusRegister, values); connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); connect(reply, &ModbusRtuReply::finished, info, [info, reply, this] { if (info->isFinished()) { return; } if (reply->error() != ModbusRtuReply::Error::NoError) { return info->finish(Thing::ThingErrorHardwareFailure); } updateStates(info->thing()); info->finish(Thing::ThingErrorNoError); }); } void IntegrationPluginDrexelUndWeiss::thingRemoved(Thing *thing) { qCDebug(dcDrexelUndWeiss()) << "Thing removed" << thing->name(); if (thing->thingClassId() == x2luThingClassId || thing->thingClassId() == x2luThingClassId) { m_modbusRtuMasters.remove(thing); } if (myThings().isEmpty()) { qCDebug(dcDrexelUndWeiss()) << "Stopping refresh timer"; hardwareManager()->pluginTimerManager()->unregisterTimer(m_refreshTimer); m_refreshTimer = nullptr; } } void IntegrationPluginDrexelUndWeiss::onRefreshTimer() { foreach (Thing *thing, myThings()) { if (thing->thingClassId() == x2luThingClassId || thing->thingClassId() == x2wpThingClassId){ updateStates(thing); } } } void IntegrationPluginDrexelUndWeiss::updateStates(Thing *thing) { if (thing->thingClassId() == x2luThingClassId) { ModbusRtuMaster *modbus = m_modbusRtuMasters.value(thing); if (!modbus) { return; } uint slaveAddress = thing->paramValue(x2luThingSlaveAddressParamTypeId).toUInt(); readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::AktiveLuefterstufe); readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Betriebsart); // Ventilation mode readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::CO2); } if (thing->thingClassId() == x2wpThingClassId) { ModbusRtuMaster *modbus = m_modbusRtuMasters.value(thing); if (!modbus) { return; } int slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt(); 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, 2); // min 2 registers must be read 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); if (reply->result().length() != 2) { return; } uint32_t value = (static_cast(reply->result()[0])<<16 | reply->result()[1]); if (thing->thingClassId() == x2wpThingClassId) { switch (reply->registerAddress()) { case ModbusRegisterX2::Waermepumpe: thing->setStateValue(x2wpPowerStateTypeId, value); break; case ModbusRegisterX2::RaumSoll: thing->setStateValue(x2wpTargetTemperatureStateTypeId, value/1000.00); break; case ModbusRegisterX2::Raum: thing->setStateValue(x2wpTemperatureStateTypeId, value/1000.00); break; case ModbusRegisterX2::TemperaturWarmwasserspeicherUnten: thing->setStateValue(x2wpWaterTemperatureStateTypeId, value/1000.00); break; case ModbusRegisterX2::BrauchwasserSolltermperatur: thing->setStateValue(x2wpTargetWaterTemperatureStateTypeId, value/1000.00); break; case ModbusRegisterX2::Auszenluft: thing->setStateValue(x2wpOutsideAirTemperatureStateTypeId, value/1000.00); break; case ModbusRegisterX2::Summenstoerung: if (value != 0) { //get actual error } else { thing->setStateValue(x2wpErrorStateTypeId, "No error"); } break; case ModbusRegisterX2::StoerungAbluftventilator: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Exhaust fan"); break; case ModbusRegisterX2::StoerungBoilerfuehlerElektroheizstab: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor electric heating element"); break; case ModbusRegisterX2::StoerungBoilerfuehlerSolar: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor solar"); break; case ModbusRegisterX2::StoerungBoilerfuehlerWaermepumpe: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor heat pump"); break; case ModbusRegisterX2::StoerungBoileruebertemperatur: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Boiler overtemperature"); break; case ModbusRegisterX2::StoerungCO2Sensor: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "CO2-Sensor"); break; case ModbusRegisterX2::StoerungDruckverlustAbluftZuGrosz: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Pressure loss exhaust air too big"); break; case ModbusRegisterX2::StoerungDruckverlustZuluftZuGrosz: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Pressure loss supply air too large"); break; case ModbusRegisterX2::StoerungDurchflussmengeHeizgkreis: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Flow rate of heating circuit"); break; case ModbusRegisterX2::StoerungDurchflussmengeSolekreis: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Flow rate brine circuit"); break; case ModbusRegisterX2::StoerungTeilnehmerNichtErreichbar: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Participant not available"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerAuszenluft: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor outside air"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerHeizkreisVorlauf: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor heating circuit flow"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerRaum: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor room"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerSolarkollektor: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor solar collector"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerSole: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor brine"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerSoleAuszenluft: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor brine outside air"); break; case ModbusRegisterX2::StoerungWaermepumpeHochdruck: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Heat pump high pressure"); break; case ModbusRegisterX2::StoerungWaermepumpeNiederdruck: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Heat pump low pressure"); break; case ModbusRegisterX2::StoerungWertNichtZulaessig: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Value not allowed"); break; case ModbusRegisterX2::StoerungZuluftventilator: if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Supply air fan"); break; case ModbusRegisterX2::LeistungKompressor: thing->setStateValue(x2wpPowerCompressorStateTypeId, value/1000.00); break; case ModbusRegisterX2::LeistungWarmwasser: thing->setStateValue(x2wpPowerWaterHeatingStateTypeId, value/1000.00); break; case ModbusRegisterX2::LeistungRaumheizung: thing->setStateValue(x2wpPowerRoomHeatingStateTypeId, value/1000.00); break; case ModbusRegisterX2::LeistungLuftvorwaermung: { float power = value/1000.00; thing->setStateValue(x2wpPowerAirPreheatingStateTypeId, power); power += thing->stateValue(x2wpPowerCompressorStateTypeId).toFloat(); thing->setStateValue(x2wpCurrentPowerStateTypeId, power); break; } case ModbusRegisterX2::EnergieKompressor: thing->setStateValue(x2wpEnergyCompressorStateTypeId, value/1000.00); break; case ModbusRegisterX2::EnergieWarmwasser: thing->setStateValue(x2wpEnergyWaterHeatingStateTypeId, value/1000.00); break; case ModbusRegisterX2::EnergieRaumheizung: thing->setStateValue(x2wpEnergyRoomHeatingStateTypeId, value/1000.00); break; case ModbusRegisterX2::EnergieLuftvorerwarrmung: { float energy = value/1000.00; thing->setStateValue(x2wpEnergyAirPreheatingStateTypeId, energy); energy += thing->stateValue(x2wpEnergyCompressorStateTypeId).toFloat(); thing->setStateValue(x2wpTotalEnergyConsumedStateTypeId, energy); break; } default: break; } } else if (thing->thingClassId() == x2luThingClassId) { switch (reply->registerAddress()) { case ModbusRegisterX2::Betriebsart: if (value == VentilationMode::ManuellStufe0) { thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 0"); } else if (value == VentilationMode::ManuellStufe1) { thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 1"); } else if (value == VentilationMode::ManuellStufe2) { thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 2"); } else if (value == VentilationMode::ManuellStufe3) { thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 3"); } else if (value == VentilationMode::Automatikbetrieb) { thing->setStateValue(x2luVentilationModeStateTypeId, "Automatic"); } else if (value == VentilationMode::Party) { thing->setStateValue(x2luVentilationModeStateTypeId, "Party"); } if (value == VentilationMode::ManuellStufe0) { thing->setStateValue(x2luPowerStateTypeId, false); } else { thing->setStateValue(x2luPowerStateTypeId, true); } break; case ModbusRegisterX2::AktiveLuefterstufe: thing->setStateValue(x2luActiveVentilationLevelStateTypeId, value); break; case ModbusRegisterX2::CO2: thing->setStateValue(x2luCo2StateTypeId, value); 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 ¶mTypeId, const QVariant &value) { // Check refresh schedule if (paramTypeId == drexelUndWeissPluginUpdateIntervalParamTypeId) { if (m_refreshTimer) { int refreshTime = value.toInt(); m_refreshTimer->stop(); m_refreshTimer->startTimer(refreshTime); } } } void IntegrationPluginDrexelUndWeiss::onConnectionStateChanged(bool status) { ModbusRtuMaster *modbusRtuMaster = static_cast(sender()); Thing *thing = m_modbusRtuMasters.key(modbusRtuMaster); if (!thing) return; thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), status); }