added energy meters intergration plugin

This commit is contained in:
Boernsman 2021-04-20 20:39:58 +02:00 committed by Michael Zanetti
parent 0a7b983650
commit 9027579cda
14 changed files with 1084 additions and 0 deletions

17
debian/control vendored
View File

@ -45,6 +45,23 @@ Description: nymea.io plugin for iDM heat pumps
This package will install the nymea.io plugin for iDM heat pumps
Package: nymea-plugin-energymeters
Architecture: any
Multi-Arch: same
Section: libs
Depends: ${shlibs:Depends},
${misc:Depends},
nymea-plugins-modbus-translations
Description: nymea.io plugin for Modbus based energy meters
The nymea daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and
allows them to interact.
With the powerful rule engine you are able to connect any device available
in the system and create individual scenes and behaviors for your environment.
.
This package will install the nymea.io plugin for energy meters
Package: nymea-plugin-modbuscommander
Architecture: any
Section: libs

View File

@ -0,0 +1 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginenergymeters.so

9
energymeters/README.md Normal file
View File

@ -0,0 +1,9 @@
# B+G e-tech
## Supported Things
## Requirements
## More

View File

@ -0,0 +1,59 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef BGETECHMODBUSREGISTER_H
#define BGETECHMODBUSREGISTER_H
#include "registerdescriptor.h"
class BgEtechModbusRegisers
{
private:
BgEtechModbusRegisers() {}
static void init () {
m_registerMap.insert(ModbusRegisterType::Voltage, ModbusRegisterDescriptor(1, 3, 2, "V", "float"));
/* m_registerMap.insert(ModbusRegisterType::Current, ModbusRegisterDescriptor(1, 3, 2, "V", "float"));
m_registerMap.insert(ModbusRegisterType::ActivePower, ModbusRegisterDescriptor(1, 3, 2, "V", "float"));
m_registerMap.insert(ModbusRegisterType::Frequency, ModbusRegisterDescriptor(1, 3, 2, "V", "float"));
m_registerMap.insert(ModbusRegisterType::PowerFactor, ModbusRegisterDescriptor(1, 3, 2, "V", "float"));
m_registerMap.insert(ModbusRegisterType::EnergyConsumed, ModbusRegisterDescriptor(1, 3, 2, "V", "float"));
m_registerMap.insert(ModbusRegisterType::EnergyProduced, ModbusRegisterDescriptor(1, 3, 2, "V", "float"));*/
}
protected:
static QHash<ModbusRegisterType, ModbusRegisterDescriptor> m_registerMap;
public:
static QHash<ModbusRegisterType, ModbusRegisterDescriptor> map()
{ BgEtechModbusRegisers();
init();
return m_registerMap;}
};
#endif // BGETECHMODBUSREGISTER_H

View File

