From 497cb617952b9572648fbd23f16c351ae9abb478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 8 Oct 2021 08:37:36 +0200 Subject: [PATCH] Move inverter to plugin main class for individual state handling --- sunspec/integrationpluginsunspec.cpp | 302 +++++++++++++++++++++++++-- sunspec/integrationpluginsunspec.h | 12 +- sunspec/sunspec.pro | 2 - sunspec/sunspecinverter.cpp | 281 ------------------------- sunspec/sunspecinverter.h | 55 ----- 5 files changed, 293 insertions(+), 359 deletions(-) delete mode 100644 sunspec/sunspecinverter.cpp delete mode 100644 sunspec/sunspecinverter.h diff --git a/sunspec/integrationpluginsunspec.cpp b/sunspec/integrationpluginsunspec.cpp index 7dc7b62..83d5148 100644 --- a/sunspec/integrationpluginsunspec.cpp +++ b/sunspec/integrationpluginsunspec.cpp @@ -36,6 +36,14 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + #include IntegrationPluginSunSpec::IntegrationPluginSunSpec() @@ -150,7 +158,7 @@ void IntegrationPluginSunSpec::discoverThings(ThingDiscoveryInfo *info) } } else { // Generic or not discoverable sunspec connection, show all network results - // - Kostal does not provide usefull information for filterin in the discovery + // - Kostal does not provide any usefull information for filtering in the discovery if (networkDeviceInfo.hostName().isEmpty()) { title += networkDeviceInfo.address().toString(); } else { @@ -264,10 +272,12 @@ void IntegrationPluginSunSpec::postSetupThing(Thing *thing) searchSolarEdgeBatteries(connection); } - } else if (m_sunspecThings.contains(thing)) { - SunSpecThing *sunSpecThing = m_sunspecThings.value(thing); + } else if (m_sunSpecThings.contains(thing)) { + SunSpecThing *sunSpecThing = m_sunSpecThings.value(thing); sunSpecThing->readBlockData(); - } else { + } else if (m_sunSpecInverters.contains(thing)) { + m_sunSpecInverters.value(thing)->readBlockData(); + } else { Q_ASSERT_X(false, "postSetupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); } } @@ -281,11 +291,13 @@ void IntegrationPluginSunSpec::thingRemoved(Thing *thing) if (connection) connection->deleteLater(); - } else if (m_sunspecThings.contains(thing)) { - SunSpecThing *sunSpecThing = m_sunspecThings.take(thing); + } else if (m_sunSpecThings.contains(thing)) { + SunSpecThing *sunSpecThing = m_sunSpecThings.take(thing); if (sunSpecThing) delete sunSpecThing; + } else if (m_sunSpecInverters.contains(thing)) { + m_sunSpecInverters.remove(thing); } else { Q_ASSERT_X(false, "thingRemoved", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); } @@ -303,7 +315,7 @@ void IntegrationPluginSunSpec::executeAction(ThingActionInfo *info) Action action = info->action(); if (thing->thingClassId() == sunspecStorageThingClassId) { - SunSpecStorage *sunSpecStorage = qobject_cast(m_sunspecThings.value(thing)); + SunSpecStorage *sunSpecStorage = qobject_cast(m_sunSpecThings.value(thing)); if (!sunSpecStorage) { qWarning(dcSunSpec()) << "Could not find sunspec instance for thing"; info->finish(Thing::ThingErrorHardwareNotAvailable); @@ -459,8 +471,8 @@ void IntegrationPluginSunSpec::setupConnection(ThingSetupInfo *info) child->setStateValue(m_connectedStateTypeIds.value(child->thingClassId()), connected); // Refresh childs if connected successfully - if (connected && m_sunspecThings.contains(child)) { - m_sunspecThings.value(child)->readBlockData(); + if (connected && m_sunSpecThings.contains(child)) { + m_sunSpecThings.value(child)->readBlockData(); } } }); @@ -505,15 +517,15 @@ void IntegrationPluginSunSpec::setupInverter(ThingSetupInfo *info) int modbusStartRegister = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt(); SunSpecConnection *connection = m_sunSpecConnections.value(thing->parentId()); if (!connection) { - qCWarning(dcSunSpec()) << "Could not find SunSpec connection"; + qCWarning(dcSunSpec()) << "Could not find SunSpec parent connection for" << thing; return info->finish(Thing::ThingErrorHardwareNotAvailable); } // Get the model from the connection foreach (SunSpecModel *model, connection->models()) { if (model->modelId() == modelId && model->modbusStartRegister() == modbusStartRegister) { - SunSpecInverter *inverter = new SunSpecInverter(thing, model, this); - m_sunspecThings.insert(thing, inverter); + connect(model, &SunSpecModel::blockUpdated, this, &IntegrationPluginSunSpec::onInverterBlockUpdated); + m_sunSpecInverters.insert(thing, model); info->finish(Thing::ThingErrorNoError); return; } @@ -527,15 +539,17 @@ void IntegrationPluginSunSpec::setupMeter(ThingSetupInfo *info) int modbusStartRegister = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt(); SunSpecConnection *connection = m_sunSpecConnections.value(thing->parentId()); if (!connection) { - qCWarning(dcSunSpec()) << "Could not find SunSpec connection"; + qCWarning(dcSunSpec()) << "Could not find SunSpec parent connection for" << thing; return info->finish(Thing::ThingErrorHardwareNotAvailable); } // Get the model from the connection foreach (SunSpecModel *model, connection->models()) { if (model->modelId() == modelId && model->modbusStartRegister() == modbusStartRegister) { +// m_sunSpecInverters.insert(thing, model); +// connect(model, &SunSpecModel::blockUpdated, this, &IntegrationPluginSunSpec::onInverterBlockUpdated); SunSpecMeter *meter = new SunSpecMeter(thing, model, this); - m_sunspecThings.insert(thing, meter); + m_sunSpecThings.insert(thing, meter); info->finish(Thing::ThingErrorNoError); return; } @@ -549,7 +563,7 @@ void IntegrationPluginSunSpec::setupStorage(ThingSetupInfo *info) int modbusStartRegister = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt(); SunSpecConnection *connection = m_sunSpecConnections.value(thing->parentId()); if (!connection) { - qCWarning(dcSunSpec()) << "Could not find SunSpec connection"; + qCWarning(dcSunSpec()) << "Could not find SunSpec parent connection for" << thing; return info->finish(Thing::ThingErrorHardwareNotAvailable); } @@ -557,7 +571,7 @@ void IntegrationPluginSunSpec::setupStorage(ThingSetupInfo *info) foreach (SunSpecModel *model, connection->models()) { if (model->modelId() == modelId && model->modbusStartRegister() == modbusStartRegister) { SunSpecStorage *storage = new SunSpecStorage(thing, model, this); - m_sunspecThings.insert(thing, storage); + m_sunSpecThings.insert(thing, storage); info->finish(Thing::ThingErrorNoError); return; } @@ -570,7 +584,7 @@ void IntegrationPluginSunSpec::setupSolarEdgeBattery(ThingSetupInfo *info) int modbusStartRegister = thing->paramValue(solarEdgeBatteryThingModbusAddressParamTypeId).toUInt(); SunSpecConnection *connection = m_sunSpecConnections.value(thing->parentId()); if (!connection) { - qCWarning(dcSunSpec()) << "Could not find SunSpec connection for setting up SolarEdge battery"; + qCWarning(dcSunSpec()) << "Could not find SunSpec parent connection for sunspec battery" << thing; return info->finish(Thing::ThingErrorHardwareNotAvailable); } @@ -582,7 +596,7 @@ void IntegrationPluginSunSpec::setupSolarEdgeBattery(ThingSetupInfo *info) return info->finish(Thing::ThingErrorHardwareFailure); } - m_sunspecThings.insert(thing, battery); + m_sunSpecThings.insert(thing, battery); info->finish(Thing::ThingErrorNoError); }); @@ -699,14 +713,129 @@ void IntegrationPluginSunSpec::autocreateSunSpecModelThing(const ThingClassId &t emit autoThingsAppeared({descriptor}); } +QString IntegrationPluginSunSpec::getInverterStateString(quint16 state) +{ + // Note: this works because the models have all the same value + QString stateString; + switch (state) { + case SunSpecInverterSinglePhaseModel::StOff: + stateString = "Off"; + break; + case SunSpecInverterSinglePhaseModel::StSleeping: + stateString = "Sleeping"; + break; + case SunSpecInverterSinglePhaseModel::StStarting: + stateString = "Starting"; + break; + case SunSpecInverterSinglePhaseModel::StMppt: + stateString = "MPPT"; + break; + case SunSpecInverterSinglePhaseModel::StThrottled: + stateString = "Throttled"; + break; + case SunSpecInverterSinglePhaseModel::StShuttingDown: + stateString = "Shutting down"; + break; + case SunSpecInverterSinglePhaseModel::StFault: + stateString = "Fault"; + break; + case SunSpecInverterSinglePhaseModel::StStandby: + stateString = "Standby"; + break; + } + return stateString; +} + +QString IntegrationPluginSunSpec::getInverterErrorString(quint32 flag) +{ + // Note: this works because the models have all the same value + QStringList errorStrings; + SunSpecInverterSinglePhaseModel::Evt1Flags event1Flag = static_cast(flag); + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1GroundFault)) { + errorStrings.append(QT_TR_NOOP("Ground fault")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1DcOverVolt)) { + errorStrings.append(QT_TR_NOOP("DC over voltage")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1AcDisconnect)) { + errorStrings.append(QT_TR_NOOP("AC disconnect")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1DcDisconnect)) { + errorStrings.append(QT_TR_NOOP("DC disconnect")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1GridDisconnect)) { + errorStrings.append(QT_TR_NOOP("Grid disconnect")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1CabinetOpen)) { + errorStrings.append(QT_TR_NOOP("Cabinet open")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1ManualShutdown)) { + errorStrings.append(QT_TR_NOOP("Manual shutdown")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1OverTemp)) { + errorStrings.append(QT_TR_NOOP("Over temperature")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1OverFrequency)) { + errorStrings.append(QT_TR_NOOP("Over frequency")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1UnderFrequency)) { + errorStrings.append(QT_TR_NOOP("Under frequency")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1AcOverVolt)) { + errorStrings.append(QT_TR_NOOP("AC over voltage")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1AcUnderVolt)) { + errorStrings.append(QT_TR_NOOP("AC under voltage")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1BlownStringFuse)) { + errorStrings.append(QT_TR_NOOP("Blown string fuse")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1UnderTemp)) { + errorStrings.append(QT_TR_NOOP("Under temperature")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1MemoryLoss)) { + errorStrings.append(QT_TR_NOOP("Memory loss")); + } + + if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1HwTestFailure)) { + errorStrings.append(QT_TR_NOOP("Hardware test failure")); + } + + if (errorStrings.isEmpty()) { + return QT_TR_NOOP("No error"); + } else { + return errorStrings.join(", "); + } + +} + void IntegrationPluginSunSpec::onRefreshTimer() { // Update all sunspec thing blocks - foreach (SunSpecThing *sunSpecThing, m_sunspecThings) { + foreach (SunSpecThing *sunSpecThing, m_sunSpecThings) { if (sunSpecThing->connection()->connected()) { sunSpecThing->readBlockData(); } } + + // Update inverters + foreach (SunSpecModel *model, m_sunSpecInverters.values()) { + model->readBlockData(); + } } void IntegrationPluginSunSpec::onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value) @@ -733,3 +862,138 @@ void IntegrationPluginSunSpec::onPluginConfigurationChanged(const ParamTypeId &p qCWarning(dcSunSpec()) << "Unknown plugin configuration" << paramTypeId << "Value" << value; } } + +void IntegrationPluginSunSpec::onInverterBlockUpdated() +{ + SunSpecModel *model = qobject_cast(sender()); + Thing *thing = m_sunSpecInverters.key(model); + if (!thing) return; + + switch (model->modelId()) { + case SunSpecModelFactory::ModelIdInverterSinglePhase: { + SunSpecInverterSinglePhaseModel *inverter = qobject_cast(model); + qCDebug(dcSunSpec()) << thing->name() << "block data updated" << inverter; + thing->setStateValue(sunspecSinglePhaseInverterConnectedStateTypeId, true); + thing->setStateValue(sunspecSinglePhaseInverterVersionStateTypeId, model->commonModelInfo().versionString); + + thing->setStateValue(sunspecSinglePhaseInverterTotalCurrentStateTypeId, inverter->amps()); + thing->setStateValue(sunspecSinglePhaseInverterCurrentPowerStateTypeId, inverter->watts()); + thing->setStateValue(sunspecSinglePhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); + thing->setStateValue(sunspecSinglePhaseInverterFrequencyStateTypeId, inverter->hz()); + thing->setStateValue(sunspecSinglePhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); + thing->setStateValue(sunspecSinglePhaseInverterPhaseVoltageStateTypeId, inverter->phaseVoltageAn()); + thing->setStateValue(sunspecSinglePhaseInverterOperatingStateStateTypeId, getInverterStateString(inverter->operatingState())); + thing->setStateValue(sunspecSinglePhaseInverterErrorStateTypeId, getInverterErrorString(inverter->event1())); + break; + } + case SunSpecModelFactory::ModelIdInverterSinglePhaseFloat: { + SunSpecInverterSinglePhaseFloatModel *inverter = qobject_cast(model); + qCDebug(dcSunSpec()) << thing->name() << "block data updated" << inverter; + thing->setStateValue(sunspecSinglePhaseInverterConnectedStateTypeId, true); + thing->setStateValue(sunspecSinglePhaseInverterVersionStateTypeId, model->commonModelInfo().versionString); + + thing->setStateValue(sunspecSinglePhaseInverterTotalCurrentStateTypeId, inverter->amps()); + thing->setStateValue(sunspecSinglePhaseInverterCurrentPowerStateTypeId, inverter->watts()); + thing->setStateValue(sunspecSinglePhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); + thing->setStateValue(sunspecSinglePhaseInverterFrequencyStateTypeId, inverter->hz()); + thing->setStateValue(sunspecSinglePhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); + thing->setStateValue(sunspecSinglePhaseInverterPhaseVoltageStateTypeId, inverter->phaseVoltageAn()); + thing->setStateValue(sunspecSinglePhaseInverterOperatingStateStateTypeId, getInverterStateString(inverter->operatingState())); + thing->setStateValue(sunspecSinglePhaseInverterErrorStateTypeId, getInverterErrorString(inverter->event1())); + break; + } + case SunSpecModelFactory::ModelIdInverterSplitPhase: { + SunSpecInverterSplitPhaseModel *inverter = qobject_cast(model); + qCDebug(dcSunSpec()) << thing->name() << "block data updated" << inverter; + thing->setStateValue(sunspecSplitPhaseInverterConnectedStateTypeId, true); + thing->setStateValue(sunspecSplitPhaseInverterVersionStateTypeId, model->commonModelInfo().versionString); + + thing->setStateValue(sunspecSplitPhaseInverterTotalCurrentStateTypeId, inverter->amps()); + thing->setStateValue(sunspecSplitPhaseInverterCurrentPowerStateTypeId, inverter->watts()); + thing->setStateValue(sunspecSplitPhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); + thing->setStateValue(sunspecSplitPhaseInverterFrequencyStateTypeId, inverter->hz()); + thing->setStateValue(sunspecSplitPhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); + thing->setStateValue(sunspecSplitPhaseInverterPhaseANVoltageStateTypeId, inverter->phaseVoltageAn()); + thing->setStateValue(sunspecSplitPhaseInverterPhaseBNVoltageStateTypeId, inverter->phaseVoltageBn()); + thing->setStateValue(sunspecSplitPhaseInverterPhaseACurrentStateTypeId, inverter->ampsPhaseA()); + thing->setStateValue(sunspecSplitPhaseInverterPhaseBCurrentStateTypeId, inverter->ampsPhaseB()); + thing->setStateValue(sunspecSplitPhaseInverterOperatingStateStateTypeId, getInverterStateString(inverter->operatingState())); + thing->setStateValue(sunspecSplitPhaseInverterErrorStateTypeId, getInverterErrorString(inverter->event1())); + break; + } + case SunSpecModelFactory::ModelIdInverterSplitPhaseFloat: { + SunSpecInverterSplitPhaseFloatModel *inverter = qobject_cast(model); + qCDebug(dcSunSpec()) << thing->name() << "block data updated" << inverter; + thing->setStateValue(sunspecSplitPhaseInverterConnectedStateTypeId, true); + thing->setStateValue(sunspecSplitPhaseInverterVersionStateTypeId, model->commonModelInfo().versionString); + + thing->setStateValue(sunspecSplitPhaseInverterTotalCurrentStateTypeId, inverter->amps()); + thing->setStateValue(sunspecSplitPhaseInverterCurrentPowerStateTypeId, inverter->watts()); + thing->setStateValue(sunspecSplitPhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); + thing->setStateValue(sunspecSplitPhaseInverterFrequencyStateTypeId, inverter->hz()); + thing->setStateValue(sunspecSplitPhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); + thing->setStateValue(sunspecSplitPhaseInverterPhaseANVoltageStateTypeId, inverter->phaseVoltageAn()); + thing->setStateValue(sunspecSplitPhaseInverterPhaseBNVoltageStateTypeId, inverter->phaseVoltageBn()); + thing->setStateValue(sunspecSplitPhaseInverterPhaseACurrentStateTypeId, inverter->ampsPhaseA()); + thing->setStateValue(sunspecSplitPhaseInverterPhaseBCurrentStateTypeId, inverter->ampsPhaseB()); + thing->setStateValue(sunspecSplitPhaseInverterOperatingStateStateTypeId, getInverterStateString(inverter->operatingState())); + thing->setStateValue(sunspecSplitPhaseInverterErrorStateTypeId, getInverterErrorString(inverter->event1())); + break; + } + case SunSpecModelFactory::ModelIdInverterThreePhase: { + SunSpecInverterThreePhaseModel *inverter = qobject_cast(model); + qCDebug(dcSunSpec()) << thing->name() << "block data updated" << inverter; + thing->setStateValue(sunspecThreePhaseInverterConnectedStateTypeId, true); + thing->setStateValue(sunspecThreePhaseInverterVersionStateTypeId, model->commonModelInfo().versionString); + + thing->setStateValue(sunspecThreePhaseInverterTotalCurrentStateTypeId, inverter->amps()); + thing->setStateValue(sunspecThreePhaseInverterCurrentPowerStateTypeId, inverter->watts()); + thing->setStateValue(sunspecThreePhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); + thing->setStateValue(sunspecThreePhaseInverterFrequencyStateTypeId, inverter->hz()); + thing->setStateValue(sunspecThreePhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); + thing->setStateValue(sunspecThreePhaseInverterPhaseANVoltageStateTypeId, inverter->phaseVoltageAn()); + thing->setStateValue(sunspecThreePhaseInverterPhaseBNVoltageStateTypeId, inverter->phaseVoltageBn()); + thing->setStateValue(sunspecThreePhaseInverterPhaseCNVoltageStateTypeId, inverter->phaseVoltageCn()); + thing->setStateValue(sunspecThreePhaseInverterPhaseACurrentStateTypeId, inverter->ampsPhaseA()); + thing->setStateValue(sunspecThreePhaseInverterPhaseBCurrentStateTypeId, inverter->ampsPhaseB()); + thing->setStateValue(sunspecThreePhaseInverterPhaseCCurrentStateTypeId, inverter->ampsPhaseC()); + thing->setStateValue(sunspecThreePhaseInverterOperatingStateStateTypeId, getInverterStateString(inverter->operatingState())); + thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, getInverterErrorString(inverter->event1())); + break; + } + case SunSpecModelFactory::ModelIdInverterThreePhaseFloat: { + SunSpecInverterThreePhaseFloatModel *inverter = qobject_cast(model); + qCDebug(dcSunSpec()) << thing->name() << "block data updated" << inverter; + thing->setStateValue(sunspecThreePhaseInverterConnectedStateTypeId, true); + thing->setStateValue(sunspecThreePhaseInverterVersionStateTypeId, model->commonModelInfo().versionString); + + thing->setStateValue(sunspecThreePhaseInverterTotalCurrentStateTypeId, inverter->amps()); + thing->setStateValue(sunspecThreePhaseInverterCurrentPowerStateTypeId, inverter->watts()); + thing->setStateValue(sunspecThreePhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); + thing->setStateValue(sunspecThreePhaseInverterFrequencyStateTypeId, inverter->hz()); + thing->setStateValue(sunspecThreePhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); + thing->setStateValue(sunspecThreePhaseInverterPhaseANVoltageStateTypeId, inverter->phaseVoltageAn()); + thing->setStateValue(sunspecThreePhaseInverterPhaseBNVoltageStateTypeId, inverter->phaseVoltageBn()); + thing->setStateValue(sunspecThreePhaseInverterPhaseCNVoltageStateTypeId, inverter->phaseVoltageCn()); + thing->setStateValue(sunspecThreePhaseInverterPhaseACurrentStateTypeId, inverter->ampsPhaseA()); + thing->setStateValue(sunspecThreePhaseInverterPhaseBCurrentStateTypeId, inverter->ampsPhaseB()); + thing->setStateValue(sunspecThreePhaseInverterPhaseCCurrentStateTypeId, inverter->ampsPhaseC()); + thing->setStateValue(sunspecThreePhaseInverterOperatingStateStateTypeId, getInverterStateString(inverter->operatingState())); + thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, getInverterErrorString(inverter->event1())); + break; + } + default: + qCWarning(dcSunSpec()) << "Received block data from unhandled model" << model; + break; + } +} + +void IntegrationPluginSunSpec::onMeterBlockUpdated() +{ + +} + +void IntegrationPluginSunSpec::onStorageBlockUpdated() +{ + +} diff --git a/sunspec/integrationpluginsunspec.h b/sunspec/integrationpluginsunspec.h index d2228fe..c6dfe68 100644 --- a/sunspec/integrationpluginsunspec.h +++ b/sunspec/integrationpluginsunspec.h @@ -37,7 +37,6 @@ #include #include -#include "sunspecinverter.h" #include "sunspecstorage.h" #include "sunspecmeter.h" @@ -80,7 +79,9 @@ private: PluginTimer *m_refreshTimer = nullptr; QHash m_sunSpecConnections; - QHash m_sunspecThings; + QHash m_sunSpecThings; + + QHash m_sunSpecInverters; bool sunspecThingAlreadyAdded(uint modelId, uint modbusAddress, const ThingId &parentId); void processDiscoveryResult(Thing *thing, SunSpecConnection *connection); @@ -101,10 +102,17 @@ private: void autocreateSunSpecModelThing(const ThingClassId &thingClassId, const QString &thingName, const ThingId &parentId, SunSpecModel *model); + QString getInverterStateString(quint16 state); + QString getInverterErrorString(quint32 flag); + private slots: void onRefreshTimer(); void onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value); + void onInverterBlockUpdated(); + void onMeterBlockUpdated(); + void onStorageBlockUpdated(); + }; #endif // INTEGRATIONPLUGINSUNSPEC_H diff --git a/sunspec/sunspec.pro b/sunspec/sunspec.pro index 1bcaa6a..7fd490d 100644 --- a/sunspec/sunspec.pro +++ b/sunspec/sunspec.pro @@ -4,7 +4,6 @@ include(../sunspec.pri) SOURCES += \ integrationpluginsunspec.cpp \ solaredgebattery.cpp \ - sunspecinverter.cpp \ sunspecmeter.cpp \ sunspecstorage.cpp \ sunspecthing.cpp @@ -12,7 +11,6 @@ SOURCES += \ HEADERS += \ integrationpluginsunspec.h \ solaredgebattery.h \ - sunspecinverter.h \ sunspecmeter.h \ sunspecstorage.h \ sunspecthing.h diff --git a/sunspec/sunspecinverter.cpp b/sunspec/sunspecinverter.cpp deleted file mode 100644 index 53f386f..0000000 --- a/sunspec/sunspecinverter.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "sunspecinverter.h" - -#include -#include -#include -#include -#include -#include -#include - -SunSpecInverter::SunSpecInverter(Thing *thing, SunSpecModel *model, QObject *parent) : - SunSpecThing(thing, model, parent) -{ - connect(m_model, &SunSpecModel::blockUpdated, this, &SunSpecInverter::onBlockDataUpdated); -} - -void SunSpecInverter::readBlockData() -{ - m_model->readBlockData(); -} - -void SunSpecInverter::onBlockDataUpdated() -{ - switch (m_model->modelId()) { - case SunSpecModelFactory::ModelIdInverterSinglePhase: { - SunSpecInverterSinglePhaseModel *inverter = qobject_cast(m_model); - qCDebug(dcSunSpec()) << m_thing->name() << "block data updated" << inverter; - m_thing->setStateValue(sunspecSinglePhaseInverterConnectedStateTypeId, true); - m_thing->setStateValue(sunspecSinglePhaseInverterVersionStateTypeId, m_model->commonModelInfo().versionString); - - m_thing->setStateValue(sunspecSinglePhaseInverterTotalCurrentStateTypeId, inverter->amps()); - m_thing->setStateValue(sunspecSinglePhaseInverterCurrentPowerStateTypeId, inverter->watts()); - m_thing->setStateValue(sunspecSinglePhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); - m_thing->setStateValue(sunspecSinglePhaseInverterFrequencyStateTypeId, inverter->hz()); - m_thing->setStateValue(sunspecSinglePhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); - m_thing->setStateValue(sunspecSinglePhaseInverterPhaseVoltageStateTypeId, inverter->phaseVoltageAn()); - m_thing->setStateValue(sunspecSinglePhaseInverterOperatingStateStateTypeId, getStateString(inverter->operatingState())); - m_thing->setStateValue(sunspecSinglePhaseInverterErrorStateTypeId, getErrorString(inverter->event1())); - break; - } - case SunSpecModelFactory::ModelIdInverterSinglePhaseFloat: { - SunSpecInverterSinglePhaseFloatModel *inverter = qobject_cast(m_model); - qCDebug(dcSunSpec()) << m_thing->name() << "block data updated" << inverter; - m_thing->setStateValue(sunspecSinglePhaseInverterConnectedStateTypeId, true); - m_thing->setStateValue(sunspecSinglePhaseInverterVersionStateTypeId, m_model->commonModelInfo().versionString); - - m_thing->setStateValue(sunspecSinglePhaseInverterTotalCurrentStateTypeId, inverter->amps()); - m_thing->setStateValue(sunspecSinglePhaseInverterCurrentPowerStateTypeId, inverter->watts()); - m_thing->setStateValue(sunspecSinglePhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); - m_thing->setStateValue(sunspecSinglePhaseInverterFrequencyStateTypeId, inverter->hz()); - m_thing->setStateValue(sunspecSinglePhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); - m_thing->setStateValue(sunspecSinglePhaseInverterPhaseVoltageStateTypeId, inverter->phaseVoltageAn()); - m_thing->setStateValue(sunspecSinglePhaseInverterOperatingStateStateTypeId, getStateString(inverter->operatingState())); - m_thing->setStateValue(sunspecSinglePhaseInverterErrorStateTypeId, getErrorString(inverter->event1())); - break; - } - case SunSpecModelFactory::ModelIdInverterSplitPhase: { - SunSpecInverterSplitPhaseModel *inverter = qobject_cast(m_model); - qCDebug(dcSunSpec()) << m_thing->name() << "block data updated" << inverter; - m_thing->setStateValue(sunspecSplitPhaseInverterConnectedStateTypeId, true); - m_thing->setStateValue(sunspecSplitPhaseInverterVersionStateTypeId, m_model->commonModelInfo().versionString); - - m_thing->setStateValue(sunspecSplitPhaseInverterTotalCurrentStateTypeId, inverter->amps()); - m_thing->setStateValue(sunspecSplitPhaseInverterCurrentPowerStateTypeId, inverter->watts()); - m_thing->setStateValue(sunspecSplitPhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); - m_thing->setStateValue(sunspecSplitPhaseInverterFrequencyStateTypeId, inverter->hz()); - m_thing->setStateValue(sunspecSplitPhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); - m_thing->setStateValue(sunspecSplitPhaseInverterPhaseANVoltageStateTypeId, inverter->phaseVoltageAn()); - m_thing->setStateValue(sunspecSplitPhaseInverterPhaseBNVoltageStateTypeId, inverter->phaseVoltageBn()); - m_thing->setStateValue(sunspecSplitPhaseInverterPhaseACurrentStateTypeId, inverter->ampsPhaseA()); - m_thing->setStateValue(sunspecSplitPhaseInverterPhaseBCurrentStateTypeId, inverter->ampsPhaseB()); - m_thing->setStateValue(sunspecSplitPhaseInverterOperatingStateStateTypeId, getStateString(inverter->operatingState())); - m_thing->setStateValue(sunspecSplitPhaseInverterErrorStateTypeId, getErrorString(inverter->event1())); - break; - } - case SunSpecModelFactory::ModelIdInverterSplitPhaseFloat: { - SunSpecInverterSplitPhaseFloatModel *inverter = qobject_cast(m_model); - qCDebug(dcSunSpec()) << m_thing->name() << "block data updated" << inverter; - m_thing->setStateValue(sunspecSplitPhaseInverterConnectedStateTypeId, true); - m_thing->setStateValue(sunspecSplitPhaseInverterVersionStateTypeId, m_model->commonModelInfo().versionString); - - m_thing->setStateValue(sunspecSplitPhaseInverterTotalCurrentStateTypeId, inverter->amps()); - m_thing->setStateValue(sunspecSplitPhaseInverterCurrentPowerStateTypeId, inverter->watts()); - m_thing->setStateValue(sunspecSplitPhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); - m_thing->setStateValue(sunspecSplitPhaseInverterFrequencyStateTypeId, inverter->hz()); - m_thing->setStateValue(sunspecSplitPhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); - m_thing->setStateValue(sunspecSplitPhaseInverterPhaseANVoltageStateTypeId, inverter->phaseVoltageAn()); - m_thing->setStateValue(sunspecSplitPhaseInverterPhaseBNVoltageStateTypeId, inverter->phaseVoltageBn()); - m_thing->setStateValue(sunspecSplitPhaseInverterPhaseACurrentStateTypeId, inverter->ampsPhaseA()); - m_thing->setStateValue(sunspecSplitPhaseInverterPhaseBCurrentStateTypeId, inverter->ampsPhaseB()); - m_thing->setStateValue(sunspecSplitPhaseInverterOperatingStateStateTypeId, getStateString(inverter->operatingState())); - m_thing->setStateValue(sunspecSplitPhaseInverterErrorStateTypeId, getErrorString(inverter->event1())); - break; - } - case SunSpecModelFactory::ModelIdInverterThreePhase: { - SunSpecInverterThreePhaseModel *inverter = qobject_cast(m_model); - qCDebug(dcSunSpec()) << m_thing->name() << "block data updated" << inverter; - m_thing->setStateValue(sunspecThreePhaseInverterConnectedStateTypeId, true); - m_thing->setStateValue(sunspecThreePhaseInverterVersionStateTypeId, m_model->commonModelInfo().versionString); - - m_thing->setStateValue(sunspecThreePhaseInverterTotalCurrentStateTypeId, inverter->amps()); - m_thing->setStateValue(sunspecThreePhaseInverterCurrentPowerStateTypeId, inverter->watts()); - m_thing->setStateValue(sunspecThreePhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); - m_thing->setStateValue(sunspecThreePhaseInverterFrequencyStateTypeId, inverter->hz()); - m_thing->setStateValue(sunspecThreePhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseANVoltageStateTypeId, inverter->phaseVoltageAn()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseBNVoltageStateTypeId, inverter->phaseVoltageBn()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseCNVoltageStateTypeId, inverter->phaseVoltageCn()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseACurrentStateTypeId, inverter->ampsPhaseA()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseBCurrentStateTypeId, inverter->ampsPhaseB()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseCCurrentStateTypeId, inverter->ampsPhaseC()); - m_thing->setStateValue(sunspecThreePhaseInverterOperatingStateStateTypeId, getStateString(inverter->operatingState())); - m_thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, getErrorString(inverter->event1())); - break; - } - case SunSpecModelFactory::ModelIdInverterThreePhaseFloat: { - SunSpecInverterThreePhaseFloatModel *inverter = qobject_cast(m_model); - qCDebug(dcSunSpec()) << m_thing->name() << "block data updated" << inverter; - m_thing->setStateValue(sunspecThreePhaseInverterConnectedStateTypeId, true); - m_thing->setStateValue(sunspecThreePhaseInverterVersionStateTypeId, m_model->commonModelInfo().versionString); - - m_thing->setStateValue(sunspecThreePhaseInverterTotalCurrentStateTypeId, inverter->amps()); - m_thing->setStateValue(sunspecThreePhaseInverterCurrentPowerStateTypeId, inverter->watts()); - m_thing->setStateValue(sunspecThreePhaseInverterTotalEnergyProducedStateTypeId, inverter->wattHours() / 1000.0); - m_thing->setStateValue(sunspecThreePhaseInverterFrequencyStateTypeId, inverter->hz()); - m_thing->setStateValue(sunspecThreePhaseInverterCabinetTemperatureStateTypeId, inverter->cabinetTemperature()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseANVoltageStateTypeId, inverter->phaseVoltageAn()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseBNVoltageStateTypeId, inverter->phaseVoltageBn()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseCNVoltageStateTypeId, inverter->phaseVoltageCn()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseACurrentStateTypeId, inverter->ampsPhaseA()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseBCurrentStateTypeId, inverter->ampsPhaseB()); - m_thing->setStateValue(sunspecThreePhaseInverterPhaseCCurrentStateTypeId, inverter->ampsPhaseC()); - m_thing->setStateValue(sunspecThreePhaseInverterOperatingStateStateTypeId, getStateString(inverter->operatingState())); - m_thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, getErrorString(inverter->event1())); - break; - } - default: - qCWarning(dcSunSpec()) << "Received block data from unhandled model" << m_model; - break; - } -} - -QString SunSpecInverter::getStateString(quint16 state) -{ - // Note: this works because the models have all the same value - QString stateString; - switch (state) { - case SunSpecInverterSinglePhaseModel::StOff: - stateString = "Off"; - break; - case SunSpecInverterSinglePhaseModel::StSleeping: - stateString = "Sleeping"; - break; - case SunSpecInverterSinglePhaseModel::StStarting: - stateString = "Starting"; - break; - case SunSpecInverterSinglePhaseModel::StMppt: - stateString = "MPPT"; - break; - case SunSpecInverterSinglePhaseModel::StThrottled: - stateString = "Throttled"; - break; - case SunSpecInverterSinglePhaseModel::StShuttingDown: - stateString = "Shutting down"; - break; - case SunSpecInverterSinglePhaseModel::StFault: - stateString = "Fault"; - break; - case SunSpecInverterSinglePhaseModel::StStandby: - stateString = "Standby"; - break; - } - return stateString; -} - -QString SunSpecInverter::getErrorString(quint32 flag) -{ - // Note: this works because the models have all the same value - QStringList errorStrings; - SunSpecInverterSinglePhaseModel::Evt1Flags event1Flag = static_cast(flag); - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1GroundFault)) { - errorStrings.append(QT_TR_NOOP("Ground fault")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1DcOverVolt)) { - errorStrings.append(QT_TR_NOOP("DC over voltage")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1AcDisconnect)) { - errorStrings.append(QT_TR_NOOP("AC disconnect")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1DcDisconnect)) { - errorStrings.append(QT_TR_NOOP("DC disconnect")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1GridDisconnect)) { - errorStrings.append(QT_TR_NOOP("Grid disconnect")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1CabinetOpen)) { - errorStrings.append(QT_TR_NOOP("Cabinet open")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1ManualShutdown)) { - errorStrings.append(QT_TR_NOOP("Manual shutdown")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1OverTemp)) { - errorStrings.append(QT_TR_NOOP("Over temperature")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1OverFrequency)) { - errorStrings.append(QT_TR_NOOP("Over frequency")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1UnderFrequency)) { - errorStrings.append(QT_TR_NOOP("Under frequency")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1AcOverVolt)) { - errorStrings.append(QT_TR_NOOP("AC over voltage")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1AcUnderVolt)) { - errorStrings.append(QT_TR_NOOP("AC under voltage")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1BlownStringFuse)) { - errorStrings.append(QT_TR_NOOP("Blown string fuse")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1UnderTemp)) { - errorStrings.append(QT_TR_NOOP("Under temperature")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1MemoryLoss)) { - errorStrings.append(QT_TR_NOOP("Memory loss")); - } - - if (event1Flag.testFlag(SunSpecInverterSinglePhaseModel::Evt1HwTestFailure)) { - errorStrings.append(QT_TR_NOOP("Hardware test failure")); - } - - if (errorStrings.isEmpty()) { - return QT_TR_NOOP("No error"); - } else { - return errorStrings.join(", "); - } - -} diff --git a/sunspec/sunspecinverter.h b/sunspec/sunspecinverter.h deleted file mode 100644 index 7866a24..0000000 --- a/sunspec/sunspecinverter.h +++ /dev/null @@ -1,55 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2021, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU Lesser General Public License Usage -* Alternatively, this project may be redistributed and/or modified under the -* terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 3. This project is distributed in the hope that -* it will be useful, but WITHOUT ANY WARRANTY; without even the implied -* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this project. If not, see . -* -* For any further details and any questions please contact us under -* contact@nymea.io or see our FAQ/Licensing Information on -* https://nymea.io/license/faq -* -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef SUNSPECINVERTER_H -#define SUNSPECINVERTER_H - -#include - -#include "sunspecthing.h" - -class SunSpecInverter : public SunSpecThing -{ - Q_OBJECT -public: - explicit SunSpecInverter(Thing *thing, SunSpecModel *model, QObject *parent = nullptr); - ~SunSpecInverter() override = default; - - void readBlockData() override; - -private slots: - void onBlockDataUpdated() override; - -private: - QString getStateString(quint16 state); - QString getErrorString(quint32 flag); -}; - -#endif // SUNSPECINVERTER_H