diff --git a/debian/control b/debian/control index 0e628d8..eadbad7 100644 --- a/debian/control +++ b/debian/control @@ -45,6 +45,23 @@ Description: nymea.io plugin for iDM heat pumps This package will install the nymea.io plugin for iDM heat pumps +Package: nymea-plugin-energymeters +Architecture: any +Multi-Arch: same +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends}, + nymea-plugins-modbus-translations +Description: nymea.io plugin for Modbus based energy meters + The nymea daemon is a plugin based IoT (Internet of Things) server. The + server works like a translator for devices, things and services and + allows them to interact. + With the powerful rule engine you are able to connect any device available + in the system and create individual scenes and behaviors for your environment. + . + This package will install the nymea.io plugin for energy meters + + Package: nymea-plugin-modbuscommander Architecture: any Section: libs diff --git a/debian/nymea-plugin-energymeters.install.in b/debian/nymea-plugin-energymeters.install.in new file mode 100644 index 0000000..2f08f1f --- /dev/null +++ b/debian/nymea-plugin-energymeters.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginenergymeters.so diff --git a/drexelundweiss/README.md b/drexelundweiss/README.md index 3c0b259..9310d54 100644 --- a/drexelundweiss/README.md +++ b/drexelundweiss/README.md @@ -9,7 +9,11 @@ nymea plug-in for Drexel und Weiss HVAC systems. ## Requirements * The package "nymea-plugin-drexelundweiss" must be installed. -* Modbus RTU interface must be avaible to nymea. +* A modbus RTU interface must be avaible to nymea. +* The modbus RTU interface must be set to: + * Parity none + * 8 Data bits + * 1 Stop bit ## More https://www.drexel-weiss.at diff --git a/drexelundweiss/drexelundweiss.pro b/drexelundweiss/drexelundweiss.pro index 561d18d..dab6785 100644 --- a/drexelundweiss/drexelundweiss.pro +++ b/drexelundweiss/drexelundweiss.pro @@ -6,9 +6,7 @@ QT += \ SOURCES += \ integrationplugindrexelundweiss.cpp \ - ../modbus/modbusrtumaster.cpp \ HEADERS += \ integrationplugindrexelundweiss.h \ - modbusdegisterdefinition.h \ - ../modbus/modbusrtumaster.h \ + modbusregisterdefinition.h diff --git a/drexelundweiss/integrationplugindrexelundweiss.cpp b/drexelundweiss/integrationplugindrexelundweiss.cpp index 0f7d9d5..493a8e0 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.cpp +++ b/drexelundweiss/integrationplugindrexelundweiss.cpp @@ -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,113 +30,151 @@ #include "integrationplugindrexelundweiss.h" #include "plugininfo.h" -#include "modbusdegisterdefinition.h" + +#include "hardwaremanager.h" +#include "hardware/modbus/modbusrtumaster.h" +#include "hardware/modbus/modbusrtuhardwareresource.h" IntegrationPluginDrexelUndWeiss::IntegrationPluginDrexelUndWeiss() { + m_connectedStateTypeIds.insert(x2luThingClassId, x2luConnectedStateTypeId); + m_connectedStateTypeIds.insert(x2wpThingClassId, x2wpConnectedStateTypeId); -} + m_discoverySlaveAddressParamTypeIds.insert(x2luThingClassId, x2luDiscoverySlaveAddressParamTypeId); + m_discoverySlaveAddressParamTypeIds.insert(x2wpThingClassId, x2wpDiscoverySlaveAddressParamTypeId); -IntegrationPluginDrexelUndWeiss::~IntegrationPluginDrexelUndWeiss() -{ + 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) { - // Create the list of available serial interfaces - QList thingDescriptors; + qCDebug(dcDrexelUndWeiss()) << "Discover things"; - 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); + if (hardwareManager()->modbusRtuResource()->modbusRtuMasters().isEmpty()) { + info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("No Modbus RTU interface available.")); return; - } else if (info->thingClassId() == x2luThingClassId) { - info->finish(Thing::ThingErrorNoError); - return; - } else if (info->thingClassId() == x2wpThingClassId) { - info->finish(Thing::ThingErrorNoError); - return; - } else { - Q_ASSERT_X(false, "discoverThings", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8()); } + + uint slaveAddress = info->params().paramValue(m_discoverySlaveAddressParamTypeIds.value(info->thingClassId())).toUInt(); + if (slaveAddress > 254 || slaveAddress == 0) { + info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("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 (thing->thingClassId() == modbusConnectionThingClassId) { - - QString serialPort = thing->paramValue(modbusConnectionThingSerialPortParamTypeId).toString(); - int baudRate = thing->paramValue(modbusConnectionThingBaudRateParamTypeId).toInt(); - - 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); - - m_modbusRTUMasters.insert(thing, modbus); - m_usedSerialPorts.append(serialPort); - info->finish(Thing::ThingErrorNoError); - return; - } else if (thing->thingClassId() == x2luThingClassId) { - info->finish(Thing::ThingErrorNoError); - return; - } else if (thing->thingClassId() == x2wpThingClassId) { - info->finish(Thing::ThingErrorNoError); - return; - } else { + 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("Modbus RTU interface not available.")); + } + ModbusRtuMaster *modbus = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(modbusMasterUuid); + if (!modbus->connected()) { + return info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("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) { - // 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"; } updateStates(thing); - // Update states } else { Q_ASSERT_X(false, "postSetupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); } @@ -147,86 +185,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(); + uint32_t data = 0; + if (power) { + data = VentilationMode::Automatikbetrieb; + } 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(); + 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) { - 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(qRound(targetTemp * 1000)); - m_pendingActions.insert(modbus->writeHoldingRegister(slave,ModbusRegisterX2::RaumSoll, data), info); - return; + 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) { - qreal targetWaterTemp = action.param(x2wpTargetWaterTemperatureActionTargetWaterTemperatureParamTypeId).value().toDouble(); - int data = static_cast(qRound(targetWaterTemp * 1000)); - m_pendingActions.insert(modbus->writeHoldingRegister(slave, ModbusRegisterX2::BrauchwasserSolltermperatur, data), info); - return; + 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()); } @@ -235,21 +227,52 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info) } } +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("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; + } + + 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) { - if (thing->thingClassId() == modbusConnectionThingClassId) { + qCDebug(dcDrexelUndWeiss()) << "Thing removed" << thing->name(); - 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()) { + qCDebug(dcDrexelUndWeiss()) << "Stopping refresh timer"; hardwareManager()->pluginTimerManager()->unregisterTimer(m_refreshTimer); m_refreshTimer = nullptr; } @@ -258,15 +281,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 +290,282 @@ 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, 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: + thing->setStateValue(x2wpPowerAirPreheatingStateTypeId, value/1000.00); + 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: + thing->setStateValue(x2wpEnergyAirPreheatingStateTypeId, value/1000.00); + 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) { @@ -322,318 +581,9 @@ void IntegrationPluginDrexelUndWeiss::onPluginConfigurationChanged(const ParamTy void IntegrationPluginDrexelUndWeiss::onConnectionStateChanged(bool status) { - ModbusRTUMaster *modbusRtuMaster = static_cast(sender()); - Thing *thing = m_modbusRTUMasters.key(modbusRtuMaster); + ModbusRtuMaster *modbusRtuMaster = static_cast(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 &values) -{ - ModbusRTUMaster *modbus = static_cast(sender()); - - if (m_modbusRTUMasters.values().contains(modbus) ){ - Thing *parentThing = m_modbusRTUMasters.key(static_cast(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 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 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); } diff --git a/drexelundweiss/integrationplugindrexelundweiss.h b/drexelundweiss/integrationplugindrexelundweiss.h index 69cc907..12235eb 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.h +++ b/drexelundweiss/integrationplugindrexelundweiss.h @@ -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 "modbusregisterdefinition.h" #include -#include 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,24 @@ public: void executeAction(ThingActionInfo *info) override; private: - QList m_usedSerialPorts; - QHash m_modbusRTUMasters; + QHash m_modbusRtuMasters; PluginTimer *m_refreshTimer = nullptr; - QHash m_pendingActions; + QHash m_connectedStateTypeIds; + QHash m_discoverySlaveAddressParamTypeIds; + QHash m_slaveIdParamTypeIds; + QHash m_modbusUuidParamTypeIds; + void sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint32_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 ¶mTypeId, const QVariant &value); - void onConnectionStateChanged(bool status); - void onReceivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector &values); - void onWriteRequestFinished(QUuid requestId, bool success); }; #endif // INTEGRATIONPLUGINDREXELUNDWEISS_H diff --git a/drexelundweiss/integrationplugindrexelundweiss.json b/drexelundweiss/integrationplugindrexelundweiss.json index 435917f..88528e2 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.json +++ b/drexelundweiss/integrationplugindrexelundweiss.json @@ -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"], - "interfaces": ["thermostat", "heating", "temperaturesensor", "connectable"], + "createMethods": ["discovery"], + "interfaces": ["thermostat", "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":[ @@ -181,10 +155,8 @@ "name": "power", "displayName": "Power", "displayNameEvent": "Power changed", - "displayNameAction": "Change power", "type": "bool", - "defaultValue": 0, - "writable": true + "defaultValue": false }, { "id": "3ab2d609-1686-4fd7-84e3-580c8e0537d0", diff --git a/drexelundweiss/modbusdegisterdefinition.h b/drexelundweiss/modbusregisterdefinition.h similarity index 99% rename from drexelundweiss/modbusdegisterdefinition.h rename to drexelundweiss/modbusregisterdefinition.h index 534583b..eac63af 100644 --- a/drexelundweiss/modbusdegisterdefinition.h +++ b/drexelundweiss/modbusregisterdefinition.h @@ -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 + enum ModbusRegisterX2 { AbsenkungderLuefterstufe1 = 5328, AktiveLuefterstufe = 1066, @@ -241,7 +243,7 @@ enum HeatPumpStatus { NachAbtauenAbtropfen }; -enum VentialtionMode { +enum VentilationMode { ManuellStufe0 = 0, ManuellStufe1, ManuellStufe2, diff --git a/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-de.ts b/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-de.ts index 0b41855..58d34f0 100644 --- a/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-de.ts +++ b/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-de.ts @@ -35,11 +35,6 @@ The name of the StateType ({0a6b44c8-e7af-4148-92ff-682ae717f3a8}) of ThingClass The name of the ActionType ({fb021cac-1236-4324-a45c-8d89ad069052}) of ThingClass x2wp Setze Zielwassertemperatur - - Discover devices - The name of the ActionType ({b9a24ecc-4433-4f31-99ba-596033bda421}) of ThingClass modbusConnection - Suche Geräte - Drexel und Weiss 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 +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 Eingeschalten Power changed - The name of the EventType ({f2ce8389-c33f-4f10-8484-f2e993841762}) of ThingClass x2wp + 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 Eingeschalten geändert @@ -205,27 +208,17 @@ The name of the StateType ({3ab2d609-1686-4fd7-84e3-580c8e0537d0}) of ThingClass The name of the EventType ({3ab2d609-1686-4fd7-84e3-580c8e0537d0}) of ThingClass x2wp Raumtemperatur geändert - - Serial port - The name of the ParamType (ThingClass: modbusConnection, Type: thing, ID: {ed49f7d8-ab18-4c37-9b80-1004b75dcb91}) - Serielle Schnittstelle - Slave address - The name of the ParamType (ThingClass: x2wp, Type: thing, ID: {b551d138-b006-4290-bfef-97072ff677c6}) + 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}) +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}) Slave-Adresse - - Software version - 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}) - Softwareversion - Target room temperature 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 The name of the ThingClass ({e548f962-92db-4110-8279-10fbcde35f93}) X2 WP - - Baud rate - The name of the ParamType (ThingClass: modbusConnection, Type: thing, ID: {d0c04612-cc3e-4d38-b4c9-708e28dc4eb3}) - Baudrate - Connected The name of the ParamType (ThingClass: x2wp, EventType: connected, ID: {baf203be-a391-4bfc-8198-53b4ecbcce80}) @@ -320,26 +308,62 @@ 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 +The name of the StateType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu Verbunden Connected changed 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 +The name of the EventType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu Verbunden geändert - Modbus connection - The name of the ThingClass ({06d04eec-ab5d-479a-b9e6-8c89efc18a8b}) - Modbusverbindung + Modbus RTU master + 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}) + + + + Set power + The name of the ActionType ({c9df6349-2bf6-46cc-bce3-d4155836dbe5}) of ThingClass x2lu + + + + + IntegrationPluginDrexelUndWeiss + + Modbus RTU interface not available. + + + + Modbus RTU interface is not connected. + + + + Modbus RTU interface not connected. + + + + No Modbus RTU interface available. + + + + Modbus slave address must be between 1 and 254 + + + + X2 Heat pump + + + + X2 Ventilation unit + + + + Slave address + diff --git a/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-en_US.ts b/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-en_US.ts index d591925..9abdbb6 100644 --- a/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-en_US.ts +++ b/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-en_US.ts @@ -35,11 +35,6 @@ The name of the StateType ({0a6b44c8-e7af-4148-92ff-682ae717f3a8}) of ThingClass The name of the ActionType ({fb021cac-1236-4324-a45c-8d89ad069052}) of ThingClass x2wp - - Discover devices - The name of the ActionType ({b9a24ecc-4433-4f31-99ba-596033bda421}) of ThingClass modbusConnection - - Drexel und Weiss 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 +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 Power changed - The name of the EventType ({f2ce8389-c33f-4f10-8484-f2e993841762}) of ThingClass x2wp + 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 @@ -205,25 +208,15 @@ The name of the StateType ({3ab2d609-1686-4fd7-84e3-580c8e0537d0}) of ThingClass The name of the EventType ({3ab2d609-1686-4fd7-84e3-580c8e0537d0}) of ThingClass x2wp - - Serial port - The name of the ParamType (ThingClass: modbusConnection, Type: thing, ID: {ed49f7d8-ab18-4c37-9b80-1004b75dcb91}) - - Slave address - The name of the ParamType (ThingClass: x2wp, Type: thing, ID: {b551d138-b006-4290-bfef-97072ff677c6}) + 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}) - - - - Software version - 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}) +The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {28a72cb7-3cd0-4704-b604-44fb090d5a88}) @@ -307,11 +300,6 @@ The name of the StateType ({77a96b57-fa0a-4946-af5b-39c3b66d9422}) of ThingClass The name of the ThingClass ({e548f962-92db-4110-8279-10fbcde35f93}) - - Baud rate - The name of the ParamType (ThingClass: modbusConnection, Type: thing, ID: {d0c04612-cc3e-4d38-b4c9-708e28dc4eb3}) - - Connected The name of the ParamType (ThingClass: x2wp, EventType: connected, ID: {baf203be-a391-4bfc-8198-53b4ecbcce80}) @@ -320,25 +308,61 @@ 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 +The name of the StateType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu Connected changed 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 +The name of the EventType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu - Modbus connection - The name of the ThingClass ({06d04eec-ab5d-479a-b9e6-8c89efc18a8b}) + Modbus RTU master + 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}) + + + + Set power + The name of the ActionType ({c9df6349-2bf6-46cc-bce3-d4155836dbe5}) of ThingClass x2lu + + + + + IntegrationPluginDrexelUndWeiss + + Modbus RTU interface not available. + + + + Modbus RTU interface is not connected. + + + + Modbus RTU interface not connected. + + + + No Modbus RTU interface available. + + + + Modbus slave address must be between 1 and 254 + + + + X2 Heat pump + + + + X2 Ventilation unit + + + + Slave address diff --git a/energymeters/README.md b/energymeters/README.md new file mode 100644 index 0000000..0c90177 --- /dev/null +++ b/energymeters/README.md @@ -0,0 +1,15 @@ +# Energy Meters + +Connect Modbus RTU based energy meters. + +## Supported Things + +* b+g e-tech + * SDM630Modbus +* inepro Metering + * PRO380-Mod + +## Requirements + +* The plugin 'nymea-plugin-energymeter' must be installed. +* At least one Modbus RTU interface must be setup. diff --git a/energymeters/bg-etechmodbusregister.h b/energymeters/bg-etechmodbusregister.h new file mode 100644 index 0000000..b16c4eb --- /dev/null +++ b/energymeters/bg-etechmodbusregister.h @@ -0,0 +1,50 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 . +* +* 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 BGETECHMODBUSREGISTER_H +#define BGETECHMODBUSREGISTER_H + +#include "registerdescriptor.h" + +static const QHash sdm630RegisterMap { + {ModbusRegisterType::VoltageL1, ModbusRegisterDescriptor(0x00, 4, 2, "V", "float")}, + {ModbusRegisterType::VoltageL2, ModbusRegisterDescriptor(0x02, 4, 2, "V", "float")}, + {ModbusRegisterType::VoltageL3, ModbusRegisterDescriptor(0x04, 4, 2, "V", "float")}, + {ModbusRegisterType::CurrentL1, ModbusRegisterDescriptor(0x06, 4, 2, "A", "float")}, + {ModbusRegisterType::CurrentL2, ModbusRegisterDescriptor(0x08, 4, 2, "A", "float")}, + {ModbusRegisterType::CurrentL3, ModbusRegisterDescriptor(0x0A, 4, 2, "A", "float")}, + {ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(0x34, 4, 2, "W", "float")}, //Total system power + {ModbusRegisterType::Frequency, ModbusRegisterDescriptor(0x46, 4, 2, "Hz", "float")}, + {ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(0x3E, 4, 2, "", "float")}, //Total system power factor + {ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(0x48, 4, 2, "kWh", "float")}, //Total Import kWh + {ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(0x4A, 4, 2, "kWh", "float")} //Total Export kWh +}; + +#endif // BGETECHMODBUSREGISTER_H diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp new file mode 100644 index 0000000..2d5991b --- /dev/null +++ b/energymeters/energymeter.cpp @@ -0,0 +1,231 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 . +* +* 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 "energymeter.h" +#include "hardware/modbus/modbusrtureply.h" + +#include "extern-plugininfo.h" + +EnergyMeter::EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const QHash &modbusRegisters, QObject *parent) : + QObject(parent), + m_modbusRtuMaster(modbusMaster), + m_slaveAddress(slaveAddress), + m_modbusRegisters(modbusRegisters) +{ + qCDebug(dcEnergyMeters()) << "EnergyMeter: Creating new meter connection, address:" << slaveAddress; +} + +ModbusRtuMaster *EnergyMeter::modbusMaster() +{ + return m_modbusRtuMaster; +} + +void EnergyMeter::setModbusMaster(ModbusRtuMaster *modbusMaster) +{ + m_modbusRtuMaster = modbusMaster; +} + +bool EnergyMeter::connected() const +{ + return m_connected; +} + +bool EnergyMeter::getVoltageL1() +{ + return getRegister(ModbusRegisterType::VoltageL1); +} + +bool EnergyMeter::getVoltageL2() +{ + return getRegister(ModbusRegisterType::VoltageL2); +} + +bool EnergyMeter::getVoltageL3() +{ + return getRegister(ModbusRegisterType::VoltageL3); +} + +bool EnergyMeter::getCurrentL1() +{ + return getRegister(ModbusRegisterType::CurrentL1); +} + +bool EnergyMeter::getCurrentL2() +{ + return getRegister(ModbusRegisterType::CurrentL2); +} + +bool EnergyMeter::getCurrentL3() +{ + return getRegister(ModbusRegisterType::CurrentL3); +} + +bool EnergyMeter::getFrequency() +{ + return getRegister(ModbusRegisterType::Frequency); +} + +bool EnergyMeter::getPowerFactor() +{ + return getRegister(ModbusRegisterType::PowerFactor); +} + +bool EnergyMeter::getActivePower() +{ + return getRegister(ModbusRegisterType::ActivePower); +} + +bool EnergyMeter::getEnergyProduced() +{ + return getRegister(ModbusRegisterType::EnergyProduced); +} + +bool EnergyMeter::getEnergyConsumed() +{ + return getRegister(ModbusRegisterType::EnergyConsumed); +} + +bool EnergyMeter::getRegister(ModbusRegisterType type) +{ + if (!m_modbusRegisters.contains(type)) { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Register type not supported" << type; + setConnectionStatus(false); + return false; + } + + if (!m_modbusRtuMaster) { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus RTU interface not available"; + setConnectionStatus(false); + return false; + } + + if (!m_modbusRtuMaster->connected()) { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus RTU interface not connected"; + setConnectionStatus(false); + return false; + } + + ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(type); + + ModbusRtuReply *reply = nullptr; + if (descriptor.functionCode() == 3){ + reply = m_modbusRtuMaster->readHoldingRegister(m_slaveAddress, descriptor.address(), descriptor.length()); + } else if (descriptor.functionCode() == 4){ + reply = m_modbusRtuMaster->readInputRegister(m_slaveAddress, descriptor.address(), descriptor.length()); + } + connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); + connect(reply, &ModbusRtuReply::finished, this, [reply, type, descriptor, this] { + if (reply->error() != ModbusRtuReply::NoError) { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus RTU reply error" << reply->errorString(); + setConnectionStatus(false); + return; + } + modbus_32_t value; + value.u = 0; + if (reply->result().length() == 1) { + value.u = static_cast(reply->result().at(0)); + } else if (reply->result().length() == 2) { + if (descriptor.dataType() == "float") { + value.u = static_cast(static_cast(reply->result().at(0)) << 16 | reply->result().at(1)); + } else { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Data type not supported" << descriptor.dataType(); + } + } else { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Reply length invalid" << reply->result().length(); + setConnectionStatus(false); + return; + } + + if (type == ModbusRegisterType::VoltageL1) { + if (descriptor.unit() == "mV") + value.f /= 1000.00; + + emit voltageL1Received(value.f); + } else if (type == ModbusRegisterType::VoltageL2) { + if (descriptor.unit() == "mV") + value.f /= 1000.00; + + emit voltageL2Received(value.f); + } else if (type == ModbusRegisterType::VoltageL3) { + if (descriptor.unit() == "mV") + value.f /= 1000.00; + + emit voltageL3Received(value.f); + } else if (type == ModbusRegisterType::CurrentL1) { + if (descriptor.unit() == "mA") + value.f /= 1000.00; + + emit currentL1Received(value.f); + } else if (type == ModbusRegisterType::CurrentL2) { + if (descriptor.unit() == "mA") + value.f /= 1000.00; + + emit currentL2Received(value.f); + } else if (type == ModbusRegisterType::CurrentL3) { + if (descriptor.unit() == "mA") + value.f /= 1000.00; + + emit currentL3Received(value.f); + } else if (type == ModbusRegisterType::ActivePower) { + if (descriptor.unit() == "kW") { + value.f *= 1000; + } else if (descriptor.unit() == "mW") { + value.f /= 1000.00; + } + emit activePowerReceived(value.f); + } else if (type == ModbusRegisterType::PowerFactor) { + emit powerFactorReceived(value.f); + } else if (type == ModbusRegisterType::Frequency) { + emit frequencyReceived(value.f); + } else if (type == ModbusRegisterType::EnergyConsumed) { + if (descriptor.unit() == "Wh") { + value.f /= 1000.00; + } + emit consumedEnergyReceived(value.f); + } else if (type == ModbusRegisterType::EnergyProduced) { + if (descriptor.unit() == "Wh") { + value.f /= 1000.00; + } + emit producedEnergyReceived(value.f); + } else { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus register type not handled" << type; + } + }); + setConnectionStatus(true); + return true; +} + +void EnergyMeter::setConnectionStatus(bool connected) +{ + if (connected != m_connected) { + m_connected = connected; + emit connectedChanged(m_connected); + } +} diff --git a/energymeters/energymeter.h b/energymeters/energymeter.h new file mode 100644 index 0000000..974fb72 --- /dev/null +++ b/energymeters/energymeter.h @@ -0,0 +1,95 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 . +* +* 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 ENERGYMETER_H +#define ENERGYMETER_H + +#include +#include + +#include "registerdescriptor.h" +#include "hardware/modbus/modbusrtumaster.h" + +class EnergyMeter : public QObject +{ + Q_OBJECT +public: + explicit EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const QHash &modbusRegisters, QObject *parent = nullptr); + + ModbusRtuMaster *modbusMaster(); + void setModbusMaster(ModbusRtuMaster *modbusMaster); + + bool connected() const; + bool getVoltageL1(); + bool getVoltageL2(); + bool getVoltageL3(); + bool getCurrentL1(); + bool getCurrentL2(); + bool getCurrentL3(); + bool getFrequency(); + bool getPowerFactor(); + bool getActivePower(); + bool getEnergyProduced(); + bool getEnergyConsumed(); + +private: + typedef union { + int32_t s; + uint32_t u; + float f; + } modbus_32_t; + + bool m_connected = false; + + ModbusRtuMaster *m_modbusRtuMaster = nullptr; + int m_slaveAddress; + + QHash m_modbusRegisters; + + bool getRegister(ModbusRegisterType type); + void setConnectionStatus(bool connected); + +signals: + void connectedChanged(bool connected); + + void voltageL1Received(double voltage); + void voltageL2Received(double voltage); + void voltageL3Received(double voltage); + void currentL1Received(double current); + void currentL2Received(double current); + void currentL3Received(double current); + void frequencyReceived(double freqeuncy); + void activePowerReceived(double power); + void powerFactorReceived(double powerFactor); + void producedEnergyReceived(double energy); + void consumedEnergyReceived(double energy); +}; + +#endif // ENERGYMETER_H diff --git a/energymeters/energymeters.pro b/energymeters/energymeters.pro new file mode 100644 index 0000000..17d879f --- /dev/null +++ b/energymeters/energymeters.pro @@ -0,0 +1,16 @@ +include(../plugins.pri) + +QT += \ + serialport \ + serialbus \ + +SOURCES += \ + energymeter.cpp \ + integrationpluginenergymeters.cpp + +HEADERS += \ + energymeter.h \ + integrationpluginenergymeters.h \ + inepromodbusregister.h \ + bg-etechmodbusregister.h \ + registerdescriptor.h diff --git a/energymeters/inepromodbusregister.h b/energymeters/inepromodbusregister.h new file mode 100644 index 0000000..b6071b4 --- /dev/null +++ b/energymeters/inepromodbusregister.h @@ -0,0 +1,49 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 . +* +* 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 INEPROMODBUSREGISTER_H +#define INEPROMODBUSREGISTER_H +#include "registerdescriptor.h" + +static const QHash pro380RegisterMap { + {ModbusRegisterType::VoltageL1, ModbusRegisterDescriptor(0x5002, 3, 2, "V", "float")}, //L1 Voltage + {ModbusRegisterType::VoltageL2, ModbusRegisterDescriptor(0x5004, 3, 2, "V", "float")}, //L2 Voltage + {ModbusRegisterType::VoltageL3, ModbusRegisterDescriptor(0x5006, 3, 2, "V", "float")}, //L3 Voltage + {ModbusRegisterType::CurrentL1, ModbusRegisterDescriptor(0x500C, 3, 2, "A", "float")}, //L1 Current + {ModbusRegisterType::CurrentL2, ModbusRegisterDescriptor(0x500E, 3, 2, "A", "float")}, //L2 Current + {ModbusRegisterType::CurrentL3, ModbusRegisterDescriptor(0x5010, 3, 2, "A", "float")}, //L3 Current + {ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(0x5012, 3, 2, "kW", "float")}, //Total active power + {ModbusRegisterType::Frequency, ModbusRegisterDescriptor(0x5008, 3, 2, "Hz", "float")}, + {ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(0x502A, 3, 2, "", "float")}, + {ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(0x600C, 3, 2, "kWh", "float")}, //Forward active energy + {ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(0x6018, 3, 2, "kWh", "float")} //Reverse active energy +}; + +#endif //INEPROMODBUSREGISTER_H diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp new file mode 100644 index 0000000..78903cd --- /dev/null +++ b/energymeters/integrationpluginenergymeters.cpp @@ -0,0 +1,403 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 . +* +* 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 "integrationpluginenergymeters.h" +#include "plugininfo.h" + +#include "bg-etechmodbusregister.h" +#include "inepromodbusregister.h" + +IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() +{ + /* + * NOTE: + * To add an new device model, the integrationplugin json file must be extended with the new model and vendor. + * Then add the new states and params to the lists here, also add the modbus register configuration file +*/ + m_slaveIdParamTypeIds.insert(pro380ThingClassId, pro380ThingSlaveAddressParamTypeId); + m_slaveIdParamTypeIds.insert(sdm630ThingClassId, sdm630ThingSlaveAddressParamTypeId); + + m_modbusUuidParamTypeIds.insert(pro380ThingClassId, pro380ThingModbusMasterUuidParamTypeId); + m_modbusUuidParamTypeIds.insert(sdm630ThingClassId, sdm630ThingModbusMasterUuidParamTypeId); + + m_connectionStateTypeIds.insert(pro380ThingClassId, pro380ConnectedStateTypeId); + m_connectionStateTypeIds.insert(sdm630ThingClassId, sdm630ConnectedStateTypeId); + + m_voltageL1StateTypeIds.insert(pro380ThingClassId, pro380VoltageL1StateTypeId); + m_voltageL1StateTypeIds.insert(sdm630ThingClassId, sdm630VoltageL1StateTypeId); + + m_voltageL2StateTypeIds.insert(pro380ThingClassId, pro380VoltageL2StateTypeId); + m_voltageL2StateTypeIds.insert(sdm630ThingClassId, sdm630VoltageL2StateTypeId); + + m_voltageL3StateTypeIds.insert(pro380ThingClassId, pro380VoltageL3StateTypeId); + m_voltageL3StateTypeIds.insert(sdm630ThingClassId, sdm630VoltageL3StateTypeId); + + m_currentL1StateTypeIds.insert(pro380ThingClassId, pro380CurrentL1StateTypeId); + m_currentL1StateTypeIds.insert(sdm630ThingClassId, sdm630CurrentL1StateTypeId); + + m_currentL2StateTypeIds.insert(pro380ThingClassId, pro380CurrentL2StateTypeId); + m_currentL2StateTypeIds.insert(sdm630ThingClassId, sdm630CurrentL2StateTypeId); + + m_currentL3StateTypeIds.insert(pro380ThingClassId, pro380CurrentL3StateTypeId); + m_currentL3StateTypeIds.insert(sdm630ThingClassId, sdm630CurrentL3StateTypeId); + + m_activePowerStateTypeIds.insert(pro380ThingClassId, pro380CurrentPowerEventTypeId); + m_activePowerStateTypeIds.insert(sdm630ThingClassId, sdm630CurrentPowerStateTypeId); + + m_frequencyStateTypeIds.insert(pro380ThingClassId, pro380FrequencyStateTypeId); + m_frequencyStateTypeIds.insert(sdm630ThingClassId, sdm630FrequencyStateTypeId); + + m_powerFactorStateTypeIds.insert(pro380ThingClassId, pro380PowerFactorStateTypeId); + m_powerFactorStateTypeIds.insert(sdm630ThingClassId, sdm630PowerFactorStateTypeId); + + m_totalEnergyConsumedStateTypeIds.insert(pro380ThingClassId, pro380TotalEnergyConsumedEventTypeId); + m_totalEnergyConsumedStateTypeIds.insert(sdm630ThingClassId, sdm630TotalEnergyConsumedEventTypeId); + + m_totalEnergyProducedStateTypeIds.insert(pro380ThingClassId, pro380TotalEnergyProducedStateTypeId); + m_totalEnergyProducedStateTypeIds.insert(sdm630ThingClassId, sdm630TotalEnergyProducedStateTypeId); + + m_discoverySlaveAddressParamTypeIds.insert(pro380ThingClassId, pro380DiscoverySlaveAddressParamTypeId); + m_discoverySlaveAddressParamTypeIds.insert(sdm630ThingClassId, sdm630DiscoverySlaveAddressParamTypeId); + + m_registerMaps.insert(pro380ThingClassId, pro380RegisterMap); + m_registerMaps.insert(sdm630ThingClassId, sdm630RegisterMap); +} + +void IntegrationPluginEnergyMeters::init() +{ + connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=] (const QUuid &modbusUuid){ + qCDebug(dcEnergyMeters()) << "Modbus RTU master has been removed" << modbusUuid.toString(); + + Q_FOREACH(Thing *thing, myThings()) { + if (m_modbusUuidParamTypeIds.contains(thing->thingClassId())) { + if (thing->paramValue(m_modbusUuidParamTypeIds.value(thing->thingClassId())) == modbusUuid) { + qCWarning(dcEnergyMeters()) << "Modbus RTU hardware resource removed for" << thing << ". The thing will not be functional any more until a new resource has been configured for it."; + thing->setStateValue(m_connectionStateTypeIds[thing->thingClassId()], false); + + EnergyMeter *meter = m_energyMeters.value(thing); + if (!meter) + return; + meter->setModbusMaster(nullptr); + } + } + } + }); +} + +void IntegrationPluginEnergyMeters::discoverThings(ThingDiscoveryInfo *info) +{ + qCDebug(dcEnergyMeters()) << "Discover things"; + QList thingDescriptors; + + if (hardwareManager()->modbusRtuResource()->modbusRtuMasters().isEmpty()) { + info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("No Modbus RTU interface available.")); + return; + } + + if (!m_connectionStateTypeIds.contains(info->thingClassId())) { + Q_ASSERT_X(false, "discoverThings", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8()); + } + uint slaveAddress = info->params().paramValue(m_discoverySlaveAddressParamTypeIds.value(info->thingClassId())).toUInt(); + if (slaveAddress > 254 || slaveAddress == 0) { + info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("Modbus slave address must be between 1 and 254")); + return; + } + Q_FOREACH(ModbusRtuMaster *modbusMaster, hardwareManager()->modbusRtuResource()->modbusRtuMasters()) { + qCDebug(dcEnergyMeters()) << "Found RTU master resource" << modbusMaster << "connected" << modbusMaster->connected(); + if (!modbusMaster->connected()) { + continue; + } + ThingDescriptor descriptor(info->thingClassId(), QT_TR_NOOP("Energy meter"), 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 IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) +{ + Thing *thing = info->thing(); + qCDebug(dcEnergyMeters()) << "Setup thing" << thing->name(); + + if (!m_connectionStateTypeIds.contains(thing->thingClassId())) { + Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); + } + + if (m_energyMeters.contains(thing)) { + qCDebug(dcEnergyMeters()) << "Setup after rediscovery, cleaning up ..."; + m_energyMeters.take(thing)->deleteLater(); + } + uint address = thing->paramValue(m_slaveIdParamTypeIds.value(thing->thingClassId())).toUInt(); + if (address > 254 || address == 0) { + qCWarning(dcEnergyMeters()) << "Setup failed, slave address is not valid" << address; + info->finish(Thing::ThingErrorSetupFailed, tr("Slave address not valid, must be between 1 and 254")); + return; + } + QUuid uuid = thing->paramValue(m_modbusUuidParamTypeIds.value(thing->thingClassId())).toUuid(); + if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(uuid)) { + qCWarning(dcEnergyMeters()) << "Setup failed, hardware manager not available"; + info->finish(Thing::ThingErrorSetupFailed, tr("Modbus RTU resource not available.")); + return; + } + + EnergyMeter *meter = new EnergyMeter(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), address, m_registerMaps.value(thing->thingClassId()), this); + connect(info, &ThingSetupInfo::aborted, meter, &EnergyMeter::deleteLater); + connect(meter, &EnergyMeter::consumedEnergyReceived, info, [this, info, meter] (double energy) { + qCDebug(dcEnergyMeters()) << "Consumed energy received" << energy << "Setup finished"; + connect(meter, &EnergyMeter::connectedChanged, this, &IntegrationPluginEnergyMeters::onConnectionStateChanged); + connect(meter, &EnergyMeter::voltageL1Received, this, &IntegrationPluginEnergyMeters::onVoltageL1Received); + connect(meter, &EnergyMeter::voltageL2Received, this, &IntegrationPluginEnergyMeters::onVoltageL2Received); + connect(meter, &EnergyMeter::voltageL3Received, this, &IntegrationPluginEnergyMeters::onVoltageL3Received); + connect(meter, &EnergyMeter::currentL1Received, this, &IntegrationPluginEnergyMeters::onCurrentL1Received); + connect(meter, &EnergyMeter::currentL2Received, this, &IntegrationPluginEnergyMeters::onCurrentL2Received); + connect(meter, &EnergyMeter::currentL3Received, this, &IntegrationPluginEnergyMeters::onCurrentL3Received); + connect(meter, &EnergyMeter::activePowerReceived, this, &IntegrationPluginEnergyMeters::onActivePowerReceived); + connect(meter, &EnergyMeter::powerFactorReceived, this, &IntegrationPluginEnergyMeters::onPowerFactorReceived); + connect(meter, &EnergyMeter::frequencyReceived, this, &IntegrationPluginEnergyMeters::onFrequencyReceived); + connect(meter, &EnergyMeter::producedEnergyReceived, this, &IntegrationPluginEnergyMeters::onProducedEnergyReceived); + connect(meter, &EnergyMeter::consumedEnergyReceived, this, &IntegrationPluginEnergyMeters::onConsumedEnergyReceived); + + m_energyMeters.insert(info->thing(), meter); + info->finish(Thing::ThingErrorNoError); + }); + meter->getEnergyConsumed(); + return; +} + +void IntegrationPluginEnergyMeters::postSetupThing(Thing *thing) +{ + qCDebug(dcEnergyMeters) << "Post setup thing" << thing->name(); + if (m_connectionStateTypeIds.contains(thing->thingClassId())) { + thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), true); + + if (m_energyMeters.contains(thing)) { + startUpdateCycle(m_energyMeters.value(thing)); + } else { + qCWarning(dcEnergyMeters()) << "Thing has no energy meter connection and will not work properly"; + } + } + + if (!m_reconnectTimer) { + qCDebug(dcEnergyMeters()) << "Starting reconnect timer"; + m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(5); + connect(m_reconnectTimer, &PluginTimer::timeout, this, [this] { + foreach (Thing *thing, myThings()) { + if (m_connectionStateTypeIds.contains(thing->thingClassId())) { + if (!thing->stateValue(m_connectionStateTypeIds.value(thing->thingClassId())).toBool()) { + EnergyMeter *meter = m_energyMeters.value(thing); + if (!meter) { + qCWarning(dcEnergyMeters()) << "On reconnect timer, could not find any EnergyMeter connection for" << thing->name(); + continue; + } + qCDebug(dcEnergyMeters()) << "On reconnect timer, restarting update cycle for" << thing->name(); + startUpdateCycle(meter); + } + } + } + }); + } +} + +void IntegrationPluginEnergyMeters::thingRemoved(Thing *thing) +{ + qCDebug(dcEnergyMeters()) << "Thing removed" << thing->name(); + + if (m_energyMeters.contains(thing)) { + EnergyMeter *meter = m_energyMeters.take(thing); + m_updateCycleInProgress.remove(meter); + meter->deleteLater(); + } + + if (myThings().isEmpty() && m_reconnectTimer) { + qCDebug(dcEnergyMeters()) << "Stopping reconnect timer"; + hardwareManager()->pluginTimerManager()->unregisterTimer(m_reconnectTimer); + m_reconnectTimer = nullptr; + } +} + +void IntegrationPluginEnergyMeters::startUpdateCycle(EnergyMeter *meter) +{ + if (m_updateCycleInProgress.contains(meter)) { + if (m_updateCycleInProgress.value(meter)) { + qCWarning(dcEnergyMeters()) << "Update cycle not startet, update cycle already in progress"; + return; + } + } + m_updateCycleInProgress.insert(meter, true); + meter->getVoltageL1(); +} + +void IntegrationPluginEnergyMeters::updateCycleFinished(EnergyMeter *meter) +{ + m_updateCycleInProgress.insert(meter, false); + + int updateInterval = configValue(energyMetersPluginUpdateIntervalParamTypeId).toInt(); + QTimer::singleShot(updateInterval, meter, [this, meter] { + startUpdateCycle(meter); // restart update cycle + }); +} + +void IntegrationPluginEnergyMeters::onConnectionStateChanged(bool status) +{ + EnergyMeter *meter = static_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + if (!status) { + updateCycleFinished(meter); + } + qCDebug(dcEnergyMeters()) << "Connection status changed" << thing->name() << status; + thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), status); +} + +void IntegrationPluginEnergyMeters::onVoltageL1Received(double voltage) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + meter->getVoltageL2(); + thing->setStateValue(m_voltageL1StateTypeIds.value(thing->thingClassId()), voltage); +} + +void IntegrationPluginEnergyMeters::onVoltageL2Received(double voltage) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + meter->getVoltageL3(); + thing->setStateValue(m_voltageL2StateTypeIds.value(thing->thingClassId()), voltage); +} + +void IntegrationPluginEnergyMeters::onVoltageL3Received(double voltage) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + meter->getCurrentL1(); + thing->setStateValue(m_voltageL3StateTypeIds.value(thing->thingClassId()), voltage); +} + +void IntegrationPluginEnergyMeters::onCurrentL1Received(double current) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + meter->getCurrentL2(); + thing->setStateValue(m_currentL1StateTypeIds.value(thing->thingClassId()), current); +} + +void IntegrationPluginEnergyMeters::onCurrentL2Received(double current) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + meter->getCurrentL3(); + thing->setStateValue(m_currentL2StateTypeIds.value(thing->thingClassId()), current); +} + +void IntegrationPluginEnergyMeters::onCurrentL3Received(double current) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + meter->getActivePower(); + thing->setStateValue(m_currentL3StateTypeIds.value(thing->thingClassId()), current); +} + +void IntegrationPluginEnergyMeters::onActivePowerReceived(double power) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + meter->getFrequency(); + thing->setStateValue(m_activePowerStateTypeIds.value(thing->thingClassId()), power); +} + +void IntegrationPluginEnergyMeters::onFrequencyReceived(double frequency) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + meter->getPowerFactor(); + thing->setStateValue(m_frequencyStateTypeIds.value(thing->thingClassId()), frequency); +} + +void IntegrationPluginEnergyMeters::onPowerFactorReceived(double powerFactor) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + meter->getEnergyProduced(); + thing->setStateValue(m_powerFactorStateTypeIds.value(thing->thingClassId()), powerFactor); +} + +void IntegrationPluginEnergyMeters::onProducedEnergyReceived(double energy) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + meter->getEnergyConsumed(); + thing->setStateValue(m_totalEnergyProducedStateTypeIds.value(thing->thingClassId()), energy); +} + +void IntegrationPluginEnergyMeters::onConsumedEnergyReceived(double energy) +{ + EnergyMeter *meter = qobject_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + updateCycleFinished(meter); + thing->setStateValue(m_totalEnergyConsumedStateTypeIds.value(thing->thingClassId()), energy); +} diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h new file mode 100644 index 0000000..dd9ae7c --- /dev/null +++ b/energymeters/integrationpluginenergymeters.h @@ -0,0 +1,100 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 . +* +* 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 INTEGRATIONPLUGINENERGYMETERS_H +#define INTEGRATIONPLUGINENERGYMETERS_H + +#include "integrations/integrationplugin.h" +#include "hardware/modbus/modbusrtuhardwareresource.h" +#include "plugintimer.h" + +#include "energymeter.h" + +#include +#include + +class IntegrationPluginEnergyMeters : public IntegrationPlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginenergymeters.json") + Q_INTERFACES(IntegrationPlugin) + +public: + explicit IntegrationPluginEnergyMeters(); + void init() override; + void discoverThings(ThingDiscoveryInfo *info) override; + void setupThing(ThingSetupInfo *info) override; + void postSetupThing(Thing *thing) override; + void thingRemoved(Thing *thing) override; + +private: + PluginTimer *m_reconnectTimer = nullptr; + QHash m_connectionStateTypeIds; + QHash m_voltageL1StateTypeIds; + QHash m_voltageL2StateTypeIds; + QHash m_voltageL3StateTypeIds; + QHash m_currentL1StateTypeIds; + QHash m_currentL2StateTypeIds; + QHash m_currentL3StateTypeIds; + QHash m_activePowerStateTypeIds; + QHash m_frequencyStateTypeIds; + QHash m_powerFactorStateTypeIds; + QHash m_totalEnergyConsumedStateTypeIds; + QHash m_totalEnergyProducedStateTypeIds; + + QHash m_discoverySlaveAddressParamTypeIds; + QHash m_slaveIdParamTypeIds; + QHash m_modbusUuidParamTypeIds; + + QHash> m_registerMaps; + + QHash m_energyMeters; + + QHash m_updateCycleInProgress; + void startUpdateCycle(EnergyMeter *meter); + void updateCycleFinished(EnergyMeter *meter); + +private slots: + void onConnectionStateChanged(bool status); + void onVoltageL1Received(double voltage); + void onVoltageL2Received(double voltage); + void onVoltageL3Received(double voltage); + void onCurrentL1Received(double current); + void onCurrentL2Received(double current); + void onCurrentL3Received(double current); + void onActivePowerReceived(double power); + void onFrequencyReceived(double frequency); + void onPowerFactorReceived(double powerFactor); + void onProducedEnergyReceived(double energy); + void onConsumedEnergyReceived(double energy); +}; + +#endif // INTEGRATIONPLUGINENERGYMETERS_H diff --git a/energymeters/integrationpluginenergymeters.json b/energymeters/integrationpluginenergymeters.json new file mode 100644 index 0000000..d6b23fc --- /dev/null +++ b/energymeters/integrationpluginenergymeters.json @@ -0,0 +1,316 @@ +{ + "name": "EnergyMeters", + "displayName": "EnergyMeters", + "id": "56e95111-fb6b-4f63-9a0a-a5ee001e89ed", + "paramTypes":[ + { + "id": "eaa84c3c-06b8-4642-a40b-c2efbe6aae66", + "name": "updateInterval", + "displayName": "Update interval", + "type": "uint", + "unit": "MilliSeconds", + "defaultValue": 300, + "minValue": 200 + } + ], + "vendors": [ + { + "name": "ineproMetering", + "displayName": "inepro Metering", + "id": "64f4df0f-18ce-409c-bf32-84a086c691ca", + "thingClasses": [ + { + "name": "pro380", + "displayName": "PRO380-Mod", + "id": "d7c6440b-54f9-4cc0-a96b-9bb7304b3e77", + "createMethods": ["discovery"], + "interfaces": ["extendedsmartmeterconsumer", "extendedsmartmeterproducer"], + "discoveryParamTypes": [ + { + "id": "a29f37f6-b344-4628-8ab4-8f4c18fada4a", + "name": "slaveAddress", + "displayName": "Slave address", + "type": "int", + "defaultValue": 1 + } + ], + "paramTypes": [ + { + "id": "c75b2c31-6ec3-49ab-8c8f-5231d0a7e941", + "name": "slaveAddress", + "displayName": "Modbus slave address", + "type": "uint", + "defaultValue": 1 + }, + { + "id": "6cdbec8c-21b9-42dc-b1ab-8901ac609482", + "name": "modbusMasterUuid", + "displayName": "Modbus RTU master", + "type": "QUuid", + "defaultValue": "", + "readOnly": true + } + ], + "stateTypes": [ + { + "id": "7f9bc504-0882-4b86-83b1-42fa345acfd9", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "cached": false, + "defaultValue": false + }, + { + "id": "04dba21a-7447-46b9-b9ae-095e5769e511", + "name": "voltageL1", + "displayName": "Voltage L1", + "displayNameEvent": "Voltage L1 changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "270d0c34-0a0c-4655-985f-faad6efd1afd", + "name": "voltageL2", + "displayName": "Voltage L2", + "displayNameEvent": "Voltage L2 changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "a1da8cfd-37cc-4c87-b857-e942cd90daec", + "name": "voltageL3", + "displayName": "Voltage L3", + "displayNameEvent": "Voltage L3 changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "1e077a3b-2dab-4ec4-ae96-ab49a564fe31", + "name": "currentL1", + "displayName": "Current L1", + "displayNameEvent": "Current L1 changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0 + }, + { + "id": "d2f54061-0807-47de-944c-68c8118ece91", + "name": "currentL2", + "displayName": "Current L2", + "displayNameEvent": "Current L2 changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0 + }, + { + "id": "610b20fb-2718-4f02-ac6e-12a9ef8c7615", + "name": "currentL3", + "displayName": "Current L3", + "displayNameEvent": "Current L3 changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0 + }, + { + "id": "464eff60-11c2-46b7-98f5-1aa8172e5a2d", + "name": "currentPower", + "displayName": "Active power", + "displayNameEvent": "Active power changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0 + }, + { + "id": "cdb34487-3d9b-492a-8c33-802f32a2e90e", + "name": "powerFactor", + "displayName": "Power factor", + "displayNameEvent": "Power factor changed", + "type": "double", + "defaultValue": 0.00 + }, + { + "id": "bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5", + "name": "frequency", + "displayName": "Frequency", + "displayNameEvent": "Frequency changed", + "type": "double", + "unit": "Hertz", + "defaultValue": 0.00 + }, + { + "id": "f18fd596-b47f-44be-a0f0-6ca44369ebf5", + "name": "totalEnergyConsumed", + "displayName": "Total energy consumed", + "displayNameEvent": "Total energy consumed changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "112911c9-14e0-4c83-ac92-f2ceb3bdecdf", + "name": "totalEnergyProduced", + "displayName": "Total energy produced", + "displayNameEvent": "Total energy produced changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + } + ] + } + ] + }, + { + "name": "bgetech", + "displayName": "B+G e-tech", + "id": "215035fe-95e8-43d8-a52e-0a31b787d902", + "thingClasses": [ + { + "name": "sdm630", + "displayName": "SDM630Modbus", + "id": "f37597bb-35fe-48f2-9617-343dd54c0903", + "createMethods": ["discovery"], + "interfaces": ["extendedsmartmeterconsumer", "extendedsmartmeterproducer"], + "discoveryParamTypes": [ + { + "id": "6ab43559-53ec-47ba-b8a0-8d3b7f8d90c2", + "name": "slaveAddress", + "displayName": "Slave address", + "type": "int", + "defaultValue": 1 + } + ], + "paramTypes": [ + { + "id": "ac77ea98-b006-486e-a3e8-b30a483f26c1", + "name": "slaveAddress", + "displayName": "Modbus slave address", + "type": "uint", + "defaultValue": 1 + }, + { + "id": "d90e9292-d03c-4f2a-957e-5d965018c9c9", + "name": "modbusMasterUuid", + "displayName": "Modbus RTU master", + "type": "QUuid", + "defaultValue": "", + "readOnly": true + } + ], + "stateTypes": [ + { + "id": "8050bd0b-1dad-4a7e-b632-c71ead3c9f8b", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "cached": false, + "defaultValue": false + }, + { + "id": "db018146-0441-4dc0-9834-6d43ebaf8311", + "name": "voltageL1", + "displayName": "Voltage L1", + "displayNameEvent": "Voltage L1 changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "406f6d02-d5eb-49b3-87da-3247568e6054", + "name": "voltageL2", + "displayName": "Voltage L2", + "displayNameEvent": "Voltage L2 changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "ace6294d-deaa-4d9a-af78-d64379bcb229", + "name": "voltageL3", + "displayName": "Voltage L3", + "displayNameEvent": "Voltage L3 changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "4baf1d08-5ffa-49cf-95ef-9527b0c6f081", + "name": "currentL1", + "displayName": "Current L1", + "displayNameEvent": "Current L1 changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0 + }, + { + "id": "99e47d06-0a6a-4bfd-b164-61ecb6ba2818", + "name": "currentL2", + "displayName": "Current L2", + "displayNameEvent": "Current L2 changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0 + }, + { + "id": "4a092a66-352d-4d60-90ab-6ac5f58b92fe", + "name": "currentL3", + "displayName": "Current L3", + "displayNameEvent": "Current L3 changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0 + }, + { + "id": "c824e97b-a6d1-4030-9d7a-00af6fb8e1c3", + "name": "currentPower", + "displayName": "Active power", + "displayNameEvent": "Active power changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0 + }, + { + "id": "31b9032f-f994-472b-94bd-44f9fb094801", + "name": "powerFactor", + "displayName": "Power factor", + "displayNameEvent": "Power factor changed", + "type": "double", + "defaultValue": 0.00 + }, + { + "id": "ab24f26c-dc15-4ec3-8d76-06a48285440b", + "name": "frequency", + "displayName": "Frequency", + "displayNameEvent": "Frequency changed", + "type": "double", + "unit": "Hertz", + "defaultValue": 0.00 + }, + { + "id": "98d858a8-22e8-4262-b5c7-25bb027942ad", + "name": "totalEnergyConsumed", + "displayName": "Total energy consumed", + "displayNameEvent": "Total energy consumed changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "e469b3ff-a4c2-42da-af35-ccafaef214af", + "name": "totalEnergyProduced", + "displayName": "Total energy produced", + "displayNameEvent": "Total energy produced changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + } + ] + } + ] + } + ] +} diff --git a/energymeters/meta.json b/energymeters/meta.json new file mode 100644 index 0000000..4f390d5 --- /dev/null +++ b/energymeters/meta.json @@ -0,0 +1,11 @@ +{ + "title": "Energy Meters", + "tagline": "Connect Modbus RTU energy meters.", + "icon": "energymeter.svg", + "stability": "consumer", + "offline": true, + "technologies": [ + ], + "categories": [ + ] +} diff --git a/energymeters/registerdescriptor.h b/energymeters/registerdescriptor.h new file mode 100644 index 0000000..d330b3f --- /dev/null +++ b/energymeters/registerdescriptor.h @@ -0,0 +1,87 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 . +* +* 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 REGISTERDESCRIPTOR_H +#define REGISTERDESCRIPTOR_H + +#include +#include + +enum ModbusRegisterType { + VoltageL1, + VoltageL2, + VoltageL3, + CurrentL1, + CurrentL2, + CurrentL3, + ActivePower, + Frequency, + PowerFactor, + EnergyProduced, + EnergyConsumed +}; + +class ModbusRegisterDescriptor +{ + +public: + ModbusRegisterDescriptor() {} + ModbusRegisterDescriptor(int address, int functionCode, int length, QString unit, QString dataType) : + m_address(address), + m_functionCode(functionCode), + m_length(length), + m_unit(unit), + m_dataType(dataType) + {} + + int address() const + { return m_address;} + + int functionCode() const + { return m_functionCode;} + + int length() const + { return m_length;} + + QString unit() const + { return m_unit;} + + QString dataType() const + { return m_dataType;} + +private: + int m_address; + int m_functionCode; + int m_length; + QString m_unit; + QString m_dataType; +}; + +#endif // REGISTERDESCRIPTOR_H diff --git a/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts new file mode 100644 index 0000000..5adaee8 --- /dev/null +++ b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts @@ -0,0 +1,391 @@ + + + + + EnergyMeters + + + + + + Active power + The name of the ParamType (ThingClass: sdm630, EventType: currentPower, ID: {c824e97b-a6d1-4030-9d7a-00af6fb8e1c3}) +---------- +The name of the StateType ({c824e97b-a6d1-4030-9d7a-00af6fb8e1c3}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentPower, ID: {464eff60-11c2-46b7-98f5-1aa8172e5a2d}) +---------- +The name of the StateType ({464eff60-11c2-46b7-98f5-1aa8172e5a2d}) of ThingClass pro380 + Leistung + + + + + Active power changed + The name of the EventType ({c824e97b-a6d1-4030-9d7a-00af6fb8e1c3}) of ThingClass sdm630 +---------- +The name of the EventType ({464eff60-11c2-46b7-98f5-1aa8172e5a2d}) of ThingClass pro380 + Leistung geändert + + + + B+G e-tech + The name of the vendor ({215035fe-95e8-43d8-a52e-0a31b787d902}) + B+G e-tech + + + + + + + Connected + The name of the ParamType (ThingClass: sdm630, EventType: connected, ID: {8050bd0b-1dad-4a7e-b632-c71ead3c9f8b}) +---------- +The name of the StateType ({8050bd0b-1dad-4a7e-b632-c71ead3c9f8b}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: connected, ID: {7f9bc504-0882-4b86-83b1-42fa345acfd9}) +---------- +The name of the StateType ({7f9bc504-0882-4b86-83b1-42fa345acfd9}) of ThingClass pro380 + Verbunden + + + + + Connected changed + The name of the EventType ({8050bd0b-1dad-4a7e-b632-c71ead3c9f8b}) of ThingClass sdm630 +---------- +The name of the EventType ({7f9bc504-0882-4b86-83b1-42fa345acfd9}) of ThingClass pro380 + Verbunden + + + + + + + Current L1 + The name of the ParamType (ThingClass: sdm630, EventType: currentL1, ID: {4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) +---------- +The name of the StateType ({4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentL1, ID: {1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) +---------- +The name of the StateType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) of ThingClass pro380 + Strom L1 + + + + + Current L1 changed + The name of the EventType ({4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) of ThingClass sdm630 +---------- +The name of the EventType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) of ThingClass pro380 + Strom L1 geändert + + + + + + + Current L2 + The name of the ParamType (ThingClass: sdm630, EventType: currentL2, ID: {99e47d06-0a6a-4bfd-b164-61ecb6ba2818}) +---------- +The name of the StateType ({99e47d06-0a6a-4bfd-b164-61ecb6ba2818}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentL2, ID: {d2f54061-0807-47de-944c-68c8118ece91}) +---------- +The name of the StateType ({d2f54061-0807-47de-944c-68c8118ece91}) of ThingClass pro380 + Strom L2 + + + + + Current L2 changed + The name of the EventType ({99e47d06-0a6a-4bfd-b164-61ecb6ba2818}) of ThingClass sdm630 +---------- +The name of the EventType ({d2f54061-0807-47de-944c-68c8118ece91}) of ThingClass pro380 + Strom L2 geändert + + + + + + + Current L3 + The name of the ParamType (ThingClass: sdm630, EventType: currentL3, ID: {4a092a66-352d-4d60-90ab-6ac5f58b92fe}) +---------- +The name of the StateType ({4a092a66-352d-4d60-90ab-6ac5f58b92fe}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentL3, ID: {610b20fb-2718-4f02-ac6e-12a9ef8c7615}) +---------- +The name of the StateType ({610b20fb-2718-4f02-ac6e-12a9ef8c7615}) of ThingClass pro380 + Strom L3 + + + + + Current L3 changed + The name of the EventType ({4a092a66-352d-4d60-90ab-6ac5f58b92fe}) of ThingClass sdm630 +---------- +The name of the EventType ({610b20fb-2718-4f02-ac6e-12a9ef8c7615}) of ThingClass pro380 + Strom L3 geändert + + + + EnergyMeters + The name of the plugin EnergyMeters ({56e95111-fb6b-4f63-9a0a-a5ee001e89ed}) + Energiezähler + + + + + + + Frequency + The name of the ParamType (ThingClass: sdm630, EventType: frequency, ID: {ab24f26c-dc15-4ec3-8d76-06a48285440b}) +---------- +The name of the StateType ({ab24f26c-dc15-4ec3-8d76-06a48285440b}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: frequency, ID: {bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5}) +---------- +The name of the StateType ({bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5}) of ThingClass pro380 + Frequenz + + + + + Frequency changed + The name of the EventType ({ab24f26c-dc15-4ec3-8d76-06a48285440b}) of ThingClass sdm630 +---------- +The name of the EventType ({bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5}) of ThingClass pro380 + Frequenz geändert + + + + + Modbus RTU master + The name of the ParamType (ThingClass: sdm630, Type: thing, ID: {d90e9292-d03c-4f2a-957e-5d965018c9c9}) +---------- +The name of the ParamType (ThingClass: pro380, Type: thing, ID: {6cdbec8c-21b9-42dc-b1ab-8901ac609482}) + Modbus RTU Master + + + + + Modbus slave address + The name of the ParamType (ThingClass: sdm630, Type: thing, ID: {ac77ea98-b006-486e-a3e8-b30a483f26c1}) +---------- +The name of the ParamType (ThingClass: pro380, Type: thing, ID: {c75b2c31-6ec3-49ab-8c8f-5231d0a7e941}) + Modbus Slave-Adresse + + + + PRO380-Mod + The name of the ThingClass ({d7c6440b-54f9-4cc0-a96b-9bb7304b3e77}) + PRO380-Mod + + + + + + + Power factor + The name of the ParamType (ThingClass: sdm630, EventType: powerFactor, ID: {31b9032f-f994-472b-94bd-44f9fb094801}) +---------- +The name of the StateType ({31b9032f-f994-472b-94bd-44f9fb094801}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: powerFactor, ID: {cdb34487-3d9b-492a-8c33-802f32a2e90e}) +---------- +The name of the StateType ({cdb34487-3d9b-492a-8c33-802f32a2e90e}) of ThingClass pro380 + Leistungsfaktor + + + + + Power factor changed + The name of the EventType ({31b9032f-f994-472b-94bd-44f9fb094801}) of ThingClass sdm630 +---------- +The name of the EventType ({cdb34487-3d9b-492a-8c33-802f32a2e90e}) of ThingClass pro380 + Leistungsfaktor geändert + + + + SDM630Modbus + The name of the ThingClass ({f37597bb-35fe-48f2-9617-343dd54c0903}) + SDM630Modbus + + + + + Slave address + The name of the ParamType (ThingClass: sdm630, Type: discovery, ID: {6ab43559-53ec-47ba-b8a0-8d3b7f8d90c2}) +---------- +The name of the ParamType (ThingClass: pro380, Type: discovery, ID: {a29f37f6-b344-4628-8ab4-8f4c18fada4a}) + Slave-Adresse + + + + + + + Total energy consumed + The name of the ParamType (ThingClass: sdm630, EventType: totalEnergyConsumed, ID: {98d858a8-22e8-4262-b5c7-25bb027942ad}) +---------- +The name of the StateType ({98d858a8-22e8-4262-b5c7-25bb027942ad}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: totalEnergyConsumed, ID: {f18fd596-b47f-44be-a0f0-6ca44369ebf5}) +---------- +The name of the StateType ({f18fd596-b47f-44be-a0f0-6ca44369ebf5}) of ThingClass pro380 + Gesamte verbrauchte Energy + + + + + Total energy consumed changed + The name of the EventType ({98d858a8-22e8-4262-b5c7-25bb027942ad}) of ThingClass sdm630 +---------- +The name of the EventType ({f18fd596-b47f-44be-a0f0-6ca44369ebf5}) of ThingClass pro380 + Gesamte verbrauchte Energie geändert + + + + + + + Total energy produced + The name of the ParamType (ThingClass: sdm630, EventType: totalEnergyProduced, ID: {e469b3ff-a4c2-42da-af35-ccafaef214af}) +---------- +The name of the StateType ({e469b3ff-a4c2-42da-af35-ccafaef214af}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: totalEnergyProduced, ID: {112911c9-14e0-4c83-ac92-f2ceb3bdecdf}) +---------- +The name of the StateType ({112911c9-14e0-4c83-ac92-f2ceb3bdecdf}) of ThingClass pro380 + Gesamte produzierte Energie + + + + + Total energy produced changed + The name of the EventType ({e469b3ff-a4c2-42da-af35-ccafaef214af}) of ThingClass sdm630 +---------- +The name of the EventType ({112911c9-14e0-4c83-ac92-f2ceb3bdecdf}) of ThingClass pro380 + Gesamte produzierte Energie geändert + + + + Update interval + The name of the ParamType (ThingClass: energyMeters, Type: plugin, ID: {eaa84c3c-06b8-4642-a40b-c2efbe6aae66}) + Updateintervall + + + + + + + Voltage L1 + The name of the ParamType (ThingClass: sdm630, EventType: voltageL1, ID: {db018146-0441-4dc0-9834-6d43ebaf8311}) +---------- +The name of the StateType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: voltageL1, ID: {04dba21a-7447-46b9-b9ae-095e5769e511}) +---------- +The name of the StateType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 + Spannung L1 + + + + + Voltage L1 changed + The name of the EventType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 +---------- +The name of the EventType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 + Spannung L1 geändert + + + + + + + Voltage L2 + The name of the ParamType (ThingClass: sdm630, EventType: voltageL2, ID: {406f6d02-d5eb-49b3-87da-3247568e6054}) +---------- +The name of the StateType ({406f6d02-d5eb-49b3-87da-3247568e6054}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: voltageL2, ID: {270d0c34-0a0c-4655-985f-faad6efd1afd}) +---------- +The name of the StateType ({270d0c34-0a0c-4655-985f-faad6efd1afd}) of ThingClass pro380 + Spannung L2 + + + + + Voltage L2 changed + The name of the EventType ({406f6d02-d5eb-49b3-87da-3247568e6054}) of ThingClass sdm630 +---------- +The name of the EventType ({270d0c34-0a0c-4655-985f-faad6efd1afd}) of ThingClass pro380 + Spannung L2 geändert + + + + + + + Voltage L3 + The name of the ParamType (ThingClass: sdm630, EventType: voltageL3, ID: {ace6294d-deaa-4d9a-af78-d64379bcb229}) +---------- +The name of the StateType ({ace6294d-deaa-4d9a-af78-d64379bcb229}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: voltageL3, ID: {a1da8cfd-37cc-4c87-b857-e942cd90daec}) +---------- +The name of the StateType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) of ThingClass pro380 + Spannung L3 + + + + + Voltage L3 changed + The name of the EventType ({ace6294d-deaa-4d9a-af78-d64379bcb229}) of ThingClass sdm630 +---------- +The name of the EventType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) of ThingClass pro380 + Spannung L3 geändert + + + + inepro Metering + The name of the vendor ({64f4df0f-18ce-409c-bf32-84a086c691ca}) + inepro Metering + + + + IntegrationPluginEnergyMeters + + + No Modbus RTU interface available. + Keine Modbus RTU Schnittstelle verfügbar + + + + Modbus slave address must be between 1 and 254 + Die Modbus-Slave-Adresse muss zwischen 1 und 254 liegen + + + + Energy meter + Energiezähler + + + + Slave address + Slave-Adresse + + + + Slave address not valid, must be between 1 and 254 + Die Slave-Adresse ist ungültig, sie muss zwischen 1 und 254 liegen + + + + Modbus RTU resource not available. + Modbus RTU Schnittstelle nicht verfügbar + + + diff --git a/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts new file mode 100644 index 0000000..c09f5ee --- /dev/null +++ b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts @@ -0,0 +1,391 @@ + + + + + EnergyMeters + + + + + + Active power + The name of the ParamType (ThingClass: sdm630, EventType: currentPower, ID: {c824e97b-a6d1-4030-9d7a-00af6fb8e1c3}) +---------- +The name of the StateType ({c824e97b-a6d1-4030-9d7a-00af6fb8e1c3}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentPower, ID: {464eff60-11c2-46b7-98f5-1aa8172e5a2d}) +---------- +The name of the StateType ({464eff60-11c2-46b7-98f5-1aa8172e5a2d}) of ThingClass pro380 + + + + + + Active power changed + The name of the EventType ({c824e97b-a6d1-4030-9d7a-00af6fb8e1c3}) of ThingClass sdm630 +---------- +The name of the EventType ({464eff60-11c2-46b7-98f5-1aa8172e5a2d}) of ThingClass pro380 + + + + + B+G e-tech + The name of the vendor ({215035fe-95e8-43d8-a52e-0a31b787d902}) + + + + + + + + Connected + The name of the ParamType (ThingClass: sdm630, EventType: connected, ID: {8050bd0b-1dad-4a7e-b632-c71ead3c9f8b}) +---------- +The name of the StateType ({8050bd0b-1dad-4a7e-b632-c71ead3c9f8b}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: connected, ID: {7f9bc504-0882-4b86-83b1-42fa345acfd9}) +---------- +The name of the StateType ({7f9bc504-0882-4b86-83b1-42fa345acfd9}) of ThingClass pro380 + + + + + + Connected changed + The name of the EventType ({8050bd0b-1dad-4a7e-b632-c71ead3c9f8b}) of ThingClass sdm630 +---------- +The name of the EventType ({7f9bc504-0882-4b86-83b1-42fa345acfd9}) of ThingClass pro380 + + + + + + + + Current L1 + The name of the ParamType (ThingClass: sdm630, EventType: currentL1, ID: {4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) +---------- +The name of the StateType ({4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentL1, ID: {1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) +---------- +The name of the StateType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) of ThingClass pro380 + + + + + + Current L1 changed + The name of the EventType ({4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) of ThingClass sdm630 +---------- +The name of the EventType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) of ThingClass pro380 + + + + + + + + Current L2 + The name of the ParamType (ThingClass: sdm630, EventType: currentL2, ID: {99e47d06-0a6a-4bfd-b164-61ecb6ba2818}) +---------- +The name of the StateType ({99e47d06-0a6a-4bfd-b164-61ecb6ba2818}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentL2, ID: {d2f54061-0807-47de-944c-68c8118ece91}) +---------- +The name of the StateType ({d2f54061-0807-47de-944c-68c8118ece91}) of ThingClass pro380 + + + + + + Current L2 changed + The name of the EventType ({99e47d06-0a6a-4bfd-b164-61ecb6ba2818}) of ThingClass sdm630 +---------- +The name of the EventType ({d2f54061-0807-47de-944c-68c8118ece91}) of ThingClass pro380 + + + + + + + + Current L3 + The name of the ParamType (ThingClass: sdm630, EventType: currentL3, ID: {4a092a66-352d-4d60-90ab-6ac5f58b92fe}) +---------- +The name of the StateType ({4a092a66-352d-4d60-90ab-6ac5f58b92fe}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentL3, ID: {610b20fb-2718-4f02-ac6e-12a9ef8c7615}) +---------- +The name of the StateType ({610b20fb-2718-4f02-ac6e-12a9ef8c7615}) of ThingClass pro380 + + + + + + Current L3 changed + The name of the EventType ({4a092a66-352d-4d60-90ab-6ac5f58b92fe}) of ThingClass sdm630 +---------- +The name of the EventType ({610b20fb-2718-4f02-ac6e-12a9ef8c7615}) of ThingClass pro380 + + + + + EnergyMeters + The name of the plugin EnergyMeters ({56e95111-fb6b-4f63-9a0a-a5ee001e89ed}) + + + + + + + + Frequency + The name of the ParamType (ThingClass: sdm630, EventType: frequency, ID: {ab24f26c-dc15-4ec3-8d76-06a48285440b}) +---------- +The name of the StateType ({ab24f26c-dc15-4ec3-8d76-06a48285440b}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: frequency, ID: {bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5}) +---------- +The name of the StateType ({bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5}) of ThingClass pro380 + + + + + + Frequency changed + The name of the EventType ({ab24f26c-dc15-4ec3-8d76-06a48285440b}) of ThingClass sdm630 +---------- +The name of the EventType ({bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5}) of ThingClass pro380 + + + + + + Modbus RTU master + The name of the ParamType (ThingClass: sdm630, Type: thing, ID: {d90e9292-d03c-4f2a-957e-5d965018c9c9}) +---------- +The name of the ParamType (ThingClass: pro380, Type: thing, ID: {6cdbec8c-21b9-42dc-b1ab-8901ac609482}) + + + + + + Modbus slave address + The name of the ParamType (ThingClass: sdm630, Type: thing, ID: {ac77ea98-b006-486e-a3e8-b30a483f26c1}) +---------- +The name of the ParamType (ThingClass: pro380, Type: thing, ID: {c75b2c31-6ec3-49ab-8c8f-5231d0a7e941}) + + + + + PRO380-Mod + The name of the ThingClass ({d7c6440b-54f9-4cc0-a96b-9bb7304b3e77}) + + + + + + + + Power factor + The name of the ParamType (ThingClass: sdm630, EventType: powerFactor, ID: {31b9032f-f994-472b-94bd-44f9fb094801}) +---------- +The name of the StateType ({31b9032f-f994-472b-94bd-44f9fb094801}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: powerFactor, ID: {cdb34487-3d9b-492a-8c33-802f32a2e90e}) +---------- +The name of the StateType ({cdb34487-3d9b-492a-8c33-802f32a2e90e}) of ThingClass pro380 + + + + + + Power factor changed + The name of the EventType ({31b9032f-f994-472b-94bd-44f9fb094801}) of ThingClass sdm630 +---------- +The name of the EventType ({cdb34487-3d9b-492a-8c33-802f32a2e90e}) of ThingClass pro380 + + + + + SDM630Modbus + The name of the ThingClass ({f37597bb-35fe-48f2-9617-343dd54c0903}) + + + + + + Slave address + The name of the ParamType (ThingClass: sdm630, Type: discovery, ID: {6ab43559-53ec-47ba-b8a0-8d3b7f8d90c2}) +---------- +The name of the ParamType (ThingClass: pro380, Type: discovery, ID: {a29f37f6-b344-4628-8ab4-8f4c18fada4a}) + + + + + + + + Total energy consumed + The name of the ParamType (ThingClass: sdm630, EventType: totalEnergyConsumed, ID: {98d858a8-22e8-4262-b5c7-25bb027942ad}) +---------- +The name of the StateType ({98d858a8-22e8-4262-b5c7-25bb027942ad}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: totalEnergyConsumed, ID: {f18fd596-b47f-44be-a0f0-6ca44369ebf5}) +---------- +The name of the StateType ({f18fd596-b47f-44be-a0f0-6ca44369ebf5}) of ThingClass pro380 + + + + + + Total energy consumed changed + The name of the EventType ({98d858a8-22e8-4262-b5c7-25bb027942ad}) of ThingClass sdm630 +---------- +The name of the EventType ({f18fd596-b47f-44be-a0f0-6ca44369ebf5}) of ThingClass pro380 + + + + + + + + Total energy produced + The name of the ParamType (ThingClass: sdm630, EventType: totalEnergyProduced, ID: {e469b3ff-a4c2-42da-af35-ccafaef214af}) +---------- +The name of the StateType ({e469b3ff-a4c2-42da-af35-ccafaef214af}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: totalEnergyProduced, ID: {112911c9-14e0-4c83-ac92-f2ceb3bdecdf}) +---------- +The name of the StateType ({112911c9-14e0-4c83-ac92-f2ceb3bdecdf}) of ThingClass pro380 + + + + + + Total energy produced changed + The name of the EventType ({e469b3ff-a4c2-42da-af35-ccafaef214af}) of ThingClass sdm630 +---------- +The name of the EventType ({112911c9-14e0-4c83-ac92-f2ceb3bdecdf}) of ThingClass pro380 + + + + + Update interval + The name of the ParamType (ThingClass: energyMeters, Type: plugin, ID: {eaa84c3c-06b8-4642-a40b-c2efbe6aae66}) + + + + + + + + Voltage L1 + The name of the ParamType (ThingClass: sdm630, EventType: voltageL1, ID: {db018146-0441-4dc0-9834-6d43ebaf8311}) +---------- +The name of the StateType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: voltageL1, ID: {04dba21a-7447-46b9-b9ae-095e5769e511}) +---------- +The name of the StateType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 + + + + + + Voltage L1 changed + The name of the EventType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 +---------- +The name of the EventType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 + + + + + + + + Voltage L2 + The name of the ParamType (ThingClass: sdm630, EventType: voltageL2, ID: {406f6d02-d5eb-49b3-87da-3247568e6054}) +---------- +The name of the StateType ({406f6d02-d5eb-49b3-87da-3247568e6054}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: voltageL2, ID: {270d0c34-0a0c-4655-985f-faad6efd1afd}) +---------- +The name of the StateType ({270d0c34-0a0c-4655-985f-faad6efd1afd}) of ThingClass pro380 + + + + + + Voltage L2 changed + The name of the EventType ({406f6d02-d5eb-49b3-87da-3247568e6054}) of ThingClass sdm630 +---------- +The name of the EventType ({270d0c34-0a0c-4655-985f-faad6efd1afd}) of ThingClass pro380 + + + + + + + + Voltage L3 + The name of the ParamType (ThingClass: sdm630, EventType: voltageL3, ID: {ace6294d-deaa-4d9a-af78-d64379bcb229}) +---------- +The name of the StateType ({ace6294d-deaa-4d9a-af78-d64379bcb229}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: voltageL3, ID: {a1da8cfd-37cc-4c87-b857-e942cd90daec}) +---------- +The name of the StateType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) of ThingClass pro380 + + + + + + Voltage L3 changed + The name of the EventType ({ace6294d-deaa-4d9a-af78-d64379bcb229}) of ThingClass sdm630 +---------- +The name of the EventType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) of ThingClass pro380 + + + + + inepro Metering + The name of the vendor ({64f4df0f-18ce-409c-bf32-84a086c691ca}) + + + + + IntegrationPluginEnergyMeters + + + No Modbus RTU interface available. + + + + + Modbus slave address must be between 1 and 254 + + + + + Energy meter + + + + + Slave address + + + + + Slave address not valid, must be between 1 and 254 + + + + + Modbus RTU resource not available. + + + + diff --git a/modbus/modbusrtumaster.cpp b/modbus/modbusrtumaster.cpp deleted file mode 100644 index d702c3b..0000000 --- a/modbus/modbusrtumaster.cpp +++ /dev/null @@ -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 . -* -* 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 - -#include - -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() << static_cast(value)); -} - - -QUuid ModbusRTUMaster::writeCoils(uint slaveAddress, uint registerAddress, const QVector &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() << value); -} - -QUuid ModbusRTUMaster::writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector &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); -} diff --git a/modbus/modbusrtumaster.h b/modbus/modbusrtumaster.h deleted file mode 100644 index 3a69db3..0000000 --- a/modbus/modbusrtumaster.h +++ /dev/null @@ -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 . -* -* 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 -#include -#include -#include -#include - -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 &values); - - QUuid writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value); - QUuid writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector &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 &values); - void receivedDiscreteInput(uint slaveAddress, uint modbusRegister, const QVector &values); - void receivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector &values); - void receivedInputRegister(uint slaveAddress, uint modbusRegister, const QVector &values); -}; - -#endif // MODBUSRTUMASTER_H diff --git a/nymea-plugins-modbus.pro b/nymea-plugins-modbus.pro index 207d8bc..2515df5 100644 --- a/nymea-plugins-modbus.pro +++ b/nymea-plugins-modbus.pro @@ -2,6 +2,7 @@ TEMPLATE = subdirs PLUGIN_DIRS = \ drexelundweiss \ + energymeters \ modbuscommander \ mypv \ sunspec \