Sn0w3y
February 8, 2024, 1:31pm
1
Hallo zusammen,
ich habe ein eigenes Modul für eine alte Samsung Batterie geschrieben.
Nun ist mir nach längerer Laufzeit aufgefallen, dass in der Historie keine Werte der Batterie angezeigt werden…
Below is the Code:
package io.openems.edge.ess.samsung.ess;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.osgi.service.event.propertytypes.EventTopics;
import org.osgi.service.metatype.annotations.Designate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.edge.common.component.AbstractOpenemsComponent;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.event.EdgeEventConstants;
import io.openems.edge.common.sum.GridMode;
import io.openems.edge.io.ess.samsung.common.SamsungApi;
import io.openems.edge.timedata.api.Timedata;
import io.openems.edge.timedata.api.TimedataProvider;
import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower;
import io.openems.edge.ess.api.SymmetricEss;
import io.openems.edge.ess.dccharger.api.EssDcCharger;
import io.openems.edge.ess.api.HybridEss;
@Designate(ocd = Config.class, factory = true)
@Component(//
name = "Ess.Samsung", immediate = true, //
configurationPolicy = ConfigurationPolicy.REQUIRE//
)
@EventTopics({ //
EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, //
EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE //
})
public class SamsungEssImpl extends AbstractOpenemsComponent
implements SamsungEss, SymmetricEss, OpenemsComponent, EventHandler, TimedataProvider, HybridEss{
private final CalculateEnergyFromPower calculateAcChargeEnergy = new CalculateEnergyFromPower(this,
SymmetricEss.ChannelId.ACTIVE_CHARGE_ENERGY);
private final CalculateEnergyFromPower calculateAcDischargeEnergy = new CalculateEnergyFromPower(this,
SymmetricEss.ChannelId.ACTIVE_DISCHARGE_ENERGY);
@Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL)
private volatile Timedata timedata = null;
private final Logger log = LoggerFactory.getLogger(SamsungEssImpl.class);
private SamsungApi samsungApi = null;
public SamsungEssImpl() {
super(//
OpenemsComponent.ChannelId.values(), //
SymmetricEss.ChannelId.values(), //
SamsungEss.ChannelId.values(),
EssDcCharger.ChannelId.values(),
HybridEss.ChannelId.values()
//
);
}
@Activate
private void activate(ComponentContext context, Config config) {
super.activate(context, config.id(), config.alias(), config.enabled());
this.samsungApi = new SamsungApi(config.ip());
this._setCapacity(config.capacity());
this._setGridMode(GridMode.ON_GRID);
}
@Override
@Deactivate
protected void deactivate() {
super.deactivate();
}
@Override
public void handleEvent(Event event) {
if (!this.isEnabled()) {
return;
}
switch (event.getTopic()) {
case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE:
this.calculateEnergy();
break;
case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE:
this.fetchAndUpdateEssRealtimeStatus();
break;
}
}
private void fetchAndUpdateEssRealtimeStatus() {
try {
// Fetch the necessary data from the API
JsonObject necessaryData = samsungApi.getEssRealtimeStatus();
// Populate the appropriate channels with the fetched data
double PvPw = necessaryData.get("PvPw").getAsDouble()*1000;
double PcsPw = necessaryData.get("PcsPw").getAsDouble();
int btSoc = necessaryData.get("BtSoc").getAsInt();
int BtStusCd = necessaryData.get("BtStusCd").getAsInt();
// Update the channels
this.channel(SymmetricEss.ChannelId.SOC).setNextValue(btSoc);
switch (BtStusCd) {
case 0:
// Battery is in Discharge mode
if (PcsPw > 0) {
this._setDcDischargePower((int) PcsPw);
this.calculateAcChargeEnergy.update(0);
this.calculateAcDischargeEnergy.update((int) PcsPw);
} else {
this._setDcDischargePower((int) -PcsPw);
this.calculateAcChargeEnergy.update((int) -PcsPw);
this.calculateAcDischargeEnergy.update(0);
}
break;
case 1:
// Battery is in Charge mode
if (PcsPw > 0) {
this._setDcDischargePower((int) -PcsPw);
this.calculateAcChargeEnergy.update((int) PcsPw);
this.calculateAcDischargeEnergy.update(0);
} else {
this._setDcDischargePower((int) -PcsPw);
this.calculateAcChargeEnergy.update(0);
this.calculateAcDischargeEnergy.update((int) -PcsPw);
}
break;
case 2:
// Battery is in Idle mode
this._setDcDischargePower(0);
this.calculateAcChargeEnergy.update(0);
this.calculateAcDischargeEnergy.update(0);
break;
default:
// Handle unknown status codes
this.logWarn(log, "Unknown Battery Status Code: " + BtStusCd);
break;
}
// this._setDcDischargePower(dcDischargePower);
this._setActivePower((int) (PcsPw - PvPw));
this._setSlaveCommunicationFailed(false);
} catch (OpenemsNamedException e) {
this._setSlaveCommunicationFailed(true);
this._setActivePower(0);
this.log.warn("Failed to fetch ESS Real-time Status", e);
}
}
@Override
public String debugLog() {
return "SoC:" + this.getSoc().asString() //
+ "|L:" + this.getActivePower().asString() //
+ "|" + this.getGridModeChannel().value().asOptionString(); //
}
@Override
public Timedata getTimedata() {
return this.timedata;
}
@Override
public Integer getSurplusPower() {
try {
// Fetch the necessary data from the API
JsonObject necessaryData = samsungApi.getEssRealtimeStatus();
// Extract relevant power values and status codes from the JSON object
double gridPw = necessaryData.get("GridPw").getAsDouble();
double pvPw = necessaryData.get("PvPw").getAsDouble();
double pcsPw = necessaryData.get("PcsPw").getAsDouble();
double consPw = necessaryData.get("ConsPw").getAsDouble();
int gridStatus = necessaryData.get("GridStusCd").getAsInt();
int batteryStatus = necessaryData.get("BtStusCd").getAsInt();
// Adjust the sign of gridPw and pcsPw based on the status codes
if (gridStatus == 1) {
gridPw = -gridPw;
}
if (batteryStatus == 0) {
pcsPw = -pcsPw;
}
// Calculate surplus power
double surplusPower = (gridPw + pvPw) - (pcsPw + consPw);
// Return the surplus power or 'null' if there is no surplus power
return surplusPower > 0 ? (int) surplusPower : null;
} catch (OpenemsNamedException e) {
log.warn("Failed to fetch ESS Real-time Status for Surplus Power Calculation", e);
return null;
}
}
private void calculateEnergy() {
/*
* Calculate AC Energy
*/
var acActivePower = this.getActivePowerChannel().getNextValue().get();
if (acActivePower == null) {
// Not available
this.calculateAcChargeEnergy.update(null);
this.calculateAcDischargeEnergy.update(null);
} else if (acActivePower > 0) {
// Discharge
this.calculateAcChargeEnergy.update(0);
this.calculateAcDischargeEnergy.update(acActivePower);
} else {
// Charge
this.calculateAcChargeEnergy.update(acActivePower * -1);
this.calculateAcDischargeEnergy.update(0);
}
}
}
Hmm, die Verwendung von CalculateEnergyFromPower
scheint korrekt zu sein. Du rufst allerdings die update()
-Methode an zwei Stellen auf, einmal in handleEvent()
und einmal in fetchAndUpdateEssRealtimeStatus()
. Das ist aber wahrscheinlich nicht so schlimm (obwohl du es dir trotzdem sparen könntest).
Meine erste Vermutung wäre, dass du keine Timedata (also z.B. Timedata RRD4J) auf der Edge aktiviert hast. Hast du das geprüft?
Beste Grüße,
Thomas
1 Like
Sn0w3y
February 10, 2024, 7:47pm
4
@stefan.feilmeier hast du noch eine Idee?
Mir ist auch aufgefallen, dass die Werte vom GoodWe DC Charger fehlen
Hast du denn Werte in den Channels ACTIVE_CHARGE_ENERGY und ACTIVE_DISCHARGE_ENERGY? (z. B. via Detailed-Debuglog)
1 Like
Sn0w3y
February 12, 2024, 3:59pm
6
Hallo Stefan,
ja die habe ich, siehe Screenshot.
Sn0w3y
February 13, 2024, 6:38pm
7
@stefan.feilmeier An was könnte es denn noch liegen?
c.lehne
February 14, 2024, 6:19am
8
Es fehlen ein paar Hintergrundinfos: Welche Datenbank verwendest du? Läuft die Datenbank Verbindung via Edge oder via Backend? Welches Datenbank Bundle wird genutzt?
Möglicherweise sind die Daten nicht in der Datenbank angekommen. Schon mal geprüft ob dort Werte hinterlegt sind?
Name des Feldes: <component ID>/ActiveChargeEnergy
Könnte mit der PersistencePriority deiner Backend Verbindung zu tun haben. Hast du evtl. eine AggregatedInfluxDB verwendet?
Sn0w3y
February 14, 2024, 6:37am
9
Guten Morgen,
ja, ich nutze eine Aggregated
Anbei 2 Screenshots:
Timedata RRD4J:
Backend:
timedata0:
Der avg Wert in der aggregated0 ist allerdings komplett leer. Und genau da vermute ich mein Problem…
c.lehne
February 15, 2024, 4:19am
10
Also greifst du über die UI des Backends zu. Hast du im “Core-Timedata Manager” die Komponenten ID der “Timedata AggregatedInfluxDB” hinterlegt? Verwenden “Timedata Influx DB” und “Timedata AggregatedInfluxDB” zwei unterschiedliche Komponenten IDs. Das Backend meckert nicht, falls zwei identische Komponenten IDs verwendet werden. Dies könnte auch noch ein möglicher Grund für die fehlenden Daten sein.
Die “Timedata AggregatedInfluxDB” wird erst ab einer 4 stelligen Zahl an Edges relevant, davor ist die Standard Implementierung “Timedata Influx DB” vollkommen ausreichend.
Abhängig von der Anzahl Edges, welche an deinem Backend hängen, würde ich dir daher empfehlen, die “Timedata AggregatedInfluxDB” vollständig zu entfernen und nur die “Timedata Influx DB” zu nutzen. Dann bitte auch im “Core Timedata Manager” prüfen, dass dort nur die Komponenten ID der “Timedata Influx DB” verwendet wird. Das macht die Fehlersuche ein gutes Stück einfacher, denn die Abläufe bei Verwendung beider Datenbanken im Zusammenspiel zwischen Edge/Backend/UI sind nicht offensichtlich.
Sn0w3y
February 15, 2024, 1:52pm
11
ja, wurde hinterlegt wie in der GettingStarted angeschrieben
korrekt. timedata0 und timedata1
Ich würde die Konfiguration ungern ändern
@stefan.feilmeier und @c.lehne habt ihr noch eine Idee um das zu debuggen?
klinki
February 16, 2024, 6:00am
12
Moin @Sn0w3y ,
Hab es nicht mehr ganz vor Augen… ich hatte für InfluxDB vor ein paar Wochen erst die fehlende Methode implementiert damit CalculateEnergyFromPower überhaupt mit Influx funktioniert, bzw. einen System-Neustart überlebt. Für AggregatedInfluxDBhatte ich das nicht gemacht - ich setze kein Backend ein.
Wie @c.lehne schon schrieb: Hast Du Werte in der DB für die Energie-Channels?
Gruß,
klinki
Sn0w3y
February 16, 2024, 6:38am
13
Moin klinki,
genau da liegt wahrscheinlich auch “der Hund begraben”
wenn ich aktuell Timedata und oder den Backend Controller im Edge restarte, hängt sich das Edge komplett auf und ich muss openems restarten - demetsprechend ist das ein Bug, den wir eventuell im Repo auch fixen sollten
Kann es daran liegen?
Ich hab gestern kurz mal mit Chronograf drauf geschaut (GUI für InfluxDB), hast du eventuell einen CLI SQL Query für mich, um zu überprüfen wo der Wert sein müsste?
Herzlichen Dank !!!
klinki
February 16, 2024, 7:00am
14
Ich hatte das Thema zusammen mit @michaelgrill bearbeitet. Dabei haben wir versucht die Änderungen möglichst allgemein zu formulieren.
Hier ein Link auf den PullRequest . Der ist ja inzwischen merged
Gaaanz komplizierte Sache : es sucht den letzten Wert des Energiechannels innerhalb der letzten 100 Tage und nimmt die Duration seit diesem Zeitpunkt.
Du musst nur die Variablen ersetzen.
Ich nutze nur das Standard-GUI auf Port 8086 von InfluxDB. Ein vernünftiges Tool habe ich leider immer noch nicht gefunden(wäre für jeden Tipp dankbar)
@Sn0w3y ich glaube du meinst folgende Fehlermeldung
java.lang.IllegalArgumentException: null
at org.apache.felix.framework.BundleContextImpl$ServiceObjectsImpl.ungetService(BundleContextImpl.java:564) ~[?:?]
....
die ist mir vor kurzem auch aufgefallen bei der BridgeHttp
gab es den selben Fehler.
Kurz zur Erklärung was diesen Fehler verursacht ist die Kombination von ServiceScope.PROTOTYPE
und ReferenceScope.PROTOTYPE_REQUIRED
ein Beispiel hierfür wäre folgendes:
@Designate(ocd = TestParent.Config.class, factory = true)
@Component(configurationPolicy = ConfigurationPolicy.REQUIRE)
public class TestParent {
@ObjectClassDefinition(name = "Test parent")
public static @interface Config {
}
@Component(scope = ServiceScope.PROTOTYPE, service = TestChild.class)
public static class TestChild {
}
@Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED)
private TestChild child;
}
immer wenn die TestParent
Klasse deaktiviert wird kommt der Fehler. Ich selbst würde behaupten, das das ein Fehler vom Apache Felix ist und eigentlich nicht das gewünschte verhalten hat.
Das kann man aber einfach mit einer Factory Klasse “umgehen” und man hat wieder das gewünschte verhalten, mit ein paar mehr Code-Zeilen.
Aber grundsätzlich wenn du das Edge neustartets sollte das keinen Einfluss auf das Senden der Daten haben. Außerdem brauchst du eigentlich zum senden der Daten ansich keine lokale Datenbank nur zum Daten nachsenden.
Wichtig wäre theoretisch noch die Einstellung am BackendController und dort der wert für die aggregationPriority
dieser sollte aber passen wenn du ihn auf default gelassen hast.
Wie auch die anderen bereits meinte wäre es hilfreich ob überhaupt Daten am Backend ankommen und in der DB gespeichert werden mit z. B.
select count(*) from rp_max.max
select count(*) from rp_avg.avg
bzw. ob die retention policies richtig angelegt wurden
show retention policies
Sn0w3y
February 16, 2024, 5:10pm
16
select count(*) from rp_max.max:
> select count(*) from rp_max.max
name: max
time count__sum/ConsumptionActiveEnergy count__sum/EssActiveChargeEnergy count__sum/EssActiveDischargeEnergy count__sum/EssDcChargeEnergy count__sum/EssDcDischargeEnergy count__sum/GridBuyActiveEnergy count__sum/GridSellActiveEnergy count__sum/ProductionAcActiveEnergy count__sum/ProductionActiveEnergy count__sum/ProductionDcActiveEnergy count_charger0/ActiveProductionEnergy count_charger0/ActualEnergy count_charger1/ActualEnergy count_ctrlChannelThreshold0/CumulatedActiveTime count_ctrlEssTimeOfUseTariff0/ChargedTime count_ctrlEssTimeOfUseTariff0/DelayedTime count_ctrlFixActivePower0/CumulatedActiveTime count_ctrlGridOptimizedCharge0/AvoidLowChargingTime count_ctrlGridOptimizedCharge0/DelayChargeTime count_ctrlGridOptimizedCharge0/NoLimitationTime count_ctrlGridOptimizedCharge0/SellToGridLimitTime count_ctrlIoHeatPump0/ForceOnStateTime count_ctrlIoHeatPump0/LockStateTime count_ctrlIoHeatPump0/RecommendationStateTime count_ctrlIoHeatPump0/RegularStateTime count_ctrlIoHeatingElement0/Level1CumulatedTime count_ctrlIoHeatingElement0/Level2CumulatedTime count_ctrlIoHeatingElement0/Level3CumulatedTime count_io0/ActiveProductionEnergy count_io1/ActiveProductionEnergy count_io2/ActiveProductionEnergy count_io3/ActiveProductionEnergy count_meter0/ActiveConsumptionEnergy count_meter0/ActiveProductionEnergy count_meter1/ActiveConsumptionEnergy count_meter1/ActiveProductionEnergy count_meter2/ActiveConsumptionEnergy count_meter2/ActiveProductionEnergy count_meter3/ActiveConsumptionEnergy count_meter3/ActiveProductionEnergy count_pvInverter0/ActiveProductionEnergy
---- ---------------------------------- -------------------------------- ----------------------------------- ---------------------------- ------------------------------- ------------------------------ ------------------------------- ----------------------------------- --------------------------------- ----------------------------------- ------------------------------------- --------------------------- --------------------------- ----------------------------------------------- ----------------------------------------- ----------------------------------------- --------------------------------------------- --------------------------------------------------- ---------------------------------------------- ----------------------------------------------- -------------------------------------------------- -------------------------------------- ----------------------------------- --------------------------------------------- -------------------------------------- ----------------------------------------------- ----------------------------------------------- ----------------------------------------------- -------------------------------- -------------------------------- -------------------------------- -------------------------------- ------------------------------------ ----------------------------------- ------------------------------------ ----------------------------------- ------------------------------------ ----------------------------------- ------------------------------------ ----------------------------------- ----------------------------------------
0 177 127 127 127 127 168 168 144 168 127 27 27 8 5 5 19 1 1 1 1 12 12 12 12 40 40 40 4 15 15 5 88 88 42 42 63 63 21 21
> ^C
select count(*) from rp_avg.avg:
> select count(*) from rp_avg.avg
name: avg
time count__sum/ConsumptionActivePower count__sum/ConsumptionActivePowerL1 count__sum/ConsumptionActivePowerL2 count__sum/ConsumptionActivePowerL3 count__sum/EssActivePower count__sum/EssActivePowerL1 count__sum/EssActivePowerL2 count__sum/EssActivePowerL3 count__sum/EssDischargePower count__sum/EssSoc count__sum/GridActivePower count__sum/GridActivePowerL1 count__sum/GridActivePowerL2 count__sum/GridActivePowerL3 count__sum/ProductionAcActivePower count__sum/ProductionAcActivePowerL1 count__sum/ProductionAcActivePowerL2 count__sum/ProductionAcActivePowerL3 count__sum/ProductionActivePower count__sum/ProductionDcActualPower count__sum/UnmanagedConsumptionActivePower count_charger0/ActualPower count_charger1/ActualPower count_ctrlEmergencyCapacityReserve0/ActualReserveSoc count_ctrlEssTimeOfUseTariff0/QuarterlyPrices count_ctrlEssTimeOfUseTariff0/StateMachine count_ctrlGridOptimizedCharge0/DelayChargeMaximumChargeLimit count_ctrlGridOptimizedCharge0/SellToGridLimitMinimumChargeLimit count_ctrlGridOptimizedCharge0/_PropertyMaximumSellToGridPower count_ctrlIoHeatPump0/Status count_ctrlIoHeatingElement0/Level count_ess0/ActivePower count_ess0/Soc count_evcs0/ChargePower count_evcs1/ChargePower count_evcs2/ChargePower count_evcs3/ChargePower count_evcs4/ChargePower count_evcs5/ChargePower count_evcs6/ChargePower count_evcs7/ChargePower count_evcs8/ChargePower count_io0/Relay1 count_io0/Relay2 count_io0/Relay3 count_io0/Relay4 count_io0/Relay5 count_io0/Relay6 count_io0/Relay7 count_io0/Relay8 count_io1/Relay1 count_io1/Relay2 count_io1/Relay3 count_io1/Relay4 count_io1/Relay5 count_io1/Relay6 count_io1/Relay7 count_io1/Relay8 count_meter0/ActivePower count_meter0/ActivePowerL1 count_meter0/ActivePowerL2 count_meter0/ActivePowerL3 count_meter1/ActivePower count_meter1/ActivePowerL1 count_meter1/ActivePowerL2 count_meter1/ActivePowerL3 count_meter2/ActivePower count_meter2/ActivePowerL1 count_meter2/ActivePowerL2 count_meter2/ActivePowerL3 count_meter3/ActivePower count_meter3/ActivePowerL1 count_meter3/ActivePowerL2 count_meter3/ActivePowerL3 count_pvInverter0/ActivePower
---- --------------------------------- ----------------------------------- ----------------------------------- ----------------------------------- ------------------------- --------------------------- --------------------------- --------------------------- ---------------------------- ----------------- -------------------------- ---------------------------- ---------------------------- ---------------------------- ---------------------------------- ------------------------------------ ------------------------------------ ------------------------------------ -------------------------------- ---------------------------------- ------------------------------------------ -------------------------- -------------------------- ---------------------------------------------------- --------------------------------------------- ------------------------------------------ ------------------------------------------------------------ ---------------------------------------------------------------- -------------------------------------------------------------- ---------------------------- --------------------------------- ---------------------- -------------- ----------------------- ----------------------- ----------------------- ----------------------- ----------------------- ----------------------- ----------------------- ----------------------- ----------------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ------------------------ -------------------------- -------------------------- -------------------------- ------------------------ -------------------------- -------------------------- -------------------------- ------------------------ -------------------------- -------------------------- -------------------------- ------------------------ -------------------------- -------------------------- -------------------------- -----------------------------
0 50588 50611 50608 50601 27947 27947 27947 27947 20859 27921 50205 43784 43784 43777 34873 20247 19822 14679 42483 14408 48656 9154 9153 2069 1653 42 162 408 997 4636 8798 27945 27919 7265 7265 7265 7265 7265 7265 7265 7265 7265 12147 12147 12147 12148 11912 11912 11912 11912 1663 1663 1663 1663 1663 1663 1663 1663 28609 22156 22156 22156 13345 6273 6273 6273 20427 20427 20427 20427 6668 6668 6668 6668 244
>
> show retention policies
name duration shardGroupDuration replicaN default
---- -------- ------------------ -------- -------
autogen 0s 168h0m0s 1 true
rp_max 2160h0m0s 24h0m0s 1 false
rp_avg 2160h0m0s 24h0m0s 1 false
>
Ok da stehen schonmal grundsätzlich Werte drin. Im UI-Widget werden glaube ich “_sum/EssDcChargeEnergy” und “_sum/EssDcDischargeEnergy” angezeigt. Sind die bei dir richtig?
z. B.
select "_sum/EssDcChargeEnergy" from rp_max.max where edge = '%edgeNr%'
btw. precision rfc3339
für lesbareren output
1 Like
Sn0w3y
February 20, 2024, 1:58pm
18
michaelgrill:
precision rfc3339
Danke für diesen Command !! den habe ich schon kange gesucht haha
Ich schau heute abend mal