NEWS
Test Victron Energy
-
@meister-mopper hast du den Victron Eneergy mit Batterie ânurâ als Eigenverbrauchserhöhung oder als Backup System eingerichtet?
So wie ich das lese, eher ersteres đ
@deralff sagte in Test Victron Energy:
@meister-mopper hast du den Victron Eneergy mit Batterie ânurâ als Eigenverbrauchserhöhung oder als Backup System eingerichtet?
Ich hĂ€tte gerne eine Notstromlösung, so ist es aber (noch) nicht eingerichtet. Muss erst mal einen lokalen Elektriker finden, der es mir fachgerecht anschlieĂt.
-
Aktuelle Test Version 0.3.1 Veröffentlichungsdatum 11.03.2023 Letzte Ănderung am 31.05.2024 Github Link https://github.com/derAlff/ioBroker.ve Hallo alle zusammen.
Ich habe einen kleinen Adapter erstellt, der die Daten eines Victron Energy Batteriespeichers auslesen kann. Ich weiĂ, der Name das Adapters ist nicht gerade gĂŒnstig (âveâ steht fĂŒr Victron Energy). Ich bin allerdings schon dran, damit ich Namen und auch Logo verwenden darf.
Der Adapter kann bisher einige Modbus-Register auslesen und in Datenpunkte speichern. Das selbe per MQTT implementiere ich auch noch.
Dann gibt es noch die Benutzer, die gerne die Daten aus dem VRM Portal haben möchten. Dazu gibt es auch irgendwann eine Option im Adapter.
Die Register, die bisher implementiert sind, wurden alle mit einem Victron Energy Multiplus 2 GX und Pylontech Akkus in mĂŒhevoller Kleinarbeit eingefĂŒgt und getestet.
Ich freue mich auf Benutzer, die ebenfalls einen Victron Energy Batteriespeicher haben. Schreibt mich einfach per Mail/DM an, oder erstellt ein GitHub Issue ;)
@deralff Super was du hier machst, ich hab den Multiplus 2 und den Pylontec Akku schon daheim liegen, mir fehlt leider grad die Zeit fĂŒr die Installation, aber sobald ich kann werde ich gerne deinen Adapter testen und helfen wenn ich kann... Konfiguriert wirds ĂŒbrgiends als "Eigenverbrauchsoptimierung" :)
VG
Chris -
@deralff Super was du hier machst, ich hab den Multiplus 2 und den Pylontec Akku schon daheim liegen, mir fehlt leider grad die Zeit fĂŒr die Installation, aber sobald ich kann werde ich gerne deinen Adapter testen und helfen wenn ich kann... Konfiguriert wirds ĂŒbrgiends als "Eigenverbrauchsoptimierung" :)
VG
Chris@mallet habe momentan auch etwas wenig Zeit nebenher⊠komme also nicht wirklich zum Programmieren đ.
Ich bin aber noch dran đ. Nebenher bin ich noch einen Adapter am entwickeln, welcher die Daten aus dem VRM Portal auslesen kann. Eventuell fasse ich die beiden Adapter dann irgendwann mal zusammen đ .
@apollon77 ist das Zusammenfassen (oder auch nur umbenennen) eines oder mehrerer Adapter irgendwie vorgesehen?
-
@mallet habe momentan auch etwas wenig Zeit nebenher⊠komme also nicht wirklich zum Programmieren đ.
Ich bin aber noch dran đ. Nebenher bin ich noch einen Adapter am entwickeln, welcher die Daten aus dem VRM Portal auslesen kann. Eventuell fasse ich die beiden Adapter dann irgendwann mal zusammen đ .
@apollon77 ist das Zusammenfassen (oder auch nur umbenennen) eines oder mehrerer Adapter irgendwie vorgesehen?
-
Das klingt sehr spannend! Vielleicht können wir den Adapter ja zu einem vollwertigen ESS-Manager fĂŒr Victron ausbauen.
Es gibt scheinbar ein paar Nutzer, die einen/drei Multiplus parallel zu (unsteuerbaren) anderen Speichern nutzen. Dann kann man die Venus-eigene Regelung leider nicht verwenden und mĂŒsste sich selber um Be-/Entladen kĂŒmmern.
Ich mache das derzeit mit einem sehr komplexen JS im Iobroker und wĂŒrde mir wĂŒnschen, einiges/alles davon in einen Adapter zu gieĂen

-
Das klingt sehr spannend! Vielleicht können wir den Adapter ja zu einem vollwertigen ESS-Manager fĂŒr Victron ausbauen.
Es gibt scheinbar ein paar Nutzer, die einen/drei Multiplus parallel zu (unsteuerbaren) anderen Speichern nutzen. Dann kann man die Venus-eigene Regelung leider nicht verwenden und mĂŒsste sich selber um Be-/Entladen kĂŒmmern.
Ich mache das derzeit mit einem sehr komplexen JS im Iobroker und wĂŒrde mir wĂŒnschen, einiges/alles davon in einen Adapter zu gieĂen