@ -0,0 +1,148 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "energymeter.h"
#include "hardware/modbus/modbusrtureply.h"
EnergyMeter::EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const QHash<ModbusRegisterType, ModbusRegisterDescriptor> &modbusRegisters, QObject *parent) :
QObject(parent),
m_modbusRtuMaster(modbusMaster),
m_slaveAddress(slaveAddress),
m_modbusRegisters(modbusRegisters)
{
}
bool EnergyMeter::init()
{
return true;
}
bool EnergyMeter::connected()
{
return m_connected;
}
bool EnergyMeter::getVoltage()
{
if (!m_modbusRegisters.contains(ModbusRegisterType::Voltage))
return false;
ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::Voltage);
getRegister(ModbusRegisterType::Voltage, descriptor);
return true;
}
bool EnergyMeter::getCurrent()
{
if (!m_modbusRegisters.contains(ModbusRegisterType::Current))
return false;
ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::Current);
getRegister(ModbusRegisterType::Current, descriptor);
return true;
}
bool EnergyMeter::getFrequency()
{
if (!m_modbusRegisters.contains(ModbusRegisterType::Frequency))
return false;
ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::Frequency);
getRegister(ModbusRegisterType::Frequency, descriptor);
return true;
}
bool EnergyMeter::getPowerFactor()
{
if (!m_modbusRegisters.contains(ModbusRegisterType::PowerFactor))
return false;
ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::PowerFactor);
getRegister(ModbusRegisterType::PowerFactor, descriptor);
return true;
}
bool EnergyMeter::getActivePower()
{
if (!m_modbusRegisters.contains(ModbusRegisterType::ActivePower))
return false;
ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::ActivePower);
getRegister(ModbusRegisterType::ActivePower, descriptor);
return true;
}
bool EnergyMeter::getEnergyProduced()
{
if (!m_modbusRegisters.contains(ModbusRegisterType::EnergyProduced))
return false;
ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::EnergyProduced);
getRegister(ModbusRegisterType::EnergyProduced, descriptor);
return true;
}
bool EnergyMeter::getEnergyConsumed()
{
if (!m_modbusRegisters.contains(ModbusRegisterType::EnergyConsumed))
return false;
ModbusRegisterDescriptor descriptor = m_modbusRegisters.value(ModbusRegisterType::EnergyConsumed);
getRegister(ModbusRegisterType::EnergyConsumed, descriptor);
return true;
}
void EnergyMeter::getRegister(ModbusRegisterType type, ModbusRegisterDescriptor descriptor)
{
ModbusRtuReply *reply;
if (descriptor.functionCode() == 1){
} else if (descriptor.functionCode() == 2){
} else if (descriptor.functionCode() == 3){
reply = m_modbusRtuMaster->readHoldingRegister(m_slaveAddress, descriptor.address(), descriptor.length());
} else if (descriptor.functionCode() == 4){
}
connect(reply, &ModbusRtuReply::finished, reply, &ModbusRtuReply::deleteLater);
connect(reply, &ModbusRtuReply::finished, this, [reply, type, this] {
if (reply->error() != ModbusRtuReply::NoError) {
return;
}
double value = 0;
if (reply->result().length() == 2) {
value = static_cast<float>(reply->result().at(0) << 16 | reply->result().at(1));
}
emit valueReceived(type, value);
});
}

View File

@ -0,0 +1,81 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef ENERGYMETER_H
#define ENERGYMETER_H
#include <QObject>
#include "registerdescriptor.h"
#include "hardware/modbus/modbusrtumaster.h"
class EnergyMeter : public QObject
{
Q_OBJECT
public:
explicit EnergyMeter(ModbusRtuMaster *modbusMaster, int slaveAddress, const QHash<ModbusRegisterType, ModbusRegisterDescriptor> &modbusRegisters, QObject *parent = nullptr);
bool init();
bool connected();
bool getVoltage();
bool getCurrent();
bool getFrequency();
bool getPowerFactor();
bool getActivePower();
bool getEnergyProduced();
bool getEnergyConsumed();
private:
bool m_connected = false;
ModbusRtuMaster *m_modbusRtuMaster = nullptr;
int m_slaveAddress;
QHash<ModbusRegisterType, ModbusRegisterDescriptor> m_modbusRegisters;
void getRegister(ModbusRegisterType type, ModbusRegisterDescriptor descriptor);
signals:
void connectedChanged(bool connected);
void valueReceived(ModbusRegisterType type, double value);
void voltageReceived(double voltage);
void currentReceived(double current);
void frequencyReceived(double freqeuncy);
void activePowerReceived(double power);
void powerFactorReceived(double powerFactor);
void producedEnergyReceived(double energy);
void consumedEnergyReceived(double energy);
//private slot:
// void onRegisterReceived();
};
#endif // ENERGYMETER_H

View File

@ -0,0 +1,16 @@
include(../plugins.pri)
QT += \
serialport \
serialbus \
SOURCES += \
energymeter.cpp \
integrationpluginenergymeters.cpp
HEADERS += \
energymeter.h \
integrationpluginenergymeters.h \
inepromodbusregister.h \
bg-etechmodbusregister.h \
registerdescriptor.h

