Add huawei basic structure

This commit is contained in:
Simon Stürz 2022-01-13 12:10:16 +01:00 committed by Michael Zanetti
parent 00915e3dc1
commit 89f152060f
10 changed files with 1507 additions and 1 deletions

View File

@ -0,0 +1,216 @@
{
"protocol": "TCP",
"endianness": "BigEndian",
"enums": [
{
"name": "InverterDeviceStatus",
"values": [
{
"key": "StandbyInitializing",
"value": 0
},
{
"key": "StandbyDetectingInsulationResistance",
"value": 1
},
{
"key": "StandbyDetectingIrradiation",
"value": 2
},
{
"key": "StandbyDridDetecting",
"value": 3
},
{
"key": "Starting",
"value": 256
},
{
"key": "OnGrid",
"value": 512
},
{
"key": "PowerLimited",
"value": 513
},
{
"key": "SelfDerating",
"value": 514
},
{
"key": "ShutdownFault",
"value": 768
},
{
"key": "ShutdownCommand",
"value": 769
},
{
"key": "ShutdownOVGR",
"value": 770
},
{
"key": "ShutdownCommunicationDisconnected",
"value": 771
},
{
"key": "ShutdownPowerLimit",
"value": 772
},
{
"key": "ShutdownManualStartupRequired",
"value": 773
},
{
"key": "ShutdownInputUnderpower",
"value": 774
},
{
"key": "GridSchedulingPCurve",
"value": 1025
},
{
"key": "GridSchedulingQUCurve",
"value": 1026
},
{
"key": "GridSchedulingPFUCurve",
"value": 1027
},
{
"key": "GridSchedulingDryContact",
"value": 1028
},
{
"key": "GridSchedulingQPCurve",
"value": 1029
},
{
"key": "SpotCheckReady",
"value": 1280
},
{
"key": "SpotChecking",
"value": 1281
},
{
"key": "Inspecting",
"value": 1536
},
{
"key": "AfciSelfCheck",
"value": 1792
},
{
"key": "IVScanning",
"value": 2048
},
{
"key": "DCInputDetection",
"value": 2304
},
{
"key": "RunningOffGridCharging",
"value": 2560
},
{
"key": "StandbyNoIrradiation",
"value": 40960
}
]
}
],
"blocks": [
],
"registers": [
{
"id": "inverterDCPower",
"address": 32064,
"size": 2,
"type": "int32",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Inverter DC power",
"unit": "kW",
"staticScaleFactor": -3,
"defaultValue": "0",
"access": "RO"
},
{
"id": "inverterActivePower",
"address": 32080,
"size": 2,
"type": "int32",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Inverter active power",
"unit": "kW",
"staticScaleFactor": -3,
"defaultValue": "0",
"access": "RO"
},
{
"id": "powerMeterActivePower",
"address": 37113,
"size": 2,
"type": "int32",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Power meter active power",
"unit": "W",
"defaultValue": "0",
"access": "RO"
},
{
"id": "lunaBattery1Power",
"address": 37001,
"size": 2,
"type": "int32",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Luna 2000 Battery 1 power",
"unit": "W",
"defaultValue": "0",
"access": "RO"
},
{
"id": "lunaBattery1Soc",
"address": 37004,
"size": 1,
"type": "uint16",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Luna 2000 Battery 1 state of charge",
"staticScaleFactor": -1,
"unit": "%",
"defaultValue": "0",
"access": "RO"
},
{
"id": "lunaBattery2Power",
"address": 37743,
"size": 2,
"type": "int32",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Luna 2000 Battery 2 power",
"unit": "W",
"defaultValue": "0",
"access": "RO"
},
{
"id": "lunaBattery2Soc",
"address": 37738,
"size": 1,
"type": "uint16",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Luna 2000 Battery 2 state of charge",
"staticScaleFactor": -1,
"unit": "%",
"defaultValue": "0",
"access": "RO"
}
]
}

17
huawei/huawei.pro Normal file
View File

@ -0,0 +1,17 @@
include(../plugins.pri)
QT += network serialbus
HEADERS += \
huaweifusionsolar.h \
huaweimodbustcpconnection.h \
integrationpluginhuawei.h \
../modbus/modbustcpmaster.h \
../modbus/modbusdatautils.h
SOURCES += \
huaweifusionsolar.cpp \
huaweimodbustcpconnection.cpp \
integrationpluginhuawei.cpp \
../modbus/modbustcpmaster.cpp \
../modbus/modbusdatautils.cpp

View File

