diff --git a/sunspec/integrationpluginsunspec.cpp b/sunspec/integrationpluginsunspec.cpp index 2ef9d3d..5c50122 100644 --- a/sunspec/integrationpluginsunspec.cpp +++ b/sunspec/integrationpluginsunspec.cpp @@ -1616,12 +1616,17 @@ void IntegrationPluginSunSpec::onStorageBlockUpdated() thing->setStateValue(sunspecStorageConnectedStateTypeId, true); thing->setStateValue(sunspecStorageVersionStateTypeId, model->commonModelInfo().versionString); - thing->setStateValue(sunspecStorageBatteryCriticalStateTypeId, storage->chaState() < 5); - thing->setStateValue(sunspecStorageBatteryLevelStateTypeId, qRound(storage->chaState())); - thing->setStateValue(sunspecStorageGridChargingStateTypeId, storage->chaGriSet() == SunSpecStorageModel::ChagrisetGrid); - thing->setStateValue(sunspecStorageEnableChargingStateTypeId, storage->storCtlMod().testFlag(SunSpecStorageModel::Storctl_modCharge)); - thing->setStateValue(sunspecStorageChargingRateStateTypeId, storage->wChaGra()); - thing->setStateValue(sunspecStorageDischargingRateStateTypeId, storage->wDisChaGra()); + const SunSpecStorageLogic::StorageStates states = SunSpecStorageLogic::readStates(storage); + + thing->setStateValue(sunspecStorageBatteryCriticalStateTypeId, states.batteryCritical); + thing->setStateValue(sunspecStorageBatteryLevelStateTypeId, states.batteryLevel); + thing->setStateValue(sunspecStorageGridChargingStateTypeId, states.gridCharging); + thing->setStateValue(sunspecStorageEnableChargingStateTypeId, states.enableCharging); + thing->setStateValue(sunspecStorageEnableDischargingStateTypeId, states.enableDischarging); + thing->setStateValue(sunspecStorageChargingRateStateTypeId, states.chargingRate); + thing->setStateValue(sunspecStorageDischargingRateStateTypeId, states.dischargingRate); + thing->setStateValue(sunspecStorageChargeGradientStateTypeId, states.chargeGradient); + thing->setStateValue(sunspecStorageDischargeGradientStateTypeId, states.dischargeGradient); switch (storage->chaSt()) { case SunSpecStorageModel::ChastOff: diff --git a/sunspec/integrationpluginsunspec.h b/sunspec/integrationpluginsunspec.h index d6a09b4..72ffc36 100644 --- a/sunspec/integrationpluginsunspec.h +++ b/sunspec/integrationpluginsunspec.h @@ -33,6 +33,7 @@ #include #include "sunspecthing.h" +#include "sunspecstoragelogic.h" #include "extern-plugininfo.h" #include diff --git a/sunspec/integrationpluginsunspec.json b/sunspec/integrationpluginsunspec.json index 6c0951c..81bf635 100644 --- a/sunspec/integrationpluginsunspec.json +++ b/sunspec/integrationpluginsunspec.json @@ -1462,6 +1462,24 @@ "writable": true, "displayNameAction": "Set discharging rate" }, + { + "id": "47035ac0-d054-491a-969d-b2aaa9168b0a", + "name": "chargeGradient", + "displayName": "Charging gradient", + "displayNameEvent": "Charging gradient changed", + "type": "double", + "unit": "Percentage", + "defaultValue": 0 + }, + { + "id": "ad00480a-54a3-498a-b937-f9943a98d453", + "name": "dischargeGradient", + "displayName": "Discharging gradient", + "displayNameEvent": "Discharging gradient changed", + "type": "double", + "unit": "Percentage", + "defaultValue": 0 + }, { "id": "fca0c151-d8fa-4d6e-a5d7-b3bc965abc09", "name": "version", diff --git a/sunspec/sunspec.pro b/sunspec/sunspec.pro index df3837a..6496657 100644 --- a/sunspec/sunspec.pro +++ b/sunspec/sunspec.pro @@ -5,10 +5,12 @@ SOURCES += \ integrationpluginsunspec.cpp \ solaredgebattery.cpp \ sunspecdiscovery.cpp \ + sunspecstoragelogic.cpp \ sunspecthing.cpp HEADERS += \ integrationpluginsunspec.h \ solaredgebattery.h \ sunspecdiscovery.h \ + sunspecstoragelogic.h \ sunspecthing.h diff --git a/sunspec/sunspecstoragelogic.cpp b/sunspec/sunspecstoragelogic.cpp new file mode 100644 index 0000000..c2b15d9 --- /dev/null +++ b/sunspec/sunspecstoragelogic.cpp @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright (C) 2013 - 2024, nymea GmbH +* Copyright (C) 2024 - 2025, chargebyte austria GmbH +* +* This file is part of nymea. +* +* nymea is free software: you can redistribute it and/or modify it under the +* terms of the GNU General Public License as published by the Free Software +* Foundation, either version 3 of the License, or (at your option) any later +* version. +* +* nymea 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with +* nymea. If not, see . +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "sunspecstoragelogic.h" + +#include + +namespace SunSpecStorageLogic { + +StorageStates readStates(SunSpecStorageModel *storage) +{ + StorageStates states; + if (!storage) + return states; + + /* InWRte / OutWRte are what the chargingRate / dischargingRate actions + * write. Reading the gradients here instead would mean the user writes one + * quantity and reads back another. */ + states.chargingRate = storage->inWRte(); + states.dischargingRate = storage->outWRte(); + + /* The gradients stay available, under names that cannot be mistaken for the + * setpoints above. */ + states.chargeGradient = storage->wChaGra(); + states.dischargeGradient = storage->wDisChaGra(); + + const SunSpecStorageModel::Storctl_modFlags controlMode = storage->storCtlMod(); + states.enableCharging = controlMode.testFlag(SunSpecStorageModel::Storctl_modCharge); + states.enableDischarging = controlMode.testFlag(SunSpecStorageModel::Storctl_modDiScharge); + + states.gridCharging = (storage->chaGriSet() == SunSpecStorageModel::ChagrisetGrid); + + states.batteryLevel = qRound(storage->chaState()); + states.batteryCritical = storage->chaState() < 5; + + return states; +} + +} diff --git a/sunspec/sunspecstoragelogic.h b/sunspec/sunspecstoragelogic.h new file mode 100644 index 0000000..815c79c --- /dev/null +++ b/sunspec/sunspecstoragelogic.h @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright (C) 2013 - 2024, nymea GmbH +* Copyright (C) 2024 - 2025, chargebyte austria GmbH +* +* This file is part of nymea. +* +* nymea is free software: you can redistribute it and/or modify it under the +* terms of the GNU General Public License as published by the Free Software +* Foundation, either version 3 of the License, or (at your option) any later +* version. +* +* nymea 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with +* nymea. If not, see . +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef SUNSPECSTORAGELOGIC_H +#define SUNSPECSTORAGELOGIC_H + +#include + +#include + +/* Decision logic of the storage (model 124) handling, kept free of the + * integration framework so it can be exercised without a running nymea. + * + * readStates() maps a storage block update onto the state values the plugin + * publishes. Having it in one place is what makes it possible to check that a + * state is fed from the very register the matching action writes to. + */ +namespace SunSpecStorageLogic { + +struct StorageStates { + /* Percent of WChaMax, from InWRte / OutWRte - the very registers the + * chargingRate / dischargingRate actions write to. */ + double chargingRate = 0; + double dischargingRate = 0; + + /* Percent of WChaMax per second, from WChaGra / WDisChaGra. A different + * quantity from the two above, and read only on several inverters. */ + double chargeGradient = 0; + double dischargeGradient = 0; + + /* Both flags are reconciled from StorCtl_Mod. Reconciling only one lets the + * other drift silently as soon as the inverter changes it on its own. */ + bool enableCharging = false; + bool enableDischarging = false; + + bool gridCharging = false; + + int batteryLevel = 0; + bool batteryCritical = false; +}; + +/* Value range of the InWRte / OutWRte setpoints of model 124. */ +const double MinimumRatePercent = -100.0; +const double MaximumRatePercent = 100.0; + +StorageStates readStates(SunSpecStorageModel *storage); + +} + +#endif // SUNSPECSTORAGELOGIC_H