Hoymiles MS-A2 in FHEM integrierbar?

Begonnen von Jackie, 23 April 2025, 10:22:19

Vorheriges Thema - Nächstes Thema

matthias_t

Hallo zusammen,

was für ein Zufall, ich scheitere auch just in diesem Moment an dieser Angelegenheit.

@sprudelverduenner: Deine komplette Config wäre wirklich Gold wert, vorab vielen Dank! :)

Grüße
Matthias

Jochen_M

#16
Hallo @sprudelverduenner, @matthias_t,
Ich habe den Hoymiles HiBattery 1920 AC am Wochenende in meiner FHEM Umgebung zum Laufen bekommen und alles hier mal zusammengefasst.

Ist vielleicht nicht der beste Weg, ab so scheint es bei mir zu funktionieren.
Gerne freue ich mich über Verbesserungsvorschläge oder Optimierungen.

Danke an die Community. 8)


Ich habe eine HiBattery 1920 AC und lesen meinen GRID Status mit einem IR Reader (Tasmota base) aus.

Devices:
- HiBattery 1920 AC >> MSA_xxxxxxxxxxxxx
  --> muss angepasst werden
  --> Arbeitsbereich SoC 15-95%
  --> Notfallbeladung SoC < 12% (Vermeidung einer Tiefenentladung)
- GRID Strommesser (Tasmota IR Reader) >> MQTT2_DVES_aaaaaa --> muss angepasst werden

Hier die Definition des Devices:
define MSA_xxxxxxxxxxxxx MQTT2_DEVICE MSA_xxxxxxxxxxxxx
attr MSA_xxxxxxxxxxxxx alias HiBattery_1920_AC
attr MSA_xxxxxxxxxxxxx devStateIcon {\
    my $onl = ReadingsVal($name,'bat_sts','standby') eq 'charge'?'10px-kreis-gruen':'10px-kreis-rot';;\
    $onl = FW_makeImage($onl);;\
    my $light = ReadingsVal($name,'bat_sts','standby') eq 'standby'?FW_makeImage('off'):FW_makeImage('on');;\
    my $emsmode = ReadingsVal($name,'ems_mode','general');;\
    my $plug_p = ReadingsNum($name,'sys_plug_p',0);;\
    my $grid_p = ReadingsNum($name,'sys_grid_p',0);;\
    my $soc = ReadingsNum($name,'soc',0);;\
    my $temp = ReadingsVal($name,'bat_temp','-100');; \
    my $batsts = ReadingsVal($name,'bat_sts','standby');; \
    my $batheating = ReadingsVal($name,'heat','false');;\
    my $connection = ReadingsNum($name,'rssi',0);;\
    \
    my $eIn = ReadingsNum($name,'grid_1_ein',0);;  # eingespeiste Energie in Batterie heute [Wh]\
    my $eOut = ReadingsNum($name,'grid_1_eout',0);; # entnommene Energie in Batterie heute [Wh]\
    my $etIn = ReadingsNum($name,'grid_1_etin',0);; # eingespeiste Energie in Batterie gesammt [Wh]\
    my $etOut = ReadingsNum($name,'grid_1_etout',0);; # entnommene Energie in Batterie gesammt [Wh]    \
    my $etRation = ReadingsNum($name,'myetRatio',0);; # Wirkungsgrad etout/etin\
    \
    qq(${light}${onl}<div>EMSmode: $emsmode / Mode: $batsts / SOC: $soc % / RSSI: $connection dBm</div><div>Power Plug: $plug_p W / Grid Plug: $grid_p W / Temp: $temp °C / BATheating: $batheating</div><div>Energie: today In: $eIn Wh Out: $eOut Wh / Total In: $etIn Wh Out: $etOut Wh / Wirkungsgrad: $etRation %</div>)\
}
attr MSA_xxxxxxxxxxxxx group Energie Devices
attr MSA_xxxxxxxxxxxxx icon measure_battery_100
attr MSA_xxxxxxxxxxxxx readingList MSA_xxxxxxxxxxxxx:homeassistant/sensor/MSA-xxxxxxxxxxxxx/quick/state:.* { json2nameValue($EVENT) }\
MSA_xxxxxxxxxxxxx:homeassistant/switch/MSA-xxxxxxxxxxxxx/config:.* { json2nameValue($EVENT) }\
MSA_xxxxxxxxxxxxx:homeassistant/sensor/MSA-xxxxxxxxxxxxx/attributes:.* { json2nameValue($EVENT) }\
MSA_xxxxxxxxxxxxx:homeassistant/number/MSA-xxxxxxxxxxxxx/power_ctrl/config:.* config\
MSA_xxxxxxxxxxxxx:homeassistant/sensor/MSA-xxxxxxxxxxxxx/soc/config:.* { json2nameValue($EVENT) }\
MSA_xxxxxxxxxxxxx:homeassistant/sensor/MSA-xxxxxxxxxxxxx/bat_p/config:.* { json2nameValue($EVENT) }\
MSA_xxxxxxxxxxxxx:homeassistant/select/MSA-xxxxxxxxxxxxx/ems_mode/config:.* config\
MSA_xxxxxxxxxxxxx:homeassistant/sensor/MSA-xxxxxxxxxxxxx/system/state:.* { json2nameValue($EVENT) }\
MSA_xxxxxxxxxxxxx:homeassistant/sensor/MSA-xxxxxxxxxxxxx/device/state:.* { json2nameValue($EVENT) }
attr MSA_xxxxxxxxxxxxx room MQTT2_DEVICE
attr MSA_xxxxxxxxxxxxx setList ems_mode_on:noArg homeassistant/select/MSA-xxxxxxxxxxxxx/ems_mode/command mqtt_ctrl\
set:slider,-500,-400,-300,-200,-100,-50,0,50,100,200,300,400,500 homeassistant/number/MSA-xxxxxxxxxxxxx/power_ctrl/set