@ -0,0 +1,77 @@
#include "huaweifusionsolar.h"
#include "extern-plugininfo.h"
HuaweiFusionSolar::HuaweiFusionSolar(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) :
HuaweiModbusTcpConnection(hostAddress, port, slaveId, parent)
{
}
void HuaweiFusionSolar::initialize()
{
// No init registers defined. Nothing to be done and we are finished.
emit initializationFinished();
}
void HuaweiFusionSolar::update()
{
// Make sure there is not an update still running
if (!m_registersQueue.isEmpty())
return;
// Add the requests
m_registersQueue.enqueue(HuaweiModbusTcpConnection::RegisterInverterDCPower);
m_registersQueue.enqueue(HuaweiModbusTcpConnection::RegisterInverterActivePower);
m_registersQueue.enqueue(HuaweiModbusTcpConnection::RegisterLunaBattery1Power);
m_registersQueue.enqueue(HuaweiModbusTcpConnection::RegisterLunaBattery1Soc);
m_registersQueue.enqueue(HuaweiModbusTcpConnection::RegisterPowerMeterActivePower);
m_registersQueue.enqueue(HuaweiModbusTcpConnection::RegisterLunaBattery2Soc);
m_registersQueue.enqueue(HuaweiModbusTcpConnection::RegisterLunaBattery2Power);
// Note: since huawei can only process one request at the time, we need to queue the requests
readNextRegister();
}
void HuaweiFusionSolar::readNextRegister()
{
// Check if currently a reply is pending
if (m_currentRegisterRequest >= 0)
return;
switch (m_currentRegisterRequest) {
case HuaweiModbusTcpConnection::RegisterInverterDCPower:
// Update registers from Inverter DC power
qCDebug(dcHuawei()) << "--> Read \"Inverter DC power\" register:" << 32064 << "size:" << 2;
QModbusReply *reply = readInverterDCPower();
if (reply) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
const QVector<quint16> values = unit.values();
qCDebug(dcHuawei()) << "<-- Response from \"Inverter DC power\" register" << 32064 << "size:" << 2 << values;
float receivedInverterDCPower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -3);
if (m_inverterDCPower != receivedInverterDCPower) {
m_inverterDCPower = receivedInverterDCPower;
emit inverterDCPowerChanged(m_inverterDCPower);
}
}
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
qCWarning(dcHuawei()) << "Modbus reply error occurred while updating \"Inverter DC power\" registers from" << hostAddress().toString() << error << reply->errorString();
emit reply->finished(); // To make sure it will be deleted
});
} else {
delete reply; // Broadcast reply returns immediatly
}
} else {
qCWarning(dcHuawei()) << "Error occurred while reading \"Inverter DC power\" registers from" << hostAddress().toString() << errorString();
}
break;
}
}

View File

@ -0,0 +1,26 @@
#ifndef HUAWEIFUSIONSOLAR_H
#define HUAWEIFUSIONSOLAR_H
#include <QObject>
#include <QQueue>
#include "huaweimodbustcpconnection.h"
class HuaweiFusionSolar : public HuaweiModbusTcpConnection
{
Q_OBJECT
public:
explicit HuaweiFusionSolar(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr);
virtual void initialize() override;
virtual void update() override;
private:
QQueue<HuaweiModbusTcpConnection::Registers> m_registersQueue;
int m_currentRegisterRequest = -1;
void readNextRegister();
};
#endif // HUAWEIFUSIONSOLAR_H

View File