-
@oxident das klingt spannend. Kannst du mir eventuell das JS zur VerfĂŒgung stellen? Mich interessiert schon lange, wie man sowas herstellerunabhĂ€ngig macht đ .
@deralff Gerne ... aber wirklich "herstellerunabhĂ€ngig" ist es nicht, da ich es auf mein Senec-System gemĂŒnzt habe. Ich hoffe, Du steigst da irgendwie durch. Ist halt nie wirklich fĂŒr "andere Augen" gemacht worden (das ewige Problem der Skripter...):
// Allgemeine Datenpunkte const dpEnabled = "0_userdata.0.PV.Victron.VictronAutomatik"; // Skript aktiv const dpEnableCharging = "0_userdata.0.PV.Victron.VictronEnableCharging"; // Akkuladung erlaubt const dpEnableDischarging = "0_userdata.0.PV.Victron.VictronEnableDischarging"; // Akkuentladung erlaubt // Datenpunkt fĂŒr aktuellen Netzbezug (positive Werte) oder Netzeinspeisung (negative Werte) // WATT const dpNetzbezug = "0_userdata.0.Verbrauch.StromzĂ€hler.Leistung-Gesamt"; // Skript-Einstellungen // Datenpunkt fĂŒr Mindest-SOC const dpVictronMinSoC = "0_userdata.0.PV.Victron.VictronMinSOC"; // % // Datenpunkt fĂŒr Toleranz zu Nulleinspeisung und Nullbezug // WATT const dpVictronGridTolerance = "0_userdata.0.PV.Victron.VictronGridTolerance"; // Fremdspeicher / -anlagen // Datenpunkt fĂŒr aktuelle Entladung (negative Werte) oder Ladung (positive Werte) von Fremdakkus // WATT const dpForeignFlow = "senec.0.ENERGY.GUI_BAT_DATA_POWER"; // Victron beim Laden bevorzugen const dpPreferCharging = "0_userdata.0.PV.Victron.VictronPreferCharging"; // Victron beim Entladen bevorzugen const dpPreferDischarging = "0_userdata.0.PV.Victron.VictronPreferDischarging"; // Victron // aktueller (IST) Energiefluss vom Multiplus // >0: Akku wird geladen // =0: Standby // <0: Akku wird entladen // WATT const dpVictronFlowModbus = "modbus.2.inputRegisters.227._/Ac/ActiveIn/L1/P"; // aktueller (SOLL) Energiefluss vom Multiplus // >0: Akku soll geladen werden // =0: Standby // <0: Akku soll entladen werden // WATT const dpVictronSetPointModbus = "modbus.2.holdingRegisters.227._/Hub4/L1/AcPowerSetpoint"; // aktueller (IST) SoC und KapazitĂ€t vom Multiplus // PROZENT const dpVictronSoCModbus = "modbus.2.inputRegisters.100._/Dc/Battery/Soc"; // Ah const dpVictronAvailCapModbus = "modbus.2.inputRegisters.225._/Capacity"; // Unterschied der Zellspannungen // Ziel-DP: let dpVictronCellDerivation = '0_userdata.0.PV.Victron.VictronCellDrift' // Quell-DPs: let dpVictronCellMinVoltage = 'modbus.2.inputRegisters.225._/System/MinCellVoltage' let dpVictronCellMaxVoltage = 'modbus.2.inputRegisters.225._/System/MaxCellVoltage' // Multiplus-Leerlaufzeit // schaltet Inverter und LadegerĂ€t nach x Minuten aus // falls nicht mehr benötigt const idleTimerMin = 10; //min // Nennspannung const BatteryVoltageRated = 48; //V // AgressivitĂ€t der Laderegelung // Faktor mit dem der Netzbezug oder die Einspeisung // pro Schritt ausgeglichen wird // 0.0 (0%) ... 1.0 (100%) const regulationLevel = 0.6; // // aktueller (IST) ESS-Modus vom Multiplus // 1: ESS mit Phasenkompensation (Standard) // 2: ESS ohne Phasenkompensation // 3: Externe Steuerung const dpVictronESSModeModbus = "modbus.2.holdingRegisters.100._/Settings/Cgwacs/Hub4Mode"; // Modbus // aktueller Betriebsmodus vom Multiplus // 1=Charger Only;2=Inverter Only;3=On;4=Off const dpVictronModeModbus = "modbus.2.holdingRegisters.227._/Mode"; // Modbus function calcVictronFlow() { if((getState(dpVictronFlowModbus).val)!=null) { if((getState(dpEnabled).val)&&(getState(dpVictronESSModeModbus).val==3)) { var Netzbezug = getState(dpNetzbezug).val; // + = Bezug, - = Einspeisung var Fremdbezug = getState(dpForeignFlow).val; // + = Fremdakku lĂ€dt, - = Fremdakku entlĂ€dt var VictronSoC = getState(dpVictronSoCModbus).val; var VictronSetPoint = getState(dpVictronFlowModbus).val; // + = Victron lĂ€dt, - = Victron entlĂ€dt var Hausverbrauch = Netzbezug + (VictronSetPoint*-1); var ForeignBatteryModificator = 0; if(Fremdbezug > getState(dpVictronGridTolerance).val) { // Fremdakku wird geladen if(getState(dpPreferCharging).val) { // ... stattdessen Victron laden ForeignBatteryModificator = Fremdbezug - getState(dpVictronGridTolerance).val; ForeignBatteryModificator *= -1; } } else if (Fremdbezug < (0-getState(dpVictronGridTolerance).val)) { // Fremdakku wird entladen if(getState(dpPreferCharging).val) { // ... stattdessen Victron entladen ForeignBatteryModificator = Fremdbezug + getState(dpVictronGridTolerance).val; } } Netzbezug += ForeignBatteryModificator; Netzbezug = Math.ceil(Netzbezug); //console.log(Hausverbrauch); if(Hausverbrauch > getState(dpVictronGridTolerance).val) { // Netzbezug ĂŒber Toleranz if(Fremdbezug>getState(dpVictronGridTolerance).val) { // Sonderfall: Vermeiden, dass Fremdakku durch Victron geladen wird //console.log("Fremdakku wird trotz " + Netzbezug + "W Netzbezug / " + Hausverbrauch + "W Hausverbrauch geladen mit " + Fremdbezug + "W"); //VictronSetPoint = 0; VictronSetPoint += Math.floor(Fremdbezug * regulationLevel); setSetPoint(VictronSetPoint); } else { if(getState(dpEnableDischarging).val) { // Entladen erlaubt (via DP) //console.log("Entladen mit: " + Netzbezug); //console.log("Netzbezug " + Netzbezug + "W, Setpoint: " + VictronSetPoint + "W, Fremdbezug " + Fremdbezug); VictronSetPoint-=Math.floor(Netzbezug * regulationLevel); if((Math.abs(Fremdbezug) > getState(dpVictronGridTolerance).val)) { // Fremdakku wird genutzt //VictronSetPoint-=Netzbezug; VictronSetPoint+=(getState(dpVictronGridTolerance).val * regulationLevel); } else { // Fremdakku wird NICHT genutzt //VictronSetPoint-=Math.floor(Netzbezug * regulationLevel); } //console.log("Setpoint Neu: " + VictronSetPoint + "W"); setSetPoint(VictronSetPoint); } else { // Entladen nicht erlaubt (via DP) VictronSetPoint = 0; setSetPoint(0); //console.log("Laden gesperrt via DP"); } } } else if (Hausverbrauch < (0 - getState(dpVictronGridTolerance).val)) { // Netzeinspeisung ĂŒber Toleranz if(getState(dpEnableCharging).val) { // Beladen erlaubt //console.log("Beladen mit: " + (Netzbezug*-1)); VictronSetPoint+=Math.floor(Netzbezug*-1*regulationLevel); if((Math.abs(Fremdbezug) > getState(dpVictronGridTolerance).val)) { // Fremdakku wird genutzt VictronSetPoint-=Math.floor(getState(dpVictronGridTolerance).val/2); } //if(Fremdbezug<0) { // VictronSetPoint += Fremdbezug; // sonst Problem bei vollem Fremdakku // VictronSetPoint -= getState(dpVictronGridTolerance).val; //} //console.log(Fremdbezug); setSetPoint(VictronSetPoint); } else { // Beladen nicht erlaubt (via DP) VictronSetPoint = 0; setSetPoint(0); //console.log("Entladen gesperrt via DP"); } } else { //console.log("Standby"); if(getState(dpEnabled).val) VictronSetPoint = 0; setSetPoint(VictronSetPoint); } } else { if(getState(dpVictronESSModeModbus).val==3) { // Skript deaktiviert // manueller Modus // ESS-Mode 3 VictronSetPoint = getState("0_userdata.0.PV.Victron.VictronSetPoint").val; setSetPoint(VictronSetPoint); } else { // ESS-Mode 1/2 // Buggy! setState(dpEnabled, false, false); } setState(dpEnabled, false, true); //console.log("Victron inaktiv"); } } else { // Victron-Werte nicht aktuell / Keep-Alive abwarten // console.log("Werte nicht aktuell"); // console.log(console.trace()); } } function getSafeSetPoint(desiredSetPoint) { var SafeSetPoint = desiredSetPoint; //console.log(desiredSetPoint + " angefragt"); if(desiredSetPoint>0) { // Laden des Akkus angefragt // (sollte eigentlich immer durch BMS begrenzt werden) if(getState("modbus.2.inputRegisters.227._/Bms/AllowToCharge").val==1) { // Laden durch BMS erlaubt // BOL-Limit SafeSetPoint = Math.min(getState("modbus.2.inputRegisters.225._/Info/MaxChargeCurrent").val * getState("modbus.2.inputRegisters.225._/Info/MaxChargeVoltage").val, SafeSetPoint); // Hard-Limit AC (7kW) SafeSetPoint = Math.min(7000, SafeSetPoint); // 80%-Kappung (Workaround wegen Fremdakku) // aber nur im Automatik-Modus // if(getState(dpEnabled).val) SafeSetPoint *= 0.8; // Mindesteinspeisung erreichen (wegen Fremdakku) // aber nur im Automatik-Modus //if(getState(dpEnabled).val) SafeSetPoint -= getState(dpVictronGridTolerance).val; // Ladelimits anhand SoC if((getState(dpVictronSoCModbus).val) >= 99) { SafeSetPoint = Math.min(desiredSetPoint, 0); } else if((getState(dpVictronSoCModbus).val) >= 98) { SafeSetPoint = Math.min(desiredSetPoint, 100); } else if((getState(dpVictronSoCModbus).val) >= 95) { SafeSetPoint = Math.min(desiredSetPoint, 500); } else if((getState(dpVictronSoCModbus).val) >= 90) { SafeSetPoint = Math.min(desiredSetPoint, 1500); } // Cell-Drift if((getState(dpVictronCellDerivation).val) > 150) { SafeSetPoint = Math.min(desiredSetPoint, 0); console.log("Hohe Abweichung der Zellenspannung - Ladung gesperrt!"); } else if((getState(dpVictronCellDerivation).val) > 100) { SafeSetPoint = Math.min(desiredSetPoint, 200); //console.log("Hohe Abweichung der Zellenspannung - Ladung gedrosselt."); } // Vergleich zum gewĂŒnschten SetPoint SafeSetPoint = Math.min(desiredSetPoint, SafeSetPoint); } else { SafeSetPoint = 0; } } else if(desiredSetPoint<0) { // Entladen des Akkus angefragt // (wird nicht durch BMS geprĂŒft!) //console.log("Entladen angefragt"); // Minimum-SoC if (getState(dpVictronMinSoC).val > getState(dpVictronSoCModbus).val) { //console.log("SoC zu niedrig"); SafeSetPoint = 0; } else if(getState("modbus.2.inputRegisters.227._/Bms/AllowToDischarge").val==1) { //console.log("SoC ok"); // Entladen durch BMS ind Mindest-SoC erlaubt //console.log("Min-SoC: " + getState(dpVictronMinSoC).val + " SoC: " + getState(dpVictronSoCModbus).val); // Battery-Limit SafeSetPoint = Math.max(getState("modbus.2.inputRegisters.225._/Info/MaxDischargeCurrent").val * getState("modbus.2.inputRegisters.225._/Info/BatteryLowVoltage").val*-1, SafeSetPoint); // Hard-Limit AC (7kW) SafeSetPoint = Math.max(-7000, SafeSetPoint); // 90%-Kappung (Workaround wegen Fremdakku) // aber nur im Automatik-Modus // if(getState(dpEnabled).val) SafeSetPoint *= 0.9; // geringen Netzbezug erlauben // aber nur im Automatik-Modus //if(getState(dpEnabled).val) SafeSetPoint -= getState(dpVictronGridTolerance).val; // Entladelimits anhand SoC if((getState(dpVictronSoCModbus).val) <= 10) { SafeSetPoint = Math.max(desiredSetPoint, -1000); } else if((getState(dpVictronSoCModbus).val) <= 20) { SafeSetPoint = Math.max(desiredSetPoint, -2000); } // Vergleich zum gewĂŒnschten SetPoint SafeSetPoint = Math.max(desiredSetPoint, SafeSetPoint); } else { SafeSetPoint = 0; } } else { // Standby angefragt SafeSetPoint = 0; } SafeSetPoint = Math.floor(SafeSetPoint); if(Math.abs(SafeSetPoint) < 70) SafeSetPoint = 0; if(SafeSetPoint!=desiredSetPoint) { //console.log("SetPoint limitiert von " + desiredSetPoint + "W auf " + SafeSetPoint + "W"); } //console.log(SafeSetPoint); return SafeSetPoint; } function setSetPoint(newSetPoint) { if(getState(dpVictronESSModeModbus).val==3) { var targetSetpoint = getSafeSetPoint(newSetPoint); //console.log("SafeSetPoint: " + targetSetpoint); if(targetSetpoint>0) { if(getState(dpEnableDischarging).val) { // LadegerĂ€t und Inverter aktivieren if(getState(dpVictronModeModbus).val != 3) { setState(dpVictronModeModbus, 3); return; // warte bis MP eingeschaltet } } else { // nur LadegerĂ€t aktivieren if(getState(dpVictronModeModbus).val != 1) { setState(dpVictronModeModbus, 1); return; // warte bis MP eingeschaltet } } //console.log("setSetPoint " + targetSetpoint); setState(dpVictronSetPointModbus, targetSetpoint); setState("0_userdata.0.PV.Victron.VictronSetPoint", targetSetpoint, true); } else if(targetSetpoint<0) { if(getState(dpEnableCharging).val) { // LadegerĂ€t und Inverter aktivieren if(getState(dpVictronModeModbus).val != 3) { setState(dpVictronModeModbus, 3); return; // warte bis MP eingeschaltet } } else { // nur Inverter aktivieren if(getState(dpVictronModeModbus).val != 2) { setState(dpVictronModeModbus, 2); return; // warte bis MP eingeschaltet } } //console.log("setSetPoint " + targetSetpoint); setState(dpVictronSetPointModbus, targetSetpoint); setState("0_userdata.0.PV.Victron.VictronSetPoint", targetSetpoint, true); } else { // Aus /*if(getState(dpVictronSetPointModbus).val != 0)*/ //console.log("Modus: " + getState(dpVictronModeModbus).val); if(getState(dpVictronModeModbus).val != 4) { if(getState(dpVictronSetPointModbus).val != 0) setState(dpVictronSetPointModbus, 0); if(getState(dpVictronSetPointModbus).lc<(Date.now()-(idleTimerMin*60*1000))) { // nach x min MP ausschalten //console.log("Schalte Victron aus"); setState(dpVictronModeModbus, 4); } } } } else { // keine externe Steuerung } } function getCapacity() { setState("0_userdata.0.PV.Victron.VictronSOC", getState(dpVictronSoCModbus).val, true); setState("0_userdata.0.PV.Victron.VictronLadestandJetzt", (getState(dpVictronAvailCapModbus).val * BatteryVoltageRated)/1000, true); setState("0_userdata.0.PV.Victron.VictronLadestandMax", 11184, true); } function calcCellDerivation() { setState(dpVictronCellDerivation, 1000*(getState(dpVictronCellMaxVoltage).val - getState(dpVictronCellMinVoltage).val), true); } // Trigger // Skript aktiviert / deaktiviert on({id: dpEnabled, change: 'ne', ack: false}, function(obj) { setSetPoint(0); setState("0_userdata.0.PV.Victron.VictronSetPoint", 0, true); setState(dpEnabled, getState(dpEnabled).val, true); }); on({id: dpEnableCharging, change: 'ne', ack: false}, function(obj) { setSetPoint(0); setState(dpEnableCharging, getState(dpEnableCharging).val, true); }); on({id: dpEnableDischarging, change: 'ne', ack: false}, function(obj) { setSetPoint(0); setState(dpEnableDischarging, getState(dpEnableDischarging).val, true); }); on({id: dpPreferCharging, change: 'ne'}, function(obj) { calcVictronFlow(); }); on({id: dpPreferDischarging, change: 'ne'}, function(obj) { calcVictronFlow(); }); // Netzbezug-Ănderung on({id: dpNetzbezug, change: 'ne'}, function(obj) { calcVictronFlow(); }); schedule("*/3 * * * * *", function () { // calcVictronFlow() }); on({id: dpVictronGridTolerance, change: 'ne'}, function(obj) { calcVictronFlow(); }); // Fremdbezug / Fremdladung Ănderung on({id: dpForeignFlow, change: 'ne'}, function(obj) { //calcVictronFlow(); }); // Victron SoC-Ănderung on({id: dpVictronSoCModbus, change: 'ne'}, function(obj) { getCapacity(); //calcVictronFlow(); }); on({id: dpVictronAvailCapModbus, change: 'ne'}, function(obj) { getCapacity(); //calcVictronFlow(); }); // Victron Flow-Ănderung on({id: dpVictronFlowModbus, change: 'ne'}, function(obj) { setState("0_userdata.0.PV.Victron.VictronFlow", getState(dpVictronFlowModbus).val, true); if(getState(dpVictronFlowModbus).val<=-100) { // LĂ€dt setState("0_userdata.0.PV.Victron.VictronAkkuRichtungVis", 1, true); } else if (getState(dpVictronFlowModbus).val>=100) { // EntlĂ€dt setState("0_userdata.0.PV.Victron.VictronAkkuRichtungVis", 2, true); } else { // Standby setState("0_userdata.0.PV.Victron.VictronAkkuRichtungVis", 0, true); } //calcVictronFlow(); }); // Victron ESSMode-Ănderung on({id: dpVictronESSModeModbus, change: 'ne'}, function(obj) { setState("0_userdata.0.PV.Victron.VictronESSMode", getState(dpVictronESSModeModbus).val, true); if(getState(dpVictronESSModeModbus).val!=3) setSetPoint(0); calcVictronFlow(); }); // Victron Zellspannungs-Ănderung on({id: dpVictronCellMinVoltage, change: 'ne'}, function(obj) { calcCellDerivation(); }); on({id: dpVictronCellMaxVoltage, change: 'ne'}, function(obj) { calcCellDerivation(); }); // Keep-Alives schedule("*/30 * * * * *", function () { if(getState(dpEnabled).val) { //calcVictronFlow(); } else { setSetPoint(getState("0_userdata.0.PV.Victron.VictronSetPoint").val); } }); // Skriptstart // --------------------------------------------------------------------- if(getState(dpEnabled).val) { setState(dpEnabled, true, true); calcVictronFlow(); } else { setSetPoint(0); setState(dpEnabled, false, true); } calcCellDerivation(); -
@deralff Gerne ... aber wirklich "herstellerunabhĂ€ngig" ist es nicht, da ich es auf mein Senec-System gemĂŒnzt habe. Ich hoffe, Du steigst da irgendwie durch. Ist halt nie wirklich fĂŒr "andere Augen" gemacht worden (das ewige Problem der Skripter...):
// Allgemeine Datenpunkte const dpEnabled = "0_userdata.0.PV.Victron.VictronAutomatik"; // Skript aktiv const dpEnableCharging = "0_userdata.0.PV.Victron.VictronEnableCharging"; // Akkuladung erlaubt const dpEnableDischarging = "0_userdata.0.PV.Victron.VictronEnableDischarging"; // Akkuentladung erlaubt // Datenpunkt fĂŒr aktuellen Netzbezug (positive Werte) oder Netzeinspeisung (negative Werte) // WATT const dpNetzbezug = "0_userdata.0.Verbrauch.StromzĂ€hler.Leistung-Gesamt"; // Skript-Einstellungen // Datenpunkt fĂŒr Mindest-SOC const dpVictronMinSoC = "0_userdata.0.PV.Victron.VictronMinSOC"; // % // Datenpunkt fĂŒr Toleranz zu Nulleinspeisung und Nullbezug // WATT const dpVictronGridTolerance = "0_userdata.0.PV.Victron.VictronGridTolerance"; // Fremdspeicher / -anlagen // Datenpunkt fĂŒr aktuelle Entladung (negative Werte) oder Ladung (positive Werte) von Fremdakkus // WATT const dpForeignFlow = "senec.0.ENERGY.GUI_BAT_DATA_POWER"; // Victron beim Laden bevorzugen const dpPreferCharging = "0_userdata.0.PV.Victron.VictronPreferCharging"; // Victron beim Entladen bevorzugen const dpPreferDischarging = "0_userdata.0.PV.Victron.VictronPreferDischarging"; // Victron // aktueller (IST) Energiefluss vom Multiplus // >0: Akku wird geladen // =0: Standby // <0: Akku wird entladen // WATT const dpVictronFlowModbus = "modbus.2.inputRegisters.227._/Ac/ActiveIn/L1/P"; // aktueller (SOLL) Energiefluss vom Multiplus // >0: Akku soll geladen werden // =0: Standby // <0: Akku soll entladen werden // WATT const dpVictronSetPointModbus = "modbus.2.holdingRegisters.227._/Hub4/L1/AcPowerSetpoint"; // aktueller (IST) SoC und KapazitĂ€t vom Multiplus // PROZENT const dpVictronSoCModbus = "modbus.2.inputRegisters.100._/Dc/Battery/Soc"; // Ah const dpVictronAvailCapModbus = "modbus.2.inputRegisters.225._/Capacity"; // Unterschied der Zellspannungen // Ziel-DP: let dpVictronCellDerivation = '0_userdata.0.PV.Victron.VictronCellDrift' // Quell-DPs: let dpVictronCellMinVoltage = 'modbus.2.inputRegisters.225._/System/MinCellVoltage' let dpVictronCellMaxVoltage = 'modbus.2.inputRegisters.225._/System/MaxCellVoltage' // Multiplus-Leerlaufzeit // schaltet Inverter und LadegerĂ€t nach x Minuten aus // falls nicht mehr benötigt const idleTimerMin = 10; //min // Nennspannung const BatteryVoltageRated = 48; //V // AgressivitĂ€t der Laderegelung // Faktor mit dem der Netzbezug oder die Einspeisung // pro Schritt ausgeglichen wird // 0.0 (0%) ... 1.0 (100%) const regulationLevel = 0.6; // // aktueller (IST) ESS-Modus vom Multiplus // 1: ESS mit Phasenkompensation (Standard) // 2: ESS ohne Phasenkompensation // 3: Externe Steuerung const dpVictronESSModeModbus = "modbus.2.holdingRegisters.100._/Settings/Cgwacs/Hub4Mode"; // Modbus // aktueller Betriebsmodus vom Multiplus // 1=Charger Only;2=Inverter Only;3=On;4=Off const dpVictronModeModbus = "modbus.2.holdingRegisters.227._/Mode"; // Modbus function calcVictronFlow() { if((getState(dpVictronFlowModbus).val)!=null) { if((getState(dpEnabled).val)&&(getState(dpVictronESSModeModbus).val==3)) { var Netzbezug = getState(dpNetzbezug).val; // + = Bezug, - = Einspeisung var Fremdbezug = getState(dpForeignFlow).val; // + = Fremdakku lĂ€dt, - = Fremdakku entlĂ€dt var VictronSoC = getState(dpVictronSoCModbus).val; var VictronSetPoint = getState(dpVictronFlowModbus).val; // + = Victron lĂ€dt, - = Victron entlĂ€dt var Hausverbrauch = Netzbezug + (VictronSetPoint*-1); var ForeignBatteryModificator = 0; if(Fremdbezug > getState(dpVictronGridTolerance).val) { // Fremdakku wird geladen if(getState(dpPreferCharging).val) { // ... stattdessen Victron laden ForeignBatteryModificator = Fremdbezug - getState(dpVictronGridTolerance).val; ForeignBatteryModificator *= -1; } } else if (Fremdbezug < (0-getState(dpVictronGridTolerance).val)) { // Fremdakku wird entladen if(getState(dpPreferCharging).val) { // ... stattdessen Victron entladen ForeignBatteryModificator = Fremdbezug + getState(dpVictronGridTolerance).val; } } Netzbezug += ForeignBatteryModificator; Netzbezug = Math.ceil(Netzbezug); //console.log(Hausverbrauch); if(Hausverbrauch > getState(dpVictronGridTolerance).val) { // Netzbezug ĂŒber Toleranz if(Fremdbezug>getState(dpVictronGridTolerance).val) { // Sonderfall: Vermeiden, dass Fremdakku durch Victron geladen wird //console.log("Fremdakku wird trotz " + Netzbezug + "W Netzbezug / " + Hausverbrauch + "W Hausverbrauch geladen mit " + Fremdbezug + "W"); //VictronSetPoint = 0; VictronSetPoint += Math.floor(Fremdbezug * regulationLevel); setSetPoint(VictronSetPoint); } else { if(getState(dpEnableDischarging).val) { // Entladen erlaubt (via DP) //console.log("Entladen mit: " + Netzbezug); //console.log("Netzbezug " + Netzbezug + "W, Setpoint: " + VictronSetPoint + "W, Fremdbezug " + Fremdbezug); VictronSetPoint-=Math.floor(Netzbezug * regulationLevel); if((Math.abs(Fremdbezug) > getState(dpVictronGridTolerance).val)) { // Fremdakku wird genutzt //VictronSetPoint-=Netzbezug; VictronSetPoint+=(getState(dpVictronGridTolerance).val * regulationLevel); } else { // Fremdakku wird NICHT genutzt //VictronSetPoint-=Math.floor(Netzbezug * regulationLevel); } //console.log("Setpoint Neu: " + VictronSetPoint + "W"); setSetPoint(VictronSetPoint); } else { // Entladen nicht erlaubt (via DP) VictronSetPoint = 0; setSetPoint(0); //console.log("Laden gesperrt via DP"); } } } else if (Hausverbrauch < (0 - getState(dpVictronGridTolerance).val)) { // Netzeinspeisung ĂŒber Toleranz if(getState(dpEnableCharging).val) { // Beladen erlaubt //console.log("Beladen mit: " + (Netzbezug*-1)); VictronSetPoint+=Math.floor(Netzbezug*-1*regulationLevel); if((Math.abs(Fremdbezug) > getState(dpVictronGridTolerance).val)) { // Fremdakku wird genutzt VictronSetPoint-=Math.floor(getState(dpVictronGridTolerance).val/2); } //if(Fremdbezug<0) { // VictronSetPoint += Fremdbezug; // sonst Problem bei vollem Fremdakku // VictronSetPoint -= getState(dpVictronGridTolerance).val; //} //console.log(Fremdbezug); setSetPoint(VictronSetPoint); } else { // Beladen nicht erlaubt (via DP) VictronSetPoint = 0; setSetPoint(0); //console.log("Entladen gesperrt via DP"); } } else { //console.log("Standby"); if(getState(dpEnabled).val) VictronSetPoint = 0; setSetPoint(VictronSetPoint); } } else { if(getState(dpVictronESSModeModbus).val==3) { // Skript deaktiviert // manueller Modus // ESS-Mode 3 VictronSetPoint = getState("0_userdata.0.PV.Victron.VictronSetPoint").val; setSetPoint(VictronSetPoint); } else { // ESS-Mode 1/2 // Buggy! setState(dpEnabled, false, false); } setState(dpEnabled, false, true); //console.log("Victron inaktiv"); } } else { // Victron-Werte nicht aktuell / Keep-Alive abwarten // console.log("Werte nicht aktuell"); // console.log(console.trace()); } } function getSafeSetPoint(desiredSetPoint) { var SafeSetPoint = desiredSetPoint; //console.log(desiredSetPoint + " angefragt"); if(desiredSetPoint>0) { // Laden des Akkus angefragt // (sollte eigentlich immer durch BMS begrenzt werden) if(getState("modbus.2.inputRegisters.227._/Bms/AllowToCharge").val==1) { // Laden durch BMS erlaubt // BOL-Limit SafeSetPoint = Math.min(getState("modbus.2.inputRegisters.225._/Info/MaxChargeCurrent").val * getState("modbus.2.inputRegisters.225._/Info/MaxChargeVoltage").val, SafeSetPoint); // Hard-Limit AC (7kW) SafeSetPoint = Math.min(7000, SafeSetPoint); // 80%-Kappung (Workaround wegen Fremdakku) // aber nur im Automatik-Modus // if(getState(dpEnabled).val) SafeSetPoint *= 0.8; // Mindesteinspeisung erreichen (wegen Fremdakku) // aber nur im Automatik-Modus //if(getState(dpEnabled).val) SafeSetPoint -= getState(dpVictronGridTolerance).val; // Ladelimits anhand SoC if((getState(dpVictronSoCModbus).val) >= 99) { SafeSetPoint = Math.min(desiredSetPoint, 0); } else if((getState(dpVictronSoCModbus).val) >= 98) { SafeSetPoint = Math.min(desiredSetPoint, 100); } else if((getState(dpVictronSoCModbus).val) >= 95) { SafeSetPoint = Math.min(desiredSetPoint, 500); } else if((getState(dpVictronSoCModbus).val) >= 90) { SafeSetPoint = Math.min(desiredSetPoint, 1500); } // Cell-Drift if((getState(dpVictronCellDerivation).val) > 150) { SafeSetPoint = Math.min(desiredSetPoint, 0); console.log("Hohe Abweichung der Zellenspannung - Ladung gesperrt!"); } else if((getState(dpVictronCellDerivation).val) > 100) { SafeSetPoint = Math.min(desiredSetPoint, 200); //console.log("Hohe Abweichung der Zellenspannung - Ladung gedrosselt."); } // Vergleich zum gewĂŒnschten SetPoint SafeSetPoint = Math.min(desiredSetPoint, SafeSetPoint); } else { SafeSetPoint = 0; } } else if(desiredSetPoint<0) { // Entladen des Akkus angefragt // (wird nicht durch BMS geprĂŒft!) //console.log("Entladen angefragt"); // Minimum-SoC if (getState(dpVictronMinSoC).val > getState(dpVictronSoCModbus).val) { //console.log("SoC zu niedrig"); SafeSetPoint = 0; } else if(getState("modbus.2.inputRegisters.227._/Bms/AllowToDischarge").val==1) { //console.log("SoC ok"); // Entladen durch BMS ind Mindest-SoC erlaubt //console.log("Min-SoC: " + getState(dpVictronMinSoC).val + " SoC: " + getState(dpVictronSoCModbus).val); // Battery-Limit SafeSetPoint = Math.max(getState("modbus.2.inputRegisters.225._/Info/MaxDischargeCurrent").val * getState("modbus.2.inputRegisters.225._/Info/BatteryLowVoltage").val*-1, SafeSetPoint); // Hard-Limit AC (7kW) SafeSetPoint = Math.max(-7000, SafeSetPoint); // 90%-Kappung (Workaround wegen Fremdakku) // aber nur im Automatik-Modus // if(getState(dpEnabled).val) SafeSetPoint *= 0.9; // geringen Netzbezug erlauben // aber nur im Automatik-Modus //if(getState(dpEnabled).val) SafeSetPoint -= getState(dpVictronGridTolerance).val; // Entladelimits anhand SoC if((getState(dpVictronSoCModbus).val) <= 10) { SafeSetPoint = Math.max(desiredSetPoint, -1000); } else if((getState(dpVictronSoCModbus).val) <= 20) { SafeSetPoint = Math.max(desiredSetPoint, -2000); } // Vergleich zum gewĂŒnschten SetPoint SafeSetPoint = Math.max(desiredSetPoint, SafeSetPoint); } else { SafeSetPoint = 0; } } else { // Standby angefragt SafeSetPoint = 0; } SafeSetPoint = Math.floor(SafeSetPoint); if(Math.abs(SafeSetPoint) < 70) SafeSetPoint = 0; if(SafeSetPoint!=desiredSetPoint) { //console.log("SetPoint limitiert von " + desiredSetPoint + "W auf " + SafeSetPoint + "W"); } //console.log(SafeSetPoint); return SafeSetPoint; } function setSetPoint(newSetPoint) { if(getState(dpVictronESSModeModbus).val==3) { var targetSetpoint = getSafeSetPoint(newSetPoint); //console.log("SafeSetPoint: " + targetSetpoint); if(targetSetpoint>0) { if(getState(dpEnableDischarging).val) { // LadegerĂ€t und Inverter aktivieren if(getState(dpVictronModeModbus).val != 3) { setState(dpVictronModeModbus, 3); return; // warte bis MP eingeschaltet } } else { // nur LadegerĂ€t aktivieren if(getState(dpVictronModeModbus).val != 1) { setState(dpVictronModeModbus, 1); return; // warte bis MP eingeschaltet } } //console.log("setSetPoint " + targetSetpoint); setState(dpVictronSetPointModbus, targetSetpoint); setState("0_userdata.0.PV.Victron.VictronSetPoint", targetSetpoint, true); } else if(targetSetpoint<0) { if(getState(dpEnableCharging).val) { // LadegerĂ€t und Inverter aktivieren if(getState(dpVictronModeModbus).val != 3) { setState(dpVictronModeModbus, 3); return; // warte bis MP eingeschaltet } } else { // nur Inverter aktivieren if(getState(dpVictronModeModbus).val != 2) { setState(dpVictronModeModbus, 2); return; // warte bis MP eingeschaltet } } //console.log("setSetPoint " + targetSetpoint); setState(dpVictronSetPointModbus, targetSetpoint); setState("0_userdata.0.PV.Victron.VictronSetPoint", targetSetpoint, true); } else { // Aus /*if(getState(dpVictronSetPointModbus).val != 0)*/ //console.log("Modus: " + getState(dpVictronModeModbus).val); if(getState(dpVictronModeModbus).val != 4) { if(getState(dpVictronSetPointModbus).val != 0) setState(dpVictronSetPointModbus, 0); if(getState(dpVictronSetPointModbus).lc<(Date.now()-(idleTimerMin*60*1000))) { // nach x min MP ausschalten //console.log("Schalte Victron aus"); setState(dpVictronModeModbus, 4); } } } } else { // keine externe Steuerung } } function getCapacity() { setState("0_userdata.0.PV.Victron.VictronSOC", getState(dpVictronSoCModbus).val, true); setState("0_userdata.0.PV.Victron.VictronLadestandJetzt", (getState(dpVictronAvailCapModbus).val * BatteryVoltageRated)/1000, true); setState("0_userdata.0.PV.Victron.VictronLadestandMax", 11184, true); } function calcCellDerivation() { setState(dpVictronCellDerivation, 1000*(getState(dpVictronCellMaxVoltage).val - getState(dpVictronCellMinVoltage).val), true); } // Trigger // Skript aktiviert / deaktiviert on({id: dpEnabled, change: 'ne', ack: false}, function(obj) { setSetPoint(0); setState("0_userdata.0.PV.Victron.VictronSetPoint", 0, true); setState(dpEnabled, getState(dpEnabled).val, true); }); on({id: dpEnableCharging, change: 'ne', ack: false}, function(obj) { setSetPoint(0); setState(dpEnableCharging, getState(dpEnableCharging).val, true); }); on({id: dpEnableDischarging, change: 'ne', ack: false}, function(obj) { setSetPoint(0); setState(dpEnableDischarging, getState(dpEnableDischarging).val, true); }); on({id: dpPreferCharging, change: 'ne'}, function(obj) { calcVictronFlow(); }); on({id: dpPreferDischarging, change: 'ne'}, function(obj) { calcVictronFlow(); }); // Netzbezug-Ănderung on({id: dpNetzbezug, change: 'ne'}, function(obj) { calcVictronFlow(); }); schedule("*/3 * * * * *", function () { // calcVictronFlow() }); on({id: dpVictronGridTolerance, change: 'ne'}, function(obj) { calcVictronFlow(); }); // Fremdbezug / Fremdladung Ănderung on({id: dpForeignFlow, change: 'ne'}, function(obj) { //calcVictronFlow(); }); // Victron SoC-Ănderung on({id: dpVictronSoCModbus, change: 'ne'}, function(obj) { getCapacity(); //calcVictronFlow(); }); on({id: dpVictronAvailCapModbus, change: 'ne'}, function(obj) { getCapacity(); //calcVictronFlow(); }); // Victron Flow-Ănderung on({id: dpVictronFlowModbus, change: 'ne'}, function(obj) { setState("0_userdata.0.PV.Victron.VictronFlow", getState(dpVictronFlowModbus).val, true); if(getState(dpVictronFlowModbus).val<=-100) { // LĂ€dt setState("0_userdata.0.PV.Victron.VictronAkkuRichtungVis", 1, true); } else if (getState(dpVictronFlowModbus).val>=100) { // EntlĂ€dt setState("0_userdata.0.PV.Victron.VictronAkkuRichtungVis", 2, true); } else { // Standby setState("0_userdata.0.PV.Victron.VictronAkkuRichtungVis", 0, true); } //calcVictronFlow(); }); // Victron ESSMode-Ănderung on({id: dpVictronESSModeModbus, change: 'ne'}, function(obj) { setState("0_userdata.0.PV.Victron.VictronESSMode", getState(dpVictronESSModeModbus).val, true); if(getState(dpVictronESSModeModbus).val!=3) setSetPoint(0); calcVictronFlow(); }); // Victron Zellspannungs-Ănderung on({id: dpVictronCellMinVoltage, change: 'ne'}, function(obj) { calcCellDerivation(); }); on({id: dpVictronCellMaxVoltage, change: 'ne'}, function(obj) { calcCellDerivation(); }); // Keep-Alives schedule("*/30 * * * * *", function () { if(getState(dpEnabled).val) { //calcVictronFlow(); } else { setSetPoint(getState("0_userdata.0.PV.Victron.VictronSetPoint").val); } }); // Skriptstart // --------------------------------------------------------------------- if(getState(dpEnabled).val) { setState(dpEnabled, true, true); calcVictronFlow(); } else { setSetPoint(0); setState(dpEnabled, false, true); } calcCellDerivation();@oxident said in Test Victron Energy:
@deralff Gerne ... aber wirklich "herstellerunabhĂ€ngig" ist es nicht, da ich es auf mein Senec-System gemĂŒnzt habe. Ich hoffe, Du steigst da irgendwie durch. Ist halt nie wirklich fĂŒr "andere Augen" gemacht worden (das ewige Problem der Skripter...):
// Allgemeine Datenpunkte const dpEnabled = "0_userdata.0.PV.Victron.VictronAutomatik"; // Skript aktiv const dpEnableCharging = "0_userdata.0.PV.Victron.VictronEnableCharging"; // Akkuladung erlaubt const dpEnableDischarging = "0_userdata.0.PV.Victron.VictronEnableDischarging"; // Akkuentladung erlaubt // Datenpunkt fĂŒr aktuellen Netzbezug (positive Werte) oder Netzeinspeisung (negative Werte) // WATT const dpNetzbezug = "0_userdata.0.Verbrauch.StromzĂ€hler.Leistung-Gesamt"; // Skript-Einstellungen // Datenpunkt fĂŒr Mindest-SOC const dpVictronMinSoC = "0_userdata.0.PV.Victron.VictronMinSOC"; // % // Datenpunkt fĂŒr Toleranz zu Nulleinspeisung und Nullbezug // WATT const dpVictronGridTolerance = "0_userdata.0.PV.Victron.VictronGridTolerance"; // Fremdspeicher / -anlagen // Datenpunkt fĂŒr aktuelle Entladung (negative Werte) oder Ladung (positive Werte) von Fremdakkus // WATT const dpForeignFlow = "senec.0.ENERGY.GUI_BAT_DATA_POWER"; // Victron beim Laden bevorzugen const dpPreferCharging = "0_userdata.0.PV.Victron.VictronPreferCharging"; // Victron beim Entladen bevorzugen const dpPreferDischarging = "0_userdata.0.PV.Victron.VictronPreferDischarging"; // Victron // aktueller (IST) Energiefluss vom Multiplus // >0: Akku wird geladen // =0: Standby // <0: Akku wird entladen // WATT const dpVictronFlowModbus = "modbus.2.inputRegisters.227._/Ac/ActiveIn/L1/P"; // aktueller (SOLL) Energiefluss vom Multiplus // >0: Akku soll geladen werden // =0: Standby // <0: Akku soll entladen werden // WATT const dpVictronSetPointModbus = "modbus.2.holdingRegisters.227._/Hub4/L1/AcPowerSetpoint"; // aktueller (IST) SoC und KapazitĂ€t vom Multiplus // PROZENT const dpVictronSoCModbus = "modbus.2.inputRegisters.100._/Dc/Battery/Soc"; // Ah const dpVictronAvailCapModbus = "modbus.2.inputRegisters.225._/Capacity"; // Unterschied der Zellspannungen // Ziel-DP: let dpVictronCellDerivation = '0_userdata.0.PV.Victron.VictronCellDrift' // Quell-DPs: let dpVictronCellMinVoltage = 'modbus.2.inputRegisters.225._/System/MinCellVoltage' let dpVictronCellMaxVoltage = 'modbus.2.inputRegisters.225._/System/MaxCellVoltage' // Multiplus-Leerlaufzeit // schaltet Inverter und LadegerĂ€t nach x Minuten aus // falls nicht mehr benötigt const idleTimerMin = 10; //min // Nennspannung const BatteryVoltageRated = 48; //V // AgressivitĂ€t der Laderegelung // Faktor mit dem der Netzbezug oder die Einspeisung // pro Schritt ausgeglichen wird // 0.0 (0%) ... 1.0 (100%) const regulationLevel = 0.6; // // aktueller (IST) ESS-Modus vom Multiplus // 1: ESS mit Phasenkompensation (Standard) // 2: ESS ohne Phasenkompensation // 3: Externe Steuerung const dpVictronESSModeModbus = "modbus.2.holdingRegisters.100._/Settings/Cgwacs/Hub4Mode"; // Modbus // aktueller Betriebsmodus vom Multiplus // 1=Charger Only;2=Inverter Only;3=On;4=Off const dpVictronModeModbus = "modbus.2.holdingRegisters.227._/Mode"; // Modbus function calcVictronFlow() { if((getState(dpVictronFlowModbus).val)!=null) { if((getState(dpEnabled).val)&&(getState(dpVictronESSModeModbus).val==3)) { var Netzbezug = getState(dpNetzbezug).val; // + = Bezug, - = Einspeisung var Fremdbezug = getState(dpForeignFlow).val; // + = Fremdakku lĂ€dt, - = Fremdakku entlĂ€dt var VictronSoC = getState(dpVictronSoCModbus).val; var VictronSetPoint = getState(dpVictronFlowModbus).val; // + = Victron lĂ€dt, - = Victron entlĂ€dt var Hausverbrauch = Netzbezug + (VictronSetPoint*-1); var ForeignBatteryModificator = 0; if(Fremdbezug > getState(dpVictronGridTolerance).val) { // Fremdakku wird geladen if(getState(dpPreferCharging).val) { // ... stattdessen Victron laden ForeignBatteryModificator = Fremdbezug - getState(dpVictronGridTolerance).val; ForeignBatteryModificator *= -1; } } else if (Fremdbezug < (0-getState(dpVictronGridTolerance).val)) { // Fremdakku wird entladen if(getState(dpPreferCharging).val) { // ... stattdessen Victron entladen ForeignBatteryModificator = Fremdbezug + getState(dpVictronGridTolerance).val; } } Netzbezug += ForeignBatteryModificator; Netzbezug = Math.ceil(Netzbezug); //console.log(Hausverbrauch); if(Hausverbrauch > getState(dpVictronGridTolerance).val) { // Netzbezug ĂŒber Toleranz if(Fremdbezug>getState(dpVictronGridTolerance).val) { // Sonderfall: Vermeiden, dass Fremdakku durch Victron geladen wird //console.log("Fremdakku wird trotz " + Netzbezug + "W Netzbezug / " + Hausverbrauch + "W Hausverbrauch geladen mit " + Fremdbezug + "W"); //VictronSetPoint = 0; VictronSetPoint += Math.floor(Fremdbezug * regulationLevel); setSetPoint(VictronSetPoint); } else { if(getState(dpEnableDischarging).val) { // Entladen erlaubt (via DP) //console.log("Entladen mit: " + Netzbezug); //console.log("Netzbezug " + Netzbezug + "W, Setpoint: " + VictronSetPoint + "W, Fremdbezug " + Fremdbezug); VictronSetPoint-=Math.floor(Netzbezug * regulationLevel); if((Math.abs(Fremdbezug) > getState(dpVictronGridTolerance).val)) { // Fremdakku wird genutzt //VictronSetPoint-=Netzbezug; VictronSetPoint+=(getState(dpVictronGridTolerance).val * regulationLevel); } else { // Fremdakku wird NICHT genutzt //VictronSetPoint-=Math.floor(Netzbezug * regulationLevel); } //console.log("Setpoint Neu: " + VictronSetPoint + "W"); setSetPoint(VictronSetPoint); } else { // Entladen nicht erlaubt (via DP) VictronSetPoint = 0; setSetPoint(0); //console.log("Laden gesperrt via DP"); } } } else if (Hausverbrauch < (0 - getState(dpVictronGridTolerance).val)) { // Netzeinspeisung ĂŒber Toleranz if(getState(dpEnableCharging).val) { // Beladen erlaubt //console.log("Beladen mit: " + (Netzbezug*-1)); VictronSetPoint+=Math.floor(Netzbezug*-1*regulationLevel); if((Math.abs(Fremdbezug) > getState(dpVictronGridTolerance).val)) { // Fremdakku wird genutzt VictronSetPoint-=Math.floor(getState(dpVictronGridTolerance).val/2); } //if(Fremdbezug<0) { // VictronSetPoint += Fremdbezug; // sonst Problem bei vollem Fremdakku // VictronSetPoint -= getState(dpVictronGridTolerance).val; //} //console.log(Fremdbezug); setSetPoint(VictronSetPoint); } else { // Beladen nicht erlaubt (via DP) VictronSetPoint = 0; setSetPoint(0); //console.log("Entladen gesperrt via DP"); } } else { //console.log("Standby"); if(getState(dpEnabled).val) VictronSetPoint = 0; setSetPoint(VictronSetPoint); } } else { if(getState(dpVictronESSModeModbus).val==3) { // Skript deaktiviert // manueller Modus // ESS-Mode 3 VictronSetPoint = getState("0_userdata.0.PV.Victron.VictronSetPoint").val; setSetPoint(VictronSetPoint); } else { // ESS-Mode 1/2 // Buggy! setState(dpEnabled, false, false); } setState(dpEnabled, false, true); //console.log("Victron inaktiv"); } } else { // Victron-Werte nicht aktuell / Keep-Alive abwarten // console.log("Werte nicht aktuell"); // console.log(console.trace()); } } function getSafeSetPoint(desiredSetPoint) { var SafeSetPoint = desiredSetPoint; //console.log(desiredSetPoint + " angefragt"); if(desiredSetPoint>0) { // Laden des Akkus angefragt // (sollte eigentlich immer durch BMS begrenzt werden) if(getState("modbus.2.inputRegisters.227._/Bms/AllowToCharge").val==1) { // Laden durch BMS erlaubt // BOL-Limit SafeSetPoint = Math.min(getState("modbus.2.inputRegisters.225._/Info/MaxChargeCurrent").val * getState("modbus.2.inputRegisters.225._/Info/MaxChargeVoltage").val, SafeSetPoint); // Hard-Limit AC (7kW) SafeSetPoint = Math.min(7000, SafeSetPoint); // 80%-Kappung (Workaround wegen Fremdakku) // aber nur im Automatik-Modus // if(getState(dpEnabled).val) SafeSetPoint *= 0.8; // Mindesteinspeisung erreichen (wegen Fremdakku) // aber nur im Automatik-Modus //if(getState(dpEnabled).val) SafeSetPoint -= getState(dpVictronGridTolerance).val; // Ladelimits anhand SoC if((getState(dpVictronSoCModbus).val) >= 99) { SafeSetPoint = Math.min(desiredSetPoint, 0); } else if((getState(dpVictronSoCModbus).val) >= 98) { SafeSetPoint = Math.min(desiredSetPoint, 100); } else if((getState(dpVictronSoCModbus).val) >= 95) { SafeSetPoint = Math.min(desiredSetPoint, 500); } else if((getState(dpVictronSoCModbus).val) >= 90) { SafeSetPoint = Math.min(desiredSetPoint, 1500); } // Cell-Drift if((getState(dpVictronCellDerivation).val) > 150) { SafeSetPoint = Math.min(desiredSetPoint, 0); console.log("Hohe Abweichung der Zellenspannung - Ladung gesperrt!"); } else if((getState(dpVictronCellDerivation).val) > 100) { SafeSetPoint = Math.min(desiredSetPoint, 200); //console.log("Hohe Abweichung der Zellenspannung - Ladung gedrosselt."); } // Vergleich zum gewĂŒnschten SetPoint SafeSetPoint = Math.min(desiredSetPoint, SafeSetPoint); } else { SafeSetPoint = 0; } } else if(desiredSetPoint<0) { // Entladen des Akkus angefragt // (wird nicht durch BMS geprĂŒft!) //console.log("Entladen angefragt"); // Minimum-SoC if (getState(dpVictronMinSoC).val > getState(dpVictronSoCModbus).val) { //console.log("SoC zu niedrig"); SafeSetPoint = 0; } else if(getState("modbus.2.inputRegisters.227._/Bms/AllowToDischarge").val==1) { //console.log("SoC ok"); // Entladen durch BMS ind Mindest-SoC erlaubt //console.log("Min-SoC: " + getState(dpVictronMinSoC).val + " SoC: " + getState(dpVictronSoCModbus).val); // Battery-Limit SafeSetPoint = Math.max(getState("modbus.2.inputRegisters.225._/Info/MaxDischargeCurrent").val * getState("modbus.2.inputRegisters.225._/Info/BatteryLowVoltage").val*-1, SafeSetPoint); // Hard-Limit AC (7kW) SafeSetPoint = Math.max(-7000, SafeSetPoint); // 90%-Kappung (Workaround wegen Fremdakku) // aber nur im Automatik-Modus // if(getState(dpEnabled).val) SafeSetPoint *= 0.9; // geringen Netzbezug erlauben // aber nur im Automatik-Modus //if(getState(dpEnabled).val) SafeSetPoint -= getState(dpVictronGridTolerance).val; // Entladelimits anhand SoC if((getState(dpVictronSoCModbus).val) <= 10) { SafeSetPoint = Math.max(desiredSetPoint, -1000); } else if((getState(dpVictronSoCModbus).val) <= 20) { SafeSetPoint = Math.max(desiredSetPoint, -2000); } // Vergleich zum gewĂŒnschten SetPoint SafeSetPoint = Math.max(desiredSetPoint, SafeSetPoint); } else { SafeSetPoint = 0; } } else { // Standby angefragt SafeSetPoint = 0; } SafeSetPoint = Math.floor(SafeSetPoint); if(Math.abs(SafeSetPoint) < 70) SafeSetPoint = 0; if(SafeSetPoint!=desiredSetPoint) { //console.log("SetPoint limitiert von " + desiredSetPoint + "W auf " + SafeSetPoint + "W"); } //console.log(SafeSetPoint); return SafeSetPoint; } function setSetPoint(newSetPoint) { if(getState(dpVictronESSModeModbus).val==3) { var targetSetpoint = getSafeSetPoint(newSetPoint); //console.log("SafeSetPoint: " + targetSetpoint); if(targetSetpoint>0) { if(getState(dpEnableDischarging).val) { // LadegerĂ€t und Inverter aktivieren if(getState(dpVictronModeModbus).val != 3) { setState(dpVictronModeModbus, 3); return; // warte bis MP eingeschaltet } } else { // nur LadegerĂ€t aktivieren if(getState(dpVictronModeModbus).val != 1) { setState(dpVictronModeModbus, 1); return; // warte bis MP eingeschaltet } } //console.log("setSetPoint " + targetSetpoint); setState(dpVictronSetPointModbus, targetSetpoint); setState("0_userdata.0.PV.Victron.VictronSetPoint", targetSetpoint, true); } else if(targetSetpoint<0) { if(getState(dpEnableCharging).val) { // LadegerĂ€t und Inverter aktivieren if(getState(dpVictronModeModbus).val != 3) { setState(dpVictronModeModbus, 3); return; // warte bis MP eingeschaltet } } else { // nur Inverter aktivieren if(getState(dpVictronModeModbus).val != 2) { setState(dpVictronModeModbus, 2); return; // warte bis MP eingeschaltet } } //console.log("setSetPoint " + targetSetpoint); setState(dpVictronSetPointModbus, targetSetpoint); setState("0_userdata.0.PV.Victron.VictronSetPoint", targetSetpoint, true); } else { // Aus /*if(getState(dpVictronSetPointModbus).val != 0)*/ //console.log("Modus: " + getState(dpVictronModeModbus).val); if(getState(dpVictronModeModbus).val != 4) { if(getState(dpVictronSetPointModbus).val != 0) setState(dpVictronSetPointModbus, 0); if(getState(dpVictronSetPointModbus).lc<(Date.now()-(idleTimerMin*60*1000))) { // nach x min MP ausschalten //console.log("Schalte Victron aus"); setState(dpVictronModeModbus, 4); } } } } else { // keine externe Steuerung } } function getCapacity() { setState("0_userdata.0.PV.Victron.VictronSOC", getState(dpVictronSoCModbus).val, true); setState("0_userdata.0.PV.Victron.VictronLadestandJetzt", (getState(dpVictronAvailCapModbus).val * BatteryVoltageRated)/1000, true); setState("0_userdata.0.PV.Victron.VictronLadestandMax", 11184, true); } function calcCellDerivation() { setState(dpVictronCellDerivation, 1000*(getState(dpVictronCellMaxVoltage).val - getState(dpVictronCellMinVoltage).val), true); } // Trigger // Skript aktiviert / deaktiviert on({id: dpEnabled, change: 'ne', ack: false}, function(obj) { setSetPoint(0); setState("0_userdata.0.PV.Victron.VictronSetPoint", 0, true); setState(dpEnabled, getState(dpEnabled).val, true); }); on({id: dpEnableCharging, change: 'ne', ack: false}, function(obj) { setSetPoint(0); setState(dpEnableCharging, getState(dpEnableCharging).val, true); }); on({id: dpEnableDischarging, change: 'ne', ack: false}, function(obj) { setSetPoint(0); setState(dpEnableDischarging, getState(dpEnableDischarging).val, true); }); on({id: dpPreferCharging, change: 'ne'}, function(obj) { calcVictronFlow(); }); on({id: dpPreferDischarging, change: 'ne'}, function(obj) { calcVictronFlow(); }); // Netzbezug-Ănderung on({id: dpNetzbezug, change: 'ne'}, function(obj) { calcVictronFlow(); }); schedule("*/3 * * * * *", function () { // calcVictronFlow() }); on({id: dpVictronGridTolerance, change: 'ne'}, function(obj) { calcVictronFlow(); }); // Fremdbezug / Fremdladung Ănderung on({id: dpForeignFlow, change: 'ne'}, function(obj) { //calcVictronFlow(); }); // Victron SoC-Ănderung on({id: dpVictronSoCModbus, change: 'ne'}, function(obj) { getCapacity(); //calcVictronFlow(); }); on({id: dpVictronAvailCapModbus, change: 'ne'}, function(obj) { getCapacity(); //calcVictronFlow(); }); // Victron Flow-Ănderung on({id: dpVictronFlowModbus, change: 'ne'}, function(obj) { setState("0_userdata.0.PV.Victron.VictronFlow", getState(dpVictronFlowModbus).val, true); if(getState(dpVictronFlowModbus).val<=-100) { // LĂ€dt setState("0_userdata.0.PV.Victron.VictronAkkuRichtungVis", 1, true); } else if (getState(dpVictronFlowModbus).val>=100) { // EntlĂ€dt setState("0_userdata.0.PV.Victron.VictronAkkuRichtungVis", 2, true); } else { // Standby setState("0_userdata.0.PV.Victron.VictronAkkuRichtungVis", 0, true); } //calcVictronFlow(); }); // Victron ESSMode-Ănderung on({id: dpVictronESSModeModbus, change: 'ne'}, function(obj) { setState("0_userdata.0.PV.Victron.VictronESSMode", getState(dpVictronESSModeModbus).val, true); if(getState(dpVictronESSModeModbus).val!=3) setSetPoint(0); calcVictronFlow(); }); // Victron Zellspannungs-Ănderung on({id: dpVictronCellMinVoltage, change: 'ne'}, function(obj) { calcCellDerivation(); }); on({id: dpVictronCellMaxVoltage, change: 'ne'}, function(obj) { calcCellDerivation(); }); // Keep-Alives schedule("*/30 * * * * *", function () { if(getState(dpEnabled).val) { //calcVictronFlow(); } else { setSetPoint(getState("0_userdata.0.PV.Victron.VictronSetPoint").val); } }); // Skriptstart // --------------------------------------------------------------------- if(getState(dpEnabled).val) { setState(dpEnabled, true, true); calcVictronFlow(); } else { setSetPoint(0); setState(dpEnabled, false, true); } calcCellDerivation();Das solte kein Problem darstellen. Ist ja alles schön kommentiert ;)
Und glaub mir... DAS IST NICHT IMMER SO... ganz lustig wirds dann, wenn drei verschiedene Sprachen in einem Code vorhanden sind :)Danke dir!
-
Habe jetzt mal spontan den Adapter getestet. Lief sofort ohne Probleme. Super Arbeit!!
Wegen der Möglichkeiten, den Multiplus bzw. das ganze ESS manuell zu regeln habe ich mal ein Issue aufgemacht:
https://github.com/derAlff/ioBroker.ve/issues/12 -
Habe jetzt mal spontan den Adapter getestet. Lief sofort ohne Probleme. Super Arbeit!!
Wegen der Möglichkeiten, den Multiplus bzw. das ganze ESS manuell zu regeln habe ich mal ein Issue aufgemacht:
https://github.com/derAlff/ioBroker.ve/issues/12@oxident ja danke! Den feature request habe ich so schon in meine ToDo aufgenommen đ
Kannst du mir eventuell noch sagen, welches GX GerÀt du benutzt?
Noch was an alle in diesem Thread: Ich habe die PV-Wechselrichter in der letzten Version in ein separates Objekt gepackt. Dieses Objekt fasse ich allerdings noch gar nicht an đ . Das heiĂt, die Daten des/der PV Wechselrichter werden zur Zeit nicht geloggt đ.
-
@oxident ja danke! Den feature request habe ich so schon in meine ToDo aufgenommen đ
Kannst du mir eventuell noch sagen, welches GX GerÀt du benutzt?
Noch was an alle in diesem Thread: Ich habe die PV-Wechselrichter in der letzten Version in ein separates Objekt gepackt. Dieses Objekt fasse ich allerdings noch gar nicht an đ . Das heiĂt, die Daten des/der PV Wechselrichter werden zur Zeit nicht geloggt đ.
@deralff Ich nutze ganz klassisch einen Cerbo GX (mit der Large-Firmware).
StromzÀhler emuliere ich via dbus (lese den ABB-StromzÀhler/Enfluri von Senec und ziehe dort die Akkuladung des Senec-Speichers ab).
Akku-Entladung des Senec simuliere ich ebenfalls via dbus (als PV-Wechselrichter). Ebenfalls verbunden ist ein Fronius-WR via TCP/IP.
Am Multiplus-II/5000 hÀngt ein China-Akku (11kWh Lifepo4). Dessen BMS ist via CAN-Bus am Cerbo.
Das erkennt und verarbeitet Dein Adapter auch prima:

Passt also alles. Gute Arbeit

Spontan fÀllt mir noch auf, dass es eventuell sinnvoll wÀre, auch die "installed capacity" auszuwerten. Dein Adapter zeigt ja derzeit die "available capacity".
Auch die, vermutlich ja recht wichtige, Abweichung der Zellspannung wÀre vermutlich in mV besser. Aber da weià ich nicht, was Victron da liefert. Ich vergleiche derzeit halt min/max und reagiere entsprechend.
-
Gerade eben habe ich eine neue Version des Adapters auf Github hochgeladen.
Im Grunde habe ich die Wechselrichter, die abgefragt werden können, dynamisch als Objekt angelegt. Dieses Objekt wird nun anhand einer "Anzahl Wechselrichter" in der Adapter Konfiguration festgelegt.

Ist genau diese Anzahl mit 0 angegeben, so werden die Wechselrichter ignoriert.
Die Wechselrichter werden in den Objekten in einem Separaten Ordner (Inverter) mit der jeweiligen ID angelegt.

-
Aktuelle Test Version 0.3.1 Veröffentlichungsdatum 11.03.2023 Letzte Ănderung am 31.05.2024 Github Link https://github.com/derAlff/ioBroker.ve Hallo alle zusammen.
Ich habe einen kleinen Adapter erstellt, der die Daten eines Victron Energy Batteriespeichers auslesen kann. Ich weiĂ, der Name das Adapters ist nicht gerade gĂŒnstig (âveâ steht fĂŒr Victron Energy). Ich bin allerdings schon dran, damit ich Namen und auch Logo verwenden darf.
Der Adapter kann bisher einige Modbus-Register auslesen und in Datenpunkte speichern. Das selbe per MQTT implementiere ich auch noch.
Dann gibt es noch die Benutzer, die gerne die Daten aus dem VRM Portal haben möchten. Dazu gibt es auch irgendwann eine Option im Adapter.
Die Register, die bisher implementiert sind, wurden alle mit einem Victron Energy Multiplus 2 GX und Pylontech Akkus in mĂŒhevoller Kleinarbeit eingefĂŒgt und getestet.
Ich freue mich auf Benutzer, die ebenfalls einen Victron Energy Batteriespeicher haben. Schreibt mich einfach per Mail/DM an, oder erstellt ein GitHub Issue ;)
-
@deralff Super, besten Dank fĂŒr deine Arbeit! Ich bin auch einer, der ĂŒber das VRM Daten brĂ€uchte. Bei mir wird es ein 520 GSM sein, dass einen SmartShunt ins VRM bringt. Diese Daten hĂ€tte ich gerne im ioBroker :)
@humidor da bin ich parallel dran am arbeiten đ. Ist das super dringend? Der Adapter kann zur Zeit nicht wirklich viel und ist auch noch nicht online đ .
Brauche noch etwas Zeit -> Umbau und so đ
Darf ich dich noch fragen warum unbedingt die Daten aus dem VRM?
Viele GrĂŒĂe
-
Hallo liebe Tester,
ich habe gerade eben eine neue Version zum Testen auf Github hochgeladen. Die neue Version hört auf den Namen "0.3.0".
Folgendes hat sich geÀndert:
- Die Datenpunkte werden nun als nur lesbar oder auch schreibbar angelegt. Dazu kam in der JSON der Register eine Option "writable" hinzu.
- FĂŒr die Wechselrichter habe ich das Register 1052 (Total Power) hinzugefĂŒgt.
- Grid hat auch weitere Datenpunkte bekommen (Voltage/Spannung, Current/Strom, EnergyFromNet/EnergieVomNetz und EnergyToNet/EnergieZumNetz)
- In den 4 Registern "BatteryError" hatte sich ein Fehler eingeschliechen -> wurde behoben.
- Die Wichtigste Ănderung! Ich habe nun die Objekte bzw Datenpunkte im Objektbaum in Unterordner zusammengefasst. Also, wenn ihr die Datenpunkte in irgendwelchen Scripts benutzt, dann denkt bitte daran, die neuern Datenpunkte mit den Unterordnern in den Scripten einzutragen.
Vorher:
Ab version 0.3.0:

Viele GrĂŒĂe!
-
Hallo liebe Tester,
ich habe gerade eben eine neue Version zum Testen auf Github hochgeladen. Die neue Version hört auf den Namen "0.3.0".
Folgendes hat sich geÀndert:
- Die Datenpunkte werden nun als nur lesbar oder auch schreibbar angelegt. Dazu kam in der JSON der Register eine Option "writable" hinzu.
- FĂŒr die Wechselrichter habe ich das Register 1052 (Total Power) hinzugefĂŒgt.
- Grid hat auch weitere Datenpunkte bekommen (Voltage/Spannung, Current/Strom, EnergyFromNet/EnergieVomNetz und EnergyToNet/EnergieZumNetz)
- In den 4 Registern "BatteryError" hatte sich ein Fehler eingeschliechen -> wurde behoben.
- Die Wichtigste Ănderung! Ich habe nun die Objekte bzw Datenpunkte im Objektbaum in Unterordner zusammengefasst. Also, wenn ihr die Datenpunkte in irgendwelchen Scripts benutzt, dann denkt bitte daran, die neuern Datenpunkte mit den Unterordnern in den Scripten einzutragen.
Vorher:
Ab version 0.3.0:

Viele GrĂŒĂe!
-
@deralff Also ich habe einen MP2 GX und 2 Pylontech uc3000.
KEINEN PV Wechselrichter im System, da meiner noch kein WLAN / LAN hat.
Was liefert mir der Adapter alles?
Im Moment bekomme ich diese Daten ĂŒber Mdobus:
@ben1983 [OT]
wo hast du die Vmin und Vmax her?ich bekomme nix ĂŒber

