SMA SBS25 mit Batterie - entladen / beladen (ModBusdevice vorausgesetzt)

Begonnen von 300P, 23 Februar 2025, 17:38:17

Vorheriges Thema - Nächstes Thema

300P

Hallo an alle Interessierten !

im Thread für das Modul 76_SMAInverter wurde von MadMax angeregt einen Thread für SMA Batteriewechselrichter aufzumachen, in dem das Laden / Einladen dieser SMA-BWR behandelt. wird

Während meiner 12 Monate als Tibber-Kunde habe ich mittels diese 3 kleinen Sub-Routinen in MyUtils das Vorhaben gelöst. ;D
Inzwischen bin ich schon länger wieder "Strom-Festpreis-Kunde" (aus rein wirtschaftlicher Erwägung).
Die Zeilen für die Lade-Steuerung gemäß der vermeintlich günstigsten Ladezeit hab ich irgendwo als Backup - aber das ist ja nicht Thema in diesem Thread. ;)

Hier die wenigen Zeilen - ein passendes Modbusdevice vorausgesetzt - für meine beiden SMA-SBS25:

sub SMABatteryChargeON()
{
    #Werte für Ladung der Batterie per Grid/Netzstrom Modbus an Battery senden
    fhem("set MB_SBS25 Set_Leistung_W -8000"); # 0 Watt Netzleistung am Übergabemesspunkt (WR1)
    fhem("set MB_SBS25_2 Set_Leistung_W -8000");  # 0 Watt Netzleistung am Übergabemesspunkt (WR2)
    fhem("set MB_SBS25 Set_Aktiv 802");  # 802 - Steuerung aktiv (WR1)
    fhem("set MB_SBS25_2 Set_Aktiv 802");   # 802 - Steuerung aktiv (WR2)
}

sub SMABatteryChargeOFF()
{
    #Werte für KEINE Ladung der Batterie per Netz/Netzstrom per Modbus an Battery senden  - (wenn nicht klappt evtl delay oder wait einbauen???)
    fhem("set MB_SBS25 Set_Leistung_W -20"); # 0 Watt Netzleistung am Übergabemesspunkt (WR1)
    fhem("set MB_SBS25_2 Set_Leistung_W -20");  # 0 Watt Netzleistung am Übergabemesspunkt (WR2)
    fhem("set MB_SBS25 Set_Aktiv 803");  # 803 - Steuerung nicht aktiv (WR1)
    fhem("set MB_SBS25_2 Set_Aktiv 803");   # 803 - Steuerung nicht aktiv (WR2)
}

sub SMABatteryEnergyControl($$)
{
    #mit Werteübergabe für Ladung- und Beladung per Modbus an Battery senden
my ($Set_Leistung01, $Set_Leistung02) = @_;

if($Set_Leistung01 eq "")
# Standart ohne Angabe = "-20" = 20 Watt Einspeiseleistung am Übergabemesspunkt - gleiche Werte beide WR setzen
  {
    $Set_Leistung01 = "-20";
  }
if($Set_Leistung02 eq "")
# Standart ohne Angabe = "-20" = 20 Watt Einspeiseleistung am Übergabemesspunkt - gleiche Werte  beide WR setzen
  {
    $Set_Leistung02 = "-20";
  }

   Log3 undef, 3, "SMABatteryEnergyControl: BatteryCharge  Battery01 :  $Set_Leistung01 W    Battery0102 : $Set_Leistung02  W";

    fhem("set MB_SBS25 Set_Leistung_W ".$Set_Leistung01); # Standart ohne Angabe = "-20" = 20 Watt Einspeiseleistung am Übergabemesspunkt (WR1 SBS25)
    fhem("set MB_SBS25_2 Set_Leistung_W ".$Set_Leistung02); # Standart ohne Angabe = "-20") 20 Watt Einspeiseleistung am Übergabemesspunkt (WR2 SBS25_2)
    fhem("set MB_SBS25 Set_Aktiv 802");  # 802 - Steuerung aktiv (WR1 SBS25)
    fhem("set MB_SBS25_2 Set_Aktiv 802");   # 802 - Steuerung aktiv (WR2 SBS25_2)
}


Hier auch noch die zugehörigen ModBus Adressen und Kurzhinweise dazu:

manuelles Ent-/Beladen einschalten:

Set_Leistung_W 8000 / -8000       
# gewählter Max. +/-Bezug in Watt am Netzübergangspunkt (ADDR 40149)

Set_Aktiv  802                   
# Einschalten Kommunikationsregelung (ADDR 40151)
Dieser SET (803) ergibt folgenden Eintrag im WR:
10421 Eigenverbrauchsregelung wurde gestoppt

Achtung:
- Bei mir in den SBS25-Batterien steht.....:
  30 Minuten mit aktuellen Werten auf Kommunikationssteuerung warten (bevor autom. auf Normal geregelt wird).
  Dadurch bleibt die Ent-/Beladung 30 Minuten so ohne erneut geschrieben zu werden.
  Ansonsten muss man alle max. 15 Sekunden diese Werte erneut schreiben.
  Daher extra zum Ausschalten (bei mir):

Ausschalten ("direkt") dann mit dieser Wartezeit beendet wird mit :
Set_Aktiv  803                   # Ausschalten Kommunikationsregelung

Dieser SET (803) ergibt folgenden Eintrag im WR:
10420 Eigenverbrauchsregelung wurde gestartet

Notwendige anzusprechende ModBus-Register-Adressen im SBS25:

obj-h40149-expr $val
obj-h40149-len 2
obj-h40149-name SBS25_Set_Leistung_W
obj-h40149-poll once
obj-h40149-reading Set_Leistung_W
obj-h40149-set 1
obj-h40149-unpack I>
obj-h40151-expr $val
obj-h40151-name SBS25_Set_Aktiv
obj-h40151-poll once
obj-h40151-reading Set_Aktiv
obj-h40151-set 1
Bei anderen SMA-BWR bitte explizit die evtl. anderslautenden und richtigen Adressen in der zugehörigen ModBus-Dokumentation nutzen/prüfen ! 8)

Viel Spass beim Erproben der Routinen. ;)

Gruß
300P
FHEM 6.4|RaspberryPi|SMAEM|SMAInverter|SolarForecast|DbLog|DbRep|MariaDB|QNAP|
JsonMod|HTTPMOD|Modbus ser+TCP|ESP32-Digitizer-AI_on_the_edge|ESP32CAM

MadMax

Hier meine Lösung.

Als erstes der Dummy der die Daten sammelt und über den ich Eingreifen kann.

defmod PV_Battery.d dummy
attr PV_Battery.d alias PV_Battery.d
attr PV_Battery.d devStateIcon {\
my $mode = 'message_attention@red';;;;\
$mode = 'time_manual_mode@yellow' if (ReadingsVal($name, "Automatic", "") eq "test");;;;\
$mode = 'system_fhem_reboot@green' if (ReadingsVal($name, "Automatic", "") eq "on");;;;\
\
my $chargePw = ReadingsNum($name, "BAT_PWR", "");;;;\
my $chargePCT = ReadingsNum($name, "BAT_PCT", "");;;;\
\
my $charge = '';;;;\
$charge = 'control_arrow_leftward@greenyellow' if ($chargePw < 0);;;;\
$charge = 'control_arrow_rightward@green' if ($chargePw > 0);;;;\
\
my $ChargeStatus = 'measure_battery_100@green';;;;\
$ChargeStatus = 'measure_battery_75@green' if ($chargePCT < 80);;;;\
$ChargeStatus = 'measure_battery_50@yellow' if ($chargePCT < 55);;;;\
$ChargeStatus = 'measure_battery_25@orange' if ($chargePCT < 30);;;;\
$ChargeStatus = 'measure_battery_0@red' if ($chargePCT < 6);;;;\
\
"<div>" .\
FW_makeImage($ChargeStatus,"") . \
FW_makeImage($charge,"") ." ". $chargePw ."W   ". \
$chargePCT ."% ".\
" </br> ".FW_makeImage($mode,"measure_power")." ".\
ReadingsVal($name, "INFO_Sollwertherkunft", "")."\
</div>"}
attr PV_Battery.d event-min-interval .*:900
attr PV_Battery.d event-on-change-reading DischargeMode.*:0.1,SBS_Bereit:0.1,SBS_Bereit:0.1,BAT_PCT:0.5,.*:10
attr PV_Battery.d readingList DischargeSpeicherWechsel ladenVoll MaxSOC MinSOC Send Calc Set_Aktiv Set_BMS_Mode Set_EntladeP_max Set_EntladeP_min Set_LadeP_max Set_LadeP_min Set_Leistung Set_Netzaustauschleistung Automatic LadeStop
attr PV_Battery.d room PV->BYD,PV->Speichersteuerung,PV->Stromversorgung
attr PV_Battery.d setList DischargeSpeicherWechsel:HVM,- ladenVoll MaxSOC MinSOC Send:trigger Calc:trigger Set_Aktiv:802,803 Set_BMS_Mode Set_EntladeP_max Set_EntladeP_min Set_LadeP_max Set_LadeP_min Set_Leistung:slider,-8000,100,8000 Set_Netzaustauschleistung Set_Leistung_Aktiv:on,off Send_Aktiv:on,off Automatic:on,off,test LadeStop:on,off
attr PV_Battery.d webCmd Automatic:DischargeSpeicherWechsel

Dann ein Dummy für den Hybrid WR.
defmod STP8SE.d dummy
attr STP8SE.d alias STP8SE.d
attr STP8SE.d devStateIcon {\
my $mode = 'time_automatic@green';;;;\
$mode = 'system_fhem_reboot@green' if (ReadingsVal($name, "Set_Aktiv", "") eq "802");;;;\
$mode = 'time_automatic@red' if (ReadingsVal($name, "Set_Aktiv", "") eq "803" && ReadingsVal($name, "INFO_Sollwert_herkunftNR", "") eq "816");;;;\
$mode = 'time_automatic@yellow' if (ReadingsVal($name, "Set_Aktiv", "") eq "803" && ReadingsVal($name, "INFO_Sollwert_herkunftNR", "") eq "814");;;;\
$mode = 'system_fhem_reboot@yellow' if (ReadingsVal($name, "Set_Aktiv", "") eq "802" && ReadingsVal($name, "INFO_Sollwert_herkunftNR", "") eq "814");;;;\
$mode = 'time_manual_mode@yellow' if (ReadingsVal($name, "Automatic", "") eq "test");;;;\
\
"<div>" . \
FW_makeImage($mode,"measure_power") ." ".ReadingsVal($name, "state", "")."\
</div>"}
attr STP8SE.d event-min-interval .*:600,Calc:1,Send.*:1
attr STP8SE.d event-on-change-reading .*
attr STP8SE.d readingList ladenVoll MaxSOC MinSOC Send Calc Set_Aktiv Set_BMS_Mode Set_EntladeP_max Set_EntladeP_min Set_LadeP_max Set_LadeP_min Set_Leistung Set_Netzaustauschleistung Set_Leistung_Aktiv Send_Aktiv Automatic LadeStop EntladeStop
attr STP8SE.d room PV->Speichersteuerung,PV->Stromversorgung
attr STP8SE.d setList ladenVoll MaxSOC MinSOC Send:trigger Calc:trigger Set_Aktiv:802,803 Set_BMS_Mode Set_EntladeP_max Set_EntladeP_min Set_LadeP_max Set_LadeP_min Set_Leistung:slider,-8000,100,8000 Set_Netzaustauschleistung Set_Leistung_Aktiv:on,off Send_Aktiv:on,off Automatic:on,off,test LadeStop:on,off EntladeStop:on,off
attr STP8SE.d userReadings Set_Aktiv_ {my %arr = (803 => 'SMA', 802 => 'FHEM');; $arr{ReadingsNum($name,"Set_Aktiv",0)}}
attr STP8SE.d webCmd Automatic:Set_Aktiv:Set_Leistung