@ -0,0 +1,389 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, 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 <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 "huaweimodbustcpconnection.h"
#include "loggingcategories.h"
NYMEA_LOGGING_CATEGORY(dcHuaweiModbusTcpConnection, "HuaweiModbusTcpConnection")
HuaweiModbusTcpConnection::HuaweiModbusTcpConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) :
ModbusTCPMaster(hostAddress, port, parent),
m_slaveId(slaveId)
{
}
float HuaweiModbusTcpConnection::inverterDCPower() const
{
return m_inverterDCPower;
}
float HuaweiModbusTcpConnection::inverterActivePower() const
{
return m_inverterActivePower;
}
qint32 HuaweiModbusTcpConnection::powerMeterActivePower() const
{
return m_powerMeterActivePower;
}
qint32 HuaweiModbusTcpConnection::lunaBattery1Power() const
{
return m_lunaBattery1Power;
}
float HuaweiModbusTcpConnection::lunaBattery1Soc() const
{
return m_lunaBattery1Soc;
}
qint32 HuaweiModbusTcpConnection::lunaBattery2Power() const
{
return m_lunaBattery2Power;
}
float HuaweiModbusTcpConnection::lunaBattery2Soc() const
{
return m_lunaBattery2Soc;
}
void HuaweiModbusTcpConnection::initialize()
{
// No init registers defined. Nothing to be done and we are finished.
emit initializationFinished();
}
void HuaweiModbusTcpConnection::update()
{
updateInverterDCPower();
updateInverterActivePower();
updatePowerMeterActivePower();
updateLunaBattery1Power();
updateLunaBattery1Soc();
updateLunaBattery2Power();
updateLunaBattery2Soc();
}
void HuaweiModbusTcpConnection::updateInverterDCPower()
{
// Update registers from Inverter DC power
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Inverter DC power\" register:" << 32064 << "size:" << 2;
QModbusReply *reply = readInverterDCPower();
if (reply) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
const QVector<quint16> values = unit.values();
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Inverter DC power\" register" << 32064 << "size:" << 2 << values;
float receivedInverterDCPower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -3);
if (m_inverterDCPower != receivedInverterDCPower) {
m_inverterDCPower = receivedInverterDCPower;
emit inverterDCPowerChanged(m_inverterDCPower);
}
}
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Inverter DC power\" registers from" << hostAddress().toString() << error << reply->errorString();
emit reply->finished(); // To make sure it will be deleted
});
} else {
delete reply; // Broadcast reply returns immediatly
}
} else {
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Inverter DC power\" registers from" << hostAddress().toString() << errorString();
}
}
void HuaweiModbusTcpConnection::updateInverterActivePower()
{
// Update registers from Inverter active power
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Inverter active power\" register:" << 32080 << "size:" << 2;
QModbusReply *reply = readInverterActivePower();
if (reply) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
const QVector<quint16> values = unit.values();
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Inverter active power\" register" << 32080 << "size:" << 2 << values;
float receivedInverterActivePower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -3);
if (m_inverterActivePower != receivedInverterActivePower) {
m_inverterActivePower = receivedInverterActivePower;
emit inverterActivePowerChanged(m_inverterActivePower);
}
}
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Inverter active power\" registers from" << hostAddress().toString() << error << reply->errorString();
emit reply->finished(); // To make sure it will be deleted
});
} else {
delete reply; // Broadcast reply returns immediatly
}
} else {
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Inverter active power\" registers from" << hostAddress().toString() << errorString();
}
}
void HuaweiModbusTcpConnection::updatePowerMeterActivePower()
{
// Update registers from Power meter active power
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Power meter active power\" register:" << 37113 << "size:" << 2;
QModbusReply *reply = readPowerMeterActivePower();
if (reply) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
const QVector<quint16> values = unit.values();
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Power meter active power\" register" << 37113 << "size:" << 2 << values;
qint32 receivedPowerMeterActivePower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian);
if (m_powerMeterActivePower != receivedPowerMeterActivePower) {
m_powerMeterActivePower = receivedPowerMeterActivePower;
emit powerMeterActivePowerChanged(m_powerMeterActivePower);
}
}
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Power meter active power\" registers from" << hostAddress().toString() << error << reply->errorString();
emit reply->finished(); // To make sure it will be deleted
});
} else {
delete reply; // Broadcast reply returns immediatly
}
} else {
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Power meter active power\" registers from" << hostAddress().toString() << errorString();
}
}
void HuaweiModbusTcpConnection::updateLunaBattery1Power()
{
// Update registers from Luna 2000 Battery 1 power
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 1 power\" register:" << 37001 << "size:" << 2;
QModbusReply *reply = readLunaBattery1Power();
if (reply) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
const QVector<quint16> values = unit.values();
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 1 power\" register" << 37001 << "size:" << 2 << values;
qint32 receivedLunaBattery1Power = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian);
if (m_lunaBattery1Power != receivedLunaBattery1Power) {
m_lunaBattery1Power = receivedLunaBattery1Power;
emit lunaBattery1PowerChanged(m_lunaBattery1Power);
}
}
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 1 power\" registers from" << hostAddress().toString() << error << reply->errorString();
emit reply->finished(); // To make sure it will be deleted
});
} else {
delete reply; // Broadcast reply returns immediatly
}
} else {
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 1 power\" registers from" << hostAddress().toString() << errorString();
}
}
void HuaweiModbusTcpConnection::updateLunaBattery1Soc()
{
// Update registers from Luna 2000 Battery 1 state of charge
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 1 state of charge\" register:" << 37004 << "size:" << 1;
QModbusReply *reply = readLunaBattery1Soc();
if (reply) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
const QVector<quint16> values = unit.values();
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 1 state of charge\" register" << 37004 << "size:" << 1 << values;
float receivedLunaBattery1Soc = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1);
if (m_lunaBattery1Soc != receivedLunaBattery1Soc) {
m_lunaBattery1Soc = receivedLunaBattery1Soc;
emit lunaBattery1SocChanged(m_lunaBattery1Soc);
}
}
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 1 state of charge\" registers from" << hostAddress().toString() << error << reply->errorString();
emit reply->finished(); // To make sure it will be deleted
});
} else {
delete reply; // Broadcast reply returns immediatly
}
} else {
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 1 state of charge\" registers from" << hostAddress().toString() << errorString();
}
}
void HuaweiModbusTcpConnection::updateLunaBattery2Power()
{
// Update registers from Luna 2000 Battery 2 power
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 2 power\" register:" << 37743 << "size:" << 2;
QModbusReply *reply = readLunaBattery2Power();
if (reply) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
const QVector<quint16> values = unit.values();
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 2 power\" register" << 37743 << "size:" << 2 << values;
qint32 receivedLunaBattery2Power = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian);
if (m_lunaBattery2Power != receivedLunaBattery2Power) {
m_lunaBattery2Power = receivedLunaBattery2Power;
emit lunaBattery2PowerChanged(m_lunaBattery2Power);
}
}
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 2 power\" registers from" << hostAddress().toString() << error << reply->errorString();
emit reply->finished(); // To make sure it will be deleted
});
} else {
delete reply; // Broadcast reply returns immediatly
}
} else {
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 2 power\" registers from" << hostAddress().toString() << errorString();
}
}
void HuaweiModbusTcpConnection::updateLunaBattery2Soc()
{
// Update registers from Luna 2000 Battery 2 state of charge
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 2 state of charge\" register:" << 37738 << "size:" << 1;
QModbusReply *reply = readLunaBattery2Soc();
if (reply) {
if (!reply->isFinished()) {
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
const QVector<quint16> values = unit.values();
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 2 state of charge\" register" << 37738 << "size:" << 1 << values;
float receivedLunaBattery2Soc = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1);
if (m_lunaBattery2Soc != receivedLunaBattery2Soc) {
m_lunaBattery2Soc = receivedLunaBattery2Soc;
emit lunaBattery2SocChanged(m_lunaBattery2Soc);
}
}
});
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 2 state of charge\" registers from" << hostAddress().toString() << error << reply->errorString();
emit reply->finished(); // To make sure it will be deleted
});
} else {
delete reply; // Broadcast reply returns immediatly
}
} else {
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 2 state of charge\" registers from" << hostAddress().toString() << errorString();
}
}
QModbusReply *HuaweiModbusTcpConnection::readInverterDCPower()
{
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 32064, 2);
return sendReadRequest(request, m_slaveId);
}
QModbusReply *HuaweiModbusTcpConnection::readInverterActivePower()
{
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 32080, 2);
return sendReadRequest(request, m_slaveId);
}
QModbusReply *HuaweiModbusTcpConnection::readPowerMeterActivePower()
{
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37113, 2);
return sendReadRequest(request, m_slaveId);
}
QModbusReply *HuaweiModbusTcpConnection::readLunaBattery1Power()
{
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37001, 2);
return sendReadRequest(request, m_slaveId);
}
QModbusReply *HuaweiModbusTcpConnection::readLunaBattery1Soc()
{
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37004, 1);
return sendReadRequest(request, m_slaveId);
}
QModbusReply *HuaweiModbusTcpConnection::readLunaBattery2Power()
{
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37743, 2);
return sendReadRequest(request, m_slaveId);
}
QModbusReply *HuaweiModbusTcpConnection::readLunaBattery2Soc()
{
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37738, 1);
return sendReadRequest(request, m_slaveId);
}
void HuaweiModbusTcpConnection::verifyInitFinished()
{
if (m_pendingInitReplies.isEmpty()) {
qCDebug(dcHuaweiModbusTcpConnection()) << "Initialization finished of HuaweiModbusTcpConnection" << hostAddress().toString();
emit initializationFinished();
}
}
QDebug operator<<(QDebug debug, HuaweiModbusTcpConnection *huaweiModbusTcpConnection)
{
debug.nospace().noquote() << "HuaweiModbusTcpConnection(" << huaweiModbusTcpConnection->hostAddress().toString() << ":" << huaweiModbusTcpConnection->port() << ")" << "\n";
debug.nospace().noquote() << " - Inverter DC power:" << huaweiModbusTcpConnection->inverterDCPower() << " [kW]" << "\n";
debug.nospace().noquote() << " - Inverter active power:" << huaweiModbusTcpConnection->inverterActivePower() << " [kW]" << "\n";
debug.nospace().noquote() << " - Power meter active power:" << huaweiModbusTcpConnection->powerMeterActivePower() << " [W]" << "\n";
debug.nospace().noquote() << " - Luna 2000 Battery 1 power:" << huaweiModbusTcpConnection->lunaBattery1Power() << " [W]" << "\n";
debug.nospace().noquote() << " - Luna 2000 Battery 1 state of charge:" << huaweiModbusTcpConnection->lunaBattery1Soc() << " [%]" << "\n";
debug.nospace().noquote() << " - Luna 2000 Battery 2 power:" << huaweiModbusTcpConnection->lunaBattery2Power() << " [W]" << "\n";
debug.nospace().noquote() << " - Luna 2000 Battery 2 state of charge:" << huaweiModbusTcpConnection->lunaBattery2Soc() << " [%]" << "\n";
return debug.quote().space();
}

