From 0ef3940c45364e994f1a5e0c1a089a062ec9d7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 10 Nov 2021 16:50:48 +0100 Subject: [PATCH] Migrate SDM630 Migrate PRO380 to energymeter interface --- energymeters/README.md | 10 +- energymeters/bg-etechmodbusregister.h | 50 -- energymeters/energymeter.cpp | 231 ------ energymeters/energymeter.h | 95 --- energymeters/energymeters.pro | 22 +- energymeters/inepromodbusregister.h | 49 -- .../integrationpluginenergymeters.cpp | 513 ++++++------ energymeters/integrationpluginenergymeters.h | 48 +- .../integrationpluginenergymeters.json | 264 ++++-- energymeters/meta.json | 4 +- energymeters/pro380-registers.json | 266 ++++++ energymeters/pro380modbusrtuconnection.cpp | 537 ++++++++++++ energymeters/pro380modbusrtuconnection.h | 204 +++++ energymeters/registerdescriptor.h | 87 -- energymeters/sdm630-registers.json | 260 ++++++ energymeters/sdm630modbusrtuconnection.cpp | 455 +++++++++++ energymeters/sdm630modbusrtuconnection.h | 199 +++++ ...56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts | 596 +++++++++----- ...95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts | 582 ++++++++----- modbus/tools/README.md | 55 +- modbus/tools/generate-connection.py | 772 ++++++++++++++---- 21 files changed, 3822 insertions(+), 1477 deletions(-) delete mode 100644 energymeters/bg-etechmodbusregister.h delete mode 100644 energymeters/energymeter.cpp delete mode 100644 energymeters/energymeter.h delete mode 100644 energymeters/inepromodbusregister.h create mode 100644 energymeters/pro380-registers.json create mode 100644 energymeters/pro380modbusrtuconnection.cpp create mode 100644 energymeters/pro380modbusrtuconnection.h delete mode 100644 energymeters/registerdescriptor.h create mode 100644 energymeters/sdm630-registers.json create mode 100644 energymeters/sdm630modbusrtuconnection.cpp create mode 100644 energymeters/sdm630modbusrtuconnection.h diff --git a/energymeters/README.md b/energymeters/README.md index 0c90177..9f0e154 100644 --- a/energymeters/README.md +++ b/energymeters/README.md @@ -2,14 +2,20 @@ Connect Modbus RTU based energy meters. -## Supported Things +Once you configured in the system settings a Modbus RTU resource using the configured settings of your meter, you can start adding the energy meter to your system. + +While discovering, nymea will offer you the configured modbus resources as possible connections. + + +## Supported things * b+g e-tech * SDM630Modbus * inepro Metering * PRO380-Mod + ## Requirements -* The plugin 'nymea-plugin-energymeter' must be installed. +* The plugin 'nymea-plugin-energymeters' must be installed. * At least one Modbus RTU interface must be setup. diff --git a/energymeters/bg-etechmodbusregister.h b/energymeters/bg-etechmodbusregister.h deleted file mode 100644 index b16c4eb..0000000 --- a/energymeters/bg-etechmodbusregister.h +++ /dev/null @@ -1,50 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef BGETECHMODBUSREGISTER_H -#define BGETECHMODBUSREGISTER_H - -#include "registerdescriptor.h" - -static const QHash sdm630RegisterMap { - {ModbusRegisterType::VoltageL1, ModbusRegisterDescriptor(0x00, 4, 2, "V", "float")}, - {ModbusRegisterType::VoltageL2, ModbusRegisterDescriptor(0x02, 4, 2, "V", "float")}, - {ModbusRegisterType::VoltageL3, ModbusRegisterDescriptor(0x04, 4, 2, "V", "float")}, - {ModbusRegisterType::CurrentL1, ModbusRegisterDescriptor(0x06, 4, 2, "A", "float")}, - {ModbusRegisterType::CurrentL2, ModbusRegisterDescriptor(0x08, 4, 2, "A", "float")}, - {ModbusRegisterType::CurrentL3, ModbusRegisterDescriptor(0x0A, 4, 2, "A", "float")}, - {ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(0x34, 4, 2, "W", "float")}, //Total system power - {ModbusRegisterType::Frequency, ModbusRegisterDescriptor(0x46, 4, 2, "Hz", "float")}, - {ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(0x3E, 4, 2, "", "float")}, //Total system power factor - {ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(0x48, 4, 2, "kWh", "float")}, //Total Import kWh - {ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(0x4A, 4, 2, "kWh", "float")} //Total Export kWh -}; - -#endif // BGETECHMODBUSREGISTER_H diff --git a/energymeters/energymeter.cpp b/energymeters/energymeter.cpp deleted file mode 100644 index 2d5991b..0000000 --- a/energymeters/energymeter.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "energymeter.h" -#include "hardware/modbus/modbusrtureply.h" - -#include "extern-plugininfo.h" - -EnergyMeter::EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const QHash &modbusRegisters, QObject *parent) : - QObject(parent), - m_modbusRtuMaster(modbusMaster), - m_slaveAddress(slaveAddress), - m_modbusRegisters(modbusRegisters) -{ - qCDebug(dcEnergyMeters()) << "EnergyMeter: Creating new meter connection, address:" << slaveAddress; -} - -ModbusRtuMaster *EnergyMeter::modbusMaster() -{ - return m_modbusRtuMaster; -} - -void EnergyMeter::setModbusMaster(ModbusRtuMaster *modbusMaster) -{ - m_modbusRtuMaster = modbusMaster; -} - -bool EnergyMeter::connected() const -{ - return m_connected; -} - -bool EnergyMeter::getVoltageL1() -{ - return getRegister(ModbusRegisterType::VoltageL1); -} - -bool EnergyMeter::getVoltageL2() -{ - return getRegister(ModbusRegisterType::VoltageL2); -} - -bool EnergyMeter::getVoltageL3() -{ - return getRegister(ModbusRegisterType::VoltageL3); -} - -bool EnergyMeter::getCurrentL1() -{ - return getRegister(ModbusRegisterType::CurrentL1); -} - -bool EnergyMeter::getCurrentL2() -{ - return getRegister(ModbusRegisterType::CurrentL2); -} - -bool EnergyMeter::getCurrentL3() -{ - return getRegister(ModbusRegisterType::CurrentL3); -} - -bool EnergyMeter::getFrequency() -{ - return getRegister(ModbusRegisterType::Frequency); -} - -bool EnergyMeter::getPowerFactor() -{ - return getRegister(ModbusRegisterType::PowerFactor); -} - -bool EnergyMeter::getActivePower() -{ - return getRegister(ModbusRegisterType::ActivePower); -} - -bool EnergyMeter::getEnergyProduced() -{ - return getRegister(ModbusRegisterType::EnergyProduced); -} - -bool EnergyMeter::getEnergyConsumed() -{ - return getRegister(ModbusRegisterType::EnergyConsumed); -} - -bool EnergyMeter::getRegister(ModbusRegisterType type) -{ - if (!m_modbusRegisters.contains(type)) { - qCWarning(dcEnergyMeters()) << "EnergyMeter: Register type not supported" << type; - setConnectionStatus(false); - return false; - } - - if (!m_modbusRtuMaster) { - qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus RTU interface not available"; - setConnectionStatus(false); - return false; - } - - if (!m_modbusRtuMaster->connected()) { - qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus RTU interface not connected"; - setConnectionStatus(false); - return false; - } - - ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(type); - - ModbusRtuReply *reply = nullptr; - if (descriptor.functionCode() == 3){ - reply = m_modbusRtuMaster->readHoldingRegister(m_slaveAddress, descriptor.address(), descriptor.length()); - } else if (descriptor.functionCode() == 4){ - reply = m_modbusRtuMaster->readInputRegister(m_slaveAddress, descriptor.address(), descriptor.length()); - } - connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater); - connect(reply, &ModbusRtuReply::finished, this, [reply, type, descriptor, this] { - if (reply->error() != ModbusRtuReply::NoError) { - qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus RTU reply error" << reply->errorString(); - setConnectionStatus(false); - return; - } - modbus_32_t value; - value.u = 0; - if (reply->result().length() == 1) { - value.u = static_cast(reply->result().at(0)); - } else if (reply->result().length() == 2) { - if (descriptor.dataType() == "float") { - value.u = static_cast(static_cast(reply->result().at(0)) << 16 | reply->result().at(1)); - } else { - qCWarning(dcEnergyMeters()) << "EnergyMeter: Data type not supported" << descriptor.dataType(); - } - } else { - qCWarning(dcEnergyMeters()) << "EnergyMeter: Reply length invalid" << reply->result().length(); - setConnectionStatus(false); - return; - } - - if (type == ModbusRegisterType::VoltageL1) { - if (descriptor.unit() == "mV") - value.f /= 1000.00; - - emit voltageL1Received(value.f); - } else if (type == ModbusRegisterType::VoltageL2) { - if (descriptor.unit() == "mV") - value.f /= 1000.00; - - emit voltageL2Received(value.f); - } else if (type == ModbusRegisterType::VoltageL3) { - if (descriptor.unit() == "mV") - value.f /= 1000.00; - - emit voltageL3Received(value.f); - } else if (type == ModbusRegisterType::CurrentL1) { - if (descriptor.unit() == "mA") - value.f /= 1000.00; - - emit currentL1Received(value.f); - } else if (type == ModbusRegisterType::CurrentL2) { - if (descriptor.unit() == "mA") - value.f /= 1000.00; - - emit currentL2Received(value.f); - } else if (type == ModbusRegisterType::CurrentL3) { - if (descriptor.unit() == "mA") - value.f /= 1000.00; - - emit currentL3Received(value.f); - } else if (type == ModbusRegisterType::ActivePower) { - if (descriptor.unit() == "kW") { - value.f *= 1000; - } else if (descriptor.unit() == "mW") { - value.f /= 1000.00; - } - emit activePowerReceived(value.f); - } else if (type == ModbusRegisterType::PowerFactor) { - emit powerFactorReceived(value.f); - } else if (type == ModbusRegisterType::Frequency) { - emit frequencyReceived(value.f); - } else if (type == ModbusRegisterType::EnergyConsumed) { - if (descriptor.unit() == "Wh") { - value.f /= 1000.00; - } - emit consumedEnergyReceived(value.f); - } else if (type == ModbusRegisterType::EnergyProduced) { - if (descriptor.unit() == "Wh") { - value.f /= 1000.00; - } - emit producedEnergyReceived(value.f); - } else { - qCWarning(dcEnergyMeters()) << "EnergyMeter: Modbus register type not handled" << type; - } - }); - setConnectionStatus(true); - return true; -} - -void EnergyMeter::setConnectionStatus(bool connected) -{ - if (connected != m_connected) { - m_connected = connected; - emit connectedChanged(m_connected); - } -} diff --git a/energymeters/energymeter.h b/energymeters/energymeter.h deleted file mode 100644 index 974fb72..0000000 --- a/energymeters/energymeter.h +++ /dev/null @@ -1,95 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef ENERGYMETER_H -#define ENERGYMETER_H - -#include -#include - -#include "registerdescriptor.h" -#include "hardware/modbus/modbusrtumaster.h" - -class EnergyMeter : public QObject -{ - Q_OBJECT -public: - explicit EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const QHash &modbusRegisters, QObject *parent = nullptr); - - ModbusRtuMaster *modbusMaster(); - void setModbusMaster(ModbusRtuMaster *modbusMaster); - - bool connected() const; - bool getVoltageL1(); - bool getVoltageL2(); - bool getVoltageL3(); - bool getCurrentL1(); - bool getCurrentL2(); - bool getCurrentL3(); - bool getFrequency(); - bool getPowerFactor(); - bool getActivePower(); - bool getEnergyProduced(); - bool getEnergyConsumed(); - -private: - typedef union { - int32_t s; - uint32_t u; - float f; - } modbus_32_t; - - bool m_connected = false; - - ModbusRtuMaster *m_modbusRtuMaster = nullptr; - int m_slaveAddress; - - QHash m_modbusRegisters; - - bool getRegister(ModbusRegisterType type); - void setConnectionStatus(bool connected); - -signals: - void connectedChanged(bool connected); - - void voltageL1Received(double voltage); - void voltageL2Received(double voltage); - void voltageL3Received(double voltage); - void currentL1Received(double current); - void currentL2Received(double current); - void currentL3Received(double current); - void frequencyReceived(double freqeuncy); - void activePowerReceived(double power); - void powerFactorReceived(double powerFactor); - void producedEnergyReceived(double energy); - void consumedEnergyReceived(double energy); -}; - -#endif // ENERGYMETER_H diff --git a/energymeters/energymeters.pro b/energymeters/energymeters.pro index 17d879f..9dd6c12 100644 --- a/energymeters/energymeters.pro +++ b/energymeters/energymeters.pro @@ -1,16 +1,16 @@ include(../plugins.pri) -QT += \ - serialport \ - serialbus \ - -SOURCES += \ - energymeter.cpp \ - integrationpluginenergymeters.cpp +QT += serialport serialbus HEADERS += \ - energymeter.h \ integrationpluginenergymeters.h \ - inepromodbusregister.h \ - bg-etechmodbusregister.h \ - registerdescriptor.h + sdm630modbusrtuconnection.h \ + pro380modbusrtuconnection.h \ + ../modbus/modbusdatautils.h + +SOURCES += \ + integrationpluginenergymeters.cpp \ + sdm630modbusrtuconnection.cpp \ + pro380modbusrtuconnection.cpp \ + ../modbus/modbusdatautils.cpp + diff --git a/energymeters/inepromodbusregister.h b/energymeters/inepromodbusregister.h deleted file mode 100644 index b6071b4..0000000 --- a/energymeters/inepromodbusregister.h +++ /dev/null @@ -1,49 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef INEPROMODBUSREGISTER_H -#define INEPROMODBUSREGISTER_H -#include "registerdescriptor.h" - -static const QHash pro380RegisterMap { - {ModbusRegisterType::VoltageL1, ModbusRegisterDescriptor(0x5002, 3, 2, "V", "float")}, //L1 Voltage - {ModbusRegisterType::VoltageL2, ModbusRegisterDescriptor(0x5004, 3, 2, "V", "float")}, //L2 Voltage - {ModbusRegisterType::VoltageL3, ModbusRegisterDescriptor(0x5006, 3, 2, "V", "float")}, //L3 Voltage - {ModbusRegisterType::CurrentL1, ModbusRegisterDescriptor(0x500C, 3, 2, "A", "float")}, //L1 Current - {ModbusRegisterType::CurrentL2, ModbusRegisterDescriptor(0x500E, 3, 2, "A", "float")}, //L2 Current - {ModbusRegisterType::CurrentL3, ModbusRegisterDescriptor(0x5010, 3, 2, "A", "float")}, //L3 Current - {ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(0x5012, 3, 2, "kW", "float")}, //Total active power - {ModbusRegisterType::Frequency, ModbusRegisterDescriptor(0x5008, 3, 2, "Hz", "float")}, - {ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(0x502A, 3, 2, "", "float")}, - {ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(0x600C, 3, 2, "kWh", "float")}, //Forward active energy - {ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(0x6018, 3, 2, "kWh", "float")} //Reverse active energy -}; - -#endif //INEPROMODBUSREGISTER_H diff --git a/energymeters/integrationpluginenergymeters.cpp b/energymeters/integrationpluginenergymeters.cpp index 78903cd..01272ad 100644 --- a/energymeters/integrationpluginenergymeters.cpp +++ b/energymeters/integrationpluginenergymeters.cpp @@ -31,63 +31,19 @@ #include "integrationpluginenergymeters.h" #include "plugininfo.h" -#include "bg-etechmodbusregister.h" -#include "inepromodbusregister.h" - IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters() { - /* - * NOTE: - * To add an new device model, the integrationplugin json file must be extended with the new model and vendor. - * Then add the new states and params to the lists here, also add the modbus register configuration file -*/ m_slaveIdParamTypeIds.insert(pro380ThingClassId, pro380ThingSlaveAddressParamTypeId); m_slaveIdParamTypeIds.insert(sdm630ThingClassId, sdm630ThingSlaveAddressParamTypeId); m_modbusUuidParamTypeIds.insert(pro380ThingClassId, pro380ThingModbusMasterUuidParamTypeId); m_modbusUuidParamTypeIds.insert(sdm630ThingClassId, sdm630ThingModbusMasterUuidParamTypeId); - m_connectionStateTypeIds.insert(pro380ThingClassId, pro380ConnectedStateTypeId); - m_connectionStateTypeIds.insert(sdm630ThingClassId, sdm630ConnectedStateTypeId); - - m_voltageL1StateTypeIds.insert(pro380ThingClassId, pro380VoltageL1StateTypeId); - m_voltageL1StateTypeIds.insert(sdm630ThingClassId, sdm630VoltageL1StateTypeId); - - m_voltageL2StateTypeIds.insert(pro380ThingClassId, pro380VoltageL2StateTypeId); - m_voltageL2StateTypeIds.insert(sdm630ThingClassId, sdm630VoltageL2StateTypeId); - - m_voltageL3StateTypeIds.insert(pro380ThingClassId, pro380VoltageL3StateTypeId); - m_voltageL3StateTypeIds.insert(sdm630ThingClassId, sdm630VoltageL3StateTypeId); - - m_currentL1StateTypeIds.insert(pro380ThingClassId, pro380CurrentL1StateTypeId); - m_currentL1StateTypeIds.insert(sdm630ThingClassId, sdm630CurrentL1StateTypeId); - - m_currentL2StateTypeIds.insert(pro380ThingClassId, pro380CurrentL2StateTypeId); - m_currentL2StateTypeIds.insert(sdm630ThingClassId, sdm630CurrentL2StateTypeId); - - m_currentL3StateTypeIds.insert(pro380ThingClassId, pro380CurrentL3StateTypeId); - m_currentL3StateTypeIds.insert(sdm630ThingClassId, sdm630CurrentL3StateTypeId); - - m_activePowerStateTypeIds.insert(pro380ThingClassId, pro380CurrentPowerEventTypeId); - m_activePowerStateTypeIds.insert(sdm630ThingClassId, sdm630CurrentPowerStateTypeId); - - m_frequencyStateTypeIds.insert(pro380ThingClassId, pro380FrequencyStateTypeId); - m_frequencyStateTypeIds.insert(sdm630ThingClassId, sdm630FrequencyStateTypeId); - - m_powerFactorStateTypeIds.insert(pro380ThingClassId, pro380PowerFactorStateTypeId); - m_powerFactorStateTypeIds.insert(sdm630ThingClassId, sdm630PowerFactorStateTypeId); - - m_totalEnergyConsumedStateTypeIds.insert(pro380ThingClassId, pro380TotalEnergyConsumedEventTypeId); - m_totalEnergyConsumedStateTypeIds.insert(sdm630ThingClassId, sdm630TotalEnergyConsumedEventTypeId); - - m_totalEnergyProducedStateTypeIds.insert(pro380ThingClassId, pro380TotalEnergyProducedStateTypeId); - m_totalEnergyProducedStateTypeIds.insert(sdm630ThingClassId, sdm630TotalEnergyProducedStateTypeId); - m_discoverySlaveAddressParamTypeIds.insert(pro380ThingClassId, pro380DiscoverySlaveAddressParamTypeId); m_discoverySlaveAddressParamTypeIds.insert(sdm630ThingClassId, sdm630DiscoverySlaveAddressParamTypeId); - m_registerMaps.insert(pro380ThingClassId, pro380RegisterMap); - m_registerMaps.insert(sdm630ThingClassId, sdm630RegisterMap); + m_connectionStateTypeIds.insert(pro380ThingClassId, pro380ConnectedStateTypeId); + m_connectionStateTypeIds.insert(sdm630ThingClassId, sdm630ConnectedStateTypeId); } void IntegrationPluginEnergyMeters::init() @@ -95,16 +51,17 @@ void IntegrationPluginEnergyMeters::init() connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=] (const QUuid &modbusUuid){ qCDebug(dcEnergyMeters()) << "Modbus RTU master has been removed" << modbusUuid.toString(); - Q_FOREACH(Thing *thing, myThings()) { + foreach (Thing *thing, myThings()) { if (m_modbusUuidParamTypeIds.contains(thing->thingClassId())) { if (thing->paramValue(m_modbusUuidParamTypeIds.value(thing->thingClassId())) == modbusUuid) { qCWarning(dcEnergyMeters()) << "Modbus RTU hardware resource removed for" << thing << ". The thing will not be functional any more until a new resource has been configured for it."; thing->setStateValue(m_connectionStateTypeIds[thing->thingClassId()], false); - EnergyMeter *meter = m_energyMeters.value(thing); - if (!meter) - return; - meter->setModbusMaster(nullptr); + if (thing->thingClassId() == sdm630ThingClassId) { + delete m_sdmConnections.take(thing); + } else if (thing->thingClassId() == pro380ThingClassId) { + delete m_ineproConnections.take(thing); + } } } } @@ -113,34 +70,33 @@ void IntegrationPluginEnergyMeters::init() void IntegrationPluginEnergyMeters::discoverThings(ThingDiscoveryInfo *info) { - qCDebug(dcEnergyMeters()) << "Discover things"; - QList thingDescriptors; - + qCDebug(dcEnergyMeters()) << "Discover modbus RTU resources..."; if (hardwareManager()->modbusRtuResource()->modbusRtuMasters().isEmpty()) { info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("No Modbus RTU interface available.")); return; } - if (!m_connectionStateTypeIds.contains(info->thingClassId())) { - Q_ASSERT_X(false, "discoverThings", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8()); - } + Q_ASSERT_X(m_connectionStateTypeIds.contains(info->thingClassId()), "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()) { + + foreach (ModbusRtuMaster *modbusMaster, hardwareManager()->modbusRtuResource()->modbusRtuMasters()) { qCDebug(dcEnergyMeters()) << "Found RTU master resource" << modbusMaster << "connected" << modbusMaster->connected(); - if (!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()); + + 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; } @@ -148,84 +104,235 @@ void IntegrationPluginEnergyMeters::discoverThings(ThingDiscoveryInfo *info) void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); - qCDebug(dcEnergyMeters()) << "Setup thing" << thing->name(); + qCDebug(dcEnergyMeters()) << "Setup thing" << thing << thing->params(); + Q_ASSERT_X(m_connectionStateTypeIds.contains(thing->thingClassId()), "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); - 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")); + info->finish(Thing::ThingErrorSetupFailed, QT_TR_NOOP("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.")); + info->finish(Thing::ThingErrorSetupFailed, QT_TR_NOOP("Modbus RTU resource not available.")); return; } - EnergyMeter *meter = new EnergyMeter(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), address, m_registerMaps.value(thing->thingClassId()), this); - connect(info, &ThingSetupInfo::aborted, meter, &EnergyMeter::deleteLater); - connect(meter, &EnergyMeter::consumedEnergyReceived, info, [this, info, meter] (double energy) { - qCDebug(dcEnergyMeters()) << "Consumed energy received" << energy << "Setup finished"; - connect(meter, &EnergyMeter::connectedChanged, this, &IntegrationPluginEnergyMeters::onConnectionStateChanged); - connect(meter, &EnergyMeter::voltageL1Received, this, &IntegrationPluginEnergyMeters::onVoltageL1Received); - connect(meter, &EnergyMeter::voltageL2Received, this, &IntegrationPluginEnergyMeters::onVoltageL2Received); - connect(meter, &EnergyMeter::voltageL3Received, this, &IntegrationPluginEnergyMeters::onVoltageL3Received); - connect(meter, &EnergyMeter::currentL1Received, this, &IntegrationPluginEnergyMeters::onCurrentL1Received); - connect(meter, &EnergyMeter::currentL2Received, this, &IntegrationPluginEnergyMeters::onCurrentL2Received); - connect(meter, &EnergyMeter::currentL3Received, this, &IntegrationPluginEnergyMeters::onCurrentL3Received); - connect(meter, &EnergyMeter::activePowerReceived, this, &IntegrationPluginEnergyMeters::onActivePowerReceived); - connect(meter, &EnergyMeter::powerFactorReceived, this, &IntegrationPluginEnergyMeters::onPowerFactorReceived); - connect(meter, &EnergyMeter::frequencyReceived, this, &IntegrationPluginEnergyMeters::onFrequencyReceived); - connect(meter, &EnergyMeter::producedEnergyReceived, this, &IntegrationPluginEnergyMeters::onProducedEnergyReceived); - connect(meter, &EnergyMeter::consumedEnergyReceived, this, &IntegrationPluginEnergyMeters::onConsumedEnergyReceived); + if (thing->thingClassId() == sdm630ThingClassId) { + if (m_sdmConnections.contains(thing)) { + qCDebug(dcEnergyMeters()) << "Setup after rediscovery, cleaning up ..."; + m_sdmConnections.take(thing)->deleteLater(); + } - m_energyMeters.insert(info->thing(), meter); + Sdm630ModbusRtuConnection *sdmConnection = new Sdm630ModbusRtuConnection(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), address, this); + connect(sdmConnection->modbusRtuMaster(), &ModbusRtuMaster::connectedChanged, this, [=](bool connected){ + if (connected) { + qCDebug(dcEnergyMeters()) << "Modbus RTU resource connected" << thing << sdmConnection->modbusRtuMaster()->serialPort(); + } else { + qCWarning(dcEnergyMeters()) << "Modbus RTU resource disconnected" << thing << sdmConnection->modbusRtuMaster()->serialPort(); + } + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::currentPhaseAChanged, this, [=](float currentPhaseA){ + thing->setStateValue(sdm630CurrentPhaseAStateTypeId, currentPhaseA); + thing->setStateValue(sdm630ConnectedStateTypeId, true); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::currentPhaseBChanged, this, [=](float currentPhaseB){ + thing->setStateValue(sdm630CurrentPhaseBStateTypeId, currentPhaseB); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::currentPhaseCChanged, this, [=](float currentPhaseC){ + thing->setStateValue(sdm630CurrentPhaseCStateTypeId, currentPhaseC); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::voltagePhaseAChanged, this, [=](float voltagePhaseA){ + thing->setStateValue(sdm630VoltagePhaseAStateTypeId, voltagePhaseA); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::voltagePhaseBChanged, this, [=](float voltagePhaseB){ + thing->setStateValue(sdm630VoltagePhaseBStateTypeId, voltagePhaseB); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::voltagePhaseCChanged, this, [=](float voltagePhaseC){ + thing->setStateValue(sdm630VoltagePhaseCStateTypeId, voltagePhaseC); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::totalCurrentPowerChanged, this, [=](float currentPower){ + thing->setStateValue(sdm630CurrentPowerStateTypeId, currentPower); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::powerPhaseAChanged, this, [=](float powerPhaseA){ + thing->setStateValue(sdm630CurrentPowerPhaseAStateTypeId, powerPhaseA); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::powerPhaseBChanged, this, [=](float powerPhaseB){ + thing->setStateValue(sdm630CurrentPowerPhaseBStateTypeId, powerPhaseB); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::powerPhaseCChanged, this, [=](float powerPhaseC){ + thing->setStateValue(sdm630CurrentPowerPhaseCStateTypeId, powerPhaseC); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::frequencyChanged, this, [=](float frequency){ + thing->setStateValue(sdm630FrequencyStateTypeId, frequency); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::totalEnergyConsumedChanged, this, [=](float totalEnergyConsumed){ + thing->setStateValue(sdm630TotalEnergyConsumedStateTypeId, totalEnergyConsumed); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::totalEnergyProducedChanged, this, [=](float totalEnergyProduced){ + thing->setStateValue(sdm630TotalEnergyProducedStateTypeId, totalEnergyProduced); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::energyProducedPhaseAChanged, this, [=](float energyProducedPhaseA){ + thing->setStateValue(sdm630EnergyProducedPhaseAStateTypeId, energyProducedPhaseA); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::energyProducedPhaseBChanged, this, [=](float energyProducedPhaseB){ + thing->setStateValue(sdm630EnergyProducedPhaseBStateTypeId, energyProducedPhaseB); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::energyProducedPhaseCChanged, this, [=](float energyProducedPhaseC){ + thing->setStateValue(sdm630EnergyProducedPhaseCStateTypeId, energyProducedPhaseC); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::energyConsumedPhaseAChanged, this, [=](float energyConsumedPhaseA){ + thing->setStateValue(sdm630EnergyConsumedPhaseAStateTypeId, energyConsumedPhaseA); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::energyConsumedPhaseBChanged, this, [=](float energyConsumedPhaseB){ + thing->setStateValue(sdm630EnergyConsumedPhaseBStateTypeId, energyConsumedPhaseB); + }); + + connect(sdmConnection, &Sdm630ModbusRtuConnection::energyConsumedPhaseCChanged, this, [=](float energyConsumedPhaseC){ + thing->setStateValue(sdm630EnergyConsumedPhaseCStateTypeId, energyConsumedPhaseC); + }); + + // FIXME: try to read before setup success + m_sdmConnections.insert(thing, sdmConnection); info->finish(Thing::ThingErrorNoError); - }); - meter->getEnergyConsumed(); - return; + + } else if (thing->thingClassId() == pro380ThingClassId) { + if (m_ineproConnections.contains(thing)) { + qCDebug(dcEnergyMeters()) << "Setup after rediscovery, cleaning up ..."; + m_ineproConnections.take(thing)->deleteLater(); + } + + Pro380ModbusRtuConnection *proConnection = new Pro380ModbusRtuConnection(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), address, this); + connect(proConnection->modbusRtuMaster(), &ModbusRtuMaster::connectedChanged, this, [=](bool connected){ + if (connected) { + qCDebug(dcEnergyMeters()) << "Modbus RTU resource connected" << thing << proConnection->modbusRtuMaster()->serialPort(); + } else { + qCWarning(dcEnergyMeters()) << "Modbus RTU resource disconnected" << thing << proConnection->modbusRtuMaster()->serialPort(); + } + }); + + connect(proConnection, &Pro380ModbusRtuConnection::currentPhaseAChanged, this, [=](float currentPhaseA){ + thing->setStateValue(pro380CurrentPhaseAStateTypeId, currentPhaseA); + thing->setStateValue(pro380ConnectedStateTypeId, true); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::currentPhaseBChanged, this, [=](float currentPhaseB){ + thing->setStateValue(pro380CurrentPhaseBStateTypeId, currentPhaseB); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::currentPhaseCChanged, this, [=](float currentPhaseC){ + thing->setStateValue(pro380CurrentPhaseCStateTypeId, currentPhaseC); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::voltagePhaseAChanged, this, [=](float voltagePhaseA){ + thing->setStateValue(pro380VoltagePhaseAStateTypeId, voltagePhaseA); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::voltagePhaseBChanged, this, [=](float voltagePhaseB){ + thing->setStateValue(pro380VoltagePhaseBStateTypeId, voltagePhaseB); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::voltagePhaseCChanged, this, [=](float voltagePhaseC){ + thing->setStateValue(pro380VoltagePhaseCStateTypeId, voltagePhaseC); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::totalCurrentPowerChanged, this, [=](float currentPower){ + thing->setStateValue(pro380CurrentPowerStateTypeId, currentPower * 1000); // kW + }); + + connect(proConnection, &Pro380ModbusRtuConnection::powerPhaseAChanged, this, [=](float powerPhaseA){ + thing->setStateValue(pro380CurrentPowerPhaseAStateTypeId, powerPhaseA * 1000); // kW + }); + + connect(proConnection, &Pro380ModbusRtuConnection::powerPhaseBChanged, this, [=](float powerPhaseB){ + thing->setStateValue(pro380CurrentPowerPhaseBStateTypeId, powerPhaseB * 1000); // kW + }); + + connect(proConnection, &Pro380ModbusRtuConnection::powerPhaseCChanged, this, [=](float powerPhaseC){ + thing->setStateValue(pro380CurrentPowerPhaseCStateTypeId, powerPhaseC * 1000); // kW + }); + + connect(proConnection, &Pro380ModbusRtuConnection::frequencyChanged, this, [=](float frequency){ + thing->setStateValue(pro380FrequencyStateTypeId, frequency); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::totalEnergyConsumedChanged, this, [=](float totalEnergyConsumed){ + thing->setStateValue(pro380TotalEnergyConsumedStateTypeId, totalEnergyConsumed); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::totalEnergyProducedChanged, this, [=](float totalEnergyProduced){ + thing->setStateValue(pro380TotalEnergyProducedStateTypeId, totalEnergyProduced); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::energyProducedPhaseAChanged, this, [=](float energyProducedPhaseA){ + thing->setStateValue(pro380EnergyProducedPhaseAStateTypeId, energyProducedPhaseA); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::energyProducedPhaseBChanged, this, [=](float energyProducedPhaseB){ + thing->setStateValue(pro380EnergyProducedPhaseBStateTypeId, energyProducedPhaseB); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::energyProducedPhaseCChanged, this, [=](float energyProducedPhaseC){ + thing->setStateValue(pro380EnergyProducedPhaseCStateTypeId, energyProducedPhaseC); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::energyConsumedPhaseAChanged, this, [=](float energyConsumedPhaseA){ + thing->setStateValue(pro380EnergyConsumedPhaseAStateTypeId, energyConsumedPhaseA); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::energyConsumedPhaseBChanged, this, [=](float energyConsumedPhaseB){ + thing->setStateValue(pro380EnergyConsumedPhaseBStateTypeId, energyConsumedPhaseB); + }); + + connect(proConnection, &Pro380ModbusRtuConnection::energyConsumedPhaseCChanged, this, [=](float energyConsumedPhaseC){ + thing->setStateValue(pro380EnergyConsumedPhaseCStateTypeId, energyConsumedPhaseC); + }); + + + // FIXME: try to read before setup success + m_ineproConnections.insert(thing, proConnection); + info->finish(Thing::ThingErrorNoError); + } } 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_refreshTimer) { + m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(2); + connect(m_refreshTimer, &PluginTimer::timeout, this, [this] { + foreach (Thing *thing, myThings().filterByThingClassId(sdm630ThingClassId)) { + m_sdmConnections.value(thing)->update(); + } - if (m_energyMeters.contains(thing)) { - startUpdateCycle(m_energyMeters.value(thing)); - } else { - qCWarning(dcEnergyMeters()) << "Thing has no energy meter connection and will not work properly"; - } - } - - if (!m_reconnectTimer) { - qCDebug(dcEnergyMeters()) << "Starting reconnect timer"; - m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(5); - connect(m_reconnectTimer, &PluginTimer::timeout, this, [this] { - foreach (Thing *thing, myThings()) { - if (m_connectionStateTypeIds.contains(thing->thingClassId())) { - if (!thing->stateValue(m_connectionStateTypeIds.value(thing->thingClassId())).toBool()) { - EnergyMeter *meter = m_energyMeters.value(thing); - if (!meter) { - qCWarning(dcEnergyMeters()) << "On reconnect timer, could not find any EnergyMeter connection for" << thing->name(); - continue; - } - qCDebug(dcEnergyMeters()) << "On reconnect timer, restarting update cycle for" << thing->name(); - startUpdateCycle(meter); - } - } + foreach (Thing *thing, myThings().filterByThingClassId(pro380ThingClassId)) { + m_sdmConnections.value(thing)->update(); } }); + + qCDebug(dcEnergyMeters()) << "Starting refresh timer..."; + m_refreshTimer->start(); } } @@ -233,171 +340,15 @@ void IntegrationPluginEnergyMeters::thingRemoved(Thing *thing) { qCDebug(dcEnergyMeters()) << "Thing removed" << thing->name(); - if (m_energyMeters.contains(thing)) { - EnergyMeter *meter = m_energyMeters.take(thing); - m_updateCycleInProgress.remove(meter); - meter->deleteLater(); - } + if (m_sdmConnections.contains(thing)) + m_sdmConnections.take(thing)->deleteLater(); - if (myThings().isEmpty() && m_reconnectTimer) { + if (m_ineproConnections.contains(thing)) + m_ineproConnections.take(thing)->deleteLater(); + + if (myThings().isEmpty() && m_refreshTimer) { qCDebug(dcEnergyMeters()) << "Stopping reconnect timer"; - hardwareManager()->pluginTimerManager()->unregisterTimer(m_reconnectTimer); - m_reconnectTimer = nullptr; + hardwareManager()->pluginTimerManager()->unregisterTimer(m_refreshTimer); + m_refreshTimer = nullptr; } } - -void IntegrationPluginEnergyMeters::startUpdateCycle(EnergyMeter *meter) -{ - if (m_updateCycleInProgress.contains(meter)) { - if (m_updateCycleInProgress.value(meter)) { - qCWarning(dcEnergyMeters()) << "Update cycle not startet, update cycle already in progress"; - return; - } - } - m_updateCycleInProgress.insert(meter, true); - meter->getVoltageL1(); -} - -void IntegrationPluginEnergyMeters::updateCycleFinished(EnergyMeter *meter) -{ - m_updateCycleInProgress.insert(meter, false); - - int updateInterval = configValue(energyMetersPluginUpdateIntervalParamTypeId).toInt(); - QTimer::singleShot(updateInterval, meter, [this, meter] { - startUpdateCycle(meter); // restart update cycle - }); -} - -void IntegrationPluginEnergyMeters::onConnectionStateChanged(bool status) -{ - EnergyMeter *meter = static_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - if (!status) { - updateCycleFinished(meter); - } - qCDebug(dcEnergyMeters()) << "Connection status changed" << thing->name() << status; - thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), status); -} - -void IntegrationPluginEnergyMeters::onVoltageL1Received(double voltage) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - meter->getVoltageL2(); - thing->setStateValue(m_voltageL1StateTypeIds.value(thing->thingClassId()), voltage); -} - -void IntegrationPluginEnergyMeters::onVoltageL2Received(double voltage) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - meter->getVoltageL3(); - thing->setStateValue(m_voltageL2StateTypeIds.value(thing->thingClassId()), voltage); -} - -void IntegrationPluginEnergyMeters::onVoltageL3Received(double voltage) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - meter->getCurrentL1(); - thing->setStateValue(m_voltageL3StateTypeIds.value(thing->thingClassId()), voltage); -} - -void IntegrationPluginEnergyMeters::onCurrentL1Received(double current) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - meter->getCurrentL2(); - thing->setStateValue(m_currentL1StateTypeIds.value(thing->thingClassId()), current); -} - -void IntegrationPluginEnergyMeters::onCurrentL2Received(double current) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - meter->getCurrentL3(); - thing->setStateValue(m_currentL2StateTypeIds.value(thing->thingClassId()), current); -} - -void IntegrationPluginEnergyMeters::onCurrentL3Received(double current) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - meter->getActivePower(); - thing->setStateValue(m_currentL3StateTypeIds.value(thing->thingClassId()), current); -} - -void IntegrationPluginEnergyMeters::onActivePowerReceived(double power) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - meter->getFrequency(); - thing->setStateValue(m_activePowerStateTypeIds.value(thing->thingClassId()), power); -} - -void IntegrationPluginEnergyMeters::onFrequencyReceived(double frequency) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - meter->getPowerFactor(); - thing->setStateValue(m_frequencyStateTypeIds.value(thing->thingClassId()), frequency); -} - -void IntegrationPluginEnergyMeters::onPowerFactorReceived(double powerFactor) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - meter->getEnergyProduced(); - thing->setStateValue(m_powerFactorStateTypeIds.value(thing->thingClassId()), powerFactor); -} - -void IntegrationPluginEnergyMeters::onProducedEnergyReceived(double energy) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - - meter->getEnergyConsumed(); - thing->setStateValue(m_totalEnergyProducedStateTypeIds.value(thing->thingClassId()), energy); -} - -void IntegrationPluginEnergyMeters::onConsumedEnergyReceived(double energy) -{ - EnergyMeter *meter = qobject_cast(sender()); - Thing *thing = m_energyMeters.key(meter); - if (!thing) - return; - updateCycleFinished(meter); - thing->setStateValue(m_totalEnergyConsumedStateTypeIds.value(thing->thingClassId()), energy); -} diff --git a/energymeters/integrationpluginenergymeters.h b/energymeters/integrationpluginenergymeters.h index dd9ae7c..c836b42 100644 --- a/energymeters/integrationpluginenergymeters.h +++ b/energymeters/integrationpluginenergymeters.h @@ -31,11 +31,12 @@ #ifndef INTEGRATIONPLUGINENERGYMETERS_H #define INTEGRATIONPLUGINENERGYMETERS_H -#include "integrations/integrationplugin.h" -#include "hardware/modbus/modbusrtuhardwareresource.h" -#include "plugintimer.h" +#include +#include +#include -#include "energymeter.h" +#include "sdm630modbusrtuconnection.h" +#include "pro380modbusrtuconnection.h" #include #include @@ -56,45 +57,16 @@ public: void thingRemoved(Thing *thing) override; private: - PluginTimer *m_reconnectTimer = nullptr; - QHash m_connectionStateTypeIds; - QHash m_voltageL1StateTypeIds; - QHash m_voltageL2StateTypeIds; - QHash m_voltageL3StateTypeIds; - QHash m_currentL1StateTypeIds; - QHash m_currentL2StateTypeIds; - QHash m_currentL3StateTypeIds; - QHash m_activePowerStateTypeIds; - QHash m_frequencyStateTypeIds; - QHash m_powerFactorStateTypeIds; - QHash m_totalEnergyConsumedStateTypeIds; - QHash m_totalEnergyProducedStateTypeIds; + PluginTimer *m_refreshTimer = nullptr; + + QHash m_sdmConnections; // sdm 630 + QHash m_ineproConnections; // pro 380 QHash m_discoverySlaveAddressParamTypeIds; QHash m_slaveIdParamTypeIds; QHash m_modbusUuidParamTypeIds; + QHash m_connectionStateTypeIds; - QHash> m_registerMaps; - - QHash m_energyMeters; - - QHash m_updateCycleInProgress; - void startUpdateCycle(EnergyMeter *meter); - void updateCycleFinished(EnergyMeter *meter); - -private slots: - void onConnectionStateChanged(bool status); - void onVoltageL1Received(double voltage); - void onVoltageL2Received(double voltage); - void onVoltageL3Received(double voltage); - void onCurrentL1Received(double current); - void onCurrentL2Received(double current); - void onCurrentL3Received(double current); - void onActivePowerReceived(double power); - void onFrequencyReceived(double frequency); - void onPowerFactorReceived(double powerFactor); - void onProducedEnergyReceived(double energy); - void onConsumedEnergyReceived(double energy); }; #endif // INTEGRATIONPLUGINENERGYMETERS_H diff --git a/energymeters/integrationpluginenergymeters.json b/energymeters/integrationpluginenergymeters.json index b9edb88..fb48126 100644 --- a/energymeters/integrationpluginenergymeters.json +++ b/energymeters/integrationpluginenergymeters.json @@ -2,17 +2,7 @@ "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 - } - ], + "paramTypes":[ ], "vendors": [ { "name": "ineproMetering", @@ -24,7 +14,7 @@ "displayName": "PRO380-Mod", "id": "d7c6440b-54f9-4cc0-a96b-9bb7304b3e77", "createMethods": ["discovery"], - "interfaces": ["smartmeterconsumer", "smartmeterproducer"], + "interfaces": ["energymeter", "connectable"], "discoveryParamTypes": [ { "id": "a29f37f6-b344-4628-8ab4-8f4c18fada4a", @@ -63,54 +53,54 @@ }, { "id": "04dba21a-7447-46b9-b9ae-095e5769e511", - "name": "voltageL1", - "displayName": "Voltage L1", - "displayNameEvent": "Voltage L1 changed", + "name": "voltagePhaseA", + "displayName": "Voltage phase A", + "displayNameEvent": "Voltage phase A changed", "type": "double", "unit": "Volt", "defaultValue": 0 }, { "id": "270d0c34-0a0c-4655-985f-faad6efd1afd", - "name": "voltageL2", - "displayName": "Voltage L2", - "displayNameEvent": "Voltage L2 changed", + "name": "voltagePhaseB", + "displayName": "Voltage phase B", + "displayNameEvent": "Voltage phase B changed", "type": "double", "unit": "Volt", "defaultValue": 0 }, { "id": "a1da8cfd-37cc-4c87-b857-e942cd90daec", - "name": "voltageL3", - "displayName": "Voltage L3", - "displayNameEvent": "Voltage L3 changed", + "name": "voltagePhaseC", + "displayName": "Voltage phase C", + "displayNameEvent": "Voltage phase C changed", "type": "double", "unit": "Volt", "defaultValue": 0 }, { "id": "1e077a3b-2dab-4ec4-ae96-ab49a564fe31", - "name": "currentL1", - "displayName": "Current L1", - "displayNameEvent": "Current L1 changed", + "name": "currentPhaseA", + "displayName": "Current phase A", + "displayNameEvent": "Current phase A changed", "type": "double", "unit": "Ampere", "defaultValue": 0 }, { "id": "d2f54061-0807-47de-944c-68c8118ece91", - "name": "currentL2", - "displayName": "Current L2", - "displayNameEvent": "Current L2 changed", + "name": "currentPhaseB", + "displayName": "Current phase B", + "displayNameEvent": "Current phase B changed", "type": "double", "unit": "Ampere", "defaultValue": 0 }, { "id": "610b20fb-2718-4f02-ac6e-12a9ef8c7615", - "name": "currentL3", - "displayName": "Current L3", - "displayNameEvent": "Current L3 changed", + "name": "currentPhaseC", + "displayName": "Current phase C", + "displayNameEvent": "Current phase C changed", "type": "double", "unit": "Ampere", "defaultValue": 0 @@ -118,19 +108,38 @@ { "id": "464eff60-11c2-46b7-98f5-1aa8172e5a2d", "name": "currentPower", - "displayName": "Active power", - "displayNameEvent": "Active power changed", + "displayName": "Current power", + "displayNameEvent": "Current power changed", "type": "double", "unit": "Watt", "defaultValue": 0 }, { - "id": "cdb34487-3d9b-492a-8c33-802f32a2e90e", - "name": "powerFactor", - "displayName": "Power factor", - "displayNameEvent": "Power factor changed", + "id": "55283773-0a4e-4574-b21a-d4a3f287eab1", + "name": "currentPowerPhaseA", + "displayName": "Current power phase A", + "displayNameEvent": "Current power phase A changed", "type": "double", - "defaultValue": 0.00 + "unit": "Watt", + "defaultValue": 0 + }, + { + "id": "8f15d104-5ff7-4c33-9cf9-fdbef4b6f721", + "name": "currentPowerPhaseB", + "displayName": "Current power phase B", + "displayNameEvent": "Current power phase B changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0 + }, + { + "id": "86c0f968-ee70-4f56-bdfc-33b8e2b134a4", + "name": "currentPowerPhaseC", + "displayName": "Current power phase C", + "displayNameEvent": "Current power phase C changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0 }, { "id": "bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5", @@ -158,6 +167,60 @@ "type": "double", "unit": "KiloWattHour", "defaultValue": 0.00 + }, + { + "id": "b16b3b0c-82d9-4b3c-a172-0e6631c8ce16", + "name": "energyConsumedPhaseA", + "displayName": "Energy consumed phase A", + "displayNameEvent": "Energy consumed phase A changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "64225f7f-9b2f-4bfc-87b2-38758804a28b", + "name": "energyConsumedPhaseB", + "displayName": "Energy consumed phase B", + "displayNameEvent": "Energy consumed phase B changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "a6e82d61-e837-4ec8-b14a-af0d49bea9d2", + "name": "energyConsumedPhaseC", + "displayName": "Energy consumed phase C", + "displayNameEvent": "Energy consumed phase C changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "95bd476e-c247-4f7d-ab01-d9f1b7c0d996", + "name": "energyProducedPhaseA", + "displayName": "Energy produced phase A", + "displayNameEvent": "Energy produced phase A changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "f0a0bd81-708c-48d6-b5c9-165464a5b309", + "name": "energyProducedPhaseB", + "displayName": "Energy produced phase B", + "displayNameEvent": "Energy produced phase B changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "c33fcd11-b4a9-44b2-9e30-40dfa2e4c9b1", + "name": "energyProducedPhaseC", + "displayName": "Energy produced phase C", + "displayNameEvent": "Energy produced phase C changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 } ] } @@ -170,10 +233,10 @@ "thingClasses": [ { "name": "sdm630", - "displayName": "SDM630Modbus", + "displayName": "SDM630 Modbus", "id": "f37597bb-35fe-48f2-9617-343dd54c0903", "createMethods": ["discovery"], - "interfaces": ["smartmeterconsumer", "smartmeterproducer"], + "interfaces": ["energymeter", "connectable"], "discoveryParamTypes": [ { "id": "6ab43559-53ec-47ba-b8a0-8d3b7f8d90c2", @@ -212,54 +275,54 @@ }, { "id": "db018146-0441-4dc0-9834-6d43ebaf8311", - "name": "voltageL1", - "displayName": "Voltage L1", - "displayNameEvent": "Voltage L1 changed", + "name": "voltagePhaseA", + "displayName": "Voltage phase A", + "displayNameEvent": "Voltage phase A changed", "type": "double", "unit": "Volt", "defaultValue": 0 }, { "id": "406f6d02-d5eb-49b3-87da-3247568e6054", - "name": "voltageL2", - "displayName": "Voltage L2", - "displayNameEvent": "Voltage L2 changed", + "name": "voltagePhaseB", + "displayName": "Voltage phase B", + "displayNameEvent": "Voltage phase B changed", "type": "double", "unit": "Volt", "defaultValue": 0 }, { "id": "ace6294d-deaa-4d9a-af78-d64379bcb229", - "name": "voltageL3", - "displayName": "Voltage L3", - "displayNameEvent": "Voltage L3 changed", + "name": "voltagePhaseC", + "displayName": "Voltage phase C", + "displayNameEvent": "Voltage phase C changed", "type": "double", "unit": "Volt", "defaultValue": 0 }, { "id": "4baf1d08-5ffa-49cf-95ef-9527b0c6f081", - "name": "currentL1", - "displayName": "Current L1", - "displayNameEvent": "Current L1 changed", + "name": "currentPhaseA", + "displayName": "Current phase A", + "displayNameEvent": "Current phase A changed", "type": "double", "unit": "Ampere", "defaultValue": 0 }, { "id": "99e47d06-0a6a-4bfd-b164-61ecb6ba2818", - "name": "currentL2", - "displayName": "Current L2", - "displayNameEvent": "Current L2 changed", + "name": "currentPhaseB", + "displayName": "Current phase B", + "displayNameEvent": "Current phase B changed", "type": "double", "unit": "Ampere", "defaultValue": 0 }, { "id": "4a092a66-352d-4d60-90ab-6ac5f58b92fe", - "name": "currentL3", - "displayName": "Current L3", - "displayNameEvent": "Current L3 changed", + "name": "currentPhaseC", + "displayName": "Current phase C", + "displayNameEvent": "Current phase C changed", "type": "double", "unit": "Ampere", "defaultValue": 0 @@ -267,19 +330,38 @@ { "id": "c824e97b-a6d1-4030-9d7a-00af6fb8e1c3", "name": "currentPower", - "displayName": "Active power", - "displayNameEvent": "Active power changed", + "displayName": "Current power", + "displayNameEvent": "Current power changed", "type": "double", "unit": "Watt", "defaultValue": 0 }, { - "id": "31b9032f-f994-472b-94bd-44f9fb094801", - "name": "powerFactor", - "displayName": "Power factor", - "displayNameEvent": "Power factor changed", + "id": "3982fb12-b179-40f7-9b27-36adb1cadd37", + "name": "currentPowerPhaseA", + "displayName": "Current power phase A", + "displayNameEvent": "Current power phase A changed", "type": "double", - "defaultValue": 0.00 + "unit": "Watt", + "defaultValue": 0 + }, + { + "id": "2a231c58-b095-4037-8394-a730431e70b8", + "name": "currentPowerPhaseB", + "displayName": "Current power phase B", + "displayNameEvent": "Current power phase B changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0 + }, + { + "id": "ee8c4f0c-2b69-4210-9966-1553a592b06d", + "name": "currentPowerPhaseC", + "displayName": "Current power phase C", + "displayNameEvent": "Current power phase C changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0 }, { "id": "ab24f26c-dc15-4ec3-8d76-06a48285440b", @@ -307,6 +389,60 @@ "type": "double", "unit": "KiloWattHour", "defaultValue": 0.00 + }, + { + "id": "6ca06c81-fe75-4448-a22f-47c303421440", + "name": "energyConsumedPhaseA", + "displayName": "Energy consumed phase A", + "displayNameEvent": "Energy consumed phase A changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "fa2b879b-2a81-4bc8-9577-98082c4d9330", + "name": "energyConsumedPhaseB", + "displayName": "Energy consumed phase B", + "displayNameEvent": "Energy consumed phase B changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "4c084c9e-7a5d-42d1-96b2-a8a4b4a25713", + "name": "energyConsumedPhaseC", + "displayName": "Energy consumed phase C", + "displayNameEvent": "Energy consumed phase C changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "308fa88e-6054-4c79-b12a-be2d0a404ef6", + "name": "energyProducedPhaseA", + "displayName": "Energy produced phase A", + "displayNameEvent": "Energy produced phase A changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "48ab6e61-dfb4-4f85-b5cc-9d89e53c6b39", + "name": "energyProducedPhaseB", + "displayName": "Energy produced phase B", + "displayNameEvent": "Energy produced phase B changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "6b3ddf15-3d4b-4dc1-8e5a-84fbf90b49ff", + "name": "energyProducedPhaseC", + "displayName": "Energy produced phase C", + "displayNameEvent": "Energy produced phase C changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 } ] } diff --git a/energymeters/meta.json b/energymeters/meta.json index 4f390d5..1158181 100644 --- a/energymeters/meta.json +++ b/energymeters/meta.json @@ -1,11 +1,13 @@ { "title": "Energy Meters", "tagline": "Connect Modbus RTU energy meters.", - "icon": "energymeter.svg", + "icon": "", "stability": "consumer", "offline": true, "technologies": [ + "modbus" ], "categories": [ + "energy" ] } diff --git a/energymeters/pro380-registers.json b/energymeters/pro380-registers.json new file mode 100644 index 0000000..d9c189e --- /dev/null +++ b/energymeters/pro380-registers.json @@ -0,0 +1,266 @@ +{ + "protocol": "RTU", + "endianness": "BigEndian", + "blocks": [ + { + "id": "phasesVoltage", + "readSchedule": "update", + "registers": [ + { + "id": "voltagePhaseA", + "address": 20482, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Voltage phase L1", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "voltagePhaseB", + "address": 20484, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Voltage phase L2", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "voltagePhaseC", + "address": 20486, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Voltage phase L3", + "unit": "V", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "phasesCurrent", + "readSchedule": "update", + "registers": [ + { + "id": "currentPhaseA", + "address": 20492, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Current phase L1", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "currentPhaseB", + "address": 20494, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Current phase L2", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "currentPhaseC", + "address": 20496, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Current phase L3", + "unit": "A", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "currentPower", + "readSchedule": "update", + "registers": [ + { + "id": "totalCurrentPower", + "address": 20498, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Total system power", + "unit": "kW", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerPhaseA", + "address": 20500, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Power phase L1", + "unit": "kW", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerPhaseB", + "address": 20502, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Power phase L2", + "unit": "kW", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerPhaseC", + "address": 20504, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Power phase L3", + "unit": "kW", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "phasesEnergyConsumed", + "readSchedule": "update", + "registers": [ + { + "id": "energyConsumedPhaseA", + "address": 24594, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Energy consumed phase A", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "energyConsumedPhaseB", + "address": 24596, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Energy consumed phase B", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "energyConsumedPhaseC", + "address": 24598, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Energy consumed phase C", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "phasesEnergyProduced", + "readSchedule": "update", + "registers": [ + { + "id": "energyProducedPhaseA", + "address": 24606, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Energy produced phase A", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "energyProducedPhaseB", + "address": 24608, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Energy produced phase B", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "energyProducedPhaseC", + "address": 24610, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Energy produced phase C", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + } + ] + } + ], + "registers": [ + { + "id": "frequency", + "address": 20488, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Frequency", + "unit": "Hz", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "totalEnergyConsumed", + "address": 24588, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Total energy consumed (Forward active energy)", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "totalEnergyProduced", + "address": 24600, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Total energy produced (Reverse active energy)", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + } + ] +} \ No newline at end of file diff --git a/energymeters/pro380modbusrtuconnection.cpp b/energymeters/pro380modbusrtuconnection.cpp new file mode 100644 index 0000000..013b80c --- /dev/null +++ b/energymeters/pro380modbusrtuconnection.cpp @@ -0,0 +1,537 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This fileDescriptor 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 "pro380modbusrtuconnection.h" +#include "loggingcategories.h" + +NYMEA_LOGGING_CATEGORY(dcPro380ModbusRtuConnection, "Pro380ModbusRtuConnection") + +Pro380ModbusRtuConnection::Pro380ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent) : + QObject(parent), + m_modbusRtuMaster(modbusRtuMaster), + m_slaveId(slaveId) +{ + +} + +ModbusRtuMaster *Pro380ModbusRtuConnection::modbusRtuMaster() const +{ + return m_modbusRtuMaster; +} +quint16 Pro380ModbusRtuConnection::slaveId() const +{ + return m_slaveId; +} +float Pro380ModbusRtuConnection::frequency() const +{ + return m_frequency; +} + +float Pro380ModbusRtuConnection::totalEnergyConsumed() const +{ + return m_totalEnergyConsumed; +} + +float Pro380ModbusRtuConnection::totalEnergyProduced() const +{ + return m_totalEnergyProduced; +} + +float Pro380ModbusRtuConnection::voltagePhaseA() const +{ + return m_voltagePhaseA; +} + +float Pro380ModbusRtuConnection::voltagePhaseB() const +{ + return m_voltagePhaseB; +} + +float Pro380ModbusRtuConnection::voltagePhaseC() const +{ + return m_voltagePhaseC; +} + +float Pro380ModbusRtuConnection::currentPhaseA() const +{ + return m_currentPhaseA; +} + +float Pro380ModbusRtuConnection::currentPhaseB() const +{ + return m_currentPhaseB; +} + +float Pro380ModbusRtuConnection::currentPhaseC() const +{ + return m_currentPhaseC; +} + +float Pro380ModbusRtuConnection::totalCurrentPower() const +{ + return m_totalCurrentPower; +} + +float Pro380ModbusRtuConnection::powerPhaseA() const +{ + return m_powerPhaseA; +} + +float Pro380ModbusRtuConnection::powerPhaseB() const +{ + return m_powerPhaseB; +} + +float Pro380ModbusRtuConnection::powerPhaseC() const +{ + return m_powerPhaseC; +} + +float Pro380ModbusRtuConnection::energyConsumedPhaseA() const +{ + return m_energyConsumedPhaseA; +} + +float Pro380ModbusRtuConnection::energyConsumedPhaseB() const +{ + return m_energyConsumedPhaseB; +} + +float Pro380ModbusRtuConnection::energyConsumedPhaseC() const +{ + return m_energyConsumedPhaseC; +} + +float Pro380ModbusRtuConnection::energyProducedPhaseA() const +{ + return m_energyProducedPhaseA; +} + +float Pro380ModbusRtuConnection::energyProducedPhaseB() const +{ + return m_energyProducedPhaseB; +} + +float Pro380ModbusRtuConnection::energyProducedPhaseC() const +{ + return m_energyProducedPhaseC; +} + +void Pro380ModbusRtuConnection::initialize() +{ + // No init registers defined. Nothing to be done and we are finished. + emit initializationFinished(); +} + +void Pro380ModbusRtuConnection::update() +{ + updateFrequency(); + updateTotalEnergyConsumed(); + updateTotalEnergyProduced(); + updatePhasesVoltageBlock(); + updatePhasesCurrentBlock(); + updateCurrentPowerBlock(); + updatePhasesEnergyConsumedBlock(); + updatePhasesEnergyProducedBlock(); +} + +void Pro380ModbusRtuConnection::updateFrequency() +{ + // Update registers from Frequency + qCDebug(dcPro380ModbusRtuConnection()) << "--> Read \"Frequency\" register:" << 20488 << "size:" << 2; + ModbusRtuReply *reply = readFrequency(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector values = reply->result(); + qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from \"Frequency\" register" << 20488 << "size:" << 2 << values; + float receivedFrequency = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_frequency != receivedFrequency) { + m_frequency = receivedFrequency; + emit frequencyChanged(m_frequency); + } + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Frequency\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading \"Frequency\" registers"; + } +} + +void Pro380ModbusRtuConnection::updateTotalEnergyConsumed() +{ + // Update registers from Total energy consumed (Forward active energy) + qCDebug(dcPro380ModbusRtuConnection()) << "--> Read \"Total energy consumed (Forward active energy)\" register:" << 24588 << "size:" << 2; + ModbusRtuReply *reply = readTotalEnergyConsumed(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector values = reply->result(); + qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from \"Total energy consumed (Forward active energy)\" register" << 24588 << "size:" << 2 << values; + float receivedTotalEnergyConsumed = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_totalEnergyConsumed != receivedTotalEnergyConsumed) { + m_totalEnergyConsumed = receivedTotalEnergyConsumed; + emit totalEnergyConsumedChanged(m_totalEnergyConsumed); + } + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Total energy consumed (Forward active energy)\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading \"Total energy consumed (Forward active energy)\" registers"; + } +} + +void Pro380ModbusRtuConnection::updateTotalEnergyProduced() +{ + // Update registers from Total energy produced (Reverse active energy) + qCDebug(dcPro380ModbusRtuConnection()) << "--> Read \"Total energy produced (Reverse active energy)\" register:" << 24600 << "size:" << 2; + ModbusRtuReply *reply = readTotalEnergyProduced(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector values = reply->result(); + qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from \"Total energy produced (Reverse active energy)\" register" << 24600 << "size:" << 2 << values; + float receivedTotalEnergyProduced = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_totalEnergyProduced != receivedTotalEnergyProduced) { + m_totalEnergyProduced = receivedTotalEnergyProduced; + emit totalEnergyProducedChanged(m_totalEnergyProduced); + } + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Total energy produced (Reverse active energy)\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading \"Total energy produced (Reverse active energy)\" registers"; + } +} + +void Pro380ModbusRtuConnection::updatePhasesVoltageBlock() +{ + // Update register block "phasesVoltage" + qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesVoltage\" registers from:" << 20482 << "size:" << 6; + ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20482, 6); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector blockValues = reply->result(); + QVector values; + qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesVoltage\" register" << 20482 << "size:" << 6 << blockValues; + values = blockValues.mid(0, 2); + float receivedVoltagePhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_voltagePhaseA != receivedVoltagePhaseA) { + m_voltagePhaseA = receivedVoltagePhaseA; + emit voltagePhaseAChanged(m_voltagePhaseA); + } + + values = blockValues.mid(2, 2); + float receivedVoltagePhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_voltagePhaseB != receivedVoltagePhaseB) { + m_voltagePhaseB = receivedVoltagePhaseB; + emit voltagePhaseBChanged(m_voltagePhaseB); + } + + values = blockValues.mid(4, 2); + float receivedVoltagePhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_voltagePhaseC != receivedVoltagePhaseC) { + m_voltagePhaseC = receivedVoltagePhaseC; + emit voltagePhaseCChanged(m_voltagePhaseC); + } + + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesVoltage\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesVoltage\" registers"; + } +} + +void Pro380ModbusRtuConnection::updatePhasesCurrentBlock() +{ + // Update register block "phasesCurrent" + qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesCurrent\" registers from:" << 20492 << "size:" << 6; + ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20492, 6); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector blockValues = reply->result(); + QVector values; + qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesCurrent\" register" << 20492 << "size:" << 6 << blockValues; + values = blockValues.mid(0, 2); + float receivedCurrentPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_currentPhaseA != receivedCurrentPhaseA) { + m_currentPhaseA = receivedCurrentPhaseA; + emit currentPhaseAChanged(m_currentPhaseA); + } + + values = blockValues.mid(2, 2); + float receivedCurrentPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_currentPhaseB != receivedCurrentPhaseB) { + m_currentPhaseB = receivedCurrentPhaseB; + emit currentPhaseBChanged(m_currentPhaseB); + } + + values = blockValues.mid(4, 2); + float receivedCurrentPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_currentPhaseC != receivedCurrentPhaseC) { + m_currentPhaseC = receivedCurrentPhaseC; + emit currentPhaseCChanged(m_currentPhaseC); + } + + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesCurrent\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesCurrent\" registers"; + } +} + +void Pro380ModbusRtuConnection::updateCurrentPowerBlock() +{ + // Update register block "currentPower" + qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"currentPower\" registers from:" << 20498 << "size:" << 8; + ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20498, 8); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector blockValues = reply->result(); + QVector values; + qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"currentPower\" register" << 20498 << "size:" << 8 << blockValues; + values = blockValues.mid(0, 2); + float receivedTotalCurrentPower = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_totalCurrentPower != receivedTotalCurrentPower) { + m_totalCurrentPower = receivedTotalCurrentPower; + emit totalCurrentPowerChanged(m_totalCurrentPower); + } + + values = blockValues.mid(2, 2); + float receivedPowerPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_powerPhaseA != receivedPowerPhaseA) { + m_powerPhaseA = receivedPowerPhaseA; + emit powerPhaseAChanged(m_powerPhaseA); + } + + values = blockValues.mid(4, 2); + float receivedPowerPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_powerPhaseB != receivedPowerPhaseB) { + m_powerPhaseB = receivedPowerPhaseB; + emit powerPhaseBChanged(m_powerPhaseB); + } + + values = blockValues.mid(6, 2); + float receivedPowerPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_powerPhaseC != receivedPowerPhaseC) { + m_powerPhaseC = receivedPowerPhaseC; + emit powerPhaseCChanged(m_powerPhaseC); + } + + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"currentPower\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"currentPower\" registers"; + } +} + +void Pro380ModbusRtuConnection::updatePhasesEnergyConsumedBlock() +{ + // Update register block "phasesEnergyConsumed" + qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesEnergyConsumed\" registers from:" << 24594 << "size:" << 6; + ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24594, 6); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector blockValues = reply->result(); + QVector values; + qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesEnergyConsumed\" register" << 24594 << "size:" << 6 << blockValues; + values = blockValues.mid(0, 2); + float receivedEnergyConsumedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyConsumedPhaseA != receivedEnergyConsumedPhaseA) { + m_energyConsumedPhaseA = receivedEnergyConsumedPhaseA; + emit energyConsumedPhaseAChanged(m_energyConsumedPhaseA); + } + + values = blockValues.mid(2, 2); + float receivedEnergyConsumedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyConsumedPhaseB != receivedEnergyConsumedPhaseB) { + m_energyConsumedPhaseB = receivedEnergyConsumedPhaseB; + emit energyConsumedPhaseBChanged(m_energyConsumedPhaseB); + } + + values = blockValues.mid(4, 2); + float receivedEnergyConsumedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyConsumedPhaseC != receivedEnergyConsumedPhaseC) { + m_energyConsumedPhaseC = receivedEnergyConsumedPhaseC; + emit energyConsumedPhaseCChanged(m_energyConsumedPhaseC); + } + + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesEnergyConsumed\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesEnergyConsumed\" registers"; + } +} + +void Pro380ModbusRtuConnection::updatePhasesEnergyProducedBlock() +{ + // Update register block "phasesEnergyProduced" + qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesEnergyProduced\" registers from:" << 24606 << "size:" << 6; + ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24606, 6); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector blockValues = reply->result(); + QVector values; + qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesEnergyProduced\" register" << 24606 << "size:" << 6 << blockValues; + values = blockValues.mid(0, 2); + float receivedEnergyProducedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyProducedPhaseA != receivedEnergyProducedPhaseA) { + m_energyProducedPhaseA = receivedEnergyProducedPhaseA; + emit energyProducedPhaseAChanged(m_energyProducedPhaseA); + } + + values = blockValues.mid(2, 2); + float receivedEnergyProducedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyProducedPhaseB != receivedEnergyProducedPhaseB) { + m_energyProducedPhaseB = receivedEnergyProducedPhaseB; + emit energyProducedPhaseBChanged(m_energyProducedPhaseB); + } + + values = blockValues.mid(4, 2); + float receivedEnergyProducedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyProducedPhaseC != receivedEnergyProducedPhaseC) { + m_energyProducedPhaseC = receivedEnergyProducedPhaseC; + emit energyProducedPhaseCChanged(m_energyProducedPhaseC); + } + + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesEnergyProduced\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesEnergyProduced\" registers"; + } +} + +ModbusRtuReply *Pro380ModbusRtuConnection::readFrequency() +{ + return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20488, 2); +} + +ModbusRtuReply *Pro380ModbusRtuConnection::readTotalEnergyConsumed() +{ + return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24588, 2); +} + +ModbusRtuReply *Pro380ModbusRtuConnection::readTotalEnergyProduced() +{ + return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24600, 2); +} + +void Pro380ModbusRtuConnection::verifyInitFinished() +{ + if (m_pendingInitReplies.isEmpty()) { + qCDebug(dcPro380ModbusRtuConnection()) << "Initialization finished of Pro380ModbusRtuConnection"; + emit initializationFinished(); + } +} + +QDebug operator<<(QDebug debug, Pro380ModbusRtuConnection *pro380ModbusRtuConnection) +{ + debug.nospace().noquote() << "Pro380ModbusRtuConnection(" << pro380ModbusRtuConnection->modbusRtuMaster()->modbusUuid().toString() << ", " << pro380ModbusRtuConnection->modbusRtuMaster()->serialPort() << ", slave ID:" << pro380ModbusRtuConnection->slaveId() << ")" << "\n"; + debug.nospace().noquote() << " - Frequency:" << pro380ModbusRtuConnection->frequency() << " [Hz]" << "\n"; + debug.nospace().noquote() << " - Total energy consumed (Forward active energy):" << pro380ModbusRtuConnection->totalEnergyConsumed() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Total energy produced (Reverse active energy):" << pro380ModbusRtuConnection->totalEnergyProduced() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Voltage phase L1:" << pro380ModbusRtuConnection->voltagePhaseA() << " [V]" << "\n"; + debug.nospace().noquote() << " - Voltage phase L2:" << pro380ModbusRtuConnection->voltagePhaseB() << " [V]" << "\n"; + debug.nospace().noquote() << " - Voltage phase L3:" << pro380ModbusRtuConnection->voltagePhaseC() << " [V]" << "\n"; + debug.nospace().noquote() << " - Current phase L1:" << pro380ModbusRtuConnection->currentPhaseA() << " [A]" << "\n"; + debug.nospace().noquote() << " - Current phase L2:" << pro380ModbusRtuConnection->currentPhaseB() << " [A]" << "\n"; + debug.nospace().noquote() << " - Current phase L3:" << pro380ModbusRtuConnection->currentPhaseC() << " [A]" << "\n"; + debug.nospace().noquote() << " - Total system power:" << pro380ModbusRtuConnection->totalCurrentPower() << " [kW]" << "\n"; + debug.nospace().noquote() << " - Power phase L1:" << pro380ModbusRtuConnection->powerPhaseA() << " [kW]" << "\n"; + debug.nospace().noquote() << " - Power phase L2:" << pro380ModbusRtuConnection->powerPhaseB() << " [kW]" << "\n"; + debug.nospace().noquote() << " - Power phase L3:" << pro380ModbusRtuConnection->powerPhaseC() << " [kW]" << "\n"; + debug.nospace().noquote() << " - Energy consumed phase A:" << pro380ModbusRtuConnection->energyConsumedPhaseA() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy consumed phase B:" << pro380ModbusRtuConnection->energyConsumedPhaseB() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy consumed phase C:" << pro380ModbusRtuConnection->energyConsumedPhaseC() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy produced phase A:" << pro380ModbusRtuConnection->energyProducedPhaseA() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy produced phase B:" << pro380ModbusRtuConnection->energyProducedPhaseB() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy produced phase C:" << pro380ModbusRtuConnection->energyProducedPhaseC() << " [kWh]" << "\n"; + return debug.quote().space(); +} + diff --git a/energymeters/pro380modbusrtuconnection.h b/energymeters/pro380modbusrtuconnection.h new file mode 100644 index 0000000..3f26c0b --- /dev/null +++ b/energymeters/pro380modbusrtuconnection.h @@ -0,0 +1,204 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This fileDescriptor 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 PRO380MODBUSRTUCONNECTION_H +#define PRO380MODBUSRTUCONNECTION_H + +#include + +#include "../modbus/modbusdatautils.h" +#include + +class Pro380ModbusRtuConnection : public QObject +{ + Q_OBJECT +public: + explicit Pro380ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr); + ~Pro380ModbusRtuConnection() = default; + + ModbusRtuMaster *modbusRtuMaster() const; + quint16 slaveId() const; + + /* Frequency [Hz] - Address: 20488, Size: 2 */ + float frequency() const; + + /* Total energy consumed (Forward active energy) [kWh] - Address: 24588, Size: 2 */ + float totalEnergyConsumed() const; + + /* Total energy produced (Reverse active energy) [kWh] - Address: 24600, Size: 2 */ + float totalEnergyProduced() const; + + /* Voltage phase L1 [V] - Address: 20482, Size: 2 */ + float voltagePhaseA() const; + + /* Voltage phase L2 [V] - Address: 20484, Size: 2 */ + float voltagePhaseB() const; + + /* Voltage phase L3 [V] - Address: 20486, Size: 2 */ + float voltagePhaseC() const; + + /* Read block from start addess 20482 with size of 6 registers containing following 3 properties: + - Voltage phase L1 [V] - Address: 20482, Size: 2 + - Voltage phase L2 [V] - Address: 20484, Size: 2 + - Voltage phase L3 [V] - Address: 20486, Size: 2 + */ + void updatePhasesVoltageBlock(); + /* Current phase L1 [A] - Address: 20492, Size: 2 */ + float currentPhaseA() const; + + /* Current phase L2 [A] - Address: 20494, Size: 2 */ + float currentPhaseB() const; + + /* Current phase L3 [A] - Address: 20496, Size: 2 */ + float currentPhaseC() const; + + /* Read block from start addess 20492 with size of 6 registers containing following 3 properties: + - Current phase L1 [A] - Address: 20492, Size: 2 + - Current phase L2 [A] - Address: 20494, Size: 2 + - Current phase L3 [A] - Address: 20496, Size: 2 + */ + void updatePhasesCurrentBlock(); + /* Total system power [kW] - Address: 20498, Size: 2 */ + float totalCurrentPower() const; + + /* Power phase L1 [kW] - Address: 20500, Size: 2 */ + float powerPhaseA() const; + + /* Power phase L2 [kW] - Address: 20502, Size: 2 */ + float powerPhaseB() const; + + /* Power phase L3 [kW] - Address: 20504, Size: 2 */ + float powerPhaseC() const; + + /* Read block from start addess 20498 with size of 8 registers containing following 4 properties: + - Total system power [kW] - Address: 20498, Size: 2 + - Power phase L1 [kW] - Address: 20500, Size: 2 + - Power phase L2 [kW] - Address: 20502, Size: 2 + - Power phase L3 [kW] - Address: 20504, Size: 2 + */ + void updateCurrentPowerBlock(); + /* Energy consumed phase A [kWh] - Address: 24594, Size: 2 */ + float energyConsumedPhaseA() const; + + /* Energy consumed phase B [kWh] - Address: 24596, Size: 2 */ + float energyConsumedPhaseB() const; + + /* Energy consumed phase C [kWh] - Address: 24598, Size: 2 */ + float energyConsumedPhaseC() const; + + /* Read block from start addess 24594 with size of 6 registers containing following 3 properties: + - Energy consumed phase A [kWh] - Address: 24594, Size: 2 + - Energy consumed phase B [kWh] - Address: 24596, Size: 2 + - Energy consumed phase C [kWh] - Address: 24598, Size: 2 + */ + void updatePhasesEnergyConsumedBlock(); + /* Energy produced phase A [kWh] - Address: 24606, Size: 2 */ + float energyProducedPhaseA() const; + + /* Energy produced phase B [kWh] - Address: 24608, Size: 2 */ + float energyProducedPhaseB() const; + + /* Energy produced phase C [kWh] - Address: 24610, Size: 2 */ + float energyProducedPhaseC() const; + + /* Read block from start addess 24606 with size of 6 registers containing following 3 properties: + - Energy produced phase A [kWh] - Address: 24606, Size: 2 + - Energy produced phase B [kWh] - Address: 24608, Size: 2 + - Energy produced phase C [kWh] - Address: 24610, Size: 2 + */ + void updatePhasesEnergyProducedBlock(); + + void updateFrequency(); + void updateTotalEnergyConsumed(); + void updateTotalEnergyProduced(); + + virtual void initialize(); + virtual void update(); + +signals: + void initializationFinished(); + + void frequencyChanged(float frequency); + void totalEnergyConsumedChanged(float totalEnergyConsumed); + void totalEnergyProducedChanged(float totalEnergyProduced); + void voltagePhaseAChanged(float voltagePhaseA); + void voltagePhaseBChanged(float voltagePhaseB); + void voltagePhaseCChanged(float voltagePhaseC); + void currentPhaseAChanged(float currentPhaseA); + void currentPhaseBChanged(float currentPhaseB); + void currentPhaseCChanged(float currentPhaseC); + void totalCurrentPowerChanged(float totalCurrentPower); + void powerPhaseAChanged(float powerPhaseA); + void powerPhaseBChanged(float powerPhaseB); + void powerPhaseCChanged(float powerPhaseC); + void energyConsumedPhaseAChanged(float energyConsumedPhaseA); + void energyConsumedPhaseBChanged(float energyConsumedPhaseB); + void energyConsumedPhaseCChanged(float energyConsumedPhaseC); + void energyProducedPhaseAChanged(float energyProducedPhaseA); + void energyProducedPhaseBChanged(float energyProducedPhaseB); + void energyProducedPhaseCChanged(float energyProducedPhaseC); + +private: + ModbusRtuMaster *m_modbusRtuMaster = nullptr; + quint16 m_slaveId = 1; + QVector m_pendingInitReplies; + + float m_frequency = 0; + float m_totalEnergyConsumed = 0; + float m_totalEnergyProduced = 0; + float m_voltagePhaseA = 0; + float m_voltagePhaseB = 0; + float m_voltagePhaseC = 0; + float m_currentPhaseA = 0; + float m_currentPhaseB = 0; + float m_currentPhaseC = 0; + float m_totalCurrentPower = 0; + float m_powerPhaseA = 0; + float m_powerPhaseB = 0; + float m_powerPhaseC = 0; + float m_energyConsumedPhaseA = 0; + float m_energyConsumedPhaseB = 0; + float m_energyConsumedPhaseC = 0; + float m_energyProducedPhaseA = 0; + float m_energyProducedPhaseB = 0; + float m_energyProducedPhaseC = 0; + + void verifyInitFinished(); + + ModbusRtuReply *readFrequency(); + ModbusRtuReply *readTotalEnergyConsumed(); + ModbusRtuReply *readTotalEnergyProduced(); + + +}; + +QDebug operator<<(QDebug debug, Pro380ModbusRtuConnection *pro380ModbusRtuConnection); + +#endif // PRO380MODBUSRTUCONNECTION_H diff --git a/energymeters/registerdescriptor.h b/energymeters/registerdescriptor.h deleted file mode 100644 index d330b3f..0000000 --- a/energymeters/registerdescriptor.h +++ /dev/null @@ -1,87 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef REGISTERDESCRIPTOR_H -#define REGISTERDESCRIPTOR_H - -#include -#include - -enum ModbusRegisterType { - VoltageL1, - VoltageL2, - VoltageL3, - CurrentL1, - CurrentL2, - CurrentL3, - ActivePower, - Frequency, - PowerFactor, - EnergyProduced, - EnergyConsumed -}; - -class ModbusRegisterDescriptor -{ - -public: - ModbusRegisterDescriptor() {} - ModbusRegisterDescriptor(int address, int functionCode, int length, QString unit, QString dataType) : - m_address(address), - m_functionCode(functionCode), - m_length(length), - m_unit(unit), - m_dataType(dataType) - {} - - int address() const - { return m_address;} - - int functionCode() const - { return m_functionCode;} - - int length() const - { return m_length;} - - QString unit() const - { return m_unit;} - - QString dataType() const - { return m_dataType;} - -private: - int m_address; - int m_functionCode; - int m_length; - QString m_unit; - QString m_dataType; -}; - -#endif // REGISTERDESCRIPTOR_H diff --git a/energymeters/sdm630-registers.json b/energymeters/sdm630-registers.json new file mode 100644 index 0000000..b4d9f0d --- /dev/null +++ b/energymeters/sdm630-registers.json @@ -0,0 +1,260 @@ +{ + "protocol": "RTU", + "endianness": "BigEndian", + "registers": [ + { + "id": "totalCurrentPower", + "address": 52, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Total system power", + "unit": "W", + "defaultValue": "0", + "access": "RO" + } + ], + "blocks": [ + { + "id": "phaseVoltageAndCurrent", + "readSchedule": "update", + "registers": [ + { + "id": "voltagePhaseA", + "address": 0, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Voltage phase L1", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "voltagePhaseB", + "address": 2, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Voltage phase L2", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "voltagePhaseC", + "address": 4, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Voltage phase L3", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "currentPhaseA", + "address": 6, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Current phase L1", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "currentPhaseB", + "address": 8, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Current phase L2", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "currentPhaseC", + "address": 10, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Current phase L3", + "unit": "A", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "phasePower", + "readSchedule": "update", + "registers": [ + { + "id": "powerPhaseA", + "address": 12, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Power phase L1", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerPhaseB", + "address": 14, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Power phase L2", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerPhaseC", + "address": 16, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Power phase L3", + "unit": "W", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "frequencyAndTotalEnergy", + "readSchedule": "update", + "registers": [ + { + "id": "frequency", + "address": 70, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Frequency", + "unit": "Hz", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "totalEnergyConsumed", + "address": 72, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Total energy consumed", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "totalEnergyProduced", + "address": 74, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Total energy produced", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "phaseEnergyEnergy", + "readSchedule": "update", + "registers": [ + { + "id": "energyProducedPhaseA", + "address": 346, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Energy produced phase A", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "energyProducedPhaseB", + "address": 348, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Energy produced phase B", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "energyProducedPhaseC", + "address": 350, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Energy produced phase C", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "energyConsumedPhaseA", + "address": 352, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Energy consumed phase A", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "energyConsumedPhaseB", + "address": 354, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Energy consumed phase B", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "energyConsumedPhaseC", + "address": 356, + "size": 2, + "type": "float", + "registerType": "inputRegister", + "readSchedule": "update", + "description": "Energy consumed phase C", + "unit": "kWh", + "defaultValue": "0", + "access": "RO" + } + ] + } + ] +} \ No newline at end of file diff --git a/energymeters/sdm630modbusrtuconnection.cpp b/energymeters/sdm630modbusrtuconnection.cpp new file mode 100644 index 0000000..1134d2f --- /dev/null +++ b/energymeters/sdm630modbusrtuconnection.cpp @@ -0,0 +1,455 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This fileDescriptor 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 "sdm630modbusrtuconnection.h" +#include "loggingcategories.h" + +NYMEA_LOGGING_CATEGORY(dcSdm630ModbusRtuConnection, "Sdm630ModbusRtuConnection") + +Sdm630ModbusRtuConnection::Sdm630ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent) : + QObject(parent), + m_modbusRtuMaster(modbusRtuMaster), + m_slaveId(slaveId) +{ + +} + +ModbusRtuMaster *Sdm630ModbusRtuConnection::modbusRtuMaster() const +{ + return m_modbusRtuMaster; +} +quint16 Sdm630ModbusRtuConnection::slaveId() const +{ + return m_slaveId; +} +float Sdm630ModbusRtuConnection::totalCurrentPower() const +{ + return m_totalCurrentPower; +} + +float Sdm630ModbusRtuConnection::voltagePhaseA() const +{ + return m_voltagePhaseA; +} + +float Sdm630ModbusRtuConnection::voltagePhaseB() const +{ + return m_voltagePhaseB; +} + +float Sdm630ModbusRtuConnection::voltagePhaseC() const +{ + return m_voltagePhaseC; +} + +float Sdm630ModbusRtuConnection::currentPhaseA() const +{ + return m_currentPhaseA; +} + +float Sdm630ModbusRtuConnection::currentPhaseB() const +{ + return m_currentPhaseB; +} + +float Sdm630ModbusRtuConnection::currentPhaseC() const +{ + return m_currentPhaseC; +} + +float Sdm630ModbusRtuConnection::powerPhaseA() const +{ + return m_powerPhaseA; +} + +float Sdm630ModbusRtuConnection::powerPhaseB() const +{ + return m_powerPhaseB; +} + +float Sdm630ModbusRtuConnection::powerPhaseC() const +{ + return m_powerPhaseC; +} + +float Sdm630ModbusRtuConnection::frequency() const +{ + return m_frequency; +} + +float Sdm630ModbusRtuConnection::totalEnergyConsumed() const +{ + return m_totalEnergyConsumed; +} + +float Sdm630ModbusRtuConnection::totalEnergyProduced() const +{ + return m_totalEnergyProduced; +} + +float Sdm630ModbusRtuConnection::energyProducedPhaseA() const +{ + return m_energyProducedPhaseA; +} + +float Sdm630ModbusRtuConnection::energyProducedPhaseB() const +{ + return m_energyProducedPhaseB; +} + +float Sdm630ModbusRtuConnection::energyProducedPhaseC() const +{ + return m_energyProducedPhaseC; +} + +float Sdm630ModbusRtuConnection::energyConsumedPhaseA() const +{ + return m_energyConsumedPhaseA; +} + +float Sdm630ModbusRtuConnection::energyConsumedPhaseB() const +{ + return m_energyConsumedPhaseB; +} + +float Sdm630ModbusRtuConnection::energyConsumedPhaseC() const +{ + return m_energyConsumedPhaseC; +} + +void Sdm630ModbusRtuConnection::initialize() +{ + // No init registers defined. Nothing to be done and we are finished. + emit initializationFinished(); +} + +void Sdm630ModbusRtuConnection::update() +{ + updateTotalCurrentPower(); + updatePhaseVoltageAndCurrentBlock(); + updatePhasePowerBlock(); + updateFrequencyAndTotalEnergyBlock(); + updatePhaseEnergyEnergyBlock(); +} + +void Sdm630ModbusRtuConnection::updateTotalCurrentPower() +{ + // Update registers from Total system power + qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read \"Total system power\" register:" << 52 << "size:" << 2; + ModbusRtuReply *reply = readTotalCurrentPower(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector values = reply->result(); + qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from \"Total system power\" register" << 52 << "size:" << 2 << values; + float receivedTotalCurrentPower = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_totalCurrentPower != receivedTotalCurrentPower) { + m_totalCurrentPower = receivedTotalCurrentPower; + emit totalCurrentPowerChanged(m_totalCurrentPower); + } + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Total system power\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading \"Total system power\" registers"; + } +} + +void Sdm630ModbusRtuConnection::updatePhaseVoltageAndCurrentBlock() +{ + // Update register block "phaseVoltageAndCurrent" + qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"phaseVoltageAndCurrent\" registers from:" << 0 << "size:" << 12; + ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 0, 12); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector blockValues = reply->result(); + QVector values; + qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"phaseVoltageAndCurrent\" register" << 0 << "size:" << 12 << blockValues; + values = blockValues.mid(0, 2); + float receivedVoltagePhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_voltagePhaseA != receivedVoltagePhaseA) { + m_voltagePhaseA = receivedVoltagePhaseA; + emit voltagePhaseAChanged(m_voltagePhaseA); + } + + values = blockValues.mid(2, 2); + float receivedVoltagePhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_voltagePhaseB != receivedVoltagePhaseB) { + m_voltagePhaseB = receivedVoltagePhaseB; + emit voltagePhaseBChanged(m_voltagePhaseB); + } + + values = blockValues.mid(4, 2); + float receivedVoltagePhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_voltagePhaseC != receivedVoltagePhaseC) { + m_voltagePhaseC = receivedVoltagePhaseC; + emit voltagePhaseCChanged(m_voltagePhaseC); + } + + values = blockValues.mid(6, 2); + float receivedCurrentPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_currentPhaseA != receivedCurrentPhaseA) { + m_currentPhaseA = receivedCurrentPhaseA; + emit currentPhaseAChanged(m_currentPhaseA); + } + + values = blockValues.mid(8, 2); + float receivedCurrentPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_currentPhaseB != receivedCurrentPhaseB) { + m_currentPhaseB = receivedCurrentPhaseB; + emit currentPhaseBChanged(m_currentPhaseB); + } + + values = blockValues.mid(10, 2); + float receivedCurrentPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_currentPhaseC != receivedCurrentPhaseC) { + m_currentPhaseC = receivedCurrentPhaseC; + emit currentPhaseCChanged(m_currentPhaseC); + } + + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phaseVoltageAndCurrent\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"phaseVoltageAndCurrent\" registers"; + } +} + +void Sdm630ModbusRtuConnection::updatePhasePowerBlock() +{ + // Update register block "phasePower" + qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"phasePower\" registers from:" << 12 << "size:" << 6; + ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 12, 6); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector blockValues = reply->result(); + QVector values; + qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"phasePower\" register" << 12 << "size:" << 6 << blockValues; + values = blockValues.mid(0, 2); + float receivedPowerPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_powerPhaseA != receivedPowerPhaseA) { + m_powerPhaseA = receivedPowerPhaseA; + emit powerPhaseAChanged(m_powerPhaseA); + } + + values = blockValues.mid(2, 2); + float receivedPowerPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_powerPhaseB != receivedPowerPhaseB) { + m_powerPhaseB = receivedPowerPhaseB; + emit powerPhaseBChanged(m_powerPhaseB); + } + + values = blockValues.mid(4, 2); + float receivedPowerPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_powerPhaseC != receivedPowerPhaseC) { + m_powerPhaseC = receivedPowerPhaseC; + emit powerPhaseCChanged(m_powerPhaseC); + } + + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasePower\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"phasePower\" registers"; + } +} + +void Sdm630ModbusRtuConnection::updateFrequencyAndTotalEnergyBlock() +{ + // Update register block "frequencyAndTotalEnergy" + qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"frequencyAndTotalEnergy\" registers from:" << 70 << "size:" << 6; + ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 70, 6); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector blockValues = reply->result(); + QVector values; + qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"frequencyAndTotalEnergy\" register" << 70 << "size:" << 6 << blockValues; + values = blockValues.mid(0, 2); + float receivedFrequency = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_frequency != receivedFrequency) { + m_frequency = receivedFrequency; + emit frequencyChanged(m_frequency); + } + + values = blockValues.mid(2, 2); + float receivedTotalEnergyConsumed = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_totalEnergyConsumed != receivedTotalEnergyConsumed) { + m_totalEnergyConsumed = receivedTotalEnergyConsumed; + emit totalEnergyConsumedChanged(m_totalEnergyConsumed); + } + + values = blockValues.mid(4, 2); + float receivedTotalEnergyProduced = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_totalEnergyProduced != receivedTotalEnergyProduced) { + m_totalEnergyProduced = receivedTotalEnergyProduced; + emit totalEnergyProducedChanged(m_totalEnergyProduced); + } + + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"frequencyAndTotalEnergy\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"frequencyAndTotalEnergy\" registers"; + } +} + +void Sdm630ModbusRtuConnection::updatePhaseEnergyEnergyBlock() +{ + // Update register block "phaseEnergyEnergy" + qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"phaseEnergyEnergy\" registers from:" << 346 << "size:" << 12; + ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 346, 12); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &ModbusRtuReply::finished, this, [this, reply](){ + if (reply->error() == ModbusRtuReply::NoError) { + QVector blockValues = reply->result(); + QVector values; + qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"phaseEnergyEnergy\" register" << 346 << "size:" << 12 << blockValues; + values = blockValues.mid(0, 2); + float receivedEnergyProducedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyProducedPhaseA != receivedEnergyProducedPhaseA) { + m_energyProducedPhaseA = receivedEnergyProducedPhaseA; + emit energyProducedPhaseAChanged(m_energyProducedPhaseA); + } + + values = blockValues.mid(2, 2); + float receivedEnergyProducedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyProducedPhaseB != receivedEnergyProducedPhaseB) { + m_energyProducedPhaseB = receivedEnergyProducedPhaseB; + emit energyProducedPhaseBChanged(m_energyProducedPhaseB); + } + + values = blockValues.mid(4, 2); + float receivedEnergyProducedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyProducedPhaseC != receivedEnergyProducedPhaseC) { + m_energyProducedPhaseC = receivedEnergyProducedPhaseC; + emit energyProducedPhaseCChanged(m_energyProducedPhaseC); + } + + values = blockValues.mid(6, 2); + float receivedEnergyConsumedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyConsumedPhaseA != receivedEnergyConsumedPhaseA) { + m_energyConsumedPhaseA = receivedEnergyConsumedPhaseA; + emit energyConsumedPhaseAChanged(m_energyConsumedPhaseA); + } + + values = blockValues.mid(8, 2); + float receivedEnergyConsumedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyConsumedPhaseB != receivedEnergyConsumedPhaseB) { + m_energyConsumedPhaseB = receivedEnergyConsumedPhaseB; + emit energyConsumedPhaseBChanged(m_energyConsumedPhaseB); + } + + values = blockValues.mid(10, 2); + float receivedEnergyConsumedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian); + if (m_energyConsumedPhaseC != receivedEnergyConsumedPhaseC) { + m_energyConsumedPhaseC = receivedEnergyConsumedPhaseC; + emit energyConsumedPhaseCChanged(m_energyConsumedPhaseC); + } + + } + }); + + connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){ + qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phaseEnergyEnergy\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"phaseEnergyEnergy\" registers"; + } +} + +ModbusRtuReply *Sdm630ModbusRtuConnection::readTotalCurrentPower() +{ + return m_modbusRtuMaster->readInputRegister(m_slaveId, 52, 2); +} + +void Sdm630ModbusRtuConnection::verifyInitFinished() +{ + if (m_pendingInitReplies.isEmpty()) { + qCDebug(dcSdm630ModbusRtuConnection()) << "Initialization finished of Sdm630ModbusRtuConnection"; + emit initializationFinished(); + } +} + +QDebug operator<<(QDebug debug, Sdm630ModbusRtuConnection *sdm630ModbusRtuConnection) +{ + debug.nospace().noquote() << "Sdm630ModbusRtuConnection(" << sdm630ModbusRtuConnection->modbusRtuMaster()->modbusUuid().toString() << ", " << sdm630ModbusRtuConnection->modbusRtuMaster()->serialPort() << ", slave ID:" << sdm630ModbusRtuConnection->slaveId() << ")" << "\n"; + debug.nospace().noquote() << " - Total system power:" << sdm630ModbusRtuConnection->totalCurrentPower() << " [W]" << "\n"; + debug.nospace().noquote() << " - Voltage phase L1:" << sdm630ModbusRtuConnection->voltagePhaseA() << " [V]" << "\n"; + debug.nospace().noquote() << " - Voltage phase L2:" << sdm630ModbusRtuConnection->voltagePhaseB() << " [V]" << "\n"; + debug.nospace().noquote() << " - Voltage phase L3:" << sdm630ModbusRtuConnection->voltagePhaseC() << " [V]" << "\n"; + debug.nospace().noquote() << " - Current phase L1:" << sdm630ModbusRtuConnection->currentPhaseA() << " [A]" << "\n"; + debug.nospace().noquote() << " - Current phase L2:" << sdm630ModbusRtuConnection->currentPhaseB() << " [A]" << "\n"; + debug.nospace().noquote() << " - Current phase L3:" << sdm630ModbusRtuConnection->currentPhaseC() << " [A]" << "\n"; + debug.nospace().noquote() << " - Power phase L1:" << sdm630ModbusRtuConnection->powerPhaseA() << " [W]" << "\n"; + debug.nospace().noquote() << " - Power phase L2:" << sdm630ModbusRtuConnection->powerPhaseB() << " [W]" << "\n"; + debug.nospace().noquote() << " - Power phase L3:" << sdm630ModbusRtuConnection->powerPhaseC() << " [W]" << "\n"; + debug.nospace().noquote() << " - Frequency:" << sdm630ModbusRtuConnection->frequency() << " [Hz]" << "\n"; + debug.nospace().noquote() << " - Total energy consumed:" << sdm630ModbusRtuConnection->totalEnergyConsumed() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Total energy produced:" << sdm630ModbusRtuConnection->totalEnergyProduced() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy produced phase A:" << sdm630ModbusRtuConnection->energyProducedPhaseA() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy produced phase B:" << sdm630ModbusRtuConnection->energyProducedPhaseB() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy produced phase C:" << sdm630ModbusRtuConnection->energyProducedPhaseC() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy consumed phase A:" << sdm630ModbusRtuConnection->energyConsumedPhaseA() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy consumed phase B:" << sdm630ModbusRtuConnection->energyConsumedPhaseB() << " [kWh]" << "\n"; + debug.nospace().noquote() << " - Energy consumed phase C:" << sdm630ModbusRtuConnection->energyConsumedPhaseC() << " [kWh]" << "\n"; + return debug.quote().space(); +} + diff --git a/energymeters/sdm630modbusrtuconnection.h b/energymeters/sdm630modbusrtuconnection.h new file mode 100644 index 0000000..649a667 --- /dev/null +++ b/energymeters/sdm630modbusrtuconnection.h @@ -0,0 +1,199 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This fileDescriptor 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 SDM630MODBUSRTUCONNECTION_H +#define SDM630MODBUSRTUCONNECTION_H + +#include + +#include "../modbus/modbusdatautils.h" +#include + +class Sdm630ModbusRtuConnection : public QObject +{ + Q_OBJECT +public: + explicit Sdm630ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr); + ~Sdm630ModbusRtuConnection() = default; + + ModbusRtuMaster *modbusRtuMaster() const; + quint16 slaveId() const; + + /* Total system power [W] - Address: 52, Size: 2 */ + float totalCurrentPower() const; + + /* Voltage phase L1 [V] - Address: 0, Size: 2 */ + float voltagePhaseA() const; + + /* Voltage phase L2 [V] - Address: 2, Size: 2 */ + float voltagePhaseB() const; + + /* Voltage phase L3 [V] - Address: 4, Size: 2 */ + float voltagePhaseC() const; + + /* Current phase L1 [A] - Address: 6, Size: 2 */ + float currentPhaseA() const; + + /* Current phase L2 [A] - Address: 8, Size: 2 */ + float currentPhaseB() const; + + /* Current phase L3 [A] - Address: 10, Size: 2 */ + float currentPhaseC() const; + + /* Read block from start addess 0 with size of 12 registers containing following 6 properties: + - Voltage phase L1 [V] - Address: 0, Size: 2 + - Voltage phase L2 [V] - Address: 2, Size: 2 + - Voltage phase L3 [V] - Address: 4, Size: 2 + - Current phase L1 [A] - Address: 6, Size: 2 + - Current phase L2 [A] - Address: 8, Size: 2 + - Current phase L3 [A] - Address: 10, Size: 2 + */ + void updatePhaseVoltageAndCurrentBlock(); + /* Power phase L1 [W] - Address: 12, Size: 2 */ + float powerPhaseA() const; + + /* Power phase L2 [W] - Address: 14, Size: 2 */ + float powerPhaseB() const; + + /* Power phase L3 [W] - Address: 16, Size: 2 */ + float powerPhaseC() const; + + /* Read block from start addess 12 with size of 6 registers containing following 3 properties: + - Power phase L1 [W] - Address: 12, Size: 2 + - Power phase L2 [W] - Address: 14, Size: 2 + - Power phase L3 [W] - Address: 16, Size: 2 + */ + void updatePhasePowerBlock(); + /* Frequency [Hz] - Address: 70, Size: 2 */ + float frequency() const; + + /* Total energy consumed [kWh] - Address: 72, Size: 2 */ + float totalEnergyConsumed() const; + + /* Total energy produced [kWh] - Address: 74, Size: 2 */ + float totalEnergyProduced() const; + + /* Read block from start addess 70 with size of 6 registers containing following 3 properties: + - Frequency [Hz] - Address: 70, Size: 2 + - Total energy consumed [kWh] - Address: 72, Size: 2 + - Total energy produced [kWh] - Address: 74, Size: 2 + */ + void updateFrequencyAndTotalEnergyBlock(); + /* Energy produced phase A [kWh] - Address: 346, Size: 2 */ + float energyProducedPhaseA() const; + + /* Energy produced phase B [kWh] - Address: 348, Size: 2 */ + float energyProducedPhaseB() const; + + /* Energy produced phase C [kWh] - Address: 350, Size: 2 */ + float energyProducedPhaseC() const; + + /* Energy consumed phase A [kWh] - Address: 352, Size: 2 */ + float energyConsumedPhaseA() const; + + /* Energy consumed phase B [kWh] - Address: 354, Size: 2 */ + float energyConsumedPhaseB() const; + + /* Energy consumed phase C [kWh] - Address: 356, Size: 2 */ + float energyConsumedPhaseC() const; + + /* Read block from start addess 346 with size of 12 registers containing following 6 properties: + - Energy produced phase A [kWh] - Address: 346, Size: 2 + - Energy produced phase B [kWh] - Address: 348, Size: 2 + - Energy produced phase C [kWh] - Address: 350, Size: 2 + - Energy consumed phase A [kWh] - Address: 352, Size: 2 + - Energy consumed phase B [kWh] - Address: 354, Size: 2 + - Energy consumed phase C [kWh] - Address: 356, Size: 2 + */ + void updatePhaseEnergyEnergyBlock(); + + void updateTotalCurrentPower(); + + virtual void initialize(); + virtual void update(); + +signals: + void initializationFinished(); + + void totalCurrentPowerChanged(float totalCurrentPower); + void voltagePhaseAChanged(float voltagePhaseA); + void voltagePhaseBChanged(float voltagePhaseB); + void voltagePhaseCChanged(float voltagePhaseC); + void currentPhaseAChanged(float currentPhaseA); + void currentPhaseBChanged(float currentPhaseB); + void currentPhaseCChanged(float currentPhaseC); + void powerPhaseAChanged(float powerPhaseA); + void powerPhaseBChanged(float powerPhaseB); + void powerPhaseCChanged(float powerPhaseC); + void frequencyChanged(float frequency); + void totalEnergyConsumedChanged(float totalEnergyConsumed); + void totalEnergyProducedChanged(float totalEnergyProduced); + void energyProducedPhaseAChanged(float energyProducedPhaseA); + void energyProducedPhaseBChanged(float energyProducedPhaseB); + void energyProducedPhaseCChanged(float energyProducedPhaseC); + void energyConsumedPhaseAChanged(float energyConsumedPhaseA); + void energyConsumedPhaseBChanged(float energyConsumedPhaseB); + void energyConsumedPhaseCChanged(float energyConsumedPhaseC); + +private: + ModbusRtuMaster *m_modbusRtuMaster = nullptr; + quint16 m_slaveId = 1; + QVector m_pendingInitReplies; + + float m_totalCurrentPower = 0; + float m_voltagePhaseA = 0; + float m_voltagePhaseB = 0; + float m_voltagePhaseC = 0; + float m_currentPhaseA = 0; + float m_currentPhaseB = 0; + float m_currentPhaseC = 0; + float m_powerPhaseA = 0; + float m_powerPhaseB = 0; + float m_powerPhaseC = 0; + float m_frequency = 0; + float m_totalEnergyConsumed = 0; + float m_totalEnergyProduced = 0; + float m_energyProducedPhaseA = 0; + float m_energyProducedPhaseB = 0; + float m_energyProducedPhaseC = 0; + float m_energyConsumedPhaseA = 0; + float m_energyConsumedPhaseB = 0; + float m_energyConsumedPhaseC = 0; + + void verifyInitFinished(); + + ModbusRtuReply *readTotalCurrentPower(); + + +}; + +QDebug operator<<(QDebug debug, Sdm630ModbusRtuConnection *sdm630ModbusRtuConnection); + +#endif // SDM630MODBUSRTUCONNECTION_H diff --git a/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts index 5adaee8..1ac5b4d 100644 --- a/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts +++ b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-de.ts @@ -4,40 +4,16 @@ 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}) ---------- @@ -49,8 +25,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,88 +34,328 @@ The name of the EventType ({7f9bc504-0882-4b86-83b1-42fa345acfd9}) of ThingClass Verbunden - - - - - Current L1 - The name of the ParamType (ThingClass: sdm630, EventType: currentL1, ID: {4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) + + + + + Current phase A + The name of the ParamType (ThingClass: sdm630, EventType: currentPhaseA, ID: {4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) ---------- The name of the StateType ({4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) of ThingClass sdm630 ---------- -The name of the ParamType (ThingClass: pro380, EventType: currentL1, ID: {1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) +The name of the ParamType (ThingClass: pro380, EventType: currentPhaseA, ID: {1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) ---------- The name of the StateType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) of ThingClass pro380 - Strom L1 + - - - Current L1 changed + + + Current phase A changed The name of the EventType ({4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) of ThingClass sdm630 ---------- The name of the EventType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) of ThingClass pro380 - Strom L1 geändert + - - - - - Current L2 - The name of the ParamType (ThingClass: sdm630, EventType: currentL2, ID: {99e47d06-0a6a-4bfd-b164-61ecb6ba2818}) + + + + + Current phase B + The name of the ParamType (ThingClass: sdm630, EventType: currentPhaseB, 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 ParamType (ThingClass: pro380, EventType: currentPhaseB, ID: {d2f54061-0807-47de-944c-68c8118ece91}) ---------- The name of the StateType ({d2f54061-0807-47de-944c-68c8118ece91}) of ThingClass pro380 - Strom L2 + - - - Current L2 changed + + + Current phase B 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}) + + + + + Current phase C + The name of the ParamType (ThingClass: sdm630, EventType: currentPhaseC, 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 ParamType (ThingClass: pro380, EventType: currentPhaseC, ID: {610b20fb-2718-4f02-ac6e-12a9ef8c7615}) ---------- The name of the StateType ({610b20fb-2718-4f02-ac6e-12a9ef8c7615}) of ThingClass pro380 - Strom L3 + - - - Current L3 changed + + + Current phase C 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 + - + + + + + Current 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 + + + + + + Current 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 + + + + + + + + Current power phase A + The name of the ParamType (ThingClass: sdm630, EventType: currentPowerPhaseA, ID: {3982fb12-b179-40f7-9b27-36adb1cadd37}) +---------- +The name of the StateType ({3982fb12-b179-40f7-9b27-36adb1cadd37}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentPowerPhaseA, ID: {55283773-0a4e-4574-b21a-d4a3f287eab1}) +---------- +The name of the StateType ({55283773-0a4e-4574-b21a-d4a3f287eab1}) of ThingClass pro380 + + + + + + Current power phase A changed + The name of the EventType ({3982fb12-b179-40f7-9b27-36adb1cadd37}) of ThingClass sdm630 +---------- +The name of the EventType ({55283773-0a4e-4574-b21a-d4a3f287eab1}) of ThingClass pro380 + + + + + + + + Current power phase B + The name of the ParamType (ThingClass: sdm630, EventType: currentPowerPhaseB, ID: {2a231c58-b095-4037-8394-a730431e70b8}) +---------- +The name of the StateType ({2a231c58-b095-4037-8394-a730431e70b8}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentPowerPhaseB, ID: {8f15d104-5ff7-4c33-9cf9-fdbef4b6f721}) +---------- +The name of the StateType ({8f15d104-5ff7-4c33-9cf9-fdbef4b6f721}) of ThingClass pro380 + + + + + + Current power phase B changed + The name of the EventType ({2a231c58-b095-4037-8394-a730431e70b8}) of ThingClass sdm630 +---------- +The name of the EventType ({8f15d104-5ff7-4c33-9cf9-fdbef4b6f721}) of ThingClass pro380 + + + + + + + + Current power phase C + The name of the ParamType (ThingClass: sdm630, EventType: currentPowerPhaseC, ID: {ee8c4f0c-2b69-4210-9966-1553a592b06d}) +---------- +The name of the StateType ({ee8c4f0c-2b69-4210-9966-1553a592b06d}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentPowerPhaseC, ID: {86c0f968-ee70-4f56-bdfc-33b8e2b134a4}) +---------- +The name of the StateType ({86c0f968-ee70-4f56-bdfc-33b8e2b134a4}) of ThingClass pro380 + + + + + + Current power phase C changed + The name of the EventType ({ee8c4f0c-2b69-4210-9966-1553a592b06d}) of ThingClass sdm630 +---------- +The name of the EventType ({86c0f968-ee70-4f56-bdfc-33b8e2b134a4}) of ThingClass pro380 + + + + + + + + Energy consumed phase A + The name of the ParamType (ThingClass: sdm630, EventType: energyConsumedPhaseA, ID: {6ca06c81-fe75-4448-a22f-47c303421440}) +---------- +The name of the StateType ({6ca06c81-fe75-4448-a22f-47c303421440}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyConsumedPhaseA, ID: {b16b3b0c-82d9-4b3c-a172-0e6631c8ce16}) +---------- +The name of the StateType ({b16b3b0c-82d9-4b3c-a172-0e6631c8ce16}) of ThingClass pro380 + + + + + + Energy consumed phase A changed + The name of the EventType ({6ca06c81-fe75-4448-a22f-47c303421440}) of ThingClass sdm630 +---------- +The name of the EventType ({b16b3b0c-82d9-4b3c-a172-0e6631c8ce16}) of ThingClass pro380 + + + + + + + + Energy consumed phase B + The name of the ParamType (ThingClass: sdm630, EventType: energyConsumedPhaseB, ID: {fa2b879b-2a81-4bc8-9577-98082c4d9330}) +---------- +The name of the StateType ({fa2b879b-2a81-4bc8-9577-98082c4d9330}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyConsumedPhaseB, ID: {64225f7f-9b2f-4bfc-87b2-38758804a28b}) +---------- +The name of the StateType ({64225f7f-9b2f-4bfc-87b2-38758804a28b}) of ThingClass pro380 + + + + + + Energy consumed phase B changed + The name of the EventType ({fa2b879b-2a81-4bc8-9577-98082c4d9330}) of ThingClass sdm630 +---------- +The name of the EventType ({64225f7f-9b2f-4bfc-87b2-38758804a28b}) of ThingClass pro380 + + + + + + + + Energy consumed phase C + The name of the ParamType (ThingClass: sdm630, EventType: energyConsumedPhaseC, ID: {4c084c9e-7a5d-42d1-96b2-a8a4b4a25713}) +---------- +The name of the StateType ({4c084c9e-7a5d-42d1-96b2-a8a4b4a25713}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyConsumedPhaseC, ID: {a6e82d61-e837-4ec8-b14a-af0d49bea9d2}) +---------- +The name of the StateType ({a6e82d61-e837-4ec8-b14a-af0d49bea9d2}) of ThingClass pro380 + + + + + + Energy consumed phase C changed + The name of the EventType ({4c084c9e-7a5d-42d1-96b2-a8a4b4a25713}) of ThingClass sdm630 +---------- +The name of the EventType ({a6e82d61-e837-4ec8-b14a-af0d49bea9d2}) of ThingClass pro380 + + + + + + + + Energy produced phase A + The name of the ParamType (ThingClass: sdm630, EventType: energyProducedPhaseA, ID: {308fa88e-6054-4c79-b12a-be2d0a404ef6}) +---------- +The name of the StateType ({308fa88e-6054-4c79-b12a-be2d0a404ef6}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyProducedPhaseA, ID: {95bd476e-c247-4f7d-ab01-d9f1b7c0d996}) +---------- +The name of the StateType ({95bd476e-c247-4f7d-ab01-d9f1b7c0d996}) of ThingClass pro380 + + + + + + Energy produced phase A changed + The name of the EventType ({308fa88e-6054-4c79-b12a-be2d0a404ef6}) of ThingClass sdm630 +---------- +The name of the EventType ({95bd476e-c247-4f7d-ab01-d9f1b7c0d996}) of ThingClass pro380 + + + + + + + + Energy produced phase B + The name of the ParamType (ThingClass: sdm630, EventType: energyProducedPhaseB, ID: {48ab6e61-dfb4-4f85-b5cc-9d89e53c6b39}) +---------- +The name of the StateType ({48ab6e61-dfb4-4f85-b5cc-9d89e53c6b39}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyProducedPhaseB, ID: {f0a0bd81-708c-48d6-b5c9-165464a5b309}) +---------- +The name of the StateType ({f0a0bd81-708c-48d6-b5c9-165464a5b309}) of ThingClass pro380 + + + + + + Energy produced phase B changed + The name of the EventType ({48ab6e61-dfb4-4f85-b5cc-9d89e53c6b39}) of ThingClass sdm630 +---------- +The name of the EventType ({f0a0bd81-708c-48d6-b5c9-165464a5b309}) of ThingClass pro380 + + + + + + + + Energy produced phase C + The name of the ParamType (ThingClass: sdm630, EventType: energyProducedPhaseC, ID: {6b3ddf15-3d4b-4dc1-8e5a-84fbf90b49ff}) +---------- +The name of the StateType ({6b3ddf15-3d4b-4dc1-8e5a-84fbf90b49ff}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyProducedPhaseC, ID: {c33fcd11-b4a9-44b2-9e30-40dfa2e4c9b1}) +---------- +The name of the StateType ({c33fcd11-b4a9-44b2-9e30-40dfa2e4c9b1}) of ThingClass pro380 + + + + + + Energy produced phase C changed + The name of the EventType ({6b3ddf15-3d4b-4dc1-8e5a-84fbf90b49ff}) of ThingClass sdm630 +---------- +The name of the EventType ({c33fcd11-b4a9-44b2-9e30-40dfa2e4c9b1}) of ThingClass pro380 + + + + 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}) ---------- @@ -151,8 +367,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 ---------- @@ -160,8 +376,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}) ---------- @@ -169,8 +385,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}) ---------- @@ -178,44 +394,92 @@ 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}) ----------- -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 + + SDM630 Modbus The name of the ThingClass ({f37597bb-35fe-48f2-9617-343dd54c0903}) - SDM630Modbus + - - + + + + + Voltage phase A + The name of the ParamType (ThingClass: sdm630, EventType: voltagePhaseA, ID: {db018146-0441-4dc0-9834-6d43ebaf8311}) +---------- +The name of the StateType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: voltagePhaseA, ID: {04dba21a-7447-46b9-b9ae-095e5769e511}) +---------- +The name of the StateType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 + + + + + + Voltage phase A 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 phase B + The name of the ParamType (ThingClass: sdm630, EventType: voltagePhaseB, 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: voltagePhaseB, ID: {270d0c34-0a0c-4655-985f-faad6efd1afd}) +---------- +The name of the StateType ({270d0c34-0a0c-4655-985f-faad6efd1afd}) of ThingClass pro380 + + + + + + Voltage phase B 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 phase C + The name of the ParamType (ThingClass: sdm630, EventType: voltagePhaseC, 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: voltagePhaseC, ID: {a1da8cfd-37cc-4c87-b857-e942cd90daec}) +---------- +The name of the StateType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) of ThingClass pro380 + + + + + + Voltage phase C 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 + + + + + Slave address The name of the ParamType (ThingClass: sdm630, Type: discovery, ID: {6ab43559-53ec-47ba-b8a0-8d3b7f8d90c2}) ---------- @@ -223,10 +487,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}) ---------- @@ -238,8 +502,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 ---------- @@ -247,10 +511,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}) ---------- @@ -262,8 +526,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 ---------- @@ -271,85 +535,7 @@ 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 L1 - The name of the ParamType (ThingClass: sdm630, EventType: voltageL1, ID: {db018146-0441-4dc0-9834-6d43ebaf8311}) ----------- -The name of the StateType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 ----------- -The name of the ParamType (ThingClass: pro380, EventType: voltageL1, ID: {04dba21a-7447-46b9-b9ae-095e5769e511}) ----------- -The name of the StateType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 - Spannung L1 - - - - - Voltage L1 changed - The name of the EventType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 ----------- -The name of the EventType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 - Spannung L1 geändert - - - - - - - Voltage L2 - The name of the ParamType (ThingClass: sdm630, EventType: voltageL2, ID: {406f6d02-d5eb-49b3-87da-3247568e6054}) ----------- -The name of the StateType ({406f6d02-d5eb-49b3-87da-3247568e6054}) of ThingClass sdm630 ----------- -The name of the ParamType (ThingClass: pro380, EventType: voltageL2, ID: {270d0c34-0a0c-4655-985f-faad6efd1afd}) ----------- -The name of the StateType ({270d0c34-0a0c-4655-985f-faad6efd1afd}) of ThingClass pro380 - Spannung L2 - - - - - Voltage L2 changed - The name of the EventType ({406f6d02-d5eb-49b3-87da-3247568e6054}) of ThingClass sdm630 ----------- -The name of the EventType ({270d0c34-0a0c-4655-985f-faad6efd1afd}) of ThingClass pro380 - Spannung L2 geändert - - - - - - - Voltage L3 - The name of the ParamType (ThingClass: sdm630, EventType: voltageL3, ID: {ace6294d-deaa-4d9a-af78-d64379bcb229}) ----------- -The name of the StateType ({ace6294d-deaa-4d9a-af78-d64379bcb229}) of ThingClass sdm630 ----------- -The name of the ParamType (ThingClass: pro380, EventType: voltageL3, ID: {a1da8cfd-37cc-4c87-b857-e942cd90daec}) ----------- -The name of the StateType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) of ThingClass pro380 - Spannung L3 - - - - - Voltage L3 changed - The name of the EventType ({ace6294d-deaa-4d9a-af78-d64379bcb229}) of ThingClass sdm630 ----------- -The name of the EventType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) of ThingClass pro380 - Spannung L3 geändert - - - + inepro Metering The name of the vendor ({64f4df0f-18ce-409c-bf32-84a086c691ca}) inepro Metering @@ -358,32 +544,32 @@ The name of the EventType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) 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 c09f5ee..f84148f 100644 --- a/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts +++ b/energymeters/translations/56e95111-fb6b-4f63-9a0a-a5ee001e89ed-en_US.ts @@ -4,40 +4,16 @@ 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}) ---------- @@ -49,8 +25,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,88 +34,328 @@ The name of the EventType ({7f9bc504-0882-4b86-83b1-42fa345acfd9}) of ThingClass - - - - - Current L1 - The name of the ParamType (ThingClass: sdm630, EventType: currentL1, ID: {4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) + + + + + Current phase A + The name of the ParamType (ThingClass: sdm630, EventType: currentPhaseA, ID: {4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) ---------- The name of the StateType ({4baf1d08-5ffa-49cf-95ef-9527b0c6f081}) of ThingClass sdm630 ---------- -The name of the ParamType (ThingClass: pro380, EventType: currentL1, ID: {1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) +The name of the ParamType (ThingClass: pro380, EventType: currentPhaseA, ID: {1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) ---------- The name of the StateType ({1e077a3b-2dab-4ec4-ae96-ab49a564fe31}) of ThingClass pro380 - - - Current L1 changed + + + Current phase A 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}) + + + + + Current phase B + The name of the ParamType (ThingClass: sdm630, EventType: currentPhaseB, 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 ParamType (ThingClass: pro380, EventType: currentPhaseB, ID: {d2f54061-0807-47de-944c-68c8118ece91}) ---------- The name of the StateType ({d2f54061-0807-47de-944c-68c8118ece91}) of ThingClass pro380 - - - Current L2 changed + + + Current phase B 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}) + + + + + Current phase C + The name of the ParamType (ThingClass: sdm630, EventType: currentPhaseC, 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 ParamType (ThingClass: pro380, EventType: currentPhaseC, ID: {610b20fb-2718-4f02-ac6e-12a9ef8c7615}) ---------- The name of the StateType ({610b20fb-2718-4f02-ac6e-12a9ef8c7615}) of ThingClass pro380 - - - Current L3 changed + + + Current phase C 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 - + + + + + Current 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 + + + + + + Current 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 + + + + + + + + Current power phase A + The name of the ParamType (ThingClass: sdm630, EventType: currentPowerPhaseA, ID: {3982fb12-b179-40f7-9b27-36adb1cadd37}) +---------- +The name of the StateType ({3982fb12-b179-40f7-9b27-36adb1cadd37}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentPowerPhaseA, ID: {55283773-0a4e-4574-b21a-d4a3f287eab1}) +---------- +The name of the StateType ({55283773-0a4e-4574-b21a-d4a3f287eab1}) of ThingClass pro380 + + + + + + Current power phase A changed + The name of the EventType ({3982fb12-b179-40f7-9b27-36adb1cadd37}) of ThingClass sdm630 +---------- +The name of the EventType ({55283773-0a4e-4574-b21a-d4a3f287eab1}) of ThingClass pro380 + + + + + + + + Current power phase B + The name of the ParamType (ThingClass: sdm630, EventType: currentPowerPhaseB, ID: {2a231c58-b095-4037-8394-a730431e70b8}) +---------- +The name of the StateType ({2a231c58-b095-4037-8394-a730431e70b8}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentPowerPhaseB, ID: {8f15d104-5ff7-4c33-9cf9-fdbef4b6f721}) +---------- +The name of the StateType ({8f15d104-5ff7-4c33-9cf9-fdbef4b6f721}) of ThingClass pro380 + + + + + + Current power phase B changed + The name of the EventType ({2a231c58-b095-4037-8394-a730431e70b8}) of ThingClass sdm630 +---------- +The name of the EventType ({8f15d104-5ff7-4c33-9cf9-fdbef4b6f721}) of ThingClass pro380 + + + + + + + + Current power phase C + The name of the ParamType (ThingClass: sdm630, EventType: currentPowerPhaseC, ID: {ee8c4f0c-2b69-4210-9966-1553a592b06d}) +---------- +The name of the StateType ({ee8c4f0c-2b69-4210-9966-1553a592b06d}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: currentPowerPhaseC, ID: {86c0f968-ee70-4f56-bdfc-33b8e2b134a4}) +---------- +The name of the StateType ({86c0f968-ee70-4f56-bdfc-33b8e2b134a4}) of ThingClass pro380 + + + + + + Current power phase C changed + The name of the EventType ({ee8c4f0c-2b69-4210-9966-1553a592b06d}) of ThingClass sdm630 +---------- +The name of the EventType ({86c0f968-ee70-4f56-bdfc-33b8e2b134a4}) of ThingClass pro380 + + + + + + + + Energy consumed phase A + The name of the ParamType (ThingClass: sdm630, EventType: energyConsumedPhaseA, ID: {6ca06c81-fe75-4448-a22f-47c303421440}) +---------- +The name of the StateType ({6ca06c81-fe75-4448-a22f-47c303421440}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyConsumedPhaseA, ID: {b16b3b0c-82d9-4b3c-a172-0e6631c8ce16}) +---------- +The name of the StateType ({b16b3b0c-82d9-4b3c-a172-0e6631c8ce16}) of ThingClass pro380 + + + + + + Energy consumed phase A changed + The name of the EventType ({6ca06c81-fe75-4448-a22f-47c303421440}) of ThingClass sdm630 +---------- +The name of the EventType ({b16b3b0c-82d9-4b3c-a172-0e6631c8ce16}) of ThingClass pro380 + + + + + + + + Energy consumed phase B + The name of the ParamType (ThingClass: sdm630, EventType: energyConsumedPhaseB, ID: {fa2b879b-2a81-4bc8-9577-98082c4d9330}) +---------- +The name of the StateType ({fa2b879b-2a81-4bc8-9577-98082c4d9330}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyConsumedPhaseB, ID: {64225f7f-9b2f-4bfc-87b2-38758804a28b}) +---------- +The name of the StateType ({64225f7f-9b2f-4bfc-87b2-38758804a28b}) of ThingClass pro380 + + + + + + Energy consumed phase B changed + The name of the EventType ({fa2b879b-2a81-4bc8-9577-98082c4d9330}) of ThingClass sdm630 +---------- +The name of the EventType ({64225f7f-9b2f-4bfc-87b2-38758804a28b}) of ThingClass pro380 + + + + + + + + Energy consumed phase C + The name of the ParamType (ThingClass: sdm630, EventType: energyConsumedPhaseC, ID: {4c084c9e-7a5d-42d1-96b2-a8a4b4a25713}) +---------- +The name of the StateType ({4c084c9e-7a5d-42d1-96b2-a8a4b4a25713}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyConsumedPhaseC, ID: {a6e82d61-e837-4ec8-b14a-af0d49bea9d2}) +---------- +The name of the StateType ({a6e82d61-e837-4ec8-b14a-af0d49bea9d2}) of ThingClass pro380 + + + + + + Energy consumed phase C changed + The name of the EventType ({4c084c9e-7a5d-42d1-96b2-a8a4b4a25713}) of ThingClass sdm630 +---------- +The name of the EventType ({a6e82d61-e837-4ec8-b14a-af0d49bea9d2}) of ThingClass pro380 + + + + + + + + Energy produced phase A + The name of the ParamType (ThingClass: sdm630, EventType: energyProducedPhaseA, ID: {308fa88e-6054-4c79-b12a-be2d0a404ef6}) +---------- +The name of the StateType ({308fa88e-6054-4c79-b12a-be2d0a404ef6}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyProducedPhaseA, ID: {95bd476e-c247-4f7d-ab01-d9f1b7c0d996}) +---------- +The name of the StateType ({95bd476e-c247-4f7d-ab01-d9f1b7c0d996}) of ThingClass pro380 + + + + + + Energy produced phase A changed + The name of the EventType ({308fa88e-6054-4c79-b12a-be2d0a404ef6}) of ThingClass sdm630 +---------- +The name of the EventType ({95bd476e-c247-4f7d-ab01-d9f1b7c0d996}) of ThingClass pro380 + + + + + + + + Energy produced phase B + The name of the ParamType (ThingClass: sdm630, EventType: energyProducedPhaseB, ID: {48ab6e61-dfb4-4f85-b5cc-9d89e53c6b39}) +---------- +The name of the StateType ({48ab6e61-dfb4-4f85-b5cc-9d89e53c6b39}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyProducedPhaseB, ID: {f0a0bd81-708c-48d6-b5c9-165464a5b309}) +---------- +The name of the StateType ({f0a0bd81-708c-48d6-b5c9-165464a5b309}) of ThingClass pro380 + + + + + + Energy produced phase B changed + The name of the EventType ({48ab6e61-dfb4-4f85-b5cc-9d89e53c6b39}) of ThingClass sdm630 +---------- +The name of the EventType ({f0a0bd81-708c-48d6-b5c9-165464a5b309}) of ThingClass pro380 + + + + + + + + Energy produced phase C + The name of the ParamType (ThingClass: sdm630, EventType: energyProducedPhaseC, ID: {6b3ddf15-3d4b-4dc1-8e5a-84fbf90b49ff}) +---------- +The name of the StateType ({6b3ddf15-3d4b-4dc1-8e5a-84fbf90b49ff}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: energyProducedPhaseC, ID: {c33fcd11-b4a9-44b2-9e30-40dfa2e4c9b1}) +---------- +The name of the StateType ({c33fcd11-b4a9-44b2-9e30-40dfa2e4c9b1}) of ThingClass pro380 + + + + + + Energy produced phase C changed + The name of the EventType ({6b3ddf15-3d4b-4dc1-8e5a-84fbf90b49ff}) of ThingClass sdm630 +---------- +The name of the EventType ({c33fcd11-b4a9-44b2-9e30-40dfa2e4c9b1}) 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}) ---------- @@ -151,8 +367,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 ---------- @@ -160,8 +376,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}) ---------- @@ -169,8 +385,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}) ---------- @@ -178,44 +394,92 @@ 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}) ----------- -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 + + SDM630 Modbus The name of the ThingClass ({f37597bb-35fe-48f2-9617-343dd54c0903}) - - + + + + + Voltage phase A + The name of the ParamType (ThingClass: sdm630, EventType: voltagePhaseA, ID: {db018146-0441-4dc0-9834-6d43ebaf8311}) +---------- +The name of the StateType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 +---------- +The name of the ParamType (ThingClass: pro380, EventType: voltagePhaseA, ID: {04dba21a-7447-46b9-b9ae-095e5769e511}) +---------- +The name of the StateType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 + + + + + + Voltage phase A 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 phase B + The name of the ParamType (ThingClass: sdm630, EventType: voltagePhaseB, 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: voltagePhaseB, ID: {270d0c34-0a0c-4655-985f-faad6efd1afd}) +---------- +The name of the StateType ({270d0c34-0a0c-4655-985f-faad6efd1afd}) of ThingClass pro380 + + + + + + Voltage phase B 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 phase C + The name of the ParamType (ThingClass: sdm630, EventType: voltagePhaseC, 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: voltagePhaseC, ID: {a1da8cfd-37cc-4c87-b857-e942cd90daec}) +---------- +The name of the StateType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) of ThingClass pro380 + + + + + + Voltage phase C 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 + + + + + Slave address The name of the ParamType (ThingClass: sdm630, Type: discovery, ID: {6ab43559-53ec-47ba-b8a0-8d3b7f8d90c2}) ---------- @@ -223,10 +487,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}) ---------- @@ -238,8 +502,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 ---------- @@ -247,10 +511,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}) ---------- @@ -262,8 +526,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 ---------- @@ -271,85 +535,7 @@ 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 L1 - The name of the ParamType (ThingClass: sdm630, EventType: voltageL1, ID: {db018146-0441-4dc0-9834-6d43ebaf8311}) ----------- -The name of the StateType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 ----------- -The name of the ParamType (ThingClass: pro380, EventType: voltageL1, ID: {04dba21a-7447-46b9-b9ae-095e5769e511}) ----------- -The name of the StateType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 - - - - - - Voltage L1 changed - The name of the EventType ({db018146-0441-4dc0-9834-6d43ebaf8311}) of ThingClass sdm630 ----------- -The name of the EventType ({04dba21a-7447-46b9-b9ae-095e5769e511}) of ThingClass pro380 - - - - - - - - Voltage L2 - The name of the ParamType (ThingClass: sdm630, EventType: voltageL2, ID: {406f6d02-d5eb-49b3-87da-3247568e6054}) ----------- -The name of the StateType ({406f6d02-d5eb-49b3-87da-3247568e6054}) of ThingClass sdm630 ----------- -The name of the ParamType (ThingClass: pro380, EventType: voltageL2, ID: {270d0c34-0a0c-4655-985f-faad6efd1afd}) ----------- -The name of the StateType ({270d0c34-0a0c-4655-985f-faad6efd1afd}) of ThingClass pro380 - - - - - - Voltage L2 changed - The name of the EventType ({406f6d02-d5eb-49b3-87da-3247568e6054}) of ThingClass sdm630 ----------- -The name of the EventType ({270d0c34-0a0c-4655-985f-faad6efd1afd}) of ThingClass pro380 - - - - - - - - Voltage L3 - The name of the ParamType (ThingClass: sdm630, EventType: voltageL3, ID: {ace6294d-deaa-4d9a-af78-d64379bcb229}) ----------- -The name of the StateType ({ace6294d-deaa-4d9a-af78-d64379bcb229}) of ThingClass sdm630 ----------- -The name of the ParamType (ThingClass: pro380, EventType: voltageL3, ID: {a1da8cfd-37cc-4c87-b857-e942cd90daec}) ----------- -The name of the StateType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) of ThingClass pro380 - - - - - - Voltage L3 changed - The name of the EventType ({ace6294d-deaa-4d9a-af78-d64379bcb229}) of ThingClass sdm630 ----------- -The name of the EventType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) of ThingClass pro380 - - - - + inepro Metering The name of the vendor ({64f4df0f-18ce-409c-bf32-84a086c691ca}) @@ -358,32 +544,32 @@ The name of the EventType ({a1da8cfd-37cc-4c87-b857-e942cd90daec}) 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. diff --git a/modbus/tools/README.md b/modbus/tools/README.md index 400b082..72b0309 100644 --- a/modbus/tools/README.md +++ b/modbus/tools/README.md @@ -65,7 +65,7 @@ The basic structure of the modbus register JSON looks like following example: }, ... ] -} +} ``` @@ -78,6 +78,15 @@ There are 2 possibilities: * `BigEndian`: default if not specified: register bytes come in following order `[0, 1, 2, 3]`: `ABCD` * `LittleEndian`: register bytes come in following order `[0, 1, 2, 3]`: `CDAB` +## Protocol + +Depending on the communication protocol, a different base class will be used for the resulting output class. + +There are 2 possibilities: + +* `RTU`: a communication based on the RS485 serial RTU transport protocol +* `TCP`: a communication based on the TCP transport protocol + ## Enums Many modbus devices provide inforation using `Enums`, indicating a special state trough a defined list of values. If a register implements an enum, you can define it in the `enums` section. The `name` property defines the name of the enum, and the script will generate a c++ enum definition from this section. Each enum value will then be generated using ` = `. @@ -120,6 +129,50 @@ Earch register will be defined as a property in the resulting class modbus TCP c * `staticScaleFactor`: Optional. Use this static scale factor to convert this register value to float. `floatValue = registerValue * 10^staticScaleFactor`. The scale factor value is normally a `int16` value, i.e. -10 or 10 * `defaultValue`: Optional. The value for initializing the property. +# Register blocks + +On many device it is possible to read multiple registers in one modbus call. This can improve speed significantly when reading many register addresses which are in a row. + +> Important: all registers within the block must exist, be in a row with no gaps inbetween! + +A block sequence looks like this and will define a read method for reading the entwire block. Writing multiple blocks is currently not supported since not needed so far, but could be added to. In any case, all registers must be read or written, never have combinations. + +* `id`: Mandatory. The id defines the name of the block used in the resulting class. +* `readSchedule`: Optional. Defines when the register needs to be fetched. If no read schedule has been defined, the class will provide only the update methods, but will not read the value during `initialize()` or `update()` calls. Possible values are: + * `init`: The register will be fetched during initialization. Once all `init `registers have been fetched, the `initializationFinished()` signal will be emitted. + * `update`: The register will be feched each time the `update()` method will be called. +* `registers`: Mandatory. The list of registers within the block. Please see the [Registers](#register) definition for more details about registers. The must be from the same register type, the same access type and there are no gaps allowed. + +Example block: + + "blocks": [ + { + "id": "meaningFullName", + "readSchedule": "update", + "registers": [ + { + "id": "registerOne", + "address": 0, + "size": 2, + ... + }, + { + "id": "registerTwo", + "address": 2, + "size": 1, + ... + }, + { + "id": "registerThree", + "address": 3, + "size": 2, + ... + }, + ] + } + ] + + # Example Change into your plugin sub directory. diff --git a/modbus/tools/generate-connection.py b/modbus/tools/generate-connection.py index 83f3214..73e9d26 100644 --- a/modbus/tools/generate-connection.py +++ b/modbus/tools/generate-connection.py @@ -230,56 +230,56 @@ def getValueConversionMethod(registerDefinition): if 'enum' in registerDefinition: enumName = registerDefinition['enum'] if registerDefinition['type'] == 'uint16': - return ('static_cast<%s>(ModbusDataUtils::convertToUInt16(unit.values()))' % (enumName)) + return ('static_cast<%s>(ModbusDataUtils::convertToUInt16(values))' % (enumName)) elif registerDefinition['type'] == 'int16': - return ('static_cast<%s>(ModbusDataUtils::convertToInt16(unit.values()))' % (enumName)) + return ('static_cast<%s>(ModbusDataUtils::convertToInt16(values))' % (enumName)) elif registerDefinition['type'] == 'uint32': - return ('static_cast<%s>(ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrder%s))' % (enumName, endianness)) + return ('static_cast<%s>(ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrder%s))' % (enumName, endianness)) elif registerDefinition['type'] == 'int32': - return ('static_cast<%s>(ModbusDataUtils::convertToInt32(unit.values(), ModbusDataUtils::ByteOrder%s))' % (enumName, endianness)) + return ('static_cast<%s>(ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrder%s))' % (enumName, endianness)) # Handle scale factors if 'scaleFactor' in registerDefinition: scaleFactorProperty = 'm_%s' % registerDefinition['scaleFactor'] if registerDefinition['type'] == 'uint16': - return ('ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, %s)' % (scaleFactorProperty)) + return ('ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, %s)' % (scaleFactorProperty)) elif registerDefinition['type'] == 'int16': - return ('ModbusDataUtils::convertToInt16(unit.values()) * 1.0 * pow(10, %s)' % (scaleFactorProperty)) + return ('ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, %s)' % (scaleFactorProperty)) elif registerDefinition['type'] == 'uint32': - return ('ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactorProperty)) + return ('ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactorProperty)) elif registerDefinition['type'] == 'int32': - return ('ModbusDataUtils::convertToInt32(unit.values(), ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactorProperty)) + return ('ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactorProperty)) elif 'staticScaleFactor' in registerDefinition: scaleFactor = registerDefinition['staticScaleFactor'] if registerDefinition['type'] == 'uint16': - return ('ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, %s)' % (scaleFactor)) + return ('ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, %s)' % (scaleFactor)) elif registerDefinition['type'] == 'int16': - return ('ModbusDataUtils::convertToInt16(unit.values()) * 1.0 * pow(10, %s)' % (scaleFactor)) + return ('ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, %s)' % (scaleFactor)) elif registerDefinition['type'] == 'uint32': - return ('ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactor)) + return ('ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactor)) elif registerDefinition['type'] == 'int32': - return ('ModbusDataUtils::convertToInt32(unit.values(), ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactor)) + return ('ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactor)) # Handle default types elif registerDefinition['type'] == 'uint16': - return ('ModbusDataUtils::convertToUInt16(unit.values())') + return ('ModbusDataUtils::convertToUInt16(values)') elif registerDefinition['type'] == 'int16': - return ('ModbusDataUtils::convertToInt16(unit.values())') + return ('ModbusDataUtils::convertToInt16(values)') elif registerDefinition['type'] == 'uint32': - return ('ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness) + return ('ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrder%s)' % endianness) elif registerDefinition['type'] == 'int32': - return ('ModbusDataUtils::convertToInt32(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness) + return ('ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrder%s)' % endianness) elif registerDefinition['type'] == 'uint64': - return ('ModbusDataUtils::convertToUInt64(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness) + return ('ModbusDataUtils::convertToUInt64(values, ModbusDataUtils::ByteOrder%s)' % endianness) elif registerDefinition['type'] == 'int64': - return ('ModbusDataUtils::convertToInt64(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness) + return ('ModbusDataUtils::convertToInt64(values, ModbusDataUtils::ByteOrder%s)' % endianness) elif registerDefinition['type'] == 'float': - return ('ModbusDataUtils::convertToFloat32(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness) + return ('ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrder%s)' % endianness) elif registerDefinition['type'] == 'float64': - return ('ModbusDataUtils::convertToFloat64(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness) + return ('ModbusDataUtils::convertToFloat64(values, ModbusDataUtils::ByteOrder%s)' % endianness) elif registerDefinition['type'] == 'string': - return ('ModbusDataUtils::convertToString(unit.values())') + return ('ModbusDataUtils::convertToString(values)') def writePropertyGetSetMethodDeclarations(fileDescriptor, registerDefinitions): @@ -300,7 +300,7 @@ def writePropertyGetSetMethodDeclarations(fileDescriptor, registerDefinitions): writeLine(fileDescriptor) -def writePropertyGetSetMethodImplementations(fileDescriptor, className, registerDefinitions): +def writePropertyGetSetMethodImplementationsTcp(fileDescriptor, className, registerDefinitions): for registerDefinition in registerDefinitions: propertyName = registerDefinition['id'] propertyTyp = getCppDataType(registerDefinition) @@ -324,8 +324,11 @@ def writePropertyGetSetMethodImplementations(fileDescriptor, className, register writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Write \\"%s\\" register:" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) if registerDefinition['registerType'] == 'holdingRegister': writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, values.count());' % (registerDefinition['address'])) - - # TODO: other write methods + elif registerDefinition['registerType'] == 'coils': + writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, values.count());' % (registerDefinition['address'])) + else: + print('Error: invalid register type for writing.') + exit(1) writeLine(fileDescriptor, ' request.setValues(values);') writeLine(fileDescriptor, ' return sendWriteRequest(request, m_slaveId);') @@ -333,6 +336,39 @@ def writePropertyGetSetMethodImplementations(fileDescriptor, className, register writeLine(fileDescriptor) +def writePropertyGetSetMethodImplementationsRtu(fileDescriptor, className, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + # Get + if 'enum' in registerDefinition: + writeLine(fileDescriptor, '%s::%s %s::%s() const' % (className, propertyTyp, className, propertyName)) + else: + writeLine(fileDescriptor, '%s %s::%s() const' % (propertyTyp, className, propertyName)) + + writeLine(fileDescriptor, '{') + writeLine(fileDescriptor, ' return m_%s;' % propertyName) + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + + # Check if we require a set method + if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO': + writeLine(fileDescriptor, 'ModbusRtuReply *%s::set%s(%s %s)' % (className, propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName)) + writeLine(fileDescriptor, '{') + + writeLine(fileDescriptor, ' QVector values = %s;' % getConversionToValueMethod(registerDefinition)) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Write \\"%s\\" register:" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + if registerDefinition['registerType'] == 'holdingRegister': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeHoldingRegisters(m_slaveId, %s, values);' % (registerDefinition['address'])) + elif registerDefinition['registerType'] == 'coils': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeCoils(m_slaveId, %s, values);' % (registerDefinition['address'])) + else: + print('Error: invalid register type for writing.') + exit(1) + + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + def writePropertyUpdateMethodDeclarations(fileDescriptor, registerDefinitions): for registerDefinition in registerDefinitions: @@ -344,7 +380,76 @@ def writePropertyUpdateMethodDeclarations(fileDescriptor, registerDefinitions): writeLine(fileDescriptor, ' void update%s();' % (propertyName[0].upper() + propertyName[1:])) -def writePropertyUpdateMethodImplementations(fileDescriptor, className, registerDefinitions): +def validateBlocks(blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerAccess = "" + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerAccess = blockRegister['access'] + registerType = blockRegister['registerType'] + else: + previouseRegisterAddress = blockRegisters[i - 1]['address'] + previouseRegisterSize = blockRegisters[i - 1]['size'] + previouseRegisterType = blockRegisters[i - 1]['registerType'] + if previouseRegisterAddress + previouseRegisterSize != blockRegister['address']: + print('Error: block %s has invalid register order in register %s. There seems to be a gap between the registers.' % (blockName, blockRegister['id'])) + exit(1) + + if blockRegister['access'] != registerAccess: + print('Error: block %s has inconsistent register access in register %s. The block registers dont seem to have the same access rights.' % (blockName, blockRegister['id'])) + exit(1) + + if blockRegister['registerType'] != registerType: + print('Error: block %s has inconsistent register type in register %s. The block registers dont seem to be from the same type.' % (blockName, blockRegister['id'])) + exit(1) + + registerCount += 1 + blockSize += blockRegister['size'] + + print('Define valid block \"%s\" starting at %s with length %s containing %s properties to read.' % (blockName, blockStartAddress, blockSize, registerCount)) + + +def writeBlocksUpdateMethodDeclarations(fileDescriptor, blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + + # Write the property get / set methods for the block registers + writePropertyGetSetMethodDeclarations(fileDescriptor, blockRegisters) + + blockStartAddress = 0 + blockSize = 0 + registerCount = 0 + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + + registerCount += 1 + blockSize += blockRegister['size'] + + # Write the block update method + writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount)) + for i, registerDefinition in enumerate(blockRegisters): + if 'unit' in registerDefinition and registerDefinition['unit'] != '': + writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size'])) + else: + writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' */ ' ) + writeLine(fileDescriptor, ' void update%sBlock();' % (blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor) + + +def writePropertyUpdateMethodImplementationsTcp(fileDescriptor, className, registerDefinitions): for registerDefinition in registerDefinitions: if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': continue @@ -362,9 +467,8 @@ def writePropertyUpdateMethodImplementations(fileDescriptor, className, register writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){') writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {') writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();') - writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) - - # FIXME: introduce bool and check register type for parsing + writeLine(fileDescriptor, ' const QVector values = unit.values();') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(registerDefinition))) writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:])) writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:])) @@ -387,13 +491,132 @@ def writePropertyUpdateMethodImplementations(fileDescriptor, className, register writeLine(fileDescriptor) -def writeInternalPropertyReadMethodDeclarations(fileDescriptor, registerDefinitions): +def writePropertyUpdateMethodImplementationsRtu(fileDescriptor, className, registerDefinitions): + for registerDefinition in registerDefinitions: + if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init': + continue + + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + writeLine(fileDescriptor, 'void %s::update%s()' % (className, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, '{') + writeLine(fileDescriptor, ' // Update registers from %s' % registerDefinition['description']) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read \\"%s\\" register:" << %s << "size:" << %s;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + writeLine(fileDescriptor, ' ModbusRtuReply *reply = read%s();' % (propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' if (reply) {') + writeLine(fileDescriptor, ' if (!reply->isFinished()) {') + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') + writeLine(fileDescriptor, ' QVector values = reply->result();') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size'])) + + # FIXME: introduce bool and check register type for parsing + writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(registerDefinition))) + writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName)) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating \\"%s\\" registers" << error << reply->errorString();' % (className, registerDefinition['description'])) + writeLine(fileDescriptor, ' emit reply->finished();') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers";' % (className, registerDefinition['description'])) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + + +def writeBlockUpdateMethodImplementationsRtu(fileDescriptor, className, blockDefinitions): + for blockDefinition in blockDefinitions: + blockName = blockDefinition['id'] + blockRegisters = blockDefinition['registers'] + blockStartAddress = 0 + registerCount = 0 + blockSize = 0 + registerType = "" + + for i, blockRegister in enumerate(blockRegisters): + if i == 0: + blockStartAddress = blockRegister['address'] + registerType = blockRegister['registerType'] + + registerCount += 1 + blockSize += blockRegister['size'] + + writeLine(fileDescriptor, 'void %s::update%sBlock()' % (className, blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor, '{') + writeLine(fileDescriptor, ' // Update register block \"%s\"' % blockName) + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read block \\"%s\\" registers from:" << %s << "size:" << %s;' % (className, blockName, blockStartAddress, blockSize)) + + + # Build request depending on the register type + if registerType == 'inputRegister': + writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + elif registerType == 'discreteInputs': + writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readDiscreteInput(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + elif registerType == 'coils': + writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readCoil(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + else: + #Default to holdingRegister + writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize)) + + writeLine(fileDescriptor, ' if (reply) {') + writeLine(fileDescriptor, ' if (!reply->isFinished()) {') + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){') + writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {') + writeLine(fileDescriptor, ' QVector blockValues = reply->result();') + writeLine(fileDescriptor, ' QVector values;') + writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize)) + + # Start parsing the registers using offsets + offset = 0 + for i, blockRegister in enumerate(blockRegisters): + propertyName = blockRegister['id'] + propertyTyp = getCppDataType(blockRegister) + writeLine(fileDescriptor, ' values = blockValues.mid(%s, %s);' % (offset, blockRegister['size'])) + writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(blockRegister))) + writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName)) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor) + offset += blockRegister['size'] + + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor) + writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName)) + writeLine(fileDescriptor, ' emit reply->finished();') + writeLine(fileDescriptor, ' });') + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, ' } else {') + writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName)) + writeLine(fileDescriptor, ' }') + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + + + + +def writeInternalPropertyReadMethodDeclarationsTcp(fileDescriptor, registerDefinitions): for registerDefinition in registerDefinitions: propertyName = registerDefinition['id'] writeLine(fileDescriptor, ' QModbusReply *read%s();' % (propertyName[0].upper() + propertyName[1:])) -def writeInternalPropertyReadMethodImplementations(fileDescriptor, className, registerDefinitions): +def writeInternalPropertyReadMethodDeclarationsRtu(fileDescriptor, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + writeLine(fileDescriptor, ' ModbusRtuReply *read%s();' % (propertyName[0].upper() + propertyName[1:])) + + +def writeInternalPropertyReadMethodImplementationsTcp(fileDescriptor, className, registerDefinitions): for registerDefinition in registerDefinitions: propertyName = registerDefinition['id'] writeLine(fileDescriptor, 'QModbusReply *%s::read%s()' % (className, propertyName[0].upper() + propertyName[1:])) @@ -415,6 +638,28 @@ def writeInternalPropertyReadMethodImplementations(fileDescriptor, className, re writeLine(fileDescriptor) +def writeInternalPropertyReadMethodImplementationsRtu(fileDescriptor, className, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + writeLine(fileDescriptor, 'ModbusRtuReply *%s::read%s()' % (className, propertyName[0].upper() + propertyName[1:])) + writeLine(fileDescriptor, '{') + + # Build request depending on the register type + if registerDefinition['registerType'] == 'inputRegister': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readInputRegister(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + elif registerDefinition['registerType'] == 'discreteInputs': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readDiscreteInput(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + elif registerDefinition['registerType'] == 'coils': + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readCoil(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + else: + #Default to holdingRegister + writeLine(fileDescriptor, ' return m_modbusRtuMaster->readHoldingRegister(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size'])) + + writeLine(fileDescriptor, '}') + writeLine(fileDescriptor) + + + def writePropertyChangedSignals(fileDescriptor, registerDefinitions): for registerDefinition in registerDefinitions: propertyName = registerDefinition['id'] @@ -447,6 +692,7 @@ def writeInitializeMethod(fileDescriptor, className, registerDefinitions): break if initRequired: + # FIXME: distinguish between RTU and TCP writeLine(fileDescriptor, ' QModbusReply *reply = nullptr;') writeLine(fileDescriptor) writeLine(fileDescriptor, ' if (!m_pendingInitReplies.isEmpty()) {') @@ -508,10 +754,332 @@ def writeUpdateMethod(fileDescriptor, className, registerDefinitions): if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'update': writeLine(fileDescriptor, ' update%s();' % (propertyName[0].upper() + propertyName[1:])) + # Add the update block methods + if 'blocks' in registerJson: + for blockDefinition in registerJson['blocks']: + blockName = blockDefinition['id'] + writeLine(fileDescriptor, ' update%sBlock();' % (blockName[0].upper() + blockName[1:])) + writeLine(fileDescriptor, '}') writeLine(fileDescriptor) +def writeRegistersDebugLine(fileDescriptor, debugObjectParamName, registerDefinitions): + for registerDefinition in registerDefinitions: + propertyName = registerDefinition['id'] + propertyTyp = getCppDataType(registerDefinition) + line = ('" - %s:" << %s->%s()' % (registerDefinition['description'], debugObjectParamName, propertyName)) + if 'unit' in registerDefinition and registerDefinition['unit'] != '': + line += (' << " [%s]"' % registerDefinition['unit']) + writeLine(fileDescriptor, ' debug.nospace().noquote() << %s << "\\n";' % (line)) + + +def writeTcpHeaderFile(): + print('Writing modbus TCP hader file %s' % headerFilePath) + headerFile = open(headerFilePath, 'w') + + writeLicenseHeader(headerFile) + writeLine(headerFile, '#ifndef %s_H' % className.upper()) + writeLine(headerFile, '#define %s_H' % className.upper()) + writeLine(headerFile) + writeLine(headerFile, '#include ') + writeLine(headerFile) + writeLine(headerFile, '#include "../modbus/modbusdatautils.h"') + writeLine(headerFile, '#include "../modbus/modbustcpmaster.h"') + + writeLine(headerFile) + + # Begin of class + writeLine(headerFile, 'class %s : public ModbusTCPMaster' % className) + writeLine(headerFile, '{') + writeLine(headerFile, ' Q_OBJECT') + + # Public members + writeLine(headerFile, 'public:') + + # Enum declarations + if 'enums' in registerJson: + for enumDefinition in registerJson['enums']: + writeEnumDefinition(headerFile, enumDefinition) + + # Constructor + writeLine(headerFile, ' explicit %s(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr);' % className) + writeLine(headerFile, ' ~%s() = default;' % className) + writeLine(headerFile) + + # Write registers get method declarations + writePropertyGetSetMethodDeclarations(headerFile, registerJson['registers']) + + # Write block get/set method declarations + writeBlocksUpdateMethodDeclarations(headerFile, registerJson['blocks']) + + # Write init and update method declarations + writeLine(headerFile, ' virtual void initialize();') + writeLine(headerFile, ' virtual void update();') + writeLine(headerFile) + + writePropertyUpdateMethodDeclarations(headerFile, registerJson['registers']) + writeLine(headerFile) + + # Write registers value changed signals + writeLine(headerFile, 'signals:') + writeLine(headerFile, ' void initializationFinished();') + writeLine(headerFile) + writePropertyChangedSignals(headerFile, registerJson['registers']) + for blockDefinition in registerJson['blocks']: + writePropertyChangedSignals(headerFile, blockDefinition['registers']) + writeLine(headerFile) + + # Private members + writeLine(headerFile, 'private:') + writeLine(headerFile, ' quint16 m_slaveId = 1;') + writeLine(headerFile, ' QVector m_pendingInitReplies;') + writeLine(headerFile) + writePrivatePropertyMembers(headerFile, registerJson['registers']) + for blockDefinition in registerJson['blocks']: + writePrivatePropertyMembers(headerFile, blockDefinition['registers']) + writeLine(headerFile) + writeLine(headerFile, ' void verifyInitFinished();') + writeLine(headerFile) + writeInternalPropertyReadMethodDeclarationsTcp(headerFile, registerJson['registers']) + writeLine(headerFile) + + # End of class + writeLine(headerFile) + writeLine(headerFile, '};') + writeLine(headerFile) + writeLine(headerFile, 'QDebug operator<<(QDebug debug, %s *%s);' % (className, className[0].lower() + className[1:])) + writeLine(headerFile) + writeLine(headerFile, '#endif // %s_H' % className.upper()) + + headerFile.close() + + +def writeTcpSourceFile(): + print('Writing modbus TCP source file %s' % sourceFilePath) + sourceFile = open(sourceFilePath, 'w') + writeLicenseHeader(sourceFile) + writeLine(sourceFile) + writeLine(sourceFile, '#include "%s"' % headerFileName) + writeLine(sourceFile, '#include "loggingcategories.h"') + writeLine(sourceFile) + writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className)) + writeLine(sourceFile) + + # Constructor + writeLine(sourceFile, '%s::%s(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) :' % (className, className)) + writeLine(sourceFile, ' ModbusTCPMaster(hostAddress, port, parent),') + writeLine(sourceFile, ' m_slaveId(slaveId)') + writeLine(sourceFile, '{') + writeLine(sourceFile, ' ') + writeLine(sourceFile, '}') + writeLine(sourceFile) + + # Property get methods + writePropertyGetSetMethodImplementationsTcp(sourceFile, className, registerJson['registers']) + + # Write init and update method implementation + writeInitializeMethod(sourceFile, className, registerJson['registers']) + writeUpdateMethod(sourceFile, className, registerJson['registers']) + + # Write update methods + writePropertyUpdateMethodImplementationsTcp(sourceFile, className, registerJson['registers']) + + # Write property read method implementations + writeInternalPropertyReadMethodImplementationsTcp(sourceFile, className, registerJson['registers']) + + writeLine(sourceFile, 'void %s::verifyInitFinished()' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' if (m_pendingInitReplies.isEmpty()) {') + writeLine(sourceFile, ' qCDebug(dc%s()) << "Initialization finished of %s" << hostAddress().toString();' % (className, className)) + writeLine(sourceFile, ' emit initializationFinished();') + writeLine(sourceFile, ' }') + writeLine(sourceFile, '}') + writeLine(sourceFile) + + # Write the debug print + debugObjectParamName = className[0].lower() + className[1:] + writeLine(sourceFile, 'QDebug operator<<(QDebug debug, %s *%s)' % (className, debugObjectParamName)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' debug.nospace().noquote() << "%s(" << %s->hostAddress().toString() << ":" << %s->port() << ")" << "\\n";' % (className, debugObjectParamName, debugObjectParamName)) + writeRegistersDebugLine(sourceFile, debugObjectParamName, registerJson['registers']) + + for blockDefinition in registerJson['blocks']: + writeRegistersDebugLine(sourceFile, debugObjectParamName, blockDefinition['registers']) + + writeLine(sourceFile, ' return debug.quote().space();') + writeLine(sourceFile, '}') + writeLine(sourceFile) + + sourceFile.close() + + +########################################################################################################## +def writeRtuHeaderFile(): + print('Writing modbus TCP hader file %s' % headerFilePath) + headerFile = open(headerFilePath, 'w') + + writeLicenseHeader(headerFile) + writeLine(headerFile, '#ifndef %s_H' % className.upper()) + writeLine(headerFile, '#define %s_H' % className.upper()) + writeLine(headerFile) + writeLine(headerFile, '#include ') + writeLine(headerFile) + writeLine(headerFile, '#include "../modbus/modbusdatautils.h"') + writeLine(headerFile, '#include ') + + writeLine(headerFile) + + # Begin of class + writeLine(headerFile, 'class %s : public QObject' % className) + writeLine(headerFile, '{') + writeLine(headerFile, ' Q_OBJECT') + + # Public members + writeLine(headerFile, 'public:') + + # Enum declarations + if 'enums' in registerJson: + for enumDefinition in registerJson['enums']: + writeEnumDefinition(headerFile, enumDefinition) + + # Constructor + writeLine(headerFile, ' explicit %s(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr);' % className) + writeLine(headerFile, ' ~%s() = default;' % className) + writeLine(headerFile) + + writeLine(headerFile, ' ModbusRtuMaster *modbusRtuMaster() const;') + writeLine(headerFile, ' quint16 slaveId() const;') + writeLine(headerFile) + + # Write registers get/set method declarations + writePropertyGetSetMethodDeclarations(headerFile, registerJson['registers']) + + # Write block get/set method declarations + writeBlocksUpdateMethodDeclarations(headerFile, registerJson['blocks']) + + writePropertyUpdateMethodDeclarations(headerFile, registerJson['registers']) + writeLine(headerFile) + + # Write init and update method declarations + writeLine(headerFile, ' virtual void initialize();') + writeLine(headerFile, ' virtual void update();') + writeLine(headerFile) + + # Write registers value changed signals + writeLine(headerFile, 'signals:') + writeLine(headerFile, ' void initializationFinished();') + writeLine(headerFile) + writePropertyChangedSignals(headerFile, registerJson['registers']) + for blockDefinition in registerJson['blocks']: + writePropertyChangedSignals(headerFile, blockDefinition['registers']) + writeLine(headerFile) + + # Private members + writeLine(headerFile, 'private:') + writeLine(headerFile, ' ModbusRtuMaster *m_modbusRtuMaster = nullptr;') + writeLine(headerFile, ' quint16 m_slaveId = 1;') + writeLine(headerFile, ' QVector m_pendingInitReplies;') + writeLine(headerFile) + writePrivatePropertyMembers(headerFile, registerJson['registers']) + for blockDefinition in registerJson['blocks']: + writePrivatePropertyMembers(headerFile, blockDefinition['registers']) + + writeLine(headerFile) + writeLine(headerFile, ' void verifyInitFinished();') + writeLine(headerFile) + writeInternalPropertyReadMethodDeclarationsRtu(headerFile, registerJson['registers']) + writeLine(headerFile) + + # End of class + writeLine(headerFile) + writeLine(headerFile, '};') + writeLine(headerFile) + writeLine(headerFile, 'QDebug operator<<(QDebug debug, %s *%s);' % (className, className[0].lower() + className[1:])) + writeLine(headerFile) + writeLine(headerFile, '#endif // %s_H' % className.upper()) + + headerFile.close() + + +def writeRtuSourceFile(): + print('Writing modbus RTU source file %s' % sourceFilePath) + sourceFile = open(sourceFilePath, 'w') + writeLicenseHeader(sourceFile) + + writeLine(sourceFile, '#include "%s"' % headerFileName) + writeLine(sourceFile, '#include "loggingcategories.h"') + writeLine(sourceFile) + writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className)) + writeLine(sourceFile) + + # Constructor + writeLine(sourceFile, '%s::%s(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent) :' % (className, className)) + writeLine(sourceFile, ' QObject(parent),') + writeLine(sourceFile, ' m_modbusRtuMaster(modbusRtuMaster),') + writeLine(sourceFile, ' m_slaveId(slaveId)') + writeLine(sourceFile, '{') + writeLine(sourceFile, ' ') + writeLine(sourceFile, '}') + writeLine(sourceFile) + + writeLine(sourceFile, 'ModbusRtuMaster *%s::modbusRtuMaster() const' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' return m_modbusRtuMaster;') + writeLine(sourceFile, '}') + + writeLine(sourceFile, 'quint16 %s::slaveId() const' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' return m_slaveId;') + writeLine(sourceFile, '}') + + + # Property get methods + writePropertyGetSetMethodImplementationsRtu(sourceFile, className, registerJson['registers']) + + # Block property get methods + for blockDefinition in registerJson['blocks']: + writePropertyGetSetMethodImplementationsRtu(sourceFile, className, blockDefinition['registers']) + + # Write init and update method implementation + writeInitializeMethod(sourceFile, className, registerJson['registers']) + writeUpdateMethod(sourceFile, className, registerJson['registers']) + + # Write update methods + writePropertyUpdateMethodImplementationsRtu(sourceFile, className, registerJson['registers']) + + # Write block update method + writeBlockUpdateMethodImplementationsRtu(sourceFile, className, registerJson['blocks']) + + # Write property read method implementations + writeInternalPropertyReadMethodImplementationsRtu(sourceFile, className, registerJson['registers']) + + writeLine(sourceFile, 'void %s::verifyInitFinished()' % (className)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' if (m_pendingInitReplies.isEmpty()) {') + writeLine(sourceFile, ' qCDebug(dc%s()) << "Initialization finished of %s";' % (className, className)) + writeLine(sourceFile, ' emit initializationFinished();') + writeLine(sourceFile, ' }') + writeLine(sourceFile, '}') + writeLine(sourceFile) + + # Write the debug print + debugObjectParamName = className[0].lower() + className[1:] + writeLine(sourceFile, 'QDebug operator<<(QDebug debug, %s *%s)' % (className, debugObjectParamName)) + writeLine(sourceFile, '{') + writeLine(sourceFile, ' debug.nospace().noquote() << "%s(" << %s->modbusRtuMaster()->modbusUuid().toString() << ", " << %s->modbusRtuMaster()->serialPort() << ", slave ID:" << %s->slaveId() << ")" << "\\n";' % (className, debugObjectParamName, debugObjectParamName, debugObjectParamName)) + writeRegistersDebugLine(sourceFile, debugObjectParamName, registerJson['registers']) + + for blockDefinition in registerJson['blocks']: + writeRegistersDebugLine(sourceFile, debugObjectParamName, blockDefinition['registers']) + + writeLine(sourceFile, ' return debug.quote().space();') + writeLine(sourceFile, '}') + writeLine(sourceFile) + + sourceFile.close() + + ############################################################################################ # Main ############################################################################################ @@ -545,142 +1113,18 @@ endianness = 'BigEndian' if 'endianness' in registerJson: endianness = registerJson['endianness'] +protocol = 'TCP' +if 'protocol' in registerJson: + protocol = registerJson['protocol'] -############################################################################# -# Write header file -############################################################################# +validateBlocks(registerJson['blocks']) -headerFile = open(headerFilePath, 'w') - -writeLicenseHeader(headerFile) -writeLine(headerFile, '#ifndef %s_H' % className.upper()) -writeLine(headerFile, '#define %s_H' % className.upper()) -writeLine(headerFile) -writeLine(headerFile, '#include ') -writeLine(headerFile) -writeLine(headerFile, '#include "../modbus/modbusdatautils.h"') -writeLine(headerFile, '#include "../modbus/modbustcpmaster.h"') - -writeLine(headerFile) - -# Begin of class -writeLine(headerFile, 'class %s : public ModbusTCPMaster' % className) -writeLine(headerFile, '{') -writeLine(headerFile, ' Q_OBJECT') - -# Public members -writeLine(headerFile, 'public:') - -# Enum declarations -for enumDefinition in registerJson['enums']: - writeEnumDefinition(headerFile, enumDefinition) - -# Constructor -writeLine(headerFile, ' explicit %s(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr);' % className) -writeLine(headerFile, ' ~%s() = default;' % className) -writeLine(headerFile) - -# Write registers get method declarations -writePropertyGetSetMethodDeclarations(headerFile, registerJson['registers']) - -# Write init and update method declarations -writeLine(headerFile, ' virtual void initialize();') -writeLine(headerFile, ' virtual void update();') -writeLine(headerFile) - -writePropertyUpdateMethodDeclarations(headerFile, registerJson['registers']) -writeLine(headerFile) - -# Write registers value changed signals -writeLine(headerFile, 'signals:') -writeLine(headerFile, ' void initializationFinished();') -writeLine(headerFile) -writePropertyChangedSignals(headerFile, registerJson['registers']) -writeLine(headerFile) - -# Private members -writeLine(headerFile, 'private:') -writeLine(headerFile, ' quint16 m_slaveId = 1;') -writeLine(headerFile, ' QVector m_pendingInitReplies;') -writeLine(headerFile) -writePrivatePropertyMembers(headerFile, registerJson['registers']) -writeLine(headerFile) -writeLine(headerFile, ' void verifyInitFinished();') -writeLine(headerFile) -writeInternalPropertyReadMethodDeclarations(headerFile, registerJson['registers']) -writeLine(headerFile) - -# End of class -writeLine(headerFile) -writeLine(headerFile, '};') -writeLine(headerFile) -writeLine(headerFile, 'QDebug operator<<(QDebug debug, %s *%s);' % (className, className[0].lower() + className[1:])) -writeLine(headerFile) -writeLine(headerFile, '#endif // %s_H' % className.upper()) - -headerFile.close() +if protocol == 'TCP': + writeTcpHeaderFile() + writeTcpSourceFile() +else: + writeRtuHeaderFile() + writeRtuSourceFile() -############################################################################# -# Write source file -############################################################################# - -sourceFile = open(sourceFilePath, 'w') -writeLicenseHeader(sourceFile) -writeLine(sourceFile) -writeLine(sourceFile, '#include "%s"' % headerFileName) -writeLine(sourceFile, '#include "loggingcategories.h"') -writeLine(sourceFile) -writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className)) -writeLine(sourceFile) - -# Constructor -writeLine(sourceFile, '%s::%s(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) :' % (className, className)) -writeLine(sourceFile, ' ModbusTCPMaster(hostAddress, port, parent),') -writeLine(sourceFile, ' m_slaveId(slaveId)') -writeLine(sourceFile, '{') -writeLine(sourceFile, ' ') -writeLine(sourceFile, '}') -writeLine(sourceFile) - -# Property get methods -writePropertyGetSetMethodImplementations(sourceFile, className, registerJson['registers']) - -# Write init and update method implementation -writeInitializeMethod(sourceFile, className, registerJson['registers']) -writeUpdateMethod(sourceFile, className, registerJson['registers']) - -# Write update methods -writePropertyUpdateMethodImplementations(sourceFile, className, registerJson['registers']) - -# Write property read method implementations -writeInternalPropertyReadMethodImplementations(sourceFile, className, registerJson['registers']) - -writeLine(sourceFile, 'void %s::verifyInitFinished()' % (className)) -writeLine(sourceFile, '{') -writeLine(sourceFile, ' if (m_pendingInitReplies.isEmpty()) {') -writeLine(sourceFile, ' qCDebug(dc%s()) << "Initialization finished of %s" << hostAddress().toString();' % (className, className)) -writeLine(sourceFile, ' emit initializationFinished();') -writeLine(sourceFile, ' }') -writeLine(sourceFile, '}') -writeLine(sourceFile) - -# Write the debug print -debugObjectParamName = className[0].lower() + className[1:] -writeLine(sourceFile, 'QDebug operator<<(QDebug debug, %s *%s)' % (className, debugObjectParamName)) -writeLine(sourceFile, '{') -writeLine(sourceFile, ' debug.nospace().noquote() << "%s(" << %s->hostAddress().toString() << ":" << %s->port() << ")" << "\\n";' % (className, debugObjectParamName, debugObjectParamName)) -for registerDefinition in registerJson['registers']: - propertyName = registerDefinition['id'] - propertyTyp = getCppDataType(registerDefinition) - line = ('" - %s:" << %s->%s()' % (registerDefinition['description'], debugObjectParamName, propertyName)) - if 'unit' in registerDefinition and registerDefinition['unit'] != '': - line += (' << " [%s]"' % registerDefinition['unit']) - writeLine(sourceFile, ' debug.nospace().noquote() << %s << "\\n";' % (line)) - -writeLine(sourceFile, ' return debug.quote().space();') -writeLine(sourceFile, '}') -writeLine(sourceFile) - -sourceFile.close() \ No newline at end of file