Und ein Dummy für den SBS 2.5

defmod SBS2_5.d dummy
attr SBS2_5.d alias SBS2_5.d
attr SBS2_5.d devStateIcon {\
my $mode = 'time_automatic@green';;;;\
$mode = 'system_fhem_reboot@green' if (ReadingsVal($name, "Set_Aktiv", "") eq "802");;;;\
$mode = 'time_automatic@red' if (ReadingsVal($name, "Set_Aktiv", "") eq "803" && ReadingsVal($name, "INFO_Sollwert_herkunftNR", "") eq "816");;;;\
$mode = 'time_automatic@yellow' if (ReadingsVal($name, "Set_Aktiv", "") eq "803" && ReadingsVal($name, "INFO_Sollwert_herkunftNR", "") eq "814");;;;\
$mode = 'system_fhem_reboot@yellow' if (ReadingsVal($name, "Set_Aktiv", "") eq "802" && ReadingsVal($name, "INFO_Sollwert_herkunftNR", "") eq "814");;;;\
$mode = 'time_manual_mode@yellow' if (ReadingsVal($name, "Automatic", "") eq "test");;;;\
\
"<div>" . \
FW_makeImage($mode,"measure_power") ." ".ReadingsVal($name, "state", "")."\
</div>"}
attr SBS2_5.d event-min-interval .*:600,Calc:1,Send.*:1
attr SBS2_5.d event-on-change-reading .*
attr SBS2_5.d readingList Set_Operating_condition ladenVoll MaxSOC MinSOC Send Calc Set_Aktiv Set_BMS_Mode Set_EntladeP_max Set_EntladeP_min Set_LadeP_max Set_LadeP_min Set_Leistung Set_Netzaustauschleistung Set_Leistung_Aktiv Send_Aktiv Automatic LadeStop EntladeStop
attr SBS2_5.d room PV->Speichersteuerung,PV->Stromversorgung
attr SBS2_5.d setList ladenVoll MaxSOC MinSOC Send:trigger Calc:trigger Set_Aktiv:802,803 Set_Operating_condition:381,235 Set_BMS_Mode Set_EntladeP_max Set_EntladeP_min Set_LadeP_max Set_LadeP_min Set_Leistung:slider,-2500,100,2500 Set_Netzaustauschleistung Set_Leistung_Aktiv:on,off Send_Aktiv:on,off Automatic:on,off,test LadeStop:on,off EntladeStop:on,off
attr SBS2_5.d userReadings Set_Aktiv_ {my %arr = (803 => 'SMA', 802 => 'FHEM');; $arr{ReadingsNum($name,"Set_Aktiv",0)}}
attr SBS2_5.d webCmd Automatic:Set_Aktiv:Set_Leistung
Lenovo M910Q Tiny Debian 12, FHEM 6.3, 2x Siemens Logo 0BA7, Homematic CCU3, Philips HUE, 6x SMA Wechselrichter, BYD HVM, BYD HVS, SMA EVCharger, KEBA Wallbox, 2x HMS800W, Daikin Wärmepumpe über CAN, viele ESPs

Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/MadMax

MadMax

Hier das Notify was die Daten zum ModbusATTr Device des Hybridwechselrichters gibt.

defmod STP8SE.send.n notify STP8SE.d:Send:.* { \
\
my $this                    = "STP8SE.d";;\
\
if(ReadingsVal($this, "Send_Aktiv", "") eq "on")\
{\
\
    fhem("set STP8SE Set_Aktiv ".ReadingsVal($this, "Set_Aktiv", ""));;\
    \
    fhem("set STP8SE Set_Leistung ".ReadingsVal($this, "Set_Leistung", ""));;  \
\
    fhem("setreading ".$this." Send_check ".ReadingsVal($this, "Send", 1));;\
}\
\
}
attr STP8SE.send.n alias STP8SE.send.n
attr STP8SE.send.n room PV->Speichersteuerung

Das gleiche für den SBS 2.5

defmod SBS2_5.send.n notify SBS2_5.d:Send:.* { \
\
my $this                    = "SBS2_5.d";;\
\
if(ReadingsVal($this, "Send_Aktiv", "") eq "on")\
{\
\
    fhem("set SBS2_5 Set_Aktiv ".ReadingsVal($this, "Set_Aktiv", ""));;\
    \
    fhem("set SBS2_5 Set_Leistung ".ReadingsVal($this, "Set_Leistung", ""));;  \
\
    fhem("setreading ".$this." Send_check ".ReadingsVal($this, "Send", 1));;\
}\
\
}
attr SBS2_5.send.n alias SBS2_5.send.n
attr SBS2_5.send.n room PV->Speichersteuerung

Dann das ModbusATTr für den Hybriden.
defmod STP8SE ModbusAttr 3  30   192.168.xx.xxx:502  TCP
attr STP8SE alias STP8SE
attr STP8SE dev-h-defLen 2
attr STP8SE dev-h-defPoll 1
attr STP8SE dev-h-defUnpack N
attr STP8SE devStateIcon {\
my $mode = 'measure_power@green';;;;\
$mode = 'measure_power@yellow' if (ReadingsNum($name, "Wirkleistung", "") < 1);;;;\
\
my $dc_sum = ReadingsNum($name,"DC_Leistung",0);; \
\
my $mode2 = 'sani_solar@green';;;;\
$mode2 = 'sani_solar@yellow' if ($dc_sum < 1);;;;\
\
my $mode3 = 'solar@green';;;;\
$mode3 = 'solar@yellow' if (ReadingsNum($name,"DC_Leistung_1",0) < 1);;;;\
\
my $mode4 = 'solar@green';;;;\
$mode4 = 'solar@yellow' if (ReadingsNum($name,"DC_Leistung_2",0) < 1);;;;\
\
my $chargePw = ReadingsNum($name, "Batterieleistung", "");;;;\
my $chargePCT = ReadingsNum($name, "Ladezustand", "");;;;\
\
my $charge = '';;;;\
$charge = 'control_arrow_leftward@greenyellow' if ($chargePw < 0);;;;\
$charge = 'control_arrow_rightward@green' if ($chargePw > 0);;;;\
\
my $ChargeStatus = 'measure_battery_100@green';;;;\
$ChargeStatus = 'measure_battery_75@green' if ($chargePCT < 80);;;;\
$ChargeStatus = 'measure_battery_50@yellow' if ($chargePCT < 55);;;;\
$ChargeStatus = 'measure_battery_25@orange' if ($chargePCT < 30);;;;\
$ChargeStatus = 'measure_battery_0@red' if ($chargePCT < 6);;;;\
\
my $Cap = ($chargePCT -5) * 190;;\
\
\
"<div>" . \
FW_makeImage($mode,"measure_power") ." AC ". ReadingsVal($name,"Wirkleistung",0) ."W  ". \
FW_makeImage($mode2,"sani_solar") ." DC ".$dc_sum."W  ". \
FW_makeImage($mode3,"solar") ." MPP1 ".ReadingsVal($name,"DC_Leistung_1",0)."W  ". \
FW_makeImage($mode4,"solar") ." MPP2 ".ReadingsVal($name,"DC_Leistung_2",0)."W  </br>". \
FW_makeImage($ChargeStatus,"") . \
FW_makeImage($charge,"") ." ". $chargePw ."W   ". \
$chargePCT ."% ".\
$Cap."wh  ".\
"</div>"}
attr STP8SE event-min-interval .*:1800
attr STP8SE event-on-change-reading .*eistung.*:10,.*DC_Spannung.*:5,.*trom.*:0.2,.*EYESTERDAY.*,.*Batteriespannung.*:0.5,Ladezustand.*,.*emperatur.*:0.5
attr STP8SE obj-h30201-map 35:Fehler, 303:Aus, 307:OK, 455:Warnung
attr STP8SE obj-h30201-reading Status
attr STP8SE obj-h30217-map 16777213:Fehler, 51:geschlossen, 311:offen
attr STP8SE obj-h30217-reading Netzrelais
attr STP8SE obj-h30529-reading Gesamtertrag
attr STP8SE obj-h30535-reading Tagesertrag
attr STP8SE obj-h30769-expr ($val  & 0xFFFF) / 1000
attr STP8SE obj-h30769-format %.3f
attr STP8SE obj-h30769-reading DC_Strom_1
attr STP8SE obj-h30771-expr ($val  & 0xFFFF) / 100
attr STP8SE obj-h30771-format %.2f
attr STP8SE obj-h30771-reading DC_Spannung_1
attr STP8SE obj-h30773-reading DC_Leistung_1
attr STP8SE obj-h30775-expr $val
attr STP8SE obj-h30775-len 2
attr STP8SE obj-h30775-reading Wirkleistung
attr STP8SE obj-h30775-unpack i>
attr STP8SE obj-h30777-expr $val
attr STP8SE obj-h30777-reading Wirkleistung_L1
attr STP8SE obj-h30777-unpack i>
attr STP8SE obj-h30779-expr $val
attr STP8SE obj-h30779-reading Wirkleistung_L2
attr STP8SE obj-h30779-unpack i>
attr STP8SE obj-h30781-expr $val
attr STP8SE obj-h30781-reading Wirkleistung_L3
attr STP8SE obj-h30781-unpack i>
attr STP8SE obj-h30783-expr ($val  & 0xFFFF) / 100
attr STP8SE obj-h30783-format %.2f
attr STP8SE obj-h30783-reading AC_Spannung_1
attr STP8SE obj-h30785-expr ($val  & 0xFFFF) / 100
attr STP8SE obj-h30785-format %.2f
attr STP8SE obj-h30785-reading AC_Spannung_2
attr STP8SE obj-h30787-expr ($val  & 0xFFFF) / 100
attr STP8SE obj-h30787-format %.2f
attr STP8SE obj-h30787-reading AC_Spannung_3
attr STP8SE obj-h30843-expr $val/1000
attr STP8SE obj-h30843-format %.3f
attr STP8SE obj-h30843-reading Batteriestrom
attr STP8SE obj-h30843-unpack i>
attr STP8SE obj-h30845-reading Ladezustand
attr STP8SE obj-h30849-expr ($val  & 0xFFFF) / 10
attr STP8SE obj-h30849-format %.1f
attr STP8SE obj-h30849-reading Batterietemperatur
attr STP8SE obj-h30851-expr ($val  & 0xFFFF) / 100
attr STP8SE obj-h30851-format %.2f
attr STP8SE obj-h30851-reading Batteriespannung
attr STP8SE obj-h30953-expr ($val  & 0xFFFF) / 10
attr STP8SE obj-h30953-format %.1f
attr STP8SE obj-h30953-reading Temperatur
attr STP8SE obj-h30955-map 16777213:Fehler, 303:Aus, 2291:standby, 2292:laden, 2293:entladen
attr STP8SE obj-h30955-reading Batteriestatus
attr STP8SE obj-h30957-expr ($val  & 0xFFFF) / 1000
attr STP8SE obj-h30957-format %.3f
attr STP8SE obj-h30957-reading DC_Strom_2
attr STP8SE obj-h30959-expr ($val  & 0xFFFF) / 100
attr STP8SE obj-h30959-format %.2f
attr STP8SE obj-h30959-reading DC_Spannung_2
attr STP8SE obj-h30961-reading DC_Leistung_2
attr STP8SE obj-h31391-map 16777213:Fehler, 303:Aus, 307:OK, 455:Warnung, 35:Fehler
attr STP8SE obj-h31391-reading Batteriezustand
attr STP8SE obj-h31393-reading Batterieladeleistung
attr STP8SE obj-h31395-reading Batterieentladleistung
attr STP8SE obj-h31397-expr $val & 0xFFFFFFFFFFFFFFFF
attr STP8SE obj-h31397-len 4
attr STP8SE obj-h31397-reading Batterieladung
attr STP8SE obj-h31397-unpack Q>
attr STP8SE obj-h31401-expr $val & 0xFFFFFFFFFFFFFFFF
attr STP8SE obj-h31401-len 4
attr STP8SE obj-h31401-reading Batterieentladung
attr STP8SE obj-h31401-unpack Q>
attr STP8SE obj-h40073-reading BAT_EV_Untere_Batterieentladegrenze
attr STP8SE obj-h40073-set 1
attr STP8SE obj-h40149-len 2
attr STP8SE obj-h40149-reading Set_Leistung
attr STP8SE obj-h40149-set 1
attr STP8SE obj-h40149-unpack i>
attr STP8SE obj-h40151-reading Set_Aktiv
attr STP8SE obj-h40151-set 1
attr STP8SE obj-h40236-reading Set_BMS_Mode
attr STP8SE obj-h40236-set 1
attr STP8SE obj-h40721-reading BAT_Minimale_Breite_des_Tiefentladeschutzbereichs
attr STP8SE obj-h40721-set 1
attr STP8SE obj-h40723-reading BAT_Minimale_Breite_des_Ersatzstromsbereichs
attr STP8SE obj-h40723-set 1
attr STP8SE obj-h40781-reading Set_Netzaustauschleistung
attr STP8SE obj-h40781-set 1
attr STP8SE obj-h40793-reading Set_LadeP_min
attr STP8SE obj-h40793-set 1
attr STP8SE obj-h40795-reading Set_LadeP_max
attr STP8SE obj-h40795-set 1
attr STP8SE obj-h40797-reading Set_EntladeP_min
attr STP8SE obj-h40797-set 1
attr STP8SE obj-h40799-reading Set_EntladeP_max
attr STP8SE obj-h40799-set 1
attr STP8SE room PV->Speichersteuerung,PV->Stromversorgung
attr STP8SE verbose 0