View File

@ -0,0 +1,45 @@
#ifndef INEPROMODBUSREGISTER_H
#define INEPROMODBUSREGISTER_H
enum InputRegisters {
Phase1ToNeutralVolts = 1,
Phase2ToNeutralVolts = 3,
Phase3ToNeutralVolts = 5,
Phase1Current = 7,
Phase2Current = 9,
Phase3Current = 11,
Phase1Power = 13,
Phase2Power = 15,
Phase3Power = 17,
Phase1ApparentPower = 19,
Phase2ApparentPower = 21,
Phase3ApparentPower = 23,
Phase1ReactivePower = 25,
Phase2ReactivePower = 27,
Phase3ReactivePower = 29,
Phase1PowerFactor = 31,
Phase2PowerFactor = 33,
Phase3PowerFactor = 35,
Phase1Angle = 37,
Phase2Angle = 39,
Phase3Angle = 41,
Frequency = 71,
ImportActiveEnergy = 73,
ExportActiveEnergy = 75,
ImportReactiveEnergy = 77,
ExportReactiveEnergy = 79,
TotalActiveEnergy = 343,
TotalReactiveEnergy = 345
};
enum HoldingRegisters {
RelayPulseWidth = 13,
NetworkParityStop = 19,
NetworkPortNode = 21,
NetworkBaudRate = 29,
Pulse1Output = 87,
Pulse1Constant = 63761,
MeasurementMode = 63776
};
#endif // BGETECHMODBUSREGISTER_H

View File

