diff --git a/fhem/CHANGED b/fhem/CHANGED index 6222a479e..9e1c2c880 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,7 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - change: 76_SMAInverter: readings bat_loadtotal / bat_loadtoday included, + thanks to 300P - change: 70_SolarEdgeAPI: increment version number for previous change - change: 70_SolarEdgeAPI: show SolarEdge logo to comply with API requirements - update: 98_MSwitch: New Version 2.6a diff --git a/fhem/FHEM/76_SMAInverter.pm b/fhem/FHEM/76_SMAInverter.pm index a331e5699..e420b2970 100644 --- a/fhem/FHEM/76_SMAInverter.pm +++ b/fhem/FHEM/76_SMAInverter.pm @@ -1,7 +1,7 @@ ################################################################################################################# # $Id$ ################################################################################################################# -# +# # Copyright notice # # Published according Creative Commons : Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) @@ -13,7 +13,7 @@ # - Waldmensch for various improvements # - sbfspot (https://sbfspot.codeplex.com/) # - rewritten by Thomas Schoedl (sct14675) with inputs from Volker, waldmensch and DS_Starter -# +# # Description: # This is an FHEM-Module for SMA Inverters. # @@ -23,15 +23,16 @@ package main; use strict; use warnings; -eval "use IO::Socket::INET;1" or my $MissModulSocket = "IO::Socket::INET"; -eval "use DateTime;1" or my $MissModulDateTime = "DateTime"; +eval "use IO::Socket::INET;1" or my $MissModulSocket = "IO::Socket::INET"; +eval "use DateTime;1" or my $MissModulDateTime = "DateTime"; use Time::HiRes qw(gettimeofday tv_interval); use Blocking; use Time::Local; -eval "use FHEM::Meta;1" or my $modMetaAbsent = 1; +eval "use FHEM::Meta;1" or my $modMetaAbsent = 1; # Versions History by DS_Starter our %SMAInverter_vNotesIntern = ( + "2.14.0" => "08.10.2019 readings bat_loadtotal (BAT_LOADTOTAL), bat_loadtoday (BAT_LOADTODAY) included by 300P, Forum: #topic,56080.msg986302.html#msg986302", "2.13.4" => "30.08.2019 STP10.0-3AV-40 298 included into %SMAInverter_devtypes ", "2.13.3" => "28.08.2019 commandref revised ", "2.13.2" => "27.08.2019 fix WARNING: Use of uninitialized value \$_ in substitution (s///) at /opt/fhem//FHEM/Blocking.pm line 238 ", @@ -89,9 +90,9 @@ our %SMAInverter_vNotesIntern = ( # $inv_SPOT_ETOTAL # Total yield # $inv_SPOT_PDC1 # DC power input 1 # $inv_SPOT_PDC2 # DC power input 2 -# $inv_SPOT_PAC1 # Power L1 -# $inv_SPOT_PAC2 # Power L2 -# $inv_SPOT_PAC3 # Power L3 +# $inv_SPOT_PAC1 # Power L1 +# $inv_SPOT_PAC2 # Power L2 +# $inv_SPOT_PAC3 # Power L3 # $inv_PACMAX1 # Nominal power in Ok Mode # $inv_PACMAX2 # Nominal power in Warning Mode # $inv_PACMAX3 # Nominal power in Fault Mode @@ -120,6 +121,8 @@ our %SMAInverter_vNotesIntern = ( # $inv_TEMP # Inverter temperature # $inv_GRIDRELAY # Grid Relay/Contactor Status # $inv_STATUS # Inverter Status +# $inv_BAT_LOADTODAY # Today Batteryload +# $inv_BAT_LOADTOTAL # Total Batteryload # Aufbau Wechselrichter Type-Hash my %SMAInverter_devtypes = ( @@ -292,7 +295,7 @@ sub SMAInverter_Initialize($) { $hash->{DefFn} = "SMAInverter_Define"; $hash->{UndefFn} = "SMAInverter_Undef"; $hash->{GetFn} = "SMAInverter_Get"; - $hash->{AttrList} = "interval " . + $hash->{AttrList} = "interval " . "detail-level:0,1,2 " . "disable:1,0 " . "mode:manual,automatic ". @@ -304,10 +307,11 @@ sub SMAInverter_Initialize($) { "target-susyid " . "target-serial " . $readingFnAttributes; + $hash->{AttrFn} = "SMAInverter_Attr"; - + eval { FHEM::Meta::InitMod( __FILE__, $hash ) }; # für Meta.pm (https://forum.fhem.de/index.php/topic,97589.0.html) - + return; } @@ -317,10 +321,10 @@ return; sub SMAInverter_Define($$) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); - - return "Error: Perl module ".$MissModulSocket." is missing. + + return "Error: Perl module ".$MissModulSocket." is missing. Install it on Debian with: sudo apt-get install libio-socket-multicast-perl" if($MissModulSocket); - return "Error: Perl module ".$MissModulDateTime." is missing. + return "Error: Perl module ".$MissModulDateTime." is missing. Install it on Debian with: sudo apt-get install libdatetime-perl" if($MissModulDateTime); return "Wrong syntax: use define SMAInverter " if ((int(@a) < 4) and (int(@a) > 5)); @@ -330,7 +334,7 @@ sub SMAInverter_Define($$) { $hash->{INTERVAL} = $hash->{HELPER}{INTERVAL} = AttrVal($name, "interval", 60); $hash->{HELPER}{FAULTEDCYCLES} = 0; delete($hash->{HELPER}{AVERAGEBUF}) if($hash->{HELPER}{AVERAGEBUF}); - + # protocol related defaults $hash->{HELPER}{MYSUSYID} = 233; # random number, has to be different from any device in local network $hash->{HELPER}{MYSERIALNUMBER} = 123321123; # random number, has to be different from any device in local network @@ -339,7 +343,7 @@ sub SMAInverter_Define($$) { $hash->{HELPER}{PKT_ID} = 0x8001; # Packet ID $hash->{HELPER}{MAXBYTES} = 300; # constant MAXBYTES scalar 300 $hash->{HELPER}{MODMETAABSENT} = 1 if($modMetaAbsent); # Modul Meta.pm nicht vorhanden - + # Versionsinformationen setzen SMAInverter_setVersionInfo($hash); @@ -358,7 +362,7 @@ sub SMAInverter_Define($$) { return "Argument:{$a[3]} not accepted as Host or IP. Read device specific help file."; } - $hash->{PASS} = $Pass; + $hash->{PASS} = $Pass; $hash->{HOST} = $Host; InternalTimer(gettimeofday()+5, "SMAInverter_GetData", $hash, 0); # Start Hauptroutine @@ -370,13 +374,12 @@ return undef; # SMAInverter Undefine ############################################################### sub SMAInverter_Undef($$) { - my ($hash, $name) = @_; - RemoveInternalTimer($hash); - BlockingKill($hash->{HELPER}{RUNNING_PID}); + my ($hash, $name) = @_; + RemoveInternalTimer($hash); + BlockingKill($hash->{HELPER}{RUNNING_PID}); return undef; } - ############################################################### # SMAInverter Get ############################################################### @@ -386,17 +389,17 @@ sub SMAInverter_Get($$) { my $name = shift @a; my $opt = shift @a; my $timeout = AttrVal($name, "timeout", 60); - + my $getlist = "Unknown argument $opt, choose one of ". "data:noArg "; - + return "module is disabled" if(IsDisabled($name)); - + if ($opt eq "data") { - SMAInverter_GetData($hash); + SMAInverter_GetData($hash); } else { return "$getlist"; - } + } return undef; } @@ -419,16 +422,16 @@ sub SMAInverter_Attr(@) { } InternalTimer(time+5, 'SMAInverter_GetData', $hash, 0); } - + if ($aName eq "disable") { if($cmd eq "set") { $do = ($aVal) ? 1 : 0; } $do = 0 if($cmd eq "del"); my $val = ($do == 1 ? "disabled" : "initialized"); - + readingsSingleUpdate($hash, "state", $val, 1); - + if ($do == 0) { my $mode = AttrVal($name, "mode", "automatic"); RemoveInternalTimer($hash); @@ -441,7 +444,7 @@ sub SMAInverter_Attr(@) { if ($aName eq "detail-level") { delete $defs{$name}{READINGS}; } - + if ($aName eq "SBFSpotComp") { delete $defs{$name}{READINGS}; } @@ -456,10 +459,10 @@ sub SMAInverter_Attr(@) { $hash->{INTERVAL} = $hash->{HELPER}{INTERVAL} = 60; } } - + if ($cmd eq "set" && $aName eq "offset") { if($aVal !~ /^\d+$/ || $aVal < 0 || $aVal > 7200) { return "The Value of $aName is not valid. Use value between 0 ... 7200 !";} - } + } if ($cmd eq "set" && $aName eq "timeout") { unless ($aVal =~ /^[0-9]+$/) { return " The Value for $aName is not valid. Use only figures 1-9 !";} } @@ -474,31 +477,31 @@ sub SMAInverter_GetData($) { my $name = $hash->{NAME}; my $interval = AttrVal($name, "interval", 60); my $timeout = AttrVal($name, "timeout", 60); - + RemoveInternalTimer($hash, "SMAInverter_GetData"); - + if ($init_done != 1) { InternalTimer(gettimeofday()+5, "SMAInverter_GetData", $hash, 0); return; } - + return if(IsDisabled($name)); - + if (exists($hash->{HELPER}{RUNNING_PID})) { Log3 ($name, 3, "SMAInverter $name - WARNING - old process $hash->{HELPER}{RUNNING_PID}{pid} will be killed now to start a new BlockingCall"); BlockingKill($hash->{HELPER}{RUNNING_PID}); } - + Log3 ($name, 4, "$name - ###############################################################"); Log3 ($name, 4, "$name - ########## Begin of new SMAInverter get data cycle ##########"); Log3 ($name, 4, "$name - ###############################################################"); Log3 ($name, 4, "$name - timeout cycles since module start: $hash->{HELPER}{FAULTEDCYCLES}"); - - # decide of operation + + # decide of operation if(AttrVal($name,"mode","automatic") eq "automatic") { # automatic operation mode - InternalTimer(gettimeofday()+$interval, "SMAInverter_GetData", $hash, 0); - } + InternalTimer(gettimeofday()+$interval, "SMAInverter_GetData", $hash, 0); + } $hash->{HELPER}{RUNNING_PID} = BlockingCall("SMAInverter_getstatusDoParse", "$name", "SMAInverter_getstatusParseDone", $timeout, "SMAInverter_getstatusParseAborted", $hash); $hash->{HELPER}{RUNNING_PID}{loglevel} = 4; @@ -514,22 +517,24 @@ sub SMAInverter_getstatusDoParse($) { my $hash = $defs{$name}; my $interval = AttrVal($name, "interval", 60); my $sc = AttrVal($name, "SBFSpotComp", 0); - my ($sup_EnergyProduction, - $sup_SpotDCPower, - $sup_SpotACPower, - $sup_MaxACPower, - $sup_MaxACPower2, - $sup_SpotACTotalPower, - $sup_ChargeStatus, - $sup_SpotDCVoltage, - $sup_SpotACVoltage, - $sup_BatteryInfo, - $sup_SpotGridFrequency, - $sup_TypeLabel, - $sup_OperationTime, - $sup_InverterTemperature, - $sup_GridRelayStatus, + my ($sup_EnergyProduction, + $sup_SpotDCPower, + $sup_SpotACPower, + $sup_MaxACPower, + $sup_MaxACPower2, + $sup_SpotACTotalPower, + $sup_ChargeStatus, + $sup_SpotDCVoltage, + $sup_SpotACVoltage, + $sup_BatteryInfo, + $sup_SpotGridFrequency, + $sup_TypeLabel, + $sup_OperationTime, + $sup_InverterTemperature, + $sup_GridRelayStatus, + $sup_SpotBatteryLoad, $sup_DeviceStatus); + my ($inv_TYPE, $inv_CLASS, $inv_SPOT_ETODAY, $inv_SPOT_ETOTAL, $inv_susyid, @@ -545,35 +550,37 @@ sub SMAInverter_getstatusDoParse($) { $inv_BAT_UDC, $inv_BAT_IDC, $inv_BAT_CYCLES, $inv_BAT_TEMP, + $inv_BAT_LOADTODAY, $inv_BAT_LOADTOTAL, $inv_SPOT_FREQ, $inv_SPOT_OPERTM, $inv_SPOT_FEEDTM, $inv_TEMP, $inv_GRIDRELAY, $inv_STATUS,); + my @row_array; my @array; my $avg = 0; my ($ist,$bst,$irt,$brt,$rt); - + # Background-Startzeit $bst = [gettimeofday]; - + Log3 ($name, 4, "$name -> Start BlockingCall SMAInverter_getstatusDoParse"); - - # set dependency from surise/sunset used for inverter operation time + + # set dependency from surise/sunset used for inverter operation time my $offset = AttrVal($name,"offset",0); my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); - + my ($sunrise_h,$sunrise_m,$sunrise_s) = split(":",sunrise_abs('-'.$offset)); my ($sunset_h,$sunset_m,$sunset_s) = split(":",sunset_abs('+'.$offset)); - + my $oper_start = DateTime->new(year=>$year+1900,month=>$mon+1,day=>$mday,hour=>$sunrise_h,minute=>$sunrise_m,second=>$sunrise_s,time_zone=>'local'); my $oper_stop = DateTime->new(year=>$year+1900,month=>$mon+1,day=>$mday,hour=>$sunset_h,minute=>$sunset_m,second=>$sunset_s,time_zone=>'local'); my $dt_now = DateTime->now(time_zone=>'local'); - + Log3 $name, 4, "$name - current time: ".$dt_now->dmy('.')." ".$dt_now->hms; Log3 $name, 4, "$name - operation time begin: ".$oper_start->dmy('.')." ".$oper_start->hms; Log3 $name, 4, "$name - operation time end: ".$oper_stop->dmy('.')." ".$oper_stop->hms; - + my $opertime_start = $oper_start->dmy('.')." ".$oper_start->hms; my $opertime_stop = $oper_stop->dmy('.')." ".$oper_stop->hms; - + # ETOTAL speichern für ETODAY-Berechnung wenn WR ETODAY nicht liefert if ($dt_now >= $oper_stop) { my $val = 0; @@ -581,32 +588,41 @@ sub SMAInverter_getstatusDoParse($) { $val = ReadingsNum($name, "SPOT_ETOTAL", 0) if (exists $defs{$name}{READINGS}{SPOT_ETOTAL}); BlockingInformParent("SMAInverter_setReadingFromBlocking", [$name, ".etotal_yesterday", $val], 0); } - + + # BATTERYLOAD_TOTAL speichern für BAT_LOADTODAY-Berechnung wenn WR BAT_LOADTODAY nicht liefert + if ($dt_now >= $oper_stop) { + my $val = 0; + $val = ReadingsNum($name, "bat_loadtotal", 0)*1000 if (exists $defs{$name}{READINGS}{bat_loadtotal}); + $val = ReadingsNum($name, "BAT_LOADTOTAL", 0) if (exists $defs{$name}{READINGS}{BAT_LOADTOTAL}); + BlockingInformParent("SMAInverter_setReadingFromBlocking", [$name, ".bat_loadtotal_yesterday", $val], 0); + } + if (($oper_start <= $dt_now && $dt_now <= $oper_stop) || AttrVal($name,"suppressSleep",0)) { # normal operation or suppressed sleepmode - + # Abfrage Inverter Startzeit $ist = [gettimeofday]; - + # Get the current attributes my $detail_level = AttrVal($name, "detail-level", 0); - + # Aufbau Command-Array my @commands = ("sup_TypeLabel", # Check TypeLabel "sup_EnergyProduction", # Check EnergyProduction - "sup_SpotDCPower", # Check SpotDCPower - "sup_SpotACPower", # Check SpotACPower - "sup_SpotACTotalPower", # Check SpotACTotalPower - "sup_ChargeStatus" # Check BatteryChargeStatus + "sup_SpotDCPower", # Check SpotDCPower + "sup_SpotACPower", # Check SpotACPower + "sup_SpotACTotalPower", # Check SpotACTotalPower + "sup_ChargeStatus" # Check BatteryChargeStatus ); - + if($detail_level > 0) { # Detail Level 1 or 2 >> get voltage and current levels push(@commands, "sup_SpotDCVoltage"); # Check SpotDCVoltage push(@commands, "sup_SpotACVoltage"); # Check SpotACVoltage push(@commands, "sup_BatteryInfo"); # Check BatteryInfo + push(@commands, "sup_SpotBatteryLoad"); # Check Batteryload } - + if($detail_level > 1) { # Detail Level 2 >> get all data push(@commands, "sup_SpotGridFrequency"); # Check SpotGridFrequency @@ -615,97 +631,100 @@ sub SMAInverter_getstatusDoParse($) { push(@commands, "sup_MaxACPower"); # Check MaxACPower push(@commands, "sup_MaxACPower2"); # Check MaxACPower2 push(@commands, "sup_GridRelayStatus"); # Check GridRelayStatus - push(@commands, "sup_DeviceStatus"); # Check DeviceStatus + push(@commands, "sup_DeviceStatus"); # Check DeviceStatus } if(SMAInverter_SMAlogon($hash->{HOST}, $hash->{PASS}, $hash)) { Log3 $name, 5, "$name - Logged in now"; - + foreach my $i(@commands) { if ($i eq "sup_TypeLabel") { ($sup_TypeLabel,$inv_TYPE,$inv_CLASS,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x58000200, 0x00821E00, 0x008220FF); - } + } elsif ($i eq "sup_EnergyProduction") { ($sup_EnergyProduction,$inv_SPOT_ETODAY,$inv_SPOT_ETOTAL,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x54000200, 0x00260100, 0x002622FF); - } + } elsif ($i eq "sup_SpotDCPower") { ($sup_SpotDCPower,$inv_SPOT_PDC1,$inv_SPOT_PDC2,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x53800200, 0x00251E00, 0x00251EFF); - } + } elsif ($i eq "sup_SpotACPower") { ($sup_SpotACPower,$inv_SPOT_PAC1,$inv_SPOT_PAC2,$inv_SPOT_PAC3,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51000200, 0x00464000, 0x004642FF); - } + } elsif ($i eq "sup_SpotACTotalPower") { ($sup_SpotACTotalPower,$inv_SPOT_PACTOT,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51000200, 0x00263F00, 0x00263FFF); - } + } elsif ($i eq "sup_ChargeStatus") { ($sup_ChargeStatus,$inv_ChargeStatus,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51000200, 0x00295A00, 0x00295AFF); - } + } elsif ($i eq "sup_SpotDCVoltage") { ($sup_SpotDCVoltage,$inv_SPOT_UDC1,$inv_SPOT_UDC2,$inv_SPOT_IDC1,$inv_SPOT_IDC2,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x53800200, 0x00451F00, 0x004521FF); - } + } elsif ($i eq "sup_SpotACVoltage") { ($sup_SpotACVoltage,$inv_SPOT_UAC1,$inv_SPOT_UAC2,$inv_SPOT_UAC3,$inv_SPOT_IAC1,$inv_SPOT_IAC2,$inv_SPOT_IAC3,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51000200, 0x00464800, 0x004655FF); - } + } elsif ($i eq "sup_BatteryInfo") { ($sup_BatteryInfo,$inv_BAT_CYCLES,$inv_BAT_TEMP,$inv_BAT_UDC,$inv_BAT_IDC,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51000200, 0x00491E00, 0x00495DFF); - } + } elsif ($i eq "sup_SpotGridFrequency") { ($sup_SpotGridFrequency,$inv_SPOT_FREQ,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51000200, 0x00465700, 0x004657FF); - } + } elsif ($i eq "sup_OperationTime") { ($sup_OperationTime,$inv_SPOT_OPERTM,$inv_SPOT_FEEDTM,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x54000200, 0x00462E00, 0x00462FFF); - } + } elsif ($i eq "sup_InverterTemperature") { ($sup_InverterTemperature,$inv_TEMP,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x52000200, 0x00237700, 0x002377FF); - } + } elsif ($i eq "sup_MaxACPower") { ($sup_MaxACPower,$inv_PACMAX1,$inv_PACMAX2,$inv_PACMAX3,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51000200, 0x00411E00, 0x004120FF); - } + } elsif ($i eq "sup_MaxACPower2") { ($sup_MaxACPower2,$inv_PACMAX1_2,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51000200, 0x00832A00, 0x00832AFF); - } + } elsif ($i eq "sup_GridRelayStatus") { ($sup_GridRelayStatus,$inv_GRIDRELAY,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51800200, 0x00416400, 0x004164FF); - } + } elsif ($i eq "sup_DeviceStatus") { ($sup_DeviceStatus,$inv_STATUS,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51800200, 0x00214800, 0x002148FF); - } - } - + } + elsif ($i eq "sup_SpotBatteryLoad") { + ($sup_SpotBatteryLoad,$inv_BAT_LOADTODAY,$inv_BAT_LOADTOTAL,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x54000200, 0x00496700, 0x004967FF); + } + } + # nothing more to do, just log out SMAInverter_SMAlogout($hash,$hash->{HOST}); - + # Inverter Laufzeit ermitteln $irt = tv_interval($ist); - + # Aufbau Ergebnis-Array push(@row_array, "modulstate normal"."\n"); push(@row_array, "opertime_start ".$opertime_start."\n"); - push(@row_array, "opertime_stop ".$opertime_stop."\n"); - - # Durchschnittswerteberechnung Energieerzeugung der letzten 5, 10, 15 Messungen - + push(@row_array, "opertime_stop ".$opertime_stop."\n"); + + # Durchschnittswerteberechnung Energieerzeugung der letzten 5, 10, 15 Messungen + my ($sum05, $sum10, $sum15); my $cnt05 = int(300/$interval); # Anzahl der Zyklen innerhalb 5 Minuten my $cnt10 = int(600/$interval); # Anzahl der Zyklen innerhalb 10 Minuten my $cnt15 = int(900/$interval); # Anzahl der Zyklen innerhalb 15 Minuten = Summe aller Messzyklen my $cntsum = $cnt15+1; # Sicherheitszuschlag Summe Anzahl aller Zyklen my @averagebuf; - if ($sup_TypeLabel && $sup_EnergyProduction && $inv_CLASS eq 8001) { + if ($sup_TypeLabel && $sup_EnergyProduction && $inv_CLASS eq 8001) { # only for this block because of warnings if values not set at restart - no warnings 'uninitialized'; + no warnings 'uninitialized'; if (!$hash->{HELPER}{AVERAGEBUF}) { for my $count (0..$cntsum) { # fill with new values $inv_SPOT_PACTOT = $inv_SPOT_PACTOT?$inv_SPOT_PACTOT:0; - push(@averagebuf, $inv_SPOT_PACTOT); + push(@averagebuf, $inv_SPOT_PACTOT); } } else { @averagebuf = split(/,/, $hash->{HELPER}{AVERAGEBUF}) } - - # rechtes Element aus average buffer löschen - pop(@averagebuf); + + # rechtes Element aus average buffer löschen + pop(@averagebuf); # und links mit neuem Wert füllen unshift(@averagebuf, $inv_SPOT_PACTOT); $avg = join(',', @averagebuf); @@ -729,21 +748,21 @@ sub SMAInverter_getstatusDoParse($) { } $k++; } - + my $AvP05 = int( $sum05 / ($cnt05+1) ); my $AvP10 = int( $sum10 / ($cnt10+1) ); my $AvP15 = int( $sum15 / ($cnt15+1) ); Log3 $name, 5, "$name - Content of Averagebuffer:"; Log3 $name, 5, "$name - $avg"; Log3 $name, 5, "$name - avg_power_lastminutes_05 = $AvP05, avg_power_lastminutes_10 = $AvP10, avg_power_lastminutes_15 = $AvP15"; - + push(@row_array, "avg_power_lastminutes_05 ".$AvP05."\n"); # Average Energy (last) 5 minutes push(@row_array, "avg_power_lastminutes_10 ".$AvP10."\n"); # Average Energy (last) 10 minutes push(@row_array, "avg_power_lastminutes_15 ".$AvP15."\n"); # Average Energy (last) 15 minutes - + use warnings; - } - + } + if ($sc) { # SBFSpot Kompatibilitätsmodus if($sup_EnergyProduction) { push(@row_array, "etotal ".($inv_SPOT_ETOTAL/1000)."\n"); @@ -751,32 +770,33 @@ sub SMAInverter_getstatusDoParse($) { } if($sup_SpotDCPower) { push(@row_array, "string_1_pdc ".sprintf("%.3f",$inv_SPOT_PDC1/1000)."\n"); - push(@row_array, "string_2_pdc ".sprintf("%.3f",$inv_SPOT_PDC2/1000)."\n"); + push(@row_array, "string_2_pdc ".sprintf("%.3f",$inv_SPOT_PDC2/1000)."\n"); } if($sup_SpotACPower) { push(@row_array, "phase_1_pac ".sprintf("%.3f",$inv_SPOT_PAC1/1000)."\n"); - push(@row_array, "phase_2_pac ".sprintf("%.3f",$inv_SPOT_PAC2/1000)."\n"); - push(@row_array, "phase_3_pac ".sprintf("%.3f",$inv_SPOT_PAC3/1000)."\n"); + push(@row_array, "phase_2_pac ".sprintf("%.3f",$inv_SPOT_PAC2/1000)."\n"); + push(@row_array, "phase_3_pac ".sprintf("%.3f",$inv_SPOT_PAC3/1000)."\n"); } if($sup_SpotACTotalPower) { - push(@row_array, "total_pac ".sprintf("%.3f",$inv_SPOT_PACTOT/1000)."\n"); - push(@row_array, "state ".sprintf("%.3f",$inv_SPOT_PACTOT/1000)."\n"); + push(@row_array, "total_pac ".sprintf("%.3f",$inv_SPOT_PACTOT/1000)."\n"); + push(@row_array, "state ".sprintf("%.3f",$inv_SPOT_PACTOT/1000)."\n"); } if($sup_ChargeStatus) { - push(@row_array, "chargestatus ".$inv_ChargeStatus."\n"); + push(@row_array, "chargestatus ".$inv_ChargeStatus."\n"); } + if($inv_CLASS && $inv_CLASS eq 8007 && defined($inv_SPOT_PACTOT)) { # V2.10.1 28.04.2019 if($inv_SPOT_PACTOT < 0) { push(@row_array, "power_out "."0"."\n"); push(@row_array, "power_in ".(-1 * $inv_SPOT_PACTOT)."\n"); } else { push(@row_array, "power_out ".$inv_SPOT_PACTOT."\n"); - push(@row_array, "power_in "."0"."\n"); + push(@row_array, "power_in "."0"."\n"); } } - + if($detail_level > 0) { - # For Detail Level 1 + # For Detail Level 1 if($sup_SpotDCVoltage) { push(@row_array, "string_1_udc ".sprintf("%.2f",$inv_SPOT_UDC1)."\n"); push(@row_array, "string_2_udc ".sprintf("%.2f",$inv_SPOT_UDC2)."\n"); @@ -795,16 +815,20 @@ sub SMAInverter_getstatusDoParse($) { push(@row_array, "bat_udc ".$inv_BAT_UDC."\n"); push(@row_array, "bat_idc ".$inv_BAT_IDC."\n"); } + if($sup_SpotBatteryLoad) { + push(@row_array, "bat_loadtotal ".($inv_BAT_LOADTOTAL/1000)."\n"); + push(@row_array, "bat_loadtoday ".($inv_BAT_LOADTODAY/1000)."\n"); + } } - + if($detail_level > 1) { # For Detail Level 2 if($sup_BatteryInfo) { - push(@row_array,"bat_cycles ".$inv_BAT_CYCLES."\n"); + push(@row_array, "bat_cycles ".$inv_BAT_CYCLES."\n"); push(@row_array, "bat_temp ".$inv_BAT_TEMP."\n"); } if($sup_SpotGridFrequency) { - push(@row_array, "grid_freq. ".sprintf("%.2f",$inv_SPOT_FREQ)."\n"); + push(@row_array, "grid_freq ".sprintf("%.2f",$inv_SPOT_FREQ)."\n"); } if($sup_TypeLabel) { push(@row_array, "device_type ".SMAInverter_devtype($inv_TYPE)."\n"); @@ -834,8 +858,9 @@ sub SMAInverter_getstatusDoParse($) { if($sup_DeviceStatus) { push(@row_array, "device_status ".SMAInverter_StatusText($inv_STATUS)."\n"); } - } - } else { # kein SBFSpot Compatibility Mode + } + + } else { # kein SBFSpot Compatibility Mode if($sup_EnergyProduction) { push(@row_array, "SPOT_ETOTAL ".$inv_SPOT_ETOTAL."\n"); push(@row_array, "SPOT_ETODAY ".$inv_SPOT_ETODAY."\n"); @@ -866,7 +891,7 @@ sub SMAInverter_getstatusDoParse($) { } } if($detail_level > 0) { - # For Detail Level 1 + # For Detail Level 1 if($sup_SpotDCVoltage) { push(@row_array, "SPOT_UDC1 ".$inv_SPOT_UDC1."\n"); push(@row_array, "SPOT_UDC2 ".$inv_SPOT_UDC2."\n"); @@ -885,8 +910,12 @@ sub SMAInverter_getstatusDoParse($) { push(@row_array, "BAT_UDC ".$inv_BAT_UDC."\n"); push(@row_array, "BAT_IDC ".$inv_BAT_IDC."\n"); } + if($sup_SpotBatteryLoad) { + push(@row_array, "BAT_LOADTOTAL ".$inv_BAT_LOADTOTAL."\n"); + push(@row_array, "BAT_LOADTODAY ".$inv_BAT_LOADTODAY."\n"); + } } - + if($detail_level > 1) { # For Detail Level 2 if($sup_BatteryInfo) { @@ -923,12 +952,12 @@ sub SMAInverter_getstatusDoParse($) { if($sup_DeviceStatus) { push(@row_array, "INV_STATUS ".SMAInverter_StatusText($inv_STATUS)."\n"); } - } + } } } else { # Login failed/not possible push(@row_array, "state Login failed"."\n"); - push(@row_array, "modulstate login failed"."\n"); + push(@row_array, "modulstate login failed"."\n"); } } else { # sleepmode at current time and not suppressed @@ -937,27 +966,27 @@ sub SMAInverter_getstatusDoParse($) { push(@row_array, "opertime_stop ".$opertime_stop."\n"); push(@row_array, "state done"."\n"); } - + Log3 ($name, 5, "$name -> row_array before encoding:"); foreach my $row (@row_array) { chomp $row; Log3 ($name, 5, "$name -> $row"); } - - # encoding result + + # encoding result my $rowlist = join('|', @row_array); $rowlist = encode_base64($rowlist,""); - + # Background-Laufzeit ermitteln $brt = tv_interval($bst); $rt = ($irt?$irt:'').",".$brt; - + Log3 ($name, 4, "$name -> BlockingCall SMAInverter_getstatusDoParse finished"); - -return "$name|$rowlist|$avg|$rt"; + +return "$name|$rowlist|$avg|$rt"; } - + ############################################################### # Auswertung non-blocking Inverter Datenabruf ############################################################### @@ -968,11 +997,11 @@ sub SMAInverter_getstatusParseDone ($) { my $hash = $defs{$name}; my $rowlist = decode_base64($a[1]); $hash->{HELPER}{AVERAGEBUF} = $a[2] if($a[2]); - my $rt = $a[3]; + my $rt = $a[3]; my ($irt,$brt) = split(",", $rt); - + Log3 ($name, 4, "$name -> Start BlockingCall SMAInverter_getstatusParseDone"); - + # proctime Readings löschen if(!AttrVal($name, "showproctime", undef)) { delete($defs{$name}{READINGS}{inverter_processing_time}); @@ -980,33 +1009,33 @@ sub SMAInverter_getstatusParseDone ($) { } else { delete($defs{$name}{READINGS}{inverter_processing_time}) if(!$irt); } - + # Get current time my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); - $hash->{LASTUPDATE} = sprintf "%02d.%02d.%04d / %02d:%02d:%02d" , $mday , $mon+=1 ,$year+=1900 , $hour , $min , $sec ; + $hash->{LASTUPDATE} = sprintf "%02d.%02d.%04d / %02d:%02d:%02d" , $mday , $mon+=1 ,$year+=1900 , $hour , $min , $sec ; my @row_array = split("\\|", $rowlist); - + Log3 ($name, 5, "$name -> row_array after decoding:"); foreach my $row (@row_array) { chomp $row; Log3 ($name, 5, "$name -> $row"); } - - readingsBeginUpdate($hash); + + readingsBeginUpdate($hash); foreach my $row (@row_array) { chomp $row; my @a = split(" ", $row, 2); $hash->{MODEL} = $a[1] if($a[0] eq "device_type"); readingsBulkUpdate($hash, $a[0], $a[1]); } - readingsBulkUpdate($hash, "background_processing_time", sprintf("%.4f",$brt)) if(AttrVal($name, "showproctime", undef)); + readingsBulkUpdate($hash, "background_processing_time", sprintf("%.4f",$brt)) if(AttrVal($name, "showproctime", undef)); readingsBulkUpdate($hash, "inverter_processing_time", sprintf("%.4f",$irt)) if(AttrVal($name, "showproctime", undef) && $irt); readingsEndUpdate($hash, 1); - + delete($hash->{HELPER}{RUNNING_PID}); Log3 ($name, 4, "$name -> BlockingCall SMAInverter_getstatusParseDone finished"); - + return; } @@ -1018,14 +1047,14 @@ sub SMAInverter_getstatusParseAborted(@) { my $name = $hash->{NAME}; my $discycles = $hash->{HELPER}{FAULTEDCYCLES}; $cause = $cause?$cause:"Timeout: process terminated"; - + # count of timeouts since module start $discycles++; $hash->{HELPER}{FAULTEDCYCLES} = $discycles; - + Log3 ($name, 1, "SMAInverter $name -> BlockingCall $hash->{HELPER}{RUNNING_PID}{fn} $cause"); readingsSingleUpdate($hash,"state",$cause, 1); - + delete($hash->{HELPER}{RUNNING_PID}); return; @@ -1056,25 +1085,26 @@ sub SMAInverter_SMAcommand($$$$$) { $inv_BAT_UDC, $inv_BAT_IDC, $inv_BAT_CYCLES, $inv_BAT_TEMP, + $inv_BAT_LOADTODAY, $inv_BAT_LOADTOTAL, $inv_SPOT_FREQ, $inv_SPOT_OPERTM, $inv_SPOT_FEEDTM, $inv_TEMP, $inv_GRIDRELAY, $inv_STATUS); my $mysusyid = $hash->{HELPER}{MYSUSYID}; my $myserialnumber = $hash->{HELPER}{MYSERIALNUMBER}; my ($cmd, $myID, $target_ID, $spkt_ID, $cmd_ID); my ($socket,$data,$size,$data_ID); my ($i, $temp); # Variables for loops and calculation - - # Seriennummer und SuSyID des Ziel-WR setzen + + # Seriennummer und SuSyID des Ziel-WR setzen my $default_target_susyid = $hash->{HELPER}{DEFAULT_TARGET_SUSYID}; - my $default_target_serial = $hash->{HELPER}{DEFAULT_TARGET_SERIAL}; + my $default_target_serial = $hash->{HELPER}{DEFAULT_TARGET_SERIAL}; my $target_susyid = AttrVal($name, "target-susyid", $default_target_susyid); my $target_serial = AttrVal($name, "target-serial", $default_target_serial); # Define own ID and target ID and packet ID $myID = SMAInverter_ByteOrderShort(substr(sprintf("%04X",$mysusyid),0,4)) . SMAInverter_ByteOrderLong(sprintf("%08X",$myserialnumber)); $target_ID = SMAInverter_ByteOrderShort(substr(sprintf("%04X",$target_susyid),0,4)) . SMAInverter_ByteOrderLong(sprintf("%08X",$target_serial)); - + # Increasing Packet ID - $hash->{HELPER}{PKT_ID} = $hash->{HELPER}{PKT_ID} + 1; + $hash->{HELPER}{PKT_ID} = $hash->{HELPER}{PKT_ID} + 1; $spkt_ID = SMAInverter_ByteOrderShort(sprintf("%04X",$hash->{HELPER}{PKT_ID})); $cmd_ID = SMAInverter_ByteOrderLong(sprintf("%08X",$command)) . SMAInverter_ByteOrderLong(sprintf("%08X",$first)) . SMAInverter_ByteOrderLong(sprintf("%08X",$last)); @@ -1083,8 +1113,8 @@ sub SMAInverter_SMAcommand($$$$$) { $cmd = $cmdheader . $pktlength . $esignature . $target_ID . "0000" . $myID . "0000" . "00000000" . $spkt_ID . $cmd_ID . "00000000"; # flush after every write - $| = 1; - + $| = 1; + # Create Socket and check if successful $socket = new IO::Socket::INET (PeerHost => $host, PeerPort => 9522, Proto => 'udp',); # open Socket @@ -1110,7 +1140,7 @@ sub SMAInverter_SMAcommand($$$$$) { my $received = unpack("H*", $data); Log3 $name, 5, "$name - Received: $received"; } - + # Nothing received -> exit if (not defined $size) { Log3 $name, 1, "$name - Nothing received..."; @@ -1136,23 +1166,23 @@ sub SMAInverter_SMAcommand($$$$$) { return 0; } } - + # All seems ok, data received $inv_susyid = unpack("v*", substr $data, 28, 2); $inv_serial = unpack("V*", substr $data, 30, 4); $socket->close(); - + if (AttrVal($name, "target-serial", undef)) { return 0 unless($target_serial eq $inv_serial); } if (AttrVal($name, "target-susyid", undef)) { return 0 unless($target_susyid eq $inv_susyid); } - + # Check the data identifier $data_ID = unpack("v*", substr $data, 55, 2); Log3 $name, 5, "$name - Data identifier $data_ID"; - + if($data_ID eq 0x2601) { if (length($data) >= 66) { $inv_SPOT_ETOTAL = unpack("V*", substr($data, 62, 4)); @@ -1172,14 +1202,41 @@ sub SMAInverter_SMAcommand($$$$$) { Log3 $name, 3, "$name - ETODAY calculated successfully !"; } else { Log3 $name, 3, "$name - WARNING - unable to calculate ETODAY ... set it to \"0\" !"; - $inv_SPOT_ETODAY = 0; - } + $inv_SPOT_ETODAY = 0; + } } Log3 $name, 5, "$name - Data SPOT_ETOTAL=$inv_SPOT_ETOTAL and SPOT_ETODAY=$inv_SPOT_ETODAY"; return (1,$inv_SPOT_ETODAY,$inv_SPOT_ETOTAL,$inv_susyid,$inv_serial); } - + + if($data_ID eq 0x4967) { + if (length($data) >= 66) { + $inv_BAT_LOADTOTAL = unpack("V*", substr($data, 62, 4)); + } else { + Log3 $name, 3, "$name - WARNING - BATTERYLOAD_TOTAL wasn't deliverd ... set it to \"0\" !"; + $inv_SPOT_ETOTAL = 0; + } + + if (length($data) >= 82) { + $inv_BAT_LOADTODAY = unpack("V*", substr ($data, 78, 4)); + } else { + # BATTERYLOAD_TODAY wurde vom WR nicht geliefert, es wird versucht ihn zu berechnen + Log3 $name, 3, "$name - BATTERYLOAD_TODAY wasn't delivered from inverter, try to calculate it ..."; + my $bltotold = ReadingsNum($name, ".bat_loadtotal_yesterday", undef); + if(defined $bltotold && $inv_BAT_LOADTOTAL > $bltotold) { + $inv_BAT_LOADTODAY = $inv_BAT_LOADTOTAL - $bltotold; + Log3 $name, 3, "$name - BATTERYLOAD_TODAY calculated successfully !"; + } else { + Log3 $name, 3, "$name - WARNING - unable to calculate BATTERYLOAD_TODAY ... set it to \"0\" !"; + $inv_BAT_LOADTODAY = 0; + } + } + + Log3 $name, 5, "$name - Data BAT_LOADTOTAL=$inv_BAT_LOADTOTAL and BAT_LOADTODAY=$inv_BAT_LOADTODAY"; + return (1,$inv_BAT_LOADTODAY,$inv_BAT_LOADTOTAL,$inv_susyid,$inv_serial); + } + if($data_ID eq 0x251E) { $inv_SPOT_PDC1 = unpack("V*", substr $data, 62, 4); if($size < 90) {$inv_SPOT_PDC2 = 0; } else {$inv_SPOT_PDC2 = unpack("V*", substr $data, 90, 4); } # catch short response, in case PDC2 not supported @@ -1187,8 +1244,8 @@ sub SMAInverter_SMAcommand($$$$$) { $inv_SPOT_PDC2 = ($inv_SPOT_PDC2 == 2147483648) ? 0 : $inv_SPOT_PDC2; Log3 $name, 5, "$name - Found Data SPOT_PDC1=$inv_SPOT_PDC1 and SPOT_PDC2=$inv_SPOT_PDC2"; return (1,$inv_SPOT_PDC1,$inv_SPOT_PDC2,$inv_susyid,$inv_serial); - } - + } + if($data_ID eq 0x4640) { $inv_SPOT_PAC1 = unpack("l*", substr $data, 62, 4); if($inv_SPOT_PAC1 eq -2147483648) {$inv_SPOT_PAC1 = 0; } # Catch 0x80000000 as 0 value @@ -1199,7 +1256,7 @@ sub SMAInverter_SMAcommand($$$$$) { Log3 $name, 5, "$name - Found Data SPOT_PAC1=$inv_SPOT_PAC1 and SPOT_PAC2=$inv_SPOT_PAC2 and SPOT_PAC3=$inv_SPOT_PAC3"; return (1,$inv_SPOT_PAC1,$inv_SPOT_PAC2,$inv_SPOT_PAC3,$inv_susyid,$inv_serial); } - + if($data_ID eq 0x411E) { $inv_PACMAX1 = unpack("V*", substr $data, 62, 4); $inv_PACMAX2 = unpack("V*", substr $data, 90, 4); @@ -1207,20 +1264,20 @@ sub SMAInverter_SMAcommand($$$$$) { Log3 $name, 5, "$name - Found Data INV_PACMAX1=$inv_PACMAX1 and INV_PACMAX2=$inv_PACMAX2 and INV_PACMAX3=$inv_PACMAX3"; return (1,$inv_PACMAX1,$inv_PACMAX2,$inv_PACMAX3,$inv_susyid,$inv_serial); } - + if($data_ID eq 0x832A) { $inv_PACMAX1_2 = unpack("V*", substr $data, 62, 4); Log3 $name, 5, "$name - Found Data INV_PACMAX1_2=$inv_PACMAX1_2"; return (1,$inv_PACMAX1_2,$inv_susyid,$inv_serial); } - + if($data_ID eq 0x263F) { $inv_SPOT_PACTOT = unpack("l*", substr $data, 62, 4); if($inv_SPOT_PACTOT eq -2147483648) {$inv_SPOT_PACTOT = 0; } # Catch 0x80000000 as 0 value Log3 $name, 5, "$name - Found Data SPOT_PACTOT=$inv_SPOT_PACTOT"; return (1,$inv_SPOT_PACTOT,$inv_susyid,$inv_serial); } - + if($data_ID eq 0x295A) { $inv_ChargeStatus = unpack("V*", substr $data, 62, 4); Log3 $name, 5, "$name - Found Data Battery Charge Status=$inv_ChargeStatus"; @@ -1233,7 +1290,7 @@ sub SMAInverter_SMAcommand($$$$$) { if($size < 146) { $inv_SPOT_UDC2 = 0; $inv_SPOT_IDC1 = unpack("l*", substr $data, 90, 4); - $inv_SPOT_IDC2 = 0; + $inv_SPOT_IDC2 = 0; } else { $inv_SPOT_UDC2 = unpack("l*", substr $data, 90, 4); $inv_SPOT_IDC1 = unpack("l*", substr $data, 118, 4); @@ -1266,9 +1323,9 @@ sub SMAInverter_SMAcommand($$$$$) { if($data_ID eq 0x491E) { $inv_BAT_CYCLES = unpack("V*", substr $data, 62, 4); - $inv_BAT_TEMP = unpack("V*", substr $data, 90, 4) / 10; + $inv_BAT_TEMP = unpack("V*", substr $data, 90, 4) / 10; $inv_BAT_UDC = unpack("V*", substr $data, 118, 4) / 100; - $inv_BAT_IDC = unpack("l*", substr $data, 146, 4); + $inv_BAT_IDC = unpack("l*", substr $data, 146, 4); if($inv_BAT_IDC eq -2147483648) {$inv_BAT_IDC = 0; } else { $inv_BAT_IDC = $inv_BAT_IDC / 1000;} # Catch 0x80000000 as 0 value Log3 $name, 5, "$name - Found Data BAT_CYCLES=$inv_BAT_CYCLES and BAT_TEMP=$inv_BAT_TEMP and BAT_UDC=$inv_BAT_UDC and BAT_IDC=$inv_BAT_IDC"; return (1,$inv_BAT_CYCLES,$inv_BAT_TEMP,$inv_BAT_UDC,$inv_BAT_IDC,$inv_susyid,$inv_serial); @@ -1334,7 +1391,7 @@ sub SMAInverter_SMAcommand($$$$$) { Log3 $name, 5, "$name - Found Data inv_STATUS=$inv_STATUS"; return (1,$inv_STATUS,$inv_susyid,$inv_serial); } - + return 0; } @@ -1353,21 +1410,21 @@ sub SMAInverter_SMAlogon($$$) { my $pkt_ID = $hash->{HELPER}{PKT_ID}; my ($cmd, $timestmp, $myID, $target_ID, $spkt_ID, $cmd_ID); my ($socket,$data,$size); - - # Seriennummer und SuSyID des Ziel-WR setzen + + # Seriennummer und SuSyID des Ziel-WR setzen my $default_target_susyid = $hash->{HELPER}{DEFAULT_TARGET_SUSYID}; - my $default_target_serial = $hash->{HELPER}{DEFAULT_TARGET_SERIAL}; + my $default_target_serial = $hash->{HELPER}{DEFAULT_TARGET_SERIAL}; my $target_susyid = AttrVal($name, "target-susyid", $default_target_susyid); my $target_serial = AttrVal($name, "target-serial", $default_target_serial); #Encode the password - my $encpasswd = "888888888888888888888888"; # template for password + my $encpasswd = "888888888888888888888888"; # template for password for my $index (0..length $pass ) # encode password { if ( (hex(substr($encpasswd,($index*2),2)) + ord(substr($pass,$index,1))) < 256 ) { substr($encpasswd,($index*2),2) = substr(sprintf ("%lX", (hex(substr($encpasswd,($index*2),2)) + ord(substr($pass,$index,1)))),0,2); } else { - substr($encpasswd,($index*2),2) = substr(sprintf ("%lX", (hex(substr($encpasswd,($index*2),2)) + ord(substr($pass,$index,1)))),1,2); + substr($encpasswd,($index*2),2) = substr(sprintf ("%lX", (hex(substr($encpasswd,($index*2),2)) + ord(substr($pass,$index,1)))),1,2); } } @@ -1387,7 +1444,7 @@ sub SMAInverter_SMAlogon($$$) { $cmd = $cmdheader . $pktlength . $esignature . $target_ID . "0001" . $myID . "0001" . "00000000" . $spkt_ID . $cmd_ID . $timestmp . "00000000" . $encpasswd . "00000000"; # flush after every write - $| = 1; + $| = 1; # Create Socket and check if successful $socket = new IO::Socket::INET (PeerHost => $host, PeerPort => 9522, Proto => 'udp',); # open Socket @@ -1403,7 +1460,7 @@ sub SMAInverter_SMAlogon($$$) { $socket->send($data); Log3 $name, 4, "$name - Send login to $host on Port 9522 with password $pass "; Log3 $name, 5, "$name - Send: $cmd "; - + # Receive Data and do a first check regarding length eval { $socket->recv($data, $hash->{HELPER}{MAXBYTES}); @@ -1451,25 +1508,25 @@ sub SMAInverter_SMAlogon($$$) { } } - # All seems ok, logged in! + # All seems ok, logged in! my $inv_susyid = unpack("v*", substr $data, 28, 2); my $inv_serial = unpack("V*", substr $data, 30, 4); $socket->close(); - + if (AttrVal($name, "target-serial", undef)) { return 0 unless($inv_serial eq $target_serial); } else { - BlockingInformParent("SMAInverter_setAttrFromBlocking", [$name, "target-serial", $inv_serial], 0); # Serial automatisch setzen, Forum: https://forum.fhem.de/index.php/topic,56080.msg967448.html#msg967448 + BlockingInformParent("SMAInverter_setAttrFromBlocking", [$name, "target-serial", $inv_serial], 0); # Serial automatisch setzen, Forum: https://forum.fhem.de/index.php/topic,56080.msg967448.html#msg967448 } - + if (AttrVal($name, "target-susyid", undef)) { return 0 unless($inv_susyid eq $target_susyid); } else { BlockingInformParent("SMAInverter_setAttrFromBlocking", [$name, "target-susyid", $inv_susyid], 0); # SuSyId automatisch setzen, Forum: https://forum.fhem.de/index.php/topic,56080.msg967448.html#msg967448 } - + Log3 $name, 4, "$name - logged in to inverter serial: $inv_serial, susyid: $inv_susyid"; - + return 1; } @@ -1512,10 +1569,10 @@ sub SMAInverter_SMAlogout($$) { my $pkt_ID = $hash->{HELPER}{PKT_ID}; my ($cmd, $myID, $target_ID, $spkt_ID, $cmd_ID); my ($socket,$data,$size); - - # Seriennummer und SuSyID des Ziel-WR setzen + + # Seriennummer und SuSyID des Ziel-WR setzen my $default_target_susyid = $hash->{HELPER}{DEFAULT_TARGET_SUSYID}; - my $default_target_serial = $hash->{HELPER}{DEFAULT_TARGET_SERIAL}; + my $default_target_serial = $hash->{HELPER}{DEFAULT_TARGET_SERIAL}; my $target_susyid = AttrVal($name, "target-susyid", $default_target_susyid); my $target_serial = AttrVal($name, "target-serial", $default_target_serial); @@ -1523,9 +1580,9 @@ sub SMAInverter_SMAlogout($$) { $myID = SMAInverter_ByteOrderShort(substr(sprintf("%04X",$mysusyid),0,4)) . SMAInverter_ByteOrderLong(sprintf("%08X",$myserialnumber)); $target_ID = SMAInverter_ByteOrderShort(substr(sprintf("%04X",$target_susyid),0,4)) . SMAInverter_ByteOrderLong(sprintf("%08X",$target_serial)); # Increasing Packet ID - $hash->{HELPER}{PKT_ID} = $hash->{HELPER}{PKT_ID} + 1; + $hash->{HELPER}{PKT_ID} = $hash->{HELPER}{PKT_ID} + 1; $spkt_ID = SMAInverter_ByteOrderShort(sprintf("%04X",$hash->{HELPER}{PKT_ID})); - + # Logout command $cmd_ID = "0E01FDFF" . "FFFFFFFF"; # Logout command @@ -1533,7 +1590,7 @@ sub SMAInverter_SMAlogout($$) { $cmd = $cmdheader . $pktlength . $esignature . $target_ID . "0003" . $myID . "0003" . "00000000" . $spkt_ID . $cmd_ID . "00000000"; # flush after every write - $| = 1; + $| = 1; # Create Socket and check if successful $socket = new IO::Socket::INET (PeerHost => $host, PeerPort => 9522, Proto => 'udp',); # open Socket @@ -1549,14 +1606,14 @@ sub SMAInverter_SMAlogout($$) { $socket->send($data); Log3 $name, 4, "$name - Send logout to $host on Port 9522"; Log3 $name, 5, "$name - Send: $cmd "; - + $target_serial = ($target_serial eq $default_target_serial)?"any inverter":$target_serial; $target_susyid = ($target_susyid eq $default_target_susyid)?"any susyid":$target_susyid; Log3 $name, 4, "$name - logged out now from inverter serial: $target_serial, susyid: $target_susyid"; - - $socket->close(); - -return 1; + + $socket->close(); + +return 1; } ########################################################################## @@ -1571,26 +1628,26 @@ sub SMAInverter_setVersionInfo($) { my $type = $hash->{TYPE}; $hash->{HELPER}{PACKAGE} = __PACKAGE__; $hash->{HELPER}{VERSION} = $v; - + if($modules{$type}{META}{x_prereqs_src} && !$hash->{HELPER}{MODMETAABSENT}) { # META-Daten sind vorhanden $modules{$type}{META}{version} = "v".$v; # Version aus META.json überschreiben, Anzeige mit {Dumper $modules{SMAPortal}{META}} if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id$ im Kopf komplett! vorhanden ) $modules{$type}{META}{x_version} =~ s/1.1.1/$v/g; } else { - $modules{$type}{META}{x_version} = $v; + $modules{$type}{META}{x_version} = $v; } return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id$ im Kopf komplett! vorhanden ) if(__PACKAGE__ eq "FHEM::$type" || __PACKAGE__ eq $type) { # es wird mit Packages gearbeitet -> Perl übliche Modulversion setzen # mit {->VERSION()} im FHEMWEB kann Modulversion abgefragt werden - use version 0.77; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); + use version 0.77; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); } } else { # herkömmliche Modulstruktur $hash->{VERSION} = $v; } - + return; } @@ -1601,7 +1658,7 @@ sub SMAInverter_ByteOrderShort($) { my $input = $_[0]; my $output = ""; $output = substr($input, 2, 2) . substr($input, 0, 2); - + return $output; } @@ -1612,13 +1669,13 @@ sub SMAInverter_ByteOrderLong($) { my $input = $_[0]; my $output = ""; $output = substr($input, 6, 2) . substr($input, 4, 2) . substr($input, 2, 2) . substr($input, 0, 2); - + return $output; } ########################################################################## # Texte for State -# Parameter is the code, return value is the Text or if not known then +# Parameter is the code, return value is the Text or if not known then # the code as string ########################################################################## sub SMAInverter_StatusText($) { @@ -1641,10 +1698,10 @@ return sprintf("%d", $code); ########################################################################## sub SMAInverter_devtype ($) { my ($code) = @_; - + unless (exists($SMAInverter_devtypes{$code})) { return $code;} my $dev = $SMAInverter_devtypes{$code}; - + return ($dev); } @@ -1654,7 +1711,7 @@ return ($dev); sub SMAInverter_classtype ($) { my ($code) = @_; my $class; - + if(AttrVal("global", "language", "EN") eq "DE") { unless (exists($SMAInverter_classesDE{$code})) { return $code;} $class = $SMAInverter_classesDE{$code}; @@ -1662,7 +1719,7 @@ sub SMAInverter_classtype ($) { unless (exists($SMAInverter_classesEN{$code})) { return $code;} $class = $SMAInverter_classesEN{$code}; } - + return ($class); } @@ -1685,7 +1742,7 @@ Questions and discussions about this module you can find in the FHEM-Forum link: 76_SMAInverter.pm - Abfrage von SMA Wechselrichter.