Logfile:
define FileLog_MSA_xxxxxxxxxxxxx FileLog ./log/MSA_HiBattery-%Y-%m.log MSA_xxxxxxxxxxxxx:my.*:.*
attr FileLog_MSA_xxxxxxxxxxxxx logtype text
attr FileLog_MSA_xxxxxxxxxxxxx room MQTT2_DEVICE

#falls HiBattery in "ems_mode" "general" wechselt, rückstellung auf "mqtt_ctrl"
#dazu Funktion "EMSModeWatchdog" in 99_myUtils.pm (siehe unten)

define di_ems_mode_watchdog DOIF (\
 ([MQTT2_DVES_aaaaaa:SML_curr_w])\
 and\
 ([?di_ems_mode_watchdog:active] <= 1)\
 and\
 ([?MSA_xxxxxxxxxxxxx:ems_mode] ne "mqtt_ctrl")\
)\
(\
  { EMSModeWatchdog("MSA_xxxxxxxxxxxxx") }\
)\
DOELSE\
()
attr di_ems_mode_watchdog cmdState 1#wakeUp|#2MQTTconnected
attr di_ems_mode_watchdog cmdpause 60:60
attr di_ems_mode_watchdog do always
attr di_ems_mode_watchdog icon time_timer
attr di_ems_mode_watchdog room MQTT2_DEVICE,Power_Analyse