View File

@ -0,0 +1,161 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2022, 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 <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 HUAWEIMODBUSTCPCONNECTION_H
#define HUAWEIMODBUSTCPCONNECTION_H
#include <QObject>
#include "../modbus/modbusdatautils.h"
#include "../modbus/modbustcpmaster.h"
class HuaweiModbusTcpConnection : public ModbusTCPMaster
{
Q_OBJECT
public:
enum Registers {
RegisterInverterDCPower = 32064,
RegisterInverterActivePower = 32080,
RegisterLunaBattery1Power = 37001,
RegisterLunaBattery1Soc = 37004,
RegisterPowerMeterActivePower = 37113,
RegisterLunaBattery2Soc = 37738,
RegisterLunaBattery2Power = 37743
};
Q_ENUM(Registers)
enum InverterDeviceStatus {
InverterDeviceStatusStandbyInitializing = 0,
InverterDeviceStatusStandbyDetectingInsulationResistance = 1,
InverterDeviceStatusStandbyDetectingIrradiation = 2,
InverterDeviceStatusStandbyDridDetecting = 3,
InverterDeviceStatusStarting = 256,
InverterDeviceStatusOnGrid = 512,
InverterDeviceStatusPowerLimited = 513,
InverterDeviceStatusSelfDerating = 514,
InverterDeviceStatusShutdownFault = 768,
InverterDeviceStatusShutdownCommand = 769,
InverterDeviceStatusShutdownOVGR = 770,
InverterDeviceStatusShutdownCommunicationDisconnected = 771,
InverterDeviceStatusShutdownPowerLimit = 772,
InverterDeviceStatusShutdownManualStartupRequired = 773,
InverterDeviceStatusShutdownInputUnderpower = 774,
InverterDeviceStatusGridSchedulingPCurve = 1025,
InverterDeviceStatusGridSchedulingQUCurve = 1026,
InverterDeviceStatusGridSchedulingPFUCurve = 1027,
InverterDeviceStatusGridSchedulingDryContact = 1028,
InverterDeviceStatusGridSchedulingQPCurve = 1029,
InverterDeviceStatusSpotCheckReady = 1280,
InverterDeviceStatusSpotChecking = 1281,
InverterDeviceStatusInspecting = 1536,
InverterDeviceStatusAfciSelfCheck = 1792,
InverterDeviceStatusIVScanning = 2048,
InverterDeviceStatusDCInputDetection = 2304,
InverterDeviceStatusRunningOffGridCharging = 2560,
InverterDeviceStatusStandbyNoIrradiation = 40960
};
Q_ENUM(InverterDeviceStatus)
explicit HuaweiModbusTcpConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr);
~HuaweiModbusTcpConnection() = default;
/* Inverter DC power [kW] - Address: 32064, Size: 2 */
float inverterDCPower() const;
/* Inverter active power [kW] - Address: 32080, Size: 2 */
float inverterActivePower() const;
/* Power meter active power [W] - Address: 37113, Size: 2 */
qint32 powerMeterActivePower() const;
/* Luna 2000 Battery 1 power [W] - Address: 37001, Size: 2 */
qint32 lunaBattery1Power() const;
/* Luna 2000 Battery 1 state of charge [%] - Address: 37004, Size: 1 */
float lunaBattery1Soc() const;
/* Luna 2000 Battery 2 power [W] - Address: 37743, Size: 2 */
qint32 lunaBattery2Power() const;
/* Luna 2000 Battery 2 state of charge [%] - Address: 37738, Size: 1 */
float lunaBattery2Soc() const;
virtual void initialize();
virtual void update();
void updateInverterDCPower();
void updateInverterActivePower();
void updatePowerMeterActivePower();
void updateLunaBattery1Power();
void updateLunaBattery1Soc();
void updateLunaBattery2Power();
void updateLunaBattery2Soc();
signals:
void initializationFinished();
void inverterDCPowerChanged(float inverterDCPower);
void inverterActivePowerChanged(float inverterActivePower);
void powerMeterActivePowerChanged(qint32 powerMeterActivePower);
void lunaBattery1PowerChanged(qint32 lunaBattery1Power);
void lunaBattery1SocChanged(float lunaBattery1Soc);
void lunaBattery2PowerChanged(qint32 lunaBattery2Power);
void lunaBattery2SocChanged(float lunaBattery2Soc);
protected:
QModbusReply *readInverterDCPower();
QModbusReply *readInverterActivePower();
QModbusReply *readPowerMeterActivePower();
QModbusReply *readLunaBattery1Power();
QModbusReply *readLunaBattery1Soc();
QModbusReply *readLunaBattery2Power();
QModbusReply *readLunaBattery2Soc();
private:
quint16 m_slaveId = 1;
QVector<QModbusReply *> m_pendingInitReplies;
float m_inverterDCPower = 0;
float m_inverterActivePower = 0;
qint32 m_powerMeterActivePower = 0;
qint32 m_lunaBattery1Power = 0;
float m_lunaBattery1Soc = 0;
qint32 m_lunaBattery2Power = 0;
float m_lunaBattery2Soc = 0;
void verifyInitFinished();
};
QDebug operator<<(QDebug debug, HuaweiModbusTcpConnection *huaweiModbusTcpConnection);
#endif // HUAWEIMODBUSTCPCONNECTION_H