-Requirements +Requirements

This module requires:
    @@ -1717,63 +1774,63 @@ The module sends commands to the inverter and checks if they are supported by th In case of a positive answer the data is collected and displayed in the readings according to the detail-level.

    The normal operation time of the inverter is supposed from sunrise to sunset. In that time period the inverter will be polled. -The time of sunrise and sunset will be calculated by functions of FHEM module 99_SUNRISE_EL.pm which is loaded automatically by default. -Therefore the global attribute "longitude" and "latitude" should be set to determine the position of the solar system +The time of sunrise and sunset will be calculated by functions of FHEM module 99_SUNRISE_EL.pm which is loaded automatically by default. +Therefore the global attribute "longitude" and "latitude" should be set to determine the position of the solar system (see Commandref SUNRISE_EL).

    By the attribute "suppressSleep" the sleep mode between sunset and sunrise can be suppressed. Using attribute "offset" you may prefer the sunrise and defer the sunset virtually. So the working period of the inverter will be extended.

    -In operating mode "automatic" the inverter will be requested periodically corresponding the preset attribute "interval". The operating mode can be +In operating mode "automatic" the inverter will be requested periodically corresponding the preset attribute "interval". The operating mode can be switched to "manual" to realize the retrieval manually (e.g. to synchronize the requst with a SMA energy meter by notify).

    -During inverter operating time the average energy production of the last 5, 10 and 15 minutes will be calculated and displayed in the readings -"avg_power_lastminutes_05", "avg_power_lastminutes_10" and "avg_power_lastminutes_15". Note: To permit a precise calculation, you should +During inverter operating time the average energy production of the last 5, 10 and 15 minutes will be calculated and displayed in the readings +"avg_power_lastminutes_05", "avg_power_lastminutes_10" and "avg_power_lastminutes_15". Note: To permit a precise calculation, you should also set the real request interval into the attribute "interval" although you would use the "manual" operation mode !

    The retrieval of the inverter will be executed non-blocking. You can adjust the timeout value for this background process by attribute "timeout".
