From 4d5911a098eec87724d432f98dbe5f59ba011f0c Mon Sep 17 00:00:00 2001 From: Boernsman Date: Sun, 2 May 2021 11:27:57 +0200 Subject: [PATCH 01/26] switched to modbus rtu resource --- drexelundweiss/drexelundweiss.pro | 4 +- .../integrationplugindrexelundweiss.cpp | 890 ++++++++---------- .../integrationplugindrexelundweiss.h | 24 +- .../integrationplugindrexelundweiss.json | 112 +-- drexelundweiss/modbusdegisterdefinition.h | 6 +- ...68d78ce6-82d0-4a5b-b901-7c3b843ef63c-de.ts | 80 +- ...78ce6-82d0-4a5b-b901-7c3b843ef63c-en_US.ts | 76 +- modbus/modbusrtumaster.cpp | 410 -------- modbus/modbusrtumaster.h | 90 -- 9 files changed, 554 insertions(+), 1138 deletions(-) delete mode 100644 modbus/modbusrtumaster.cpp delete mode 100644 modbus/modbusrtumaster.h diff --git a/drexelundweiss/drexelundweiss.pro b/drexelundweiss/drexelundweiss.pro index 561d18d..925e659 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 \ + modbusdegisterdefinition.h diff --git a/drexelundweiss/integrationplugindrexelundweiss.cpp b/drexelundweiss/integrationplugindrexelundweiss.cpp index 0f7d9d5..19932af 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,50 +30,39 @@ #include "integrationplugindrexelundweiss.h" #include "plugininfo.h" -#include "modbusdegisterdefinition.h" + +#include "hardwaremanager.h" +#include "hardware/modbus/modbusrtumaster.h" +#include "hardware/modbus/modbusrtuhardwareresource.h" IntegrationPluginDrexelUndWeiss::IntegrationPluginDrexelUndWeiss() { - -} - -IntegrationPluginDrexelUndWeiss::~IntegrationPluginDrexelUndWeiss() -{ - + m_connectedStateTypeIds.insert(x2luThingClassId, x2luConnectedStateTypeId); + m_connectedStateTypeIds.insert(x2wpThingClassId, x2wpConnectedStateTypeId); } void IntegrationPluginDrexelUndWeiss::init() { connect(this, &IntegrationPluginDrexelUndWeiss::configValueChanged, this, &IntegrationPluginDrexelUndWeiss::onPluginConfigurationChanged); + + connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=](const QUuid &modbusUuid){ + qCDebug(dcDrexelUndWeiss()) << "Modbus RTU master has been removed" << modbusUuid.toString(); + + // Check if there is any device using this resource + foreach (Thing *thing, m_modbusRtuMasters.keys()) { + if (m_modbusRtuMasters.value(thing)->modbusUuid() == modbusUuid) { + qCWarning(dcDrexelUndWeiss()) << "Hardware resource removed for" << thing << ". The thing will not be functional any more until a new resource has been configured for it."; + m_modbusRtuMasters.remove(thing); + thing->setStateValue(m_connectedStateTypeIds[thing->thingClassId()], false); + } + } + }); } void IntegrationPluginDrexelUndWeiss::discoverThings(ThingDiscoveryInfo *info) { - // Create the list of available serial interfaces - QList thingDescriptors; - - if (info->thingClassId() == modbusConnectionThingClassId) { - Q_FOREACH(QSerialPortInfo port, QSerialPortInfo::availablePorts()) { - if (m_usedSerialPorts.contains(port.systemLocation())){ - //Thing already in use - qCDebug(dcDrexelUndWeiss()) << "Found serial port that is already used:" << port.portName(); - } else { - //Serial port is not yet used, create now a new one - qCDebug(dcDrexelUndWeiss()) << "Found serial port:" << port.portName(); - QString description = port.manufacturer() + " " + port.description(); - ThingDescriptor descriptor(info->thingClassId(), port.portName(), description); - ParamList parameters; - parameters.append(Param(modbusConnectionThingSerialPortParamTypeId, port.systemLocation())); - descriptor.setParams(parameters); - info->addThingDescriptor(descriptor); - } - } - info->finish(Thing::ThingErrorNoError); - return; - } else if (info->thingClassId() == x2luThingClassId) { - info->finish(Thing::ThingErrorNoError); - return; - } else if (info->thingClassId() == x2wpThingClassId) { + if (info->thingClassId() == x2luThingClassId || info->thingClassId() == x2wpThingClassId) { + QList thingDescriptors; info->finish(Thing::ThingErrorNoError); return; } else { @@ -84,26 +73,79 @@ void IntegrationPluginDrexelUndWeiss::discoverThings(ThingDiscoveryInfo *info) void IntegrationPluginDrexelUndWeiss::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); + qCDebug(dcDrexelUndWeiss()) << "Setup thing" << thing->name(); - if (thing->thingClassId() == modbusConnectionThingClassId) { + if (thing->thingClassId() == x2luThingClassId) { - QString serialPort = thing->paramValue(modbusConnectionThingSerialPortParamTypeId).toString(); - int baudRate = thing->paramValue(modbusConnectionThingBaudRateParamTypeId).toInt(); + QUuid modbusMasterUuid = thing->paramValue(x2luThingModbusMasterUuidParamTypeId).toUuid(); + uint slaveAddress = thing->paramValue(x2luThingSlaveAddressParamTypeId).toUInt(); - ModbusRTUMaster *modbus = new ModbusRTUMaster(serialPort, baudRate, QSerialPort::Parity::NoParity, 8, 1, this); - connect(modbus, &ModbusRTUMaster::connectionStateChanged, this, &IntegrationPluginDrexelUndWeiss::onConnectionStateChanged); - connect(modbus, &ModbusRTUMaster::receivedHoldingRegister, this, &IntegrationPluginDrexelUndWeiss::onReceivedHoldingRegister); + if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(modbusMasterUuid)) { + return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface not available.")); + } + ModbusRtuMaster *modbus = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(modbusMasterUuid); + if (!modbus->connected()) { + return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface is not connected.")); + } - m_modbusRTUMasters.insert(thing, modbus); - m_usedSerialPorts.append(serialPort); + ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, ModbusRegisterX2::Geraetetyp); + connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); + connect(reply, &ModbusRtuReply::finished, info, [reply, modbus, info, thing, this] { + if (reply->error() != ModbusRtuReply::Error::NoError) { + qCWarning(dcDrexelUndWeiss()) << "Setup failed, received modbus error" << reply->errorString(); + return info->finish(Thing::ThingErrorHardwareNotAvailable); + } + + if (reply->result().length() != 1) { + qCWarning(dcDrexelUndWeiss()) << "Setup failed, received reply has an illegal length"; + return info->finish(Thing::ThingErrorHardwareNotAvailable); + } + if (reply->result().first() != DeviceType::X2_LU) { + qCWarning(dcDrexelUndWeiss()) << "Device on slave addresss" << reply->slaveAddress() << "is not a X2 ventilation unit"; + return info->finish(Thing::ThingErrorHardwareNotAvailable); + } + + info->finish(Thing::ThingErrorNoError); + m_modbusRtuMasters.insert(thing, modbus); + }); + connect(modbus, &ModbusRtuMaster::connectedChanged, this, &IntegrationPluginDrexelUndWeiss::onConnectionStateChanged); info->finish(Thing::ThingErrorNoError); - return; - } else if (thing->thingClassId() == x2luThingClassId) { - info->finish(Thing::ThingErrorNoError); - return; + } else if (thing->thingClassId() == x2wpThingClassId) { + + QUuid modbusMasterUuid = thing->paramValue(x2wpThingModbusMasterUuidParamTypeId).toUuid(); + uint slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt(); + + if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(modbusMasterUuid)) { + return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface not available.")); + } + ModbusRtuMaster *modbus = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(modbusMasterUuid); + if (!modbus->connected()) { + return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface is not connected.")); + } + ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, ModbusRegisterX2::Geraetetyp); + connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); + connect(reply, &ModbusRtuReply::finished, info, [reply, modbus, info, thing, this] { + if (reply->error() != ModbusRtuReply::Error::NoError) { + qCWarning(dcDrexelUndWeiss()) << "Setup failed, received modbus error" << reply->errorString(); + return info->finish(Thing::ThingErrorHardwareNotAvailable); + } + + if (reply->result().length() != 1) { + qCWarning(dcDrexelUndWeiss()) << "Setup failed, received reply has an illegal length"; + return info->finish(Thing::ThingErrorHardwareNotAvailable); + } + if (reply->result().first() != DeviceType::X2_WP) { + qCWarning(dcDrexelUndWeiss()) << "Device on slave addresss" << reply->slaveAddress() << "is not a X2 heat pump"; + return info->finish(Thing::ThingErrorHardwareNotAvailable); + } + + info->finish(Thing::ThingErrorNoError); + m_modbusRtuMasters.insert(thing, modbus); + }); + connect(modbus, &ModbusRtuMaster::connectedChanged, this, &IntegrationPluginDrexelUndWeiss::onConnectionStateChanged); info->finish(Thing::ThingErrorNoError); - return; + } else { Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); } @@ -111,27 +153,21 @@ void IntegrationPluginDrexelUndWeiss::setupThing(ThingSetupInfo *info) void IntegrationPluginDrexelUndWeiss::postSetupThing(Thing *thing) { + qCDebug(dcDrexelUndWeiss()) << "Post setup thing" << thing->name(); if (!m_refreshTimer) { - // Refresh timer for TCP read + qCDebug(dcDrexelUndWeiss()) << "Creating refresh timer"; int refreshTime = configValue(drexelUndWeissPluginUpdateIntervalParamTypeId).toInt(); m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(refreshTime); connect(m_refreshTimer, &PluginTimer::timeout, this, &IntegrationPluginDrexelUndWeiss::onRefreshTimer); } - if (thing->thingClassId() == modbusConnectionThingClassId) { - // read Register 5000 and emit auto-Thing - ModbusRTUMaster *modbus = m_modbusRTUMasters.value(thing); - if (!modbus){ - qCWarning(dcDrexelUndWeiss()) << "No modbus master available"; - } - thing->setStateValue(modbusConnectionConnectedStateTypeId, true); - } else if ((thing->thingClassId() == x2luThingClassId) || (thing->thingClassId() == x2wpThingClassId)) { + if ((thing->thingClassId() == x2luThingClassId) || (thing->thingClassId() == x2wpThingClassId)) { Thing *parentThing = myThings().findById(thing->parentId()); if (!parentThing) { qCWarning(dcDrexelUndWeiss()) << "Could not find the parent Thing"; return; } - ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parentThing); + ModbusRtuMaster *modbus = m_modbusRtuMasters.value(parentThing); if (!modbus){ qCWarning(dcDrexelUndWeiss()) << "No modbus interface available"; } @@ -147,86 +183,40 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info) Thing *thing = info->thing(); Action action = info->action(); - if (thing->thingClassId() == modbusConnectionThingClassId) { + if (thing->thingClassId() == x2luThingClassId) { - ModbusRTUMaster *modbus = m_modbusRTUMasters.value(thing); - if (!modbus){ - qCWarning(dcDrexelUndWeiss()) << "No modbus interface available"; - info->finish(Thing::ThingErrorHardwareFailure); - return; - } - - if (action.actionTypeId() == modbusConnectionDiscoverDevicesActionTypeId) { - int slave = action.param(modbusConnectionDiscoverDevicesActionSlaveAddressParamTypeId).value().toInt(); - discoverModbusSlaves(modbus, slave); - info->finish(Thing::ThingErrorNoError); - return; - } else { - Q_ASSERT_X(false, "executeAction", QString("Unhandled ActionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); - } - - } else if (thing->thingClassId() == x2luThingClassId) { - Thing *parentThing = myThings().findById(thing->parentId()); - if (!parentThing) { - qWarning(dcDrexelUndWeiss()) << "Could not find the parent thing"; - info->finish(Thing::ThingErrorHardwareFailure); - return; - } - ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parentThing); - int slave = thing->paramValue(x2luThingSlaveAddressParamTypeId).toInt(); - if (!modbus){ - qCWarning(dcDrexelUndWeiss()) << "No modbus interface available"; - info->finish(Thing::ThingErrorHardwareFailure); - return; - } - - if (action.actionTypeId() == x2luVentilationModeActionTypeId) { - QString mode = action.param(x2luVentilationModeActionVentilationModeParamTypeId).value().toString(); - int data = 0; - - if (mode == "Manual level 0") { - data = VentialtionMode::ManuellStufe0; - } else if(mode == "Manual level 1") { - data = VentialtionMode::ManuellStufe1; - } else if(mode == "Manual level 2") { - data = VentialtionMode::ManuellStufe2; - }else if(mode == "Manual level 3") { - data = VentialtionMode::ManuellStufe3; - } else if(mode == "Automatic") { - data = VentialtionMode::Automatikbetrieb; - } else if(mode == "Party") { - data = VentialtionMode::Party; + uint slaveAddress = thing->paramValue(x2luThingSlaveAddressParamTypeId).toUInt(); + if (action.actionTypeId() == x2luPowerActionTypeId) { + bool power = action.paramValue(x2luPowerActionPowerParamTypeId).toBool(); + uint16_t data = 0; + if (power) { + data = getVentilationModeFromString(thing->stateValue(x2luVentilationModeStateTypeId).toString()); + } else { + data = VentilationMode::ManuellStufe0; } - m_pendingActions.insert(modbus->writeHoldingRegister(slave, ModbusRegisterX2::Betriebsart, data), info); - return; + sendWriteRequest(info, slaveAddress, ModbusRegisterX2::Betriebsart, data); + + } else if (action.actionTypeId() == x2luVentilationModeActionTypeId) { + QString mode = action.param(x2luVentilationModeActionVentilationModeParamTypeId).value().toString(); + uint16_t data = getVentilationModeFromString(mode); + sendWriteRequest(info, slaveAddress, ModbusRegisterX2::Betriebsart, data); + } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled ActionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } } else if (thing->thingClassId() == x2wpThingClassId) { - Thing *parentThing = myThings().findById(thing->parentId()); - if (!parentThing) { - qWarning(dcDrexelUndWeiss()) << "Could not find modbus interface"; - info->finish(Thing::ThingErrorHardwareFailure); - return; - } - ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parentThing); - int slave = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toInt(); - if (!modbus){ - qCWarning(dcDrexelUndWeiss()) << "No modbus master available"; - info->finish(Thing::ThingErrorHardwareFailure); - return; - } + uint slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt(); if (action.actionTypeId() == x2wpTargetTemperatureActionTypeId) { qreal targetTemp = (action.param(x2wpTargetTemperatureActionTargetTemperatureParamTypeId).value().toDouble()); - int data = static_cast(qRound(targetTemp * 1000)); - m_pendingActions.insert(modbus->writeHoldingRegister(slave,ModbusRegisterX2::RaumSoll, data), info); - return; + uint16_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; + sendWriteRequest(info, slaveAddress, ModbusRegisterX2::BrauchwasserSolltermperatur, data); + } else { Q_ASSERT_X(false, "executeAction", QString("Unhandled ActionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8()); } @@ -235,18 +225,40 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info) } } +void IntegrationPluginDrexelUndWeiss::sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint16_t value) +{ + ModbusRtuMaster *modbus = m_modbusRtuMasters.value(info->thing()); + + if (!modbus){ + qCWarning(dcDrexelUndWeiss()) << "Modbus RTU interface available"; + info->finish(Thing::ThingErrorHardwareFailure, tr("Modbus RTU interface not available.")); + return; + } + + if (!modbus->connected()) { + qCWarning(dcDrexelUndWeiss()) << "Modbus RTU interface not connected"; + info->finish(Thing::ThingErrorHardwareFailure, tr("Modbus RTU interface not connected.")); + return; + } + + ModbusRtuReply *reply = modbus->writeHoldingRegisters(slaveAddress, modbusRegister, QVector() << value); + connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); + connect(reply, &ModbusRtuReply::finished, info, [info, reply] { + + if (reply->error() != ModbusRtuReply::Error::NoError) { + return info->finish(Thing::ThingErrorHardwareFailure); + } + //TODO update thing state after successfull write requests + info->finish(Thing::ThingErrorNoError); + }); +} + void IntegrationPluginDrexelUndWeiss::thingRemoved(Thing *thing) { - if (thing->thingClassId() == modbusConnectionThingClassId) { - ModbusRTUMaster *modbus = m_modbusRTUMasters.take(thing); - if (!modbus){ - qCWarning(dcDrexelUndWeiss()) << "No modbus interface available"; - return; - } - m_usedSerialPorts.removeAll(modbus->serialPort()); - modbus->deleteLater(); + if (thing->thingClassId() == x2luThingClassId || thing->thingClassId() == x2luThingClassId) { + m_modbusRtuMasters.remove(thing); } if (myThings().isEmpty()) { @@ -258,15 +270,7 @@ void IntegrationPluginDrexelUndWeiss::thingRemoved(Thing *thing) void IntegrationPluginDrexelUndWeiss::onRefreshTimer() { foreach (Thing *thing, myThings()) { - - if (thing->thingClassId() == modbusConnectionThingClassId) { - ModbusRTUMaster *modbus = m_modbusRTUMasters.value(thing); - - if (!modbus) { - qCWarning(dcDrexelUndWeiss()) << "No modbus master available"; - return; - } - } else if (thing->thingClassId() == x2luThingClassId || thing->thingClassId() == x2wpThingClassId){ + if (thing->thingClassId() == x2luThingClassId || thing->thingClassId() == x2wpThingClassId){ updateStates(thing); } } @@ -275,38 +279,279 @@ void IntegrationPluginDrexelUndWeiss::onRefreshTimer() void IntegrationPluginDrexelUndWeiss::updateStates(Thing *thing) { if (thing->thingClassId() == x2luThingClassId) { - Thing *parent = myThings().findById(thing->parentId()); - ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parent); - int slave = thing->paramValue(x2luThingSlaveAddressParamTypeId).toInt(); + ModbusRtuMaster *modbus = m_modbusRtuMasters.value(thing); + if (!modbus) { + return; + } + uint slaveAddress = thing->paramValue(x2luThingSlaveAddressParamTypeId).toUInt(); - modbus->readHoldingRegister(slave, ModbusRegisterX2::AktiveLuefterstufe); - modbus->readHoldingRegister(slave, ModbusRegisterX2::Betriebsart); // Ventilation mode - modbus->readHoldingRegister(slave, ModbusRegisterX2::CO2); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::AktiveLuefterstufe); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Betriebsart); // Ventilation mode + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::CO2); } if (thing->thingClassId() == x2wpThingClassId) { - Thing *parent = myThings().findById(thing->parentId()); - ModbusRTUMaster *modbus = m_modbusRTUMasters.value(parent); - int slave = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toInt(); + ModbusRtuMaster *modbus = m_modbusRtuMasters.value(thing); + if (!modbus) { + return; + } + int slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt(); - modbus->readHoldingRegister(slave, ModbusRegisterX2::Waermepumpe); - modbus->readHoldingRegister(slave, ModbusRegisterX2::RaumSoll); - modbus->readHoldingRegister(slave, ModbusRegisterX2::Raum); - modbus->readHoldingRegister(slave, ModbusRegisterX2::TemperaturWarmwasserspeicherUnten); - modbus->readHoldingRegister(slave, ModbusRegisterX2::BrauchwasserSolltermperatur); - modbus->readHoldingRegister(slave, ModbusRegisterX2::Auszenluft); - modbus->readHoldingRegister(slave, ModbusRegisterX2::Summenstoerung); - modbus->readHoldingRegister(slave, ModbusRegisterX2::LeistungKompressor); - modbus->readHoldingRegister(slave, ModbusRegisterX2::LeistungWarmwasser); - modbus->readHoldingRegister(slave, ModbusRegisterX2::LeistungRaumheizung); - modbus->readHoldingRegister(slave, ModbusRegisterX2::LeistungLuftvorwaermung); - modbus->readHoldingRegister(slave, ModbusRegisterX2::EnergieKompressor); - modbus->readHoldingRegister(slave, ModbusRegisterX2::EnergieWarmwasser); - modbus->readHoldingRegister(slave, ModbusRegisterX2::EnergieRaumheizung); - modbus->readHoldingRegister(slave, ModbusRegisterX2::EnergieLuftvorerwarrmung); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Waermepumpe); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::RaumSoll); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Raum); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::TemperaturWarmwasserspeicherUnten); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::BrauchwasserSolltermperatur); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Auszenluft); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::Summenstoerung); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::LeistungKompressor); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::LeistungWarmwasser); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::LeistungRaumheizung); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::LeistungLuftvorwaermung); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::EnergieKompressor); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::EnergieWarmwasser); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::EnergieRaumheizung); + readHoldingRegister(thing, modbus, slaveAddress, ModbusRegisterX2::EnergieLuftvorerwarrmung); } } +void IntegrationPluginDrexelUndWeiss::readHoldingRegister(Thing *thing, ModbusRtuMaster *modbus, uint slaveAddress, uint modbusRegister) +{ + ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, modbusRegister); + connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); + connect(reply, &ModbusRtuReply::finished, this, [reply, thing, this] { + if (reply->error() != ModbusRtuReply::Error::NoError) { + qCWarning(dcDrexelUndWeiss()) << "Modbus error" << reply->errorString(); + thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), false); + return; + } + thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true); + QVector values = reply->result(); + + if (thing->thingClassId() == x2luThingClassId) { + switch (reply->registerAddress()) { + case ModbusRegisterX2::Waermepumpe: + thing->setStateValue(x2wpPowerStateTypeId, values[0]); + break; + + case ModbusRegisterX2::RaumSoll: + thing->setStateValue(x2wpTargetTemperatureStateTypeId, values[0]/1000.00); + break; + + case ModbusRegisterX2::Raum: + thing->setStateValue(x2wpTemperatureStateTypeId, values[0]/1000.00); + break; + + case ModbusRegisterX2::TemperaturWarmwasserspeicherUnten: + thing->setStateValue(x2wpWaterTemperatureStateTypeId, values[0]/1000.00); + break; + case ModbusRegisterX2::BrauchwasserSolltermperatur: + thing->setStateValue(x2wpTargetWaterTemperatureStateTypeId, values[0]/1000.00); + break; + case ModbusRegisterX2::Auszenluft: + thing->setStateValue(x2wpOutsideAirTemperatureStateTypeId, values[0]/1000.00); + break; + + case ModbusRegisterX2::Summenstoerung: + if (values[0] != 0) { + //get actual error + } else { + thing->setStateValue(x2wpErrorStateTypeId, "No Error"); + } + break; + + case ModbusRegisterX2::StoerungAbluftventilator: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Exhaust fan"); + break; + + case ModbusRegisterX2::StoerungBoilerfuehlerElektroheizstab: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor electric heating element"); + break; + + case ModbusRegisterX2::StoerungBoilerfuehlerSolar: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor solar"); + break; + + case ModbusRegisterX2::StoerungBoilerfuehlerWaermepumpe: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor heat pump"); + break; + + case ModbusRegisterX2::StoerungBoileruebertemperatur: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Boiler overtemperature"); + break; + + case ModbusRegisterX2::StoerungCO2Sensor: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "CO2-Sensor"); + break; + + case ModbusRegisterX2::StoerungDruckverlustAbluftZuGrosz: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Pressure loss exhaust air too big"); + break; + + case ModbusRegisterX2::StoerungDruckverlustZuluftZuGrosz: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Pressure loss supply air too large"); + break; + + case ModbusRegisterX2::StoerungDurchflussmengeHeizgkreis: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Flow rate of heating circuit"); + break; + + case ModbusRegisterX2::StoerungDurchflussmengeSolekreis: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Flow rate brine circuit"); + break; + + case ModbusRegisterX2::StoerungTeilnehmerNichtErreichbar: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Participant not available"); + break; + + case ModbusRegisterX2::StoerungTemperaturfuehlerAuszenluft: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor outside air"); + break; + + case ModbusRegisterX2::StoerungTemperaturfuehlerHeizkreisVorlauf: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor heating circuit flow"); + break; + + case ModbusRegisterX2::StoerungTemperaturfuehlerRaum: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor room"); + break; + + case ModbusRegisterX2::StoerungTemperaturfuehlerSolarkollektor: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor solar collector"); + break; + + case ModbusRegisterX2::StoerungTemperaturfuehlerSole: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor brine"); + break; + + case ModbusRegisterX2::StoerungTemperaturfuehlerSoleAuszenluft: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor brine outside air"); + break; + + case ModbusRegisterX2::StoerungWaermepumpeHochdruck: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Heat pump high pressure"); + break; + + case ModbusRegisterX2::StoerungWaermepumpeNiederdruck: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Heat pump low pressure"); + break; + + case ModbusRegisterX2::StoerungWertNichtZulaessig: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Value not allowed"); + break; + + case ModbusRegisterX2::StoerungZuluftventilator: + if (values[0] != 0) + thing->setStateValue(x2wpErrorStateTypeId, "Supply air fan"); + break; + + case ModbusRegisterX2::LeistungKompressor: + thing->setStateValue(x2wpPowerCompressorStateTypeId, values[0]/1000.00); + break; + case ModbusRegisterX2::LeistungWarmwasser: + thing->setStateValue(x2wpPowerWaterHeatingStateTypeId, values[0]/1000.00); + break; + + case ModbusRegisterX2::LeistungRaumheizung: + thing->setStateValue(x2wpPowerRoomHeatingStateTypeId, values[0]/1000.00); + break; + + case ModbusRegisterX2::LeistungLuftvorwaermung: + thing->setStateValue(x2wpPowerAirPreheatingStateTypeId, values[0]/1000.00); + break; + + case ModbusRegisterX2::EnergieKompressor: + thing->setStateValue(x2wpEnergyCompressorStateTypeId, values[0]/1000.00); + break; + + case ModbusRegisterX2::EnergieWarmwasser: + thing->setStateValue(x2wpEnergyWaterHeatingStateTypeId, values[0]/1000.00); + break; + + case ModbusRegisterX2::EnergieRaumheizung: + thing->setStateValue(x2wpEnergyRoomHeatingStateTypeId, values[0]/1000.00); + break; + + case ModbusRegisterX2::EnergieLuftvorerwarrmung: + thing->setStateValue(x2wpEnergyAirPreheatingStateTypeId, values[0]/1000.00); + break; + default: + break; + } + } else if (thing->thingClassId() == x2wpThingClassId) { + + switch (reply->registerAddress()) { + case ModbusRegisterX2::Betriebsart: + if (values[0] == VentilationMode::ManuellStufe0) { + thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 0"); + } else if (values[0] == VentilationMode::ManuellStufe1) { + thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 1"); + } else if (values[0] == VentilationMode::ManuellStufe2) { + thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 2"); + } else if (values[0] == VentilationMode::ManuellStufe3) { + thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 3"); + } else if (values[0] == VentilationMode::Automatikbetrieb) { + thing->setStateValue(x2luVentilationModeStateTypeId, "Automatic"); + } else if (values[0] == VentilationMode::Party) { + thing->setStateValue(x2luVentilationModeStateTypeId, "Party"); + } + if (values[0] == VentilationMode::ManuellStufe0) { + thing->setStateValue(x2luPowerStateTypeId, false); + } else { + thing->setStateValue(x2luPowerStateTypeId, true); + } + break; + case ModbusRegisterX2::AktiveLuefterstufe: + thing->setStateValue(x2luActiveVentilationLevelStateTypeId, values[0]); + break; + case ModbusRegisterX2::CO2: + thing->setStateValue(x2luCo2StateTypeId, values[0]); + break; + } + } + }); +} + +VentilationMode IntegrationPluginDrexelUndWeiss::getVentilationModeFromString(const QString &modeString) +{ + if (modeString == "Manual level 0") { + return VentilationMode::ManuellStufe0; + } else if(modeString == "Manual level 1") { + return VentilationMode::ManuellStufe1; + } else if(modeString == "Manual level 2") { + return VentilationMode::ManuellStufe2; + }else if(modeString == "Manual level 3") { + return VentilationMode::ManuellStufe3; + } else if(modeString == "Automatic") { + return VentilationMode::Automatikbetrieb; + } else if(modeString == "Party") { + return VentilationMode::Party; + } else { + qCWarning(dcDrexelUndWeiss()) << "Unknown ventilation mode string" << modeString; + } + return VentilationMode::ManuellStufe0; +} + void IntegrationPluginDrexelUndWeiss::onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value) { @@ -322,318 +567,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..f68ceaa 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 "modbusdegisterdefinition.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,21 @@ 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; + void sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint16_t value); void updateStates(Thing *thing); - void discoverModbusSlaves(ModbusRTUMaster *modbus, int slaveAddress); + void discoverModbusSlaves(ModbusRtuMaster *modbus, uint slaveAddress); + void readHoldingRegister(Thing *thing, ModbusRtuMaster *modbus, uint slaveAddress, uint modbusRegister); + + VentilationMode getVentilationModeFromString(const QString &modeString); private slots: void onRefreshTimer(); void onPluginConfigurationChanged(const ParamTypeId ¶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..8454854 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"], + "createMethods": ["discovery"], "interfaces": ["thermostat", "heating", "temperaturesensor", "connectable"], + "discoveryParamTypes": [ + { + "id": "d4923c90-22c8-477e-a37a-341858e59dcb", + "name": "slaveAddress", + "displayName": "Slave address", + "type": "int", + "defaultValue": 1 + } + ], "paramTypes": [ { "id": "b551d138-b006-4290-bfef-97072ff677c6", "name": "slaveAddress", "displayName": "Slave address", - "type": "int", + "type": "uint", "minValue": 0, "maxValue": 250, "defaultValue": 0 }, { - "id": "1ffd72a9-7b3f-4287-b671-7f22e159f9b8", - "name": "sofwareVersion", - "displayName": "Software version", - "type": "QString", - "inputType": "TextLine", - "defaultValue": "-" + "id": "db8358f3-f573-44e3-b024-c4613ee3a270", + "name": "modbusMasterUuid", + "displayName": "Modbus RTU master", + "type": "QUuid", + "defaultValue": "" } ], "stateTypes":[ diff --git a/drexelundweiss/modbusdegisterdefinition.h b/drexelundweiss/modbusdegisterdefinition.h index 534583b..eac63af 100644 --- a/drexelundweiss/modbusdegisterdefinition.h +++ b/drexelundweiss/modbusdegisterdefinition.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..efef0f1 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,42 @@ The name of the StateType ({baf203be-a391-4bfc-8198-53b4ecbcce80}) of ThingClass ---------- The name of the ParamType (ThingClass: x2lu, EventType: connected, ID: {b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) ---------- -The name of the StateType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu ----------- -The name of the ParamType (ThingClass: modbusConnection, EventType: connected, ID: {181ce6e2-9c55-45c6-b329-adf379679e07}) ----------- -The name of the StateType ({181ce6e2-9c55-45c6-b329-adf379679e07}) of ThingClass modbusConnection +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. + 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..029501e 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,41 @@ The name of the StateType ({baf203be-a391-4bfc-8198-53b4ecbcce80}) of ThingClass ---------- The name of the ParamType (ThingClass: x2lu, EventType: connected, ID: {b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) ---------- -The name of the StateType ({b4c4726f-d3d7-46e8-badb-0d590e7f5fac}) of ThingClass x2lu ----------- -The name of the ParamType (ThingClass: modbusConnection, EventType: connected, ID: {181ce6e2-9c55-45c6-b329-adf379679e07}) ----------- -The name of the StateType ({181ce6e2-9c55-45c6-b329-adf379679e07}) of ThingClass modbusConnection +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. 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 From 33816b02e2f6838820744eb17c2ed051d161d9d1 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Sun, 9 May 2021 23:34:19 +0200 Subject: [PATCH 02/26] implemented the modbus RTU discovery --- .../integrationplugindrexelundweiss.cpp | 154 +++++++++--------- .../integrationplugindrexelundweiss.h | 3 + 2 files changed, 80 insertions(+), 77 deletions(-) diff --git a/drexelundweiss/integrationplugindrexelundweiss.cpp b/drexelundweiss/integrationplugindrexelundweiss.cpp index 19932af..806699a 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.cpp +++ b/drexelundweiss/integrationplugindrexelundweiss.cpp @@ -39,6 +39,15 @@ IntegrationPluginDrexelUndWeiss::IntegrationPluginDrexelUndWeiss() { m_connectedStateTypeIds.insert(x2luThingClassId, x2luConnectedStateTypeId); m_connectedStateTypeIds.insert(x2wpThingClassId, x2wpConnectedStateTypeId); + + m_discoverySlaveAddressParamTypeIds.insert(x2luThingClassId, x2luDiscoverySlaveAddressParamTypeId); + m_discoverySlaveAddressParamTypeIds.insert(x2wpThingClassId, x2wpDiscoverySlaveAddressParamTypeId); + + m_slaveIdParamTypeIds.insert(x2luThingClassId, x2luThingSlaveAddressParamTypeId); + m_slaveIdParamTypeIds.insert(x2wpThingClassId, x2wpThingSlaveAddressParamTypeId); + + m_modbusUuidParamTypeIds.insert(x2luThingClassId, x2luThingModbusMasterUuidParamTypeId); + m_modbusUuidParamTypeIds.insert(x2wpThingClassId, x2wpThingModbusMasterUuidParamTypeId); } void IntegrationPluginDrexelUndWeiss::init() @@ -61,13 +70,38 @@ void IntegrationPluginDrexelUndWeiss::init() void IntegrationPluginDrexelUndWeiss::discoverThings(ThingDiscoveryInfo *info) { - if (info->thingClassId() == x2luThingClassId || info->thingClassId() == x2wpThingClassId) { - QList thingDescriptors; - info->finish(Thing::ThingErrorNoError); + qCDebug(dcDrexelUndWeiss()) << "Discover things"; + + if (hardwareManager()->modbusRtuResource()->modbusRtuMasters().isEmpty()) { + info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("No Modbus RTU interface available.")); 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) @@ -75,80 +109,46 @@ void IntegrationPluginDrexelUndWeiss::setupThing(ThingSetupInfo *info) Thing *thing = info->thing(); qCDebug(dcDrexelUndWeiss()) << "Setup thing" << thing->name(); - if (thing->thingClassId() == x2luThingClassId) { - - QUuid modbusMasterUuid = thing->paramValue(x2luThingModbusMasterUuidParamTypeId).toUuid(); - uint slaveAddress = thing->paramValue(x2luThingSlaveAddressParamTypeId).toUInt(); - - if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(modbusMasterUuid)) { - return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface not available.")); - } - ModbusRtuMaster *modbus = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(modbusMasterUuid); - if (!modbus->connected()) { - return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface is not connected.")); - } - - ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, ModbusRegisterX2::Geraetetyp); - connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); - connect(reply, &ModbusRtuReply::finished, info, [reply, modbus, info, thing, this] { - if (reply->error() != ModbusRtuReply::Error::NoError) { - qCWarning(dcDrexelUndWeiss()) << "Setup failed, received modbus error" << reply->errorString(); - return info->finish(Thing::ThingErrorHardwareNotAvailable); - } - - if (reply->result().length() != 1) { - qCWarning(dcDrexelUndWeiss()) << "Setup failed, received reply has an illegal length"; - return info->finish(Thing::ThingErrorHardwareNotAvailable); - } - if (reply->result().first() != DeviceType::X2_LU) { - qCWarning(dcDrexelUndWeiss()) << "Device on slave addresss" << reply->slaveAddress() << "is not a X2 ventilation unit"; - return info->finish(Thing::ThingErrorHardwareNotAvailable); - } - - info->finish(Thing::ThingErrorNoError); - m_modbusRtuMasters.insert(thing, modbus); - }); - connect(modbus, &ModbusRtuMaster::connectedChanged, this, &IntegrationPluginDrexelUndWeiss::onConnectionStateChanged); - info->finish(Thing::ThingErrorNoError); - - } else if (thing->thingClassId() == x2wpThingClassId) { - - QUuid modbusMasterUuid = thing->paramValue(x2wpThingModbusMasterUuidParamTypeId).toUuid(); - uint slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt(); - - if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(modbusMasterUuid)) { - return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface not available.")); - } - ModbusRtuMaster *modbus = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(modbusMasterUuid); - if (!modbus->connected()) { - return info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Modbus RTU interface is not connected.")); - } - ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, ModbusRegisterX2::Geraetetyp); - connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); - connect(reply, &ModbusRtuReply::finished, info, [reply, modbus, info, thing, this] { - if (reply->error() != ModbusRtuReply::Error::NoError) { - qCWarning(dcDrexelUndWeiss()) << "Setup failed, received modbus error" << reply->errorString(); - return info->finish(Thing::ThingErrorHardwareNotAvailable); - } - - if (reply->result().length() != 1) { - qCWarning(dcDrexelUndWeiss()) << "Setup failed, received reply has an illegal length"; - return info->finish(Thing::ThingErrorHardwareNotAvailable); - } - if (reply->result().first() != DeviceType::X2_WP) { - qCWarning(dcDrexelUndWeiss()) << "Device on slave addresss" << reply->slaveAddress() << "is not a X2 heat pump"; - return info->finish(Thing::ThingErrorHardwareNotAvailable); - } - - info->finish(Thing::ThingErrorNoError); - m_modbusRtuMasters.insert(thing, modbus); - }); - connect(modbus, &ModbusRtuMaster::connectedChanged, this, &IntegrationPluginDrexelUndWeiss::onConnectionStateChanged); - info->finish(Thing::ThingErrorNoError); - - } 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); + connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); + connect(reply, &ModbusRtuReply::finished, info, [reply, modbus, info, thing, this] { + if (reply->error() != ModbusRtuReply::Error::NoError) { + qCWarning(dcDrexelUndWeiss()) << "Setup failed, received modbus error" << reply->errorString(); + return info->finish(Thing::ThingErrorHardwareNotAvailable); + } + + if (reply->result().length() != 1) { + qCWarning(dcDrexelUndWeiss()) << "Setup failed, received reply has an illegal length"; + return info->finish(Thing::ThingErrorHardwareNotAvailable); + } + if (thing->thingClassId() == x2luThingClassId && reply->result().first() == DeviceType::X2_LU) { + info->finish(Thing::ThingErrorNoError); + m_modbusRtuMasters.insert(thing, modbus); + } else if (thing->thingClassId() == x2wpThingClassId && reply->result().first() == DeviceType::X2_WP) { + info->finish(Thing::ThingErrorNoError); + m_modbusRtuMasters.insert(thing, modbus); + } else { + qCWarning(dcDrexelUndWeiss()) << "Device on slave addresss" << reply->slaveAddress() << "is not the wanted one."; + return info->finish(Thing::ThingErrorHardwareNotAvailable); + } + + }); + connect(modbus, &ModbusRtuMaster::connectedChanged, this, &IntegrationPluginDrexelUndWeiss::onConnectionStateChanged); } void IntegrationPluginDrexelUndWeiss::postSetupThing(Thing *thing) diff --git a/drexelundweiss/integrationplugindrexelundweiss.h b/drexelundweiss/integrationplugindrexelundweiss.h index f68ceaa..5cc6001 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.h +++ b/drexelundweiss/integrationplugindrexelundweiss.h @@ -60,6 +60,9 @@ private: PluginTimer *m_refreshTimer = nullptr; QHash m_connectedStateTypeIds; + QHash m_discoverySlaveAddressParamTypeIds; + QHash m_slaveIdParamTypeIds; + QHash m_modbusUuidParamTypeIds; void sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint16_t value); void updateStates(Thing *thing); void discoverModbusSlaves(ModbusRtuMaster *modbus, uint slaveAddress); From 6bfcefcc349b2d17b4f6c53228ae9fb7c49ec96e Mon Sep 17 00:00:00 2001 From: Boernsman Date: Mon, 10 May 2021 01:03:09 +0200 Subject: [PATCH 03/26] fixed thingSetup device type check --- drexelundweiss/README.md | 6 +++- .../integrationplugindrexelundweiss.cpp | 30 +++++++++++-------- ...68d78ce6-82d0-4a5b-b901-7c3b843ef63c-de.ts | 20 +++++++++++++ ...78ce6-82d0-4a5b-b901-7c3b843ef63c-en_US.ts | 20 +++++++++++++ 4 files changed, 62 insertions(+), 14 deletions(-) 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/integrationplugindrexelundweiss.cpp b/drexelundweiss/integrationplugindrexelundweiss.cpp index 806699a..249346c 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.cpp +++ b/drexelundweiss/integrationplugindrexelundweiss.cpp @@ -124,26 +124,29 @@ void IntegrationPluginDrexelUndWeiss::setupThing(ThingSetupInfo *info) return info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("Modbus RTU interface is not connected.")); } - ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, ModbusRegisterX2::Geraetetyp); + 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() != 1) { + 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().first() == DeviceType::X2_LU) { + 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().first() == DeviceType::X2_WP) { + } 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 addresss" << reply->slaveAddress() << "is not the wanted one."; + qCWarning(dcDrexelUndWeiss()) << "Device on slave address" << reply->slaveAddress() << "is not the wanted one."; return info->finish(Thing::ThingErrorHardwareNotAvailable); } @@ -172,7 +175,6 @@ void IntegrationPluginDrexelUndWeiss::postSetupThing(Thing *thing) 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()); } @@ -256,12 +258,14 @@ void IntegrationPluginDrexelUndWeiss::sendWriteRequest(ThingActionInfo *info, ui void IntegrationPluginDrexelUndWeiss::thingRemoved(Thing *thing) { + qCDebug(dcDrexelUndWeiss()) << "Thing removed" << thing->name(); if (thing->thingClassId() == x2luThingClassId || thing->thingClassId() == x2luThingClassId) { m_modbusRtuMasters.remove(thing); } if (myThings().isEmpty()) { + qCDebug(dcDrexelUndWeiss()) << "Stopping refresh timer"; hardwareManager()->pluginTimerManager()->unregisterTimer(m_refreshTimer); m_refreshTimer = nullptr; } @@ -317,7 +321,7 @@ void IntegrationPluginDrexelUndWeiss::updateStates(Thing *thing) void IntegrationPluginDrexelUndWeiss::readHoldingRegister(Thing *thing, ModbusRtuMaster *modbus, uint slaveAddress, uint modbusRegister) { - ModbusRtuReply *reply = modbus->readHoldingRegister(slaveAddress, 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) { @@ -331,25 +335,25 @@ void IntegrationPluginDrexelUndWeiss::readHoldingRegister(Thing *thing, ModbusRt if (thing->thingClassId() == x2luThingClassId) { switch (reply->registerAddress()) { case ModbusRegisterX2::Waermepumpe: - thing->setStateValue(x2wpPowerStateTypeId, values[0]); + thing->setStateValue(x2wpPowerStateTypeId, values[1]); break; case ModbusRegisterX2::RaumSoll: - thing->setStateValue(x2wpTargetTemperatureStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpTargetTemperatureStateTypeId, (static_cast(values[0])<<16 | values[1])/1000.00); break; case ModbusRegisterX2::Raum: - thing->setStateValue(x2wpTemperatureStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpTemperatureStateTypeId, (static_cast(values[0])<<16 | values[1])/1000.00); break; case ModbusRegisterX2::TemperaturWarmwasserspeicherUnten: - thing->setStateValue(x2wpWaterTemperatureStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpWaterTemperatureStateTypeId, (static_cast(values[0])<<16 | values[1])/1000.00); break; case ModbusRegisterX2::BrauchwasserSolltermperatur: - thing->setStateValue(x2wpTargetWaterTemperatureStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpTargetWaterTemperatureStateTypeId, (static_cast(values[0])<<16 | values[1])/1000.00); break; case ModbusRegisterX2::Auszenluft: - thing->setStateValue(x2wpOutsideAirTemperatureStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpOutsideAirTemperatureStateTypeId, (static_cast(values[0])<<16 | values[1])/1000.00); break; case ModbusRegisterX2::Summenstoerung: diff --git a/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-de.ts b/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-de.ts index efef0f1..58d34f0 100644 --- a/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-de.ts +++ b/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-de.ts @@ -345,5 +345,25 @@ The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {d25197d1-b1b9-45a 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 029501e..9abdbb6 100644 --- a/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-en_US.ts +++ b/drexelundweiss/translations/68d78ce6-82d0-4a5b-b901-7c3b843ef63c-en_US.ts @@ -345,5 +345,25 @@ The name of the ParamType (ThingClass: x2lu, Type: thing, ID: {d25197d1-b1b9-45a 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 + + From 616cd85554fa7fd1255ae5d94e3fc1af12d4bbe9 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Mon, 10 May 2021 01:19:56 +0200 Subject: [PATCH 04/26] fixed register to double conversion --- .../integrationplugindrexelundweiss.cpp | 107 ++++++++++-------- 1 file changed, 57 insertions(+), 50 deletions(-) diff --git a/drexelundweiss/integrationplugindrexelundweiss.cpp b/drexelundweiss/integrationplugindrexelundweiss.cpp index 249346c..56b85d0 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.cpp +++ b/drexelundweiss/integrationplugindrexelundweiss.cpp @@ -245,12 +245,16 @@ void IntegrationPluginDrexelUndWeiss::sendWriteRequest(ThingActionInfo *info, ui ModbusRtuReply *reply = modbus->writeHoldingRegisters(slaveAddress, modbusRegister, QVector() << value); connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); - connect(reply, &ModbusRtuReply::finished, info, [info, reply] { + connect(reply, &ModbusRtuReply::finished, info, [info, reply, this] { + + if (info->isFinished()) { + return; + } if (reply->error() != ModbusRtuReply::Error::NoError) { return info->finish(Thing::ThingErrorHardwareFailure); } - //TODO update thing state after successfull write requests + updateStates(info->thing()); info->finish(Thing::ThingErrorNoError); }); } @@ -330,34 +334,37 @@ void IntegrationPluginDrexelUndWeiss::readHoldingRegister(Thing *thing, ModbusRt return; } thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true); - QVector values = reply->result(); + if (reply->result().length() != 2) { + return; + } + uint32_t value = (static_cast(reply->result()[0])<<16 | reply->result()[1]); - if (thing->thingClassId() == x2luThingClassId) { + if (thing->thingClassId() == x2wpThingClassId) { switch (reply->registerAddress()) { case ModbusRegisterX2::Waermepumpe: - thing->setStateValue(x2wpPowerStateTypeId, values[1]); + thing->setStateValue(x2wpPowerStateTypeId, value); break; case ModbusRegisterX2::RaumSoll: - thing->setStateValue(x2wpTargetTemperatureStateTypeId, (static_cast(values[0])<<16 | values[1])/1000.00); + thing->setStateValue(x2wpTargetTemperatureStateTypeId, value/1000.00); break; case ModbusRegisterX2::Raum: - thing->setStateValue(x2wpTemperatureStateTypeId, (static_cast(values[0])<<16 | values[1])/1000.00); + thing->setStateValue(x2wpTemperatureStateTypeId, value/1000.00); break; case ModbusRegisterX2::TemperaturWarmwasserspeicherUnten: - thing->setStateValue(x2wpWaterTemperatureStateTypeId, (static_cast(values[0])<<16 | values[1])/1000.00); + thing->setStateValue(x2wpWaterTemperatureStateTypeId, value/1000.00); break; case ModbusRegisterX2::BrauchwasserSolltermperatur: - thing->setStateValue(x2wpTargetWaterTemperatureStateTypeId, (static_cast(values[0])<<16 | values[1])/1000.00); + thing->setStateValue(x2wpTargetWaterTemperatureStateTypeId, value/1000.00); break; case ModbusRegisterX2::Auszenluft: - thing->setStateValue(x2wpOutsideAirTemperatureStateTypeId, (static_cast(values[0])<<16 | values[1])/1000.00); + thing->setStateValue(x2wpOutsideAirTemperatureStateTypeId, value/1000.00); break; case ModbusRegisterX2::Summenstoerung: - if (values[0] != 0) { + if (value != 0) { //get actual error } else { thing->setStateValue(x2wpErrorStateTypeId, "No Error"); @@ -365,171 +372,171 @@ void IntegrationPluginDrexelUndWeiss::readHoldingRegister(Thing *thing, ModbusRt break; case ModbusRegisterX2::StoerungAbluftventilator: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Exhaust fan"); break; case ModbusRegisterX2::StoerungBoilerfuehlerElektroheizstab: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor electric heating element"); break; case ModbusRegisterX2::StoerungBoilerfuehlerSolar: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor solar"); break; case ModbusRegisterX2::StoerungBoilerfuehlerWaermepumpe: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Boiler sensor heat pump"); break; case ModbusRegisterX2::StoerungBoileruebertemperatur: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Boiler overtemperature"); break; case ModbusRegisterX2::StoerungCO2Sensor: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "CO2-Sensor"); break; case ModbusRegisterX2::StoerungDruckverlustAbluftZuGrosz: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Pressure loss exhaust air too big"); break; case ModbusRegisterX2::StoerungDruckverlustZuluftZuGrosz: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Pressure loss supply air too large"); break; case ModbusRegisterX2::StoerungDurchflussmengeHeizgkreis: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Flow rate of heating circuit"); break; case ModbusRegisterX2::StoerungDurchflussmengeSolekreis: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Flow rate brine circuit"); break; case ModbusRegisterX2::StoerungTeilnehmerNichtErreichbar: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Participant not available"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerAuszenluft: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor outside air"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerHeizkreisVorlauf: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor heating circuit flow"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerRaum: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor room"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerSolarkollektor: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor solar collector"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerSole: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor brine"); break; case ModbusRegisterX2::StoerungTemperaturfuehlerSoleAuszenluft: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Temperature sensor brine outside air"); break; case ModbusRegisterX2::StoerungWaermepumpeHochdruck: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Heat pump high pressure"); break; case ModbusRegisterX2::StoerungWaermepumpeNiederdruck: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Heat pump low pressure"); break; case ModbusRegisterX2::StoerungWertNichtZulaessig: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Value not allowed"); break; case ModbusRegisterX2::StoerungZuluftventilator: - if (values[0] != 0) + if (value != 0) thing->setStateValue(x2wpErrorStateTypeId, "Supply air fan"); break; case ModbusRegisterX2::LeistungKompressor: - thing->setStateValue(x2wpPowerCompressorStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpPowerCompressorStateTypeId, value/1000.00); break; case ModbusRegisterX2::LeistungWarmwasser: - thing->setStateValue(x2wpPowerWaterHeatingStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpPowerWaterHeatingStateTypeId, value/1000.00); break; case ModbusRegisterX2::LeistungRaumheizung: - thing->setStateValue(x2wpPowerRoomHeatingStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpPowerRoomHeatingStateTypeId, value/1000.00); break; case ModbusRegisterX2::LeistungLuftvorwaermung: - thing->setStateValue(x2wpPowerAirPreheatingStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpPowerAirPreheatingStateTypeId, value/1000.00); break; case ModbusRegisterX2::EnergieKompressor: - thing->setStateValue(x2wpEnergyCompressorStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpEnergyCompressorStateTypeId, value/1000.00); break; case ModbusRegisterX2::EnergieWarmwasser: - thing->setStateValue(x2wpEnergyWaterHeatingStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpEnergyWaterHeatingStateTypeId, value/1000.00); break; case ModbusRegisterX2::EnergieRaumheizung: - thing->setStateValue(x2wpEnergyRoomHeatingStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpEnergyRoomHeatingStateTypeId, value/1000.00); break; case ModbusRegisterX2::EnergieLuftvorerwarrmung: - thing->setStateValue(x2wpEnergyAirPreheatingStateTypeId, values[0]/1000.00); + thing->setStateValue(x2wpEnergyAirPreheatingStateTypeId, value/1000.00); break; default: break; } - } else if (thing->thingClassId() == x2wpThingClassId) { + } else if (thing->thingClassId() == x2luThingClassId) { switch (reply->registerAddress()) { case ModbusRegisterX2::Betriebsart: - if (values[0] == VentilationMode::ManuellStufe0) { + if (value == VentilationMode::ManuellStufe0) { thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 0"); - } else if (values[0] == VentilationMode::ManuellStufe1) { + } else if (value == VentilationMode::ManuellStufe1) { thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 1"); - } else if (values[0] == VentilationMode::ManuellStufe2) { + } else if (value == VentilationMode::ManuellStufe2) { thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 2"); - } else if (values[0] == VentilationMode::ManuellStufe3) { + } else if (value == VentilationMode::ManuellStufe3) { thing->setStateValue(x2luVentilationModeStateTypeId, "Manual level 3"); - } else if (values[0] == VentilationMode::Automatikbetrieb) { + } else if (value == VentilationMode::Automatikbetrieb) { thing->setStateValue(x2luVentilationModeStateTypeId, "Automatic"); - } else if (values[0] == VentilationMode::Party) { + } else if (value == VentilationMode::Party) { thing->setStateValue(x2luVentilationModeStateTypeId, "Party"); } - if (values[0] == VentilationMode::ManuellStufe0) { + if (value == VentilationMode::ManuellStufe0) { thing->setStateValue(x2luPowerStateTypeId, false); } else { thing->setStateValue(x2luPowerStateTypeId, true); } break; case ModbusRegisterX2::AktiveLuefterstufe: - thing->setStateValue(x2luActiveVentilationLevelStateTypeId, values[0]); + thing->setStateValue(x2luActiveVentilationLevelStateTypeId, value); break; case ModbusRegisterX2::CO2: - thing->setStateValue(x2luCo2StateTypeId, values[0]); + thing->setStateValue(x2luCo2StateTypeId, value); break; } } From 46d85092a6377cbc4a319bb195ed716334b28c80 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Mon, 10 May 2021 01:36:59 +0200 Subject: [PATCH 05/26] changed write requests to uint32 --- .../integrationplugindrexelundweiss.cpp | 32 +++++++++++++------ .../integrationplugindrexelundweiss.h | 2 +- .../integrationplugindrexelundweiss.json | 2 +- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drexelundweiss/integrationplugindrexelundweiss.cpp b/drexelundweiss/integrationplugindrexelundweiss.cpp index 56b85d0..3e11fac 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.cpp +++ b/drexelundweiss/integrationplugindrexelundweiss.cpp @@ -190,7 +190,7 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info) uint slaveAddress = thing->paramValue(x2luThingSlaveAddressParamTypeId).toUInt(); if (action.actionTypeId() == x2luPowerActionTypeId) { bool power = action.paramValue(x2luPowerActionPowerParamTypeId).toBool(); - uint16_t data = 0; + uint32_t data = 0; if (power) { data = getVentilationModeFromString(thing->stateValue(x2luVentilationModeStateTypeId).toString()); } else { @@ -200,7 +200,7 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info) } else if (action.actionTypeId() == x2luVentilationModeActionTypeId) { QString mode = action.param(x2luVentilationModeActionVentilationModeParamTypeId).value().toString(); - uint16_t data = getVentilationModeFromString(mode); + uint32_t data = getVentilationModeFromString(mode); sendWriteRequest(info, slaveAddress, ModbusRegisterX2::Betriebsart, data); } else { @@ -209,14 +209,25 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info) } else if (thing->thingClassId() == x2wpThingClassId) { uint slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt(); - if (action.actionTypeId() == x2wpTargetTemperatureActionTypeId) { - qreal targetTemp = (action.param(x2wpTargetTemperatureActionTargetTemperatureParamTypeId).value().toDouble()); - uint16_t data = static_cast(qRound(targetTemp * 1000)); + if (action.actionTypeId() == x2wpPowerActionTypeId) { + bool power = action.paramValue(x2wpPowerActionPowerParamTypeId).toBool(); + uint32_t data = 0; + if (power) { + double targetTemp = thing->stateValue(x2wpTargetTemperatureActionTargetTemperatureParamTypeId).toDouble(); + data = static_cast(qRound(targetTemp * 1000)); + } else { + data = 18 * 1000; //set to min temperature + } + sendWriteRequest(info, slaveAddress, ModbusRegisterX2::RaumSoll, data); + + } else if (action.actionTypeId() == x2wpTargetTemperatureActionTypeId) { + double targetTemp = (action.param(x2wpTargetTemperatureActionTargetTemperatureParamTypeId).value().toDouble()); + uint32_t data = static_cast(qRound(targetTemp * 1000)); sendWriteRequest(info, slaveAddress, ModbusRegisterX2::RaumSoll, data); } else if (action.actionTypeId() == x2wpTargetWaterTemperatureActionTypeId) { - qreal targetWaterTemp = action.param(x2wpTargetWaterTemperatureActionTargetWaterTemperatureParamTypeId).value().toDouble(); - int data = static_cast(qRound(targetWaterTemp * 1000)); + double targetWaterTemp = action.param(x2wpTargetWaterTemperatureActionTargetWaterTemperatureParamTypeId).value().toDouble(); + uint32_t data = static_cast(qRound(targetWaterTemp * 1000)); sendWriteRequest(info, slaveAddress, ModbusRegisterX2::BrauchwasserSolltermperatur, data); } else { @@ -227,7 +238,7 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info) } } -void IntegrationPluginDrexelUndWeiss::sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint16_t value) +void IntegrationPluginDrexelUndWeiss::sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint32_t value) { ModbusRtuMaster *modbus = m_modbusRtuMasters.value(info->thing()); @@ -243,7 +254,10 @@ void IntegrationPluginDrexelUndWeiss::sendWriteRequest(ThingActionInfo *info, ui return; } - ModbusRtuReply *reply = modbus->writeHoldingRegisters(slaveAddress, modbusRegister, QVector() << value); + QVector values; + values.append(static_cast(value>>16)); + values.append(static_cast(value&0xff)); + ModbusRtuReply *reply = modbus->writeHoldingRegisters(slaveAddress, modbusRegister, values); connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); connect(reply, &ModbusRtuReply::finished, info, [info, reply, this] { diff --git a/drexelundweiss/integrationplugindrexelundweiss.h b/drexelundweiss/integrationplugindrexelundweiss.h index 5cc6001..3167e8e 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.h +++ b/drexelundweiss/integrationplugindrexelundweiss.h @@ -63,7 +63,7 @@ private: QHash m_discoverySlaveAddressParamTypeIds; QHash m_slaveIdParamTypeIds; QHash m_modbusUuidParamTypeIds; - void sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint16_t value); + void sendWriteRequest(ThingActionInfo *info, uint slaveAddress, uint modbusRegister, uint32_t value); void updateStates(Thing *thing); void discoverModbusSlaves(ModbusRtuMaster *modbus, uint slaveAddress); void readHoldingRegister(Thing *thing, ModbusRtuMaster *modbus, uint slaveAddress, uint modbusRegister); diff --git a/drexelundweiss/integrationplugindrexelundweiss.json b/drexelundweiss/integrationplugindrexelundweiss.json index 8454854..43e4161 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.json +++ b/drexelundweiss/integrationplugindrexelundweiss.json @@ -157,7 +157,7 @@ "displayNameEvent": "Power changed", "displayNameAction": "Change power", "type": "bool", - "defaultValue": 0, + "defaultValue": false, "writable": true }, { From 2c4d6d0191a10d84486f32dc06d1dbb6938a4904 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Tue, 11 May 2021 05:48:17 +0200 Subject: [PATCH 06/26] fixed ventilation unit power action --- drexelundweiss/integrationplugindrexelundweiss.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drexelundweiss/integrationplugindrexelundweiss.cpp b/drexelundweiss/integrationplugindrexelundweiss.cpp index 3e11fac..4ce0f39 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.cpp +++ b/drexelundweiss/integrationplugindrexelundweiss.cpp @@ -192,7 +192,7 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info) bool power = action.paramValue(x2luPowerActionPowerParamTypeId).toBool(); uint32_t data = 0; if (power) { - data = getVentilationModeFromString(thing->stateValue(x2luVentilationModeStateTypeId).toString()); + data = VentilationMode::Automatikbetrieb; } else { data = VentilationMode::ManuellStufe0; } From 88c3d5df0d00e495f4e3e53985ea12612fe60e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 12 May 2021 08:21:19 +0200 Subject: [PATCH 07/26] Rename modbus register header file --- drexelundweiss/drexelundweiss.pro | 2 +- drexelundweiss/integrationplugindrexelundweiss.h | 2 +- .../{modbusdegisterdefinition.h => modbusregisterdefinition.h} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename drexelundweiss/{modbusdegisterdefinition.h => modbusregisterdefinition.h} (100%) diff --git a/drexelundweiss/drexelundweiss.pro b/drexelundweiss/drexelundweiss.pro index 925e659..dab6785 100644 --- a/drexelundweiss/drexelundweiss.pro +++ b/drexelundweiss/drexelundweiss.pro @@ -9,4 +9,4 @@ SOURCES += \ HEADERS += \ integrationplugindrexelundweiss.h \ - modbusdegisterdefinition.h + modbusregisterdefinition.h diff --git a/drexelundweiss/integrationplugindrexelundweiss.h b/drexelundweiss/integrationplugindrexelundweiss.h index 3167e8e..12235eb 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.h +++ b/drexelundweiss/integrationplugindrexelundweiss.h @@ -34,7 +34,7 @@ #include "integrations/integrationplugin.h" #include "hardware/modbus/modbusrtumaster.h" #include "plugintimer.h" -#include "modbusdegisterdefinition.h" +#include "modbusregisterdefinition.h" #include diff --git a/drexelundweiss/modbusdegisterdefinition.h b/drexelundweiss/modbusregisterdefinition.h similarity index 100% rename from drexelundweiss/modbusdegisterdefinition.h rename to drexelundweiss/modbusregisterdefinition.h From 53e0c175bdb7fc2374e8a11cfa48ab4d90d5946c Mon Sep 17 00:00:00 2001 From: Boernsman Date: Tue, 25 May 2021 20:54:53 +0200 Subject: [PATCH 08/26] removed heating interface --- .../integrationplugindrexelundweiss.cpp | 15 ++------------- .../integrationplugindrexelundweiss.json | 6 ++---- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/drexelundweiss/integrationplugindrexelundweiss.cpp b/drexelundweiss/integrationplugindrexelundweiss.cpp index 4ce0f39..95758ef 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.cpp +++ b/drexelundweiss/integrationplugindrexelundweiss.cpp @@ -209,18 +209,7 @@ void IntegrationPluginDrexelUndWeiss::executeAction(ThingActionInfo *info) } else if (thing->thingClassId() == x2wpThingClassId) { uint slaveAddress = thing->paramValue(x2wpThingSlaveAddressParamTypeId).toUInt(); - if (action.actionTypeId() == x2wpPowerActionTypeId) { - bool power = action.paramValue(x2wpPowerActionPowerParamTypeId).toBool(); - uint32_t data = 0; - if (power) { - double targetTemp = thing->stateValue(x2wpTargetTemperatureActionTargetTemperatureParamTypeId).toDouble(); - data = static_cast(qRound(targetTemp * 1000)); - } else { - data = 18 * 1000; //set to min temperature - } - sendWriteRequest(info, slaveAddress, ModbusRegisterX2::RaumSoll, data); - - } else if (action.actionTypeId() == x2wpTargetTemperatureActionTypeId) { + if (action.actionTypeId() == x2wpTargetTemperatureActionTypeId) { double targetTemp = (action.param(x2wpTargetTemperatureActionTargetTemperatureParamTypeId).value().toDouble()); uint32_t data = static_cast(qRound(targetTemp * 1000)); sendWriteRequest(info, slaveAddress, ModbusRegisterX2::RaumSoll, data); @@ -381,7 +370,7 @@ void IntegrationPluginDrexelUndWeiss::readHoldingRegister(Thing *thing, ModbusRt if (value != 0) { //get actual error } else { - thing->setStateValue(x2wpErrorStateTypeId, "No Error"); + thing->setStateValue(x2wpErrorStateTypeId, "No error"); } break; diff --git a/drexelundweiss/integrationplugindrexelundweiss.json b/drexelundweiss/integrationplugindrexelundweiss.json index 43e4161..88528e2 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.json +++ b/drexelundweiss/integrationplugindrexelundweiss.json @@ -112,7 +112,7 @@ "displayName": "X2 WP", "id": "e548f962-92db-4110-8279-10fbcde35f93", "createMethods": ["discovery"], - "interfaces": ["thermostat", "heating", "temperaturesensor", "connectable"], + "interfaces": ["thermostat", "connectable"], "discoveryParamTypes": [ { "id": "d4923c90-22c8-477e-a37a-341858e59dcb", @@ -155,10 +155,8 @@ "name": "power", "displayName": "Power", "displayNameEvent": "Power changed", - "displayNameAction": "Change power", "type": "bool", - "defaultValue": false, - "writable": true + "defaultValue": false }, { "id": "3ab2d609-1686-4fd7-84e3-580c8e0537d0", From 0a7b9836506df3d3e3b2e1d6615d33b47ba3592d Mon Sep 17 00:00:00 2001 From: Boernsman Date: Tue, 25 May 2021 22:15:08 +0200 Subject: [PATCH 09/26] fixed target temperature action --- drexelundweiss/integrationplugindrexelundweiss.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drexelundweiss/integrationplugindrexelundweiss.cpp b/drexelundweiss/integrationplugindrexelundweiss.cpp index 95758ef..493a8e0 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.cpp +++ b/drexelundweiss/integrationplugindrexelundweiss.cpp @@ -245,7 +245,7 @@ void IntegrationPluginDrexelUndWeiss::sendWriteRequest(ThingActionInfo *info, ui QVector values; values.append(static_cast(value>>16)); - values.append(static_cast(value&0xff)); + 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] { From 9027579cda5145f3161338a82bf1ce89620715e0 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Tue, 20 Apr 2021 20:39:58 +0200 Subject: [PATCH 10/26] added energy meters intergration plugin --- debian/control | 17 + debian/nymea-plugin-energymeters.install.in | 1 + energymeters/README.md | 9 + energymeters/bg-etechmodbusregister.h | 59 ++++ energymeters/energymeter.cpp | 148 +++++++++ energymeters/energymeter.h | 81 +++++ energymeters/energymeters.pro | 16 + energymeters/inepromodbusregister.h | 45 +++ .../integrationpluginenergymeters.cpp | 291 ++++++++++++++++++ energymeters/integrationpluginenergymeters.h | 89 ++++++ .../integrationpluginenergymeters.json | 244 +++++++++++++++ energymeters/meta.json | 0 energymeters/registerdescriptor.h | 83 +++++ nymea-plugins-modbus.pro | 1 + 14 files changed, 1084 insertions(+) create mode 100644 debian/nymea-plugin-energymeters.install.in create mode 100644 energymeters/README.md create mode 100644 energymeters/bg-etechmodbusregister.h create mode 100644 energymeters/energymeter.cpp create mode 100644 energymeters/energymeter.h create mode 100644 energymeters/energymeters.pro create mode 100644 energymeters/inepromodbusregister.h create mode 100644 energymeters/integrationpluginenergymeters.cpp create mode 100644 energymeters/integrationpluginenergymeters.h create mode 100644 energymeters/integrationpluginenergymeters.json create mode 100644 energymeters/meta.json create mode 100644 energymeters/registerdescriptor.h 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/energymeters/README.md b/energymeters/README.md new file mode 100644 index 0000000..b8b1fb8 --- /dev/null +++ b/energymeters/README.md @@ -0,0 +1,9 @@ +# B+G e-tech + +## Supported Things + + +## Requirements + + +## More diff --git a/energymeters/bg-etechmodbusregister.h b/energymeters/bg-etechmodbusregister.h new file mode 100644 index 0000000..368c5eb --- /dev/null +++ b/energymeters/bg-etechmodbusregister.h @@ -0,0 +1,59 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 BGETECHMODBUSREGISTER_H +#define BGETECHMODBUSREGISTER_H + +#include "registerdescriptor.h" + +class BgEtechModbusRegisers +{ + +private: + BgEtechModbusRegisers() {} + static void init () { + m_registerMap.insert(ModbusRegisterType::Voltage, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); + /* m_registerMap.insert(ModbusRegisterType::Current, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); + m_registerMap.insert(ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); + m_registerMap.insert(ModbusRegisterType::Frequency, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); + m_registerMap.insert(ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); + m_registerMap.insert(ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); + m_registerMap.insert(ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(1, 3, 2, "V", "float"));*/ + } +protected: + static QHash m_registerMap; +public: + static QHash map() + { BgEtechModbusRegisers(); + init(); + return m_registerMap;} +}; + +#endif // BGETECHMODBUSREGISTER_H diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp new file mode 100644 index 0000000..65c6f63 --- /dev/null +++ b/energymeters/energymeter.cpp @@ -0,0 +1,148 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 "energymeter.h" +#include "hardware/modbus/modbusrtureply.h" + +EnergyMeter::EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const QHash &modbusRegisters, QObject *parent) : + QObject(parent), + m_modbusRtuMaster(modbusMaster), + m_slaveAddress(slaveAddress), + m_modbusRegisters(modbusRegisters) +{ + +} + +bool EnergyMeter::init() +{ + return true; +} + +bool EnergyMeter::connected() +{ + return m_connected; +} + +bool EnergyMeter::getVoltage() +{ + if (!m_modbusRegisters.contains(ModbusRegisterType::Voltage)) + return false; + + ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::Voltage); + getRegister(ModbusRegisterType::Voltage, descriptor); + return true; +} + +bool EnergyMeter::getCurrent() +{ + if (!m_modbusRegisters.contains(ModbusRegisterType::Current)) + return false; + + ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::Current); + getRegister(ModbusRegisterType::Current, descriptor); + return true; +} + +bool EnergyMeter::getFrequency() +{ + if (!m_modbusRegisters.contains(ModbusRegisterType::Frequency)) + return false; + + ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::Frequency); + getRegister(ModbusRegisterType::Frequency, descriptor); + return true; +} + +bool EnergyMeter::getPowerFactor() +{ + if (!m_modbusRegisters.contains(ModbusRegisterType::PowerFactor)) + return false; + + ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::PowerFactor); + getRegister(ModbusRegisterType::PowerFactor, descriptor); + return true; +} + +bool EnergyMeter::getActivePower() +{ + if (!m_modbusRegisters.contains(ModbusRegisterType::ActivePower)) + return false; + + ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::ActivePower); + getRegister(ModbusRegisterType::ActivePower, descriptor); + return true; +} + +bool EnergyMeter::getEnergyProduced() +{ + if (!m_modbusRegisters.contains(ModbusRegisterType::EnergyProduced)) + return false; + + ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::EnergyProduced); + getRegister(ModbusRegisterType::EnergyProduced, descriptor); + return true; +} + +bool EnergyMeter::getEnergyConsumed() +{ + if (!m_modbusRegisters.contains(ModbusRegisterType::EnergyConsumed)) + return false; + + ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::EnergyConsumed); + getRegister(ModbusRegisterType::EnergyConsumed, descriptor); + return true; +} + +void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor descriptor) +{ + + ModbusRtuReply *reply; + if (descriptor.functionCode() == 1){ + + } else if (descriptor.functionCode() == 2){ + + } else if (descriptor.functionCode() == 3){ + reply = m_modbusRtuMaster->readHoldingRegister(m_slaveAddress, descriptor.address(), descriptor.length()); + } else if (descriptor.functionCode() == 4){ + } + connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); + connect(reply, &ModbusRtuReply::finished, this, [reply, type, this] { + if (reply->error() != ModbusRtuReply::NoError) { + return; + } + double value = 0; + if (reply->result().length() == 2) { + value = static_cast(reply->result().at(0) << 16 | reply->result().at(1)); + } + + emit valueReceived(type, value); + }); +} + diff --git a/energymeters/energymeter.h b/energymeters/energymeter.h new file mode 100644 index 0000000..d5e4fe9 --- /dev/null +++ b/energymeters/energymeter.h @@ -0,0 +1,81 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 ENERGYMETER_H +#define ENERGYMETER_H + +#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); + bool init(); + + bool connected(); + bool getVoltage(); + bool getCurrent(); + bool getFrequency(); + bool getPowerFactor(); + bool getActivePower(); + bool getEnergyProduced(); + bool getEnergyConsumed(); + +private: + bool m_connected = false; + + ModbusRtuMaster *m_modbusRtuMaster = nullptr; + int m_slaveAddress; + + QHash m_modbusRegisters; + + void getRegister(ModbusRegisterType type, ModbusRegisterDescriptor descriptor); + +signals: + void connectedChanged(bool connected); + void valueReceived(ModbusRegisterType type, double value); + + void voltageReceived(double voltage); + void currentReceived(double current); + void frequencyReceived(double freqeuncy); + void activePowerReceived(double power); + void powerFactorReceived(double powerFactor); + void producedEnergyReceived(double energy); + void consumedEnergyReceived(double energy); + +//private slot: +// void onRegisterReceived(); +}; + +#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..370a4ed --- /dev/null +++ b/energymeters/inepromodbusregister.h @@ -0,0 +1,45 @@ +#ifndef INEPROMODBUSREGISTER_H +#define INEPROMODBUSREGISTER_H + +enum InputRegisters { + Phase1ToNeutralVolts = 1, + Phase2ToNeutralVolts = 3, + Phase3ToNeutralVolts = 5, + Phase1Current = 7, + Phase2Current = 9, + Phase3Current = 11, + Phase1Power = 13, + Phase2Power = 15, + Phase3Power = 17, + Phase1ApparentPower = 19, + Phase2ApparentPower = 21, + Phase3ApparentPower = 23, + Phase1ReactivePower = 25, + Phase2ReactivePower = 27, + Phase3ReactivePower = 29, + Phase1PowerFactor = 31, + Phase2PowerFactor = 33, + Phase3PowerFactor = 35, + Phase1Angle = 37, + Phase2Angle = 39, + Phase3Angle = 41, + Frequency = 71, + ImportActiveEnergy = 73, + ExportActiveEnergy = 75, + ImportReactiveEnergy = 77, + ExportReactiveEnergy = 79, + TotalActiveEnergy = 343, + TotalReactiveEnergy = 345 +}; + +enum HoldingRegisters { + RelayPulseWidth = 13, + NetworkParityStop = 19, + NetworkPortNode = 21, + NetworkBaudRate = 29, + Pulse1Output = 87, + Pulse1Constant = 63761, + MeasurementMode = 63776 +}; + +#endif // BGETECHMODBUSREGISTER_H diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp new file mode 100644 index 0000000..e7b5743 --- /dev/null +++ b/energymeters/integrationpluginenergymeters.cpp @@ -0,0 +1,291 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 "integrationpluginenergymeters.h" +#include "plugininfo.h" + +#include "bg-etechmodbusregister.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_voltageStateTypeIds.insert(pro380ThingClassId, pro380VoltageStateTypeId); + m_voltageStateTypeIds.insert(sdm630ThingClassId, sdm630VoltageStateTypeId); + + m_currentStateTypeIds.insert(pro380ThingClassId, pro380CurrentStateTypeId); + m_currentStateTypeIds.insert(sdm630ThingClassId, sdm630CurrentStateTypeId); + + 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_discoverySlaveAddressParamTypeIds.insert(pro380ThingClassId, pro380DiscoverySlaveAddressParamTypeId); + m_discoverySlaveAddressParamTypeIds.insert(sdm630ThingClassId, sdm630DiscoverySlaveAddressParamTypeId); + + // Modbus RTU hardware resource + connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=](const QUuid &modbusUuid){ + qCDebug(dcEnergyMeters()) << "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(dcEnergyMeters()) << "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_connectionStateTypeIds[thing->thingClassId()], false); + + // Set all child things disconnected + foreach (Thing *childThing, myThings()) { + if (childThing->parentId() == thing->id()) { + thing->setStateValue(m_connectionStateTypeIds[childThing->thingClassId()], false); + } + } + } + } + }); +} + +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())) { + int slaveAddress = info->params().paramValue(m_discoverySlaveAddressParamTypeIds.value(info->thingClassId())).toInt(); + if (slaveAddress > 254 || slaveAddress == 0) { + info->finish(Thing::ThingErrorInvalidParameter, tr("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(), "Modbus interface "+modbusMaster->serialPort(), modbusMaster->modbusUuid().toString()); + 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; + } else { + Q_ASSERT_X(false, "discoverThings", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8()); + } +} + +void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) +{ + Thing *thing = info->thing(); + qCDebug(dcEnergyMeters()) << "Setup thing" << thing->name(); + + if (m_connectionStateTypeIds.contains(thing->thingClassId())) { + + if (m_energyMeters.contains(thing)) { + qCDebug(dcEnergyMeters()) << "Setup after rediscovery, cleaning up ..."; + m_energyMeters.take(thing)->deleteLater(); + } + int address = thing->paramValue(m_slaveIdParamTypeIds.value(thing->thingClassId())).toInt(); + 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())).toString(); + 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, BgEtechModbusRegisers::map(), this); + connect(info, &ThingSetupInfo::aborted, meter, &EnergyMeter::deleteLater); + connect(meter, &EnergyMeter::consumedEnergyReceived, info, [this, info, meter] { + qCDebug(dcEnergyMeters()) << "Reply received, setup finished"; + connect(meter, &EnergyMeter::connectedChanged, this, &IntegrationPluginEnergyMeters::onConnectionStateChanged); + connect(meter, &EnergyMeter::voltageReceived, this, &IntegrationPluginEnergyMeters::onVoltageReceived); + connect(meter, &EnergyMeter::currentReceived, this, &IntegrationPluginEnergyMeters::onCurrentReceived); + connect(meter, &EnergyMeter::activePowerReceived, this, &IntegrationPluginEnergyMeters::onActivePowerReceived); + connect(meter, &EnergyMeter::powerFactorReceived, this, &IntegrationPluginEnergyMeters::onPowerFactorReceived); + connect(meter, &EnergyMeter::frequencyReceived, this, &IntegrationPluginEnergyMeters::onActivePowerReceived); + connect(meter, &EnergyMeter::producedEnergyReceived, this, &IntegrationPluginEnergyMeters::onProducedEnergyReceived); + connect(meter, &EnergyMeter::consumedEnergyReceived, this, &IntegrationPluginEnergyMeters::onConsumedEnergyReceived); + + m_energyMeters.insert(info->thing(), meter); + info->finish(Thing::ThingErrorNoError); + }); + return; + } else { + Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); + } +} + +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_updateTimer) { + qCDebug(dcEnergyMeters()) << "Creating update timer"; + m_updateTimer = new QTimer(this); + m_updateTimer->start(configValue(energyMetersPluginUpdateIntervalParamTypeId).toInt()); + connect(m_updateTimer, &QTimer::timeout, this, [this] { + foreach (EnergyMeter *meter, m_energyMeters) { + meter->getVoltage(); + } + }); + connect(this, &IntegrationPlugin::configValueChanged, [this] (const ParamTypeId ¶mTypeId, const QVariant value) { + if (m_updateTimer && (paramTypeId == energyMetersPluginUpdateIntervalParamTypeId)) { + qCDebug(dcEnergyMeters()) << "Updating update interval to" << value; + m_updateTimer->setInterval(value.toInt()); + } + }); + } +} + +void IntegrationPluginEnergyMeters::thingRemoved(Thing *thing) +{ + qCDebug(dcEnergyMeters()) << "Thing removed" << thing->name(); + + if (m_energyMeters.contains(thing)) { + m_energyMeters.take(thing)->deleteLater(); + } + + if (myThings().isEmpty() && !m_updateTimer) { + qCDebug(dcEnergyMeters()) << "Deleting update timer"; + m_updateTimer->deleteLater(); + m_updateTimer = nullptr; + } +} + +void IntegrationPluginEnergyMeters::onConnectionStateChanged(bool status) +{ + EnergyMeter *meter = static_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), status); +} + +void IntegrationPluginEnergyMeters::onVoltageReceived(double voltage) +{ + EnergyMeter *meter = static_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + thing->setStateValue(m_voltageStateTypeIds.value(thing->thingClassId()), voltage); +} + +void IntegrationPluginEnergyMeters::onCurrentReceived(double current) +{ + EnergyMeter *meter = static_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + thing->setStateValue(m_currentStateTypeIds.value(thing->thingClassId()), current); +} + +void IntegrationPluginEnergyMeters::onActivePowerReceived(double power) +{ + EnergyMeter *meter = static_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + thing->setStateValue(m_activePowerStateTypeIds.value(thing->thingClassId()), power); +} + +void IntegrationPluginEnergyMeters::onFrequencyReceived(double frequency) +{ + EnergyMeter *meter = static_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + thing->setStateValue(m_frequencyStateTypeIds.value(thing->thingClassId()), frequency); +} + +void IntegrationPluginEnergyMeters::onPowerFactorReceived(double powerFactor) +{ + EnergyMeter *meter = static_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + thing->setStateValue(m_powerFactorStateTypeIds.value(thing->thingClassId()), powerFactor); +} + +void IntegrationPluginEnergyMeters::onProducedEnergyReceived(double energy) +{ + EnergyMeter *meter = static_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + thing->setStateValue(m_totalEnergyProducedStateTypeIds.value(thing->thingClassId()), energy); +} + +void IntegrationPluginEnergyMeters::onConsumedEnergyReceived(double energy) +{ + EnergyMeter *meter = static_cast(sender()); + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; + + thing->setStateValue(m_totalEnergyConsumedStateTypeIds.value(thing->thingClassId()), energy); +} diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h new file mode 100644 index 0000000..9dfbf10 --- /dev/null +++ b/energymeters/integrationpluginenergymeters.h @@ -0,0 +1,89 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 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 discoverThings(ThingDiscoveryInfo *info) override; + void setupThing(ThingSetupInfo *info) override; + void postSetupThing(Thing *thing) override; + void thingRemoved(Thing *thing) override; + +private: + QTimer *m_updateTimer = nullptr; + QHash m_connectionStateTypeIds; + QHash m_voltageStateTypeIds; + QHash m_currentStateTypeIds; + 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_energyMeters; + QHash m_modbusRtuMasters; + PluginTimer *m_pluginTimer = nullptr; + QHash m_asyncActions; + +private slots: + void onConnectionStateChanged(bool status); + void onVoltageReceived(double voltage); + void onCurrentReceived(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..56016eb --- /dev/null +++ b/energymeters/integrationpluginenergymeters.json @@ -0,0 +1,244 @@ +{ + "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"], + "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": "int", + "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": "voltage", + "displayName": "Voltage", + "displayNameEvent": "Voltage changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "1e077a3b-2dab-4ec4-ae96-ab49a564fe31", + "name": "current", + "displayName": "Current", + "displayNameEvent": "Current 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"], + "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": "int", + "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": "4636ec5c-fcb9-45b7-ad68-2818cb615ce1", + "name": "voltage", + "displayName": "Voltage", + "displayNameEvent": "Voltage changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "96bc65ce-5bde-4a69-9ebf-711d65c6501c", + "name": "current", + "displayName": "Current", + "displayNameEvent": "Current 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..e69de29 diff --git a/energymeters/registerdescriptor.h b/energymeters/registerdescriptor.h new file mode 100644 index 0000000..5e53807 --- /dev/null +++ b/energymeters/registerdescriptor.h @@ -0,0 +1,83 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 REGISTERDESCRIPTOR_H +#define REGISTERDESCRIPTOR_H + +#include +#include + +enum ModbusRegisterType { + Voltage, + Current, + 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/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 \ From 9b413b185a17ace24b9d42deeb747318549da509 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Wed, 21 Apr 2021 18:41:35 +0200 Subject: [PATCH 11/26] added modbus maps and add value received signals --- energymeters/bg-etechmodbusregister.h | 29 ++----- energymeters/energymeter.cpp | 54 ++++++++++--- energymeters/energymeter.h | 1 - energymeters/inepromodbusregister.h | 80 +++++++++---------- .../integrationpluginenergymeters.cpp | 6 +- energymeters/integrationpluginenergymeters.h | 2 + 6 files changed, 100 insertions(+), 72 deletions(-) diff --git a/energymeters/bg-etechmodbusregister.h b/energymeters/bg-etechmodbusregister.h index 368c5eb..deffe6b 100644 --- a/energymeters/bg-etechmodbusregister.h +++ b/energymeters/bg-etechmodbusregister.h @@ -33,27 +33,14 @@ #include "registerdescriptor.h" -class BgEtechModbusRegisers -{ - -private: - BgEtechModbusRegisers() {} - static void init () { - m_registerMap.insert(ModbusRegisterType::Voltage, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); - /* m_registerMap.insert(ModbusRegisterType::Current, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); - m_registerMap.insert(ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); - m_registerMap.insert(ModbusRegisterType::Frequency, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); - m_registerMap.insert(ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); - m_registerMap.insert(ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(1, 3, 2, "V", "float")); - m_registerMap.insert(ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(1, 3, 2, "V", "float"));*/ - } -protected: - static QHash m_registerMap; -public: - static QHash map() - { BgEtechModbusRegisers(); - init(); - return m_registerMap;} +static const QHash sdm630RegisterMap { + {ModbusRegisterType::Voltage, ModbusRegisterDescriptor(30043, 4, 2, "V", "float")}, //Average line to neutral volts + {ModbusRegisterType::Current, ModbusRegisterDescriptor(30047, 4, 2, "A", "float")}, //Average line current + {ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(30053, 4, 2, "W", "float")}, //Total system power + {ModbusRegisterType::Frequency, ModbusRegisterDescriptor(30071, 4, 2, "Hz", "float")}, + {ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(30067, 4, 2, "Degree", "float")}, //Total system phase angle + {ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(30073, 4, 2, "kWh", "float")}, //Total Import kWh + {ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(30075, 4, 2, "kWh", "float")} //Total Export kWh }; #endif // BGETECHMODBUSREGISTER_H diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp index 65c6f63..8083f49 100644 --- a/energymeters/energymeter.cpp +++ b/energymeters/energymeter.cpp @@ -31,6 +31,8 @@ #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), @@ -123,26 +125,60 @@ bool EnergyMeter::getEnergyConsumed() void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor descriptor) { - ModbusRtuReply *reply; - if (descriptor.functionCode() == 1){ - - } else if (descriptor.functionCode() == 2){ - - } else if (descriptor.functionCode() == 3){ + 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, this] { + connect(reply, &ModbusRtuReply::finished, this, [reply, type, descriptor, this] { if (reply->error() != ModbusRtuReply::NoError) { return; } double value = 0; - if (reply->result().length() == 2) { + if (reply->result().length() == 1) { + value = static_cast(reply->result().at(0)); + } else if (reply->result().length() == 2) { + if (descriptor.dataType() == "float") { value = static_cast(reply->result().at(0) << 16 | reply->result().at(1)); + } else { + qCWarning(dcEnergyMeters()) << "Data type not supported" << descriptor.dataType(); + } } - emit valueReceived(type, value); + if (type == ModbusRegisterType::Voltage) { + if (descriptor.unit() == "mV") + value /= 1000; + + emit voltageReceived(value); + } else if (type == ModbusRegisterType::Current) { + if (descriptor.unit() == "mA") + value /= 1000; + + emit currentReceived(value); + } else if (type == ModbusRegisterType::ActivePower) { + if (descriptor.unit() == "kW") { + value *= 1000; + } else if (descriptor.unit() == "mW") { + value /= 1000; + } + emit activePowerReceived(value); + } else if (type == ModbusRegisterType::PowerFactor) { + emit powerFactorReceived(value); + } else if (type == ModbusRegisterType::Frequency) { + emit frequencyReceived(value); + } else if (type == ModbusRegisterType::EnergyConsumed) { + if (descriptor.unit() == "Wh") { + value /= 1000; + } + emit consumedEnergyReceived(value); + } else if (type == ModbusRegisterType::EnergyProduced) { + if (descriptor.unit() == "Wh") { + value /= 1000; + } + emit producedEnergyReceived(value); + } }); } diff --git a/energymeters/energymeter.h b/energymeters/energymeter.h index d5e4fe9..1773d5d 100644 --- a/energymeters/energymeter.h +++ b/energymeters/energymeter.h @@ -64,7 +64,6 @@ private: signals: void connectedChanged(bool connected); - void valueReceived(ModbusRegisterType type, double value); void voltageReceived(double voltage); void currentReceived(double current); diff --git a/energymeters/inepromodbusregister.h b/energymeters/inepromodbusregister.h index 370a4ed..b4e23eb 100644 --- a/energymeters/inepromodbusregister.h +++ b/energymeters/inepromodbusregister.h @@ -1,45 +1,45 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* 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 INEPROMODBUSREGISTER_H #define INEPROMODBUSREGISTER_H +#include "registerdescriptor.h" -enum InputRegisters { - Phase1ToNeutralVolts = 1, - Phase2ToNeutralVolts = 3, - Phase3ToNeutralVolts = 5, - Phase1Current = 7, - Phase2Current = 9, - Phase3Current = 11, - Phase1Power = 13, - Phase2Power = 15, - Phase3Power = 17, - Phase1ApparentPower = 19, - Phase2ApparentPower = 21, - Phase3ApparentPower = 23, - Phase1ReactivePower = 25, - Phase2ReactivePower = 27, - Phase3ReactivePower = 29, - Phase1PowerFactor = 31, - Phase2PowerFactor = 33, - Phase3PowerFactor = 35, - Phase1Angle = 37, - Phase2Angle = 39, - Phase3Angle = 41, - Frequency = 71, - ImportActiveEnergy = 73, - ExportActiveEnergy = 75, - ImportReactiveEnergy = 77, - ExportReactiveEnergy = 79, - TotalActiveEnergy = 343, - TotalReactiveEnergy = 345 +static const QHash pro380RegisterMap { + {ModbusRegisterType::Voltage, ModbusRegisterDescriptor(20482, 3, 2, "V", "float")}, //L1 Voltage + {ModbusRegisterType::Current, ModbusRegisterDescriptor(20492, 3, 2, "A", "float")}, //L1 Current + {ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(20498, 3, 2, "kW", "float")}, //Total active power + {ModbusRegisterType::Frequency, ModbusRegisterDescriptor(20488, 3, 2, "Hz", "float")}, + {ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(20522, 3, 2, "Degree", "float")}, + {ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(24588, 3, 2, "kWh", "float")}, //Forward active energy + {ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(24600, 3, 2, "kWh", "float")} //Reverse active energy }; -enum HoldingRegisters { - RelayPulseWidth = 13, - NetworkParityStop = 19, - NetworkPortNode = 21, - NetworkBaudRate = 29, - Pulse1Output = 87, - Pulse1Constant = 63761, - MeasurementMode = 63776 -}; - -#endif // BGETECHMODBUSREGISTER_H +#endif //INEPROMODBUSREGISTER_H diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index e7b5743..2dd79a4 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -32,6 +32,7 @@ #include "plugininfo.h" #include "bg-etechmodbusregister.h" +#include "inepromodbusregister.h" IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() { @@ -67,6 +68,9 @@ IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() m_discoverySlaveAddressParamTypeIds.insert(pro380ThingClassId, pro380DiscoverySlaveAddressParamTypeId); m_discoverySlaveAddressParamTypeIds.insert(sdm630ThingClassId, sdm630DiscoverySlaveAddressParamTypeId); + m_registerMaps.insert(pro380ThingClassId, &pro380RegisterMap); + m_registerMaps.insert(sdm630ThingClassId, &sdm630RegisterMap); + // Modbus RTU hardware resource connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=](const QUuid &modbusUuid){ qCDebug(dcEnergyMeters()) << "Modbus RTU master has been removed" << modbusUuid.toString(); @@ -148,7 +152,7 @@ void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) return; } - EnergyMeter *meter = new EnergyMeter(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), address, BgEtechModbusRegisers::map(), this); + 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] { qCDebug(dcEnergyMeters()) << "Reply received, setup finished"; diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h index 9dfbf10..8f9dc91 100644 --- a/energymeters/integrationpluginenergymeters.h +++ b/energymeters/integrationpluginenergymeters.h @@ -70,6 +70,8 @@ private: QHash m_slaveIdParamTypeIds; QHash m_modbusUuidParamTypeIds; + QHash *> m_registerMaps; + QHash m_energyMeters; QHash m_modbusRtuMasters; PluginTimer *m_pluginTimer = nullptr; From ce9a98b91ef88ae32b067b56c91cb34993f0c931 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Wed, 21 Apr 2021 18:49:07 +0200 Subject: [PATCH 12/26] added translation --- ...56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts | 285 ++++++++++++++++++ ...95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts | 285 ++++++++++++++++++ 2 files changed, 570 insertions(+) create mode 100644 energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts create mode 100644 energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts 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..11c88e3 --- /dev/null +++ b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts @@ -0,0 +1,285 @@ + + + + + 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 + The name of the ParamType (ThingClass: sdm630, EventType: current, ID: {96bc65ce-5bde-4a69-9ebf-711d65c6501c}) +---------- +The name of the StateType ({96bc65ce-5bde-4a69-9ebf-711d65c6501c}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: current, ID: {1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) +---------- +The name of the StateType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) of ThingClass pro380 + Strom + + + + + Current changed + The name of the EventType ({96bc65ce-5bde-4a69-9ebf-711d65c6501c}) of ThingClass sdm630 +---------- +The name of the EventType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) of ThingClass pro380 + Strom 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 + The name of the ParamType (ThingClass: sdm630, EventType: voltage, ID: {4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) +---------- +The name of the StateType ({4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: voltage, ID: {04dba21a-7447-46b9-b9ae-095e5769e511}) +---------- +The name of the StateType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 + Spannung + + + + + Voltage changed + The name of the EventType ({4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) of ThingClass sdm630 +---------- +The name of the EventType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 + Spannung 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 + + + + 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..a1262c8 --- /dev/null +++ b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts @@ -0,0 +1,285 @@ + + + + + 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 + The name of the ParamType (ThingClass: sdm630, EventType: current, ID: {96bc65ce-5bde-4a69-9ebf-711d65c6501c}) +---------- +The name of the StateType ({96bc65ce-5bde-4a69-9ebf-711d65c6501c}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: current, ID: {1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) +---------- +The name of the StateType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) of ThingClass pro380 + + + + + + Current changed + The name of the EventType ({96bc65ce-5bde-4a69-9ebf-711d65c6501c}) of ThingClass sdm630 +---------- +The name of the EventType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) 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 + The name of the ParamType (ThingClass: sdm630, EventType: voltage, ID: {4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) +---------- +The name of the StateType ({4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: voltage, ID: {04dba21a-7447-46b9-b9ae-095e5769e511}) +---------- +The name of the StateType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 + + + + + + Voltage changed + The name of the EventType ({4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) of ThingClass sdm630 +---------- +The name of the EventType ({04dba21a-7447-46b9-b9ae-095e5769e511}) 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 + + + + + Slave address not valid, must be between 1 and 254 + + + + + Modbus RTU resource not available. + + + + From 7dded817c936c93c90fcda9eddaa034d585e4355 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Wed, 21 Apr 2021 19:49:51 +0200 Subject: [PATCH 13/26] fixed on modbus RTU master removed lambda --- energymeters/energymeter.cpp | 5 ++++ energymeters/energymeter.h | 2 ++ .../integrationpluginenergymeters.cpp | 24 ++++++++----------- energymeters/integrationpluginenergymeters.h | 4 +--- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp index 8083f49..2555a71 100644 --- a/energymeters/energymeter.cpp +++ b/energymeters/energymeter.cpp @@ -47,6 +47,11 @@ bool EnergyMeter::init() return true; } +QUuid EnergyMeter::modbusRtuMasterUuid() +{ + return m_modbusRtuMaster->modbusUuid(); +} + bool EnergyMeter::connected() { return m_connected; diff --git a/energymeters/energymeter.h b/energymeters/energymeter.h index 1773d5d..67cb175 100644 --- a/energymeters/energymeter.h +++ b/energymeters/energymeter.h @@ -32,6 +32,7 @@ #define ENERGYMETER_H #include +#include #include "registerdescriptor.h" #include "hardware/modbus/modbusrtumaster.h" @@ -43,6 +44,7 @@ public: explicit EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const QHash &modbusRegisters, QObject *parent = nullptr); bool init(); + QUuid modbusRtuMasterUuid(); bool connected(); bool getVoltage(); bool getCurrent(); diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index 2dd79a4..8059280 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -68,26 +68,22 @@ IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() m_discoverySlaveAddressParamTypeIds.insert(pro380ThingClassId, pro380DiscoverySlaveAddressParamTypeId); m_discoverySlaveAddressParamTypeIds.insert(sdm630ThingClassId, sdm630DiscoverySlaveAddressParamTypeId); - m_registerMaps.insert(pro380ThingClassId, &pro380RegisterMap); - m_registerMaps.insert(sdm630ThingClassId, &sdm630RegisterMap); + m_registerMaps.insert(pro380ThingClassId, pro380RegisterMap); + m_registerMaps.insert(sdm630ThingClassId, sdm630RegisterMap); // Modbus RTU hardware resource connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=](const QUuid &modbusUuid){ qCDebug(dcEnergyMeters()) << "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(dcEnergyMeters()) << "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_connectionStateTypeIds[thing->thingClassId()], false); + foreach (EnergyMeter * meter, m_energyMeters) { + if (meter->modbusRtuMasterUuid() == modbusUuid) { + Thing *thing = m_energyMeters.key(meter); + if (!thing) + return; - // Set all child things disconnected - foreach (Thing *childThing, myThings()) { - if (childThing->parentId() == thing->id()) { - thing->setStateValue(m_connectionStateTypeIds[childThing->thingClassId()], false); - } - } + 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); } } }); @@ -152,7 +148,7 @@ void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) return; } - EnergyMeter *meter = new EnergyMeter(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), address, *m_registerMaps.value(thing->thingClassId()), this); + 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] { qCDebug(dcEnergyMeters()) << "Reply received, setup finished"; diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h index 8f9dc91..16e2f95 100644 --- a/energymeters/integrationpluginenergymeters.h +++ b/energymeters/integrationpluginenergymeters.h @@ -70,12 +70,10 @@ private: QHash m_slaveIdParamTypeIds; QHash m_modbusUuidParamTypeIds; - QHash *> m_registerMaps; + QHash> m_registerMaps; QHash m_energyMeters; - QHash m_modbusRtuMasters; PluginTimer *m_pluginTimer = nullptr; - QHash m_asyncActions; private slots: void onConnectionStateChanged(bool status); From 799a831081539205753ab4306fc30fe525a137b8 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Wed, 21 Apr 2021 20:30:37 +0200 Subject: [PATCH 14/26] fixed thing setup --- energymeters/integrationpluginenergymeters.cpp | 7 ++++--- energymeters/integrationpluginenergymeters.h | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index 8059280..94fea54 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -71,8 +71,8 @@ IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() m_registerMaps.insert(pro380ThingClassId, pro380RegisterMap); m_registerMaps.insert(sdm630ThingClassId, sdm630RegisterMap); - // Modbus RTU hardware resource - connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=](const QUuid &modbusUuid){ + // FIXME leads to crash, probably an issue in the modbus rtu resource + /*connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=] (const QUuid &modbusUuid){ qCDebug(dcEnergyMeters()) << "Modbus RTU master has been removed" << modbusUuid.toString(); // Check if there is any device using this resource @@ -86,7 +86,7 @@ IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() thing->setStateValue(m_connectionStateTypeIds[thing->thingClassId()], false); } } - }); + }); */ } void IntegrationPluginEnergyMeters::discoverThings(ThingDiscoveryInfo *info) @@ -164,6 +164,7 @@ void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) m_energyMeters.insert(info->thing(), meter); info->finish(Thing::ThingErrorNoError); }); + meter->getEnergyConsumed(); return; } else { Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h index 16e2f95..ce56b47 100644 --- a/energymeters/integrationpluginenergymeters.h +++ b/energymeters/integrationpluginenergymeters.h @@ -73,7 +73,6 @@ private: QHash> m_registerMaps; QHash m_energyMeters; - PluginTimer *m_pluginTimer = nullptr; private slots: void onConnectionStateChanged(bool status); From cd91ae28c82f0bcaea6eb781d65d74453dfdebf9 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Wed, 21 Apr 2021 20:51:15 +0200 Subject: [PATCH 15/26] fixed update cycle --- energymeters/energymeter.cpp | 11 ++++- .../integrationpluginenergymeters.cpp | 41 ++++++++----------- energymeters/integrationpluginenergymeters.h | 1 - 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp index 2555a71..ae0a6cd 100644 --- a/energymeters/energymeter.cpp +++ b/energymeters/energymeter.cpp @@ -139,14 +139,23 @@ void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); connect(reply, &ModbusRtuReply::finished, this, [reply, type, descriptor, this] { if (reply->error() != ModbusRtuReply::NoError) { + if (m_connected) { + m_connected = false; + emit connectedChanged(m_connected); + } return; + } else { + if (!m_connected) { + m_connected = true; + emit connectedChanged(m_connected); + } } double value = 0; if (reply->result().length() == 1) { value = static_cast(reply->result().at(0)); } else if (reply->result().length() == 2) { if (descriptor.dataType() == "float") { - value = static_cast(reply->result().at(0) << 16 | reply->result().at(1)); + value = static_cast(reply->result().at(0) << 16 | reply->result().at(1)); } else { qCWarning(dcEnergyMeters()) << "Data type not supported" << descriptor.dataType(); } diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index 94fea54..724b4ec 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -177,23 +177,6 @@ void IntegrationPluginEnergyMeters::postSetupThing(Thing *thing) if (m_connectionStateTypeIds.contains(thing->thingClassId())) { thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), true); } - - if (!m_updateTimer) { - qCDebug(dcEnergyMeters()) << "Creating update timer"; - m_updateTimer = new QTimer(this); - m_updateTimer->start(configValue(energyMetersPluginUpdateIntervalParamTypeId).toInt()); - connect(m_updateTimer, &QTimer::timeout, this, [this] { - foreach (EnergyMeter *meter, m_energyMeters) { - meter->getVoltage(); - } - }); - connect(this, &IntegrationPlugin::configValueChanged, [this] (const ParamTypeId ¶mTypeId, const QVariant value) { - if (m_updateTimer && (paramTypeId == energyMetersPluginUpdateIntervalParamTypeId)) { - qCDebug(dcEnergyMeters()) << "Updating update interval to" << value; - m_updateTimer->setInterval(value.toInt()); - } - }); - } } void IntegrationPluginEnergyMeters::thingRemoved(Thing *thing) @@ -203,12 +186,6 @@ void IntegrationPluginEnergyMeters::thingRemoved(Thing *thing) if (m_energyMeters.contains(thing)) { m_energyMeters.take(thing)->deleteLater(); } - - if (myThings().isEmpty() && !m_updateTimer) { - qCDebug(dcEnergyMeters()) << "Deleting update timer"; - m_updateTimer->deleteLater(); - m_updateTimer = nullptr; - } } void IntegrationPluginEnergyMeters::onConnectionStateChanged(bool status) @@ -219,6 +196,14 @@ void IntegrationPluginEnergyMeters::onConnectionStateChanged(bool status) return; thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), status); + if (!status) { + QTimer::singleShot(5000, meter, [this, meter, thing] { + if (!thing->stateValue(m_connectionStateTypeIds.value(thing->thingClassId())).toBool()) { + // Check if the device is still disconnected + meter->getVoltage(); // restart update cycle + } + }); + } } void IntegrationPluginEnergyMeters::onVoltageReceived(double voltage) @@ -228,6 +213,7 @@ void IntegrationPluginEnergyMeters::onVoltageReceived(double voltage) if (!thing) return; + meter->getCurrent(); thing->setStateValue(m_voltageStateTypeIds.value(thing->thingClassId()), voltage); } @@ -238,6 +224,7 @@ void IntegrationPluginEnergyMeters::onCurrentReceived(double current) if (!thing) return; + meter->getActivePower(); thing->setStateValue(m_currentStateTypeIds.value(thing->thingClassId()), current); } @@ -248,6 +235,7 @@ void IntegrationPluginEnergyMeters::onActivePowerReceived(double power) if (!thing) return; + meter->getFrequency(); thing->setStateValue(m_activePowerStateTypeIds.value(thing->thingClassId()), power); } @@ -258,6 +246,7 @@ void IntegrationPluginEnergyMeters::onFrequencyReceived(double frequency) if (!thing) return; + meter->getPowerFactor(); thing->setStateValue(m_frequencyStateTypeIds.value(thing->thingClassId()), frequency); } @@ -268,6 +257,7 @@ void IntegrationPluginEnergyMeters::onPowerFactorReceived(double powerFactor) if (!thing) return; + meter->getEnergyProduced(); thing->setStateValue(m_powerFactorStateTypeIds.value(thing->thingClassId()), powerFactor); } @@ -278,6 +268,7 @@ void IntegrationPluginEnergyMeters::onProducedEnergyReceived(double energy) if (!thing) return; + meter->getEnergyConsumed(); thing->setStateValue(m_totalEnergyProducedStateTypeIds.value(thing->thingClassId()), energy); } @@ -288,5 +279,9 @@ void IntegrationPluginEnergyMeters::onConsumedEnergyReceived(double energy) if (!thing) return; + int updateInterval = configValue(energyMetersPluginUpdateIntervalParamTypeId).toInt(); + QTimer::singleShot(updateInterval, meter, [meter] { + meter->getVoltage(); // restart update cycle + }); thing->setStateValue(m_totalEnergyConsumedStateTypeIds.value(thing->thingClassId()), energy); } diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h index ce56b47..5260a79 100644 --- a/energymeters/integrationpluginenergymeters.h +++ b/energymeters/integrationpluginenergymeters.h @@ -56,7 +56,6 @@ public: void thingRemoved(Thing *thing) override; private: - QTimer *m_updateTimer = nullptr; QHash m_connectionStateTypeIds; QHash m_voltageStateTypeIds; QHash m_currentStateTypeIds; From 465936f9ac02814c7e9ee41cfd5e46a3561cbb56 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Wed, 21 Apr 2021 21:05:15 +0200 Subject: [PATCH 16/26] fixed float value conversion --- energymeters/energymeter.cpp | 32 ++++++++++++++++---------------- energymeters/energymeter.h | 6 ++++++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp index ae0a6cd..ae58717 100644 --- a/energymeters/energymeter.cpp +++ b/energymeters/energymeter.cpp @@ -150,12 +150,12 @@ void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor emit connectedChanged(m_connected); } } - double value = 0; + modbus_32_t value; if (reply->result().length() == 1) { - value = static_cast(reply->result().at(0)); + value.u = static_cast(reply->result().at(0)); } else if (reply->result().length() == 2) { if (descriptor.dataType() == "float") { - value = static_cast(reply->result().at(0) << 16 | reply->result().at(1)); + value.u = static_cast(static_cast(reply->result().at(0)) << 16 | reply->result().at(1)); } else { qCWarning(dcEnergyMeters()) << "Data type not supported" << descriptor.dataType(); } @@ -163,35 +163,35 @@ void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor if (type == ModbusRegisterType::Voltage) { if (descriptor.unit() == "mV") - value /= 1000; + value.f /= 1000.00; - emit voltageReceived(value); + emit voltageReceived(value.f); } else if (type == ModbusRegisterType::Current) { if (descriptor.unit() == "mA") - value /= 1000; + value.f /= 1000.00; - emit currentReceived(value); + emit currentReceived(value.f); } else if (type == ModbusRegisterType::ActivePower) { if (descriptor.unit() == "kW") { - value *= 1000; + value.f *= 1000; } else if (descriptor.unit() == "mW") { - value /= 1000; + value.f /= 1000.00; } - emit activePowerReceived(value); + emit activePowerReceived(value.f); } else if (type == ModbusRegisterType::PowerFactor) { - emit powerFactorReceived(value); + emit powerFactorReceived(value.f); } else if (type == ModbusRegisterType::Frequency) { - emit frequencyReceived(value); + emit frequencyReceived(value.f); } else if (type == ModbusRegisterType::EnergyConsumed) { if (descriptor.unit() == "Wh") { - value /= 1000; + value.f /= 1000.00; } - emit consumedEnergyReceived(value); + emit consumedEnergyReceived(value.f); } else if (type == ModbusRegisterType::EnergyProduced) { if (descriptor.unit() == "Wh") { - value /= 1000; + value.f /= 1000.00; } - emit producedEnergyReceived(value); + emit producedEnergyReceived(value.f); } }); } diff --git a/energymeters/energymeter.h b/energymeters/energymeter.h index 67cb175..ece1400 100644 --- a/energymeters/energymeter.h +++ b/energymeters/energymeter.h @@ -55,6 +55,12 @@ public: bool getEnergyConsumed(); private: + typedef union { + int32_t s; + uint32_t u; + float f; + } modbus_32_t; + bool m_connected = false; ModbusRtuMaster *m_modbusRtuMaster = nullptr; From 739d1a4dd24b7425f55ce904626572511ce7ace9 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Wed, 21 Apr 2021 21:42:59 +0200 Subject: [PATCH 17/26] improved update cycle process --- energymeters/energymeter.cpp | 2 + .../integrationpluginenergymeters.cpp | 64 +++++++++++++++---- energymeters/integrationpluginenergymeters.h | 5 ++ 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp index ae58717..6485dc8 100644 --- a/energymeters/energymeter.cpp +++ b/energymeters/energymeter.cpp @@ -159,6 +159,8 @@ void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor } else { qCWarning(dcEnergyMeters()) << "Data type not supported" << descriptor.dataType(); } + } else { + return; } if (type == ModbusRegisterType::Voltage) { diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index 724b4ec..ceb545c 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -110,7 +110,7 @@ void IntegrationPluginEnergyMeters::discoverThings(ThingDiscoveryInfo *info) if (!modbusMaster->connected()) { continue; } - ThingDescriptor descriptor(info->thingClassId(), "Modbus interface "+modbusMaster->serialPort(), modbusMaster->modbusUuid().toString()); + 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()); @@ -176,6 +176,27 @@ 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)); + } + } + + if (!m_reconnectTimer) { + m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(5000); + 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) + continue; + + startUpdateCycle(meter); + } + } + } + }); } } @@ -186,6 +207,32 @@ void IntegrationPluginEnergyMeters::thingRemoved(Thing *thing) if (m_energyMeters.contains(thing)) { m_energyMeters.take(thing)->deleteLater(); } + + if (myThings().isEmpty() && m_reconnectTimer) { + hardwareManager()->pluginTimerManager()->unregisterTimer(m_reconnectTimer); + m_reconnectTimer = nullptr; + } +} + +void IntegrationPluginEnergyMeters::startUpdateCycle(EnergyMeter *meter) +{ + if (m_updateCycleInProgress.contains(meter)) { + if (m_updateCycleInProgress.value(meter)) { + return; + } + } + m_updateCycleInProgress.insert(meter, true); + meter->getVoltage(); +} + +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) @@ -195,15 +242,10 @@ void IntegrationPluginEnergyMeters::onConnectionStateChanged(bool status) if (!thing) return; - thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), status); if (!status) { - QTimer::singleShot(5000, meter, [this, meter, thing] { - if (!thing->stateValue(m_connectionStateTypeIds.value(thing->thingClassId())).toBool()) { - // Check if the device is still disconnected - meter->getVoltage(); // restart update cycle - } - }); + updateCycleFinished(meter); } + thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), status); } void IntegrationPluginEnergyMeters::onVoltageReceived(double voltage) @@ -278,10 +320,6 @@ void IntegrationPluginEnergyMeters::onConsumedEnergyReceived(double energy) Thing *thing = m_energyMeters.key(meter); if (!thing) return; - - int updateInterval = configValue(energyMetersPluginUpdateIntervalParamTypeId).toInt(); - QTimer::singleShot(updateInterval, meter, [meter] { - meter->getVoltage(); // restart update cycle - }); + updateCycleFinished(meter); thing->setStateValue(m_totalEnergyConsumedStateTypeIds.value(thing->thingClassId()), energy); } diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h index 5260a79..05be244 100644 --- a/energymeters/integrationpluginenergymeters.h +++ b/energymeters/integrationpluginenergymeters.h @@ -56,6 +56,7 @@ public: void thingRemoved(Thing *thing) override; private: + PluginTimer *m_reconnectTimer = nullptr; QHash m_connectionStateTypeIds; QHash m_voltageStateTypeIds; QHash m_currentStateTypeIds; @@ -73,6 +74,10 @@ private: QHash m_energyMeters; + QHash m_updateCycleInProgress; + void startUpdateCycle(EnergyMeter *meter); + void updateCycleFinished(EnergyMeter *meter); + private slots: void onConnectionStateChanged(bool status); void onVoltageReceived(double voltage); From 205a4783dc9d8b345e95abc4c7f362c0259a6d1c Mon Sep 17 00:00:00 2001 From: Boernsman Date: Wed, 21 Apr 2021 21:45:05 +0200 Subject: [PATCH 18/26] improved update cycle process --- energymeters/energymeter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp index 6485dc8..b41e11f 100644 --- a/energymeters/energymeter.cpp +++ b/energymeters/energymeter.cpp @@ -151,6 +151,7 @@ void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor } } 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) { From 78aee3cbb6a9c6d0d9625995def282cae7bdf50f Mon Sep 17 00:00:00 2001 From: Boernsman Date: Wed, 21 Apr 2021 22:03:49 +0200 Subject: [PATCH 19/26] fixed bug in update cycle process --- energymeters/inepromodbusregister.h | 14 +++++++------- energymeters/integrationpluginenergymeters.cpp | 8 +++++++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/energymeters/inepromodbusregister.h b/energymeters/inepromodbusregister.h index b4e23eb..a1471b1 100644 --- a/energymeters/inepromodbusregister.h +++ b/energymeters/inepromodbusregister.h @@ -33,13 +33,13 @@ #include "registerdescriptor.h" static const QHash pro380RegisterMap { - {ModbusRegisterType::Voltage, ModbusRegisterDescriptor(20482, 3, 2, "V", "float")}, //L1 Voltage - {ModbusRegisterType::Current, ModbusRegisterDescriptor(20492, 3, 2, "A", "float")}, //L1 Current - {ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(20498, 3, 2, "kW", "float")}, //Total active power - {ModbusRegisterType::Frequency, ModbusRegisterDescriptor(20488, 3, 2, "Hz", "float")}, - {ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(20522, 3, 2, "Degree", "float")}, - {ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(24588, 3, 2, "kWh", "float")}, //Forward active energy - {ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(24600, 3, 2, "kWh", "float")} //Reverse active energy + {ModbusRegisterType::Voltage, ModbusRegisterDescriptor(0x5002, 3, 2, "V", "float")}, //L1 Voltage + {ModbusRegisterType::Current, ModbusRegisterDescriptor(0x500C, 3, 2, "A", "float")}, //L1 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, "Degree", "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 index ceb545c..88480a3 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -65,6 +65,12 @@ IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() 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); @@ -157,7 +163,7 @@ void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) connect(meter, &EnergyMeter::currentReceived, this, &IntegrationPluginEnergyMeters::onCurrentReceived); connect(meter, &EnergyMeter::activePowerReceived, this, &IntegrationPluginEnergyMeters::onActivePowerReceived); connect(meter, &EnergyMeter::powerFactorReceived, this, &IntegrationPluginEnergyMeters::onPowerFactorReceived); - connect(meter, &EnergyMeter::frequencyReceived, this, &IntegrationPluginEnergyMeters::onActivePowerReceived); + connect(meter, &EnergyMeter::frequencyReceived, this, &IntegrationPluginEnergyMeters::onFrequencyReceived); connect(meter, &EnergyMeter::producedEnergyReceived, this, &IntegrationPluginEnergyMeters::onProducedEnergyReceived); connect(meter, &EnergyMeter::consumedEnergyReceived, this, &IntegrationPluginEnergyMeters::onConsumedEnergyReceived); From 3d0dd6839bfa3f212e66060c4e7ec5649fb4738b Mon Sep 17 00:00:00 2001 From: Boernsman Date: Wed, 21 Apr 2021 22:38:56 +0200 Subject: [PATCH 20/26] added voltage and current for all phases --- energymeters/bg-etechmodbusregister.h | 8 +- energymeters/energymeter.cpp | 111 ++++---- energymeters/energymeter.h | 19 +- energymeters/inepromodbusregister.h | 8 +- .../integrationpluginenergymeters.cpp | 84 +++++- energymeters/integrationpluginenergymeters.h | 16 +- .../integrationpluginenergymeters.json | 100 ++++++- energymeters/registerdescriptor.h | 8 +- ...56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts | 266 ++++++++++++------ ...95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts | 258 ++++++++++++----- 10 files changed, 627 insertions(+), 251 deletions(-) diff --git a/energymeters/bg-etechmodbusregister.h b/energymeters/bg-etechmodbusregister.h index deffe6b..a0dd0ed 100644 --- a/energymeters/bg-etechmodbusregister.h +++ b/energymeters/bg-etechmodbusregister.h @@ -34,8 +34,12 @@ #include "registerdescriptor.h" static const QHash sdm630RegisterMap { - {ModbusRegisterType::Voltage, ModbusRegisterDescriptor(30043, 4, 2, "V", "float")}, //Average line to neutral volts - {ModbusRegisterType::Current, ModbusRegisterDescriptor(30047, 4, 2, "A", "float")}, //Average line current + {ModbusRegisterType::VoltageL1, ModbusRegisterDescriptor(30001, 4, 2, "V", "float")}, + {ModbusRegisterType::VoltageL2, ModbusRegisterDescriptor(30003, 4, 2, "V", "float")}, + {ModbusRegisterType::VoltageL3, ModbusRegisterDescriptor(30005, 4, 2, "V", "float")}, + {ModbusRegisterType::CurrentL1, ModbusRegisterDescriptor(30007, 4, 2, "A", "float")}, + {ModbusRegisterType::CurrentL2, ModbusRegisterDescriptor(30009, 4, 2, "A", "float")}, + {ModbusRegisterType::CurrentL3, ModbusRegisterDescriptor(30011, 4, 2, "A", "float")}, {ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(30053, 4, 2, "W", "float")}, //Total system power {ModbusRegisterType::Frequency, ModbusRegisterDescriptor(30071, 4, 2, "Hz", "float")}, {ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(30067, 4, 2, "Degree", "float")}, //Total system phase angle diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp index b41e11f..ac6bdda 100644 --- a/energymeters/energymeter.cpp +++ b/energymeters/energymeter.cpp @@ -42,11 +42,6 @@ EnergyMeter::EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const } -bool EnergyMeter::init() -{ - return true; -} - QUuid EnergyMeter::modbusRtuMasterUuid() { return m_modbusRtuMaster->modbusUuid(); @@ -57,78 +52,67 @@ bool EnergyMeter::connected() return m_connected; } -bool EnergyMeter::getVoltage() +bool EnergyMeter::getVoltageL1() { - if (!m_modbusRegisters.contains(ModbusRegisterType::Voltage)) - return false; - - ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::Voltage); - getRegister(ModbusRegisterType::Voltage, descriptor); - return true; + return getRegister(ModbusRegisterType::VoltageL1); } -bool EnergyMeter::getCurrent() +bool EnergyMeter::getVoltageL2() { - if (!m_modbusRegisters.contains(ModbusRegisterType::Current)) - return false; + return getRegister(ModbusRegisterType::VoltageL2); +} - ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::Current); - getRegister(ModbusRegisterType::Current, descriptor); - return true; +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() { - if (!m_modbusRegisters.contains(ModbusRegisterType::Frequency)) - return false; - - ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::Frequency); - getRegister(ModbusRegisterType::Frequency, descriptor); - return true; + return getRegister(ModbusRegisterType::Frequency); } bool EnergyMeter::getPowerFactor() { - if (!m_modbusRegisters.contains(ModbusRegisterType::PowerFactor)) - return false; - - ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::PowerFactor); - getRegister(ModbusRegisterType::PowerFactor, descriptor); - return true; + return getRegister(ModbusRegisterType::PowerFactor); } bool EnergyMeter::getActivePower() { - if (!m_modbusRegisters.contains(ModbusRegisterType::ActivePower)) - return false; - - ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::ActivePower); - getRegister(ModbusRegisterType::ActivePower, descriptor); - return true; + return getRegister(ModbusRegisterType::ActivePower); } bool EnergyMeter::getEnergyProduced() { - if (!m_modbusRegisters.contains(ModbusRegisterType::EnergyProduced)) - return false; - - ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::EnergyProduced); - getRegister(ModbusRegisterType::EnergyProduced, descriptor); - return true; + return getRegister(ModbusRegisterType::EnergyProduced); } bool EnergyMeter::getEnergyConsumed() { - if (!m_modbusRegisters.contains(ModbusRegisterType::EnergyConsumed)) - return false; - - ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::EnergyConsumed); - getRegister(ModbusRegisterType::EnergyConsumed, descriptor); - return true; + return getRegister(ModbusRegisterType::EnergyConsumed); } -void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor descriptor) +bool EnergyMeter::getRegister(ModbusRegisterType type) { + if (!m_modbusRegisters.contains(type)) + return false; + + ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(type); ModbusRtuReply *reply = nullptr; if (descriptor.functionCode() == 3){ @@ -164,16 +148,36 @@ void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor return; } - if (type == ModbusRegisterType::Voltage) { + if (type == ModbusRegisterType::VoltageL1) { if (descriptor.unit() == "mV") value.f /= 1000.00; - emit voltageReceived(value.f); - } else if (type == ModbusRegisterType::Current) { + 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 currentReceived(value.f); + 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; @@ -197,5 +201,6 @@ void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor emit producedEnergyReceived(value.f); } }); + return true; } diff --git a/energymeters/energymeter.h b/energymeters/energymeter.h index ece1400..46b3da2 100644 --- a/energymeters/energymeter.h +++ b/energymeters/energymeter.h @@ -42,12 +42,15 @@ class EnergyMeter : public QObject Q_OBJECT public: explicit EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const QHash &modbusRegisters, QObject *parent = nullptr); - bool init(); QUuid modbusRtuMasterUuid(); bool connected(); - bool getVoltage(); - bool getCurrent(); + bool getVoltageL1(); + bool getVoltageL2(); + bool getVoltageL3(); + bool getCurrentL1(); + bool getCurrentL2(); + bool getCurrentL3(); bool getFrequency(); bool getPowerFactor(); bool getActivePower(); @@ -68,13 +71,17 @@ private: QHash m_modbusRegisters; - void getRegister(ModbusRegisterType type, ModbusRegisterDescriptor descriptor); + bool getRegister(ModbusRegisterType type); signals: void connectedChanged(bool connected); - void voltageReceived(double voltage); - void currentReceived(double current); + 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); diff --git a/energymeters/inepromodbusregister.h b/energymeters/inepromodbusregister.h index a1471b1..2bf4f24 100644 --- a/energymeters/inepromodbusregister.h +++ b/energymeters/inepromodbusregister.h @@ -33,8 +33,12 @@ #include "registerdescriptor.h" static const QHash pro380RegisterMap { - {ModbusRegisterType::Voltage, ModbusRegisterDescriptor(0x5002, 3, 2, "V", "float")}, //L1 Voltage - {ModbusRegisterType::Current, ModbusRegisterDescriptor(0x500C, 3, 2, "A", "float")}, //L1 Current + {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, "Degree", "float")}, diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index 88480a3..ee336c0 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -50,11 +50,23 @@ IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() m_connectionStateTypeIds.insert(pro380ThingClassId, pro380ConnectedStateTypeId); m_connectionStateTypeIds.insert(sdm630ThingClassId, sdm630ConnectedStateTypeId); - m_voltageStateTypeIds.insert(pro380ThingClassId, pro380VoltageStateTypeId); - m_voltageStateTypeIds.insert(sdm630ThingClassId, sdm630VoltageStateTypeId); + m_voltageL1StateTypeIds.insert(pro380ThingClassId, pro380VoltageL1StateTypeId); + m_voltageL1StateTypeIds.insert(sdm630ThingClassId, sdm630VoltageL1StateTypeId); - m_currentStateTypeIds.insert(pro380ThingClassId, pro380CurrentStateTypeId); - m_currentStateTypeIds.insert(sdm630ThingClassId, sdm630CurrentStateTypeId); + 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); @@ -159,8 +171,12 @@ void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) connect(meter, &EnergyMeter::consumedEnergyReceived, info, [this, info, meter] { qCDebug(dcEnergyMeters()) << "Reply received, setup finished"; connect(meter, &EnergyMeter::connectedChanged, this, &IntegrationPluginEnergyMeters::onConnectionStateChanged); - connect(meter, &EnergyMeter::voltageReceived, this, &IntegrationPluginEnergyMeters::onVoltageReceived); - connect(meter, &EnergyMeter::currentReceived, this, &IntegrationPluginEnergyMeters::onCurrentReceived); + 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); @@ -228,7 +244,7 @@ void IntegrationPluginEnergyMeters::startUpdateCycle(EnergyMeter *meter) } } m_updateCycleInProgress.insert(meter, true); - meter->getVoltage(); + meter->getVoltageL1(); } void IntegrationPluginEnergyMeters::updateCycleFinished(EnergyMeter *meter) @@ -254,18 +270,62 @@ void IntegrationPluginEnergyMeters::onConnectionStateChanged(bool status) thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), status); } -void IntegrationPluginEnergyMeters::onVoltageReceived(double voltage) +void IntegrationPluginEnergyMeters::onVoltageL1Received(double voltage) { EnergyMeter *meter = static_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; - meter->getCurrent(); - thing->setStateValue(m_voltageStateTypeIds.value(thing->thingClassId()), voltage); + meter->getVoltageL2(); + thing->setStateValue(m_voltageL1StateTypeIds.value(thing->thingClassId()), voltage); } -void IntegrationPluginEnergyMeters::onCurrentReceived(double current) +void IntegrationPluginEnergyMeters::onVoltageL2Received(double voltage) +{ + EnergyMeter *meter = static_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 = static_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 = static_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 = static_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 = static_cast(sender()); Thing *thing = m_energyMeters.key(meter); @@ -273,7 +333,7 @@ void IntegrationPluginEnergyMeters::onCurrentReceived(double current) return; meter->getActivePower(); - thing->setStateValue(m_currentStateTypeIds.value(thing->thingClassId()), current); + thing->setStateValue(m_currentL3StateTypeIds.value(thing->thingClassId()), current); } void IntegrationPluginEnergyMeters::onActivePowerReceived(double power) diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h index 05be244..89e0e9c 100644 --- a/energymeters/integrationpluginenergymeters.h +++ b/energymeters/integrationpluginenergymeters.h @@ -58,8 +58,12 @@ public: private: PluginTimer *m_reconnectTimer = nullptr; QHash m_connectionStateTypeIds; - QHash m_voltageStateTypeIds; - QHash m_currentStateTypeIds; + 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; @@ -80,8 +84,12 @@ private: private slots: void onConnectionStateChanged(bool status); - void onVoltageReceived(double voltage); - void onCurrentReceived(double current); + 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); diff --git a/energymeters/integrationpluginenergymeters.json b/energymeters/integrationpluginenergymeters.json index 56016eb..7ad8198 100644 --- a/energymeters/integrationpluginenergymeters.json +++ b/energymeters/integrationpluginenergymeters.json @@ -63,18 +63,54 @@ }, { "id": "04dba21a-7447-46b9-b9ae-095e5769e511", - "name": "voltage", - "displayName": "Voltage", - "displayNameEvent": "Voltage changed", + "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": "current", - "displayName": "Current", - "displayNameEvent": "Current changed", + "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 @@ -175,19 +211,55 @@ "defaultValue": false }, { - "id": "4636ec5c-fcb9-45b7-ad68-2818cb615ce1", - "name": "voltage", - "displayName": "Voltage", - "displayNameEvent": "Voltage changed", + "id": "db018146-0441-4dc0-9834-6d43ebaf8311", + "name": "voltageL1", + "displayName": "Voltage L1", + "displayNameEvent": "Voltage L1 changed", "type": "double", "unit": "Volt", "defaultValue": 0 }, { - "id": "96bc65ce-5bde-4a69-9ebf-711d65c6501c", - "name": "current", - "displayName": "Current", - "displayNameEvent": "Current changed", + "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 diff --git a/energymeters/registerdescriptor.h b/energymeters/registerdescriptor.h index 5e53807..868a221 100644 --- a/energymeters/registerdescriptor.h +++ b/energymeters/registerdescriptor.h @@ -35,8 +35,12 @@ #include enum ModbusRegisterType { - Voltage, - Current, + VoltageL1, + VoltageL2, + VoltageL3, + CurrentL1, + CurrentL2, + CurrentL3, ActivePower, Frequency, PowerFactor, diff --git a/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts index 11c88e3..5adaee8 100644 --- a/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts +++ b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts @@ -4,10 +4,10 @@ EnergyMeters - - - - + + + + Active power The name of the ParamType (ThingClass: sdm630, EventType: currentPower, ID: {c824e97b-a6d1-4030-9d7a-00af6fb8e1c3}) ---------- @@ -19,8 +19,8 @@ The name of the StateType ({464eff60-11c2-46b7-98f5-1aa8172e5a2d}) of ThingClass Leistung - - + + Active power changed The name of the EventType ({c824e97b-a6d1-4030-9d7a-00af6fb8e1c3}) of ThingClass sdm630 ---------- @@ -28,16 +28,16 @@ The name of the EventType ({464eff60-11c2-46b7-98f5-1aa8172e5a2d}) of ThingClass 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}) ---------- @@ -49,8 +49,8 @@ The name of the StateType ({7f9bc504-0882-4b86-83b1-42fa345acfd9}) of ThingClass Verbunden - - + + Connected changed The name of the EventType ({8050bd0b-1dad-4a7e-b632-c71ead3c9f8b}) of ThingClass sdm630 ---------- @@ -58,40 +58,88 @@ The name of the EventType ({7f9bc504-0882-4b86-83b1-42fa345acfd9}) of ThingClass Verbunden - - - - - Current - The name of the ParamType (ThingClass: sdm630, EventType: current, ID: {96bc65ce-5bde-4a69-9ebf-711d65c6501c}) + + + + + Current L1 + The name of the ParamType (ThingClass: sdm630, EventType: currentL1, ID: {4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) ---------- -The name of the StateType ({96bc65ce-5bde-4a69-9ebf-711d65c6501c}) of ThingClass sdm630 +The name of the StateType ({4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) of ThingClass sdm630 ---------- -The name of the ParamType (ThingClass: pro380, EventType: current, ID: {1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) +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 + Strom L1 - - - Current changed - The name of the EventType ({96bc65ce-5bde-4a69-9ebf-711d65c6501c}) of ThingClass sdm630 + + + 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 geändert + 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}) ---------- @@ -103,8 +151,8 @@ The name of the StateType ({bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5}) of ThingClass Frequenz - - + + Frequency changed The name of the EventType ({ab24f26c-dc15-4ec3-8d76-06a48285440b}) of ThingClass sdm630 ---------- @@ -112,8 +160,8 @@ The name of the EventType ({bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5}) of ThingClass Frequenz geändert - - + + Modbus RTU master The name of the ParamType (ThingClass: sdm630, Type: thing, ID: {d90e9292-d03c-4f2a-957e-5d965018c9c9}) ---------- @@ -121,8 +169,8 @@ The name of the ParamType (ThingClass: pro380, Type: thing, ID: {6cdbec8c-21b9-4 Modbus RTU Master - - + + Modbus slave address The name of the ParamType (ThingClass: sdm630, Type: thing, ID: {ac77ea98-b006-486e-a3e8-b30a483f26c1}) ---------- @@ -130,16 +178,16 @@ The name of the ParamType (ThingClass: pro380, Type: thing, ID: {c75b2c31-6ec3-4 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}) ---------- @@ -151,8 +199,8 @@ The name of the StateType ({cdb34487-3d9b-492a-8c33-802f32a2e90e}) of ThingClass Leistungsfaktor - - + + Power factor changed The name of the EventType ({31b9032f-f994-472b-94bd-44f9fb094801}) of ThingClass sdm630 ---------- @@ -160,14 +208,14 @@ The name of the EventType ({cdb34487-3d9b-492a-8c33-802f32a2e90e}) of ThingClass 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}) ---------- @@ -175,10 +223,10 @@ The name of the ParamType (ThingClass: pro380, Type: discovery, ID: {a29f37f6-b3 Slave-Adresse - - - - + + + + Total energy consumed The name of the ParamType (ThingClass: sdm630, EventType: totalEnergyConsumed, ID: {98d858a8-22e8-4262-b5c7-25bb027942ad}) ---------- @@ -190,8 +238,8 @@ The name of the StateType ({f18fd596-b47f-44be-a0f0-6ca44369ebf5}) of ThingClass Gesamte verbrauchte Energy - - + + Total energy consumed changed The name of the EventType ({98d858a8-22e8-4262-b5c7-25bb027942ad}) of ThingClass sdm630 ---------- @@ -199,10 +247,10 @@ The name of the EventType ({f18fd596-b47f-44be-a0f0-6ca44369ebf5}) of ThingClass Gesamte verbrauchte Energie geändert - - - - + + + + Total energy produced The name of the ParamType (ThingClass: sdm630, EventType: totalEnergyProduced, ID: {e469b3ff-a4c2-42da-af35-ccafaef214af}) ---------- @@ -214,8 +262,8 @@ The name of the StateType ({112911c9-14e0-4c83-ac92-f2ceb3bdecdf}) of ThingClass Gesamte produzierte Energie - - + + Total energy produced changed The name of the EventType ({e469b3ff-a4c2-42da-af35-ccafaef214af}) of ThingClass sdm630 ---------- @@ -223,37 +271,85 @@ The name of the EventType ({112911c9-14e0-4c83-ac92-f2ceb3bdecdf}) of ThingClass Gesamte produzierte Energie geändert - + Update interval The name of the ParamType (ThingClass: energyMeters, Type: plugin, ID: {eaa84c3c-06b8-4642-a40b-c2efbe6aae66}) Updateintervall - - - - - Voltage - The name of the ParamType (ThingClass: sdm630, EventType: voltage, ID: {4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) + + + + + Voltage L1 + The name of the ParamType (ThingClass: sdm630, EventType: voltageL1, ID: {db018146-0441-4dc0-9834-6d43ebaf8311}) ---------- -The name of the StateType ({4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) of ThingClass sdm630 +The name of the StateType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 ---------- -The name of the ParamType (ThingClass: pro380, EventType: voltage, ID: {04dba21a-7447-46b9-b9ae-095e5769e511}) +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 + Spannung L1 - - - Voltage changed - The name of the EventType ({4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) of ThingClass sdm630 + + + 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 geändert + 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 @@ -262,22 +358,32 @@ The name of the EventType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass 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 index a1262c8..c09f5ee 100644 --- a/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts +++ b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts @@ -4,10 +4,10 @@ EnergyMeters - - - - + + + + Active power The name of the ParamType (ThingClass: sdm630, EventType: currentPower, ID: {c824e97b-a6d1-4030-9d7a-00af6fb8e1c3}) ---------- @@ -19,8 +19,8 @@ The name of the StateType ({464eff60-11c2-46b7-98f5-1aa8172e5a2d}) of ThingClass - - + + Active power changed The name of the EventType ({c824e97b-a6d1-4030-9d7a-00af6fb8e1c3}) of ThingClass sdm630 ---------- @@ -28,16 +28,16 @@ The name of the EventType ({464eff60-11c2-46b7-98f5-1aa8172e5a2d}) of ThingClass - + 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}) ---------- @@ -49,8 +49,8 @@ The name of the StateType ({7f9bc504-0882-4b86-83b1-42fa345acfd9}) of ThingClass - - + + Connected changed The name of the EventType ({8050bd0b-1dad-4a7e-b632-c71ead3c9f8b}) of ThingClass sdm630 ---------- @@ -58,40 +58,88 @@ The name of the EventType ({7f9bc504-0882-4b86-83b1-42fa345acfd9}) of ThingClass - - - - - Current - The name of the ParamType (ThingClass: sdm630, EventType: current, ID: {96bc65ce-5bde-4a69-9ebf-711d65c6501c}) + + + + + Current L1 + The name of the ParamType (ThingClass: sdm630, EventType: currentL1, ID: {4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) ---------- -The name of the StateType ({96bc65ce-5bde-4a69-9ebf-711d65c6501c}) of ThingClass sdm630 +The name of the StateType ({4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) of ThingClass sdm630 ---------- -The name of the ParamType (ThingClass: pro380, EventType: current, ID: {1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) +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 changed - The name of the EventType ({96bc65ce-5bde-4a69-9ebf-711d65c6501c}) of ThingClass sdm630 + + + 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}) ---------- @@ -103,8 +151,8 @@ The name of the StateType ({bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5}) of ThingClass - - + + Frequency changed The name of the EventType ({ab24f26c-dc15-4ec3-8d76-06a48285440b}) of ThingClass sdm630 ---------- @@ -112,8 +160,8 @@ The name of the EventType ({bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5}) of ThingClass - - + + Modbus RTU master The name of the ParamType (ThingClass: sdm630, Type: thing, ID: {d90e9292-d03c-4f2a-957e-5d965018c9c9}) ---------- @@ -121,8 +169,8 @@ The name of the ParamType (ThingClass: pro380, Type: thing, ID: {6cdbec8c-21b9-4 - - + + Modbus slave address The name of the ParamType (ThingClass: sdm630, Type: thing, ID: {ac77ea98-b006-486e-a3e8-b30a483f26c1}) ---------- @@ -130,16 +178,16 @@ The name of the ParamType (ThingClass: pro380, Type: thing, ID: {c75b2c31-6ec3-4 - + 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}) ---------- @@ -151,8 +199,8 @@ The name of the StateType ({cdb34487-3d9b-492a-8c33-802f32a2e90e}) of ThingClass - - + + Power factor changed The name of the EventType ({31b9032f-f994-472b-94bd-44f9fb094801}) of ThingClass sdm630 ---------- @@ -160,14 +208,14 @@ The name of the EventType ({cdb34487-3d9b-492a-8c33-802f32a2e90e}) of ThingClass - + 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}) ---------- @@ -175,10 +223,10 @@ The name of the ParamType (ThingClass: pro380, Type: discovery, ID: {a29f37f6-b3 - - - - + + + + Total energy consumed The name of the ParamType (ThingClass: sdm630, EventType: totalEnergyConsumed, ID: {98d858a8-22e8-4262-b5c7-25bb027942ad}) ---------- @@ -190,8 +238,8 @@ The name of the StateType ({f18fd596-b47f-44be-a0f0-6ca44369ebf5}) of ThingClass - - + + Total energy consumed changed The name of the EventType ({98d858a8-22e8-4262-b5c7-25bb027942ad}) of ThingClass sdm630 ---------- @@ -199,10 +247,10 @@ The name of the EventType ({f18fd596-b47f-44be-a0f0-6ca44369ebf5}) of ThingClass - - - - + + + + Total energy produced The name of the ParamType (ThingClass: sdm630, EventType: totalEnergyProduced, ID: {e469b3ff-a4c2-42da-af35-ccafaef214af}) ---------- @@ -214,8 +262,8 @@ The name of the StateType ({112911c9-14e0-4c83-ac92-f2ceb3bdecdf}) of ThingClass - - + + Total energy produced changed The name of the EventType ({e469b3ff-a4c2-42da-af35-ccafaef214af}) of ThingClass sdm630 ---------- @@ -223,37 +271,85 @@ The name of the EventType ({112911c9-14e0-4c83-ac92-f2ceb3bdecdf}) of ThingClass - + Update interval The name of the ParamType (ThingClass: energyMeters, Type: plugin, ID: {eaa84c3c-06b8-4642-a40b-c2efbe6aae66}) - - - - - Voltage - The name of the ParamType (ThingClass: sdm630, EventType: voltage, ID: {4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) + + + + + Voltage L1 + The name of the ParamType (ThingClass: sdm630, EventType: voltageL1, ID: {db018146-0441-4dc0-9834-6d43ebaf8311}) ---------- -The name of the StateType ({4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) of ThingClass sdm630 +The name of the StateType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 ---------- -The name of the ParamType (ThingClass: pro380, EventType: voltage, ID: {04dba21a-7447-46b9-b9ae-095e5769e511}) +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 changed - The name of the EventType ({4636ec5c-fcb9-45b7-ad68-2818cb615ce1}) of ThingClass sdm630 + + + 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}) @@ -262,22 +358,32 @@ The name of the EventType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass 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. From ade5be50ff4acc7b8057f126141e4f876228e98b Mon Sep 17 00:00:00 2001 From: Boernsman Date: Thu, 22 Apr 2021 10:33:50 +0200 Subject: [PATCH 21/26] adjusted reconnect timer interval --- energymeters/README.md | 14 ++++++++++---- energymeters/integrationpluginenergymeters.cpp | 7 +++++-- energymeters/meta.json | 11 +++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/energymeters/README.md b/energymeters/README.md index b8b1fb8..eea6276 100644 --- a/energymeters/README.md +++ b/energymeters/README.md @@ -1,9 +1,15 @@ -# B+G e-tech +# Energy Meters + +Connect Modbus RTU based energy meters. ## Supported Things - +* b+g e-tech + * SDM630Modbus +* inepro Metering + * PRO380-Mod + ## Requirements - -## More +* The plugin 'nymea-plugin-energymeter' must be installed +* At least one Modbus RTU interface must be setup. diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index ee336c0..f00aa32 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -205,7 +205,7 @@ void IntegrationPluginEnergyMeters::postSetupThing(Thing *thing) } if (!m_reconnectTimer) { - m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(5000); + m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(5); connect(m_reconnectTimer, &PluginTimer::timeout, this, [this] { foreach (Thing *thing, myThings()) { if (m_connectionStateTypeIds.contains(thing->thingClassId())) { @@ -227,10 +227,13 @@ void IntegrationPluginEnergyMeters::thingRemoved(Thing *thing) qCDebug(dcEnergyMeters()) << "Thing removed" << thing->name(); if (m_energyMeters.contains(thing)) { - m_energyMeters.take(thing)->deleteLater(); + 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; } diff --git a/energymeters/meta.json b/energymeters/meta.json index e69de29..4f390d5 100644 --- a/energymeters/meta.json +++ 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": [ + ] +} From 9fde1e7473b0c7bc3f43e94d125ed3fd5a6ab78b Mon Sep 17 00:00:00 2001 From: Boernsman Date: Thu, 29 Apr 2021 11:34:54 +0200 Subject: [PATCH 22/26] fixed crash on plugin constructor --- energymeters/integrationpluginenergymeters.cpp | 8 +++++--- energymeters/integrationpluginenergymeters.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index f00aa32..b0d85fc 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -88,9 +88,11 @@ IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() m_registerMaps.insert(pro380ThingClassId, pro380RegisterMap); m_registerMaps.insert(sdm630ThingClassId, sdm630RegisterMap); +} - // FIXME leads to crash, probably an issue in the modbus rtu resource - /*connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=] (const QUuid &modbusUuid){ +void IntegrationPluginEnergyMeters::init() +{ + connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=] (const QUuid &modbusUuid){ qCDebug(dcEnergyMeters()) << "Modbus RTU master has been removed" << modbusUuid.toString(); // Check if there is any device using this resource @@ -104,7 +106,7 @@ IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() thing->setStateValue(m_connectionStateTypeIds[thing->thingClassId()], false); } } - }); */ + }); } void IntegrationPluginEnergyMeters::discoverThings(ThingDiscoveryInfo *info) diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h index 89e0e9c..1764b44 100644 --- a/energymeters/integrationpluginenergymeters.h +++ b/energymeters/integrationpluginenergymeters.h @@ -49,7 +49,7 @@ class IntegrationPluginEnergyMeters : public IntegrationPlugin public: explicit IntegrationPluginEnergyMeters(); - + void init() override; void discoverThings(ThingDiscoveryInfo *info) override; void setupThing(ThingSetupInfo *info) override; void postSetupThing(Thing *thing) override; From c393bbcf192a055812ddb2bd8080d0a7ba8bd54c Mon Sep 17 00:00:00 2001 From: Boernsman Date: Thu, 29 Apr 2021 16:34:45 +0200 Subject: [PATCH 23/26] changes requested by reviewer --- energymeters/README.md | 2 +- energymeters/bg-etechmodbusregister.h | 2 +- energymeters/energymeter.cpp | 21 ++- energymeters/energymeter.h | 11 +- energymeters/inepromodbusregister.h | 2 +- .../integrationpluginenergymeters.cpp | 166 +++++++++--------- energymeters/integrationpluginenergymeters.h | 2 +- .../integrationpluginenergymeters.json | 4 +- energymeters/registerdescriptor.h | 2 +- 9 files changed, 112 insertions(+), 100 deletions(-) diff --git a/energymeters/README.md b/energymeters/README.md index eea6276..0c90177 100644 --- a/energymeters/README.md +++ b/energymeters/README.md @@ -11,5 +11,5 @@ Connect Modbus RTU based energy meters. ## Requirements -* The plugin 'nymea-plugin-energymeter' must be installed +* 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 index a0dd0ed..34bd78f 100644 --- a/energymeters/bg-etechmodbusregister.h +++ b/energymeters/bg-etechmodbusregister.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. diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp index ac6bdda..cfb94b5 100644 --- a/energymeters/energymeter.cpp +++ b/energymeters/energymeter.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. @@ -42,12 +42,17 @@ EnergyMeter::EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const } -QUuid EnergyMeter::modbusRtuMasterUuid() +ModbusRtuMaster *EnergyMeter::modbusMaster() { - return m_modbusRtuMaster->modbusUuid(); + return m_modbusRtuMaster; } -bool EnergyMeter::connected() +void EnergyMeter::setModbusMaster(ModbusRtuMaster *modbusMaster) +{ + m_modbusRtuMaster = modbusMaster; +} + +bool EnergyMeter::connected() const { return m_connected; } @@ -112,6 +117,12 @@ bool EnergyMeter::getRegister(ModbusRegisterType type) if (!m_modbusRegisters.contains(type)) return false; + if (!m_modbusRtuMaster) + return false; + + if (!m_modbusRtuMaster->connected()) + return false; + ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(type); ModbusRtuReply *reply = nullptr; @@ -199,6 +210,8 @@ bool EnergyMeter::getRegister(ModbusRegisterType type) value.f /= 1000.00; } emit producedEnergyReceived(value.f); + } else { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus register type not handled" << type; } }); return true; diff --git a/energymeters/energymeter.h b/energymeters/energymeter.h index 46b3da2..208fb23 100644 --- a/energymeters/energymeter.h +++ b/energymeters/energymeter.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. @@ -43,8 +43,10 @@ class EnergyMeter : public QObject public: explicit EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const QHash &modbusRegisters, QObject *parent = nullptr); - QUuid modbusRtuMasterUuid(); - bool connected(); + ModbusRtuMaster *modbusMaster(); + void setModbusMaster(ModbusRtuMaster *modbusMaster); + + bool connected() const; bool getVoltageL1(); bool getVoltageL2(); bool getVoltageL3(); @@ -87,9 +89,6 @@ signals: void powerFactorReceived(double powerFactor); void producedEnergyReceived(double energy); void consumedEnergyReceived(double energy); - -//private slot: -// void onRegisterReceived(); }; #endif // ENERGYMETER_H diff --git a/energymeters/inepromodbusregister.h b/energymeters/inepromodbusregister.h index 2bf4f24..e419c9d 100644 --- a/energymeters/inepromodbusregister.h +++ b/energymeters/inepromodbusregister.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. diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index b0d85fc..8b68f1d 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.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. @@ -95,15 +95,17 @@ void IntegrationPluginEnergyMeters::init() connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=] (const QUuid &modbusUuid){ qCDebug(dcEnergyMeters()) << "Modbus RTU master has been removed" << modbusUuid.toString(); - // Check if there is any device using this resource - foreach (EnergyMeter * meter, m_energyMeters) { - if (meter->modbusRtuMasterUuid() == modbusUuid) { - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; + 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); - 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); + } } } }); @@ -119,29 +121,28 @@ void IntegrationPluginEnergyMeters::discoverThings(ThingDiscoveryInfo *info) return; } - if (m_connectionStateTypeIds.contains(info->thingClassId())) { - int slaveAddress = info->params().paramValue(m_discoverySlaveAddressParamTypeIds.value(info->thingClassId())).toInt(); - if (slaveAddress > 254 || slaveAddress == 0) { - info->finish(Thing::ThingErrorInvalidParameter, tr("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; - } else { + 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, tr("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) @@ -149,50 +150,49 @@ void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) Thing *thing = info->thing(); qCDebug(dcEnergyMeters()) << "Setup thing" << thing->name(); - if (m_connectionStateTypeIds.contains(thing->thingClassId())) { - - if (m_energyMeters.contains(thing)) { - qCDebug(dcEnergyMeters()) << "Setup after rediscovery, cleaning up ..."; - m_energyMeters.take(thing)->deleteLater(); - } - int address = thing->paramValue(m_slaveIdParamTypeIds.value(thing->thingClassId())).toInt(); - 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())).toString(); - 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] { - qCDebug(dcEnergyMeters()) << "Reply received, 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; - } else { + 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] { + qCDebug(dcEnergyMeters()) << "Reply received, 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) @@ -277,7 +277,7 @@ void IntegrationPluginEnergyMeters::onConnectionStateChanged(bool status) void IntegrationPluginEnergyMeters::onVoltageL1Received(double voltage) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; @@ -288,7 +288,7 @@ void IntegrationPluginEnergyMeters::onVoltageL1Received(double voltage) void IntegrationPluginEnergyMeters::onVoltageL2Received(double voltage) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; @@ -299,7 +299,7 @@ void IntegrationPluginEnergyMeters::onVoltageL2Received(double voltage) void IntegrationPluginEnergyMeters::onVoltageL3Received(double voltage) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; @@ -310,7 +310,7 @@ void IntegrationPluginEnergyMeters::onVoltageL3Received(double voltage) void IntegrationPluginEnergyMeters::onCurrentL1Received(double current) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; @@ -321,7 +321,7 @@ void IntegrationPluginEnergyMeters::onCurrentL1Received(double current) void IntegrationPluginEnergyMeters::onCurrentL2Received(double current) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; @@ -332,7 +332,7 @@ void IntegrationPluginEnergyMeters::onCurrentL2Received(double current) void IntegrationPluginEnergyMeters::onCurrentL3Received(double current) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; @@ -343,7 +343,7 @@ void IntegrationPluginEnergyMeters::onCurrentL3Received(double current) void IntegrationPluginEnergyMeters::onActivePowerReceived(double power) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; @@ -354,7 +354,7 @@ void IntegrationPluginEnergyMeters::onActivePowerReceived(double power) void IntegrationPluginEnergyMeters::onFrequencyReceived(double frequency) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; @@ -365,7 +365,7 @@ void IntegrationPluginEnergyMeters::onFrequencyReceived(double frequency) void IntegrationPluginEnergyMeters::onPowerFactorReceived(double powerFactor) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; @@ -376,7 +376,7 @@ void IntegrationPluginEnergyMeters::onPowerFactorReceived(double powerFactor) void IntegrationPluginEnergyMeters::onProducedEnergyReceived(double energy) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; @@ -387,7 +387,7 @@ void IntegrationPluginEnergyMeters::onProducedEnergyReceived(double energy) void IntegrationPluginEnergyMeters::onConsumedEnergyReceived(double energy) { - EnergyMeter *meter = static_cast(sender()); + EnergyMeter *meter = qobject_cast(sender()); Thing *thing = m_energyMeters.key(meter); if (!thing) return; diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h index 1764b44..dd9ae7c 100644 --- a/energymeters/integrationpluginenergymeters.h +++ b/energymeters/integrationpluginenergymeters.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. diff --git a/energymeters/integrationpluginenergymeters.json b/energymeters/integrationpluginenergymeters.json index 7ad8198..8878bc5 100644 --- a/energymeters/integrationpluginenergymeters.json +++ b/energymeters/integrationpluginenergymeters.json @@ -39,7 +39,7 @@ "id": "c75b2c31-6ec3-49ab-8c8f-5231d0a7e941", "name": "slaveAddress", "displayName": "Modbus slave address", - "type": "int", + "type": "uint", "defaultValue": 1 }, { @@ -188,7 +188,7 @@ "id": "ac77ea98-b006-486e-a3e8-b30a483f26c1", "name": "slaveAddress", "displayName": "Modbus slave address", - "type": "int", + "type": "uint", "defaultValue": 1 }, { diff --git a/energymeters/registerdescriptor.h b/energymeters/registerdescriptor.h index 868a221..d330b3f 100644 --- a/energymeters/registerdescriptor.h +++ b/energymeters/registerdescriptor.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. From 278e7febcd0d0f96b62b92998bedef523a3b7fc3 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Fri, 7 May 2021 11:01:28 +0200 Subject: [PATCH 24/26] added producer interface and more debug output --- energymeters/integrationpluginenergymeters.cpp | 7 +++++-- energymeters/integrationpluginenergymeters.json | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index 8b68f1d..91eb130 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -173,8 +173,8 @@ void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) 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] { - qCDebug(dcEnergyMeters()) << "Reply received, setup finished"; + connect(meter, &EnergyMeter::consumedEnergyReceived, info, [this, info, meter] (double energy) { + qCDebug(dcEnergyMeters()) << "Consumed energy receieved" << energy << "Setup finished"; connect(meter, &EnergyMeter::connectedChanged, this, &IntegrationPluginEnergyMeters::onConnectionStateChanged); connect(meter, &EnergyMeter::voltageL1Received, this, &IntegrationPluginEnergyMeters::onVoltageL1Received); connect(meter, &EnergyMeter::voltageL2Received, this, &IntegrationPluginEnergyMeters::onVoltageL2Received); @@ -203,6 +203,8 @@ void IntegrationPluginEnergyMeters::postSetupThing(Thing *thing) if (m_energyMeters.contains(thing)) { startUpdateCycle(m_energyMeters.value(thing)); + } else { + qCWarning(dcEnergyMeters()) << "Thing has no energy meter connection and will not work properly"; } } @@ -272,6 +274,7 @@ void IntegrationPluginEnergyMeters::onConnectionStateChanged(bool status) if (!status) { updateCycleFinished(meter); } + qCDebug(dcEnergyMeters()) << "Connection status changed" << thing->name() << status; thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), status); } diff --git a/energymeters/integrationpluginenergymeters.json b/energymeters/integrationpluginenergymeters.json index 8878bc5..d6b23fc 100644 --- a/energymeters/integrationpluginenergymeters.json +++ b/energymeters/integrationpluginenergymeters.json @@ -24,7 +24,7 @@ "displayName": "PRO380-Mod", "id": "d7c6440b-54f9-4cc0-a96b-9bb7304b3e77", "createMethods": ["discovery"], - "interfaces": ["extendedsmartmeterconsumer"], + "interfaces": ["extendedsmartmeterconsumer", "extendedsmartmeterproducer"], "discoveryParamTypes": [ { "id": "a29f37f6-b344-4628-8ab4-8f4c18fada4a", @@ -173,7 +173,7 @@ "displayName": "SDM630Modbus", "id": "f37597bb-35fe-48f2-9617-343dd54c0903", "createMethods": ["discovery"], - "interfaces": ["extendedsmartmeterconsumer"], + "interfaces": ["extendedsmartmeterconsumer", "extendedsmartmeterproducer"], "discoveryParamTypes": [ { "id": "6ab43559-53ec-47ba-b8a0-8d3b7f8d90c2", From 807a472b573e3125456506fde20b92b45806f890 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Sun, 9 May 2021 22:44:46 +0200 Subject: [PATCH 25/26] improved connection state and added more debug output --- energymeters/energymeter.cpp | 40 ++++++++++++------- energymeters/energymeter.h | 1 + .../integrationpluginenergymeters.cpp | 12 ++++-- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp index cfb94b5..2d5991b 100644 --- a/energymeters/energymeter.cpp +++ b/energymeters/energymeter.cpp @@ -39,7 +39,7 @@ EnergyMeter::EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const m_slaveAddress(slaveAddress), m_modbusRegisters(modbusRegisters) { - + qCDebug(dcEnergyMeters()) << "EnergyMeter: Creating new meter connection, address:" << slaveAddress; } ModbusRtuMaster *EnergyMeter::modbusMaster() @@ -114,14 +114,23 @@ bool EnergyMeter::getEnergyConsumed() bool EnergyMeter::getRegister(ModbusRegisterType type) { - if (!m_modbusRegisters.contains(type)) + if (!m_modbusRegisters.contains(type)) { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Register type not supported" << type; + setConnectionStatus(false); return false; + } - if (!m_modbusRtuMaster) + if (!m_modbusRtuMaster) { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus RTU interface not available"; + setConnectionStatus(false); return false; + } - if (!m_modbusRtuMaster->connected()) + if (!m_modbusRtuMaster->connected()) { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus RTU interface not connected"; + setConnectionStatus(false); return false; + } ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(type); @@ -134,16 +143,9 @@ bool EnergyMeter::getRegister(ModbusRegisterType type) connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); connect(reply, &ModbusRtuReply::finished, this, [reply, type, descriptor, this] { if (reply->error() != ModbusRtuReply::NoError) { - if (m_connected) { - m_connected = false; - emit connectedChanged(m_connected); - } + qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus RTU reply error" << reply->errorString(); + setConnectionStatus(false); return; - } else { - if (!m_connected) { - m_connected = true; - emit connectedChanged(m_connected); - } } modbus_32_t value; value.u = 0; @@ -153,9 +155,11 @@ bool EnergyMeter::getRegister(ModbusRegisterType type) if (descriptor.dataType() == "float") { value.u = static_cast(static_cast(reply->result().at(0)) << 16 | reply->result().at(1)); } else { - qCWarning(dcEnergyMeters()) << "Data type not supported" << descriptor.dataType(); + qCWarning(dcEnergyMeters()) << "EnergyMeter: Data type not supported" << descriptor.dataType(); } } else { + qCWarning(dcEnergyMeters()) << "EnergyMeter: Reply length invalid" << reply->result().length(); + setConnectionStatus(false); return; } @@ -214,6 +218,14 @@ bool EnergyMeter::getRegister(ModbusRegisterType type) 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 index 208fb23..974fb72 100644 --- a/energymeters/energymeter.h +++ b/energymeters/energymeter.h @@ -74,6 +74,7 @@ private: QHash m_modbusRegisters; bool getRegister(ModbusRegisterType type); + void setConnectionStatus(bool connected); signals: void connectedChanged(bool connected); diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index 91eb130..78903cd 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -126,7 +126,7 @@ void IntegrationPluginEnergyMeters::discoverThings(ThingDiscoveryInfo *info) } uint slaveAddress = info->params().paramValue(m_discoverySlaveAddressParamTypeIds.value(info->thingClassId())).toUInt(); if (slaveAddress > 254 || slaveAddress == 0) { - info->finish(Thing::ThingErrorInvalidParameter, tr("Modbus slave address must be between 1 and 254")); + info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("Modbus slave address must be between 1 and 254")); return; } Q_FOREACH(ModbusRtuMaster *modbusMaster, hardwareManager()->modbusRtuResource()->modbusRtuMasters()) { @@ -174,7 +174,7 @@ void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) 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 receieved" << energy << "Setup finished"; + 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); @@ -209,15 +209,18 @@ void IntegrationPluginEnergyMeters::postSetupThing(Thing *thing) } 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) + 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); } } @@ -247,6 +250,7 @@ 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; } } From 8f281ed30491d6e1fe4d169ba0ce5a6c8377f636 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Tue, 25 May 2021 21:25:49 +0200 Subject: [PATCH 26/26] fixed bg e-tech energy meter register map --- energymeters/bg-etechmodbusregister.h | 22 +++++++++++----------- energymeters/inepromodbusregister.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/energymeters/bg-etechmodbusregister.h b/energymeters/bg-etechmodbusregister.h index 34bd78f..b16c4eb 100644 --- a/energymeters/bg-etechmodbusregister.h +++ b/energymeters/bg-etechmodbusregister.h @@ -34,17 +34,17 @@ #include "registerdescriptor.h" static const QHash sdm630RegisterMap { - {ModbusRegisterType::VoltageL1, ModbusRegisterDescriptor(30001, 4, 2, "V", "float")}, - {ModbusRegisterType::VoltageL2, ModbusRegisterDescriptor(30003, 4, 2, "V", "float")}, - {ModbusRegisterType::VoltageL3, ModbusRegisterDescriptor(30005, 4, 2, "V", "float")}, - {ModbusRegisterType::CurrentL1, ModbusRegisterDescriptor(30007, 4, 2, "A", "float")}, - {ModbusRegisterType::CurrentL2, ModbusRegisterDescriptor(30009, 4, 2, "A", "float")}, - {ModbusRegisterType::CurrentL3, ModbusRegisterDescriptor(30011, 4, 2, "A", "float")}, - {ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(30053, 4, 2, "W", "float")}, //Total system power - {ModbusRegisterType::Frequency, ModbusRegisterDescriptor(30071, 4, 2, "Hz", "float")}, - {ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(30067, 4, 2, "Degree", "float")}, //Total system phase angle - {ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(30073, 4, 2, "kWh", "float")}, //Total Import kWh - {ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(30075, 4, 2, "kWh", "float")} //Total Export kWh + {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/inepromodbusregister.h b/energymeters/inepromodbusregister.h index e419c9d..b6071b4 100644 --- a/energymeters/inepromodbusregister.h +++ b/energymeters/inepromodbusregister.h @@ -41,7 +41,7 @@ static const QHash pro380RegisterM {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, "Degree", "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 };