@ -0,0 +1,291 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "integrationpluginenergymeters.h"
#include "plugininfo.h"
#include "bg-etechmodbusregister.h"
IntegrationPluginEnergyMeters::IntegrationPluginEnergyMeters()
{
/*
* NOTE:
* To add an new device model, the integrationplugin json file must be extended with the new model and vendor.
* Then add the new states and params to the lists here, also add the modbus register configuration file
*/
m_slaveIdParamTypeIds.insert(pro380ThingClassId, pro380ThingSlaveAddressParamTypeId);
m_slaveIdParamTypeIds.insert(sdm630ThingClassId, sdm630ThingSlaveAddressParamTypeId);
m_modbusUuidParamTypeIds.insert(pro380ThingClassId, pro380ThingModbusMasterUuidParamTypeId);
m_modbusUuidParamTypeIds.insert(sdm630ThingClassId, sdm630ThingModbusMasterUuidParamTypeId);
m_connectionStateTypeIds.insert(pro380ThingClassId, pro380ConnectedStateTypeId);
m_connectionStateTypeIds.insert(sdm630ThingClassId, sdm630ConnectedStateTypeId);
m_voltageStateTypeIds.insert(pro380ThingClassId, pro380VoltageStateTypeId);
m_voltageStateTypeIds.insert(sdm630ThingClassId, sdm630VoltageStateTypeId);
m_currentStateTypeIds.insert(pro380ThingClassId, pro380CurrentStateTypeId);
m_currentStateTypeIds.insert(sdm630ThingClassId, sdm630CurrentStateTypeId);
m_activePowerStateTypeIds.insert(pro380ThingClassId, pro380CurrentPowerEventTypeId);
m_activePowerStateTypeIds.insert(sdm630ThingClassId, sdm630CurrentPowerStateTypeId);
m_frequencyStateTypeIds.insert(pro380ThingClassId, pro380FrequencyStateTypeId);
m_frequencyStateTypeIds.insert(sdm630ThingClassId, sdm630FrequencyStateTypeId);
m_powerFactorStateTypeIds.insert(pro380ThingClassId, pro380PowerFactorStateTypeId);
m_powerFactorStateTypeIds.insert(sdm630ThingClassId, sdm630PowerFactorStateTypeId);
m_discoverySlaveAddressParamTypeIds.insert(pro380ThingClassId, pro380DiscoverySlaveAddressParamTypeId);
m_discoverySlaveAddressParamTypeIds.insert(sdm630ThingClassId, sdm630DiscoverySlaveAddressParamTypeId);
// Modbus RTU hardware resource
connect(hardwareManager()->modbusRtuResource(), &ModbusRtuHardwareResource::modbusRtuMasterRemoved, this, [=](const QUuid &modbusUuid){
qCDebug(dcEnergyMeters()) << "Modbus RTU master has been removed" << modbusUuid.toString();
// Check if there is any device using this resource
foreach (Thing *thing, m_modbusRtuMasters.keys()) {
if (m_modbusRtuMasters.value(thing)->modbusUuid() == modbusUuid) {
qCWarning(dcEnergyMeters()) << "Hardware resource removed for" << thing << ". The thing will not be functional any more until a new resource has been configured for it.";
m_modbusRtuMasters.remove(thing);
thing->setStateValue(m_connectionStateTypeIds[thing->thingClassId()], false);
// Set all child things disconnected
foreach (Thing *childThing, myThings()) {
if (childThing->parentId() == thing->id()) {
thing->setStateValue(m_connectionStateTypeIds[childThing->thingClassId()], false);
}
}
}
}
});
}
void IntegrationPluginEnergyMeters::discoverThings(ThingDiscoveryInfo *info)
{
qCDebug(dcEnergyMeters()) << "Discover things";
QList<ThingDescriptor> thingDescriptors;
if (hardwareManager()->modbusRtuResource()->modbusRtuMasters().isEmpty()) {
info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("No Modbus RTU interface available."));
return;
}
if (m_connectionStateTypeIds.contains(info->thingClassId())) {
int slaveAddress = info->params().paramValue(m_discoverySlaveAddressParamTypeIds.value(info->thingClassId())).toInt();
if (slaveAddress > 254 || slaveAddress == 0) {
info->finish(Thing::ThingErrorInvalidParameter, tr("Modbus slave address must be between 1 and 254"));
return;
}
Q_FOREACH(ModbusRtuMaster *modbusMaster, hardwareManager()->modbusRtuResource()->modbusRtuMasters()) {
qCDebug(dcEnergyMeters()) << "Found RTU master resource" << modbusMaster << "connected" << modbusMaster->connected();
if (!modbusMaster->connected()) {
continue;
}
ThingDescriptor descriptor(info->thingClassId(), "Modbus interface "+modbusMaster->serialPort(), modbusMaster->modbusUuid().toString());
ParamList params;
params << Param(m_slaveIdParamTypeIds.value(info->thingClassId()), slaveAddress);
params << Param(m_modbusUuidParamTypeIds.value(info->thingClassId()), modbusMaster->modbusUuid());
descriptor.setParams(params);
info->addThingDescriptor(descriptor);
}
info->finish(Thing::ThingErrorNoError);
return;
} else {
Q_ASSERT_X(false, "discoverThings", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8());
}
}
void IntegrationPluginEnergyMeters::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
qCDebug(dcEnergyMeters()) << "Setup thing" << thing->name();
if (m_connectionStateTypeIds.contains(thing->thingClassId())) {
if (m_energyMeters.contains(thing)) {
qCDebug(dcEnergyMeters()) << "Setup after rediscovery, cleaning up ...";
m_energyMeters.take(thing)->deleteLater();
}
int address = thing->paramValue(m_slaveIdParamTypeIds.value(thing->thingClassId())).toInt();
if (address > 254 || address == 0) {
qCWarning(dcEnergyMeters()) << "Setup failed, slave address is not valid" << address;
info->finish(Thing::ThingErrorSetupFailed, tr("Slave address not valid, must be between 1 and 254"));
return;
}
QUuid uuid = thing->paramValue(m_modbusUuidParamTypeIds.value(thing->thingClassId())).toString();
if (!hardwareManager()->modbusRtuResource()->hasModbusRtuMaster(uuid)) {
qCWarning(dcEnergyMeters()) << "Setup failed, hardware manager not available";
info->finish(Thing::ThingErrorSetupFailed, tr("Modbus RTU resource not available."));
return;
}
EnergyMeter *meter = new EnergyMeter(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), address, BgEtechModbusRegisers::map(), this);
connect(info, &ThingSetupInfo::aborted, meter, &EnergyMeter::deleteLater);
connect(meter, &EnergyMeter::consumedEnergyReceived, info, [this, info, meter] {
qCDebug(dcEnergyMeters()) << "Reply received, setup finished";
connect(meter, &EnergyMeter::connectedChanged, this, &IntegrationPluginEnergyMeters::onConnectionStateChanged);
connect(meter, &EnergyMeter::voltageReceived, this, &IntegrationPluginEnergyMeters::onVoltageReceived);
connect(meter, &EnergyMeter::currentReceived, this, &IntegrationPluginEnergyMeters::onCurrentReceived);
connect(meter, &EnergyMeter::activePowerReceived, this, &IntegrationPluginEnergyMeters::onActivePowerReceived);
connect(meter, &EnergyMeter::powerFactorReceived, this, &IntegrationPluginEnergyMeters::onPowerFactorReceived);
connect(meter, &EnergyMeter::frequencyReceived, this, &IntegrationPluginEnergyMeters::onActivePowerReceived);
connect(meter, &EnergyMeter::producedEnergyReceived, this, &IntegrationPluginEnergyMeters::onProducedEnergyReceived);
connect(meter, &EnergyMeter::consumedEnergyReceived, this, &IntegrationPluginEnergyMeters::onConsumedEnergyReceived);
m_energyMeters.insert(info->thing(), meter);
info->finish(Thing::ThingErrorNoError);
});
return;
} else {
Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
}
}
void IntegrationPluginEnergyMeters::postSetupThing(Thing *thing)
{
qCDebug(dcEnergyMeters) << "Post setup thing" << thing->name();
if (m_connectionStateTypeIds.contains(thing->thingClassId())) {
thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), true);
}
if (!m_updateTimer) {
qCDebug(dcEnergyMeters()) << "Creating update timer";
m_updateTimer = new QTimer(this);
m_updateTimer->start(configValue(energyMetersPluginUpdateIntervalParamTypeId).toInt());
connect(m_updateTimer, &QTimer::timeout, this, [this] {
foreach (EnergyMeter *meter, m_energyMeters) {
meter->getVoltage();
}
});
connect(this, &IntegrationPlugin::configValueChanged, [this] (const ParamTypeId &paramTypeId, const QVariant value) {
if (m_updateTimer && (paramTypeId == energyMetersPluginUpdateIntervalParamTypeId)) {
qCDebug(dcEnergyMeters()) << "Updating update interval to" << value;
m_updateTimer->setInterval(value.toInt());
}
});
}
}
void IntegrationPluginEnergyMeters::thingRemoved(Thing *thing)
{
qCDebug(dcEnergyMeters()) << "Thing removed" << thing->name();
if (m_energyMeters.contains(thing)) {
m_energyMeters.take(thing)->deleteLater();
}
if (myThings().isEmpty() && !m_updateTimer) {
qCDebug(dcEnergyMeters()) << "Deleting update timer";
m_updateTimer->deleteLater();
m_updateTimer = nullptr;
}
}
void IntegrationPluginEnergyMeters::onConnectionStateChanged(bool status)
{
EnergyMeter *meter = static_cast<EnergyMeter *>(sender());
Thing *thing = m_energyMeters.key(meter);
if (!thing)
return;
thing->setStateValue(m_connectionStateTypeIds.value(thing->thingClassId()), status);
}
void IntegrationPluginEnergyMeters::onVoltageReceived(double voltage)
{
EnergyMeter *meter = static_cast<EnergyMeter *>(sender());
Thing *thing = m_energyMeters.key(meter);
if (!thing)
return;
thing->setStateValue(m_voltageStateTypeIds.value(thing->thingClassId()), voltage);
}
void IntegrationPluginEnergyMeters::onCurrentReceived(double current)
{
EnergyMeter *meter = static_cast<EnergyMeter *>(sender());
Thing *thing = m_energyMeters.key(meter);
if (!thing)
return;
thing->setStateValue(m_currentStateTypeIds.value(thing->thingClassId()), current);
}
void IntegrationPluginEnergyMeters::onActivePowerReceived(double power)
{
EnergyMeter *meter = static_cast<EnergyMeter *>(sender());
Thing *thing = m_energyMeters.key(meter);
if (!thing)
return;
thing->setStateValue(m_activePowerStateTypeIds.value(thing->thingClassId()), power);
}
void IntegrationPluginEnergyMeters::onFrequencyReceived(double frequency)
{
EnergyMeter *meter = static_cast<EnergyMeter *>(sender());
Thing *thing = m_energyMeters.key(meter);
if (!thing)
return;
thing->setStateValue(m_frequencyStateTypeIds.value(thing->thingClassId()), frequency);
}
void IntegrationPluginEnergyMeters::onPowerFactorReceived(double powerFactor)
{
EnergyMeter *meter = static_cast<EnergyMeter *>(sender());
Thing *thing = m_energyMeters.key(meter);
if (!thing)
return;
thing->setStateValue(m_powerFactorStateTypeIds.value(thing->thingClassId()), powerFactor);
}
void IntegrationPluginEnergyMeters::onProducedEnergyReceived(double energy)
{
EnergyMeter *meter = static_cast<EnergyMeter *>(sender());
Thing *thing = m_energyMeters.key(meter);
if (!thing)
return;
thing->setStateValue(m_totalEnergyProducedStateTypeIds.value(thing->thingClassId()), energy);
}
void IntegrationPluginEnergyMeters::onConsumedEnergyReceived(double energy)
{
EnergyMeter *meter = static_cast<EnergyMeter *>(sender());
Thing *thing = m_energyMeters.key(meter);
if (!thing)
return;
thing->setStateValue(m_totalEnergyConsumedStateTypeIds.value(thing->thingClassId()), energy);
}