Und für den SBS2.5
defmod SBS2_5 ModbusAttr 3  16   192.168.xx.xxx:502  TCP
attr SBS2_5 alias SBS2_5
attr SBS2_5 dev-h-defLen 2
attr SBS2_5 dev-h-defPoll 1
attr SBS2_5 dev-h-defUnpack N
attr SBS2_5 devStateIcon {\
my $pwr = ReadingsNum($name,"Wirkleistung",0);;\
\
my $mode = 'measure_power@green';;;;\
$mode = 'measure_power@yellow' if ($pwr < 1);;;;\
\
my $chargePw = ReadingsNum($name, "Batterieleistung", 0);;;;\
my $chargePCT = ReadingsNum($name, "Ladezustand", 0);;;;\
\
my $charge = '';;;;\
if($chargePw ne ""){\
  $charge = 'control_arrow_leftward@greenyellow' if ($chargePw < 0);;;;\
  $charge = 'control_arrow_rightward@green' if ($chargePw > 0);;;;\
}\
\
my $ChargeStatus = 'measure_battery_100@green';;;;\
$ChargeStatus = 'measure_battery_75@green' if ($chargePCT < 80);;;;\
$ChargeStatus = 'measure_battery_50@yellow' if ($chargePCT < 55);;;;\
$ChargeStatus = 'measure_battery_25@orange' if ($chargePCT < 30);;;;\
$ChargeStatus = 'measure_battery_0@red' if ($chargePCT < 6);;;;\
\
my $Cap = ($chargePCT -5) * 51;;\
\
\
"<div>" . \
FW_makeImage($mode,"measure_power") ." AC ". $pwr ."W  ". \
FW_makeImage($ChargeStatus,"") . \
FW_makeImage($charge,"") ." ". $chargePw ."W   ". \
$chargePCT ."% ".\
$Cap."wh  ".\
"</div>"}
attr SBS2_5 event-min-interval .*:1800
attr SBS2_5 event-on-change-reading .*eistung.*:10,.*DC_Spannung.*:5,.*trom.*:0.2,.*EYESTERDAY.*,.*Batteriespannung.*:0.5,Ladezustand.*,.*emperatur.*:0.5
attr SBS2_5 obj-h30201-map 35:Fehler, 303:Aus, 307:OK, 455:Warnung
attr SBS2_5 obj-h30201-reading Status
attr SBS2_5 obj-h30217-map 16777213:Fehler, 51:geschlossen, 311:offen
attr SBS2_5 obj-h30217-reading Netzrelais
attr SBS2_5 obj-h30529-reading Gesamtertrag
attr SBS2_5 obj-h30535-reading Tagesertrag
attr SBS2_5 obj-h30775-expr $val
attr SBS2_5 obj-h30775-len 2
attr SBS2_5 obj-h30775-reading Wirkleistung
attr SBS2_5 obj-h30775-unpack i>
attr SBS2_5 obj-h30783-expr ($val  & 0xFFFF) / 100
attr SBS2_5 obj-h30783-format %.2f
attr SBS2_5 obj-h30783-reading AC_Spannung_1
attr SBS2_5 obj-h30785-expr ($val  & 0xFFFF) / 100
attr SBS2_5 obj-h30785-format %.2f
attr SBS2_5 obj-h30785-reading AC_Spannung_2
attr SBS2_5 obj-h30787-expr ($val  & 0xFFFF) / 100
attr SBS2_5 obj-h30787-format %.2f
attr SBS2_5 obj-h30787-reading AC_Spannung_3
attr SBS2_5 obj-h30843-expr $val/1000
attr SBS2_5 obj-h30843-format %.3f
attr SBS2_5 obj-h30843-reading Batteriestrom
attr SBS2_5 obj-h30843-unpack i>
attr SBS2_5 obj-h30845-reading Ladezustand
attr SBS2_5 obj-h30849-expr ($val  & 0xFFFF) / 10
attr SBS2_5 obj-h30849-format %.1f
attr SBS2_5 obj-h30849-reading Batterietemperatur
attr SBS2_5 obj-h30851-expr ($val  & 0xFFFF) / 100
attr SBS2_5 obj-h30851-format %.2f
attr SBS2_5 obj-h30851-reading Batteriespannung
attr SBS2_5 obj-h30953-expr ($val  & 0xFFFF) / 10
attr SBS2_5 obj-h30953-format %.1f
attr SBS2_5 obj-h30953-reading Temperatur
attr SBS2_5 obj-h30955-map 16777213:Fehler, 303:Aus, 2291:standby, 2292:laden, 2293:entladen
attr SBS2_5 obj-h30955-reading Batteriestatus
attr SBS2_5 obj-h31391-map 16777213:Fehler, 303:Aus, 307:OK, 455:Warnung, 35:Fehler
attr SBS2_5 obj-h31391-reading Batteriezustand
attr SBS2_5 obj-h31393-reading Batterieladeleistung
attr SBS2_5 obj-h31395-reading Batterieentladleistung
attr SBS2_5 obj-h31397-expr $val & 0xFFFFFFFFFFFFFFFF
attr SBS2_5 obj-h31397-len 4
attr SBS2_5 obj-h31397-reading Batterieladung
attr SBS2_5 obj-h31397-unpack Q>
attr SBS2_5 obj-h31401-expr $val & 0xFFFFFFFFFFFFFFFF
attr SBS2_5 obj-h31401-len 4
attr SBS2_5 obj-h31401-reading Batterieentladung
attr SBS2_5 obj-h31401-unpack Q>
attr SBS2_5 obj-h40003-reading Set_Operating_condition
attr SBS2_5 obj-h40003-set 1
attr SBS2_5 obj-h40073-reading BAT_EV_Untere_Batterieentladegrenze
attr SBS2_5 obj-h40073-set 1
attr SBS2_5 obj-h40149-len 2
attr SBS2_5 obj-h40149-reading Set_Leistung
attr SBS2_5 obj-h40149-set 1
attr SBS2_5 obj-h40149-unpack i>
attr SBS2_5 obj-h40151-reading Set_Aktiv
attr SBS2_5 obj-h40151-set 1
attr SBS2_5 obj-h40236-reading Set_BMS_Mode
attr SBS2_5 obj-h40236-set 1
attr SBS2_5 obj-h40721-reading BAT_Minimale_Breite_des_Tiefentladeschutzbereichs
attr SBS2_5 obj-h40721-set 1
attr SBS2_5 obj-h40723-reading BAT_Minimale_Breite_des_Ersatzstromsbereichs
attr SBS2_5 obj-h40723-set 1
attr SBS2_5 obj-h40781-reading Set_Netzaustauschleistung
attr SBS2_5 obj-h40781-set 1
attr SBS2_5 obj-h40793-reading Set_LadeP_min
attr SBS2_5 obj-h40793-set 1
attr SBS2_5 obj-h40795-reading Set_LadeP_max
attr SBS2_5 obj-h40795-set 1
attr SBS2_5 obj-h40797-reading Set_EntladeP_min
attr SBS2_5 obj-h40797-set 1
attr SBS2_5 obj-h40799-reading Set_EntladeP_max
attr SBS2_5 obj-h40799-set 1
attr SBS2_5 room PV->Speichersteuerung,PV->Stromversorgung
attr SBS2_5 verbose 0
Lenovo M910Q Tiny Debian 12, FHEM 6.3, 2x Siemens Logo 0BA7, Homematic CCU3, Philips HUE, 6x SMA Wechselrichter, BYD HVM, BYD HVS, SMA EVCharger, KEBA Wallbox, 2x HMS800W, Daikin Wärmepumpe über CAN, viele ESPs

Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/MadMax

MadMax

Und hier noch die "inteligenz" die alles steuert, da bin ich immernoch am basteln und verbessern.
Sowas ist ja bekantlich nie fertig.