#Steuerung, basierend auf dem Verbrauch/Einspeisungswert des GRID Strommesser (Tasmota IR Reader)
define DI_HiBattery_1_SMLcurrW DOIF (\
 (\
  ([MQTT2_DVES_aaaaaa:SML_curr_w] >= 0)\
 )\
)\
(\
 {\
  my $GRIDpower = round(ReadingsNum('MQTT2_DVES_aaaaaa','SML_curr_w',0),0);;\
  my $newValue = $GRIDpower-50;;\
  my $soc = ReadingsNum('MSA_xxxxxxxxxxxxx','soc',0);;\
  my $AlertChargeStatus = ReadingsNum('DI_HiBattery_1_SMLcurrW','AlertCharge',0);;\
  if ($AlertChargeStatus == 1) {\
    fhem("set MSA_xxxxxxxxxxxxx set -50");;\
    Log 3, "DI_HiBattery_1_SMLcurrW - cmd1 : Alert SoC= $soc % - CHARGE -50 W";; \
  }\
  elsif (($newValue <=50) || ($soc <= 16)) {\
    fhem("set MSA_xxxxxxxxxxxxx set 0");;\
    Log 3, "DI_HiBattery_1_SMLcurrW - cmd1 : Value MSA: 0 - SoC= $soc % - GRIDpower= $GRIDpower - newValue=$newValue";; \
  }\
  elsif ($newValue >=50.1) {\
      fhem("set MSA_xxxxxxxxxxxxx set $newValue");;\
      Log 3, "DI_HiBattery_1_SMLcurrW - cmd1 : newValue= $newValue";; \
  }\
  else{\
    my $MSApower = round(ReadingsNum('MSA_xxxxxxxxxxxxx','bat_p',0),0);;\
    fhem("set MSA_xxxxxxxxxxxxx set $MSApower");;\
    Log 3, "DI_HiBattery_1_SMLcurrW - cmd1 : Value MSA: $MSApower";; \
  }\
 }\
)\
DOELSEIF\
(\
 (\
  ([MQTT2_DVES_aaaaaa:SML_curr_w] <= 10)\
  and\
  ([?MQTT2_DVES_aaaaaa:SML_curr_w] >= -30)\
 )\
 or\
 (\
  ([?MSA_xxxxxxxxxxxxx:soc] >= 95)\
 )\
 or\
 (\
  ([?MQTT2_DVES_aaaaaa:SML_curr_w] >= -30)\
  and\
  ([?MSA_xxxxxxxxxxxxx:soc] <= 15)\
 )\
)\
(\
 set MSA_xxxxxxxxxxxxx set 0;;\
 {\
 Log 3, "DI_HiBattery_1_SMLcurrW - cmd2 : Value MSA: 0";; \
 }\
)\
DOELSEIF\
(\
 (\
  ([MQTT2_DVES_aaaaaa:SML_curr_w] <= -100)\
  and\
  ([?MSA_xxxxxxxxxxxxx:soc] <= 94.9)\
 )\
)\
(\
 {\
  my $GRIDpower = ReadingsNum('MQTT2_DVES_aaaaaa','SML_curr_w',0);;\
  my $MSApower = ReadingsNum('MSA_xxxxxxxxxxxxx','bat_p',0);;\
  my $newValue = round($MSApower+$GRIDpower+50,0);;\
  fhem("set MSA_xxxxxxxxxxxxx set $newValue");;\
  Log 3, "DI_HiBattery_1_SMLcurrW - cmd3 : Value MSA: $MSApower GRID: $GRIDpower newValue: $newValue";; \
 }\
)\
DOELSE\
(\
)\
(\
 {\
  my $MSApower = round(ReadingsNum('MSA_xxxxxxxxxxxxx','bat_p',0),0);;\
  fhem("set MSA_xxxxxxxxxxxxx set $MSApower");;\
  Log 3, "DI_HiBattery_1_SMLcurrW - cmd4 : Value MSA: $MSApower";; \
 }\
)
attr DI_HiBattery_1_SMLcurrW checkall event
attr DI_HiBattery_1_SMLcurrW cmdState #1SetAkkuDisCharge|#2SetAkkuoff|#3SetAkkuCharge|#4KeepAlive
attr DI_HiBattery_1_SMLcurrW cmdpause 0:5:15:15
attr DI_HiBattery_1_SMLcurrW do always
attr DI_HiBattery_1_SMLcurrW icon measure_power
attr DI_HiBattery_1_SMLcurrW room MQTT2_DEVICE

#Vermeidung der vielen Events im LOG, eigene Readings zum loggen der "wichtigen" Messwerte
#Quick Daten, alle 1 Minuten
define atPowerDataStore_HiBatttery_1 at +*00:01:00 {\
  my $function = "atPowerDataStore_HiBatttery_1";;\
  my $DeviceName_HiBatt = "MSA_xxxxxxxxxxxxx";;\
  my $Value_sys_plug_p = ReadingsNum($DeviceName_HiBatt,'sys_plug_p',0) || 0;;\
  if ($Value_sys_plug_p != 0) {\
   fhem ("setreading $DeviceName_HiBatt myPowerPlug $Value_sys_plug_p");;\
   Log 3, $function.": data stored";;\
  }\
}
attr atPowerDataStore_HiBatttery_1 alignTime 00:00
attr atPowerDataStore_HiBatttery_1 icon time_clock
attr atPowerDataStore_HiBatttery_1 room MQTT2_DEVICE

