Merge PR #213: Wattsonic: Refactor connection structure and improve gen2 / gen3 support

This commit is contained in:
jenkins 2025-05-22 15:29:08 +02:00
commit 525e4ac3fc
9 changed files with 1582 additions and 99 deletions

View File

@ -1,4 +1,44 @@
# Wattsonic
This plugin allows to connect wattsonic hybrid inverters to nymea
This plugin allows to connect wattsonic hybrid inverters to nymea. If there are any meters and energy storages connected to the system, they should be detected automatically.
## Supported inverters
Currently all `Gen2` and `Gen3` single and three phase inverters should be supported.
The full list of supported models can be found here:
Single Phase Hybrid
* 3.0K-30A-1P
* 3.6K-30A-1P
* 4.2K-30A-1P
* 4.6K-30A-1P
* 5.0K-30A-1P
* 6.0K-30A-1P
* 7.0K-30A-1P
* 8.0K-30A-1P
* 3.0K-30A-1P-S
* 3.6K-30A-1P-S
Three Phase Hybrid
* 4.0K-25A-3P
* 5.0K-25A-3P
* 6.0K-25A-3P
* 8.0K-25A-3P
* 10K-25A-3P
* 12K-25A-3P
* 10K-40A-3P
* 12K-40A-3P
* 15K-40A-3P
* 20K-40A-3P
Three Phase Hybrid (25-50K)
* 25K-100A-3P
* 30K-100A-3P
* 36K-100A-3P
* 40K-100A-3P
* 50K-100A-3P

View File