-Get +Get
  • get <name> data

    - The request of the inverter will be executed. Those possibility is especifically created for the "manual" operation + The request of the inverter will be executed. Those possibility is especifically created for the "manual" operation mode (see attribute "mode").
  • - +
Attributes
    - +
  • detail-level [0|1|2]
    Defines the complexity of the generated readings.

    - -
      - + +
        +
      0 - only Power and Energy
      1 - as 0, additional voltage and current
      2 - all values
      -
    - +
+
- +
  • disable [1|0]
    Deactivate/activate the module.

  • - +
  • interval
    Request cycle in seconds. (default: 60) @@ -1783,37 +1840,37 @@ The retrieval of the inverter will be executed non-blocking. You can adjust the
  • mode [automatic|manual]
    The request mode of the inverter. (default: automatic)

    - -
      - + +
        +
      automatic - the inverter will be polled regularly as defined by attribute "interval"
      manual - query only by command "get <name> data"
      -
    +

  • - +
  • offset <0 - 7200>
    - Time in seconds to forward the real sunrise respectively defer the real sunset. + Time in seconds to forward the real sunrise respectively defer the real sunset. You will be able to extend the working period of the module.

  • - +
  • SBFSpotComp [1|0]
    The reading names are created like the SBFSpot-style. (default: 0)

  • - +
  • showproctime [1|0]
    Shows the processing time in background and the wasted time to retrieve inverter data. (default: 0)

  • - +
  • suppressSleep [1|0]
    The sleep mode (after sunset and before sunrise) is deactivated and the inverter will be polled continuously. (default: 0) @@ -1822,16 +1879,16 @@ The retrieval of the inverter will be executed non-blocking. You can adjust the
  • target-serial
    - In case of a Multigate the target serial number has to be defined. If more than one inverter is installed, + In case of a Multigate the target serial number has to be defined. If more than one inverter is installed, you have to set the inverter serial number to assign the inverter to the device definition. If only one inverter available, the attribut is set automatically once the serial number of the inverter was detected. (default: 0xFFFFFFFF = means any serial number)

  • - +
  • target-susyid
    - In case of a Multigate the target SUSyID has to be defined. If more than one inverter is installed, + In case of a Multigate the target SUSyID has to be defined. If more than one inverter is installed, you have to set the inverter-SUSyID to assign the inverter to the device definition. If only one inverter available, the attribut is set automatically once the SUSyID of the inverter was detected. (default: 0xFFFF = means any SUSyID) @@ -1843,7 +1900,7 @@ The retrieval of the inverter will be executed non-blocking. You can adjust the Setup timeout of inverter data request in seconds. (default 60)

  • - + Readings @@ -1853,6 +1910,9 @@ The retrieval of the inverter will be executed non-blocking. You can adjust the
  • BAT_TEMP / bat_temp : Battery temperature
  • BAT_UDC / bat_udc : Battery Voltage
  • ChargeStatus / chargestatus : Battery Charge status
  • +
  • BAT_LOADTODAY : Battery Load Today
  • +
  • BAT_LOADTOTAL : Battery Load Total
  • +
  • ChargeStatus / chargestatus : Battery Charge status
  • CLASS / device_class : Inverter Class
  • PACMAX1 / pac_max_phase_1 : Nominal power in Ok Mode
  • PACMAX1_2 / pac_max_phase_1_2 : Maximum active power device (Some inverters like SB3300/SB1200)
  • @@ -1862,7 +1922,7 @@ The retrieval of the inverter will be executed non-blocking. You can adjust the
  • SPOT_ETODAY / etoday : Today yield
  • SPOT_ETOTAL / etotal : Total yield
  • SPOT_FEEDTM / feed-in_time : Feed-in time
  • -
  • SPOT_FREQ / grid_freq. : Grid Frequency
  • +
  • SPOT_FREQ / grid_freq : Grid Frequency
  • SPOT_IAC1 / phase_1_iac : Grid current phase L1
  • SPOT_IAC2 / phase_2_iac : Grid current phase L2
  • SPOT_IAC3 / phase_3_iac : Grid current phase L3
  • @@ -1887,13 +1947,13 @@ The retrieval of the inverter will be executed non-blocking. You can adjust the
  • POWER_OUT / power_out : Battery Discharging power
  • INV_GRIDRELAY / gridrelay_status : Grid Relay/Contactor Status
  • INV_STATUS / device_status : Inverter Status
  • -
  • opertime_start : Begin of iverter operating time corresponding the calculated time of sunrise with consideration of the +
  • opertime_start : Begin of iverter operating time corresponding the calculated time of sunrise with consideration of the attribute "offset" (if set)
  • -
  • opertime_stop : End of iverter operating time corresponding the calculated time of sunrise with consideration of the +
  • opertime_stop : End of iverter operating time corresponding the calculated time of sunrise with consideration of the attribute "offset" (if set)
  • modulstate : shows the current module state "normal" or "sleep" if the inverter won't be requested at the time.
  • -
  • avg_power_lastminutes_05 : average power of the last 5 minutes.
  • -
  • avg_power_lastminutes_10 : average power of the last 10 minutes.
  • +
  • avg_power_lastminutes_05 : average power of the last 5 minutes.
  • +
  • avg_power_lastminutes_10 : average power of the last 10 minutes.
  • avg_power_lastminutes_15 : average power of the last 15 minutes.
  • inverter_processing_time : wasted time to retrieve the inverter data
  • background_processing_time : total wasted time by background process (BlockingCall)
  • @@ -1916,7 +1976,7 @@ Fragen und Diskussionen rund um dieses Modul finden sie im FHEM-Forum unter:
    76_SMAInverter.pm - Abfrage von SMA Wechselrichter.

    -Voraussetzungen +Voraussetzungen

    Dieses Modul benötigt:
      @@ -1952,25 +2012,25 @@ Attribute longitude und latitude gesetzt sein um den Standort der Anlage genau z Mit dem Attribut "suppressSleep" kann der Schlafmodus unterdrückt werden. Das Attribut "offset" dient dazu den effektiven Zeitpunkt des Sonnenaufgangs / Sonnenuntergangs um den Betrag "offset" vorzuziehen (Sonnenaufgang) bzw. zu verzögern (Sonnenuntergang) und somit die Abfrageperiode des Wechselrichters zu verlängern.

      -Im Betriebsmodus "automatic" wird der Wechselrichter entsprechend des eingestellten Attributs "interval" abgefragt. Der Betriebsmodus kann in "manual" +Im Betriebsmodus "automatic" wird der Wechselrichter entsprechend des eingestellten Attributs "interval" abgefragt. Der Betriebsmodus kann in "manual" umgestellt werden um eine manuelle Abfrage zu realisieren (z.B. Synchronisierung mit einem SMA Energymeter über ein Notify).

      -Während der Betriebszeit des Wechselrichters wird die durchschnittliche Energieerzeugung der letzten 5, 10, 15 Minuten berechnet und in den Readings -"avg_power_lastminutes_05", "avg_power_lastminutes_10" und "avg_power_lastminutes_15" ausgegeben. Hinweis: Um eine korrekte Berechnung zu +Während der Betriebszeit des Wechselrichters wird die durchschnittliche Energieerzeugung der letzten 5, 10, 15 Minuten berechnet und in den Readings +"avg_power_lastminutes_05", "avg_power_lastminutes_10" und "avg_power_lastminutes_15" ausgegeben. Hinweis: Um eine korrekte Berechnung zu ermöglichen, sollte auch im Betriebsmodus "manual" das tatsächliche Abfrageinterval im Attribute "interval" hinterlegt werden !

      Die Abfrage des Wechselrichters wird non-blocking ausgeführt. Der Timeoutwert für diesen Hintergrundprozess kann mit dem Attribut "timeout" eingestellt werden.
    -Get +Get
      - +
    • get <name> data

      - Die Datenabfrage des Wechselrichters wird ausgeführt. Diese Möglichkeit ist speziell für den Betriebsmodus "manual" + Die Datenabfrage des Wechselrichters wird ausgeführt. Diese Möglichkeit ist speziell für den Betriebsmodus "manual" vorgesehen (siehe Attribut "mode").
    • @@ -1980,29 +2040,29 @@ Die Abfrage des Wechselrichters wird non-blocking ausgeführt. Der Timeoutwert f Attribute
        - +
      • detail-level [0|1|2]
        Legt den Umfang der ausgegebenen Readings fest.

        - -
          - + +
            +
          0 - nur Leistung und Energie
          1 - wie 0, zusätzlich Strom und Spannung
          2 - alle Werte
          -
        - +
      +
      - +
    • disable [1|0]
      Deaktiviert/aktiviert das Modul.

    • - +
    • interval
      Abfrageinterval in Sekunden. (default: 60) @@ -2012,25 +2072,25 @@ Die Abfrage des Wechselrichters wird non-blocking ausgeführt. Der Timeoutwert f
    • mode [automatic|manual]
      Abfragemodus des Wechselrichters. (default: automatic)

      - -
        - + +
          +
        automatic - die Wechselrichterwerte werden im eingestellten Interval abgefragt (Attribut "interval")
        manual - Abfrage nur mit "get <name> data"
        -
      +

    - +
  • offset <0 - 7200>
    - Zeit in Sekunden, um die der reale Sonnenaufgang vorgezogen bzw. reale Sonnenuntergang verzögert wird. + Zeit in Sekunden, um die der reale Sonnenaufgang vorgezogen bzw. reale Sonnenuntergang verzögert wird. Dadurch wird die effektive Aktivzeit des Moduls erweitert.

  • - +
  • SBFSpotComp [1|0]
    Die Readingnamen werden kompatibel zu SBFSpot-Ausgaben erzeugt. (default: 0) @@ -2042,7 +2102,7 @@ Die Abfrage des Wechselrichters wird non-blocking ausgeführt. Der Timeoutwert f Zeigt die für den Hintergrundprozess und die Abfrage des Wechselrichter verbrauchte Zeit. (default: 0)

  • - +
  • suppressSleep [1|0]
    Der Schlafmodus (nach Sonnenuntergang und vor Sonnenaufgang) wird ausgeschaltet und der WR abgefragt. (default: 0) @@ -2053,17 +2113,17 @@ Die Abfrage des Wechselrichters wird non-blocking ausgeführt. Der Timeoutwert f
  • target-serial
    Im Falle eines Multigate muss die Ziel-Seriennummer definiert werden. Ist mehr als ein Wechselrichter installiert, muß die Wechselreichter-Seriennummer gesetzt werden um den Wechselrichter der Device-Definition eindeutig zuzuweisen. - Ist nur ein Wechselrichter vorhanden und das Attribut nicht gesetzt, wird es automatisch definiert sobald die + Ist nur ein Wechselrichter vorhanden und das Attribut nicht gesetzt, wird es automatisch definiert sobald die Seriennummer des Wechselrichters erkannt wurde. (default: 0xFFFFFFFF = keine Einschränkung)

  • - +
  • target-susyid
    Im Falle eines Multigate muss die Ziel-SUSyID definiert werden. Ist mehr als ein Wechselrichter installiert, muß die Wechselreichter-SUSyID gesetzt werden um den Wechselrichter der Device-Definition eindeutig zuzuweisen. - Ist nur ein Wechselrichter vorhanden und das Attribut nicht gesetzt, wird es automatisch definiert sobald die + Ist nur ein Wechselrichter vorhanden und das Attribut nicht gesetzt, wird es automatisch definiert sobald die SUSyID des Wechselrichters erkannt wurde. (default: 0xFFFF = keine Einschränkung)
  • @@ -2084,6 +2144,8 @@ Die Abfrage des Wechselrichters wird non-blocking ausgeführt. Der Timeoutwert f
  • BAT_TEMP / bat_temp : Akku Temperatur
  • BAT_UDC / bat_udc : Akku Spannung
  • ChargeStatus / chargestatus : Akku Ladestand
  • +
  • BAT_LOADTODAY : Battery Load Today
  • +
  • BAT_LOADTOTAL : Battery Load Total
  • CLASS / device_class : Wechselrichter Klasse
  • PACMAX1 / pac_max_phase_1 : Nominelle Leistung in Ok Mode
  • PACMAX1_2 / pac_max_phase_1_2 : Maximale Leistung (für einige Wechselrichtertypen)
  • @@ -2093,10 +2155,10 @@ Die Abfrage des Wechselrichters wird non-blocking ausgeführt. Der Timeoutwert f
  • SPOT_ETODAY / etoday : Energie heute
  • SPOT_ETOTAL / etotal : Energie Insgesamt
  • SPOT_FEEDTM / feed-in_time : Einspeise-Stunden
  • -
  • SPOT_FREQ / grid_freq. : Netz Frequenz
  • +
  • SPOT_FREQ / grid_freq : Netz Frequenz
  • SPOT_IAC1 / phase_1_iac : Netz Strom phase L1
  • SPOT_IAC2 / phase_2_iac : Netz Strom phase L2
  • -
  • SPOT_IAC3 / phase_3_iac : Netz Strom phase L3
  • +
  • SPOT_IAC3 / phase_3_iac : Netz Strom phase L3
  • SPOT_IDC1 / string_1_idc : DC Strom Eingang 1
  • SPOT_IDC2 / string_2_idc : DC Strom Eingang 2
  • SPOT_OPERTM / operation_time : Betriebsstunden
  • @@ -2118,17 +2180,17 @@ Die Abfrage des Wechselrichters wird non-blocking ausgeführt. Der Timeoutwert f
  • POWER_OUT / power_out : Akku Entladeleistung
  • INV_GRIDRELAY / gridrelay_status : Netz Relais Status
  • INV_STATUS / device_status : Wechselrichter Status
  • -
  • opertime_start : Beginn Aktivzeit des Wechselrichters entsprechend des ermittelten Sonnenaufgangs mit Berücksichtigung des +
  • opertime_start : Beginn Aktivzeit des Wechselrichters entsprechend des ermittelten Sonnenaufgangs mit Berücksichtigung des Attributs "offset" (wenn gesetzt)
  • -
  • opertime_stop : Ende Aktivzeit des Wechselrichters entsprechend des ermittelten Sonnenuntergangs mit Berücksichtigung des +
  • opertime_stop : Ende Aktivzeit des Wechselrichters entsprechend des ermittelten Sonnenuntergangs mit Berücksichtigung des Attributs "offset" (wenn gesetzt)
  • modulstate : zeigt den aktuellen Modulstatus "normal" oder "sleep" falls der Wechselrichter nicht abgefragt wird.
  • -
  • avg_power_lastminutes_05 : durchschnittlich erzeugte Leistung der letzten 5 Minuten.
  • -
  • avg_power_lastminutes_10 : durchschnittlich erzeugte Leistung der letzten 10 Minuten.
  • -
  • avg_power_lastminutes_15 : durchschnittlich erzeugte Leistung der letzten 15 Minuten.
  • +
  • avg_power_lastminutes_05 : durchschnittlich erzeugte Leistung der letzten 5 Minuten.
  • +
  • avg_power_lastminutes_10 : durchschnittlich erzeugte Leistung der letzten 10 Minuten.
  • +
  • avg_power_lastminutes_15 : durchschnittlich erzeugte Leistung der letzten 15 Minuten.
  • inverter_processing_time : verbrauchte Zeit um den Wechelrichter abzufragen.
  • -
  • background_processing_time : gesamte durch den Hintergrundprozess (BlockingCall) verbrauchte Zeit.
  • - +
  • background_processing_time : gesamte durch den Hintergrundprozess (BlockingCall) verbrauchte Zeit.
  • +

    @@ -2167,12 +2229,12 @@ Die Abfrage des Wechselrichters wird non-blocking ausgeführt. Der Timeoutwert f "perl": 5.014, "IO::Socket::INET": 0, "DateTime": 0, - "Time::HiRes": 0, - "Blocking": 0, - "Time::Local": 0 + "Time::HiRes": 0, + "Blocking": 0, + "Time::Local": 0 }, "recommends": { - "FHEM::Meta": 0 + "FHEM::Meta": 0 }, "suggests": { } diff --git a/fhem/contrib/DS_Starter/76_SMAInverter.pm b/fhem/contrib/DS_Starter/76_SMAInverter.pm index 1c2829b9d..d26d82df6 100644 --- a/fhem/contrib/DS_Starter/76_SMAInverter.pm +++ b/fhem/contrib/DS_Starter/76_SMAInverter.pm @@ -23,16 +23,16 @@ package main; use strict; use warnings; -eval "use IO::Socket::INET;1" or my $MissModulSocket = "IO::Socket::INET"; -eval "use DateTime;1" or my $MissModulDateTime = "DateTime"; +eval "use IO::Socket::INET;1" or my $MissModulSocket = "IO::Socket::INET"; +eval "use DateTime;1" or my $MissModulDateTime = "DateTime"; use Time::HiRes qw(gettimeofday tv_interval); use Blocking; use Time::Local; -eval "use FHEM::Meta;1" or my $modMetaAbsent = 1; +eval "use FHEM::Meta;1" or my $modMetaAbsent = 1; # Versions History by DS_Starter our %SMAInverter_vNotesIntern = ( - "2.14.0" => "08.10.2019 readings bat_loadtotal (BAT_LOADTOTAL), bat_loadtoday (BAT_LOADTODAY) included by 300P", + "2.14.0" => "08.10.2019 readings bat_loadtotal (BAT_LOADTOTAL), bat_loadtoday (BAT_LOADTODAY) included by 300P, Forum: #topic,56080.msg986302.html#msg986302", "2.13.4" => "30.08.2019 STP10.0-3AV-40 298 included into %SMAInverter_devtypes ", "2.13.3" => "28.08.2019 commandref revised ", "2.13.2" => "27.08.2019 fix WARNING: Use of uninitialized value \$_ in substitution (s///) at /opt/fhem//FHEM/Blocking.pm line 238 ", @@ -687,7 +687,7 @@ sub SMAInverter_getstatusDoParse($) { ($sup_DeviceStatus,$inv_STATUS,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x51800200, 0x00214800, 0x002148FF); } elsif ($i eq "sup_SpotBatteryLoad") { - ($sup_SpotBatteryLoad,$inv_BAT_LOADTODAY,$inv_BAT_LOADTOTAL,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x54000200, 0x00461F00, 0x00461FFF); + ($sup_SpotBatteryLoad,$inv_BAT_LOADTODAY,$inv_BAT_LOADTOTAL,$inv_susyid,$inv_serial) = SMAInverter_SMAcommand($hash, $hash->{HOST}, 0x54000200, 0x00496700, 0x004967FF); } } @@ -1210,12 +1210,7 @@ sub SMAInverter_SMAcommand($$$$$) { return (1,$inv_SPOT_ETODAY,$inv_SPOT_ETOTAL,$inv_susyid,$inv_serial); } -####300? - - - - - if($data_ID eq 0x461F) { + if($data_ID eq 0x4967) { if (length($data) >= 66) { $inv_BAT_LOADTOTAL = unpack("V*", substr($data, 62, 4)); } else {