-
@homoran Aus der Adressliste von Victron:

(+1)@ben1983
DANKE!
welche GerÀte ID?
battery lĂ€uft bei mir ĂŒber 225. -
@deralff Also ich habe einen MP2 GX und 2 Pylontech uc3000.
KEINEN PV Wechselrichter im System, da meiner noch kein WLAN / LAN hat.
Was liefert mir der Adapter alles?
Im Moment bekomme ich diese Daten ĂŒber Mdobus:
@ben1983 Dazu dann einfach den Adapter installieren und in der Konfiguration bei "Anzahl PV-Wechselrichter" eine 0 eintragen.

Du musst im GX Modbus aktivieren! Sonst funktioniert das Ganze nicht. Am besten auch die IP-Adresse statisch vergeben. Nicht das der GX nach einem Stromausfall oder so, eine andere IP bekommt ;)
Bisher werden folgende Werte abgefragt:

Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.
Hast du es satt, bei jedem Besuch durch die gleichen BeitrĂ€ge zu scrollen? Wenn du dich fĂŒr ein Konto anmeldest, kommst du immer genau dorthin zurĂŒck, wo du zuvor warst, und kannst dich ĂŒber neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und BeitrĂ€ge positiv bewerten, um anderen Community-Mitgliedern deine WertschĂ€tzung zu zeigen.
Mit deinem Input könnte dieser Beitrag noch besser werden đ
Registrieren Anmelden