@ -54,8 +54,8 @@ void IntegrationPluginWattsonic::discoverThings(ThingDiscoveryInfo *info)
foreach (const WattsonicDiscovery::Result &result, discovery->discoveryResults()) {
QString name = "Wattsonic inverter (" + result.serialNumber + ")";
ThingDescriptor descriptor(inverterThingClassId, name, QString("Modbus ID: %1").arg(result.slaveId));
QString name = "Wattsonic " + result.inverterInfo.type + + " " + result.inverterInfo.model;
ThingDescriptor descriptor(inverterThingClassId, name, QString("Serial number: %1").arg(result.serialNumber));
qCDebug(dcWattsonic()) << "Discovered:" << descriptor.title() << descriptor.description();
ParamList params {
@ -157,16 +157,16 @@ void IntegrationPluginWattsonic::setupWattsonicConnection(ThingSetupInfo *info)
return;
}
WattsonicModbusRtuConnection *connection = new WattsonicModbusRtuConnection(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), slaveId, this);
WattsonicInverter *connection = new WattsonicInverter(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), slaveId, this);
m_connections.insert(thing, connection);
// Only for setup
connect(info, &ThingSetupInfo::aborted, connection, &WattsonicModbusRtuConnection::deleteLater);
connect(info, &ThingSetupInfo::aborted, connection, &WattsonicInverter::deleteLater);
connect(info, &ThingSetupInfo::aborted, this, [=](){
m_connections.take(info->thing())->deleteLater();
});
connect(connection, &WattsonicModbusRtuConnection::initializationFinished, info, [=](bool success){
connect(connection, &WattsonicInverter::customInitializationFinished, info, [=](bool success){
qCDebug(dcWattsonic()) << "Initialization finished" << success;
if (info->isInitialSetup() && !success) {
m_connections.take(info->thing())->deleteLater();
@ -179,7 +179,7 @@ void IntegrationPluginWattsonic::setupWattsonicConnection(ThingSetupInfo *info)
});
// Runtime connections
connect(connection, &WattsonicModbusRtuConnection::reachableChanged, thing, [connection, thing, this](bool reachable){
connect(connection, &WattsonicInverter::reachableChanged, thing, [connection, thing, this](bool reachable){
qCDebug(dcWattsonic()) << "Reachable state changed" << reachable;
if (reachable) {
connection->initialize();
@ -188,11 +188,11 @@ void IntegrationPluginWattsonic::setupWattsonicConnection(ThingSetupInfo *info)
setConnectedStates(thing, reachable);
});
connect(connection, &WattsonicModbusRtuConnection::reachableChanged, thing, [this, thing](bool reachable){
connect(connection, &WattsonicInverter::reachableChanged, thing, [this, thing](bool reachable){
setConnectedStates(thing, reachable);
});
connect(connection, &WattsonicModbusRtuConnection::updateFinished, thing, [this, connection, thing](){
connect(connection, &WattsonicInverter::updateFinished, thing, [this, connection, thing](){
qCDebug(dcWattsonic()) << "Update finished:" << thing->name() << connection;
// We received an update, make sure we are connected
@ -207,7 +207,13 @@ void IntegrationPluginWattsonic::setupWattsonicConnection(ThingSetupInfo *info)
// Check if a meter is connected or not. We detect a meter by reading the totalEnergyPurchasedFromGrid totalEnergyInjectedToGrid registers,
// As of now, there is no other way to detect the presence of the meter. Voltage is always there, even if there is no meter connected.
bool meterDetected = connection->totalEnergyPurchasedFromGrid() != 0 || connection->totalEnergyInjectedToGrid() != 0;
// Some meters do not have the total counters, for whatever reason...
bool meterDetected = connection->totalEnergyInjectedToGrid() != 0 ||
connection->totalEnergyPurchasedFromGrid() != 0 ||
connection->phaseAPower() != 0 ||
connection->phaseBPower() != 0 ||
connection->phaseCPower() != 0;
if (meterDetected) {
if (meters.isEmpty()) {
@ -232,21 +238,21 @@ void IntegrationPluginWattsonic::setupWattsonicConnection(ThingSetupInfo *info)
if (!meters.isEmpty()) {
Thing *meter = meters.first();
meter->setStateValue(meterCurrentPowerStateTypeId, connection->totalPowerOnMeter() * -1.0);
meter->setStateValue(meterTotalEnergyConsumedStateTypeId, connection->totalEnergyPurchasedFromGrid() / 10.0);
meter->setStateValue(meterTotalEnergyProducedStateTypeId, connection->totalEnergyInjectedToGrid() / 10.0);
meter->setStateValue(meterTotalEnergyConsumedStateTypeId, connection->totalEnergyPurchasedFromGrid());
meter->setStateValue(meterTotalEnergyProducedStateTypeId, connection->totalEnergyInjectedToGrid());
meter->setStateValue(meterCurrentPowerPhaseAStateTypeId, connection->phaseAPower() * -1.0);
meter->setStateValue(meterCurrentPowerPhaseBStateTypeId, connection->phaseBPower() * -1.0);
meter->setStateValue(meterCurrentPowerPhaseCStateTypeId, connection->phaseCPower() * -1.0);
meter->setStateValue(meterVoltagePhaseAStateTypeId, connection->gridPhaseAVoltage() / 10.0);
meter->setStateValue(meterVoltagePhaseBStateTypeId, connection->gridPhaseBVoltage() / 10.0);
meter->setStateValue(meterVoltagePhaseCStateTypeId, connection->gridPhaseCVoltage() / 10.0);
meter->setStateValue(meterVoltagePhaseAStateTypeId, connection->gridPhaseAVoltage());
meter->setStateValue(meterVoltagePhaseBStateTypeId, connection->gridPhaseBVoltage());
meter->setStateValue(meterVoltagePhaseCStateTypeId, connection->gridPhaseCVoltage());
// The phase current registers don't seem to contain proper values. Calculating ourselves instead
// meter->setStateValue(meterCurrentPhaseAStateTypeId, connection->gridPhaseACurrent() / 10.0);
// meter->setStateValue(meterCurrentPhaseBStateTypeId, connection->gridPhaseBCurrent() / 10.0);
// meter->setStateValue(meterCurrentPhaseCStateTypeId, connection->gridPhaseCCurrent() / 10.0);
meter->setStateValue(meterCurrentPhaseAStateTypeId, (connection->phaseAPower() * -1.0) / (connection->gridPhaseAVoltage() / 10.0));
meter->setStateValue(meterCurrentPhaseBStateTypeId, (connection->phaseBPower() * -1.0) / (connection->gridPhaseBVoltage() / 10.0));
meter->setStateValue(meterCurrentPhaseCStateTypeId, (connection->phaseCPower() * -1.0) / (connection->gridPhaseCVoltage() / 10.0));
// meter->setStateValue(meterCurrentPhaseAStateTypeId, connection->gridPhaseACurrent());
// meter->setStateValue(meterCurrentPhaseBStateTypeId, connection->gridPhaseBCurrent());
// meter->setStateValue(meterCurrentPhaseCStateTypeId, connection->gridPhaseCCurrent());
meter->setStateValue(meterCurrentPhaseAStateTypeId, (connection->phaseAPower() * -1.0) / connection->gridPhaseAVoltage());
meter->setStateValue(meterCurrentPhaseBStateTypeId, (connection->phaseBPower() * -1.0) / connection->gridPhaseBVoltage());
meter->setStateValue(meterCurrentPhaseCStateTypeId, (connection->phaseCPower() * -1.0) / connection->gridPhaseCVoltage());
qCInfo(dcWattsonic()) << "Updating meter:" << meter->stateValue(meterCurrentPowerStateTypeId).toDouble() << "W" << meter->stateValue(meterTotalEnergyProducedStateTypeId).toDouble() << "kWh";
}
@ -273,14 +279,15 @@ void IntegrationPluginWattsonic::setupWattsonicConnection(ThingSetupInfo *info)
if (!batteries.isEmpty() && connection->SOC() > 0) {
Thing *battery = batteries.first();
QHash<WattsonicModbusRtuConnection::BatteryMode, QString> map {
{WattsonicModbusRtuConnection::BatteryModeDischarge, "discharging"},
{WattsonicModbusRtuConnection::BatteryModeCharge, "charging"}
QHash<WattsonicInverter::BatteryMode, QString> map {
{WattsonicInverter::BatteryModeDischarge, "discharging"},
{WattsonicInverter::BatteryModeCharge, "charging"}
};
battery->setStateValue(batteryChargingStateStateTypeId, map.value(connection->batteryMode()));
battery->setStateValue(batteryCurrentPowerStateTypeId, connection->batteryPower() * -1.0);
battery->setStateValue(batteryBatteryLevelStateTypeId, connection->SOC() / 100.0);
battery->setStateValue(batteryBatteryCriticalStateTypeId, connection->SOC() < 500);
battery->setStateValue(batteryBatteryLevelStateTypeId, connection->SOC());
battery->setStateValue(batteryBatteryCriticalStateTypeId, connection->SOC() < 5);
}
});
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2024, nymea GmbH
* Copyright 2013 - 2025, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -36,8 +36,7 @@
#include <network/networkdevicemonitor.h>
#include "extern-plugininfo.h"
#include "wattsonicmodbusrtuconnection.h"
#include "wattsonicinverter.h"
class IntegrationPluginWattsonic: public IntegrationPlugin
{
@ -58,7 +57,7 @@ private:
void setupWattsonicConnection(ThingSetupInfo *info);
PluginTimer *m_pluginTimer = nullptr;
QHash<Thing *, WattsonicModbusRtuConnection *> m_connections;
QHash<Thing *, WattsonicInverter *> m_connections;
void setConnectedStates(Thing * thing, bool connected);
};

View File

@ -48,8 +48,7 @@
]
}
],
"blocks": [
],
"blocks": [ ],
"registers": [
{
"id": "serialNumber",
@ -61,6 +60,16 @@
"description": "Serial number",
"access": "RO"
},
{
"id": "equipmentInfo",
"address": 10008,
"size": 1,
"type": "uint16",
"readSchedule": "init",
"registerType": "holdingRegister",
"description": "EquipmentInfo",
"access": "RO"
},
{
"id": "firmwareVersion",
"address": 10011,
@ -140,7 +149,8 @@
"registerType": "holdingRegister",
"description": "Total grid injection energy on meter",
"defaultValue": 0,
"unit": "1/100 kWh",
"staticScaleFactor": -2,
"unit": "kWh",
"access": "RO"
},
{
@ -152,7 +162,8 @@
"registerType": "holdingRegister",
"description": "Total purchasing energy from grid on meter",
"defaultValue": 0,
"unit": "1/100 kWh",
"staticScaleFactor": -2,
"unit": "kWh",
"access": "RO"
},
{
@ -164,7 +175,8 @@
"registerType": "holdingRegister",
"description": "Grid Phase A Voltage",
"defaultValue": 0,
"unit": "1/10 V",
"staticScaleFactor": -1,
"unit": "V",
"access": "RO"
},
{
@ -176,7 +188,8 @@
"registerType": "holdingRegister",
"description": "Grid Phase A Current",
"defaultValue": 0,
"unit": "1/10 A",
"staticScaleFactor": -1,
"unit": "A",
"access": "RO"
},
{
@ -188,7 +201,8 @@
"registerType": "holdingRegister",
"description": "Grid Phase B Voltage",
"defaultValue": 0,
"unit": "1/10 V",
"staticScaleFactor": -1,
"unit": "V",
"access": "RO"
},
{
@ -200,7 +214,8 @@
"registerType": "holdingRegister",
"description": "Grid Phase B Current",
"defaultValue": 0,
"unit": "1/10 A",
"staticScaleFactor": -1,
"unit": "A",
"access": "RO"
},
{
@ -212,7 +227,8 @@
"registerType": "holdingRegister",
"description": "Grid Phase C Voltage",
"defaultValue": 0,
"unit": "1/10 V",
"staticScaleFactor": -1,
"unit": "V",
"access": "RO"
},
{
@ -224,7 +240,8 @@
"registerType": "holdingRegister",
"description": "Grid Phase C Current",
"defaultValue": 0,
"unit": "1/10 A",
"staticScaleFactor": -1,
"unit": "A",
"access": "RO"
},
{
@ -248,7 +265,8 @@
"registerType": "holdingRegister",
"description": "Total PV Generation from installation",
"defaultValue": 0,
"unit": "1/10 kWh",
"staticScaleFactor": -1,
"unit": "kWh",
"access": "RO"
},
{
@ -263,111 +281,180 @@
"unit": "W",
"access": "RO"
},
{
"id": "totalBackupP",
"address": 30230,
"size": 2,
"type": "int32",
"readSchedule": "update",
"registerType": "holdingRegister",
"description": "Total_Backup_P/AC Active Power",
"unit": "W",
"defaultValue": 0,
"access": "RO"
},
{
"id": "batteryVoltageDc",
"id": "batteryVoltageDcGen3",
"address": 30254,
"size": 1,
"type": "uint16",
"readSchedule": "update",
"registerType": "holdingRegister",
"description": "Battery voltage DC",
"description": "Battery voltage DC (gen3)",
"defaultValue": 0,
"unit": "1/10 V",
"staticScaleFactor": -1,
"unit": "V",
"access": "RO"
},
{
"id": "batteryMode",
"id": "batteryModeGen3",
"address": 30256,
"size": 1,
"type": "uint16",
"readSchedule": "update",
"registerType": "holdingRegister",
"description": "Battery mode",
"description": "Battery mode (gen3)",
"enum": "BatteryMode",
"defaultValue": "BatteryModeDischarge",
"access": "RO"
},
{
"id": "batteryPower",
"id": "batteryPowerGen3",
"address": 30258,
"size": 2,
"type": "int32",
"readSchedule": "update",
"registerType": "holdingRegister",
"description": "Battery power",
"description": "Battery power (gen3)",
"defaultValue": 0,
"unit": "W",
"access": "RO"
},
{
"id": "totalEnergyInjectedToGrid",
"id": "totalEnergyInjectedToGridGen3",
"address": 31102,
"size": 2,
"type": "uint32",
"readSchedule": "update",
"registerType": "holdingRegister",
"description": "Total energy injected to grid",
"description": "Total energy injected to grid (gen3)",
"defaultValue": 0,
"unit": "1/10 kWh",
"staticScaleFactor": -1,
"unit": "kWh",
"access": "RO"
},
{
"id": "totalEnergyPurchasedFromGrid",
"id": "totalEnergyPurchasedFromGridGen3",
"address": 31104,
"size": 2,
"type": "uint32",
"readSchedule": "update",
"registerType": "holdingRegister",
"description": "Total energy purchased from grid",
"description": "Total energy purchased from grid (gen3)",
"defaultValue": 0,
"unit": "1/10 kWh",
"staticScaleFactor": -1,
"unit": "kWh",
"access": "RO"
},
{
"id": "batteryStrings",
"address": 32001,
"size": 1,
"type": "uint16",
"readSchedule": "update",
"registerType": "holdingRegister",
"description": "Battery strings",
"defaultValue": 0,
"access": "RO"
},
{
"id": "SOC",
"id": "SOCGen3",
"address": 33000,
"size": 1,
"type": "uint16",
"readSchedule": "update",
"registerType": "holdingRegister",
"description": "SOC",
"description": "SOC (gen3)",
"defaultValue": 0,
"unit": "% * 100",
"staticScaleFactor": -2,
"unit": "%",
"access": "RO"
},
{
"id": "SOH",
"id": "SOHGen3",
"address": 33001,
"size": 1,
"type": "uint16",
"readSchedule": "update",
"registerType": "holdingRegister",
"description": "SOH",
"description": "SOH (gen3)",
"defaultValue": 0,
"unit": "% * 100",
"staticScaleFactor": -2,
"unit": "%",
"access": "RO"
},
{
"id": "batteryVoltageDcGen2",
"address": 40254,
"size": 1,
"type": "uint16",
"readSchedule": "update",
"registerType": "holdingRegister",
"description": "Battery voltage DC (gen2)",
"defaultValue": 0,
"staticScaleFactor": -1,
"unit": "V",
"access": "RO"
},
{
"id": "batteryModeGen2",
"address": 40256,
"size": 1,
"type": "uint16",
"registerType": "holdingRegister",
"description": "Battery mode (gen2)",
"enum": "BatteryMode",
"defaultValue": "BatteryModeDischarge",
"access": "RO"
},
{
"id": "batteryPowerGen2",
"address": 40258,
"size": 2,
"type": "int32",
"registerType": "holdingRegister",
"description": "Battery power (gen2)",
"defaultValue": 0,
"unit": "W",
"access": "RO"
},
{
"id": "totalEnergyInjectedToGridGen2",
"address": 41102,
"size": 2,
"type": "uint32",
"registerType": "holdingRegister",
"description": "Total energy injected to grid (gen2)",
"defaultValue": 0,
"staticScaleFactor": -1,
"unit": "kWh",
"access": "RO"
},
{
"id": "totalEnergyPurchasedFromGridGen2",
"address": 41104,
"size": 2,
"type": "uint32",
"registerType": "holdingRegister",
"description": "Total energy purchased from grid (gen2)",
"defaultValue": 0,
"staticScaleFactor": -1,
"unit": "kWh",
"access": "RO"
},
{
"id": "SOCGen2",
"address": 43000,
"size": 1,
"type": "uint16",
"registerType": "holdingRegister",
"description": "SOC (gen2)",
"defaultValue": 0,
"staticScaleFactor": -2,
"unit": "%",
"access": "RO"
},
{
"id": "SOHGen2",
"address": 43001,
"size": 1,
"type": "uint16",
"registerType": "holdingRegister",
"description": "SOH (gen2)",
"defaultValue": 0,
"staticScaleFactor": -2,
"unit": "%",
"access": "RO"
}
]

View File

@ -8,8 +8,10 @@ include(../modbus.pri)
HEADERS += \
wattsonicdiscovery.h \
integrationpluginwattsonic.h
integrationpluginwattsonic.h \
wattsonicinverter.h
SOURCES += \
wattsonicdiscovery.cpp \
integrationpluginwattsonic.cpp
integrationpluginwattsonic.cpp \
wattsonicinverter.cpp

View File

@ -43,21 +43,22 @@ WattsonicDiscovery::WattsonicDiscovery(ModbusRtuHardwareResource *modbusRtuResou
void WattsonicDiscovery::startDiscovery(quint16 slaveId)
{
qCInfo(dcWattsonic()) << "Discovery: Searching for Wattsonic device on modbus RTU...";
m_candidateMasters.clear();
m_verifiedMasters.clear();
QList<ModbusRtuMaster*> candidateMasters;
foreach (ModbusRtuMaster *master, m_modbusRtuResource->modbusRtuMasters()) {
if (master->baudrate() == 9600 && master->dataBits() == 8 && master->stopBits() == 1 && master->parity() == QSerialPort::NoParity) {
candidateMasters.append(master);
m_candidateMasters.append(master);
}
}
if (candidateMasters.isEmpty()) {
if (m_candidateMasters.isEmpty()) {
qCWarning(dcWattsonic()) << "Discovery: No usable modbus RTU master found.";
emit discoveryFinished(false);
return;
}
foreach (ModbusRtuMaster *master, candidateMasters) {
foreach (ModbusRtuMaster *master, m_candidateMasters) {
if (master->connected()) {
tryConnect(master, slaveId);
} else {
@ -74,18 +75,35 @@ QList<WattsonicDiscovery::Result> WattsonicDiscovery::discoveryResults() const
void WattsonicDiscovery::tryConnect(ModbusRtuMaster *master, quint16 slaveId)
{
qCDebug(dcWattsonic()) << "Discovery: Scanning modbus RTU master" << master->modbusUuid() << "Slave ID:" << slaveId;
m_verifiedMasters.append(master);
ModbusRtuReply *reply = master->readHoldingRegister(slaveId, 10000, 8);
connect(reply, &ModbusRtuReply::finished, this, [this, master, reply, slaveId](){
WattsonicInverter *connection = new WattsonicInverter(master, slaveId, this);
connect(connection, &WattsonicInverter::reachableChanged, this, [connection](bool reachable){
if (reachable) {
qCDebug(dcWattsonic()) << "Discovery: The connection is now reachable. Starting the initialization";
connection->initialize();
} else {
connection->deleteLater();
}
});
if (reply->error() == ModbusRtuReply::NoError) {
QString serialNumber = ModbusDataUtils::convertToString(reply->result(), ModbusDataUtils::ByteOrderBigEndian);
qCDebug(dcWattsonic()) << "Discovery: Test reply finished!" << reply->error() << reply->result() << serialNumber;
Result result {master->modbusUuid(), serialNumber, slaveId};
m_discoveryResults.append(result);
connect(connection, &WattsonicInverter::customInitializationFinished, this, [this, connection, master, slaveId](bool success){
if (!success) {
qCDebug(dcWattsonic()) << "Initialization failed on" << master << "skip ";
return;
}
emit discoveryFinished(true);
qCDebug(dcWattsonic()) << "Discovery: Init finished successfully:" << connection->serialNumber()
<< connection->inverterInfo().type << connection->inverterInfo().model << connection->generation();
Result result {master->modbusUuid(), connection->serialNumber(), slaveId, connection->generation(), connection->inverterInfo()};
m_discoveryResults.append(result);
if (m_verifiedMasters.count() == m_candidateMasters.count()) {
qCDebug(dcWattsonic()) << "Discovery: Verified all masters. Finish discovery with" << m_discoveryResults.count() << "discovered inverters.";
emit discoveryFinished(true);
}
});
}

View File

@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2023, nymea GmbH
* Copyright 2013 - 2025, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@ -32,8 +32,11 @@
#define WATTSONICDISCOVERY_H
#include <QObject>
#include <hardware/modbus/modbusrtuhardwareresource.h>
#include "wattsonicinverter.h"
class WattsonicDiscovery : public QObject
{
Q_OBJECT
@ -44,12 +47,15 @@ public:
QUuid modbusRtuMasterId;
QString serialNumber;
quint16 slaveId;
WattsonicInverter::Generation generation;
WattsonicInverter::Info inverterInfo;
};
void startDiscovery(quint16 slaveId);
QList<Result> discoveryResults() const;
signals:
void discoveryFinished(bool modbusRtuMasterAvailable);
@ -58,7 +64,8 @@ private slots:
private:
ModbusRtuHardwareResource *m_modbusRtuResource = nullptr;
QList<ModbusRtuMaster *> m_candidateMasters;
QList<ModbusRtuMaster *> m_verifiedMasters;
QList<Result> m_discoveryResults;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2025, 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 WATTSONICINVERTER_H
#define WATTSONICINVERTER_H
#include <QObject>
#include "wattsonicmodbusrtuconnection.h"
class WattsonicInverter : public WattsonicModbusRtuConnection
{
Q_OBJECT
public:
struct Info {
QString type;
QString model;
};
enum Generation {
GenerationUnknwon,
Generation2,
Generation3
};
Q_ENUM(Generation)
explicit WattsonicInverter(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr);
Generation generation() const;
WattsonicInverter::Info inverterInfo() const;
// Generation specific registers
float batteryVoltageDc() const;
BatteryMode batteryMode() const;
qint32 batteryPower() const;
float totalEnergyInjectedToGrid() const;
float totalEnergyPurchasedFromGrid() const;
float SOC() const;
float SOH() const;
bool update() override;
static WattsonicInverter::Info getInverterInfo(quint16 equipmentInfo);
signals:
void generationChanged();
void customInitializationFinished(bool success);
private:
WattsonicInverter::Info m_inverterInfo;
Generation m_generation = GenerationUnknwon;
};
#endif // WATTSONICINVERTER_H