defmod Speichersteuerung.calc.n notify STP8SE.t:Calc:.* {\
\
my $EMSN = "SMAEM3009886953_";;\
\
my $debug = "off";;\
\
my $STP8SE                          = "STP8SE.d";;\
my $SBS2_5                          = "SBS2_5.d";;\
my $STP8SE_MODBUS                   = "STP8SE";;\
my $SBS2_5_MODBUS                   = "SBS2_5";;\
my $this = "PV_Battery.d";;\
my $MaxCargePowerParam_STP          = 2000;;\
my $BalancePowerParam_STP           = 500;;\
my $MaxCargePowe2_STP               = 8000;;\
my $BatCappa_STP                    = 19300;;\
my $MaxCargePowerParam_SBS          = 1000;;\
my $BalancePowerParam_SBS           = 150;;\
my $MaxCargePowe2_SBS               = 2200;;\
my $BatCappa_SBS                    = 5100;;\
my $PV_Energie_Spitzen_NVP          = 26000;;\
my $PV_Energie_Spitzen_PV           = 26000;;\
my $PV_Energie_Spitzen_NVP_MAX      = 28000;;\
my $PV_Energie_Spitzen_WR_Phase     = 9200;;\
my $PV_Energie_Spitzen_STP8SE       = 7800;;\
my $balancing_Period                = 3;; #Tage\
my $hysteraese                      = 2;; #%\
my $Min_Energy_for_Autocharge = 30000;;\
\
my $STP8SE_MinSOC                   = ReadingsNum($STP8SE, "MinSOC", 50);;\
my $STP8SE_MaxSOC                   = ReadingsNum($STP8SE, "MaxSOC", 80);;\
my $SBS2_5_MinSOC                   = ReadingsNum($SBS2_5, "MinSOC", 50);;\
my $SBS2_5_MaxSOC                   = ReadingsNum($SBS2_5, "MaxSOC", 80);;\
my $MinSOC                          = ReadingsNum($this, "MinSOC", 50);;\
my $MaxSOC                          = ReadingsNum($this, "MaxSOC", 80);;\
\
my $P_NVP                    = ReadingsNum("SMA_Energymeter", $EMSN."Saldo_Wirkleistung", "x");;\
\
my $sollCargePower_STP          = ReadingsNum($STP8SE, "Set_Leistung", 0) * -1;;\
my $sollCargePower_SBS          = ReadingsNum($SBS2_5, "Set_Leistung", 0) * -1;;\
my $STP_kWh_to_min          = ReadingsNum($STP8SE, "INFO_kWh_to_min", 0);;\
my $SBS_kWh_to_min          = ReadingsNum($SBS2_5, "INFO_kWh_to_min", 0);;\
my $istSOC                  = ReadingsNum("PV_Battery.d", "BAT_PCT", 0);;\
my $PV_STP8SE_P              = ReadingsNum("STP_8_0_SE", "SPOT_PDC", 0);;\
my $AC_STP8SE_P              = ReadingsNum("STP_8_0_SE", "SPOT_PACTOT", 0);;\
\
my $STP8SE_AC_Power = ReadingsNum($STP8SE_MODBUS, "Wirkleistung", 0);;\
my $STP8SE_istCargePower            = ReadingsNum("STP_8_0_SE", "BAT_PDC", 0);;\
my $SBS2_5_istCargePower          = ReadingsNum($SBS2_5_MODBUS, "Batterieentladleistung", 0);;\
my $STP8SE_Ladestand                = ReadingsNum($STP8SE_MODBUS, "Ladezustand", 0);;\
my $SBS2_5_Ladestand                = ReadingsNum($SBS2_5_MODBUS, "Ladezustand", 0);;\
\
my $STP8SE_Auto                    = ReadingsVal($STP8SE, "Automatic", "");;\
my $SBS2_5_Auto                    = ReadingsVal($SBS2_5, "Automatic", "");;\
\
my $istCargePower = $STP8SE_istCargePower + $SBS2_5_istCargePower;;\
\
my $SpeicherWechsel = ReadingsVal($this, "DischargeSpeicherWechsel", "-");;\
\
my $SolarForecast_Spitzen   = 16000;;\
\
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time());;\
\
$hour = int($hour);;\
\
fhem("setreading ".$this." INFO_hour ".$hour);;\
\
my $spitzenSchneiden        = "off";;\
my $send_change = 0;;\
my $send_change2 = 0;;\
\
my $sollwert = "off";;\
my $sollwertNR = 0;;\
my $sollwert_SBS = "off";;\
my $sollwertNR_SBS = 0;;\
\
my $ChargePower_STP   = 0;;\
my $ChargePower_SBS   = 0;;\
my $MaxCargePowe_STP = $MaxCargePowerParam_STP;;\
my $MaxCargePowe_SBS = $MaxCargePowerParam_SBS;;\
\
my $BatCappa_STPPerOne = $BatCappa_STP  / 100;;\
my $BatCappa_STPPerOne2 = $BatCappa_SBS / 100;;\
\
my $STP_Bereit = 0;;\
my $SBS_Bereit = 0;;\
\
my $set_Aktiv_STP = "802";;\
my $set_Aktiv_SBS = "802";;\
\
my $set_Aktiv_STP_ist = ReadingsVal($STP8SE, "Set_Aktiv", "");;\
my $set_Aktiv_SBS_ist = ReadingsVal($SBS2_5, "Set_Aktiv", "");;\
\
$STP_Bereit = 1 if($STP8SE_Auto eq "on" && ReadingsVal($STP8SE_MODBUS, "state", "") eq "opened" && ReadingsVal($STP8SE_MODBUS, "Batteriezustand", "") eq "OK" && ReadingsVal($STP8SE_MODBUS, "Status", "") eq "OK" && ReadingsNum($STP8SE_MODBUS, "AC_Spannung_3", 0) > 200  && ReadingsNum($STP8SE_MODBUS, "AC_Spannung_3", 0) < 254);;\
$SBS_Bereit = 1 if($SBS2_5_Auto eq "on" && ReadingsVal($SBS2_5_MODBUS, "state", "") eq "opened" && ReadingsVal($SBS2_5_MODBUS, "Batteriezustand", "") eq "OK" && ReadingsVal($SBS2_5_MODBUS, "Status", "") eq "OK" && ReadingsNum($SBS2_5_MODBUS, "AC_Spannung_3", 0) > 200  && ReadingsNum($SBS2_5_MODBUS, "AC_Spannung_3", 0) < 254);;\
\
fhem("setreading ".$this." STP_Bereit ".$STP_Bereit);;\
fhem("setreading ".$this." SBS_Bereit ".$SBS_Bereit);;\
\
if(ReadingsVal($this, "Automatic", "") eq "on")\
{\
  $sollwertNR = 1;;\
  \
  my $P = $P_NVP;;\
  my $DC_STP8SE_toCarge = sprintf("%.0f",($PV_STP8SE_P * 0.85));;\
  \
  fhem("setreading ".$STP8SE." INFO_DC_STP8SE_toCarge ".$DC_STP8SE_toCarge);;\
 \
  #Werte aus Berechnung holen\
  $MaxCargePowe_STP = ReadingsNum($STP8SE, "control_ChargePower", 2000);;\
  my $chargeStartTime_STP = ReadingsNum($STP8SE, "control_ChargeStartTime", 8);;\
  my $chargeStartTimeMin_STP = ReadingsNum($STP8SE, "control_ChargeStartTimeMin", 8);;\
  my $moreEnergy_STP = ReadingsNum($STP8SE, "control_moreEnergy", "off");;\
  my $kWh_to_max_STP = ReadingsNum($STP8SE, "kWh_to_max", 10000);;\
  \
  $MaxCargePowe_SBS = ReadingsNum($SBS2_5, "control_ChargePower", 1000);;\
  my $chargeStartTime_SBS = ReadingsNum($SBS2_5, "control_ChargeStartTime", 8);;\
  my $chargeStartTimeMin_SBS = ReadingsNum($SBS2_5, "control_ChargeStartTimeMin", 8);;\
  my $moreEnergy_SBS = ReadingsNum($SBS2_5, "control_moreEnergy", "off");;\
  my $kWh_to_max_SBS = ReadingsNum($SBS2_5, "kWh_to_max", 10000);;\
  \
  my @SolarForecast    = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);;\
  my @SolarForecastSE = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);;\
  my @SolarForecastCON = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);;\
  my @Charge = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);;\
  \
  my $pv_next_hours    = 0;;\
  my $pvSE_next_hours  = 0;;\
  my $Con_next_hours = 0;;\
  my $charge_next_hours = 0;;\
  \
  my $PV_WR_P                 = ReadingsVal("Inverters", "SPOT_PACTOT", "0");;\
  \
  my $h_text = "";;\
  \
#Forecastdaten Laden\
  my $i = 10;;\
  while($i < 20) {\
$SolarForecast[$i]         = ReadingsNum("SolarForecast",   "Today_Hour".$i."_PVforecast", 0);;\
$pv_next_hours += $SolarForecast[$i] if($hour lt $i);;\
\
$SolarForecastSE[$i]       = ReadingsNum("SolarForecastSE", "Today_Hour".$i."_PVforecast", 0);;\
$pvSE_next_hours += $SolarForecastSE[$i] if($hour lt $i);;\
\
$SolarForecastCON[$i]       = ReadingsNum("SolarForecastSE", "statistic_todayConsumptionForecast_".$i."", 0);;\
$Con_next_hours += $SolarForecastCON[$i] if($hour lt $i);;\
\
$h_text = $i;;\
    $h_text = "0".$i if ($i < 10);;\
\
$Charge[$i]       = ReadingsNum("DWD_Forecast_Halberstadt", "fc0_".$h_text."_BatChargeforecast", 0);;\
$charge_next_hours += $Charge[$i] if($hour lt $i);;\
\
$i++;;\
  }\
  \
  my $Energy_next_Hours = ($pv_next_hours - $Con_next_hours) * 0.7;;\
  \
  $P = $P * 0.95 if($P > 1);;\
  \
  my $ChargePowerMax_NVP = sprintf("%.0f",(($istCargePower * -1)  + $P) * 0.99);;\
  fhem("setreading ".$STP8SE." INFO_ChargePowerMax_NVP ".$ChargePowerMax_NVP);;\
  \
  if($STP8SE_Ladestand eq "100")\
  {\
     fhem("setreading ".$STP8SE." INFO_Vollladung ".localtime()) if(ReadingsAge($STP8SE, "INFO_Vollladung", 999999) > 600);;\
     fhem("setreading ".$STP8SE." ladenVoll off");;\
\
$SpeicherWechsel = "HVM"\
  }\
  \
  if($SBS2_5_Ladestand eq "100")\
  {\
     fhem("setreading ".$SBS2_5." INFO_Vollladung ".localtime()) if(ReadingsAge($SBS2_5, "INFO_Vollladung", 999999) > 600);;\
     fhem("setreading ".$SBS2_5." ladenVoll off");;\
  }\
  \
  my $sollPCT_Auto = ReadingsNum("Enyaq.Ladeparameter", "PrioLadestand", "60");;\
  $sollPCT_Auto = ReadingsNum("my_skoda", "status.charging.settings.targetStateOfChargeInPercent", "0") if(ReadingsNum("my_skoda", "status.charging.settings.targetStateOfChargeInPercent", "0") < $sollPCT_Auto);;\
 \
  my $cntWB = 0;;\
  $cntWB = $cntWB + 1 if(ReadingsNum("EV_CHarger_22", "Leistung_Ladestation", "") > 1000);; #&& \
#(ReadingsNum("my_skoda", "status.charging.status.battery.stateOfChargeInPercent", "0") < $sollPCT_Auto || ReadingsNum("EV_CHarger_22", "Leistung_Ladestation", "") > 1000));;\
  $cntWB = $cntWB + 1 if(ReadingsNum("KEBA_P30", "CabelState", 0) >= 5 && ReadingsNum("KEBA_P30", "ActivePower", 0) >= 1000);;\
  \
  fhem("setreading ".$this." cntWB ".$cntWB);;\
  \
  my $Control_Mode = ReadingsVal($this, "laden", "");;\
  \