View File

@ -0,0 +1,184 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <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 "integrationpluginhuawei.h"
#include "network/networkdevicediscovery.h"
#include "hardwaremanager.h"
#include "plugininfo.h"
IntegrationPluginHuawei::IntegrationPluginHuawei()
{
}
void IntegrationPluginHuawei::discoverThings(ThingDiscoveryInfo *info)
{
if (!hardwareManager()->networkDeviceDiscovery()->available()) {
qCWarning(dcHuawei()) << "The network discovery is not available on this platform.";
info->finish(Thing::ThingErrorUnsupportedFeature, QT_TR_NOOP("The network device discovery is not available."));
return;
}
NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover();
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) {
qCDebug(dcHuawei()) << "Found" << networkDeviceInfo;
// Filter for mac manufacturer
if (!networkDeviceInfo.macAddressManufacturer().contains("Huawei"))
continue;
QString title;
if (networkDeviceInfo.hostName().isEmpty()) {
title = networkDeviceInfo.address().toString();
} else {
title = networkDeviceInfo.hostName() + " (" + networkDeviceInfo.address().toString() + ")";
}
QString description;
if (networkDeviceInfo.macAddressManufacturer().isEmpty()) {
description = networkDeviceInfo.macAddress();
} else {
description = networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")";
}
ThingDescriptor descriptor(huaweiInverterThingClassId, title, description);
ParamList params;
params << Param(huaweiInverterThingIpAddressParamTypeId, networkDeviceInfo.address().toString());
params << Param(huaweiInverterThingMacAddressParamTypeId, networkDeviceInfo.macAddress());
descriptor.setParams(params);
// Check if we already have set up this device
Things existingThings = myThings().filterByParam(huaweiInverterThingMacAddressParamTypeId, networkDeviceInfo.macAddress());
if (existingThings.count() == 1) {
qCDebug(dcHuawei()) << "This connection already exists in the system:" << networkDeviceInfo;
descriptor.setThingId(existingThings.first()->id());
}
info->addThingDescriptor(descriptor);
}
info->finish(Thing::ThingErrorNoError);
});
}
void IntegrationPluginHuawei::startMonitoringAutoThings()
{
}
void IntegrationPluginHuawei::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
qCDebug(dcHuawei()) << "Setup" << thing << thing->params();
if (thing->thingClassId() == huaweiInverterThingClassId) {
QHostAddress hostAddress = QHostAddress(thing->paramValue(huaweiInverterThingIpAddressParamTypeId).toString());
if (hostAddress.isNull()) {
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("No IP address given"));
return;
}
uint port = thing->paramValue(huaweiInverterThingPortParamTypeId).toUInt();
quint16 slaveId = thing->paramValue(huaweiInverterThingSlaveIdParamTypeId).toUInt();
HuaweiModbusTcpConnection *connection = new HuaweiModbusTcpConnection(hostAddress, port, slaveId, this);
connect(connection, &HuaweiModbusTcpConnection::initializationFinished, this, [this, thing, connection, info]{
qCDebug(dcHuawei()) << "Connection init" << connection;
// FIXME: check if success
m_connections.insert(thing, connection);
info->finish(Thing::ThingErrorNoError);
// Set connected true
thing->setStateValue(huaweiInverterConnectedStateTypeId, true);
// Update registers
connection->update();
});
connect(connection, &HuaweiModbusTcpConnection::connectionStateChanged, this, [thing, connection](bool status){
qCDebug(dcHuawei()) << "Connected changed to" << status << "for" << thing;
if (status) {
// Connected true will be set after successfull init
connection->initialize();
} else {
thing->setStateValue(huaweiInverterConnectedStateTypeId, false);
}
});
connection->connectDevice();
// FIXME: make async and check if this is really a huawei
info->finish(Thing::ThingErrorNoError);
}
}
void IntegrationPluginHuawei::postSetupThing(Thing *thing)
{
Q_UNUSED(thing)
if (thing->thingClassId() == huaweiInverterThingClassId) {
if (!m_pluginTimer) {
qCDebug(dcHuawei()) << "Starting plugin timer...";
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
connect(m_pluginTimer, &PluginTimer::timeout, this, [this] {
foreach(HuaweiModbusTcpConnection *connection, m_connections) {
if (connection->connected()) {
connection->update();
}
}
});
}
}
}
void IntegrationPluginHuawei::thingRemoved(Thing *thing)
{
if (thing->thingClassId() == huaweiInverterThingClassId && m_connections.contains(thing)) {
HuaweiModbusTcpConnection *connection = m_connections.take(thing);
delete connection;
}
if (myThings().isEmpty() && m_pluginTimer) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
m_pluginTimer = nullptr;
}
}
void IntegrationPluginHuawei::executeAction(ThingActionInfo *info)
{
info->finish(Thing::ThingErrorNoError);
}