#Status Daten, alle 5 Minuten
define atPowerDataStore_HiBatttery_2 at +*00:05:00 {\
  my $function = "atPowerDataStore_HiBatttery_5";;\
  my $DeviceName_HiBatt = "MSA_xxxxxxxxxxxxx";;\
  my $Value_soc = ReadingsNum($DeviceName_HiBatt,'soc',0) || 0;;\
  my $Value_ems_mode = ReadingsVal($DeviceName_HiBatt,'ems_mode',"na");;\
  my $Value_grid_1_ein = ReadingsNum($DeviceName_HiBatt,'grid_1_ein',0) || 0;;\
  my $Value_grid_1_eout = ReadingsNum($DeviceName_HiBatt,'grid_1_eout',0) || 0;;\
  my $Value_grid_1_etin = ReadingsNum($DeviceName_HiBatt,'grid_1_etin',0) || 0;;\
  my $Value_grid_1_etout = ReadingsNum($DeviceName_HiBatt,'grid_1_etout',0) || 0;;\
  my $ValueetRatio = 0;;\
  if ($Value_grid_1_etout >= 0.1) {\
   $ValueetRatio = round($Value_grid_1_etout/$Value_grid_1_etin*100,0);;\
  }\
  fhem ("setreading $DeviceName_HiBatt mysoc $Value_soc");;  \
  fhem ("setreading $DeviceName_HiBatt myems_mode $Value_ems_mode");;\
  fhem ("setreading $DeviceName_HiBatt myein $Value_grid_1_ein");;\
  fhem ("setreading $DeviceName_HiBatt myeout $Value_grid_1_eout");;\
  fhem ("setreading $DeviceName_HiBatt myetin $Value_grid_1_etin");;\
  fhem ("setreading $DeviceName_HiBatt myetout $Value_grid_1_etout");;\
  fhem ("setreading $DeviceName_HiBatt myetRatio $ValueetRatio");;\
  Log 3, $function.": data stored";;\
}
attr atPowerDataStore_HiBatttery_2 alignTime 00:01
attr atPowerDataStore_HiBatttery_2 icon time_clock
attr atPowerDataStore_HiBatttery_2 room MQTT2_DEVICE

#Plot zum Darstung der Leistung "myPowerPlug" und SoC Status "mysoc"
define SVG_FileLog_MSA_xxxxxxxxxxxxx_1 SVG FileLog_MSA_xxxxxxxxxxxxx:SVG_FileLog_MSA_xxxxxxxxxxxxx_1:CURRENT
attr SVG_FileLog_MSA_xxxxxxxxxxxxx_1 alias HiBatteryStatus#0
attr SVG_FileLog_MSA_xxxxxxxxxxxxx_1 plotsize 800,320
attr SVG_FileLog_MSA_xxxxxxxxxxxxx_1 room MQTT2_DEVICE

#wenn SoC < 12% dann LadeAlert setzen, entfernen wenn 15% erreicht ist
#Sicherstellung, das das HiBattery nicht tiefentladen wird (z.B. im Winter)
define DI_HiBattery_1_AlertCharge DOIF (\
  ([MSA_xxxxxxxxxxxxx:soc] <= 12)\
)\
(\
  {\
    fhem("setreading DI_HiBattery_1_SMLcurrW AlertCharge 1");;\
    my $soc = ReadingsNum('MSA_xxxxxxxxxxxxx','soc',0);;\
    Log 3, "DI_HiBattery_1_AlertCharge - cmd1 : SoC= $soc % - AlertCharge >> 1 (Alert)";; \
  }\
)\
DOELSEIF\
(\
  ([MSA_xxxxxxxxxxxxx:soc] >= 15)\
  and\
  ([?DI_HiBattery_1_SMLcurrW:AlertCharge] >= 0.1)\
)\
(\
  {\
    fhem("setreading DI_HiBattery_1_SMLcurrW AlertCharge 0");;\
    my $soc = ReadingsNum('MSA_xxxxxxxxxxxxx','soc',0);;\
    Log 3, "DI_HiBattery_1_AlertCharge - cmd1 : SoC= $soc % - AlertCharge >> 0";; \
  }\
)\
DOELSE\
()\
attr DI_HiBattery_1_AlertCharge checkall event
attr DI_HiBattery_1_AlertCharge cmdState #1SoCState-Charging|#2SoCState-ChargingFinish|#3:-
attr DI_HiBattery_1_AlertCharge do always
attr DI_HiBattery_1_AlertCharge icon measure_power
attr DI_HiBattery_1_AlertCharge room MQTT2_DEVICE