\
  if(($PV_WR_P > 1300 && $PV_WR_P < 12000 && $cntWB == 1) || ($PV_WR_P > 1300 && $PV_WR_P < 23000 && $cntWB == 2)) #Wallboxen\
  {\
fhem("setreading ".$this." Control_Mode BEV");;\
$Control_Mode = "BEV";;\
    fhem("setreading ".$this." ladenStart off");;\
  }\
  elsif($P_NVP < 1 && ReadingsAge($this, "ladenStart", 9999999999) > 10) #Laden beenden\
  {\
      fhem("setreading ".$this." ladenStop on") if(ReadingsVal($this, "ladenStop", "") ne "on");;;;\
      \
      if(ReadingsAge($this, "ladenStop", 9999999999) > 10 || ($P_NVP < -20 && $Control_Mode eq "laden"))\
      {\
        fhem("setreading ".$this." Control_Mode off");;\
        fhem("setreading ".$this." ladenStart off");;\
      }\
  if(ReadingsVal($STP8SE, "state", "") eq "SMA_aktiv" && $istCargePower  > 10)\
      {\
        fhem("setreading ".$this." Control_Mode offX");;\
        fhem("setreading ".$this." ladenStart off");;\
      }\
  } \
  elsif(($P_NVP > 10 && $istCargePower  == 0) #Laden Starten\
  || $istCargePower  < -10)\
  {\
      fhem("setreading ".$this." ladenStart on") if(ReadingsVal($this, "ladenStart", "") ne "on");;\
      fhem("setreading ".$this." Control_Mode laden");;\
      fhem("setreading ".$this." ladenStop off");;\
  }\
  \
  if($Energy_next_Hours < $Min_Energy_for_Autocharge && #Laden aber SMA Steuert\
($Control_Mode eq "Laden_SMA" || $Control_Mode eq "laden" || ReadingsVal($this, "Control_Mode", "") eq "Laden_SMA" || ReadingsVal($this, "Control_Mode", "") eq "laden"))\
  {\
fhem("setreading ".$this." Control_Mode Laden_SMA");;\
$Control_Mode = "Laden_SMA";;\
    fhem("setreading ".$this." ladenStart on");;\
  }\