View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 INTEGRATIONPLUGINHUAWEI_H
#define INTEGRATIONPLUGINHUAWEI_H
#include "plugintimer.h"
#include "integrations/integrationplugin.h"
#include "huaweimodbustcpconnection.h"
class IntegrationPluginHuawei: public IntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginhuawei.json")
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginHuawei();
void discoverThings(ThingDiscoveryInfo *info) override;
void startMonitoringAutoThings() override;
void setupThing(ThingSetupInfo *info) override;
void postSetupThing(Thing *thing) override;
void thingRemoved(Thing *thing) override;
void executeAction(ThingActionInfo *info) override;
private:
PluginTimer *m_pluginTimer = nullptr;
QHash<Thing *, HuaweiModbusTcpConnection *> m_connections;
};
#endif // INTEGRATIONPLUGINHUAWEI_H

View File

@ -0,0 +1,370 @@
{
"name": "Huawei",
"displayName": "Huawei FusionSolar",
"id": "fc3e4509-47f3-4622-9bc4-0a90fe2b6262",
"vendors": [
{
"name": "huawei",
"displayName": "Huawei",
"id": "f654c99d-a286-4abb-b33e-1a71843d8da0",
"thingClasses": [
{
"name": "huaweiInverter",
"displayName": "Huawei FusionSolar Inverter",
"id": "87e75ee0-d544-457b-add3-bd4e58160fcd",
"createMethods": ["discovery", "user"],
"interfaces": ["solarinverter", "connectable"],
"paramTypes": [
{
"id": "d93371db-0954-4dcd-a1a5-6881b78cb0ea",
"name": "ipAddress",
"displayName": "IP address",
"type": "QString",
"inputType": "IPv4Address",
"defaultValue": "127.0.0.1"
},
{
"id": "93517bff-1928-4c4a-8207-5fe596c86eba",
"name":"macAddress",
"displayName": "MAC address",
"type": "QString",
"inputType": "MacAddress",
"defaultValue": ""
},
{
"id": "55c4ec99-6342-4309-84a8-d1615f19b2e8",
"name":"port",
"displayName": "Port",
"type": "int",
"defaultValue": 502
},
{
"id": "aa6e978e-a16b-4722-8330-e706f3c7c21e",
"name":"slaveId",
"displayName": "Slave ID",
"type": "int",
"defaultValue": 1
}
],
"stateTypes": [
{
"id": "a51f0ceb-bd2c-444f-8b39-77cf8a4e1bc6",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "f463f36e-69f9-4614-b690-664ce22d76e0",
"name": "currentPower",
"displayName": "Active power",
"displayNameEvent": "Active power changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0
},
{
"id": "e97fe328-6ca4-4fe4-86f7-fee6e9e406a5",
"name": "totalEnergyProduced",
"displayName": "AC energy",
"displayNameEvent": "AC energy changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0.00
},
{
"id": "6609a589-8f0f-4747-9240-c0d0e0d87f29",
"name": "phaseACurrent",
"displayName": "Phase A current",
"displayNameEvent": "Phase A current changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0.00
},
{
"id": "1bff8853-ec1e-4fe8-b148-c04d1db67e74",
"name": "phaseBCurrent",
"displayName": "Phase B current",
"displayNameEvent": "Phase B current changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0.00
},
{
"id": "0977c3bc-7798-4161-a75f-19858d44c463",
"name": "phaseCCurrent",
"displayName": "Phase C current",
"displayNameEvent": "Phase C current changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0.00
},
{
"id": "e91281b3-d89f-4d3e-b81e-96645a8de63f",
"name": "voltagePhaseA",
"displayName": "Voltage phase A",
"displayNameEvent": "Voltage phase A changed",
"type": "double",
"unit": "Volt",
"defaultValue": 0.00
},
{
"id": "ee921f23-ceeb-4818-adca-8c2fa1e75b17",
"name": "voltagePhaseB",
"displayName": "Voltage phase B",
"displayNameEvent": "Voltage phase B changed",
"type": "double",
"unit": "Volt",
"defaultValue": 0.00
},
{
"id": "5613cea9-11cb-4b81-9b61-0e9a7ec737a3",
"name": "voltagePhaseC",
"displayName": "Voltage phase C",
"displayNameEvent": "Voltage phase C changed",
"type": "double",
"unit": "Volt",
"defaultValue": 0.00
},
{
"id": "4db7c66c-7676-449d-94c5-1b8c0ddf368a",
"name": "currentPowerPhaseA",
"displayName": "Current power phase A",
"displayNameEvent": "Current power phase A changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0.00
},
{
"id": "59026351-1cea-45e8-bffe-9ab65b44ddb2",
"name": "currentPowerPhaseB",
"displayName": "Current power phase B",
"displayNameEvent": "Current power phase B changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0.00
},
{
"id": "89ccd9d7-fd26-431a-b198-5001564373dc",
"name": "currentPowerPhaseC",
"displayName": "Current power phase C",
"displayNameEvent": "Current power phase C changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0.00
}
],
"actionTypes": [ ]
},
{
"name": "huaweiMeter",
"displayName": "Huawei Meter",
"id": "529c2a19-ca6a-4df2-b56e-3fb2673fa95f",
"createMethods": ["auto"],
"interfaces": [ "energymeter", "connectable"],
"paramTypes": [
],
"stateTypes": [
{
"id": "720ece7a-b0b3-4fa3-9f52-6f23042624a5",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "f480dc82-68e2-44e2-839c-df38b9c10310",
"name": "currentPower",
"displayName": "Total real power",
"displayNameEvent": "Total real power changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0.00
},
{
"id": "759554dd-74c5-4836-9792-96e02eb816f0",
"name": "totalEnergyProduced",
"displayName": "AC energy",
"displayNameEvent": "AC energy changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0.00
},
{
"id": "2cf8d885-37f7-478f-819e-c4e20f2dbe01",
"name": "totalEnergyConsumed",
"displayName": "Total real energy imported",
"displayNameEvent": "Total real energy imported changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0.00
},
{
"id": "af48ff45-11ba-401e-a812-bb1db0896449",
"name": "currentPhaseA",
"displayName": "Phase A current",
"displayNameEvent": "Phase A current changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0.00
},
{
"id": "fb5082e4-a2d8-4958-a47d-e80928795ece",
"name": "currentPhaseB",
"displayName": "Phase B current",
"displayNameEvent": "Phase B current changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0.00
},
{
"id": "bdd9aa8b-93fe-4b6b-8a31-08e99d85a06c",
"name": "currentPhaseC",
"displayName": "Phase C current",
"displayNameEvent": "Phase C current changed",
"type": "double",
"unit": "Ampere",
"defaultValue": 0.00
},
{
"id": "ecc03e9b-88b1-424f-a179-66bbdebaaea9",
"name": "currentPowerPhaseA",
"displayName": "Current power phase A",
"displayNameEvent": "Current power phase A changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0.00
},
{
"id": "7971cbde-b2ea-4474-b68a-71e040ed3b1d",
"name": "currentPowerPhaseB",
"displayName": "Current power phase B",
"displayNameEvent": "Current power phase B changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0.00
},
{
"id": "7ca21c4d-6763-49e4-a056-4c9c76923971",
"name": "currentPowerPhaseC",
"displayName": "Current power phase C",
"displayNameEvent": "Current power phase C changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0.00
},
{
"id": "ea5d7924-19a8-415c-aeeb-e04ce08bed33",
"name": "voltagePhaseA",
"displayName": "Voltage phase A",
"displayNameEvent": "Voltage phase A changed",
"type": "double",
"unit": "Volt",
"defaultValue": 0.00
},
{
"id": "f15856d1-645f-4d34-89a7-c1585ca329cc",
"name": "voltagePhaseB",
"displayName": "Voltage phase B",
"displayNameEvent": "Voltage phase B changed",
"type": "double",
"unit": "Volt",
"defaultValue": 0.00
},
{
"id": "aafb5de4-caa1-4a90-8149-cdf85ae5dc2b",
"name": "voltagePhaseC",
"displayName": "Voltage phase C",
"displayNameEvent": "Voltage phase C changed",
"type": "double",
"unit": "Volt",
"defaultValue": 0.00
},
{
"id": "1e2252be-80b3-4e9a-97f7-105d6d1c50f9",
"name": "frequency",
"displayName": "Frequency",
"displayNameEvent": "Frequency changed",
"type": "double",
"unit": "Hertz",
"defaultValue": 0.00
}
],
"actionTypes": [ ]
},
{
"name": "huaweiBattery",
"displayName": "Huawei Battery",
"id": "40104aac-0456-475d-8bd6-18f946597d96",
"createMethods": ["auto"],
"interfaces": [ "energystorage", "connectable"],
"paramTypes": [
],
"stateTypes": [
{
"id": "917bc284-9d43-430c-a8c3-642d302448e6",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "223ddf60-ff73-4acf-b8ab-6337aeb972e8",
"name": "batteryCritical",
"displayName": "Battery critical",
"displayNameEvent": "Battery critical changed",
"type": "bool",
"defaultValue": false
},
{
"id": "94d609bf-1f67-47c4-a23d-2fd14e7c0b21",
"name": "batteryLevel",
"displayName": "Battery level",
"displayNameEvent": "Battery level changed",
"type": "int",
"unit": "Percentage",
"minValue": 0,
"maxValue": 100,
"defaultValue": 0
},
{
"id": "53ca1f8a-0267-40aa-b563-762a943c8f55",
"name": "currentPower",
"displayName": "Total real power",
"displayNameEvent": "Total real power changed",
"type": "double",
"unit": "Watt",
"defaultValue": 0.00
},
{
"id": "3eed974a-0acb-4e38-bcb8-0e3f6fbfd51a",
"name": "capacity",
"displayName": "Capacity",
"displayNameEvent": "Capacity changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0.00
},
{
"id": "d9604513-d5a9-463a-ad18-d2f259a7a99d",
"name": "chargingState",
"displayName": "Charging state",
"displayNameEvent": "Charging state changed",
"type": "QString",
"possibleValues": ["idle", "charging", "discharging"],
"defaultValue": "idle"
}
],
"actionTypes": [ ]
}
]
}
]
}

View File

@ -7,7 +7,8 @@ SUBDIRS += libnymea-sunspec
PLUGIN_DIRS = \
alphainnotec \
drexelundweiss \
energymeters \
energymeters \
huawei \
modbuscommander \
mtec \
mypv \
@ -46,6 +47,9 @@ QMAKE_EXTRA_TARGETS += lrelease
# For Qt-Creator's code model: Add CPATH to INCLUDEPATH explicitly
INCLUDEPATH += $$(CPATH)
CONFIG += selection
PLUGINS=huawei
# Verify if building only a selection of plugins
contains(CONFIG, selection) {
# Check each plugin if the subdir exists