#Email, wenn SoC LadeAlert gesetzt wird
define DI_HiBattery_1_AlertCharge_EMail DOIF ([DI_HiBattery_1_SMLcurrW:AlertCharge] >= 0.1) \
(\
  {\
  my $soc = ReadingsNum('MSA_xxxxxxxxxxxxx','soc',0);;\
  DebianMail('myemail@provider.de',"RASPI Info HiBattery SoC Alert - SoC Wert: ".$soc,\
     "INFO: DI_HiBattery_1_SMLcurrW - SoC Alert"\
    ."\n"."   Batteriestatus: ".$soc." %"\
    ."\n"\
     ."\n"."Datenerhebung vom ".JM_time_DE_system()."\n"\
    ,'');;\
  }\
)\
DOELSE\
()
attr DI_HiBattery_1_AlertCharge_EMail checkall event
attr DI_HiBattery_1_AlertCharge_EMail cmdState #1:AlertEMail|#2:-
attr DI_HiBattery_1_AlertCharge_EMail do always
attr DI_HiBattery_1_AlertCharge_EMail icon message_mail_open
attr DI_HiBattery_1_AlertCharge_EMail room MQTT2_DEVICE


Funktion in 99_myUtils.pm
sub EMSModeWatchdog($)
{
  my ($dev) = @_;

  my $target = "mqtt_ctrl";
  my $mode   = ReadingsVal($dev, 'ems_mode', '');

  my $state  = ReadingsNum('di_ems_mode_watchdog','active',0);
  my $start  = ReadingsNum('di_ems_mode_watchdog','start',0);
  my $now    = time();

  # Start initialisieren
  if(!$state)
  {
    fhem("setreading di_ems_mode_watchdog active 1");
    fhem("setreading di_ems_mode_watchdog start $now");
  }

  # Ziel erreicht -> Stop
  if($mode eq $target)
  {
    fhem("setreading di_ems_mode_watchdog active 0");
    return;
  }

  my $elapsed = $now - $start;

  # 10 Minuten Timeout
  if($elapsed >= 600)
  {
    fhem("set Mailer msg 'EMS Mode Fehler: mqtt_ctrl nicht erreicht'");
    fhem("setreading di_ems_mode_watchdog active 0");
    return;
  }

  # alle 120s re-init
  if(($now - ReadingsNum('di_ems_mode_watchdog','lastInit',0)) >= 120)
  {
    fhem("set $dev ems_mode_on");
    fhem("setreading di_ems_mode_watchdog lastInit $now");
  }

  # 15s retry
  fhem("set $dev set 0");

  InternalTimer($now+15, "EMSModeWatchdog", $dev, 0);
}


matthias_t

Hallo Jochenm_M,

besten Dank für den umfangreichen Input!

Mein Use Case ist ein wenig anders, ich will in die automatische Einspeisung meiner beiden MS-A2 gar nicht eingreifen, das läuft wunderbar autark über den Shelly Pro 3 EM. Ich möchte aber die beiden MS-A2 auf Einspeisung "0" setzen, wenn unser künftiges eAuto an der mobilen Wallbox hängt. Bisher weigern sich die beiden MS-A2 aber beharrlich, überhaupt aus dem ems-Mode "general" herauszukommen. :(

Aber für meinen Ansatz werde ich sicherlich ein Paar Zeilen bei dir abschreiben... ;)

Akzeptiert Deine HiBattery mehrmals hintereinander identische Zielwerte per set? Hier ließt man auch immer verschiedenes...

Grüße
Matthias

Jochen_M

Hallo matthias_t,
ich auch noch am evaluieren, aber bisher hatte ich noch keine Problemen mit der aktuellen FW.

Viel Erfolg und die Shelly EM 3Pro habe ich noch nicht implementiert, das kommt erst, wenn der andere Weg zu viel Aufwand macht ;-)

Viel Erfolg
Jochen