\
  if(ReadingsVal($this, "Control_Mode", "") eq "laden" || $Control_Mode eq "laden") #zwei Zyklen überwachen für das deaktivieren\
  {\
   \
#Maximal Ladepegel STP Anfang\
    if($STP8SE_Ladestand >= $STP8SE_MaxSOC || $SpeicherWechsel eq "HVM")\
    {\
        fhem("setreading ".$STP8SE." ladenMax off");;\
    }\
elsif($STP8SE_Ladestand < $STP8SE_MaxSOC - $hysteraese)\
    {\
        fhem("setreading ".$STP8SE." ladenMax on");;\
    }\
    \
    if(ReadingsVal($STP8SE, "ladenMax", "") eq "on" && $hour >= $chargeStartTime_STP)\
    {\
        $ChargePower_STP = $DC_STP8SE_toCarge;;\
        $sollwert = "ladenMax";;\
$sollwertNR = 804;;\
    }\
\
if(ReadingsVal($STP8SE, "ladenMax", "") eq "on" && ReadingsVal($STP8SE, "control_moreEnergy", "") eq "on" && $hour >= $chargeStartTime_STP)\
    {\
        $ChargePower_STP = $MaxCargePowe_STP;;\
        $sollwert = "ladenMax_more_energy";;\
$sollwertNR = 804.5;;\
    }\
#Maximal Ladepegel STP Ende\
\
#Maximal Ladepegel SBS Anfang\
    if($SBS2_5_Ladestand >= $SBS2_5_MaxSOC)\
    {\
        fhem("setreading ".$SBS2_5." ladenMax off");;\
    }\
elsif($STP8SE_Ladestand < $STP8SE_MaxSOC - $hysteraese)\
    {\
        fhem("setreading ".$SBS2_5." ladenMax on");;\
    }\
    \
    if(ReadingsVal($SBS2_5, "ladenMax", "") eq "on" && $hour >= $chargeStartTime_SBS)\
    {\
        $ChargePower_SBS = $MaxCargePowe_SBS;;\
        $sollwert_SBS = "ladenMax";;\
$sollwertNR_SBS = 804;;\
    }\
\
if(ReadingsVal($SBS2_5, "ladenMax", "") eq "on" && ReadingsVal($SBS2_5, "control_moreEnergy", "") eq "on" && $hour >= $chargeStartTime_SBS)\
    {\
        $ChargePower_SBS = $MaxCargePowe_SBS;;\
        $sollwert_SBS = "ladenMax_more_energy";;\
$sollwertNR_SBS = 804.5;;\
    }\
#Maximal Ladepegel SBS Ende\
\
    my $Today_PVforecast        = ReadingsNum("SolarForecast", "Today_PVforecast", 0);;\
\
#Volladen für Zellausgleich STP Anfang\
    if(ReadingsAge($STP8SE, "INFO_Vollladung", 9999999999) > 3600*24*$balancing_Period && $hms lt "08:00:00" && \
(ReadingsVal($STP8SE, "INFO_SpitzenSchneiden", "") eq "off" || $hms lt "14:00:00"))# && $Today_PVforecast > 40000)\
    {   \
        fhem("setreading ".$STP8SE." ladenVoll on");;\
    }\
    \
    if(ReadingsVal($STP8SE, "ladenVoll", "") eq "on" && $hour >= $chargeStartTime_STP)\
    {\
        $ChargePower_STP = $DC_STP8SE_toCarge;;\
        \
        $sollwert = "ladenVoll";;\
$sollwertNR = 805;;\
    }\
#Volladen für Zellausgleich STP Ende\
\
#Volladen für Zellausgleich SBS Anfang\
    if(ReadingsAge($SBS2_5, "INFO_Vollladung", 9999999999) > 3600*24*$balancing_Period && $hms lt "08:00:00")# && $Today_PVforecast > 40000)\
    {   \
        fhem("setreading ".$SBS2_5." ladenVoll on");;\
    }\
    \
    if(ReadingsVal($SBS2_5, "ladenVoll", "") eq "on" && $hour >= $chargeStartTime_SBS)\
    {\
        $ChargePower_SBS = $MaxCargePowe_SBS;;\
        \
        $sollwert_SBS = "ladenVoll";;\
$sollwertNR_SBS = 805;;\
    }\
#Volladen für Zellausgleich SBS Ende\
    \
    $ChargePower_STP = $MaxCargePowe_STP if($ChargePower_STP > $MaxCargePowe_STP);;\
    $ChargePower_SBS = $MaxCargePowe_SBS if($ChargePower_SBS > $MaxCargePowe_SBS);;\
\
#Spitzenabregelung nötig? anfang\
    if((($SolarForecast[10] > $SolarForecast_Spitzen && $hms lt "10:00:00") || ($SolarForecast[11] > $SolarForecast_Spitzen && $hms lt "11:00:00") || ($SolarForecast[12] > $SolarForecast_Spitzen && $hms lt "12:00:00") || \
       ($SolarForecast[13] > $SolarForecast_Spitzen && $hms lt "13:00:00") || ($SolarForecast[14] > $SolarForecast_Spitzen && $hms lt "14:00:00") || ($SolarForecast[15] > $SolarForecast_Spitzen && $hms lt "15:00:00")) &&\
       $hms lt "15:00:00")\
    {\
        $spitzenSchneiden = "Forecast";;\
    }\
\
$spitzenSchneiden = ReadingsVal($STP8SE, "INFO_SpitzenSchneiden", "") if($spitzenSchneiden eq "off");;\
\
$spitzenSchneiden = "MAX" if($P_NVP > $PV_Energie_Spitzen_NVP_MAX && $spitzenSchneiden eq "off");;\
$spitzenSchneiden = "off" if($P_NVP < $PV_Energie_Spitzen_NVP_MAX - 500 && $spitzenSchneiden eq "Max");;\
\
    $spitzenSchneiden = "SE" if($PV_STP8SE_P > $PV_Energie_Spitzen_STP8SE && $spitzenSchneiden eq "off");;\
$spitzenSchneiden = "off" if($PV_STP8SE_P < $PV_Energie_Spitzen_STP8SE - 300 && $spitzenSchneiden eq "SE");;\
\
$spitzenSchneiden = "PV" if($PV_WR_P > $PV_Energie_Spitzen_PV && $spitzenSchneiden eq "off");;\
$spitzenSchneiden = "off" if($PV_WR_P < $PV_Energie_Spitzen_PV - 500 && $spitzenSchneiden eq "PV");;\
\
    fhem("setreading ".$STP8SE." INFO_SpitzenSchneiden ".$spitzenSchneiden);;\
#Spitzenabregelung nötig? ende\
    \
#Spitzenabregelung berechnung anfang\
    my $spitzenSchneidenAktiv = "off";;\
my $Spitze = 0;;\
    #$spitzenSchneidenAktiv = "on";;\
\
    if($spitzenSchneiden ne "off")\
    {\
        my $PV_WR_P1                = ReadingsVal("Inverters", "SPOT_PAC1", "0");;\
        my $PV_WR_P2                = ReadingsVal("Inverters", "SPOT_PAC2", "0");;\
        my $PV_WR_P3                = ReadingsVal("Inverters", "SPOT_PAC3", "0");;\
        \
        my $EVC_P1                = ReadingsVal("EV_CHarger_22", "Netzspannung_Phase_L1", "0") * ReadingsVal("EV_CHarger_22", "Netzstrom_Phase_L1", "0") * -1;;\
        my $EVC_P2                = ReadingsVal("EV_CHarger_22", "Netzspannung_Phase_L2", "0") * ReadingsVal("EV_CHarger_22", "Netzstrom_Phase_L2", "0") * -1;;\
        my $EVC_P3                = ReadingsVal("EV_CHarger_22", "Netzspannung_Phase_L3", "0") * ReadingsVal("EV_CHarger_22", "Netzstrom_Phase_L3", "0") * -1;;\
        \
#Keba Wallbox Phasen um eins verschoben\
$EVC_P2                = $EVC_P2 + ReadingsVal("KEBA_P30", "VoltageL1", "0") * ReadingsVal("KEBA_P30", "CurrentL1", "0") / 1000;;\
        $EVC_P3                = $EVC_P3 + ReadingsVal("KEBA_P30", "VoltageL2", "0") * ReadingsVal("KEBA_P30", "CurrentL2", "0") / 1000;;\
        $EVC_P1                = $EVC_P1 + ReadingsVal("KEBA_P30", "VoltageL3", "0") * ReadingsVal("KEBA_P30", "CurrentL3", "0") / 1000;;\
\
if($STP8SE_Ladestand  > 85)\
{\
$PV_Energie_Spitzen_NVP          = 29500;;\
$PV_Energie_Spitzen_PV           = 29500;;\
$PV_Energie_Spitzen_WR_Phase     = 9400;;\
}\
\
        if(($P_NVP + ($STP8SE_istCargePower * -1)) > $PV_Energie_Spitzen_NVP || $PV_STP8SE_P > $PV_Energie_Spitzen_STP8SE || $PV_WR_P1 > $PV_Energie_Spitzen_WR_Phase || $PV_WR_P2 > $PV_Energie_Spitzen_WR_Phase || $PV_WR_P3 > $PV_Energie_Spitzen_WR_Phase)\
        #if($spitzenSchneiden ne "off")\
{\
            $spitzenSchneidenAktiv = "NVP";;\
            \
            #am NVP\
$Spitze = ReadingsVal($STP8SE,"control_spitze",0);;\
my $Spitz_diff = ($P_NVP - $PV_Energie_Spitzen_NVP);;\
if($STP8SE_istCargePower > -10)\
{\
$Spitze = $Spitz_diff;;\
}\
elsif($Spitz_diff > 0)\
{\
$Spitze = $Spitze + $Spitz_diff;;\
}\
elsif($Spitz_diff < -100)\
{\
$Spitze = $Spitze + ($Spitz_diff / 2);;\
}\
\
            #$Spitze = $Spitze + ($P_NVP - $PV_Energie_Spitzen_NVP);;#Leistung aufadieren #($STP8SE_istCargePower * -1) + ($P_NVP - $PV_Energie_Spitzen_NVP);;\
#$Spitze = ($P_NVP - $PV_Energie_Spitzen_NVP) if($STP8SE_istCargePower < 10);; #erst aufaddieren wenn der WR lädt\
\
            #am STP SE\
            if($PV_STP8SE_P - $PV_Energie_Spitzen_STP8SE > $Spitze)\
            {\
                $Spitze = $PV_STP8SE_P - $PV_Energie_Spitzen_STP8SE;;\
                $spitzenSchneidenAktiv = "SE";;\
            }\
            \
            #am PV Anschluss\
            if(($PV_WR_P1 - $EVC_P1) - $PV_Energie_Spitzen_WR_Phase > $Spitze)\
            {\
                $Spitze = (($PV_WR_P1 -$EVC_P1) - $PV_Energie_Spitzen_WR_Phase) * 3;;\
                $spitzenSchneidenAktiv = "L1";;\
            }\
            if(($PV_WR_P2 - $EVC_P2) - $PV_Energie_Spitzen_WR_Phase > $Spitze)\
            {\
                $Spitze = (($PV_WR_P2 -$EVC_P2) - $PV_Energie_Spitzen_WR_Phase) * 3;;\
                $spitzenSchneidenAktiv = "L2";;\
            }\
            if(($PV_WR_P3 - $EVC_P3) - $PV_Energie_Spitzen_WR_Phase > $Spitze)\
            {\
                $Spitze = (($PV_WR_P3 -$EVC_P3) - $PV_Energie_Spitzen_WR_Phase) * 3;;\
                $spitzenSchneidenAktiv = "L3";;\
            }\
\
$Spitze = 0 if($Spitze < 0);;\
\
fhem("setreading ".$STP8SE." control_spitze ".$Spitze);;\
\
my $Spitze2 = movingAverage($STP8SE,"control_spitze",60);;\
\
if($STP8SE_Ladestand  > 90 && $Spitze2 > 4000)\
{\
if($spitzenSchneidenAktiv eq "NVP" || $spitzenSchneidenAktiv eq "L3")\
{\
$ChargePower_SBS = $Spitze2 - 4000;;\
$ChargePower_SBS = 2000 if($ChargePower_SBS > 2000);;\
\
$sollwert_SBS = "Spitzenschneiden";;\
$sollwertNR_SBS = 806;;\
}\
$Spitze2 = 4000 ;;\
}\
\
if($Spitze2 > $ChargePower_STP && $Spitze2 > 100)\
{\
$ChargePower_STP = $Spitze2;;\
$sollwert = "Spitzenschneiden";;\
$sollwertNR = 806;;\
}\
        }\
    }\
else\
{\
fhem("setreading ".$STP8SE." control_spitze 0");;\
}\
fhem("setreading ".$STP8SE." control_spitze ".$Spitze);;\
    fhem("setreading ".$STP8SE." INFO_SpitzenSchneidenAktiv ".$spitzenSchneidenAktiv);;\
#Spitzenabregelung berechnung ende\
    \
#MindestLadung erreichen STP\
    if($STP8SE_Ladestand < $STP8SE_MinSOC - $hysteraese)\
    {\
        fhem("setreading ".$STP8SE." ladenMin on");;\
    }\
    elsif($STP8SE_Ladestand >= $STP8SE_MinSOC)\
    {\
        fhem("setreading ".$STP8SE." ladenMin off");;\
    }\
\
    \
    if(ReadingsVal($STP8SE, "ladenMin", "") eq "on" && $hour >= $chargeStartTimeMin_STP)\
    {\
        #$ChargePower_STP = $DC_STP8SE_toCarge if($DC_STP8SE_toCarge > $ChargePower_STP);;\
        $sollwert = "ladenMin";;\
$sollwertNR = 807;;\
\
$ChargePower_STP = $MaxCargePowe_STP * 1.1 if($MaxCargePowe_STP * 1.1 > $ChargePower_STP);;\
\
        if($Energy_next_Hours < ($STP_kWh_to_min * 1.2)) #$istSOC < $STP8SE_MinSOC - 20 && $hour > 12) #nach 12 Uhr immernoch zu wenig im Speicher?\
        {\
            #$ChargePower_STP = $ChargePowerMax_NVP * 0.85;;\
$ChargePower_STP = $MaxCargePowe2_STP / 2 if($ChargePower_STP > $MaxCargePowe2_STP / 2);;\
            $sollwert = "ladenMin_schnell";;\
$sollwertNR = 808;;\
        }\
    }\
    \
    $ChargePower_STP = $ChargePowerMax_NVP if($ChargePower_STP > $ChargePowerMax_NVP && $ChargePowerMax_NVP > 0);;\
    $ChargePower_STP = $MaxCargePowe2_STP if($ChargePower_STP > $MaxCargePowe2_STP);;\
# Mindestladung STP ende\
\
#MindestLadung erreichen SBS\
    if($SBS2_5_Ladestand < $SBS2_5_MinSOC - $hysteraese)\
    {\
        fhem("setreading ".$SBS2_5." ladenMin on");;\
    }\
    elsif($SBS2_5_Ladestand >= $SBS2_5_MinSOC)\
    {\
        fhem("setreading ".$SBS2_5." ladenMin off");;\
    }\
\
    \
    if(ReadingsVal($SBS2_5, "ladenMin", "") eq "on" && $hour >= $chargeStartTimeMin_SBS)\
    {\
        #$ChargePower_SBS = $ChargePowerMax_NVP if($ChargePowerMax_NVP > $ChargePower_SBS);;\
        $sollwert_SBS = "ladenMin";;\
$sollwertNR_SBS = 807;;\
\
$ChargePower_SBS = $MaxCargePowe_SBS * 1.1 if($MaxCargePowe_SBS * 1.1 > $ChargePower_SBS);;\
\
        if($Energy_next_Hours < ($SBS_kWh_to_min * 1.2)) #$istSOC < $SBS8SE_MinSOC - 20 && $hour > 12) #nach 12 Uhr immernoch zu wenig im Speicher?\
        {\
            #$ChargePower_SBS = $ChargePowerMax_NVP * 0.85;;\
$ChargePower_SBS = $MaxCargePowe2_SBS / 2 if($ChargePower_SBS > $MaxCargePowe2_SBS / 2);;\
            $sollwert_SBS = "ladenMin_schnell";;\
$sollwertNR_SBS = 808;;\
        }\
    }\
    \
    $ChargePower_SBS = $ChargePowerMax_NVP if($ChargePowerMax_NVP < $ChargePower_SBS && $ChargePowerMax_NVP > 0);;\
    $ChargePower_SBS = $MaxCargePowe2_SBS if($ChargePower_SBS > $MaxCargePowe2_SBS);;\
# Mindestladung SBS ende\
\
if(ReadingsVal($STP8SE, "LadeStop", "") eq "on")\
    {\
       $ChargePower_STP = 0;;\
   $sollwert = "ladenStop";;\
   $sollwertNR = 809;;\
    }\
\
if(ReadingsVal($SBS2_5, "LadeStop", "") eq "on")\
    {\
       $ChargePower_SBS = 0;;\
   $sollwert_SBS = "ladenStop";;\
   $sollwertNR_SBS = 809;;\
    }\
\
if($sollwert eq "off" && ($hour < $chargeStartTimeMin_STP || $hour < $chargeStartTime_STP))\
{\
$sollwert = "Startzeit nicht Erreicht";;\
$sollwertNR = 810;;\
}\
\
if($sollwert_SBS eq "off" && ($hour < $chargeStartTimeMin_SBS || $hour < $chargeStartTime_SBS))\
{\
$sollwert_SBS = "Startzeit nicht Erreicht";;\
$sollwertNR_SBS = 810;;\
}\
    \
    $ChargePower_STP = sprintf("%.0f",$ChargePower_STP) *-1;;\
    $ChargePower_SBS = sprintf("%.0f",$ChargePower_SBS) *-1;;\
\
#Benötigter Sollwert höher als verfügbare Leistung? Das hätte nicht passieren dürfen!\
\
if($MaxCargePowe_STP * 0.8 > $ChargePowerMax_NVP && \
($hour > $chargeStartTimeMin_STP || $hour > $chargeStartTime_STP) &&\
$kWh_to_max_STP > $charge_next_hours &&\
(ReadingsVal($STP8SE,"INFO_kWh_to_min", "") * 0.95) > $pv_next_hours)\
{\
$set_Aktiv_STP = "803";;\
\
$sollwert = "SMA steuert, das haette nicht passieren duerfen!";;\
$sollwertNR = 816;;\
}\
\
#Provisorisch\
#$ChargePower_SBS = ($ChargePower_STP * 0.25);;\
#$set_Aktiv_SBS = $set_Aktiv_STP;;\
#Provisorisch\
\
my $smothFaktor = 20;;\
$ChargePower_SBS = sprintf("%.0f",$ChargePower_SBS / $smothFaktor) * $smothFaktor;;\
$ChargePower_STP = sprintf("%.0f",$ChargePower_STP / $smothFaktor) * $smothFaktor;;\
\
#$ChargePower_STP =\
\
#Werte geändert? Senden!\
    $send_change = 1 if(ReadingsVal($STP8SE, "Set_Leistung", "") != $ChargePower_STP);;\
$send_change = 1 if(ReadingsVal($STP8SE, "Set_Aktiv", "") ne $set_Aktiv_STP);;\
$send_change2 = 1 if(ReadingsVal($SBS2_5, "Set_Leistung", "") != $ChargePower_SBS);;\
$send_change2 = 1 if(ReadingsVal($SBS2_5, "Set_Aktiv", "") ne $set_Aktiv_SBS);;\
\
    fhem("setreading ".$STP8SE." Set_Leistung ".$ChargePower_STP) if($STP8SE_Auto eq "on");;\
    fhem("set ".$STP8SE." Set_Aktiv ".$set_Aktiv_STP) if($STP8SE_Auto eq "on");;\
fhem("setreading ".$SBS2_5." Set_Leistung ".$ChargePower_SBS) if($SBS2_5_Auto eq "on");;\
    fhem("set ".$SBS2_5." Set_Aktiv ".$set_Aktiv_SBS) if($SBS2_5_Auto eq "on");;\
\
    fhem("set ".$STP8SE." FHEM_aktiv_SollP:".$ChargePower_STP."w_Sollwert:".$sollwert) if($STP8SE_Auto eq "on");;\
fhem("set ".$SBS2_5." FHEM_aktiv_SollP:".$ChargePower_SBS."w_Sollwert:".$sollwert_SBS) if($SBS2_5_Auto eq "on");;\
\
my $p = 0;;\
$p = $p + $ChargePower_STP if($STP8SE_Auto eq "on");;\
$p = $p + $ChargePower_SBS if($SBS2_5_Auto eq "on");;\
\
fhem("setreading ".$this." INFO_Sollwertherkunft FHEM_aktiv_SollP:".$p."w_Sollwert:".$sollwert);;\
fhem("setreading ".$this." DischargeMode 0");;\
  }\
  elsif($Control_Mode eq "Laden_SMA") #LADEN SMA Steuert die Wechselrichter\
  {\
    #$STP_Bereit = 0;;\
#$SBS_Bereit = 0;;\
  $sollwert = "Laden_SMA";;\
  $sollwert_SBS = "Laden_SMA";;\
  $sollwertNR = 831;;\
  \
  my $maxPCT_STP8SE = 100;; #ReadingsNum($STP8SE, "MinSOC", 80);;\
  my $maxPCT_SBS2_5 = 100;; #ReadingsNum($SBS2_5, "MinSOC", 80);;\
  my $ChargePower_STP = 0;;\
  my $ChargePower_SBS = 0;;\
  my $mode = ReadingsNum($this, "ChargeMode", 0);;\
  my $modeAktiv = ReadingsNum($this, "ChargeModeAktiv", 0);;\
  my $DischargeModeAktiv = ReadingsNum($this, "DischargeModeAktiv", 0);;\
  \
  my $cargePower = ($STP8SE_istCargePower + $SBS2_5_istCargePower) * -1;;\
  \
  my $NVP_PWR = 0;;\
  $NVP_PWR = $P_NVP * -1 if($P_NVP < $NVP_PWR);;\
  \
  my $UeberschussPower = $cargePower + $P_NVP;;\
  \
  if($STP8SE_Ladestand >= $maxPCT_STP8SE)\
  {\
fhem("setreading ".$STP8SE." wurdeGeladen 1");;\
  }\
  elsif($STP8SE_Ladestand < $maxPCT_STP8SE - $hysteraese)\
  {\
fhem("setreading ".$STP8SE." wurdeGeladen 0");;\
  }\
  \
  if($SBS2_5_Ladestand >= $maxPCT_SBS2_5)\
  {\
fhem("setreading ".$SBS2_5." wurdeGeladen 1");;\
  }\
  elsif($SBS2_5_Ladestand < $maxPCT_SBS2_5 - $hysteraese)\
  {\
fhem("setreading ".$SBS2_5." wurdeGeladen 0");;\
  }\
  \
  my $STP8SE_wurdeGeladen = ReadingsNum($STP8SE, "wurdeGeladen", 0);;\
  my $SBS2_5_wurdeGeladen = ReadingsNum($SBS2_5, "wurdeGeladen", 0);;\
  \
  #HVM entladen wenn er voll geladen wurde\
  #$SpeicherWechsel = "HVM" if($STP8SE_Ladestand >= 99);;\
  #$SpeicherWechsel = "-" if($STP8SE_Ladestand <= 5 && $SpeicherWechsel eq "HVM");;\
  \
  #der große darf loslegen wenn er bereits aktiv ist und nicht voll\
  $mode = 6 if($STP_Bereit == 1 && $STP8SE_wurdeGeladen == 0 && $DischargeModeAktiv == 2);;\
  #der kleine darf loslegen wenn er bereits aktiv ist und nicht voll\
  $mode = 5 if($SBS_Bereit == 1 && $SBS2_5_wurdeGeladen == 0 && $DischargeModeAktiv == 1);;\
  #der große darf loslegen wenn er nicht voll ist und bereit ist\
  $mode = 2 if($STP_Bereit == 1 && $STP8SE_wurdeGeladen == 0 && $mode != 99);;\
  #der kleine darf loslegen wenn der große voll ist\
  $mode = 1 if($SBS_Bereit == 1 && $STP8SE_wurdeGeladen == 1 && $mode != 99);; \
  #der kleine darf loslegen wenn der große nicht bereit\
  $mode = 3 if($STP_Bereit != 1 && $SBS_Bereit == 1);;\
  #der große darf loslegen wenn der kleine nicht bereit\
  $mode = 4 if($SBS_Bereit != 1 && $STP_Bereit == 1);;\
  \
  #beide aktiv und einer lädt und der andere entlädt? zurück auf Ursprung\
  $mode = 55 if(($SBS2_5_istCargePower > 0 && $STP8SE_istCargePower < 0) || ($SBS2_5_istCargePower < 0 && $STP8SE_istCargePower > 0));;\
  \
  #der so viel leistung das beide laden können.\
  $mode = 99 if($SBS_Bereit == 1 && $STP_Bereit == 1 && $STP8SE_wurdeGeladen == 0 && $SBS2_5_wurdeGeladen == 0 && \
  ($UeberschussPower > 7000 || ($UeberschussPower > 5000 && $mode == 99)));;\
  \
  if($mode == 1 || $mode == 3|| $mode == 5) #SBS\
  {\
if($set_Aktiv_SBS_ist == "802" && $SBS2_5_istCargePower < -50)\
{\
$ChargePower_SBS = -300;;\
$ChargePower_SBS = $STP8SE_istCargePower * 1.1 if($ChargePower_SBS < $STP8SE_istCargePower);;\
$ChargePower_SBS = $NVP_PWR * 1.1 if($ChargePower_SBS < $NVP_PWR);;\
$set_Aktiv_STP = "803";; #SMA Steuert\
$modeAktiv = 1.1;;\
$sollwertNR = 832.1;;\
$sollwert_SBS = "Laden_SMA_aktivierung";;\
}\
else\
{\
$set_Aktiv_SBS = "803";; #SMA Steuert\
$set_Aktiv_STP = "802";; #FHEM Steuert\
$modeAktiv = 1;;\
$sollwertNR = 832;;\
$sollwert_SBS = "Laden_SMA_aktiv";;\
}\
  }\
  elsif($mode == 2 || $mode == 4 || $mode == 6) #STP\
  {\
if($set_Aktiv_STP_ist == "802" && $STP8SE_istCargePower < -50)\
{\
$ChargePower_STP = -300;;\
$ChargePower_STP = $SBS2_5_istCargePower * 1.1 if($ChargePower_STP < $SBS2_5_istCargePower);;\
$ChargePower_STP = $NVP_PWR * 1.1 if($ChargePower_STP < $NVP_PWR);;\
$set_Aktiv_SBS = "803";; #SMA Steuert\
$modeAktiv = 2.1;;\
$sollwertNR = 833.1;;\
$sollwert = "Laden_SMA_aktivierung";;\
}\
else\
{\
$set_Aktiv_SBS = "802";; #FHEM Steuert\
$set_Aktiv_STP = "803";; #SMA Steuert\
$modeAktiv = 2;;\
$sollwertNR = 833;;\
$sollwert = "Laden_SMA_aktiv";;\
}\
  }\
  elsif($mode == 99) #beide\
  {\
$ChargePower_SBS = $cargePower / 5 * -1;;\
$ChargePower_SBS = -2000 if ($ChargePower_SBS < -2000);;\
\
$set_Aktiv_SBS = "802";; #FHEM Steuert\
$set_Aktiv_STP = "803";; #SMA Steuert\
$sollwert = "Laden_SMA_aktiv";;\
$sollwert_SBS = "Laden_SMA_DUO";;\
\
$modeAktiv = 3;;\
$sollwertNR = 834;;\
\
$mode = 1 if($STP8SE_wurdeGeladen == 1 && $SBS2_5_wurdeGeladen == 0);;\
$mode = 2 if($STP8SE_wurdeGeladen == 0 && $SBS2_5_wurdeGeladen == 1);;\
$mode = 2 if($cargePower < 3000);;\
  }\
  elsif($mode == 55)\
  {\
if($istCargePower > -2000 && $SBS_Bereit == 1 && $SBS2_5_Ladestand < $maxPCT_SBS2_5)\
{\
$set_Aktiv_SBS = "803";; #SMA Steuert\
$set_Aktiv_STP = "802";; #FHEM Steuert\
$mode = 2;;\
}\
else\
{\
$set_Aktiv_SBS = "802";; #FHEM Steuert\
$set_Aktiv_STP = "803";; #SMA Steuert\
$mode = 1;;\
}\
$modeAktiv = 5;;\
$sollwertNR = 836;;\
  }\
  else #fehler!!\
  {\
$set_Aktiv_SBS = "803";; #SMA Steuert\
$set_Aktiv_STP = "803";; #SMA Steuert\
$modeAktiv = 4;;\
$sollwertNR = 835;;\
$sollwert = "Laden_SMA_aktiv";;\
$sollwert_SBS = "Laden_SMA_aktiv";;\
  }\
  \
  \
  $sollwert_SBS = "Laden_SMA_fertig" if($SBS2_5_wurdeGeladen == 1);;\
  $sollwert = "Laden_SMA_fertig" if($STP8SE_wurdeGeladen == 1);;\
  \
  fhem("setreading ".$this." DischargeMode 0");;\
  fhem("setreading ".$this." DischargeModeAktiv 0");;\
  fhem("setreading ".$this." ChargeMode ".$mode);;\
  fhem("setreading ".$this." ChargeModeAktiv ".$modeAktiv);;\
      fhem("setreading ".$this." ChargeSpeicherWechsel ".$SpeicherWechsel);;\
  \
  fhem("setreading ".$STP8SE." Set_Leistung ".$ChargePower_STP) if($STP8SE_Auto eq "on");;\
  fhem("set ".$STP8SE." Set_Aktiv ".$set_Aktiv_STP) if($STP8SE_Auto eq "on");;\
  fhem("setreading ".$SBS2_5." Set_Leistung ".$ChargePower_SBS) if($SBS2_5_Auto eq "on");;\
  fhem("set ".$SBS2_5." Set_Aktiv ".$set_Aktiv_SBS) if($SBS2_5_Auto eq "on");;\
  \
  $send_change = 1 if(ReadingsVal($STP8SE, "Set_Leistung", "") != $ChargePower_STP);;\
  $send_change = 1 if(ReadingsVal($STP8SE, "Set_Aktiv", "") ne $set_Aktiv_STP);;\
  $send_change2 = 1 if(ReadingsVal($SBS2_5, "Set_Leistung", "") != $ChargePower_SBS);;\
  $send_change2 = 1 if(ReadingsVal($SBS2_5, "Set_Aktiv", "") ne $set_Aktiv_SBS);;\
  \
  fhem("setreading ".$this." INFO_Sollwertherkunft Laden_SMA");;\
  fhem("set ".$STP8SE." ".$sollwert) if($STP8SE_Auto eq "on");;\
  fhem("set ".$SBS2_5." ".$sollwert_SBS) if($SBS2_5_Auto eq "on");;\
  }\
  else\
  {\
  # Entladen\
    #$STP_Bereit = 0;;\
#$SBS_Bereit = 0;;\
  \
  $sollwertNR = 817;;\
  \
  my $minPCT = 5;;\
  my $minPCT_SBS2_5 = 1;;\
  my $DischargePower_STP = 0;;\
  my $DischargePower_SBS = 0;;\
  my $modeAge = ReadingsAge($this, "DischargeMode", 0);;\
  my $mode = ReadingsNum($this, "DischargeMode", 0);;\
  my $modeAktiv = ReadingsNum($this, "DischargeModeAktiv", 0);;\
  my $ChargeModeAktiv = ReadingsNum($this, "ChargeModeAktiv", 0);;\
  \
  my $NVP_PWR = 0;;\
  $NVP_PWR = $P_NVP * -1 if($P_NVP < $NVP_PWR);;\
  \
  #HVM entladen wenn er voll geladen wurde\
  $SpeicherWechsel = "HVM" if($STP8SE_Ladestand >= 99);;\
  $SpeicherWechsel = "-" if($STP8SE_Ladestand <= 5 && $SpeicherWechsel eq "HVM");;\
  \
  $STP_Bereit = 0 if(ReadingsVal($STP8SE, "EntladeStop", "off") eq "on");;\
  $SBS_Bereit = 0 if(ReadingsVal($SBS2_5, "EntladeStop", "off") eq "on");;\
  \
  #der große darf loslegen wenn er bereits aktiv ist und nicht leer\
  $mode = 9 if($STP_Bereit == 1 && $STP8SE_Ladestand >= $minPCT && $ChargeModeAktiv == 2);;\
  #der kleine darf loslegen wenn er bereits aktiv ist und nicht leer\
  $mode = 0  if($mode == 10 && $modeAge > 900 && $SpeicherWechsel eq "HVM");;\
  $mode = 10 if($SBS_Bereit == 1 && $SBS2_5_Ladestand >= $minPCT_SBS2_5 && $ChargeModeAktiv == 1);;\
  #der kleine darf loslegen wenn der große nicht läuft\
  $mode = 1 if($SBS_Bereit == 1 && $SBS2_5_Ladestand >= $minPCT_SBS2_5 \
&& $modeAktiv != 2 && $SpeicherWechsel ne "HVM" && $Control_Mode ne "BEV");; #&& $SBS2_5_istCargePower  < 1000 && $mode != 3);;\
  #weniger als 1000W auf dem großen, der kleine soll wieder übernemehm \
  $mode = 2 if($SBS_Bereit == 1 && $SBS2_5_Ladestand >= $minPCT_SBS2_5 \
&& $STP8SE_istCargePower  < 1000 && $modeAktiv == 2);;\
  #der kleine ist n icht bereit oder leer, der große übernimmt \
  $mode = 3 if($STP_Bereit != 1 || $STP8SE_Ladestand <= $minPCT\
&& $SBS_Bereit == 1 && $SBS2_5_Ladestand >= $minPCT_SBS2_5);;\
  #der kleine kommt an seine leistunsgrenze der große übernimmt \
  $mode = 4 if($SBS_Bereit == 1 && $SBS2_5_Ladestand >= $minPCT_SBS2_5\
&& $STP_Bereit == 1 && $STP8SE_Ladestand >= $minPCT\
&& ($SBS2_5_istCargePower  > 1700 || $NVP_PWR > 1700));;\
  #der kleine ist leer oder nicht verfügbar, der große übernimmt\
  $mode = 5 if($SBS_Bereit != 1 || $SBS2_5_Ladestand <= $minPCT_SBS2_5);;\
  #wir brauchen alles was leistung bring, beide WR frei geben\
  $mode = 6 if($SBS2_5_istCargePower + $STP8SE_istCargePower > 7500 || $STP8SE_AC_Power > 7800);;\
  #beide aktiv und einer lädt und der andere entlädt? zurück auf Ursprung\
  $mode = 55 if(($SBS2_5_istCargePower > 0 && $STP8SE_istCargePower < 0) || ($SBS2_5_istCargePower < 0 && $STP8SE_istCargePower > 0));;\
  #HVM wird priorisiert\
  $mode = 8 if($STP_Bereit == 1 && $STP8SE_Ladestand >= $minPCT && (($SpeicherWechsel eq "HVM" && $mode != 10) || $Control_Mode eq "BEV") );;\
  #BEV und großer Speicher voll\
  $mode = 51 if($STP_Bereit == 1 && $SBS_Bereit == 1 && $STP8SE_Ladestand >= 90 && $SBS2_5_Ladestand < 90 && $Control_Mode eq "BEV");;\
  \
  if($mode == 1 || $mode == 2 || $mode == 3 || $mode == 6 || $mode == 10) #SBS\
  {\
if($set_Aktiv_SBS_ist == "802" && $SBS2_5_istCargePower < 50)\
{\
$DischargePower_SBS = 200;;\
$DischargePower_SBS = $STP8SE_istCargePower * 1.1 if($DischargePower_SBS < $STP8SE_istCargePower);;\
$DischargePower_SBS = $NVP_PWR * 1.1 if($DischargePower_SBS < $NVP_PWR);;\
$set_Aktiv_STP = "803";; #SMA Steuert\
$modeAktiv = 1.1;;\
$sollwertNR = 818.1;;\
}\
else\
{\
$set_Aktiv_SBS = "803";; #SMA Steuert\
$set_Aktiv_STP = "802";; #FHEM Steuert\
$modeAktiv = 1;;\
$sollwertNR = 818;;\
}\
  }\
  elsif($mode == 4 || $mode == 5 || $mode == 8|| $mode == 9) #STP\
  {\
if($set_Aktiv_STP_ist == "802" && $STP8SE_istCargePower < 50)\
{\
$DischargePower_STP = 200;;\
$DischargePower_STP = $SBS2_5_istCargePower * 1.1 if($DischargePower_STP < $SBS2_5_istCargePower);;\
$DischargePower_STP = $NVP_PWR * 1.1 if($DischargePower_STP < $NVP_PWR);;\
$set_Aktiv_SBS = "803";; #SMA Steuert\
$modeAktiv = 2.1;;\
$sollwertNR = 819.1;;\
}\
else\
{\
$set_Aktiv_SBS = "802";; #FHEM Steuert\
$set_Aktiv_STP = "803";; #SMA Steuert\
$modeAktiv = 2;;\
$sollwertNR = 819;;\
}\
  }\
  elsif($mode == 51) #beide aber STP ist fast voll\
  {\
$set_Aktiv_SBS = "802";; #FHEM Steuert\
$set_Aktiv_STP = "803";; #SMA Steuert\
$modeAktiv = 5;;\
$sollwertNR = 822;;\
$DischargePower_SBS = $STP8SE_istCargePower if($STP8SE_istCargePower <= -200);;\
$DischargePower_SBS = -2000 if($DischargePower_SBS <= -2000);;\
  }\
  elsif($mode == 55)\
  {\
if($istCargePower < 2000 && $SBS_Bereit == 1 && $SBS2_5_Ladestand >= $minPCT)\
{\
$set_Aktiv_SBS = "803";; #SMA Steuert\
$set_Aktiv_STP = "802";; #FHEM Steuert\
$mode = 1;;\
}\
else\
{\
$set_Aktiv_SBS = "802";; #FHEM Steuert\
$set_Aktiv_STP = "803";; #SMA Steuert\
$mode = 4;;\
}\
$modeAktiv = 3;;\
$sollwertNR = 820;;\
  }\
  else\
  {\
$set_Aktiv_SBS = "803";; #SMA Steuert\
$set_Aktiv_STP = "803";; #SMA Steuert\
$modeAktiv = 4;;\
$sollwertNR = 821;;\
  }\
  \
  fhem("setreading ".$this." ChargeMode 0");;\
  fhem("setreading ".$this." ChargeModeAktiv 0");;\
  fhem("setreading ".$this." DischargeMode ".$mode) if(ReadingsNum($this, "DischargeMode", 0) ne $mode);;\
  fhem("setreading ".$this." DischargeModeAktiv ".$modeAktiv);;\
      fhem("setreading ".$this." DischargeSpeicherWechsel ".$SpeicherWechsel);;\
  \
  fhem("setreading ".$STP8SE." Set_Leistung ".$DischargePower_STP) if($STP8SE_Auto eq "on");;\
  fhem("set ".$STP8SE." Set_Aktiv ".$set_Aktiv_STP) if($STP8SE_Auto eq "on");;\
  fhem("setreading ".$SBS2_5." Set_Leistung ".$DischargePower_SBS) if($SBS2_5_Auto eq "on");;\
  fhem("set ".$SBS2_5." Set_Aktiv ".$set_Aktiv_SBS) if($SBS2_5_Auto eq "on");;\
  \
  $send_change = 1 if(ReadingsVal($STP8SE, "Set_Leistung", "") != $DischargePower_STP);;\
  $send_change = 1 if(ReadingsVal($STP8SE, "Set_Aktiv", "") ne $set_Aktiv_STP);;\
  $send_change2 = 1 if(ReadingsVal($SBS2_5, "Set_Leistung", "") != $DischargePower_SBS);;\
  $send_change2 = 1 if(ReadingsVal($SBS2_5, "Set_Aktiv", "") ne $set_Aktiv_SBS);;\
  \
  if($Control_Mode eq "BEV")\
  {\
  fhem("set ".$STP8SE." BEV") if($STP8SE_Auto eq "on");;\
  fhem("set ".$SBS2_5." BEV") if($SBS2_5_Auto eq "on");;\
  fhem("setreading ".$this." INFO_Sollwertherkunft BEV");;\
  $sollwert = "BEV";;\
  $sollwertNR = 813.5;;\
  }\
  else\
  {\
fhem("set ".$STP8SE." Entladen") if($STP8SE_Auto eq "on");;\
fhem("set ".$SBS2_5." Entladen") if($SBS2_5_Auto eq "on");;\
fhem("setreading ".$this." INFO_Sollwertherkunft Entladen");;\
$sollwert = "entladen";;\
$sollwertNR = 813;;\
  }\
  }\
}\
elsif(ReadingsVal($this, "Automatic", "") eq "test")\
{\
    $send_change = 1;;\
\
$sollwert = "test";;\
$sollwertNR = 814;;\
fhem("set ".$STP8SE." Test_aktiv");;\
fhem("set ".$SBS2_5." Test_aktiv");;\
}\
else\
{\
    $send_change = 1 if(ReadingsVal($STP8SE, "Set_Aktiv", "") ne "803");;\
    fhem("set ".$STP8SE." Set_Aktiv 803");;\
#fhem("setreading ".$STP8SE." Set_Aktiv_ SMA");;\
    fhem("set ".$STP8SE." SMA_aktiv");;\
\
$sollwert = "Auto_off";;\
$sollwertNR = 815;;\
}\
\
if($STP8SE_Auto eq "test")\
{\
fhem("set ".$STP8SE." Test_aktiv");;\
$send_change = 1 if(ReadingsAge($STP8SE, "Send", 9999999999) > 10);;\
}\
\
$send_change = 1 if(ReadingsAge($STP8SE, "Send", 9999999999) > 20);;\
\
if(ReadingsVal($STP8SE, "Send_Aktiv", "") eq "on" && $send_change == 1)\
{\
my $trigger = ReadingsNum($STP8SE, "Send", 1) + 1;;\
$trigger = 1 if($trigger > 999);;\
    fhem("set ".$STP8SE." Send ".$trigger);;\
}\
\
if($SBS2_5_Auto eq "test")\
{\
fhem("set ".$SBS2_5." Test_aktiv");;\
$send_change2 = 1 if(ReadingsAge($SBS2_5, "Send", 9999999999) > 10);;\
}\
\
$send_change2 = 1 if(ReadingsAge($SBS2_5, "Send", 9999999999) > 20);;\
\
if(ReadingsVal($SBS2_5, "Send_Aktiv", "") eq "on" && $send_change2 == 1)\
{\
my $trigger = ReadingsNum($SBS2_5, "Send", 1) + 1;;\
$trigger = 1 if($trigger > 999);;\
    fhem("set ".$SBS2_5." Send ".$trigger);;\
}\
\
fhem("setreading ".$this." DischargeSpeicherWechsel ".$SpeicherWechsel);;\
\
fhem("setreading ".$STP8SE." INFO_Sollwert_herkunft ".$sollwert);;\
fhem("setreading ".$STP8SE." INFO_Sollwert_herkunftNR ".$sollwertNR);;\
\
fhem("setreading ".$SBS2_5." INFO_Sollwert_herkunft ".$sollwert_SBS);;\
fhem("setreading ".$SBS2_5." INFO_Sollwert_herkunftNR ".$sollwertNR_SBS);;\
\
fhem("setreading ".$STP8SE." Calc_check ".ReadingsVal($STP8SE, "Calc", 1));;\
}
attr Speichersteuerung.calc.n alias Speichersteuerung.calc.n
attr Speichersteuerung.calc.n room PV->Speichersteuerung,PV->Stromversorgung

Lenovo M910Q Tiny Debian 12, FHEM 6.3, 2x Siemens Logo 0BA7, Homematic CCU3, Philips HUE, 6x SMA Wechselrichter, BYD HVM, BYD HVS, SMA EVCharger, KEBA Wallbox, 2x HMS800W, Daikin Wärmepumpe über CAN, viele ESPs

Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/MadMax