View File

@ -0,0 +1,89 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef INTEGRATIONPLUGINENERGYMETERS_H
#define INTEGRATIONPLUGINENERGYMETERS_H
#include "integrations/integrationplugin.h"
#include "hardware/modbus/modbusrtuhardwareresource.h"
#include "plugintimer.h"
#include "energymeter.h"
#include <QObject>
#include <QTimer>
class IntegrationPluginEnergyMeters : public IntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginenergymeters.json")
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginEnergyMeters();
void discoverThings(ThingDiscoveryInfo *info) override;
void setupThing(ThingSetupInfo *info) override;
void postSetupThing(Thing *thing) override;
void thingRemoved(Thing *thing) override;
private:
QTimer *m_updateTimer = nullptr;
QHash<ThingClassId, StateTypeId> m_connectionStateTypeIds;
QHash<ThingClassId, StateTypeId> m_voltageStateTypeIds;
QHash<ThingClassId, StateTypeId> m_currentStateTypeIds;
QHash<ThingClassId, StateTypeId> m_activePowerStateTypeIds;
QHash<ThingClassId, StateTypeId> m_frequencyStateTypeIds;
QHash<ThingClassId, StateTypeId> m_powerFactorStateTypeIds;
QHash<ThingClassId, StateTypeId> m_totalEnergyConsumedStateTypeIds;
QHash<ThingClassId, StateTypeId> m_totalEnergyProducedStateTypeIds;
QHash<ThingClassId, ParamTypeId> m_discoverySlaveAddressParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_slaveIdParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_modbusUuidParamTypeIds;
QHash<Thing *, EnergyMeter *> m_energyMeters;
QHash<Thing *, ModbusRtuMaster *> m_modbusRtuMasters;
PluginTimer *m_pluginTimer = nullptr;
QHash<QUuid, ThingActionInfo *> m_asyncActions;
private slots:
void onConnectionStateChanged(bool status);
void onVoltageReceived(double voltage);
void onCurrentReceived(double current);
void onActivePowerReceived(double power);
void onFrequencyReceived(double frequency);
void onPowerFactorReceived(double powerFactor);
void onProducedEnergyReceived(double energy);
void onConsumedEnergyReceived(double energy);
};
#endif // INTEGRATIONPLUGINENERGYMETERS_H

View File

@ -0,0 +1,244 @@
{
"name": "EnergyMeters",
"displayName": "EnergyMeters",
"id": "56e95111-fb6b-4f63-9a0a-a5ee001e89ed",
"paramTypes":[
{
"id": "eaa84c3c-06b8-4642-a40b-c2efbe6aae66",
"name": "updateInterval",
"displayName": "Update interval",
"type": "uint",
"unit": "MilliSeconds",
"defaultValue": 300,
"minValue": 200
}
],
"vendors": [
{
"name": "ineproMetering",
"displayName": "inepro Metering",
"id": "64f4df0f-18ce-409c-bf32-84a086c691ca",
"thingClasses": [
{
"name": "pro380",
"displayName": "PRO380-Mod",
"id": "d7c6440b-54f9-4cc0-a96b-9bb7304b3e77",
"createMethods": ["discovery"],
"interfaces": ["extendedsmartmeterconsumer"],
"discoveryParamTypes": [
{
"id": "a29f37f6-b344-4628-8ab4-8f4c18fada4a",
"name": "slaveAddress",
"displayName": "Slave address",
"type": "int",
"defaultValue": 1
}
],
"paramTypes": [
{
"id": "c75b2c31-6ec3-49ab-8c8f-5231d0a7e941",
"name": "slaveAddress",
"displayName": "Modbus slave address",
"type": "int",
"defaultValue": 1
},
{
"id": "6cdbec8c-21b9-42dc-b1ab-8901ac609482",
"name": "modbusMasterUuid",
"displayName": "Modbus RTU master",
"type": "QUuid",
"defaultValue": "",
"readOnly": true
}
],
"stateTypes": [
{
"id": "7f9bc504-0882-4b86-83b1-42fa345acfd9",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"cached": false,
"defaultValue": false
},
{
"id": "04dba21a-7447-46b9-b9ae-095e5769e511",
"name": "voltage",
"displayName": "Voltage",
"displayNameEvent": "Voltage changed",
"type": "double",
"unit": "Volt",
"defaultValue": 0
},
{
"id": "1e077a3b-2dab-4ec4-ae96-ab49a564fe31",
"name": "current",
"displayName": "Current",
"displayNameEvent": "Current changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0
},
{
"id": "464eff60-11c2-46b7-98f5-1aa8172e5a2d",
"name": "currentPower",
"displayName": "Active power",
"displayNameEvent": "Active power changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0
},
{
"id": "cdb34487-3d9b-492a-8c33-802f32a2e90e",
"name": "powerFactor",
"displayName": "Power factor",
"displayNameEvent": "Power factor changed",
"type": "double",
"defaultValue": 0.00
},
{
"id": "bb6fd00c-3bbb-4977-bb8a-96787bb6f5c5",
"name": "frequency",
"displayName": "Frequency",
"displayNameEvent": "Frequency changed",
"type": "double",
"unit": "Hertz",
"defaultValue": 0.00
},
{
"id": "f18fd596-b47f-44be-a0f0-6ca44369ebf5",
"name": "totalEnergyConsumed",
"displayName": "Total energy consumed",
"displayNameEvent": "Total energy consumed changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0.00
},
{
"id": "112911c9-14e0-4c83-ac92-f2ceb3bdecdf",
"name": "totalEnergyProduced",
"displayName": "Total energy produced",
"displayNameEvent": "Total energy produced changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0.00
}
]
}
]
},
{
"name": "bgetech",
"displayName": "B+G e-tech",
"id": "215035fe-95e8-43d8-a52e-0a31b787d902",
"thingClasses": [
{
"name": "sdm630",
"displayName": "SDM630Modbus",
"id": "f37597bb-35fe-48f2-9617-343dd54c0903",
"createMethods": ["discovery"],
"interfaces": ["extendedsmartmeterconsumer"],
"discoveryParamTypes": [
{
"id": "6ab43559-53ec-47ba-b8a0-8d3b7f8d90c2",
"name": "slaveAddress",
"displayName": "Slave address",
"type": "int",
"defaultValue": 1
}
],
"paramTypes": [
{
"id": "ac77ea98-b006-486e-a3e8-b30a483f26c1",
"name": "slaveAddress",
"displayName": "Modbus slave address",
"type": "int",
"defaultValue": 1
},
{
"id": "d90e9292-d03c-4f2a-957e-5d965018c9c9",
"name": "modbusMasterUuid",
"displayName": "Modbus RTU master",
"type": "QUuid",
"defaultValue": "",
"readOnly": true
}
],
"stateTypes": [
{
"id": "8050bd0b-1dad-4a7e-b632-c71ead3c9f8b",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"cached": false,
"defaultValue": false
},
{
"id": "4636ec5c-fcb9-45b7-ad68-2818cb615ce1",
"name": "voltage",
"displayName": "Voltage",
"displayNameEvent": "Voltage changed",
"type": "double",
"unit": "Volt",
"defaultValue": 0
},
{
"id": "96bc65ce-5bde-4a69-9ebf-711d65c6501c",
"name": "current",
"displayName": "Current",
"displayNameEvent": "Current changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0
},
{
"id": "c824e97b-a6d1-4030-9d7a-00af6fb8e1c3",
"name": "currentPower",
"displayName": "Active power",
"displayNameEvent": "Active power changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0
},
{
"id": "31b9032f-f994-472b-94bd-44f9fb094801",
"name": "powerFactor",
"displayName": "Power factor",
"displayNameEvent": "Power factor changed",
"type": "double",
"defaultValue": 0.00
},
{
"id": "ab24f26c-dc15-4ec3-8d76-06a48285440b",
"name": "frequency",
"displayName": "Frequency",
"displayNameEvent": "Frequency changed",
"type": "double",
"unit": "Hertz",
"defaultValue": 0.00
},
{
"id": "98d858a8-22e8-4262-b5c7-25bb027942ad",
"name": "totalEnergyConsumed",
"displayName": "Total energy consumed",
"displayNameEvent": "Total energy consumed changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0.00
},
{
"id": "e469b3ff-a4c2-42da-af35-ccafaef214af",
"name": "totalEnergyProduced",
"displayName": "Total energy produced",
"displayNameEvent": "Total energy produced changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0.00
}
]
}
]
}
]
}

0
energymeters/meta.json Normal file
View File

View File

@ -0,0 +1,83 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef REGISTERDESCRIPTOR_H
#define REGISTERDESCRIPTOR_H
#include <QObject>
#include <QHash>
enum ModbusRegisterType {
Voltage,
Current,
ActivePower,
Frequency,
PowerFactor,
EnergyProduced,
EnergyConsumed
};
class ModbusRegisterDescriptor
{
public:
ModbusRegisterDescriptor() {}
ModbusRegisterDescriptor(int address, int functionCode, int length, QString unit, QString dataType) :
m_address(address),
m_functionCode(functionCode),
m_length(length),
m_unit(unit),
m_dataType(dataType)
{}
int address() const
{ return m_address;}
int functionCode() const
{ return m_functionCode;}
int length() const
{ return m_length;}
QString unit() const
{ return m_unit;}
QString dataType() const
{ return m_dataType;}
private:
int m_address;
int m_functionCode;
int m_length;
QString m_unit;
QString m_dataType;
};
#endif // REGISTERDESCRIPTOR_H

View File

@ -2,6 +2,7 @@ TEMPLATE = subdirs
PLUGIN_DIRS = \
drexelundweiss \
energymeters \
modbuscommander \
mypv \
sunspec \